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