added a ads_do_search_all() call, which is a more convenient interface
[samba.git] / source3 / 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 KRB5_DNS_HACK
51         /* this is a really nasty hack to avoid ADS DNS problems. It needs a patch
52            to MIT kerberos to work (tridge) */
53         {
54                 char *env;
55                 asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->server_realm);
56                 setenv(env, inet_ntoa(*interpret_addr2(ads->ldap_server)), 1);
57                 free(env);
58         }
59 #endif
60
61         if (ads->password) {
62                 if ((code = ads_kinit_password(ads)))
63                         return ADS_ERROR_KRB5(code);
64         }
65
66         return ads_sasl_bind(ads);
67 }
68
69
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 */
73
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)
78 {
79         int rc;
80 #define ADS_PAGE_CTL_OID "1.2.840.113556.1.4.319"
81         int version;
82         LDAPControl PagedResults; 
83         BerElement *berelem = NULL;
84         struct berval *berval = NULL;
85         LDAPControl *controls[2];
86         LDAPControl **rcontrols, *cur_control;
87
88         *res = NULL;
89
90         ldap_get_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
91
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);
97
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 */
102                 *cookie = NULL;
103         } else {
104                 ber_printf(berelem, "{io}", (ber_int_t) 1000, "", 0);
105         }
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;
111                         
112         controls[0] = &PagedResults;
113         controls[1] = NULL;
114
115         *res = NULL;
116
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);
122
123         rc = ldap_search_ext_s(ads->ld, bind_path, scope, exp, 
124                                (char **) attrs, 0, controls, NULL,
125                                NULL, LDAP_NO_LIMIT,
126                                (LDAPMessage **)res);
127
128         if (rc) {
129                 DEBUG(3,("ldap_search_ext_s(%s) -> %s\n", exp, ldap_err2string(rc)));
130                 return ADS_ERROR(rc);
131         }
132
133         ber_free(berelem, 1);
134         ber_bvfree(berval);
135
136         rc = ldap_parse_result(ads->ld, *res, NULL, NULL, NULL,
137                                         NULL, &rcontrols,  0);
138
139         if (!rcontrols) {
140                 return ADS_ERROR(rc);
141         }
142
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,
147                                   &berval);
148                         /* the berval is the cookie, but must be freed when
149                            it is all done */
150                         if (berval->bv_len) /* still more to do */
151                                 *cookie=ber_bvdup(berval);
152                         else
153                                 *cookie=NULL;
154                         ber_bvfree(berval);
155                         ber_free(berelem, 1);
156                         break;
157                 }
158         }
159         ldap_controls_free(rcontrols);
160                         
161         return ADS_ERROR(rc);
162 }
163
164
165 /*
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
169  */
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)
173 {
174         void *cookie = NULL;
175         int count = 0;
176         ADS_STATUS status;
177
178         status = ads_do_paged_search(ads, bind_path, scope, exp, attrs, res, &count, &cookie);
179
180         if (!ADS_ERR_OK(status)) return status;
181
182         while (cookie) {
183                 void *res2 = NULL;
184                 ADS_STATUS status2;
185                 LDAPMessage *msg, *next;
186
187                 status2 = ads_do_paged_search(ads, bind_path, scope, exp, attrs, &res2, &count, &cookie);
188
189                 if (!ADS_ERR_OK(status2)) break;
190
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);
196                 }
197
198                 /* note that we do not free res2, as the memory is now
199                    part of the main returned list */
200         }
201
202         return status;
203 }
204
205 /*
206   do a search with a timeout
207 */
208 ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope, 
209                          const char *exp,
210                          const char **attrs, void **res)
211 {
212         struct timeval timeout;
213         int rc;
214
215         timeout.tv_sec = ADS_SEARCH_TIMEOUT;
216         timeout.tv_usec = 0;
217         *res = NULL;
218
219         rc = ldap_search_ext_s(ads->ld, 
220                                bind_path, scope,
221                                exp, (char **) attrs, 0, NULL, NULL, 
222                                &timeout, LDAP_NO_LIMIT, (LDAPMessage **)res);
223
224         if (rc == LDAP_SIZELIMIT_EXCEEDED) {
225                 DEBUG(3,("Warning! sizelimit exceeded in ldap. Truncating.\n"));
226                 rc = 0;
227         }
228
229         return ADS_ERROR(rc);
230 }
231 /*
232   do a general ADS search
233 */
234 ADS_STATUS ads_search(ADS_STRUCT *ads, void **res, 
235                       const char *exp, 
236                       const char **attrs)
237 {
238         return ads_do_search(ads, ads->bind_path, LDAP_SCOPE_SUBTREE, 
239                              exp, attrs, res);
240 }
241
242 /*
243   do a search on a specific DistinguishedName
244 */
245 ADS_STATUS ads_search_dn(ADS_STRUCT *ads, void **res, 
246                          const char *dn, 
247                          const char **attrs)
248 {
249         return ads_do_search(ads, dn, LDAP_SCOPE_BASE, "(objectclass=*)", attrs, res);
250 }
251
252 /*
253   free up memory from a ads_search
254 */
255 void ads_msgfree(ADS_STRUCT *ads, void *msg)
256 {
257         if (!msg) return;
258         ldap_msgfree(msg);
259 }
260
261 /*
262   free up memory from various ads requests
263 */
264 void ads_memfree(ADS_STRUCT *ads, void *mem)
265 {
266         if (!mem) return;
267         ldap_memfree(mem);
268 }
269
270 /*
271   get a dn from search results
272 */
273 char *ads_get_dn(ADS_STRUCT *ads, void *res)
274 {
275         return ldap_get_dn(ads->ld, res);
276 }
277
278 /*
279   find a machine account given a hostname 
280 */
281 ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *host)
282 {
283         ADS_STATUS status;
284         char *exp;
285         const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
286
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);
291         free(exp);
292         return status;
293 }
294
295 /*
296   duplicate an already-assembled list of values so that it can be
297   freed as part of the standard msgfree call
298 */
299 static char **ads_dup_values(TALLOC_CTX *ctx, char **values)
300 {
301         char **newvals;
302         int i;
303 #define ADS_MAX_NUM_VALUES 32
304
305         for (i=0; values[i] && i<ADS_MAX_NUM_VALUES; i++);
306         if (!(newvals = talloc_zero(ctx, (i+1)*sizeof(char *))))
307                 return NULL;
308         for (i=0; values[i] && i<ADS_MAX_NUM_VALUES; i++)
309                 newvals[i] = values[i];
310         newvals[i] = NULL;
311         return newvals;
312 }
313
314 /*
315   initialize a list of mods 
316 */
317
318 ADS_MODLIST ads_init_mods(TALLOC_CTX *ctx)
319 {
320 #define ADS_MODLIST_ALLOC_SIZE 10
321         LDAPMod **mods;
322         
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;
328         
329         return mods;
330 }
331
332 /*
333   add an attribute to the list, with values list already constructed
334 */
335 static ADS_STATUS ads_modlist_add(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
336                                   int mod_op, const char *name, char **values)
337 {
338         int curmod;
339         LDAPMod **modlist = (LDAPMod **) *mods;
340
341         /* find the first empty slot */
342         for (curmod=0; modlist[curmod] && modlist[curmod] != (LDAPMod *) -1;
343              curmod++);
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;
351                 *mods = modlist;
352         }
353                 
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;
359         else
360                 modlist[curmod]->mod_values = values;
361         modlist[curmod]->mod_op = mod_op;
362         return ADS_ERROR(LDAP_SUCCESS);
363 }
364
365 ADS_STATUS ads_mod_add_list(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
366                             char *name, char **values)
367 {
368         char **newvals = ads_dup_values(ctx, values);
369         if (newvals)
370                 return ads_modlist_add(ctx, mods, LDAP_MOD_ADD, name, newvals);
371         else
372                 return ADS_ERROR(LDAP_NO_MEMORY);
373 }
374
375 ADS_STATUS ads_mod_repl_list(TALLOC_CTX *ctx, ADS_MODLIST *mods,
376                              char *name, char **values)
377 {
378         char **newvals;
379         if (values && *values) {
380                 if (!(newvals = ads_dup_values(ctx, values)))
381                         return ADS_ERROR(LDAP_NO_MEMORY);
382                 else
383                         return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE,
384                                                 name, newvals);
385         }
386         else
387                 return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
388 }
389
390 /*
391   add an attribute to the list, with values list to be built from args
392 */
393 ADS_STATUS ads_mod_add_var(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
394                            int mod_op, const char *name, ...)
395 {
396         va_list ap;
397         int num_vals, i, do_op;
398         char *value, **values;
399
400         /* count the number of values */
401         va_start(ap, name);
402         for (num_vals=0; va_arg(ap, char *); num_vals++);
403         va_end(ap);
404
405         if (num_vals) {
406                 if (!(values = talloc_zero(ctx, sizeof(char *)*(num_vals+1))))
407                         return ADS_ERROR(LDAP_NO_MEMORY);
408                 va_start(ap, name);
409                 for (i=0; (value = (char *) va_arg(ap, char *)) &&
410                              i < num_vals; i++)
411                         values[i] = value;
412                 va_end(ap);
413                 values[i] = NULL;
414                 do_op = mod_op;
415         } else {
416                 do_op = LDAP_MOD_DELETE;
417                 values = NULL;
418         }
419         return ads_modlist_add(ctx, mods, do_op, name, values);
420 }
421
422 ADS_STATUS ads_mod_add_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
423                            int mod_op, const char *name, ...)
424 {
425         va_list ap;
426         int num_vals, i, do_op;
427         char *value, **values;
428
429         /* count the number of values */
430         va_start(ap, name);
431         for (num_vals=0; va_arg(ap, struct berval *); num_vals++);
432         va_end(ap);
433
434         if (num_vals) {
435                 if (!(values = talloc_zero(ctx, sizeof(struct berval) * 
436                                            (num_vals + 1))))
437                         return ADS_ERROR(LDAP_NO_MEMORY);
438                 va_start(ap, name);
439                 for (i=0; (value = (char *) va_arg(ap, char *)) &&
440                              i < num_vals; i++)
441                         values[i] = value;
442                 va_end(ap);
443                 values[i] = NULL;
444                 do_op = mod_op;
445         } else {
446                 do_op = LDAP_MOD_DELETE;
447                 values = NULL;
448         }
449         do_op |= LDAP_MOD_BVALUES;
450         return ads_modlist_add(ctx, mods, do_op, name, values);
451 }
452
453 ADS_STATUS ads_mod_repl(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
454                         char *name, char *val)
455 {
456         if (val)
457                 return ads_mod_add_var(ctx, mods, LDAP_MOD_REPLACE,
458                                        name, val, NULL);
459         else
460                 return ads_mod_add_var(ctx, mods, LDAP_MOD_DELETE, name, NULL);
461 }
462
463 ADS_STATUS ads_mod_add(TALLOC_CTX *ctx, ADS_MODLIST *mods, 
464                        const char *name, const char *val)
465 {
466         return ads_mod_add_var(ctx, mods, LDAP_MOD_ADD, name, val, NULL);
467 }
468
469 ADS_STATUS ads_mod_add_len(TALLOC_CTX *ctx, ADS_MODLIST *mods,
470                            char *name, size_t size, char *val)
471 {
472         struct berval *bval = NULL;
473
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);
478
479         bval->bv_val = val;
480         bval->bv_len = size;
481         return ads_mod_add_ber(ctx, mods, LDAP_MOD_ADD, name, bval, NULL);
482 }
483
484 ADS_STATUS ads_mod_repl_len(TALLOC_CTX *ctx, ADS_MODLIST *mods,
485                             const char *name, size_t size, char *val)
486 {
487         struct berval *bval = NULL;
488
489         if (!(bval = talloc_zero(ctx, sizeof(struct berval *))))
490                 return ADS_ERROR(LDAP_NO_MEMORY);
491
492         if (!val)
493                 return ads_mod_add_ber(ctx, mods, LDAP_MOD_DELETE, name, NULL);
494         else {
495                 if (!(bval->bv_val = talloc_zero(ctx, sizeof(char *))))
496                         return ADS_ERROR(LDAP_NO_MEMORY);
497                 bval->bv_val = val;
498                 bval->bv_len = size;
499                 return ads_mod_add_ber(ctx, mods, LDAP_MOD_REPLACE, name, 
500                                        bval, NULL);
501         }
502 }
503
504 ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods)
505 {
506         int ret,i;
507         /* 
508            this control is needed to modify that contains a currently 
509            non-existent attribute (but allowable for the object) to run
510         */
511         LDAPControl PermitModify = {
512                 "1.2.840.113556.1.4.1413",
513                 {0, NULL},
514                 (char) 1};
515         LDAPControl *controls[2];
516
517         controls[0] = &PermitModify;
518         controls[1] = NULL;
519
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 */
523         mods[i] = NULL;
524         ret = ldap_modify_ext_s(ads->ld, mod_dn, (LDAPMod **) mods,
525                                 controls, NULL);
526         return ADS_ERROR(ret);
527 }
528
529 ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods)
530 {
531         int i;
532
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 */
536         mods[i] = NULL;
537
538         return ADS_ERROR(ldap_add_s(ads->ld, new_dn, mods));
539 }
540
541 ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn)
542 {
543         return ADS_ERROR(ldap_delete(ads->ld, del_dn));
544 }
545
546 /*
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
550   caller must free
551 */
552 char *ads_ou_string(const char *org_unit)
553 {       
554         if (!org_unit || !*org_unit || strcasecmp(org_unit, "Computers") == 0) {
555                 return strdup("cn=Computers");
556         }
557
558         return ads_build_path(org_unit, "\\/", "ou=", 1);
559 }
560
561
562
563 /*
564   add a machine account to the ADS server
565 */
566 static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *hostname, 
567                                        const char *org_unit)
568 {
569         ADS_STATUS ret;
570         char *host_spn, *host_upn, *new_dn, *samAccountName, *controlstr;
571         char *ou_str;
572         TALLOC_CTX *ctx;
573         ADS_MODLIST mods;
574
575         if (!(ctx = talloc_init_named("machine_account")))
576                 return ADS_ERROR(LDAP_NO_MEMORY);
577
578         ret = ADS_ERROR(LDAP_NO_MEMORY);
579
580         if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", hostname)))
581                 goto done;
582         if (!(host_upn = talloc_asprintf(ctx, "%s@%s", host_spn, ads->realm)))
583                 goto done;
584         ou_str = ads_ou_string(org_unit);
585         new_dn = talloc_asprintf(ctx, "cn=%s,%s,%s", hostname, ou_str, 
586                                  ads->bind_path);
587         free(ou_str);
588         if (!new_dn)
589                 goto done;
590
591         if (!(samAccountName = talloc_asprintf(ctx, "%s$", hostname)))
592                 goto done;
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)))
596                 goto done;
597
598         if (!(mods = ads_init_mods(ctx)))
599                 goto done;
600         
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);
612
613         ads_gen_add(ads, new_dn, mods);
614         ret = ads_set_machine_sd(ads, hostname, new_dn);
615
616 done:
617         talloc_destroy(ctx);
618         return ret;
619 }
620
621 /*
622   dump a binary result from ldap
623 */
624 static void dump_binary(const char *field, struct berval **values)
625 {
626         int i, j;
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]);
631                 }
632                 printf("\n");
633         }
634 }
635
636 /*
637   dump a sid result from ldap
638 */
639 static void dump_sid(const char *field, struct berval **values)
640 {
641         int i;
642         for (i=0; values[i]; i++) {
643                 DOM_SID sid;
644                 sid_parse(values[i]->bv_val, values[i]->bv_len, &sid);
645                 printf("%s: %s\n", field, sid_string_static(&sid));
646         }
647 }
648
649 /*
650   dump ntSecurityDescriptor
651 */
652 static void dump_sd(const char *filed, struct berval **values)
653 {
654         prs_struct ps;
655         
656         SEC_DESC   *psd = 0;
657         TALLOC_CTX *ctx = 0;
658
659         if (!(ctx = talloc_init_named("sec_io_desc")))
660                 return;
661
662         /* prepare data */
663         prs_init(&ps, values[0]->bv_len, ctx, UNMARSHALL);
664         prs_append_data(&ps, values[0]->bv_val, values[0]->bv_len);
665         ps.data_offset = 0;
666
667         /* parse secdesc */
668         if (!sec_io_desc("sd", &psd, &ps, 1)) {
669                 prs_mem_free(&ps);
670                 talloc_destroy(ctx);
671                 return;
672         }
673         if (psd) ads_disp_sd(psd);
674
675         prs_mem_free(&ps);
676         talloc_destroy(ctx);
677 }
678
679 /*
680   dump a string result from ldap
681 */
682 static void dump_string(const char *field, struct berval **values)
683 {
684         int i;
685         for (i=0; values[i]; i++) {
686                 printf("%s: %s\n", field, values[i]->bv_val);
687         }
688 }
689
690 /*
691   dump a record from LDAP on stdout
692   used for debugging
693 */
694 void ads_dump(ADS_STRUCT *ads, void *res)
695 {
696         char *field;
697         void *msg;
698         BerElement *b;
699         struct {
700                 char *name;
701                 void (*handler)(const char *, struct berval **);
702         } handlers[] = {
703                 {"objectGUID", dump_binary},
704                 {"nTSecurityDescriptor", dump_sd},
705                 {"objectSid", dump_sid},
706                 {NULL, NULL}
707         };
708     
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); 
711                      field;
712                      field = ldap_next_attribute(ads->ld, (LDAPMessage *)msg, b)) {
713                         struct berval **values;
714                         int i;
715
716                         values = ldap_get_values_len(ads->ld, (LDAPMessage *)msg, field);
717
718                         for (i=0; handlers[i].name; i++) {
719                                 if (StrCaseCmp(handlers[i].name, field) == 0) {
720                                         handlers[i].handler(field, values);
721                                         break;
722                                 }
723                         }
724                         if (!handlers[i].name) {
725                                 dump_string(field, values);
726                         }
727                         ldap_value_free_len(values);
728                         ldap_memfree(field);
729                 }
730
731                 ber_free(b, 1);
732                 printf("\n");
733         }
734 }
735
736 /*
737   count how many replies are in a LDAPMessage
738 */
739 int ads_count_replies(ADS_STRUCT *ads, void *res)
740 {
741         return ldap_count_entries(ads->ld, (LDAPMessage *)res);
742 }
743
744 /*
745   join a machine to a realm, creating the machine account
746   and setting the machine password
747 */
748 ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *hostname, const char *org_unit)
749 {
750         ADS_STATUS status;
751         LDAPMessage *res;
752         char *host;
753
754         /* hostname must be lowercase */
755         host = strdup(hostname);
756         strlower(host);
757
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", 
764                                   host, ads->realm));
765                         return status;
766                 }
767         }
768
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)));
772                 return status;
773         }
774
775         status = ads_find_machine_acct(ads, (void **)&res, host);
776         if (!ADS_ERR_OK(status)) {
777                 DEBUG(0, ("Host account test failed\n"));
778                 return status;
779         }
780
781         free(host);
782
783         return status;
784 }
785
786 /*
787   delete a machine from the realm
788 */
789 ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
790 {
791         ADS_STATUS status;
792         void *res;
793         char *hostnameDN, *host; 
794         int rc;
795
796         /* hostname must be lowercase */
797         host = strdup(hostname);
798         strlower(host);
799
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));
803             return status;
804         }
805
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);
811         }
812
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"));
816                 return status;
817         }
818
819         free(host);
820
821         return status;
822 }
823
824 /* 
825   add machine account to existing security descriptor 
826 */
827 ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
828 {
829         const char     *attrs[] = {"ntSecurityDescriptor", "objectSid", 0};
830         char           *exp     = 0;
831         size_t          sd_size = 0;
832         struct berval **bvals   = 0;
833         prs_struct      ps;
834         prs_struct      ps_wire;
835
836         LDAPMessage *res  = 0;
837         LDAPMessage *msg  = 0;
838         ADS_MODLIST  mods = 0;
839
840         NTSTATUS    status;
841         ADS_STATUS  ret;
842         DOM_SID     sid;
843         SEC_DESC   *psd = 0;
844         TALLOC_CTX *ctx = 0;    
845
846         if (!ads) return ADS_ERROR(LDAP_SERVER_DOWN);
847
848         ret = ADS_ERROR(LDAP_SUCCESS);
849
850         asprintf(&exp, "(samAccountName=%s$)", hostname);
851         ret = ads_search(ads, (void *) &res, exp, attrs);
852
853         if (!ADS_ERR_OK(ret)) return ret;
854
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);
859 #if 0
860         file_save("/tmp/sec_desc.old", bvals[0]->bv_val, bvals[0]->bv_len);
861 #endif
862         if (!(ctx = talloc_init_named("sec_io_desc")))
863                 return ADS_ERROR(LDAP_NO_MEMORY);
864
865         prs_init(&ps, bvals[0]->bv_len, ctx, UNMARSHALL);
866         prs_append_data(&ps, bvals[0]->bv_val, bvals[0]->bv_len);
867         ps.data_offset = 0;
868         ldap_value_free_len(bvals);
869
870         if (!sec_io_desc("sd", &psd, &ps, 1))
871                 goto ads_set_sd_error;
872
873         status = sec_desc_add_sid(ctx, &psd, &sid, SEC_RIGHTS_FULL_CTRL, &sd_size);
874
875         if (!NT_STATUS_IS_OK(status))
876                 goto ads_set_sd_error;
877
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;
881
882 #if 0
883         file_save("/tmp/sec_desc.new", ps_wire.data_p, sd_size);
884 #endif
885         if (!(mods = ads_init_mods(ctx))) return ADS_ERROR(LDAP_NO_MEMORY);
886
887         ads_mod_repl_len(ctx, &mods, attrs[0], sd_size, ps_wire.data_p);
888         ret = ads_gen_mod(ads, dn, mods);
889
890         prs_mem_free(&ps);
891         prs_mem_free(&ps_wire);
892         talloc_destroy(ctx);
893         return ret;
894
895 ads_set_sd_error:
896         prs_mem_free(&ps);
897         prs_mem_free(&ps_wire);
898         talloc_destroy(ctx);
899         return ADS_ERROR(LDAP_NO_MEMORY);
900 }
901
902 ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
903                                     const char *hostname, 
904                                     const char *password)
905 {
906         ADS_STATUS status;
907         char *host = strdup(hostname);
908         char *principal; 
909
910         if (!ads->kdc_server) {
911                 DEBUG(0, ("Unable to find KDC server\n"));
912                 return ADS_ERROR(LDAP_SERVER_DOWN);
913         }
914
915         strlower(host);
916
917         asprintf(&principal, "%s@%s", host, ads->realm);
918         
919         status = krb5_set_password(ads->kdc_server, principal, password);
920         
921         free(host);
922         free(principal);
923
924         return status;
925 }
926
927 /*
928   pull the first entry from a ADS result
929 */
930 void *ads_first_entry(ADS_STRUCT *ads, void *res)
931 {
932         return (void *)ldap_first_entry(ads->ld, (LDAPMessage *)res);
933 }
934
935 /*
936   pull the next entry from a ADS result
937 */
938 void *ads_next_entry(ADS_STRUCT *ads, void *res)
939 {
940         return (void *)ldap_next_entry(ads->ld, (LDAPMessage *)res);
941 }
942
943 /*
944   pull a single string from a ADS result
945 */
946 char *ads_pull_string(ADS_STRUCT *ads, 
947                       TALLOC_CTX *mem_ctx, void *msg, const char *field)
948 {
949         char **values;
950         char *ret = NULL;
951
952         values = ldap_get_values(ads->ld, msg, field);
953         if (!values) return NULL;
954         
955         if (values[0]) {
956                 ret = talloc_strdup(mem_ctx, values[0]);
957         }
958         ldap_value_free(values);
959         return ret;
960 }
961
962 /*
963   pull a single uint32 from a ADS result
964 */
965 BOOL ads_pull_uint32(ADS_STRUCT *ads, 
966                      void *msg, const char *field, uint32 *v)
967 {
968         char **values;
969
970         values = ldap_get_values(ads->ld, msg, field);
971         if (!values) return False;
972         if (!values[0]) {
973                 ldap_value_free(values);
974                 return False;
975         }
976
977         *v = atoi(values[0]);
978         ldap_value_free(values);
979         return True;
980 }
981
982 /*
983   pull a single DOM_SID from a ADS result
984 */
985 BOOL ads_pull_sid(ADS_STRUCT *ads, 
986                   void *msg, const char *field, DOM_SID *sid)
987 {
988         struct berval **values;
989         BOOL ret = False;
990
991         values = ldap_get_values_len(ads->ld, msg, field);
992
993         if (!values) return False;
994
995         if (values[0]) {
996                 ret = sid_parse(values[0]->bv_val, values[0]->bv_len, sid);
997         }
998         
999         ldap_value_free_len(values);
1000         return ret;
1001 }
1002
1003 /*
1004   pull an array of DOM_SIDs from a ADS result
1005   return the count of SIDs pulled
1006 */
1007 int ads_pull_sids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
1008                   void *msg, const char *field, DOM_SID **sids)
1009 {
1010         struct berval **values;
1011         BOOL ret;
1012         int count, i;
1013
1014         values = ldap_get_values_len(ads->ld, msg, field);
1015
1016         if (!values) return 0;
1017
1018         for (i=0; values[i]; i++) /* nop */ ;
1019
1020         (*sids) = talloc(mem_ctx, sizeof(DOM_SID) * i);
1021
1022         count = 0;
1023         for (i=0; values[i]; i++) {
1024                 ret = sid_parse(values[i]->bv_val, values[i]->bv_len, &(*sids)[count]);
1025                 if (ret) count++;
1026         }
1027         
1028         ldap_value_free_len(values);
1029         return count;
1030 }
1031
1032
1033 /* find the update serial number - this is the core of the ldap cache */
1034 ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
1035 {
1036         const char *attrs[] = {"highestCommittedUSN", NULL};
1037         ADS_STATUS status;
1038         void *res;
1039
1040         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1041         if (!ADS_ERR_OK(status)) return status;
1042
1043         if (ads_count_replies(ads, res) != 1) {
1044                 return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
1045         }
1046
1047         ads_pull_uint32(ads, res, "highestCommittedUSN", usn);
1048         ads_msgfree(ads, res);
1049         return ADS_SUCCESS;
1050 }
1051
1052
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
1056 */
1057 ADS_STATUS ads_server_info(ADS_STRUCT *ads)
1058 {
1059         const char *attrs[] = {"ldapServiceName", NULL};
1060         ADS_STATUS status;
1061         void *res;
1062         char **values;
1063         char *p;
1064
1065         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1066         if (!ADS_ERR_OK(status)) return status;
1067
1068         values = ldap_get_values(ads->ld, res, "ldapServiceName");
1069         if (!values || !values[0]) return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
1070
1071         p = strchr(values[0], ':');
1072         if (!p) {
1073                 ldap_value_free(values);
1074                 ldap_msgfree(res);
1075                 return ADS_ERROR(LDAP_DECODING_ERROR);
1076         }
1077
1078         SAFE_FREE(ads->ldap_server_name);
1079
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);
1084                 ldap_msgfree(res);
1085                 SAFE_FREE(ads->ldap_server_name);
1086                 return ADS_ERROR(LDAP_DECODING_ERROR);
1087         }
1088
1089         *p = 0;
1090
1091         SAFE_FREE(ads->server_realm);
1092         SAFE_FREE(ads->bind_path);
1093
1094         ads->server_realm = strdup(p+2);
1095         ads->bind_path = ads_build_dn(ads->server_realm);
1096
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);
1101         }
1102
1103         DEBUG(3,("got ldap server name %s@%s\n", 
1104                  ads->ldap_server_name, ads->realm));
1105
1106         return ADS_SUCCESS;
1107 }
1108
1109
1110 /* 
1111    find the list of trusted domains
1112 */
1113 ADS_STATUS ads_trusted_domains(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, 
1114                                int *num_trusts, char ***names, DOM_SID **sids)
1115 {
1116         const char *attrs[] = {"flatName", "securityIdentifier", NULL};
1117         ADS_STATUS status;
1118         void *res, *msg;
1119         int count, i;
1120
1121         *num_trusts = 0;
1122
1123         status = ads_search(ads, &res, "(objectcategory=trustedDomain)", attrs);
1124         if (!ADS_ERR_OK(status)) return status;
1125
1126         count = ads_count_replies(ads, res);
1127         if (count == 0) {
1128                 ads_msgfree(ads, res);
1129                 return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
1130         }
1131
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);
1135
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])) {
1139                         i++;
1140                 }
1141         }
1142
1143         ads_msgfree(ads, res);
1144
1145         *num_trusts = i;
1146
1147         return ADS_SUCCESS;
1148 }
1149
1150 /* find the domain sid for our domain */
1151 ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)
1152 {
1153         const char *attrs[] = {"objectSid", NULL};
1154         void *res;
1155         ADS_STATUS rc;
1156
1157         rc = ads_do_search(ads, ads->bind_path, LDAP_SCOPE_BASE, "(objectclass=*)", 
1158                            attrs, &res);
1159         if (!ADS_ERR_OK(rc)) return rc;
1160         if (!ads_pull_sid(ads, res, "objectSid", sid)) {
1161                 return ADS_ERROR_SYSTEM(ENOENT);
1162         }
1163         ads_msgfree(ads, res);
1164         
1165         return ADS_SUCCESS;
1166 }
1167
1168 #endif