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