e3bf58d816585e58a8441455a29ad8d8a624f1e3
[metze/samba/wip.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 "winbindd_ads.h"
29 #include "idmap.h"
30 #include "smbldap.h"
31 #include "nsswitch/winbind_client.h"
32 #include "lib/winbind_util.h"
33 #include "libcli/security/dom_sid.h"
34
35 /*
36  * Config and connection info per domain.
37  */
38 struct idmap_rfc2307_context {
39         const char *bind_path_user;
40         const char *bind_path_group;
41         const char *ldap_domain;
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         } else {
86                 DEBUG(1, ("Could not connect to domain %s: %s\n", dom->name,
87                           ads_errstr(status)));
88         }
89
90         return ads_ntstatus(status);
91 }
92
93 static NTSTATUS idmap_rfc2307_ads_search(struct idmap_rfc2307_context *ctx,
94                                          const char *bind_path,
95                                          const char *expr,
96                                          const char **attrs,
97                                          LDAPMessage **result)
98 {
99         ADS_STATUS status;
100
101         status = ads_do_search_retry(ctx->ads, bind_path,
102                                      LDAP_SCOPE_SUBTREE, expr, attrs, result);
103
104         if (!ADS_ERR_OK(status)) {
105                 return ads_ntstatus(status);
106         }
107
108         ctx->ldap = ctx->ads->ldap.ld;
109         return ads_ntstatus(status);
110 }
111
112 static NTSTATUS idmap_rfc2307_init_ads(struct idmap_rfc2307_context *ctx,
113                                        const char *domain_name)
114 {
115         const char *ldap_domain;
116
117         ctx->search = idmap_rfc2307_ads_search;
118         ctx->check_connection = idmap_rfc2307_ads_check_connection;
119
120         ldap_domain = idmap_config_const_string(domain_name, "ldap_domain",
121                                                 NULL);
122         if (ldap_domain) {
123                 ctx->ldap_domain = talloc_strdup(ctx, ldap_domain);
124                 if (ctx->ldap_domain == NULL) {
125                         return NT_STATUS_NO_MEMORY;
126                 }
127         }
128
129         return NT_STATUS_OK;
130 }
131
132 /*
133  * backend function for LDAP queries through stand-alone LDAP server
134  */
135
136 static NTSTATUS idmap_rfc2307_ldap_search(struct idmap_rfc2307_context *ctx,
137                                           const char *bind_path,
138                                           const char *expr,
139                                           const char **attrs,
140                                           LDAPMessage **result)
141 {
142         int ret;
143
144         ret = smbldap_search(ctx->smbldap_state, bind_path, LDAP_SCOPE_SUBTREE,
145                              expr, attrs, 0, result);
146         ctx->ldap = smbldap_get_ldap(ctx->smbldap_state);
147
148         if (ret == LDAP_SUCCESS) {
149                 return NT_STATUS_OK;
150         }
151
152         return NT_STATUS_LDAP(ret);
153 }
154
155 static bool idmap_rfc2307_get_uint32(LDAP *ldap, LDAPMessage *entry,
156                                      const char *field, uint32_t *value)
157 {
158         bool b;
159         char str[20];
160
161         b = smbldap_get_single_attribute(ldap, entry, field, str, sizeof(str));
162
163         if (b) {
164                 *value = atoi(str);
165         }
166
167         return b;
168 }
169
170 static NTSTATUS idmap_rfc2307_init_ldap(struct idmap_rfc2307_context *ctx,
171                                         const char *domain_name)
172 {
173         NTSTATUS ret;
174         char *url;
175         char *secret = NULL;
176         const char *ldap_url, *user_dn;
177         TALLOC_CTX *mem_ctx = ctx;
178
179         ldap_url = idmap_config_const_string(domain_name, "ldap_url", NULL);
180         if (!ldap_url) {
181                 DEBUG(1, ("ERROR: missing idmap ldap url\n"));
182                 return NT_STATUS_UNSUCCESSFUL;
183         }
184
185         url = talloc_strdup(talloc_tos(), ldap_url);
186
187         user_dn = idmap_config_const_string(domain_name, "ldap_user_dn", NULL);
188         if (user_dn) {
189                 secret = idmap_fetch_secret("ldap", domain_name, user_dn);
190                 if (!secret) {
191                         ret = NT_STATUS_ACCESS_DENIED;
192                         goto done;
193                 }
194         }
195
196         /* assume anonymous if we don't have a specified user */
197         ret = smbldap_init(mem_ctx, global_event_context(), url,
198                            (user_dn == NULL), user_dn, secret,
199                            &ctx->smbldap_state);
200         SAFE_FREE(secret);
201         if (!NT_STATUS_IS_OK(ret)) {
202                 DEBUG(1, ("ERROR: smbldap_init (%s) failed!\n", url));
203                 goto done;
204         }
205
206         ctx->search = idmap_rfc2307_ldap_search;
207
208 done:
209         talloc_free(url);
210         return ret;
211 }
212
213 /*
214  * common code for stand-alone LDAP and ADS
215  */
216
217 static void idmap_rfc2307_map_sid_results(struct idmap_rfc2307_context *ctx,
218                                           TALLOC_CTX *mem_ctx,
219                                           struct id_map **ids,
220                                           LDAPMessage *result,
221                                           const char *dom_name,
222                                           const char **attrs, int type)
223 {
224         int count, i;
225         LDAPMessage *entry;
226
227         count = ldap_count_entries(ctx->ldap, result);
228
229         for (i = 0; i < count; i++) {
230                 char *name;
231                 enum lsa_SidType lsa_type;
232                 struct id_map *map;
233                 uint32_t id;
234                 bool b;
235
236                 if (i == 0) {
237                         entry = ldap_first_entry(ctx->ldap, result);
238                 } else {
239                         entry = ldap_next_entry(ctx->ldap, entry);
240                 }
241                 if (!entry) {
242                         DEBUG(2, ("Unable to fetch entry.\n"));
243                         break;
244                 }
245
246                 name = smbldap_talloc_single_attribute(ctx->ldap, entry,
247                                                        attrs[0], mem_ctx);
248                 if (!name) {
249                         DEBUG(1, ("Could not get user name\n"));
250                         continue;
251                 }
252
253                 b = idmap_rfc2307_get_uint32(ctx->ldap, entry, attrs[1], &id);
254                 if (!b) {
255                         DEBUG(1, ("Could not pull id for record %s\n", name));
256                         continue;
257                 }
258
259                 map = idmap_find_map_by_id(ids, type, id);
260                 if (!map) {
261                         DEBUG(1, ("Could not find id %d, name %s\n", id, name));
262                         continue;
263                 }
264
265                 if (ctx->realm != NULL) {
266                         /* Strip @realm from user or group name */
267                         char *delim;
268
269                         delim = strchr(name, '@');
270                         if (delim) {
271                                 *delim = '\0';
272                         }
273                 }
274
275                 /* by default calls to winbindd are disabled
276                    the following call will not recurse so this is safe */
277                 (void)winbind_on();
278                 /* Lookup name from PDC using lsa_lookup_names() */
279                 b = winbind_lookup_name(dom_name, name, map->sid, &lsa_type);
280                 (void)winbind_off();
281
282                 if (!b) {
283                         DEBUG(1, ("SID lookup failed for id %d, %s\n",
284                                   id, name));
285                         continue;
286                 }
287
288                 if (type == ID_TYPE_UID && lsa_type != SID_NAME_USER) {
289                         DEBUG(1, ("Wrong type %d for user name %s\n",
290                                   type, name));
291                         continue;
292                 }
293
294                 if (type == ID_TYPE_GID && lsa_type != SID_NAME_DOM_GRP &&
295                     lsa_type != SID_NAME_ALIAS &&
296                     lsa_type != SID_NAME_WKN_GRP) {
297                         DEBUG(1, ("Wrong type %d for group name %s\n",
298                                   type, name));
299                         continue;
300                 }
301
302                 map->status = ID_MAPPED;
303         }
304 }
305
306 /*
307  * Map unixids to names and then to sids.
308  */
309 static NTSTATUS idmap_rfc2307_unixids_to_sids(struct idmap_domain *dom,
310                                               struct id_map **ids)
311 {
312         struct idmap_rfc2307_context *ctx;
313         char *fltr_usr = NULL, *fltr_grp = NULL;
314         TALLOC_CTX *mem_ctx;
315         int cnt_usr = 0, cnt_grp = 0, idx = 0, bidx = 0;
316         LDAPMessage *result = NULL;
317         NTSTATUS ret;
318
319         ctx = talloc_get_type(dom->private_data, struct idmap_rfc2307_context);
320         mem_ctx = talloc_new(ctx);
321         if (!mem_ctx) {
322                 return NT_STATUS_NO_MEMORY;
323         }
324
325         if (ctx->check_connection) {
326                 ret = ctx->check_connection(dom);
327                 if (!NT_STATUS_IS_OK(ret)) {
328                         goto out;
329                 }
330         }
331
332 again:
333         bidx = idx;
334
335         if (!fltr_usr) {
336                 /* prepare new user query, see getpwuid() in RFC2307 */
337                 fltr_usr = talloc_asprintf(mem_ctx,
338                                              "(&(objectClass=posixAccount)(|");
339         }
340
341         if (!fltr_grp) {
342                 /* prepare new group query, see getgrgid() in RFC2307 */
343                 fltr_grp = talloc_asprintf(mem_ctx,
344                                              "(&(objectClass=posixGroup)(|");
345         }
346
347         if (!fltr_usr || !fltr_grp) {
348                 ret = NT_STATUS_NO_MEMORY;
349                 goto out;
350         }
351
352         while (cnt_usr < IDMAP_LDAP_MAX_IDS &&
353                cnt_grp < IDMAP_LDAP_MAX_IDS && ids[idx]) {
354
355                 switch (ids[idx]->xid.type) {
356                 case ID_TYPE_UID:
357                         fltr_usr = talloc_asprintf_append_buffer(fltr_usr,
358                                         "(uidNumber=%d)", ids[idx]->xid.id);
359                         cnt_usr++;
360                         break;
361                 case ID_TYPE_GID:
362                         fltr_grp = talloc_asprintf_append_buffer(fltr_grp,
363                                         "(gidNumber=%d)", ids[idx]->xid.id);
364                         cnt_grp++;
365                         break;
366                 default:
367                         DEBUG(3, ("Error: unknown ID type %d\n",
368                                   ids[idx]->xid.type));
369                         ret = NT_STATUS_UNSUCCESSFUL;
370                         goto out;
371                 }
372
373                 if (!fltr_usr || !fltr_grp) {
374                         ret = NT_STATUS_NO_MEMORY;
375                         goto out;
376                 }
377
378                 idx++;
379         }
380
381         if (cnt_usr == IDMAP_LDAP_MAX_IDS || (cnt_usr != 0 && !ids[idx])) {
382                 const char *attrs[] = { NULL, /* uid or cn */
383                                         "uidNumber",
384                                         NULL };
385
386                 fltr_usr = talloc_strdup_append(fltr_usr, "))");
387                 if (!fltr_usr) {
388                         ret = NT_STATUS_NO_MEMORY;
389                         goto out;
390                 }
391
392                 attrs[0] = ctx->user_cn ? "cn" : "uid";
393                 ret = ctx->search(ctx, ctx->bind_path_user, fltr_usr, attrs,
394                                   &result);
395                 if (!NT_STATUS_IS_OK(ret)) {
396                         goto out;
397                 }
398
399                 idmap_rfc2307_map_sid_results(ctx, mem_ctx, &ids[bidx], result,
400                                               dom->name, attrs, ID_TYPE_UID);
401                 cnt_usr = 0;
402                 TALLOC_FREE(fltr_usr);
403         }
404
405         if (cnt_grp == IDMAP_LDAP_MAX_IDS || (cnt_grp != 0 && !ids[idx])) {
406                 const char *attrs[] = { "cn", "gidNumber", NULL };
407
408                 fltr_grp = talloc_strdup_append(fltr_grp, "))");
409                 if (!fltr_grp) {
410                         ret = NT_STATUS_NO_MEMORY;
411                         goto out;
412                 }
413                 ret = ctx->search(ctx, ctx->bind_path_group, fltr_grp, attrs,
414                                   &result);
415                 if (!NT_STATUS_IS_OK(ret)) {
416                         goto out;
417                 }
418
419                 idmap_rfc2307_map_sid_results(ctx, mem_ctx, &ids[bidx], result,
420                                               dom->name, attrs, ID_TYPE_GID);
421                 cnt_grp = 0;
422                 TALLOC_FREE(fltr_grp);
423         }
424
425         if (ids[idx]) {
426                 goto again;
427         }
428
429         ret = NT_STATUS_OK;
430
431 out:
432         talloc_free(mem_ctx);
433         return ret;
434 }
435
436 struct idmap_rfc2307_map {
437         struct id_map *map;
438         const char *name;
439         enum id_type type;
440 };
441
442 /*
443  * Lookup names for SIDS and store the data in the local mapping
444  * array.
445  */
446 static NTSTATUS idmap_rfc_2307_sids_to_names(TALLOC_CTX *mem_ctx,
447                                              struct id_map **ids,
448                                              struct idmap_rfc2307_map *maps,
449                                              struct idmap_rfc2307_context *ctx)
450 {
451         int i;
452
453         for (i = 0; ids[i]; i++) {
454                 const char *domain, *name;
455                 enum lsa_SidType lsa_type;
456                 struct id_map *id = ids[i];
457                 struct idmap_rfc2307_map *map = &maps[i];
458                 struct dom_sid_buf buf;
459                 bool b;
460
461                 /* by default calls to winbindd are disabled
462                    the following call will not recurse so this is safe */
463                 (void)winbind_on();
464                 b = winbind_lookup_sid(mem_ctx, ids[i]->sid, &domain, &name,
465                                        &lsa_type);
466                 (void)winbind_off();
467
468                 if (!b) {
469                         DEBUG(1, ("Lookup sid %s failed.\n",
470                                   dom_sid_str_buf(ids[i]->sid, &buf)));
471                         continue;
472                 }
473
474                 switch(lsa_type) {
475                 case SID_NAME_USER:
476                         id->xid.type = map->type = ID_TYPE_UID;
477                         if (ctx->user_cn && ctx->realm != NULL) {
478                                 name = talloc_asprintf(mem_ctx, "%s@%s",
479                                                        name, ctx->realm);
480                         }
481                         id->xid.type = map->type = ID_TYPE_UID;
482                         break;
483
484                 case SID_NAME_DOM_GRP:
485                 case SID_NAME_ALIAS:
486                 case SID_NAME_WKN_GRP:
487                         if (ctx->realm != NULL) {
488                                 name = talloc_asprintf(mem_ctx, "%s@%s",
489                                                        name, ctx->realm);
490                         }
491                         id->xid.type = map->type = ID_TYPE_GID;
492                         break;
493
494                 default:
495                         DEBUG(1, ("Unknown lsa type %d for sid %s\n",
496                                   lsa_type,
497                                   dom_sid_str_buf(id->sid, &buf)));
498                         id->status = ID_UNMAPPED;
499                         continue;
500                 }
501
502                 map->map = id;
503                 id->status = ID_UNKNOWN;
504                 map->name = strupper_talloc(mem_ctx, name);
505
506                 if (!map->name) {
507                         return NT_STATUS_NO_MEMORY;
508                 }
509         }
510
511         return NT_STATUS_OK;
512 }
513
514 /*
515  * Find id_map entry by looking up the name in the internal
516  * mapping array.
517  */
518 static struct id_map* idmap_rfc2307_find_map(struct idmap_rfc2307_map *maps,
519                                              enum id_type type,
520                                              const char *name)
521 {
522         int i;
523
524         DEBUG(10, ("Looking for name %s, type %d\n", name, type));
525
526         for (i = 0; maps[i].map != NULL; i++) {
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, entry);
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(TALLOC_CTX *ctx)
847 {
848         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "rfc2307",
849                                   &rfc2307_methods);
850 }