fix for IRIX compile error
[tprouty/samba.git] / source / libads / ldap.c
1 /* 
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
7    
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
24
25 #ifdef HAVE_ADS
26
27 /*
28   connect to the LDAP server
29 */
30 ADS_STATUS ads_connect(ADS_STRUCT *ads)
31 {
32         int version = LDAP_VERSION3;
33         int code;
34         ADS_STATUS status;
35
36         ads->last_attempt = time(NULL);
37
38         ads->ld = ldap_open(ads->ldap_server, ads->ldap_port);
39         if (!ads->ld) {
40                 return ADS_ERROR_SYSTEM(errno);
41         }
42         status = ads_server_info(ads);
43         if (!ADS_ERR_OK(status)) {
44                 DEBUG(1,("Failed to get ldap server info\n"));
45                 return status;
46         }
47
48         ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
49
50         if (ads->password) {
51                 if ((code = ads_kinit_password(ads)))
52                         return ADS_ERROR_KRB5(code);
53         }
54
55         return ads_sasl_bind(ads);
56 }
57
58 /*
59   do a search with a timeout
60 */
61 ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope, 
62                          const char *exp,
63                          const char **attrs, void **res)
64 {
65         struct timeval timeout;
66         int rc;
67
68         timeout.tv_sec = ADS_SEARCH_TIMEOUT;
69         timeout.tv_usec = 0;
70         *res = NULL;
71
72         rc = ldap_search_ext_s(ads->ld, 
73                                bind_path, scope,
74                                exp, (char **) attrs, 0, NULL, NULL, 
75                                &timeout, LDAP_NO_LIMIT, (LDAPMessage **)res);
76         return ADS_ERROR(rc);
77 }
78 /*
79   do a general ADS search
80 */
81 ADS_STATUS ads_search(ADS_STRUCT *ads, void **res, 
82                       const char *exp, 
83                       const char **attrs)
84 {
85         return ads_do_search(ads, ads->bind_path, LDAP_SCOPE_SUBTREE, 
86                              exp, attrs, res);
87 }
88
89 /*
90   do a search on a specific DistinguishedName
91 */
92 ADS_STATUS ads_search_dn(ADS_STRUCT *ads, void **res, 
93                          const char *dn, 
94                          const char **attrs)
95 {
96         return ads_do_search(ads, dn, LDAP_SCOPE_BASE, "(objectclass=*)", attrs, res);
97 }
98
99 /*
100   free up memory from a ads_search
101 */
102 void ads_msgfree(ADS_STRUCT *ads, void *msg)
103 {
104         if (!msg) return;
105         ldap_msgfree(msg);
106 }
107
108 /*
109   free up memory from various ads requests
110 */
111 void ads_memfree(ADS_STRUCT *ads, void *mem)
112 {
113         if (!mem) return;
114         ldap_memfree(mem);
115 }
116
117 /*
118   get a dn from search results
119 */
120 char *ads_get_dn(ADS_STRUCT *ads, void *res)
121 {
122         return ldap_get_dn(ads->ld, res);
123 }
124
125 /*
126   find a machine account given a hostname 
127 */
128 ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *host)
129 {
130         ADS_STATUS status;
131         char *exp;
132         const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
133
134         /* the easiest way to find a machine account anywhere in the tree
135            is to look for hostname$ */
136         asprintf(&exp, "(samAccountName=%s$)", host);
137         status = ads_search(ads, res, exp, attrs);
138         free(exp);
139         return status;
140 }
141
142 /*
143   duplicate an already-assembled list of values so that it can be
144   freed as part of the standard msgfree call
145 */
146 static char **ads_dup_values(TALLOC_CTX *ctx, char **values)
147 {
148         char **newvals;
149         int i;
150 #define ADS_MAX_NUM_VALUES 32
151
152         for (i=0; values[i] && i<ADS_MAX_NUM_VALUES; i++);
153         if (!(newvals = talloc_zero(ctx, (i+1)*sizeof(char *))))
154                 return NULL;
155         for (i=0; values[i] && i<ADS_MAX_NUM_VALUES; i++)
156                 newvals[i] = values[i];
157         newvals[i] = NULL;
158         return newvals;
159 }
160
161 /*
162   initialize a list of mods 
163 */
164
165 ADS_MODLIST ads_init_mods(TALLOC_CTX *ctx)
166 {
167 #define ADS_MODLIST_ALLOC_SIZE 10
168         LDAPMod **mods;
169         
170         if ((mods = (LDAPMod **) talloc_zero(ctx, sizeof(LDAPMod *) * 
171                                              (ADS_MODLIST_ALLOC_SIZE + 1))))
172                 /* -1 is safety to make sure we don't go over the end.
173                    need to reset it to NULL before doing ldap modify */
174                 mods[ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
175         
176         return mods;
177 }
178
179 /*
180   add an attribute to the list, with values list already constructed
181 */
182 static ADS_STATUS ads_modlist_add(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
183                                   int mod_op, char *name, char **values)
184 {
185         int curmod;
186         LDAPMod **modlist = (LDAPMod **) *mods;
187
188         /* find the first empty slot */
189         for (curmod=0; modlist[curmod] && modlist[curmod] != (LDAPMod *) -1;
190              curmod++);
191         if (modlist[curmod] == (LDAPMod *) -1) {
192                 if (!(modlist = talloc_realloc(ctx, modlist, 
193                         (curmod+ADS_MODLIST_ALLOC_SIZE+1)*sizeof(LDAPMod *))))
194                         return ADS_ERROR(LDAP_NO_MEMORY);
195                 memset(&modlist[curmod], 0, 
196                        ADS_MODLIST_ALLOC_SIZE*sizeof(LDAPMod *));
197                 modlist[curmod+ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
198                 *mods = modlist;
199         }
200                 
201         if (!(modlist[curmod] = talloc_zero(ctx, sizeof(LDAPMod))))
202                 return ADS_ERROR(LDAP_NO_MEMORY);
203         modlist[curmod]->mod_type = name;
204         if (mod_op & LDAP_MOD_BVALUES)
205                 modlist[curmod]->mod_bvalues = (struct berval **) values;
206         else
207                 modlist[curmod]->mod_values = values;
208         modlist[curmod]->mod_op = mod_op;
209         return ADS_ERROR(LDAP_SUCCESS);
210 }
211
212 ADS_STATUS ads_mod_add_list(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
213                             char *name, char **values)
214 {
215         char **newvals = ads_dup_values(ctx, values);
216         if (newvals)
217                 return ads_modlist_add(ctx, mods, LDAP_MOD_ADD, name, newvals);
218         else
219                 return ADS_ERROR(LDAP_NO_MEMORY);
220 }
221
222 ADS_STATUS ads_mod_repl_list(TALLOC_CTX *ctx, ADS_MODLIST *mods,
223                              char *name, char **values)
224 {
225         char **newvals;
226         if (values && *values) {
227                 if (!(newvals = ads_dup_values(ctx, values)))
228                         return ADS_ERROR(LDAP_NO_MEMORY);
229                 else
230                         return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE,
231                                                 name, newvals);
232         }
233         else
234                 return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
235 }
236
237 /*
238   add an attribute to the list, with values list to be built from args
239 */
240 ADS_STATUS ads_mod_add_var(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
241                            int mod_op, char *name, ...)
242 {
243         va_list ap;
244         int num_vals, i, do_op;
245         char *value, **values;
246
247         /* count the number of values */
248         va_start(ap, name);
249         for (num_vals=0; va_arg(ap, char *); num_vals++);
250         va_end(ap);
251
252         if (num_vals) {
253                 if (!(values = talloc_zero(ctx, sizeof(char *)*(num_vals+1))))
254                         return ADS_ERROR(LDAP_NO_MEMORY);
255                 va_start(ap, name);
256                 for (i=0; (value = (char *) va_arg(ap, char *)) &&
257                              i < num_vals; i++)
258                         values[i] = value;
259                 va_end(ap);
260                 values[i] = NULL;
261                 do_op = mod_op;
262         } else {
263                 do_op = LDAP_MOD_DELETE;
264                 values = NULL;
265         }
266         return ads_modlist_add(ctx, mods, do_op, name, values);
267 }
268
269 ADS_STATUS ads_mod_add_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
270                            int mod_op, char *name, ...)
271 {
272         va_list ap;
273         int num_vals, i, do_op;
274         char *value, **values;
275
276         /* count the number of values */
277         va_start(ap, name);
278         for (num_vals=0; va_arg(ap, struct berval *); num_vals++);
279         va_end(ap);
280
281         if (num_vals) {
282                 if (!(values = talloc_zero(ctx, sizeof(struct berval) * 
283                                            (num_vals + 1))))
284                         return ADS_ERROR(LDAP_NO_MEMORY);
285                 va_start(ap, name);
286                 for (i=0; (value = (char *) va_arg(ap, char *)) &&
287                              i < num_vals; i++)
288                         values[i] = value;
289                 va_end(ap);
290                 values[i] = NULL;
291                 do_op = mod_op;
292         } else {
293                 do_op = LDAP_MOD_DELETE;
294                 values = NULL;
295         }
296         do_op |= LDAP_MOD_BVALUES;
297         return ads_modlist_add(ctx, mods, do_op, name, values);
298 }
299
300 ADS_STATUS ads_mod_repl(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
301                         char *name, char *val)
302 {
303         if (val)
304                 return ads_mod_add_var(ctx, mods, LDAP_MOD_REPLACE,
305                                        name, val, NULL);
306         else
307                 return ads_mod_add_var(ctx, mods, LDAP_MOD_DELETE, name, NULL);
308 }
309
310 ADS_STATUS ads_mod_add(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
311                        char *name, char *val)
312 {
313         return ads_mod_add_var(ctx, mods, LDAP_MOD_ADD, name, val, NULL);
314 }
315
316 ADS_STATUS ads_mod_add_len(TALLOC_CTX *ctx, ADS_MODLIST *mods,
317                            char *name, size_t size, char *val)
318 {
319         struct berval *bval = NULL;
320
321         if (!(bval = talloc_zero(ctx, sizeof(struct berval *))))
322                 return ADS_ERROR(LDAP_NO_MEMORY);
323         if (!(bval->bv_val = talloc_zero(ctx, sizeof(char *))))
324                 return ADS_ERROR(LDAP_NO_MEMORY);
325
326         bval->bv_val = val;
327         bval->bv_len = size;
328         return ads_mod_add_ber(ctx, mods, LDAP_MOD_ADD, name, bval, NULL);
329 }
330
331 ADS_STATUS ads_mod_repl_len(TALLOC_CTX *ctx, ADS_MODLIST *mods,
332                            char *name, size_t size, char *val)
333 {
334         struct berval *bval = NULL;
335
336         if (!(bval = talloc_zero(ctx, sizeof(struct berval *))))
337                 return ADS_ERROR(LDAP_NO_MEMORY);
338
339         if (!val)
340                 return ads_mod_add_ber(ctx, mods, LDAP_MOD_DELETE, name, NULL);
341         else {
342                 if (!(bval->bv_val = talloc_zero(ctx, sizeof(char *))))
343                         return ADS_ERROR(LDAP_NO_MEMORY);
344                 bval->bv_val = val;
345                 bval->bv_len = size;
346                 return ads_mod_add_ber(ctx, mods, LDAP_MOD_REPLACE, name, 
347                                        bval, NULL);
348         }
349 }
350
351 ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods)
352 {
353         int ret,i;
354         /* 
355            this control is needed to modify that contains a currently 
356            non-existent attribute (but allowable for the object) to run
357         */
358         LDAPControl PermitModify = {
359                 "1.2.840.113556.1.4.1413",
360                 {0, NULL},
361                 (char) 1};
362         LDAPControl *controls[2];
363
364         controls[0] = &PermitModify;
365         controls[1] = NULL;
366
367         /* find the end of the list, marked by NULL or -1 */
368         for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
369         /* make sure the end of the list is NULL */
370         mods[i] = NULL;
371         ret = ldap_modify_ext_s(ads->ld, mod_dn, (LDAPMod **) mods,
372                                 controls, NULL);
373         return ADS_ERROR(ret);
374 }
375
376 ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods)
377 {
378         int i;
379
380         /* find the end of the list, marked by NULL or -1 */
381         for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
382         /* make sure the end of the list is NULL */
383         mods[i] = NULL;
384
385         return ADS_ERROR(ldap_add_s(ads->ld, new_dn, mods));
386 }
387
388 ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn)
389 {
390         return ADS_ERROR(ldap_delete(ads->ld, del_dn));
391 }
392
393 /*
394   build an org unit string
395   if org unit is Computers or blank then assume a container, otherwise
396   assume a \ separated list of organisational units
397   caller must free
398 */
399 char *ads_ou_string(const char *org_unit)
400 {       
401         if (!org_unit || !*org_unit || strcasecmp(org_unit, "Computers") == 0) {
402                 return strdup("cn=Computers");
403         }
404
405         return ads_build_path(org_unit, "\\/", "ou=", 1);
406 }
407
408
409
410 /*
411   add a machine account to the ADS server
412 */
413 static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname, 
414                                        const char *org_unit)
415 {
416         ADS_STATUS ret;
417         char *host_spn, *host_upn, *new_dn, *samAccountName, *controlstr;
418         char *ou_str;
419         TALLOC_CTX *ctx;
420         ADS_MODLIST mods;
421
422         if (!(ctx = talloc_init_named("machine_account")))
423                 return ADS_ERROR(LDAP_NO_MEMORY);
424
425         ret = ADS_ERROR(LDAP_NO_MEMORY);
426
427         if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", hostname)))
428                 goto done;
429         if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->realm)))
430                 goto done;
431         ou_str = ads_ou_string(org_unit);
432         new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", hostname, ou_str, 
433                                  ads->bind_path);
434         free(ou_str);
435         if (!new_dn)
436                 goto done;
437
438         if (!(samAccountName = talloc_asprintf(ctx, "%s$", hostname)))
439                 goto done;
440         if (!(controlstr = talloc_asprintf(ctx, "%u", 
441                    UF_DONT_EXPIRE_PASSWD | UF_WORKSTATION_TRUST_ACCOUNT | 
442                    UF_TRUSTED_FOR_DELEGATION | UF_USE_DES_KEY_ONLY)))
443                 goto done;
444
445         if (!(mods = ads_init_mods(ctx)))
446                 goto done;
447         
448         ads_mod_add(ctx, &mods, "cn", hostname);
449         ads_mod_add(ctx, &mods, "sAMAccountName", samAccountName);
450         ads_mod_add_var(ctx, &mods, LDAP_MOD_ADD, "objectClass",
451                         "top", "person", "organizationalPerson",
452                         "user", "computer", NULL);
453         ads_mod_add(ctx, &mods, "userPrincipalName", host_upn);
454         ads_mod_add(ctx, &mods, "servicePrincipalName", host_spn);
455         ads_mod_add(ctx, &mods, "dNSHostName", hostname);
456         ads_mod_add(ctx, &mods, "userAccountControl", controlstr);
457         ads_mod_add(ctx, &mods, "operatingSystem", "Samba");
458         ads_mod_add(ctx, &mods, "operatingSystemVersion", VERSION);
459
460         ret = ads_gen_add(ads, new_dn, mods);
461
462 done:
463         talloc_destroy(ctx);
464         return ret;
465 }
466
467 /*
468   dump a binary result from ldap
469 */
470 static void dump_binary(const char *field, struct berval **values)
471 {
472         int i, j;
473         for (i=0; values[i]; i++) {
474                 printf("%s: ", field);
475                 for (j=0; j<values[i]->bv_len; j++) {
476                         printf("%02X", (unsigned char)values[i]->bv_val[j]);
477                 }
478                 printf("\n");
479         }
480 }
481
482 /*
483   dump a sid result from ldap
484 */
485 static void dump_sid(const char *field, struct berval **values)
486 {
487         int i;
488         for (i=0; values[i]; i++) {
489                 DOM_SID sid;
490                 sid_parse(values[i]->bv_val, values[i]->bv_len, &sid);
491                 printf("%s: %s\n", field, sid_string_static(&sid));
492         }
493 }
494
495 /*
496   dump a string result from ldap
497 */
498 static void dump_string(const char *field, struct berval **values)
499 {
500         int i;
501         for (i=0; values[i]; i++) {
502                 printf("%s: %s\n", field, values[i]->bv_val);
503         }
504 }
505
506 /*
507   dump a record from LDAP on stdout
508   used for debugging
509 */
510 void ads_dump(ADS_STRUCT *ads, void *res)
511 {
512         char *field;
513         void *msg;
514         BerElement *b;
515         struct {
516                 char *name;
517                 void (*handler)(const char *, struct berval **);
518         } handlers[] = {
519                 {"objectGUID", dump_binary},
520                 {"nTSecurityDescriptor", dump_binary},
521                 {"objectSid", dump_sid},
522                 {NULL, NULL}
523         };
524     
525         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
526                 for (field = ldap_first_attribute(ads->ld, (LDAPMessage *)msg, &b); 
527                      field;
528                      field = ldap_next_attribute(ads->ld, (LDAPMessage *)msg, b)) {
529                         struct berval **values;
530                         int i;
531
532                         values = ldap_get_values_len(ads->ld, (LDAPMessage *)msg, field);
533
534                         for (i=0; handlers[i].name; i++) {
535                                 if (StrCaseCmp(handlers[i].name, field) == 0) {
536                                         handlers[i].handler(field, values);
537                                         break;
538                                 }
539                         }
540                         if (!handlers[i].name) {
541                                 dump_string(field, values);
542                         }
543                         ldap_value_free_len(values);
544                         ldap_memfree(field);
545                 }
546
547                 ber_free(b, 1);
548                 printf("\n");
549         }
550 }
551
552 /*
553   count how many replies are in a LDAPMessage
554 */
555 int ads_count_replies(ADS_STRUCT *ads, void *res)
556 {
557         return ldap_count_entries(ads->ld, (LDAPMessage *)res);
558 }
559
560 /*
561   join a machine to a realm, creating the machine account
562   and setting the machine password
563 */
564 ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org_unit)
565 {
566         ADS_STATUS status;
567         LDAPMessage *res;
568         char *host;
569
570         /* hostname must be lowercase */
571         host = strdup(hostname);
572         strlower(host);
573
574         status = ads_find_machine_acct(ads, (void **)&res, host);
575         if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
576                 DEBUG(0, ("Host account for %s already exists - deleting for readd\n", host));
577                 status = ads_leave_realm(ads, host);
578                 if (!ADS_ERR_OK(status)) {
579                         DEBUG(0, ("Failed to delete host '%s' from the '%s' realm.\n", 
580                                   host, ads->realm));
581                         return status;
582                 }
583         }
584
585         status = ads_add_machine_acct(ads, host, org_unit);
586         if (!ADS_ERR_OK(status)) {
587                 DEBUG(0, ("ads_add_machine_acct: %s\n", ads_errstr(status)));
588                 return status;
589         }
590
591         status = ads_find_machine_acct(ads, (void **)&res, host);
592         if (!ADS_ERR_OK(status)) {
593                 DEBUG(0, ("Host account test failed\n"));
594                 return status;
595         }
596
597         free(host);
598
599         return status;
600 }
601
602 /*
603   delete a machine from the realm
604 */
605 ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
606 {
607         ADS_STATUS status;
608         void *res;
609         char *hostnameDN, *host; 
610         int rc;
611
612         /* hostname must be lowercase */
613         host = strdup(hostname);
614         strlower(host);
615
616         status = ads_find_machine_acct(ads, &res, host);
617         if (!ADS_ERR_OK(status)) {
618             DEBUG(0, ("Host account for %s does not exist.\n", host));
619             return status;
620         }
621
622         hostnameDN = ads_get_dn(ads, (LDAPMessage *)res);
623         rc = ldap_delete_s(ads->ld, hostnameDN);
624         ads_memfree(ads, hostnameDN);
625         if (rc != LDAP_SUCCESS) {
626                 return ADS_ERROR(rc);
627         }
628
629         status = ads_find_machine_acct(ads, &res, host);
630         if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
631                 DEBUG(0, ("Failed to remove host account.\n"));
632                 return status;
633         }
634
635         free(host);
636
637         return status;
638 }
639
640
641 ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
642                                     const char *hostname, 
643                                     const char *password)
644 {
645         ADS_STATUS status;
646         char *host = strdup(hostname);
647         char *principal; 
648
649         strlower(host);
650
651         asprintf(&principal, "%s@%s", host, ads->realm);
652         
653         status = krb5_set_password(ads->kdc_server, principal, password);
654         
655         free(host);
656         free(principal);
657
658         return status;
659 }
660
661 /*
662   pull the first entry from a ADS result
663 */
664 void *ads_first_entry(ADS_STRUCT *ads, void *res)
665 {
666         return (void *)ldap_first_entry(ads->ld, (LDAPMessage *)res);
667 }
668
669 /*
670   pull the next entry from a ADS result
671 */
672 void *ads_next_entry(ADS_STRUCT *ads, void *res)
673 {
674         return (void *)ldap_next_entry(ads->ld, (LDAPMessage *)res);
675 }
676
677 /*
678   pull a single string from a ADS result
679 */
680 char *ads_pull_string(ADS_STRUCT *ads, 
681                       TALLOC_CTX *mem_ctx, void *msg, const char *field)
682 {
683         char **values;
684         char *ret = NULL;
685
686         values = ldap_get_values(ads->ld, msg, field);
687         if (!values) return NULL;
688         
689         if (values[0]) {
690                 ret = talloc_strdup(mem_ctx, values[0]);
691         }
692         ldap_value_free(values);
693         return ret;
694 }
695
696 /*
697   pull a single uint32 from a ADS result
698 */
699 BOOL ads_pull_uint32(ADS_STRUCT *ads, 
700                      void *msg, const char *field, uint32 *v)
701 {
702         char **values;
703
704         values = ldap_get_values(ads->ld, msg, field);
705         if (!values) return False;
706         if (!values[0]) {
707                 ldap_value_free(values);
708                 return False;
709         }
710
711         *v = atoi(values[0]);
712         ldap_value_free(values);
713         return True;
714 }
715
716 /*
717   pull a single DOM_SID from a ADS result
718 */
719 BOOL ads_pull_sid(ADS_STRUCT *ads, 
720                   void *msg, const char *field, DOM_SID *sid)
721 {
722         struct berval **values;
723         BOOL ret = False;
724
725         values = ldap_get_values_len(ads->ld, msg, field);
726
727         if (!values) return False;
728
729         if (values[0]) {
730                 ret = sid_parse(values[0]->bv_val, values[0]->bv_len, sid);
731         }
732         
733         ldap_value_free_len(values);
734         return ret;
735 }
736
737 /*
738   pull an array of DOM_SIDs from a ADS result
739   return the count of SIDs pulled
740 */
741 int ads_pull_sids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
742                   void *msg, const char *field, DOM_SID **sids)
743 {
744         struct berval **values;
745         BOOL ret;
746         int count, i;
747
748         values = ldap_get_values_len(ads->ld, msg, field);
749
750         if (!values) return 0;
751
752         for (i=0; values[i]; i++) /* nop */ ;
753
754         (*sids) = talloc(mem_ctx, sizeof(DOM_SID) * i);
755
756         count = 0;
757         for (i=0; values[i]; i++) {
758                 ret = sid_parse(values[i]->bv_val, values[i]->bv_len, &(*sids)[count]);
759                 if (ret) count++;
760         }
761         
762         ldap_value_free_len(values);
763         return count;
764 }
765
766
767 /* find the update serial number - this is the core of the ldap cache */
768 ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
769 {
770         const char *attrs[] = {"highestCommittedUSN", NULL};
771         ADS_STATUS status;
772         void *res;
773
774         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
775         if (!ADS_ERR_OK(status)) return status;
776
777         if (ads_count_replies(ads, res) != 1) {
778                 return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
779         }
780
781         ads_pull_uint32(ads, res, "highestCommittedUSN", usn);
782         ads_msgfree(ads, res);
783         return ADS_SUCCESS;
784 }
785
786
787 /* find the servers name and realm - this can be done before authentication 
788    The ldapServiceName field on w2k  looks like this:
789      vnet3.home.samba.org:win2000-vnet3$@VNET3.HOME.SAMBA.ORG
790 */
791 ADS_STATUS ads_server_info(ADS_STRUCT *ads)
792 {
793         const char *attrs[] = {"ldapServiceName", NULL};
794         ADS_STATUS status;
795         void *res;
796         char **values;
797         char *p;
798
799         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
800         if (!ADS_ERR_OK(status)) return status;
801
802         values = ldap_get_values(ads->ld, res, "ldapServiceName");
803         if (!values || !values[0]) return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
804
805         p = strchr(values[0], ':');
806         if (!p) {
807                 ldap_value_free(values);
808                 ldap_msgfree(res);
809                 return ADS_ERROR(LDAP_DECODING_ERROR);
810         }
811
812         SAFE_FREE(ads->ldap_server_name);
813
814         ads->ldap_server_name = strdup(p+1);
815         p = strchr(ads->ldap_server_name, '$');
816         if (!p || p[1] != '@') {
817                 ldap_value_free(values);
818                 ldap_msgfree(res);
819                 SAFE_FREE(ads->ldap_server_name);
820                 return ADS_ERROR(LDAP_DECODING_ERROR);
821         }
822
823         *p = 0;
824
825         SAFE_FREE(ads->server_realm);
826         SAFE_FREE(ads->bind_path);
827
828         ads->server_realm = strdup(p+2);
829         ads->bind_path = ads_build_dn(ads->server_realm);
830
831         /* in case the realm isn't configured in smb.conf */
832         if (!ads->realm || !ads->realm[0]) {
833                 SAFE_FREE(ads->realm);
834                 ads->realm = strdup(ads->server_realm);
835         }
836
837         DEBUG(3,("got ldap server name %s@%s\n", 
838                  ads->ldap_server_name, ads->realm));
839
840         return ADS_SUCCESS;
841 }
842
843
844 /* 
845    find the list of trusted domains
846 */
847 ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, 
848                                int *num_trusts, char ***names, DOM_SID **sids)
849 {
850         const char *attrs[] = {"flatName", "securityIdentifier", NULL};
851         ADS_STATUS status;
852         void *res, *msg;
853         int count, i;
854
855         *num_trusts = 0;
856
857         status = ads_search(ads, &res, "(objectcategory=trustedDomain)", attrs);
858         if (!ADS_ERR_OK(status)) return status;
859
860         count = ads_count_replies(ads, res);
861         if (count == 0) {
862                 ads_msgfree(ads, res);
863                 return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
864         }
865
866         (*names) = talloc(mem_ctx, sizeof(char *) * count);
867         (*sids) = talloc(mem_ctx, sizeof(DOM_SID) * count);
868         if (! *names || ! *sids) return ADS_ERROR(LDAP_NO_MEMORY);
869
870         for (i=0, msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
871                 (*names)[i] = ads_pull_string(ads, mem_ctx, msg, "flatName");
872                 if (ads_pull_sid(ads, msg, "securityIdentifier", &(*sids)[i])) {
873                         i++;
874                 }
875         }
876
877         ads_msgfree(ads, res);
878
879         *num_trusts = i;
880
881         return ADS_SUCCESS;
882 }
883
884 /* find the domain sid for our domain */
885 ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)
886 {
887         const char *attrs[] = {"objectSid", NULL};
888         void *res;
889         ADS_STATUS rc;
890
891         rc = ads_do_search(ads, ads->bind_path, LDAP_SCOPE_BASE, "(objectclass=*)", 
892                            attrs, &res);
893         if (!ADS_ERR_OK(rc)) return rc;
894         if (!ads_pull_sid(ads, res, "objectSid", sid)) {
895                 return ADS_ERROR_SYSTEM(ENOENT);
896         }
897         ads_msgfree(ads, res);
898         
899         return ADS_SUCCESS;
900 }
901
902 #endif