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