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