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