idmap_ad: Use idmap_config_const_string
[sfrench/samba-autobuild/.git] / source3 / winbindd / idmap_ad.c
1 /*
2  * idmap_ad: map between Active Directory and RFC 2307 accounts
3  *
4  * Copyright (C) Volker Lendecke 2015
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "winbindd.h"
22 #include "idmap.h"
23 #include "tldap_gensec_bind.h"
24 #include "tldap_util.h"
25 #include "passdb.h"
26 #include "lib/param/param.h"
27 #include "utils/net.h"
28 #include "auth/gensec/gensec.h"
29 #include "librpc/gen_ndr/ndr_netlogon.h"
30 #include "libads/ldap_schema_oids.h"
31 #include "../libds/common/flags.h"
32 #include "libcli/ldap/ldap_ndr.h"
33 #include "libcli/security/dom_sid.h"
34
35 struct idmap_ad_schema_names;
36
37 struct idmap_ad_context {
38         struct idmap_domain *dom;
39         struct tldap_context *ld;
40         struct idmap_ad_schema_names *schema;
41         const char *default_nc;
42
43         bool unix_primary_group;
44         bool unix_nss_info;
45 };
46
47 static NTSTATUS idmap_ad_get_context(struct idmap_domain *dom,
48                                      struct idmap_ad_context **pctx);
49
50 static char *get_schema_path(TALLOC_CTX *mem_ctx, struct tldap_context *ld)
51 {
52         struct tldap_message *rootdse;
53
54         rootdse = tldap_rootdse(ld);
55         if (rootdse == NULL) {
56                 return NULL;
57         }
58
59         return tldap_talloc_single_attribute(rootdse, "schemaNamingContext",
60                                              mem_ctx);
61 }
62
63 static char *get_default_nc(TALLOC_CTX *mem_ctx, struct tldap_context *ld)
64 {
65         struct tldap_message *rootdse;
66
67         rootdse = tldap_rootdse(ld);
68         if (rootdse == NULL) {
69                 return NULL;
70         }
71
72         return tldap_talloc_single_attribute(rootdse, "defaultNamingContext",
73                                              mem_ctx);
74 }
75
76 struct idmap_ad_schema_names {
77         char *name;
78         char *uid;
79         char *gid;
80         char *gecos;
81         char *dir;
82         char *shell;
83 };
84
85 static TLDAPRC get_attrnames_by_oids(struct tldap_context *ld,
86                                      TALLOC_CTX *mem_ctx,
87                                      const char *schema_path,
88                                      size_t num_oids,
89                                      const char **oids,
90                                      char **names)
91 {
92         char *filter;
93         const char *attrs[] = { "lDAPDisplayName", "attributeId" };
94         size_t i;
95         TLDAPRC rc;
96         struct tldap_message **msgs;
97         size_t num_msgs;
98
99         filter = talloc_strdup(mem_ctx, "(|");
100         if (filter == NULL) {
101                 return TLDAP_NO_MEMORY;
102         }
103
104         for (i=0; i<num_oids; i++) {
105                 filter = talloc_asprintf_append_buffer(
106                         filter, "(attributeId=%s)", oids[i]);
107                 if (filter == NULL) {
108                         return TLDAP_NO_MEMORY;
109                 }
110         }
111
112         filter = talloc_asprintf_append_buffer(filter, ")");
113         if (filter == NULL) {
114                 return TLDAP_NO_MEMORY;
115         }
116
117         rc = tldap_search(ld, schema_path, TLDAP_SCOPE_SUB, filter,
118                           attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
119                           0, 0, 0, mem_ctx, &msgs);;
120         TALLOC_FREE(filter);
121         if (!TLDAP_RC_IS_SUCCESS(rc)) {
122                 return rc;
123         }
124
125         for (i=0; i<num_oids; i++) {
126                 names[i] = NULL;
127         }
128
129         num_msgs = talloc_array_length(msgs);
130
131         for (i=0; i<num_msgs; i++) {
132                 struct tldap_message *msg = msgs[i];
133                 char *oid;
134                 size_t j;
135
136                 if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
137                         /* Could be a TLDAP_RES_SEARCH_REFERENCE */
138                         continue;
139                 }
140
141                 oid = tldap_talloc_single_attribute(
142                         msg, "attributeId", msg);
143                 if (oid == NULL) {
144                         continue;
145                 }
146
147                 for (j=0; j<num_oids; j++) {
148                         if (strequal(oid, oids[j])) {
149                                 break;
150                         }
151                 }
152                 TALLOC_FREE(oid);
153
154                 if (j == num_oids) {
155                         /* not found */
156                         continue;
157                 }
158
159                 names[j] = tldap_talloc_single_attribute(
160                         msg, "lDAPDisplayName", mem_ctx);
161         }
162
163         TALLOC_FREE(msgs);
164
165         return TLDAP_SUCCESS;
166 }
167
168 static TLDAPRC get_posix_schema_names(struct tldap_context *ld,
169                                       const char *schema_mode,
170                                       TALLOC_CTX *mem_ctx,
171                                       struct idmap_ad_schema_names **pschema)
172 {
173         char *schema_path;
174         struct idmap_ad_schema_names *schema;
175         char *names[6];
176         const char *oids_sfu[] = {
177                 ADS_ATTR_SFU_UIDNUMBER_OID,
178                 ADS_ATTR_SFU_GIDNUMBER_OID,
179                 ADS_ATTR_SFU_HOMEDIR_OID,
180                 ADS_ATTR_SFU_SHELL_OID,
181                 ADS_ATTR_SFU_GECOS_OID,
182                 ADS_ATTR_SFU_UID_OID
183         };
184         const char *oids_sfu20[] = {
185                 ADS_ATTR_SFU20_UIDNUMBER_OID,
186                 ADS_ATTR_SFU20_GIDNUMBER_OID,
187                 ADS_ATTR_SFU20_HOMEDIR_OID,
188                 ADS_ATTR_SFU20_SHELL_OID,
189                 ADS_ATTR_SFU20_GECOS_OID,
190                 ADS_ATTR_SFU20_UID_OID
191         };
192         const char *oids_rfc2307[] = {
193                 ADS_ATTR_RFC2307_UIDNUMBER_OID,
194                 ADS_ATTR_RFC2307_GIDNUMBER_OID,
195                 ADS_ATTR_RFC2307_HOMEDIR_OID,
196                 ADS_ATTR_RFC2307_SHELL_OID,
197                 ADS_ATTR_RFC2307_GECOS_OID,
198                 ADS_ATTR_RFC2307_UID_OID
199         };
200         const char **oids;
201
202         TLDAPRC rc;
203
204         schema = talloc(mem_ctx, struct idmap_ad_schema_names);
205         if (schema == NULL) {
206                 return TLDAP_NO_MEMORY;
207         }
208
209         schema_path = get_schema_path(schema, ld);
210         if (schema_path == NULL) {
211                 TALLOC_FREE(schema);
212                 return TLDAP_NO_MEMORY;
213         }
214
215         oids = oids_rfc2307;
216
217         if ((schema_mode != NULL) && (schema_mode[0] != '\0')) {
218                 if (strequal(schema_mode, "sfu")) {
219                         oids = oids_sfu;
220                 } else if (strequal(schema_mode, "sfu20")) {
221                         oids = oids_sfu20;
222                 } else if (strequal(schema_mode, "rfc2307" )) {
223                         oids = oids_rfc2307;
224                 } else {
225                         DBG_WARNING("Unknown schema mode %s\n", schema_mode);
226                 }
227         }
228
229         rc = get_attrnames_by_oids(ld, schema, schema_path, 6, oids, names);
230         TALLOC_FREE(schema_path);
231         if (!TLDAP_RC_IS_SUCCESS(rc)) {
232                 TALLOC_FREE(schema);
233                 return rc;
234         }
235
236         schema->uid = names[0];
237         schema->gid = names[1];
238         schema->dir = names[2];
239         schema->shell = names[3];
240         schema->gecos = names[4];
241         schema->name = names[5];
242
243         *pschema = schema;
244
245         return TLDAP_SUCCESS;
246 }
247
248 static NTSTATUS idmap_ad_get_tldap_ctx(TALLOC_CTX *mem_ctx,
249                                        const char *domname,
250                                        struct tldap_context **pld)
251 {
252         struct netr_DsRGetDCNameInfo *dcinfo;
253         struct sockaddr_storage dcaddr;
254         struct cli_credentials *creds;
255         struct loadparm_context *lp_ctx;
256         struct tldap_context *ld;
257         int fd;
258         NTSTATUS status;
259         bool ok;
260         TLDAPRC rc;
261
262         status = wb_dsgetdcname_gencache_get(mem_ctx, domname, &dcinfo);
263         if (!NT_STATUS_IS_OK(status)) {
264                 DBG_DEBUG("Could not get dcinfo for %s: %s\n", domname,
265                           nt_errstr(status));
266                 return status;
267         }
268
269         if (dcinfo->dc_unc == NULL) {
270                 TALLOC_FREE(dcinfo);
271                 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
272         }
273         if (dcinfo->dc_unc[0] == '\\') {
274                 dcinfo->dc_unc += 1;
275         }
276         if (dcinfo->dc_unc[0] == '\\') {
277                 dcinfo->dc_unc += 1;
278         }
279
280         ok = resolve_name(dcinfo->dc_unc, &dcaddr, 0x20, true);
281         if (!ok) {
282                 DBG_DEBUG("Could not resolve name %s\n", dcinfo->dc_unc);
283                 TALLOC_FREE(dcinfo);
284                 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
285         }
286
287         status = open_socket_out(&dcaddr, 389, 10000, &fd);
288         if (!NT_STATUS_IS_OK(status)) {
289                 DBG_DEBUG("open_socket_out failed: %s\n", nt_errstr(status));
290                 TALLOC_FREE(dcinfo);
291                 return status;
292         }
293
294         ld = tldap_context_create(dcinfo, fd);
295         if (ld == NULL) {
296                 DBG_DEBUG("tldap_context_create failed\n");
297                 close(fd);
298                 TALLOC_FREE(dcinfo);
299                 return NT_STATUS_NO_MEMORY;
300         }
301
302         /*
303          * Here we use or own machine account as
304          * we run as domain member.
305          */
306         status = pdb_get_trust_credentials(lp_workgroup(),
307                                            lp_realm(),
308                                            dcinfo,
309                                            &creds);
310         if (!NT_STATUS_IS_OK(status)) {
311                 DBG_DEBUG("pdb_get_trust_credentials() failed - %s\n",
312                           nt_errstr(status));
313                 TALLOC_FREE(dcinfo);
314                 return status;
315         }
316
317         lp_ctx = loadparm_init_s3(dcinfo, loadparm_s3_helpers());
318         if (lp_ctx == NULL) {
319                 DBG_DEBUG("loadparm_init_s3 failed\n");
320                 TALLOC_FREE(dcinfo);
321                 return NT_STATUS_NO_MEMORY;
322         }
323
324         rc = tldap_gensec_bind(ld, creds, "ldap", dcinfo->dc_unc, NULL, lp_ctx,
325                                GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
326         if (!TLDAP_RC_IS_SUCCESS(rc)) {
327                 DBG_DEBUG("tldap_gensec_bind failed: %s\n",
328                           tldap_errstr(dcinfo, ld, rc));
329                 TALLOC_FREE(dcinfo);
330                 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
331         }
332
333         rc = tldap_fetch_rootdse(ld);
334         if (!TLDAP_RC_IS_SUCCESS(rc)) {
335                 DBG_DEBUG("tldap_fetch_rootdse failed: %s\n",
336                           tldap_errstr(dcinfo, ld, rc));
337                 TALLOC_FREE(dcinfo);
338                 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
339         }
340
341         *pld = talloc_move(mem_ctx, &ld);
342         TALLOC_FREE(dcinfo);
343         return NT_STATUS_OK;
344 }
345
346 static int idmap_ad_context_destructor(struct idmap_ad_context *ctx)
347 {
348         if ((ctx->dom != NULL) && (ctx->dom->private_data == ctx)) {
349                 ctx->dom->private_data = NULL;
350         }
351         return 0;
352 }
353
354 static NTSTATUS idmap_ad_context_create(TALLOC_CTX *mem_ctx,
355                                         struct idmap_domain *dom,
356                                         const char *domname,
357                                         struct idmap_ad_context **pctx)
358 {
359         struct idmap_ad_context *ctx;
360         char *schema_config_option;
361         const char *schema_mode;
362         NTSTATUS status;
363         TLDAPRC rc;
364
365         ctx = talloc(mem_ctx, struct idmap_ad_context);
366         if (ctx == NULL) {
367                 return NT_STATUS_NO_MEMORY;
368         }
369         ctx->dom = dom;
370
371         talloc_set_destructor(ctx, idmap_ad_context_destructor);
372
373         status = idmap_ad_get_tldap_ctx(ctx, domname, &ctx->ld);
374         if (!NT_STATUS_IS_OK(status)) {
375                 DBG_DEBUG("idmap_ad_get_tldap_ctx failed: %s\n",
376                           nt_errstr(status));
377                 TALLOC_FREE(ctx);
378                 return status;
379         }
380
381         ctx->default_nc = get_default_nc(ctx, ctx->ld);
382         if (ctx->default_nc == NULL) {
383                 DBG_DEBUG("No default nc\n");
384                 TALLOC_FREE(ctx);
385                 return status;
386         }
387
388         schema_config_option = talloc_asprintf(
389                 ctx, "idmap config %s", domname);
390         if (schema_config_option == NULL) {
391                 TALLOC_FREE(ctx);
392                 return NT_STATUS_NO_MEMORY;
393         }
394
395         ctx->unix_primary_group = lp_parm_bool(
396                 -1, schema_config_option, "unix_primary_group", false);
397         ctx->unix_nss_info = lp_parm_bool(
398                 -1, schema_config_option, "unix_nss_info", false);
399
400         TALLOC_FREE(schema_config_option);
401
402         schema_mode = idmap_config_const_string(
403                 domname, "schema_mode", "rfc2307");
404
405         rc = get_posix_schema_names(ctx->ld, schema_mode, ctx, &ctx->schema);
406         if (!TLDAP_RC_IS_SUCCESS(rc)) {
407                 DBG_DEBUG("get_posix_schema_names failed: %s\n",
408                           tldap_errstr(ctx, ctx->ld, rc));
409                 TALLOC_FREE(ctx);
410                 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
411         }
412
413         *pctx = ctx;
414         return NT_STATUS_OK;
415 }
416
417 static NTSTATUS idmap_ad_query_user(struct idmap_domain *domain,
418                                     struct wbint_userinfo *info)
419 {
420         struct idmap_ad_context *ctx;
421         TLDAPRC rc;
422         NTSTATUS status;
423         char *sidstr, *filter;
424         const char *attrs[4];
425         size_t i, num_msgs;
426         struct tldap_message **msgs;
427
428         status = idmap_ad_get_context(domain, &ctx);
429         if (!NT_STATUS_IS_OK(status)) {
430                 return status;
431         }
432
433         if (!(ctx->unix_primary_group || ctx->unix_nss_info)) {
434                 return NT_STATUS_OK;
435         }
436
437         attrs[0] = ctx->schema->gid;
438         attrs[1] = ctx->schema->gecos;
439         attrs[2] = ctx->schema->dir;
440         attrs[3] = ctx->schema->shell;
441
442         sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), &info->user_sid);
443         if (sidstr == NULL) {
444                 return NT_STATUS_NO_MEMORY;
445         }
446
447         filter = talloc_asprintf(talloc_tos(), "(objectsid=%s)", sidstr);
448         TALLOC_FREE(sidstr);
449         if (filter == NULL) {
450                 return NT_STATUS_NO_MEMORY;
451         }
452
453         DBG_DEBUG("Filter: [%s]\n", filter);
454
455         rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter,
456                           attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
457                           0, 0, 0, talloc_tos(), &msgs);
458         if (!TLDAP_RC_IS_SUCCESS(rc)) {
459                 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
460         }
461
462         TALLOC_FREE(filter);
463
464         num_msgs = talloc_array_length(msgs);
465
466         for (i=0; i<num_msgs; i++) {
467                 struct tldap_message *msg = msgs[i];
468
469                 if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
470                         continue;
471                 }
472
473                 if (ctx->unix_primary_group) {
474                         bool ok;
475                         uint32_t gid;
476
477                         ok = tldap_pull_uint32(msg, ctx->schema->gid, &gid);
478                         if (ok) {
479                                 DBG_DEBUG("Setting primary group "
480                                           "to %"PRIu32" from attr %s\n",
481                                           gid, ctx->schema->gid);
482                                 info->primary_gid = gid;
483                         }
484                 }
485
486                 if (ctx->unix_nss_info) {
487                         char *attr;
488
489                         attr = tldap_talloc_single_attribute(
490                                 msg, ctx->schema->dir, talloc_tos());
491                         if (attr != NULL) {
492                                 info->homedir = talloc_move(info, &attr);
493                         }
494                         TALLOC_FREE(attr);
495
496                         attr = tldap_talloc_single_attribute(
497                                 msg, ctx->schema->shell, talloc_tos());
498                         if (attr != NULL) {
499                                 info->shell = talloc_move(info, &attr);
500                         }
501                         TALLOC_FREE(attr);
502
503                         attr = tldap_talloc_single_attribute(
504                                 msg, ctx->schema->gecos, talloc_tos());
505                         if (attr != NULL) {
506                                 info->full_name = talloc_move(info, &attr);
507                         }
508                         TALLOC_FREE(attr);
509                 }
510         }
511
512         return NT_STATUS_OK;
513 }
514
515 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom)
516 {
517         dom->query_user = idmap_ad_query_user;
518         dom->private_data = NULL;
519         return NT_STATUS_OK;
520 }
521
522 static NTSTATUS idmap_ad_get_context(struct idmap_domain *dom,
523                                      struct idmap_ad_context **pctx)
524 {
525         struct idmap_ad_context *ctx = NULL;
526         NTSTATUS status;
527
528         if (dom->private_data != NULL) {
529                 *pctx = talloc_get_type_abort(dom->private_data,
530                                               struct idmap_ad_context);
531                 return NT_STATUS_OK;
532         }
533
534         status = idmap_ad_context_create(dom, dom, dom->name, &ctx);
535         if (!NT_STATUS_IS_OK(status)) {
536                 DBG_DEBUG("idmap_ad_context_create failed: %s\n",
537                           nt_errstr(status));
538                 return status;
539         }
540
541         dom->private_data = ctx;
542         *pctx = ctx;
543         return NT_STATUS_OK;
544 }
545
546 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom,
547                                          struct id_map **ids)
548 {
549         struct idmap_ad_context *ctx;
550         TLDAPRC rc;
551         NTSTATUS status;
552         struct tldap_message **msgs;
553
554         size_t i, num_msgs;
555         char *u_filter, *g_filter, *filter;
556
557         const char *attrs[] = {
558                 "sAMAccountType",
559                 "objectSid",
560                 NULL, /* attr_uidnumber */
561                 NULL, /* attr_gidnumber */
562         };
563
564         status = idmap_ad_get_context(dom, &ctx);
565         if (!NT_STATUS_IS_OK(status)) {
566                 return status;
567         }
568
569         attrs[2] = ctx->schema->uid;
570         attrs[3] = ctx->schema->gid;
571
572         u_filter = talloc_strdup(talloc_tos(), "");
573         if (u_filter == NULL) {
574                 return NT_STATUS_NO_MEMORY;
575         }
576
577         g_filter = talloc_strdup(talloc_tos(), "");
578         if (g_filter == NULL) {
579                 return NT_STATUS_NO_MEMORY;
580         }
581
582         for (i=0; ids[i] != NULL; i++) {
583                 struct id_map *id = ids[i];
584
585                 id->status = ID_UNKNOWN;
586
587                 switch (id->xid.type) {
588                     case ID_TYPE_UID: {
589                             u_filter = talloc_asprintf_append_buffer(
590                                     u_filter, "(%s=%ju)", ctx->schema->uid,
591                                     (uintmax_t)id->xid.id);
592                             if (u_filter == NULL) {
593                                     return NT_STATUS_NO_MEMORY;
594                             }
595                             break;
596                     }
597
598                     case ID_TYPE_GID: {
599                             g_filter = talloc_asprintf_append_buffer(
600                                     g_filter, "(%s=%ju)", ctx->schema->gid,
601                                     (uintmax_t)id->xid.id);
602                             if (g_filter == NULL) {
603                                     return NT_STATUS_NO_MEMORY;
604                             }
605                             break;
606                     }
607
608                     default:
609                             DBG_WARNING("Unknown id type: %u\n",
610                                         (unsigned)id->xid.type);
611                             break;
612                 }
613         }
614
615         filter = talloc_strdup(talloc_tos(), "(|");
616         if (filter == NULL) {
617                 return NT_STATUS_NO_MEMORY;
618         }
619
620         if (*u_filter != '\0') {
621                 filter = talloc_asprintf_append_buffer(
622                         filter,
623                         "(&(|(sAMAccountType=%d)(sAMAccountType=%d)"
624                         "(sAMAccountType=%d))(|%s))",
625                         ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST,
626                         ATYPE_INTERDOMAIN_TRUST, u_filter);
627                 if (filter == NULL) {
628                         return NT_STATUS_NO_MEMORY;
629                 }
630         }
631         TALLOC_FREE(u_filter);
632
633         if (*g_filter != '\0') {
634                 filter = talloc_asprintf_append_buffer(
635                         filter,
636                         "(&(|(sAMAccountType=%d)(sAMAccountType=%d))(|%s))",
637                         ATYPE_SECURITY_GLOBAL_GROUP,
638                         ATYPE_SECURITY_LOCAL_GROUP,
639                         g_filter);
640                 if (filter == NULL) {
641                         return NT_STATUS_NO_MEMORY;
642                 }
643         }
644         TALLOC_FREE(g_filter);
645
646         filter = talloc_asprintf_append_buffer(filter, ")");
647         if (filter == NULL) {
648                 return NT_STATUS_NO_MEMORY;
649         }
650
651         DBG_DEBUG("Filter: [%s]\n", filter);
652
653         rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter,
654                           attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
655                           0, 0, 0, talloc_tos(), &msgs);
656         if (!TLDAP_RC_IS_SUCCESS(rc)) {
657                 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
658         }
659
660         TALLOC_FREE(filter);
661
662         num_msgs = talloc_array_length(msgs);
663
664         for (i=0; i<num_msgs; i++) {
665                 struct tldap_message *msg = msgs[i];
666                 char *dn;
667                 struct id_map *map;
668                 struct dom_sid sid;
669                 size_t j;
670                 bool ok;
671                 uint32_t atype, xid;
672                 enum id_type type;
673
674                 if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
675                         continue;
676                 }
677
678                 ok = tldap_entry_dn(msg, &dn);
679                 if (!ok) {
680                         DBG_DEBUG("No dn found in msg %zu\n", i);
681                         continue;
682                 }
683
684                 ok = tldap_pull_uint32(msg, "sAMAccountType", &atype);
685                 if (!ok) {
686                         DBG_DEBUG("No atype in object %s\n", dn);
687                         continue;
688                 }
689
690                 switch (atype & 0xF0000000) {
691                     case ATYPE_SECURITY_GLOBAL_GROUP:
692                     case ATYPE_SECURITY_LOCAL_GROUP:
693                             type = ID_TYPE_GID;
694                             break;
695                     case ATYPE_NORMAL_ACCOUNT:
696                     case ATYPE_WORKSTATION_TRUST:
697                     case ATYPE_INTERDOMAIN_TRUST:
698                             type = ID_TYPE_UID;
699                             break;
700                     default:
701                             DBG_WARNING("unrecognized SAM account type %08x\n",
702                                         atype);
703                         continue;
704                 }
705
706                 ok = tldap_pull_uint32(msg, (type == ID_TYPE_UID) ?
707                                        ctx->schema->uid : ctx->schema->gid,
708                                        &xid);
709                 if (!ok) {
710                         DBG_WARNING("No unix id in object %s\n", dn);
711                         continue;
712                 }
713
714                 ok = tldap_pull_binsid(msg, "objectSid", &sid);
715                 if (!ok) {
716                         DBG_DEBUG("No objectSid in object %s\n", dn);
717                         continue;
718                 }
719
720                 map = NULL;
721                 for (j=0; ids[j]; j++) {
722                         if ((type == ids[j]->xid.type) &&
723                             (xid == ids[j]->xid.id)) {
724                                 map = ids[j];
725                                 break;
726                         }
727                 }
728                 if (map == NULL) {
729                         DBG_DEBUG("Got unexpected sid %s from object %s\n",
730                                   sid_string_tos(&sid), dn);
731                         continue;
732                 }
733
734                 sid_copy(map->sid, &sid);
735                 map->status = ID_MAPPED;
736
737                 DBG_DEBUG("Mapped %s -> %ju (%d)\n", sid_string_dbg(map->sid),
738                           (uintmax_t)map->xid.id, map->xid.type);
739         }
740
741         TALLOC_FREE(msgs);
742
743         return NT_STATUS_OK;
744 }
745
746 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom,
747                                          struct id_map **ids)
748 {
749         struct idmap_ad_context *ctx;
750         TLDAPRC rc;
751         NTSTATUS status;
752         struct tldap_message **msgs;
753
754         char *filter;
755         size_t i, num_msgs;
756
757         const char *attrs[] = {
758                 "sAMAccountType",
759                 "objectSid",
760                 NULL, /* attr_uidnumber */
761                 NULL, /* attr_gidnumber */
762         };
763
764         status = idmap_ad_get_context(dom, &ctx);
765         if (!NT_STATUS_IS_OK(status)) {
766                 return status;
767         }
768
769         attrs[2] = ctx->schema->uid;
770         attrs[3] = ctx->schema->gid;
771
772         filter = talloc_asprintf(
773                 talloc_tos(),
774                 "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)"
775                 "(sAMAccountType=%d)(sAMAccountType=%d))(|",
776                 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST,
777                 ATYPE_INTERDOMAIN_TRUST, ATYPE_SECURITY_GLOBAL_GROUP,
778                 ATYPE_SECURITY_LOCAL_GROUP);
779         if (filter == NULL) {
780                 return NT_STATUS_NO_MEMORY;
781         }
782
783         for (i=0; ids[i]; i++) {
784                 char *sidstr;
785
786                 ids[i]->status = ID_UNKNOWN;
787
788                 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), ids[i]->sid);
789                 if (sidstr == NULL) {
790                         return NT_STATUS_NO_MEMORY;
791                 }
792
793                 filter = talloc_asprintf_append_buffer(
794                         filter, "(objectSid=%s)", sidstr);
795                 TALLOC_FREE(sidstr);
796                 if (filter == NULL) {
797                         return NT_STATUS_NO_MEMORY;
798                 }
799         }
800
801         filter = talloc_asprintf_append_buffer(filter, "))");
802         if (filter == NULL) {
803                 return NT_STATUS_NO_MEMORY;
804         }
805
806         DBG_DEBUG("Filter: [%s]\n", filter);
807
808         rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter,
809                           attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
810                           0, 0, 0, talloc_tos(), &msgs);
811         if (!TLDAP_RC_IS_SUCCESS(rc)) {
812                 return NT_STATUS_LDAP(TLDAP_RC_V(rc));
813         }
814
815         TALLOC_FREE(filter);
816
817         num_msgs = talloc_array_length(msgs);
818
819         for (i=0; i<num_msgs; i++) {
820                 struct tldap_message *msg = msgs[i];
821                 char *dn;
822                 struct id_map *map;
823                 struct dom_sid sid;
824                 size_t j;
825                 bool ok;
826                 uint64_t account_type, xid;
827                 enum id_type type;
828
829                 if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
830                         continue;
831                 }
832
833                 ok = tldap_entry_dn(msg, &dn);
834                 if (!ok) {
835                         DBG_DEBUG("No dn found in msg %zu\n", i);
836                         continue;
837                 }
838
839                 ok = tldap_pull_binsid(msg, "objectSid", &sid);
840                 if (!ok) {
841                         DBG_DEBUG("No objectSid in object %s\n", dn);
842                         continue;
843                 }
844
845                 map = NULL;
846                 for (j=0; ids[j]; j++) {
847                         if (dom_sid_equal(&sid, ids[j]->sid)) {
848                                 map = ids[j];
849                                 break;
850                         }
851                 }
852                 if (map == NULL) {
853                         DBG_DEBUG("Got unexpected sid %s from object %s\n",
854                                   sid_string_tos(&sid), dn);
855                         continue;
856                 }
857
858                 ok = tldap_pull_uint64(msg, "sAMAccountType", &account_type);
859                 if (!ok) {
860                         DBG_DEBUG("No sAMAccountType in %s\n", dn);
861                         continue;
862                 }
863
864                 switch (account_type & 0xF0000000) {
865                 case ATYPE_SECURITY_GLOBAL_GROUP:
866                 case ATYPE_SECURITY_LOCAL_GROUP:
867                         type = ID_TYPE_GID;
868                         break;
869                 case ATYPE_NORMAL_ACCOUNT:
870                 case ATYPE_WORKSTATION_TRUST:
871                 case ATYPE_INTERDOMAIN_TRUST:
872                         type = ID_TYPE_UID;
873                         break;
874                 default:
875                         DBG_WARNING("unrecognized SAM account type %"PRIu64"\n",
876                                     account_type);
877                         continue;
878                 }
879
880                 ok = tldap_pull_uint64(msg,
881                                        type == ID_TYPE_UID ?
882                                        ctx->schema->uid : ctx->schema->gid,
883                                        &xid);
884                 if (!ok) {
885                         DBG_DEBUG("No xid in %s\n", dn);
886                         continue;
887                 }
888
889                 /* mapped */
890                 map->xid.type = type;
891                 map->xid.id = xid;
892                 map->status = ID_MAPPED;
893
894                 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
895                            (unsigned long)map->xid.id, map->xid.type));
896         }
897
898         TALLOC_FREE(msgs);
899
900         return NT_STATUS_OK;
901 }
902
903 static NTSTATUS idmap_ad_unixids_to_sids_retry(struct idmap_domain *dom,
904                                                struct id_map **ids)
905 {
906         const NTSTATUS status_server_down =
907                 NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN));
908         NTSTATUS status;
909
910         status = idmap_ad_unixids_to_sids(dom, ids);
911
912         if (NT_STATUS_EQUAL(status, status_server_down)) {
913                 TALLOC_FREE(dom->private_data);
914                 status = idmap_ad_unixids_to_sids(dom, ids);
915         }
916
917         return status;
918 }
919
920 static NTSTATUS idmap_ad_sids_to_unixids_retry(struct idmap_domain *dom,
921                                                struct id_map **ids)
922 {
923         const NTSTATUS status_server_down =
924                 NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN));
925         NTSTATUS status;
926
927         status = idmap_ad_sids_to_unixids(dom, ids);
928
929         if (NT_STATUS_EQUAL(status, status_server_down)) {
930                 TALLOC_FREE(dom->private_data);
931                 status = idmap_ad_sids_to_unixids(dom, ids);
932         }
933
934         return status;
935 }
936
937 static struct idmap_methods ad_methods = {
938         .init            = idmap_ad_initialize,
939         .unixids_to_sids = idmap_ad_unixids_to_sids_retry,
940         .sids_to_unixids = idmap_ad_sids_to_unixids_retry,
941 };
942
943 static_decl_idmap;
944 NTSTATUS idmap_ad_init(void)
945 {
946         NTSTATUS status;
947
948         status = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
949                                     "ad", &ad_methods);
950         if (!NT_STATUS_IS_OK(status)) {
951                 return status;
952         }
953
954         status = idmap_ad_nss_init();
955         if (!NT_STATUS_IS_OK(status)) {
956                 return status;
957         }
958
959         return NT_STATUS_OK;
960 }