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