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