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