* Allow an admin to define the "uid" attribute for a RFC2307
[ira/wip.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                                     const char *params)
165 {
166         struct idmap_ad_context *ctx;
167         char *config_option;
168         const char *range = NULL;
169         const char *schema_mode = NULL; 
170
171         if ( (ctx = TALLOC_ZERO_P(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, "sfu20" ) )
201                         ad_map_type = WB_POSIX_MAP_SFU20;
202                 else if ( strequal(schema_mode, "rfc2307" ) )
203                         ad_map_type = WB_POSIX_MAP_RFC2307;
204                 else
205                         DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n",
206                                  schema_mode));
207         }
208
209         dom->private_data = ctx;
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         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
281
282         if ( (memctx = talloc_new(ctx)) == NULL ) {
283                 DEBUG(0, ("Out of memory!\n"));
284                 return NT_STATUS_NO_MEMORY;
285         }
286
287         if ( (ads = ad_idmap_cached_connection()) == NULL ) {
288                 DEBUG(1, ("ADS uninitialized\n"));
289                 ret = NT_STATUS_UNSUCCESSFUL;
290                 goto done;
291         }
292
293         attrs[2] = ad_schema->posix_uidnumber_attr;
294         attrs[3] = ad_schema->posix_gidnumber_attr;
295
296 again:
297         bidx = idx;
298         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
299                 switch (ids[idx]->xid.type) {
300                 case ID_TYPE_UID:     
301                         if ( ! u_filter) {
302                                 u_filter = talloc_asprintf(memctx, "(&(|"
303                                                            "(sAMAccountType=%d)"
304                                                            "(sAMAccountType=%d)"
305                                                            "(sAMAccountType=%d))(|",
306                                                            ATYPE_NORMAL_ACCOUNT,
307                                                            ATYPE_WORKSTATION_TRUST,
308                                                            ATYPE_INTERDOMAIN_TRUST);
309                         }
310                         u_filter = talloc_asprintf_append_buffer(u_filter, "(%s=%lu)",
311                                                           ad_schema->posix_uidnumber_attr,
312                                                           (unsigned long)ids[idx]->xid.id);
313                         CHECK_ALLOC_DONE(u_filter);
314                         break;
315                                 
316                 case ID_TYPE_GID:
317                         if ( ! g_filter) {
318                                 g_filter = talloc_asprintf(memctx, "(&(|"
319                                                            "(sAMAccountType=%d)"
320                                                            "(sAMAccountType=%d))(|",
321                                                            ATYPE_SECURITY_GLOBAL_GROUP,
322                                                            ATYPE_SECURITY_LOCAL_GROUP);
323                         }
324                         g_filter = talloc_asprintf_append_buffer(g_filter, "(%s=%lu)",
325                                                           ad_schema->posix_gidnumber_attr,
326                                                           (unsigned long)ids[idx]->xid.id);
327                         CHECK_ALLOC_DONE(g_filter);
328                         break;
329
330                 default:
331                         DEBUG(3, ("Error: mapping requested but Unknown ID type\n"));
332                         ids[idx]->status = ID_UNKNOWN;
333                         continue;
334                 }
335         }
336         filter = talloc_asprintf(memctx, "(|");
337         CHECK_ALLOC_DONE(filter);
338         if ( u_filter) {
339                 filter = talloc_asprintf_append_buffer(filter, "%s))", u_filter);
340                 CHECK_ALLOC_DONE(filter);
341                         TALLOC_FREE(u_filter);
342         }
343         if ( g_filter) {
344                 filter = talloc_asprintf_append_buffer(filter, "%s))", g_filter);
345                 CHECK_ALLOC_DONE(filter);
346                 TALLOC_FREE(g_filter);
347         }
348         filter = talloc_asprintf_append_buffer(filter, ")");
349         CHECK_ALLOC_DONE(filter);
350
351         rc = ads_search_retry(ads, &res, filter, attrs);
352         if (!ADS_ERR_OK(rc)) {
353                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
354                 ret = NT_STATUS_UNSUCCESSFUL;
355                 goto done;
356         }
357
358         if ( (count = ads_count_replies(ads, res)) == 0 ) {
359                 DEBUG(10, ("No IDs found\n"));
360         }
361
362         entry = res;
363         for (i = 0; (i < count) && entry; i++) {
364                 DOM_SID sid;
365                 enum id_type type;
366                 struct id_map *map;
367                 uint32_t id;
368                 uint32_t atype;
369
370                 if (i == 0) { /* first entry */
371                         entry = ads_first_entry(ads, entry);
372                 } else { /* following ones */
373                         entry = ads_next_entry(ads, entry);
374                 }
375
376                 if ( !entry ) {
377                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
378                         break;
379                 }
380
381                 /* first check if the SID is present */
382                 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
383                         DEBUG(2, ("Could not retrieve SID from entry\n"));
384                         continue;
385                 }
386
387                 /* get type */
388                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
389                         DEBUG(1, ("could not get SAM account type\n"));
390                         continue;
391                 }
392
393                 switch (atype & 0xF0000000) {
394                 case ATYPE_SECURITY_GLOBAL_GROUP:
395                 case ATYPE_SECURITY_LOCAL_GROUP:
396                         type = ID_TYPE_GID;
397                         break;
398                 case ATYPE_NORMAL_ACCOUNT:
399                 case ATYPE_WORKSTATION_TRUST:
400                 case ATYPE_INTERDOMAIN_TRUST:
401                         type = ID_TYPE_UID;
402                         break;
403                 default:
404                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
405                         continue;
406                 }
407
408                 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
409                                                  ad_schema->posix_uidnumber_attr : 
410                                                  ad_schema->posix_gidnumber_attr, 
411                                      &id)) 
412                 {
413                         DEBUG(1, ("Could not get unix ID\n"));
414                         continue;
415                 }
416
417                 if ((id == 0) ||
418                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
419                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
420                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
421                                 id, ctx->filter_low_id, ctx->filter_high_id));
422                         continue;
423                 }
424
425                 map = find_map_by_id(&ids[bidx], type, id);
426                 if (!map) {
427                         DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
428                         continue;
429                 }
430
431                 sid_copy(map->sid, &sid);
432
433                 /* mapped */
434                 map->status = ID_MAPPED;
435
436                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
437                            (unsigned long)map->xid.id,
438                            map->xid.type));
439         }
440
441         if (res) {
442                 ads_msgfree(ads, res);
443         }
444
445         if (ids[idx]) { /* still some values to map */
446                 goto again;
447         }
448
449         ret = NT_STATUS_OK;
450
451         /* mark all unknown/expired ones as unmapped */
452         for (i = 0; ids[i]; i++) {
453                 if (ids[i]->status != ID_MAPPED) 
454                         ids[i]->status = ID_UNMAPPED;
455         }
456
457 done:
458         talloc_free(memctx);
459         return ret;
460 }
461
462 /************************************************************************
463  ***********************************************************************/
464
465 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
466 {
467         NTSTATUS ret;
468         TALLOC_CTX *memctx;
469         struct idmap_ad_context *ctx;
470         ADS_STATUS rc;
471         ADS_STRUCT *ads;
472         const char *attrs[] = { "sAMAccountType", 
473                                 "objectSid",
474                                 NULL, /* attr_uidnumber */
475                                 NULL, /* attr_gidnumber */
476                                 NULL };
477         LDAPMessage *res = NULL;
478         LDAPMessage *entry = NULL;
479         char *filter = NULL;
480         int idx = 0;
481         int bidx = 0;
482         int count;
483         int i;
484         char *sidstr;
485
486         /* Only do query if we are online */
487         if (idmap_is_offline()) {
488                 return NT_STATUS_FILE_IS_OFFLINE;
489         }
490
491         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);      
492
493         if ( (memctx = talloc_new(ctx)) == NULL ) {             
494                 DEBUG(0, ("Out of memory!\n"));
495                 return NT_STATUS_NO_MEMORY;
496         }
497
498         if ( (ads = ad_idmap_cached_connection()) == NULL ) {
499                 DEBUG(1, ("ADS uninitialized\n"));
500                 ret = NT_STATUS_UNSUCCESSFUL;
501                 goto done;
502         }
503
504         attrs[2] = ad_schema->posix_uidnumber_attr;
505         attrs[3] = ad_schema->posix_gidnumber_attr;
506
507 again:
508         filter = talloc_asprintf(memctx, "(&(|"
509                                  "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
510                                  "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
511                                  ")(|",
512                                  ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
513                                  ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
514                 
515         CHECK_ALLOC_DONE(filter);
516
517         bidx = idx;
518         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
519
520                 sidstr = sid_binstring(ids[idx]->sid);
521                 filter = talloc_asprintf_append_buffer(filter, "(objectSid=%s)", sidstr);
522                         
523                 free(sidstr);
524                 CHECK_ALLOC_DONE(filter);
525         }
526         filter = talloc_asprintf_append_buffer(filter, "))");
527         CHECK_ALLOC_DONE(filter);
528         DEBUG(10, ("Filter: [%s]\n", filter));
529
530         rc = ads_search_retry(ads, &res, filter, attrs);
531         if (!ADS_ERR_OK(rc)) {
532                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
533                 ret = NT_STATUS_UNSUCCESSFUL;
534                 goto done;
535         }
536
537         if ( (count = ads_count_replies(ads, res)) == 0 ) {
538                 DEBUG(10, ("No IDs found\n"));
539         }
540
541         entry = res;    
542         for (i = 0; (i < count) && entry; i++) {
543                 DOM_SID sid;
544                 enum id_type type;
545                 struct id_map *map;
546                 uint32_t id;
547                 uint32_t atype;
548
549                 if (i == 0) { /* first entry */
550                         entry = ads_first_entry(ads, entry);
551                 } else { /* following ones */
552                         entry = ads_next_entry(ads, entry);
553                 }
554
555                 if ( !entry ) {
556                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
557                         break;
558                 }
559
560                 /* first check if the SID is present */
561                 if (!ads_pull_sid(ads, entry, "objectSid", &sid)) {
562                         DEBUG(2, ("Could not retrieve SID from entry\n"));
563                         continue;
564                 }
565
566                 map = find_map_by_sid(&ids[bidx], &sid);
567                 if (!map) {
568                         DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
569                         continue;
570                 }
571
572                 /* get type */
573                 if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) {
574                         DEBUG(1, ("could not get SAM account type\n"));
575                         continue;
576                 }
577
578                 switch (atype & 0xF0000000) {
579                 case ATYPE_SECURITY_GLOBAL_GROUP:
580                 case ATYPE_SECURITY_LOCAL_GROUP:
581                         type = ID_TYPE_GID;
582                         break;
583                 case ATYPE_NORMAL_ACCOUNT:
584                 case ATYPE_WORKSTATION_TRUST:
585                 case ATYPE_INTERDOMAIN_TRUST:
586                         type = ID_TYPE_UID;
587                         break;
588                 default:
589                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
590                         continue;
591                 }
592
593                 if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
594                                                  ad_schema->posix_uidnumber_attr : 
595                                                  ad_schema->posix_gidnumber_attr, 
596                                      &id)) 
597                 {
598                         DEBUG(1, ("Could not get unix ID\n"));
599                         continue;
600                 }
601                 if ((id == 0) ||
602                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
603                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
604                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
605                                 id, ctx->filter_low_id, ctx->filter_high_id));
606                         continue;
607                 }
608
609                 /* mapped */
610                 map->xid.type = type;
611                 map->xid.id = id;
612                 map->status = ID_MAPPED;
613
614                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
615                            (unsigned long)map->xid.id,
616                            map->xid.type));
617         }
618
619         if (res) {
620                 ads_msgfree(ads, res);
621         }
622
623         if (ids[idx]) { /* still some values to map */
624                 goto again;
625         }
626
627         ret = NT_STATUS_OK;
628
629         /* mark all unknwoni/expired ones as unmapped */
630         for (i = 0; ids[i]; i++) {
631                 if (ids[i]->status != ID_MAPPED) 
632                         ids[i]->status = ID_UNMAPPED;
633         }
634
635 done:
636         talloc_free(memctx);
637         return ret;
638 }
639
640 /************************************************************************
641  ***********************************************************************/
642
643 static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
644 {
645         ADS_STRUCT *ads = ad_idmap_ads;
646
647         if (ads != NULL) {
648                 /* we own this ADS_STRUCT so make sure it goes away */
649                 ads->is_mine = True;
650                 ads_destroy( &ads );
651                 ad_idmap_ads = NULL;
652         }
653
654         TALLOC_FREE( ad_schema );
655         
656         return NT_STATUS_OK;
657 }
658
659 /*
660  * nss_info_{sfu,sfu20,rfc2307}
661  */
662
663 /************************************************************************
664  Initialize the {sfu,sfu20,rfc2307} state
665  ***********************************************************************/
666
667 static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
668 {
669         /* Sanity check if we have previously been called with a
670            different schema model */
671
672         if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
673              (ad_map_type != WB_POSIX_MAP_SFU) ) 
674         {
675                 DEBUG(0,("nss_sfu_init: Posix Map type has already been set.  "
676                          "Mixed schema models not supported!\n"));
677                 return NT_STATUS_NOT_SUPPORTED;
678         }
679         
680         ad_map_type = WB_POSIX_MAP_SFU; 
681
682         return NT_STATUS_OK;
683 }
684
685 static NTSTATUS nss_sfu20_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_SFU20) )
692         {
693                 DEBUG(0,("nss_sfu20_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_SFU20;       
699
700         return NT_STATUS_OK;
701 }
702
703 static NTSTATUS nss_rfc2307_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_RFC2307) ) 
710         {
711                 DEBUG(0,("nss_rfc2307_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_RFC2307;
717
718         return NT_STATUS_OK;
719 }
720
721
722 /************************************************************************
723  ***********************************************************************/
724 static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, 
725                                   const DOM_SID *sid, 
726                                   TALLOC_CTX *ctx,
727                                   ADS_STRUCT *ads, 
728                                   LDAPMessage *msg,
729                                   char **homedir,
730                                   char **shell, 
731                                   char **gecos,
732                                   uint32 *gid )
733 {
734         ADS_STRUCT *ads_internal = NULL;
735         const char *attrs[] = {NULL, /* attr_homedir */
736                                NULL, /* attr_shell */
737                                NULL, /* attr_gecos */
738                                NULL, /* attr_gidnumber */
739                                NULL };
740         char *filter = NULL;
741         LDAPMessage *msg_internal = NULL;
742         ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
743         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
744         char *sidstr = NULL;
745
746         /* Only do query if we are online */
747         if (idmap_is_offline()) {
748                 return NT_STATUS_FILE_IS_OFFLINE;
749         }
750
751         /* We are assuming that the internal ADS_STRUCT is for the 
752            same forest as the incoming *ads pointer */
753
754         ads_internal = ad_idmap_cached_connection();
755
756         if ( !ads_internal || !ad_schema ) {
757                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
758         }
759
760         if (!sid || !homedir || !shell || !gecos) {
761                 return NT_STATUS_INVALID_PARAMETER;
762         }
763
764         /* See if we can use the ADS connection struct swe were given */
765
766         if (ads) {
767                 *homedir = ads_pull_string( ads, ctx, msg, ad_schema->posix_homedir_attr );
768                 *shell   = ads_pull_string( ads, ctx, msg, ad_schema->posix_shell_attr );
769                 *gecos   = ads_pull_string( ads, ctx, msg, ad_schema->posix_gecos_attr );
770
771                 if (gid) {
772                         if ( !ads_pull_uint32(ads, msg, ad_schema->posix_gidnumber_attr, gid ) )
773                                 *gid = (uint32)-1;
774                 }
775
776                 nt_status = NT_STATUS_OK;
777                 goto done;
778         }
779
780         /* Have to do our own query */
781
782         attrs[0] = ad_schema->posix_homedir_attr;
783         attrs[1] = ad_schema->posix_shell_attr;
784         attrs[2] = ad_schema->posix_gecos_attr;
785         attrs[3] = ad_schema->posix_gidnumber_attr;
786
787         sidstr = sid_binstring(sid);
788         filter = talloc_asprintf(ctx, "(objectSid=%s)", sidstr);
789         SAFE_FREE(sidstr);
790
791         if (!filter) {
792                 nt_status = NT_STATUS_NO_MEMORY;
793                 goto done;
794         }
795
796         ads_status = ads_search_retry(ads_internal, &msg_internal, filter, attrs);
797         if (!ADS_ERR_OK(ads_status)) {
798                 nt_status = ads_ntstatus(ads_status);
799                 goto done;
800         }
801
802         *homedir = ads_pull_string(ads_internal, ctx, msg_internal, ad_schema->posix_homedir_attr);
803         *shell   = ads_pull_string(ads_internal, ctx, msg_internal, ad_schema->posix_shell_attr);
804         *gecos   = ads_pull_string(ads_internal, ctx, msg_internal, ad_schema->posix_gecos_attr);
805
806         if (gid) {
807                 if (!ads_pull_uint32(ads_internal, msg_internal, ad_schema->posix_gidnumber_attr, gid))
808                         *gid = (uint32)-1;
809         }
810
811         nt_status = NT_STATUS_OK;
812
813 done:
814         if (msg_internal) {
815                 ads_msgfree(ads_internal, msg_internal);
816         }
817
818         return nt_status;
819 }
820
821 /**********************************************************************
822  *********************************************************************/
823
824 static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx,
825                                     const char *domain,
826                                     const char *name,
827                                     char **alias)
828 {
829         ADS_STRUCT *ads_internal = NULL;
830         const char *attrs[] = {NULL, /* attr_uid */
831                                NULL };
832         char *filter = NULL;
833         LDAPMessage *msg = NULL;
834         ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
835         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
836
837         /* Check incoming parameters */
838
839         if ( !domain || !name || !*alias) {
840                 nt_status = NT_STATUS_INVALID_PARAMETER;
841                 goto done;
842         }
843
844         /* Only do query if we are online */
845
846         if (idmap_is_offline()) {
847                 nt_status = NT_STATUS_FILE_IS_OFFLINE;
848                 goto done;
849         }
850
851         ads_internal = ad_idmap_cached_connection();
852
853         if (!ads_internal || !ad_schema) {
854                 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
855                 goto done;
856         }
857
858         attrs[0] = ad_schema->posix_uid_attr;
859
860         filter = talloc_asprintf(mem_ctx,
861                                  "(sAMAccountName=%s)",
862                                  name);
863         if (!filter) {
864                 nt_status = NT_STATUS_NO_MEMORY;
865                 goto done;
866         }
867
868         ads_status = ads_search_retry(ads_internal, &msg, filter, attrs);
869         if (!ADS_ERR_OK(ads_status)) {
870                 nt_status = ads_ntstatus(ads_status);
871                 goto done;
872         }
873
874         *alias = ads_pull_string(ads_internal, mem_ctx, msg, ad_schema->posix_uid_attr );
875
876         if (!*alias) {
877                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
878         }
879
880         nt_status = NT_STATUS_OK;
881
882 done:
883         if (filter) {
884                 talloc_destroy(filter);
885         }
886         if (msg) {
887                 ads_msgfree(ads_internal, msg);
888         }
889
890         return nt_status;
891 }
892
893 /**********************************************************************
894  *********************************************************************/
895
896 static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx,
897                                              const char *domain,
898                                              const char *alias,
899                                              char **name )
900 {
901         ADS_STRUCT *ads_internal = NULL;
902         const char *attrs[] = {"sAMAccountName",
903                                NULL };
904         char *filter = NULL;
905         LDAPMessage *msg = NULL;
906         ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
907         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
908         char *username;
909
910         /* Check incoming parameters */
911
912         if ( !alias || !name) {
913                 nt_status = NT_STATUS_INVALID_PARAMETER;
914                 goto done;
915         }
916
917         /* Only do query if we are online */
918
919         if (idmap_is_offline()) {
920                 nt_status = NT_STATUS_FILE_IS_OFFLINE;
921                 goto done;
922         }
923
924         ads_internal = ad_idmap_cached_connection();
925
926         if (!ads_internal || !ad_schema) {
927                 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
928                 goto done;
929         }
930
931         filter = talloc_asprintf(mem_ctx,
932                                  "(%s=%s)",
933                                  ad_schema->posix_uid_attr,
934                                  alias);
935         if (!filter) {
936                 nt_status = NT_STATUS_NO_MEMORY;
937                 goto done;
938         }
939
940         ads_status = ads_search_retry(ads_internal, &msg, filter, attrs);
941         if (!ADS_ERR_OK(ads_status)) {
942                 nt_status = ads_ntstatus(ads_status);
943                 goto done;
944         }
945
946         username = ads_pull_string(ads_internal, mem_ctx, msg,
947                                    "sAMAccountName");
948         if (!username) {
949                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
950         }
951
952         *name = talloc_asprintf(mem_ctx, "%s\\%s",
953                                 lp_workgroup(),
954                                 username);
955         if (!*name) {
956                 nt_status = NT_STATUS_NO_MEMORY;
957                 goto done;
958         }
959
960         nt_status = NT_STATUS_OK;
961
962 done:
963         if (filter) {
964                 talloc_destroy(filter);
965         }
966         if (msg) {
967                 ads_msgfree(ads_internal, msg);
968         }
969
970         return nt_status;
971 }
972
973
974 /************************************************************************
975  ***********************************************************************/
976
977 static NTSTATUS nss_ad_close( void )
978 {
979         /* nothing to do.  All memory is free()'d by the idmap close_fn() */
980
981         return NT_STATUS_OK;
982 }
983
984 /************************************************************************
985  Function dispatch tables for the idmap and nss plugins
986  ***********************************************************************/
987
988 static struct idmap_methods ad_methods = {
989         .init            = idmap_ad_initialize,
990         .unixids_to_sids = idmap_ad_unixids_to_sids,
991         .sids_to_unixids = idmap_ad_sids_to_unixids,
992         .close_fn        = idmap_ad_close
993 };
994
995 /* The SFU and RFC2307 NSS plugins share everything but the init
996    function which sets the intended schema model to use */
997   
998 static struct nss_info_methods nss_rfc2307_methods = {
999         .init           = nss_rfc2307_init,
1000         .get_nss_info   = nss_ad_get_info,
1001         .map_to_alias   = nss_ad_map_to_alias,
1002         .map_from_alias = nss_ad_map_from_alias,
1003         .close_fn       = nss_ad_close
1004 };
1005
1006 static struct nss_info_methods nss_sfu_methods = {
1007         .init           = nss_sfu_init,
1008         .get_nss_info   = nss_ad_get_info,
1009         .map_to_alias   = nss_ad_map_to_alias,
1010         .map_from_alias = nss_ad_map_from_alias,
1011         .close_fn       = nss_ad_close
1012 };
1013
1014 static struct nss_info_methods nss_sfu20_methods = {
1015         .init           = nss_sfu20_init,
1016         .get_nss_info   = nss_ad_get_info,
1017         .map_to_alias   = nss_ad_map_to_alias,
1018         .map_from_alias = nss_ad_map_from_alias,
1019         .close_fn       = nss_ad_close
1020 };
1021
1022
1023
1024 /************************************************************************
1025  Initialize the plugins
1026  ***********************************************************************/
1027
1028 NTSTATUS idmap_ad_init(void)
1029 {
1030         static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
1031         static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
1032         static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
1033         static NTSTATUS status_nss_sfu20 = NT_STATUS_UNSUCCESSFUL;
1034
1035         /* Always register the AD method first in order to get the
1036            idmap_domain interface called */
1037
1038         if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
1039                 status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, 
1040                                                      "ad", &ad_methods);
1041                 if ( !NT_STATUS_IS_OK(status_idmap_ad) )
1042                         return status_idmap_ad;         
1043         }
1044         
1045         if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
1046                 status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1047                                                             "rfc2307",  &nss_rfc2307_methods );         
1048                 if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
1049                         return status_nss_rfc2307;
1050         }
1051
1052         if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
1053                 status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1054                                                         "sfu",  &nss_sfu_methods );             
1055                 if ( !NT_STATUS_IS_OK(status_nss_sfu) )
1056                         return status_nss_sfu;          
1057         }
1058
1059         if ( !NT_STATUS_IS_OK( status_nss_sfu20 ) ) {
1060                 status_nss_sfu20 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1061                                                         "sfu20",  &nss_sfu20_methods );         
1062                 if ( !NT_STATUS_IS_OK(status_nss_sfu20) )
1063                         return status_nss_sfu20;                
1064         }
1065
1066         return NT_STATUS_OK;    
1067 }
1068