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