s3:idmap_ldap: use ranges from idmap domain in idmap_ldap_allocate_id()
[metze/samba/wip.git] / source3 / winbindd / idmap_ldap.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    idmap LDAP backend
5
6    Copyright (C) Tim Potter             2000
7    Copyright (C) Jim McDonough <jmcd@us.ibm.com>        2003
8    Copyright (C) Gerald Carter          2003
9    Copyright (C) Simo Sorce             2003-2007
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "winbindd.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_IDMAP
30
31 #include <lber.h>
32 #include <ldap.h>
33
34 #include "smbldap.h"
35
36 static char *idmap_fetch_secret(const char *backend, bool alloc,
37                                 const char *domain, const char *identity)
38 {
39         char *tmp, *ret;
40         int r;
41
42         if (alloc) {
43                 r = asprintf(&tmp, "IDMAP_ALLOC_%s", backend);
44         } else {
45                 r = asprintf(&tmp, "IDMAP_%s_%s", backend, domain);
46         }
47
48         if (r < 0)
49                 return NULL;
50
51         strupper_m(tmp); /* make sure the key is case insensitive */
52         ret = secrets_fetch_generic(tmp, identity);
53
54         SAFE_FREE(tmp);
55
56         return ret;
57 }
58
59 struct idmap_ldap_context {
60         struct smbldap_state *smbldap_state;
61         char *url;
62         char *suffix;
63         char *user_dn;
64         bool anon;
65 };
66
67 struct idmap_ldap_alloc_context {
68         struct smbldap_state *smbldap_state;
69         char *url;
70         char *suffix;
71         char *user_dn;
72         uid_t low_uid, high_uid;      /* Range of uids */
73         gid_t low_gid, high_gid;      /* Range of gids */
74
75 };
76
77 #define CHECK_ALLOC_DONE(mem) do { \
78         if (!mem) { \
79                 DEBUG(0, ("Out of memory!\n")); \
80                 ret = NT_STATUS_NO_MEMORY; \
81                 goto done; \
82         } } while (0)
83
84 /**********************************************************************
85  IDMAP ALLOC TDB BACKEND
86 **********************************************************************/
87
88 static struct idmap_ldap_alloc_context *idmap_alloc_ldap;
89
90 /*********************************************************************
91  ********************************************************************/
92
93 static NTSTATUS get_credentials( TALLOC_CTX *mem_ctx,
94                                  struct smbldap_state *ldap_state,
95                                  const char *config_option,
96                                  struct idmap_domain *dom,
97                                  char **dn )
98 {
99         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
100         char *secret = NULL;
101         const char *tmp = NULL;
102         char *user_dn = NULL;
103         bool anon = False;
104
105         /* assume anonymous if we don't have a specified user */
106
107         tmp = lp_parm_const_string(-1, config_option, "ldap_user_dn", NULL);
108
109         if ( tmp ) {
110                 if (!dom) {
111                         /* only the alloc backend can pass in a NULL dom */
112                         secret = idmap_fetch_secret("ldap", True,
113                                                     NULL, tmp);
114                 } else {
115                         secret = idmap_fetch_secret("ldap", False,
116                                                     dom->name, tmp);
117                 }
118
119                 if (!secret) {
120                         DEBUG(0, ("get_credentials: Unable to fetch "
121                                   "auth credentials for %s in %s\n",
122                                   tmp, (dom==NULL)?"ALLOC":dom->name));
123                         ret = NT_STATUS_ACCESS_DENIED;
124                         goto done;
125                 }
126                 *dn = talloc_strdup(mem_ctx, tmp);
127                 CHECK_ALLOC_DONE(*dn);
128         } else {
129                 if (!fetch_ldap_pw(&user_dn, &secret)) {
130                         DEBUG(2, ("get_credentials: Failed to lookup ldap "
131                                   "bind creds. Using anonymous connection.\n"));
132                         anon = True;
133                 } else {
134                         *dn = talloc_strdup(mem_ctx, user_dn);
135                         SAFE_FREE( user_dn );
136                         CHECK_ALLOC_DONE(*dn);
137                 }
138         }
139
140         smbldap_set_creds(ldap_state, anon, *dn, secret);
141         ret = NT_STATUS_OK;
142
143 done:
144         SAFE_FREE(secret);
145
146         return ret;
147 }
148
149
150 /**********************************************************************
151  Verify the sambaUnixIdPool entry in the directory.
152 **********************************************************************/
153
154 static NTSTATUS verify_idpool(struct idmap_domain *dom)
155 {
156         NTSTATUS ret;
157         TALLOC_CTX *ctx;
158         LDAPMessage *result = NULL;
159         LDAPMod **mods = NULL;
160         const char **attr_list;
161         char *filter;
162         int count;
163         int rc;
164
165         if ( ! idmap_alloc_ldap) {
166                 return NT_STATUS_UNSUCCESSFUL;
167         }
168
169         ctx = talloc_new(idmap_alloc_ldap);
170         if ( ! ctx) {
171                 DEBUG(0, ("Out of memory!\n"));
172                 return NT_STATUS_NO_MEMORY;
173         }
174
175         filter = talloc_asprintf(ctx, "(objectclass=%s)", LDAP_OBJ_IDPOOL);
176         CHECK_ALLOC_DONE(filter);
177
178         attr_list = get_attr_list(ctx, idpool_attr_list);
179         CHECK_ALLOC_DONE(attr_list);
180
181         rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
182                                 idmap_alloc_ldap->suffix,
183                                 LDAP_SCOPE_SUBTREE,
184                                 filter,
185                                 attr_list,
186                                 0,
187                                 &result);
188
189         if (rc != LDAP_SUCCESS) {
190                 DEBUG(1, ("Unable to verify the idpool, "
191                           "cannot continue initialization!\n"));
192                 return NT_STATUS_UNSUCCESSFUL;
193         }
194
195         count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
196                                    result);
197
198         ldap_msgfree(result);
199
200         if ( count > 1 ) {
201                 DEBUG(0,("Multiple entries returned from %s (base == %s)\n",
202                         filter, idmap_alloc_ldap->suffix));
203                 ret = NT_STATUS_UNSUCCESSFUL;
204                 goto done;
205         }
206         else if (count == 0) {
207                 char *uid_str, *gid_str;
208
209                 uid_str = talloc_asprintf(ctx, "%lu",
210                                 (unsigned long)dom->low_id);
211                 gid_str = talloc_asprintf(ctx, "%lu",
212                                 (unsigned long)dom->low_id);
213
214                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
215                                 "objectClass", LDAP_OBJ_IDPOOL);
216                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
217                                 get_attr_key2string(idpool_attr_list,
218                                                     LDAP_ATTR_UIDNUMBER),
219                                 uid_str);
220                 smbldap_set_mod(&mods, LDAP_MOD_ADD,
221                                 get_attr_key2string(idpool_attr_list,
222                                                     LDAP_ATTR_GIDNUMBER),
223                                 gid_str);
224                 if (mods) {
225                         rc = smbldap_modify(idmap_alloc_ldap->smbldap_state,
226                                                 idmap_alloc_ldap->suffix,
227                                                 mods);
228                         ldap_mods_free(mods, True);
229                 } else {
230                         ret = NT_STATUS_UNSUCCESSFUL;
231                         goto done;
232                 }
233         }
234
235         ret = (rc == LDAP_SUCCESS)?NT_STATUS_OK:NT_STATUS_UNSUCCESSFUL;
236 done:
237         talloc_free(ctx);
238         return ret;
239 }
240
241 /*****************************************************************************
242  Initialise idmap database.
243 *****************************************************************************/
244
245 static NTSTATUS idmap_ldap_alloc_init(struct idmap_domain *dom,
246                                       const char *params)
247 {
248         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
249         const char *tmp;
250
251         /* Only do init if we are online */
252         if (idmap_is_offline()) {
253                 return NT_STATUS_FILE_IS_OFFLINE;
254         }
255
256         idmap_alloc_ldap = TALLOC_ZERO_P(NULL, struct idmap_ldap_alloc_context);
257         CHECK_ALLOC_DONE( idmap_alloc_ldap );
258
259         if (params && *params) {
260                 /* assume location is the only parameter */
261                 idmap_alloc_ldap->url = talloc_strdup(idmap_alloc_ldap, params);
262         } else {
263                 tmp = lp_parm_const_string(-1, "idmap alloc config",
264                                            "ldap_url", NULL);
265
266                 if ( ! tmp) {
267                         DEBUG(1, ("ERROR: missing idmap ldap url\n"));
268                         ret = NT_STATUS_UNSUCCESSFUL;
269                         goto done;
270                 }
271
272                 idmap_alloc_ldap->url = talloc_strdup(idmap_alloc_ldap, tmp);
273         }
274         CHECK_ALLOC_DONE( idmap_alloc_ldap->url );
275
276         trim_char(idmap_alloc_ldap->url, '\"', '\"');
277
278         tmp = lp_parm_const_string(-1, "idmap alloc config",
279                                    "ldap_base_dn", NULL);
280         if ( ! tmp || ! *tmp) {
281                 tmp = lp_ldap_idmap_suffix();
282                 if ( ! tmp) {
283                         DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
284                         ret = NT_STATUS_UNSUCCESSFUL;
285                         goto done;
286                 }
287         }
288
289         idmap_alloc_ldap->suffix = talloc_strdup(idmap_alloc_ldap, tmp);
290         CHECK_ALLOC_DONE( idmap_alloc_ldap->suffix );
291
292         ret = smbldap_init(idmap_alloc_ldap, winbind_event_context(),
293                            idmap_alloc_ldap->url,
294                            &idmap_alloc_ldap->smbldap_state);
295         if (!NT_STATUS_IS_OK(ret)) {
296                 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n",
297                           idmap_alloc_ldap->url));
298                 goto done;
299         }
300
301         ret = get_credentials( idmap_alloc_ldap,
302                                idmap_alloc_ldap->smbldap_state,
303                                "idmap alloc config", NULL,
304                                &idmap_alloc_ldap->user_dn );
305         if ( !NT_STATUS_IS_OK(ret) ) {
306                 DEBUG(1,("idmap_ldap_alloc_init: Failed to get connection "
307                          "credentials (%s)\n", nt_errstr(ret)));
308                 goto done;
309         }
310
311         /* see if the idmap suffix and sub entries exists */
312
313         ret = verify_idpool(dom);
314
315  done:
316         if ( !NT_STATUS_IS_OK( ret ) )
317                 TALLOC_FREE( idmap_alloc_ldap );
318
319         return ret;
320 }
321
322 /********************************
323  Allocate a new uid or gid
324 ********************************/
325
326 static NTSTATUS idmap_ldap_allocate_id(struct idmap_domain *dom,
327                                        struct unixid *xid)
328 {
329         TALLOC_CTX *ctx;
330         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
331         int rc = LDAP_SERVER_DOWN;
332         int count = 0;
333         LDAPMessage *result = NULL;
334         LDAPMessage *entry = NULL;
335         LDAPMod **mods = NULL;
336         char *id_str;
337         char *new_id_str;
338         char *filter = NULL;
339         const char *dn = NULL;
340         const char **attr_list;
341         const char *type;
342
343         /* Only do query if we are online */
344         if (idmap_is_offline()) {
345                 return NT_STATUS_FILE_IS_OFFLINE;
346         }
347
348         if ( ! idmap_alloc_ldap) {
349                 return NT_STATUS_UNSUCCESSFUL;
350         }
351
352         ctx = talloc_new(idmap_alloc_ldap);
353         if ( ! ctx) {
354                 DEBUG(0, ("Out of memory!\n"));
355                 return NT_STATUS_NO_MEMORY;
356         }
357
358         /* get type */
359         switch (xid->type) {
360
361         case ID_TYPE_UID:
362                 type = get_attr_key2string(idpool_attr_list,
363                                            LDAP_ATTR_UIDNUMBER);
364                 break;
365
366         case ID_TYPE_GID:
367                 type = get_attr_key2string(idpool_attr_list,
368                                            LDAP_ATTR_GIDNUMBER);
369                 break;
370
371         default:
372                 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
373                 return NT_STATUS_INVALID_PARAMETER;
374         }
375
376         filter = talloc_asprintf(ctx, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
377         CHECK_ALLOC_DONE(filter);
378
379         attr_list = get_attr_list(ctx, idpool_attr_list);
380         CHECK_ALLOC_DONE(attr_list);
381
382         DEBUG(10, ("Search of the id pool (filter: %s)\n", filter));
383
384         rc = smbldap_search(idmap_alloc_ldap->smbldap_state,
385                                 idmap_alloc_ldap->suffix,
386                                LDAP_SCOPE_SUBTREE, filter,
387                                attr_list, 0, &result);
388
389         if (rc != LDAP_SUCCESS) {
390                 DEBUG(0,("%s object not found\n", LDAP_OBJ_IDPOOL));
391                 goto done;
392         }
393
394         talloc_autofree_ldapmsg(ctx, result);
395
396         count = ldap_count_entries(idmap_alloc_ldap->smbldap_state->ldap_struct,
397                                    result);
398         if (count != 1) {
399                 DEBUG(0,("Single %s object not found\n", LDAP_OBJ_IDPOOL));
400                 goto done;
401         }
402
403         entry = ldap_first_entry(idmap_alloc_ldap->smbldap_state->ldap_struct,
404                                  result);
405
406         dn = smbldap_talloc_dn(ctx,
407                                idmap_alloc_ldap->smbldap_state->ldap_struct,
408                                entry);
409         if ( ! dn) {
410                 goto done;
411         }
412
413         if ( ! (id_str = smbldap_talloc_single_attribute(idmap_alloc_ldap->smbldap_state->ldap_struct,
414                                 entry, type, ctx))) {
415                 DEBUG(0,("%s attribute not found\n", type));
416                 goto done;
417         }
418         if ( ! id_str) {
419                 DEBUG(0,("Out of memory\n"));
420                 ret = NT_STATUS_NO_MEMORY;
421                 goto done;
422         }
423
424         xid->id = strtoul(id_str, NULL, 10);
425
426         /* make sure we still have room to grow */
427
428         switch (xid->type) {
429         case ID_TYPE_UID:
430                 if (xid->id > dom->high_id) {
431                         DEBUG(0,("Cannot allocate uid above %lu!\n",
432                                  (unsigned long)dom->high_id));
433                         goto done;
434                 }
435                 break;
436
437         case ID_TYPE_GID:
438                 if (xid->id > dom->high_id) {
439                         DEBUG(0,("Cannot allocate gid above %lu!\n",
440                                  (unsigned long)dom->high_id));
441                         goto done;
442                 }
443                 break;
444
445         default:
446                 /* impossible */
447                 goto done;
448         }
449
450         new_id_str = talloc_asprintf(ctx, "%lu", (unsigned long)xid->id + 1);
451         if ( ! new_id_str) {
452                 DEBUG(0,("Out of memory\n"));
453                 ret = NT_STATUS_NO_MEMORY;
454                 goto done;
455         }
456
457         smbldap_set_mod(&mods, LDAP_MOD_DELETE, type, id_str);
458         smbldap_set_mod(&mods, LDAP_MOD_ADD, type, new_id_str);
459
460         if (mods == NULL) {
461                 DEBUG(0,("smbldap_set_mod() failed.\n"));
462                 goto done;
463         }
464
465         DEBUG(10, ("Try to atomically increment the id (%s -> %s)\n",
466                    id_str, new_id_str));
467
468         rc = smbldap_modify(idmap_alloc_ldap->smbldap_state, dn, mods);
469
470         ldap_mods_free(mods, True);
471
472         if (rc != LDAP_SUCCESS) {
473                 DEBUG(1,("Failed to allocate new %s. "
474                          "smbldap_modify() failed.\n", type));
475                 goto done;
476         }
477
478         ret = NT_STATUS_OK;
479
480 done:
481         talloc_free(ctx);
482         return ret;
483 }
484
485 /**********************************
486  Close idmap ldap alloc
487 **********************************/
488
489 static NTSTATUS idmap_ldap_alloc_close(void)
490 {
491         if (idmap_alloc_ldap) {
492                 smbldap_free_struct(&idmap_alloc_ldap->smbldap_state);
493                 DEBUG(5,("The connection to the LDAP server was closed\n"));
494                 /* maybe free the results here --metze */
495                 TALLOC_FREE(idmap_alloc_ldap);
496         }
497         return NT_STATUS_OK;
498 }
499
500
501 /**********************************************************************
502  IDMAP MAPPING LDAP BACKEND
503 **********************************************************************/
504
505 static int idmap_ldap_close_destructor(struct idmap_ldap_context *ctx)
506 {
507         smbldap_free_struct(&ctx->smbldap_state);
508         DEBUG(5,("The connection to the LDAP server was closed\n"));
509         /* maybe free the results here --metze */
510
511         return 0;
512 }
513
514 /********************************
515  Initialise idmap database.
516 ********************************/
517
518 static NTSTATUS idmap_ldap_db_init(struct idmap_domain *dom,
519                                    const char *params)
520 {
521         NTSTATUS ret;
522         struct idmap_ldap_context *ctx = NULL;
523         char *config_option = NULL;
524         const char *tmp = NULL;
525
526         /* Only do init if we are online */
527         if (idmap_is_offline()) {
528                 return NT_STATUS_FILE_IS_OFFLINE;
529         }
530
531         ctx = TALLOC_ZERO_P(dom, struct idmap_ldap_context);
532         if ( ! ctx) {
533                 DEBUG(0, ("Out of memory!\n"));
534                 return NT_STATUS_NO_MEMORY;
535         }
536
537         if (strequal(dom->name, "*")) {
538                 /* more specific configuration can go here */
539         } else {
540                 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
541                 if ( ! config_option) {
542                         DEBUG(0, ("Out of memory!\n"));
543                         ret = NT_STATUS_NO_MEMORY;
544                         goto done;
545                 }
546         }
547
548         if (params != NULL) {
549                 /* assume location is the only parameter */
550                 ctx->url = talloc_strdup(ctx, params);
551         } else {
552                 tmp = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
553
554                 if ( ! tmp) {
555                         DEBUG(1, ("ERROR: missing idmap ldap url\n"));
556                         ret = NT_STATUS_UNSUCCESSFUL;
557                         goto done;
558                 }
559
560                 ctx->url = talloc_strdup(ctx, tmp);
561         }
562         CHECK_ALLOC_DONE(ctx->url);
563
564         trim_char(ctx->url, '\"', '\"');
565
566         tmp = lp_parm_const_string(-1, config_option, "ldap_base_dn", NULL);
567         if ( ! tmp || ! *tmp) {
568                 tmp = lp_ldap_idmap_suffix();
569                 if ( ! tmp) {
570                         DEBUG(1, ("ERROR: missing idmap ldap suffix\n"));
571                         ret = NT_STATUS_UNSUCCESSFUL;
572                         goto done;
573                 }
574         }
575
576         ctx->suffix = talloc_strdup(ctx, tmp);
577         CHECK_ALLOC_DONE(ctx->suffix);
578
579         ret = smbldap_init(ctx, winbind_event_context(), ctx->url,
580                            &ctx->smbldap_state);
581         if (!NT_STATUS_IS_OK(ret)) {
582                 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", ctx->url));
583                 goto done;
584         }
585
586         ret = get_credentials( ctx, ctx->smbldap_state, config_option,
587                                dom, &ctx->user_dn );
588         if ( !NT_STATUS_IS_OK(ret) ) {
589                 DEBUG(1,("idmap_ldap_db_init: Failed to get connection "
590                          "credentials (%s)\n", nt_errstr(ret)));
591                 goto done;
592         }
593
594         /* set the destructor on the context, so that resource are properly
595            freed if the contexts is released */
596
597         talloc_set_destructor(ctx, idmap_ldap_close_destructor);
598
599         dom->private_data = ctx;
600
601         talloc_free(config_option);
602         return NT_STATUS_OK;
603
604 /*failed */
605 done:
606         talloc_free(ctx);
607         return ret;
608 }
609
610 /* max number of ids requested per batch query */
611 #define IDMAP_LDAP_MAX_IDS 30
612
613 /**********************************
614  lookup a set of unix ids.
615 **********************************/
616
617 /* this function searches up to IDMAP_LDAP_MAX_IDS entries
618  * in maps for a match */
619 static struct id_map *find_map_by_id(struct id_map **maps,
620                                      enum id_type type,
621                                      uint32_t id)
622 {
623         int i;
624
625         for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
626                 if (maps[i] == NULL) { /* end of the run */
627                         return NULL;
628                 }
629                 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
630                         return maps[i];
631                 }
632         }
633
634         return NULL;
635 }
636
637 static NTSTATUS idmap_ldap_unixids_to_sids(struct idmap_domain *dom,
638                                            struct id_map **ids)
639 {
640         NTSTATUS ret;
641         TALLOC_CTX *memctx;
642         struct idmap_ldap_context *ctx;
643         LDAPMessage *result = NULL;
644         LDAPMessage *entry = NULL;
645         const char *uidNumber;
646         const char *gidNumber;
647         const char **attr_list;
648         char *filter = NULL;
649         bool multi = False;
650         int idx = 0;
651         int bidx = 0;
652         int count;
653         int rc;
654         int i;
655
656         /* Only do query if we are online */
657         if (idmap_is_offline()) {
658                 return NT_STATUS_FILE_IS_OFFLINE;
659         }
660
661         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
662
663         memctx = talloc_new(ctx);
664         if ( ! memctx) {
665                 DEBUG(0, ("Out of memory!\n"));
666                 return NT_STATUS_NO_MEMORY;
667         }
668
669         uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
670         gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
671
672         attr_list = get_attr_list(memctx, sidmap_attr_list);
673
674         if ( ! ids[1]) {
675                 /* if we are requested just one mapping use the simple filter */
676
677                 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%lu))",
678                                 LDAP_OBJ_IDMAP_ENTRY,
679                                 (ids[0]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
680                                 (unsigned long)ids[0]->xid.id);
681                 CHECK_ALLOC_DONE(filter);
682                 DEBUG(10, ("Filter: [%s]\n", filter));
683         } else {
684                 /* multiple mappings */
685                 multi = True;
686         }
687
688         for (i = 0; ids[i]; i++) {
689                 ids[i]->status = ID_UNKNOWN;
690         }
691
692 again:
693         if (multi) {
694
695                 talloc_free(filter);
696                 filter = talloc_asprintf(memctx,
697                                          "(&(objectClass=%s)(|",
698                                          LDAP_OBJ_IDMAP_ENTRY);
699                 CHECK_ALLOC_DONE(filter);
700
701                 bidx = idx;
702                 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
703                         filter = talloc_asprintf_append_buffer(filter, "(%s=%lu)",
704                                         (ids[idx]->xid.type==ID_TYPE_UID)?uidNumber:gidNumber,
705                                         (unsigned long)ids[idx]->xid.id);
706                         CHECK_ALLOC_DONE(filter);
707                 }
708                 filter = talloc_asprintf_append_buffer(filter, "))");
709                 CHECK_ALLOC_DONE(filter);
710                 DEBUG(10, ("Filter: [%s]\n", filter));
711         } else {
712                 bidx = 0;
713                 idx = 1;
714         }
715
716         rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
717                 filter, attr_list, 0, &result);
718
719         if (rc != LDAP_SUCCESS) {
720                 DEBUG(3,("Failure looking up ids (%s)\n", ldap_err2string(rc)));
721                 ret = NT_STATUS_UNSUCCESSFUL;
722                 goto done;
723         }
724
725         count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
726
727         if (count == 0) {
728                 DEBUG(10, ("NO SIDs found\n"));
729         }
730
731         for (i = 0; i < count; i++) {
732                 char *sidstr = NULL;
733                 char *tmp = NULL;
734                 enum id_type type;
735                 struct id_map *map;
736                 uint32_t id;
737
738                 if (i == 0) { /* first entry */
739                         entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
740                                                  result);
741                 } else { /* following ones */
742                         entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
743                                                 entry);
744                 }
745                 if ( ! entry) {
746                         DEBUG(2, ("ERROR: Unable to fetch ldap entries "
747                                   "from results\n"));
748                         break;
749                 }
750
751                 /* first check if the SID is present */
752                 sidstr = smbldap_talloc_single_attribute(
753                                 ctx->smbldap_state->ldap_struct,
754                                 entry, LDAP_ATTRIBUTE_SID, memctx);
755                 if ( ! sidstr) { /* no sid, skip entry */
756                         DEBUG(2, ("WARNING SID not found on entry\n"));
757                         continue;
758                 }
759
760                 /* now try to see if it is a uid, if not try with a gid
761                  * (gid is more common, but in case both uidNumber and
762                  * gidNumber are returned the SID is mapped to the uid
763                  *not the gid) */
764                 type = ID_TYPE_UID;
765                 tmp = smbldap_talloc_single_attribute(
766                                 ctx->smbldap_state->ldap_struct,
767                                 entry, uidNumber, memctx);
768                 if ( ! tmp) {
769                         type = ID_TYPE_GID;
770                         tmp = smbldap_talloc_single_attribute(
771                                         ctx->smbldap_state->ldap_struct,
772                                         entry, gidNumber, memctx);
773                 }
774                 if ( ! tmp) { /* wow very strange entry, how did it match ? */
775                         DEBUG(5, ("Unprobable match on (%s), no uidNumber, "
776                                   "nor gidNumber returned\n", sidstr));
777                         TALLOC_FREE(sidstr);
778                         continue;
779                 }
780
781                 id = strtoul(tmp, NULL, 10);
782                 if (!idmap_unix_id_is_in_range(id, dom)) {
783                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
784                                   "Filtered!\n", id,
785                                   dom->low_id, dom->high_id));
786                         TALLOC_FREE(sidstr);
787                         TALLOC_FREE(tmp);
788                         continue;
789                 }
790                 TALLOC_FREE(tmp);
791
792                 map = find_map_by_id(&ids[bidx], type, id);
793                 if (!map) {
794                         DEBUG(2, ("WARNING: couldn't match sid (%s) "
795                                   "with requested ids\n", sidstr));
796                         TALLOC_FREE(sidstr);
797                         continue;
798                 }
799
800                 if ( ! string_to_sid(map->sid, sidstr)) {
801                         DEBUG(2, ("ERROR: Invalid SID on entry\n"));
802                         TALLOC_FREE(sidstr);
803                         continue;
804                 }
805
806                 if (map->status == ID_MAPPED) {
807                         DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
808                               "overwriting mapping %u -> %s with %u -> %s\n",
809                               (type == ID_TYPE_UID) ? "UID" : "GID",
810                               id, sid_string_dbg(map->sid), id, sidstr));
811                 }
812
813                 TALLOC_FREE(sidstr);
814
815                 /* mapped */
816                 map->status = ID_MAPPED;
817
818                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
819                            (unsigned long)map->xid.id, map->xid.type));
820         }
821
822         /* free the ldap results */
823         if (result) {
824                 ldap_msgfree(result);
825                 result = NULL;
826         }
827
828         if (multi && ids[idx]) { /* still some values to map */
829                 goto again;
830         }
831
832         ret = NT_STATUS_OK;
833
834         /* mark all unknwon/expired ones as unmapped */
835         for (i = 0; ids[i]; i++) {
836                 if (ids[i]->status != ID_MAPPED)
837                         ids[i]->status = ID_UNMAPPED;
838         }
839
840 done:
841         talloc_free(memctx);
842         return ret;
843 }
844
845 /**********************************
846  lookup a set of sids.
847 **********************************/
848
849 /* this function searches up to IDMAP_LDAP_MAX_IDS entries
850  * in maps for a match */
851 static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
852 {
853         int i;
854
855         for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
856                 if (maps[i] == NULL) { /* end of the run */
857                         return NULL;
858                 }
859                 if (sid_equal(maps[i]->sid, sid)) {
860                         return maps[i];
861                 }
862         }
863
864         return NULL;
865 }
866
867 static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom,
868                                            struct id_map **ids)
869 {
870         LDAPMessage *entry = NULL;
871         NTSTATUS ret;
872         TALLOC_CTX *memctx;
873         struct idmap_ldap_context *ctx;
874         LDAPMessage *result = NULL;
875         const char *uidNumber;
876         const char *gidNumber;
877         const char **attr_list;
878         char *filter = NULL;
879         bool multi = False;
880         int idx = 0;
881         int bidx = 0;
882         int count;
883         int rc;
884         int i;
885
886         /* Only do query if we are online */
887         if (idmap_is_offline()) {
888                 return NT_STATUS_FILE_IS_OFFLINE;
889         }
890
891         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
892
893         memctx = talloc_new(ctx);
894         if ( ! memctx) {
895                 DEBUG(0, ("Out of memory!\n"));
896                 return NT_STATUS_NO_MEMORY;
897         }
898
899         uidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER);
900         gidNumber = get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER);
901
902         attr_list = get_attr_list(memctx, sidmap_attr_list);
903
904         if ( ! ids[1]) {
905                 /* if we are requested just one mapping use the simple filter */
906
907                 filter = talloc_asprintf(memctx, "(&(objectClass=%s)(%s=%s))",
908                                 LDAP_OBJ_IDMAP_ENTRY,
909                                 LDAP_ATTRIBUTE_SID,
910                                 sid_string_talloc(memctx, ids[0]->sid));
911                 CHECK_ALLOC_DONE(filter);
912                 DEBUG(10, ("Filter: [%s]\n", filter));
913         } else {
914                 /* multiple mappings */
915                 multi = True;
916         }
917
918         for (i = 0; ids[i]; i++) {
919                 ids[i]->status = ID_UNKNOWN;
920         }
921
922 again:
923         if (multi) {
924
925                 TALLOC_FREE(filter);
926                 filter = talloc_asprintf(memctx,
927                                          "(&(objectClass=%s)(|",
928                                          LDAP_OBJ_IDMAP_ENTRY);
929                 CHECK_ALLOC_DONE(filter);
930
931                 bidx = idx;
932                 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
933                         filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
934                                         LDAP_ATTRIBUTE_SID,
935                                         sid_string_talloc(memctx,
936                                                           ids[idx]->sid));
937                         CHECK_ALLOC_DONE(filter);
938                 }
939                 filter = talloc_asprintf_append_buffer(filter, "))");
940                 CHECK_ALLOC_DONE(filter);
941                 DEBUG(10, ("Filter: [%s]", filter));
942         } else {
943                 bidx = 0;
944                 idx = 1;
945         }
946
947         rc = smbldap_search(ctx->smbldap_state, ctx->suffix, LDAP_SCOPE_SUBTREE,
948                 filter, attr_list, 0, &result);
949
950         if (rc != LDAP_SUCCESS) {
951                 DEBUG(3,("Failure looking up sids (%s)\n",
952                          ldap_err2string(rc)));
953                 ret = NT_STATUS_UNSUCCESSFUL;
954                 goto done;
955         }
956
957         count = ldap_count_entries(ctx->smbldap_state->ldap_struct, result);
958
959         if (count == 0) {
960                 DEBUG(10, ("NO SIDs found\n"));
961         }
962
963         for (i = 0; i < count; i++) {
964                 char *sidstr = NULL;
965                 char *tmp = NULL;
966                 enum id_type type;
967                 struct id_map *map;
968                 DOM_SID sid;
969                 uint32_t id;
970
971                 if (i == 0) { /* first entry */
972                         entry = ldap_first_entry(ctx->smbldap_state->ldap_struct,
973                                                  result);
974                 } else { /* following ones */
975                         entry = ldap_next_entry(ctx->smbldap_state->ldap_struct,
976                                                 entry);
977                 }
978                 if ( ! entry) {
979                         DEBUG(2, ("ERROR: Unable to fetch ldap entries "
980                                   "from results\n"));
981                         break;
982                 }
983
984                 /* first check if the SID is present */
985                 sidstr = smbldap_talloc_single_attribute(
986                                 ctx->smbldap_state->ldap_struct,
987                                 entry, LDAP_ATTRIBUTE_SID, memctx);
988                 if ( ! sidstr) { /* no sid ??, skip entry */
989                         DEBUG(2, ("WARNING SID not found on entry\n"));
990                         continue;
991                 }
992
993                 if ( ! string_to_sid(&sid, sidstr)) {
994                         DEBUG(2, ("ERROR: Invalid SID on entry\n"));
995                         TALLOC_FREE(sidstr);
996                         continue;
997                 }
998
999                 map = find_map_by_sid(&ids[bidx], &sid);
1000                 if (!map) {
1001                         DEBUG(2, ("WARNING: couldn't find entry sid (%s) "
1002                                   "in ids", sidstr));
1003                         TALLOC_FREE(sidstr);
1004                         continue;
1005                 }
1006
1007                 /* now try to see if it is a uid, if not try with a gid
1008                  * (gid is more common, but in case both uidNumber and
1009                  * gidNumber are returned the SID is mapped to the uid
1010                  * not the gid) */
1011                 type = ID_TYPE_UID;
1012                 tmp = smbldap_talloc_single_attribute(
1013                                 ctx->smbldap_state->ldap_struct,
1014                                 entry, uidNumber, memctx);
1015                 if ( ! tmp) {
1016                         type = ID_TYPE_GID;
1017                         tmp = smbldap_talloc_single_attribute(
1018                                         ctx->smbldap_state->ldap_struct,
1019                                         entry, gidNumber, memctx);
1020                 }
1021                 if ( ! tmp) { /* no ids ?? */
1022                         DEBUG(5, ("no uidNumber, "
1023                                   "nor gidNumber attributes found\n"));
1024                         TALLOC_FREE(sidstr);
1025                         continue;
1026                 }
1027
1028                 id = strtoul(tmp, NULL, 10);
1029                 if (!idmap_unix_id_is_in_range(id, dom)) {
1030                         DEBUG(5, ("Requested id (%u) out of range (%u - %u). "
1031                                   "Filtered!\n", id,
1032                                   dom->low_id, dom->high_id));
1033                         TALLOC_FREE(sidstr);
1034                         TALLOC_FREE(tmp);
1035                         continue;
1036                 }
1037                 TALLOC_FREE(tmp);
1038
1039                 if (map->status == ID_MAPPED) {
1040                         DEBUG(1, ("WARNING: duplicate %s mapping in LDAP. "
1041                               "overwriting mapping %s -> %u with %s -> %u\n",
1042                               (type == ID_TYPE_UID) ? "UID" : "GID",
1043                               sidstr, map->xid.id, sidstr, id));
1044                 }
1045
1046                 TALLOC_FREE(sidstr);
1047
1048                 /* mapped */
1049                 map->xid.type = type;
1050                 map->xid.id = id;
1051                 map->status = ID_MAPPED;
1052
1053                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
1054                            (unsigned long)map->xid.id, map->xid.type));
1055         }
1056
1057         /* free the ldap results */
1058         if (result) {
1059                 ldap_msgfree(result);
1060                 result = NULL;
1061         }
1062
1063         if (multi && ids[idx]) { /* still some values to map */
1064                 goto again;
1065         }
1066
1067         ret = NT_STATUS_OK;
1068
1069         /* mark all unknwon/expired ones as unmapped */
1070         for (i = 0; ids[i]; i++) {
1071                 if (ids[i]->status != ID_MAPPED)
1072                         ids[i]->status = ID_UNMAPPED;
1073         }
1074
1075 done:
1076         talloc_free(memctx);
1077         return ret;
1078 }
1079
1080 /**********************************
1081  set a mapping.
1082 **********************************/
1083
1084 /* TODO: change this:  This function cannot be called to modify a mapping,
1085  * only set a new one */
1086
1087 static NTSTATUS idmap_ldap_set_mapping(struct idmap_domain *dom,
1088                                        const struct id_map *map)
1089 {
1090         NTSTATUS ret;
1091         TALLOC_CTX *memctx;
1092         struct idmap_ldap_context *ctx;
1093         LDAPMessage *entry = NULL;
1094         LDAPMod **mods = NULL;
1095         const char *type;
1096         char *id_str;
1097         char *sid;
1098         char *dn;
1099         int rc = -1;
1100
1101         /* Only do query if we are online */
1102         if (idmap_is_offline()) {
1103                 return NT_STATUS_FILE_IS_OFFLINE;
1104         }
1105
1106         ctx = talloc_get_type(dom->private_data, struct idmap_ldap_context);
1107
1108         switch(map->xid.type) {
1109         case ID_TYPE_UID:
1110                 type = get_attr_key2string(sidmap_attr_list,
1111                                            LDAP_ATTR_UIDNUMBER);
1112                 break;
1113
1114         case ID_TYPE_GID:
1115                 type = get_attr_key2string(sidmap_attr_list,
1116                                            LDAP_ATTR_GIDNUMBER);
1117                 break;
1118
1119         default:
1120                 return NT_STATUS_INVALID_PARAMETER;
1121         }
1122
1123         memctx = talloc_new(ctx);
1124         if ( ! memctx) {
1125                 DEBUG(0, ("Out of memory!\n"));
1126                 return NT_STATUS_NO_MEMORY;
1127         }
1128
1129         id_str = talloc_asprintf(memctx, "%lu", (unsigned long)map->xid.id);
1130         CHECK_ALLOC_DONE(id_str);
1131
1132         sid = talloc_strdup(memctx, sid_string_talloc(memctx, map->sid));
1133         CHECK_ALLOC_DONE(sid);
1134
1135         dn = talloc_asprintf(memctx, "%s=%s,%s",
1136                         get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
1137                         sid,
1138                         ctx->suffix);
1139         CHECK_ALLOC_DONE(dn);
1140
1141         smbldap_set_mod(&mods, LDAP_MOD_ADD,
1142                         "objectClass", LDAP_OBJ_IDMAP_ENTRY);
1143
1144         smbldap_make_mod(ctx->smbldap_state->ldap_struct,
1145                          entry, &mods, type, id_str);
1146
1147         smbldap_make_mod(ctx->smbldap_state->ldap_struct, entry, &mods,
1148                          get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
1149                          sid);
1150
1151         if ( ! mods) {
1152                 DEBUG(2, ("ERROR: No mods?\n"));
1153                 ret = NT_STATUS_UNSUCCESSFUL;
1154                 goto done;
1155         }
1156
1157         /* TODO: remove conflicting mappings! */
1158
1159         smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY);
1160
1161         DEBUG(10, ("Set DN %s (%s -> %s)\n", dn, sid, id_str));
1162
1163         rc = smbldap_add(ctx->smbldap_state, dn, mods);
1164         ldap_mods_free(mods, True);
1165
1166         if (rc != LDAP_SUCCESS) {
1167                 char *ld_error = NULL;
1168                 ldap_get_option(ctx->smbldap_state->ldap_struct,
1169                                 LDAP_OPT_ERROR_STRING, &ld_error);
1170                 DEBUG(0,("ldap_set_mapping_internals: Failed to add %s to %lu "
1171                          "mapping [%s]\n", sid,
1172                          (unsigned long)map->xid.id, type));
1173                 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
1174                         ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
1175                 if (ld_error) {
1176                         ldap_memfree(ld_error);
1177                 }
1178                 ret = NT_STATUS_UNSUCCESSFUL;
1179                 goto done;
1180         }
1181
1182         DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to "
1183                   "%lu [%s]\n", sid, (unsigned long)map->xid.id, type));
1184
1185         ret = NT_STATUS_OK;
1186
1187 done:
1188         talloc_free(memctx);
1189         return ret;
1190 }
1191
1192 /**********************************
1193  Close the idmap ldap instance
1194 **********************************/
1195
1196 static NTSTATUS idmap_ldap_close(struct idmap_domain *dom)
1197 {
1198         struct idmap_ldap_context *ctx;
1199
1200         if (dom->private_data) {
1201                 ctx = talloc_get_type(dom->private_data,
1202                                       struct idmap_ldap_context);
1203
1204                 talloc_free(ctx);
1205                 dom->private_data = NULL;
1206         }
1207
1208         return NT_STATUS_OK;
1209 }
1210
1211 static struct idmap_methods idmap_ldap_methods = {
1212
1213         .init = idmap_ldap_db_init,
1214         .unixids_to_sids = idmap_ldap_unixids_to_sids,
1215         .sids_to_unixids = idmap_ldap_sids_to_unixids,
1216         .allocate_id = idmap_ldap_get_new_id,
1217         .close_fn = idmap_ldap_close
1218 };
1219
1220 NTSTATUS idmap_ldap_init(void);
1221 NTSTATUS idmap_ldap_init(void)
1222 {
1223         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap",
1224                                   &idmap_ldap_methods);
1225 }
1226