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