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