r20774: I thought I committed this before Xmas holidays ...
[Samba.git] / source / nsswitch / idmap_ad.c
blob252e2159aa64ca73a55f452aa3678942a73c1237
1 /*
2 * idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts
4 * Unix SMB/CIFS implementation.
6 * Winbind ADS backend functions
8 * Copyright (C) Andrew Tridgell 2001
9 * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
10 * Copyright (C) Gerald (Jerry) Carter 2004
11 * Copyright (C) Luke Howard 2001-2004
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include "includes.h"
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_IDMAP
33 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
35 NTSTATUS init_module(void);
37 static ADS_STRUCT *ad_idmap_ads = NULL;
39 static char *attr_uidnumber = NULL;
40 static char *attr_gidnumber = NULL;
42 static ADS_STATUS ad_idmap_check_attr_mapping(ADS_STRUCT *ads)
44 ADS_STATUS status;
45 enum wb_posix_mapping map_type;
47 if (attr_uidnumber != NULL && attr_gidnumber != NULL) {
48 return ADS_ERROR(LDAP_SUCCESS);
51 SMB_ASSERT(ads->server.workgroup);
53 map_type = get_nss_info(ads->server.workgroup);
55 if ((map_type == WB_POSIX_MAP_SFU) ||
56 (map_type == WB_POSIX_MAP_RFC2307)) {
58 status = ads_check_posix_schema_mapping(ads, map_type);
59 if (ADS_ERR_OK(status)) {
60 attr_uidnumber = SMB_STRDUP(ads->schema.posix_uidnumber_attr);
61 attr_gidnumber = SMB_STRDUP(ads->schema.posix_gidnumber_attr);
62 ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
63 ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
64 return ADS_ERROR(LDAP_SUCCESS);
65 } else {
66 DEBUG(0,("ads_check_posix_schema_mapping failed: %s\n", ads_errstr(status)));
67 /* return status; */
71 /* fallback to XAD defaults */
72 attr_uidnumber = SMB_STRDUP("uidNumber");
73 attr_gidnumber = SMB_STRDUP("gidNumber");
74 ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
75 ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
77 return ADS_ERROR(LDAP_SUCCESS);
80 static ADS_STRUCT *ad_idmap_cached_connection(void)
82 ADS_STRUCT *ads;
83 ADS_STATUS status;
84 BOOL local = False;
86 if (ad_idmap_ads != NULL) {
87 ads = ad_idmap_ads;
89 /* check for a valid structure */
91 DEBUG(7, ("Current tickets expire at %d, time is now %d\n",
92 (uint32) ads->auth.expire, (uint32) time(NULL)));
93 if ( ads->config.realm && (ads->auth.expire > time(NULL))) {
94 return ads;
95 } else {
96 /* we own this ADS_STRUCT so make sure it goes away */
97 ads->is_mine = True;
98 ads_destroy( &ads );
99 ads_kdestroy(WINBIND_CCACHE_NAME);
100 ad_idmap_ads = NULL;
104 if (!local) {
105 /* we don't want this to affect the users ccache */
106 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
109 ads = ads_init(lp_realm(), lp_workgroup(), NULL);
110 if (!ads) {
111 DEBUG(1,("ads_init failed\n"));
112 return NULL;
115 /* the machine acct password might have change - fetch it every time */
116 SAFE_FREE(ads->auth.password);
117 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
119 SAFE_FREE(ads->auth.realm);
120 ads->auth.realm = SMB_STRDUP(lp_realm());
122 status = ads_connect(ads);
123 if (!ADS_ERR_OK(status)) {
124 DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
125 ads_destroy(&ads);
126 return NULL;
129 ads->is_mine = False;
131 status = ad_idmap_check_attr_mapping(ads);
132 if (!ADS_ERR_OK(status)) {
133 DEBUG(1, ("ad_idmap_init: failed to check attribute mapping\n"));
134 return NULL;
137 ad_idmap_ads = ads;
138 return ads;
141 struct idmap_ad_context {
142 uint32_t filter_low_id, filter_high_id; /* Filter range */
145 /* Initialize and check conf is appropriate */
146 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params)
148 struct idmap_ad_context *ctx;
149 char *config_option;
150 const char *range;
151 ADS_STRUCT *ads;
153 /* verify AD is reachable (not critical, we may just be offline at start) */
154 ads = ad_idmap_cached_connection();
155 if (ads == NULL) {
156 DEBUG(1, ("WARNING: Could not init an AD connection! Mapping might not work.\n"));
159 ctx = talloc_zero(dom, struct idmap_ad_context);
160 if ( ! ctx) {
161 DEBUG(0, ("Out of memory!\n"));
162 return NT_STATUS_NO_MEMORY;
165 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
166 if ( ! config_option) {
167 DEBUG(0, ("Out of memory!\n"));
168 talloc_free(ctx);
169 return NT_STATUS_NO_MEMORY;
172 /* load ranges */
173 range = lp_parm_const_string(-1, config_option, "range", NULL);
174 if (range && range[0]) {
175 if ((sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
176 (ctx->filter_low_id > ctx->filter_high_id)) {
177 DEBUG(1, ("ERROR: invalid filter range [%s]", range));
178 ctx->filter_low_id = 0;
179 ctx->filter_high_id = 0;
183 /* idmap AD can work well only if it is the default module (trusts)
184 * with additional BUILTIN and alloc using TDB */
185 if ( ! dom->default_domain) {
186 DEBUG(1, ("WARNING: idmap_ad is not configured as the default domain.\n"
187 "For best results we suggest you to configure this module as\n"
188 "default and configure BULTIN to use idmap_tdb\n"
189 "ex: idmap domains = BUILTIN %s\n"
190 " idmap alloc config: range = 5000 - 9999\n"
191 " idmap config %s: default = yes\n"
192 " idmap config %s: backend = ad\n"
193 " idmap config %s: range = 10000 - 10000000 #this is optional\n"
194 "NOTE: make sure the ranges do not overlap\n",
195 dom->name, dom->name, dom->name, dom->name));
197 if ( ! dom->readonly) {
198 DEBUG(1, ("WARNING: forcing to readonly, as idmap_ad can't write on AD.\n"));
199 dom->readonly = true; /* force readonly */
202 dom->private_data = ctx;
204 talloc_free(config_option);
205 return NT_STATUS_OK;
208 #define IDMAP_AD_MAX_IDS 30
209 #define CHECK_ALLOC_DONE(mem) do { if (!mem) { DEBUG(0, ("Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } } while (0)
211 /* this function searches up to IDMAP_AD_MAX_IDS entries in maps for a match */
212 static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
214 int i;
216 for (i = 0; i < IDMAP_AD_MAX_IDS; i++) {
217 if (maps[i] == NULL) { /* end of the run */
218 return NULL;
220 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
221 return maps[i];
225 return NULL;
228 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
230 NTSTATUS ret;
231 TALLOC_CTX *memctx;
232 struct idmap_ad_context *ctx;
233 ADS_STATUS rc;
234 ADS_STRUCT *ads;
235 const char *attrs[] = { "sAMAccountType",
236 "objectSid",
237 NULL, /* attr_uidnumber */
238 NULL, /* attr_gidnumber */
239 NULL };
240 LDAPMessage *res = NULL;
241 char *filter = NULL;
242 BOOL multi = False;
243 int idx = 0;
244 int bidx = 0;
245 int count;
246 int i;
248 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
250 memctx = talloc_new(ctx);
251 if ( ! memctx) {
252 DEBUG(0, ("Out of memory!\n"));
253 return NT_STATUS_NO_MEMORY;
256 ads = ad_idmap_cached_connection();
257 if (ads == NULL) {
258 DEBUG(1, ("ADS uninitialized\n"));
259 ret = NT_STATUS_UNSUCCESSFUL;
260 goto done;
263 /* attr_uidnumber and attr_gidnumber are surely successfully initialized now */
264 attrs[2] = attr_uidnumber;
265 attrs[3] = attr_gidnumber;
267 if ( ! ids[1]) {
268 /* if we are requested just one mapping use the simple filter */
269 switch (ids[0]->xid.type) {
270 case ID_TYPE_UID:
272 filter = talloc_asprintf(memctx,
273 "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d))(%s=%lu))",
274 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
275 attr_uidnumber,
276 (unsigned long)ids[0]->xid.id);
277 break;
278 case ID_TYPE_GID:
280 filter = talloc_asprintf(memctx,
281 "(&(|(sAMAccountType=%d)(sAMAccountType=%d))(%s=%lu))",
282 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP,
283 attr_gidnumber,
284 (unsigned long)ids[0]->xid.id);
285 break;
286 default:
287 DEBUG(3, ("Unknown ID type\n"));
288 ret = NT_STATUS_INVALID_PARAMETER;
289 goto done;
291 CHECK_ALLOC_DONE(filter);
292 DEBUG(10, ("Filter: [%s]\n", filter));
293 } else {
294 /* multiple mappings */
295 multi = True;
298 again:
299 if (multi) {
300 char *u_filter = NULL;
301 char *g_filter = NULL;
303 bidx = idx;
304 for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
305 switch (ids[idx]->xid.type) {
306 case ID_TYPE_UID:
308 if ( ! u_filter) {
309 u_filter = talloc_asprintf(memctx, "(&(|"
310 "(sAMAccountType=%d)"
311 "(sAMAccountType=%d)"
312 "(sAMAccountType=%d))(|",
313 ATYPE_NORMAL_ACCOUNT,
314 ATYPE_WORKSTATION_TRUST,
315 ATYPE_INTERDOMAIN_TRUST);
317 u_filter = talloc_asprintf_append(u_filter, "(%s=%lu)",
318 attr_uidnumber,
319 (unsigned long)ids[idx]->xid.id);
320 CHECK_ALLOC_DONE(u_filter);
321 break;
323 case ID_TYPE_GID:
324 if ( ! g_filter) {
325 g_filter = talloc_asprintf(memctx, "(&(|"
326 "(sAMAccountType=%d)"
327 "(sAMAccountType=%d))(|",
328 ATYPE_SECURITY_GLOBAL_GROUP,
329 ATYPE_SECURITY_LOCAL_GROUP);
331 g_filter = talloc_asprintf_append(g_filter, "(%s=%lu)",
332 attr_gidnumber,
333 (unsigned long)ids[idx]->xid.id);
334 CHECK_ALLOC_DONE(g_filter);
335 break;
337 default:
338 DEBUG(3, ("Unknown ID type\n"));
339 ids[idx]->status = ID_UNKNOWN;
340 continue;
343 filter = talloc_asprintf(memctx, "(|");
344 CHECK_ALLOC_DONE(filter);
345 if ( u_filter) {
346 filter = talloc_asprintf_append(filter, "%s))", u_filter);
347 CHECK_ALLOC_DONE(filter);
348 TALLOC_FREE(u_filter);
350 if ( g_filter) {
351 filter = talloc_asprintf_append(filter, "%s))", g_filter);
352 CHECK_ALLOC_DONE(filter);
353 TALLOC_FREE(g_filter);
355 filter = talloc_asprintf_append(filter, ")");
356 CHECK_ALLOC_DONE(filter);
357 DEBUG(10, ("Filter: [%s]\n", filter));
358 } else {
359 bidx = 0;
360 idx = 1;
363 rc = ads_search_retry(ads, &res, filter, attrs);
364 if (!ADS_ERR_OK(rc)) {
365 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
366 ret = NT_STATUS_UNSUCCESSFUL;
367 goto done;
370 count = ads_count_replies(ads, res);
371 if (count == 0) {
372 DEBUG(10, ("No IDs found\n"));
375 for (i = 0; i < count; i++) {
376 LDAPMessage *entry = NULL;
377 DOM_SID sid;
378 enum id_type type;
379 struct id_map *map;
380 uint32_t id;
381 uint32_t atype;
383 if (i == 0) { /* first entry */
384 entry = ads_first_entry(ads, res);
385 } else { /* following ones */
386 entry = ads_next_entry(ads, entry);
388 if ( ! entry) {
389 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
390 continue;
393 /* first check if the SID is present */
394 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
395 DEBUG(2, ("Could not retrieve SID from entry\n"));
396 continue;
399 /* get type */
400 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
401 DEBUG(1, ("could not get SAM account type\n"));
402 continue;
405 switch (atype & 0xF0000000) {
406 case ATYPE_SECURITY_GLOBAL_GROUP:
407 case ATYPE_SECURITY_LOCAL_GROUP:
408 type = ID_TYPE_GID;
409 break;
410 case ATYPE_NORMAL_ACCOUNT:
411 case ATYPE_WORKSTATION_TRUST:
412 case ATYPE_INTERDOMAIN_TRUST:
413 type = ID_TYPE_UID;
414 break;
415 default:
416 DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
417 continue;
420 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID)?attr_uidnumber:attr_gidnumber, &id)) {
421 DEBUG(1, ("Could not get unix ID\n"));
422 continue;
424 if ((id == 0) ||
425 (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
426 (ctx->filter_high_id && (id > ctx->filter_high_id))) {
427 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
428 id, ctx->filter_low_id, ctx->filter_high_id));
429 continue;
432 map = find_map_by_id(&ids[bidx], type, id);
433 if (!map) {
434 DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
435 continue;
438 sid_copy(map->sid, &sid);
440 /* mapped */
441 map->status = ID_MAPPED;
443 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
444 sid_string_static(map->sid),
445 (unsigned long)map->xid.id,
446 map->xid.type));
449 if (res) {
450 ads_msgfree(ads, res);
453 if (multi && ids[idx]) { /* still some values to map */
454 goto again;
457 ret = NT_STATUS_OK;
459 /* mark all unknwon ones as unmapped */
460 for (i = 0; ids[i]; i++) {
461 if (ids[i]->status == ID_UNKNOWN) ids[i]->status = ID_UNMAPPED;
464 done:
465 talloc_free(memctx);
466 return ret;
469 /* this function searches up to IDMAP_AD_MAX_IDS entries in maps for a match */
470 static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
472 int i;
474 for (i = 0; i < IDMAP_AD_MAX_IDS; i++) {
475 if (maps[i] == NULL) { /* end of the run */
476 return NULL;
478 if (sid_equal(maps[i]->sid, sid)) {
479 return maps[i];
483 return NULL;
486 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
488 NTSTATUS ret;
489 TALLOC_CTX *memctx;
490 struct idmap_ad_context *ctx;
491 ADS_STATUS rc;
492 ADS_STRUCT *ads;
493 const char *attrs[] = { "sAMAccountType",
494 "objectSid",
495 NULL, /* attr_uidnumber */
496 NULL, /* attr_gidnumber */
497 NULL };
498 LDAPMessage *res = NULL;
499 char *filter = NULL;
500 BOOL multi = False;
501 int idx = 0;
502 int bidx = 0;
503 int count;
504 int i;
506 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
508 memctx = talloc_new(ctx);
509 if ( ! memctx) {
510 DEBUG(0, ("Out of memory!\n"));
511 return NT_STATUS_NO_MEMORY;
514 ads = ad_idmap_cached_connection();
515 if (ads == NULL) {
516 DEBUG(1, ("ADS uninitialized\n"));
517 ret = NT_STATUS_UNSUCCESSFUL;
518 goto done;
521 /* attr_uidnumber and attr_gidnumber are surely successfully initialized now */
522 attrs[2] = attr_uidnumber;
523 attrs[3] = attr_gidnumber;
526 if ( ! ids[1]) {
527 /* if we are requested just one mapping use the simple filter */
528 char *sidstr;
530 sidstr = sid_binstring(ids[0]->sid);
531 filter = talloc_asprintf(memctx, "(&(objectSid=%s)(|" /* the requested Sid */
532 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
533 "(sAMAccountType=%d)(sAMAccountType=%d)))", /* group account types */
534 sidstr,
535 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
536 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
537 if (! filter) {
538 free(sidstr);
539 ret = NT_STATUS_NO_MEMORY;
540 goto done;
542 CHECK_ALLOC_DONE(filter);
543 DEBUG(10, ("Filter: [%s]\n", filter));
544 } else {
545 /* multiple mappings */
546 multi = True;
549 again:
550 if (multi) {
551 char *sidstr;
553 filter = talloc_asprintf(memctx,
554 "(&(|"
555 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
556 "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
557 ")(|",
558 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
559 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
561 CHECK_ALLOC_DONE(filter);
563 bidx = idx;
564 for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
566 sidstr = sid_binstring(ids[idx]->sid);
567 filter = talloc_asprintf_append(filter, "(objectSid=%s)", sidstr);
569 free(sidstr);
570 CHECK_ALLOC_DONE(filter);
572 filter = talloc_asprintf_append(filter, "))");
573 CHECK_ALLOC_DONE(filter);
574 DEBUG(10, ("Filter: [%s]\n", filter));
575 } else {
576 bidx = 0;
577 idx = 1;
580 rc = ads_search_retry(ads, &res, filter, attrs);
581 if (!ADS_ERR_OK(rc)) {
582 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
583 ret = NT_STATUS_UNSUCCESSFUL;
584 goto done;
587 count = ads_count_replies(ads, res);
588 if (count == 0) {
589 DEBUG(10, ("No IDs found\n"));
592 for (i = 0; i < count; i++) {
593 LDAPMessage *entry = NULL;
594 DOM_SID sid;
595 enum id_type type;
596 struct id_map *map;
597 uint32_t id;
598 uint32_t atype;
600 if (i == 0) { /* first entry */
601 entry = ads_first_entry(ads, res);
602 } else { /* following ones */
603 entry = ads_next_entry(ads, entry);
605 if ( ! entry) {
606 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
607 continue;
610 /* first check if the SID is present */
611 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
612 DEBUG(2, ("Could not retrieve SID from entry\n"));
613 continue;
616 map = find_map_by_sid(&ids[bidx], &sid);
617 if (!map) {
618 DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
619 continue;
622 /* get type */
623 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
624 DEBUG(1, ("could not get SAM account type\n"));
625 continue;
628 switch (atype & 0xF0000000) {
629 case ATYPE_SECURITY_GLOBAL_GROUP:
630 case ATYPE_SECURITY_LOCAL_GROUP:
631 type = ID_TYPE_GID;
632 break;
633 case ATYPE_NORMAL_ACCOUNT:
634 case ATYPE_WORKSTATION_TRUST:
635 case ATYPE_INTERDOMAIN_TRUST:
636 type = ID_TYPE_UID;
637 break;
638 default:
639 DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
640 continue;
643 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID)?attr_uidnumber:attr_gidnumber, &id)) {
644 DEBUG(1, ("Could not get unix ID\n"));
645 continue;
647 if ((id == 0) ||
648 (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
649 (ctx->filter_high_id && (id > ctx->filter_high_id))) {
650 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
651 id, ctx->filter_low_id, ctx->filter_high_id));
652 continue;
655 /* mapped */
656 map->xid.type = type;
657 map->xid.id = id;
658 map->status = ID_MAPPED;
660 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
661 sid_string_static(map->sid),
662 (unsigned long)map->xid.id,
663 map->xid.type));
666 if (res) {
667 ads_msgfree(ads, res);
670 if (multi && ids[idx]) { /* still some values to map */
671 goto again;
674 ret = NT_STATUS_OK;
676 /* mark all unknwon ones as unmapped */
677 for (i = 0; ids[i]; i++) {
678 if (ids[i]->status == ID_UNKNOWN) ids[i]->status = ID_UNMAPPED;
681 done:
682 talloc_free(memctx);
683 return ret;
686 static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
688 ADS_STRUCT *ads = ad_idmap_ads;
690 if (ads != NULL) {
691 /* we own this ADS_STRUCT so make sure it goes away */
692 ads->is_mine = True;
693 ads_destroy( &ads );
694 ad_idmap_ads = NULL;
697 SAFE_FREE(attr_uidnumber);
698 SAFE_FREE(attr_gidnumber);
700 return NT_STATUS_OK;
703 static struct idmap_methods ad_methods = {
704 .init = idmap_ad_initialize,
705 .unixids_to_sids = idmap_ad_unixids_to_sids,
706 .sids_to_unixids = idmap_ad_sids_to_unixids,
707 .close_fn = idmap_ad_close
710 /* support for new authentication subsystem */
711 NTSTATUS idmap_ad_init(void)
713 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ad", &ad_methods);