r20986: Commit the prototype of the nss_info plugin interface.
[kai/samba.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                 ads = ad_idmap_ads;
68
69                 /* check for a valid structure */
70
71                 DEBUG(7, ("Current tickets expire at %d, time is now %d\n",
72                           (uint32) ads->auth.expire, (uint32) time(NULL)));
73                 if ( ads->config.realm && (ads->auth.expire > time(NULL))) {
74                         return ads;
75                 } else {
76                         /* we own this ADS_STRUCT so make sure it goes away */
77                         ads->is_mine = True;
78                         ads_destroy( &ads );
79                         ads_kdestroy(WINBIND_CCACHE_NAME);
80                         ad_idmap_ads = NULL;
81                         TALLOC_FREE( ad_schema );                       
82                 }
83         }
84
85         if (!local) {
86                 /* we don't want this to affect the users ccache */
87                 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
88         }
89
90         if ( (ads = ads_init(lp_realm(), lp_workgroup(), NULL)) == NULL ) {
91                 DEBUG(1,("ads_init failed\n"));
92                 return NULL;
93         }
94
95         /* the machine acct password might have change - fetch it every time */
96         SAFE_FREE(ads->auth.password);
97         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
98
99         SAFE_FREE(ads->auth.realm);
100         ads->auth.realm = SMB_STRDUP(lp_realm());
101
102         /* setup server affinity */
103
104         get_dc_name( NULL, ads->auth.realm, dc_name, &dc_ip );
105         
106         status = ads_connect(ads);
107         if (!ADS_ERR_OK(status)) {
108                 DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
109                 ads_destroy(&ads);
110                 return NULL;
111         }
112
113         ads->is_mine = False;
114
115         ad_idmap_ads = ads;
116
117         return ads;
118 }
119
120 /************************************************************************
121  ***********************************************************************/
122
123 static ADS_STRUCT *ad_idmap_cached_connection(void)
124 {
125         ADS_STRUCT *ads = ad_idmap_cached_connection_internal();
126         
127         if ( !ads )
128                 return NULL;
129
130         /* if we have a valid ADS_STRUCT and the schema model is
131            defined, then we can return here. */
132
133         if ( ad_schema )
134                 return ads;
135
136         /* Otherwise, set the schema model */
137
138         if ( (ad_map_type ==  WB_POSIX_MAP_SFU) ||
139              (ad_map_type ==  WB_POSIX_MAP_RFC2307) ) 
140         {
141                 ADS_STATUS schema_status;
142                 
143                 schema_status = ads_check_posix_schema_mapping( NULL, ads, ad_map_type, &ad_schema);
144                 if ( !ADS_ERR_OK(schema_status) ) {
145                         DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
146                         return NULL;                    
147                 }
148         }
149         
150         return ads;
151 }
152
153 /************************************************************************
154  ***********************************************************************/
155
156 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params)
157 {
158         struct idmap_ad_context *ctx;
159         char *config_option;
160         const char *range;
161         ADS_STRUCT *ads;
162
163         /* verify AD is reachable (not critical, we may just be offline at start) */
164         if ( (ads = ad_idmap_cached_connection()) == NULL ) {
165                 DEBUG(1, ("WARNING: Could not init an AD connection! Mapping might not work.\n"));
166         }
167
168         if ( (ctx = talloc_zero(dom, struct idmap_ad_context)) == NULL ) {
169                 DEBUG(0, ("Out of memory!\n"));
170                 return NT_STATUS_NO_MEMORY;
171         }
172
173         if ( (config_option = talloc_asprintf(ctx, "idmap config %s", dom->name)) == NULL ) {
174                 DEBUG(0, ("Out of memory!\n"));
175                 talloc_free(ctx);
176                 return NT_STATUS_NO_MEMORY;
177         }
178
179         /* load ranges */
180         range = lp_parm_const_string(-1, config_option, "range", NULL);
181         if (range && range[0]) {
182                 if ((sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
183                     (ctx->filter_low_id > ctx->filter_high_id)) {
184                         DEBUG(1, ("ERROR: invalid filter range [%s]", range));
185                         ctx->filter_low_id = 0;
186                         ctx->filter_high_id = 0;
187                 }
188         }
189
190         /* idmap AD can work well only if it is the default module (trusts)
191          * with additional BUILTIN and alloc using TDB */
192         if ( ! dom->default_domain) {
193                 DEBUG(1, ("WARNING: idmap_ad is not configured as the default domain.\n"
194                           "For best results we suggest you to configure this module as\n"
195                           "default and configure BULTIN to use idmap_tdb\n"
196                           "ex: idmap domains = BUILTIN %s\n"
197                           "    idmap alloc config: range = 5000 - 9999\n"
198                           "    idmap config %s: default = yes\n"
199                           "    idmap config %s: backend = ad\n"
200                           "    idmap config %s: range = 10000 - 10000000  #this is optional\n"
201                           "NOTE: make sure the ranges do not overlap\n",
202                           dom->name, dom->name, dom->name, dom->name));
203         }
204
205         if ( !dom->readonly ) {
206                 DEBUG(1, ("WARNING: forcing to readonly, as idmap_ad can't write on AD.\n"));
207                 dom->readonly = true;
208         }
209
210         dom->private_data = ctx;
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         char *filter = NULL;
268         int idx = 0;
269         int bidx = 0;
270         int count;
271         int i;
272         char *u_filter = NULL;
273         char *g_filter = NULL;
274
275         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
276
277         if ( (memctx = talloc_new(ctx)) == NULL ) {
278                 DEBUG(0, ("Out of memory!\n"));
279                 return NT_STATUS_NO_MEMORY;
280         }
281
282         if ( (ads = ad_idmap_cached_connection()) == NULL ) {
283                 DEBUG(1, ("ADS uninitialized\n"));
284                 ret = NT_STATUS_UNSUCCESSFUL;
285                 goto done;
286         }
287
288         attrs[2] = ad_schema->posix_uidnumber_attr;
289         attrs[3] = ad_schema->posix_gidnumber_attr;
290
291 again:
292         bidx = idx;
293         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
294                 switch (ids[idx]->xid.type) {
295                 case ID_TYPE_UID:     
296                         if ( ! u_filter) {
297                                 u_filter = talloc_asprintf(memctx, "(&(|"
298                                                            "(sAMAccountType=%d)"
299                                                            "(sAMAccountType=%d)"
300                                                            "(sAMAccountType=%d))(|",
301                                                            ATYPE_NORMAL_ACCOUNT,
302                                                            ATYPE_WORKSTATION_TRUST,
303                                                            ATYPE_INTERDOMAIN_TRUST);
304                         }
305                         u_filter = talloc_asprintf_append(u_filter, "(%s=%lu)",
306                                                           ad_schema->posix_uidnumber_attr,
307                                                           (unsigned long)ids[idx]->xid.id);
308                         CHECK_ALLOC_DONE(u_filter);
309                         break;
310                                 
311                 case ID_TYPE_GID:
312                         if ( ! g_filter) {
313                                 g_filter = talloc_asprintf(memctx, "(&(|"
314                                                            "(sAMAccountType=%d)"
315                                                            "(sAMAccountType=%d))(|",
316                                                            ATYPE_SECURITY_GLOBAL_GROUP,
317                                                            ATYPE_SECURITY_LOCAL_GROUP);
318                         }
319                         g_filter = talloc_asprintf_append(g_filter, "(%s=%lu)",
320                                                           ad_schema->posix_gidnumber_attr,
321                                                           (unsigned long)ids[idx]->xid.id);
322                         CHECK_ALLOC_DONE(g_filter);
323                         break;
324
325                 default:
326                         DEBUG(3, ("Unknown ID type\n"));
327                         ids[idx]->status = ID_UNKNOWN;
328                         continue;
329                 }
330         }
331         filter = talloc_asprintf(memctx, "(|");
332         CHECK_ALLOC_DONE(filter);
333         if ( u_filter) {
334                 filter = talloc_asprintf_append(filter, "%s))", u_filter);
335                 CHECK_ALLOC_DONE(filter);
336                         TALLOC_FREE(u_filter);
337         }
338         if ( g_filter) {
339                 filter = talloc_asprintf_append(filter, "%s))", g_filter);
340                 CHECK_ALLOC_DONE(filter);
341                 TALLOC_FREE(g_filter);
342         }
343         filter = talloc_asprintf_append(filter, ")");
344         CHECK_ALLOC_DONE(filter);
345         DEBUG(10, ("Filter: [%s]\n", filter));
346         rc = ads_search_retry(ads, &res, filter, attrs);
347         if (!ADS_ERR_OK(rc)) {
348                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
349                 ret = NT_STATUS_UNSUCCESSFUL;
350                 goto done;
351         }
352
353         if ( (count = ads_count_replies(ads, res)) == 0 ) {
354                 DEBUG(10, ("No IDs found\n"));
355         }
356
357         for (i = 0; i < count; i++) {
358                 LDAPMessage *entry = NULL;
359                 DOM_SID sid;
360                 enum id_type type;
361                 struct id_map *map;
362                 uint32_t id;
363                 uint32_t atype;
364
365                 if (i == 0) { /* first entry */
366                         entry = ads_first_entry(ads, res);
367                 } else { /* following ones */
368                         entry = ads_next_entry(ads, entry);
369                 }
370                 if ( ! entry) {
371                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
372                         continue;
373                 }
374
375                 /* first check if the SID is present */
376                 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
377                         DEBUG(2, ("Could not retrieve SID from entry\n"));
378                         continue;
379                 }
380
381                 /* get type */
382                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
383                         DEBUG(1, ("could not get SAM account type\n"));
384                         continue;
385                 }
386
387                 switch (atype & 0xF0000000) {
388                 case ATYPE_SECURITY_GLOBAL_GROUP:
389                 case ATYPE_SECURITY_LOCAL_GROUP:
390                         type = ID_TYPE_GID;
391                         break;
392                 case ATYPE_NORMAL_ACCOUNT:
393                 case ATYPE_WORKSTATION_TRUST:
394                 case ATYPE_INTERDOMAIN_TRUST:
395                         type = ID_TYPE_UID;
396                         break;
397                 default:
398                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
399                         continue;
400                 }
401
402                 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
403                                                  ad_schema->posix_uidnumber_attr : 
404                                                  ad_schema->posix_gidnumber_attr, 
405                                      &id)) 
406                 {
407                         DEBUG(1, ("Could not get unix ID\n"));
408                         continue;
409                 }
410
411                 if ((id == 0) ||
412                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
413                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
414                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
415                                 id, ctx->filter_low_id, ctx->filter_high_id));
416                         continue;
417                 }
418
419                 map = find_map_by_id(&ids[bidx], type, id);
420                 if (!map) {
421                         DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
422                         continue;
423                 }
424
425                 sid_copy(map->sid, &sid);
426
427                 /* mapped */
428                 map->status = ID_MAPPED;
429
430                 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
431                            sid_string_static(map->sid),
432                            (unsigned long)map->xid.id,
433                            map->xid.type));
434         }
435
436         if (res) {
437                 ads_msgfree(ads, res);
438         }
439
440         if (ids[idx]) { /* still some values to map */
441                 goto again;
442         }
443
444         ret = NT_STATUS_OK;
445
446         /* mark all unknown ones as unmapped */
447         for (i = 0; ids[i]; i++) {
448                 if (ids[i]->status == ID_UNKNOWN) 
449                         ids[i]->status = ID_UNMAPPED;
450         }
451
452 done:
453         talloc_free(memctx);
454         return ret;
455 }
456
457 /************************************************************************
458  ***********************************************************************/
459
460 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
461 {
462         NTSTATUS ret;
463         TALLOC_CTX *memctx;
464         struct idmap_ad_context *ctx;
465         ADS_STATUS rc;
466         ADS_STRUCT *ads;
467         const char *attrs[] = { "sAMAccountType", 
468                                 "objectSid",
469                                 NULL, /* attr_uidnumber */
470                                 NULL, /* attr_gidnumber */
471                                 NULL };
472         LDAPMessage *res = NULL;
473         char *filter = NULL;
474         int idx = 0;
475         int bidx = 0;
476         int count;
477         int i;
478         char *sidstr;
479
480         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);      
481
482         if ( (memctx = talloc_new(ctx)) == NULL ) {             
483                 DEBUG(0, ("Out of memory!\n"));
484                 return NT_STATUS_NO_MEMORY;
485         }
486
487         if ( (ads = ad_idmap_cached_connection()) == NULL ) {
488                 DEBUG(1, ("ADS uninitialized\n"));
489                 ret = NT_STATUS_UNSUCCESSFUL;
490                 goto done;
491         }
492
493         attrs[2] = ad_schema->posix_uidnumber_attr;
494         attrs[3] = ad_schema->posix_gidnumber_attr;
495
496 again:
497         filter = talloc_asprintf(memctx, "(&(|"
498                                  "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
499                                  "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
500                                  ")(|",
501                                  ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
502                                  ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
503                 
504         CHECK_ALLOC_DONE(filter);
505
506         bidx = idx;
507         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
508
509                 sidstr = sid_binstring(ids[idx]->sid);
510                 filter = talloc_asprintf_append(filter, "(objectSid=%s)", sidstr);
511                         
512                 free(sidstr);
513                 CHECK_ALLOC_DONE(filter);
514         }
515         filter = talloc_asprintf_append(filter, "))");
516         CHECK_ALLOC_DONE(filter);
517         DEBUG(10, ("Filter: [%s]\n", filter));
518
519         rc = ads_search_retry(ads, &res, filter, attrs);
520         if (!ADS_ERR_OK(rc)) {
521                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
522                 ret = NT_STATUS_UNSUCCESSFUL;
523                 goto done;
524         }
525
526         if ( (count = ads_count_replies(ads, res)) == 0 ) {
527                 DEBUG(10, ("No IDs found\n"));
528         }
529
530         for (i = 0; i < count; i++) {
531                 LDAPMessage *entry = NULL;
532                 DOM_SID sid;
533                 enum id_type type;
534                 struct id_map *map;
535                 uint32_t id;
536                 uint32_t atype;
537
538                 if (i == 0) { /* first entry */
539                         entry = ads_first_entry(ads, res);
540                 } else { /* following ones */
541                         entry = ads_next_entry(ads, entry);
542                 }
543                 if ( ! entry) {
544                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
545                         continue;
546                 }
547
548                 /* first check if the SID is present */
549                 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
550                         DEBUG(2, ("Could not retrieve SID from entry\n"));
551                         continue;
552                 }
553
554                 map = find_map_by_sid(&ids[bidx], &sid);
555                 if (!map) {
556                         DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
557                         continue;
558                 }
559
560                 /* get type */
561                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
562                         DEBUG(1, ("could not get SAM account type\n"));
563                         continue;
564                 }
565
566                 switch (atype & 0xF0000000) {
567                 case ATYPE_SECURITY_GLOBAL_GROUP:
568                 case ATYPE_SECURITY_LOCAL_GROUP:
569                         type = ID_TYPE_GID;
570                         break;
571                 case ATYPE_NORMAL_ACCOUNT:
572                 case ATYPE_WORKSTATION_TRUST:
573                 case ATYPE_INTERDOMAIN_TRUST:
574                         type = ID_TYPE_UID;
575                         break;
576                 default:
577                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
578                         continue;
579                 }
580
581                 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
582                                                  ad_schema->posix_uidnumber_attr : 
583                                                  ad_schema->posix_gidnumber_attr, 
584                                      &id)) 
585                 {
586                         DEBUG(1, ("Could not get unix ID\n"));
587                         continue;
588                 }
589                 if ((id == 0) ||
590                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
591                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
592                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
593                                 id, ctx->filter_low_id, ctx->filter_high_id));
594                         continue;
595                 }
596
597                 /* mapped */
598                 map->xid.type = type;
599                 map->xid.id = id;
600                 map->status = ID_MAPPED;
601
602                 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
603                            sid_string_static(map->sid),
604                            (unsigned long)map->xid.id,
605                            map->xid.type));
606         }
607
608         if (res) {
609                 ads_msgfree(ads, res);
610         }
611
612         if (ids[idx]) { /* still some values to map */
613                 goto again;
614         }
615
616         ret = NT_STATUS_OK;
617
618         /* mark all unknwon ones as unmapped */
619         for (i = 0; ids[i]; i++) {
620                 if (ids[i]->status == ID_UNKNOWN) 
621                         ids[i]->status = ID_UNMAPPED;
622         }
623
624 done:
625         talloc_free(memctx);
626         return ret;
627 }
628
629 /************************************************************************
630  ***********************************************************************/
631
632 static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
633 {
634         ADS_STRUCT *ads = ad_idmap_ads;
635
636         if (ads != NULL) {
637                 /* we own this ADS_STRUCT so make sure it goes away */
638                 ads->is_mine = True;
639                 ads_destroy( &ads );
640                 ad_idmap_ads = NULL;
641         }
642
643         TALLOC_FREE( ad_schema );
644         
645         return NT_STATUS_OK;
646 }
647
648 /*
649  * nss_info_{sfu,rfc2307}
650  */
651
652 /************************************************************************
653  Initialize the {sfu,rfc2307} state
654  ***********************************************************************/
655
656 static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
657 {
658         /* Sanity check if we have previously been called with a
659            different schema model */
660
661         if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
662              (ad_map_type != WB_POSIX_MAP_SFU) ) 
663         {
664                 DEBUG(0,("nss_sfu_init: Posix Map type has already been set.  "
665                          "Mixed schema models not supported!\n"));
666                 return NT_STATUS_NOT_SUPPORTED;
667         }
668         
669         ad_map_type =  WB_POSIX_MAP_SFU;        
670
671         if ( !ad_idmap_ads ) 
672                 return idmap_ad_initialize( NULL, NULL );       
673
674         return NT_STATUS_OK;
675 }
676
677 static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
678 {
679         /* Sanity check if we have previously been called with a
680            different schema model */
681          
682         if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
683              (ad_map_type != WB_POSIX_MAP_RFC2307) ) 
684         {
685                 DEBUG(0,("nss_rfc2307_init: Posix Map type has already been set.  "
686                          "Mixed schema models not supported!\n"));
687                 return NT_STATUS_NOT_SUPPORTED;
688         }
689         
690         ad_map_type =  WB_POSIX_MAP_RFC2307;
691
692         if ( !ad_idmap_ads ) 
693                 return idmap_ad_initialize( NULL, NULL );       
694
695         return NT_STATUS_OK;
696 }
697
698
699 /************************************************************************
700  ***********************************************************************/
701 static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, 
702                                   const DOM_SID *sid, 
703                                   TALLOC_CTX *ctx,
704                                   ADS_STRUCT *ads, 
705                                   LDAPMessage *msg,
706                                   char **homedir,
707                                   char **shell, 
708                                   char **gecos,
709                                   uint32 *gid )
710 {
711         char *home, *sh, *gec;
712
713         if ( !ad_schema )
714                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
715         
716         if ( !homedir || !shell || !gecos )
717                 return NT_STATUS_INVALID_PARAMETER;
718
719         home = ads_pull_string( ads, ctx, msg, ad_schema->posix_homedir_attr );
720         sh   = ads_pull_string( ads, ctx, msg, ad_schema->posix_shell_attr );
721         gec  = ads_pull_string( ads, ctx, msg, ad_schema->posix_gecos_attr );
722        
723         if ( gid ) {            
724                 if ( !ads_pull_uint32(ads, msg, ad_schema->posix_gidnumber_attr, gid ) )
725                         *gid = 0;               
726         }
727                 
728         if ( home )
729                 *homedir = talloc_strdup( ctx, home );
730         if ( sh )
731                 *shell   = talloc_strdup( ctx, sh );
732         if ( gec )
733                 *gecos   = talloc_strdup( ctx, gec );
734         
735         SAFE_FREE( home );
736         SAFE_FREE( sh );
737         SAFE_FREE( gec );
738         
739         return NT_STATUS_OK;
740 }
741
742 /************************************************************************
743  ***********************************************************************/
744
745 static NTSTATUS nss_ad_close( void )
746 {
747         /* nothing to do.  All memory is free()'d by the idmap close_fn() */
748
749         return NT_STATUS_OK;
750 }
751
752 /************************************************************************
753  Function dispatch tables for the idmap and nss plugins
754  ***********************************************************************/
755
756 static struct idmap_methods ad_methods = {
757         .init            = idmap_ad_initialize,
758         .unixids_to_sids = idmap_ad_unixids_to_sids,
759         .sids_to_unixids = idmap_ad_sids_to_unixids,
760         .close_fn        = idmap_ad_close
761 };
762
763 /* The SFU and RFC2307 NSS plugins share everything but the init
764    function which sets the intended schema model to use */
765   
766 static struct nss_info_methods nss_rfc2307_methods = {
767         .init         = nss_rfc2307_init,
768         .get_nss_info = nss_ad_get_info,
769         .close_fn     = nss_ad_close
770 };
771
772 static struct nss_info_methods nss_sfu_methods = {
773         .init         = nss_sfu_init,
774         .get_nss_info = nss_ad_get_info,
775         .close_fn     = nss_ad_close
776 };
777
778
779 /************************************************************************
780  Initialize the plugins
781  ***********************************************************************/
782
783 NTSTATUS idmap_ad_init(void)
784 {
785         static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
786         static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
787         static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
788
789         /* Always register the AD method first in order to get the
790            idmap_domain interface called */
791
792         if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
793                 status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, 
794                                                      "ad", &ad_methods);
795                 if ( !NT_STATUS_IS_OK(status_idmap_ad) )
796                         return status_idmap_ad;         
797         }
798         
799         if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
800                 status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
801                                                             "rfc2307",  &nss_rfc2307_methods );         
802                 if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
803                         return status_nss_rfc2307;
804         }
805
806         if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
807                 status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
808                                                         "sfu",  &nss_sfu_methods );             
809                 if ( !NT_STATUS_IS_OK(status_nss_sfu) )
810                         return status_nss_sfu;          
811         }
812
813         return NT_STATUS_OK;    
814 }
815