eff3545d1575cbd2db8371c8ac9a4354337e61c3
[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         ADS_STRUCT *ads;
170
171         if ( (ctx = talloc_zero(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, "rfc2307" ) )
201                         ad_map_type = WB_POSIX_MAP_RFC2307;
202                 else
203                         DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n",
204                                  schema_mode));
205         }
206
207         dom->private_data = ctx;
208
209         talloc_free(config_option);
210
211         return NT_STATUS_OK;
212 }
213
214 /************************************************************************
215  Search up to IDMAP_AD_MAX_IDS entries in maps for a match.
216  ***********************************************************************/
217
218 static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
219 {
220         int i;
221
222         for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
223                 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
224                         return maps[i];
225                 }
226         }
227
228         return NULL;    
229 }
230
231 /************************************************************************
232  Search up to IDMAP_AD_MAX_IDS entries in maps for a match
233  ***********************************************************************/
234
235 static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
236 {
237         int i;
238
239         for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
240                 if (sid_equal(maps[i]->sid, sid)) {
241                         return maps[i];
242                 }
243         }
244
245         return NULL;    
246 }
247
248 /************************************************************************
249  ***********************************************************************/
250
251 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
252 {
253         NTSTATUS ret;
254         TALLOC_CTX *memctx;
255         struct idmap_ad_context *ctx;
256         ADS_STATUS rc;
257         ADS_STRUCT *ads;
258         const char *attrs[] = { "sAMAccountType", 
259                                 "objectSid",
260                                 NULL, /* uidnumber */
261                                 NULL, /* gidnumber */
262                                 NULL };
263         LDAPMessage *res = 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         DEBUG(10, ("Filter: [%s]\n", filter));
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         for (i = 0; i < count; i++) {
355                 LDAPMessage *entry = NULL;
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, res);
364                 } else { /* following ones */
365                         entry = ads_next_entry(ads, entry);
366                 }
367                 if ( ! entry) {
368                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
369                         continue;
370                 }
371
372                 /* first check if the SID is present */
373                 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
374                         DEBUG(2, ("Could not retrieve SID from entry\n"));
375                         continue;
376                 }
377
378                 /* get type */
379                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
380                         DEBUG(1, ("could not get SAM account type\n"));
381                         continue;
382                 }
383
384                 switch (atype & 0xF0000000) {
385                 case ATYPE_SECURITY_GLOBAL_GROUP:
386                 case ATYPE_SECURITY_LOCAL_GROUP:
387                         type = ID_TYPE_GID;
388                         break;
389                 case ATYPE_NORMAL_ACCOUNT:
390                 case ATYPE_WORKSTATION_TRUST:
391                 case ATYPE_INTERDOMAIN_TRUST:
392                         type = ID_TYPE_UID;
393                         break;
394                 default:
395                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
396                         continue;
397                 }
398
399                 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
400                                                  ad_schema->posix_uidnumber_attr : 
401                                                  ad_schema->posix_gidnumber_attr, 
402                                      &id)) 
403                 {
404                         DEBUG(1, ("Could not get unix ID\n"));
405                         continue;
406                 }
407
408                 if ((id == 0) ||
409                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
410                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
411                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
412                                 id, ctx->filter_low_id, ctx->filter_high_id));
413                         continue;
414                 }
415
416                 map = find_map_by_id(&ids[bidx], type, id);
417                 if (!map) {
418                         DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
419                         continue;
420                 }
421
422                 sid_copy(map->sid, &sid);
423
424                 /* mapped */
425                 map->status = ID_MAPPED;
426
427                 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
428                            sid_string_static(map->sid),
429                            (unsigned long)map->xid.id,
430                            map->xid.type));
431         }
432
433         if (res) {
434                 ads_msgfree(ads, res);
435         }
436
437         if (ids[idx]) { /* still some values to map */
438                 goto again;
439         }
440
441         ret = NT_STATUS_OK;
442
443         /* mark all unknown ones as unmapped */
444         for (i = 0; ids[i]; i++) {
445                 if (ids[i]->status == ID_UNKNOWN) 
446                         ids[i]->status = ID_UNMAPPED;
447         }
448
449 done:
450         talloc_free(memctx);
451         return ret;
452 }
453
454 /************************************************************************
455  ***********************************************************************/
456
457 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
458 {
459         NTSTATUS ret;
460         TALLOC_CTX *memctx;
461         struct idmap_ad_context *ctx;
462         ADS_STATUS rc;
463         ADS_STRUCT *ads;
464         const char *attrs[] = { "sAMAccountType", 
465                                 "objectSid",
466                                 NULL, /* attr_uidnumber */
467                                 NULL, /* attr_gidnumber */
468                                 NULL };
469         LDAPMessage *res = NULL;
470         char *filter = NULL;
471         int idx = 0;
472         int bidx = 0;
473         int count;
474         int i;
475         char *sidstr;
476
477         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);      
478
479         if ( (memctx = talloc_new(ctx)) == NULL ) {             
480                 DEBUG(0, ("Out of memory!\n"));
481                 return NT_STATUS_NO_MEMORY;
482         }
483
484         if ( (ads = ad_idmap_cached_connection()) == NULL ) {
485                 DEBUG(1, ("ADS uninitialized\n"));
486                 ret = NT_STATUS_UNSUCCESSFUL;
487                 goto done;
488         }
489
490         attrs[2] = ad_schema->posix_uidnumber_attr;
491         attrs[3] = ad_schema->posix_gidnumber_attr;
492
493 again:
494         filter = talloc_asprintf(memctx, "(&(|"
495                                  "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
496                                  "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
497                                  ")(|",
498                                  ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
499                                  ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
500                 
501         CHECK_ALLOC_DONE(filter);
502
503         bidx = idx;
504         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
505
506                 sidstr = sid_binstring(ids[idx]->sid);
507                 filter = talloc_asprintf_append(filter, "(objectSid=%s)", sidstr);
508                         
509                 free(sidstr);
510                 CHECK_ALLOC_DONE(filter);
511         }
512         filter = talloc_asprintf_append(filter, "))");
513         CHECK_ALLOC_DONE(filter);
514         DEBUG(10, ("Filter: [%s]\n", filter));
515
516         rc = ads_search_retry(ads, &res, filter, attrs);
517         if (!ADS_ERR_OK(rc)) {
518                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
519                 ret = NT_STATUS_UNSUCCESSFUL;
520                 goto done;
521         }
522
523         if ( (count = ads_count_replies(ads, res)) == 0 ) {
524                 DEBUG(10, ("No IDs found\n"));
525         }
526
527         for (i = 0; i < count; i++) {
528                 LDAPMessage *entry = NULL;
529                 DOM_SID sid;
530                 enum id_type type;
531                 struct id_map *map;
532                 uint32_t id;
533                 uint32_t atype;
534
535                 if (i == 0) { /* first entry */
536                         entry = ads_first_entry(ads, res);
537                 } else { /* following ones */
538                         entry = ads_next_entry(ads, entry);
539                 }
540                 if ( ! entry) {
541                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
542                         continue;
543                 }
544
545                 /* first check if the SID is present */
546                 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
547                         DEBUG(2, ("Could not retrieve SID from entry\n"));
548                         continue;
549                 }
550
551                 map = find_map_by_sid(&ids[bidx], &sid);
552                 if (!map) {
553                         DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
554                         continue;
555                 }
556
557                 /* get type */
558                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
559                         DEBUG(1, ("could not get SAM account type\n"));
560                         continue;
561                 }
562
563                 switch (atype & 0xF0000000) {
564                 case ATYPE_SECURITY_GLOBAL_GROUP:
565                 case ATYPE_SECURITY_LOCAL_GROUP:
566                         type = ID_TYPE_GID;
567                         break;
568                 case ATYPE_NORMAL_ACCOUNT:
569                 case ATYPE_WORKSTATION_TRUST:
570                 case ATYPE_INTERDOMAIN_TRUST:
571                         type = ID_TYPE_UID;
572                         break;
573                 default:
574                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
575                         continue;
576                 }
577
578                 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
579                                                  ad_schema->posix_uidnumber_attr : 
580                                                  ad_schema->posix_gidnumber_attr, 
581                                      &id)) 
582                 {
583                         DEBUG(1, ("Could not get unix ID\n"));
584                         continue;
585                 }
586                 if ((id == 0) ||
587                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
588                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
589                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
590                                 id, ctx->filter_low_id, ctx->filter_high_id));
591                         continue;
592                 }
593
594                 /* mapped */
595                 map->xid.type = type;
596                 map->xid.id = id;
597                 map->status = ID_MAPPED;
598
599                 DEBUG(10, ("Mapped %s -> %lu (%d)\n",
600                            sid_string_static(map->sid),
601                            (unsigned long)map->xid.id,
602                            map->xid.type));
603         }
604
605         if (res) {
606                 ads_msgfree(ads, res);
607         }
608
609         if (ids[idx]) { /* still some values to map */
610                 goto again;
611         }
612
613         ret = NT_STATUS_OK;
614
615         /* mark all unknwon ones as unmapped */
616         for (i = 0; ids[i]; i++) {
617                 if (ids[i]->status == ID_UNKNOWN) 
618                         ids[i]->status = ID_UNMAPPED;
619         }
620
621 done:
622         talloc_free(memctx);
623         return ret;
624 }
625
626 /************************************************************************
627  ***********************************************************************/
628
629 static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
630 {
631         ADS_STRUCT *ads = ad_idmap_ads;
632
633         if (ads != NULL) {
634                 /* we own this ADS_STRUCT so make sure it goes away */
635                 ads->is_mine = True;
636                 ads_destroy( &ads );
637                 ad_idmap_ads = NULL;
638         }
639
640         TALLOC_FREE( ad_schema );
641         
642         return NT_STATUS_OK;
643 }
644
645 /*
646  * nss_info_{sfu,rfc2307}
647  */
648
649 /************************************************************************
650  Initialize the {sfu,rfc2307} state
651  ***********************************************************************/
652
653 static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
654 {
655         /* Sanity check if we have previously been called with a
656            different schema model */
657
658         if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
659              (ad_map_type != WB_POSIX_MAP_SFU) ) 
660         {
661                 DEBUG(0,("nss_sfu_init: Posix Map type has already been set.  "
662                          "Mixed schema models not supported!\n"));
663                 return NT_STATUS_NOT_SUPPORTED;
664         }
665         
666         ad_map_type =  WB_POSIX_MAP_SFU;        
667
668         if ( !ad_idmap_ads ) 
669                 return idmap_ad_initialize( NULL, NULL );       
670
671         return NT_STATUS_OK;
672 }
673
674 static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
675 {
676         /* Sanity check if we have previously been called with a
677            different schema model */
678          
679         if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
680              (ad_map_type != WB_POSIX_MAP_RFC2307) ) 
681         {
682                 DEBUG(0,("nss_rfc2307_init: Posix Map type has already been set.  "
683                          "Mixed schema models not supported!\n"));
684                 return NT_STATUS_NOT_SUPPORTED;
685         }
686         
687         ad_map_type =  WB_POSIX_MAP_RFC2307;
688
689         if ( !ad_idmap_ads ) 
690                 return idmap_ad_initialize( NULL, NULL );       
691
692         return NT_STATUS_OK;
693 }
694
695
696 /************************************************************************
697  ***********************************************************************/
698 static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, 
699                                   const DOM_SID *sid, 
700                                   TALLOC_CTX *ctx,
701                                   ADS_STRUCT *ads, 
702                                   LDAPMessage *msg,
703                                   char **homedir,
704                                   char **shell, 
705                                   char **gecos,
706                                   uint32 *gid )
707 {
708         ADS_STRUCT *ads_internal = NULL;
709
710         /* We are assuming that the internal ADS_STRUCT is for the 
711            same forest as the incoming *ads pointer */
712
713         ads_internal = ad_idmap_cached_connection();
714
715         if ( !ads_internal || !ad_schema )
716                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
717         
718         if ( !homedir || !shell || !gecos )
719                 return NT_STATUS_INVALID_PARAMETER;
720
721         *homedir = ads_pull_string( ads, ctx, msg, ad_schema->posix_homedir_attr );
722         *shell   = ads_pull_string( ads, ctx, msg, ad_schema->posix_shell_attr );
723         *gecos   = ads_pull_string( ads, ctx, msg, ad_schema->posix_gecos_attr );
724        
725         if ( gid ) {            
726                 if ( !ads_pull_uint32(ads, msg, ad_schema->posix_gidnumber_attr, gid ) )
727                         *gid = 0;               
728         }
729                 
730         return NT_STATUS_OK;
731 }
732
733 /************************************************************************
734  ***********************************************************************/
735
736 static NTSTATUS nss_ad_close( void )
737 {
738         /* nothing to do.  All memory is free()'d by the idmap close_fn() */
739
740         return NT_STATUS_OK;
741 }
742
743 /************************************************************************
744  Function dispatch tables for the idmap and nss plugins
745  ***********************************************************************/
746
747 static struct idmap_methods ad_methods = {
748         .init            = idmap_ad_initialize,
749         .unixids_to_sids = idmap_ad_unixids_to_sids,
750         .sids_to_unixids = idmap_ad_sids_to_unixids,
751         .close_fn        = idmap_ad_close
752 };
753
754 /* The SFU and RFC2307 NSS plugins share everything but the init
755    function which sets the intended schema model to use */
756   
757 static struct nss_info_methods nss_rfc2307_methods = {
758         .init         = nss_rfc2307_init,
759         .get_nss_info = nss_ad_get_info,
760         .close_fn     = nss_ad_close
761 };
762
763 static struct nss_info_methods nss_sfu_methods = {
764         .init         = nss_sfu_init,
765         .get_nss_info = nss_ad_get_info,
766         .close_fn     = nss_ad_close
767 };
768
769
770 /************************************************************************
771  Initialize the plugins
772  ***********************************************************************/
773
774 NTSTATUS idmap_ad_init(void)
775 {
776         static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
777         static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
778         static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
779
780         /* Always register the AD method first in order to get the
781            idmap_domain interface called */
782
783         if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
784                 status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, 
785                                                      "ad", &ad_methods);
786                 if ( !NT_STATUS_IS_OK(status_idmap_ad) )
787                         return status_idmap_ad;         
788         }
789         
790         if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
791                 status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
792                                                             "rfc2307",  &nss_rfc2307_methods );         
793                 if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
794                         return status_nss_rfc2307;
795         }
796
797         if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
798                 status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
799                                                         "sfu",  &nss_sfu_methods );             
800                 if ( !NT_STATUS_IS_OK(status_nss_sfu) )
801                         return status_nss_sfu;          
802         }
803
804         return NT_STATUS_OK;    
805 }
806