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