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
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/>.
30 #include "../libds/common/flags.h"
32 #include "libads/ldap_schema.h"
38 #define DBGC_CLASS DBGC_IDMAP
40 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
42 #define IDMAP_AD_MAX_IDS 30
43 #define CHECK_ALLOC_DONE(mem) do { \
45 DEBUG(0, ("Out of memory!\n")); \
46 ret = NT_STATUS_NO_MEMORY; \
51 struct idmap_ad_context {
53 struct posix_schema *ad_schema;
54 enum wb_posix_mapping ad_map_type; /* WB_POSIX_MAP_UNKNOWN */
57 NTSTATUS init_module(void);
59 /************************************************************************
60 ***********************************************************************/
62 static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom)
68 struct sockaddr_storage dc_ip;
69 struct idmap_ad_context *ctx;
70 char *ldap_server = NULL;
72 struct winbindd_domain *wb_dom;
74 DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
77 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
79 if (ctx->ads != NULL) {
82 time_t now = time(NULL);
86 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
88 /* check for a valid structure */
89 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
90 (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
92 if ( ads->config.realm && (expire > time(NULL))) {
95 /* we own this ADS_STRUCT so make sure it goes away */
96 DEBUG(7,("Deleting expired krb5 credential cache\n"));
99 ads_kdestroy(WINBIND_CCACHE_NAME);
101 TALLOC_FREE( ctx->ad_schema );
106 /* we don't want this to affect the users ccache */
107 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
111 * At this point we only have the NetBIOS domain name.
112 * Check if we can get server nam and realm from SAF cache
113 * and the domain list.
115 ldap_server = saf_fetch(dom->name);
116 DEBUG(10, ("ldap_server from saf cache: '%s'\n", ldap_server?ldap_server:""));
118 wb_dom = find_domain_from_name_noinit(dom->name);
119 if (wb_dom == NULL) {
120 DEBUG(10, ("find_domain_from_name_noinit did not find domain '%s'\n",
124 DEBUG(10, ("find_domain_from_name_noinit found realm '%s' for "
125 " domain '%s'\n", wb_dom->alt_name, dom->name));
126 realm = wb_dom->alt_name;
129 if ( (ads = ads_init(realm, dom->name, ldap_server)) == NULL ) {
130 DEBUG(1,("ads_init failed\n"));
131 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
134 /* the machine acct password might have change - fetch it every time */
135 SAFE_FREE(ads->auth.password);
136 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
138 SAFE_FREE(ads->auth.realm);
139 ads->auth.realm = SMB_STRDUP(lp_realm());
141 /* setup server affinity */
143 get_dc_name(dom->name, realm, dc_name, &dc_ip );
145 status = ads_connect(ads);
146 if (!ADS_ERR_OK(status)) {
147 DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
152 ads->is_mine = False;
159 /************************************************************************
160 ***********************************************************************/
162 static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom)
165 struct idmap_ad_context * ctx;
167 status = ad_idmap_cached_connection_internal(dom);
168 if (!ADS_ERR_OK(status)) {
172 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
174 /* if we have a valid ADS_STRUCT and the schema model is
175 defined, then we can return here. */
177 if ( ctx->ad_schema ) {
181 /* Otherwise, set the schema model */
183 if ( (ctx->ad_map_type == WB_POSIX_MAP_SFU) ||
184 (ctx->ad_map_type == WB_POSIX_MAP_SFU20) ||
185 (ctx->ad_map_type == WB_POSIX_MAP_RFC2307) )
187 status = ads_check_posix_schema_mapping(NULL, ctx->ads, ctx->ad_map_type, &ctx->ad_schema);
188 if ( !ADS_ERR_OK(status) ) {
189 DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
196 /************************************************************************
197 ***********************************************************************/
199 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom,
202 struct idmap_ad_context *ctx;
204 const char *schema_mode = NULL;
206 ctx = TALLOC_ZERO_P(dom, struct idmap_ad_context);
208 DEBUG(0, ("Out of memory!\n"));
209 return NT_STATUS_NO_MEMORY;
212 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
213 if (config_option == NULL) {
214 DEBUG(0, ("Out of memory!\n"));
216 return NT_STATUS_NO_MEMORY;
219 /* default map type */
220 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
223 schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL);
224 if ( schema_mode && schema_mode[0] ) {
225 if ( strequal(schema_mode, "sfu") )
226 ctx->ad_map_type = WB_POSIX_MAP_SFU;
227 else if ( strequal(schema_mode, "sfu20" ) )
228 ctx->ad_map_type = WB_POSIX_MAP_SFU20;
229 else if ( strequal(schema_mode, "rfc2307" ) )
230 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
232 DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n",
236 dom->private_data = ctx;
238 talloc_free(config_option);
243 /************************************************************************
244 Search up to IDMAP_AD_MAX_IDS entries in maps for a match.
245 ***********************************************************************/
247 static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
251 for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
252 if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
260 /************************************************************************
261 Search up to IDMAP_AD_MAX_IDS entries in maps for a match
262 ***********************************************************************/
264 static struct id_map *find_map_by_sid(struct id_map **maps, struct dom_sid *sid)
268 for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
269 if (sid_equal(maps[i]->sid, sid)) {
277 /************************************************************************
278 ***********************************************************************/
280 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
284 struct idmap_ad_context *ctx;
286 const char *attrs[] = { "sAMAccountType",
288 NULL, /* uidnumber */
289 NULL, /* gidnumber */
291 LDAPMessage *res = NULL;
292 LDAPMessage *entry = NULL;
298 char *u_filter = NULL;
299 char *g_filter = NULL;
301 /* initialize the status to avoid suprise */
302 for (i = 0; ids[i]; i++) {
303 ids[i]->status = ID_UNKNOWN;
306 /* Only do query if we are online */
307 if (idmap_is_offline()) {
308 return NT_STATUS_FILE_IS_OFFLINE;
311 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
313 if ( (memctx = talloc_new(ctx)) == NULL ) {
314 DEBUG(0, ("Out of memory!\n"));
315 return NT_STATUS_NO_MEMORY;
318 rc = ad_idmap_cached_connection(dom);
319 if (!ADS_ERR_OK(rc)) {
320 DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
321 ret = NT_STATUS_UNSUCCESSFUL;
322 /* ret = ads_ntstatus(rc); */
326 attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
327 attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
331 for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
332 switch (ids[idx]->xid.type) {
335 u_filter = talloc_asprintf(memctx, "(&(|"
336 "(sAMAccountType=%d)"
337 "(sAMAccountType=%d)"
338 "(sAMAccountType=%d))(|",
339 ATYPE_NORMAL_ACCOUNT,
340 ATYPE_WORKSTATION_TRUST,
341 ATYPE_INTERDOMAIN_TRUST);
343 u_filter = talloc_asprintf_append_buffer(u_filter, "(%s=%lu)",
344 ctx->ad_schema->posix_uidnumber_attr,
345 (unsigned long)ids[idx]->xid.id);
346 CHECK_ALLOC_DONE(u_filter);
351 g_filter = talloc_asprintf(memctx, "(&(|"
352 "(sAMAccountType=%d)"
353 "(sAMAccountType=%d))(|",
354 ATYPE_SECURITY_GLOBAL_GROUP,
355 ATYPE_SECURITY_LOCAL_GROUP);
357 g_filter = talloc_asprintf_append_buffer(g_filter, "(%s=%lu)",
358 ctx->ad_schema->posix_gidnumber_attr,
359 (unsigned long)ids[idx]->xid.id);
360 CHECK_ALLOC_DONE(g_filter);
364 DEBUG(3, ("Error: mapping requested but Unknown ID type\n"));
365 ids[idx]->status = ID_UNKNOWN;
369 filter = talloc_asprintf(memctx, "(|");
370 CHECK_ALLOC_DONE(filter);
372 filter = talloc_asprintf_append_buffer(filter, "%s))", u_filter);
373 CHECK_ALLOC_DONE(filter);
374 TALLOC_FREE(u_filter);
377 filter = talloc_asprintf_append_buffer(filter, "%s))", g_filter);
378 CHECK_ALLOC_DONE(filter);
379 TALLOC_FREE(g_filter);
381 filter = talloc_asprintf_append_buffer(filter, ")");
382 CHECK_ALLOC_DONE(filter);
384 rc = ads_search_retry(ctx->ads, &res, filter, attrs);
385 if (!ADS_ERR_OK(rc)) {
386 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
387 ret = NT_STATUS_UNSUCCESSFUL;
391 if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
392 DEBUG(10, ("No IDs found\n"));
396 for (i = 0; (i < count) && entry; i++) {
403 if (i == 0) { /* first entry */
404 entry = ads_first_entry(ctx->ads, entry);
405 } else { /* following ones */
406 entry = ads_next_entry(ctx->ads, entry);
410 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
414 /* first check if the SID is present */
415 if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
416 DEBUG(2, ("Could not retrieve SID from entry\n"));
421 if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
422 DEBUG(1, ("could not get SAM account type\n"));
426 switch (atype & 0xF0000000) {
427 case ATYPE_SECURITY_GLOBAL_GROUP:
428 case ATYPE_SECURITY_LOCAL_GROUP:
431 case ATYPE_NORMAL_ACCOUNT:
432 case ATYPE_WORKSTATION_TRUST:
433 case ATYPE_INTERDOMAIN_TRUST:
437 DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
441 if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
442 ctx->ad_schema->posix_uidnumber_attr :
443 ctx->ad_schema->posix_gidnumber_attr,
446 DEBUG(1, ("Could not get unix ID\n"));
450 if (!idmap_unix_id_is_in_range(id, dom)) {
451 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
452 id, dom->low_id, dom->high_id));
456 map = find_map_by_id(&ids[bidx], type, id);
458 DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
462 sid_copy(map->sid, &sid);
465 map->status = ID_MAPPED;
467 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
468 (unsigned long)map->xid.id,
473 ads_msgfree(ctx->ads, res);
476 if (ids[idx]) { /* still some values to map */
482 /* mark all unknown/expired ones as unmapped */
483 for (i = 0; ids[i]; i++) {
484 if (ids[i]->status != ID_MAPPED)
485 ids[i]->status = ID_UNMAPPED;
493 /************************************************************************
494 ***********************************************************************/
496 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
500 struct idmap_ad_context *ctx;
502 const char *attrs[] = { "sAMAccountType",
504 NULL, /* attr_uidnumber */
505 NULL, /* attr_gidnumber */
507 LDAPMessage *res = NULL;
508 LDAPMessage *entry = NULL;
516 /* initialize the status to avoid suprise */
517 for (i = 0; ids[i]; i++) {
518 ids[i]->status = ID_UNKNOWN;
521 /* Only do query if we are online */
522 if (idmap_is_offline()) {
523 return NT_STATUS_FILE_IS_OFFLINE;
526 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
528 if ( (memctx = talloc_new(ctx)) == NULL ) {
529 DEBUG(0, ("Out of memory!\n"));
530 return NT_STATUS_NO_MEMORY;
533 rc = ad_idmap_cached_connection(dom);
534 if (!ADS_ERR_OK(rc)) {
535 DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
536 ret = NT_STATUS_UNSUCCESSFUL;
537 /* ret = ads_ntstatus(rc); */
541 if (ctx->ad_schema == NULL) {
542 DEBUG(0, ("haven't got ctx->ad_schema ! \n"));
543 ret = NT_STATUS_UNSUCCESSFUL;
547 attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
548 attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
551 filter = talloc_asprintf(memctx, "(&(|"
552 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
553 "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
555 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
556 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
558 CHECK_ALLOC_DONE(filter);
561 for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
563 ids[idx]->status = ID_UNKNOWN;
565 sidstr = sid_binstring(talloc_tos(), ids[idx]->sid);
566 filter = talloc_asprintf_append_buffer(filter, "(objectSid=%s)", sidstr);
569 CHECK_ALLOC_DONE(filter);
571 filter = talloc_asprintf_append_buffer(filter, "))");
572 CHECK_ALLOC_DONE(filter);
573 DEBUG(10, ("Filter: [%s]\n", filter));
575 rc = ads_search_retry(ctx->ads, &res, filter, attrs);
576 if (!ADS_ERR_OK(rc)) {
577 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
578 ret = NT_STATUS_UNSUCCESSFUL;
582 if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
583 DEBUG(10, ("No IDs found\n"));
587 for (i = 0; (i < count) && entry; i++) {
594 if (i == 0) { /* first entry */
595 entry = ads_first_entry(ctx->ads, entry);
596 } else { /* following ones */
597 entry = ads_next_entry(ctx->ads, entry);
601 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
605 /* first check if the SID is present */
606 if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
607 DEBUG(2, ("Could not retrieve SID from entry\n"));
611 map = find_map_by_sid(&ids[bidx], &sid);
613 DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
618 if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
619 DEBUG(1, ("could not get SAM account type\n"));
623 switch (atype & 0xF0000000) {
624 case ATYPE_SECURITY_GLOBAL_GROUP:
625 case ATYPE_SECURITY_LOCAL_GROUP:
628 case ATYPE_NORMAL_ACCOUNT:
629 case ATYPE_WORKSTATION_TRUST:
630 case ATYPE_INTERDOMAIN_TRUST:
634 DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
638 if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
639 ctx->ad_schema->posix_uidnumber_attr :
640 ctx->ad_schema->posix_gidnumber_attr,
643 DEBUG(1, ("Could not get unix ID\n"));
646 if (!idmap_unix_id_is_in_range(id, dom)) {
647 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
648 id, dom->low_id, dom->high_id));
653 map->xid.type = type;
655 map->status = ID_MAPPED;
657 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
658 (unsigned long)map->xid.id,
663 ads_msgfree(ctx->ads, res);
666 if (ids[idx]) { /* still some values to map */
672 /* mark all unknwoni/expired ones as unmapped */
673 for (i = 0; ids[i]; i++) {
674 if (ids[i]->status != ID_MAPPED)
675 ids[i]->status = ID_UNMAPPED;
683 /************************************************************************
684 ***********************************************************************/
686 static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
688 struct idmap_ad_context * ctx;
690 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
692 if (ctx->ads != NULL) {
693 /* we own this ADS_STRUCT so make sure it goes away */
694 ctx->ads->is_mine = True;
695 ads_destroy( &ctx->ads );
699 TALLOC_FREE( ctx->ad_schema );
705 * nss_info_{sfu,sfu20,rfc2307}
708 /************************************************************************
709 Initialize the {sfu,sfu20,rfc2307} state
710 ***********************************************************************/
712 static const char *wb_posix_map_unknown_string = "WB_POSIX_MAP_UNKNOWN";
713 static const char *wb_posix_map_template_string = "WB_POSIX_MAP_TEMPLATE";
714 static const char *wb_posix_map_sfu_string = "WB_POSIX_MAP_SFU";
715 static const char *wb_posix_map_sfu20_string = "WB_POSIX_MAP_SFU20";
716 static const char *wb_posix_map_rfc2307_string = "WB_POSIX_MAP_RFC2307";
717 static const char *wb_posix_map_unixinfo_string = "WB_POSIX_MAP_UNIXINFO";
719 static const char *ad_map_type_string(enum wb_posix_mapping map_type)
722 case WB_POSIX_MAP_TEMPLATE:
723 return wb_posix_map_template_string;
724 case WB_POSIX_MAP_SFU:
725 return wb_posix_map_sfu_string;
726 case WB_POSIX_MAP_SFU20:
727 return wb_posix_map_sfu20_string;
728 case WB_POSIX_MAP_RFC2307:
729 return wb_posix_map_rfc2307_string;
730 case WB_POSIX_MAP_UNIXINFO:
731 return wb_posix_map_unixinfo_string;
733 return wb_posix_map_unknown_string;
737 static NTSTATUS nss_ad_generic_init(struct nss_domain_entry *e,
738 enum wb_posix_mapping new_ad_map_type)
740 struct idmap_domain *dom;
741 struct idmap_ad_context *ctx;
743 if (e->state != NULL) {
744 dom = talloc_get_type(e->state, struct idmap_domain);
746 dom = TALLOC_ZERO_P(e, struct idmap_domain);
748 DEBUG(0, ("Out of memory!\n"));
749 return NT_STATUS_NO_MEMORY;
754 if (e->domain != NULL) {
755 dom->name = talloc_strdup(dom, e->domain);
756 if (dom->name == NULL) {
757 DEBUG(0, ("Out of memory!\n"));
758 return NT_STATUS_NO_MEMORY;
762 if (dom->private_data != NULL) {
763 ctx = talloc_get_type(dom->private_data,
764 struct idmap_ad_context);
766 ctx = TALLOC_ZERO_P(dom, struct idmap_ad_context);
768 DEBUG(0, ("Out of memory!\n"));
769 return NT_STATUS_NO_MEMORY;
771 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
772 dom->private_data = ctx;
775 if ((ctx->ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
776 (ctx->ad_map_type != new_ad_map_type))
778 DEBUG(2, ("nss_ad_generic_init: "
779 "Warning: overriding previously set posix map type "
780 "%s for domain %s with map type %s.\n",
781 ad_map_type_string(ctx->ad_map_type),
783 ad_map_type_string(new_ad_map_type)));
786 ctx->ad_map_type = new_ad_map_type;
791 static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
793 return nss_ad_generic_init(e, WB_POSIX_MAP_SFU);
796 static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e )
798 return nss_ad_generic_init(e, WB_POSIX_MAP_SFU20);
801 static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
803 return nss_ad_generic_init(e, WB_POSIX_MAP_RFC2307);
807 /************************************************************************
808 ***********************************************************************/
810 static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e,
811 const struct dom_sid *sid,
815 const char **homedir,
820 const char *attrs[] = {NULL, /* attr_homedir */
821 NULL, /* attr_shell */
822 NULL, /* attr_gecos */
823 NULL, /* attr_gidnumber */
826 LDAPMessage *msg_internal = NULL;
827 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
828 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
830 struct idmap_domain *dom;
831 struct idmap_ad_context *ctx;
833 DEBUG(10, ("nss_ad_get_info called for sid [%s] in domain '%s'\n",
834 sid_string_dbg(sid), e->domain?e->domain:"NULL"));
836 /* Only do query if we are online */
837 if (idmap_is_offline()) {
838 return NT_STATUS_FILE_IS_OFFLINE;
841 dom = talloc_get_type(e->state, struct idmap_domain);
842 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
844 ads_status = ad_idmap_cached_connection(dom);
845 if (!ADS_ERR_OK(ads_status)) {
846 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
849 if (!ctx->ad_schema) {
850 DEBUG(10, ("nss_ad_get_info: no ad_schema configured!\n"));
851 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
854 if (!sid || !homedir || !shell || !gecos) {
855 return NT_STATUS_INVALID_PARAMETER;
858 /* See if we can use the ADS connection struct swe were given */
861 DEBUG(10, ("nss_ad_get_info: using given ads connection and "
862 "LDAP message (%p)\n", msg));
864 *homedir = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_homedir_attr );
865 *shell = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_shell_attr );
866 *gecos = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_gecos_attr );
869 if ( !ads_pull_uint32(ads, msg, ctx->ad_schema->posix_gidnumber_attr, gid ) )
873 nt_status = NT_STATUS_OK;
877 /* Have to do our own query */
879 DEBUG(10, ("nss_ad_get_info: no ads connection given, doing our "
882 attrs[0] = ctx->ad_schema->posix_homedir_attr;
883 attrs[1] = ctx->ad_schema->posix_shell_attr;
884 attrs[2] = ctx->ad_schema->posix_gecos_attr;
885 attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
887 sidstr = sid_binstring(mem_ctx, sid);
888 filter = talloc_asprintf(mem_ctx, "(objectSid=%s)", sidstr);
892 nt_status = NT_STATUS_NO_MEMORY;
896 ads_status = ads_search_retry(ctx->ads, &msg_internal, filter, attrs);
897 if (!ADS_ERR_OK(ads_status)) {
898 nt_status = ads_ntstatus(ads_status);
902 *homedir = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_homedir_attr);
903 *shell = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_shell_attr);
904 *gecos = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_gecos_attr);
907 if (!ads_pull_uint32(ctx->ads, msg_internal, ctx->ad_schema->posix_gidnumber_attr, gid))
911 nt_status = NT_STATUS_OK;
915 ads_msgfree(ctx->ads, msg_internal);
921 /**********************************************************************
922 *********************************************************************/
924 static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx,
925 struct nss_domain_entry *e,
929 const char *attrs[] = {NULL, /* attr_uid */
932 LDAPMessage *msg = NULL;
933 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
934 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
935 struct idmap_domain *dom;
936 struct idmap_ad_context *ctx = NULL;
938 /* Check incoming parameters */
940 if ( !e || !e->domain || !name || !*alias) {
941 nt_status = NT_STATUS_INVALID_PARAMETER;
945 /* Only do query if we are online */
947 if (idmap_is_offline()) {
948 nt_status = NT_STATUS_FILE_IS_OFFLINE;
952 dom = talloc_get_type(e->state, struct idmap_domain);
953 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
955 ads_status = ad_idmap_cached_connection(dom);
956 if (!ADS_ERR_OK(ads_status)) {
957 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
960 if (!ctx->ad_schema) {
961 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
965 attrs[0] = ctx->ad_schema->posix_uid_attr;
967 filter = talloc_asprintf(mem_ctx,
968 "(sAMAccountName=%s)",
971 nt_status = NT_STATUS_NO_MEMORY;
975 ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
976 if (!ADS_ERR_OK(ads_status)) {
977 nt_status = ads_ntstatus(ads_status);
981 *alias = ads_pull_string(ctx->ads, mem_ctx, msg, ctx->ad_schema->posix_uid_attr);
984 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
987 nt_status = NT_STATUS_OK;
991 talloc_destroy(filter);
994 ads_msgfree(ctx->ads, msg);
1000 /**********************************************************************
1001 *********************************************************************/
1003 static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx,
1004 struct nss_domain_entry *e,
1008 const char *attrs[] = {"sAMAccountName",
1010 char *filter = NULL;
1011 LDAPMessage *msg = NULL;
1012 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
1013 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1015 struct idmap_domain *dom;
1016 struct idmap_ad_context *ctx = NULL;
1018 /* Check incoming parameters */
1020 if ( !alias || !name) {
1021 nt_status = NT_STATUS_INVALID_PARAMETER;
1025 /* Only do query if we are online */
1027 if (idmap_is_offline()) {
1028 nt_status = NT_STATUS_FILE_IS_OFFLINE;
1032 dom = talloc_get_type(e->state, struct idmap_domain);
1033 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
1035 ads_status = ad_idmap_cached_connection(dom);
1036 if (!ADS_ERR_OK(ads_status)) {
1037 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1040 if (!ctx->ad_schema) {
1041 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1045 filter = talloc_asprintf(mem_ctx,
1047 ctx->ad_schema->posix_uid_attr,
1050 nt_status = NT_STATUS_NO_MEMORY;
1054 ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
1055 if (!ADS_ERR_OK(ads_status)) {
1056 nt_status = ads_ntstatus(ads_status);
1060 username = ads_pull_string(ctx->ads, mem_ctx, msg,
1063 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1066 *name = talloc_asprintf(mem_ctx, "%s\\%s",
1070 nt_status = NT_STATUS_NO_MEMORY;
1074 nt_status = NT_STATUS_OK;
1078 talloc_destroy(filter);
1081 ads_msgfree(ctx->ads, msg);
1088 /************************************************************************
1089 ***********************************************************************/
1091 static NTSTATUS nss_ad_close( void )
1093 /* nothing to do. All memory is free()'d by the idmap close_fn() */
1095 return NT_STATUS_OK;
1098 /************************************************************************
1099 Function dispatch tables for the idmap and nss plugins
1100 ***********************************************************************/
1102 static struct idmap_methods ad_methods = {
1103 .init = idmap_ad_initialize,
1104 .unixids_to_sids = idmap_ad_unixids_to_sids,
1105 .sids_to_unixids = idmap_ad_sids_to_unixids,
1106 .close_fn = idmap_ad_close
1109 /* The SFU and RFC2307 NSS plugins share everything but the init
1110 function which sets the intended schema model to use */
1112 static struct nss_info_methods nss_rfc2307_methods = {
1113 .init = nss_rfc2307_init,
1114 .get_nss_info = nss_ad_get_info,
1115 .map_to_alias = nss_ad_map_to_alias,
1116 .map_from_alias = nss_ad_map_from_alias,
1117 .close_fn = nss_ad_close
1120 static struct nss_info_methods nss_sfu_methods = {
1121 .init = nss_sfu_init,
1122 .get_nss_info = nss_ad_get_info,
1123 .map_to_alias = nss_ad_map_to_alias,
1124 .map_from_alias = nss_ad_map_from_alias,
1125 .close_fn = nss_ad_close
1128 static struct nss_info_methods nss_sfu20_methods = {
1129 .init = nss_sfu20_init,
1130 .get_nss_info = nss_ad_get_info,
1131 .map_to_alias = nss_ad_map_to_alias,
1132 .map_from_alias = nss_ad_map_from_alias,
1133 .close_fn = nss_ad_close
1138 /************************************************************************
1139 Initialize the plugins
1140 ***********************************************************************/
1142 NTSTATUS idmap_ad_init(void)
1144 static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
1145 static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
1146 static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
1147 static NTSTATUS status_nss_sfu20 = NT_STATUS_UNSUCCESSFUL;
1149 /* Always register the AD method first in order to get the
1150 idmap_domain interface called */
1152 if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
1153 status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
1155 if ( !NT_STATUS_IS_OK(status_idmap_ad) )
1156 return status_idmap_ad;
1159 if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
1160 status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1161 "rfc2307", &nss_rfc2307_methods );
1162 if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
1163 return status_nss_rfc2307;
1166 if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
1167 status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1168 "sfu", &nss_sfu_methods );
1169 if ( !NT_STATUS_IS_OK(status_nss_sfu) )
1170 return status_nss_sfu;
1173 if ( !NT_STATUS_IS_OK( status_nss_sfu20 ) ) {
1174 status_nss_sfu20 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1175 "sfu20", &nss_sfu20_methods );
1176 if ( !NT_STATUS_IS_OK(status_nss_sfu20) )
1177 return status_nss_sfu20;
1180 return NT_STATUS_OK;