s3:idmap_ldap: make idmap_ldap_alloc_context a member of idmap_ldap_context
[metze/samba/wip.git] / source3 / winbindd / idmap_ldap.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    idmap LDAP backend
5
6    Copyright (C) Tim Potter             2000
7    Copyright (C) Jim McDonough <jmcd@us.ibm.com>        2003
8    Copyright (C) Gerald Carter          2003
9    Copyright (C) Simo Sorce             2003-2007
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "winbindd.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_IDMAP
30
31 #include <lber.h>
32 #include <ldap.h>
33
34 #include "smbldap.h"
35
36 static char *idmap_fetch_secret(const char *backend, bool alloc,
37                                 const char *domain, const char *identity)
38 {
39         char *tmp, *ret;
40         int r;
41
42         if (alloc) {
43                 r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend);
44         } else {
45                 r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
46         }
47
48         if (r < 0)
49                 return NULL;
50
51         strupper_m(tmp); /* make sure the key is case insensitive */
52         ret = secrets_fetch_generic(tmp, identity);
53
54         SAFE_FREE(tmp);
55
56         return ret;
57 }
58
59 struct idmap_ldap_alloc_context {
60         struct smbldap_state *smbldap_state;
61         char *url;
62         char *suffix;
63         char *user_dn;
64 };
65
66 struct idmap_ldap_context {
67         struct smbldap_state *smbldap_state;
68         char *url;
69         char *suffix;
70         char *user_dn;
71         bool anon;
72         struct idmap_ldap_alloc_context *alloc;
73 };
74
75 #define CHECK_ALLOC_DONE(mem) do { \
76         if (!mem) { \
77                 DEBUG(0, ("Out of memory!\n")); \
78                 ret = NT_STATUS_NO_MEMORY; \
79                 goto done; \
80         } } while (0)
81
82 /**********************************************************************
83  IDMAP ALLOC TDB BACKEND
84 **********************************************************************/
85
86 /*********************************************************************
87  ********************************************************************/
88
89 static NTSTATUS get_credentials( TALLOC_CTX *mem_ctx,
90                                  struct smbldap_state *ldap_state,
91                                  const char *config_option,
92                                  struct idmap_domain *dom,
93                                  char **dn )
94 {
95         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
96         char *secret = NULL;
97         const char *tmp = NULL;
98         char *user_dn = NULL;
99         bool anon = False;
100
101         /* assume anonymous if we don't have a specified user */
102
103         tmp = lp_parm_const_string(-1, config_option, "ldap_user_dn", NULL);
104
105         if ( tmp ) {
106                 if (!dom) {
107                         /* only the alloc backend can pass in a NULL dom */
108                         secret = idmap_fetch_secret("ldap", True,
109                                                     NULL, tmp);
110                 } else {
111                         secret = idmap_fetch_secret("ldap", False,
112                                                     dom->name, tmp);
113                 }
114
115                 if (!secret) {
116                         DEBUG(0, ("get_credentials: Unable to fetch "
117                                   "auth credentials for %s in %s\n",
118                                   tmp, (dom==NULL)?"ALLOC":dom->name));
119                         ret = NT_STATUS_ACCESS_DENIED;
120                         goto done;
121                 }
122                 *dn = talloc_strdup(mem_ctx, tmp);
123                 CHECK_ALLOC_DONE(*dn);
124         } else {
125                 if (!fetch_ldap_pw(&user_dn, &secret)) {
126                         DEBUG(2, ("get_credentials: Failed to lookup ldap "
127                                   "bind creds. Using anonymous connection.\n"));
128                         anon = True;
129                 } else {
130                         *dn = talloc_strdup(mem_ctx, user_dn);
131                         SAFE_FREE( user_dn );
132                         CHECK_ALLOC_DONE(*dn);
133                 }
134         }
135
136         smbldap_set_creds(ldap_state, anon, *dn, secret);
137         ret = NT_STATUS_OK;
138
139 done:
140         SAFE_FREE(secret);
141
142         return ret;
143 }
144
145
146 /**********************************************************************
147  Verify the sambaUnixIdPool entry in the directory.
148 **********************************************************************/
149
150 static NTSTATUS verify_idpool(struct idmap_domain *dom)
151 {
152         NTSTATUS ret;
153         TALLOC_CTX *mem_ctx;
154         LDAPMessage *result = NULL;
155         LDAPMod **mods = NULL;
156         const char **attr_list;
157         char *filter;
158         int count;
159         int rc;
160         struct idmap_ldap_context *ctx;
161
162         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
163
164         if (!ctx->alloc) {
165                 return NT_STATUS_UNSUCCESSFUL;
166         }
167
168         mem_ctx = talloc_new(ctx->alloc);
169         if (mem_ctx == NULL) {
170                 DEBUG(0, ("Out of memory!\n"));
171                 return NT_STATUS_NO_MEMORY;
172         }
173
174         filter = talloc_asprintf(mem_ctx, "(objectclass=%s)", LDAP_OBJ_IDPOOL);
175         CHECK_ALLOC_DONE(filter);
176
177         attr_list = get_attr_list(mem_ctx, idpool_attr_list);
178         CHECK_ALLOC_DONE(attr_list);
179
180         rc = smbldap_search(ctx->alloc->smbldap_state,
181                                 ctx->alloc->suffix,
182                                 LDAP_SCOPE_SUBTREE,
183                                 filter,
184                                 attr_list,
185                                 0,
186                                 &result);
187
188         if (rc != LDAP_SUCCESS) {
189                 DEBUG(1, ("Unable to verify the idpool, "
190                           "cannot continue initialization!\n"));
191                 return NT_STATUS_UNSUCCESSFUL;
192         }
193
194         count = ldap_count_entries(ctx->alloc->smbldap_state->ldap_struct,
195                                    result);
196
197         ldap_msgfree(result);
198
199         if ( count > 1 ) {
200                 DEBUG(0,("Multiple entries returned from %s (base == %s)\n",
201                         filter, ctx->alloc->suffix));
202                 ret = NT_STATUS_UNSUCCESSFUL;
203                 goto done;
204         }
205         else if (count == 0) {
206                 char *uid_str, *gid_str;
207
208                 uid_str = talloc_asprintf(mem_ctx, "%lu",
209                                 (unsigned long)dom->low_id);
210                 gid_str = talloc_asprintf(mem_ctx, "%lu",
211                                 (unsigned long)dom->low_id);
212
213                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
214                                 "objectClass", LDAP_OBJ_IDPOOL);
215                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
216                                 get_attr_key2string(idpool_attr_list,
217                                                     LDAP_ATTR_UIDNUMBER),
218                                 uid_str);
219                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
220                                 get_attr_key2string(idpool_attr_list,
221                                                     LDAP_ATTR_GIDNUMBER),
222                                 gid_str);
223                 if (mods) {
224                         rc = smbldap_modify(ctx->alloc->smbldap_state,
225                                                 ctx->alloc->suffix,
226                                                 mods);
227                         ldap_mods_free(mods, True);
228                 } else {
229                         ret = NT_STATUS_UNSUCCESSFUL;
230                         goto done;
231                 }
232         }
233
234         ret = (rc == LDAP_SUCCESS)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL;
235 done:
236         talloc_free(mem_ctx);
237         return ret;
238 }
239
240 /*****************************************************************************
241  Initialise idmap database.
242 *****************************************************************************/
243
244 static int idmap_ldap_alloc_close_destructor(struct idmap_ldap_alloc_context *ctx)
245 {
246         smbldap_free_struct(&ctx->smbldap_state);
247         DEBUG(5,("The connection to the LDAP server was closed\n"));
248         /* maybe free the results here --metze */
249         return 0;
250 }
251
252 static NTSTATUS idmap_ldap_alloc_init(struct idmap_domain *dom,
253                                       const char *params)
254 {
255         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
256         const char *tmp;
257         struct idmap_ldap_context *ctx;
258
259         /* Only do init if we are online */
260         if (idmap_is_offline()) {
261                 return NT_STATUS_FILE_IS_OFFLINE;
262         }
263
264         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
265
266         ctx->alloc = talloc_zero(ctx, struct idmap_ldap_alloc_context);
267         CHECK_ALLOC_DONE(ctx->alloc);
268
269         if (params && *params) {
270                 /* assume location is the only parameter */
271                 ctx->alloc->url = talloc_strdup(ctx->alloc, params);
272         } else {
273                 tmp = lp_parm_const_string(-1, "idmap alloc config",
274                                            "ldap_url", NULL);
275
276                 if ( ! tmp) {
277                         DEBUG(1, ("ERROR: missing idmap ldap url\n"));
278                         ret = NT_STATUS_UNSUCCESSFUL;
279                         goto done;
280                 }
281
282                 ctx->alloc->url = talloc_strdup(ctx->alloc, tmp);
283         }
284         CHECK_ALLOC_DONE(ctx->alloc->url);
285
286         trim_char(ctx->alloc->url, '\"', '\"');
287
288         tmp = lp_parm_const_string(-1, "idmap alloc config",
289                                    "ldap_base_dn", NULL);
290         if ( ! tmp || ! *tmp) {
291                 tmp = lp_ldap_idmap_suffix();
292                 if ( ! tmp) {
293                         DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
294                         ret = NT_STATUS_UNSUCCESSFUL;
295                         goto done;
296                 }
297         }
298
299         ctx->alloc->suffix = talloc_strdup(ctx->alloc, tmp);
300         CHECK_ALLOC_DONE(ctx->alloc->suffix);
301
302         ret = smbldap_init(ctx->alloc, winbind_event_context(),
303                            ctx->alloc->url,
304                            &ctx->alloc->smbldap_state);
305         if (!NT_STATUS_IS_OK(ret)) {
306                 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n",
307                           ctx->alloc->url));
308                 goto done;
309         }
310
311         talloc_set_destructor(ctx->alloc, idmap_ldap_alloc_close_destructor);
312
313         ret = get_credentials(ctx->alloc,
314                               ctx->alloc->smbldap_state,
315                               "idmap alloc config", NULL,
316                               &ctx->alloc->user_dn);
317         if ( !NT_STATUS_IS_OK(ret) ) {
318                 DEBUG(1,("idmap_ldap_alloc_init: Failed to get connection "
319                          "credentials (%s)\n", nt_errstr(ret)));
320                 goto done;
321         }
322
323         /* see if the idmap suffix and sub entries exists */
324
325         ret = verify_idpool(dom);
326
327  done:
328         if ( !NT_STATUS_IS_OK( ret ) )
329                 TALLOC_FREE(ctx->alloc);
330
331         return ret;
332 }
333
334 /********************************
335  Allocate a new uid or gid
336 ********************************/
337
338 static NTSTATUS idmap_ldap_allocate_id(struct idmap_domain *dom,
339                                        struct unixid *xid)
340 {
341         TALLOC_CTX *mem_ctx;
342         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
343         int rc = LDAP_SERVER_DOWN;
344         int count = 0;
345         LDAPMessage *result = NULL;
346         LDAPMessage *entry = NULL;
347         LDAPMod **mods = NULL;
348         char *id_str;
349         char *new_id_str;
350         char *filter = NULL;
351         const char *dn = NULL;
352         const char **attr_list;
353         const char *type;
354         struct idmap_ldap_context *ctx;
355
356         /* Only do query if we are online */
357         if (idmap_is_offline()) {
358                 return NT_STATUS_FILE_IS_OFFLINE;
359         }
360
361         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
362
363         if (!ctx->alloc) {
364                 return NT_STATUS_UNSUCCESSFUL;
365         }
366
367         mem_ctx = talloc_new(ctx->alloc);
368         if (!mem_ctx) {
369                 DEBUG(0, ("Out of memory!\n"));
370                 return NT_STATUS_NO_MEMORY;
371         }
372
373         /* get type */
374         switch (xid->type) {
375
376         case ID_TYPE_UID:
377                 type = get_attr_key2string(idpool_attr_list,
378                                            LDAP_ATTR_UIDNUMBER);
379                 break;
380
381         case ID_TYPE_GID:
382                 type = get_attr_key2string(idpool_attr_list,
383                                            LDAP_ATTR_GIDNUMBER);
384                 break;
385
386         default:
387                 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
388                 return NT_STATUS_INVALID_PARAMETER;
389         }
390
391         filter = talloc_asprintf(mem_ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
392         CHECK_ALLOC_DONE(filter);
393
394         attr_list = get_attr_list(mem_ctx, idpool_attr_list);
395         CHECK_ALLOC_DONE(attr_list);
396
397         DEBUG(10, ("Search of the id pool (filter: %s)\n", filter));
398
399         rc = smbldap_search(ctx->alloc->smbldap_state,
400                                 ctx->alloc->suffix,
401                                LDAP_SCOPE_SUBTREE, filter,
402                                attr_list, 0, &result);
403
404         if (rc != LDAP_SUCCESS) {
405                 DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
406                 goto done;
407         }
408
409         talloc_autofree_ldapmsg(mem_ctx, result);
410
411         count = ldap_count_entries(ctx->alloc->smbldap_state->ldap_struct,
412                                    result);
413         if (count != 1) {
414                 DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
415                 goto done;
416         }
417
418         entry = ldap_first_entry(ctx->alloc->smbldap_state->ldap_struct,
419                                  result);
420
421         dn = smbldap_talloc_dn(mem_ctx,
422                                ctx->alloc->smbldap_state->ldap_struct,
423                                entry);
424         if ( ! dn) {
425                 goto done;
426         }
427
428         id_str = smbldap_talloc_single_attribute(
429                                 ctx->alloc->smbldap_state->ldap_struct,
430                                 entry, type, mem_ctx);
431         if (id_str == NULL) {
432                 DEBUG(0,("%s attribute not found\n", type));
433                 goto done;
434         }
435         if ( ! id_str) {
436                 DEBUG(0,("Out of memory\n"));
437                 ret = NT_STATUS_NO_MEMORY;
438                 goto done;
439         }
440
441         xid->id = strtoul(id_str, NULL, 10);
442
443         /* make sure we still have room to grow */
444
445         switch (xid->type) {
446         case ID_TYPE_UID:
447                 if (xid->id > dom->high_id) {
448                         DEBUG(0,("Cannot allocate uid above %lu!\n",
449                                  (unsigned long)dom->high_id));
450                         goto done;
451                 }
452                 break;
453
454         case ID_TYPE_GID:
455                 if (xid->id > dom->high_id) {
456                         DEBUG(0,("Cannot allocate gid above %lu!\n",
457                                  (unsigned long)dom->high_id));
458                         goto done;
459                 }
460                 break;
461
462         default:
463                 /* impossible */
464                 goto done;
465         }
466
467         new_id_str = talloc_asprintf(mem_ctx, "%lu", (unsigned long)xid->id + 1);
468         if ( ! new_id_str) {
469                 DEBUG(0,("Out of memory\n"));
470                 ret = NT_STATUS_NO_MEMORY;
471                 goto done;
472         }
473
474         smbldap_set_mod(&mods, LDAP_MOD_DELETE, type, id_str);
475         smbldap_set_mod(&mods, LDAP_MOD_ADD, type, new_id_str);
476
477         if (mods == NULL) {
478                 DEBUG(0,("smbldap_set_mod() failed.\n"));
479                 goto done;
480         }
481
482         DEBUG(10, ("Try to atomically increment the id (%s -> %s)\n",
483                    id_str, new_id_str));
484
485         rc = smbldap_modify(ctx->alloc->smbldap_state, dn, mods);
486
487         ldap_mods_free(mods, True);
488
489         if (rc != LDAP_SUCCESS) {
490                 DEBUG(1,("Failed to allocate new %s. "
491                          "smbldap_modify() failed.\n", type));
492                 goto done;
493         }
494
495         ret = NT_STATUS_OK;
496
497 done:
498         talloc_free(mem_ctx);
499         return ret;
500 }
501
502 /**********************************************************************
503  IDMAP MAPPING LDAP BACKEND
504 **********************************************************************/
505
506 static int idmap_ldap_close_destructor(struct idmap_ldap_context *ctx)
507 {
508         smbldap_free_struct(&ctx->smbldap_state);
509         DEBUG(5,("The connection to the LDAP server was closed\n"));
510         /* maybe free the results here --metze */
511
512         return 0;
513 }
514
515 /********************************
516  Initialise idmap database.
517 ********************************/
518
519 static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom,
520                                    const char *params)
521 {
522         NTSTATUS ret;
523         struct idmap_ldap_context *ctx = NULL;
524         char *config_option = NULL;
525         const char *tmp = NULL;
526
527         /* Only do init if we are online */
528         if (idmap_is_offline()) {
529                 return NT_STATUS_FILE_IS_OFFLINE;
530         }
531
532         ctx = TALLOC_ZERO_P(dom, struct idmap_ldap_context);
533         if ( ! ctx) {
534                 DEBUG(0, ("Out of memory!\n"));
535                 return NT_STATUS_NO_MEMORY;
536         }
537
538         if (strequal(dom->name, "*")) {
539                 /* more specific configuration can go here */
540         } else {
541                 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
542                 if ( ! config_option) {
543                         DEBUG(0, ("Out of memory!\n"));
544                         ret = NT_STATUS_NO_MEMORY;
545                         goto done;
546                 }
547         }
548
549         if (params != NULL) {
550                 /* assume location is the only parameter */
551                 ctx->url = talloc_strdup(ctx, params);
552         } else {
553                 tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
554
555                 if ( ! tmp) {
556                         DEBUG(1, ("ERROR: missing idmap ldap url\n"));
557                         ret = NT_STATUS_UNSUCCESSFUL;
558                         goto done;
559                 }
560
561                 ctx->url = talloc_strdup(ctx, tmp);
562         }
563         CHECK_ALLOC_DONE(ctx->url);
564
565         trim_char(ctx->url, '\"', '\"');
566
567         tmp = lp_parm_const_string(-1, config_option, "ldap_base_dn", NULL);
568         if ( ! tmp || ! *tmp) {
569                 tmp = lp_ldap_idmap_suffix();
570                 if ( ! tmp) {
571                         DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
572                         ret = NT_STATUS_UNSUCCESSFUL;
573                         goto done;
574                 }
575         }
576
577         ctx->suffix = talloc_strdup(ctx, tmp);
578         CHECK_ALLOC_DONE(ctx->suffix);
579
580         ret = smbldap_init(ctx, winbind_event_context(), ctx->url,
581                            &ctx->smbldap_state);
582         if (!NT_STATUS_IS_OK(ret)) {
583                 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", ctx->url));
584                 goto done;
585         }
586
587         ret = get_credentials( ctx, ctx->smbldap_state, config_option,
588                                dom, &ctx->user_dn );
589         if ( !NT_STATUS_IS_OK(ret) ) {
590                 DEBUG(1,("idmap_ldap_db_init: Failed to get connection "
591                          "credentials (%s)\n", nt_errstr(ret)));
592                 goto done;
593         }
594
595         /* set the destructor on the context, so that resource are properly
596            freed if the contexts is released */
597
598         talloc_set_destructor(ctx, idmap_ldap_close_destructor);
599
600         dom->private_data = ctx;
601
602         ret = idmap_ldap_alloc_init(dom, params);
603         if (!NT_STATUS_IS_OK(ret)) {
604                 DEBUG(1, ("idmap_ldap_db_init: Failed to initialize alloc "
605                           "subsystem: %s\n", nt_errstr(ret)));
606                 goto done;
607         }
608
609         talloc_free(config_option);
610         return NT_STATUS_OK;
611
612 /*failed */
613 done:
614         talloc_free(ctx);
615         return ret;
616 }
617
618 /* max number of ids requested per batch query */
619 #define IDMAP_LDAP_MAX_IDS 30
620
621 /**********************************
622  lookup a set of unix ids.
623 **********************************/
624
625 /* this function searches up to IDMAP_LDAP_MAX_IDS entries
626  * in maps for a match */
627 static struct id_map *find_map_by_id(struct id_map **maps,
628                                      enum id_type type,
629                                      uint32_t id)
630 {
631         int i;
632
633         for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
634                 if (maps[i] == NULL) { /* end of the run */
635                         return NULL;
636                 }
637                 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
638                         return maps[i];
639                 }
640         }
641
642         return NULL;
643 }
644
645 static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
646                                            struct id_map **ids)
647 {
648         NTSTATUS ret;
649         TALLOC_CTX *memctx;
650         struct idmap_ldap_context *ctx;
651         LDAPMessage *result = NULL;
652         LDAPMessage *entry = NULL;
653         const char *uidNumber;
654         const char *gidNumber;
655         const char **attr_list;
656         char *filter = NULL;
657         bool multi = False;
658         int idx = 0;
659         int bidx = 0;
660         int count;
661         int rc;
662         int i;
663
664         /* Only do query if we are online */
665         if (idmap_is_offline()) {
666                 return NT_STATUS_FILE_IS_OFFLINE;
667         }
668
669         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
670
671         memctx = talloc_new(ctx);
672         if ( ! memctx) {
673                 DEBUG(0, ("Out of memory!\n"));
674                 return NT_STATUS_NO_MEMORY;
675         }
676
677         uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
678         gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
679
680         attr_list = get_attr_list(memctx, sidmap_attr_list);
681
682         if ( ! ids[1]) {
683                 /* if we are requested just one mapping use the simple filter */
684
685                 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%lu))",
686                                 LDAP_OBJ_IDMAP_ENTRY,
687                                 (ids[0]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
688                                 (unsigned long)ids[0]->xid.id);
689                 CHECK_ALLOC_DONE(filter);
690                 DEBUG(10, ("Filter: [%s]\n", filter));
691         } else {
692                 /* multiple mappings */
693                 multi = True;
694         }
695
696         for (i = 0; ids[i]; i++) {
697                 ids[i]->status = ID_UNKNOWN;
698         }
699
700 again:
701         if (multi) {
702
703                 talloc_free(filter);
704                 filter = talloc_asprintf(memctx,
705                                          "(&(objectClass=%s)(|",
706                                          LDAP_OBJ_IDMAP_ENTRY);
707                 CHECK_ALLOC_DONE(filter);
708
709                 bidx = idx;
710                 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
711                         filter = talloc_asprintf_append_buffer(filter, "(%s=%lu)",
712                                         (ids[idx]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
713                                         (unsigned long)ids[idx]->xid.id);
714                         CHECK_ALLOC_DONE(filter);
715                 }
716                 filter = talloc_asprintf_append_buffer(filter, "))");
717                 CHECK_ALLOC_DONE(filter);
718                 DEBUG(10, ("Filter: [%s]\n", filter));
719         } else {
720                 bidx = 0;
721                 idx = 1;
722         }
723
724         rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
725                 filter, attr_list, 0, &result);
726
727         if (rc != LDAP_SUCCESS) {
728                 DEBUG(3,("Failure looking up ids (%s)\n", ldap_err2string(rc)));
729                 ret = NT_STATUS_UNSUCCESSFUL;
730                 goto done;
731         }
732
733         count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
734
735         if (count == 0) {
736                 DEBUG(10, ("NO SIDs found\n"));
737         }
738
739         for (i = 0; i < count; i++) {
740                 char *sidstr = NULL;
741                 char *tmp = NULL;
742                 enum id_type type;
743                 struct id_map *map;
744                 uint32_t id;
745
746                 if (i == 0) { /* first entry */
747                         entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
748                                                  result);
749                 } else { /* following ones */
750                         entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
751                                                 entry);
752                 }
753                 if ( ! entry) {
754                         DEBUG(2, ("ERROR: Unable to fetch ldap entries "
755                                   "from results\n"));
756                         break;
757                 }
758
759                 /* first check if the SID is present */
760                 sidstr = smbldap_talloc_single_attribute(
761                                 ctx->smbldap_state->ldap_struct,
762                                 entry, LDAP_ATTRIBUTE_SID, memctx);
763                 if ( ! sidstr) { /* no sid, skip entry */
764                         DEBUG(2, ("WARNING SID not found on entry\n"));
765                         continue;
766                 }
767
768                 /* now try to see if it is a uid, if not try with a gid
769                  * (gid is more common, but in case both uidNumber and
770                  * gidNumber are returned the SID is mapped to the uid
771                  *not the gid) */
772                 type = ID_TYPE_UID;
773                 tmp = smbldap_talloc_single_attribute(
774                                 ctx->smbldap_state->ldap_struct,
775                                 entry, uidNumber, memctx);
776                 if ( ! tmp) {
777                         type = ID_TYPE_GID;
778                         tmp = smbldap_talloc_single_attribute(
779                                         ctx->smbldap_state->ldap_struct,
780                                         entry, gidNumber, memctx);
781                 }
782                 if ( ! tmp) { /* wow very strange entry, how did it match ? */
783                         DEBUG(5, ("Unprobable match on (%s), no uidNumber, "
784                                   "nor gidNumber returned\n", sidstr));
785                         TALLOC_FREE(sidstr);
786                         continue;
787                 }
788
789                 id = strtoul(tmp, NULL, 10);
790                 if (!idmap_unix_id_is_in_range(id, dom)) {
791                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
792                                   "Filtered!\n", id,
793                                   dom->low_id, dom->high_id));
794                         TALLOC_FREE(sidstr);
795                         TALLOC_FREE(tmp);
796                         continue;
797                 }
798                 TALLOC_FREE(tmp);
799
800                 map = find_map_by_id(&ids[bidx], type, id);
801                 if (!map) {
802                         DEBUG(2, ("WARNING: couldn't match sid (%s) "
803                                   "with requested ids\n", sidstr));
804                         TALLOC_FREE(sidstr);
805                         continue;
806                 }
807
808                 if ( ! string_to_sid(map->sid, sidstr)) {
809                         DEBUG(2, ("ERROR: Invalid SID on entry\n"));
810                         TALLOC_FREE(sidstr);
811                         continue;
812                 }
813
814                 if (map->status == ID_MAPPED) {
815                         DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
816                               "overwriting mapping %u -> %s with %u -> %s\n",
817                               (type == ID_TYPE_UID) ? "UID" : "GID",
818                               id, sid_string_dbg(map->sid), id, sidstr));
819                 }
820
821                 TALLOC_FREE(sidstr);
822
823                 /* mapped */
824                 map->status = ID_MAPPED;
825
826                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
827                            (unsigned long)map->xid.id, map->xid.type));
828         }
829
830         /* free the ldap results */
831         if (result) {
832                 ldap_msgfree(result);
833                 result = NULL;
834         }
835
836         if (multi && ids[idx]) { /* still some values to map */
837                 goto again;
838         }
839
840         ret = NT_STATUS_OK;
841
842         /* mark all unknwon/expired ones as unmapped */
843         for (i = 0; ids[i]; i++) {
844                 if (ids[i]->status != ID_MAPPED)
845                         ids[i]->status = ID_UNMAPPED;
846         }
847
848 done:
849         talloc_free(memctx);
850         return ret;
851 }
852
853 /**********************************
854  lookup a set of sids.
855 **********************************/
856
857 /* this function searches up to IDMAP_LDAP_MAX_IDS entries
858  * in maps for a match */
859 static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
860 {
861         int i;
862
863         for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
864                 if (maps[i] == NULL) { /* end of the run */
865                         return NULL;
866                 }
867                 if (sid_equal(maps[i]->sid, sid)) {
868                         return maps[i];
869                 }
870         }
871
872         return NULL;
873 }
874
875 static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
876                                            struct id_map **ids)
877 {
878         LDAPMessage *entry = NULL;
879         NTSTATUS ret;
880         TALLOC_CTX *memctx;
881         struct idmap_ldap_context *ctx;
882         LDAPMessage *result = NULL;
883         const char *uidNumber;
884         const char *gidNumber;
885         const char **attr_list;
886         char *filter = NULL;
887         bool multi = False;
888         int idx = 0;
889         int bidx = 0;
890         int count;
891         int rc;
892         int i;
893
894         /* Only do query if we are online */
895         if (idmap_is_offline()) {
896                 return NT_STATUS_FILE_IS_OFFLINE;
897         }
898
899         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
900
901         memctx = talloc_new(ctx);
902         if ( ! memctx) {
903                 DEBUG(0, ("Out of memory!\n"));
904                 return NT_STATUS_NO_MEMORY;
905         }
906
907         uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
908         gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
909
910         attr_list = get_attr_list(memctx, sidmap_attr_list);
911
912         if ( ! ids[1]) {
913                 /* if we are requested just one mapping use the simple filter */
914
915                 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%s))",
916                                 LDAP_OBJ_IDMAP_ENTRY,
917                                 LDAP_ATTRIBUTE_SID,
918                                 sid_string_talloc(memctx, ids[0]->sid));
919                 CHECK_ALLOC_DONE(filter);
920                 DEBUG(10, ("Filter: [%s]\n", filter));
921         } else {
922                 /* multiple mappings */
923                 multi = True;
924         }
925
926         for (i = 0; ids[i]; i++) {
927                 ids[i]->status = ID_UNKNOWN;
928         }
929
930 again:
931         if (multi) {
932
933                 TALLOC_FREE(filter);
934                 filter = talloc_asprintf(memctx,
935                                          "(&(objectClass=%s)(|",
936                                          LDAP_OBJ_IDMAP_ENTRY);
937                 CHECK_ALLOC_DONE(filter);
938
939                 bidx = idx;
940                 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
941                         filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
942                                         LDAP_ATTRIBUTE_SID,
943                                         sid_string_talloc(memctx,
944                                                           ids[idx]->sid));
945                         CHECK_ALLOC_DONE(filter);
946                 }
947                 filter = talloc_asprintf_append_buffer(filter, "))");
948                 CHECK_ALLOC_DONE(filter);
949                 DEBUG(10, ("Filter: [%s]", filter));
950         } else {
951                 bidx = 0;
952                 idx = 1;
953         }
954
955         rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
956                 filter, attr_list, 0, &result);
957
958         if (rc != LDAP_SUCCESS) {
959                 DEBUG(3,("Failure looking up sids (%s)\n",
960                          ldap_err2string(rc)));
961                 ret = NT_STATUS_UNSUCCESSFUL;
962                 goto done;
963         }
964
965         count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
966
967         if (count == 0) {
968                 DEBUG(10, ("NO SIDs found\n"));
969         }
970
971         for (i = 0; i < count; i++) {
972                 char *sidstr = NULL;
973                 char *tmp = NULL;
974                 enum id_type type;
975                 struct id_map *map;
976                 DOM_SID sid;
977                 uint32_t id;
978
979                 if (i == 0) { /* first entry */
980                         entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
981                                                  result);
982                 } else { /* following ones */
983                         entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
984                                                 entry);
985                 }
986                 if ( ! entry) {
987                         DEBUG(2, ("ERROR: Unable to fetch ldap entries "
988                                   "from results\n"));
989                         break;
990                 }
991
992                 /* first check if the SID is present */
993                 sidstr = smbldap_talloc_single_attribute(
994                                 ctx->smbldap_state->ldap_struct,
995                                 entry, LDAP_ATTRIBUTE_SID, memctx);
996                 if ( ! sidstr) { /* no sid ??, skip entry */
997                         DEBUG(2, ("WARNING SID not found on entry\n"));
998                         continue;
999                 }
1000
1001                 if ( ! string_to_sid(&sid, sidstr)) {
1002                         DEBUG(2, ("ERROR: Invalid SID on entry\n"));
1003                         TALLOC_FREE(sidstr);
1004                         continue;
1005                 }
1006
1007                 map = find_map_by_sid(&ids[bidx], &sid);
1008                 if (!map) {
1009                         DEBUG(2, ("WARNING: couldn't find entry sid (%s) "
1010                                   "in ids", sidstr));
1011                         TALLOC_FREE(sidstr);
1012                         continue;
1013                 }
1014
1015                 /* now try to see if it is a uid, if not try with a gid
1016                  * (gid is more common, but in case both uidNumber and
1017                  * gidNumber are returned the SID is mapped to the uid
1018                  * not the gid) */
1019                 type = ID_TYPE_UID;
1020                 tmp = smbldap_talloc_single_attribute(
1021                                 ctx->smbldap_state->ldap_struct,
1022                                 entry, uidNumber, memctx);
1023                 if ( ! tmp) {
1024                         type = ID_TYPE_GID;
1025                         tmp = smbldap_talloc_single_attribute(
1026                                         ctx->smbldap_state->ldap_struct,
1027                                         entry, gidNumber, memctx);
1028                 }
1029                 if ( ! tmp) { /* no ids ?? */
1030                         DEBUG(5, ("no uidNumber, "
1031                                   "nor gidNumber attributes found\n"));
1032                         TALLOC_FREE(sidstr);
1033                         continue;
1034                 }
1035
1036                 id = strtoul(tmp, NULL, 10);
1037                 if (!idmap_unix_id_is_in_range(id, dom)) {
1038                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
1039                                   "Filtered!\n", id,
1040                                   dom->low_id, dom->high_id));
1041                         TALLOC_FREE(sidstr);
1042                         TALLOC_FREE(tmp);
1043                         continue;
1044                 }
1045                 TALLOC_FREE(tmp);
1046
1047                 if (map->status == ID_MAPPED) {
1048                         DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
1049                               "overwriting mapping %s -> %u with %s -> %u\n",
1050                               (type == ID_TYPE_UID) ? "UID" : "GID",
1051                               sidstr, map->xid.id, sidstr, id));
1052                 }
1053
1054                 TALLOC_FREE(sidstr);
1055
1056                 /* mapped */
1057                 map->xid.type = type;
1058                 map->xid.id = id;
1059                 map->status = ID_MAPPED;
1060
1061                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
1062                            (unsigned long)map->xid.id, map->xid.type));
1063         }
1064
1065         /* free the ldap results */
1066         if (result) {
1067                 ldap_msgfree(result);
1068                 result = NULL;
1069         }
1070
1071         if (multi && ids[idx]) { /* still some values to map */
1072                 goto again;
1073         }
1074
1075         ret = NT_STATUS_OK;
1076
1077         /* mark all unknwon/expired ones as unmapped */
1078         for (i = 0; ids[i]; i++) {
1079                 if (ids[i]->status != ID_MAPPED)
1080                         ids[i]->status = ID_UNMAPPED;
1081         }
1082
1083 done:
1084         talloc_free(memctx);
1085         return ret;
1086 }
1087
1088 /**********************************
1089  set a mapping.
1090 **********************************/
1091
1092 /* TODO: change this:  This function cannot be called to modify a mapping,
1093  * only set a new one */
1094
1095 static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
1096                                        const struct id_map *map)
1097 {
1098         NTSTATUS ret;
1099         TALLOC_CTX *memctx;
1100         struct idmap_ldap_context *ctx;
1101         LDAPMessage *entry = NULL;
1102         LDAPMod **mods = NULL;
1103         const char *type;
1104         char *id_str;
1105         char *sid;
1106         char *dn;
1107         int rc = -1;
1108
1109         /* Only do query if we are online */
1110         if (idmap_is_offline()) {
1111                 return NT_STATUS_FILE_IS_OFFLINE;
1112         }
1113
1114         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
1115
1116         switch(map->xid.type) {
1117         case ID_TYPE_UID:
1118                 type = get_attr_key2string(sidmap_attr_list,
1119                                            LDAP_ATTR_UIDNUMBER);
1120                 break;
1121
1122         case ID_TYPE_GID:
1123                 type = get_attr_key2string(sidmap_attr_list,
1124                                            LDAP_ATTR_GIDNUMBER);
1125                 break;
1126
1127         default:
1128                 return NT_STATUS_INVALID_PARAMETER;
1129         }
1130
1131         memctx = talloc_new(ctx);
1132         if ( ! memctx) {
1133                 DEBUG(0, ("Out of memory!\n"));
1134                 return NT_STATUS_NO_MEMORY;
1135         }
1136
1137         id_str = talloc_asprintf(memctx, "%lu", (unsigned long)map->xid.id);
1138         CHECK_ALLOC_DONE(id_str);
1139
1140         sid = talloc_strdup(memctx, sid_string_talloc(memctx, map->sid));
1141         CHECK_ALLOC_DONE(sid);
1142
1143         dn = talloc_asprintf(memctx, "%s=%s,%s",
1144                         get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
1145                         sid,
1146                         ctx->suffix);
1147         CHECK_ALLOC_DONE(dn);
1148
1149         smbldap_set_mod(&mods, LDAP_MOD_ADD,
1150                         "objectClass", LDAP_OBJ_IDMAP_ENTRY);
1151
1152         smbldap_make_mod(ctx->smbldap_state->ldap_struct,
1153                          entry, &mods, type, id_str);
1154
1155         smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods,
1156                          get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
1157                          sid);
1158
1159         if ( ! mods) {
1160                 DEBUG(2, ("ERROR: No mods?\n"));
1161                 ret = NT_STATUS_UNSUCCESSFUL;
1162                 goto done;
1163         }
1164
1165         /* TODO: remove conflicting mappings! */
1166
1167         smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY);
1168
1169         DEBUG(10, ("Set DN %s (%s -> %s)\n", dn, sid, id_str));
1170
1171         rc = smbldap_add(ctx->smbldap_state, dn, mods);
1172         ldap_mods_free(mods, True);
1173
1174         if (rc != LDAP_SUCCESS) {
1175                 char *ld_error = NULL;
1176                 ldap_get_option(ctx->smbldap_state->ldap_struct,
1177                                 LDAP_OPT_ERROR_STRING, &ld_error);
1178                 DEBUG(0,("ldap_set_mapping_internals: Failed to add %s to %lu "
1179                          "mapping [%s]\n", sid,
1180                          (unsigned long)map->xid.id, type));
1181                 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
1182                         ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
1183                 if (ld_error) {
1184                         ldap_memfree(ld_error);
1185                 }
1186                 ret = NT_STATUS_UNSUCCESSFUL;
1187                 goto done;
1188         }
1189
1190         DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to "
1191                   "%lu [%s]\n", sid, (unsigned long)map->xid.id, type));
1192
1193         ret = NT_STATUS_OK;
1194
1195 done:
1196         talloc_free(memctx);
1197         return ret;
1198 }
1199
1200 /**********************************
1201  Close the idmap ldap instance
1202 **********************************/
1203
1204 static NTSTATUS idmap_ldap_close(struct idmap_domain *dom)
1205 {
1206         struct idmap_ldap_context *ctx;
1207
1208         if (dom->private_data) {
1209                 ctx = talloc_get_type(dom->private_data,
1210                                       struct idmap_ldap_context);
1211
1212                 talloc_free(ctx);
1213                 dom->private_data = NULL;
1214         }
1215
1216         return NT_STATUS_OK;
1217 }
1218
1219 static struct idmap_methods idmap_ldap_methods = {
1220
1221         .init = idmap_ldap_db_init,
1222         .unixids_to_sids = idmap_ldap_unixids_to_sids,
1223         .sids_to_unixids = idmap_ldap_sids_to_unixids,
1224         .allocate_id = idmap_ldap_get_new_id,
1225         .close_fn = idmap_ldap_close
1226 };
1227
1228 NTSTATUS idmap_ldap_init(void);
1229 NTSTATUS idmap_ldap_init(void)
1230 {
1231         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap",
1232                                   &idmap_ldap_methods);
1233 }
1234