Coverage Report

Created: 2025-11-16 06:57

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