s3-winbindd: Move code for verifying ADS connection to common helper function
[Samba/gebeck_regimport.git] / source3 / winbindd / idmap_ad.c
blob0e00a340bf24c365431c85607a3fd990d89231ab
1 /*
2 * idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts
4 * Unix SMB/CIFS implementation.
6 * Winbind ADS backend functions
8 * Copyright (C) Andrew Tridgell 2001
9 * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
10 * Copyright (C) Gerald (Jerry) Carter 2004-2007
11 * Copyright (C) Luke Howard 2001-2004
12 * Copyright (C) Michael Adam 2008,2010
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 #include "includes.h"
29 #include "winbindd.h"
30 #include "../libds/common/flags.h"
31 #include "ads.h"
32 #include "libads/ldap_schema.h"
33 #include "nss_info.h"
34 #include "secrets.h"
35 #include "idmap.h"
36 #include "../libcli/ldap/ldap_ndr.h"
37 #include "../libcli/security/security.h"
39 #undef DBGC_CLASS
40 #define DBGC_CLASS DBGC_IDMAP
42 #define CHECK_ALLOC_DONE(mem) do { \
43 if (!mem) { \
44 DEBUG(0, ("Out of memory!\n")); \
45 ret = NT_STATUS_NO_MEMORY; \
46 goto done; \
47 } \
48 } while (0)
50 struct idmap_ad_context {
51 ADS_STRUCT *ads;
52 struct posix_schema *ad_schema;
53 enum wb_posix_mapping ad_map_type; /* WB_POSIX_MAP_UNKNOWN */
56 /************************************************************************
57 ***********************************************************************/
59 static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom)
61 ADS_STRUCT *ads;
62 ADS_STATUS status;
63 fstring dc_name;
64 struct sockaddr_storage dc_ip;
65 struct idmap_ad_context *ctx;
66 char *ldap_server = NULL;
67 char *realm = NULL;
68 struct winbindd_domain *wb_dom;
70 DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
71 dom->name));
73 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
75 ads_cached_connection_reuse(&ctx->ads);
76 if (ctx->ads != NULL) {
77 return ADS_SUCCESS;
80 /* we don't want this to affect the users ccache */
81 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
84 * At this point we only have the NetBIOS domain name.
85 * Check if we can get server nam and realm from SAF cache
86 * and the domain list.
88 ldap_server = saf_fetch(dom->name);
89 DEBUG(10, ("ldap_server from saf cache: '%s'\n", ldap_server?ldap_server:""));
91 wb_dom = find_domain_from_name_noinit(dom->name);
92 if (wb_dom == NULL) {
93 DEBUG(10, ("find_domain_from_name_noinit did not find domain '%s'\n",
94 dom->name));
95 realm = NULL;
96 } else {
97 DEBUG(10, ("find_domain_from_name_noinit found realm '%s' for "
98 " domain '%s'\n", wb_dom->alt_name, dom->name));
99 realm = wb_dom->alt_name;
102 if ( (ads = ads_init(realm, dom->name, ldap_server)) == NULL ) {
103 DEBUG(1,("ads_init failed\n"));
104 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
107 /* the machine acct password might have change - fetch it every time */
108 SAFE_FREE(ads->auth.password);
109 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
111 SAFE_FREE(ads->auth.realm);
112 ads->auth.realm = SMB_STRDUP(lp_realm());
114 /* setup server affinity */
116 get_dc_name(dom->name, realm, dc_name, &dc_ip );
118 status = ads_connect(ads);
119 if (!ADS_ERR_OK(status)) {
120 DEBUG(1, ("ad_idmap_cached_connection_internal: failed to "
121 "connect to AD\n"));
122 ads_destroy(&ads);
123 return status;
126 ads->is_mine = False;
128 ctx->ads = ads;
130 return ADS_SUCCESS;
133 /************************************************************************
134 ***********************************************************************/
136 static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom)
138 ADS_STATUS status;
139 struct idmap_ad_context * ctx;
141 status = ad_idmap_cached_connection_internal(dom);
142 if (!ADS_ERR_OK(status)) {
143 return status;
146 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
148 /* if we have a valid ADS_STRUCT and the schema model is
149 defined, then we can return here. */
151 if ( ctx->ad_schema ) {
152 return ADS_SUCCESS;
155 /* Otherwise, set the schema model */
157 if ( (ctx->ad_map_type == WB_POSIX_MAP_SFU) ||
158 (ctx->ad_map_type == WB_POSIX_MAP_SFU20) ||
159 (ctx->ad_map_type == WB_POSIX_MAP_RFC2307) )
161 status = ads_check_posix_schema_mapping(
162 ctx, ctx->ads, ctx->ad_map_type, &ctx->ad_schema);
163 if ( !ADS_ERR_OK(status) ) {
164 DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
168 return status;
171 static int idmap_ad_context_destructor(struct idmap_ad_context *ctx)
173 if (ctx->ads != NULL) {
174 /* we own this ADS_STRUCT so make sure it goes away */
175 ctx->ads->is_mine = True;
176 ads_destroy( &ctx->ads );
177 ctx->ads = NULL;
179 return 0;
182 /************************************************************************
183 ***********************************************************************/
185 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom)
187 struct idmap_ad_context *ctx;
188 char *config_option;
189 const char *schema_mode = NULL;
191 ctx = talloc_zero(dom, struct idmap_ad_context);
192 if (ctx == NULL) {
193 DEBUG(0, ("Out of memory!\n"));
194 return NT_STATUS_NO_MEMORY;
196 talloc_set_destructor(ctx, idmap_ad_context_destructor);
198 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
199 if (config_option == NULL) {
200 DEBUG(0, ("Out of memory!\n"));
201 talloc_free(ctx);
202 return NT_STATUS_NO_MEMORY;
205 /* default map type */
206 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
208 /* schema mode */
209 schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL);
210 if ( schema_mode && schema_mode[0] ) {
211 if ( strequal(schema_mode, "sfu") )
212 ctx->ad_map_type = WB_POSIX_MAP_SFU;
213 else if ( strequal(schema_mode, "sfu20" ) )
214 ctx->ad_map_type = WB_POSIX_MAP_SFU20;
215 else if ( strequal(schema_mode, "rfc2307" ) )
216 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
217 else
218 DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n",
219 schema_mode));
222 dom->private_data = ctx;
224 talloc_free(config_option);
226 return NT_STATUS_OK;
229 /************************************************************************
230 ***********************************************************************/
232 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
234 NTSTATUS ret;
235 TALLOC_CTX *memctx;
236 struct idmap_ad_context *ctx;
237 ADS_STATUS rc;
238 const char *attrs[] = { "sAMAccountType",
239 "objectSid",
240 NULL, /* uidnumber */
241 NULL, /* gidnumber */
242 NULL };
243 LDAPMessage *res = NULL;
244 LDAPMessage *entry = NULL;
245 char *filter = NULL;
246 int idx = 0;
247 int bidx = 0;
248 int count;
249 int i;
250 char *u_filter = NULL;
251 char *g_filter = NULL;
253 /* initialize the status to avoid suprise */
254 for (i = 0; ids[i]; i++) {
255 ids[i]->status = ID_UNKNOWN;
258 /* Only do query if we are online */
259 if (idmap_is_offline()) {
260 return NT_STATUS_FILE_IS_OFFLINE;
263 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
265 if ( (memctx = talloc_new(ctx)) == NULL ) {
266 DEBUG(0, ("Out of memory!\n"));
267 return NT_STATUS_NO_MEMORY;
270 rc = ad_idmap_cached_connection(dom);
271 if (!ADS_ERR_OK(rc)) {
272 DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
273 ret = NT_STATUS_UNSUCCESSFUL;
274 /* ret = ads_ntstatus(rc); */
275 goto done;
278 attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
279 attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
281 again:
282 bidx = idx;
283 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
284 switch (ids[idx]->xid.type) {
285 case ID_TYPE_UID:
286 if ( ! u_filter) {
287 u_filter = talloc_asprintf(memctx, "(&(|"
288 "(sAMAccountType=%d)"
289 "(sAMAccountType=%d)"
290 "(sAMAccountType=%d))(|",
291 ATYPE_NORMAL_ACCOUNT,
292 ATYPE_WORKSTATION_TRUST,
293 ATYPE_INTERDOMAIN_TRUST);
295 u_filter = talloc_asprintf_append_buffer(u_filter, "(%s=%lu)",
296 ctx->ad_schema->posix_uidnumber_attr,
297 (unsigned long)ids[idx]->xid.id);
298 CHECK_ALLOC_DONE(u_filter);
299 break;
301 case ID_TYPE_GID:
302 if ( ! g_filter) {
303 g_filter = talloc_asprintf(memctx, "(&(|"
304 "(sAMAccountType=%d)"
305 "(sAMAccountType=%d))(|",
306 ATYPE_SECURITY_GLOBAL_GROUP,
307 ATYPE_SECURITY_LOCAL_GROUP);
309 g_filter = talloc_asprintf_append_buffer(g_filter, "(%s=%lu)",
310 ctx->ad_schema->posix_gidnumber_attr,
311 (unsigned long)ids[idx]->xid.id);
312 CHECK_ALLOC_DONE(g_filter);
313 break;
315 default:
316 DEBUG(3, ("Error: mapping requested but Unknown ID type\n"));
317 ids[idx]->status = ID_UNKNOWN;
318 continue;
321 filter = talloc_asprintf(memctx, "(|");
322 CHECK_ALLOC_DONE(filter);
323 if ( u_filter) {
324 filter = talloc_asprintf_append_buffer(filter, "%s))", u_filter);
325 CHECK_ALLOC_DONE(filter);
326 TALLOC_FREE(u_filter);
328 if ( g_filter) {
329 filter = talloc_asprintf_append_buffer(filter, "%s))", g_filter);
330 CHECK_ALLOC_DONE(filter);
331 TALLOC_FREE(g_filter);
333 filter = talloc_asprintf_append_buffer(filter, ")");
334 CHECK_ALLOC_DONE(filter);
336 rc = ads_search_retry(ctx->ads, &res, filter, attrs);
337 if (!ADS_ERR_OK(rc)) {
338 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
339 ret = NT_STATUS_UNSUCCESSFUL;
340 goto done;
343 if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
344 DEBUG(10, ("No IDs found\n"));
347 entry = res;
348 for (i = 0; (i < count) && entry; i++) {
349 struct dom_sid sid;
350 enum id_type type;
351 struct id_map *map;
352 uint32_t id;
353 uint32_t atype;
355 if (i == 0) { /* first entry */
356 entry = ads_first_entry(ctx->ads, entry);
357 } else { /* following ones */
358 entry = ads_next_entry(ctx->ads, entry);
361 if ( !entry ) {
362 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
363 break;
366 /* first check if the SID is present */
367 if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
368 DEBUG(2, ("Could not retrieve SID from entry\n"));
369 continue;
372 /* get type */
373 if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
374 DEBUG(1, ("could not get SAM account type\n"));
375 continue;
378 switch (atype & 0xF0000000) {
379 case ATYPE_SECURITY_GLOBAL_GROUP:
380 case ATYPE_SECURITY_LOCAL_GROUP:
381 type = ID_TYPE_GID;
382 break;
383 case ATYPE_NORMAL_ACCOUNT:
384 case ATYPE_WORKSTATION_TRUST:
385 case ATYPE_INTERDOMAIN_TRUST:
386 type = ID_TYPE_UID;
387 break;
388 default:
389 DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
390 continue;
393 if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
394 ctx->ad_schema->posix_uidnumber_attr :
395 ctx->ad_schema->posix_gidnumber_attr,
396 &id))
398 DEBUG(1, ("Could not get unix ID\n"));
399 continue;
402 if (!idmap_unix_id_is_in_range(id, dom)) {
403 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
404 id, dom->low_id, dom->high_id));
405 continue;
408 map = idmap_find_map_by_id(&ids[bidx], type, id);
409 if (!map) {
410 DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
411 continue;
414 sid_copy(map->sid, &sid);
416 /* mapped */
417 map->status = ID_MAPPED;
419 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
420 (unsigned long)map->xid.id,
421 map->xid.type));
424 if (res) {
425 ads_msgfree(ctx->ads, res);
428 if (ids[idx]) { /* still some values to map */
429 goto again;
432 ret = NT_STATUS_OK;
434 /* mark all unknown/expired ones as unmapped */
435 for (i = 0; ids[i]; i++) {
436 if (ids[i]->status != ID_MAPPED)
437 ids[i]->status = ID_UNMAPPED;
440 done:
441 talloc_free(memctx);
442 return ret;
445 /************************************************************************
446 ***********************************************************************/
448 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
450 NTSTATUS ret;
451 TALLOC_CTX *memctx;
452 struct idmap_ad_context *ctx;
453 ADS_STATUS rc;
454 const char *attrs[] = { "sAMAccountType",
455 "objectSid",
456 NULL, /* attr_uidnumber */
457 NULL, /* attr_gidnumber */
458 NULL };
459 LDAPMessage *res = NULL;
460 LDAPMessage *entry = NULL;
461 char *filter = NULL;
462 int idx = 0;
463 int bidx = 0;
464 int count;
465 int i;
466 char *sidstr;
468 /* initialize the status to avoid suprise */
469 for (i = 0; ids[i]; i++) {
470 ids[i]->status = ID_UNKNOWN;
473 /* Only do query if we are online */
474 if (idmap_is_offline()) {
475 return NT_STATUS_FILE_IS_OFFLINE;
478 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
480 if ( (memctx = talloc_new(ctx)) == NULL ) {
481 DEBUG(0, ("Out of memory!\n"));
482 return NT_STATUS_NO_MEMORY;
485 rc = ad_idmap_cached_connection(dom);
486 if (!ADS_ERR_OK(rc)) {
487 DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
488 ret = NT_STATUS_UNSUCCESSFUL;
489 /* ret = ads_ntstatus(rc); */
490 goto done;
493 if (ctx->ad_schema == NULL) {
494 DEBUG(0, ("haven't got ctx->ad_schema ! \n"));
495 ret = NT_STATUS_UNSUCCESSFUL;
496 goto done;
499 attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
500 attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
502 again:
503 filter = talloc_asprintf(memctx, "(&(|"
504 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
505 "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
506 ")(|",
507 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
508 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
510 CHECK_ALLOC_DONE(filter);
512 bidx = idx;
513 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
515 ids[idx]->status = ID_UNKNOWN;
517 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), ids[idx]->sid);
518 filter = talloc_asprintf_append_buffer(filter, "(objectSid=%s)", sidstr);
520 TALLOC_FREE(sidstr);
521 CHECK_ALLOC_DONE(filter);
523 filter = talloc_asprintf_append_buffer(filter, "))");
524 CHECK_ALLOC_DONE(filter);
525 DEBUG(10, ("Filter: [%s]\n", filter));
527 rc = ads_search_retry(ctx->ads, &res, filter, attrs);
528 if (!ADS_ERR_OK(rc)) {
529 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
530 ret = NT_STATUS_UNSUCCESSFUL;
531 goto done;
534 if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
535 DEBUG(10, ("No IDs found\n"));
538 entry = res;
539 for (i = 0; (i < count) && entry; i++) {
540 struct dom_sid sid;
541 enum id_type type;
542 struct id_map *map;
543 uint32_t id;
544 uint32_t atype;
546 if (i == 0) { /* first entry */
547 entry = ads_first_entry(ctx->ads, entry);
548 } else { /* following ones */
549 entry = ads_next_entry(ctx->ads, entry);
552 if ( !entry ) {
553 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
554 break;
557 /* first check if the SID is present */
558 if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
559 DEBUG(2, ("Could not retrieve SID from entry\n"));
560 continue;
563 map = idmap_find_map_by_sid(&ids[bidx], &sid);
564 if (!map) {
565 DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
566 continue;
569 /* get type */
570 if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
571 DEBUG(1, ("could not get SAM account type\n"));
572 continue;
575 switch (atype & 0xF0000000) {
576 case ATYPE_SECURITY_GLOBAL_GROUP:
577 case ATYPE_SECURITY_LOCAL_GROUP:
578 type = ID_TYPE_GID;
579 break;
580 case ATYPE_NORMAL_ACCOUNT:
581 case ATYPE_WORKSTATION_TRUST:
582 case ATYPE_INTERDOMAIN_TRUST:
583 type = ID_TYPE_UID;
584 break;
585 default:
586 DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
587 continue;
590 if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
591 ctx->ad_schema->posix_uidnumber_attr :
592 ctx->ad_schema->posix_gidnumber_attr,
593 &id))
595 DEBUG(1, ("Could not get unix ID\n"));
596 continue;
598 if (!idmap_unix_id_is_in_range(id, dom)) {
599 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
600 id, dom->low_id, dom->high_id));
601 continue;
604 /* mapped */
605 map->xid.type = type;
606 map->xid.id = id;
607 map->status = ID_MAPPED;
609 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
610 (unsigned long)map->xid.id,
611 map->xid.type));
614 if (res) {
615 ads_msgfree(ctx->ads, res);
618 if (ids[idx]) { /* still some values to map */
619 goto again;
622 ret = NT_STATUS_OK;
624 /* mark all unknown/expired ones as unmapped */
625 for (i = 0; ids[i]; i++) {
626 if (ids[i]->status != ID_MAPPED)
627 ids[i]->status = ID_UNMAPPED;
630 done:
631 talloc_free(memctx);
632 return ret;
636 * nss_info_{sfu,sfu20,rfc2307}
639 /************************************************************************
640 Initialize the {sfu,sfu20,rfc2307} state
641 ***********************************************************************/
643 static const char *wb_posix_map_unknown_string = "WB_POSIX_MAP_UNKNOWN";
644 static const char *wb_posix_map_template_string = "WB_POSIX_MAP_TEMPLATE";
645 static const char *wb_posix_map_sfu_string = "WB_POSIX_MAP_SFU";
646 static const char *wb_posix_map_sfu20_string = "WB_POSIX_MAP_SFU20";
647 static const char *wb_posix_map_rfc2307_string = "WB_POSIX_MAP_RFC2307";
648 static const char *wb_posix_map_unixinfo_string = "WB_POSIX_MAP_UNIXINFO";
650 static const char *ad_map_type_string(enum wb_posix_mapping map_type)
652 switch (map_type) {
653 case WB_POSIX_MAP_TEMPLATE:
654 return wb_posix_map_template_string;
655 case WB_POSIX_MAP_SFU:
656 return wb_posix_map_sfu_string;
657 case WB_POSIX_MAP_SFU20:
658 return wb_posix_map_sfu20_string;
659 case WB_POSIX_MAP_RFC2307:
660 return wb_posix_map_rfc2307_string;
661 case WB_POSIX_MAP_UNIXINFO:
662 return wb_posix_map_unixinfo_string;
663 default:
664 return wb_posix_map_unknown_string;
668 static NTSTATUS nss_ad_generic_init(struct nss_domain_entry *e,
669 enum wb_posix_mapping new_ad_map_type)
671 struct idmap_domain *dom;
672 struct idmap_ad_context *ctx;
674 if (e->state != NULL) {
675 dom = talloc_get_type(e->state, struct idmap_domain);
676 } else {
677 dom = talloc_zero(e, struct idmap_domain);
678 if (dom == NULL) {
679 DEBUG(0, ("Out of memory!\n"));
680 return NT_STATUS_NO_MEMORY;
682 e->state = dom;
685 if (e->domain != NULL) {
686 dom->name = talloc_strdup(dom, e->domain);
687 if (dom->name == NULL) {
688 DEBUG(0, ("Out of memory!\n"));
689 return NT_STATUS_NO_MEMORY;
693 if (dom->private_data != NULL) {
694 ctx = talloc_get_type(dom->private_data,
695 struct idmap_ad_context);
696 } else {
697 ctx = talloc_zero(dom, struct idmap_ad_context);
698 if (ctx == NULL) {
699 DEBUG(0, ("Out of memory!\n"));
700 return NT_STATUS_NO_MEMORY;
702 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
703 dom->private_data = ctx;
706 if ((ctx->ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
707 (ctx->ad_map_type != new_ad_map_type))
709 DEBUG(2, ("nss_ad_generic_init: "
710 "Warning: overriding previously set posix map type "
711 "%s for domain %s with map type %s.\n",
712 ad_map_type_string(ctx->ad_map_type),
713 dom->name,
714 ad_map_type_string(new_ad_map_type)));
717 ctx->ad_map_type = new_ad_map_type;
719 return NT_STATUS_OK;
722 static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
724 return nss_ad_generic_init(e, WB_POSIX_MAP_SFU);
727 static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e )
729 return nss_ad_generic_init(e, WB_POSIX_MAP_SFU20);
732 static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
734 return nss_ad_generic_init(e, WB_POSIX_MAP_RFC2307);
738 /************************************************************************
739 ***********************************************************************/
741 static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e,
742 const struct dom_sid *sid,
743 TALLOC_CTX *mem_ctx,
744 const char **homedir,
745 const char **shell,
746 const char **gecos,
747 uint32 *gid )
749 const char *attrs[] = {NULL, /* attr_homedir */
750 NULL, /* attr_shell */
751 NULL, /* attr_gecos */
752 NULL, /* attr_gidnumber */
753 NULL };
754 char *filter = NULL;
755 LDAPMessage *msg_internal = NULL;
756 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
757 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
758 char *sidstr = NULL;
759 struct idmap_domain *dom;
760 struct idmap_ad_context *ctx;
762 DEBUG(10, ("nss_ad_get_info called for sid [%s] in domain '%s'\n",
763 sid_string_dbg(sid), e->domain?e->domain:"NULL"));
765 /* Only do query if we are online */
766 if (idmap_is_offline()) {
767 return NT_STATUS_FILE_IS_OFFLINE;
770 dom = talloc_get_type(e->state, struct idmap_domain);
771 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
773 ads_status = ad_idmap_cached_connection(dom);
774 if (!ADS_ERR_OK(ads_status)) {
775 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
778 if (!ctx->ad_schema) {
779 DEBUG(10, ("nss_ad_get_info: no ad_schema configured!\n"));
780 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
783 if (!sid || !homedir || !shell || !gecos) {
784 return NT_STATUS_INVALID_PARAMETER;
787 /* Have to do our own query */
789 DEBUG(10, ("nss_ad_get_info: no ads connection given, doing our "
790 "own query\n"));
792 attrs[0] = ctx->ad_schema->posix_homedir_attr;
793 attrs[1] = ctx->ad_schema->posix_shell_attr;
794 attrs[2] = ctx->ad_schema->posix_gecos_attr;
795 attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
797 sidstr = ldap_encode_ndr_dom_sid(mem_ctx, sid);
798 filter = talloc_asprintf(mem_ctx, "(objectSid=%s)", sidstr);
799 TALLOC_FREE(sidstr);
801 if (!filter) {
802 nt_status = NT_STATUS_NO_MEMORY;
803 goto done;
806 ads_status = ads_search_retry(ctx->ads, &msg_internal, filter, attrs);
807 if (!ADS_ERR_OK(ads_status)) {
808 nt_status = ads_ntstatus(ads_status);
809 goto done;
812 *homedir = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_homedir_attr);
813 *shell = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_shell_attr);
814 *gecos = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_gecos_attr);
816 if (gid) {
817 if (!ads_pull_uint32(ctx->ads, msg_internal, ctx->ad_schema->posix_gidnumber_attr, gid))
818 *gid = (uint32)-1;
821 nt_status = NT_STATUS_OK;
823 done:
824 if (msg_internal) {
825 ads_msgfree(ctx->ads, msg_internal);
828 return nt_status;
831 /**********************************************************************
832 *********************************************************************/
834 static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx,
835 struct nss_domain_entry *e,
836 const char *name,
837 char **alias)
839 const char *attrs[] = {NULL, /* attr_uid */
840 NULL };
841 char *filter = NULL;
842 LDAPMessage *msg = NULL;
843 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
844 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
845 struct idmap_domain *dom;
846 struct idmap_ad_context *ctx = NULL;
848 /* Check incoming parameters */
850 if ( !e || !e->domain || !name || !*alias) {
851 nt_status = NT_STATUS_INVALID_PARAMETER;
852 goto done;
855 /* Only do query if we are online */
857 if (idmap_is_offline()) {
858 nt_status = NT_STATUS_FILE_IS_OFFLINE;
859 goto done;
862 dom = talloc_get_type(e->state, struct idmap_domain);
863 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
865 ads_status = ad_idmap_cached_connection(dom);
866 if (!ADS_ERR_OK(ads_status)) {
867 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
870 if (!ctx->ad_schema) {
871 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
872 goto done;
875 attrs[0] = ctx->ad_schema->posix_uid_attr;
877 filter = talloc_asprintf(mem_ctx,
878 "(sAMAccountName=%s)",
879 name);
880 if (!filter) {
881 nt_status = NT_STATUS_NO_MEMORY;
882 goto done;
885 ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
886 if (!ADS_ERR_OK(ads_status)) {
887 nt_status = ads_ntstatus(ads_status);
888 goto done;
891 *alias = ads_pull_string(ctx->ads, mem_ctx, msg, ctx->ad_schema->posix_uid_attr);
893 if (!*alias) {
894 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
897 nt_status = NT_STATUS_OK;
899 done:
900 if (filter) {
901 talloc_destroy(filter);
903 if (msg) {
904 ads_msgfree(ctx->ads, msg);
907 return nt_status;
910 /**********************************************************************
911 *********************************************************************/
913 static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx,
914 struct nss_domain_entry *e,
915 const char *alias,
916 char **name )
918 const char *attrs[] = {"sAMAccountName",
919 NULL };
920 char *filter = NULL;
921 LDAPMessage *msg = NULL;
922 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
923 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
924 char *username;
925 struct idmap_domain *dom;
926 struct idmap_ad_context *ctx = NULL;
928 /* Check incoming parameters */
930 if ( !alias || !name) {
931 nt_status = NT_STATUS_INVALID_PARAMETER;
932 goto done;
935 /* Only do query if we are online */
937 if (idmap_is_offline()) {
938 nt_status = NT_STATUS_FILE_IS_OFFLINE;
939 goto done;
942 dom = talloc_get_type(e->state, struct idmap_domain);
943 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
945 ads_status = ad_idmap_cached_connection(dom);
946 if (!ADS_ERR_OK(ads_status)) {
947 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
950 if (!ctx->ad_schema) {
951 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
952 goto done;
955 filter = talloc_asprintf(mem_ctx,
956 "(%s=%s)",
957 ctx->ad_schema->posix_uid_attr,
958 alias);
959 if (!filter) {
960 nt_status = NT_STATUS_NO_MEMORY;
961 goto done;
964 ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
965 if (!ADS_ERR_OK(ads_status)) {
966 nt_status = ads_ntstatus(ads_status);
967 goto done;
970 username = ads_pull_string(ctx->ads, mem_ctx, msg,
971 "sAMAccountName");
972 if (!username) {
973 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
976 *name = talloc_asprintf(mem_ctx, "%s\\%s",
977 lp_workgroup(),
978 username);
979 if (!*name) {
980 nt_status = NT_STATUS_NO_MEMORY;
981 goto done;
984 nt_status = NT_STATUS_OK;
986 done:
987 if (filter) {
988 talloc_destroy(filter);
990 if (msg) {
991 ads_msgfree(ctx->ads, msg);
994 return nt_status;
997 /************************************************************************
998 Function dispatch tables for the idmap and nss plugins
999 ***********************************************************************/
1001 static struct idmap_methods ad_methods = {
1002 .init = idmap_ad_initialize,
1003 .unixids_to_sids = idmap_ad_unixids_to_sids,
1004 .sids_to_unixids = idmap_ad_sids_to_unixids,
1007 /* The SFU and RFC2307 NSS plugins share everything but the init
1008 function which sets the intended schema model to use */
1010 static struct nss_info_methods nss_rfc2307_methods = {
1011 .init = nss_rfc2307_init,
1012 .get_nss_info = nss_ad_get_info,
1013 .map_to_alias = nss_ad_map_to_alias,
1014 .map_from_alias = nss_ad_map_from_alias,
1017 static struct nss_info_methods nss_sfu_methods = {
1018 .init = nss_sfu_init,
1019 .get_nss_info = nss_ad_get_info,
1020 .map_to_alias = nss_ad_map_to_alias,
1021 .map_from_alias = nss_ad_map_from_alias,
1024 static struct nss_info_methods nss_sfu20_methods = {
1025 .init = nss_sfu20_init,
1026 .get_nss_info = nss_ad_get_info,
1027 .map_to_alias = nss_ad_map_to_alias,
1028 .map_from_alias = nss_ad_map_from_alias,
1033 /************************************************************************
1034 Initialize the plugins
1035 ***********************************************************************/
1037 NTSTATUS samba_init_module(void)
1039 static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
1040 static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
1041 static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
1042 static NTSTATUS status_nss_sfu20 = NT_STATUS_UNSUCCESSFUL;
1044 /* Always register the AD method first in order to get the
1045 idmap_domain interface called */
1047 if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
1048 status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
1049 "ad", &ad_methods);
1050 if ( !NT_STATUS_IS_OK(status_idmap_ad) )
1051 return status_idmap_ad;
1054 if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
1055 status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1056 "rfc2307", &nss_rfc2307_methods );
1057 if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
1058 return status_nss_rfc2307;
1061 if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
1062 status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1063 "sfu", &nss_sfu_methods );
1064 if ( !NT_STATUS_IS_OK(status_nss_sfu) )
1065 return status_nss_sfu;
1068 if ( !NT_STATUS_IS_OK( status_nss_sfu20 ) ) {
1069 status_nss_sfu20 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1070 "sfu20", &nss_sfu20_methods );
1071 if ( !NT_STATUS_IS_OK(status_nss_sfu20) )
1072 return status_nss_sfu20;
1075 return NT_STATUS_OK;