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