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