s3: Remove close_fn from idmap_methods
[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  * Copyright (C) Michael Adam 2008,2010
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, see <http://www.gnu.org/licenses/>.
26  */
27
28 #include "includes.h"
29 #include "winbindd.h"
30 #include "../libds/common/flags.h"
31 #include "ads.h"
32 #include "libads/ldap_schema.h"
33 #include "nss_info.h"
34 #include "secrets.h"
35 #include "idmap.h"
36 #include "../libcli/ldap/ldap_ndr.h"
37 #include "../libcli/security/security.h"
38
39 #undef DBGC_CLASS
40 #define DBGC_CLASS DBGC_IDMAP
41
42 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
43
44 #define IDMAP_AD_MAX_IDS 30
45 #define CHECK_ALLOC_DONE(mem) do { \
46      if (!mem) { \
47            DEBUG(0, ("Out of memory!\n")); \
48            ret = NT_STATUS_NO_MEMORY; \
49            goto done; \
50       } \
51 } while (0)
52
53 struct idmap_ad_context {
54         ADS_STRUCT *ads;
55         struct posix_schema *ad_schema;
56         enum wb_posix_mapping ad_map_type; /* WB_POSIX_MAP_UNKNOWN */
57 };
58
59 NTSTATUS init_module(void);
60
61 /************************************************************************
62  ***********************************************************************/
63
64 static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom)
65 {
66         ADS_STRUCT *ads;
67         ADS_STATUS status;
68         bool local = False;
69         fstring dc_name;
70         struct sockaddr_storage dc_ip;
71         struct idmap_ad_context *ctx;
72         char *ldap_server = NULL;
73         char *realm = NULL;
74         struct winbindd_domain *wb_dom;
75
76         DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
77                    dom->name));
78
79         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
80
81         if (ctx->ads != NULL) {
82
83                 time_t expire;
84                 time_t now = time(NULL);
85
86                 ads = ctx->ads;
87
88                 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
89
90                 /* check for a valid structure */
91                 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
92                           (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
93
94                 if ( ads->config.realm && (expire > time(NULL))) {
95                         return ADS_SUCCESS;
96                 } else {
97                         /* we own this ADS_STRUCT so make sure it goes away */
98                         DEBUG(7,("Deleting expired krb5 credential cache\n"));
99                         ads->is_mine = True;
100                         ads_destroy( &ads );
101                         ads_kdestroy(WINBIND_CCACHE_NAME);
102                         ctx->ads = NULL;
103                 }
104         }
105
106         if (!local) {
107                 /* we don't want this to affect the users ccache */
108                 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
109         }
110
111         /*
112          * At this point we only have the NetBIOS domain name.
113          * Check if we can get server nam and realm from SAF cache
114          * and the domain list.
115          */
116         ldap_server = saf_fetch(dom->name);
117         DEBUG(10, ("ldap_server from saf cache: '%s'\n", ldap_server?ldap_server:""));
118
119         wb_dom = find_domain_from_name_noinit(dom->name);
120         if (wb_dom == NULL) {
121                 DEBUG(10, ("find_domain_from_name_noinit did not find domain '%s'\n",
122                            dom->name));
123                 realm = NULL;
124         } else {
125                 DEBUG(10, ("find_domain_from_name_noinit found realm '%s' for "
126                           " domain '%s'\n", wb_dom->alt_name, dom->name));
127                 realm = wb_dom->alt_name;
128         }
129
130         if ( (ads = ads_init(realm, dom->name, ldap_server)) == NULL ) {
131                 DEBUG(1,("ads_init failed\n"));
132                 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
133         }
134
135         /* the machine acct password might have change - fetch it every time */
136         SAFE_FREE(ads->auth.password);
137         ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
138
139         SAFE_FREE(ads->auth.realm);
140         ads->auth.realm = SMB_STRDUP(lp_realm());
141
142         /* setup server affinity */
143
144         get_dc_name(dom->name, realm, dc_name, &dc_ip );
145
146         status = ads_connect(ads);
147         if (!ADS_ERR_OK(status)) {
148                 DEBUG(1, ("ad_idmap_cached_connection_internal: failed to "
149                           "connect to AD\n"));
150                 ads_destroy(&ads);
151                 return status;
152         }
153
154         ads->is_mine = False;
155
156         ctx->ads = ads;
157
158         return ADS_SUCCESS;
159 }
160
161 /************************************************************************
162  ***********************************************************************/
163
164 static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom)
165 {
166         ADS_STATUS status;
167         struct idmap_ad_context * ctx;
168
169         status = ad_idmap_cached_connection_internal(dom);
170         if (!ADS_ERR_OK(status)) {
171                 return status;
172         }
173
174         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
175
176         /* if we have a valid ADS_STRUCT and the schema model is
177            defined, then we can return here. */
178
179         if ( ctx->ad_schema ) {
180                 return ADS_SUCCESS;
181         }
182
183         /* Otherwise, set the schema model */
184
185         if ( (ctx->ad_map_type ==  WB_POSIX_MAP_SFU) ||
186              (ctx->ad_map_type ==  WB_POSIX_MAP_SFU20) ||
187              (ctx->ad_map_type ==  WB_POSIX_MAP_RFC2307) )
188         {
189                 status = ads_check_posix_schema_mapping(
190                         ctx, ctx->ads, ctx->ad_map_type, &ctx->ad_schema);
191                 if ( !ADS_ERR_OK(status) ) {
192                         DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
193                 }
194         }
195
196         return status;
197 }
198
199 static int idmap_ad_context_destructor(struct idmap_ad_context *ctx)
200 {
201         if (ctx->ads != NULL) {
202                 /* we own this ADS_STRUCT so make sure it goes away */
203                 ctx->ads->is_mine = True;
204                 ads_destroy( &ctx->ads );
205                 ctx->ads = NULL;
206         }
207         return 0;
208 }
209
210 /************************************************************************
211  ***********************************************************************/
212
213 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom,
214                                     const char *params)
215 {
216         struct idmap_ad_context *ctx;
217         char *config_option;
218         const char *schema_mode = NULL; 
219
220         ctx = TALLOC_ZERO_P(dom, struct idmap_ad_context);
221         if (ctx == NULL) {
222                 DEBUG(0, ("Out of memory!\n"));
223                 return NT_STATUS_NO_MEMORY;
224         }
225         talloc_set_destructor(ctx, idmap_ad_context_destructor);
226
227         config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
228         if (config_option == NULL) {
229                 DEBUG(0, ("Out of memory!\n"));
230                 talloc_free(ctx);
231                 return NT_STATUS_NO_MEMORY;
232         }
233
234         /* default map type */
235         ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
236
237         /* schema mode */
238         schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL);
239         if ( schema_mode && schema_mode[0] ) {
240                 if ( strequal(schema_mode, "sfu") )
241                         ctx->ad_map_type = WB_POSIX_MAP_SFU;
242                 else if ( strequal(schema_mode, "sfu20" ) )
243                         ctx->ad_map_type = WB_POSIX_MAP_SFU20;
244                 else if ( strequal(schema_mode, "rfc2307" ) )
245                         ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
246                 else
247                         DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n",
248                                  schema_mode));
249         }
250
251         dom->private_data = ctx;
252
253         talloc_free(config_option);
254
255         return NT_STATUS_OK;
256 }
257
258 /************************************************************************
259  Search up to IDMAP_AD_MAX_IDS entries in maps for a match.
260  ***********************************************************************/
261
262 static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
263 {
264         int i;
265
266         for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
267                 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
268                         return maps[i];
269                 }
270         }
271
272         return NULL;    
273 }
274
275 /************************************************************************
276  Search up to IDMAP_AD_MAX_IDS entries in maps for a match
277  ***********************************************************************/
278
279 static struct id_map *find_map_by_sid(struct id_map **maps, struct dom_sid *sid)
280 {
281         int i;
282
283         for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
284                 if (dom_sid_equal(maps[i]->sid, sid)) {
285                         return maps[i];
286                 }
287         }
288
289         return NULL;    
290 }
291
292 /************************************************************************
293  ***********************************************************************/
294
295 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
296 {
297         NTSTATUS ret;
298         TALLOC_CTX *memctx;
299         struct idmap_ad_context *ctx;
300         ADS_STATUS rc;
301         const char *attrs[] = { "sAMAccountType", 
302                                 "objectSid",
303                                 NULL, /* uidnumber */
304                                 NULL, /* gidnumber */
305                                 NULL };
306         LDAPMessage *res = NULL;
307         LDAPMessage *entry = NULL;
308         char *filter = NULL;
309         int idx = 0;
310         int bidx = 0;
311         int count;
312         int i;
313         char *u_filter = NULL;
314         char *g_filter = NULL;
315
316         /* initialize the status to avoid suprise */
317         for (i = 0; ids[i]; i++) {
318                 ids[i]->status = ID_UNKNOWN;
319         }
320
321         /* Only do query if we are online */
322         if (idmap_is_offline()) {
323                 return NT_STATUS_FILE_IS_OFFLINE;
324         }
325
326         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
327
328         if ( (memctx = talloc_new(ctx)) == NULL ) {
329                 DEBUG(0, ("Out of memory!\n"));
330                 return NT_STATUS_NO_MEMORY;
331         }
332
333         rc = ad_idmap_cached_connection(dom);
334         if (!ADS_ERR_OK(rc)) {
335                 DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
336                 ret = NT_STATUS_UNSUCCESSFUL;
337                 /* ret = ads_ntstatus(rc); */
338                 goto done;
339         }
340
341         attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
342         attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
343
344 again:
345         bidx = idx;
346         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
347                 switch (ids[idx]->xid.type) {
348                 case ID_TYPE_UID:     
349                         if ( ! u_filter) {
350                                 u_filter = talloc_asprintf(memctx, "(&(|"
351                                                            "(sAMAccountType=%d)"
352                                                            "(sAMAccountType=%d)"
353                                                            "(sAMAccountType=%d))(|",
354                                                            ATYPE_NORMAL_ACCOUNT,
355                                                            ATYPE_WORKSTATION_TRUST,
356                                                            ATYPE_INTERDOMAIN_TRUST);
357                         }
358                         u_filter = talloc_asprintf_append_buffer(u_filter, "(%s=%lu)",
359                                                           ctx->ad_schema->posix_uidnumber_attr,
360                                                           (unsigned long)ids[idx]->xid.id);
361                         CHECK_ALLOC_DONE(u_filter);
362                         break;
363
364                 case ID_TYPE_GID:
365                         if ( ! g_filter) {
366                                 g_filter = talloc_asprintf(memctx, "(&(|"
367                                                            "(sAMAccountType=%d)"
368                                                            "(sAMAccountType=%d))(|",
369                                                            ATYPE_SECURITY_GLOBAL_GROUP,
370                                                            ATYPE_SECURITY_LOCAL_GROUP);
371                         }
372                         g_filter = talloc_asprintf_append_buffer(g_filter, "(%s=%lu)",
373                                                           ctx->ad_schema->posix_gidnumber_attr,
374                                                           (unsigned long)ids[idx]->xid.id);
375                         CHECK_ALLOC_DONE(g_filter);
376                         break;
377
378                 default:
379                         DEBUG(3, ("Error: mapping requested but Unknown ID type\n"));
380                         ids[idx]->status = ID_UNKNOWN;
381                         continue;
382                 }
383         }
384         filter = talloc_asprintf(memctx, "(|");
385         CHECK_ALLOC_DONE(filter);
386         if ( u_filter) {
387                 filter = talloc_asprintf_append_buffer(filter, "%s))", u_filter);
388                 CHECK_ALLOC_DONE(filter);
389                         TALLOC_FREE(u_filter);
390         }
391         if ( g_filter) {
392                 filter = talloc_asprintf_append_buffer(filter, "%s))", g_filter);
393                 CHECK_ALLOC_DONE(filter);
394                 TALLOC_FREE(g_filter);
395         }
396         filter = talloc_asprintf_append_buffer(filter, ")");
397         CHECK_ALLOC_DONE(filter);
398
399         rc = ads_search_retry(ctx->ads, &res, filter, attrs);
400         if (!ADS_ERR_OK(rc)) {
401                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
402                 ret = NT_STATUS_UNSUCCESSFUL;
403                 goto done;
404         }
405
406         if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
407                 DEBUG(10, ("No IDs found\n"));
408         }
409
410         entry = res;
411         for (i = 0; (i < count) && entry; i++) {
412                 struct dom_sid sid;
413                 enum id_type type;
414                 struct id_map *map;
415                 uint32_t id;
416                 uint32_t atype;
417
418                 if (i == 0) { /* first entry */
419                         entry = ads_first_entry(ctx->ads, entry);
420                 } else { /* following ones */
421                         entry = ads_next_entry(ctx->ads, entry);
422                 }
423
424                 if ( !entry ) {
425                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
426                         break;
427                 }
428
429                 /* first check if the SID is present */
430                 if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
431                         DEBUG(2, ("Could not retrieve SID from entry\n"));
432                         continue;
433                 }
434
435                 /* get type */
436                 if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
437                         DEBUG(1, ("could not get SAM account type\n"));
438                         continue;
439                 }
440
441                 switch (atype & 0xF0000000) {
442                 case ATYPE_SECURITY_GLOBAL_GROUP:
443                 case ATYPE_SECURITY_LOCAL_GROUP:
444                         type = ID_TYPE_GID;
445                         break;
446                 case ATYPE_NORMAL_ACCOUNT:
447                 case ATYPE_WORKSTATION_TRUST:
448                 case ATYPE_INTERDOMAIN_TRUST:
449                         type = ID_TYPE_UID;
450                         break;
451                 default:
452                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
453                         continue;
454                 }
455
456                 if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
457                                                  ctx->ad_schema->posix_uidnumber_attr :
458                                                  ctx->ad_schema->posix_gidnumber_attr,
459                                      &id)) 
460                 {
461                         DEBUG(1, ("Could not get unix ID\n"));
462                         continue;
463                 }
464
465                 if (!idmap_unix_id_is_in_range(id, dom)) {
466                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
467                                 id, dom->low_id, dom->high_id));
468                         continue;
469                 }
470
471                 map = find_map_by_id(&ids[bidx], type, id);
472                 if (!map) {
473                         DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
474                         continue;
475                 }
476
477                 sid_copy(map->sid, &sid);
478
479                 /* mapped */
480                 map->status = ID_MAPPED;
481
482                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
483                            (unsigned long)map->xid.id,
484                            map->xid.type));
485         }
486
487         if (res) {
488                 ads_msgfree(ctx->ads, res);
489         }
490
491         if (ids[idx]) { /* still some values to map */
492                 goto again;
493         }
494
495         ret = NT_STATUS_OK;
496
497         /* mark all unknown/expired ones as unmapped */
498         for (i = 0; ids[i]; i++) {
499                 if (ids[i]->status != ID_MAPPED) 
500                         ids[i]->status = ID_UNMAPPED;
501         }
502
503 done:
504         talloc_free(memctx);
505         return ret;
506 }
507
508 /************************************************************************
509  ***********************************************************************/
510
511 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
512 {
513         NTSTATUS ret;
514         TALLOC_CTX *memctx;
515         struct idmap_ad_context *ctx;
516         ADS_STATUS rc;
517         const char *attrs[] = { "sAMAccountType", 
518                                 "objectSid",
519                                 NULL, /* attr_uidnumber */
520                                 NULL, /* attr_gidnumber */
521                                 NULL };
522         LDAPMessage *res = NULL;
523         LDAPMessage *entry = NULL;
524         char *filter = NULL;
525         int idx = 0;
526         int bidx = 0;
527         int count;
528         int i;
529         char *sidstr;
530
531         /* initialize the status to avoid suprise */
532         for (i = 0; ids[i]; i++) {
533                 ids[i]->status = ID_UNKNOWN;
534         }
535
536         /* Only do query if we are online */
537         if (idmap_is_offline()) {
538                 return NT_STATUS_FILE_IS_OFFLINE;
539         }
540
541         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);      
542
543         if ( (memctx = talloc_new(ctx)) == NULL ) {             
544                 DEBUG(0, ("Out of memory!\n"));
545                 return NT_STATUS_NO_MEMORY;
546         }
547
548         rc = ad_idmap_cached_connection(dom);
549         if (!ADS_ERR_OK(rc)) {
550                 DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
551                 ret = NT_STATUS_UNSUCCESSFUL;
552                 /* ret = ads_ntstatus(rc); */
553                 goto done;
554         }
555
556         if (ctx->ad_schema == NULL) {
557                 DEBUG(0, ("haven't got ctx->ad_schema ! \n"));
558                 ret = NT_STATUS_UNSUCCESSFUL;
559                 goto done;
560         }
561
562         attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
563         attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
564
565 again:
566         filter = talloc_asprintf(memctx, "(&(|"
567                                  "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
568                                  "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
569                                  ")(|",
570                                  ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
571                                  ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
572
573         CHECK_ALLOC_DONE(filter);
574
575         bidx = idx;
576         for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
577
578                 ids[idx]->status = ID_UNKNOWN;
579
580                 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), ids[idx]->sid);
581                 filter = talloc_asprintf_append_buffer(filter, "(objectSid=%s)", sidstr);
582
583                 TALLOC_FREE(sidstr);
584                 CHECK_ALLOC_DONE(filter);
585         }
586         filter = talloc_asprintf_append_buffer(filter, "))");
587         CHECK_ALLOC_DONE(filter);
588         DEBUG(10, ("Filter: [%s]\n", filter));
589
590         rc = ads_search_retry(ctx->ads, &res, filter, attrs);
591         if (!ADS_ERR_OK(rc)) {
592                 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
593                 ret = NT_STATUS_UNSUCCESSFUL;
594                 goto done;
595         }
596
597         if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
598                 DEBUG(10, ("No IDs found\n"));
599         }
600
601         entry = res;    
602         for (i = 0; (i < count) && entry; i++) {
603                 struct dom_sid sid;
604                 enum id_type type;
605                 struct id_map *map;
606                 uint32_t id;
607                 uint32_t atype;
608
609                 if (i == 0) { /* first entry */
610                         entry = ads_first_entry(ctx->ads, entry);
611                 } else { /* following ones */
612                         entry = ads_next_entry(ctx->ads, entry);
613                 }
614
615                 if ( !entry ) {
616                         DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
617                         break;
618                 }
619
620                 /* first check if the SID is present */
621                 if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
622                         DEBUG(2, ("Could not retrieve SID from entry\n"));
623                         continue;
624                 }
625
626                 map = find_map_by_sid(&ids[bidx], &sid);
627                 if (!map) {
628                         DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
629                         continue;
630                 }
631
632                 /* get type */
633                 if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
634                         DEBUG(1, ("could not get SAM account type\n"));
635                         continue;
636                 }
637
638                 switch (atype & 0xF0000000) {
639                 case ATYPE_SECURITY_GLOBAL_GROUP:
640                 case ATYPE_SECURITY_LOCAL_GROUP:
641                         type = ID_TYPE_GID;
642                         break;
643                 case ATYPE_NORMAL_ACCOUNT:
644                 case ATYPE_WORKSTATION_TRUST:
645                 case ATYPE_INTERDOMAIN_TRUST:
646                         type = ID_TYPE_UID;
647                         break;
648                 default:
649                         DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
650                         continue;
651                 }
652
653                 if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
654                                                  ctx->ad_schema->posix_uidnumber_attr :
655                                                  ctx->ad_schema->posix_gidnumber_attr,
656                                      &id)) 
657                 {
658                         DEBUG(1, ("Could not get unix ID\n"));
659                         continue;
660                 }
661                 if (!idmap_unix_id_is_in_range(id, dom)) {
662                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
663                                 id, dom->low_id, dom->high_id));
664                         continue;
665                 }
666
667                 /* mapped */
668                 map->xid.type = type;
669                 map->xid.id = id;
670                 map->status = ID_MAPPED;
671
672                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
673                            (unsigned long)map->xid.id,
674                            map->xid.type));
675         }
676
677         if (res) {
678                 ads_msgfree(ctx->ads, res);
679         }
680
681         if (ids[idx]) { /* still some values to map */
682                 goto again;
683         }
684
685         ret = NT_STATUS_OK;
686
687         /* mark all unknown/expired ones as unmapped */
688         for (i = 0; ids[i]; i++) {
689                 if (ids[i]->status != ID_MAPPED) 
690                         ids[i]->status = ID_UNMAPPED;
691         }
692
693 done:
694         talloc_free(memctx);
695         return ret;
696 }
697
698 /*
699  * nss_info_{sfu,sfu20,rfc2307}
700  */
701
702 /************************************************************************
703  Initialize the {sfu,sfu20,rfc2307} state
704  ***********************************************************************/
705
706 static const char *wb_posix_map_unknown_string = "WB_POSIX_MAP_UNKNOWN";
707 static const char *wb_posix_map_template_string = "WB_POSIX_MAP_TEMPLATE";
708 static const char *wb_posix_map_sfu_string = "WB_POSIX_MAP_SFU";
709 static const char *wb_posix_map_sfu20_string = "WB_POSIX_MAP_SFU20";
710 static const char *wb_posix_map_rfc2307_string = "WB_POSIX_MAP_RFC2307";
711 static const char *wb_posix_map_unixinfo_string = "WB_POSIX_MAP_UNIXINFO";
712
713 static const char *ad_map_type_string(enum wb_posix_mapping map_type)
714 {
715         switch (map_type) {
716                 case WB_POSIX_MAP_TEMPLATE:
717                         return wb_posix_map_template_string;
718                 case WB_POSIX_MAP_SFU:
719                         return wb_posix_map_sfu_string;
720                 case WB_POSIX_MAP_SFU20:
721                         return wb_posix_map_sfu20_string;
722                 case WB_POSIX_MAP_RFC2307:
723                         return wb_posix_map_rfc2307_string;
724                 case WB_POSIX_MAP_UNIXINFO:
725                         return wb_posix_map_unixinfo_string;
726                 default:
727                         return wb_posix_map_unknown_string;
728         }
729 }
730
731 static NTSTATUS nss_ad_generic_init(struct nss_domain_entry *e,
732                                     enum wb_posix_mapping new_ad_map_type)
733 {
734         struct idmap_domain *dom;
735         struct idmap_ad_context *ctx;
736
737         if (e->state != NULL) {
738                 dom = talloc_get_type(e->state, struct idmap_domain);
739         } else {
740                 dom = TALLOC_ZERO_P(e, struct idmap_domain);
741                 if (dom == NULL) {
742                         DEBUG(0, ("Out of memory!\n"));
743                         return NT_STATUS_NO_MEMORY;
744                 }
745                 e->state = dom;
746         }
747
748         if (e->domain != NULL) {
749                 dom->name = talloc_strdup(dom, e->domain);
750                 if (dom->name == NULL) {
751                         DEBUG(0, ("Out of memory!\n"));
752                         return NT_STATUS_NO_MEMORY;
753                 }
754         }
755
756         if (dom->private_data != NULL) {
757                 ctx = talloc_get_type(dom->private_data,
758                                       struct idmap_ad_context);
759         } else {
760                 ctx = TALLOC_ZERO_P(dom, struct idmap_ad_context);
761                 if (ctx == NULL) {
762                         DEBUG(0, ("Out of memory!\n"));
763                         return NT_STATUS_NO_MEMORY;
764                 }
765                 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
766                 dom->private_data = ctx;
767         }
768
769         if ((ctx->ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
770             (ctx->ad_map_type != new_ad_map_type))
771         {
772                 DEBUG(2, ("nss_ad_generic_init: "
773                           "Warning: overriding previously set posix map type "
774                           "%s for domain %s with map type %s.\n",
775                           ad_map_type_string(ctx->ad_map_type),
776                           dom->name,
777                           ad_map_type_string(new_ad_map_type)));
778         }
779
780         ctx->ad_map_type = new_ad_map_type;
781
782         return NT_STATUS_OK;
783 }
784
785 static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
786 {
787         return nss_ad_generic_init(e, WB_POSIX_MAP_SFU);
788 }
789
790 static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e )
791 {
792         return nss_ad_generic_init(e, WB_POSIX_MAP_SFU20);
793 }
794
795 static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
796 {
797         return nss_ad_generic_init(e, WB_POSIX_MAP_RFC2307);
798 }
799
800
801 /************************************************************************
802  ***********************************************************************/
803
804 static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, 
805                                   const struct dom_sid *sid,
806                                   TALLOC_CTX *mem_ctx,
807                                   const char **homedir,
808                                   const char **shell,
809                                   const char **gecos,
810                                   uint32 *gid )
811 {
812         const char *attrs[] = {NULL, /* attr_homedir */
813                                NULL, /* attr_shell */
814                                NULL, /* attr_gecos */
815                                NULL, /* attr_gidnumber */
816                                NULL };
817         char *filter = NULL;
818         LDAPMessage *msg_internal = NULL;
819         ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
820         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
821         char *sidstr = NULL;
822         struct idmap_domain *dom;
823         struct idmap_ad_context *ctx;
824
825         DEBUG(10, ("nss_ad_get_info called for sid [%s] in domain '%s'\n",
826                    sid_string_dbg(sid), e->domain?e->domain:"NULL"));
827
828         /* Only do query if we are online */
829         if (idmap_is_offline()) {
830                 return NT_STATUS_FILE_IS_OFFLINE;
831         }
832
833         dom = talloc_get_type(e->state, struct idmap_domain);
834         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
835
836         ads_status = ad_idmap_cached_connection(dom);
837         if (!ADS_ERR_OK(ads_status)) {
838                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
839         }
840
841         if (!ctx->ad_schema) {
842                 DEBUG(10, ("nss_ad_get_info: no ad_schema configured!\n"));
843                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
844         }
845
846         if (!sid || !homedir || !shell || !gecos) {
847                 return NT_STATUS_INVALID_PARAMETER;
848         }
849
850         /* Have to do our own query */
851
852         DEBUG(10, ("nss_ad_get_info: no ads connection given, doing our "
853                    "own query\n"));
854
855         attrs[0] = ctx->ad_schema->posix_homedir_attr;
856         attrs[1] = ctx->ad_schema->posix_shell_attr;
857         attrs[2] = ctx->ad_schema->posix_gecos_attr;
858         attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
859
860         sidstr = ldap_encode_ndr_dom_sid(mem_ctx, sid);
861         filter = talloc_asprintf(mem_ctx, "(objectSid=%s)", sidstr);
862         TALLOC_FREE(sidstr);
863
864         if (!filter) {
865                 nt_status = NT_STATUS_NO_MEMORY;
866                 goto done;
867         }
868
869         ads_status = ads_search_retry(ctx->ads, &msg_internal, filter, attrs);
870         if (!ADS_ERR_OK(ads_status)) {
871                 nt_status = ads_ntstatus(ads_status);
872                 goto done;
873         }
874
875         *homedir = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_homedir_attr);
876         *shell   = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_shell_attr);
877         *gecos   = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_gecos_attr);
878
879         if (gid) {
880                 if (!ads_pull_uint32(ctx->ads, msg_internal, ctx->ad_schema->posix_gidnumber_attr, gid))
881                         *gid = (uint32)-1;
882         }
883
884         nt_status = NT_STATUS_OK;
885
886 done:
887         if (msg_internal) {
888                 ads_msgfree(ctx->ads, msg_internal);
889         }
890
891         return nt_status;
892 }
893
894 /**********************************************************************
895  *********************************************************************/
896
897 static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx,
898                                     struct nss_domain_entry *e,
899                                     const char *name,
900                                     char **alias)
901 {
902         const char *attrs[] = {NULL, /* attr_uid */
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         struct idmap_domain *dom;
909         struct idmap_ad_context *ctx = NULL;
910
911         /* Check incoming parameters */
912
913         if ( !e || !e->domain || !name || !*alias) {
914                 nt_status = NT_STATUS_INVALID_PARAMETER;
915                 goto done;
916         }
917
918         /* Only do query if we are online */
919
920         if (idmap_is_offline()) {
921                 nt_status = NT_STATUS_FILE_IS_OFFLINE;
922                 goto done;
923         }
924
925         dom = talloc_get_type(e->state, struct idmap_domain);
926         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
927
928         ads_status = ad_idmap_cached_connection(dom);
929         if (!ADS_ERR_OK(ads_status)) {
930                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
931         }
932
933         if (!ctx->ad_schema) {
934                 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
935                 goto done;
936         }
937
938         attrs[0] = ctx->ad_schema->posix_uid_attr;
939
940         filter = talloc_asprintf(mem_ctx,
941                                  "(sAMAccountName=%s)",
942                                  name);
943         if (!filter) {
944                 nt_status = NT_STATUS_NO_MEMORY;
945                 goto done;
946         }
947
948         ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
949         if (!ADS_ERR_OK(ads_status)) {
950                 nt_status = ads_ntstatus(ads_status);
951                 goto done;
952         }
953
954         *alias = ads_pull_string(ctx->ads, mem_ctx, msg, ctx->ad_schema->posix_uid_attr);
955
956         if (!*alias) {
957                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
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(ctx->ads, msg);
968         }
969
970         return nt_status;
971 }
972
973 /**********************************************************************
974  *********************************************************************/
975
976 static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx,
977                                              struct nss_domain_entry *e,
978                                              const char *alias,
979                                              char **name )
980 {
981         const char *attrs[] = {"sAMAccountName",
982                                NULL };
983         char *filter = NULL;
984         LDAPMessage *msg = NULL;
985         ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
986         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
987         char *username;
988         struct idmap_domain *dom;
989         struct idmap_ad_context *ctx = NULL;
990
991         /* Check incoming parameters */
992
993         if ( !alias || !name) {
994                 nt_status = NT_STATUS_INVALID_PARAMETER;
995                 goto done;
996         }
997
998         /* Only do query if we are online */
999
1000         if (idmap_is_offline()) {
1001                 nt_status = NT_STATUS_FILE_IS_OFFLINE;
1002                 goto done;
1003         }
1004
1005         dom = talloc_get_type(e->state, struct idmap_domain);
1006         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
1007
1008         ads_status = ad_idmap_cached_connection(dom);
1009         if (!ADS_ERR_OK(ads_status)) {
1010                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1011         }
1012
1013         if (!ctx->ad_schema) {
1014                 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1015                 goto done;
1016         }
1017
1018         filter = talloc_asprintf(mem_ctx,
1019                                  "(%s=%s)",
1020                                  ctx->ad_schema->posix_uid_attr,
1021                                  alias);
1022         if (!filter) {
1023                 nt_status = NT_STATUS_NO_MEMORY;
1024                 goto done;
1025         }
1026
1027         ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
1028         if (!ADS_ERR_OK(ads_status)) {
1029                 nt_status = ads_ntstatus(ads_status);
1030                 goto done;
1031         }
1032
1033         username = ads_pull_string(ctx->ads, mem_ctx, msg,
1034                                    "sAMAccountName");
1035         if (!username) {
1036                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1037         }
1038
1039         *name = talloc_asprintf(mem_ctx, "%s\\%s",
1040                                 lp_workgroup(),
1041                                 username);
1042         if (!*name) {
1043                 nt_status = NT_STATUS_NO_MEMORY;
1044                 goto done;
1045         }
1046
1047         nt_status = NT_STATUS_OK;
1048
1049 done:
1050         if (filter) {
1051                 talloc_destroy(filter);
1052         }
1053         if (msg) {
1054                 ads_msgfree(ctx->ads, msg);
1055         }
1056
1057         return nt_status;
1058 }
1059
1060 /************************************************************************
1061  Function dispatch tables for the idmap and nss plugins
1062  ***********************************************************************/
1063
1064 static struct idmap_methods ad_methods = {
1065         .init            = idmap_ad_initialize,
1066         .unixids_to_sids = idmap_ad_unixids_to_sids,
1067         .sids_to_unixids = idmap_ad_sids_to_unixids,
1068 };
1069
1070 /* The SFU and RFC2307 NSS plugins share everything but the init
1071    function which sets the intended schema model to use */
1072
1073 static struct nss_info_methods nss_rfc2307_methods = {
1074         .init           = nss_rfc2307_init,
1075         .get_nss_info   = nss_ad_get_info,
1076         .map_to_alias   = nss_ad_map_to_alias,
1077         .map_from_alias = nss_ad_map_from_alias,
1078 };
1079
1080 static struct nss_info_methods nss_sfu_methods = {
1081         .init           = nss_sfu_init,
1082         .get_nss_info   = nss_ad_get_info,
1083         .map_to_alias   = nss_ad_map_to_alias,
1084         .map_from_alias = nss_ad_map_from_alias,
1085 };
1086
1087 static struct nss_info_methods nss_sfu20_methods = {
1088         .init           = nss_sfu20_init,
1089         .get_nss_info   = nss_ad_get_info,
1090         .map_to_alias   = nss_ad_map_to_alias,
1091         .map_from_alias = nss_ad_map_from_alias,
1092 };
1093
1094
1095
1096 /************************************************************************
1097  Initialize the plugins
1098  ***********************************************************************/
1099
1100 NTSTATUS idmap_ad_init(void)
1101 {
1102         static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
1103         static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
1104         static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
1105         static NTSTATUS status_nss_sfu20 = NT_STATUS_UNSUCCESSFUL;
1106
1107         /* Always register the AD method first in order to get the
1108            idmap_domain interface called */
1109
1110         if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
1111                 status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, 
1112                                                      "ad", &ad_methods);
1113                 if ( !NT_STATUS_IS_OK(status_idmap_ad) )
1114                         return status_idmap_ad;         
1115         }
1116
1117         if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
1118                 status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1119                                                             "rfc2307",  &nss_rfc2307_methods );         
1120                 if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
1121                         return status_nss_rfc2307;
1122         }
1123
1124         if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
1125                 status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1126                                                         "sfu",  &nss_sfu_methods );             
1127                 if ( !NT_STATUS_IS_OK(status_nss_sfu) )
1128                         return status_nss_sfu;          
1129         }
1130
1131         if ( !NT_STATUS_IS_OK( status_nss_sfu20 ) ) {
1132                 status_nss_sfu20 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1133                                                         "sfu20",  &nss_sfu20_methods );         
1134                 if ( !NT_STATUS_IS_OK(status_nss_sfu20) )
1135                         return status_nss_sfu20;                
1136         }
1137
1138         return NT_STATUS_OK;    
1139 }
1140