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