LCOV - code coverage report
Current view: top level - source3/libads - ldap.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 1097 2178 50.4 %
Date: 2024-05-31 13:13:24 Functions: 76 100 76.0 %

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

Generated by: LCOV version 1.14