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