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