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