s3-winbindd: add and use winbindd_lookup_sids().
[ira/wip.git] / source3 / winbindd / 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 static char *idmap_fetch_secret(const char *backend, bool alloc,
37                                 const char *domain, const char *identity)
38 {
39         char *tmp, *ret;
40         int r;
41
42         if (alloc) {
43                 r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend);
44         } else {
45                 r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
46         }
47
48         if (r < 0)
49                 return NULL;
50
51         strupper_m(tmp); /* make sure the key is case insensitive */
52         ret = secrets_fetch_generic(tmp, identity);
53
54         SAFE_FREE(tmp);
55
56         return ret;
57 }
58
59 struct idmap_ldap_context {
60         struct smbldap_state *smbldap_state;
61         char *url;
62         char *suffix;
63         char *user_dn;
64         uint32_t filter_low_id, filter_high_id;         /* Filter range */
65         bool anon;
66 };
67
68 struct idmap_ldap_alloc_context {
69         struct smbldap_state *smbldap_state;
70         char *url;
71         char *suffix;
72         char *user_dn;
73         uid_t low_uid, high_uid;      /* Range of uids */
74         gid_t low_gid, high_gid;      /* Range of gids */
75
76 };
77
78 #define CHECK_ALLOC_DONE(mem) do { \
79         if (!mem) { \
80                 DEBUG(0, ("Out of memory!\n")); \
81                 ret = NT_STATUS_NO_MEMORY; \
82                 goto done; \
83         } } while (0)
84
85 /**********************************************************************
86  IDMAP ALLOC TDB BACKEND
87 **********************************************************************/
88
89 static struct idmap_ldap_alloc_context *idmap_alloc_ldap;
90
91 /*********************************************************************
92  ********************************************************************/
93
94 static NTSTATUS get_credentials( TALLOC_CTX *mem_ctx,
95                                  struct smbldap_state *ldap_state,
96                                  const char *config_option,
97                                  struct idmap_domain *dom,
98                                  char **dn )
99 {
100         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
101         char *secret = NULL;
102         const char *tmp = NULL;
103         char *user_dn = NULL;
104         bool anon = False;
105
106         /* assume anonymous if we don't have a specified user */
107
108         tmp = lp_parm_const_string(-1, config_option, "ldap_user_dn", NULL);
109
110         if ( tmp ) {
111                 if (!dom) {
112                         /* only the alloc backend can pass in a NULL dom */
113                         secret = idmap_fetch_secret("ldap", True,
114                                                     NULL, tmp);
115                 } else {
116                         secret = idmap_fetch_secret("ldap", False,
117                                                     dom->name, tmp);
118                 }
119
120                 if (!secret) {
121                         DEBUG(0, ("get_credentials: Unable to fetch "
122                                   "auth credentials for %s in %s\n",
123                                   tmp, (dom==NULL)?"ALLOC":dom->name));
124                         ret = NT_STATUS_ACCESS_DENIED;
125                         goto done;
126                 }
127                 *dn = talloc_strdup(mem_ctx, tmp);
128                 CHECK_ALLOC_DONE(*dn);
129         } else {
130                 if (!fetch_ldap_pw(&user_dn, &secret)) {
131                         DEBUG(2, ("get_credentials: Failed to lookup ldap "
132                                   "bind creds. Using anonymous connection.\n"));
133                         anon = True;
134                 } else {
135                         *dn = talloc_strdup(mem_ctx, user_dn);
136                         SAFE_FREE( user_dn );
137                         CHECK_ALLOC_DONE(*dn);
138                 }
139         }
140
141         smbldap_set_creds(ldap_state, anon, *dn, secret);
142         ret = NT_STATUS_OK;
143
144 done:
145         SAFE_FREE(secret);
146
147         return ret;
148 }
149
150
151 /**********************************************************************
152  Verify the sambaUnixIdPool entry in the directory.
153 **********************************************************************/
154
155 static NTSTATUS verify_idpool(void)
156 {
157         NTSTATUS ret;
158         TALLOC_CTX *ctx;
159         LDAPMessage *result = NULL;
160         LDAPMod **mods = NULL;
161         const char **attr_list;
162         char *filter;
163         int count;
164         int rc;
165
166         if ( ! idmap_alloc_ldap) {
167                 return NT_STATUS_UNSUCCESSFUL;
168         }
169
170         ctx = talloc_new(idmap_alloc_ldap);
171         if ( ! ctx) {
172                 DEBUG(0, ("Out of memory!\n"));
173                 return NT_STATUS_NO_MEMORY;
174         }
175
176         filter = talloc_asprintf(ctx, "(objectclass=%s)", LDAP_OBJ_IDPOOL);
177         CHECK_ALLOC_DONE(filter);
178
179         attr_list = get_attr_list(ctx, idpool_attr_list);
180         CHECK_ALLOC_DONE(attr_list);
181
182         rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
183                                 idmap_alloc_ldap->suffix,
184                                 LDAP_SCOPE_SUBTREE,
185                                 filter,
186                                 attr_list,
187                                 0,
188                                 &result);
189
190         if (rc != LDAP_SUCCESS) {
191                 DEBUG(1, ("Unable to verify the idpool, "
192                           "cannot continue initialization!\n"));
193                 return NT_STATUS_UNSUCCESSFUL;
194         }
195
196         count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
197                                    result);
198
199         ldap_msgfree(result);
200
201         if ( count > 1 ) {
202                 DEBUG(0,("Multiple entries returned from %s (base == %s)\n",
203                         filter, idmap_alloc_ldap->suffix));
204                 ret = NT_STATUS_UNSUCCESSFUL;
205                 goto done;
206         }
207         else if (count == 0) {
208                 char *uid_str, *gid_str;
209
210                 uid_str = talloc_asprintf(ctx, "%lu",
211                                 (unsigned long)idmap_alloc_ldap->low_uid);
212                 gid_str = talloc_asprintf(ctx, "%lu",
213                                 (unsigned long)idmap_alloc_ldap->low_gid);
214
215                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
216                                 "objectClass", LDAP_OBJ_IDPOOL);
217                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
218                                 get_attr_key2string(idpool_attr_list,
219                                                     LDAP_ATTR_UIDNUMBER),
220                                 uid_str);
221                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
222                                 get_attr_key2string(idpool_attr_list,
223                                                     LDAP_ATTR_GIDNUMBER),
224                                 gid_str);
225                 if (mods) {
226                         rc = smbldap_modify(idmap_alloc_ldap->smbldap_state,
227                                                 idmap_alloc_ldap->suffix,
228                                                 mods);
229                         ldap_mods_free(mods, True);
230                 } else {
231                         ret = NT_STATUS_UNSUCCESSFUL;
232                         goto done;
233                 }
234         }
235
236         ret = (rc == LDAP_SUCCESS)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL;
237 done:
238         talloc_free(ctx);
239         return ret;
240 }
241
242 /*****************************************************************************
243  Initialise idmap database.
244 *****************************************************************************/
245
246 static NTSTATUS idmap_ldap_alloc_init(const char *params)
247 {
248         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
249         const char *tmp;
250         uid_t low_uid = 0;
251         uid_t high_uid = 0;
252         gid_t low_gid = 0;
253         gid_t high_gid = 0;
254
255         /* Only do init if we are online */
256         if (idmap_is_offline()) {
257                 return NT_STATUS_FILE_IS_OFFLINE;
258         }
259
260         idmap_alloc_ldap = TALLOC_ZERO_P(NULL, struct idmap_ldap_alloc_context);
261         CHECK_ALLOC_DONE( idmap_alloc_ldap );
262
263         /* load ranges */
264
265         if (!lp_idmap_uid(&low_uid, &high_uid)
266             || !lp_idmap_gid(&low_gid, &high_gid)) {
267                 DEBUG(1, ("idmap uid or idmap gid missing\n"));
268                 ret = NT_STATUS_UNSUCCESSFUL;
269                 goto done;
270         }
271
272         idmap_alloc_ldap->low_uid = low_uid;
273         idmap_alloc_ldap->high_uid = high_uid;
274         idmap_alloc_ldap->low_gid = low_gid;
275         idmap_alloc_ldap->high_gid= high_gid;
276
277         if (idmap_alloc_ldap->high_uid <= idmap_alloc_ldap->low_uid) {
278                 DEBUG(1, ("idmap uid range 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 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                                    const char *params)
764 {
765         NTSTATUS ret;
766         struct idmap_ldap_context *ctx = NULL;
767         char *config_option = 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         if (strequal(dom->name, "*")) {
782                 uid_t low_uid = 0;
783                 uid_t high_uid = 0;
784                 gid_t low_gid = 0;
785                 gid_t high_gid = 0;
786
787                 ctx->filter_low_id = 0;
788                 ctx->filter_high_id = 0;
789
790                 if (lp_idmap_uid(&low_uid, &high_uid)) {
791                         ctx->filter_low_id = low_uid;
792                         ctx->filter_high_id = high_uid;
793                 } else {
794                         DEBUG(3, ("Warning: 'idmap uid' not set!\n"));
795                 }
796
797                 if (lp_idmap_gid(&low_gid, &high_gid)) {
798                         if ((low_gid != low_uid) || (high_gid != high_uid)) {
799                                 DEBUG(1, ("Warning: 'idmap uid' and 'idmap gid'"
800                                       " ranges do not agree -- building "
801                                       "intersection\n"));
802                                 ctx->filter_low_id = MAX(ctx->filter_low_id,
803                                                          low_gid);
804                                 ctx->filter_high_id = MIN(ctx->filter_high_id,
805                                                           high_gid);
806                         }
807                 } else {
808                         DEBUG(3, ("Warning: 'idmap gid' not set!\n"));
809                 }
810         } else {
811                 const char *range = NULL;
812
813                 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
814                 if ( ! config_option) {
815                         DEBUG(0, ("Out of memory!\n"));
816                         ret = NT_STATUS_NO_MEMORY;
817                         goto done;
818                 }
819
820                 /* load ranges */
821                 range = lp_parm_const_string(-1, config_option, "range", NULL);
822                 if (range && range[0]) {
823                         if ((sscanf(range, "%u - %u", &ctx->filter_low_id,
824                                                         &ctx->filter_high_id) != 2))
825                         {
826                                 DEBUG(1, ("ERROR: invalid filter range [%s]", range));
827                                 ctx->filter_low_id = 0;
828                                 ctx->filter_high_id = 0;
829                         }
830                 }
831         }
832
833         if (ctx->filter_low_id > ctx->filter_high_id) {
834                 DEBUG(1, ("ERROR: invalid filter range [%u-%u]",
835                       ctx->filter_low_id, ctx->filter_high_id));
836                 ctx->filter_low_id = 0;
837                 ctx->filter_high_id = 0;
838         }
839
840         if (params != NULL) {
841                 /* assume location is the only parameter */
842                 ctx->url = talloc_strdup(ctx, params);
843         } else {
844                 tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
845
846                 if ( ! tmp) {
847                         DEBUG(1, ("ERROR: missing idmap ldap url\n"));
848                         ret = NT_STATUS_UNSUCCESSFUL;
849                         goto done;
850                 }
851
852                 ctx->url = talloc_strdup(ctx, tmp);
853         }
854         CHECK_ALLOC_DONE(ctx->url);
855
856         tmp = lp_parm_const_string(-1, config_option, "ldap_base_dn", NULL);
857         if ( ! tmp || ! *tmp) {
858                 tmp = lp_ldap_idmap_suffix();
859                 if ( ! tmp) {
860                         DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
861                         ret = NT_STATUS_UNSUCCESSFUL;
862                         goto done;
863                 }
864         }
865
866         ctx->suffix = talloc_strdup(ctx, tmp);
867         CHECK_ALLOC_DONE(ctx->suffix);
868
869         ret = smbldap_init(ctx, winbind_event_context(), ctx->url,
870                            &ctx->smbldap_state);
871         if (!NT_STATUS_IS_OK(ret)) {
872                 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", ctx->url));
873                 goto done;
874         }
875
876         ret = get_credentials( ctx, ctx->smbldap_state, config_option,
877                                dom, &ctx->user_dn );
878         if ( !NT_STATUS_IS_OK(ret) ) {
879                 DEBUG(1,("idmap_ldap_db_init: Failed to get connection "
880                          "credentials (%s)\n", nt_errstr(ret)));
881                 goto done;
882         }
883
884         /* set the destructor on the context, so that resource are properly
885            freed if the contexts is released */
886
887         talloc_set_destructor(ctx, idmap_ldap_close_destructor);
888
889         dom->private_data = ctx;
890
891         talloc_free(config_option);
892         return NT_STATUS_OK;
893
894 /*failed */
895 done:
896         talloc_free(ctx);
897         return ret;
898 }
899
900 /* max number of ids requested per batch query */
901 #define IDMAP_LDAP_MAX_IDS 30
902
903 /**********************************
904  lookup a set of unix ids.
905 **********************************/
906
907 /* this function searches up to IDMAP_LDAP_MAX_IDS entries
908  * in maps for a match */
909 static struct id_map *find_map_by_id(struct id_map **maps,
910                                      enum id_type type,
911                                      uint32_t id)
912 {
913         int i;
914
915         for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
916                 if (maps[i] == NULL) { /* end of the run */
917                         return NULL;
918                 }
919                 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
920                         return maps[i];
921                 }
922         }
923
924         return NULL;
925 }
926
927 static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
928                                            struct id_map **ids)
929 {
930         NTSTATUS ret;
931         TALLOC_CTX *memctx;
932         struct idmap_ldap_context *ctx;
933         LDAPMessage *result = NULL;
934         LDAPMessage *entry = NULL;
935         const char *uidNumber;
936         const char *gidNumber;
937         const char **attr_list;
938         char *filter = NULL;
939         bool multi = False;
940         int idx = 0;
941         int bidx = 0;
942         int count;
943         int rc;
944         int i;
945
946         /* Only do query if we are online */
947         if (idmap_is_offline()) {
948                 return NT_STATUS_FILE_IS_OFFLINE;
949         }
950
951         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
952
953         memctx = talloc_new(ctx);
954         if ( ! memctx) {
955                 DEBUG(0, ("Out of memory!\n"));
956                 return NT_STATUS_NO_MEMORY;
957         }
958
959         uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
960         gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
961
962         attr_list = get_attr_list(memctx, sidmap_attr_list);
963
964         if ( ! ids[1]) {
965                 /* if we are requested just one mapping use the simple filter */
966
967                 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%lu))",
968                                 LDAP_OBJ_IDMAP_ENTRY,
969                                 (ids[0]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
970                                 (unsigned long)ids[0]->xid.id);
971                 CHECK_ALLOC_DONE(filter);
972                 DEBUG(10, ("Filter: [%s]\n", filter));
973         } else {
974                 /* multiple mappings */
975                 multi = True;
976         }
977
978         for (i = 0; ids[i]; i++) {
979                 ids[i]->status = ID_UNKNOWN;
980         }
981
982 again:
983         if (multi) {
984
985                 talloc_free(filter);
986                 filter = talloc_asprintf(memctx,
987                                          "(&(objectClass=%s)(|",
988                                          LDAP_OBJ_IDMAP_ENTRY);
989                 CHECK_ALLOC_DONE(filter);
990
991                 bidx = idx;
992                 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
993                         filter = talloc_asprintf_append_buffer(filter, "(%s=%lu)",
994                                         (ids[idx]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
995                                         (unsigned long)ids[idx]->xid.id);
996                         CHECK_ALLOC_DONE(filter);
997                 }
998                 filter = talloc_asprintf_append_buffer(filter, "))");
999                 CHECK_ALLOC_DONE(filter);
1000                 DEBUG(10, ("Filter: [%s]\n", filter));
1001         } else {
1002                 bidx = 0;
1003                 idx = 1;
1004         }
1005
1006         rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
1007                 filter, attr_list, 0, &result);
1008
1009         if (rc != LDAP_SUCCESS) {
1010                 DEBUG(3,("Failure looking up ids (%s)\n", ldap_err2string(rc)));
1011                 ret = NT_STATUS_UNSUCCESSFUL;
1012                 goto done;
1013         }
1014
1015         count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
1016
1017         if (count == 0) {
1018                 DEBUG(10, ("NO SIDs found\n"));
1019         }
1020
1021         for (i = 0; i < count; i++) {
1022                 char *sidstr = NULL;
1023                 char *tmp = NULL;
1024                 enum id_type type;
1025                 struct id_map *map;
1026                 uint32_t id;
1027
1028                 if (i == 0) { /* first entry */
1029                         entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
1030                                                  result);
1031                 } else { /* following ones */
1032                         entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
1033                                                 entry);
1034                 }
1035                 if ( ! entry) {
1036                         DEBUG(2, ("ERROR: Unable to fetch ldap entries "
1037                                   "from results\n"));
1038                         break;
1039                 }
1040
1041                 /* first check if the SID is present */
1042                 sidstr = smbldap_talloc_single_attribute(
1043                                 ctx->smbldap_state->ldap_struct,
1044                                 entry, LDAP_ATTRIBUTE_SID, memctx);
1045                 if ( ! sidstr) { /* no sid, skip entry */
1046                         DEBUG(2, ("WARNING SID not found on entry\n"));
1047                         continue;
1048                 }
1049
1050                 /* now try to see if it is a uid, if not try with a gid
1051                  * (gid is more common, but in case both uidNumber and
1052                  * gidNumber are returned the SID is mapped to the uid
1053                  *not the gid) */
1054                 type = ID_TYPE_UID;
1055                 tmp = smbldap_talloc_single_attribute(
1056                                 ctx->smbldap_state->ldap_struct,
1057                                 entry, uidNumber, memctx);
1058                 if ( ! tmp) {
1059                         type = ID_TYPE_GID;
1060                         tmp = smbldap_talloc_single_attribute(
1061                                         ctx->smbldap_state->ldap_struct,
1062                                         entry, gidNumber, memctx);
1063                 }
1064                 if ( ! tmp) { /* wow very strange entry, how did it match ? */
1065                         DEBUG(5, ("Unprobable match on (%s), no uidNumber, "
1066                                   "nor gidNumber returned\n", sidstr));
1067                         TALLOC_FREE(sidstr);
1068                         continue;
1069                 }
1070
1071                 id = strtoul(tmp, NULL, 10);
1072                 if ((id == 0) ||
1073                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
1074                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
1075                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
1076                                   "Filtered!\n", id,
1077                                   ctx->filter_low_id, ctx->filter_high_id));
1078                         TALLOC_FREE(sidstr);
1079                         TALLOC_FREE(tmp);
1080                         continue;
1081                 }
1082                 TALLOC_FREE(tmp);
1083
1084                 map = find_map_by_id(&ids[bidx], type, id);
1085                 if (!map) {
1086                         DEBUG(2, ("WARNING: couldn't match sid (%s) "
1087                                   "with requested ids\n", sidstr));
1088                         TALLOC_FREE(sidstr);
1089                         continue;
1090                 }
1091
1092                 if ( ! string_to_sid(map->sid, sidstr)) {
1093                         DEBUG(2, ("ERROR: Invalid SID on entry\n"));
1094                         TALLOC_FREE(sidstr);
1095                         continue;
1096                 }
1097
1098                 if (map->status == ID_MAPPED) {
1099                         DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
1100                               "overwriting mapping %u -> %s with %u -> %s\n",
1101                               (type == ID_TYPE_UID) ? "UID" : "GID",
1102                               id, sid_string_dbg(map->sid), id, sidstr));
1103                 }
1104
1105                 TALLOC_FREE(sidstr);
1106
1107                 /* mapped */
1108                 map->status = ID_MAPPED;
1109
1110                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
1111                            (unsigned long)map->xid.id, map->xid.type));
1112         }
1113
1114         /* free the ldap results */
1115         if (result) {
1116                 ldap_msgfree(result);
1117                 result = NULL;
1118         }
1119
1120         if (multi && ids[idx]) { /* still some values to map */
1121                 goto again;
1122         }
1123
1124         ret = NT_STATUS_OK;
1125
1126         /* mark all unknwon/expired ones as unmapped */
1127         for (i = 0; ids[i]; i++) {
1128                 if (ids[i]->status != ID_MAPPED)
1129                         ids[i]->status = ID_UNMAPPED;
1130         }
1131
1132 done:
1133         talloc_free(memctx);
1134         return ret;
1135 }
1136
1137 /**********************************
1138  lookup a set of sids.
1139 **********************************/
1140
1141 /* this function searches up to IDMAP_LDAP_MAX_IDS entries
1142  * in maps for a match */
1143 static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
1144 {
1145         int i;
1146
1147         for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
1148                 if (maps[i] == NULL) { /* end of the run */
1149                         return NULL;
1150                 }
1151                 if (sid_equal(maps[i]->sid, sid)) {
1152                         return maps[i];
1153                 }
1154         }
1155
1156         return NULL;
1157 }
1158
1159 static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
1160                                            struct id_map **ids)
1161 {
1162         LDAPMessage *entry = NULL;
1163         NTSTATUS ret;
1164         TALLOC_CTX *memctx;
1165         struct idmap_ldap_context *ctx;
1166         LDAPMessage *result = NULL;
1167         const char *uidNumber;
1168         const char *gidNumber;
1169         const char **attr_list;
1170         char *filter = NULL;
1171         bool multi = False;
1172         int idx = 0;
1173         int bidx = 0;
1174         int count;
1175         int rc;
1176         int i;
1177
1178         /* Only do query if we are online */
1179         if (idmap_is_offline()) {
1180                 return NT_STATUS_FILE_IS_OFFLINE;
1181         }
1182
1183         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
1184
1185         memctx = talloc_new(ctx);
1186         if ( ! memctx) {
1187                 DEBUG(0, ("Out of memory!\n"));
1188                 return NT_STATUS_NO_MEMORY;
1189         }
1190
1191         uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
1192         gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
1193
1194         attr_list = get_attr_list(memctx, sidmap_attr_list);
1195
1196         if ( ! ids[1]) {
1197                 /* if we are requested just one mapping use the simple filter */
1198
1199                 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%s))",
1200                                 LDAP_OBJ_IDMAP_ENTRY,
1201                                 LDAP_ATTRIBUTE_SID,
1202                                 sid_string_talloc(memctx, ids[0]->sid));
1203                 CHECK_ALLOC_DONE(filter);
1204                 DEBUG(10, ("Filter: [%s]\n", filter));
1205         } else {
1206                 /* multiple mappings */
1207                 multi = True;
1208         }
1209
1210         for (i = 0; ids[i]; i++) {
1211                 ids[i]->status = ID_UNKNOWN;
1212         }
1213
1214 again:
1215         if (multi) {
1216
1217                 TALLOC_FREE(filter);
1218                 filter = talloc_asprintf(memctx,
1219                                          "(&(objectClass=%s)(|",
1220                                          LDAP_OBJ_IDMAP_ENTRY);
1221                 CHECK_ALLOC_DONE(filter);
1222
1223                 bidx = idx;
1224                 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
1225                         filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
1226                                         LDAP_ATTRIBUTE_SID,
1227                                         sid_string_talloc(memctx,
1228                                                           ids[idx]->sid));
1229                         CHECK_ALLOC_DONE(filter);
1230                 }
1231                 filter = talloc_asprintf_append_buffer(filter, "))");
1232                 CHECK_ALLOC_DONE(filter);
1233                 DEBUG(10, ("Filter: [%s]", filter));
1234         } else {
1235                 bidx = 0;
1236                 idx = 1;
1237         }
1238
1239         rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
1240                 filter, attr_list, 0, &result);
1241
1242         if (rc != LDAP_SUCCESS) {
1243                 DEBUG(3,("Failure looking up sids (%s)\n",
1244                          ldap_err2string(rc)));
1245                 ret = NT_STATUS_UNSUCCESSFUL;
1246                 goto done;
1247         }
1248
1249         count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
1250
1251         if (count == 0) {
1252                 DEBUG(10, ("NO SIDs found\n"));
1253         }
1254
1255         for (i = 0; i < count; i++) {
1256                 char *sidstr = NULL;
1257                 char *tmp = NULL;
1258                 enum id_type type;
1259                 struct id_map *map;
1260                 DOM_SID sid;
1261                 uint32_t id;
1262
1263                 if (i == 0) { /* first entry */
1264                         entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
1265                                                  result);
1266                 } else { /* following ones */
1267                         entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
1268                                                 entry);
1269                 }
1270                 if ( ! entry) {
1271                         DEBUG(2, ("ERROR: Unable to fetch ldap entries "
1272                                   "from results\n"));
1273                         break;
1274                 }
1275
1276                 /* first check if the SID is present */
1277                 sidstr = smbldap_talloc_single_attribute(
1278                                 ctx->smbldap_state->ldap_struct,
1279                                 entry, LDAP_ATTRIBUTE_SID, memctx);
1280                 if ( ! sidstr) { /* no sid ??, skip entry */
1281                         DEBUG(2, ("WARNING SID not found on entry\n"));
1282                         continue;
1283                 }
1284
1285                 if ( ! string_to_sid(&sid, sidstr)) {
1286                         DEBUG(2, ("ERROR: Invalid SID on entry\n"));
1287                         TALLOC_FREE(sidstr);
1288                         continue;
1289                 }
1290
1291                 map = find_map_by_sid(&ids[bidx], &sid);
1292                 if (!map) {
1293                         DEBUG(2, ("WARNING: couldn't find entry sid (%s) "
1294                                   "in ids", sidstr));
1295                         TALLOC_FREE(sidstr);
1296                         continue;
1297                 }
1298
1299                 /* now try to see if it is a uid, if not try with a gid
1300                  * (gid is more common, but in case both uidNumber and
1301                  * gidNumber are returned the SID is mapped to the uid
1302                  * not the gid) */
1303                 type = ID_TYPE_UID;
1304                 tmp = smbldap_talloc_single_attribute(
1305                                 ctx->smbldap_state->ldap_struct,
1306                                 entry, uidNumber, memctx);
1307                 if ( ! tmp) {
1308                         type = ID_TYPE_GID;
1309                         tmp = smbldap_talloc_single_attribute(
1310                                         ctx->smbldap_state->ldap_struct,
1311                                         entry, gidNumber, memctx);
1312                 }
1313                 if ( ! tmp) { /* no ids ?? */
1314                         DEBUG(5, ("no uidNumber, "
1315                                   "nor gidNumber attributes found\n"));
1316                         TALLOC_FREE(sidstr);
1317                         continue;
1318                 }
1319
1320                 id = strtoul(tmp, NULL, 10);
1321                 if ((id == 0) ||
1322                     (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
1323                     (ctx->filter_high_id && (id > ctx->filter_high_id))) {
1324                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
1325                                   "Filtered!\n", id,
1326                                   ctx->filter_low_id, ctx->filter_high_id));
1327                         TALLOC_FREE(sidstr);
1328                         TALLOC_FREE(tmp);
1329                         continue;
1330                 }
1331                 TALLOC_FREE(tmp);
1332
1333                 if (map->status == ID_MAPPED) {
1334                         DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
1335                               "overwriting mapping %s -> %u with %s -> %u\n",
1336                               (type == ID_TYPE_UID) ? "UID" : "GID",
1337                               sidstr, map->xid.id, sidstr, id));
1338                 }
1339
1340                 TALLOC_FREE(sidstr);
1341
1342                 /* mapped */
1343                 map->xid.type = type;
1344                 map->xid.id = id;
1345                 map->status = ID_MAPPED;
1346
1347                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
1348                            (unsigned long)map->xid.id, map->xid.type));
1349         }
1350
1351         /* free the ldap results */
1352         if (result) {
1353                 ldap_msgfree(result);
1354                 result = NULL;
1355         }
1356
1357         if (multi && ids[idx]) { /* still some values to map */
1358                 goto again;
1359         }
1360
1361         ret = NT_STATUS_OK;
1362
1363         /* mark all unknwon/expired ones as unmapped */
1364         for (i = 0; ids[i]; i++) {
1365                 if (ids[i]->status != ID_MAPPED)
1366                         ids[i]->status = ID_UNMAPPED;
1367         }
1368
1369 done:
1370         talloc_free(memctx);
1371         return ret;
1372 }
1373
1374 /**********************************
1375  set a mapping.
1376 **********************************/
1377
1378 /* TODO: change this:  This function cannot be called to modify a mapping,
1379  * only set a new one */
1380
1381 static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
1382                                        const struct id_map *map)
1383 {
1384         NTSTATUS ret;
1385         TALLOC_CTX *memctx;
1386         struct idmap_ldap_context *ctx;
1387         LDAPMessage *entry = NULL;
1388         LDAPMod **mods = NULL;
1389         const char *type;
1390         char *id_str;
1391         char *sid;
1392         char *dn;
1393         int rc = -1;
1394
1395         /* Only do query if we are online */
1396         if (idmap_is_offline()) {
1397                 return NT_STATUS_FILE_IS_OFFLINE;
1398         }
1399
1400         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
1401
1402         switch(map->xid.type) {
1403         case ID_TYPE_UID:
1404                 type = get_attr_key2string(sidmap_attr_list,
1405                                            LDAP_ATTR_UIDNUMBER);
1406                 break;
1407
1408         case ID_TYPE_GID:
1409                 type = get_attr_key2string(sidmap_attr_list,
1410                                            LDAP_ATTR_GIDNUMBER);
1411                 break;
1412
1413         default:
1414                 return NT_STATUS_INVALID_PARAMETER;
1415         }
1416
1417         memctx = talloc_new(ctx);
1418         if ( ! memctx) {
1419                 DEBUG(0, ("Out of memory!\n"));
1420                 return NT_STATUS_NO_MEMORY;
1421         }
1422
1423         id_str = talloc_asprintf(memctx, "%lu", (unsigned long)map->xid.id);
1424         CHECK_ALLOC_DONE(id_str);
1425
1426         sid = talloc_strdup(memctx, sid_string_talloc(memctx, map->sid));
1427         CHECK_ALLOC_DONE(sid);
1428
1429         dn = talloc_asprintf(memctx, "%s=%s,%s",
1430                         get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
1431                         sid,
1432                         ctx->suffix);
1433         CHECK_ALLOC_DONE(dn);
1434
1435         smbldap_set_mod(&mods, LDAP_MOD_ADD,
1436                         "objectClass", LDAP_OBJ_IDMAP_ENTRY);
1437
1438         smbldap_make_mod(ctx->smbldap_state->ldap_struct,
1439                          entry, &mods, type, id_str);
1440
1441         smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods,
1442                          get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
1443                          sid);
1444
1445         if ( ! mods) {
1446                 DEBUG(2, ("ERROR: No mods?\n"));
1447                 ret = NT_STATUS_UNSUCCESSFUL;
1448                 goto done;
1449         }
1450
1451         /* TODO: remove conflicting mappings! */
1452
1453         smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY);
1454
1455         DEBUG(10, ("Set DN %s (%s -> %s)\n", dn, sid, id_str));
1456
1457         rc = smbldap_add(ctx->smbldap_state, dn, mods);
1458         ldap_mods_free(mods, True);
1459
1460         if (rc != LDAP_SUCCESS) {
1461                 char *ld_error = NULL;
1462                 ldap_get_option(ctx->smbldap_state->ldap_struct,
1463                                 LDAP_OPT_ERROR_STRING, &ld_error);
1464                 DEBUG(0,("ldap_set_mapping_internals: Failed to add %s to %lu "
1465                          "mapping [%s]\n", sid,
1466                          (unsigned long)map->xid.id, type));
1467                 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
1468                         ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
1469                 if (ld_error) {
1470                         ldap_memfree(ld_error);
1471                 }
1472                 ret = NT_STATUS_UNSUCCESSFUL;
1473                 goto done;
1474         }
1475
1476         DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to "
1477                   "%lu [%s]\n", sid, (unsigned long)map->xid.id, type));
1478
1479         ret = NT_STATUS_OK;
1480
1481 done:
1482         talloc_free(memctx);
1483         return ret;
1484 }
1485
1486 /**********************************
1487  Close the idmap ldap instance
1488 **********************************/
1489
1490 static NTSTATUS idmap_ldap_close(struct idmap_domain *dom)
1491 {
1492         struct idmap_ldap_context *ctx;
1493
1494         if (dom->private_data) {
1495                 ctx = talloc_get_type(dom->private_data,
1496                                       struct idmap_ldap_context);
1497
1498                 talloc_free(ctx);
1499                 dom->private_data = NULL;
1500         }
1501
1502         return NT_STATUS_OK;
1503 }
1504
1505 static struct idmap_methods idmap_ldap_methods = {
1506
1507         .init = idmap_ldap_db_init,
1508         .unixids_to_sids = idmap_ldap_unixids_to_sids,
1509         .sids_to_unixids = idmap_ldap_sids_to_unixids,
1510         .set_mapping = idmap_ldap_set_mapping,
1511         .close_fn = idmap_ldap_close
1512 };
1513
1514 static struct idmap_alloc_methods idmap_ldap_alloc_methods = {
1515
1516         .init = idmap_ldap_alloc_init,
1517         .allocate_id = idmap_ldap_allocate_id,
1518         .get_id_hwm = idmap_ldap_get_hwm,
1519         .set_id_hwm = idmap_ldap_set_hwm,
1520         .close_fn = idmap_ldap_alloc_close,
1521         /* .dump_data = TODO */
1522 };
1523
1524 static NTSTATUS idmap_alloc_ldap_init(void)
1525 {
1526         return smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "ldap",
1527                                         &idmap_ldap_alloc_methods);
1528 }
1529
1530 NTSTATUS idmap_ldap_init(void);
1531 NTSTATUS idmap_ldap_init(void)
1532 {
1533         NTSTATUS ret;
1534
1535         /* FIXME: bad hack to actually register also the alloc_ldap module
1536          * without changining configure.in */
1537         ret = idmap_alloc_ldap_init();
1538         if (! NT_STATUS_IS_OK(ret)) {
1539                 return ret;
1540         }
1541         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap",
1542                                   &idmap_ldap_methods);
1543 }
1544