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