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