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