r20118: Fix some more warnings
[ira/wip.git] / source3 / nsswitch / idmap_ad.c
1 /*
2  *  idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts
3  *
4  * Unix SMB/CIFS implementation.
5  *
6  * Winbind ADS backend functions
7  *
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
12  *
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.
17  *
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.
22  *
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.
26  */
27
28 #include "includes.h"
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_IDMAP
32
33 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
34
35 NTSTATUS init_module(void);
36
37 static ADS_STRUCT *ad_idmap_ads = NULL;
38
39 static char *attr_uidnumber = NULL;
40 static char *attr_gidnumber = NULL;
41
42 static ADS_STATUS ad_idmap_check_attr_mapping(ADS_STRUCT *ads)
43 {
44         ADS_STATUS status;
45         enum wb_posix_mapping map_type;
46
47         if (attr_uidnumber != NULL && attr_gidnumber != NULL) {
48                 return ADS_ERROR(LDAP_SUCCESS);
49         }
50
51         SMB_ASSERT(ads->server.workgroup);
52
53         map_type = get_nss_info(ads->server.workgroup);
54
55         if ((map_type == WB_POSIX_MAP_SFU) ||
56             (map_type == WB_POSIX_MAP_RFC2307)) {
57
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; */
68                 }
69         }
70         
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);
76
77         return ADS_ERROR(LDAP_SUCCESS);
78 }
79
80 static ADS_STRUCT *ad_idmap_cached_connection(void)
81 {
82         ADS_STRUCT *ads;
83         ADS_STATUS status;
84         BOOL local = False;
85
86         if (ad_idmap_ads != NULL) {
87                 ads = ad_idmap_ads;
88
89                 /* check for a valid structure */
90
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;
101                 }
102         }
103
104         if (!local) {
105                 /* we don't want this to affect the users ccache */
106                 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
107         }
108
109         ads = ads_init(lp_realm(), lp_workgroup(), NULL);
110         if (!ads) {
111                 DEBUG(1,("ads_init failed\n"));
112                 return NULL;
113         }
114
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);
118
119         SAFE_FREE(ads->auth.realm);
120         ads->auth.realm = SMB_STRDUP(lp_realm());
121
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;
127         }
128
129         ads->is_mine = False;
130
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;
135         }
136
137         ad_idmap_ads = ads;
138         return ads;
139 }
140
141 struct idmap_ad_context {
142         uint32_t filter_low_id, filter_high_id;         /* Filter range */
143 };
144
145 /* Initialize and check conf is appropriate */
146 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params)
147 {
148         struct idmap_ad_context *ctx;
149         char *config_option;
150         const char *range;
151         ADS_STRUCT *ads;
152
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"));
157         }
158
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;
163         }
164
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;
170         }
171
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;
180                 }
181         }
182
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));
196         }
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 */
200         }
201
202         dom->private_data = ctx;
203
204         talloc_free(config_option);
205         return NT_STATUS_OK;
206 }
207
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)
210
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)
213 {
214         int i;
215
216         for (i = 0; i < IDMAP_AD_MAX_IDS; i++) {
217                 if (maps[i] == NULL) { /* end of the run */
218                         return NULL;
219                 }
220                 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
221                         return maps[i];
222                 }
223         }
224
225         return NULL;    
226 }
227
228 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
229 {
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;
247
248         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);      
249
250         memctx = talloc_new(ctx);
251         if ( ! memctx) {
252                 DEBUG(0, ("Out of memory!\n"));
253                 return NT_STATUS_NO_MEMORY;
254         }
255
256         ads = ad_idmap_cached_connection();
257         if (ads == NULL) {
258                 DEBUG(1, ("ADS uninitialized\n"));
259                 ret = NT_STATUS_UNSUCCESSFUL;
260                 goto done;
261         }
262
263         /* attr_uidnumber and attr_gidnumber are surely successfully initialized now */
264         attrs[2] = attr_uidnumber;
265         attrs[3] = attr_gidnumber;
266
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:
271
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:
279
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;
290                 }
291                 CHECK_ALLOC_DONE(filter);
292                 DEBUG(10, ("Filter: [%s]\n", filter));
293         } else {
294                 /* multiple mappings */
295                 multi = True;
296         }
297
298 again:
299         if (multi) {
300                 char *u_filter = NULL;
301                 char *g_filter = NULL;
302
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:
307         
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);
316                                 }
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;
322                                 
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);
330                                 }
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;
336
337                         default:
338                                 DEBUG(3, ("Unknown ID type\n"));
339                                 ids[idx]->mapped = false;
340                                 continue;
341                         }
342                 }
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);
349                 }
350                 if ( g_filter) {
351                         filter = talloc_asprintf_append(filter, "%s))", g_filter);
352                         CHECK_ALLOC_DONE(filter);
353                         TALLOC_FREE(g_filter);
354                 }
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;
361         }
362
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;
368         }
369
370         count = ads_count_replies(ads, res);
371         if (count == 0) {
372                 DEBUG(10, ("No IDs found\n"));
373         }
374
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;
382
383                 if (i == 0) { /* first entry */
384                         entry = ads_first_entry(ads, res);
385                 } else { /* following ones */
386                         entry = ads_next_entry(ads, entry);
387                 }
388                 if ( ! entry) {
389                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
390                         continue;
391                 }
392
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;
397                 }
398
399                 /* get type */
400                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
401                         DEBUG(1, ("could not get SAM account type\n"));
402                         continue;
403                 }
404
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;
418                 }
419
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;
423                 }
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;
430                 }
431
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;
436                 }
437
438                 sid_copy(map->sid, &sid);
439
440                 /* mapped */
441                 map->mapped = True;
442
443                 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
444                            sid_string_static(map->sid),
445                            (unsigned long)map->xid.id,
446                            map->xid.type));
447         }
448
449         if (res) {
450                 ads_msgfree(ads, res);
451         }
452
453         if (multi && ids[idx]) { /* still some values to map */
454                 goto again;
455         }
456
457         ret = NT_STATUS_OK;
458 done:
459         talloc_free(memctx);
460         return ret;
461 }
462
463 /* this function searches up to IDMAP_AD_MAX_IDS entries in maps for a match */
464 static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
465 {
466         int i;
467
468         for (i = 0; i < IDMAP_AD_MAX_IDS; i++) {
469                 if (maps[i] == NULL) { /* end of the run */
470                         return NULL;
471                 }
472                 if (sid_equal(maps[i]->sid, sid)) {
473                         return maps[i];
474                 }
475         }
476
477         return NULL;    
478 }
479
480 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
481 {
482         NTSTATUS ret;
483         TALLOC_CTX *memctx;
484         struct idmap_ad_context *ctx;
485         ADS_STATUS rc;
486         ADS_STRUCT *ads;
487         const char *attrs[] = { "sAMAccountType", 
488                                 "objectSid",
489                                 NULL, /* attr_uidnumber */
490                                 NULL, /* attr_gidnumber */
491                                 NULL };
492         LDAPMessage *res = NULL;
493         char *filter = NULL;
494         BOOL multi = False;
495         int idx = 0;
496         int bidx = 0;
497         int count;
498         int i;
499
500         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);      
501
502         memctx = talloc_new(ctx);
503         if ( ! memctx) {
504                 DEBUG(0, ("Out of memory!\n"));
505                 return NT_STATUS_NO_MEMORY;
506         }
507
508         ads = ad_idmap_cached_connection();
509         if (ads == NULL) {
510                 DEBUG(1, ("ADS uninitialized\n"));
511                 ret = NT_STATUS_UNSUCCESSFUL;
512                 goto done;
513         }
514
515         /* attr_uidnumber and attr_gidnumber are surely successfully initialized now */
516         attrs[2] = attr_uidnumber;
517         attrs[3] = attr_gidnumber;
518
519
520         if ( ! ids[1]) {
521                 /* if we are requested just one mapping use the simple filter */
522                 char *sidstr;
523
524                 sidstr = sid_binstring(ids[0]->sid);
525                 filter = talloc_asprintf(memctx, "(&(objectSid=%s)(|" /* the requested Sid */
526                                                  "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
527                                                  "(sAMAccountType=%d)(sAMAccountType=%d)))", /* group account types */
528                                                  sidstr,
529                                                  ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
530                                                  ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
531                 if (! filter) {
532                         free(sidstr);
533                         ret = NT_STATUS_NO_MEMORY;
534                         goto done;
535                 }
536                 CHECK_ALLOC_DONE(filter);
537                 DEBUG(10, ("Filter: [%s]\n", filter));
538         } else {
539                 /* multiple mappings */
540                 multi = True;
541         }
542
543 again:
544         if (multi) {
545                 char *sidstr;
546
547                 filter = talloc_asprintf(memctx,
548                                 "(&(|"
549                                     "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
550                                     "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
551                                   ")(|",
552                                         ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
553                                         ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
554                 
555                 CHECK_ALLOC_DONE(filter);
556
557                 bidx = idx;
558                 for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
559
560                         sidstr = sid_binstring(ids[idx]->sid);
561                         filter = talloc_asprintf_append(filter, "(objectSid=%s)", sidstr);
562                         
563                         free(sidstr);
564                         CHECK_ALLOC_DONE(filter);
565                 }
566                 filter = talloc_asprintf_append(filter, "))");
567                 CHECK_ALLOC_DONE(filter);
568                 DEBUG(10, ("Filter: [%s]\n", filter));
569         } else {
570                 bidx = 0;
571                 idx = 1;
572         }
573
574         rc = ads_search_retry(ads, &res, filter, attrs);
575         if (!ADS_ERR_OK(rc)) {
576                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
577                 ret = NT_STATUS_UNSUCCESSFUL;
578                 goto done;
579         }
580
581         count = ads_count_replies(ads, res);
582         if (count == 0) {
583                 DEBUG(10, ("No IDs found\n"));
584         }
585
586         for (i = 0; i < count; i++) {
587                 LDAPMessage *entry = NULL;
588                 DOM_SID sid;
589                 enum id_type type;
590                 struct id_map *map;
591                 uint32_t id;
592                 uint32_t atype;
593
594                 if (i == 0) { /* first entry */
595                         entry = ads_first_entry(ads, res);
596                 } else { /* following ones */
597                         entry = ads_next_entry(ads, entry);
598                 }
599                 if ( ! entry) {
600                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
601                         continue;
602                 }
603
604                 /* first check if the SID is present */
605                 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
606                         DEBUG(2, ("Could not retrieve SID from entry\n"));
607                         continue;
608                 }
609
610                 map = find_map_by_sid(&ids[bidx], &sid);
611                 if (!map) {
612                         DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
613                         continue;
614                 }
615
616                 /* get type */
617                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
618                         DEBUG(1, ("could not get SAM account type\n"));
619                         continue;
620                 }
621
622                 switch (atype & 0xF0000000) {
623                 case ATYPE_SECURITY_GLOBAL_GROUP:
624                 case ATYPE_SECURITY_LOCAL_GROUP:
625                         type = ID_TYPE_GID;
626                         break;
627                 case ATYPE_NORMAL_ACCOUNT:
628                 case ATYPE_WORKSTATION_TRUST:
629                 case ATYPE_INTERDOMAIN_TRUST:
630                         type = ID_TYPE_UID;
631                         break;
632                 default:
633                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
634                         continue;
635                 }
636
637                 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID)?attr_uidnumber:attr_gidnumber, &id)) {
638                         DEBUG(1, ("Could not get unix ID\n"));
639                         continue;
640                 }
641                 if ((id == 0) ||
642                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
643                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
644                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
645                                 id, ctx->filter_low_id, ctx->filter_high_id));
646                         continue;
647                 }
648
649                 /* mapped */
650                 map->xid.type = type;
651                 map->xid.id = id;
652                 map->mapped = True;
653
654                 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
655                            sid_string_static(map->sid),
656                            (unsigned long)map->xid.id,
657                            map->xid.type));
658         }
659
660         if (res) {
661                 ads_msgfree(ads, res);
662         }
663
664         if (multi && ids[idx]) { /* still some values to map */
665                 goto again;
666         }
667
668         ret = NT_STATUS_OK;
669 done:
670         talloc_free(memctx);
671         return ret;
672 }
673
674 static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
675 {
676         ADS_STRUCT *ads = ad_idmap_ads;
677
678         if (ads != NULL) {
679                 /* we own this ADS_STRUCT so make sure it goes away */
680                 ads->is_mine = True;
681                 ads_destroy( &ads );
682                 ad_idmap_ads = NULL;
683         }
684
685         SAFE_FREE(attr_uidnumber);
686         SAFE_FREE(attr_gidnumber);
687         
688         return NT_STATUS_OK;
689 }
690
691 static struct idmap_methods ad_methods = {
692         .init = idmap_ad_initialize,
693         .unixids_to_sids = idmap_ad_unixids_to_sids,
694         .sids_to_unixids = idmap_ad_sids_to_unixids,
695         .close_fn = idmap_ad_close
696 };
697
698 /* support for new authentication subsystem */
699 NTSTATUS idmap_ad_init(void)
700 {
701         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ad", &ad_methods);
702 }
703