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
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 2 of the License, or
13
(at your option) any later version.
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.
20
You should have received a copy of the GNU General Public License
21
along with this program; if not, write to the Free Software
22
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31
* @brief basic ldap client-side routines for ads server communications
33
* The routines contained here should do the necessary ldap calls for
36
* Important note: attribute names passed into ads_ routines must
37
* already be in UTF-8 format. We do not convert them because in almost
38
* all cases, they are just ascii (which is represented with the same
39
* codepoints in UTF-8). This may have to change at some point
43
#define LDAP_SERVER_TREE_DELETE_OID "1.2.840.113556.1.4.805"
45
static SIG_ATOMIC_T gotalarm;
47
/***************************************************************
48
Signal function to tell us we timed out.
49
****************************************************************/
51
static void gotalarm_sig(void)
56
LDAP *ldap_open_with_timeout(const char *server, int port, unsigned int to)
62
CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
64
/* End setup timeout. */
66
ldp = ldap_open(server, port);
68
/* Teardown timeout. */
69
CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
75
static int ldap_search_with_timeout(LDAP *ld,
76
LDAP_CONST char *base,
78
LDAP_CONST char *filter,
86
struct timeval timeout;
89
/* Setup timeout for the ldap_search_ext_s call - local and remote. */
90
timeout.tv_sec = lp_ldap_timeout();
93
/* Setup alarm timeout.... Do we need both of these ? JRA. */
95
CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
96
alarm(lp_ldap_timeout());
97
/* End setup timeout. */
99
result = ldap_search_ext_s(ld, base, scope, filter, attrs,
100
attrsonly, sctrls, cctrls, &timeout,
103
/* Teardown timeout. */
104
CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
108
return LDAP_TIMELIMIT_EXCEEDED;
114
try a connection to a given ldap server, returning True and setting the servers IP
115
in the ads struct if successful
117
BOOL ads_try_connect(ADS_STRUCT *ads, const char *server )
120
struct cldap_netlogon_reply cldap_reply;
122
if (!server || !*server) {
126
DEBUG(5,("ads_try_connect: sending CLDAP request to %s (realm: %s)\n",
127
server, ads->server.realm));
129
/* this copes with inet_ntoa brokenness */
131
srv = SMB_STRDUP(server);
133
ZERO_STRUCT( cldap_reply );
135
if ( !ads_cldap_netlogon( srv, ads->server.realm, &cldap_reply ) ) {
136
DEBUG(3,("ads_try_connect: CLDAP request %s failed.\n", srv));
140
/* Check the CLDAP reply flags */
142
if ( !(cldap_reply.flags & ADS_LDAP) ) {
143
DEBUG(1,("ads_try_connect: %s's CLDAP reply says it is not an LDAP server!\n",
149
/* Fill in the ads->config values */
151
SAFE_FREE(ads->config.realm);
152
SAFE_FREE(ads->config.bind_path);
153
SAFE_FREE(ads->config.ldap_server_name);
154
SAFE_FREE(ads->server.workgroup);
156
ads->config.ldap_server_name = SMB_STRDUP(cldap_reply.hostname);
157
strupper_m(cldap_reply.domain);
158
ads->config.realm = SMB_STRDUP(cldap_reply.domain);
159
ads->config.bind_path = ads_build_dn(ads->config.realm);
160
ads->server.workgroup = SMB_STRDUP(cldap_reply.netbios_domain);
162
ads->ldap_port = LDAP_PORT;
163
ads->ldap_ip = *interpret_addr2(srv);
166
/* cache the successful connection */
168
saf_store( ads->server.workgroup, server );
173
/**********************************************************************
174
Try to find an AD dc using our internal name resolution routines
175
Try the realm first and then then workgroup name if netbios is not
177
**********************************************************************/
179
static BOOL ads_find_dc(ADS_STRUCT *ads)
183
struct ip_service *ip_list;
185
BOOL got_realm = False;
186
BOOL use_own_domain = False;
188
/* if the realm and workgroup are both empty, assume they are ours */
191
c_realm = ads->server.realm;
193
if ( !c_realm || !*c_realm ) {
194
/* special case where no realm and no workgroup means our own */
195
if ( !ads->server.workgroup || !*ads->server.workgroup ) {
196
use_own_domain = True;
197
c_realm = lp_realm();
201
if (c_realm && *c_realm)
205
/* we need to try once with the realm name and fallback to the
206
netbios domain name if we fail (if netbios has not been disabled */
208
if ( !got_realm && !lp_disable_netbios() ) {
209
c_realm = ads->server.workgroup;
210
if (!c_realm || !*c_realm) {
211
if ( use_own_domain )
212
c_realm = lp_workgroup();
215
if ( !c_realm || !*c_realm ) {
216
DEBUG(0,("ads_find_dc: no realm or workgroup! Don't know what to do\n"));
221
pstrcpy( realm, c_realm );
223
DEBUG(6,("ads_find_dc: looking for %s '%s'\n",
224
(got_realm ? "realm" : "domain"), realm));
226
if ( !get_sorted_dc_list(realm, &ip_list, &count, got_realm) ) {
227
/* fall back to netbios if we can */
228
if ( got_realm && !lp_disable_netbios() ) {
236
/* if we fail this loop, then giveup since all the IP addresses returned were dead */
237
for ( i=0; i<count; i++ ) {
240
fstrcpy( server, inet_ntoa(ip_list[i].ip) );
242
if ( !NT_STATUS_IS_OK(check_negative_conn_cache(realm, server)) )
245
if ( ads_try_connect(ads, server) ) {
250
/* keep track of failures */
251
add_failed_connection_entry( realm, server, NT_STATUS_UNSUCCESSFUL );
261
* Connect to the LDAP server
262
* @param ads Pointer to an existing ADS_STRUCT
263
* @return status of connection
265
ADS_STATUS ads_connect(ADS_STRUCT *ads)
267
int version = LDAP_VERSION3;
270
ads->last_attempt = time(NULL);
273
/* try with a user specified server */
275
if (ads->server.ldap_server &&
276
ads_try_connect(ads, ads->server.ldap_server)) {
280
if (ads_find_dc(ads)) {
284
return ADS_ERROR_SYSTEM(errno?errno:ENOENT);
287
DEBUG(3,("Connected to LDAP server %s\n", inet_ntoa(ads->ldap_ip)));
289
if (!ads->auth.user_name) {
290
/* Must use the userPrincipalName value here or sAMAccountName
291
and not servicePrincipalName; found by Guenther Deschner */
293
asprintf(&ads->auth.user_name, "%s$", global_myname() );
296
if (!ads->auth.realm) {
297
ads->auth.realm = SMB_STRDUP(ads->config.realm);
300
if (!ads->auth.kdc_server) {
301
ads->auth.kdc_server = SMB_STRDUP(inet_ntoa(ads->ldap_ip));
305
/* this is a really nasty hack to avoid ADS DNS problems. It needs a patch
306
to MIT kerberos to work (tridge) */
309
asprintf(&env, "KRB5_KDC_ADDRESS_%s", ads->config.realm);
310
setenv(env, ads->auth.kdc_server, 1);
315
/* If the caller() requested no LDAP bind, then we are done */
317
if (ads->auth.flags & ADS_AUTH_NO_BIND) {
321
/* Otherwise setup the TCP LDAP session */
323
if ( (ads->ld = ldap_open_with_timeout(ads->config.ldap_server_name,
324
LDAP_PORT, lp_ldap_timeout())) == NULL )
326
return ADS_ERROR(LDAP_OPERATIONS_ERROR);
328
ldap_set_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
330
status = ADS_ERROR(smb_ldap_start_tls(ads->ld, version));
331
if (!ADS_ERR_OK(status)) {
335
/* fill in the current time and offsets */
337
status = ads_current_time( ads );
338
if ( !ADS_ERR_OK(status) ) {
342
/* Now do the bind */
344
if (ads->auth.flags & ADS_AUTH_ANON_BIND) {
345
return ADS_ERROR(ldap_simple_bind_s( ads->ld, NULL, NULL));
348
if (ads->auth.flags & ADS_AUTH_SIMPLE_BIND) {
349
return ADS_ERROR(ldap_simple_bind_s( ads->ld, ads->auth.user_name, ads->auth.password));
352
return ads_sasl_bind(ads);
356
Duplicate a struct berval into talloc'ed memory
358
static struct berval *dup_berval(TALLOC_CTX *ctx, const struct berval *in_val)
360
struct berval *value;
362
if (!in_val) return NULL;
364
value = TALLOC_ZERO_P(ctx, struct berval);
367
if (in_val->bv_len == 0) return value;
369
value->bv_len = in_val->bv_len;
370
value->bv_val = TALLOC_MEMDUP(ctx, in_val->bv_val, in_val->bv_len);
375
Make a values list out of an array of (struct berval *)
377
static struct berval **ads_dup_values(TALLOC_CTX *ctx,
378
const struct berval **in_vals)
380
struct berval **values;
383
if (!in_vals) return NULL;
384
for (i=0; in_vals[i]; i++)
386
values = TALLOC_ZERO_ARRAY(ctx, struct berval *, i+1);
387
if (!values) return NULL;
389
for (i=0; in_vals[i]; i++) {
390
values[i] = dup_berval(ctx, in_vals[i]);
396
UTF8-encode a values list out of an array of (char *)
398
static char **ads_push_strvals(TALLOC_CTX *ctx, const char **in_vals)
403
if (!in_vals) return NULL;
404
for (i=0; in_vals[i]; i++)
406
values = TALLOC_ZERO_ARRAY(ctx, char *, i+1);
407
if (!values) return NULL;
409
for (i=0; in_vals[i]; i++) {
410
push_utf8_talloc(ctx, &values[i], in_vals[i]);
416
Pull a (char *) array out of a UTF8-encoded values list
418
static char **ads_pull_strvals(TALLOC_CTX *ctx, const char **in_vals)
423
if (!in_vals) return NULL;
424
for (i=0; in_vals[i]; i++)
426
values = TALLOC_ZERO_ARRAY(ctx, char *, i+1);
427
if (!values) return NULL;
429
for (i=0; in_vals[i]; i++) {
430
pull_utf8_talloc(ctx, &values[i], in_vals[i]);
436
* Do a search with paged results. cookie must be null on the first
437
* call, and then returned on each subsequent call. It will be null
438
* again when the entire search is complete
439
* @param ads connection to ads server
440
* @param bind_path Base dn for the search
441
* @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
442
* @param expr Search expression - specified in local charset
443
* @param attrs Attributes to retrieve - specified in utf8 or ascii
444
* @param res ** which will contain results - free res* with ads_msgfree()
445
* @param count Number of entries retrieved on this page
446
* @param cookie The paged results cookie to be returned on subsequent calls
447
* @return status of search
449
ADS_STATUS ads_do_paged_search_args(ADS_STRUCT *ads, const char *bind_path,
450
int scope, const char *expr,
451
const char **attrs, void *args, void **res,
452
int *count, void **cookie)
455
char *utf8_expr, *utf8_path, **search_attrs;
456
LDAPControl PagedResults, NoReferrals, ExtendedDn, *controls[4], **rcontrols;
457
BerElement *cookie_be = NULL;
458
struct berval *cookie_bv= NULL;
459
BerElement *extdn_be = NULL;
460
struct berval *extdn_bv= NULL;
463
ads_control *external_control = (ads_control *) args;
467
if (!(ctx = talloc_init("ads_do_paged_search_args")))
468
return ADS_ERROR(LDAP_NO_MEMORY);
470
/* 0 means the conversion worked but the result was empty
471
so we only fail if it's -1. In any case, it always
472
at least nulls out the dest */
473
if ((push_utf8_talloc(ctx, &utf8_expr, expr) == (size_t)-1) ||
474
(push_utf8_talloc(ctx, &utf8_path, bind_path) == (size_t)-1)) {
479
if (!attrs || !(*attrs))
482
/* This would be the utf8-encoded version...*/
483
/* if (!(search_attrs = ads_push_strvals(ctx, attrs))) */
484
if (!(str_list_copy(&search_attrs, attrs))) {
491
/* Paged results only available on ldap v3 or later */
492
ldap_get_option(ads->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
493
if (version < LDAP_VERSION3) {
494
rc = LDAP_NOT_SUPPORTED;
498
cookie_be = ber_alloc_t(LBER_USE_DER);
499
if (cookie && *cookie) {
500
ber_printf(cookie_be, "{iO}", (ber_int_t) 1000, *cookie);
501
ber_bvfree(*cookie); /* don't need it from last time */
504
ber_printf(cookie_be, "{io}", (ber_int_t) 1000, "", 0);
506
ber_flatten(cookie_be, &cookie_bv);
507
PagedResults.ldctl_oid = CONST_DISCARD(char *, ADS_PAGE_CTL_OID);
508
PagedResults.ldctl_iscritical = (char) 1;
509
PagedResults.ldctl_value.bv_len = cookie_bv->bv_len;
510
PagedResults.ldctl_value.bv_val = cookie_bv->bv_val;
512
NoReferrals.ldctl_oid = CONST_DISCARD(char *, ADS_NO_REFERRALS_OID);
513
NoReferrals.ldctl_iscritical = (char) 0;
514
NoReferrals.ldctl_value.bv_len = 0;
515
NoReferrals.ldctl_value.bv_val = CONST_DISCARD(char *, "");
517
if (external_control && strequal(external_control->control, ADS_EXTENDED_DN_OID)) {
519
ExtendedDn.ldctl_oid = CONST_DISCARD(char *, external_control->control);
520
ExtendedDn.ldctl_iscritical = (char) external_control->critical;
522
/* win2k does not accept a ldctl_value beeing passed in */
524
if (external_control->val != 0) {
526
if ((extdn_be = ber_alloc_t(LBER_USE_DER)) == NULL ) {
531
if ((ber_printf(extdn_be, "{i}", (ber_int_t) external_control->val)) == -1) {
535
if ((ber_flatten(extdn_be, &extdn_bv)) == -1) {
540
ExtendedDn.ldctl_value.bv_len = extdn_bv->bv_len;
541
ExtendedDn.ldctl_value.bv_val = extdn_bv->bv_val;
544
ExtendedDn.ldctl_value.bv_len = 0;
545
ExtendedDn.ldctl_value.bv_val = NULL;
548
controls[0] = &NoReferrals;
549
controls[1] = &PagedResults;
550
controls[2] = &ExtendedDn;
554
controls[0] = &NoReferrals;
555
controls[1] = &PagedResults;
559
/* we need to disable referrals as the openldap libs don't
560
handle them and paged results at the same time. Using them
561
together results in the result record containing the server
562
page control being removed from the result list (tridge/jmcd)
564
leaving this in despite the control that says don't generate
565
referrals, in case the server doesn't support it (jmcd)
567
ldap_set_option(ads->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
569
rc = ldap_search_with_timeout(ads->ld, utf8_path, scope, utf8_expr,
570
search_attrs, 0, controls,
572
(LDAPMessage **)res);
574
ber_free(cookie_be, 1);
575
ber_bvfree(cookie_bv);
578
DEBUG(3,("ads_do_paged_search_args: ldap_search_with_timeout(%s) -> %s\n", expr,
579
ldap_err2string(rc)));
583
rc = ldap_parse_result(ads->ld, *res, NULL, NULL, NULL,
584
NULL, &rcontrols, 0);
590
for (i=0; rcontrols[i]; i++) {
591
if (strcmp(ADS_PAGE_CTL_OID, rcontrols[i]->ldctl_oid) == 0) {
592
cookie_be = ber_init(&rcontrols[i]->ldctl_value);
593
ber_scanf(cookie_be,"{iO}", (ber_int_t *) count,
595
/* the berval is the cookie, but must be freed when
597
if (cookie_bv->bv_len) /* still more to do */
598
*cookie=ber_bvdup(cookie_bv);
601
ber_bvfree(cookie_bv);
602
ber_free(cookie_be, 1);
606
ldap_controls_free(rcontrols);
612
ber_free(extdn_be, 1);
616
ber_bvfree(extdn_bv);
619
/* if/when we decide to utf8-encode attrs, take out this next line */
620
str_list_free(&search_attrs);
622
return ADS_ERROR(rc);
625
ADS_STATUS ads_do_paged_search(ADS_STRUCT *ads, const char *bind_path,
626
int scope, const char *expr,
627
const char **attrs, void **res,
628
int *count, void **cookie)
630
return ads_do_paged_search_args(ads, bind_path, scope, expr, attrs, NULL, res, count, cookie);
635
* Get all results for a search. This uses ads_do_paged_search() to return
636
* all entries in a large search.
637
* @param ads connection to ads server
638
* @param bind_path Base dn for the search
639
* @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
640
* @param expr Search expression
641
* @param attrs Attributes to retrieve
642
* @param res ** which will contain results - free res* with ads_msgfree()
643
* @return status of search
645
ADS_STATUS ads_do_search_all_args(ADS_STRUCT *ads, const char *bind_path,
646
int scope, const char *expr,
647
const char **attrs, void *args, void **res)
654
status = ads_do_paged_search_args(ads, bind_path, scope, expr, attrs, args, res,
657
if (!ADS_ERR_OK(status))
660
#ifdef HAVE_LDAP_ADD_RESULT_ENTRY
664
LDAPMessage *msg, *next;
666
status2 = ads_do_paged_search_args(ads, bind_path, scope, expr,
667
attrs, args, &res2, &count, &cookie);
669
if (!ADS_ERR_OK(status2)) break;
671
/* this relies on the way that ldap_add_result_entry() works internally. I hope
672
that this works on all ldap libs, but I have only tested with openldap */
673
for (msg = ads_first_entry(ads, res2); msg; msg = next) {
674
next = ads_next_entry(ads, msg);
675
ldap_add_result_entry((LDAPMessage **)res, msg);
677
/* note that we do not free res2, as the memory is now
678
part of the main returned list */
681
DEBUG(0, ("no ldap_add_result_entry() support in LDAP libs!\n"));
682
status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
688
ADS_STATUS ads_do_search_all(ADS_STRUCT *ads, const char *bind_path,
689
int scope, const char *expr,
690
const char **attrs, void **res)
692
return ads_do_search_all_args(ads, bind_path, scope, expr, attrs, NULL, res);
696
* Run a function on all results for a search. Uses ads_do_paged_search() and
697
* runs the function as each page is returned, using ads_process_results()
698
* @param ads connection to ads server
699
* @param bind_path Base dn for the search
700
* @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
701
* @param expr Search expression - specified in local charset
702
* @param attrs Attributes to retrieve - specified in UTF-8 or ascii
703
* @param fn Function which takes attr name, values list, and data_area
704
* @param data_area Pointer which is passed to function on each call
705
* @return status of search
707
ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path,
708
int scope, const char *expr, const char **attrs,
709
BOOL(*fn)(char *, void **, void *),
717
status = ads_do_paged_search(ads, bind_path, scope, expr, attrs, &res,
720
if (!ADS_ERR_OK(status)) return status;
722
ads_process_results(ads, res, fn, data_area);
723
ads_msgfree(ads, res);
726
status = ads_do_paged_search(ads, bind_path, scope, expr, attrs,
727
&res, &count, &cookie);
729
if (!ADS_ERR_OK(status)) break;
731
ads_process_results(ads, res, fn, data_area);
732
ads_msgfree(ads, res);
739
* Do a search with a timeout.
740
* @param ads connection to ads server
741
* @param bind_path Base dn for the search
742
* @param scope Scope of search (LDAP_SCOPE_BASE | LDAP_SCOPE_ONE | LDAP_SCOPE_SUBTREE)
743
* @param expr Search expression
744
* @param attrs Attributes to retrieve
745
* @param res ** which will contain results - free res* with ads_msgfree()
746
* @return status of search
748
ADS_STATUS ads_do_search(ADS_STRUCT *ads, const char *bind_path, int scope,
750
const char **attrs, void **res)
753
char *utf8_expr, *utf8_path, **search_attrs = NULL;
757
if (!(ctx = talloc_init("ads_do_search"))) {
758
DEBUG(1,("ads_do_search: talloc_init() failed!"));
759
return ADS_ERROR(LDAP_NO_MEMORY);
762
/* 0 means the conversion worked but the result was empty
763
so we only fail if it's negative. In any case, it always
764
at least nulls out the dest */
765
if ((push_utf8_talloc(ctx, &utf8_expr, expr) == (size_t)-1) ||
766
(push_utf8_talloc(ctx, &utf8_path, bind_path) == (size_t)-1)) {
767
DEBUG(1,("ads_do_search: push_utf8_talloc() failed!"));
772
if (!attrs || !(*attrs))
775
/* This would be the utf8-encoded version...*/
776
/* if (!(search_attrs = ads_push_strvals(ctx, attrs))) */
777
if (!(str_list_copy(&search_attrs, attrs)))
779
DEBUG(1,("ads_do_search: str_list_copy() failed!"));
785
/* see the note in ads_do_paged_search - we *must* disable referrals */
786
ldap_set_option(ads->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
788
rc = ldap_search_with_timeout(ads->ld, utf8_path, scope, utf8_expr,
789
search_attrs, 0, NULL, NULL,
791
(LDAPMessage **)res);
793
if (rc == LDAP_SIZELIMIT_EXCEEDED) {
794
DEBUG(3,("Warning! sizelimit exceeded in ldap. Truncating.\n"));
800
/* if/when we decide to utf8-encode attrs, take out this next line */
801
str_list_free(&search_attrs);
802
return ADS_ERROR(rc);
805
* Do a general ADS search
806
* @param ads connection to ads server
807
* @param res ** which will contain results - free res* with ads_msgfree()
808
* @param expr Search expression
809
* @param attrs Attributes to retrieve
810
* @return status of search
812
ADS_STATUS ads_search(ADS_STRUCT *ads, void **res,
816
return ads_do_search(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,
821
* Do a search on a specific DistinguishedName
822
* @param ads connection to ads server
823
* @param res ** which will contain results - free res* with ads_msgfree()
824
* @param dn DistinguishName to search
825
* @param attrs Attributes to retrieve
826
* @return status of search
828
ADS_STATUS ads_search_dn(ADS_STRUCT *ads, void *_res,
832
void **res = (void **)_res;
833
return ads_do_search(ads, dn, LDAP_SCOPE_BASE, "(objectclass=*)", attrs, res);
837
* Free up memory from a ads_search
838
* @param ads connection to ads server
839
* @param msg Search results to free
841
void ads_msgfree(ADS_STRUCT *ads, void *msg)
848
* Free up memory from various ads requests
849
* @param ads connection to ads server
850
* @param mem Area to free
852
void ads_memfree(ADS_STRUCT *ads, void *mem)
858
* Get a dn from search results
859
* @param ads connection to ads server
860
* @param msg Search result
863
char *ads_get_dn(ADS_STRUCT *ads, void *msg)
865
char *utf8_dn, *unix_dn;
867
utf8_dn = ldap_get_dn(ads->ld, msg);
870
DEBUG (5, ("ads_get_dn: ldap_get_dn failed\n"));
874
if (pull_utf8_allocate(&unix_dn, utf8_dn) == (size_t)-1) {
875
DEBUG(0,("ads_get_dn: string conversion failure utf8 [%s]\n",
879
ldap_memfree(utf8_dn);
884
* Get a canonical dn from search results
885
* @param ads connection to ads server
886
* @param msg Search result
889
char *ads_get_dn_canonical(ADS_STRUCT *ads, void *msg)
891
#ifdef HAVE_LDAP_DN2AD_CANONICAL
892
return ldap_dn2ad_canonical(ads_get_dn(ads, msg));
899
* Get the parent from a dn
900
* @param dn the dn to return the parent from
901
* @return parent dn string
903
char *ads_parent_dn(const char *dn)
921
* Find a machine account given a hostname
922
* @param ads connection to ads server
923
* @param res ** which will contain results - free res* with ads_msgfree()
924
* @param host Hostname to search for
925
* @return status of search
927
ADS_STATUS ads_find_machine_acct(ADS_STRUCT *ads, void **res, const char *machine)
931
const char *attrs[] = {"*", "nTSecurityDescriptor", NULL};
935
/* the easiest way to find a machine account anywhere in the tree
936
is to look for hostname$ */
937
if (asprintf(&expr, "(samAccountName=%s$)", machine) == -1) {
938
DEBUG(1, ("asprintf failed!\n"));
939
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
942
status = ads_search(ads, res, expr, attrs);
948
* Initialize a list of mods to be used in a modify request
949
* @param ctx An initialized TALLOC_CTX
950
* @return allocated ADS_MODLIST
952
ADS_MODLIST ads_init_mods(TALLOC_CTX *ctx)
954
#define ADS_MODLIST_ALLOC_SIZE 10
957
if ((mods = TALLOC_ZERO_ARRAY(ctx, LDAPMod *, ADS_MODLIST_ALLOC_SIZE + 1)))
958
/* -1 is safety to make sure we don't go over the end.
959
need to reset it to NULL before doing ldap modify */
960
mods[ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
962
return (ADS_MODLIST)mods;
967
add an attribute to the list, with values list already constructed
969
static ADS_STATUS ads_modlist_add(TALLOC_CTX *ctx, ADS_MODLIST *mods,
970
int mod_op, const char *name,
973
const void **invals = (const void **)_invals;
975
LDAPMod **modlist = (LDAPMod **) *mods;
976
struct berval **ber_values = NULL;
977
char **char_values = NULL;
980
mod_op = LDAP_MOD_DELETE;
982
if (mod_op & LDAP_MOD_BVALUES)
983
ber_values = ads_dup_values(ctx,
984
(const struct berval **)invals);
986
char_values = ads_push_strvals(ctx,
987
(const char **) invals);
990
/* find the first empty slot */
991
for (curmod=0; modlist[curmod] && modlist[curmod] != (LDAPMod *) -1;
993
if (modlist[curmod] == (LDAPMod *) -1) {
994
if (!(modlist = TALLOC_REALLOC_ARRAY(ctx, modlist, LDAPMod *,
995
curmod+ADS_MODLIST_ALLOC_SIZE+1)))
996
return ADS_ERROR(LDAP_NO_MEMORY);
997
memset(&modlist[curmod], 0,
998
ADS_MODLIST_ALLOC_SIZE*sizeof(LDAPMod *));
999
modlist[curmod+ADS_MODLIST_ALLOC_SIZE] = (LDAPMod *) -1;
1000
*mods = (ADS_MODLIST)modlist;
1003
if (!(modlist[curmod] = TALLOC_ZERO_P(ctx, LDAPMod)))
1004
return ADS_ERROR(LDAP_NO_MEMORY);
1005
modlist[curmod]->mod_type = talloc_strdup(ctx, name);
1006
if (mod_op & LDAP_MOD_BVALUES) {
1007
modlist[curmod]->mod_bvalues = ber_values;
1008
} else if (mod_op & LDAP_MOD_DELETE) {
1009
modlist[curmod]->mod_values = NULL;
1011
modlist[curmod]->mod_values = char_values;
1014
modlist[curmod]->mod_op = mod_op;
1015
return ADS_ERROR(LDAP_SUCCESS);
1019
* Add a single string value to a mod list
1020
* @param ctx An initialized TALLOC_CTX
1021
* @param mods An initialized ADS_MODLIST
1022
* @param name The attribute name to add
1023
* @param val The value to add - NULL means DELETE
1024
* @return ADS STATUS indicating success of add
1026
ADS_STATUS ads_mod_str(TALLOC_CTX *ctx, ADS_MODLIST *mods,
1027
const char *name, const char *val)
1029
const char *values[2];
1035
return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
1036
return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE, name, values);
1040
* Add an array of string values to a mod list
1041
* @param ctx An initialized TALLOC_CTX
1042
* @param mods An initialized ADS_MODLIST
1043
* @param name The attribute name to add
1044
* @param vals The array of string values to add - NULL means DELETE
1045
* @return ADS STATUS indicating success of add
1047
ADS_STATUS ads_mod_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
1048
const char *name, const char **vals)
1051
return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
1052
return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE,
1053
name, (const void **) vals);
1058
* Add a single ber-encoded value to a mod list
1059
* @param ctx An initialized TALLOC_CTX
1060
* @param mods An initialized ADS_MODLIST
1061
* @param name The attribute name to add
1062
* @param val The value to add - NULL means DELETE
1063
* @return ADS STATUS indicating success of add
1065
static ADS_STATUS ads_mod_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods,
1066
const char *name, const struct berval *val)
1068
const struct berval *values[2];
1073
return ads_modlist_add(ctx, mods, LDAP_MOD_DELETE, name, NULL);
1074
return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE|LDAP_MOD_BVALUES,
1075
name, (const void **) values);
1080
* Perform an ldap modify
1081
* @param ads connection to ads server
1082
* @param mod_dn DistinguishedName to modify
1083
* @param mods list of modifications to perform
1084
* @return status of modify
1086
ADS_STATUS ads_gen_mod(ADS_STRUCT *ads, const char *mod_dn, ADS_MODLIST mods)
1089
char *utf8_dn = NULL;
1091
this control is needed to modify that contains a currently
1092
non-existent attribute (but allowable for the object) to run
1094
LDAPControl PermitModify = {
1095
CONST_DISCARD(char *, ADS_PERMIT_MODIFY_OID),
1098
LDAPControl *controls[2];
1100
controls[0] = &PermitModify;
1103
if (push_utf8_allocate(&utf8_dn, mod_dn) == -1) {
1104
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1107
/* find the end of the list, marked by NULL or -1 */
1108
for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
1109
/* make sure the end of the list is NULL */
1111
ret = ldap_modify_ext_s(ads->ld, utf8_dn,
1112
(LDAPMod **) mods, controls, NULL);
1114
return ADS_ERROR(ret);
1118
* Perform an ldap add
1119
* @param ads connection to ads server
1120
* @param new_dn DistinguishedName to add
1121
* @param mods list of attributes and values for DN
1122
* @return status of add
1124
ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods)
1127
char *utf8_dn = NULL;
1129
if (push_utf8_allocate(&utf8_dn, new_dn) == -1) {
1130
DEBUG(1, ("ads_gen_add: push_utf8_allocate failed!"));
1131
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1134
/* find the end of the list, marked by NULL or -1 */
1135
for(i=0;(mods[i]!=0)&&(mods[i]!=(LDAPMod *) -1);i++);
1136
/* make sure the end of the list is NULL */
1139
ret = ldap_add_s(ads->ld, utf8_dn, (LDAPMod**)mods);
1141
return ADS_ERROR(ret);
1145
* Delete a DistinguishedName
1146
* @param ads connection to ads server
1147
* @param new_dn DistinguishedName to delete
1148
* @return status of delete
1150
ADS_STATUS ads_del_dn(ADS_STRUCT *ads, char *del_dn)
1153
char *utf8_dn = NULL;
1154
if (push_utf8_allocate(&utf8_dn, del_dn) == -1) {
1155
DEBUG(1, ("ads_del_dn: push_utf8_allocate failed!"));
1156
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1159
ret = ldap_delete_s(ads->ld, utf8_dn);
1160
return ADS_ERROR(ret);
1164
* Build an org unit string
1165
* if org unit is Computers or blank then assume a container, otherwise
1166
* assume a / separated list of organisational units.
1167
* jmcd: '\' is now used for escapes so certain chars can be in the ou (e.g. #)
1168
* @param ads connection to ads server
1169
* @param org_unit Organizational unit
1170
* @return org unit string - caller must free
1172
char *ads_ou_string(ADS_STRUCT *ads, const char *org_unit)
1176
if (!org_unit || !*org_unit) {
1178
ret = ads_default_ou_string(ads, WELL_KNOWN_GUID_COMPUTERS);
1180
/* samba4 might not yet respond to a wellknownobject-query */
1181
return ret ? ret : SMB_STRDUP("cn=Computers");
1184
if (strequal(org_unit, "Computers")) {
1185
return SMB_STRDUP("cn=Computers");
1188
/* jmcd: removed "\\" from the separation chars, because it is
1189
needed as an escape for chars like '#' which are valid in an
1191
return ads_build_path(org_unit, "/", "ou=", 1);
1195
* Get a org unit string for a well-known GUID
1196
* @param ads connection to ads server
1197
* @param wknguid Well known GUID
1198
* @return org unit string - caller must free
1200
char *ads_default_ou_string(ADS_STRUCT *ads, const char *wknguid)
1204
char *base, *wkn_dn, *ret, **wkn_dn_exp, **bind_dn_exp;
1205
const char *attrs[] = {"distinguishedName", NULL};
1206
int new_ln, wkn_ln, bind_ln, i;
1208
if (wknguid == NULL) {
1212
if (asprintf(&base, "<WKGUID=%s,%s>", wknguid, ads->config.bind_path ) == -1) {
1213
DEBUG(1, ("asprintf failed!\n"));
1217
status = ads_search_dn(ads, &res, base, attrs);
1218
if (!ADS_ERR_OK(status)) {
1219
DEBUG(1,("Failed while searching for: %s\n", base));
1225
if (ads_count_replies(ads, res) != 1) {
1229
/* substitute the bind-path from the well-known-guid-search result */
1230
wkn_dn = ads_get_dn(ads, res);
1231
wkn_dn_exp = ldap_explode_dn(wkn_dn, 0);
1232
bind_dn_exp = ldap_explode_dn(ads->config.bind_path, 0);
1234
for (wkn_ln=0; wkn_dn_exp[wkn_ln]; wkn_ln++)
1236
for (bind_ln=0; bind_dn_exp[bind_ln]; bind_ln++)
1239
new_ln = wkn_ln - bind_ln;
1241
ret = wkn_dn_exp[0];
1243
for (i=1; i < new_ln; i++) {
1245
asprintf(&s, "%s,%s", ret, wkn_dn_exp[i]);
1246
ret = SMB_STRDUP(s);
1250
ads_memfree(ads, wkn_dn);
1251
ldap_value_free(wkn_dn_exp);
1252
ldap_value_free(bind_dn_exp);
1258
* Adds (appends) an item to an attribute array, rather then
1259
* replacing the whole list
1260
* @param ctx An initialized TALLOC_CTX
1261
* @param mods An initialized ADS_MODLIST
1262
* @param name name of the ldap attribute to append to
1263
* @param vals an array of values to add
1264
* @return status of addition
1267
ADS_STATUS ads_add_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
1268
const char *name, const char **vals)
1270
return ads_modlist_add(ctx, mods, LDAP_MOD_ADD, name, (const void **) vals);
1274
* Determines the computer account's current KVNO via an LDAP lookup
1275
* @param ads An initialized ADS_STRUCT
1276
* @param machine_name the NetBIOS name of the computer, which is used to identify the computer account.
1277
* @return the kvno for the computer account, or -1 in case of a failure.
1280
uint32 ads_get_kvno(ADS_STRUCT *ads, const char *machine_name)
1282
LDAPMessage *res = NULL;
1283
uint32 kvno = (uint32)-1; /* -1 indicates a failure */
1285
const char *attrs[] = {"msDS-KeyVersionNumber", NULL};
1286
char *dn_string = NULL;
1287
ADS_STATUS ret = ADS_ERROR(LDAP_SUCCESS);
1289
DEBUG(5,("ads_get_kvno: Searching for host %s\n", machine_name));
1290
if (asprintf(&filter, "(samAccountName=%s$)", machine_name) == -1) {
1293
ret = ads_search(ads, (void**)(void *)&res, filter, attrs);
1295
if (!ADS_ERR_OK(ret) && ads_count_replies(ads, res)) {
1296
DEBUG(1,("ads_get_kvno: Computer Account For %s not found.\n", machine_name));
1297
ads_msgfree(ads, res);
1301
dn_string = ads_get_dn(ads, res);
1303
DEBUG(0,("ads_get_kvno: out of memory.\n"));
1304
ads_msgfree(ads, res);
1307
DEBUG(5,("ads_get_kvno: Using: %s\n", dn_string));
1308
ads_memfree(ads, dn_string);
1310
/* ---------------------------------------------------------
1311
* 0 is returned as a default KVNO from this point on...
1312
* This is done because Windows 2000 does not support key
1313
* version numbers. Chances are that a failure in the next
1314
* step is simply due to Windows 2000 being used for a
1315
* domain controller. */
1318
if (!ads_pull_uint32(ads, res, "msDS-KeyVersionNumber", &kvno)) {
1319
DEBUG(3,("ads_get_kvno: Error Determining KVNO!\n"));
1320
DEBUG(3,("ads_get_kvno: Windows 2000 does not support KVNO's, so this may be normal.\n"));
1321
ads_msgfree(ads, res);
1326
DEBUG(5,("ads_get_kvno: Looked Up KVNO of: %d\n", kvno));
1327
ads_msgfree(ads, res);
1332
* This clears out all registered spn's for a given hostname
1333
* @param ads An initilaized ADS_STRUCT
1334
* @param machine_name the NetBIOS name of the computer.
1335
* @return 0 upon success, non-zero otherwise.
1338
ADS_STATUS ads_clear_service_principal_names(ADS_STRUCT *ads, const char *machine_name)
1341
LDAPMessage *res = NULL;
1343
const char *servicePrincipalName[1] = {NULL};
1344
ADS_STATUS ret = ADS_ERROR(LDAP_SUCCESS);
1345
char *dn_string = NULL;
1347
ret = ads_find_machine_acct(ads, (void **)(void *)&res, machine_name);
1348
if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) {
1349
DEBUG(5,("ads_clear_service_principal_names: WARNING: Host Account for %s not found... skipping operation.\n", machine_name));
1350
DEBUG(5,("ads_clear_service_principal_names: WARNING: Service Principals for %s have NOT been cleared.\n", machine_name));
1351
ads_msgfree(ads, res);
1352
return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
1355
DEBUG(5,("ads_clear_service_principal_names: Host account for %s found\n", machine_name));
1356
ctx = talloc_init("ads_clear_service_principal_names");
1358
ads_msgfree(ads, res);
1359
return ADS_ERROR(LDAP_NO_MEMORY);
1362
if (!(mods = ads_init_mods(ctx))) {
1363
talloc_destroy(ctx);
1364
ads_msgfree(ads, res);
1365
return ADS_ERROR(LDAP_NO_MEMORY);
1367
ret = ads_mod_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
1368
if (!ADS_ERR_OK(ret)) {
1369
DEBUG(1,("ads_clear_service_principal_names: Error creating strlist.\n"));
1370
ads_msgfree(ads, res);
1371
talloc_destroy(ctx);
1374
dn_string = ads_get_dn(ads, res);
1376
talloc_destroy(ctx);
1377
ads_msgfree(ads, res);
1378
return ADS_ERROR(LDAP_NO_MEMORY);
1380
ret = ads_gen_mod(ads, dn_string, mods);
1381
ads_memfree(ads,dn_string);
1382
if (!ADS_ERR_OK(ret)) {
1383
DEBUG(1,("ads_clear_service_principal_names: Error: Updating Service Principals for machine %s in LDAP\n",
1385
ads_msgfree(ads, res);
1386
talloc_destroy(ctx);
1390
ads_msgfree(ads, res);
1391
talloc_destroy(ctx);
1396
* This adds a service principal name to an existing computer account
1397
* (found by hostname) in AD.
1398
* @param ads An initialized ADS_STRUCT
1399
* @param machine_name the NetBIOS name of the computer, which is used to identify the computer account.
1400
* @param my_fqdn The fully qualified DNS name of the machine
1401
* @param spn A string of the service principal to add, i.e. 'host'
1402
* @return 0 upon sucess, or non-zero if a failure occurs
1405
ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_name,
1406
const char *my_fqdn, const char *spn)
1410
LDAPMessage *res = NULL;
1413
char *dn_string = NULL;
1414
const char *servicePrincipalName[3] = {NULL, NULL, NULL};
1416
ret = ads_find_machine_acct(ads, (void **)(void *)&res, machine_name);
1417
if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) {
1418
DEBUG(1,("ads_add_service_principal_name: WARNING: Host Account for %s not found... skipping operation.\n",
1420
DEBUG(1,("ads_add_service_principal_name: WARNING: Service Principal '%s/%s@%s' has NOT been added.\n",
1421
spn, machine_name, ads->config.realm));
1422
ads_msgfree(ads, res);
1423
return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
1426
DEBUG(1,("ads_add_service_principal_name: Host account for %s found\n", machine_name));
1427
if (!(ctx = talloc_init("ads_add_service_principal_name"))) {
1428
ads_msgfree(ads, res);
1429
return ADS_ERROR(LDAP_NO_MEMORY);
1432
/* add short name spn */
1434
if ( (psp1 = talloc_asprintf(ctx, "%s/%s", spn, machine_name)) == NULL ) {
1435
talloc_destroy(ctx);
1436
ads_msgfree(ads, res);
1437
return ADS_ERROR(LDAP_NO_MEMORY);
1440
strlower_m(&psp1[strlen(spn)]);
1441
servicePrincipalName[0] = psp1;
1443
DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n",
1444
psp1, machine_name));
1447
/* add fully qualified spn */
1449
if ( (psp2 = talloc_asprintf(ctx, "%s/%s", spn, my_fqdn)) == NULL ) {
1450
ret = ADS_ERROR(LDAP_NO_MEMORY);
1454
strlower_m(&psp2[strlen(spn)]);
1455
servicePrincipalName[1] = psp2;
1457
DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n",
1458
psp2, machine_name));
1460
if ( (mods = ads_init_mods(ctx)) == NULL ) {
1461
ret = ADS_ERROR(LDAP_NO_MEMORY);
1465
ret = ads_add_strlist(ctx, &mods, "servicePrincipalName", servicePrincipalName);
1466
if (!ADS_ERR_OK(ret)) {
1467
DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n"));
1471
if ( (dn_string = ads_get_dn(ads, res)) == NULL ) {
1472
ret = ADS_ERROR(LDAP_NO_MEMORY);
1476
ret = ads_gen_mod(ads, dn_string, mods);
1477
ads_memfree(ads,dn_string);
1478
if (!ADS_ERR_OK(ret)) {
1479
DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n"));
1485
ads_msgfree(ads, res);
1490
* adds a machine account to the ADS server
1491
* @param ads An intialized ADS_STRUCT
1492
* @param machine_name - the NetBIOS machine name of this account.
1493
* @param account_type A number indicating the type of account to create
1494
* @param org_unit The LDAP path in which to place this account
1495
* @return 0 upon success, or non-zero otherwise
1498
ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name,
1499
const char *org_unit)
1502
char *samAccountName, *controlstr;
1506
const char *objectClass[] = {"top", "person", "organizationalPerson",
1507
"user", "computer", NULL};
1508
LDAPMessage *res = NULL;
1509
uint32 acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\
1510
UF_DONT_EXPIRE_PASSWD |\
1511
UF_ACCOUNTDISABLE );
1513
if (!(ctx = talloc_init("ads_add_machine_acct")))
1514
return ADS_ERROR(LDAP_NO_MEMORY);
1516
ret = ADS_ERROR(LDAP_NO_MEMORY);
1518
new_dn = talloc_asprintf(ctx, "cn=%s,%s", machine_name, org_unit);
1519
samAccountName = talloc_asprintf(ctx, "%s$", machine_name);
1521
if ( !new_dn || !samAccountName ) {
1525
#ifndef ENCTYPE_ARCFOUR_HMAC
1526
acct_control |= UF_USE_DES_KEY_ONLY;
1529
if (!(controlstr = talloc_asprintf(ctx, "%u", acct_control))) {
1533
if (!(mods = ads_init_mods(ctx))) {
1537
ads_mod_str(ctx, &mods, "cn", machine_name);
1538
ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName);
1539
ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
1540
ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
1542
ret = ads_gen_add(ads, new_dn, mods);
1545
ads_msgfree(ads, res);
1546
talloc_destroy(ctx);
1552
dump a binary result from ldap
1554
static void dump_binary(const char *field, struct berval **values)
1557
for (i=0; values[i]; i++) {
1558
printf("%s: ", field);
1559
for (j=0; j<values[i]->bv_len; j++) {
1560
printf("%02X", (unsigned char)values[i]->bv_val[j]);
1566
static void dump_guid(const char *field, struct berval **values)
1570
for (i=0; values[i]; i++) {
1571
memcpy(guid.info, values[i]->bv_val, sizeof(guid.info));
1572
printf("%s: %s\n", field,
1573
smb_uuid_string_static(smb_uuid_unpack_static(guid)));
1578
dump a sid result from ldap
1580
static void dump_sid(const char *field, struct berval **values)
1583
for (i=0; values[i]; i++) {
1585
sid_parse(values[i]->bv_val, values[i]->bv_len, &sid);
1586
printf("%s: %s\n", field, sid_string_static(&sid));
1591
dump ntSecurityDescriptor
1593
static void dump_sd(const char *filed, struct berval **values)
1598
TALLOC_CTX *ctx = 0;
1600
if (!(ctx = talloc_init("sec_io_desc")))
1604
prs_init(&ps, values[0]->bv_len, ctx, UNMARSHALL);
1605
prs_copy_data_in(&ps, values[0]->bv_val, values[0]->bv_len);
1606
prs_set_offset(&ps,0);
1609
if (!sec_io_desc("sd", &psd, &ps, 1)) {
1611
talloc_destroy(ctx);
1614
if (psd) ads_disp_sd(psd);
1617
talloc_destroy(ctx);
1621
dump a string result from ldap
1623
static void dump_string(const char *field, char **values)
1626
for (i=0; values[i]; i++) {
1627
printf("%s: %s\n", field, values[i]);
1632
dump a field from LDAP on stdout
1636
static BOOL ads_dump_field(char *field, void **values, void *data_area)
1641
void (*handler)(const char *, struct berval **);
1643
{"objectGUID", False, dump_guid},
1644
{"netbootGUID", False, dump_guid},
1645
{"nTSecurityDescriptor", False, dump_sd},
1646
{"dnsRecord", False, dump_binary},
1647
{"objectSid", False, dump_sid},
1648
{"tokenGroups", False, dump_sid},
1649
{"tokenGroupsNoGCAcceptable", False, dump_sid},
1650
{"tokengroupsGlobalandUniversal", False, dump_sid},
1655
if (!field) { /* must be end of an entry */
1660
for (i=0; handlers[i].name; i++) {
1661
if (StrCaseCmp(handlers[i].name, field) == 0) {
1662
if (!values) /* first time, indicate string or not */
1663
return handlers[i].string;
1664
handlers[i].handler(field, (struct berval **) values);
1668
if (!handlers[i].name) {
1669
if (!values) /* first time, indicate string conversion */
1671
dump_string(field, (char **)values);
1677
* Dump a result from LDAP on stdout
1678
* used for debugging
1679
* @param ads connection to ads server
1680
* @param res Results to dump
1683
void ads_dump(ADS_STRUCT *ads, void *res)
1685
ads_process_results(ads, res, ads_dump_field, NULL);
1689
* Walk through results, calling a function for each entry found.
1690
* The function receives a field name, a berval * array of values,
1691
* and a data area passed through from the start. The function is
1692
* called once with null for field and values at the end of each
1694
* @param ads connection to ads server
1695
* @param res Results to process
1696
* @param fn Function for processing each result
1697
* @param data_area user-defined area to pass to function
1699
void ads_process_results(ADS_STRUCT *ads, void *res,
1700
BOOL(*fn)(char *, void **, void *),
1706
if (!(ctx = talloc_init("ads_process_results")))
1709
for (msg = ads_first_entry(ads, res); msg;
1710
msg = ads_next_entry(ads, msg)) {
1714
for (utf8_field=ldap_first_attribute(ads->ld,
1715
(LDAPMessage *)msg,&b);
1717
utf8_field=ldap_next_attribute(ads->ld,
1718
(LDAPMessage *)msg,b)) {
1719
struct berval **ber_vals;
1720
char **str_vals, **utf8_vals;
1724
pull_utf8_talloc(ctx, &field, utf8_field);
1725
string = fn(field, NULL, data_area);
1728
utf8_vals = ldap_get_values(ads->ld,
1729
(LDAPMessage *)msg, field);
1730
str_vals = ads_pull_strvals(ctx,
1731
(const char **) utf8_vals);
1732
fn(field, (void **) str_vals, data_area);
1733
ldap_value_free(utf8_vals);
1735
ber_vals = ldap_get_values_len(ads->ld,
1736
(LDAPMessage *)msg, field);
1737
fn(field, (void **) ber_vals, data_area);
1739
ldap_value_free_len(ber_vals);
1741
ldap_memfree(utf8_field);
1744
talloc_free_children(ctx);
1745
fn(NULL, NULL, data_area); /* completed an entry */
1748
talloc_destroy(ctx);
1752
* count how many replies are in a LDAPMessage
1753
* @param ads connection to ads server
1754
* @param res Results to count
1755
* @return number of replies
1757
int ads_count_replies(ADS_STRUCT *ads, void *res)
1759
return ldap_count_entries(ads->ld, (LDAPMessage *)res);
1763
* pull the first entry from a ADS result
1764
* @param ads connection to ads server
1765
* @param res Results of search
1766
* @return first entry from result
1768
void *ads_first_entry(ADS_STRUCT *ads, void *res)
1770
return (void *)ldap_first_entry(ads->ld, (LDAPMessage *)res);
1774
* pull the next entry from a ADS result
1775
* @param ads connection to ads server
1776
* @param res Results of search
1777
* @return next entry from result
1779
void *ads_next_entry(ADS_STRUCT *ads, void *res)
1781
return (void *)ldap_next_entry(ads->ld, (LDAPMessage *)res);
1785
* pull a single string from a ADS result
1786
* @param ads connection to ads server
1787
* @param mem_ctx TALLOC_CTX to use for allocating result string
1788
* @param msg Results of search
1789
* @param field Attribute to retrieve
1790
* @return Result string in talloc context
1792
char *ads_pull_string(ADS_STRUCT *ads,
1793
TALLOC_CTX *mem_ctx, void *msg, const char *field)
1800
values = ldap_get_values(ads->ld, msg, field);
1805
rc = pull_utf8_talloc(mem_ctx, &ux_string,
1807
if (rc != (size_t)-1)
1811
ldap_value_free(values);
1816
* pull an array of strings from a ADS result
1817
* @param ads connection to ads server
1818
* @param mem_ctx TALLOC_CTX to use for allocating result string
1819
* @param msg Results of search
1820
* @param field Attribute to retrieve
1821
* @return Result strings in talloc context
1823
char **ads_pull_strings(ADS_STRUCT *ads,
1824
TALLOC_CTX *mem_ctx, void *msg, const char *field,
1831
values = ldap_get_values(ads->ld, msg, field);
1835
*num_values = ldap_count_values(values);
1837
ret = TALLOC_ARRAY(mem_ctx, char *, *num_values + 1);
1839
ldap_value_free(values);
1843
for (i=0;i<*num_values;i++) {
1844
if (pull_utf8_talloc(mem_ctx, &ret[i], values[i]) == -1) {
1845
ldap_value_free(values);
1851
ldap_value_free(values);
1856
* pull an array of strings from a ADS result
1857
* (handle large multivalue attributes with range retrieval)
1858
* @param ads connection to ads server
1859
* @param mem_ctx TALLOC_CTX to use for allocating result string
1860
* @param msg Results of search
1861
* @param field Attribute to retrieve
1862
* @param current_strings strings returned by a previous call to this function
1863
* @param next_attribute The next query should ask for this attribute
1864
* @param num_values How many values did we get this time?
1865
* @param more_values Are there more values to get?
1866
* @return Result strings in talloc context
1868
char **ads_pull_strings_range(ADS_STRUCT *ads,
1869
TALLOC_CTX *mem_ctx,
1870
void *msg, const char *field,
1871
char **current_strings,
1872
const char **next_attribute,
1873
size_t *num_strings,
1877
char *expected_range_attrib, *range_attr;
1878
BerElement *ptr = NULL;
1881
size_t num_new_strings;
1882
unsigned long int range_start;
1883
unsigned long int range_end;
1885
/* we might have been given the whole lot anyway */
1886
if ((strings = ads_pull_strings(ads, mem_ctx, msg, field, num_strings))) {
1887
*more_strings = False;
1891
expected_range_attrib = talloc_asprintf(mem_ctx, "%s;Range=", field);
1893
/* look for Range result */
1894
for (attr = ldap_first_attribute(ads->ld, (LDAPMessage *)msg, &ptr);
1896
attr = ldap_next_attribute(ads->ld, (LDAPMessage *)msg, ptr)) {
1897
/* we ignore the fact that this is utf8, as all attributes are ascii... */
1898
if (strnequal(attr, expected_range_attrib, strlen(expected_range_attrib))) {
1906
/* nothing here - this field is just empty */
1907
*more_strings = False;
1911
if (sscanf(&range_attr[strlen(expected_range_attrib)], "%lu-%lu",
1912
&range_start, &range_end) == 2) {
1913
*more_strings = True;
1915
if (sscanf(&range_attr[strlen(expected_range_attrib)], "%lu-*",
1916
&range_start) == 1) {
1917
*more_strings = False;
1919
DEBUG(1, ("ads_pull_strings_range: Cannot parse Range attriubte (%s)\n",
1921
ldap_memfree(range_attr);
1922
*more_strings = False;
1927
if ((*num_strings) != range_start) {
1928
DEBUG(1, ("ads_pull_strings_range: Range attribute (%s) doesn't start at %u, but at %lu"
1929
" - aborting range retreival\n",
1930
range_attr, (unsigned int)(*num_strings) + 1, range_start));
1931
ldap_memfree(range_attr);
1932
*more_strings = False;
1936
new_strings = ads_pull_strings(ads, mem_ctx, msg, range_attr, &num_new_strings);
1938
if (*more_strings && ((*num_strings + num_new_strings) != (range_end + 1))) {
1939
DEBUG(1, ("ads_pull_strings_range: Range attribute (%s) tells us we have %lu "
1940
"strings in this bunch, but we only got %lu - aborting range retreival\n",
1941
range_attr, (unsigned long int)range_end - range_start + 1,
1942
(unsigned long int)num_new_strings));
1943
ldap_memfree(range_attr);
1944
*more_strings = False;
1948
strings = TALLOC_REALLOC_ARRAY(mem_ctx, current_strings, char *,
1949
*num_strings + num_new_strings);
1951
if (strings == NULL) {
1952
ldap_memfree(range_attr);
1953
*more_strings = False;
1957
if (new_strings && num_new_strings) {
1958
memcpy(&strings[*num_strings], new_strings,
1959
sizeof(*new_strings) * num_new_strings);
1962
(*num_strings) += num_new_strings;
1964
if (*more_strings) {
1965
*next_attribute = talloc_asprintf(mem_ctx,
1970
if (!*next_attribute) {
1971
DEBUG(1, ("talloc_asprintf for next attribute failed!\n"));
1972
ldap_memfree(range_attr);
1973
*more_strings = False;
1978
ldap_memfree(range_attr);
1984
* pull a single uint32 from a ADS result
1985
* @param ads connection to ads server
1986
* @param msg Results of search
1987
* @param field Attribute to retrieve
1988
* @param v Pointer to int to store result
1989
* @return boolean inidicating success
1991
BOOL ads_pull_uint32(ADS_STRUCT *ads,
1992
void *msg, const char *field, uint32 *v)
1996
values = ldap_get_values(ads->ld, msg, field);
2000
ldap_value_free(values);
2004
*v = atoi(values[0]);
2005
ldap_value_free(values);
2010
* pull a single objectGUID from an ADS result
2011
* @param ads connection to ADS server
2012
* @param msg results of search
2013
* @param guid 37-byte area to receive text guid
2014
* @return boolean indicating success
2016
BOOL ads_pull_guid(ADS_STRUCT *ads,
2017
void *msg, struct uuid *guid)
2020
UUID_FLAT flat_guid;
2022
values = ldap_get_values(ads->ld, msg, "objectGUID");
2027
memcpy(&flat_guid.info, values[0], sizeof(UUID_FLAT));
2028
smb_uuid_unpack(flat_guid, guid);
2029
ldap_value_free(values);
2032
ldap_value_free(values);
2039
* pull a single DOM_SID from a ADS result
2040
* @param ads connection to ads server
2041
* @param msg Results of search
2042
* @param field Attribute to retrieve
2043
* @param sid Pointer to sid to store result
2044
* @return boolean inidicating success
2046
BOOL ads_pull_sid(ADS_STRUCT *ads,
2047
void *msg, const char *field, DOM_SID *sid)
2049
struct berval **values;
2052
values = ldap_get_values_len(ads->ld, msg, field);
2058
ret = sid_parse(values[0]->bv_val, values[0]->bv_len, sid);
2060
ldap_value_free_len(values);
2065
* pull an array of DOM_SIDs from a ADS result
2066
* @param ads connection to ads server
2067
* @param mem_ctx TALLOC_CTX for allocating sid array
2068
* @param msg Results of search
2069
* @param field Attribute to retrieve
2070
* @param sids pointer to sid array to allocate
2071
* @return the count of SIDs pulled
2073
int ads_pull_sids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
2074
void *msg, const char *field, DOM_SID **sids)
2076
struct berval **values;
2080
values = ldap_get_values_len(ads->ld, msg, field);
2085
for (i=0; values[i]; i++)
2088
(*sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, i);
2090
ldap_value_free_len(values);
2095
for (i=0; values[i]; i++) {
2096
ret = sid_parse(values[i]->bv_val, values[i]->bv_len, &(*sids)[count]);
2099
DEBUG(10, ("pulling SID: %s\n", sid_to_string(sid, &(*sids)[count])));
2104
ldap_value_free_len(values);
2109
* pull a SEC_DESC from a ADS result
2110
* @param ads connection to ads server
2111
* @param mem_ctx TALLOC_CTX for allocating sid array
2112
* @param msg Results of search
2113
* @param field Attribute to retrieve
2114
* @param sd Pointer to *SEC_DESC to store result (talloc()ed)
2115
* @return boolean inidicating success
2117
BOOL ads_pull_sd(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
2118
void *msg, const char *field, SEC_DESC **sd)
2120
struct berval **values;
2124
values = ldap_get_values_len(ads->ld, msg, field);
2126
if (!values) return False;
2129
prs_init(&ps, values[0]->bv_len, mem_ctx, UNMARSHALL);
2130
prs_copy_data_in(&ps, values[0]->bv_val, values[0]->bv_len);
2131
prs_set_offset(&ps,0);
2133
ret = sec_io_desc("sd", sd, &ps, 1);
2136
ldap_value_free_len(values);
2141
* in order to support usernames longer than 21 characters we need to
2142
* use both the sAMAccountName and the userPrincipalName attributes
2143
* It seems that not all users have the userPrincipalName attribute set
2145
* @param ads connection to ads server
2146
* @param mem_ctx TALLOC_CTX for allocating sid array
2147
* @param msg Results of search
2148
* @return the username
2150
char *ads_pull_username(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, void *msg)
2155
/* lookup_name() only works on the sAMAccountName to
2156
returning the username portion of userPrincipalName
2157
breaks winbindd_getpwnam() */
2159
ret = ads_pull_string(ads, mem_ctx, msg, "userPrincipalName");
2160
if (ret && (p = strchr_m(ret, '@'))) {
2165
return ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
2170
* find the update serial number - this is the core of the ldap cache
2171
* @param ads connection to ads server
2172
* @param ads connection to ADS server
2173
* @param usn Pointer to retrieved update serial number
2174
* @return status of search
2176
ADS_STATUS ads_USN(ADS_STRUCT *ads, uint32 *usn)
2178
const char *attrs[] = {"highestCommittedUSN", NULL};
2182
status = ads_do_search_retry(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
2183
if (!ADS_ERR_OK(status))
2186
if (ads_count_replies(ads, res) != 1) {
2187
return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
2190
ads_pull_uint32(ads, res, "highestCommittedUSN", usn);
2191
ads_msgfree(ads, res);
2195
/* parse a ADS timestring - typical string is
2196
'20020917091222.0Z0' which means 09:12.22 17th September
2198
static time_t ads_parse_time(const char *str)
2204
if (sscanf(str, "%4d%2d%2d%2d%2d%2d",
2205
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
2206
&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
2215
/********************************************************************
2216
********************************************************************/
2218
ADS_STATUS ads_current_time(ADS_STRUCT *ads)
2220
const char *attrs[] = {"currentTime", NULL};
2225
ADS_STRUCT *ads_s = ads;
2227
if (!(ctx = talloc_init("ads_current_time"))) {
2228
return ADS_ERROR(LDAP_NO_MEMORY);
2231
/* establish a new ldap tcp session if necessary */
2234
if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup,
2235
ads->server.ldap_server )) == NULL )
2239
ads_s->auth.flags = ADS_AUTH_ANON_BIND;
2240
status = ads_connect( ads_s );
2241
if ( !ADS_ERR_OK(status))
2245
status = ads_do_search(ads_s, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
2246
if (!ADS_ERR_OK(status)) {
2250
timestr = ads_pull_string(ads_s, ctx, res, "currentTime");
2252
ads_msgfree(ads, res);
2253
status = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
2257
/* but save the time and offset in the original ADS_STRUCT */
2259
ads->config.current_time = ads_parse_time(timestr);
2261
if (ads->config.current_time != 0) {
2262
ads->auth.time_offset = ads->config.current_time - time(NULL);
2263
DEBUG(4,("time offset is %d seconds\n", ads->auth.time_offset));
2266
ads_msgfree(ads, res);
2268
status = ADS_SUCCESS;
2271
/* free any temporary ads connections */
2272
if ( ads_s != ads ) {
2273
ads_destroy( &ads_s );
2275
talloc_destroy(ctx);
2280
/********************************************************************
2281
********************************************************************/
2283
ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32 *val)
2285
const char *attrs[] = {"domainFunctionality", NULL};
2288
ADS_STRUCT *ads_s = ads;
2290
*val = DS_DOMAIN_FUNCTION_2000;
2292
/* establish a new ldap tcp session if necessary */
2295
if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup,
2296
ads->server.ldap_server )) == NULL )
2300
ads_s->auth.flags = ADS_AUTH_ANON_BIND;
2301
status = ads_connect( ads_s );
2302
if ( !ADS_ERR_OK(status))
2306
/* If the attribute does not exist assume it is a Windows 2000
2307
functional domain */
2309
status = ads_do_search(ads_s, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
2310
if (!ADS_ERR_OK(status)) {
2311
if ( status.err.rc == LDAP_NO_SUCH_ATTRIBUTE ) {
2312
status = ADS_SUCCESS;
2317
if ( !ads_pull_uint32(ads_s, res, "domainFunctionality", val) ) {
2318
DEBUG(5,("ads_domain_func_level: Failed to pull the domainFunctionality attribute.\n"));
2320
DEBUG(3,("ads_domain_func_level: %d\n", *val));
2323
ads_msgfree(ads, res);
2326
/* free any temporary ads connections */
2327
if ( ads_s != ads ) {
2328
ads_destroy( &ads_s );
2335
* find the domain sid for our domain
2336
* @param ads connection to ads server
2337
* @param sid Pointer to domain sid
2338
* @return status of search
2340
ADS_STATUS ads_domain_sid(ADS_STRUCT *ads, DOM_SID *sid)
2342
const char *attrs[] = {"objectSid", NULL};
2346
rc = ads_do_search_retry(ads, ads->config.bind_path, LDAP_SCOPE_BASE, "(objectclass=*)",
2348
if (!ADS_ERR_OK(rc)) return rc;
2349
if (!ads_pull_sid(ads, res, "objectSid", sid)) {
2350
ads_msgfree(ads, res);
2351
return ADS_ERROR_SYSTEM(ENOENT);
2353
ads_msgfree(ads, res);
2359
* find our site name
2360
* @param ads connection to ads server
2361
* @param mem_ctx Pointer to talloc context
2362
* @param site_name Pointer to the sitename
2363
* @return status of search
2365
ADS_STATUS ads_site_dn(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char **site_name)
2369
const char *dn, *service_name;
2370
const char *attrs[] = { "dsServiceName", NULL };
2372
status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
2373
if (!ADS_ERR_OK(status)) {
2377
service_name = ads_pull_string(ads, mem_ctx, res, "dsServiceName");
2378
if (service_name == NULL) {
2379
return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
2382
/* go up three levels */
2383
dn = ads_parent_dn(ads_parent_dn(ads_parent_dn(service_name)));
2385
return ADS_ERROR(LDAP_NO_MEMORY);
2388
*site_name = talloc_strdup(mem_ctx, dn);
2389
if (*site_name == NULL) {
2390
return ADS_ERROR(LDAP_NO_MEMORY);
2393
ads_msgfree(ads, res);
2397
dsServiceName: CN=NTDS Settings,CN=W2K3DC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ber,DC=suse,DC=de
2402
* find the site dn where a machine resides
2403
* @param ads connection to ads server
2404
* @param mem_ctx Pointer to talloc context
2405
* @param computer_name name of the machine
2406
* @param site_name Pointer to the sitename
2407
* @return status of search
2409
ADS_STATUS ads_site_dn_for_machine(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const char *computer_name, const char **site_dn)
2413
const char *parent, *config_context, *filter;
2414
const char *attrs[] = { "configurationNamingContext", NULL };
2417
/* shortcut a query */
2418
if (strequal(computer_name, ads->config.ldap_server_name)) {
2419
return ads_site_dn(ads, mem_ctx, site_dn);
2422
status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
2423
if (!ADS_ERR_OK(status)) {
2427
config_context = ads_pull_string(ads, mem_ctx, res, "configurationNamingContext");
2428
if (config_context == NULL) {
2429
return ADS_ERROR(LDAP_NO_MEMORY);
2432
filter = talloc_asprintf(mem_ctx, "(cn=%s)", computer_name);
2433
if (filter == NULL) {
2434
return ADS_ERROR(LDAP_NO_MEMORY);
2437
status = ads_do_search(ads, config_context, LDAP_SCOPE_SUBTREE, filter, NULL, &res);
2438
if (!ADS_ERR_OK(status)) {
2442
if (ads_count_replies(ads, res) != 1) {
2443
return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
2446
dn = ads_get_dn(ads, res);
2448
return ADS_ERROR(LDAP_NO_MEMORY);
2451
/* go up three levels */
2452
parent = ads_parent_dn(ads_parent_dn(ads_parent_dn(dn)));
2453
if (parent == NULL) {
2454
ads_memfree(ads, dn);
2455
return ADS_ERROR(LDAP_NO_MEMORY);
2458
*site_dn = talloc_strdup(mem_ctx, parent);
2459
if (*site_dn == NULL) {
2460
ads_memfree(ads, dn);
2461
ADS_ERROR(LDAP_NO_MEMORY);
2464
ads_memfree(ads, dn);
2465
ads_msgfree(ads, res);
2471
* get the upn suffixes for a domain
2472
* @param ads connection to ads server
2473
* @param mem_ctx Pointer to talloc context
2474
* @param suffixes Pointer to an array of suffixes
2475
* @param site_name Pointer to the number of suffixes
2476
* @return status of search
2478
ADS_STATUS ads_upn_suffixes(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **suffixes, size_t *num_suffixes)
2482
const char *config_context, *base;
2483
const char *attrs[] = { "configurationNamingContext", NULL };
2484
const char *attrs2[] = { "uPNSuffixes", NULL };
2486
status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
2487
if (!ADS_ERR_OK(status)) {
2491
config_context = ads_pull_string(ads, mem_ctx, res, "configurationNamingContext");
2492
if (config_context == NULL) {
2493
return ADS_ERROR(LDAP_NO_MEMORY);
2496
base = talloc_asprintf(mem_ctx, "cn=Partitions,%s", config_context);
2498
return ADS_ERROR(LDAP_NO_MEMORY);
2501
status = ads_search_dn(ads, &res, base, attrs2);
2502
if (!ADS_ERR_OK(status)) {
2506
if (ads_count_replies(ads, res) != 1) {
2507
return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
2510
suffixes = ads_pull_strings(ads, mem_ctx, &res, "uPNSuffixes", num_suffixes);
2511
if (suffixes == NULL) {
2512
ads_msgfree(ads, res);
2513
return ADS_ERROR(LDAP_NO_MEMORY);
2516
ads_msgfree(ads, res);
2522
* pull a DOM_SID from an extended dn string
2523
* @param mem_ctx TALLOC_CTX
2524
* @param flags string type of extended_dn
2525
* @param sid pointer to a DOM_SID
2526
* @return boolean inidicating success
2528
BOOL ads_get_sid_from_extended_dn(TALLOC_CTX *mem_ctx,
2530
enum ads_extended_dn_flags flags,
2540
* ADS_EXTENDED_DN_HEX_STRING:
2541
* <GUID=238e1963cb390f4bb032ba0105525a29>;<SID=010500000000000515000000bb68c8fd6b61b427572eb04556040000>;CN=gd,OU=berlin,OU=suse,DC=ber,DC=suse,DC=de
2543
* ADS_EXTENDED_DN_STRING (only with w2k3):
2544
<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
2547
p = strchr(dn, ';');
2552
if (strncmp(p, ";<SID=", strlen(";<SID=")) != 0) {
2556
p += strlen(";<SID=");
2565
DEBUG(100,("ads_get_sid_from_extended_dn: sid string is %s\n", p));
2569
case ADS_EXTENDED_DN_STRING:
2570
if (!string_to_sid(sid, p)) {
2574
case ADS_EXTENDED_DN_HEX_STRING: {
2578
buf_len = strhex_to_str(buf, strlen(p), p);
2583
if (!sid_parse(buf, buf_len, sid)) {
2584
DEBUG(10,("failed to parse sid\n"));
2590
DEBUG(10,("unknown extended dn format\n"));
2598
* pull an array of DOM_SIDs from a ADS result
2599
* @param ads connection to ads server
2600
* @param mem_ctx TALLOC_CTX for allocating sid array
2601
* @param msg Results of search
2602
* @param field Attribute to retrieve
2603
* @param flags string type of extended_dn
2604
* @param sids pointer to sid array to allocate
2605
* @return the count of SIDs pulled
2607
int ads_pull_sids_from_extendeddn(ADS_STRUCT *ads,
2608
TALLOC_CTX *mem_ctx,
2611
enum ads_extended_dn_flags flags,
2618
if ((dn_strings = ads_pull_strings(ads, mem_ctx, msg, field,
2619
&dn_count)) == NULL) {
2623
(*sids) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, dn_count + 1);
2625
TALLOC_FREE(dn_strings);
2629
for (i=0; i<dn_count; i++) {
2631
if (!ads_get_sid_from_extended_dn(mem_ctx, dn_strings[i],
2632
flags, &(*sids)[i])) {
2634
TALLOC_FREE(dn_strings);
2639
TALLOC_FREE(dn_strings);
2644
/********************************************************************
2645
********************************************************************/
2647
char* ads_get_dnshostname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
2649
LDAPMessage *res = NULL;
2654
status = ads_find_machine_acct(ads, (void **)(void *)&res, global_myname());
2655
if (!ADS_ERR_OK(status)) {
2656
DEBUG(0,("ads_get_dnshostname: Failed to find account for %s\n",
2661
if ( (count = ads_count_replies(ads, res)) != 1 ) {
2662
DEBUG(1,("ads_get_dnshostname: %d entries returned!\n", count));
2666
if ( (name = ads_pull_string(ads, ctx, res, "dNSHostName")) == NULL ) {
2667
DEBUG(0,("ads_get_dnshostname: No dNSHostName attribute!\n"));
2671
ads_msgfree(ads, res);
2676
/********************************************************************
2677
********************************************************************/
2679
char* ads_get_upn( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
2681
LDAPMessage *res = NULL;
2686
status = ads_find_machine_acct(ads, (void **)(void *)&res, global_myname());
2687
if (!ADS_ERR_OK(status)) {
2688
DEBUG(0,("ads_get_dnshostname: Failed to find account for %s\n",
2693
if ( (count = ads_count_replies(ads, res)) != 1 ) {
2694
DEBUG(1,("ads_get_dnshostname: %d entries returned!\n", count));
2698
if ( (name = ads_pull_string(ads, ctx, res, "userPrincipalName")) == NULL ) {
2699
DEBUG(0,("ads_get_dnshostname: No userPrincipalName attribute!\n"));
2703
ads_msgfree(ads, res);
2708
/********************************************************************
2709
********************************************************************/
2711
char* ads_get_samaccountname( ADS_STRUCT *ads, TALLOC_CTX *ctx, const char *machine_name )
2713
LDAPMessage *res = NULL;
2718
status = ads_find_machine_acct(ads, (void **)(void *)&res, global_myname());
2719
if (!ADS_ERR_OK(status)) {
2720
DEBUG(0,("ads_get_dnshostname: Failed to find account for %s\n",
2725
if ( (count = ads_count_replies(ads, res)) != 1 ) {
2726
DEBUG(1,("ads_get_dnshostname: %d entries returned!\n", count));
2730
if ( (name = ads_pull_string(ads, ctx, res, "sAMAccountName")) == NULL ) {
2731
DEBUG(0,("ads_get_dnshostname: No sAMAccountName attribute!\n"));
2735
ads_msgfree(ads, res);