r22173: BUG 4491, 4501: Additional fixes for protecting against
[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_RFC2307) ) 
147         {
148                 ADS_STATUS schema_status;
149                 
150                 schema_status = ads_check_posix_schema_mapping( NULL, ads, ad_map_type, &ad_schema);
151                 if ( !ADS_ERR_OK(schema_status) ) {
152                         DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
153                         return NULL;                    
154                 }
155         }
156         
157         return ads;
158 }
159
160 /************************************************************************
161  ***********************************************************************/
162
163 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params)
164 {
165         struct idmap_ad_context *ctx;
166         char *config_option;
167         const char *range = NULL;
168         const char *schema_mode = NULL; 
169
170         if ( (ctx = talloc_zero(dom, struct idmap_ad_context)) == NULL ) {
171                 DEBUG(0, ("Out of memory!\n"));
172                 return NT_STATUS_NO_MEMORY;
173         }
174
175         if ( (config_option = talloc_asprintf(ctx, "idmap config %s", dom->name)) == NULL ) {
176                 DEBUG(0, ("Out of memory!\n"));
177                 talloc_free(ctx);
178                 return NT_STATUS_NO_MEMORY;
179         }
180
181         /* load ranges */
182         range = lp_parm_const_string(-1, config_option, "range", NULL);
183         if (range && range[0]) {
184                 if ((sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
185                     (ctx->filter_low_id > ctx->filter_high_id)) {
186                         DEBUG(1, ("ERROR: invalid filter range [%s]", range));
187                         ctx->filter_low_id = 0;
188                         ctx->filter_high_id = 0;
189                 }
190         }
191
192         /* schema mode */
193         if ( ad_map_type == WB_POSIX_MAP_UNKNOWN )
194                 ad_map_type = WB_POSIX_MAP_RFC2307;
195         schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL);
196         if ( schema_mode && schema_mode[0] ) {
197                 if ( strequal(schema_mode, "sfu") )
198                         ad_map_type = WB_POSIX_MAP_SFU;
199                 else if ( strequal(schema_mode, "rfc2307" ) )
200                         ad_map_type = WB_POSIX_MAP_RFC2307;
201                 else
202                         DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n",
203                                  schema_mode));
204         }
205
206         dom->private_data = ctx;
207
208         talloc_free(config_option);
209
210         return NT_STATUS_OK;
211 }
212
213 /************************************************************************
214  Search up to IDMAP_AD_MAX_IDS entries in maps for a match.
215  ***********************************************************************/
216
217 static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
218 {
219         int i;
220
221         for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
222                 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
223                         return maps[i];
224                 }
225         }
226
227         return NULL;    
228 }
229
230 /************************************************************************
231  Search up to IDMAP_AD_MAX_IDS entries in maps for a match
232  ***********************************************************************/
233
234 static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
235 {
236         int i;
237
238         for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
239                 if (sid_equal(maps[i]->sid, sid)) {
240                         return maps[i];
241                 }
242         }
243
244         return NULL;    
245 }
246
247 /************************************************************************
248  ***********************************************************************/
249
250 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
251 {
252         NTSTATUS ret;
253         TALLOC_CTX *memctx;
254         struct idmap_ad_context *ctx;
255         ADS_STATUS rc;
256         ADS_STRUCT *ads;
257         const char *attrs[] = { "sAMAccountType", 
258                                 "objectSid",
259                                 NULL, /* uidnumber */
260                                 NULL, /* gidnumber */
261                                 NULL };
262         LDAPMessage *res = NULL;
263         LDAPMessage *entry = NULL;
264         char *filter = NULL;
265         int idx = 0;
266         int bidx = 0;
267         int count;
268         int i;
269         char *u_filter = NULL;
270         char *g_filter = NULL;
271
272         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
273
274         if ( (memctx = talloc_new(ctx)) == NULL ) {
275                 DEBUG(0, ("Out of memory!\n"));
276                 return NT_STATUS_NO_MEMORY;
277         }
278
279         if ( (ads = ad_idmap_cached_connection()) == NULL ) {
280                 DEBUG(1, ("ADS uninitialized\n"));
281                 ret = NT_STATUS_UNSUCCESSFUL;
282                 goto done;
283         }
284
285         attrs[2] = ad_schema->posix_uidnumber_attr;
286         attrs[3] = ad_schema->posix_gidnumber_attr;
287
288 again:
289         bidx = idx;
290         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
291                 switch (ids[idx]->xid.type) {
292                 case ID_TYPE_UID:     
293                         if ( ! u_filter) {
294                                 u_filter = talloc_asprintf(memctx, "(&(|"
295                                                            "(sAMAccountType=%d)"
296                                                            "(sAMAccountType=%d)"
297                                                            "(sAMAccountType=%d))(|",
298                                                            ATYPE_NORMAL_ACCOUNT,
299                                                            ATYPE_WORKSTATION_TRUST,
300                                                            ATYPE_INTERDOMAIN_TRUST);
301                         }
302                         u_filter = talloc_asprintf_append(u_filter, "(%s=%lu)",
303                                                           ad_schema->posix_uidnumber_attr,
304                                                           (unsigned long)ids[idx]->xid.id);
305                         CHECK_ALLOC_DONE(u_filter);
306                         break;
307                                 
308                 case ID_TYPE_GID:
309                         if ( ! g_filter) {
310                                 g_filter = talloc_asprintf(memctx, "(&(|"
311                                                            "(sAMAccountType=%d)"
312                                                            "(sAMAccountType=%d))(|",
313                                                            ATYPE_SECURITY_GLOBAL_GROUP,
314                                                            ATYPE_SECURITY_LOCAL_GROUP);
315                         }
316                         g_filter = talloc_asprintf_append(g_filter, "(%s=%lu)",
317                                                           ad_schema->posix_gidnumber_attr,
318                                                           (unsigned long)ids[idx]->xid.id);
319                         CHECK_ALLOC_DONE(g_filter);
320                         break;
321
322                 default:
323                         DEBUG(3, ("Unknown ID type\n"));
324                         ids[idx]->status = ID_UNKNOWN;
325                         continue;
326                 }
327         }
328         filter = talloc_asprintf(memctx, "(|");
329         CHECK_ALLOC_DONE(filter);
330         if ( u_filter) {
331                 filter = talloc_asprintf_append(filter, "%s))", u_filter);
332                 CHECK_ALLOC_DONE(filter);
333                         TALLOC_FREE(u_filter);
334         }
335         if ( g_filter) {
336                 filter = talloc_asprintf_append(filter, "%s))", g_filter);
337                 CHECK_ALLOC_DONE(filter);
338                 TALLOC_FREE(g_filter);
339         }
340         filter = talloc_asprintf_append(filter, ")");
341         CHECK_ALLOC_DONE(filter);
342
343         rc = ads_search_retry(ads, &res, filter, attrs);
344         if (!ADS_ERR_OK(rc)) {
345                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
346                 ret = NT_STATUS_UNSUCCESSFUL;
347                 goto done;
348         }
349
350         if ( (count = ads_count_replies(ads, res)) == 0 ) {
351                 DEBUG(10, ("No IDs found\n"));
352         }
353
354         entry = res;
355         for (i = 0; (i < count) && entry; i++) {
356                 DOM_SID sid;
357                 enum id_type type;
358                 struct id_map *map;
359                 uint32_t id;
360                 uint32_t atype;
361
362                 if (i == 0) { /* first entry */
363                         entry = ads_first_entry(ads, entry);
364                 } else { /* following ones */
365                         entry = ads_next_entry(ads, entry);
366                 }
367
368                 if ( !entry ) {
369                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
370                         break;
371                 }
372
373                 /* first check if the SID is present */
374                 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
375                         DEBUG(2, ("Could not retrieve SID from entry\n"));
376                         continue;
377                 }
378
379                 /* get type */
380                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
381                         DEBUG(1, ("could not get SAM account type\n"));
382                         continue;
383                 }
384
385                 switch (atype & 0xF0000000) {
386                 case ATYPE_SECURITY_GLOBAL_GROUP:
387                 case ATYPE_SECURITY_LOCAL_GROUP:
388                         type = ID_TYPE_GID;
389                         break;
390                 case ATYPE_NORMAL_ACCOUNT:
391                 case ATYPE_WORKSTATION_TRUST:
392                 case ATYPE_INTERDOMAIN_TRUST:
393                         type = ID_TYPE_UID;
394                         break;
395                 default:
396                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
397                         continue;
398                 }
399
400                 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
401                                                  ad_schema->posix_uidnumber_attr : 
402                                                  ad_schema->posix_gidnumber_attr, 
403                                      &id)) 
404                 {
405                         DEBUG(1, ("Could not get unix ID\n"));
406                         continue;
407                 }
408
409                 if ((id == 0) ||
410                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
411                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
412                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
413                                 id, ctx->filter_low_id, ctx->filter_high_id));
414                         continue;
415                 }
416
417                 map = find_map_by_id(&ids[bidx], type, id);
418                 if (!map) {
419                         DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
420                         continue;
421                 }
422
423                 sid_copy(map->sid, &sid);
424
425                 /* mapped */
426                 map->status = ID_MAPPED;
427
428                 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
429                            sid_string_static(map->sid),
430                            (unsigned long)map->xid.id,
431                            map->xid.type));
432         }
433
434         if (res) {
435                 ads_msgfree(ads, res);
436         }
437
438         if (ids[idx]) { /* still some values to map */
439                 goto again;
440         }
441
442         ret = NT_STATUS_OK;
443
444         /* mark all unknown ones as unmapped */
445         for (i = 0; ids[i]; i++) {
446                 if (ids[i]->status == ID_UNKNOWN) 
447                         ids[i]->status = ID_UNMAPPED;
448         }
449
450 done:
451         talloc_free(memctx);
452         return ret;
453 }
454
455 /************************************************************************
456  ***********************************************************************/
457
458 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
459 {
460         NTSTATUS ret;
461         TALLOC_CTX *memctx;
462         struct idmap_ad_context *ctx;
463         ADS_STATUS rc;
464         ADS_STRUCT *ads;
465         const char *attrs[] = { "sAMAccountType", 
466                                 "objectSid",
467                                 NULL, /* attr_uidnumber */
468                                 NULL, /* attr_gidnumber */
469                                 NULL };
470         LDAPMessage *res = NULL;
471         LDAPMessage *entry = NULL;
472         char *filter = NULL;
473         int idx = 0;
474         int bidx = 0;
475         int count;
476         int i;
477         char *sidstr;
478
479         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);      
480
481         if ( (memctx = talloc_new(ctx)) == NULL ) {             
482                 DEBUG(0, ("Out of memory!\n"));
483                 return NT_STATUS_NO_MEMORY;
484         }
485
486         if ( (ads = ad_idmap_cached_connection()) == NULL ) {
487                 DEBUG(1, ("ADS uninitialized\n"));
488                 ret = NT_STATUS_UNSUCCESSFUL;
489                 goto done;
490         }
491
492         attrs[2] = ad_schema->posix_uidnumber_attr;
493         attrs[3] = ad_schema->posix_gidnumber_attr;
494
495 again:
496         filter = talloc_asprintf(memctx, "(&(|"
497                                  "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
498                                  "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
499                                  ")(|",
500                                  ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
501                                  ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
502                 
503         CHECK_ALLOC_DONE(filter);
504
505         bidx = idx;
506         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
507
508                 sidstr = sid_binstring(ids[idx]->sid);
509                 filter = talloc_asprintf_append(filter, "(objectSid=%s)", sidstr);
510                         
511                 free(sidstr);
512                 CHECK_ALLOC_DONE(filter);
513         }
514         filter = talloc_asprintf_append(filter, "))");
515         CHECK_ALLOC_DONE(filter);
516         DEBUG(10, ("Filter: [%s]\n", filter));
517
518         rc = ads_search_retry(ads, &res, filter, attrs);
519         if (!ADS_ERR_OK(rc)) {
520                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
521                 ret = NT_STATUS_UNSUCCESSFUL;
522                 goto done;
523         }
524
525         if ( (count = ads_count_replies(ads, res)) == 0 ) {
526                 DEBUG(10, ("No IDs found\n"));
527         }
528
529         entry = res;    
530         for (i = 0; (i < count) && entry; i++) {
531                 DOM_SID sid;
532                 enum id_type type;
533                 struct id_map *map;
534                 uint32_t id;
535                 uint32_t atype;
536
537                 if (i == 0) { /* first entry */
538                         entry = ads_first_entry(ads, entry);
539                 } else { /* following ones */
540                         entry = ads_next_entry(ads, entry);
541                 }
542
543                 if ( !entry ) {
544                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
545                         break;
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         ADS_STRUCT *ads_internal = NULL;
712
713         /* We are assuming that the internal ADS_STRUCT is for the 
714            same forest as the incoming *ads pointer */
715
716         ads_internal = ad_idmap_cached_connection();
717
718         if ( !ads_internal || !ad_schema )
719                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
720         
721         if ( !homedir || !shell || !gecos )
722                 return NT_STATUS_INVALID_PARAMETER;
723
724         *homedir = ads_pull_string( ads, ctx, msg, ad_schema->posix_homedir_attr );
725         *shell   = ads_pull_string( ads, ctx, msg, ad_schema->posix_shell_attr );
726         *gecos   = ads_pull_string( ads, ctx, msg, ad_schema->posix_gecos_attr );
727        
728         if ( gid ) {            
729                 if ( !ads_pull_uint32(ads, msg, ad_schema->posix_gidnumber_attr, gid ) )
730                         *gid = 0;               
731         }
732                 
733         return NT_STATUS_OK;
734 }
735
736 /************************************************************************
737  ***********************************************************************/
738
739 static NTSTATUS nss_ad_close( void )
740 {
741         /* nothing to do.  All memory is free()'d by the idmap close_fn() */
742
743         return NT_STATUS_OK;
744 }
745
746 /************************************************************************
747  Function dispatch tables for the idmap and nss plugins
748  ***********************************************************************/
749
750 static struct idmap_methods ad_methods = {
751         .init            = idmap_ad_initialize,
752         .unixids_to_sids = idmap_ad_unixids_to_sids,
753         .sids_to_unixids = idmap_ad_sids_to_unixids,
754         .close_fn        = idmap_ad_close
755 };
756
757 /* The SFU and RFC2307 NSS plugins share everything but the init
758    function which sets the intended schema model to use */
759   
760 static struct nss_info_methods nss_rfc2307_methods = {
761         .init         = nss_rfc2307_init,
762         .get_nss_info = nss_ad_get_info,
763         .close_fn     = nss_ad_close
764 };
765
766 static struct nss_info_methods nss_sfu_methods = {
767         .init         = nss_sfu_init,
768         .get_nss_info = nss_ad_get_info,
769         .close_fn     = nss_ad_close
770 };
771
772
773 /************************************************************************
774  Initialize the plugins
775  ***********************************************************************/
776
777 NTSTATUS idmap_ad_init(void)
778 {
779         static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
780         static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
781         static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
782
783         /* Always register the AD method first in order to get the
784            idmap_domain interface called */
785
786         if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
787                 status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, 
788                                                      "ad", &ad_methods);
789                 if ( !NT_STATUS_IS_OK(status_idmap_ad) )
790                         return status_idmap_ad;         
791         }
792         
793         if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
794                 status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
795                                                             "rfc2307",  &nss_rfc2307_methods );         
796                 if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
797                         return status_nss_rfc2307;
798         }
799
800         if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
801                 status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
802                                                         "sfu",  &nss_sfu_methods );             
803                 if ( !NT_STATUS_IS_OK(status_nss_sfu) )
804                         return status_nss_sfu;          
805         }
806
807         return NT_STATUS_OK;    
808 }
809