r23608: Just inline comment cosmetics.
[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-2007
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 #define IDMAP_AD_MAX_IDS 30
36 #define CHECK_ALLOC_DONE(mem) do { \
37      if (!mem) { \
38            DEBUG(0, ("Out of memory!\n")); \
39            ret = NT_STATUS_NO_MEMORY; \
40            goto done; \
41       } \
42 } while (0)
43
44 struct idmap_ad_context {
45         uint32_t filter_low_id;
46         uint32_t filter_high_id;
47 };
48
49 NTSTATUS init_module(void);
50
51 static ADS_STRUCT *ad_idmap_ads = NULL;
52 static struct posix_schema *ad_schema = NULL;
53 static enum wb_posix_mapping ad_map_type = WB_POSIX_MAP_UNKNOWN;
54
55 /************************************************************************
56  ***********************************************************************/
57
58 static ADS_STRUCT *ad_idmap_cached_connection_internal(void)
59 {
60         ADS_STRUCT *ads;
61         ADS_STATUS status;
62         BOOL local = False;
63         fstring dc_name;
64         struct in_addr dc_ip;   
65
66         if (ad_idmap_ads != NULL) {
67
68                 time_t expire;
69                 time_t now = time(NULL);
70
71                 ads = ad_idmap_ads;
72
73                 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
74
75                 /* check for a valid structure */
76                 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
77                           (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
78
79                 if ( ads->config.realm && (expire > time(NULL))) {
80                         return ads;
81                 } else {
82                         /* we own this ADS_STRUCT so make sure it goes away */
83                         DEBUG(7,("Deleting expired krb5 credential cache\n"));
84                         ads->is_mine = True;
85                         ads_destroy( &ads );
86                         ads_kdestroy(WINBIND_CCACHE_NAME);
87                         ad_idmap_ads = NULL;
88                         TALLOC_FREE( ad_schema );                       
89                 }
90         }
91
92         if (!local) {
93                 /* we don't want this to affect the users ccache */
94                 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
95         }
96
97         if ( (ads = ads_init(lp_realm(), lp_workgroup(), NULL)) == NULL ) {
98                 DEBUG(1,("ads_init failed\n"));
99                 return NULL;
100         }
101
102         /* the machine acct password might have change - fetch it every time */
103         SAFE_FREE(ads->auth.password);
104         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
105
106         SAFE_FREE(ads->auth.realm);
107         ads->auth.realm = SMB_STRDUP(lp_realm());
108
109         /* setup server affinity */
110
111         get_dc_name( NULL, ads->auth.realm, dc_name, &dc_ip );
112         
113         status = ads_connect(ads);
114         if (!ADS_ERR_OK(status)) {
115                 DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
116                 ads_destroy(&ads);
117                 return NULL;
118         }
119
120         ads->is_mine = False;
121
122         ad_idmap_ads = ads;
123
124         return ads;
125 }
126
127 /************************************************************************
128  ***********************************************************************/
129
130 static ADS_STRUCT *ad_idmap_cached_connection(void)
131 {
132         ADS_STRUCT *ads = ad_idmap_cached_connection_internal();
133         
134         if ( !ads )
135                 return NULL;
136
137         /* if we have a valid ADS_STRUCT and the schema model is
138            defined, then we can return here. */
139
140         if ( ad_schema )
141                 return ads;
142
143         /* Otherwise, set the schema model */
144
145         if ( (ad_map_type ==  WB_POSIX_MAP_SFU) ||
146              (ad_map_type ==  WB_POSIX_MAP_SFU20) || 
147              (ad_map_type ==  WB_POSIX_MAP_RFC2307) ) 
148         {
149                 ADS_STATUS schema_status;
150                 
151                 schema_status = ads_check_posix_schema_mapping( NULL, ads, ad_map_type, &ad_schema);
152                 if ( !ADS_ERR_OK(schema_status) ) {
153                         DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
154                         return NULL;                    
155                 }
156         }
157         
158         return ads;
159 }
160
161 /************************************************************************
162  ***********************************************************************/
163
164 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom)
165 {
166         struct idmap_ad_context *ctx;
167         char *config_option;
168         const char *range = NULL;
169         const char *schema_mode = NULL; 
170
171         if ( (ctx = TALLOC_ZERO_P(dom, struct idmap_ad_context)) == NULL ) {
172                 DEBUG(0, ("Out of memory!\n"));
173                 return NT_STATUS_NO_MEMORY;
174         }
175
176         if ( (config_option = talloc_asprintf(ctx, "idmap config %s", dom->name)) == NULL ) {
177                 DEBUG(0, ("Out of memory!\n"));
178                 talloc_free(ctx);
179                 return NT_STATUS_NO_MEMORY;
180         }
181
182         /* load ranges */
183         range = lp_parm_const_string(-1, config_option, "range", NULL);
184         if (range && range[0]) {
185                 if ((sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
186                     (ctx->filter_low_id > ctx->filter_high_id)) {
187                         DEBUG(1, ("ERROR: invalid filter range [%s]", range));
188                         ctx->filter_low_id = 0;
189                         ctx->filter_high_id = 0;
190                 }
191         }
192
193         /* schema mode */
194         if ( ad_map_type == WB_POSIX_MAP_UNKNOWN )
195                 ad_map_type = WB_POSIX_MAP_RFC2307;
196         schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL);
197         if ( schema_mode && schema_mode[0] ) {
198                 if ( strequal(schema_mode, "sfu") )
199                         ad_map_type = WB_POSIX_MAP_SFU;
200                 else if ( strequal(schema_mode, "sfu20" ) )
201                         ad_map_type = WB_POSIX_MAP_SFU20;
202                 else if ( strequal(schema_mode, "rfc2307" ) )
203                         ad_map_type = WB_POSIX_MAP_RFC2307;
204                 else
205                         DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n",
206                                  schema_mode));
207         }
208
209         dom->private_data = ctx;
210         dom->initialized = True;
211
212         talloc_free(config_option);
213
214         return NT_STATUS_OK;
215 }
216
217 /************************************************************************
218  Search up to IDMAP_AD_MAX_IDS entries in maps for a match.
219  ***********************************************************************/
220
221 static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
222 {
223         int i;
224
225         for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
226                 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
227                         return maps[i];
228                 }
229         }
230
231         return NULL;    
232 }
233
234 /************************************************************************
235  Search up to IDMAP_AD_MAX_IDS entries in maps for a match
236  ***********************************************************************/
237
238 static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
239 {
240         int i;
241
242         for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
243                 if (sid_equal(maps[i]->sid, sid)) {
244                         return maps[i];
245                 }
246         }
247
248         return NULL;    
249 }
250
251 /************************************************************************
252  ***********************************************************************/
253
254 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
255 {
256         NTSTATUS ret;
257         TALLOC_CTX *memctx;
258         struct idmap_ad_context *ctx;
259         ADS_STATUS rc;
260         ADS_STRUCT *ads;
261         const char *attrs[] = { "sAMAccountType", 
262                                 "objectSid",
263                                 NULL, /* uidnumber */
264                                 NULL, /* gidnumber */
265                                 NULL };
266         LDAPMessage *res = NULL;
267         LDAPMessage *entry = NULL;
268         char *filter = NULL;
269         int idx = 0;
270         int bidx = 0;
271         int count;
272         int i;
273         char *u_filter = NULL;
274         char *g_filter = NULL;
275
276         /* Only do query if we are online */
277         if (idmap_is_offline()) {
278                 return NT_STATUS_FILE_IS_OFFLINE;
279         }
280
281         /* Initilization my have been deferred because we were offline */
282         if ( ! dom->initialized) {
283                 ret = idmap_ad_initialize(dom);
284                 if ( ! NT_STATUS_IS_OK(ret)) {
285                         return ret;
286                 }
287         }
288
289         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
290
291         if ( (memctx = talloc_new(ctx)) == NULL ) {
292                 DEBUG(0, ("Out of memory!\n"));
293                 return NT_STATUS_NO_MEMORY;
294         }
295
296         if ( (ads = ad_idmap_cached_connection()) == NULL ) {
297                 DEBUG(1, ("ADS uninitialized\n"));
298                 ret = NT_STATUS_UNSUCCESSFUL;
299                 goto done;
300         }
301
302         attrs[2] = ad_schema->posix_uidnumber_attr;
303         attrs[3] = ad_schema->posix_gidnumber_attr;
304
305 again:
306         bidx = idx;
307         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
308                 switch (ids[idx]->xid.type) {
309                 case ID_TYPE_UID:     
310                         if ( ! u_filter) {
311                                 u_filter = talloc_asprintf(memctx, "(&(|"
312                                                            "(sAMAccountType=%d)"
313                                                            "(sAMAccountType=%d)"
314                                                            "(sAMAccountType=%d))(|",
315                                                            ATYPE_NORMAL_ACCOUNT,
316                                                            ATYPE_WORKSTATION_TRUST,
317                                                            ATYPE_INTERDOMAIN_TRUST);
318                         }
319                         u_filter = talloc_asprintf_append(u_filter, "(%s=%lu)",
320                                                           ad_schema->posix_uidnumber_attr,
321                                                           (unsigned long)ids[idx]->xid.id);
322                         CHECK_ALLOC_DONE(u_filter);
323                         break;
324                                 
325                 case ID_TYPE_GID:
326                         if ( ! g_filter) {
327                                 g_filter = talloc_asprintf(memctx, "(&(|"
328                                                            "(sAMAccountType=%d)"
329                                                            "(sAMAccountType=%d))(|",
330                                                            ATYPE_SECURITY_GLOBAL_GROUP,
331                                                            ATYPE_SECURITY_LOCAL_GROUP);
332                         }
333                         g_filter = talloc_asprintf_append(g_filter, "(%s=%lu)",
334                                                           ad_schema->posix_gidnumber_attr,
335                                                           (unsigned long)ids[idx]->xid.id);
336                         CHECK_ALLOC_DONE(g_filter);
337                         break;
338
339                 default:
340                         DEBUG(3, ("Error: mapping requested but Unknown ID type\n"));
341                         ids[idx]->status = ID_UNKNOWN;
342                         continue;
343                 }
344         }
345         filter = talloc_asprintf(memctx, "(|");
346         CHECK_ALLOC_DONE(filter);
347         if ( u_filter) {
348                 filter = talloc_asprintf_append(filter, "%s))", u_filter);
349                 CHECK_ALLOC_DONE(filter);
350                         TALLOC_FREE(u_filter);
351         }
352         if ( g_filter) {
353                 filter = talloc_asprintf_append(filter, "%s))", g_filter);
354                 CHECK_ALLOC_DONE(filter);
355                 TALLOC_FREE(g_filter);
356         }
357         filter = talloc_asprintf_append(filter, ")");
358         CHECK_ALLOC_DONE(filter);
359
360         rc = ads_search_retry(ads, &res, filter, attrs);
361         if (!ADS_ERR_OK(rc)) {
362                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
363                 ret = NT_STATUS_UNSUCCESSFUL;
364                 goto done;
365         }
366
367         if ( (count = ads_count_replies(ads, res)) == 0 ) {
368                 DEBUG(10, ("No IDs found\n"));
369         }
370
371         entry = res;
372         for (i = 0; (i < count) && entry; i++) {
373                 DOM_SID sid;
374                 enum id_type type;
375                 struct id_map *map;
376                 uint32_t id;
377                 uint32_t atype;
378
379                 if (i == 0) { /* first entry */
380                         entry = ads_first_entry(ads, entry);
381                 } else { /* following ones */
382                         entry = ads_next_entry(ads, entry);
383                 }
384
385                 if ( !entry ) {
386                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
387                         break;
388                 }
389
390                 /* first check if the SID is present */
391                 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
392                         DEBUG(2, ("Could not retrieve SID from entry\n"));
393                         continue;
394                 }
395
396                 /* get type */
397                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
398                         DEBUG(1, ("could not get SAM account type\n"));
399                         continue;
400                 }
401
402                 switch (atype & 0xF0000000) {
403                 case ATYPE_SECURITY_GLOBAL_GROUP:
404                 case ATYPE_SECURITY_LOCAL_GROUP:
405                         type = ID_TYPE_GID;
406                         break;
407                 case ATYPE_NORMAL_ACCOUNT:
408                 case ATYPE_WORKSTATION_TRUST:
409                 case ATYPE_INTERDOMAIN_TRUST:
410                         type = ID_TYPE_UID;
411                         break;
412                 default:
413                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
414                         continue;
415                 }
416
417                 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
418                                                  ad_schema->posix_uidnumber_attr : 
419                                                  ad_schema->posix_gidnumber_attr, 
420                                      &id)) 
421                 {
422                         DEBUG(1, ("Could not get unix ID\n"));
423                         continue;
424                 }
425
426                 if ((id == 0) ||
427                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
428                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
429                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
430                                 id, ctx->filter_low_id, ctx->filter_high_id));
431                         continue;
432                 }
433
434                 map = find_map_by_id(&ids[bidx], type, id);
435                 if (!map) {
436                         DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
437                         continue;
438                 }
439
440                 sid_copy(map->sid, &sid);
441
442                 /* mapped */
443                 map->status = ID_MAPPED;
444
445                 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
446                            sid_string_static(map->sid),
447                            (unsigned long)map->xid.id,
448                            map->xid.type));
449         }
450
451         if (res) {
452                 ads_msgfree(ads, res);
453         }
454
455         if (ids[idx]) { /* still some values to map */
456                 goto again;
457         }
458
459         ret = NT_STATUS_OK;
460
461         /* mark all unknown/expired ones as unmapped */
462         for (i = 0; ids[i]; i++) {
463                 if (ids[i]->status != ID_MAPPED) 
464                         ids[i]->status = ID_UNMAPPED;
465         }
466
467 done:
468         talloc_free(memctx);
469         return ret;
470 }
471
472 /************************************************************************
473  ***********************************************************************/
474
475 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
476 {
477         NTSTATUS ret;
478         TALLOC_CTX *memctx;
479         struct idmap_ad_context *ctx;
480         ADS_STATUS rc;
481         ADS_STRUCT *ads;
482         const char *attrs[] = { "sAMAccountType", 
483                                 "objectSid",
484                                 NULL, /* attr_uidnumber */
485                                 NULL, /* attr_gidnumber */
486                                 NULL };
487         LDAPMessage *res = NULL;
488         LDAPMessage *entry = NULL;
489         char *filter = NULL;
490         int idx = 0;
491         int bidx = 0;
492         int count;
493         int i;
494         char *sidstr;
495
496         /* Only do query if we are online */
497         if (idmap_is_offline()) {
498                 return NT_STATUS_FILE_IS_OFFLINE;
499         }
500
501         /* Initilization my have been deferred because we were offline */
502         if ( ! dom->initialized) {
503                 ret = idmap_ad_initialize(dom);
504                 if ( ! NT_STATUS_IS_OK(ret)) {
505                         return ret;
506                 }
507         }
508
509         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);      
510
511         if ( (memctx = talloc_new(ctx)) == NULL ) {             
512                 DEBUG(0, ("Out of memory!\n"));
513                 return NT_STATUS_NO_MEMORY;
514         }
515
516         if ( (ads = ad_idmap_cached_connection()) == NULL ) {
517                 DEBUG(1, ("ADS uninitialized\n"));
518                 ret = NT_STATUS_UNSUCCESSFUL;
519                 goto done;
520         }
521
522         attrs[2] = ad_schema->posix_uidnumber_attr;
523         attrs[3] = ad_schema->posix_gidnumber_attr;
524
525 again:
526         filter = talloc_asprintf(memctx, "(&(|"
527                                  "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
528                                  "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
529                                  ")(|",
530                                  ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
531                                  ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
532                 
533         CHECK_ALLOC_DONE(filter);
534
535         bidx = idx;
536         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
537
538                 sidstr = sid_binstring(ids[idx]->sid);
539                 filter = talloc_asprintf_append(filter, "(objectSid=%s)", sidstr);
540                         
541                 free(sidstr);
542                 CHECK_ALLOC_DONE(filter);
543         }
544         filter = talloc_asprintf_append(filter, "))");
545         CHECK_ALLOC_DONE(filter);
546         DEBUG(10, ("Filter: [%s]\n", filter));
547
548         rc = ads_search_retry(ads, &res, filter, attrs);
549         if (!ADS_ERR_OK(rc)) {
550                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
551                 ret = NT_STATUS_UNSUCCESSFUL;
552                 goto done;
553         }
554
555         if ( (count = ads_count_replies(ads, res)) == 0 ) {
556                 DEBUG(10, ("No IDs found\n"));
557         }
558
559         entry = res;    
560         for (i = 0; (i < count) && entry; i++) {
561                 DOM_SID sid;
562                 enum id_type type;
563                 struct id_map *map;
564                 uint32_t id;
565                 uint32_t atype;
566
567                 if (i == 0) { /* first entry */
568                         entry = ads_first_entry(ads, entry);
569                 } else { /* following ones */
570                         entry = ads_next_entry(ads, entry);
571                 }
572
573                 if ( !entry ) {
574                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
575                         break;
576                 }
577
578                 /* first check if the SID is present */
579                 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
580                         DEBUG(2, ("Could not retrieve SID from entry\n"));
581                         continue;
582                 }
583
584                 map = find_map_by_sid(&ids[bidx], &sid);
585                 if (!map) {
586                         DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
587                         continue;
588                 }
589
590                 /* get type */
591                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
592                         DEBUG(1, ("could not get SAM account type\n"));
593                         continue;
594                 }
595
596                 switch (atype & 0xF0000000) {
597                 case ATYPE_SECURITY_GLOBAL_GROUP:
598                 case ATYPE_SECURITY_LOCAL_GROUP:
599                         type = ID_TYPE_GID;
600                         break;
601                 case ATYPE_NORMAL_ACCOUNT:
602                 case ATYPE_WORKSTATION_TRUST:
603                 case ATYPE_INTERDOMAIN_TRUST:
604                         type = ID_TYPE_UID;
605                         break;
606                 default:
607                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
608                         continue;
609                 }
610
611                 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
612                                                  ad_schema->posix_uidnumber_attr : 
613                                                  ad_schema->posix_gidnumber_attr, 
614                                      &id)) 
615                 {
616                         DEBUG(1, ("Could not get unix ID\n"));
617                         continue;
618                 }
619                 if ((id == 0) ||
620                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
621                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
622                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
623                                 id, ctx->filter_low_id, ctx->filter_high_id));
624                         continue;
625                 }
626
627                 /* mapped */
628                 map->xid.type = type;
629                 map->xid.id = id;
630                 map->status = ID_MAPPED;
631
632                 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
633                            sid_string_static(map->sid),
634                            (unsigned long)map->xid.id,
635                            map->xid.type));
636         }
637
638         if (res) {
639                 ads_msgfree(ads, res);
640         }
641
642         if (ids[idx]) { /* still some values to map */
643                 goto again;
644         }
645
646         ret = NT_STATUS_OK;
647
648         /* mark all unknwoni/expired ones as unmapped */
649         for (i = 0; ids[i]; i++) {
650                 if (ids[i]->status != ID_MAPPED) 
651                         ids[i]->status = ID_UNMAPPED;
652         }
653
654 done:
655         talloc_free(memctx);
656         return ret;
657 }
658
659 /************************************************************************
660  ***********************************************************************/
661
662 static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
663 {
664         ADS_STRUCT *ads = ad_idmap_ads;
665
666         if (ads != NULL) {
667                 /* we own this ADS_STRUCT so make sure it goes away */
668                 ads->is_mine = True;
669                 ads_destroy( &ads );
670                 ad_idmap_ads = NULL;
671         }
672
673         TALLOC_FREE( ad_schema );
674         
675         return NT_STATUS_OK;
676 }
677
678 /*
679  * nss_info_{sfu,sfu20,rfc2307}
680  */
681
682 /************************************************************************
683  Initialize the {sfu,sfu20,rfc2307} state
684  ***********************************************************************/
685
686 static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
687 {
688         /* Sanity check if we have previously been called with a
689            different schema model */
690
691         if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
692              (ad_map_type != WB_POSIX_MAP_SFU) ) 
693         {
694                 DEBUG(0,("nss_sfu_init: Posix Map type has already been set.  "
695                          "Mixed schema models not supported!\n"));
696                 return NT_STATUS_NOT_SUPPORTED;
697         }
698         
699         ad_map_type = WB_POSIX_MAP_SFU; 
700
701         return NT_STATUS_OK;
702 }
703
704 static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e )
705 {
706         /* Sanity check if we have previously been called with a
707            different schema model */
708
709         if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
710              (ad_map_type != WB_POSIX_MAP_SFU20) )
711         {
712                 DEBUG(0,("nss_sfu20_init: Posix Map type has already been set.  "
713                          "Mixed schema models not supported!\n"));
714                 return NT_STATUS_NOT_SUPPORTED;
715         }
716         
717         ad_map_type = WB_POSIX_MAP_SFU20;       
718
719         return NT_STATUS_OK;
720 }
721
722 static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
723 {
724         /* Sanity check if we have previously been called with a
725            different schema model */
726          
727         if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
728              (ad_map_type != WB_POSIX_MAP_RFC2307) ) 
729         {
730                 DEBUG(0,("nss_rfc2307_init: Posix Map type has already been set.  "
731                          "Mixed schema models not supported!\n"));
732                 return NT_STATUS_NOT_SUPPORTED;
733         }
734         
735         ad_map_type = WB_POSIX_MAP_RFC2307;
736
737         return NT_STATUS_OK;
738 }
739
740
741 /************************************************************************
742  ***********************************************************************/
743 static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, 
744                                   const DOM_SID *sid, 
745                                   TALLOC_CTX *ctx,
746                                   ADS_STRUCT *ads, 
747                                   LDAPMessage *msg,
748                                   char **homedir,
749                                   char **shell, 
750                                   char **gecos,
751                                   uint32 *gid )
752 {
753         ADS_STRUCT *ads_internal = NULL;
754
755         /* Only do query if we are online */
756         if (idmap_is_offline()) {
757                 return NT_STATUS_FILE_IS_OFFLINE;
758         }
759
760         /* We are assuming that the internal ADS_STRUCT is for the 
761            same forest as the incoming *ads pointer */
762
763         ads_internal = ad_idmap_cached_connection();
764
765         if ( !ads_internal || !ad_schema )
766                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
767         
768         if ( !homedir || !shell || !gecos )
769                 return NT_STATUS_INVALID_PARAMETER;
770
771         *homedir = ads_pull_string( ads, ctx, msg, ad_schema->posix_homedir_attr );
772         *shell   = ads_pull_string( ads, ctx, msg, ad_schema->posix_shell_attr );
773         *gecos   = ads_pull_string( ads, ctx, msg, ad_schema->posix_gecos_attr );
774        
775         if ( gid ) {            
776                 if ( !ads_pull_uint32(ads, msg, ad_schema->posix_gidnumber_attr, gid ) )
777                         *gid = 0;               
778         }
779                 
780         return NT_STATUS_OK;
781 }
782
783 /************************************************************************
784  ***********************************************************************/
785
786 static NTSTATUS nss_ad_close( void )
787 {
788         /* nothing to do.  All memory is free()'d by the idmap close_fn() */
789
790         return NT_STATUS_OK;
791 }
792
793 /************************************************************************
794  Function dispatch tables for the idmap and nss plugins
795  ***********************************************************************/
796
797 static struct idmap_methods ad_methods = {
798         .init            = idmap_ad_initialize,
799         .unixids_to_sids = idmap_ad_unixids_to_sids,
800         .sids_to_unixids = idmap_ad_sids_to_unixids,
801         .close_fn        = idmap_ad_close
802 };
803
804 /* The SFU and RFC2307 NSS plugins share everything but the init
805    function which sets the intended schema model to use */
806   
807 static struct nss_info_methods nss_rfc2307_methods = {
808         .init         = nss_rfc2307_init,
809         .get_nss_info = nss_ad_get_info,
810         .close_fn     = nss_ad_close
811 };
812
813 static struct nss_info_methods nss_sfu_methods = {
814         .init         = nss_sfu_init,
815         .get_nss_info = nss_ad_get_info,
816         .close_fn     = nss_ad_close
817 };
818
819 static struct nss_info_methods nss_sfu20_methods = {
820         .init         = nss_sfu20_init,
821         .get_nss_info = nss_ad_get_info,
822         .close_fn     = nss_ad_close
823 };
824
825
826
827 /************************************************************************
828  Initialize the plugins
829  ***********************************************************************/
830
831 NTSTATUS idmap_ad_init(void)
832 {
833         static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
834         static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
835         static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
836         static NTSTATUS status_nss_sfu20 = NT_STATUS_UNSUCCESSFUL;
837
838         /* Always register the AD method first in order to get the
839            idmap_domain interface called */
840
841         if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
842                 status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, 
843                                                      "ad", &ad_methods);
844                 if ( !NT_STATUS_IS_OK(status_idmap_ad) )
845                         return status_idmap_ad;         
846         }
847         
848         if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
849                 status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
850                                                             "rfc2307",  &nss_rfc2307_methods );         
851                 if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
852                         return status_nss_rfc2307;
853         }
854
855         if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
856                 status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
857                                                         "sfu",  &nss_sfu_methods );             
858                 if ( !NT_STATUS_IS_OK(status_nss_sfu) )
859                         return status_nss_sfu;          
860         }
861
862         if ( !NT_STATUS_IS_OK( status_nss_sfu20 ) ) {
863                 status_nss_sfu20 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
864                                                         "sfu20",  &nss_sfu20_methods );         
865                 if ( !NT_STATUS_IS_OK(status_nss_sfu20) )
866                         return status_nss_sfu20;                
867         }
868
869         return NT_STATUS_OK;    
870 }
871