Replace sid_string_static by sid_string_dbg in DEBUGs
[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 sockaddr_storage 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_buffer(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_buffer(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_buffer(filter, "%s))", u_filter);
348                 CHECK_ALLOC_DONE(filter);
349                         TALLOC_FREE(u_filter);
350         }
351         if ( g_filter) {
352                 filter = talloc_asprintf_append_buffer(filter, "%s))", g_filter);
353                 CHECK_ALLOC_DONE(filter);
354                 TALLOC_FREE(g_filter);
355         }
356         filter = talloc_asprintf_append_buffer(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", sid_string_dbg(map->sid),
445                            (unsigned long)map->xid.id,
446                            map->xid.type));
447         }
448
449         if (res) {
450                 ads_msgfree(ads, res);
451         }
452
453         if (ids[idx]) { /* still some values to map */
454                 goto again;
455         }
456
457         ret = NT_STATUS_OK;
458
459         /* mark all unknown/expired ones as unmapped */
460         for (i = 0; ids[i]; i++) {
461                 if (ids[i]->status != ID_MAPPED) 
462                         ids[i]->status = ID_UNMAPPED;
463         }
464
465 done:
466         talloc_free(memctx);
467         return ret;
468 }
469
470 /************************************************************************
471  ***********************************************************************/
472
473 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
474 {
475         NTSTATUS ret;
476         TALLOC_CTX *memctx;
477         struct idmap_ad_context *ctx;
478         ADS_STATUS rc;
479         ADS_STRUCT *ads;
480         const char *attrs[] = { "sAMAccountType", 
481                                 "objectSid",
482                                 NULL, /* attr_uidnumber */
483                                 NULL, /* attr_gidnumber */
484                                 NULL };
485         LDAPMessage *res = NULL;
486         LDAPMessage *entry = NULL;
487         char *filter = NULL;
488         int idx = 0;
489         int bidx = 0;
490         int count;
491         int i;
492         char *sidstr;
493
494         /* Only do query if we are online */
495         if (idmap_is_offline()) {
496                 return NT_STATUS_FILE_IS_OFFLINE;
497         }
498
499         /* Initilization my have been deferred because we were offline */
500         if ( ! dom->initialized) {
501                 ret = idmap_ad_initialize(dom);
502                 if ( ! NT_STATUS_IS_OK(ret)) {
503                         return ret;
504                 }
505         }
506
507         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);      
508
509         if ( (memctx = talloc_new(ctx)) == NULL ) {             
510                 DEBUG(0, ("Out of memory!\n"));
511                 return NT_STATUS_NO_MEMORY;
512         }
513
514         if ( (ads = ad_idmap_cached_connection()) == NULL ) {
515                 DEBUG(1, ("ADS uninitialized\n"));
516                 ret = NT_STATUS_UNSUCCESSFUL;
517                 goto done;
518         }
519
520         attrs[2] = ad_schema->posix_uidnumber_attr;
521         attrs[3] = ad_schema->posix_gidnumber_attr;
522
523 again:
524         filter = talloc_asprintf(memctx, "(&(|"
525                                  "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
526                                  "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
527                                  ")(|",
528                                  ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
529                                  ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
530                 
531         CHECK_ALLOC_DONE(filter);
532
533         bidx = idx;
534         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
535
536                 sidstr = sid_binstring(ids[idx]->sid);
537                 filter = talloc_asprintf_append_buffer(filter, "(objectSid=%s)", sidstr);
538                         
539                 free(sidstr);
540                 CHECK_ALLOC_DONE(filter);
541         }
542         filter = talloc_asprintf_append_buffer(filter, "))");
543         CHECK_ALLOC_DONE(filter);
544         DEBUG(10, ("Filter: [%s]\n", filter));
545
546         rc = ads_search_retry(ads, &res, filter, attrs);
547         if (!ADS_ERR_OK(rc)) {
548                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
549                 ret = NT_STATUS_UNSUCCESSFUL;
550                 goto done;
551         }
552
553         if ( (count = ads_count_replies(ads, res)) == 0 ) {
554                 DEBUG(10, ("No IDs found\n"));
555         }
556
557         entry = res;    
558         for (i = 0; (i < count) && entry; i++) {
559                 DOM_SID sid;
560                 enum id_type type;
561                 struct id_map *map;
562                 uint32_t id;
563                 uint32_t atype;
564
565                 if (i == 0) { /* first entry */
566                         entry = ads_first_entry(ads, entry);
567                 } else { /* following ones */
568                         entry = ads_next_entry(ads, entry);
569                 }
570
571                 if ( !entry ) {
572                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
573                         break;
574                 }
575
576                 /* first check if the SID is present */
577                 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
578                         DEBUG(2, ("Could not retrieve SID from entry\n"));
579                         continue;
580                 }
581
582                 map = find_map_by_sid(&ids[bidx], &sid);
583                 if (!map) {
584                         DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
585                         continue;
586                 }
587
588                 /* get type */
589                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
590                         DEBUG(1, ("could not get SAM account type\n"));
591                         continue;
592                 }
593
594                 switch (atype & 0xF0000000) {
595                 case ATYPE_SECURITY_GLOBAL_GROUP:
596                 case ATYPE_SECURITY_LOCAL_GROUP:
597                         type = ID_TYPE_GID;
598                         break;
599                 case ATYPE_NORMAL_ACCOUNT:
600                 case ATYPE_WORKSTATION_TRUST:
601                 case ATYPE_INTERDOMAIN_TRUST:
602                         type = ID_TYPE_UID;
603                         break;
604                 default:
605                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
606                         continue;
607                 }
608
609                 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
610                                                  ad_schema->posix_uidnumber_attr : 
611                                                  ad_schema->posix_gidnumber_attr, 
612                                      &id)) 
613                 {
614                         DEBUG(1, ("Could not get unix ID\n"));
615                         continue;
616                 }
617                 if ((id == 0) ||
618                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
619                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
620                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
621                                 id, ctx->filter_low_id, ctx->filter_high_id));
622                         continue;
623                 }
624
625                 /* mapped */
626                 map->xid.type = type;
627                 map->xid.id = id;
628                 map->status = ID_MAPPED;
629
630                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
631                            (unsigned long)map->xid.id,
632                            map->xid.type));
633         }
634
635         if (res) {
636                 ads_msgfree(ads, res);
637         }
638
639         if (ids[idx]) { /* still some values to map */
640                 goto again;
641         }
642
643         ret = NT_STATUS_OK;
644
645         /* mark all unknwoni/expired ones as unmapped */
646         for (i = 0; ids[i]; i++) {
647                 if (ids[i]->status != ID_MAPPED) 
648                         ids[i]->status = ID_UNMAPPED;
649         }
650
651 done:
652         talloc_free(memctx);
653         return ret;
654 }
655
656 /************************************************************************
657  ***********************************************************************/
658
659 static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
660 {
661         ADS_STRUCT *ads = ad_idmap_ads;
662
663         if (ads != NULL) {
664                 /* we own this ADS_STRUCT so make sure it goes away */
665                 ads->is_mine = True;
666                 ads_destroy( &ads );
667                 ad_idmap_ads = NULL;
668         }
669
670         TALLOC_FREE( ad_schema );
671         
672         return NT_STATUS_OK;
673 }
674
675 /*
676  * nss_info_{sfu,sfu20,rfc2307}
677  */
678
679 /************************************************************************
680  Initialize the {sfu,sfu20,rfc2307} state
681  ***********************************************************************/
682
683 static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
684 {
685         /* Sanity check if we have previously been called with a
686            different schema model */
687
688         if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
689              (ad_map_type != WB_POSIX_MAP_SFU) ) 
690         {
691                 DEBUG(0,("nss_sfu_init: Posix Map type has already been set.  "
692                          "Mixed schema models not supported!\n"));
693                 return NT_STATUS_NOT_SUPPORTED;
694         }
695         
696         ad_map_type = WB_POSIX_MAP_SFU; 
697
698         return NT_STATUS_OK;
699 }
700
701 static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e )
702 {
703         /* Sanity check if we have previously been called with a
704            different schema model */
705
706         if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
707              (ad_map_type != WB_POSIX_MAP_SFU20) )
708         {
709                 DEBUG(0,("nss_sfu20_init: Posix Map type has already been set.  "
710                          "Mixed schema models not supported!\n"));
711                 return NT_STATUS_NOT_SUPPORTED;
712         }
713         
714         ad_map_type = WB_POSIX_MAP_SFU20;       
715
716         return NT_STATUS_OK;
717 }
718
719 static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
720 {
721         /* Sanity check if we have previously been called with a
722            different schema model */
723          
724         if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
725              (ad_map_type != WB_POSIX_MAP_RFC2307) ) 
726         {
727                 DEBUG(0,("nss_rfc2307_init: Posix Map type has already been set.  "
728                          "Mixed schema models not supported!\n"));
729                 return NT_STATUS_NOT_SUPPORTED;
730         }
731         
732         ad_map_type = WB_POSIX_MAP_RFC2307;
733
734         return NT_STATUS_OK;
735 }
736
737
738 /************************************************************************
739  ***********************************************************************/
740 static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, 
741                                   const DOM_SID *sid, 
742                                   TALLOC_CTX *ctx,
743                                   ADS_STRUCT *ads, 
744                                   LDAPMessage *msg,
745                                   char **homedir,
746                                   char **shell, 
747                                   char **gecos,
748                                   uint32 *gid )
749 {
750         ADS_STRUCT *ads_internal = NULL;
751
752         /* Only do query if we are online */
753         if (idmap_is_offline()) {
754                 return NT_STATUS_FILE_IS_OFFLINE;
755         }
756
757         /* We are assuming that the internal ADS_STRUCT is for the 
758            same forest as the incoming *ads pointer */
759
760         ads_internal = ad_idmap_cached_connection();
761
762         if ( !ads_internal || !ad_schema )
763                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
764         
765         if ( !homedir || !shell || !gecos )
766                 return NT_STATUS_INVALID_PARAMETER;
767
768         *homedir = ads_pull_string( ads, ctx, msg, ad_schema->posix_homedir_attr );
769         *shell   = ads_pull_string( ads, ctx, msg, ad_schema->posix_shell_attr );
770         *gecos   = ads_pull_string( ads, ctx, msg, ad_schema->posix_gecos_attr );
771        
772         if ( gid ) {            
773                 if ( !ads_pull_uint32(ads, msg, ad_schema->posix_gidnumber_attr, gid ) )
774                         *gid = (uint32)-1;              
775         }
776                 
777         return NT_STATUS_OK;
778 }
779
780 /************************************************************************
781  ***********************************************************************/
782
783 static NTSTATUS nss_ad_close( void )
784 {
785         /* nothing to do.  All memory is free()'d by the idmap close_fn() */
786
787         return NT_STATUS_OK;
788 }
789
790 /************************************************************************
791  Function dispatch tables for the idmap and nss plugins
792  ***********************************************************************/
793
794 static struct idmap_methods ad_methods = {
795         .init            = idmap_ad_initialize,
796         .unixids_to_sids = idmap_ad_unixids_to_sids,
797         .sids_to_unixids = idmap_ad_sids_to_unixids,
798         .close_fn        = idmap_ad_close
799 };
800
801 /* The SFU and RFC2307 NSS plugins share everything but the init
802    function which sets the intended schema model to use */
803   
804 static struct nss_info_methods nss_rfc2307_methods = {
805         .init         = nss_rfc2307_init,
806         .get_nss_info = nss_ad_get_info,
807         .close_fn     = nss_ad_close
808 };
809
810 static struct nss_info_methods nss_sfu_methods = {
811         .init         = nss_sfu_init,
812         .get_nss_info = nss_ad_get_info,
813         .close_fn     = nss_ad_close
814 };
815
816 static struct nss_info_methods nss_sfu20_methods = {
817         .init         = nss_sfu20_init,
818         .get_nss_info = nss_ad_get_info,
819         .close_fn     = nss_ad_close
820 };
821
822
823
824 /************************************************************************
825  Initialize the plugins
826  ***********************************************************************/
827
828 NTSTATUS idmap_ad_init(void)
829 {
830         static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
831         static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
832         static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
833         static NTSTATUS status_nss_sfu20 = NT_STATUS_UNSUCCESSFUL;
834
835         /* Always register the AD method first in order to get the
836            idmap_domain interface called */
837
838         if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
839                 status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, 
840                                                      "ad", &ad_methods);
841                 if ( !NT_STATUS_IS_OK(status_idmap_ad) )
842                         return status_idmap_ad;         
843         }
844         
845         if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
846                 status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
847                                                             "rfc2307",  &nss_rfc2307_methods );         
848                 if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
849                         return status_nss_rfc2307;
850         }
851
852         if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
853                 status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
854                                                         "sfu",  &nss_sfu_methods );             
855                 if ( !NT_STATUS_IS_OK(status_nss_sfu) )
856                         return status_nss_sfu;          
857         }
858
859         if ( !NT_STATUS_IS_OK( status_nss_sfu20 ) ) {
860                 status_nss_sfu20 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
861                                                         "sfu20",  &nss_sfu20_methods );         
862                 if ( !NT_STATUS_IS_OK(status_nss_sfu20) )
863                         return status_nss_sfu20;                
864         }
865
866         return NT_STATUS_OK;    
867 }
868