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