Merge branch 'master' of ctdb into 'master' of samba
[samba.git] / source3 / winbindd / idmap_rfc2307.c
1 /*
2  * Unix SMB/CIFS implementation.
3  *
4  * Id mapping using LDAP records as defined in RFC 2307
5  *
6  * The SID<->uid/gid mapping is performed in two steps: 1) Query the
7  * AD server for the name<->sid mapping. 2) Query an LDAP server
8  * according to RFC 2307 for the name<->uid/gid mapping.
9  *
10  * Copyright (C) Christof Schmitt 2012,2013
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 "ads.h"
29 #include "idmap.h"
30 #include "smbldap.h"
31 #include "nsswitch/winbind_client.h"
32 #include "lib/winbind_util.h"
33
34 /*
35  * Config and connection info per domain.
36  */
37 struct idmap_rfc2307_context {
38         const char *bind_path_user;
39         const char *bind_path_group;
40         const char *ldap_domain;
41         bool cn_realm;
42         bool user_cn;
43         const char *realm;
44
45         /*
46          * Pointer to ldap struct in ads or smbldap_state, has to be
47          * updated after connecting to server
48          */
49         LDAP *ldap;
50
51         /* Optional function to check connection to server */
52         NTSTATUS (*check_connection)(struct idmap_domain *dom);
53
54         /* Issue ldap query */
55         NTSTATUS (*search)(struct idmap_rfc2307_context *ctx,
56                            const char *bind_path, const char *expr,
57                            const char **attrs, LDAPMessage **res);
58
59         /* Access to LDAP in AD server */
60         ADS_STRUCT *ads;
61
62         /* Access to stand-alone LDAP server */
63         struct smbldap_state *smbldap_state;
64 };
65
66 /*
67  * backend functions for LDAP queries through ADS
68  */
69
70 static NTSTATUS idmap_rfc2307_ads_check_connection(struct idmap_domain *dom)
71 {
72         struct idmap_rfc2307_context *ctx;
73         const char *dom_name = dom->name;
74         ADS_STATUS status;
75
76         DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
77                    dom->name));
78
79         ctx = talloc_get_type(dom->private_data, struct idmap_rfc2307_context);
80         dom_name = ctx->ldap_domain ? ctx->ldap_domain : dom->name;
81
82         status = ads_idmap_cached_connection(&ctx->ads, dom_name);
83         if (ADS_ERR_OK(status)) {
84                 ctx->ldap = ctx->ads->ldap.ld;
85                 if (ctx->cn_realm) {
86                         ctx->realm = ctx->ads->server.realm;
87                 }
88         } else {
89                 DEBUG(1, ("Could not connect to domain %s: %s\n", dom->name,
90                           ads_errstr(status)));
91         }
92
93         return ads_ntstatus(status);
94 }
95
96 static NTSTATUS idmap_rfc2307_ads_search(struct idmap_rfc2307_context *ctx,
97                                          const char *bind_path,
98                                          const char *expr,
99                                          const char **attrs,
100                                          LDAPMessage **result)
101 {
102         ADS_STATUS status;
103
104         status = ads_do_search_retry(ctx->ads, bind_path,
105                                      LDAP_SCOPE_SUBTREE, expr, attrs, result);
106         return ads_ntstatus(status);
107 }
108
109 static NTSTATUS idmap_rfc2307_init_ads(struct idmap_rfc2307_context *ctx,
110                                        const char *cfg_opt)
111 {
112         const char *ldap_domain;
113
114         ctx->search = idmap_rfc2307_ads_search;
115         ctx->check_connection = idmap_rfc2307_ads_check_connection;
116
117         ldap_domain = lp_parm_const_string(-1, cfg_opt, "ldap_domain",
118                                               NULL);
119         if (ldap_domain) {
120                 ctx->ldap_domain = talloc_strdup(ctx, ldap_domain);
121                 if (ctx->ldap_domain == NULL) {
122                         return NT_STATUS_NO_MEMORY;
123                 }
124         }
125
126         return NT_STATUS_OK;
127 }
128
129 /*
130  * backend function for LDAP queries through stand-alone LDAP server
131  */
132
133 static NTSTATUS idmap_rfc2307_ldap_search(struct idmap_rfc2307_context *ctx,
134                                           const char *bind_path,
135                                           const char *expr,
136                                           const char **attrs,
137                                           LDAPMessage **result)
138 {
139         int ret;
140
141         ret = smbldap_search(ctx->smbldap_state, bind_path, LDAP_SCOPE_SUBTREE,
142                              expr, attrs, 0, result);
143         ctx->ldap = ctx->smbldap_state->ldap_struct;
144
145         if (ret == LDAP_SUCCESS) {
146                 return NT_STATUS_OK;
147         }
148
149         return NT_STATUS_LDAP(ret);
150 }
151
152 static bool idmap_rfc2307_get_uint32(LDAP *ldap, LDAPMessage *entry,
153                                      const char *field, uint32 *value)
154 {
155         bool b;
156         char str[20];
157
158         b = smbldap_get_single_attribute(ldap, entry, field, str, sizeof(str));
159
160         if (b) {
161                 *value = atoi(str);
162         }
163
164         return b;
165 }
166
167 static NTSTATUS idmap_rfc2307_init_ldap(struct idmap_rfc2307_context *ctx,
168                                         struct idmap_domain *dom,
169                                         const char *config_option)
170 {
171         NTSTATUS ret;
172         char *url;
173         char *secret = NULL;
174         const char *ldap_url, *user_dn, *ldap_realm;
175         TALLOC_CTX *mem_ctx = ctx;
176
177         ldap_url = lp_parm_const_string(-1, config_option, "ldap_url", NULL);
178         if (!ldap_url) {
179                 DEBUG(1, ("ERROR: missing idmap ldap url\n"));
180                 return NT_STATUS_UNSUCCESSFUL;
181         }
182
183         url = talloc_strdup(talloc_tos(), ldap_url);
184
185         user_dn = lp_parm_const_string(-1, config_option, "ldap_user_dn", NULL);
186         if (user_dn) {
187                 secret = idmap_fetch_secret("ldap", dom->name, user_dn);
188                 if (!secret) {
189                         ret = NT_STATUS_ACCESS_DENIED;
190                         goto done;
191                 }
192         }
193
194         /* assume anonymous if we don't have a specified user */
195         ret = smbldap_init(mem_ctx, winbind_event_context(), url,
196                            (user_dn == NULL), user_dn, secret,
197                            &ctx->smbldap_state);
198         SAFE_FREE(secret);
199         if (!NT_STATUS_IS_OK(ret)) {
200                 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", url));
201                 goto done;
202         }
203
204         ctx->search = idmap_rfc2307_ldap_search;
205
206         if (ctx->cn_realm) {
207                 ldap_realm = lp_parm_const_string(-1, config_option,
208                                                   "ldap_realm", NULL);
209                 if (!ldap_realm) {
210                         DEBUG(1, ("ERROR: cn_realm set, "
211                                   "but ldap_realm is missing\n"));
212                         ret = NT_STATUS_UNSUCCESSFUL;
213                         goto done;
214                 }
215                 ctx->realm = talloc_strdup(mem_ctx, ldap_realm);
216                 if (!ctx->realm) {
217                         ret = NT_STATUS_NO_MEMORY;
218                 }
219         }
220
221 done:
222         talloc_free(url);
223         return ret;
224 }
225
226 /*
227  * common code for stand-alone LDAP and ADS
228  */
229
230 static void idmap_rfc2307_map_sid_results(struct idmap_rfc2307_context *ctx,
231                                           TALLOC_CTX *mem_ctx,
232                                           struct id_map **ids,
233                                           LDAPMessage *result,
234                                           const char *dom_name,
235                                           const char **attrs, int type)
236 {
237         int count, i;
238         LDAPMessage *entry;
239
240         count = ldap_count_entries(ctx->ldap, result);
241
242         for (i = 0; i < count; i++) {
243                 char *name;
244                 enum lsa_SidType lsa_type;
245                 struct id_map *map;
246                 uint32_t id;
247                 bool b;
248
249                 if (i == 0) {
250                         entry = ldap_first_entry(ctx->ldap, result);
251                 } else {
252                         entry = ldap_next_entry(ctx->ldap, result);
253                 }
254                 if (!entry) {
255                         DEBUG(2, ("Unable to fetch entry.\n"));
256                         break;
257                 }
258
259                 name = smbldap_talloc_single_attribute(ctx->ldap, entry,
260                                                        attrs[0], mem_ctx);
261                 if (!name) {
262                         DEBUG(1, ("Could not get user name\n"));
263                         continue;
264                 }
265
266                 b = idmap_rfc2307_get_uint32(ctx->ldap, entry, attrs[1], &id);
267                 if (!b) {
268                         DEBUG(1, ("Could not pull id for record %s\n", name));
269                         continue;
270                 }
271
272                 map = idmap_find_map_by_id(ids, type, id);
273                 if (!map) {
274                         DEBUG(1, ("Could not find id %d, name %s\n", id, name));
275                         continue;
276                 }
277
278                 if (ctx->cn_realm) {
279                         /* Strip @realm from user or group name */
280                         char *delim;
281
282                         delim = strchr(name, '@');
283                         if (delim) {
284                                 *delim = '\0';
285                         }
286                 }
287
288                 /* by default calls to winbindd are disabled
289                    the following call will not recurse so this is safe */
290                 (void)winbind_on();
291                 /* Lookup name from PDC using lsa_lookup_names() */
292                 b = winbind_lookup_name(dom_name, name, map->sid, &lsa_type);
293                 (void)winbind_off();
294
295                 if (!b) {
296                         DEBUG(1, ("SID lookup failed for id %d, %s\n",
297                                   id, name));
298                         continue;
299                 }
300
301                 if (type == ID_TYPE_UID && lsa_type != SID_NAME_USER) {
302                         DEBUG(1, ("Wrong type %d for user name %s\n",
303                                   type, name));
304                         continue;
305                 }
306
307                 if (type == ID_TYPE_GID && lsa_type != SID_NAME_DOM_GRP &&
308                     lsa_type != SID_NAME_ALIAS &&
309                     lsa_type != SID_NAME_WKN_GRP) {
310                         DEBUG(1, ("Wrong type %d for group name %s\n",
311                                   type, name));
312                         continue;
313                 }
314
315                 map->status = ID_MAPPED;
316         }
317 }
318
319 /*
320  * Map unixids to names and then to sids.
321  */
322 static NTSTATUS idmap_rfc2307_unixids_to_sids(struct idmap_domain *dom,
323                                               struct id_map **ids)
324 {
325         struct idmap_rfc2307_context *ctx;
326         char *fltr_usr = NULL, *fltr_grp = NULL;
327         TALLOC_CTX *mem_ctx;
328         int cnt_usr = 0, cnt_grp = 0, idx = 0, bidx = 0;
329         LDAPMessage *result = NULL;
330         NTSTATUS ret;
331
332         ctx = talloc_get_type(dom->private_data, struct idmap_rfc2307_context);
333         mem_ctx = talloc_new(ctx);
334         if (!mem_ctx) {
335                 return NT_STATUS_NO_MEMORY;
336         }
337
338         if (ctx->check_connection) {
339                 ret = ctx->check_connection(dom);
340                 if (!NT_STATUS_IS_OK(ret)) {
341                         goto out;
342                 }
343         }
344
345 again:
346         bidx = idx;
347
348         if (!fltr_usr) {
349                 /* prepare new user query, see getpwuid() in RFC2307 */
350                 fltr_usr = talloc_asprintf(mem_ctx,
351                                              "(&(objectClass=posixAccount)(|");
352         }
353
354         if (!fltr_grp) {
355                 /* prepare new group query, see getgrgid() in RFC2307 */
356                 fltr_grp = talloc_asprintf(mem_ctx,
357                                              "(&(objectClass=posixGroup)(|");
358         }
359
360         if (!fltr_usr || !fltr_grp) {
361                 ret = NT_STATUS_NO_MEMORY;
362                 goto out;
363         }
364
365         while (cnt_usr < IDMAP_LDAP_MAX_IDS &&
366                cnt_grp < IDMAP_LDAP_MAX_IDS && ids[idx]) {
367
368                 switch (ids[idx]->xid.type) {
369                 case ID_TYPE_UID:
370                         fltr_usr = talloc_asprintf_append_buffer(fltr_usr,
371                                         "(uidNumber=%d)", ids[idx]->xid.id);
372                         cnt_usr++;
373                         break;
374                 case ID_TYPE_GID:
375                         fltr_grp = talloc_asprintf_append_buffer(fltr_grp,
376                                         "(gidNumber=%d))", ids[idx]->xid.id);
377                         cnt_grp++;
378                         break;
379                 default:
380                         DEBUG(3, ("Error: unknown ID type %d\n",
381                                   ids[idx]->xid.type));
382                         ret = NT_STATUS_UNSUCCESSFUL;
383                         goto out;
384                 }
385
386                 if (!fltr_usr || !fltr_grp) {
387                         ret = NT_STATUS_NO_MEMORY;
388                         goto out;
389                 }
390
391                 idx++;
392         }
393
394         if (cnt_usr == IDMAP_LDAP_MAX_IDS || (cnt_usr != 0 && !ids[idx])) {
395                 const char *attrs[] = { NULL, /* uid or cn */
396                                         "uidNumber",
397                                         NULL };
398
399                 fltr_usr = talloc_strdup_append(fltr_usr, "))");
400                 if (!fltr_usr) {
401                         ret = NT_STATUS_NO_MEMORY;
402                         goto out;
403                 }
404
405                 attrs[0] = ctx->user_cn ? "cn" : "uid";
406                 ret = ctx->search(ctx, ctx->bind_path_user, fltr_usr, attrs,
407                                   &result);
408                 if (!NT_STATUS_IS_OK(ret)) {
409                         goto out;
410                 }
411
412                 idmap_rfc2307_map_sid_results(ctx, mem_ctx, &ids[bidx], result,
413                                               dom->name, attrs, ID_TYPE_UID);
414                 cnt_usr = 0;
415                 TALLOC_FREE(fltr_usr);
416         }
417
418         if (cnt_grp == IDMAP_LDAP_MAX_IDS || (cnt_grp != 0 && !ids[idx])) {
419                 const char *attrs[] = { "cn", "gidNumber", NULL };
420
421                 fltr_grp = talloc_strdup_append(fltr_grp, "))");
422                 if (!fltr_grp) {
423                         ret = NT_STATUS_NO_MEMORY;
424                         goto out;
425                 }
426                 ret = ctx->search(ctx, ctx->bind_path_group, fltr_grp, attrs,
427                                   &result);
428                 if (!NT_STATUS_IS_OK(ret)) {
429                         goto out;
430                 }
431
432                 idmap_rfc2307_map_sid_results(ctx, mem_ctx, &ids[bidx], result,
433                                               dom->name, attrs, ID_TYPE_GID);
434                 cnt_grp = 0;
435                 TALLOC_FREE(fltr_grp);
436         }
437
438         if (ids[idx]) {
439                 goto again;
440         }
441
442         ret = NT_STATUS_OK;
443
444 out:
445         talloc_free(mem_ctx);
446         return ret;
447 }
448
449 struct idmap_rfc2307_map {
450         struct id_map *map;
451         const char *name;
452         enum id_type type;
453 };
454
455 /*
456  * Lookup names for SIDS and store the data in the local mapping
457  * array.
458  */
459 static NTSTATUS idmap_rfc_2307_sids_to_names(TALLOC_CTX *mem_ctx,
460                                              struct id_map **ids,
461                                              struct idmap_rfc2307_map *maps,
462                                              struct idmap_rfc2307_context *ctx)
463 {
464         int i;
465
466         for (i = 0; ids[i]; i++) {
467                 const char *domain, *name;
468                 enum lsa_SidType lsa_type;
469                 struct id_map *id = ids[i];
470                 struct idmap_rfc2307_map *map = &maps[i];
471                 bool b;
472
473                 /* by default calls to winbindd are disabled
474                    the following call will not recurse so this is safe */
475                 (void)winbind_on();
476                 b = winbind_lookup_sid(mem_ctx, ids[i]->sid, &domain, &name,
477                                        &lsa_type);
478                 (void)winbind_off();
479
480                 if (!b) {
481                         DEBUG(1, ("Lookup sid %s failed.\n",
482                                   sid_string_dbg(ids[i]->sid)));
483                         continue;
484                 }
485
486                 switch(lsa_type) {
487                 case SID_NAME_USER:
488                         id->xid.type = map->type = ID_TYPE_UID;
489                         if (ctx->user_cn && ctx->cn_realm) {
490                                 name = talloc_asprintf(mem_ctx, "%s@%s",
491                                                        name, ctx->realm);
492                         }
493                         id->xid.type = map->type = ID_TYPE_UID;
494                         break;
495
496                 case SID_NAME_DOM_GRP:
497                 case SID_NAME_ALIAS:
498                 case SID_NAME_WKN_GRP:
499                         if (ctx->cn_realm) {
500                                 name = talloc_asprintf(mem_ctx, "%s@%s",
501                                                        name, ctx->realm);
502                         }
503                         id->xid.type = map->type = ID_TYPE_GID;
504                         break;
505
506                 default:
507                         DEBUG(1, ("Unknown lsa type %d for sid %s\n",
508                                   lsa_type, sid_string_dbg(id->sid)));
509                         id->status = ID_UNMAPPED;
510                         continue;
511                 }
512
513                 map->map = id;
514                 id->status = ID_UNKNOWN;
515                 map->name = strupper_talloc(mem_ctx, name);
516
517                 if (!map->name) {
518                         return NT_STATUS_NO_MEMORY;
519                 }
520         }
521
522         return NT_STATUS_OK;
523 }
524
525 /*
526  * Find id_map entry by looking up the name in the internal
527  * mapping array.
528  */
529 static struct id_map* idmap_rfc2307_find_map(struct idmap_rfc2307_map *maps,
530                                              enum id_type type,
531                                              const char *name)
532 {
533         int i;
534
535         DEBUG(10, ("Looking for name %s, type %d\n", name, type));
536
537         for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
538                 if (maps[i].map == NULL) { /* end of the run */
539                         return NULL;
540                 }
541                 DEBUG(10, ("Entry %d: name %s, type %d\n",
542                            i, maps[i].name, maps[i].type));
543                 if (type == maps[i].type && strcmp(name, maps[i].name) == 0) {
544                         return maps[i].map;
545                 }
546         }
547
548         return NULL;
549 }
550
551 static void idmap_rfc2307_map_xid_results(struct idmap_rfc2307_context *ctx,
552                                           TALLOC_CTX *mem_ctx,
553                                           struct id_map **ids,
554                                           struct idmap_rfc2307_map *maps,
555                                           LDAPMessage *result,
556                                           struct idmap_domain *dom,
557                                           const char **attrs, enum id_type type)
558 {
559         int count, i;
560         LDAPMessage *entry;
561
562         count = ldap_count_entries(ctx->ldap, result);
563
564         for (i = 0; i < count; i++) {
565                 uint32_t id;
566                 char *name;
567                 bool b;
568                 struct id_map *id_map;
569
570                 if (i == 0) {
571                         entry = ldap_first_entry(ctx->ldap, result);
572                 } else {
573                         entry = ldap_next_entry(ctx->ldap, result);
574                 }
575                 if (!entry) {
576                         DEBUG(2, ("Unable to fetch entry.\n"));
577                         break;
578                 }
579
580                 name = smbldap_talloc_single_attribute(ctx->ldap, entry,
581                                                        attrs[0], mem_ctx);
582                 if (!name) {
583                         DEBUG(1, ("Could not get user name\n"));
584                         continue;
585                 }
586
587                 b = idmap_rfc2307_get_uint32(ctx->ldap, entry, attrs[1], &id);
588                 if (!b) {
589                         DEBUG(5, ("Could not pull id for record %s\n", name));
590                         continue;
591                 }
592
593                 if (!idmap_unix_id_is_in_range(id, dom)) {
594                         DEBUG(5, ("Requested id (%u) out of range (%u - %u).\n",
595                                   id, dom->low_id, dom->high_id));
596                         continue;
597                 }
598
599                 if (!strupper_m(name)) {
600                         DEBUG(5, ("Could not convert %s to uppercase\n", name));
601                         continue;
602                 }
603                 id_map = idmap_rfc2307_find_map(maps, type, name);
604                 if (!id_map) {
605                         DEBUG(0, ("Could not find mapping entry for name %s\n",
606                                   name));
607                         continue;
608                 }
609
610                 id_map->xid.id = id;
611                 id_map->status = ID_MAPPED;
612         }
613 }
614
615 /*
616  * Map sids to names and then to unixids.
617  */
618 static NTSTATUS idmap_rfc2307_sids_to_unixids(struct idmap_domain *dom,
619                                               struct id_map **ids)
620 {
621         struct idmap_rfc2307_context *ctx;
622         TALLOC_CTX *mem_ctx;
623         struct idmap_rfc2307_map *int_maps;
624         int cnt_usr = 0, cnt_grp = 0, idx = 0, bidx = 0;
625         char *fltr_usr = NULL, *fltr_grp = NULL;
626         NTSTATUS ret;
627         int i;
628
629         ctx = talloc_get_type(dom->private_data, struct idmap_rfc2307_context);
630         mem_ctx = talloc_new(talloc_tos());
631         if (!mem_ctx) {
632                 return NT_STATUS_NO_MEMORY;
633         }
634
635         if (ctx->check_connection) {
636                 ret = ctx->check_connection(dom);
637                 if (!NT_STATUS_IS_OK(ret)) {
638                         goto out;
639                 }
640         }
641
642         for (i = 0; ids[i]; i++);
643         int_maps = talloc_zero_array(mem_ctx, struct idmap_rfc2307_map, i);
644         if (!int_maps) {
645                 ret = NT_STATUS_NO_MEMORY;
646                 goto out;
647         }
648
649         ret = idmap_rfc_2307_sids_to_names(mem_ctx, ids, int_maps, ctx);
650         if (!NT_STATUS_IS_OK(ret)) {
651                 goto out;
652         }
653
654 again:
655         if (!fltr_usr) {
656                 /* prepare new user query, see getpwuid() in RFC2307 */
657                 fltr_usr = talloc_asprintf(mem_ctx,
658                                              "(&(objectClass=posixAccount)(|");
659         }
660
661         if (!fltr_grp) {
662                 /* prepare new group query, see getgrgid() in RFC2307 */
663                 fltr_grp = talloc_asprintf(mem_ctx,
664                                              "(&(objectClass=posixGroup)(|");
665         }
666
667         if (!fltr_usr || !fltr_grp) {
668                 ret = NT_STATUS_NO_MEMORY;
669                 goto out;
670         }
671
672         while (cnt_usr < IDMAP_LDAP_MAX_IDS &&
673                cnt_grp < IDMAP_LDAP_MAX_IDS && ids[idx]) {
674                 struct id_map *id = ids[idx];
675                 struct idmap_rfc2307_map *map = &int_maps[idx];
676
677                 switch(id->xid.type) {
678                 case ID_TYPE_UID:
679                         fltr_usr = talloc_asprintf_append_buffer(fltr_usr,
680                                      "(%s=%s)", (ctx->user_cn ? "cn" : "uid"),
681                                       map->name);
682                         cnt_usr++;
683                         break;
684
685                 case ID_TYPE_GID:
686                         fltr_grp = talloc_asprintf_append_buffer(fltr_grp,
687                                          "(cn=%s)", map->name);
688                         cnt_grp++;
689                         break;
690
691                 default:
692                         DEBUG(10, ("Nothing to do for SID %s, "
693                                    "previous name lookup failed\n",
694                                    sid_string_dbg(map->map->sid)));
695                 }
696
697                 if (!fltr_usr || !fltr_grp) {
698                         ret = NT_STATUS_NO_MEMORY;
699                         goto out;
700                 }
701
702                 idx++;
703         }
704
705         if (cnt_usr == IDMAP_LDAP_MAX_IDS || (cnt_usr != 0 && !ids[idx])) {
706                 const char *attrs[] = { NULL, /* uid or cn */
707                                         "uidNumber",
708                                         NULL };
709                 LDAPMessage *result;
710
711                 fltr_usr = talloc_strdup_append(fltr_usr, "))");
712                 if (!fltr_usr) {
713                         ret = NT_STATUS_NO_MEMORY;
714                         goto out;
715                 }
716
717                 attrs[0] = ctx->user_cn ? "cn" : "uid";
718                 ret = ctx->search(ctx, ctx->bind_path_user, fltr_usr, attrs,
719                                   &result);
720                 if (!NT_STATUS_IS_OK(ret)) {
721                         goto out;
722                 }
723
724                 idmap_rfc2307_map_xid_results(ctx, mem_ctx, &ids[bidx],
725                                               int_maps, result, dom,
726                                               attrs, ID_TYPE_UID);
727
728                 cnt_usr = 0;
729                 TALLOC_FREE(fltr_usr);
730         }
731
732         if (cnt_grp == IDMAP_LDAP_MAX_IDS || (cnt_grp != 0 && !ids[idx])) {
733                 const char *attrs[] = {"cn", "gidNumber", NULL };
734                 LDAPMessage *result;
735
736                 fltr_grp = talloc_strdup_append(fltr_grp, "))");
737                 if (!fltr_grp) {
738                         ret = NT_STATUS_NO_MEMORY;
739                         goto out;
740                 }
741
742                 ret = ctx->search(ctx, ctx->bind_path_group, fltr_grp, attrs,
743                                   &result);
744                 if (!NT_STATUS_IS_OK(ret)) {
745                         goto out;
746                 }
747
748                 idmap_rfc2307_map_xid_results(ctx, mem_ctx, &ids[bidx],
749                                               int_maps, result, dom,
750                                               attrs, ID_TYPE_GID);
751                 cnt_grp = 0;
752                 TALLOC_FREE(fltr_grp);
753         }
754
755         if (ids[idx]) {
756                 goto again;
757         }
758
759         ret = NT_STATUS_OK;
760
761 out:
762         talloc_free(mem_ctx);
763         return ret;
764 }
765
766 static int idmap_rfc2307_context_destructor(struct idmap_rfc2307_context *ctx)
767 {
768         if (ctx->ads != NULL) {
769                 /* we own this ADS_STRUCT so make sure it goes away */
770                 ctx->ads->is_mine = True;
771                 ads_destroy( &ctx->ads );
772                 ctx->ads = NULL;
773         }
774
775         if (ctx->smbldap_state != NULL) {
776                 smbldap_free_struct(&ctx->smbldap_state);
777         }
778
779         return 0;
780 }
781
782 static NTSTATUS idmap_rfc2307_initialize(struct idmap_domain *domain)
783 {
784         struct idmap_rfc2307_context *ctx;
785         char *cfg_opt;
786         const char *bind_path_user, *bind_path_group, *ldap_server;
787         NTSTATUS status;
788
789         ctx = talloc_zero(domain, struct idmap_rfc2307_context);
790         if (ctx == NULL) {
791                 return NT_STATUS_NO_MEMORY;
792         }
793         talloc_set_destructor(ctx, idmap_rfc2307_context_destructor);
794
795         cfg_opt = talloc_asprintf(ctx, "idmap config %s", domain->name);
796         if (cfg_opt == NULL) {
797                 status = NT_STATUS_NO_MEMORY;
798                 goto err;
799         }
800
801         bind_path_user = lp_parm_const_string(-1, cfg_opt, "bind_path_user",
802                                               NULL);
803         if (bind_path_user) {
804                 ctx->bind_path_user = talloc_strdup(ctx, bind_path_user);
805                 if (ctx->bind_path_user == NULL) {
806                         status = NT_STATUS_NO_MEMORY;
807                         goto err;
808                 }
809         } else {
810                 status = NT_STATUS_INVALID_PARAMETER;
811                 goto err;
812         }
813
814         bind_path_group = lp_parm_const_string(-1, cfg_opt, "bind_path_group",
815                                                NULL);
816         if (bind_path_group) {
817                 ctx->bind_path_group = talloc_strdup(ctx, bind_path_group);
818                 if (ctx->bind_path_group == NULL) {
819                         status = NT_STATUS_NO_MEMORY;
820                         goto err;
821                 }
822         } else {
823                 status = NT_STATUS_INVALID_PARAMETER;
824                 goto err;
825         }
826
827         ldap_server = lp_parm_const_string(-1, cfg_opt, "ldap_server", NULL);
828         if (!ldap_server) {
829                 status = NT_STATUS_INVALID_PARAMETER;
830                 goto err;
831         }
832
833         if (strcmp(ldap_server, "stand-alone") == 0) {
834                 status = idmap_rfc2307_init_ldap(ctx, domain, cfg_opt);
835
836         } else if (strcmp(ldap_server, "ad") == 0) {
837                 status = idmap_rfc2307_init_ads(ctx, cfg_opt);
838
839         } else {
840                 status = NT_STATUS_INVALID_PARAMETER;
841         }
842
843         if (!NT_STATUS_IS_OK(status)) {
844                 goto err;
845         }
846
847         ctx->cn_realm = lp_parm_bool(-1, cfg_opt, "cn_realm", false);
848         ctx->user_cn = lp_parm_bool(-1, cfg_opt, "user_cn", false);
849
850         domain->private_data = ctx;
851         talloc_free(cfg_opt);
852         return NT_STATUS_OK;
853
854 err:
855         talloc_free(cfg_opt);
856         talloc_free(ctx);
857         return status;
858 }
859
860 static struct idmap_methods rfc2307_methods = {
861         .init = idmap_rfc2307_initialize,
862         .unixids_to_sids = idmap_rfc2307_unixids_to_sids,
863         .sids_to_unixids = idmap_rfc2307_sids_to_unixids,
864 };
865
866 NTSTATUS idmap_rfc2307_init(void)
867 {
868         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "rfc2307",
869                                   &rfc2307_methods);
870 }