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