f24c3e982edb71f77d23dd2110e2a8a9aaf62e53
[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 <jmcd@us.ibm.com> 2002
7    Copyright (C) Guenther Deschner 2005
8    Copyright (C) Gerald Carter 2006
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "ads.h"
26 #include "libads/sitename_cache.h"
27 #include "libads/cldap.h"
28 #include "../lib/tsocket/tsocket.h"
29 #include "../lib/addns/dnsquery.h"
30 #include "../libds/common/flags.h"
31 #include "smbldap.h"
32 #include "../libcli/security/security.h"
33 #include "../librpc/gen_ndr/netlogon.h"
34 #include "lib/param/loadparm.h"
35 #include "libsmb/namequery.h"
36 #include "../librpc/gen_ndr/ndr_ads.h"
37
38 #ifdef HAVE_LDAP
39
40 /**
41  * @file ldap.c
42  * @brief basic ldap client-side routines for ads server communications
43  *
44  * The routines contained here should do the necessary ldap calls for
45  * ads setups.
46  *
47  * Important note: attribute names passed into ads_ routines must
48  * already be in UTF-8 format.  We do not convert them because in almost
49  * all cases, they are just ascii (which is represented with the same
50  * codepoints in UTF-8).  This may have to change at some point
51  **/
52
53
54 #define LDAP_SERVER_TREE_DELETE_OID     "1.2.840.113556.1.4.805"
55
56 static SIG_ATOMIC_T gotalarm;
57
58 /***************************************************************
59  Signal function to tell us we timed out.
60 ****************************************************************/
61
62 static void gotalarm_sig(int signum)
63 {
64         gotalarm = 1;
65 }
66
67  LDAP *ldap_open_with_timeout(const char *server,
68                               struct sockaddr_storage *ss,
69                               int port, unsigned int to)
70 {
71         LDAP *ldp = NULL;
72         int ldap_err;
73         char *uri;
74
75         DEBUG(10, ("Opening connection to LDAP server '%s:%d', timeout "
76                    "%u seconds\n", server, port, to));
77
78         if (to) {
79                 /* Setup timeout */
80                 gotalarm = 0;
81                 CatchSignal(SIGALRM, gotalarm_sig);
82                 alarm(to);
83                 /* End setup timeout. */
84         }
85
86         if ( strchr_m(server, ':') ) {
87                 /* IPv6 URI */
88                 uri = talloc_asprintf(talloc_tos(), "ldap://[%s]:%u", server, port);
89         } else {
90                 /* IPv4 URI */
91                 uri = talloc_asprintf(talloc_tos(), "ldap://%s:%u", server, port);
92         }
93         if (uri == NULL) {
94                 return NULL;
95         }
96
97 #ifdef HAVE_LDAP_INIT_FD
98         {
99                 int fd = -1;
100                 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
101                 unsigned timeout_ms = 1000 * to;
102
103                 status = open_socket_out(ss, port, timeout_ms, &fd);
104                 if (!NT_STATUS_IS_OK(status)) {
105                         DEBUG(3, ("open_socket_out: failed to open socket\n"));
106                         return NULL;
107                 }
108
109 /* define LDAP_PROTO_TCP from openldap.h if required */
110 #ifndef LDAP_PROTO_TCP
111 #define LDAP_PROTO_TCP 1
112 #endif
113                 ldap_err = ldap_init_fd(fd, LDAP_PROTO_TCP, uri, &ldp);
114         }
115 #elif defined(HAVE_LDAP_INITIALIZE)
116         ldap_err = ldap_initialize(&ldp, uri);
117 #else
118         ldp = ldap_open(server, port);
119         if (ldp != NULL) {
120                 ldap_err = LDAP_SUCCESS;
121         } else {
122                 ldap_err = LDAP_OTHER;
123         }
124 #endif
125         if (ldap_err != LDAP_SUCCESS) {
126                 DEBUG(2,("Could not initialize connection for LDAP server '%s': %s\n",
127                          uri, ldap_err2string(ldap_err)));
128         } else {
129                 DEBUG(10, ("Initialized connection for LDAP server '%s'\n", uri));
130         }
131
132         if (to) {
133                 /* Teardown timeout. */
134                 alarm(0);
135                 CatchSignal(SIGALRM, SIG_IGN);
136         }
137
138         return ldp;
139 }
140
141 static int ldap_search_with_timeout(LDAP *ld,
142                                     LDAP_CONST char *base,
143                                     int scope,
144                                     LDAP_CONST char *filter,
145                                     char **attrs,
146                                     int attrsonly,
147                                     LDAPControl **sctrls,
148                                     LDAPControl **cctrls,
149                                     int sizelimit,
150                                     LDAPMessage **res )
151 {
152         int to = lp_ldap_timeout();
153         struct timeval timeout;
154         struct timeval *timeout_ptr = NULL;
155         int result;
156
157         /* Setup timeout for the ldap_search_ext_s call - local and remote. */
158         gotalarm = 0;
159
160         if (to) {
161                 timeout.tv_sec = to;
162                 timeout.tv_usec = 0;
163                 timeout_ptr = &timeout;
164
165                 /* Setup alarm timeout. */
166                 CatchSignal(SIGALRM, gotalarm_sig);
167                 /* Make the alarm time one second beyond
168                    the timeout we're setting for the
169                    remote search timeout, to allow that
170                    to fire in preference. */
171                 alarm(to+1);
172                 /* End setup timeout. */
173         }
174
175
176         result = ldap_search_ext_s(ld, base, scope, filter, attrs,
177                                    attrsonly, sctrls, cctrls, timeout_ptr,
178                                    sizelimit, res);
179
180         if (to) {
181                 /* Teardown alarm timeout. */
182                 CatchSignal(SIGALRM, SIG_IGN);
183                 alarm(0);
184         }
185
186         if (gotalarm != 0)
187                 return LDAP_TIMELIMIT_EXCEEDED;
188
189         /*
190          * A bug in OpenLDAP means ldap_search_ext_s can return
191          * LDAP_SUCCESS but with a NULL res pointer. Cope with
192          * this. See bug #6279 for details. JRA.
193          */
194
195         if (*res == NULL) {
196                 return LDAP_TIMELIMIT_EXCEEDED;
197         }
198
199         return result;
200 }
201
202 /**********************************************
203  Do client and server sitename match ?
204 **********************************************/
205
206 bool ads_sitename_match(ADS_STRUCT *ads)
207 {
208         if (ads->config.server_site_name == NULL &&
209             ads->config.client_site_name == NULL ) {
210                 DEBUG(10,("ads_sitename_match: both null\n"));
211                 return True;
212         }
213         if (ads->config.server_site_name &&
214             ads->config.client_site_name &&
215             strequal(ads->config.server_site_name,
216                      ads->config.client_site_name)) {
217                 DEBUG(10,("ads_sitename_match: name %s match\n", ads->config.server_site_name));
218                 return True;
219         }
220         DEBUG(10,("ads_sitename_match: no match between server: %s and client: %s\n",
221                 ads->config.server_site_name ? ads->config.server_site_name : "NULL",
222                 ads->config.client_site_name ? ads->config.client_site_name : "NULL"));
223         return False;
224 }
225
226 /**********************************************
227  Is this the closest DC ?
228 **********************************************/
229
230 bool ads_closest_dc(ADS_STRUCT *ads)
231 {
232         if (ads->config.flags & NBT_SERVER_CLOSEST) {
233                 DEBUG(10,("ads_closest_dc: NBT_SERVER_CLOSEST flag set\n"));
234                 return True;
235         }
236
237         /* not sure if this can ever happen */
238         if (ads_sitename_match(ads)) {
239                 DEBUG(10,("ads_closest_dc: NBT_SERVER_CLOSEST flag not set but sites match\n"));
240                 return True;
241         }
242
243         if (ads->config.client_site_name == NULL) {
244                 DEBUG(10,("ads_closest_dc: client belongs to no site\n"));
245                 return True;
246         }
247
248         DEBUG(10,("ads_closest_dc: %s is not the closest DC\n",
249                 ads->config.ldap_server_name));
250
251         return False;
252 }
253
254 static bool ads_fill_cldap_reply(ADS_STRUCT *ads,
255                                  bool gc,
256                                  const struct sockaddr_storage *ss,
257                                  const struct NETLOGON_SAM_LOGON_RESPONSE_EX *cldap_reply)
258 {
259         TALLOC_CTX *frame = talloc_stackframe();
260         bool ret = false;
261         char addr[INET6_ADDRSTRLEN];
262         ADS_STATUS status;
263         char *dn;
264
265         print_sockaddr(addr, sizeof(addr), ss);
266
267         /* Check the CLDAP reply flags */
268
269         if (!(cldap_reply->server_type & NBT_SERVER_LDAP)) {
270                 DBG_WARNING("%s's CLDAP reply says it is not an LDAP server!\n",
271                             addr);
272                 ret = false;
273                 goto out;
274         }
275
276         /* Fill in the ads->config values */
277
278         ADS_TALLOC_CONST_FREE(ads->config.realm);
279         ADS_TALLOC_CONST_FREE(ads->config.bind_path);
280         ADS_TALLOC_CONST_FREE(ads->config.ldap_server_name);
281         ADS_TALLOC_CONST_FREE(ads->config.server_site_name);
282         ADS_TALLOC_CONST_FREE(ads->config.client_site_name);
283         ADS_TALLOC_CONST_FREE(ads->server.workgroup);
284
285         if (!check_cldap_reply_required_flags(cldap_reply->server_type,
286                                               ads->config.flags)) {
287                 ret = false;
288                 goto out;
289         }
290
291         ads->config.ldap_server_name = talloc_strdup(ads,
292                                                      cldap_reply->pdc_dns_name);
293         if (ads->config.ldap_server_name == NULL) {
294                 DBG_WARNING("Out of memory\n");
295                 ret = false;
296                 goto out;
297         }
298
299         ads->config.realm = talloc_asprintf_strupper_m(ads,
300                                                        "%s",
301                                                        cldap_reply->dns_domain);
302         if (ads->config.realm == NULL) {
303                 DBG_WARNING("Out of memory\n");
304                 ret = false;
305                 goto out;
306         }
307
308         status = ads_build_dn(ads->config.realm, ads, &dn);
309         if (!ADS_ERR_OK(status)) {
310                 DBG_DEBUG("Failed to build bind path: %s\n",
311                           ads_errstr(status));
312                 ret = false;
313                 goto out;
314         }
315         ads->config.bind_path = dn;
316
317         if (*cldap_reply->server_site) {
318                 ads->config.server_site_name =
319                         talloc_strdup(ads, cldap_reply->server_site);
320                 if (ads->config.server_site_name == NULL) {
321                         DBG_WARNING("Out of memory\n");
322                         ret = false;
323                         goto out;
324                 }
325         }
326
327         if (*cldap_reply->client_site) {
328                 ads->config.client_site_name =
329                         talloc_strdup(ads, cldap_reply->client_site);
330                 if (ads->config.client_site_name == NULL) {
331                         DBG_WARNING("Out of memory\n");
332                         ret = false;
333                         goto out;
334                 }
335         }
336
337         ads->server.workgroup = talloc_strdup(ads, cldap_reply->domain_name);
338         if (ads->server.workgroup == NULL) {
339                 DBG_WARNING("Out of memory\n");
340                 ret = false;
341                 goto out;
342         }
343
344         ads->ldap.port = gc ? LDAP_GC_PORT : LDAP_PORT;
345         ads->ldap.ss = *ss;
346
347         /* Store our site name. */
348         sitename_store(cldap_reply->domain_name, cldap_reply->client_site);
349         sitename_store(cldap_reply->dns_domain, cldap_reply->client_site);
350
351         /* Leave this until last so that the flags are not clobbered */
352         ads->config.flags = cldap_reply->server_type;
353
354         ret = true;
355
356  out:
357
358         TALLOC_FREE(frame);
359         return ret;
360 }
361
362 /*
363   try a connection to a given ldap server, returning True and setting the servers IP
364   in the ads struct if successful
365  */
366 static bool ads_try_connect(ADS_STRUCT *ads, bool gc,
367                             struct sockaddr_storage *ss)
368 {
369         struct NETLOGON_SAM_LOGON_RESPONSE_EX cldap_reply = {};
370         TALLOC_CTX *frame = talloc_stackframe();
371         bool ok;
372         char addr[INET6_ADDRSTRLEN] = { 0, };
373
374         if (ss == NULL) {
375                 TALLOC_FREE(frame);
376                 return false;
377         }
378
379         print_sockaddr(addr, sizeof(addr), ss);
380
381         DBG_INFO("ads_try_connect: sending CLDAP request to %s (realm: %s)\n",
382                  addr, ads->server.realm);
383
384         ok = ads_cldap_netlogon_5(frame, ss, ads->server.realm, &cldap_reply);
385         if (!ok) {
386                 DBG_NOTICE("ads_cldap_netlogon_5(%s, %s) failed.\n",
387                            addr, ads->server.realm);
388                 TALLOC_FREE(frame);
389                 return false;
390         }
391
392         ok = ads_fill_cldap_reply(ads, gc, ss, &cldap_reply);
393         if (!ok) {
394                 DBG_NOTICE("ads_fill_cldap_reply(%s, %s) failed.\n",
395                            addr, ads->server.realm);
396                 TALLOC_FREE(frame);
397                 return false;
398         }
399
400         TALLOC_FREE(frame);
401         return true;
402 }
403
404 /**********************************************************************
405  send a cldap ping to list of servers, one at a time, until one of
406  them answers it's an ldap server. Record success in the ADS_STRUCT.
407  Take note of and update negative connection cache.
408 **********************************************************************/
409
410 static NTSTATUS cldap_ping_list(ADS_STRUCT *ads,
411                         const char *domain,
412                         struct samba_sockaddr *sa_list,
413                         size_t count)
414 {
415         TALLOC_CTX *frame = talloc_stackframe();
416         struct timeval endtime = timeval_current_ofs(MAX(3,lp_ldap_timeout()/2), 0);
417         uint32_t nt_version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
418         struct tsocket_address **ts_list = NULL;
419         const struct tsocket_address * const *ts_list_const = NULL;
420         struct samba_sockaddr **req_sa_list = NULL;
421         struct netlogon_samlogon_response **responses = NULL;
422         size_t num_requests = 0;
423         NTSTATUS status;
424         size_t i;
425         bool ok = false;
426         bool retry;
427
428         ts_list = talloc_zero_array(frame,
429                                     struct tsocket_address *,
430                                     count);
431         if (ts_list == NULL) {
432                 TALLOC_FREE(frame);
433                 return NT_STATUS_NO_MEMORY;
434         }
435
436         req_sa_list = talloc_zero_array(frame,
437                                         struct samba_sockaddr *,
438                                         count);
439         if (req_sa_list == NULL) {
440                 TALLOC_FREE(frame);
441                 return NT_STATUS_NO_MEMORY;
442         }
443
444 again:
445         /*
446          * The retry loop is bound by the timeout
447          */
448         retry = false;
449         num_requests = 0;
450
451         for (i = 0; i < count; i++) {
452                 char server[INET6_ADDRSTRLEN];
453                 int ret;
454
455                 if (is_zero_addr(&sa_list[i].u.ss)) {
456                         continue;
457                 }
458
459                 print_sockaddr(server, sizeof(server), &sa_list[i].u.ss);
460
461                 status = check_negative_conn_cache(domain, server);
462                 if (!NT_STATUS_IS_OK(status)) {
463                         continue;
464                 }
465
466                 ret = tsocket_address_inet_from_strings(ts_list, "ip",
467                                                         server, LDAP_PORT,
468                                                         &ts_list[num_requests]);
469                 if (ret != 0) {
470                         status = map_nt_error_from_unix(errno);
471                         DBG_WARNING("Failed to create tsocket_address for %s - %s\n",
472                                     server, nt_errstr(status));
473                         TALLOC_FREE(frame);
474                         return status;
475                 }
476
477                 req_sa_list[num_requests] = &sa_list[i];
478                 num_requests += 1;
479         }
480
481         if (num_requests == 0) {
482                 status = NT_STATUS_NO_LOGON_SERVERS;
483                 DBG_WARNING("domain[%s] num_requests[%zu] for count[%zu] - %s\n",
484                             domain, num_requests, count, nt_errstr(status));
485                 TALLOC_FREE(frame);
486                 return status;
487         }
488
489         ts_list_const = (const struct tsocket_address * const *)ts_list;
490
491         status = cldap_multi_netlogon(frame,
492                                       ts_list_const, num_requests,
493                                       ads->server.realm, NULL,
494                                       nt_version,
495                                       1, endtime, &responses);
496         if (!NT_STATUS_IS_OK(status)) {
497                 DBG_WARNING("cldap_multi_netlogon(realm=%s, num_requests=%zu) "
498                             "for count[%zu] - %s\n",
499                             ads->server.realm,
500                             num_requests, count,
501                             nt_errstr(status));
502                 TALLOC_FREE(frame);
503                 return NT_STATUS_NO_LOGON_SERVERS;
504         }
505
506         for (i = 0; i < num_requests; i++) {
507                 struct NETLOGON_SAM_LOGON_RESPONSE_EX *cldap_reply = NULL;
508                 char server[INET6_ADDRSTRLEN];
509
510                 if (responses[i] == NULL) {
511                         continue;
512                 }
513
514                 print_sockaddr(server, sizeof(server), &req_sa_list[i]->u.ss);
515
516                 if (responses[i]->ntver != NETLOGON_NT_VERSION_5EX) {
517                         DBG_NOTICE("realm=[%s] nt_version mismatch: 0x%08x for %s\n",
518                                    ads->server.realm,
519                                    responses[i]->ntver, server);
520                         continue;
521                 }
522
523                 cldap_reply = &responses[i]->data.nt5_ex;
524
525                 /* Returns ok only if it matches the correct server type */
526                 ok = ads_fill_cldap_reply(ads,
527                                           false,
528                                           &req_sa_list[i]->u.ss,
529                                           cldap_reply);
530                 if (ok) {
531                         DBG_DEBUG("realm[%s]: selected %s => %s\n",
532                                   ads->server.realm,
533                                   server, cldap_reply->pdc_dns_name);
534                         if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
535                                 NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_EX,
536                                                 cldap_reply);
537                         }
538                         TALLOC_FREE(frame);
539                         return NT_STATUS_OK;
540                 }
541
542                 DBG_NOTICE("realm[%s] server %s %s - not usable\n",
543                            ads->server.realm,
544                            server, cldap_reply->pdc_dns_name);
545                 if (CHECK_DEBUGLVL(DBGLVL_NOTICE)) {
546                         NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_EX,
547                                         cldap_reply);
548                 }
549                 add_failed_connection_entry(domain, server,
550                                 NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID);
551                 retry = true;
552         }
553
554         if (retry) {
555                 bool expired;
556
557                 expired = timeval_expired(&endtime);
558                 if (!expired) {
559                         goto again;
560                 }
561         }
562
563         /* keep track of failures as all were not suitable */
564         for (i = 0; i < num_requests; i++) {
565                 char server[INET6_ADDRSTRLEN];
566
567                 print_sockaddr(server, sizeof(server), &req_sa_list[i]->u.ss);
568
569                 add_failed_connection_entry(domain, server,
570                                             NT_STATUS_UNSUCCESSFUL);
571         }
572
573         status = NT_STATUS_NO_LOGON_SERVERS;
574         DBG_WARNING("realm[%s] no valid response "
575                     "num_requests[%zu] for count[%zu] - %s\n",
576                     ads->server.realm,
577                     num_requests, count, nt_errstr(status));
578         TALLOC_FREE(frame);
579         return NT_STATUS_NO_LOGON_SERVERS;
580 }
581
582 /***************************************************************************
583  resolve a name and perform an "ldap ping" using NetBIOS and related methods
584 ****************************************************************************/
585
586 static NTSTATUS resolve_and_ping_netbios(ADS_STRUCT *ads,
587                                          const char *domain, const char *realm)
588 {
589         size_t i;
590         size_t count = 0;
591         struct samba_sockaddr *sa_list = NULL;
592         NTSTATUS status;
593
594         DEBUG(6, ("resolve_and_ping_netbios: (cldap) looking for domain '%s'\n",
595                   domain));
596
597         status = get_sorted_dc_list(talloc_tos(),
598                                 domain,
599                                 NULL,
600                                 &sa_list,
601                                 &count,
602                                 false);
603         if (!NT_STATUS_IS_OK(status)) {
604                 return status;
605         }
606
607         /* remove servers which are known to be dead based on
608            the corresponding DNS method */
609         if (*realm) {
610                 for (i = 0; i < count; ++i) {
611                         char server[INET6_ADDRSTRLEN];
612
613                         print_sockaddr(server, sizeof(server), &sa_list[i].u.ss);
614
615                         if(!NT_STATUS_IS_OK(
616                                 check_negative_conn_cache(realm, server))) {
617                                 /* Ensure we add the workgroup name for this
618                                    IP address as negative too. */
619                                 add_failed_connection_entry(
620                                     domain, server,
621                                     NT_STATUS_UNSUCCESSFUL);
622                         }
623                 }
624         }
625
626         status = cldap_ping_list(ads, domain, sa_list, count);
627
628         TALLOC_FREE(sa_list);
629
630         return status;
631 }
632
633
634 /**********************************************************************
635  resolve a name and perform an "ldap ping" using DNS
636 **********************************************************************/
637
638 static NTSTATUS resolve_and_ping_dns(ADS_STRUCT *ads, const char *sitename,
639                                      const char *realm)
640 {
641         size_t count = 0;
642         struct samba_sockaddr *sa_list = NULL;
643         NTSTATUS status;
644
645         DEBUG(6, ("resolve_and_ping_dns: (cldap) looking for realm '%s'\n",
646                   realm));
647
648         status = get_sorted_dc_list(talloc_tos(),
649                                 realm,
650                                 sitename,
651                                 &sa_list,
652                                 &count,
653                                 true);
654         if (!NT_STATUS_IS_OK(status)) {
655                 TALLOC_FREE(sa_list);
656                 return status;
657         }
658
659         status = cldap_ping_list(ads, realm, sa_list, count);
660
661         TALLOC_FREE(sa_list);
662
663         return status;
664 }
665
666 /**********************************************************************
667  Try to find an AD dc using our internal name resolution routines
668  Try the realm first and then then workgroup name if netbios is not
669  disabled
670 **********************************************************************/
671
672 static NTSTATUS ads_find_dc(ADS_STRUCT *ads)
673 {
674         const char *c_domain = "";
675         const char *c_realm;
676         bool use_own_domain = False;
677         char *sitename = NULL;
678         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
679         bool ok = false;
680
681         /* if the realm and workgroup are both empty, assume they are ours */
682
683         /* realm */
684         c_realm = ads->server.realm;
685
686         if (c_realm == NULL)
687                 c_realm = "";
688
689         if (!*c_realm) {
690                 /* special case where no realm and no workgroup means our own */
691                 if ( !ads->server.workgroup || !*ads->server.workgroup ) {
692                         use_own_domain = True;
693                         c_realm = lp_realm();
694                 }
695         }
696
697         if (!lp_disable_netbios()) {
698                 if (use_own_domain) {
699                         c_domain = lp_workgroup();
700                 } else {
701                         c_domain = ads->server.workgroup;
702                         if (!*c_realm && (!c_domain || !*c_domain)) {
703                                 c_domain = lp_workgroup();
704                         }
705                 }
706
707                 if (!c_domain) {
708                         c_domain = "";
709                 }
710         }
711
712         if (!*c_realm && !*c_domain) {
713                 DEBUG(0, ("ads_find_dc: no realm or workgroup!  Don't know "
714                           "what to do\n"));
715                 return NT_STATUS_INVALID_PARAMETER; /* rather need MISSING_PARAMETER ... */
716         }
717
718         /*
719          * In case of LDAP we use get_dc_name() as that
720          * creates the custom krb5.conf file
721          */
722         if (!(ads->auth.flags & ADS_AUTH_NO_BIND)) {
723                 fstring srv_name;
724                 struct sockaddr_storage ip_out;
725
726                 DEBUG(6, ("ads_find_dc: (ldap) looking for realm '%s'"
727                           " and falling back to domain '%s'\n",
728                           c_realm, c_domain));
729
730                 ok = get_dc_name(c_domain, c_realm, srv_name, &ip_out);
731                 if (ok) {
732                         if (is_zero_addr(&ip_out)) {
733                                 return NT_STATUS_NO_LOGON_SERVERS;
734                         }
735
736                         /*
737                          * we call ads_try_connect() to fill in the
738                          * ads->config details
739                          */
740                         ok = ads_try_connect(ads, false, &ip_out);
741                         if (ok) {
742                                 return NT_STATUS_OK;
743                         }
744                 }
745
746                 return NT_STATUS_NO_LOGON_SERVERS;
747         }
748
749         if (*c_realm) {
750                 sitename = sitename_fetch(talloc_tos(), c_realm);
751                 status = resolve_and_ping_dns(ads, sitename, c_realm);
752
753                 if (NT_STATUS_IS_OK(status)) {
754                         TALLOC_FREE(sitename);
755                         return status;
756                 }
757
758                 /* In case we failed to contact one of our closest DC on our
759                  * site we
760                  * need to try to find another DC, retry with a site-less SRV
761                  * DNS query
762                  * - Guenther */
763
764                 if (sitename) {
765                         DEBUG(3, ("ads_find_dc: failed to find a valid DC on "
766                                   "our site (%s), Trying to find another DC "
767                                   "for realm '%s' (domain '%s')\n",
768                                   sitename, c_realm, c_domain));
769                         namecache_delete(c_realm, 0x1C);
770                         status =
771                             resolve_and_ping_dns(ads, NULL, c_realm);
772
773                         if (NT_STATUS_IS_OK(status)) {
774                                 TALLOC_FREE(sitename);
775                                 return status;
776                         }
777                 }
778
779                 TALLOC_FREE(sitename);
780         }
781
782         /* try netbios as fallback - if permitted,
783            or if configuration specifically requests it */
784         if (*c_domain) {
785                 if (*c_realm) {
786                         DEBUG(3, ("ads_find_dc: falling back to netbios "
787                                   "name resolution for domain '%s' (realm '%s')\n",
788                                   c_domain, c_realm));
789                 }
790
791                 status = resolve_and_ping_netbios(ads, c_domain, c_realm);
792                 if (NT_STATUS_IS_OK(status)) {
793                         return status;
794                 }
795         }
796
797         DEBUG(1, ("ads_find_dc: "
798                   "name resolution for realm '%s' (domain '%s') failed: %s\n",
799                   c_realm, c_domain, nt_errstr(status)));
800         return status;
801 }
802 /**
803  * Connect to the LDAP server
804  * @param ads Pointer to an existing ADS_STRUCT
805  * @return status of connection
806  **/
807 ADS_STATUS ads_connect(ADS_STRUCT *ads)
808 {
809         int version = LDAP_VERSION3;
810         ADS_STATUS status;
811         NTSTATUS ntstatus;
812         char addr[INET6_ADDRSTRLEN];
813         struct sockaddr_storage existing_ss;
814
815         zero_sockaddr(&existing_ss);
816
817         /*
818          * ads_connect can be passed in a reused ADS_STRUCT
819          * with an existing non-zero ads->ldap.ss IP address
820          * that was stored by going through ads_find_dc()
821          * if ads->server.ldap_server was NULL.
822          *
823          * If ads->server.ldap_server is still NULL but
824          * the target address isn't the zero address, then
825          * store that address off off before zeroing out
826          * ads->ldap so we don't keep doing multiple calls
827          * to ads_find_dc() in the reuse case.
828          *
829          * If a caller wants a clean ADS_STRUCT they
830          * will TALLOC_FREE it and allocate a new one
831          * by calling ads_init(), which ensures
832          * ads->ldap.ss is a properly zero'ed out valid IP
833          * address.
834          */
835         if (ads->server.ldap_server == NULL && !is_zero_addr(&ads->ldap.ss)) {
836                 /* Save off the address we previously found by ads_find_dc(). */
837                 existing_ss = ads->ldap.ss;
838         }
839
840         ads_zero_ldap(ads);
841         ZERO_STRUCT(ads->ldap_wrap_data);
842         ads->ldap.last_attempt  = time_mono(NULL);
843         ads->ldap_wrap_data.wrap_type   = ADS_SASLWRAP_TYPE_PLAIN;
844
845         /* try with a user specified server */
846
847         if (DEBUGLEVEL >= 11) {
848                 char *s = NDR_PRINT_STRUCT_STRING(talloc_tos(), ads_struct, ads);
849                 DEBUG(11,("ads_connect: entering\n"));
850                 DEBUGADD(11,("%s\n", s));
851                 TALLOC_FREE(s);
852         }
853
854         if (ads->server.ldap_server) {
855                 bool ok = false;
856                 struct sockaddr_storage ss;
857
858                 ok = resolve_name(ads->server.ldap_server, &ss, 0x20, true);
859                 if (!ok) {
860                         DEBUG(5,("ads_connect: unable to resolve name %s\n",
861                                  ads->server.ldap_server));
862                         status = ADS_ERROR_NT(NT_STATUS_NOT_FOUND);
863                         goto out;
864                 }
865
866                 if (is_zero_addr(&ss)) {
867                         status = ADS_ERROR_NT(NT_STATUS_NOT_FOUND);
868                         goto out;
869                 }
870
871                 ok = ads_try_connect(ads, ads->server.gc, &ss);
872                 if (ok) {
873                         goto got_connection;
874                 }
875
876                 /* The choice of which GC use is handled one level up in
877                    ads_connect_gc().  If we continue on from here with
878                    ads_find_dc() we will get GC searches on port 389 which
879                    doesn't work.   --jerry */
880
881                 if (ads->server.gc == true) {
882                         return ADS_ERROR(LDAP_OPERATIONS_ERROR);
883                 }
884
885                 if (ads->server.no_fallback) {
886                         status = ADS_ERROR_NT(NT_STATUS_NOT_FOUND);
887                         goto out;
888                 }
889         }
890
891         if (!is_zero_addr(&existing_ss)) {
892                 /* We saved off who we should talk to. */
893                 bool ok = ads_try_connect(ads,
894                                           ads->server.gc,
895                                           &existing_ss);
896                 if (ok) {
897                         goto got_connection;
898                 }
899                 /*
900                  * Keep trying to find a server and fall through
901                  * into ads_find_dc() again.
902                  */
903         }
904
905         ntstatus = ads_find_dc(ads);
906         if (NT_STATUS_IS_OK(ntstatus)) {
907                 goto got_connection;
908         }
909
910         status = ADS_ERROR_NT(ntstatus);
911         goto out;
912
913 got_connection:
914
915         print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
916         DEBUG(3,("Successfully contacted LDAP server %s\n", addr));
917
918         if (!ads->auth.user_name) {
919                 /* Must use the userPrincipalName value here or sAMAccountName
920                    and not servicePrincipalName; found by Guenther Deschner */
921                 ads->auth.user_name = talloc_asprintf(ads,
922                                                       "%s$",
923                                                       lp_netbios_name());
924                 if (ads->auth.user_name == NULL) {
925                         DBG_ERR("talloc_asprintf failed\n");
926                         status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
927                         goto out;
928                 }
929         }
930
931         if (ads->auth.realm == NULL) {
932                 ads->auth.realm = talloc_strdup(ads, ads->config.realm);
933                 if (ads->auth.realm == NULL) {
934                         status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
935                         goto out;
936                 }
937         }
938
939         if (!ads->auth.kdc_server) {
940                 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
941                 ads->auth.kdc_server = talloc_strdup(ads, addr);
942                 if (ads->auth.kdc_server == NULL) {
943                         status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
944                         goto out;
945                 }
946         }
947
948         /* If the caller() requested no LDAP bind, then we are done */
949
950         if (ads->auth.flags & ADS_AUTH_NO_BIND) {
951                 status = ADS_SUCCESS;
952                 goto out;
953         }
954
955         ads->ldap_wrap_data.mem_ctx = talloc_init("ads LDAP connection memory");
956         if (!ads->ldap_wrap_data.mem_ctx) {
957                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
958                 goto out;
959         }
960
961         /* Otherwise setup the TCP LDAP session */
962
963         ads->ldap.ld = ldap_open_with_timeout(ads->config.ldap_server_name,
964                                               &ads->ldap.ss,
965                                               ads->ldap.port, lp_ldap_timeout());
966         if (ads->ldap.ld == NULL) {
967                 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
968                 goto out;
969         }
970         DEBUG(3,("Connected to LDAP server %s\n", ads->config.ldap_server_name));
971
972         /* cache the successful connection for workgroup and realm */
973         if (ads_closest_dc(ads)) {
974                 saf_store( ads->server.workgroup, ads->config.ldap_server_name);
975                 saf_store( ads->server.realm, ads->config.ldap_server_name);
976         }
977
978         ldap_set_option(ads->ldap.ld, LDAP_OPT_PROTOCOL_VERSION, &version);
979
980         /* fill in the current time and offsets */
981
982         status = ads_current_time( ads );
983         if ( !ADS_ERR_OK(status) ) {
984                 goto out;
985         }
986
987         /* Now do the bind */
988
989         if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
990                 status = ADS_ERROR(ldap_simple_bind_s(ads->ldap.ld, NULL, NULL));
991                 goto out;
992         }
993
994         if (ads->auth.flags & ADS_AUTH_SIMPLE_BIND) {
995                 status = ADS_ERROR(ldap_simple_bind_s(ads->ldap.ld, ads->auth.user_name, ads->auth.password));
996                 goto out;
997         }
998
999         status = ads_sasl_bind(ads);
1000
1001  out:
1002         if (DEBUGLEVEL >= 11) {
1003                 char *s = NDR_PRINT_STRUCT_STRING(talloc_tos(), ads_struct, ads);
1004                 DEBUG(11,("ads_connect: leaving with: %s\n",
1005                         ads_errstr(status)));
1006                 DEBUGADD(11,("%s\n", s));
1007                 TALLOC_FREE(s);
1008         }
1009
1010         return status;
1011 }
1012
1013 /**
1014  * Connect to the LDAP server using given credentials
1015  * @param ads Pointer to an existing ADS_STRUCT
1016  * @return status of connection
1017  **/
1018 ADS_STATUS ads_connect_user_creds(ADS_STRUCT *ads)
1019 {
1020         ads->auth.flags |= ADS_AUTH_USER_CREDS;
1021
1022         return ads_connect(ads);
1023 }
1024
1025 /**
1026  * Zero out the internal ads->ldap struct and initialize the address to zero IP.
1027  * @param ads Pointer to an existing ADS_STRUCT
1028  *
1029  * Sets the ads->ldap.ss to a valid
1030  * zero ip address that can be detected by
1031  * our is_zero_addr() function. Otherwise
1032  * it is left as AF_UNSPEC (0).
1033  **/
1034 void ads_zero_ldap(ADS_STRUCT *ads)
1035 {
1036         ZERO_STRUCT(ads->ldap);
1037         /*
1038          * Initialize the sockaddr_storage so we can use
1039          * sockaddr test functions against it.
1040          */
1041         zero_sockaddr(&ads->ldap.ss);
1042 }
1043
1044 /**
1045  * Disconnect the LDAP server
1046  * @param ads Pointer to an existing ADS_STRUCT
1047  **/
1048 void ads_disconnect(ADS_STRUCT *ads)
1049 {
1050         if (ads->ldap.ld) {
1051                 ldap_unbind(ads->ldap.ld);
1052                 ads->ldap.ld = NULL;
1053         }
1054         if (ads->ldap_wrap_data.wrap_ops &&
1055                 ads->ldap_wrap_data.wrap_ops->disconnect) {
1056                 ads->ldap_wrap_data.wrap_ops->disconnect(&ads->ldap_wrap_data);
1057         }
1058         if (ads->ldap_wrap_data.mem_ctx) {
1059                 talloc_free(ads->ldap_wrap_data.mem_ctx);
1060         }
1061         ads_zero_ldap(ads);
1062         ZERO_STRUCT(ads->ldap_wrap_data);
1063 }
1064
1065 /*
1066   Duplicate a struct berval into talloc'ed memory
1067  */
1068 static struct berval *dup_berval(TALLOC_CTX *ctx, const struct berval *in_val)
1069 {
1070         struct berval *value;
1071
1072         if (!in_val) return NULL;
1073
1074         value = talloc_zero(ctx, struct berval);
1075         if (value == NULL)
1076                 return NULL;
1077         if (in_val->bv_len == 0) return value;
1078
1079         value->bv_len = in_val->bv_len;
1080         value->bv_val = (char *)talloc_memdup(ctx, in_val->bv_val,
1081                                               in_val->bv_len);
1082         return value;
1083 }
1084
1085 /*
1086   Make a values list out of an array of (struct berval *)
1087  */
1088 static struct berval **ads_dup_values(TALLOC_CTX *ctx,
1089                                       const struct berval **in_vals)
1090 {
1091         struct berval **values;
1092         int i;
1093
1094         if (!in_vals) return NULL;
1095         for (i=0; in_vals[i]; i++)
1096                 ; /* count values */
1097         values = talloc_zero_array(ctx, struct berval *, i+1);
1098         if (!values) return NULL;
1099
1100         for (i=0; in_vals[i]; i++) {
1101                 values[i] = dup_berval(ctx, in_vals[i]);
1102         }
1103         return values;
1104 }
1105
1106 /*
1107   UTF8-encode a values list out of an array of (char *)
1108  */
1109 static char **ads_push_strvals(TALLOC_CTX *ctx, const char **in_vals)
1110 {
1111         char **values;
1112         int i;
1113         size_t size;
1114
1115         if (!in_vals) return NULL;
1116         for (i=0; in_vals[i]; i++)
1117                 ; /* count values */
1118         values = talloc_zero_array(ctx, char *, i+1);
1119         if (!values) return NULL;
1120
1121         for (i=0; in_vals[i]; i++) {
1122                 if (!push_utf8_talloc(ctx, &values[i], in_vals[i], &size)) {
1123                         TALLOC_FREE(values);
1124                         return NULL;
1125                 }
1126         }
1127         return values;
1128 }
1129
1130 /*
1131   Pull a (char *) array out of a UTF8-encoded values list
1132  */
1133 static char **ads_pull_strvals(TALLOC_CTX *ctx, const char **in_vals)
1134 {
1135         char **values;
1136         int i;
1137         size_t converted_size;
1138
1139         if (!in_vals) return NULL;
1140         for (i=0; in_vals[i]; i++)
1141                 ; /* count values */
1142         values = talloc_zero_array(ctx, char *, i+1);
1143         if (!values) return NULL;
1144
1145         for (i=0; in_vals[i]; i++) {
1146                 if (!pull_utf8_talloc(ctx, &values[i], in_vals[i],
1147                                       &converted_size)) {
1148                         DEBUG(0,("ads_pull_strvals: pull_utf8_talloc failed: "
1149                                  "%s\n", strerror(errno)));
1150                 }
1151         }
1152         return values;
1153 }
1154
1155 /**
1156  * Do a search with paged results.  cookie must be null on the first
1157  *  call, and then returned on each subsequent call.  It will be null
1158  *  again when the entire search is complete
1159  * @param ads connection to ads server
1160  * @param bind_path Base dn for the search
1161  * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
1162  * @param expr Search expression - specified in local charset
1163  * @param attrs Attributes to retrieve - specified in utf8 or ascii
1164  * @param res ** which will contain results - free res* with ads_msgfree()
1165  * @param count Number of entries retrieved on this page
1166  * @param cookie The paged results cookie to be returned on subsequent calls
1167  * @return status of search
1168  **/
1169 static ADS_STATUS ads_do_paged_search_args(ADS_STRUCT *ads,
1170                                            const char *bind_path,
1171                                            int scope, const char *expr,
1172                                            const char **attrs, void *args,
1173                                            LDAPMessage **res,
1174                                            int *count, struct berval **cookie)
1175 {
1176         int rc, i, version;
1177         char *utf8_expr, *utf8_path, **search_attrs = NULL;
1178         size_t converted_size;
1179         LDAPControl PagedResults, NoReferrals, ExternalCtrl, *controls[4], **rcontrols;
1180         BerElement *cookie_be = NULL;
1181         struct berval *cookie_bv= NULL;
1182         BerElement *ext_be = NULL;
1183         struct berval *ext_bv= NULL;
1184
1185         TALLOC_CTX *ctx;
1186         ads_control *external_control = (ads_control *) args;
1187
1188         *res = NULL;
1189
1190         if (!(ctx = talloc_init("ads_do_paged_search_args")))
1191                 return ADS_ERROR(LDAP_NO_MEMORY);
1192
1193         /* 0 means the conversion worked but the result was empty
1194            so we only fail if it's -1.  In any case, it always
1195            at least nulls out the dest */
1196         if (!push_utf8_talloc(ctx, &utf8_expr, expr, &converted_size) ||
1197             !push_utf8_talloc(ctx, &utf8_path, bind_path, &converted_size))
1198         {
1199                 rc = LDAP_NO_MEMORY;
1200                 goto done;
1201         }
1202
1203         if (!attrs || !(*attrs))
1204                 search_attrs = NULL;
1205         else {
1206                 /* This would be the utf8-encoded version...*/
1207                 /* if (!(search_attrs = ads_push_strvals(ctx, attrs))) */
1208                 if (!(search_attrs = str_list_copy(talloc_tos(), attrs))) {
1209                         rc = LDAP_NO_MEMORY;
1210                         goto done;
1211                 }
1212         }
1213
1214         /* Paged results only available on ldap v3 or later */
1215         ldap_get_option(ads->ldap.ld, LDAP_OPT_PROTOCOL_VERSION, &version);
1216         if (version < LDAP_VERSION3) {
1217                 rc =  LDAP_NOT_SUPPORTED;
1218                 goto done;
1219         }
1220
1221         cookie_be = ber_alloc_t(LBER_USE_DER);
1222         if (*cookie) {
1223                 ber_printf(cookie_be, "{iO}", (ber_int_t) ads->config.ldap_page_size, *cookie);
1224                 ber_bvfree(*cookie); /* don't need it from last time */
1225                 *cookie = NULL;
1226         } else {
1227                 ber_printf(cookie_be, "{io}", (ber_int_t) ads->config.ldap_page_size, "", 0);
1228         }
1229         ber_flatten(cookie_be, &cookie_bv);
1230         PagedResults.ldctl_oid = discard_const_p(char, ADS_PAGE_CTL_OID);
1231         PagedResults.ldctl_iscritical = (char) 1;
1232         PagedResults.ldctl_value.bv_len = cookie_bv->bv_len;
1233         PagedResults.ldctl_value.bv_val = cookie_bv->bv_val;
1234
1235         NoReferrals.ldctl_oid = discard_const_p(char, ADS_NO_REFERRALS_OID);
1236         NoReferrals.ldctl_iscritical = (char) 0;
1237         NoReferrals.ldctl_value.bv_len = 0;
1238         NoReferrals.ldctl_value.bv_val = discard_const_p(char, "");
1239
1240         if (external_control &&
1241             (strequal(external_control->control, ADS_EXTENDED_DN_OID) ||
1242              strequal(external_control->control, ADS_SD_FLAGS_OID))) {
1243
1244                 ExternalCtrl.ldctl_oid = discard_const_p(char, external_control->control);
1245                 ExternalCtrl.ldctl_iscritical = (char) external_control->critical;
1246
1247                 /* win2k does not accept a ldctl_value being passed in */
1248
1249                 if (external_control->val != 0) {
1250
1251                         if ((ext_be = ber_alloc_t(LBER_USE_DER)) == NULL ) {
1252                                 rc = LDAP_NO_MEMORY;
1253                                 goto done;
1254                         }
1255
1256                         if ((ber_printf(ext_be, "{i}", (ber_int_t) external_control->val)) == -1) {
1257                                 rc = LDAP_NO_MEMORY;
1258                                 goto done;
1259                         }
1260                         if ((ber_flatten(ext_be, &ext_bv)) == -1) {
1261                                 rc = LDAP_NO_MEMORY;
1262                                 goto done;
1263                         }
1264
1265                         ExternalCtrl.ldctl_value.bv_len = ext_bv->bv_len;
1266                         ExternalCtrl.ldctl_value.bv_val = ext_bv->bv_val;
1267
1268                 } else {
1269                         ExternalCtrl.ldctl_value.bv_len = 0;
1270                         ExternalCtrl.ldctl_value.bv_val = NULL;
1271                 }
1272
1273                 controls[0] = &NoReferrals;
1274                 controls[1] = &PagedResults;
1275                 controls[2] = &ExternalCtrl;
1276                 controls[3] = NULL;
1277
1278         } else {
1279                 controls[0] = &NoReferrals;
1280                 controls[1] = &PagedResults;
1281                 controls[2] = NULL;
1282         }
1283
1284         /* we need to disable referrals as the openldap libs don't
1285            handle them and paged results at the same time.  Using them
1286            together results in the result record containing the server
1287            page control being removed from the result list (tridge/jmcd)
1288
1289            leaving this in despite the control that says don't generate
1290            referrals, in case the server doesn't support it (jmcd)
1291         */
1292         ldap_set_option(ads->ldap.ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1293
1294         rc = ldap_search_with_timeout(ads->ldap.ld, utf8_path, scope, utf8_expr,
1295                                       search_attrs, 0, controls,
1296                                       NULL, LDAP_NO_LIMIT,
1297                                       (LDAPMessage **)res);
1298
1299         ber_free(cookie_be, 1);
1300         ber_bvfree(cookie_bv);
1301
1302         if (rc) {
1303                 DEBUG(3,("ads_do_paged_search_args: ldap_search_with_timeout(%s) -> %s\n", expr,
1304                          ldap_err2string(rc)));
1305                 if (rc == LDAP_OTHER) {
1306                         char *ldap_errmsg;
1307                         int ret;
1308
1309                         ret = ldap_parse_result(ads->ldap.ld,
1310                                                 *res,
1311                                                 NULL,
1312                                                 NULL,
1313                                                 &ldap_errmsg,
1314                                                 NULL,
1315                                                 NULL,
1316                                                 0);
1317                         if (ret == LDAP_SUCCESS) {
1318                                 DEBUG(3, ("ldap_search_with_timeout(%s) "
1319                                           "error: %s\n", expr, ldap_errmsg));
1320                                 ldap_memfree(ldap_errmsg);
1321                         }
1322                 }
1323                 goto done;
1324         }
1325
1326         rc = ldap_parse_result(ads->ldap.ld, *res, NULL, NULL, NULL,
1327                                         NULL, &rcontrols,  0);
1328
1329         if (!rcontrols) {
1330                 goto done;
1331         }
1332
1333         for (i=0; rcontrols[i]; i++) {
1334                 if (strcmp(ADS_PAGE_CTL_OID, rcontrols[i]->ldctl_oid) == 0) {
1335                         cookie_be = ber_init(&rcontrols[i]->ldctl_value);
1336                         ber_scanf(cookie_be,"{iO}", (ber_int_t *) count,
1337                                   &cookie_bv);
1338                         /* the berval is the cookie, but must be freed when
1339                            it is all done */
1340                         if (cookie_bv->bv_len) /* still more to do */
1341                                 *cookie=ber_bvdup(cookie_bv);
1342                         else
1343                                 *cookie=NULL;
1344                         ber_bvfree(cookie_bv);
1345                         ber_free(cookie_be, 1);
1346                         break;
1347                 }
1348         }
1349         ldap_controls_free(rcontrols);
1350
1351 done:
1352         talloc_destroy(ctx);
1353
1354         if (ext_be) {
1355                 ber_free(ext_be, 1);
1356         }
1357
1358         if (ext_bv) {
1359                 ber_bvfree(ext_bv);
1360         }
1361
1362         if (rc != LDAP_SUCCESS && *res != NULL) {
1363                 ads_msgfree(ads, *res);
1364                 *res = NULL;
1365         }
1366
1367         /* if/when we decide to utf8-encode attrs, take out this next line */
1368         TALLOC_FREE(search_attrs);
1369
1370         return ADS_ERROR(rc);
1371 }
1372
1373 static ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
1374                                       int scope, const char *expr,
1375                                       const char **attrs, LDAPMessage **res,
1376                                       int *count, struct berval **cookie)
1377 {
1378         return ads_do_paged_search_args(ads, bind_path, scope, expr, attrs, NULL, res, count, cookie);
1379 }
1380
1381
1382 /**
1383  * Get all results for a search.  This uses ads_do_paged_search() to return
1384  * all entries in a large search.
1385  * @param ads connection to ads server
1386  * @param bind_path Base dn for the search
1387  * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
1388  * @param expr Search expression
1389  * @param attrs Attributes to retrieve
1390  * @param res ** which will contain results - free res* with ads_msgfree()
1391  * @return status of search
1392  **/
1393  ADS_STATUS ads_do_search_all_args(ADS_STRUCT *ads, const char *bind_path,
1394                                    int scope, const char *expr,
1395                                    const char **attrs, void *args,
1396                                    LDAPMessage **res)
1397 {
1398         struct berval *cookie = NULL;
1399         int count = 0;
1400         ADS_STATUS status;
1401
1402         *res = NULL;
1403         status = ads_do_paged_search_args(ads, bind_path, scope, expr, attrs, args, res,
1404                                      &count, &cookie);
1405
1406         if (!ADS_ERR_OK(status))
1407                 return status;
1408
1409 #ifdef HAVE_LDAP_ADD_RESULT_ENTRY
1410         while (cookie) {
1411                 LDAPMessage *res2 = NULL;
1412                 LDAPMessage *msg, *next;
1413
1414                 status = ads_do_paged_search_args(ads, bind_path, scope, expr,
1415                                               attrs, args, &res2, &count, &cookie);
1416                 if (!ADS_ERR_OK(status)) {
1417                         break;
1418                 }
1419
1420                 /* this relies on the way that ldap_add_result_entry() works internally. I hope
1421                    that this works on all ldap libs, but I have only tested with openldap */
1422                 for (msg = ads_first_message(ads, res2); msg; msg = next) {
1423                         next = ads_next_message(ads, msg);
1424                         ldap_add_result_entry((LDAPMessage **)res, msg);
1425                 }
1426                 /* note that we do not free res2, as the memory is now
1427                    part of the main returned list */
1428         }
1429 #else
1430         DEBUG(0, ("no ldap_add_result_entry() support in LDAP libs!\n"));
1431         status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
1432 #endif
1433
1434         return status;
1435 }
1436
1437  ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path,
1438                               int scope, const char *expr,
1439                               const char **attrs, LDAPMessage **res)
1440 {
1441         return ads_do_search_all_args(ads, bind_path, scope, expr, attrs, NULL, res);
1442 }
1443
1444  ADS_STATUS ads_do_search_all_sd_flags(ADS_STRUCT *ads, const char *bind_path,
1445                                        int scope, const char *expr,
1446                                        const char **attrs, uint32_t sd_flags,
1447                                        LDAPMessage **res)
1448 {
1449         ads_control args;
1450
1451         args.control = ADS_SD_FLAGS_OID;
1452         args.val = sd_flags;
1453         args.critical = True;
1454
1455         return ads_do_search_all_args(ads, bind_path, scope, expr, attrs, &args, res);
1456 }
1457
1458
1459 /**
1460  * Run a function on all results for a search.  Uses ads_do_paged_search() and
1461  *  runs the function as each page is returned, using ads_process_results()
1462  * @param ads connection to ads server
1463  * @param bind_path Base dn for the search
1464  * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
1465  * @param expr Search expression - specified in local charset
1466  * @param attrs Attributes to retrieve - specified in UTF-8 or ascii
1467  * @param fn Function which takes attr name, values list, and data_area
1468  * @param data_area Pointer which is passed to function on each call
1469  * @return status of search
1470  **/
1471 ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
1472                                 int scope, const char *expr, const char **attrs,
1473                                 bool (*fn)(ADS_STRUCT *, char *, void **, void *),
1474                                 void *data_area)
1475 {
1476         struct berval *cookie = NULL;
1477         int count = 0;
1478         ADS_STATUS status;
1479         LDAPMessage *res;
1480
1481         status = ads_do_paged_search(ads, bind_path, scope, expr, attrs, &res,
1482                                      &count, &cookie);
1483
1484         if (!ADS_ERR_OK(status)) return status;
1485
1486         ads_process_results(ads, res, fn, data_area);
1487         ads_msgfree(ads, res);
1488
1489         while (cookie) {
1490                 status = ads_do_paged_search(ads, bind_path, scope, expr, attrs,
1491                                              &res, &count, &cookie);
1492
1493                 if (!ADS_ERR_OK(status)) break;
1494
1495                 ads_process_results(ads, res, fn, data_area);
1496                 ads_msgfree(ads, res);
1497         }
1498
1499         return status;
1500 }
1501
1502 /**
1503  * Do a search with a timeout.
1504  * @param ads connection to ads server
1505  * @param bind_path Base dn for the search
1506  * @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
1507  * @param expr Search expression
1508  * @param attrs Attributes to retrieve
1509  * @param res ** which will contain results - free res* with ads_msgfree()
1510  * @return status of search
1511  **/
1512  ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
1513                           const char *expr,
1514                           const char **attrs, LDAPMessage **res)
1515 {
1516         int rc;
1517         char *utf8_expr, *utf8_path, **search_attrs = NULL;
1518         size_t converted_size;
1519         TALLOC_CTX *ctx;
1520
1521         *res = NULL;
1522         if (!(ctx = talloc_init("ads_do_search"))) {
1523                 DEBUG(1,("ads_do_search: talloc_init() failed!\n"));
1524                 return ADS_ERROR(LDAP_NO_MEMORY);
1525         }
1526
1527         /* 0 means the conversion worked but the result was empty
1528            so we only fail if it's negative.  In any case, it always
1529            at least nulls out the dest */
1530         if (!push_utf8_talloc(ctx, &utf8_expr, expr, &converted_size) ||
1531             !push_utf8_talloc(ctx, &utf8_path, bind_path, &converted_size))
1532         {
1533                 DEBUG(1,("ads_do_search: push_utf8_talloc() failed!\n"));
1534                 rc = LDAP_NO_MEMORY;
1535                 goto done;
1536         }
1537
1538         if (!attrs || !(*attrs))
1539                 search_attrs = NULL;
1540         else {
1541                 /* This would be the utf8-encoded version...*/
1542                 /* if (!(search_attrs = ads_push_strvals(ctx, attrs)))  */
1543                 if (!(search_attrs = str_list_copy(talloc_tos(), attrs)))
1544                 {
1545                         DEBUG(1,("ads_do_search: str_list_copy() failed!\n"));
1546                         rc = LDAP_NO_MEMORY;
1547                         goto done;
1548                 }
1549         }
1550
1551         /* see the note in ads_do_paged_search - we *must* disable referrals */
1552         ldap_set_option(ads->ldap.ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1553
1554         rc = ldap_search_with_timeout(ads->ldap.ld, utf8_path, scope, utf8_expr,
1555                                       search_attrs, 0, NULL, NULL,
1556                                       LDAP_NO_LIMIT,
1557                                       (LDAPMessage **)res);
1558
1559         if (rc == LDAP_SIZELIMIT_EXCEEDED) {
1560                 DEBUG(3,("Warning! sizelimit exceeded in ldap. Truncating.\n"));
1561                 rc = 0;
1562         }
1563
1564  done:
1565         talloc_destroy(ctx);
1566         /* if/when we decide to utf8-encode attrs, take out this next line */
1567         TALLOC_FREE(search_attrs);
1568         return ADS_ERROR(rc);
1569 }
1570 /**
1571  * Do a general ADS search
1572  * @param ads connection to ads server
1573  * @param res ** which will contain results - free res* with ads_msgfree()
1574  * @param expr Search expression
1575  * @param attrs Attributes to retrieve
1576  * @return status of search
1577  **/
1578  ADS_STATUS ads_search(ADS_STRUCT *ads, LDAPMessage **res,
1579                        const char *expr, const char **attrs)
1580 {
1581         return ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,
1582                              expr, attrs, res);
1583 }
1584
1585 /**
1586  * Do a search on a specific DistinguishedName
1587  * @param ads connection to ads server
1588  * @param res ** which will contain results - free res* with ads_msgfree()
1589  * @param dn DistinguishName to search
1590  * @param attrs Attributes to retrieve
1591  * @return status of search
1592  **/
1593  ADS_STATUS ads_search_dn(ADS_STRUCT *ads, LDAPMessage **res,
1594                           const char *dn, const char **attrs)
1595 {
1596         return ads_do_search(ads, dn, LDAP_SCOPE_BASE, "(objectclass=*)",
1597                              attrs, res);
1598 }
1599
1600 /**
1601  * Free up memory from a ads_search
1602  * @param ads connection to ads server
1603  * @param msg Search results to free
1604  **/
1605  void ads_msgfree(ADS_STRUCT *ads, LDAPMessage *msg)
1606 {
1607         if (!msg) return;
1608         ldap_msgfree(msg);
1609 }
1610
1611 /**
1612  * Get a dn from search results
1613  * @param ads connection to ads server
1614  * @param msg Search result
1615  * @return dn string
1616  **/
1617  char *ads_get_dn(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, LDAPMessage *msg)
1618 {
1619         char *utf8_dn, *unix_dn;
1620         size_t converted_size;
1621
1622         utf8_dn = ldap_get_dn(ads->ldap.ld, msg);
1623
1624         if (!utf8_dn) {
1625                 DEBUG (5, ("ads_get_dn: ldap_get_dn failed\n"));
1626                 return NULL;
1627         }
1628
1629         if (!pull_utf8_talloc(mem_ctx, &unix_dn, utf8_dn, &converted_size)) {
1630                 DEBUG(0,("ads_get_dn: string conversion failure utf8 [%s]\n",
1631                         utf8_dn ));
1632                 return NULL;
1633         }
1634         ldap_memfree(utf8_dn);
1635         return unix_dn;
1636 }
1637
1638 /**
1639  * Get the parent from a dn
1640  * @param dn the dn to return the parent from
1641  * @return parent dn string
1642  **/
1643 char *ads_parent_dn(const char *dn)
1644 {
1645         char *p;
1646
1647         if (dn == NULL) {
1648                 return NULL;
1649         }
1650
1651         p = strchr(dn, ',');
1652
1653         if (p == NULL) {
1654                 return NULL;
1655         }
1656
1657         return p+1;
1658 }
1659
1660 /**
1661  * Find a machine account given a hostname
1662  * @param ads connection to ads server
1663  * @param res ** which will contain results - free res* with ads_msgfree()
1664  * @param host Hostname to search for
1665  * @return status of search
1666  **/
1667  ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, LDAPMessage **res,
1668                                   const char *machine)
1669 {
1670         ADS_STATUS status;
1671         char *expr;
1672         const char *attrs[] = {
1673                 /* This is how Windows checks for machine accounts */
1674                 "objectClass",
1675                 "SamAccountName",
1676                 "userAccountControl",
1677                 "DnsHostName",
1678                 "ServicePrincipalName",
1679                 "userPrincipalName",
1680                 "unicodePwd",
1681
1682                 /* Additional attributes Samba checks */
1683                 "msDS-AdditionalDnsHostName",
1684                 "msDS-SupportedEncryptionTypes",
1685                 "nTSecurityDescriptor",
1686                 "objectSid",
1687
1688                 NULL
1689         };
1690         TALLOC_CTX *frame = talloc_stackframe();
1691
1692         *res = NULL;
1693
1694         /* the easiest way to find a machine account anywhere in the tree
1695            is to look for hostname$ */
1696         expr = talloc_asprintf(frame, "(samAccountName=%s$)", machine);
1697         if (expr == NULL) {
1698                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1699                 goto done;
1700         }
1701
1702         status = ads_search(ads, res, expr, attrs);
1703         if (ADS_ERR_OK(status)) {
1704                 if (ads_count_replies(ads, *res) != 1) {
1705                         status = ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
1706                 }
1707         }
1708
1709 done:
1710         TALLOC_FREE(frame);
1711         return status;
1712 }
1713
1714 /**
1715  * Initialize a list of mods to be used in a modify request
1716  * @param ctx An initialized TALLOC_CTX
1717  * @return allocated ADS_MODLIST
1718  **/
1719 ADS_MODLIST ads_init_mods(TALLOC_CTX *ctx)
1720 {
1721 #define ADS_MODLIST_ALLOC_SIZE 10
1722         LDAPMod **mods;
1723
1724         if ((mods = talloc_zero_array(ctx, LDAPMod *, ADS_MODLIST_ALLOC_SIZE + 1)))
1725                 /* -1 is safety to make sure we don't go over the end.
1726                    need to reset it to NULL before doing ldap modify */
1727                 mods[ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
1728
1729         return (ADS_MODLIST)mods;
1730 }
1731
1732
1733 /*
1734   add an attribute to the list, with values list already constructed
1735 */
1736 static ADS_STATUS ads_modlist_add(TALLOC_CTX *ctx, ADS_MODLIST *mods,
1737                                   int mod_op, const char *name,
1738                                   const void *_invals)
1739 {
1740         int curmod;
1741         LDAPMod **modlist = (LDAPMod **) *mods;
1742         struct berval **ber_values = NULL;
1743         char **char_values = NULL;
1744
1745         if (!_invals) {
1746                 mod_op = LDAP_MOD_DELETE;
1747         } else {
1748                 if (mod_op & LDAP_MOD_BVALUES) {
1749                         const struct berval **b;
1750                         b = discard_const_p(const struct berval *, _invals);
1751                         ber_values = ads_dup_values(ctx, b);
1752                 } else {
1753                         const char **c;
1754                         c = discard_const_p(const char *, _invals);
1755                         char_values = ads_push_strvals(ctx, c);
1756                 }
1757         }
1758
1759         /* find the first empty slot */
1760         for (curmod=0; modlist[curmod] && modlist[curmod] != (LDAPMod *) -1;
1761              curmod++);
1762         if (modlist[curmod] == (LDAPMod *) -1) {
1763                 if (!(modlist = talloc_realloc(ctx, modlist, LDAPMod *,
1764                                 curmod+ADS_MODLIST_ALLOC_SIZE+1)))
1765                         return ADS_ERROR(LDAP_NO_MEMORY);
1766                 memset(&modlist[curmod], 0,
1767                        ADS_MODLIST_ALLOC_SIZE*sizeof(LDAPMod *));
1768                 modlist[curmod+ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
1769                 *mods = (ADS_MODLIST)modlist;
1770         }
1771
1772         if (!(modlist[curmod] = talloc_zero(ctx, LDAPMod)))
1773                 return ADS_ERROR(LDAP_NO_MEMORY);
1774         modlist[curmod]->mod_type = talloc_strdup(ctx, name);
1775         if (mod_op & LDAP_MOD_BVALUES) {
1776                 modlist[curmod]->mod_bvalues = ber_values;
1777         } else if (mod_op & LDAP_MOD_DELETE) {
1778                 modlist[curmod]->mod_values = NULL;
1779         } else {
1780                 modlist[curmod]->mod_values = char_values;
1781         }
1782
1783         modlist[curmod]->mod_op = mod_op;
1784         return ADS_ERROR(LDAP_SUCCESS);
1785 }
1786
1787 /**
1788  * Add a single string value to a mod list
1789  * @param ctx An initialized TALLOC_CTX
1790  * @param mods An initialized ADS_MODLIST
1791  * @param name The attribute name to add
1792  * @param val The value to add - NULL means DELETE
1793  * @return ADS STATUS indicating success of add
1794  **/
1795 ADS_STATUS ads_mod_str(TALLOC_CTX *ctx, ADS_MODLIST *mods,
1796                        const char *name, const char *val)
1797 {
1798         const char *values[2];
1799
1800         values[0] = val;
1801         values[1] = NULL;
1802
1803         if (!val)
1804                 return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
1805         return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE, name, values);
1806 }
1807
1808 /**
1809  * Add an array of string values to a mod list
1810  * @param ctx An initialized TALLOC_CTX
1811  * @param mods An initialized ADS_MODLIST
1812  * @param name The attribute name to add
1813  * @param vals The array of string values to add - NULL means DELETE
1814  * @return ADS STATUS indicating success of add
1815  **/
1816 ADS_STATUS ads_mod_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
1817                            const char *name, const char **vals)
1818 {
1819         if (!vals)
1820                 return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
1821         return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE,
1822                                name, (const void **) vals);
1823 }
1824
1825 /**
1826  * Add a single ber-encoded value to a mod list
1827  * @param ctx An initialized TALLOC_CTX
1828  * @param mods An initialized ADS_MODLIST
1829  * @param name The attribute name to add
1830  * @param val The value to add - NULL means DELETE
1831  * @return ADS STATUS indicating success of add
1832  **/
1833 static ADS_STATUS ads_mod_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods,
1834                               const char *name, const struct berval *val)
1835 {
1836         const struct berval *values[2];
1837
1838         values[0] = val;
1839         values[1] = NULL;
1840         if (!val)
1841                 return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
1842         return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE|LDAP_MOD_BVALUES,
1843                                name, (const void **) values);
1844 }
1845
1846 static void ads_print_error(int ret, LDAP *ld)
1847 {
1848         if (ret != 0) {
1849                 char *ld_error = NULL;
1850                 ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &ld_error);
1851                 DBG_ERR("AD LDAP ERROR: %d (%s): %s\n",
1852                         ret,
1853                         ldap_err2string(ret),
1854                         ld_error);
1855                 SAFE_FREE(ld_error);
1856         }
1857 }
1858
1859 /**
1860  * Perform an ldap modify
1861  * @param ads connection to ads server
1862  * @param mod_dn DistinguishedName to modify
1863  * @param mods list of modifications to perform
1864  * @return status of modify
1865  **/
1866 ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods)
1867 {
1868         int ret,i;
1869         char *utf8_dn = NULL;
1870         size_t converted_size;
1871         /*
1872            this control is needed to modify that contains a currently
1873            non-existent attribute (but allowable for the object) to run
1874         */
1875         LDAPControl PermitModify = {
1876                 discard_const_p(char, ADS_PERMIT_MODIFY_OID),
1877                 {0, NULL},
1878                 (char) 1};
1879         LDAPControl *controls[2];
1880
1881         DBG_INFO("AD LDAP: Modifying %s\n", mod_dn);
1882
1883         controls[0] = &PermitModify;
1884         controls[1] = NULL;
1885
1886         if (!push_utf8_talloc(talloc_tos(), &utf8_dn, mod_dn, &converted_size)) {
1887                 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1888         }
1889
1890         /* find the end of the list, marked by NULL or -1 */
1891         for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
1892         /* make sure the end of the list is NULL */
1893         mods[i] = NULL;
1894         ret = ldap_modify_ext_s(ads->ldap.ld, utf8_dn,
1895                                 (LDAPMod **) mods, controls, NULL);
1896         ads_print_error(ret, ads->ldap.ld);
1897         TALLOC_FREE(utf8_dn);
1898         return ADS_ERROR(ret);
1899 }
1900
1901 /**
1902  * Perform an ldap add
1903  * @param ads connection to ads server
1904  * @param new_dn DistinguishedName to add
1905  * @param mods list of attributes and values for DN
1906  * @return status of add
1907  **/
1908 ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods)
1909 {
1910         int ret, i;
1911         char *utf8_dn = NULL;
1912         size_t converted_size;
1913
1914         DBG_INFO("AD LDAP: Adding %s\n", new_dn);
1915
1916         if (!push_utf8_talloc(talloc_tos(), &utf8_dn, new_dn, &converted_size)) {
1917                 DEBUG(1, ("ads_gen_add: push_utf8_talloc failed!\n"));
1918                 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1919         }
1920
1921         /* find the end of the list, marked by NULL or -1 */
1922         for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
1923         /* make sure the end of the list is NULL */
1924         mods[i] = NULL;
1925
1926         ret = ldap_add_ext_s(ads->ldap.ld, utf8_dn, (LDAPMod**)mods, NULL, NULL);
1927         ads_print_error(ret, ads->ldap.ld);
1928         TALLOC_FREE(utf8_dn);
1929         return ADS_ERROR(ret);
1930 }
1931
1932 /**
1933  * Delete a DistinguishedName
1934  * @param ads connection to ads server
1935  * @param new_dn DistinguishedName to delete
1936  * @return status of delete
1937  **/
1938 ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn)
1939 {
1940         int ret;
1941         char *utf8_dn = NULL;
1942         size_t converted_size;
1943         if (!push_utf8_talloc(talloc_tos(), &utf8_dn, del_dn, &converted_size)) {
1944                 DEBUG(1, ("ads_del_dn: push_utf8_talloc failed!\n"));
1945                 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1946         }
1947
1948         DBG_INFO("AD LDAP: Deleting %s\n", del_dn);
1949
1950         ret = ldap_delete_s(ads->ldap.ld, utf8_dn);
1951         ads_print_error(ret, ads->ldap.ld);
1952         TALLOC_FREE(utf8_dn);
1953         return ADS_ERROR(ret);
1954 }
1955
1956 /**
1957  * Build an org unit string
1958  *  if org unit is Computers or blank then assume a container, otherwise
1959  *  assume a / separated list of organisational units.
1960  * jmcd: '\' is now used for escapes so certain chars can be in the ou (e.g. #)
1961  * @param ads connection to ads server
1962  * @param org_unit Organizational unit
1963  * @return org unit string - caller must free
1964  **/
1965 char *ads_ou_string(ADS_STRUCT *ads, const char *org_unit)
1966 {
1967         ADS_STATUS status;
1968         char *ret = NULL;
1969         char *dn = NULL;
1970
1971         if (!org_unit || !*org_unit) {
1972
1973                 ret = ads_default_ou_string(ads, DS_GUID_COMPUTERS_CONTAINER);
1974
1975                 /* samba4 might not yet respond to a wellknownobject-query */
1976                 return ret ? ret : SMB_STRDUP("cn=Computers");
1977         }
1978
1979         if (strequal(org_unit, "Computers")) {
1980                 return SMB_STRDUP("cn=Computers");
1981         }
1982
1983         /* jmcd: removed "\\" from the separation chars, because it is
1984            needed as an escape for chars like '#' which are valid in an
1985            OU name */
1986         status = ads_build_path(org_unit, "/", "ou=", 1, &dn);
1987         if (!ADS_ERR_OK(status)) {
1988                 return NULL;
1989         }
1990
1991         return dn;
1992 }
1993
1994 /**
1995  * Get a org unit string for a well-known GUID
1996  * @param ads connection to ads server
1997  * @param wknguid Well known GUID
1998  * @return org unit string - caller must free
1999  **/
2000 char *ads_default_ou_string(ADS_STRUCT *ads, const char *wknguid)
2001 {
2002         ADS_STATUS status;
2003         LDAPMessage *res = NULL;
2004         char *base, *wkn_dn = NULL, *ret = NULL, **wkn_dn_exp = NULL,
2005                 **bind_dn_exp = NULL;
2006         const char *attrs[] = {"distinguishedName", NULL};
2007         int new_ln, wkn_ln, bind_ln, i;
2008
2009         if (wknguid == NULL) {
2010                 return NULL;
2011         }
2012
2013         if (asprintf(&base, "<WKGUID=%s,%s>", wknguid, ads->config.bind_path ) == -1) {
2014                 DEBUG(1, ("asprintf failed!\n"));
2015                 return NULL;
2016         }
2017
2018         status = ads_search_dn(ads, &res, base, attrs);
2019         if (!ADS_ERR_OK(status)) {
2020                 DEBUG(1,("Failed while searching for: %s\n", base));
2021                 goto out;
2022         }
2023
2024         if (ads_count_replies(ads, res) != 1) {
2025                 goto out;
2026         }
2027
2028         /* substitute the bind-path from the well-known-guid-search result */
2029         wkn_dn = ads_get_dn(ads, talloc_tos(), res);
2030         if (!wkn_dn) {
2031                 goto out;
2032         }
2033
2034         wkn_dn_exp = ldap_explode_dn(wkn_dn, 0);
2035         if (!wkn_dn_exp) {
2036                 goto out;
2037         }
2038
2039         bind_dn_exp = ldap_explode_dn(ads->config.bind_path, 0);
2040         if (!bind_dn_exp) {
2041                 goto out;
2042         }
2043
2044         for (wkn_ln=0; wkn_dn_exp[wkn_ln]; wkn_ln++)
2045                 ;
2046         for (bind_ln=0; bind_dn_exp[bind_ln]; bind_ln++)
2047                 ;
2048
2049         new_ln = wkn_ln - bind_ln;
2050
2051         ret = SMB_STRDUP(wkn_dn_exp[0]);
2052         if (!ret) {
2053                 goto out;
2054         }
2055
2056         for (i=1; i < new_ln; i++) {
2057                 char *s = NULL;
2058
2059                 if (asprintf(&s, "%s,%s", ret, wkn_dn_exp[i]) == -1) {
2060                         SAFE_FREE(ret);
2061                         goto out;
2062                 }
2063
2064                 SAFE_FREE(ret);
2065                 ret = SMB_STRDUP(s);
2066                 free(s);
2067                 if (!ret) {
2068                         goto out;
2069                 }
2070         }
2071
2072  out:
2073         SAFE_FREE(base);
2074         ads_msgfree(ads, res);
2075         TALLOC_FREE(wkn_dn);
2076         if (wkn_dn_exp) {
2077                 ldap_value_free(wkn_dn_exp);
2078         }
2079         if (bind_dn_exp) {
2080                 ldap_value_free(bind_dn_exp);
2081         }
2082
2083         return ret;
2084 }
2085
2086 /**
2087  * Adds (appends) an item to an attribute array, rather then
2088  * replacing the whole list
2089  * @param ctx An initialized TALLOC_CTX
2090  * @param mods An initialized ADS_MODLIST
2091  * @param name name of the ldap attribute to append to
2092  * @param vals an array of values to add
2093  * @return status of addition
2094  **/
2095
2096 ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
2097                                 const char *name, const char **vals)
2098 {
2099         return ads_modlist_add(ctx, mods, LDAP_MOD_ADD, name,
2100                                (const void *) vals);
2101 }
2102
2103 /**
2104  * Determines the an account's current KVNO via an LDAP lookup
2105  * @param ads An initialized ADS_STRUCT
2106  * @param account_name the NT samaccountname.
2107  * @return the kvno for the account, or -1 in case of a failure.
2108  **/
2109
2110 uint32_t ads_get_kvno(ADS_STRUCT *ads, const char *account_name)
2111 {
2112         LDAPMessage *res = NULL;
2113         uint32_t kvno = (uint32_t)-1;      /* -1 indicates a failure */
2114         char *filter;
2115         const char *attrs[] = {"msDS-KeyVersionNumber", NULL};
2116         char *dn_string = NULL;
2117         ADS_STATUS ret;
2118
2119         DEBUG(5,("ads_get_kvno: Searching for account %s\n", account_name));
2120         if (asprintf(&filter, "(samAccountName=%s)", account_name) == -1) {
2121                 return kvno;
2122         }
2123         ret = ads_search(ads, &res, filter, attrs);
2124         SAFE_FREE(filter);
2125         if (!ADS_ERR_OK(ret) || (ads_count_replies(ads, res) != 1)) {
2126                 DEBUG(1,("ads_get_kvno: Account for %s not found.\n", account_name));
2127                 ads_msgfree(ads, res);
2128                 return kvno;
2129         }
2130
2131         dn_string = ads_get_dn(ads, talloc_tos(), res);
2132         if (!dn_string) {
2133                 DEBUG(0,("ads_get_kvno: out of memory.\n"));
2134                 ads_msgfree(ads, res);
2135                 return kvno;
2136         }
2137         DEBUG(5,("ads_get_kvno: Using: %s\n", dn_string));
2138         TALLOC_FREE(dn_string);
2139
2140         /* ---------------------------------------------------------
2141          * 0 is returned as a default KVNO from this point on...
2142          * This is done because Windows 2000 does not support key
2143          * version numbers.  Chances are that a failure in the next
2144          * step is simply due to Windows 2000 being used for a
2145          * domain controller. */
2146         kvno = 0;
2147
2148         if (!ads_pull_uint32(ads, res, "msDS-KeyVersionNumber", &kvno)) {
2149                 DEBUG(3,("ads_get_kvno: Error Determining KVNO!\n"));
2150                 DEBUG(3,("ads_get_kvno: Windows 2000 does not support KVNO's, so this may be normal.\n"));
2151                 ads_msgfree(ads, res);
2152                 return kvno;
2153         }
2154
2155         /* Success */
2156         DEBUG(5,("ads_get_kvno: Looked Up KVNO of: %d\n", kvno));
2157         ads_msgfree(ads, res);
2158         return kvno;
2159 }
2160
2161 /**
2162  * Determines the computer account's current KVNO via an LDAP lookup
2163  * @param ads An initialized ADS_STRUCT
2164  * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account.
2165  * @return the kvno for the computer account, or -1 in case of a failure.
2166  **/
2167
2168 uint32_t ads_get_machine_kvno(ADS_STRUCT *ads, const char *machine_name)
2169 {
2170         char *computer_account = NULL;
2171         uint32_t kvno = -1;
2172
2173         if (asprintf(&computer_account, "%s$", machine_name) < 0) {
2174                 return kvno;
2175         }
2176
2177         kvno = ads_get_kvno(ads, computer_account);
2178         free(computer_account);
2179
2180         return kvno;
2181 }
2182
2183 /**
2184  * This clears out all registered spn's for a given hostname
2185  * @param ads An initilaized ADS_STRUCT
2186  * @param machine_name the NetBIOS name of the computer.
2187  * @return 0 upon success, non-zero otherwise.
2188  **/
2189
2190 ADS_STATUS ads_clear_service_principal_names(ADS_STRUCT *ads, const char *machine_name)
2191 {
2192         TALLOC_CTX *ctx;
2193         LDAPMessage *res = NULL;
2194         ADS_MODLIST mods;
2195         const char *servicePrincipalName[1] = {NULL};
2196         ADS_STATUS ret;
2197         char *dn_string = NULL;
2198
2199         ret = ads_find_machine_acct(ads, &res, machine_name);
2200         if (!ADS_ERR_OK(ret)) {
2201                 DEBUG(5,("ads_clear_service_principal_names: WARNING: Host Account for %s not found... skipping operation.\n", machine_name));
2202                 DEBUG(5,("ads_clear_service_principal_names: WARNING: Service Principals for %s have NOT been cleared.\n", machine_name));
2203                 ads_msgfree(ads, res);
2204                 return ret;
2205         }
2206
2207         DEBUG(5,("ads_clear_service_principal_names: Host account for %s found\n", machine_name));
2208         ctx = talloc_init("ads_clear_service_principal_names");
2209         if (!ctx) {
2210                 ads_msgfree(ads, res);
2211                 return ADS_ERROR(LDAP_NO_MEMORY);
2212         }
2213
2214         if (!(mods = ads_init_mods(ctx))) {
2215                 talloc_destroy(ctx);
2216                 ads_msgfree(ads, res);
2217                 return ADS_ERROR(LDAP_NO_MEMORY);
2218         }
2219         ret = ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
2220         if (!ADS_ERR_OK(ret)) {
2221                 DEBUG(1,("ads_clear_service_principal_names: Error creating strlist.\n"));
2222                 ads_msgfree(ads, res);
2223                 talloc_destroy(ctx);
2224                 return ret;
2225         }
2226         dn_string = ads_get_dn(ads, talloc_tos(), res);
2227         if (!dn_string) {
2228                 talloc_destroy(ctx);
2229                 ads_msgfree(ads, res);
2230                 return ADS_ERROR(LDAP_NO_MEMORY);
2231         }
2232         ret = ads_gen_mod(ads, dn_string, mods);
2233         TALLOC_FREE(dn_string);
2234         if (!ADS_ERR_OK(ret)) {
2235                 DEBUG(1,("ads_clear_service_principal_names: Error: Updating Service Principals for machine %s in LDAP\n",
2236                         machine_name));
2237                 ads_msgfree(ads, res);
2238                 talloc_destroy(ctx);
2239                 return ret;
2240         }
2241
2242         ads_msgfree(ads, res);
2243         talloc_destroy(ctx);
2244         return ret;
2245 }
2246
2247 /**
2248  * @brief Search for an element in a string array.
2249  *
2250  * @param[in]  el_array  The string array to search.
2251  *
2252  * @param[in]  num_el    The number of elements in the string array.
2253  *
2254  * @param[in]  el        The string to search.
2255  *
2256  * @return               True if found, false if not.
2257  */
2258 bool ads_element_in_array(const char **el_array, size_t num_el, const char *el)
2259 {
2260         size_t i;
2261
2262         if (el_array == NULL || num_el == 0 || el == NULL) {
2263                 return false;
2264         }
2265
2266         for (i = 0; i < num_el && el_array[i] != NULL; i++) {
2267                 int cmp;
2268
2269                 cmp = strcasecmp_m(el_array[i], el);
2270                 if (cmp == 0) {
2271                         return true;
2272                 }
2273         }
2274
2275         return false;
2276 }
2277
2278 /**
2279  * @brief This gets the service principal names of an existing computer account.
2280  *
2281  * @param[in]  mem_ctx      The memory context to use to allocate the spn array.
2282  *
2283  * @param[in]  ads          The ADS context to use.
2284  *
2285  * @param[in]  machine_name The NetBIOS name of the computer, which is used to
2286  *                          identify the computer account.
2287  *
2288  * @param[in]  spn_array    A pointer to store the array for SPNs.
2289  *
2290  * @param[in]  num_spns     The number of principals stored in the array.
2291  *
2292  * @return                  0 on success, or a ADS error if a failure occurred.
2293  */
2294 ADS_STATUS ads_get_service_principal_names(TALLOC_CTX *mem_ctx,
2295                                            ADS_STRUCT *ads,
2296                                            const char *machine_name,
2297                                            char ***spn_array,
2298                                            size_t *num_spns)
2299 {
2300         ADS_STATUS status;
2301         LDAPMessage *res = NULL;
2302         int count;
2303
2304         status = ads_find_machine_acct(ads,
2305                                        &res,
2306                                        machine_name);
2307         if (!ADS_ERR_OK(status)) {
2308                 DEBUG(1,("Host Account for %s not found... skipping operation.\n",
2309                          machine_name));
2310                 return status;
2311         }
2312
2313         count = ads_count_replies(ads, res);
2314         if (count != 1) {
2315                 status = ADS_ERROR(LDAP_NO_SUCH_OBJECT);
2316                 goto done;
2317         }
2318
2319         *spn_array = ads_pull_strings(ads,
2320                                       mem_ctx,
2321                                       res,
2322                                       "servicePrincipalName",
2323                                       num_spns);
2324         if (*spn_array == NULL) {
2325                 DEBUG(1, ("Host account for %s does not have service principal "
2326                           "names.\n",
2327                           machine_name));
2328                 status = ADS_ERROR(LDAP_NO_SUCH_OBJECT);
2329                 goto done;
2330         }
2331
2332 done:
2333         ads_msgfree(ads, res);
2334
2335         return status;
2336 }
2337
2338 /**
2339  * This adds a service principal name to an existing computer account
2340  * (found by hostname) in AD.
2341  * @param ads An initialized ADS_STRUCT
2342  * @param machine_name the NetBIOS name of the computer, which is used to identify the computer account.
2343  * @param spns An array or strings for the service principals to add,
2344  *        i.e. 'cifs/machine_name', 'http/machine.full.domain.com' etc.
2345  * @return 0 upon success, or non-zero if a failure occurs
2346  **/
2347
2348 ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads,
2349                                            const char *machine_name,
2350                                            const char **spns)
2351 {
2352         ADS_STATUS ret;
2353         TALLOC_CTX *ctx;
2354         LDAPMessage *res = NULL;
2355         ADS_MODLIST mods;
2356         char *dn_string = NULL;
2357         const char **servicePrincipalName = spns;
2358
2359         ret = ads_find_machine_acct(ads, &res, machine_name);
2360         if (!ADS_ERR_OK(ret)) {
2361                 DEBUG(1,("ads_add_service_principal_name: WARNING: Host Account for %s not found... skipping operation.\n",
2362                         machine_name));
2363                 DEBUG(1,("ads_add_service_principal_name: WARNING: Service Principals have NOT been added.\n"));
2364                 ads_msgfree(ads, res);
2365                 return ret;
2366         }
2367
2368         DEBUG(1,("ads_add_service_principal_name: Host account for %s found\n", machine_name));
2369         if (!(ctx = talloc_init("ads_add_service_principal_name"))) {
2370                 ads_msgfree(ads, res);
2371                 return ADS_ERROR(LDAP_NO_MEMORY);
2372         }
2373
2374         DEBUG(5,("ads_add_service_principal_name: INFO: "
2375                 "Adding %s to host %s\n",
2376                 spns[0] ? "N/A" : spns[0], machine_name));
2377
2378
2379         DEBUG(5,("ads_add_service_principal_name: INFO: "
2380                 "Adding %s to host %s\n",
2381                 spns[1] ? "N/A" : spns[1], machine_name));
2382
2383         if ( (mods = ads_init_mods(ctx)) == NULL ) {
2384                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2385                 goto out;
2386         }
2387
2388         ret = ads_add_strlist(ctx,
2389                               &mods,
2390                               "servicePrincipalName",
2391                               servicePrincipalName);
2392         if (!ADS_ERR_OK(ret)) {
2393                 DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n"));
2394                 goto out;
2395         }
2396
2397         if ( (dn_string = ads_get_dn(ads, ctx, res)) == NULL ) {
2398                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2399                 goto out;
2400         }
2401
2402         ret = ads_gen_mod(ads, dn_string, mods);
2403         if (!ADS_ERR_OK(ret)) {
2404                 DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n"));
2405                 goto out;
2406         }
2407
2408  out:
2409         TALLOC_FREE( ctx );
2410         ads_msgfree(ads, res);
2411         return ret;
2412 }
2413
2414 static uint32_t ads_get_acct_ctrl(ADS_STRUCT *ads,
2415                                   LDAPMessage *msg)
2416 {
2417         uint32_t acct_ctrl = 0;
2418         bool ok;
2419
2420         ok = ads_pull_uint32(ads, msg, "userAccountControl", &acct_ctrl);
2421         if (!ok) {
2422                 return 0;
2423         }
2424
2425         return acct_ctrl;
2426 }
2427
2428 static ADS_STATUS ads_change_machine_acct(ADS_STRUCT *ads,
2429                                           LDAPMessage *msg,
2430                                           const struct berval *machine_pw_val)
2431 {
2432         ADS_MODLIST mods;
2433         ADS_STATUS ret;
2434         TALLOC_CTX *frame = talloc_stackframe();
2435         uint32_t acct_control;
2436         char *control_str = NULL;
2437         const char *attrs[] = {
2438                 "objectSid",
2439                 NULL
2440         };
2441         LDAPMessage *res = NULL;
2442         char *dn = NULL;
2443
2444         dn = ads_get_dn(ads, frame, msg);
2445         if (dn == NULL) {
2446                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2447                 goto done;
2448         }
2449
2450         acct_control = ads_get_acct_ctrl(ads, msg);
2451         if (acct_control == 0) {
2452                 ret = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
2453                 goto done;
2454         }
2455
2456         /*
2457          * Changing the password, disables the account. So we need to change the
2458          * userAccountControl flags to enable it again.
2459          */
2460         mods = ads_init_mods(frame);
2461         if (mods == NULL) {
2462                 ret = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
2463                 goto done;
2464         }
2465
2466         ads_mod_ber(frame, &mods, "unicodePwd", machine_pw_val);
2467
2468         ret = ads_gen_mod(ads, dn, mods);
2469         if (!ADS_ERR_OK(ret)) {
2470                 goto done;
2471         }
2472         TALLOC_FREE(mods);
2473
2474         /*
2475          * To activate the account, we need to disable and enable it.
2476          */
2477         acct_control |= UF_ACCOUNTDISABLE;
2478
2479         control_str = talloc_asprintf(frame, "%u", acct_control);
2480         if (control_str == NULL) {
2481                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2482                 goto done;
2483         }
2484
2485         mods = ads_init_mods(frame);
2486         if (mods == NULL) {
2487                 ret = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
2488                 goto done;
2489         }
2490
2491         ads_mod_str(frame, &mods, "userAccountControl", control_str);
2492
2493         ret = ads_gen_mod(ads, dn, mods);
2494         if (!ADS_ERR_OK(ret)) {
2495                 goto done;
2496         }
2497         TALLOC_FREE(mods);
2498         TALLOC_FREE(control_str);
2499
2500         /*
2501          * Enable the account again.
2502          */
2503         acct_control &= ~UF_ACCOUNTDISABLE;
2504
2505         control_str = talloc_asprintf(frame, "%u", acct_control);
2506         if (control_str == NULL) {
2507                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2508                 goto done;
2509         }
2510
2511         mods = ads_init_mods(frame);
2512         if (mods == NULL) {
2513                 ret = ADS_ERROR_LDAP(LDAP_NO_MEMORY);
2514                 goto done;
2515         }
2516
2517         ads_mod_str(frame, &mods, "userAccountControl", control_str);
2518
2519         ret = ads_gen_mod(ads, dn, mods);
2520         if (!ADS_ERR_OK(ret)) {
2521                 goto done;
2522         }
2523         TALLOC_FREE(mods);
2524         TALLOC_FREE(control_str);
2525
2526         ret = ads_search_dn(ads, &res, dn, attrs);
2527         ads_msgfree(ads, res);
2528
2529 done:
2530         talloc_free(frame);
2531
2532         return ret;
2533 }
2534
2535 /**
2536  * adds a machine account to the ADS server
2537  * @param ads An initialized ADS_STRUCT
2538  * @param machine_name - the NetBIOS machine name of this account.
2539  * @param account_type A number indicating the type of account to create
2540  * @param org_unit The LDAP path in which to place this account
2541  * @return 0 upon success, or non-zero otherwise
2542 **/
2543
2544 ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
2545                                    const char *machine_name,
2546                                    const char *machine_password,
2547                                    const char *org_unit,
2548                                    uint32_t etype_list,
2549                                    const char *dns_domain_name)
2550 {
2551         ADS_STATUS ret;
2552         char *samAccountName = NULL;
2553         char *controlstr = NULL;
2554         TALLOC_CTX *ctx = NULL;
2555         ADS_MODLIST mods;
2556         char *machine_escaped = NULL;
2557         char *dns_hostname = NULL;
2558         char *new_dn = NULL;
2559         char *utf8_pw = NULL;
2560         size_t utf8_pw_len = 0;
2561         char *utf16_pw = NULL;
2562         size_t utf16_pw_len = 0;
2563         struct berval machine_pw_val;
2564         bool ok;
2565         const char **spn_array = NULL;
2566         size_t num_spns = 0;
2567         const char *spn_prefix[] = {
2568                 "HOST",
2569                 "RestrictedKrbHost",
2570         };
2571         size_t i;
2572         LDAPMessage *res = NULL;
2573         uint32_t acct_control = UF_WORKSTATION_TRUST_ACCOUNT;
2574
2575         ctx = talloc_init("ads_add_machine_acct");
2576         if (ctx == NULL) {
2577                 return ADS_ERROR(LDAP_NO_MEMORY);
2578         }
2579
2580         machine_escaped = escape_rdn_val_string_alloc(machine_name);
2581         if (machine_escaped == NULL) {
2582                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2583                 goto done;
2584         }
2585
2586         utf8_pw = talloc_asprintf(ctx, "\"%s\"", machine_password);
2587         if (utf8_pw == NULL) {
2588                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2589                 goto done;
2590         }
2591         utf8_pw_len = strlen(utf8_pw);
2592
2593         ok = convert_string_talloc(ctx,
2594                                    CH_UTF8, CH_UTF16MUNGED,
2595                                    utf8_pw, utf8_pw_len,
2596                                    (void *)&utf16_pw, &utf16_pw_len);
2597         if (!ok) {
2598                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2599                 goto done;
2600         }
2601
2602         machine_pw_val = (struct berval) {
2603                 .bv_val = utf16_pw,
2604                 .bv_len = utf16_pw_len,
2605         };
2606
2607         /* Check if the machine account already exists. */
2608         ret = ads_find_machine_acct(ads, &res, machine_escaped);
2609         if (ADS_ERR_OK(ret)) {
2610                 /* Change the machine account password */
2611                 ret = ads_change_machine_acct(ads, res, &machine_pw_val);
2612                 ads_msgfree(ads, res);
2613
2614                 goto done;
2615         }
2616         ads_msgfree(ads, res);
2617
2618         new_dn = talloc_asprintf(ctx, "cn=%s,%s", machine_escaped, org_unit);
2619         if (new_dn == NULL) {
2620                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2621                 goto done;
2622         }
2623
2624         /* Create machine account */
2625
2626         samAccountName = talloc_asprintf(ctx, "%s$", machine_name);
2627         if (samAccountName == NULL) {
2628                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2629                 goto done;
2630         }
2631
2632         dns_hostname = talloc_asprintf(ctx,
2633                                        "%s.%s",
2634                                        machine_name,
2635                                        dns_domain_name);
2636         if (dns_hostname == NULL) {
2637                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2638                 goto done;
2639         }
2640
2641         /* Add dns_hostname SPNs */
2642         for (i = 0; i < ARRAY_SIZE(spn_prefix); i++) {
2643                 char *spn = talloc_asprintf(ctx,
2644                                             "%s/%s",
2645                                             spn_prefix[i],
2646                                             dns_hostname);
2647                 if (spn == NULL) {
2648                         ret = ADS_ERROR(LDAP_NO_MEMORY);
2649                         goto done;
2650                 }
2651
2652                 ok = add_string_to_array(spn_array,
2653                                          spn,
2654                                          &spn_array,
2655                                          &num_spns);
2656                 if (!ok) {
2657                         ret = ADS_ERROR(LDAP_NO_MEMORY);
2658                         goto done;
2659                 }
2660         }
2661
2662         /* Add machine_name SPNs */
2663         for (i = 0; i < ARRAY_SIZE(spn_prefix); i++) {
2664                 char *spn = talloc_asprintf(ctx,
2665                                             "%s/%s",
2666                                             spn_prefix[i],
2667                                             machine_name);
2668                 if (spn == NULL) {
2669                         ret = ADS_ERROR(LDAP_NO_MEMORY);
2670                         goto done;
2671                 }
2672
2673                 ok = add_string_to_array(spn_array,
2674                                          spn,
2675                                          &spn_array,
2676                                          &num_spns);
2677                 if (!ok) {
2678                         ret = ADS_ERROR(LDAP_NO_MEMORY);
2679                         goto done;
2680                 }
2681         }
2682
2683         /* Make sure to NULL terminate the array */
2684         spn_array = talloc_realloc(ctx, spn_array, const char *, num_spns + 1);
2685         if (spn_array == NULL) {
2686                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2687                 goto done;
2688         }
2689         spn_array[num_spns] = NULL;
2690
2691         controlstr = talloc_asprintf(ctx, "%u", acct_control);
2692         if (controlstr == NULL) {
2693                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2694                 goto done;
2695         }
2696
2697         mods = ads_init_mods(ctx);
2698         if (mods == NULL) {
2699                 ret = ADS_ERROR(LDAP_NO_MEMORY);
2700                 goto done;
2701         }
2702
2703         ads_mod_str(ctx, &mods, "objectClass", "Computer");
2704         ads_mod_str(ctx, &mods, "SamAccountName", samAccountName);
2705         ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
2706         ads_mod_str(ctx, &mods, "DnsHostName", dns_hostname);
2707         ads_mod_strlist(ctx, &mods, "ServicePrincipalName", spn_array);
2708         ads_mod_ber(ctx, &mods, "unicodePwd", &machine_pw_val);
2709
2710         ret = ads_gen_add(ads, new_dn, mods);
2711
2712 done:
2713         SAFE_FREE(machine_escaped);
2714         talloc_destroy(ctx);
2715
2716         return ret;
2717 }
2718
2719 /**
2720  * move a machine account to another OU on the ADS server
2721  * @param ads - An initialized ADS_STRUCT
2722  * @param machine_name - the NetBIOS machine name of this account.
2723  * @param org_unit - The LDAP path in which to place this account
2724  * @param moved - whether we moved the machine account (optional)
2725  * @return 0 upon success, or non-zero otherwise
2726 **/
2727
2728 ADS_STATUS ads_move_machine_acct(ADS_STRUCT *ads, const char *machine_name,
2729                                  const char *org_unit, bool *moved)
2730 {
2731         ADS_STATUS rc;
2732         int ldap_status;
2733         LDAPMessage *res = NULL;
2734         char *filter = NULL;
2735         char *computer_dn = NULL;
2736         char *parent_dn;
2737         char *computer_rdn = NULL;
2738         bool need_move = False;
2739
2740         if (asprintf(&filter, "(samAccountName=%s$)", machine_name) == -1) {
2741                 rc = ADS_ERROR(LDAP_NO_MEMORY);
2742                 goto done;
2743         }
2744
2745         /* Find pre-existing machine */
2746         rc = ads_search(ads, &res, filter, NULL);
2747         if (!ADS_ERR_OK(rc)) {
2748                 goto done;
2749         }
2750
2751         computer_dn = ads_get_dn(ads, talloc_tos(), res);
2752         if (!computer_dn) {
2753                 rc = ADS_ERROR(LDAP_NO_MEMORY);
2754                 goto done;
2755         }
2756
2757         parent_dn = ads_parent_dn(computer_dn);
2758         if (strequal(parent_dn, org_unit)) {
2759                 goto done;
2760         }
2761
2762         need_move = True;
2763
2764         if (asprintf(&computer_rdn, "CN=%s", machine_name) == -1) {
2765                 rc = ADS_ERROR(LDAP_NO_MEMORY);
2766                 goto done;
2767         }
2768
2769         ldap_status = ldap_rename_s(ads->ldap.ld, computer_dn, computer_rdn,
2770                                     org_unit, 1, NULL, NULL);
2771         rc = ADS_ERROR(ldap_status);
2772
2773 done:
2774         ads_msgfree(ads, res);
2775         SAFE_FREE(filter);
2776         TALLOC_FREE(computer_dn);
2777         SAFE_FREE(computer_rdn);
2778
2779         if (!ADS_ERR_OK(rc)) {
2780                 need_move = False;
2781         }
2782
2783         if (moved) {
2784                 *moved = need_move;
2785         }
2786
2787         return rc;
2788 }
2789
2790 /*
2791   dump a binary result from ldap
2792 */
2793 static void dump_binary(ADS_STRUCT *ads, const char *field, struct berval **values)
2794 {
2795         size_t i;
2796         for (i=0; values[i]; i++) {
2797                 ber_len_t j;
2798                 printf("%s: ", field);
2799                 for (j=0; j<values[i]->bv_len; j++) {
2800                         printf("%02X", (unsigned char)values[i]->bv_val[j]);
2801                 }
2802                 printf("\n");
2803         }
2804 }
2805
2806 static void dump_guid(ADS_STRUCT *ads, const char *field, struct berval **values)
2807 {
2808         int i;
2809         for (i=0; values[i]; i++) {
2810                 NTSTATUS status;
2811                 DATA_BLOB in = data_blob_const(values[i]->bv_val, values[i]->bv_len);
2812                 struct GUID guid;
2813
2814                 status = GUID_from_ndr_blob(&in, &guid);
2815                 if (NT_STATUS_IS_OK(status)) {
2816                         printf("%s: %s\n", field, GUID_string(talloc_tos(), &guid));
2817                 } else {
2818                         printf("%s: INVALID GUID\n", field);
2819                 }
2820         }
2821 }
2822
2823 /*
2824   dump a sid result from ldap
2825 */
2826 static void dump_sid(ADS_STRUCT *ads, const char *field, struct berval **values)
2827 {
2828         int i;
2829         for (i=0; values[i]; i++) {
2830                 ssize_t ret;
2831                 struct dom_sid sid;
2832                 struct dom_sid_buf tmp;
2833                 ret = sid_parse((const uint8_t *)values[i]->bv_val,
2834                                 values[i]->bv_len, &sid);
2835                 if (ret == -1) {
2836                         return;
2837                 }
2838                 printf("%s: %s\n", field, dom_sid_str_buf(&sid, &tmp));
2839         }
2840 }
2841
2842 /*
2843   dump ntSecurityDescriptor
2844 */
2845 static void dump_sd(ADS_STRUCT *ads, const char *filed, struct berval **values)
2846 {
2847         TALLOC_CTX *frame = talloc_stackframe();
2848         struct security_descriptor *psd;
2849         NTSTATUS status;
2850
2851         status = unmarshall_sec_desc(talloc_tos(), (uint8_t *)values[0]->bv_val,
2852                                      values[0]->bv_len, &psd);
2853         if (!NT_STATUS_IS_OK(status)) {
2854                 DEBUG(0, ("unmarshall_sec_desc failed: %s\n",
2855                           nt_errstr(status)));
2856                 TALLOC_FREE(frame);
2857                 return;
2858         }
2859
2860         if (psd) {
2861                 ads_disp_sd(ads, talloc_tos(), psd);
2862         }
2863
2864         TALLOC_FREE(frame);
2865 }
2866
2867 /*
2868   dump a string result from ldap
2869 */
2870 static void dump_string(const char *field, char **values)
2871 {
2872         int i;
2873         for (i=0; values[i]; i++) {
2874                 printf("%s: %s\n", field, values[i]);
2875         }
2876 }
2877
2878 /*
2879   dump a field from LDAP on stdout
2880   used for debugging
2881 */
2882
2883 static bool ads_dump_field(ADS_STRUCT *ads, char *field, void **values, void *data_area)
2884 {
2885         const struct {
2886                 const char *name;
2887                 bool string;
2888                 void (*handler)(ADS_STRUCT *, const char *, struct berval **);
2889         } handlers[] = {
2890                 {"objectGUID", False, dump_guid},
2891                 {"netbootGUID", False, dump_guid},
2892                 {"nTSecurityDescriptor", False, dump_sd},
2893                 {"dnsRecord", False, dump_binary},
2894                 {"objectSid", False, dump_sid},
2895                 {"tokenGroups", False, dump_sid},
2896                 {"tokenGroupsNoGCAcceptable", False, dump_sid},
2897                 {"tokengroupsGlobalandUniversal", False, dump_sid},
2898                 {"mS-DS-CreatorSID", False, dump_sid},
2899                 {"msExchMailboxGuid", False, dump_guid},
2900                 {NULL, True, NULL}
2901         };
2902         int i;
2903
2904         if (!field) { /* must be end of an entry */
2905                 printf("\n");
2906                 return False;
2907         }
2908
2909         for (i=0; handlers[i].name; i++) {
2910                 if (strcasecmp_m(handlers[i].name, field) == 0) {
2911                         if (!values) /* first time, indicate string or not */
2912                                 return handlers[i].string;
2913                         handlers[i].handler(ads, field, (struct berval **) values);
2914                         break;
2915                 }
2916         }
2917         if (!handlers[i].name) {
2918                 if (!values) /* first time, indicate string conversion */
2919                         return True;
2920                 dump_string(field, (char **)values);
2921         }
2922         return False;
2923 }
2924
2925 /**
2926  * Dump a result from LDAP on stdout
2927  *  used for debugging
2928  * @param ads connection to ads server
2929  * @param res Results to dump
2930  **/
2931
2932  void ads_dump(ADS_STRUCT *ads, LDAPMessage *res)
2933 {
2934         ads_process_results(ads, res, ads_dump_field, NULL);
2935 }
2936
2937 /**
2938  * Walk through results, calling a function for each entry found.
2939  *  The function receives a field name, a berval * array of values,
2940  *  and a data area passed through from the start.  The function is
2941  *  called once with null for field and values at the end of each
2942  *  entry.
2943  * @param ads connection to ads server
2944  * @param res Results to process
2945  * @param fn Function for processing each result
2946  * @param data_area user-defined area to pass to function
2947  **/
2948  void ads_process_results(ADS_STRUCT *ads, LDAPMessage *res,
2949                           bool (*fn)(ADS_STRUCT *, char *, void **, void *),
2950                           void *data_area)
2951 {
2952         LDAPMessage *msg;
2953         TALLOC_CTX *ctx;
2954         size_t converted_size;
2955
2956         if (!(ctx = talloc_init("ads_process_results")))
2957                 return;
2958
2959         for (msg = ads_first_entry(ads, res); msg;
2960              msg = ads_next_entry(ads, msg)) {
2961                 char *utf8_field;
2962                 BerElement *b;
2963
2964                 for (utf8_field=ldap_first_attribute(ads->ldap.ld,
2965                                                      (LDAPMessage *)msg,&b);
2966                      utf8_field;
2967                      utf8_field=ldap_next_attribute(ads->ldap.ld,
2968                                                     (LDAPMessage *)msg,b)) {
2969                         struct berval **ber_vals;
2970                         char **str_vals;
2971                         char **utf8_vals;
2972                         char *field;
2973                         bool string;
2974
2975                         if (!pull_utf8_talloc(ctx, &field, utf8_field,
2976                                               &converted_size))
2977                         {
2978                                 DEBUG(0,("ads_process_results: "
2979                                          "pull_utf8_talloc failed: %s\n",
2980                                          strerror(errno)));
2981                         }
2982
2983                         string = fn(ads, field, NULL, data_area);
2984
2985                         if (string) {
2986                                 const char **p;
2987
2988                                 utf8_vals = ldap_get_values(ads->ldap.ld,
2989                                                  (LDAPMessage *)msg, field);
2990                                 p = discard_const_p(const char *, utf8_vals);
2991                                 str_vals = ads_pull_strvals(ctx, p);
2992                                 fn(ads, field, (void **) str_vals, data_area);
2993                                 ldap_value_free(utf8_vals);
2994                         } else {
2995                                 ber_vals = ldap_get_values_len(ads->ldap.ld,
2996                                                  (LDAPMessage *)msg, field);
2997                                 fn(ads, field, (void **) ber_vals, data_area);
2998
2999                                 ldap_value_free_len(ber_vals);
3000                         }
3001                         ldap_memfree(utf8_field);
3002                 }
3003                 ber_free(b, 0);
3004                 talloc_free_children(ctx);
3005                 fn(ads, NULL, NULL, data_area); /* completed an entry */
3006
3007         }
3008         talloc_destroy(ctx);
3009 }
3010
3011 /**
3012  * count how many replies are in a LDAPMessage
3013  * @param ads connection to ads server
3014  * @param res Results to count
3015  * @return number of replies
3016  **/
3017 int ads_count_replies(ADS_STRUCT *ads, void *res)
3018 {
3019         return ldap_count_entries(ads->ldap.ld, (LDAPMessage *)res);
3020 }
3021
3022 /**
3023  * pull the first entry from a ADS result
3024  * @param ads connection to ads server
3025  * @param res Results of search
3026  * @return first entry from result
3027  **/
3028  LDAPMessage *ads_first_entry(ADS_STRUCT *ads, LDAPMessage *res)
3029 {
3030         return ldap_first_entry(ads->ldap.ld, res);
3031 }
3032
3033 /**
3034  * pull the next entry from a ADS result
3035  * @param ads connection to ads server
3036  * @param res Results of search
3037  * @return next entry from result
3038  **/
3039  LDAPMessage *ads_next_entry(ADS_STRUCT *ads, LDAPMessage *res)
3040 {
3041         return ldap_next_entry(ads->ldap.ld, res);
3042 }
3043
3044 /**
3045  * pull the first message from a ADS result
3046  * @param ads connection to ads server
3047  * @param res Results of search
3048  * @return first message from result
3049  **/
3050  LDAPMessage *ads_first_message(ADS_STRUCT *ads, LDAPMessage *res)
3051 {
3052         return ldap_first_message(ads->ldap.ld, res);
3053 }
3054
3055 /**
3056  * pull the next message from a ADS result
3057  * @param ads connection to ads server
3058  * @param res Results of search
3059  * @return next message from result
3060  **/
3061  LDAPMessage *ads_next_message(ADS_STRUCT *ads, LDAPMessage *res)
3062 {
3063         return ldap_next_message(ads->ldap.ld, res);
3064 }
3065
3066 /**
3067  * pull a single string from a ADS result
3068  * @param ads connection to ads server
3069  * @param mem_ctx TALLOC_CTX to use for allocating result string
3070  * @param msg Results of search
3071  * @param field Attribute to retrieve
3072  * @return Result string in talloc context
3073  **/
3074  char *ads_pull_string(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, LDAPMessage *msg,
3075                        const char *field)
3076 {
3077         char **values;
3078         char *ret = NULL;
3079         char *ux_string;
3080         size_t converted_size;
3081
3082         values = ldap_get_values(ads->ldap.ld, msg, field);
3083         if (!values)
3084                 return NULL;
3085
3086         if (values[0] && pull_utf8_talloc(mem_ctx, &ux_string, values[0],
3087                                           &converted_size))
3088         {
3089                 ret = ux_string;
3090         }
3091         ldap_value_free(values);
3092         return ret;
3093 }
3094
3095 /**
3096  * pull an array of strings from a ADS result
3097  * @param ads connection to ads server
3098  * @param mem_ctx TALLOC_CTX to use for allocating result string
3099  * @param msg Results of search
3100  * @param field Attribute to retrieve
3101  * @return Result strings in talloc context
3102  **/
3103  char **ads_pull_strings(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
3104                          LDAPMessage *msg, const char *field,
3105                          size_t *num_values)
3106 {
3107         char **values;
3108         char **ret = NULL;
3109         size_t i, converted_size;
3110
3111         values = ldap_get_values(ads->ldap.ld, msg, field);
3112         if (!values)
3113                 return NULL;
3114
3115         *num_values = ldap_count_values(values);
3116
3117         ret = talloc_array(mem_ctx, char *, *num_values + 1);
3118         if (!ret) {
3119                 ldap_value_free(values);
3120                 return NULL;
3121         }
3122
3123         for (i=0;i<*num_values;i++) {
3124                 if (!pull_utf8_talloc(mem_ctx, &ret[i], values[i],
3125                                       &converted_size))
3126                 {
3127                         ldap_value_free(values);
3128                         return NULL;
3129                 }
3130         }
3131         ret[i] = NULL;
3132
3133         ldap_value_free(values);
3134         return ret;
3135 }
3136
3137 /**
3138  * pull an array of strings from a ADS result
3139  *  (handle large multivalue attributes with range retrieval)
3140  * @param ads connection to ads server
3141  * @param mem_ctx TALLOC_CTX to use for allocating result string
3142  * @param msg Results of search
3143  * @param field Attribute to retrieve
3144  * @param current_strings strings returned by a previous call to this function
3145  * @param next_attribute The next query should ask for this attribute
3146  * @param num_values How many values did we get this time?
3147  * @param more_values Are there more values to get?
3148  * @return Result strings in talloc context
3149  **/
3150  char **ads_pull_strings_range(ADS_STRUCT *ads,
3151                                TALLOC_CTX *mem_ctx,
3152                                LDAPMessage *msg, const char *field,
3153                                char **current_strings,
3154                                const char **next_attribute,
3155                                size_t *num_strings,
3156                                bool *more_strings)
3157 {
3158         char *attr;
3159         char *expected_range_attrib, *range_attr;
3160         BerElement *ptr = NULL;
3161         char **strings;
3162         char **new_strings;
3163         size_t num_new_strings;
3164         unsigned long int range_start;
3165         unsigned long int range_end;
3166
3167         /* we might have been given the whole lot anyway */
3168         if ((strings = ads_pull_strings(ads, mem_ctx, msg, field, num_strings))) {
3169                 *more_strings = False;
3170                 return strings;
3171         }
3172
3173         expected_range_attrib = talloc_asprintf(mem_ctx, "%s;Range=", field);
3174
3175         /* look for Range result */
3176         for (attr = ldap_first_attribute(ads->ldap.ld, (LDAPMessage *)msg, &ptr);
3177              attr;
3178              attr = ldap_next_attribute(ads->ldap.ld, (LDAPMessage *)msg, ptr)) {
3179                 /* we ignore the fact that this is utf8, as all attributes are ascii... */
3180                 if (strnequal(attr, expected_range_attrib, strlen(expected_range_attrib))) {
3181                         range_attr = attr;
3182                         break;
3183                 }
3184                 ldap_memfree(attr);
3185         }
3186         if (!attr) {
3187                 ber_free(ptr, 0);
3188                 /* nothing here - this field is just empty */
3189                 *more_strings = False;
3190                 return NULL;
3191         }
3192
3193         if (sscanf(&range_attr[strlen(expected_range_attrib)], "%lu-%lu",
3194                    &range_start, &range_end) == 2) {
3195                 *more_strings = True;
3196         } else {
3197                 if (sscanf(&range_attr[strlen(expected_range_attrib)], "%lu-*",
3198                            &range_start) == 1) {
3199                         *more_strings = False;
3200                 } else {
3201                         DEBUG(1, ("ads_pull_strings_range:  Cannot parse Range attriubte (%s)\n",
3202                                   range_attr));
3203                         ldap_memfree(range_attr);
3204                         *more_strings = False;
3205                         return NULL;
3206                 }
3207         }
3208
3209         if ((*num_strings) != range_start) {
3210                 DEBUG(1, ("ads_pull_strings_range: Range attribute (%s) doesn't start at %u, but at %lu"
3211                           " - aborting range retrieval\n",
3212                           range_attr, (unsigned int)(*num_strings) + 1, range_start));
3213                 ldap_memfree(range_attr);
3214                 *more_strings = False;
3215                 return NULL;
3216         }
3217
3218         new_strings = ads_pull_strings(ads, mem_ctx, msg, range_attr, &num_new_strings);
3219
3220         if (*more_strings && ((*num_strings + num_new_strings) != (range_end + 1))) {
3221                 DEBUG(1, ("ads_pull_strings_range: Range attribute (%s) tells us we have %lu "
3222                           "strings in this bunch, but we only got %lu - aborting range retrieval\n",
3223                           range_attr, (unsigned long int)range_end - range_start + 1,
3224                           (unsigned long int)num_new_strings));
3225                 ldap_memfree(range_attr);
3226                 *more_strings = False;
3227                 return NULL;
3228         }
3229
3230         strings = talloc_realloc(mem_ctx, current_strings, char *,
3231                                  *num_strings + num_new_strings);
3232
3233         if (strings == NULL) {
3234                 ldap_memfree(range_attr);
3235                 *more_strings = False;
3236                 return NULL;
3237         }
3238
3239         if (new_strings && num_new_strings) {
3240                 memcpy(&strings[*num_strings], new_strings,
3241                        sizeof(*new_strings) * num_new_strings);
3242         }
3243
3244         (*num_strings) += num_new_strings;
3245
3246         if (*more_strings) {
3247                 *next_attribute = talloc_asprintf(mem_ctx,
3248                                                   "%s;range=%d-*",
3249                                                   field,
3250                                                   (int)*num_strings);
3251
3252                 if (!*next_attribute) {
3253                         DEBUG(1, ("talloc_asprintf for next attribute failed!\n"));
3254                         ldap_memfree(range_attr);
3255                         *more_strings = False;
3256                         return NULL;
3257                 }
3258         }
3259
3260         ldap_memfree(range_attr);
3261
3262         return strings;
3263 }
3264
3265 /**
3266  * pull a single uint32_t from a ADS result
3267  * @param ads connection to ads server
3268  * @param msg Results of search
3269  * @param field Attribute to retrieve
3270  * @param v Pointer to int to store result
3271  * @return boolean indicating success
3272 */
3273  bool ads_pull_uint32(ADS_STRUCT *ads, LDAPMessage *msg, const char *field,
3274                       uint32_t *v)
3275 {
3276         char **values;
3277
3278         values = ldap_get_values(ads->ldap.ld, msg, field);
3279         if (!values)
3280                 return False;
3281         if (!values[0]) {
3282                 ldap_value_free(values);
3283                 return False;
3284         }
3285
3286         *v = atoi(values[0]);
3287         ldap_value_free(values);
3288         return True;
3289 }
3290
3291 /**
3292  * pull a single objectGUID from an ADS result
3293  * @param ads connection to ADS server
3294  * @param msg results of search
3295  * @param guid 37-byte area to receive text guid
3296  * @return boolean indicating success
3297  **/
3298  bool ads_pull_guid(ADS_STRUCT *ads, LDAPMessage *msg, struct GUID *guid)
3299 {
3300         DATA_BLOB blob;
3301         NTSTATUS status;
3302
3303         if (!smbldap_talloc_single_blob(talloc_tos(), ads->ldap.ld, msg, "objectGUID",
3304                                         &blob)) {
3305                 return false;
3306         }
3307
3308         status = GUID_from_ndr_blob(&blob, guid);
3309         talloc_free(blob.data);
3310         return NT_STATUS_IS_OK(status);
3311 }
3312
3313
3314 /**
3315  * pull a single struct dom_sid from a ADS result
3316  * @param ads connection to ads server
3317  * @param msg Results of search
3318  * @param field Attribute to retrieve
3319  * @param sid Pointer to sid to store result
3320  * @return boolean indicating success
3321 */
3322  bool ads_pull_sid(ADS_STRUCT *ads, LDAPMessage *msg, const char *field,
3323                    struct dom_sid *sid)
3324 {
3325         return smbldap_pull_sid(ads->ldap.ld, msg, field, sid);
3326 }
3327
3328 /**
3329  * pull an array of struct dom_sids from a ADS result
3330  * @param ads connection to ads server
3331  * @param mem_ctx TALLOC_CTX for allocating sid array
3332  * @param msg Results of search
3333  * @param field Attribute to retrieve
3334  * @param sids pointer to sid array to allocate
3335  * @return the count of SIDs pulled
3336  **/
3337  int ads_pull_sids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
3338                    LDAPMessage *msg, const char *field, struct dom_sid **sids)
3339 {
3340         struct berval **values;
3341         int count, i;
3342
3343         values = ldap_get_values_len(ads->ldap.ld, msg, field);
3344
3345         if (!values)
3346                 return 0;
3347
3348         for (i=0; values[i]; i++)
3349                 /* nop */ ;
3350
3351         if (i) {
3352                 (*sids) = talloc_array(mem_ctx, struct dom_sid, i);
3353                 if (!(*sids)) {
3354                         ldap_value_free_len(values);
3355                         return 0;
3356                 }
3357         } else {
3358                 (*sids) = NULL;
3359         }
3360
3361         count = 0;
3362         for (i=0; values[i]; i++) {
3363                 ssize_t ret;
3364                 ret = sid_parse((const uint8_t *)values[i]->bv_val,
3365                                 values[i]->bv_len, &(*sids)[count]);
3366                 if (ret != -1) {
3367                         struct dom_sid_buf buf;
3368                         DBG_DEBUG("pulling SID: %s\n",
3369                                   dom_sid_str_buf(&(*sids)[count], &buf));
3370                         count++;
3371                 }
3372         }
3373
3374         ldap_value_free_len(values);
3375         return count;
3376 }
3377
3378 /**
3379  * pull a struct security_descriptor from a ADS result
3380  * @param ads connection to ads server
3381  * @param mem_ctx TALLOC_CTX for allocating sid array
3382  * @param msg Results of search
3383  * @param field Attribute to retrieve
3384  * @param sd Pointer to *struct security_descriptor to store result (talloc()ed)
3385  * @return boolean indicating success
3386 */
3387  bool ads_pull_sd(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
3388                   LDAPMessage *msg, const char *field,
3389                   struct security_descriptor **sd)
3390 {
3391         struct berval **values;
3392         bool ret = true;
3393
3394         values = ldap_get_values_len(ads->ldap.ld, msg, field);
3395
3396         if (!values) return false;
3397
3398         if (values[0]) {
3399                 NTSTATUS status;
3400                 status = unmarshall_sec_desc(mem_ctx,
3401                                              (uint8_t *)values[0]->bv_val,
3402                                              values[0]->bv_len, sd);
3403                 if (!NT_STATUS_IS_OK(status)) {
3404                         DEBUG(0, ("unmarshall_sec_desc failed: %s\n",
3405                                   nt_errstr(status)));
3406                         ret = false;
3407                 }
3408         }
3409
3410         ldap_value_free_len(values);
3411         return ret;
3412 }
3413
3414 /*
3415  * in order to support usernames longer than 21 characters we need to
3416  * use both the sAMAccountName and the userPrincipalName attributes
3417  * It seems that not all users have the userPrincipalName attribute set
3418  *
3419  * @param ads connection to ads server
3420  * @param mem_ctx TALLOC_CTX for allocating sid array
3421  * @param msg Results of search
3422  * @return the username
3423  */
3424  char *ads_pull_username(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
3425                          LDAPMessage *msg)
3426 {
3427 #if 0   /* JERRY */
3428         char *ret, *p;
3429
3430         /* lookup_name() only works on the sAMAccountName to
3431            returning the username portion of userPrincipalName
3432            breaks winbindd_getpwnam() */
3433
3434         ret = ads_pull_string(ads, mem_ctx, msg, "userPrincipalName");
3435         if (ret && (p = strchr_m(ret, '@'))) {
3436                 *p = 0;
3437                 return ret;
3438         }
3439 #endif
3440         return ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
3441 }
3442
3443
3444 /**
3445  * find the update serial number - this is the core of the ldap cache
3446  * @param ads connection to ads server
3447  * @param ads connection to ADS server
3448  * @param usn Pointer to retrieved update serial number
3449  * @return status of search
3450  **/
3451 ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32_t *usn)
3452 {
3453         const char *attrs[] = {"highestCommittedUSN", NULL};
3454         ADS_STATUS status;
3455         LDAPMessage *res;
3456
3457         status = ads_do_search_retry(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
3458         if (!ADS_ERR_OK(status))
3459                 return status;
3460
3461         if (ads_count_replies(ads, res) != 1) {
3462                 ads_msgfree(ads, res);
3463                 return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
3464         }
3465
3466         if (!ads_pull_uint32(ads, res, "highestCommittedUSN", usn)) {
3467                 ads_msgfree(ads, res);
3468                 return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
3469         }
3470
3471         ads_msgfree(ads, res);
3472         return ADS_SUCCESS;
3473 }
3474
3475 /* parse a ADS timestring - typical string is
3476    '20020917091222.0Z0' which means 09:12.22 17th September
3477    2002, timezone 0 */
3478 static time_t ads_parse_time(const char *str)
3479 {
3480         struct tm tm;
3481
3482         ZERO_STRUCT(tm);
3483
3484         if (sscanf(str, "%4d%2d%2d%2d%2d%2d",
3485                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
3486                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
3487                 return 0;
3488         }
3489         tm.tm_year -= 1900;
3490         tm.tm_mon -= 1;
3491
3492         return timegm(&tm);
3493 }
3494
3495 /********************************************************************
3496 ********************************************************************/
3497
3498 ADS_STATUS ads_current_time(ADS_STRUCT *ads)
3499 {
3500         const char *attrs[] = {"currentTime", NULL};
3501         ADS_STATUS status;
3502         LDAPMessage *res;
3503         char *timestr;
3504         TALLOC_CTX *tmp_ctx = talloc_stackframe();
3505         ADS_STRUCT *ads_s = ads;
3506
3507         /* establish a new ldap tcp session if necessary */
3508
3509         if ( !ads->ldap.ld ) {
3510                 /*
3511                  * ADS_STRUCT may be being reused after a
3512                  * DC lookup, so ads->ldap.ss may already have a
3513                  * good address. If not, re-initialize the passed-in
3514                  * ADS_STRUCT with the given server.XXXX parameters.
3515                  *
3516                  * Note that this doesn't depend on
3517                  * ads->server.ldap_server != NULL,
3518                  * as the case where ads->server.ldap_server==NULL and
3519                  * ads->ldap.ss != zero_address is precisely the DC
3520                  * lookup case where ads->ldap.ss was found by going
3521                  * through ads_find_dc() again we want to avoid repeating.
3522                  */
3523                 if (is_zero_addr(&ads->ldap.ss)) {
3524                         ads_s = ads_init(tmp_ctx,
3525                                          ads->server.realm,
3526                                          ads->server.workgroup,
3527                                          ads->server.ldap_server,
3528                                          ADS_SASL_PLAIN );
3529                         if (ads_s == NULL) {
3530                                 status = ADS_ERROR(LDAP_NO_MEMORY);
3531                                 goto done;
3532                         }
3533                 }
3534
3535                 /*
3536                  * Reset ads->config.flags as it can contain the flags
3537                  * returned by the previous CLDAP ping when reusing the struct.
3538                  */
3539                 ads_s->config.flags = 0;
3540
3541                 ads_s->auth.flags = ADS_AUTH_ANON_BIND;
3542                 status = ads_connect( ads_s );
3543                 if ( !ADS_ERR_OK(status))
3544                         goto done;
3545         }
3546
3547         status = ads_do_search(ads_s, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
3548         if (!ADS_ERR_OK(status)) {
3549                 goto done;
3550         }
3551
3552         timestr = ads_pull_string(ads_s, tmp_ctx, res, "currentTime");
3553         if (!timestr) {
3554                 ads_msgfree(ads_s, res);
3555                 status = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
3556                 goto done;
3557         }
3558
3559         /* but save the time and offset in the original ADS_STRUCT */
3560
3561         ads->config.current_time = ads_parse_time(timestr);
3562
3563         if (ads->config.current_time != 0) {
3564                 ads->auth.time_offset = ads->config.current_time - time(NULL);
3565                 DEBUG(4,("KDC time offset is %d seconds\n", ads->auth.time_offset));
3566         }
3567
3568         ads_msgfree(ads, res);
3569
3570         status = ADS_SUCCESS;
3571
3572 done:
3573         TALLOC_FREE(tmp_ctx);
3574
3575         return status;
3576 }
3577
3578 /********************************************************************
3579 ********************************************************************/
3580
3581 ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32_t *val)
3582 {
3583         TALLOC_CTX *tmp_ctx = talloc_stackframe();
3584         const char *attrs[] = {"domainFunctionality", NULL};
3585         ADS_STATUS status;
3586         LDAPMessage *res;
3587         ADS_STRUCT *ads_s = ads;
3588
3589         *val = DS_DOMAIN_FUNCTION_2000;
3590
3591         /* establish a new ldap tcp session if necessary */
3592
3593         if ( !ads->ldap.ld ) {
3594                 /*
3595                  * ADS_STRUCT may be being reused after a
3596                  * DC lookup, so ads->ldap.ss may already have a
3597                  * good address. If not, re-initialize the passed-in
3598                  * ADS_STRUCT with the given server.XXXX parameters.
3599                  *
3600                  * Note that this doesn't depend on
3601                  * ads->server.ldap_server != NULL,
3602                  * as the case where ads->server.ldap_server==NULL and
3603                  * ads->ldap.ss != zero_address is precisely the DC
3604                  * lookup case where ads->ldap.ss was found by going
3605                  * through ads_find_dc() again we want to avoid repeating.
3606                  */
3607                 if (is_zero_addr(&ads->ldap.ss)) {
3608                         ads_s = ads_init(tmp_ctx,
3609                                          ads->server.realm,
3610                                          ads->server.workgroup,
3611                                          ads->server.ldap_server,
3612                                          ADS_SASL_PLAIN );
3613                         if (ads_s == NULL ) {
3614                                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
3615                                 goto done;
3616                         }
3617                 }
3618
3619                 /*
3620                  * Reset ads->config.flags as it can contain the flags
3621                  * returned by the previous CLDAP ping when reusing the struct.
3622                  */
3623                 ads_s->config.flags = 0;
3624
3625                 ads_s->auth.flags = ADS_AUTH_ANON_BIND;
3626                 status = ads_connect( ads_s );
3627                 if ( !ADS_ERR_OK(status))
3628                         goto done;
3629         }
3630
3631         /* If the attribute does not exist assume it is a Windows 2000
3632            functional domain */
3633
3634         status = ads_do_search(ads_s, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
3635         if (!ADS_ERR_OK(status)) {
3636                 if ( status.err.rc == LDAP_NO_SUCH_ATTRIBUTE ) {
3637                         status = ADS_SUCCESS;
3638                 }
3639                 goto done;
3640         }
3641
3642         if ( !ads_pull_uint32(ads_s, res, "domainFunctionality", val) ) {
3643                 DEBUG(5,("ads_domain_func_level: Failed to pull the domainFunctionality attribute.\n"));
3644         }
3645         DEBUG(3,("ads_domain_func_level: %d\n", *val));
3646
3647
3648         ads_msgfree(ads_s, res);
3649
3650 done:
3651         TALLOC_FREE(tmp_ctx);
3652
3653         return status;
3654 }
3655
3656 /**
3657  * find the domain sid for our domain
3658  * @param ads connection to ads server
3659  * @param sid Pointer to domain sid
3660  * @return status of search
3661  **/
3662 ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, struct dom_sid *sid)
3663 {
3664         const char *attrs[] = {"objectSid", NULL};
3665         LDAPMessage *res;
3666         ADS_STATUS rc;
3667
3668         rc = ads_do_search_retry(ads, ads->config.bind_path, LDAP_SCOPE_BASE, "(objectclass=*)",
3669                            attrs, &res);
3670         if (!ADS_ERR_OK(rc)) return rc;
3671         if (!ads_pull_sid(ads, res, "objectSid", sid)) {
3672                 ads_msgfree(ads, res);
3673                 return ADS_ERROR_SYSTEM(ENOENT);
3674         }
3675         ads_msgfree(ads, res);
3676
3677         return ADS_SUCCESS;
3678 }
3679
3680 /**
3681  * find our site name
3682  * @param ads connection to ads server
3683  * @param mem_ctx Pointer to talloc context
3684  * @param site_name Pointer to the sitename
3685  * @return status of search
3686  **/
3687 ADS_STATUS ads_site_dn(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char **site_name)
3688 {
3689         ADS_STATUS status;
3690         LDAPMessage *res;
3691         const char *dn, *service_name;
3692         const char *attrs[] = { "dsServiceName", NULL };
3693
3694         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
3695         if (!ADS_ERR_OK(status)) {
3696                 return status;
3697         }
3698
3699         service_name = ads_pull_string(ads, mem_ctx, res, "dsServiceName");
3700         if (service_name == NULL) {
3701                 ads_msgfree(ads, res);
3702                 return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
3703         }
3704
3705         ads_msgfree(ads, res);
3706
3707         /* go up three levels */
3708         dn = ads_parent_dn(ads_parent_dn(ads_parent_dn(service_name)));
3709         if (dn == NULL) {
3710                 return ADS_ERROR(LDAP_NO_MEMORY);
3711         }
3712
3713         *site_name = talloc_strdup(mem_ctx, dn);
3714         if (*site_name == NULL) {
3715                 return ADS_ERROR(LDAP_NO_MEMORY);
3716         }
3717
3718         return status;
3719         /*
3720         dsServiceName: CN=NTDS Settings,CN=W2K3DC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ber,DC=suse,DC=de
3721         */
3722 }
3723
3724 /**
3725  * find the site dn where a machine resides
3726  * @param ads connection to ads server
3727  * @param mem_ctx Pointer to talloc context
3728  * @param computer_name name of the machine
3729  * @param site_name Pointer to the sitename
3730  * @return status of search
3731  **/
3732 ADS_STATUS ads_site_dn_for_machine(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char *computer_name, const char **site_dn)
3733 {
3734         ADS_STATUS status;
3735         LDAPMessage *res;
3736         const char *parent, *filter;
3737         char *config_context = NULL;
3738         char *dn;
3739
3740         /* shortcut a query */
3741         if (strequal(computer_name, ads->config.ldap_server_name)) {
3742                 return ads_site_dn(ads, mem_ctx, site_dn);
3743         }
3744
3745         status = ads_config_path(ads, mem_ctx, &config_context);
3746         if (!ADS_ERR_OK(status)) {
3747                 return status;
3748         }
3749
3750         filter = talloc_asprintf(mem_ctx, "(cn=%s)", computer_name);
3751         if (filter == NULL) {
3752                 return ADS_ERROR(LDAP_NO_MEMORY);
3753         }
3754
3755         status = ads_do_search(ads, config_context, LDAP_SCOPE_SUBTREE,
3756                                filter, NULL, &res);
3757         if (!ADS_ERR_OK(status)) {
3758                 return status;
3759         }
3760
3761         if (ads_count_replies(ads, res) != 1) {
3762                 ads_msgfree(ads, res);
3763                 return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
3764         }
3765
3766         dn = ads_get_dn(ads, mem_ctx, res);
3767         if (dn == NULL) {
3768                 ads_msgfree(ads, res);
3769                 return ADS_ERROR(LDAP_NO_MEMORY);
3770         }
3771
3772         /* go up three levels */
3773         parent = ads_parent_dn(ads_parent_dn(ads_parent_dn(dn)));
3774         if (parent == NULL) {
3775                 ads_msgfree(ads, res);
3776                 TALLOC_FREE(dn);
3777                 return ADS_ERROR(LDAP_NO_MEMORY);
3778         }
3779
3780         *site_dn = talloc_strdup(mem_ctx, parent);
3781         if (*site_dn == NULL) {
3782                 ads_msgfree(ads, res);
3783                 TALLOC_FREE(dn);
3784                 return ADS_ERROR(LDAP_NO_MEMORY);
3785         }
3786
3787         TALLOC_FREE(dn);
3788         ads_msgfree(ads, res);
3789
3790         return status;
3791 }
3792
3793 /**
3794  * get the upn suffixes for a domain
3795  * @param ads connection to ads server
3796  * @param mem_ctx Pointer to talloc context
3797  * @param suffixes Pointer to an array of suffixes
3798  * @param num_suffixes Pointer to the number of suffixes
3799  * @return status of search
3800  **/
3801 ADS_STATUS ads_upn_suffixes(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char ***suffixes, size_t *num_suffixes)
3802 {
3803         ADS_STATUS status;
3804         LDAPMessage *res;
3805         const char *base;
3806         char *config_context = NULL;
3807         const char *attrs[] = { "uPNSuffixes", NULL };
3808
3809         status = ads_config_path(ads, mem_ctx, &config_context);
3810         if (!ADS_ERR_OK(status)) {
3811                 return status;
3812         }
3813
3814         base = talloc_asprintf(mem_ctx, "cn=Partitions,%s", config_context);
3815         if (base == NULL) {
3816                 return ADS_ERROR(LDAP_NO_MEMORY);
3817         }
3818
3819         status = ads_search_dn(ads, &res, base, attrs);
3820         if (!ADS_ERR_OK(status)) {
3821                 return status;
3822         }
3823
3824         if (ads_count_replies(ads, res) != 1) {
3825                 ads_msgfree(ads, res);
3826                 return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
3827         }
3828
3829         (*suffixes) = ads_pull_strings(ads, mem_ctx, res, "uPNSuffixes", num_suffixes);
3830         if ((*suffixes) == NULL) {
3831                 ads_msgfree(ads, res);
3832                 return ADS_ERROR(LDAP_NO_MEMORY);
3833         }
3834
3835         ads_msgfree(ads, res);
3836
3837         return status;
3838 }
3839
3840 /**
3841  * get the joinable ous for a domain
3842  * @param ads connection to ads server
3843  * @param mem_ctx Pointer to talloc context
3844  * @param ous Pointer to an array of ous
3845  * @param num_ous Pointer to the number of ous
3846  * @return status of search
3847  **/
3848 ADS_STATUS ads_get_joinable_ous(ADS_STRUCT *ads,
3849                                 TALLOC_CTX *mem_ctx,
3850                                 char ***ous,
3851                                 size_t *num_ous)
3852 {
3853         ADS_STATUS status;
3854         LDAPMessage *res = NULL;
3855         LDAPMessage *msg = NULL;
3856         const char *attrs[] = { "dn", NULL };
3857         int count = 0;
3858
3859         status = ads_search(ads, &res,
3860                             "(|(objectClass=domain)(objectclass=organizationalUnit))",
3861                             attrs);
3862         if (!ADS_ERR_OK(status)) {
3863                 return status;
3864         }
3865
3866         count = ads_count_replies(ads, res);
3867         if (count < 1) {
3868                 ads_msgfree(ads, res);
3869                 return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
3870         }
3871
3872         for (msg = ads_first_entry(ads, res); msg;
3873              msg = ads_next_entry(ads, msg)) {
3874                 const char **p = discard_const_p(const char *, *ous);
3875                 char *dn = NULL;
3876
3877                 dn = ads_get_dn(ads, talloc_tos(), msg);
3878                 if (!dn) {
3879                         ads_msgfree(ads, res);
3880                         return ADS_ERROR(LDAP_NO_MEMORY);
3881                 }
3882
3883                 if (!add_string_to_array(mem_ctx, dn, &p, num_ous)) {
3884                         TALLOC_FREE(dn);
3885                         ads_msgfree(ads, res);
3886                         return ADS_ERROR(LDAP_NO_MEMORY);
3887                 }
3888
3889                 TALLOC_FREE(dn);
3890                 *ous = discard_const_p(char *, p);
3891         }
3892
3893         ads_msgfree(ads, res);
3894
3895         return status;
3896 }
3897
3898
3899 /**
3900  * pull a struct dom_sid from an extended dn string
3901  * @param mem_ctx TALLOC_CTX
3902  * @param extended_dn string
3903  * @param flags string type of extended_dn
3904  * @param sid pointer to a struct dom_sid
3905  * @return NT_STATUS_OK on success,
3906  *         NT_INVALID_PARAMETER on error,
3907  *         NT_STATUS_NOT_FOUND if no SID present
3908  **/
3909 ADS_STATUS ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx,
3910                                         const char *extended_dn,
3911                                         enum ads_extended_dn_flags flags,
3912                                         struct dom_sid *sid)
3913 {
3914         char *p, *q, *dn;
3915
3916         if (!extended_dn) {
3917                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
3918         }
3919
3920         /* otherwise extended_dn gets stripped off */
3921         if ((dn = talloc_strdup(mem_ctx, extended_dn)) == NULL) {
3922                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
3923         }
3924         /*
3925          * ADS_EXTENDED_DN_HEX_STRING:
3926          * <GUID=238e1963cb390f4bb032ba0105525a29>;<SID=010500000000000515000000bb68c8fd6b61b427572eb04556040000>;CN=gd,OU=berlin,OU=suse,DC=ber,DC=suse,DC=de
3927          *
3928          * ADS_EXTENDED_DN_STRING (only with w2k3):
3929          * <GUID=63198e23-39cb-4b0f-b032-ba0105525a29>;<SID=S-1-5-21-4257769659-666132843-1169174103-1110>;CN=gd,OU=berlin,OU=suse,DC=ber,DC=suse,DC=de
3930          *
3931          * Object with no SID, such as an Exchange Public Folder
3932          * <GUID=28907fb4bdf6854993e7f0a10b504e7c>;CN=public,CN=Microsoft Exchange System Objects,DC=sd2k3ms,DC=west,DC=isilon,DC=com
3933          */
3934
3935         p = strchr(dn, ';');
3936         if (!p) {
3937                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
3938         }
3939
3940         if (strncmp(p, ";<SID=", strlen(";<SID=")) != 0) {
3941                 DEBUG(5,("No SID present in extended dn\n"));
3942                 return ADS_ERROR_NT(NT_STATUS_NOT_FOUND);
3943         }
3944
3945         p += strlen(";<SID=");
3946
3947         q = strchr(p, '>');
3948         if (!q) {
3949                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
3950         }
3951
3952         *q = '\0';
3953
3954         DEBUG(100,("ads_get_sid_from_extended_dn: sid string is %s\n", p));
3955
3956         switch (flags) {
3957
3958         case ADS_EXTENDED_DN_STRING:
3959                 if (!string_to_sid(sid, p)) {
3960                         return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
3961                 }
3962                 break;
3963         case ADS_EXTENDED_DN_HEX_STRING: {
3964                 ssize_t ret;
3965                 fstring buf;
3966                 size_t buf_len;
3967
3968                 buf_len = strhex_to_str(buf, sizeof(buf), p, strlen(p));
3969                 if (buf_len == 0) {
3970                         return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
3971                 }
3972
3973                 ret = sid_parse((const uint8_t *)buf, buf_len, sid);
3974                 if (ret == -1) {
3975                         DEBUG(10,("failed to parse sid\n"));
3976                         return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
3977                 }
3978                 break;
3979                 }
3980         default:
3981                 DEBUG(10,("unknown extended dn format\n"));
3982                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
3983         }
3984
3985         return ADS_ERROR_NT(NT_STATUS_OK);
3986 }
3987
3988 /********************************************************************
3989 ********************************************************************/
3990
3991 char* ads_get_dnshostname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
3992 {
3993         LDAPMessage *res = NULL;
3994         ADS_STATUS status;
3995         int count = 0;
3996         char *name = NULL;
3997
3998         status = ads_find_machine_acct(ads, &res, machine_name);
3999         if (!ADS_ERR_OK(status)) {
4000                 DEBUG(0,("ads_get_dnshostname: Failed to find account for %s\n",
4001                         lp_netbios_name()));
4002                 goto out;
4003         }
4004
4005         if ( (count = ads_count_replies(ads, res)) != 1 ) {
4006                 DEBUG(1,("ads_get_dnshostname: %d entries returned!\n", count));
4007                 goto out;
4008         }
4009
4010         if ( (name = ads_pull_string(ads, ctx, res, "dNSHostName")) == NULL ) {
4011                 DEBUG(0,("ads_get_dnshostname: No dNSHostName attribute!\n"));
4012         }
4013
4014 out:
4015         ads_msgfree(ads, res);
4016
4017         return name;
4018 }
4019
4020 /********************************************************************
4021 ********************************************************************/
4022
4023 static char **get_addl_hosts(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
4024                               LDAPMessage *msg, size_t *num_values)
4025 {
4026         const char *field = "msDS-AdditionalDnsHostName";
4027         struct berval **values = NULL;
4028         char **ret = NULL;
4029         size_t i, converted_size;
4030
4031         /*
4032          * Windows DC implicitly adds a short name for each FQDN added to
4033          * msDS-AdditionalDnsHostName, but it comes with a strange binary
4034          * suffix "\0$" which we should ignore (see bug #14406).
4035          */
4036
4037         values = ldap_get_values_len(ads->ldap.ld, msg, field);
4038         if (values == NULL) {
4039                 return NULL;
4040         }
4041
4042         *num_values = ldap_count_values_len(values);
4043
4044         ret = talloc_array(mem_ctx, char *, *num_values + 1);
4045         if (ret == NULL) {
4046                 ldap_value_free_len(values);
4047                 return NULL;
4048         }
4049
4050         for (i = 0; i < *num_values; i++) {
4051                 ret[i] = NULL;
4052                 if (!convert_string_talloc(mem_ctx, CH_UTF8, CH_UNIX,
4053                                            values[i]->bv_val,
4054                                            strnlen(values[i]->bv_val,
4055                                                    values[i]->bv_len),
4056                                            &ret[i], &converted_size)) {
4057                         ldap_value_free_len(values);
4058                         return NULL;
4059                 }
4060         }
4061         ret[i] = NULL;
4062
4063         ldap_value_free_len(values);
4064         return ret;
4065 }
4066
4067 ADS_STATUS ads_get_additional_dns_hostnames(TALLOC_CTX *mem_ctx,
4068                                             ADS_STRUCT *ads,
4069                                             const char *machine_name,
4070                                             char ***hostnames_array,
4071                                             size_t *num_hostnames)
4072 {
4073         ADS_STATUS status;
4074         LDAPMessage *res = NULL;
4075         int count;
4076
4077         status = ads_find_machine_acct(ads,
4078                                        &res,
4079                                        machine_name);
4080         if (!ADS_ERR_OK(status)) {
4081                 DEBUG(1,("Host Account for %s not found... skipping operation.\n",
4082                          machine_name));
4083                 return status;
4084         }
4085
4086         count = ads_count_replies(ads, res);
4087         if (count != 1) {
4088                 status = ADS_ERROR(LDAP_NO_SUCH_OBJECT);
4089                 goto done;
4090         }
4091
4092         *hostnames_array = get_addl_hosts(ads, mem_ctx, res, num_hostnames);
4093         if (*hostnames_array == NULL) {
4094                 DEBUG(1, ("Host account for %s does not have msDS-AdditionalDnsHostName.\n",
4095                           machine_name));
4096                 status = ADS_ERROR(LDAP_NO_SUCH_OBJECT);
4097                 goto done;
4098         }
4099
4100 done:
4101         ads_msgfree(ads, res);
4102
4103         return status;
4104 }
4105
4106 /********************************************************************
4107 ********************************************************************/
4108
4109 char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
4110 {
4111         LDAPMessage *res = NULL;
4112         ADS_STATUS status;
4113         int count = 0;
4114         char *name = NULL;
4115
4116         status = ads_find_machine_acct(ads, &res, machine_name);
4117         if (!ADS_ERR_OK(status)) {
4118                 DEBUG(0,("ads_get_upn: Failed to find account for %s\n",
4119                         lp_netbios_name()));
4120                 goto out;
4121         }
4122
4123         if ( (count = ads_count_replies(ads, res)) != 1 ) {
4124                 DEBUG(1,("ads_get_upn: %d entries returned!\n", count));
4125                 goto out;
4126         }
4127
4128         if ( (name = ads_pull_string(ads, ctx, res, "userPrincipalName")) == NULL ) {
4129                 DEBUG(2,("ads_get_upn: No userPrincipalName attribute!\n"));
4130         }
4131
4132 out:
4133         ads_msgfree(ads, res);
4134
4135         return name;
4136 }
4137
4138 /********************************************************************
4139 ********************************************************************/
4140
4141 bool ads_has_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
4142 {
4143         LDAPMessage *res = NULL;
4144         ADS_STATUS status;
4145         int count = 0;
4146         char *name = NULL;
4147         bool ok = false;
4148
4149         status = ads_find_machine_acct(ads, &res, machine_name);
4150         if (!ADS_ERR_OK(status)) {
4151                 DEBUG(0,("ads_has_samaccountname: Failed to find account for %s\n",
4152                         lp_netbios_name()));
4153                 goto out;
4154         }
4155
4156         if ( (count = ads_count_replies(ads, res)) != 1 ) {
4157                 DEBUG(1,("ads_has_samaccountname: %d entries returned!\n", count));
4158                 goto out;
4159         }
4160
4161         if ( (name = ads_pull_string(ads, ctx, res, "sAMAccountName")) == NULL ) {
4162                 DEBUG(0,("ads_has_samaccountname: No sAMAccountName attribute!\n"));
4163         }
4164
4165 out:
4166         ads_msgfree(ads, res);
4167         if (name != NULL) {
4168                 ok = (strlen(name) > 0);
4169         }
4170         TALLOC_FREE(name);
4171         return ok;
4172 }
4173
4174 #if 0
4175
4176    SAVED CODE - we used to join via ldap - remember how we did this. JRA.
4177
4178 /**
4179  * Join a machine to a realm
4180  *  Creates the machine account and sets the machine password
4181  * @param ads connection to ads server
4182  * @param machine name of host to add
4183  * @param org_unit Organizational unit to place machine in
4184  * @return status of join
4185  **/
4186 ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name,
4187                         uint32_t account_type, const char *org_unit)
4188 {
4189         ADS_STATUS status;
4190         LDAPMessage *res = NULL;
4191         char *machine;
4192
4193         /* machine name must be lowercase */
4194         machine = SMB_STRDUP(machine_name);
4195         strlower_m(machine);
4196
4197         /*
4198         status = ads_find_machine_acct(ads, (void **)&res, machine);
4199         if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
4200                 DEBUG(0, ("Host account for %s already exists - deleting old account\n", machine));
4201                 status = ads_leave_realm(ads, machine);
4202                 if (!ADS_ERR_OK(status)) {
4203                         DEBUG(0, ("Failed to delete host '%s' from the '%s' realm.\n",
4204                                 machine, ads->config.realm));
4205                         return status;
4206                 }
4207         }
4208         */
4209         status = ads_add_machine_acct(ads, machine, account_type, org_unit);
4210         if (!ADS_ERR_OK(status)) {
4211                 DEBUG(0, ("ads_join_realm: ads_add_machine_acct failed (%s): %s\n", machine, ads_errstr(status)));
4212                 SAFE_FREE(machine);
4213                 return status;
4214         }
4215
4216         status = ads_find_machine_acct(ads, (void **)(void *)&res, machine);
4217         if (!ADS_ERR_OK(status)) {
4218                 DEBUG(0, ("ads_join_realm: Host account test failed for machine %s\n", machine));
4219                 SAFE_FREE(machine);
4220                 return status;
4221         }
4222
4223         SAFE_FREE(machine);
4224         ads_msgfree(ads, res);
4225
4226         return status;
4227 }
4228 #endif
4229
4230 /**
4231  * Delete a machine from the realm
4232  * @param ads connection to ads server
4233  * @param hostname Machine to remove
4234  * @return status of delete
4235  **/
4236 ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
4237 {
4238         ADS_STATUS status;
4239         void *msg;
4240         LDAPMessage *res;
4241         char *hostnameDN, *host;
4242         int rc;
4243         LDAPControl ldap_control;
4244         LDAPControl  * pldap_control[2] = {NULL, NULL};
4245
4246         pldap_control[0] = &ldap_control;
4247         memset(&ldap_control, 0, sizeof(LDAPControl));
4248         ldap_control.ldctl_oid = discard_const_p(char, LDAP_SERVER_TREE_DELETE_OID);
4249
4250         /* hostname must be lowercase */
4251         host = SMB_STRDUP(hostname);
4252         if (!strlower_m(host)) {
4253                 SAFE_FREE(host);
4254                 return ADS_ERROR_SYSTEM(EINVAL);
4255         }
4256
4257         status = ads_find_machine_acct(ads, &res, host);
4258         if (!ADS_ERR_OK(status)) {
4259                 DEBUG(0, ("Host account for %s does not exist.\n", host));
4260                 SAFE_FREE(host);
4261                 return status;
4262         }
4263
4264         msg = ads_first_entry(ads, res);
4265         if (!msg) {
4266                 SAFE_FREE(host);
4267                 return ADS_ERROR_SYSTEM(ENOENT);
4268         }
4269
4270         hostnameDN = ads_get_dn(ads, talloc_tos(), (LDAPMessage *)msg);
4271         if (hostnameDN == NULL) {
4272                 SAFE_FREE(host);
4273                 return ADS_ERROR_SYSTEM(ENOENT);
4274         }
4275
4276         rc = ldap_delete_ext_s(ads->ldap.ld, hostnameDN, pldap_control, NULL);
4277         if (rc) {
4278                 DEBUG(3,("ldap_delete_ext_s failed with error code %d\n", rc));
4279         }else {
4280                 DEBUG(3,("ldap_delete_ext_s succeeded with error code %d\n", rc));
4281         }
4282
4283         if (rc != LDAP_SUCCESS) {
4284                 const char *attrs[] = { "cn", NULL };
4285                 LDAPMessage *msg_sub;
4286
4287                 /* we only search with scope ONE, we do not expect any further
4288                  * objects to be created deeper */
4289
4290                 status = ads_do_search_retry(ads, hostnameDN,
4291                                              LDAP_SCOPE_ONELEVEL,
4292                                              "(objectclass=*)", attrs, &res);
4293
4294                 if (!ADS_ERR_OK(status)) {
4295                         SAFE_FREE(host);
4296                         TALLOC_FREE(hostnameDN);
4297                         return status;
4298                 }
4299
4300                 for (msg_sub = ads_first_entry(ads, res); msg_sub;
4301                         msg_sub = ads_next_entry(ads, msg_sub)) {
4302
4303                         char *dn = NULL;
4304
4305                         if ((dn = ads_get_dn(ads, talloc_tos(), msg_sub)) == NULL) {
4306                                 SAFE_FREE(host);
4307                                 TALLOC_FREE(hostnameDN);
4308                                 return ADS_ERROR(LDAP_NO_MEMORY);
4309                         }
4310
4311                         status = ads_del_dn(ads, dn);
4312                         if (!ADS_ERR_OK(status)) {
4313                                 DEBUG(3,("failed to delete dn %s: %s\n", dn, ads_errstr(status)));
4314                                 SAFE_FREE(host);
4315                                 TALLOC_FREE(dn);
4316                                 TALLOC_FREE(hostnameDN);
4317                                 return status;
4318                         }
4319
4320                         TALLOC_FREE(dn);
4321                 }
4322
4323                 /* there should be no subordinate objects anymore */
4324                 status = ads_do_search_retry(ads, hostnameDN,
4325                                              LDAP_SCOPE_ONELEVEL,
4326                                              "(objectclass=*)", attrs, &res);
4327
4328                 if (!ADS_ERR_OK(status) || ( (ads_count_replies(ads, res)) > 0 ) ) {
4329                         SAFE_FREE(host);
4330                         TALLOC_FREE(hostnameDN);
4331                         return status;
4332                 }
4333
4334                 /* delete hostnameDN now */
4335                 status = ads_del_dn(ads, hostnameDN);
4336                 if (!ADS_ERR_OK(status)) {
4337                         SAFE_FREE(host);
4338                         DEBUG(3,("failed to delete dn %s: %s\n", hostnameDN, ads_errstr(status)));
4339                         TALLOC_FREE(hostnameDN);
4340                         return status;
4341                 }
4342         }
4343
4344         TALLOC_FREE(hostnameDN);
4345
4346         status = ads_find_machine_acct(ads, &res, host);
4347         if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
4348             (status.err.rc != LDAP_NO_SUCH_OBJECT)) {
4349                 DEBUG(3, ("Failed to remove host account.\n"));
4350                 SAFE_FREE(host);
4351                 return status;
4352         }
4353
4354         SAFE_FREE(host);
4355         return ADS_SUCCESS;
4356 }
4357
4358 /**
4359  * pull all token-sids from an LDAP dn
4360  * @param ads connection to ads server
4361  * @param mem_ctx TALLOC_CTX for allocating sid array
4362  * @param dn of LDAP object
4363  * @param user_sid pointer to struct dom_sid (objectSid)
4364  * @param primary_group_sid pointer to struct dom_sid (self composed)
4365  * @param sids pointer to sid array to allocate
4366  * @param num_sids counter of SIDs pulled
4367  * @return status of token query
4368  **/
4369  ADS_STATUS ads_get_tokensids(ADS_STRUCT *ads,
4370                               TALLOC_CTX *mem_ctx,
4371                               const char *dn,
4372                               struct dom_sid *user_sid,
4373                               struct dom_sid *primary_group_sid,
4374                               struct dom_sid **sids,
4375                               size_t *num_sids)
4376 {
4377         ADS_STATUS status;
4378         LDAPMessage *res = NULL;
4379         int count = 0;
4380         size_t tmp_num_sids;
4381         struct dom_sid *tmp_sids;
4382         struct dom_sid tmp_user_sid;
4383         struct dom_sid tmp_primary_group_sid;
4384         uint32_t pgid;
4385         const char *attrs[] = {
4386                 "objectSid",
4387                 "tokenGroups",
4388                 "primaryGroupID",
4389                 NULL
4390         };
4391
4392         status = ads_search_retry_dn(ads, &res, dn, attrs);
4393         if (!ADS_ERR_OK(status)) {
4394                 return status;
4395         }
4396
4397         count = ads_count_replies(ads, res);
4398         if (count != 1) {
4399                 ads_msgfree(ads, res);
4400                 return ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT);
4401         }
4402
4403         if (!ads_pull_sid(ads, res, "objectSid", &tmp_user_sid)) {
4404                 ads_msgfree(ads, res);
4405                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
4406         }
4407
4408         if (!ads_pull_uint32(ads, res, "primaryGroupID", &pgid)) {
4409                 ads_msgfree(ads, res);
4410                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
4411         }
4412
4413         {
4414                 /* hack to compose the primary group sid without knowing the
4415                  * domsid */
4416
4417                 struct dom_sid domsid;
4418
4419                 sid_copy(&domsid, &tmp_user_sid);
4420
4421                 if (!sid_split_rid(&domsid, NULL)) {
4422                         ads_msgfree(ads, res);
4423                         return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
4424                 }
4425
4426                 if (!sid_compose(&tmp_primary_group_sid, &domsid, pgid)) {
4427                         ads_msgfree(ads, res);
4428                         return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
4429                 }
4430         }
4431
4432         tmp_num_sids = ads_pull_sids(ads, mem_ctx, res, "tokenGroups", &tmp_sids);
4433
4434         if (tmp_num_sids == 0 || !tmp_sids) {
4435                 ads_msgfree(ads, res);
4436                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
4437         }
4438
4439         if (num_sids) {
4440                 *num_sids = tmp_num_sids;
4441         }
4442
4443         if (sids) {
4444                 *sids = tmp_sids;
4445         }
4446
4447         if (user_sid) {
4448                 *user_sid = tmp_user_sid;
4449         }
4450
4451         if (primary_group_sid) {
4452                 *primary_group_sid = tmp_primary_group_sid;
4453         }
4454
4455         DEBUG(10,("ads_get_tokensids: returned %d sids\n", (int)tmp_num_sids + 2));
4456
4457         ads_msgfree(ads, res);
4458         return ADS_ERROR_LDAP(LDAP_SUCCESS);
4459 }
4460
4461 /**
4462  * Find a sAMAccoutName in LDAP
4463  * @param ads connection to ads server
4464  * @param mem_ctx TALLOC_CTX for allocating sid array
4465  * @param samaccountname to search
4466  * @param uac_ret uint32_t pointer userAccountControl attribute value
4467  * @param dn_ret pointer to dn
4468  * @return status of token query
4469  **/
4470 ADS_STATUS ads_find_samaccount(ADS_STRUCT *ads,
4471                                TALLOC_CTX *mem_ctx,
4472                                const char *samaccountname,
4473                                uint32_t *uac_ret,
4474                                const char **dn_ret)
4475 {
4476         ADS_STATUS status;
4477         const char *attrs[] = { "userAccountControl", NULL };
4478         const char *filter;
4479         LDAPMessage *res = NULL;
4480         char *dn = NULL;
4481         uint32_t uac = 0;
4482
4483         filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)(sAMAccountName=%s))",
4484                 samaccountname);
4485         if (filter == NULL) {
4486                 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
4487                 goto out;
4488         }
4489
4490         status = ads_do_search_all(ads, ads->config.bind_path,
4491                                    LDAP_SCOPE_SUBTREE,
4492                                    filter, attrs, &res);
4493
4494         if (!ADS_ERR_OK(status)) {
4495                 goto out;
4496         }
4497
4498         if (ads_count_replies(ads, res) != 1) {
4499                 status = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
4500                 goto out;
4501         }
4502
4503         dn = ads_get_dn(ads, talloc_tos(), res);
4504         if (dn == NULL) {
4505                 status = ADS_ERROR(LDAP_NO_MEMORY);
4506                 goto out;
4507         }
4508
4509         if (!ads_pull_uint32(ads, res, "userAccountControl", &uac)) {
4510                 status = ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
4511                 goto out;
4512         }
4513
4514         if (uac_ret) {
4515                 *uac_ret = uac;
4516         }
4517
4518         if (dn_ret) {
4519                 *dn_ret = talloc_strdup(mem_ctx, dn);
4520                 if (!*dn_ret) {
4521                         status = ADS_ERROR(LDAP_NO_MEMORY);
4522                         goto out;
4523                 }
4524         }
4525  out:
4526         TALLOC_FREE(dn);
4527         ads_msgfree(ads, res);
4528
4529         return status;
4530 }
4531
4532 /**
4533  * find our configuration path
4534  * @param ads connection to ads server
4535  * @param mem_ctx Pointer to talloc context
4536  * @param config_path Pointer to the config path
4537  * @return status of search
4538  **/
4539 ADS_STATUS ads_config_path(ADS_STRUCT *ads,
4540                            TALLOC_CTX *mem_ctx,
4541                            char **config_path)
4542 {
4543         ADS_STATUS status;
4544         LDAPMessage *res = NULL;
4545         const char *config_context = NULL;
4546         const char *attrs[] = { "configurationNamingContext", NULL };
4547
4548         status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
4549                                "(objectclass=*)", attrs, &res);
4550         if (!ADS_ERR_OK(status)) {
4551                 return status;
4552         }
4553
4554         config_context = ads_pull_string(ads, mem_ctx, res,
4555                                          "configurationNamingContext");
4556         ads_msgfree(ads, res);
4557         if (!config_context) {
4558                 return ADS_ERROR(LDAP_NO_MEMORY);
4559         }
4560
4561         if (config_path) {
4562                 *config_path = talloc_strdup(mem_ctx, config_context);
4563                 if (!*config_path) {
4564                         return ADS_ERROR(LDAP_NO_MEMORY);
4565                 }
4566         }
4567
4568         return ADS_ERROR(LDAP_SUCCESS);
4569 }
4570
4571 /**
4572  * find the displayName of an extended right
4573  * @param ads connection to ads server
4574  * @param config_path The config path
4575  * @param mem_ctx Pointer to talloc context
4576  * @param GUID struct of the rightsGUID
4577  * @return status of search
4578  **/
4579 const char *ads_get_extended_right_name_by_guid(ADS_STRUCT *ads,
4580                                                 const char *config_path,
4581                                                 TALLOC_CTX *mem_ctx,
4582                                                 const struct GUID *rights_guid)
4583 {
4584         ADS_STATUS rc;
4585         LDAPMessage *res = NULL;
4586         char *expr = NULL;
4587         const char *attrs[] = { "displayName", NULL };
4588         const char *result = NULL;
4589         const char *path;
4590
4591         if (!ads || !mem_ctx || !rights_guid) {
4592                 goto done;
4593         }
4594
4595         expr = talloc_asprintf(mem_ctx, "(rightsGuid=%s)",
4596                                GUID_string(mem_ctx, rights_guid));
4597         if (!expr) {
4598                 goto done;
4599         }
4600
4601         path = talloc_asprintf(mem_ctx, "cn=Extended-Rights,%s", config_path);
4602         if (!path) {
4603                 goto done;
4604         }
4605
4606         rc = ads_do_search_retry(ads, path, LDAP_SCOPE_SUBTREE,
4607                                  expr, attrs, &res);
4608         if (!ADS_ERR_OK(rc)) {
4609                 goto done;
4610         }
4611
4612         if (ads_count_replies(ads, res) != 1) {
4613                 goto done;
4614         }
4615
4616         result = ads_pull_string(ads, mem_ctx, res, "displayName");
4617
4618  done:
4619         ads_msgfree(ads, res);
4620         return result;
4621 }
4622
4623 /**
4624  * verify or build and verify an account ou
4625  * @param mem_ctx Pointer to talloc context
4626  * @param ads connection to ads server
4627  * @param account_ou
4628  * @return status of search
4629  **/
4630
4631 ADS_STATUS ads_check_ou_dn(TALLOC_CTX *mem_ctx,
4632                            ADS_STRUCT *ads,
4633                            const char **account_ou)
4634 {
4635         char **exploded_dn;
4636         const char *name;
4637         char *ou_string;
4638
4639         if (account_ou == NULL) {
4640                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
4641         }
4642
4643         if (*account_ou != NULL) {
4644                 exploded_dn = ldap_explode_dn(*account_ou, 0);
4645                 if (exploded_dn) {
4646                         ldap_value_free(exploded_dn);
4647                         return ADS_SUCCESS;
4648                 }
4649         }
4650
4651         ou_string = ads_ou_string(ads, *account_ou);
4652         if (!ou_string) {
4653                 return ADS_ERROR_LDAP(LDAP_INVALID_DN_SYNTAX);
4654         }
4655
4656         name = talloc_asprintf(mem_ctx, "%s,%s", ou_string,
4657                                ads->config.bind_path);
4658         SAFE_FREE(ou_string);
4659
4660         if (!name) {
4661                 return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
4662         }
4663
4664         exploded_dn = ldap_explode_dn(name, 0);
4665         if (!exploded_dn) {
4666                 return ADS_ERROR_LDAP(LDAP_INVALID_DN_SYNTAX);
4667         }
4668         ldap_value_free(exploded_dn);
4669
4670         *account_ou = name;
4671         return ADS_SUCCESS;
4672 }
4673
4674 #endif