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