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