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