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