2 Unix SMB/CIFS implementation.
3 ads (active directory) utility library
4 Copyright (C) Andrew Tridgell 2001
5 Copyright (C) Remus Koos 2001
6 Copyright (C) Jim McDonough 2002
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 connect to the LDAP server
30 ADS_STATUS ads_connect(ADS_STRUCT *ads)
32 int version = LDAP_VERSION3;
36 ads->last_attempt = time(NULL);
38 ads->ld = ldap_open(ads->ldap_server, ads->ldap_port);
40 return ADS_ERROR_SYSTEM(errno);
42 status = ads_server_info(ads);
43 if (!ADS_ERR_OK(status)) {
44 DEBUG(1,("Failed to get ldap server info\n"));
48 ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
51 /* this is a really nasty hack to avoid ADS DNS problems. It needs a patch
52 to MIT kerberos to work (tridge) */
55 asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->server_realm);
56 setenv(env, inet_ntoa(*interpret_addr2(ads->ldap_server)), 1);
62 if ((code = ads_kinit_password(ads)))
63 return ADS_ERROR_KRB5(code);
66 return ads_sasl_bind(ads);
70 /* Do a search with paged results. cookie must be null on the first
71 call, and then returned on each subsequent call. It will be null
72 again when the entire search is complete */
74 ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
75 int scope, const char *exp,
76 const char **attrs, void **res,
77 int *count, void **cookie)
80 #define ADS_PAGE_CTL_OID "1.2.840.113556.1.4.319"
82 LDAPControl PagedResults;
83 BerElement *berelem = NULL;
84 struct berval *berval = NULL;
85 LDAPControl *controls[2];
86 LDAPControl **rcontrols, *cur_control;
90 ldap_get_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
92 /* Paged results only available on ldap v3 or later, so check
93 version first before using, since at connect time we're
94 only v2. Not sure exactly why... */
95 if (version < LDAP_VERSION3)
96 return ADS_ERROR(LDAP_NOT_SUPPORTED);
98 berelem = ber_alloc_t(LBER_USE_DER);
99 if (cookie && *cookie) {
100 ber_printf(berelem, "{iO}", (ber_int_t) 1000, *cookie);
101 ber_bvfree(*cookie); /* don't need it from last time */
104 ber_printf(berelem, "{io}", (ber_int_t) 1000, "", 0);
106 ber_flatten(berelem, &berval);
107 PagedResults.ldctl_oid = ADS_PAGE_CTL_OID;
108 PagedResults.ldctl_iscritical = (char) 1;
109 PagedResults.ldctl_value.bv_len = berval->bv_len;
110 PagedResults.ldctl_value.bv_val = berval->bv_val;
112 controls[0] = &PagedResults;
117 /* we need to disable referrals as the openldap libs don't
118 seem to handle them correctly. They result in the result
119 record containing the server control being removed from the
120 result list (tridge) */
121 ldap_set_option(ads->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
123 rc = ldap_search_ext_s(ads->ld, bind_path, scope, exp,
124 (char **) attrs, 0, controls, NULL,
126 (LDAPMessage **)res);
129 DEBUG(3,("ldap_search_ext_s(%s) -> %s\n", exp, ldap_err2string(rc)));
130 return ADS_ERROR(rc);
133 ber_free(berelem, 1);
136 rc = ldap_parse_result(ads->ld, *res, NULL, NULL, NULL,
137 NULL, &rcontrols, 0);
140 return ADS_ERROR(rc);
143 for (cur_control=rcontrols[0]; cur_control; cur_control++) {
144 if (strcmp(ADS_PAGE_CTL_OID, cur_control->ldctl_oid) == 0) {
145 berelem = ber_init(&cur_control->ldctl_value);
146 ber_scanf(berelem,"{iO}", (ber_int_t *) count,
148 /* the berval is the cookie, but must be freed when
150 if (berval->bv_len) /* still more to do */
151 *cookie=ber_bvdup(berval);
155 ber_free(berelem, 1);
159 ldap_controls_free(rcontrols);
161 return ADS_ERROR(rc);
166 this uses ads_do_paged_search() to return all entries in a large
167 search. The interface is the same as ads_do_search(), which makes
168 it more convenient than the paged interface
170 ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path,
171 int scope, const char *exp,
172 const char **attrs, void **res)
178 status = ads_do_paged_search(ads, bind_path, scope, exp, attrs, res, &count, &cookie);
180 if (!ADS_ERR_OK(status)) return status;
185 LDAPMessage *msg, *next;
187 status2 = ads_do_paged_search(ads, bind_path, scope, exp, attrs, &res2, &count, &cookie);
189 if (!ADS_ERR_OK(status2)) break;
191 /* this relies on the way that ldap_add_result_entry() works internally. I hope
192 that this works on all ldap libs, but I have only tested with openldap */
193 for (msg = ads_first_entry(ads, res2); msg; msg = next) {
194 next = ads_next_entry(ads, msg);
195 ldap_add_result_entry((LDAPMessage **)res, msg);
198 /* note that we do not free res2, as the memory is now
199 part of the main returned list */
206 do a search with a timeout
208 ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
210 const char **attrs, void **res)
212 struct timeval timeout;
215 timeout.tv_sec = ADS_SEARCH_TIMEOUT;
219 rc = ldap_search_ext_s(ads->ld,
221 exp, (char **) attrs, 0, NULL, NULL,
222 &timeout, LDAP_NO_LIMIT, (LDAPMessage **)res);
224 if (rc == LDAP_SIZELIMIT_EXCEEDED) {
225 DEBUG(3,("Warning! sizelimit exceeded in ldap. Truncating.\n"));
229 return ADS_ERROR(rc);
232 do a general ADS search
234 ADS_STATUS ads_search(ADS_STRUCT *ads, void **res,
238 return ads_do_search(ads, ads->bind_path, LDAP_SCOPE_SUBTREE,
243 do a search on a specific DistinguishedName
245 ADS_STATUS ads_search_dn(ADS_STRUCT *ads, void **res,
249 return ads_do_search(ads, dn, LDAP_SCOPE_BASE, "(objectclass=*)", attrs, res);
253 free up memory from a ads_search
255 void ads_msgfree(ADS_STRUCT *ads, void *msg)
262 free up memory from various ads requests
264 void ads_memfree(ADS_STRUCT *ads, void *mem)
271 get a dn from search results
273 char *ads_get_dn(ADS_STRUCT *ads, void *res)
275 return ldap_get_dn(ads->ld, res);
279 find a machine account given a hostname
281 ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *host)
285 const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
287 /* the easiest way to find a machine account anywhere in the tree
288 is to look for hostname$ */
289 asprintf(&exp, "(samAccountName=%s$)", host);
290 status = ads_search(ads, res, exp, attrs);
296 duplicate an already-assembled list of values so that it can be
297 freed as part of the standard msgfree call
299 static char **ads_dup_values(TALLOC_CTX *ctx, char **values)
303 #define ADS_MAX_NUM_VALUES 32
305 for (i=0; values[i] && i<ADS_MAX_NUM_VALUES; i++);
306 if (!(newvals = talloc_zero(ctx, (i+1)*sizeof(char *))))
308 for (i=0; values[i] && i<ADS_MAX_NUM_VALUES; i++)
309 newvals[i] = values[i];
315 initialize a list of mods
318 ADS_MODLIST ads_init_mods(TALLOC_CTX *ctx)
320 #define ADS_MODLIST_ALLOC_SIZE 10
323 if ((mods = (LDAPMod **) talloc_zero(ctx, sizeof(LDAPMod *) *
324 (ADS_MODLIST_ALLOC_SIZE + 1))))
325 /* -1 is safety to make sure we don't go over the end.
326 need to reset it to NULL before doing ldap modify */
327 mods[ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
333 add an attribute to the list, with values list already constructed
335 static ADS_STATUS ads_modlist_add(TALLOC_CTX *ctx, ADS_MODLIST *mods,
336 int mod_op, const char *name, char **values)
339 LDAPMod **modlist = (LDAPMod **) *mods;
341 /* find the first empty slot */
342 for (curmod=0; modlist[curmod] && modlist[curmod] != (LDAPMod *) -1;
344 if (modlist[curmod] == (LDAPMod *) -1) {
345 if (!(modlist = talloc_realloc(ctx, modlist,
346 (curmod+ADS_MODLIST_ALLOC_SIZE+1)*sizeof(LDAPMod *))))
347 return ADS_ERROR(LDAP_NO_MEMORY);
348 memset(&modlist[curmod], 0,
349 ADS_MODLIST_ALLOC_SIZE*sizeof(LDAPMod *));
350 modlist[curmod+ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
354 if (!(modlist[curmod] = talloc_zero(ctx, sizeof(LDAPMod))))
355 return ADS_ERROR(LDAP_NO_MEMORY);
356 modlist[curmod]->mod_type = name;
357 if (mod_op & LDAP_MOD_BVALUES)
358 modlist[curmod]->mod_bvalues = (struct berval **) values;
360 modlist[curmod]->mod_values = values;
361 modlist[curmod]->mod_op = mod_op;
362 return ADS_ERROR(LDAP_SUCCESS);
365 ADS_STATUS ads_mod_add_list(TALLOC_CTX *ctx, ADS_MODLIST *mods,
366 char *name, char **values)
368 char **newvals = ads_dup_values(ctx, values);
370 return ads_modlist_add(ctx, mods, LDAP_MOD_ADD, name, newvals);
372 return ADS_ERROR(LDAP_NO_MEMORY);
375 ADS_STATUS ads_mod_repl_list(TALLOC_CTX *ctx, ADS_MODLIST *mods,
376 char *name, char **values)
379 if (values && *values) {
380 if (!(newvals = ads_dup_values(ctx, values)))
381 return ADS_ERROR(LDAP_NO_MEMORY);
383 return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE,
387 return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
391 add an attribute to the list, with values list to be built from args
393 ADS_STATUS ads_mod_add_var(TALLOC_CTX *ctx, ADS_MODLIST *mods,
394 int mod_op, const char *name, ...)
397 int num_vals, i, do_op;
398 char *value, **values;
400 /* count the number of values */
402 for (num_vals=0; va_arg(ap, char *); num_vals++);
406 if (!(values = talloc_zero(ctx, sizeof(char *)*(num_vals+1))))
407 return ADS_ERROR(LDAP_NO_MEMORY);
409 for (i=0; (value = (char *) va_arg(ap, char *)) &&
416 do_op = LDAP_MOD_DELETE;
419 return ads_modlist_add(ctx, mods, do_op, name, values);
422 ADS_STATUS ads_mod_add_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods,
423 int mod_op, const char *name, ...)
426 int num_vals, i, do_op;
427 char *value, **values;
429 /* count the number of values */
431 for (num_vals=0; va_arg(ap, struct berval *); num_vals++);
435 if (!(values = talloc_zero(ctx, sizeof(struct berval) *
437 return ADS_ERROR(LDAP_NO_MEMORY);
439 for (i=0; (value = (char *) va_arg(ap, char *)) &&
446 do_op = LDAP_MOD_DELETE;
449 do_op |= LDAP_MOD_BVALUES;
450 return ads_modlist_add(ctx, mods, do_op, name, values);
453 ADS_STATUS ads_mod_repl(TALLOC_CTX *ctx, ADS_MODLIST *mods,
454 char *name, char *val)
457 return ads_mod_add_var(ctx, mods, LDAP_MOD_REPLACE,
460 return ads_mod_add_var(ctx, mods, LDAP_MOD_DELETE, name, NULL);
463 ADS_STATUS ads_mod_add(TALLOC_CTX *ctx, ADS_MODLIST *mods,
464 const char *name, const char *val)
466 return ads_mod_add_var(ctx, mods, LDAP_MOD_ADD, name, val, NULL);
469 ADS_STATUS ads_mod_add_len(TALLOC_CTX *ctx, ADS_MODLIST *mods,
470 char *name, size_t size, char *val)
472 struct berval *bval = NULL;
474 if (!(bval = talloc_zero(ctx, sizeof(struct berval *))))
475 return ADS_ERROR(LDAP_NO_MEMORY);
476 if (!(bval->bv_val = talloc_zero(ctx, sizeof(char *))))
477 return ADS_ERROR(LDAP_NO_MEMORY);
481 return ads_mod_add_ber(ctx, mods, LDAP_MOD_ADD, name, bval, NULL);
484 ADS_STATUS ads_mod_repl_len(TALLOC_CTX *ctx, ADS_MODLIST *mods,
485 const char *name, size_t size, char *val)
487 struct berval *bval = NULL;
489 if (!(bval = talloc_zero(ctx, sizeof(struct berval *))))
490 return ADS_ERROR(LDAP_NO_MEMORY);
493 return ads_mod_add_ber(ctx, mods, LDAP_MOD_DELETE, name, NULL);
495 if (!(bval->bv_val = talloc_zero(ctx, sizeof(char *))))
496 return ADS_ERROR(LDAP_NO_MEMORY);
499 return ads_mod_add_ber(ctx, mods, LDAP_MOD_REPLACE, name,
504 ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods)
508 this control is needed to modify that contains a currently
509 non-existent attribute (but allowable for the object) to run
511 LDAPControl PermitModify = {
512 "1.2.840.113556.1.4.1413",
515 LDAPControl *controls[2];
517 controls[0] = &PermitModify;
520 /* find the end of the list, marked by NULL or -1 */
521 for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
522 /* make sure the end of the list is NULL */
524 ret = ldap_modify_ext_s(ads->ld, mod_dn, (LDAPMod **) mods,
526 return ADS_ERROR(ret);
529 ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods)
533 /* find the end of the list, marked by NULL or -1 */
534 for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
535 /* make sure the end of the list is NULL */
538 return ADS_ERROR(ldap_add_s(ads->ld, new_dn, mods));
541 ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn)
543 return ADS_ERROR(ldap_delete(ads->ld, del_dn));
547 build an org unit string
548 if org unit is Computers or blank then assume a container, otherwise
549 assume a \ separated list of organisational units
552 char *ads_ou_string(const char *org_unit)
554 if (!org_unit || !*org_unit || strcasecmp(org_unit, "Computers") == 0) {
555 return strdup("cn=Computers");
558 return ads_build_path(org_unit, "\\/", "ou=", 1);
564 add a machine account to the ADS server
566 static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname,
567 const char *org_unit)
570 char *host_spn, *host_upn, *new_dn, *samAccountName, *controlstr;
575 if (!(ctx = talloc_init_named("machine_account")))
576 return ADS_ERROR(LDAP_NO_MEMORY);
578 ret = ADS_ERROR(LDAP_NO_MEMORY);
580 if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", hostname)))
582 if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->realm)))
584 ou_str = ads_ou_string(org_unit);
585 new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", hostname, ou_str,
591 if (!(samAccountName = talloc_asprintf(ctx, "%s$", hostname)))
593 if (!(controlstr = talloc_asprintf(ctx, "%u",
594 UF_DONT_EXPIRE_PASSWD | UF_WORKSTATION_TRUST_ACCOUNT |
595 UF_TRUSTED_FOR_DELEGATION | UF_USE_DES_KEY_ONLY)))
598 if (!(mods = ads_init_mods(ctx)))
601 ads_mod_add(ctx, &mods, "cn", hostname);
602 ads_mod_add(ctx, &mods, "sAMAccountName", samAccountName);
603 ads_mod_add_var(ctx, &mods, LDAP_MOD_ADD, "objectClass",
604 "top", "person", "organizationalPerson",
605 "user", "computer", NULL);
606 ads_mod_add(ctx, &mods, "userPrincipalName", host_upn);
607 ads_mod_add(ctx, &mods, "servicePrincipalName", host_spn);
608 ads_mod_add(ctx, &mods, "dNSHostName", hostname);
609 ads_mod_add(ctx, &mods, "userAccountControl", controlstr);
610 ads_mod_add(ctx, &mods, "operatingSystem", "Samba");
611 ads_mod_add(ctx, &mods, "operatingSystemVersion", VERSION);
613 ads_gen_add(ads, new_dn, mods);
614 ret = ads_set_machine_sd(ads, hostname, new_dn);
622 dump a binary result from ldap
624 static void dump_binary(const char *field, struct berval **values)
627 for (i=0; values[i]; i++) {
628 printf("%s: ", field);
629 for (j=0; j<values[i]->bv_len; j++) {
630 printf("%02X", (unsigned char)values[i]->bv_val[j]);
637 dump a sid result from ldap
639 static void dump_sid(const char *field, struct berval **values)
642 for (i=0; values[i]; i++) {
644 sid_parse(values[i]->bv_val, values[i]->bv_len, &sid);
645 printf("%s: %s\n", field, sid_string_static(&sid));
650 dump ntSecurityDescriptor
652 static void dump_sd(const char *filed, struct berval **values)
659 if (!(ctx = talloc_init_named("sec_io_desc")))
663 prs_init(&ps, values[0]->bv_len, ctx, UNMARSHALL);
664 prs_append_data(&ps, values[0]->bv_val, values[0]->bv_len);
668 if (!sec_io_desc("sd", &psd, &ps, 1)) {
673 if (psd) ads_disp_sd(psd);
680 dump a string result from ldap
682 static void dump_string(const char *field, struct berval **values)
685 for (i=0; values[i]; i++) {
686 printf("%s: %s\n", field, values[i]->bv_val);
691 dump a record from LDAP on stdout
694 void ads_dump(ADS_STRUCT *ads, void *res)
701 void (*handler)(const char *, struct berval **);
703 {"objectGUID", dump_binary},
704 {"nTSecurityDescriptor", dump_sd},
705 {"objectSid", dump_sid},
709 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
710 for (field = ldap_first_attribute(ads->ld, (LDAPMessage *)msg, &b);
712 field = ldap_next_attribute(ads->ld, (LDAPMessage *)msg, b)) {
713 struct berval **values;
716 values = ldap_get_values_len(ads->ld, (LDAPMessage *)msg, field);
718 for (i=0; handlers[i].name; i++) {
719 if (StrCaseCmp(handlers[i].name, field) == 0) {
720 handlers[i].handler(field, values);
724 if (!handlers[i].name) {
725 dump_string(field, values);
727 ldap_value_free_len(values);
737 count how many replies are in a LDAPMessage
739 int ads_count_replies(ADS_STRUCT *ads, void *res)
741 return ldap_count_entries(ads->ld, (LDAPMessage *)res);
745 join a machine to a realm, creating the machine account
746 and setting the machine password
748 ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org_unit)
754 /* hostname must be lowercase */
755 host = strdup(hostname);
758 status = ads_find_machine_acct(ads, (void **)&res, host);
759 if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
760 DEBUG(0, ("Host account for %s already exists - deleting old account\n", host));
761 status = ads_leave_realm(ads, host);
762 if (!ADS_ERR_OK(status)) {
763 DEBUG(0, ("Failed to delete host '%s' from the '%s' realm.\n",
769 status = ads_add_machine_acct(ads, host, org_unit);
770 if (!ADS_ERR_OK(status)) {
771 DEBUG(0, ("ads_add_machine_acct: %s\n", ads_errstr(status)));
775 status = ads_find_machine_acct(ads, (void **)&res, host);
776 if (!ADS_ERR_OK(status)) {
777 DEBUG(0, ("Host account test failed\n"));
787 delete a machine from the realm
789 ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
793 char *hostnameDN, *host;
796 /* hostname must be lowercase */
797 host = strdup(hostname);
800 status = ads_find_machine_acct(ads, &res, host);
801 if (!ADS_ERR_OK(status)) {
802 DEBUG(0, ("Host account for %s does not exist.\n", host));
806 hostnameDN = ads_get_dn(ads, (LDAPMessage *)res);
807 rc = ldap_delete_s(ads->ld, hostnameDN);
808 ads_memfree(ads, hostnameDN);
809 if (rc != LDAP_SUCCESS) {
810 return ADS_ERROR(rc);
813 status = ads_find_machine_acct(ads, &res, host);
814 if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
815 DEBUG(0, ("Failed to remove host account.\n"));
825 add machine account to existing security descriptor
827 ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
829 const char *attrs[] = {"ntSecurityDescriptor", "objectSid", 0};
832 struct berval **bvals = 0;
836 LDAPMessage *res = 0;
837 LDAPMessage *msg = 0;
838 ADS_MODLIST mods = 0;
846 if (!ads) return ADS_ERROR(LDAP_SERVER_DOWN);
848 ret = ADS_ERROR(LDAP_SUCCESS);
850 asprintf(&exp, "(samAccountName=%s$)", hostname);
851 ret = ads_search(ads, (void *) &res, exp, attrs);
853 if (!ADS_ERR_OK(ret)) return ret;
855 msg = ads_first_entry(ads, res);
856 bvals = ldap_get_values_len(ads->ld, msg, attrs[0]);
857 ads_pull_sid(ads, msg, attrs[1], &sid);
858 ads_msgfree(ads, res);
860 file_save("/tmp/sec_desc.old", bvals[0]->bv_val, bvals[0]->bv_len);
862 if (!(ctx = talloc_init_named("sec_io_desc")))
863 return ADS_ERROR(LDAP_NO_MEMORY);
865 prs_init(&ps, bvals[0]->bv_len, ctx, UNMARSHALL);
866 prs_append_data(&ps, bvals[0]->bv_val, bvals[0]->bv_len);
868 ldap_value_free_len(bvals);
870 if (!sec_io_desc("sd", &psd, &ps, 1))
871 goto ads_set_sd_error;
873 status = sec_desc_add_sid(ctx, &psd, &sid, SEC_RIGHTS_FULL_CTRL, &sd_size);
875 if (!NT_STATUS_IS_OK(status))
876 goto ads_set_sd_error;
878 prs_init(&ps_wire, sd_size, ctx, MARSHALL);
879 if (!sec_io_desc("sd_wire", &psd, &ps_wire, 1))
880 goto ads_set_sd_error;
883 file_save("/tmp/sec_desc.new", ps_wire.data_p, sd_size);
885 if (!(mods = ads_init_mods(ctx))) return ADS_ERROR(LDAP_NO_MEMORY);
887 ads_mod_repl_len(ctx, &mods, attrs[0], sd_size, ps_wire.data_p);
888 ret = ads_gen_mod(ads, dn, mods);
891 prs_mem_free(&ps_wire);
897 prs_mem_free(&ps_wire);
899 return ADS_ERROR(LDAP_NO_MEMORY);
902 ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
903 const char *hostname,
904 const char *password)
907 char *host = strdup(hostname);
910 if (!ads->kdc_server) {
911 DEBUG(0, ("Unable to find KDC server\n"));
912 return ADS_ERROR(LDAP_SERVER_DOWN);
917 asprintf(&principal, "%s@%s", host, ads->realm);
919 status = krb5_set_password(ads->kdc_server, principal, password);
928 pull the first entry from a ADS result
930 void *ads_first_entry(ADS_STRUCT *ads, void *res)
932 return (void *)ldap_first_entry(ads->ld, (LDAPMessage *)res);
936 pull the next entry from a ADS result
938 void *ads_next_entry(ADS_STRUCT *ads, void *res)
940 return (void *)ldap_next_entry(ads->ld, (LDAPMessage *)res);
944 pull a single string from a ADS result
946 char *ads_pull_string(ADS_STRUCT *ads,
947 TALLOC_CTX *mem_ctx, void *msg, const char *field)
952 values = ldap_get_values(ads->ld, msg, field);
953 if (!values) return NULL;
956 ret = talloc_strdup(mem_ctx, values[0]);
958 ldap_value_free(values);
963 pull a single uint32 from a ADS result
965 BOOL ads_pull_uint32(ADS_STRUCT *ads,
966 void *msg, const char *field, uint32 *v)
970 values = ldap_get_values(ads->ld, msg, field);
971 if (!values) return False;
973 ldap_value_free(values);
977 *v = atoi(values[0]);
978 ldap_value_free(values);
983 pull a single DOM_SID from a ADS result
985 BOOL ads_pull_sid(ADS_STRUCT *ads,
986 void *msg, const char *field, DOM_SID *sid)
988 struct berval **values;
991 values = ldap_get_values_len(ads->ld, msg, field);
993 if (!values) return False;
996 ret = sid_parse(values[0]->bv_val, values[0]->bv_len, sid);
999 ldap_value_free_len(values);
1004 pull an array of DOM_SIDs from a ADS result
1005 return the count of SIDs pulled
1007 int ads_pull_sids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
1008 void *msg, const char *field, DOM_SID **sids)
1010 struct berval **values;
1014 values = ldap_get_values_len(ads->ld, msg, field);
1016 if (!values) return 0;
1018 for (i=0; values[i]; i++) /* nop */ ;
1020 (*sids) = talloc(mem_ctx, sizeof(DOM_SID) * i);
1023 for (i=0; values[i]; i++) {
1024 ret = sid_parse(values[i]->bv_val, values[i]->bv_len, &(*sids)[count]);
1028 ldap_value_free_len(values);
1033 /* find the update serial number - this is the core of the ldap cache */
1034 ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
1036 const char *attrs[] = {"highestCommittedUSN", NULL};
1040 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1041 if (!ADS_ERR_OK(status)) return status;
1043 if (ads_count_replies(ads, res) != 1) {
1044 return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
1047 ads_pull_uint32(ads, res, "highestCommittedUSN", usn);
1048 ads_msgfree(ads, res);
1053 /* find the servers name and realm - this can be done before authentication
1054 The ldapServiceName field on w2k looks like this:
1055 vnet3.home.samba.org:win2000-vnet3$@VNET3.HOME.SAMBA.ORG
1057 ADS_STATUS ads_server_info(ADS_STRUCT *ads)
1059 const char *attrs[] = {"ldapServiceName", NULL};
1065 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1066 if (!ADS_ERR_OK(status)) return status;
1068 values = ldap_get_values(ads->ld, res, "ldapServiceName");
1069 if (!values || !values[0]) return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
1071 p = strchr(values[0], ':');
1073 ldap_value_free(values);
1075 return ADS_ERROR(LDAP_DECODING_ERROR);
1078 SAFE_FREE(ads->ldap_server_name);
1080 ads->ldap_server_name = strdup(p+1);
1081 p = strchr(ads->ldap_server_name, '$');
1082 if (!p || p[1] != '@') {
1083 ldap_value_free(values);
1085 SAFE_FREE(ads->ldap_server_name);
1086 return ADS_ERROR(LDAP_DECODING_ERROR);
1091 SAFE_FREE(ads->server_realm);
1092 SAFE_FREE(ads->bind_path);
1094 ads->server_realm = strdup(p+2);
1095 ads->bind_path = ads_build_dn(ads->server_realm);
1097 /* in case the realm isn't configured in smb.conf */
1098 if (!ads->realm || !ads->realm[0]) {
1099 SAFE_FREE(ads->realm);
1100 ads->realm = strdup(ads->server_realm);
1103 DEBUG(3,("got ldap server name %s@%s\n",
1104 ads->ldap_server_name, ads->realm));
1111 find the list of trusted domains
1113 ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
1114 int *num_trusts, char ***names, DOM_SID **sids)
1116 const char *attrs[] = {"flatName", "securityIdentifier", NULL};
1123 status = ads_search(ads, &res, "(objectcategory=trustedDomain)", attrs);
1124 if (!ADS_ERR_OK(status)) return status;
1126 count = ads_count_replies(ads, res);
1128 ads_msgfree(ads, res);
1129 return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
1132 (*names) = talloc(mem_ctx, sizeof(char *) * count);
1133 (*sids) = talloc(mem_ctx, sizeof(DOM_SID) * count);
1134 if (! *names || ! *sids) return ADS_ERROR(LDAP_NO_MEMORY);
1136 for (i=0, msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
1137 (*names)[i] = ads_pull_string(ads, mem_ctx, msg, "flatName");
1138 if (ads_pull_sid(ads, msg, "securityIdentifier", &(*sids)[i])) {
1143 ads_msgfree(ads, res);
1150 /* find the domain sid for our domain */
1151 ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)
1153 const char *attrs[] = {"objectSid", NULL};
1157 rc = ads_do_search(ads, ads->bind_path, LDAP_SCOPE_BASE, "(objectclass=*)",
1159 if (!ADS_ERR_OK(rc)) return rc;
1160 if (!ads_pull_sid(ads, res, "objectSid", sid)) {
1161 return ADS_ERROR_SYSTEM(ENOENT);
1163 ads_msgfree(ads, res);