winbind_msrpc: Use any_nt_status_not_ok
[amitay/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 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 = ctx->smbldap_state->ldap_struct;
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, result);
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; i < IDMAP_LDAP_MAX_IDS; i++) {
524                 if (maps[i].map == NULL) { /* end of the run */
525                         return NULL;
526                 }
527                 DEBUG(10, ("Entry %d: name %s, type %d\n",
528                            i, maps[i].name, maps[i].type));
529                 if (type == maps[i].type && strcmp(name, maps[i].name) == 0) {
530                         return maps[i].map;
531                 }
532         }
533
534         return NULL;
535 }
536
537 static void idmap_rfc2307_map_xid_results(struct idmap_rfc2307_context *ctx,
538                                           TALLOC_CTX *mem_ctx,
539                                           struct idmap_rfc2307_map *maps,
540                                           LDAPMessage *result,
541                                           struct idmap_domain *dom,
542                                           const char **attrs, enum id_type type)
543 {
544         int count, i;
545         LDAPMessage *entry;
546
547         count = ldap_count_entries(ctx->ldap, result);
548
549         for (i = 0; i < count; i++) {
550                 uint32_t id;
551                 char *name;
552                 bool b;
553                 struct id_map *id_map;
554
555                 if (i == 0) {
556                         entry = ldap_first_entry(ctx->ldap, result);
557                 } else {
558                         entry = ldap_next_entry(ctx->ldap, result);
559                 }
560                 if (!entry) {
561                         DEBUG(2, ("Unable to fetch entry.\n"));
562                         break;
563                 }
564
565                 name = smbldap_talloc_single_attribute(ctx->ldap, entry,
566                                                        attrs[0], mem_ctx);
567                 if (!name) {
568                         DEBUG(1, ("Could not get user name\n"));
569                         continue;
570                 }
571
572                 b = idmap_rfc2307_get_uint32(ctx->ldap, entry, attrs[1], &id);
573                 if (!b) {
574                         DEBUG(5, ("Could not pull id for record %s\n", name));
575                         continue;
576                 }
577
578                 if (!idmap_unix_id_is_in_range(id, dom)) {
579                         DEBUG(5, ("Requested id (%u) out of range (%u - %u).\n",
580                                   id, dom->low_id, dom->high_id));
581                         continue;
582                 }
583
584                 if (!strupper_m(name)) {
585                         DEBUG(5, ("Could not convert %s to uppercase\n", name));
586                         continue;
587                 }
588                 id_map = idmap_rfc2307_find_map(maps, type, name);
589                 if (!id_map) {
590                         DEBUG(0, ("Could not find mapping entry for name %s\n",
591                                   name));
592                         continue;
593                 }
594
595                 id_map->xid.id = id;
596                 id_map->status = ID_MAPPED;
597         }
598 }
599
600 /*
601  * Map sids to names and then to unixids.
602  */
603 static NTSTATUS idmap_rfc2307_sids_to_unixids(struct idmap_domain *dom,
604                                               struct id_map **ids)
605 {
606         struct idmap_rfc2307_context *ctx;
607         TALLOC_CTX *mem_ctx;
608         struct idmap_rfc2307_map *int_maps;
609         int cnt_usr = 0, cnt_grp = 0, idx = 0;
610         char *fltr_usr = NULL, *fltr_grp = NULL;
611         NTSTATUS ret;
612         int i;
613
614         ctx = talloc_get_type(dom->private_data, struct idmap_rfc2307_context);
615         mem_ctx = talloc_new(talloc_tos());
616         if (!mem_ctx) {
617                 return NT_STATUS_NO_MEMORY;
618         }
619
620         if (ctx->check_connection) {
621                 ret = ctx->check_connection(dom);
622                 if (!NT_STATUS_IS_OK(ret)) {
623                         goto out;
624                 }
625         }
626
627         for (i = 0; ids[i]; i++);
628         int_maps = talloc_zero_array(mem_ctx, struct idmap_rfc2307_map, i);
629         if (!int_maps) {
630                 ret = NT_STATUS_NO_MEMORY;
631                 goto out;
632         }
633
634         ret = idmap_rfc_2307_sids_to_names(mem_ctx, ids, int_maps, ctx);
635         if (!NT_STATUS_IS_OK(ret)) {
636                 goto out;
637         }
638
639 again:
640         if (!fltr_usr) {
641                 /* prepare new user query, see getpwuid() in RFC2307 */
642                 fltr_usr = talloc_asprintf(mem_ctx,
643                                              "(&(objectClass=posixAccount)(|");
644         }
645
646         if (!fltr_grp) {
647                 /* prepare new group query, see getgrgid() in RFC2307 */
648                 fltr_grp = talloc_asprintf(mem_ctx,
649                                              "(&(objectClass=posixGroup)(|");
650         }
651
652         if (!fltr_usr || !fltr_grp) {
653                 ret = NT_STATUS_NO_MEMORY;
654                 goto out;
655         }
656
657         while (cnt_usr < IDMAP_LDAP_MAX_IDS &&
658                cnt_grp < IDMAP_LDAP_MAX_IDS && ids[idx]) {
659                 struct id_map *id = ids[idx];
660                 struct idmap_rfc2307_map *map = &int_maps[idx];
661
662                 switch(id->xid.type) {
663                 case ID_TYPE_UID:
664                         fltr_usr = talloc_asprintf_append_buffer(fltr_usr,
665                                      "(%s=%s)", (ctx->user_cn ? "cn" : "uid"),
666                                       map->name);
667                         cnt_usr++;
668                         break;
669
670                 case ID_TYPE_GID:
671                         fltr_grp = talloc_asprintf_append_buffer(fltr_grp,
672                                          "(cn=%s)", map->name);
673                         cnt_grp++;
674                         break;
675
676                 default:
677                         break;
678                 }
679
680                 if (!fltr_usr || !fltr_grp) {
681                         ret = NT_STATUS_NO_MEMORY;
682                         goto out;
683                 }
684
685                 idx++;
686         }
687
688         if (cnt_usr == IDMAP_LDAP_MAX_IDS || (cnt_usr != 0 && !ids[idx])) {
689                 const char *attrs[] = { NULL, /* uid or cn */
690                                         "uidNumber",
691                                         NULL };
692                 LDAPMessage *result;
693
694                 fltr_usr = talloc_strdup_append(fltr_usr, "))");
695                 if (!fltr_usr) {
696                         ret = NT_STATUS_NO_MEMORY;
697                         goto out;
698                 }
699
700                 attrs[0] = ctx->user_cn ? "cn" : "uid";
701                 ret = ctx->search(ctx, ctx->bind_path_user, fltr_usr, attrs,
702                                   &result);
703                 if (!NT_STATUS_IS_OK(ret)) {
704                         goto out;
705                 }
706
707                 idmap_rfc2307_map_xid_results(ctx, mem_ctx, int_maps,
708                                               result, dom, attrs, ID_TYPE_UID);
709
710                 cnt_usr = 0;
711                 TALLOC_FREE(fltr_usr);
712         }
713
714         if (cnt_grp == IDMAP_LDAP_MAX_IDS || (cnt_grp != 0 && !ids[idx])) {
715                 const char *attrs[] = {"cn", "gidNumber", NULL };
716                 LDAPMessage *result;
717
718                 fltr_grp = talloc_strdup_append(fltr_grp, "))");
719                 if (!fltr_grp) {
720                         ret = NT_STATUS_NO_MEMORY;
721                         goto out;
722                 }
723
724                 ret = ctx->search(ctx, ctx->bind_path_group, fltr_grp, attrs,
725                                   &result);
726                 if (!NT_STATUS_IS_OK(ret)) {
727                         goto out;
728                 }
729
730                 idmap_rfc2307_map_xid_results(ctx, mem_ctx, int_maps, result,
731                                               dom, attrs, ID_TYPE_GID);
732                 cnt_grp = 0;
733                 TALLOC_FREE(fltr_grp);
734         }
735
736         if (ids[idx]) {
737                 goto again;
738         }
739
740         ret = NT_STATUS_OK;
741
742 out:
743         talloc_free(mem_ctx);
744         return ret;
745 }
746
747 static int idmap_rfc2307_context_destructor(struct idmap_rfc2307_context *ctx)
748 {
749         if (ctx->ads != NULL) {
750                 /* we own this ADS_STRUCT so make sure it goes away */
751                 ctx->ads->is_mine = True;
752                 ads_destroy( &ctx->ads );
753                 ctx->ads = NULL;
754         }
755
756         if (ctx->smbldap_state != NULL) {
757                 smbldap_free_struct(&ctx->smbldap_state);
758         }
759
760         return 0;
761 }
762
763 static NTSTATUS idmap_rfc2307_initialize(struct idmap_domain *domain)
764 {
765         struct idmap_rfc2307_context *ctx;
766         const char *bind_path_user, *bind_path_group, *ldap_server, *realm;
767         NTSTATUS status;
768
769         ctx = talloc_zero(domain, struct idmap_rfc2307_context);
770         if (ctx == NULL) {
771                 return NT_STATUS_NO_MEMORY;
772         }
773         talloc_set_destructor(ctx, idmap_rfc2307_context_destructor);
774
775         bind_path_user = idmap_config_const_string(
776                 domain->name, "bind_path_user", NULL);
777         if (bind_path_user == NULL) {
778                 status = NT_STATUS_INVALID_PARAMETER;
779                 goto err;
780         }
781         ctx->bind_path_user = talloc_strdup(ctx, bind_path_user);
782         if (ctx->bind_path_user == NULL) {
783                 status = NT_STATUS_NO_MEMORY;
784                 goto err;
785         }
786
787         bind_path_group = idmap_config_const_string(
788                 domain->name, "bind_path_group", NULL);
789         if (bind_path_group == NULL) {
790                 status = NT_STATUS_INVALID_PARAMETER;
791                 goto err;
792         }
793         ctx->bind_path_group = talloc_strdup(ctx, bind_path_group);
794         if (ctx->bind_path_group == NULL) {
795                 status = NT_STATUS_NO_MEMORY;
796                 goto err;
797         }
798
799         ldap_server = idmap_config_const_string(
800                 domain->name, "ldap_server", NULL);
801         if (!ldap_server) {
802                 status = NT_STATUS_INVALID_PARAMETER;
803                 goto err;
804         }
805
806         if (strcmp(ldap_server, "stand-alone") == 0) {
807                 status = idmap_rfc2307_init_ldap(ctx, domain->name);
808
809         } else if (strcmp(ldap_server, "ad") == 0) {
810                 status = idmap_rfc2307_init_ads(ctx, domain->name);
811
812         } else {
813                 status = NT_STATUS_INVALID_PARAMETER;
814         }
815
816         if (!NT_STATUS_IS_OK(status)) {
817                 goto err;
818         }
819
820         realm = idmap_config_const_string(domain->name, "realm", NULL);
821         if (realm) {
822                 ctx->realm = talloc_strdup(ctx, realm);
823                 if (ctx->realm == NULL) {
824                         status = NT_STATUS_NO_MEMORY;
825                         goto err;
826                 }
827         }
828
829         ctx->user_cn = idmap_config_bool(domain->name, "user_cn", false);
830
831         domain->private_data = ctx;
832         return NT_STATUS_OK;
833
834 err:
835         talloc_free(ctx);
836         return status;
837 }
838
839 static struct idmap_methods rfc2307_methods = {
840         .init = idmap_rfc2307_initialize,
841         .unixids_to_sids = idmap_rfc2307_unixids_to_sids,
842         .sids_to_unixids = idmap_rfc2307_sids_to_unixids,
843 };
844
845 static_decl_idmap;
846 NTSTATUS idmap_rfc2307_init(void)
847 {
848         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "rfc2307",
849                                   &rfc2307_methods);
850 }