diff options
author | Andrew Tridgell <tridge@samba.org> | 2008-12-03 17:47:39 +1100 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2008-12-03 17:47:39 +1100 |
commit | a226d86dcec393b2cd657d5441c3041dfdf5cd8f (patch) | |
tree | 03ef7f3207607a4e5351bf50892b0a39dcf6f219 /source3/winbindd | |
parent | 30eff4f31b497ac94d8ee02ee2ec24bc8865ce0d (diff) | |
parent | 85b8cccab072bab263061654b677bc84826646c9 (diff) | |
download | samba-a226d86dcec393b2cd657d5441c3041dfdf5cd8f.tar.gz samba-a226d86dcec393b2cd657d5441c3041dfdf5cd8f.tar.bz2 samba-a226d86dcec393b2cd657d5441c3041dfdf5cd8f.zip |
Merge branch 'master' of ssh://git.samba.org/data/git/samba
Diffstat (limited to 'source3/winbindd')
-rw-r--r-- | source3/winbindd/idmap.c | 27 | ||||
-rw-r--r-- | source3/winbindd/idmap_ad.c | 414 | ||||
-rw-r--r-- | source3/winbindd/idmap_adex/idmap_adex.c | 16 | ||||
-rw-r--r-- | source3/winbindd/idmap_hash/idmap_hash.c | 6 | ||||
-rw-r--r-- | source3/winbindd/idmap_tdb.c | 63 | ||||
-rw-r--r-- | source3/winbindd/idmap_util.c | 12 | ||||
-rw-r--r-- | source3/winbindd/nss_info.c | 151 | ||||
-rw-r--r-- | source3/winbindd/nss_info_template.c | 4 | ||||
-rw-r--r-- | source3/winbindd/winbindd.c | 3 | ||||
-rw-r--r-- | source3/winbindd/winbindd_ads.c | 229 | ||||
-rw-r--r-- | source3/winbindd/winbindd_cache.c | 7 | ||||
-rw-r--r-- | source3/winbindd/winbindd_dual.c | 1 | ||||
-rw-r--r-- | source3/winbindd/winbindd_group.c | 4 | ||||
-rw-r--r-- | source3/winbindd/winbindd_idmap.c | 63 | ||||
-rw-r--r-- | source3/winbindd/winbindd_pam.c | 31 | ||||
-rw-r--r-- | source3/winbindd/winbindd_passdb.c | 5 | ||||
-rw-r--r-- | source3/winbindd/winbindd_proto.h | 40 | ||||
-rw-r--r-- | source3/winbindd/winbindd_rpc.c | 65 | ||||
-rw-r--r-- | source3/winbindd/winbindd_sid.c | 45 |
19 files changed, 808 insertions, 378 deletions
diff --git a/source3/winbindd/idmap.c b/source3/winbindd/idmap.c index cfc5597f42..aaba7e53ee 100644 --- a/source3/winbindd/idmap.c +++ b/source3/winbindd/idmap.c @@ -461,6 +461,9 @@ static struct idmap_domain *idmap_find_domain(const char *domname) struct idmap_domain *result; int i; + DEBUG(10, ("idmap_find_domain called for domain '%s'\n", + domname?domname:"NULL")); + /* * Always init the default domain, we can't go without one */ @@ -725,6 +728,10 @@ NTSTATUS idmap_backends_unixid_to_sid(const char *domname, struct id_map *id) struct idmap_domain *dom; struct id_map *maps[2]; + DEBUG(10, ("idmap_backend_unixid_to_sid: domain = '%s', xid = %d " + "(type %d)\n", + domname?domname:"NULL", id->xid.id, id->xid.type)); + maps[0] = id; maps[1] = NULL; @@ -751,6 +758,9 @@ NTSTATUS idmap_backends_sid_to_unixid(const char *domain, struct id_map *id) struct idmap_domain *dom; struct id_map *maps[2]; + DEBUG(10, ("idmap_backend_sid_to_unixid: domain = '%s', sid = [%s]\n", + domain?domain:"NULL", sid_string_dbg(id->sid))); + maps[0] = id; maps[1] = NULL; @@ -788,3 +798,20 @@ NTSTATUS idmap_set_mapping(const struct id_map *map) return dom->methods->set_mapping(dom, map); } + +NTSTATUS idmap_remove_mapping(const struct id_map *map) +{ + struct idmap_domain *dom; + + dom = idmap_find_domain(NULL); + if (dom == NULL) { + DEBUG(3, ("no default domain, no place to write\n")); + return NT_STATUS_ACCESS_DENIED; + } + if (dom->methods->remove_mapping == NULL) { + DEBUG(3, ("default domain not writable\n")); + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } + + return dom->methods->remove_mapping(dom, map); +} diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c index 60a2d8642a..b22e5af94a 100644 --- a/source3/winbindd/idmap_ad.c +++ b/source3/winbindd/idmap_ad.c @@ -9,6 +9,7 @@ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003 * Copyright (C) Gerald (Jerry) Carter 2004-2007 * Copyright (C) Luke Howard 2001-2004 + * Copyright (C) Michael Adam 2008 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +26,7 @@ */ #include "includes.h" +#include "winbindd.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_IDMAP @@ -43,31 +45,39 @@ struct idmap_ad_context { uint32_t filter_low_id; uint32_t filter_high_id; + ADS_STRUCT *ads; + struct posix_schema *ad_schema; + enum wb_posix_mapping ad_map_type; /* WB_POSIX_MAP_UNKNOWN */ }; NTSTATUS init_module(void); -static ADS_STRUCT *ad_idmap_ads = NULL; -static struct posix_schema *ad_schema = NULL; -static enum wb_posix_mapping ad_map_type = WB_POSIX_MAP_UNKNOWN; - /************************************************************************ ***********************************************************************/ -static ADS_STRUCT *ad_idmap_cached_connection_internal(void) +static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom) { ADS_STRUCT *ads; ADS_STATUS status; bool local = False; fstring dc_name; struct sockaddr_storage dc_ip; + struct idmap_ad_context *ctx; + char *ldap_server = NULL; + char *realm = NULL; + struct winbindd_domain *wb_dom; + + DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n", + dom->name)); + + ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); - if (ad_idmap_ads != NULL) { + if (ctx->ads != NULL) { time_t expire; time_t now = time(NULL); - ads = ad_idmap_ads; + ads = ctx->ads; expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire); @@ -76,15 +86,15 @@ static ADS_STRUCT *ad_idmap_cached_connection_internal(void) (uint32)expire-(uint32)now, (uint32) expire, (uint32) now)); if ( ads->config.realm && (expire > time(NULL))) { - return ads; + return ADS_SUCCESS; } else { /* we own this ADS_STRUCT so make sure it goes away */ DEBUG(7,("Deleting expired krb5 credential cache\n")); ads->is_mine = True; ads_destroy( &ads ); ads_kdestroy(WINBIND_CCACHE_NAME); - ad_idmap_ads = NULL; - TALLOC_FREE( ad_schema ); + ctx->ads = NULL; + TALLOC_FREE( ctx->ad_schema ); } } @@ -93,9 +103,28 @@ static ADS_STRUCT *ad_idmap_cached_connection_internal(void) setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1); } - if ( (ads = ads_init(lp_realm(), lp_workgroup(), NULL)) == NULL ) { + /* + * At this point we only have the NetBIOS domain name. + * Check if we can get server nam and realm from SAF cache + * and the domain list. + */ + ldap_server = saf_fetch(dom->name); + DEBUG(10, ("ldap_server from saf cache: '%s'\n", ldap_server?ldap_server:"")); + + wb_dom = find_domain_from_name_noinit(dom->name); + if (wb_dom == NULL) { + DEBUG(10, ("find_domain_from_name_noinit did not find domain '%s'\n", + dom->name)); + realm = NULL; + } else { + DEBUG(10, ("find_domain_from_name_noinit found realm '%s' for " + " domain '%s'\n", wb_dom->alt_name, dom->name)); + realm = wb_dom->alt_name; + } + + if ( (ads = ads_init(realm, dom->name, ldap_server)) == NULL ) { DEBUG(1,("ads_init failed\n")); - return NULL; + return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } /* the machine acct password might have change - fetch it every time */ @@ -107,54 +136,57 @@ static ADS_STRUCT *ad_idmap_cached_connection_internal(void) /* setup server affinity */ - get_dc_name( NULL, ads->auth.realm, dc_name, &dc_ip ); + get_dc_name(dom->name, realm, dc_name, &dc_ip ); status = ads_connect(ads); if (!ADS_ERR_OK(status)) { DEBUG(1, ("ad_idmap_init: failed to connect to AD\n")); ads_destroy(&ads); - return NULL; + return status; } ads->is_mine = False; - ad_idmap_ads = ads; + ctx->ads = ads; - return ads; + return ADS_SUCCESS; } /************************************************************************ ***********************************************************************/ -static ADS_STRUCT *ad_idmap_cached_connection(void) +static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom) { - ADS_STRUCT *ads = ad_idmap_cached_connection_internal(); - - if ( !ads ) - return NULL; + ADS_STATUS status; + struct idmap_ad_context * ctx; + + status = ad_idmap_cached_connection_internal(dom); + if (!ADS_ERR_OK(status)) { + return status; + } + + ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); /* if we have a valid ADS_STRUCT and the schema model is defined, then we can return here. */ - if ( ad_schema ) - return ads; + if ( ctx->ad_schema ) { + return ADS_SUCCESS; + } /* Otherwise, set the schema model */ - if ( (ad_map_type == WB_POSIX_MAP_SFU) || - (ad_map_type == WB_POSIX_MAP_SFU20) || - (ad_map_type == WB_POSIX_MAP_RFC2307) ) + if ( (ctx->ad_map_type == WB_POSIX_MAP_SFU) || + (ctx->ad_map_type == WB_POSIX_MAP_SFU20) || + (ctx->ad_map_type == WB_POSIX_MAP_RFC2307) ) { - ADS_STATUS schema_status; - - schema_status = ads_check_posix_schema_mapping( NULL, ads, ad_map_type, &ad_schema); - if ( !ADS_ERR_OK(schema_status) ) { + status = ads_check_posix_schema_mapping(NULL, ctx->ads, ctx->ad_map_type, &ctx->ad_schema); + if ( !ADS_ERR_OK(status) ) { DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n")); - return NULL; } } - return ads; + return status; } /************************************************************************ @@ -190,17 +222,18 @@ static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, } } + /* default map type */ + ctx->ad_map_type = WB_POSIX_MAP_RFC2307; + /* schema mode */ - if ( ad_map_type == WB_POSIX_MAP_UNKNOWN ) - ad_map_type = WB_POSIX_MAP_RFC2307; schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL); if ( schema_mode && schema_mode[0] ) { if ( strequal(schema_mode, "sfu") ) - ad_map_type = WB_POSIX_MAP_SFU; + ctx->ad_map_type = WB_POSIX_MAP_SFU; else if ( strequal(schema_mode, "sfu20" ) ) - ad_map_type = WB_POSIX_MAP_SFU20; + ctx->ad_map_type = WB_POSIX_MAP_SFU20; else if ( strequal(schema_mode, "rfc2307" ) ) - ad_map_type = WB_POSIX_MAP_RFC2307; + ctx->ad_map_type = WB_POSIX_MAP_RFC2307; else DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n", schema_mode)); @@ -256,7 +289,6 @@ static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map TALLOC_CTX *memctx; struct idmap_ad_context *ctx; ADS_STATUS rc; - ADS_STRUCT *ads; const char *attrs[] = { "sAMAccountType", "objectSid", NULL, /* uidnumber */ @@ -284,14 +316,16 @@ static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map return NT_STATUS_NO_MEMORY; } - if ( (ads = ad_idmap_cached_connection()) == NULL ) { - DEBUG(1, ("ADS uninitialized\n")); + rc = ad_idmap_cached_connection(dom); + if (!ADS_ERR_OK(rc)) { + DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc))); ret = NT_STATUS_UNSUCCESSFUL; + /* ret = ads_ntstatus(rc); */ goto done; } - attrs[2] = ad_schema->posix_uidnumber_attr; - attrs[3] = ad_schema->posix_gidnumber_attr; + attrs[2] = ctx->ad_schema->posix_uidnumber_attr; + attrs[3] = ctx->ad_schema->posix_gidnumber_attr; again: bidx = idx; @@ -308,7 +342,7 @@ again: ATYPE_INTERDOMAIN_TRUST); } u_filter = talloc_asprintf_append_buffer(u_filter, "(%s=%lu)", - ad_schema->posix_uidnumber_attr, + ctx->ad_schema->posix_uidnumber_attr, (unsigned long)ids[idx]->xid.id); CHECK_ALLOC_DONE(u_filter); break; @@ -322,7 +356,7 @@ again: ATYPE_SECURITY_LOCAL_GROUP); } g_filter = talloc_asprintf_append_buffer(g_filter, "(%s=%lu)", - ad_schema->posix_gidnumber_attr, + ctx->ad_schema->posix_gidnumber_attr, (unsigned long)ids[idx]->xid.id); CHECK_ALLOC_DONE(g_filter); break; @@ -348,14 +382,14 @@ again: filter = talloc_asprintf_append_buffer(filter, ")"); CHECK_ALLOC_DONE(filter); - rc = ads_search_retry(ads, &res, filter, attrs); + rc = ads_search_retry(ctx->ads, &res, filter, attrs); if (!ADS_ERR_OK(rc)) { DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc))); ret = NT_STATUS_UNSUCCESSFUL; goto done; } - if ( (count = ads_count_replies(ads, res)) == 0 ) { + if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) { DEBUG(10, ("No IDs found\n")); } @@ -368,9 +402,9 @@ again: uint32_t atype; if (i == 0) { /* first entry */ - entry = ads_first_entry(ads, entry); + entry = ads_first_entry(ctx->ads, entry); } else { /* following ones */ - entry = ads_next_entry(ads, entry); + entry = ads_next_entry(ctx->ads, entry); } if ( !entry ) { @@ -379,13 +413,13 @@ again: } /* first check if the SID is present */ - if (!ads_pull_sid(ads, entry, "objectSid", &sid)) { + if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) { DEBUG(2, ("Could not retrieve SID from entry\n")); continue; } /* get type */ - if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) { + if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) { DEBUG(1, ("could not get SAM account type\n")); continue; } @@ -405,9 +439,9 @@ again: continue; } - if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? - ad_schema->posix_uidnumber_attr : - ad_schema->posix_gidnumber_attr, + if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ? + ctx->ad_schema->posix_uidnumber_attr : + ctx->ad_schema->posix_gidnumber_attr, &id)) { DEBUG(1, ("Could not get unix ID\n")); @@ -439,7 +473,7 @@ again: } if (res) { - ads_msgfree(ads, res); + ads_msgfree(ctx->ads, res); } if (ids[idx]) { /* still some values to map */ @@ -468,7 +502,6 @@ static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map TALLOC_CTX *memctx; struct idmap_ad_context *ctx; ADS_STATUS rc; - ADS_STRUCT *ads; const char *attrs[] = { "sAMAccountType", "objectSid", NULL, /* attr_uidnumber */ @@ -495,14 +528,22 @@ static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map return NT_STATUS_NO_MEMORY; } - if ( (ads = ad_idmap_cached_connection()) == NULL ) { - DEBUG(1, ("ADS uninitialized\n")); + rc = ad_idmap_cached_connection(dom); + if (!ADS_ERR_OK(rc)) { + DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc))); + ret = NT_STATUS_UNSUCCESSFUL; + /* ret = ads_ntstatus(rc); */ + goto done; + } + + if (ctx->ad_schema == NULL) { + DEBUG(0, ("haven't got ctx->ad_schema ! \n")); ret = NT_STATUS_UNSUCCESSFUL; goto done; } - attrs[2] = ad_schema->posix_uidnumber_attr; - attrs[3] = ad_schema->posix_gidnumber_attr; + attrs[2] = ctx->ad_schema->posix_uidnumber_attr; + attrs[3] = ctx->ad_schema->posix_gidnumber_attr; again: filter = talloc_asprintf(memctx, "(&(|" @@ -529,14 +570,14 @@ again: CHECK_ALLOC_DONE(filter); DEBUG(10, ("Filter: [%s]\n", filter)); - rc = ads_search_retry(ads, &res, filter, attrs); + rc = ads_search_retry(ctx->ads, &res, filter, attrs); if (!ADS_ERR_OK(rc)) { DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc))); ret = NT_STATUS_UNSUCCESSFUL; goto done; } - if ( (count = ads_count_replies(ads, res)) == 0 ) { + if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) { DEBUG(10, ("No IDs found\n")); } @@ -549,9 +590,9 @@ again: uint32_t atype; if (i == 0) { /* first entry */ - entry = ads_first_entry(ads, entry); + entry = ads_first_entry(ctx->ads, entry); } else { /* following ones */ - entry = ads_next_entry(ads, entry); + entry = ads_next_entry(ctx->ads, entry); } if ( !entry ) { @@ -560,7 +601,7 @@ again: } /* first check if the SID is present */ - if (!ads_pull_sid(ads, entry, "objectSid", &sid)) { + if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) { DEBUG(2, ("Could not retrieve SID from entry\n")); continue; } @@ -572,7 +613,7 @@ again: } /* get type */ - if (!ads_pull_uint32(ads, entry, "sAMAccountType", &atype)) { + if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) { DEBUG(1, ("could not get SAM account type\n")); continue; } @@ -592,9 +633,9 @@ again: continue; } - if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? - ad_schema->posix_uidnumber_attr : - ad_schema->posix_gidnumber_attr, + if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ? + ctx->ad_schema->posix_uidnumber_attr : + ctx->ad_schema->posix_gidnumber_attr, &id)) { DEBUG(1, ("Could not get unix ID\n")); @@ -619,7 +660,7 @@ again: } if (res) { - ads_msgfree(ads, res); + ads_msgfree(ctx->ads, res); } if (ids[idx]) { /* still some values to map */ @@ -644,16 +685,18 @@ done: static NTSTATUS idmap_ad_close(struct idmap_domain *dom) { - ADS_STRUCT *ads = ad_idmap_ads; + struct idmap_ad_context * ctx; + + ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); - if (ads != NULL) { + if (ctx->ads != NULL) { /* we own this ADS_STRUCT so make sure it goes away */ - ads->is_mine = True; - ads_destroy( &ads ); - ad_idmap_ads = NULL; + ctx->ads->is_mine = True; + ads_destroy( &ctx->ads ); + ctx->ads = NULL; } - TALLOC_FREE( ad_schema ); + TALLOC_FREE( ctx->ad_schema ); return NT_STATUS_OK; } @@ -666,66 +709,107 @@ static NTSTATUS idmap_ad_close(struct idmap_domain *dom) Initialize the {sfu,sfu20,rfc2307} state ***********************************************************************/ -static NTSTATUS nss_sfu_init( struct nss_domain_entry *e ) -{ - /* Sanity check if we have previously been called with a - different schema model */ +static const char *wb_posix_map_unknown_string = "WB_POSIX_MAP_UNKNOWN"; +static const char *wb_posix_map_template_string = "WB_POSIX_MAP_TEMPLATE"; +static const char *wb_posix_map_sfu_string = "WB_POSIX_MAP_SFU"; +static const char *wb_posix_map_sfu20_string = "WB_POSIX_MAP_SFU20"; +static const char *wb_posix_map_rfc2307_string = "WB_POSIX_MAP_RFC2307"; +static const char *wb_posix_map_unixinfo_string = "WB_POSIX_MAP_UNIXINFO"; - if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) && - (ad_map_type != WB_POSIX_MAP_SFU) ) - { - DEBUG(0,("nss_sfu_init: Posix Map type has already been set. " - "Mixed schema models not supported!\n")); - return NT_STATUS_NOT_SUPPORTED; +static const char *ad_map_type_string(enum wb_posix_mapping map_type) +{ + switch (map_type) { + case WB_POSIX_MAP_TEMPLATE: + return wb_posix_map_template_string; + case WB_POSIX_MAP_SFU: + return wb_posix_map_sfu_string; + case WB_POSIX_MAP_SFU20: + return wb_posix_map_sfu20_string; + case WB_POSIX_MAP_RFC2307: + return wb_posix_map_rfc2307_string; + case WB_POSIX_MAP_UNIXINFO: + return wb_posix_map_unixinfo_string; + default: + return wb_posix_map_unknown_string; } - - ad_map_type = WB_POSIX_MAP_SFU; - - return NT_STATUS_OK; } -static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e ) +static NTSTATUS nss_ad_generic_init(struct nss_domain_entry *e, + enum wb_posix_mapping new_ad_map_type) { - /* Sanity check if we have previously been called with a - different schema model */ + struct idmap_domain *dom; + struct idmap_ad_context *ctx; + + if (e->state != NULL) { + dom = talloc_get_type(e->state, struct idmap_domain); + } else { + dom = TALLOC_ZERO_P(e, struct idmap_domain); + if (dom == NULL) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + e->state = dom; + } + + if (e->domain != NULL) { + dom->name = talloc_strdup(dom, e->domain); + if (dom->name == NULL) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + } - if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) && - (ad_map_type != WB_POSIX_MAP_SFU20) ) + if (dom->private_data != NULL) { + ctx = talloc_get_type(dom->private_data, + struct idmap_ad_context); + } else { + ctx = TALLOC_ZERO_P(dom, struct idmap_ad_context); + if (ctx == NULL) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + ctx->ad_map_type = WB_POSIX_MAP_RFC2307; + dom->private_data = ctx; + } + + if ((ctx->ad_map_type != WB_POSIX_MAP_UNKNOWN) && + (ctx->ad_map_type != new_ad_map_type)) { - DEBUG(0,("nss_sfu20_init: Posix Map type has already been set. " - "Mixed schema models not supported!\n")); - return NT_STATUS_NOT_SUPPORTED; + DEBUG(2, ("nss_ad_generic_init: " + "Warning: overriding previously set posix map type " + "%s for domain %s with map type %s.\n", + ad_map_type_string(ctx->ad_map_type), + dom->name, + ad_map_type_string(new_ad_map_type))); } - - ad_map_type = WB_POSIX_MAP_SFU20; + + ctx->ad_map_type = new_ad_map_type; return NT_STATUS_OK; } -static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e ) +static NTSTATUS nss_sfu_init( struct nss_domain_entry *e ) { - /* Sanity check if we have previously been called with a - different schema model */ - - if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) && - (ad_map_type != WB_POSIX_MAP_RFC2307) ) - { - DEBUG(0,("nss_rfc2307_init: Posix Map type has already been set. " - "Mixed schema models not supported!\n")); - return NT_STATUS_NOT_SUPPORTED; - } - - ad_map_type = WB_POSIX_MAP_RFC2307; + return nss_ad_generic_init(e, WB_POSIX_MAP_SFU); +} - return NT_STATUS_OK; +static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e ) +{ + return nss_ad_generic_init(e, WB_POSIX_MAP_SFU20); +} + +static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e ) +{ + return nss_ad_generic_init(e, WB_POSIX_MAP_RFC2307); } /************************************************************************ ***********************************************************************/ + static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, const DOM_SID *sid, - TALLOC_CTX *ctx, + TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, LDAPMessage *msg, char **homedir, @@ -733,7 +817,6 @@ static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, char **gecos, uint32 *gid ) { - ADS_STRUCT *ads_internal = NULL; const char *attrs[] = {NULL, /* attr_homedir */ NULL, /* attr_shell */ NULL, /* attr_gecos */ @@ -744,18 +827,27 @@ static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; char *sidstr = NULL; + struct idmap_domain *dom; + struct idmap_ad_context *ctx; + + DEBUG(10, ("nss_ad_get_info called for sid [%s] in domain '%s'\n", + sid_string_dbg(sid), e->domain?e->domain:"NULL")); /* Only do query if we are online */ if (idmap_is_offline()) { return NT_STATUS_FILE_IS_OFFLINE; } - /* We are assuming that the internal ADS_STRUCT is for the - same forest as the incoming *ads pointer */ + dom = talloc_get_type(e->state, struct idmap_domain); + ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); - ads_internal = ad_idmap_cached_connection(); + ads_status = ad_idmap_cached_connection(dom); + if (!ADS_ERR_OK(ads_status)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } - if ( !ads_internal || !ad_schema ) { + if (!ctx->ad_schema) { + DEBUG(10, ("nss_ad_get_info: no ad_schema configured!\n")); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } @@ -766,12 +858,15 @@ static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, /* See if we can use the ADS connection struct swe were given */ if (ads) { - *homedir = ads_pull_string( ads, ctx, msg, ad_schema->posix_homedir_attr ); - *shell = ads_pull_string( ads, ctx, msg, ad_schema->posix_shell_attr ); - *gecos = ads_pull_string( ads, ctx, msg, ad_schema->posix_gecos_attr ); + DEBUG(10, ("nss_ad_get_info: using given ads connection and " + "LDAP message (%p)\n", msg)); + + *homedir = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_homedir_attr ); + *shell = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_shell_attr ); + *gecos = ads_pull_string( ads, mem_ctx, msg, ctx->ad_schema->posix_gecos_attr ); if (gid) { - if ( !ads_pull_uint32(ads, msg, ad_schema->posix_gidnumber_attr, gid ) ) + if ( !ads_pull_uint32(ads, msg, ctx->ad_schema->posix_gidnumber_attr, gid ) ) *gid = (uint32)-1; } @@ -781,13 +876,16 @@ static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, /* Have to do our own query */ - attrs[0] = ad_schema->posix_homedir_attr; - attrs[1] = ad_schema->posix_shell_attr; - attrs[2] = ad_schema->posix_gecos_attr; - attrs[3] = ad_schema->posix_gidnumber_attr; + DEBUG(10, ("nss_ad_get_info: no ads connection given, doing our " + "own query\n")); + + attrs[0] = ctx->ad_schema->posix_homedir_attr; + attrs[1] = ctx->ad_schema->posix_shell_attr; + attrs[2] = ctx->ad_schema->posix_gecos_attr; + attrs[3] = ctx->ad_schema->posix_gidnumber_attr; sidstr = sid_binstring(sid); - filter = talloc_asprintf(ctx, "(objectSid=%s)", sidstr); + filter = talloc_asprintf(mem_ctx, "(objectSid=%s)", sidstr); SAFE_FREE(sidstr); if (!filter) { @@ -795,18 +893,18 @@ static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, goto done; } - ads_status = ads_search_retry(ads_internal, &msg_internal, filter, attrs); + ads_status = ads_search_retry(ctx->ads, &msg_internal, filter, attrs); if (!ADS_ERR_OK(ads_status)) { nt_status = ads_ntstatus(ads_status); goto done; } - *homedir = ads_pull_string(ads_internal, ctx, msg_internal, ad_schema->posix_homedir_attr); - *shell = ads_pull_string(ads_internal, ctx, msg_internal, ad_schema->posix_shell_attr); - *gecos = ads_pull_string(ads_internal, ctx, msg_internal, ad_schema->posix_gecos_attr); + *homedir = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_homedir_attr); + *shell = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_shell_attr); + *gecos = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_gecos_attr); if (gid) { - if (!ads_pull_uint32(ads_internal, msg_internal, ad_schema->posix_gidnumber_attr, gid)) + if (!ads_pull_uint32(ctx->ads, msg_internal, ctx->ad_schema->posix_gidnumber_attr, gid)) *gid = (uint32)-1; } @@ -814,7 +912,7 @@ static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, done: if (msg_internal) { - ads_msgfree(ads_internal, msg_internal); + ads_msgfree(ctx->ads, msg_internal); } return nt_status; @@ -824,21 +922,22 @@ done: *********************************************************************/ static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx, - const char *domain, + struct nss_domain_entry *e, const char *name, char **alias) { - ADS_STRUCT *ads_internal = NULL; const char *attrs[] = {NULL, /* attr_uid */ NULL }; char *filter = NULL; LDAPMessage *msg = NULL; ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct idmap_domain *dom; + struct idmap_ad_context *ctx = NULL; /* Check incoming parameters */ - if ( !domain || !name || !*alias) { + if ( !e || !e->domain || !name || !*alias) { nt_status = NT_STATUS_INVALID_PARAMETER; goto done; } @@ -850,14 +949,20 @@ static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx, goto done; } - ads_internal = ad_idmap_cached_connection(); + dom = talloc_get_type(e->state, struct idmap_domain); + ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); + + ads_status = ad_idmap_cached_connection(dom); + if (!ADS_ERR_OK(ads_status)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } - if (!ads_internal || !ad_schema) { + if (!ctx->ad_schema) { nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto done; } - attrs[0] = ad_schema->posix_uid_attr; + attrs[0] = ctx->ad_schema->posix_uid_attr; filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)", @@ -867,13 +972,13 @@ static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx, goto done; } - ads_status = ads_search_retry(ads_internal, &msg, filter, attrs); + ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs); if (!ADS_ERR_OK(ads_status)) { nt_status = ads_ntstatus(ads_status); goto done; } - *alias = ads_pull_string(ads_internal, mem_ctx, msg, ad_schema->posix_uid_attr ); + *alias = ads_pull_string(ctx->ads, mem_ctx, msg, ctx->ad_schema->posix_uid_attr); if (!*alias) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; @@ -886,7 +991,7 @@ done: talloc_destroy(filter); } if (msg) { - ads_msgfree(ads_internal, msg); + ads_msgfree(ctx->ads, msg); } return nt_status; @@ -896,11 +1001,10 @@ done: *********************************************************************/ static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx, - const char *domain, + struct nss_domain_entry *e, const char *alias, char **name ) { - ADS_STRUCT *ads_internal = NULL; const char *attrs[] = {"sAMAccountName", NULL }; char *filter = NULL; @@ -908,6 +1012,8 @@ static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx, ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; char *username; + struct idmap_domain *dom; + struct idmap_ad_context *ctx = NULL; /* Check incoming parameters */ @@ -923,29 +1029,35 @@ static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx, goto done; } - ads_internal = ad_idmap_cached_connection(); + dom = talloc_get_type(e->state, struct idmap_domain); + ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); + + ads_status = ad_idmap_cached_connection(dom); + if (!ADS_ERR_OK(ads_status)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } - if (!ads_internal || !ad_schema) { + if (!ctx->ad_schema) { nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto done; } filter = talloc_asprintf(mem_ctx, "(%s=%s)", - ad_schema->posix_uid_attr, + ctx->ad_schema->posix_uid_attr, alias); if (!filter) { nt_status = NT_STATUS_NO_MEMORY; goto done; } - ads_status = ads_search_retry(ads_internal, &msg, filter, attrs); + ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs); if (!ADS_ERR_OK(ads_status)) { nt_status = ads_ntstatus(ads_status); goto done; } - username = ads_pull_string(ads_internal, mem_ctx, msg, + username = ads_pull_string(ctx->ads, mem_ctx, msg, "sAMAccountName"); if (!username) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; @@ -966,7 +1078,7 @@ done: talloc_destroy(filter); } if (msg) { - ads_msgfree(ads_internal, msg); + ads_msgfree(ctx->ads, msg); } return nt_status; diff --git a/source3/winbindd/idmap_adex/idmap_adex.c b/source3/winbindd/idmap_adex/idmap_adex.c index 7596b1cbd8..7e186ca8a1 100644 --- a/source3/winbindd/idmap_adex/idmap_adex.c +++ b/source3/winbindd/idmap_adex/idmap_adex.c @@ -329,9 +329,9 @@ static NTSTATUS _nss_adex_get_info(struct /********************************************************************** *********************************************************************/ -static NTSTATUS _nss_adex_map_to_alias(TALLOC_CTX * mem_ctx, const char - *domain, const char - *name, char **alias) +static NTSTATUS _nss_adex_map_to_alias(TALLOC_CTX * mem_ctx, + struct nss_domain_entry *e, + const char *name, char **alias) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; struct likewise_cell *cell = NULL; @@ -344,7 +344,7 @@ static NTSTATUS _nss_adex_map_to_alias(TALLOC_CTX * mem_ctx, const char BAIL_ON_NTSTATUS_ERROR(nt_status); } - nt_status = cell->provider->map_to_alias(mem_ctx, domain, + nt_status = cell->provider->map_to_alias(mem_ctx, e->domain, name, alias); /* go ahead and allow the cache mgr to mark this in @@ -360,9 +360,9 @@ done: /********************************************************************** *********************************************************************/ -static NTSTATUS _nss_adex_map_from_alias(TALLOC_CTX * mem_ctx, const char - *domain, const char - *alias, char **name) +static NTSTATUS _nss_adex_map_from_alias(TALLOC_CTX * mem_ctx, + struct nss_domain_entry *e, + const char *alias, char **name) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; struct likewise_cell *cell = NULL; @@ -376,7 +376,7 @@ static NTSTATUS _nss_adex_map_from_alias(TALLOC_CTX * mem_ctx, const char } - nt_status = cell->provider->map_from_alias(mem_ctx, domain, + nt_status = cell->provider->map_from_alias(mem_ctx, e->domain, alias, name); /* go ahead and allow the cache mgr to mark this in diff --git a/source3/winbindd/idmap_hash/idmap_hash.c b/source3/winbindd/idmap_hash/idmap_hash.c index a050f99bc8..7dd94aede0 100644 --- a/source3/winbindd/idmap_hash/idmap_hash.c +++ b/source3/winbindd/idmap_hash/idmap_hash.c @@ -304,14 +304,14 @@ done: *********************************************************************/ static NTSTATUS nss_hash_map_to_alias(TALLOC_CTX *mem_ctx, - const char *domain, + struct nss_domain_entry *e, const char *name, char **alias) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; const char *value; - value = talloc_asprintf(mem_ctx, "%s\\%s", domain, name); + value = talloc_asprintf(mem_ctx, "%s\\%s", e->domain, name); BAIL_ON_PTR_NT_ERROR(value, nt_status); nt_status = mapfile_lookup_key(mem_ctx, value, alias); @@ -325,7 +325,7 @@ done: *********************************************************************/ static NTSTATUS nss_hash_map_from_alias(TALLOC_CTX *mem_ctx, - const char *domain, + struct nss_domain_entry *e, const char *alias, char **name) { diff --git a/source3/winbindd/idmap_tdb.c b/source3/winbindd/idmap_tdb.c index f9d3a9fbff..4c8cceb691 100644 --- a/source3/winbindd/idmap_tdb.c +++ b/source3/winbindd/idmap_tdb.c @@ -820,10 +820,11 @@ done: } /********************************** - set a mapping. + set a mapping. **********************************/ -static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, const struct id_map *map) +static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, + const struct id_map *map) { struct idmap_tdb_context *ctx; NTSTATUS ret; @@ -839,17 +840,19 @@ static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, const struct id_ data.dptr = NULL; /* TODO: should we filter a set_mapping using low/high filters ? */ - + ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context); switch (map->xid.type) { case ID_TYPE_UID: - kidstr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id); + kidstr = talloc_asprintf(ctx, "UID %lu", + (unsigned long)map->xid.id); break; - + case ID_TYPE_GID: - kidstr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id); + kidstr = talloc_asprintf(ctx, "GID %lu", + (unsigned long)map->xid.id); break; default: @@ -875,8 +878,13 @@ static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, const struct id_ ksid = string_term_tdb_data(ksidstr); /* *DELETE* previous mappings if any. - * This is done both SID and [U|G]ID passed in */ - + * This is done for both the SID and [U|G]ID passed in */ + + /* NOTE: We should lock both the ksid and kid records here, before + * making modifications. However, because tdb_chainlock() is a + * blocking call we could create an unrecoverable deadlock, so for now + * we only lock the ksid record. */ + /* Lock the record for this SID. */ if (tdb_chainlock(ctx->tdb, ksid) != 0) { DEBUG(10,("Failed to lock record %s. Error %s\n", @@ -886,7 +894,8 @@ static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, const struct id_ data = tdb_fetch(ctx->tdb, ksid); if (data.dptr) { - DEBUG(10, ("Deleting existing mapping %s <-> %s\n", (const char *)data.dptr, ksidstr )); + DEBUG(10, ("Deleting existing mapping %s <-> %s\n", + (const char *)data.dptr, ksidstr )); tdb_delete(ctx->tdb, data); tdb_delete(ctx->tdb, ksid); SAFE_FREE(data.dptr); @@ -894,20 +903,23 @@ static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, const struct id_ data = tdb_fetch(ctx->tdb, kid); if (data.dptr) { - DEBUG(10,("Deleting existing mapping %s <-> %s\n", (const char *)data.dptr, kidstr )); + DEBUG(10,("Deleting existing mapping %s <-> %s\n", + (const char *)data.dptr, kidstr )); tdb_delete(ctx->tdb, data); tdb_delete(ctx->tdb, kid); SAFE_FREE(data.dptr); } if (tdb_store(ctx->tdb, ksid, kid, TDB_INSERT) == -1) { - DEBUG(0, ("Error storing SID -> ID: %s\n", tdb_errorstr(ctx->tdb))); + DEBUG(0, ("Error storing SID -> ID: %s\n", + tdb_errorstr(ctx->tdb))); tdb_chainunlock(ctx->tdb, ksid); ret = NT_STATUS_UNSUCCESSFUL; goto done; } if (tdb_store(ctx->tdb, kid, ksid, TDB_INSERT) == -1) { - DEBUG(0, ("Error stroing ID -> SID: %s\n", tdb_errorstr(ctx->tdb))); + DEBUG(0, ("Error storing ID -> SID: %s\n", + tdb_errorstr(ctx->tdb))); /* try to remove the previous stored SID -> ID map */ tdb_delete(ctx->tdb, ksid); tdb_chainunlock(ctx->tdb, ksid); @@ -927,10 +939,11 @@ done: } /********************************** - remove a mapping. + remove a mapping. **********************************/ -static NTSTATUS idmap_tdb_remove_mapping(struct idmap_domain *dom, const struct id_map *map) +static NTSTATUS idmap_tdb_remove_mapping(struct idmap_domain *dom, + const struct id_map *map) { struct idmap_tdb_context *ctx; NTSTATUS ret; @@ -946,17 +959,19 @@ static NTSTATUS idmap_tdb_remove_mapping(struct idmap_domain *dom, const struct data.dptr = NULL; /* TODO: should we filter a remove_mapping using low/high filters ? */ - + ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context); switch (map->xid.type) { case ID_TYPE_UID: - kidstr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id); + kidstr = talloc_asprintf(ctx, "UID %lu", + (unsigned long)map->xid.id); break; - + case ID_TYPE_GID: - kidstr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id); + kidstr = talloc_asprintf(ctx, "GID %lu", + (unsigned long)map->xid.id); break; default: @@ -981,6 +996,11 @@ static NTSTATUS idmap_tdb_remove_mapping(struct idmap_domain *dom, const struct ksid = string_term_tdb_data(ksidstr); kid = string_term_tdb_data(kidstr); + /* NOTE: We should lock both the ksid and kid records here, before + * making modifications. However, because tdb_chainlock() is a + * blocking call we could create an unrecoverable deadlock, so for now + * we only lock the ksid record. */ + /* Lock the record for this SID. */ if (tdb_chainlock(ctx->tdb, ksid) != 0) { DEBUG(10,("Failed to lock record %s. Error %s\n", @@ -1001,16 +1021,17 @@ static NTSTATUS idmap_tdb_remove_mapping(struct idmap_domain *dom, const struct if ((data.dsize != kid.dsize) || (memcmp(data.dptr, kid.dptr, data.dsize) != 0)) { DEBUG(10,("Specified SID does not map to specified ID\n")); - DEBUGADD(10,("Actual mapping is %s -> %s\n", ksidstr, (const char *)data.dptr)); + DEBUGADD(10,("Actual mapping is %s -> %s\n", ksidstr, + (const char *)data.dptr)); tdb_chainunlock(ctx->tdb, ksid); ret = NT_STATUS_NONE_MAPPED; goto done; } - + DEBUG(10, ("Removing %s <-> %s map\n", ksidstr, kidstr)); /* Delete previous mappings. */ - + DEBUG(10, ("Deleting existing mapping %s -> %s\n", ksidstr, kidstr )); tdb_delete(ctx->tdb, ksid); diff --git a/source3/winbindd/idmap_util.c b/source3/winbindd/idmap_util.c index 9f876618be..9abf425f3e 100644 --- a/source3/winbindd/idmap_util.c +++ b/source3/winbindd/idmap_util.c @@ -33,7 +33,8 @@ NTSTATUS idmap_uid_to_sid(const char *domname, DOM_SID *sid, uid_t uid) struct id_map map; bool expired; - DEBUG(10,("uid = [%lu]\n", (unsigned long)uid)); + DEBUG(10,("idmap_uid_to_sid: uid = [%lu], domain = '%s'\n", + (unsigned long)uid, domname?domname:"NULL")); if (idmap_cache_find_uid2sid(uid, sid, &expired)) { DEBUG(10, ("idmap_cache_find_uid2sid found %d%s\n", uid, @@ -85,7 +86,8 @@ NTSTATUS idmap_gid_to_sid(const char *domname, DOM_SID *sid, gid_t gid) struct id_map map; bool expired; - DEBUG(10,("gid = [%lu]\n", (unsigned long)gid)); + DEBUG(10,("idmap_gid_to_si: gid = [%lu], domain = '%s'\n", + (unsigned long)gid, domname?domname:"NULL")); if (idmap_cache_find_gid2sid(gid, sid, &expired)) { DEBUG(10, ("idmap_cache_find_gid2sid found %d%s\n", gid, @@ -137,7 +139,8 @@ NTSTATUS idmap_sid_to_uid(const char *dom_name, DOM_SID *sid, uid_t *uid) struct id_map map; bool expired; - DEBUG(10,("idmap_sid_to_uid: sid = [%s]\n", sid_string_dbg(sid))); + DEBUG(10,("idmap_sid_to_uid: sid = [%s], domain = '%s'\n", + sid_string_dbg(sid), dom_name)); if (idmap_cache_find_sid2uid(sid, uid, &expired)) { DEBUG(10, ("idmap_cache_find_sid2uid found %d%s\n", @@ -209,7 +212,8 @@ NTSTATUS idmap_sid_to_gid(const char *domname, DOM_SID *sid, gid_t *gid) struct id_map map; bool expired; - DEBUG(10,("idmap_sid_to_gid: sid = [%s]\n", sid_string_dbg(sid))); + DEBUG(10,("idmap_sid_to_gid: sid = [%s], domain = '%s'\n", + sid_string_dbg(sid), domname)); if (idmap_cache_find_sid2gid(sid, gid, &expired)) { DEBUG(10, ("idmap_cache_find_sid2gid found %d%s\n", diff --git a/source3/winbindd/nss_info.c b/source3/winbindd/nss_info.c index 0e8cb60257..734c009602 100644 --- a/source3/winbindd/nss_info.c +++ b/source3/winbindd/nss_info.c @@ -1,19 +1,20 @@ -/* +/* Unix SMB/CIFS implementation. Idmap NSS headers Copyright (C) Gerald Carter 2006 + Copyright (C) Michael Adam 2008 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -22,6 +23,7 @@ #include "nss_info.h" static struct nss_function_entry *backends = NULL; +static struct nss_function_entry *default_backend = NULL; static struct nss_domain_entry *nss_domain_list = NULL; /********************************************************************** @@ -48,14 +50,14 @@ static struct nss_function_entry *nss_get_backend(const char *name ) { struct nss_function_entry *entry; - if ((version != SMB_NSS_INFO_INTERFACE_VERSION)) { + if ((version != SMB_NSS_INFO_INTERFACE_VERSION)) { DEBUG(0, ("smb_register_idmap_nss: Failed to register idmap_nss module.\n" - "The module was compiled against SMB_NSS_INFO_INTERFACE_VERSION %d,\n" - "current SMB_NSS_INFO_INTERFACE_VERSION is %d.\n" - "Please recompile against the current version of samba!\n", + "The module was compiled against SMB_NSS_INFO_INTERFACE_VERSION %d,\n" + "current SMB_NSS_INFO_INTERFACE_VERSION is %d.\n" + "Please recompile against the current version of samba!\n", version, SMB_NSS_INFO_INTERFACE_VERSION)); return NT_STATUS_OBJECT_TYPE_MISMATCH; - } + } if (!name || !name[0] || !methods) { DEBUG(0,("smb_register_idmap_nss: called with NULL pointer or empty name!\n")); @@ -89,12 +91,12 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain ) int len; *backend = *domain = NULL; - + if ( !config ) return False; - + p = strchr( config, ':' ); - + /* if no : then the string must be the backend name only */ if ( !p ) { @@ -107,13 +109,13 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain ) if ( strlen(p+1) > 0 ) { *domain = SMB_STRDUP( p+1 ); } - + len = PTR_DIFF(p,config)+1; if ( (q = SMB_MALLOC_ARRAY( char, len )) == NULL ) { SAFE_FREE( *backend ); return False; } - + StrnCpy( q, config, len-1); q[len-1] = '\0'; *backend = q; @@ -121,8 +123,44 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain ) return True; } +static NTSTATUS nss_domain_list_add_domain(const char *domain, + struct nss_function_entry *nss_backend) +{ + struct nss_domain_entry *nss_domain; + + nss_domain = TALLOC_ZERO_P(nss_domain_list, struct nss_domain_entry); + if (!nss_domain) { + DEBUG(0, ("nss_domain_list_add_domain: talloc() failure!\n")); + return NT_STATUS_NO_MEMORY; + } + + nss_domain->backend = nss_backend; + if (domain) { + nss_domain->domain = talloc_strdup(nss_domain, domain); + if (!nss_domain->domain) { + DEBUG(0, ("nss_domain_list_add_domain: talloc() " + "failure!\n")); + TALLOC_FREE(nss_domain); + return NT_STATUS_NO_MEMORY; + } + } + + nss_domain->init_status = nss_domain->backend->methods->init(nss_domain); + if (!NT_STATUS_IS_OK(nss_domain->init_status)) { + DEBUG(0, ("nss_init: Failed to init backend '%s' for domain " + "'%s'!\n", nss_backend->name, nss_domain->domain)); + } + + DLIST_ADD(nss_domain_list, nss_domain); + + DEBUG(10, ("Added domain '%s' with backend '%s' to nss_domain_list.\n", + domain, nss_backend->name)); + + return NT_STATUS_OK; +} + /******************************************************************** - Each nss backend must not store global state, but rather be able + Each nss backend must not store global state, but rather be able to initialize the state on a per domain basis. *******************************************************************/ @@ -133,18 +171,17 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain ) int i; char *backend, *domain; struct nss_function_entry *nss_backend; - struct nss_domain_entry *nss_domain; /* check for previous successful initializations */ if ( NT_STATUS_IS_OK(nss_initialized) ) return NT_STATUS_OK; - + /* The "template" backend should alqays be registered as it is a static module */ if ( (nss_backend = nss_get_backend( "template" )) == NULL ) { - static_init_nss_info; + static_init_nss_info; } /* Create the list of nss_domains (loading any shared plugins @@ -152,12 +189,15 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain ) for ( i=0; nss_list && nss_list[i]; i++ ) { - if ( !parse_nss_parm(nss_list[i], &backend, &domain) ) { + if ( !parse_nss_parm(nss_list[i], &backend, &domain) ) { DEBUG(0,("nss_init: failed to parse \"%s\"!\n", nss_list[i])); - continue; + continue; } + DEBUG(10, ("parsed backend = '%s', domain = '%s'\n", + backend, domain)); + /* validate the backend */ if ( (nss_backend = nss_get_backend( backend )) == NULL ) { @@ -166,41 +206,34 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain ) if ( !NT_STATUS_IS_OK(status) ) { continue; } - + /* try again */ if ( (nss_backend = nss_get_backend( backend )) == NULL ) { DEBUG(0,("nss_init: unregistered backend %s!. Skipping\n", backend)); continue; } - } - /* fill in the nss_domain_entry and add it to the - list of domains */ - - nss_domain = TALLOC_ZERO_P( nss_domain_list, struct nss_domain_entry ); - if ( !nss_domain ) { - DEBUG(0,("nss_init: talloc() failure!\n")); - return NT_STATUS_NO_MEMORY; + /* + * The first config item of the list without an explicit domain + * is treated as the default nss info backend. + */ + if ((domain == NULL) && (default_backend == NULL)) { + DEBUG(10, ("nss_init: using '%s' as default backend.\n", + backend)); + default_backend = nss_backend; } - - nss_domain->backend = nss_backend; - nss_domain->domain = talloc_strdup( nss_domain, domain ); - /* Try to init and ave the result */ - - nss_domain->init_status = nss_domain->backend->methods->init( nss_domain ); - DLIST_ADD( nss_domain_list, nss_domain ); - if ( !NT_STATUS_IS_OK(nss_domain->init_status) ) { - DEBUG(0,("nss_init: Failed to init backend for %s domain!\n", - nss_domain->domain)); + status = nss_domain_list_add_domain(domain, nss_backend); + if (!NT_STATUS_IS_OK(status)) { + return status; } /* cleanup */ SAFE_FREE( backend ); - SAFE_FREE( domain ); + SAFE_FREE( domain ); } if ( !nss_domain_list ) { @@ -210,10 +243,9 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain ) /* we shouild default to use template here */ } - - + nss_initialized = NT_STATUS_OK; - + return NT_STATUS_OK; } @@ -222,7 +254,7 @@ static bool parse_nss_parm( const char *config, char **backend, char **domain ) static struct nss_domain_entry *find_nss_domain( const char *domain ) { - NTSTATUS status; + NTSTATUS status; struct nss_domain_entry *p; status = nss_init( lp_winbind_nss_info() ); @@ -231,20 +263,30 @@ static struct nss_domain_entry *find_nss_domain( const char *domain ) nt_errstr(status))); return NULL; } - + for ( p=nss_domain_list; p; p=p->next ) { if ( strequal( p->domain, domain ) ) break; } - - /* If we didn't find a match, then use the default nss info */ + + /* If we didn't find a match, then use the default nss backend */ if ( !p ) { - if ( !nss_domain_list ) { + if (!default_backend) { + return NULL; + } + + status = nss_domain_list_add_domain(domain, default_backend); + if (!NT_STATUS_IS_OK(status)) { return NULL; } - - p = nss_domain_list; + + /* + * HACK ALERT: + * Here, we use the fact that the new domain was added at + * the beginning of the list... + */ + p = nss_domain_list; } if ( !NT_STATUS_IS_OK( p->init_status ) ) { @@ -266,15 +308,18 @@ static struct nss_domain_entry *find_nss_domain( const char *domain ) struct nss_domain_entry *p; struct nss_info_methods *m; + DEBUG(10, ("nss_get_info called for sid [%s] in domain '%s'\n", + sid_string_dbg(user_sid), domain?domain:"NULL")); + if ( (p = find_nss_domain( domain )) == NULL ) { DEBUG(4,("nss_get_info: Failed to find nss domain pointer for %s\n", domain )); return NT_STATUS_NOT_FOUND; } - + m = p->backend->methods; - return m->get_nss_info( p, user_sid, ctx, ads, msg, + return m->get_nss_info( p, user_sid, ctx, ads, msg, homedir, shell, gecos, p_gid ); } @@ -295,7 +340,7 @@ static struct nss_domain_entry *find_nss_domain( const char *domain ) m = p->backend->methods; - return m->map_to_alias( mem_ctx, domain, name, alias ); + return m->map_to_alias(mem_ctx, p, name, alias); } @@ -316,7 +361,7 @@ static struct nss_domain_entry *find_nss_domain( const char *domain ) m = p->backend->methods; - return m->map_from_alias( mem_ctx, domain, alias, name ); + return m->map_from_alias( mem_ctx, p, alias, name ); } /******************************************************************** diff --git a/source3/winbindd/nss_info_template.c b/source3/winbindd/nss_info_template.c index d8f903ddd0..f44c73f3a6 100644 --- a/source3/winbindd/nss_info_template.c +++ b/source3/winbindd/nss_info_template.c @@ -62,7 +62,7 @@ static NTSTATUS nss_template_get_info( struct nss_domain_entry *e, *********************************************************************/ static NTSTATUS nss_template_map_to_alias( TALLOC_CTX *mem_ctx, - const char *domain, + struct nss_domain_entry *e, const char *name, char **alias ) { @@ -73,7 +73,7 @@ static NTSTATUS nss_template_map_to_alias( TALLOC_CTX *mem_ctx, *********************************************************************/ static NTSTATUS nss_template_map_from_alias( TALLOC_CTX *mem_ctx, - const char *domain, + struct nss_domain_entry *e, const char *alias, char **name ) { diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c index ce1a1fe52f..82af55800f 100644 --- a/source3/winbindd/winbindd.c +++ b/source3/winbindd/winbindd.c @@ -343,6 +343,7 @@ static struct winbindd_dispatch_table { { WINBINDD_ALLOCATE_UID, winbindd_allocate_uid, "ALLOCATE_UID" }, { WINBINDD_ALLOCATE_GID, winbindd_allocate_gid, "ALLOCATE_GID" }, { WINBINDD_SET_MAPPING, winbindd_set_mapping, "SET_MAPPING" }, + { WINBINDD_REMOVE_MAPPING, winbindd_remove_mapping, "REMOVE_MAPPING" }, { WINBINDD_SET_HWM, winbindd_set_hwm, "SET_HWMS" }, /* Miscellaneous */ @@ -367,7 +368,7 @@ static struct winbindd_dispatch_table { { WINBINDD_WINS_BYNAME, winbindd_wins_byname, "WINS_BYNAME" }, { WINBINDD_WINS_BYIP, winbindd_wins_byip, "WINS_BYIP" }, - + /* End of list */ { WINBINDD_NUM_CMDS, NULL, "NONE" } diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index 1febddf110..5c7d491849 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -401,6 +401,47 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain, return NT_STATUS_OK; } +/* convert a single name to a sid in a domain - use rpc methods */ +static NTSTATUS name_to_sid(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + enum winbindd_cmd orig_cmd, + const char *domain_name, + const char *name, + DOM_SID *sid, + enum lsa_SidType *type) +{ + return reconnect_methods.name_to_sid(domain, mem_ctx, orig_cmd, + domain_name, name, + sid, type); +} + +/* convert a domain SID to a user or group name - use rpc methods */ +static NTSTATUS sid_to_name(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *sid, + char **domain_name, + char **name, + enum lsa_SidType *type) +{ + return reconnect_methods.sid_to_name(domain, mem_ctx, sid, + domain_name, name, type); +} + +/* convert a list of rids to names - use rpc methods */ +static NTSTATUS rids_to_names(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *sid, + uint32 *rids, + size_t num_rids, + char **domain_name, + char ***names, + enum lsa_SidType **types) +{ + return reconnect_methods.rids_to_names(domain, mem_ctx, sid, + rids, num_rids, + domain_name, names, types); +} + /* If you are looking for "dn_lookup": Yes, it used to be here! * It has gone now since it was a major speed bottleneck in * lookup_groupmem (its only use). It has been replaced by @@ -641,9 +682,10 @@ done: tokenGroups are not available. */ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - const char *user_dn, + const char *user_dn, DOM_SID *primary_group, - size_t *p_num_groups, DOM_SID **user_sids) + size_t *p_num_groups, + DOM_SID **user_sids) { ADS_STATUS rc; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; @@ -652,15 +694,15 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, size_t num_groups = 0; DOM_SID *group_sids = NULL; int i; - char **strings; - size_t num_strings = 0; + char **strings = NULL; + size_t num_strings = 0, num_sids = 0; DEBUG(3,("ads: lookup_usergroups_memberof\n")); if ( !winbindd_can_contact_domain( domain ) ) { - DEBUG(10,("lookup_usergroups_memberof: No incoming trust for domain %s\n", - domain->name)); + DEBUG(10,("lookup_usergroups_memberof: No incoming trust for " + "domain %s\n", domain->name)); return NT_STATUS_OK; } @@ -668,19 +710,19 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, if (!ads) { domain->last_status = NT_STATUS_SERVER_DISABLED; - goto done; + return NT_STATUS_UNSUCCESSFUL; } - rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs, - ADS_EXTENDED_DN_HEX_STRING, + rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs, + ADS_EXTENDED_DN_HEX_STRING, &strings, &num_strings); if (!ADS_ERR_OK(rc)) { - DEBUG(1,("lookup_usergroups_memberof ads_search member=%s: %s\n", - user_dn, ads_errstr(rc))); + DEBUG(1,("lookup_usergroups_memberof ads_search " + "member=%s: %s\n", user_dn, ads_errstr(rc))); return ads_ntstatus(rc); } - + *user_sids = NULL; num_groups = 0; @@ -693,21 +735,26 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, group_sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_strings + 1); if (!group_sids) { - TALLOC_FREE(strings); status = NT_STATUS_NO_MEMORY; goto done; } for (i=0; i<num_strings; i++) { - - if (!ads_get_sid_from_extended_dn(mem_ctx, strings[i], - ADS_EXTENDED_DN_HEX_STRING, - &(group_sids)[i])) { - TALLOC_FREE(group_sids); - TALLOC_FREE(strings); - status = NT_STATUS_NO_MEMORY; - goto done; + rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i], + ADS_EXTENDED_DN_HEX_STRING, + &(group_sids)[i]); + if (!ADS_ERR_OK(rc)) { + /* ignore members without SIDs */ + if (NT_STATUS_EQUAL(ads_ntstatus(rc), + NT_STATUS_NOT_FOUND)) { + continue; + } + else { + status = ads_ntstatus(rc); + goto done; + } } + num_sids++; } if (i == 0) { @@ -716,7 +763,7 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, goto done; } - for (i=0; i<num_strings; i++) { + for (i=0; i<num_sids; i++) { /* ignore Builtin groups from ADS - Guenther */ if (sid_check_is_in_builtin(&group_sids[i])) { @@ -728,14 +775,17 @@ static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, if (!NT_STATUS_IS_OK(status)) { goto done; } - + } *p_num_groups = num_groups; status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; - DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n", user_dn)); + DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n", + user_dn)); + done: + TALLOC_FREE(strings); TALLOC_FREE(group_sids); return status; @@ -894,13 +944,25 @@ done: return status; } +/* Lookup aliases a user is member of - use rpc methods */ +static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint32 num_sids, const DOM_SID *sids, + uint32 *num_aliases, uint32 **alias_rids) +{ + return reconnect_methods.lookup_useraliases(domain, mem_ctx, + num_sids, sids, + num_aliases, + alias_rids); +} + /* find the members of a group, given a group rid and domain */ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, - const DOM_SID *group_sid, uint32 *num_names, - DOM_SID **sid_mem, char ***names, + const DOM_SID *group_sid, uint32 *num_names, + DOM_SID **sid_mem, char ***names, uint32 **name_types) { ADS_STATUS rc; @@ -921,7 +983,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, uint32 num_nocache = 0; TALLOC_CTX *tmp_ctx = NULL; - DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name, + DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name, sid_string_dbg(group_sid))); *num_names = 0; @@ -935,12 +997,12 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, if ( !winbindd_can_contact_domain( domain ) ) { DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n", - domain->name)); + domain->name)); return NT_STATUS_OK; } ads = ads_cached_connection(domain); - + if (!ads) { domain->last_status = NT_STATUS_SERVER_DISABLED; goto done; @@ -952,8 +1014,8 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, } /* search for all members of the group */ - if (!(ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", - sidbinstr))) + if (!(ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", + sidbinstr))) { SAFE_FREE(sidbinstr); DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n")); @@ -966,21 +1028,21 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, args.val = ADS_EXTENDED_DN_HEX_STRING; args.critical = True; - rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path, + rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path, ldap_exp, &args, "member", &members, &num_members); if (!ADS_ERR_OK(rc)) { DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc))); status = NT_STATUS_UNSUCCESSFUL; goto done; - } - + } + DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members)); - + /* Now that we have a list of sids, we need to get the * lists of names and name_types belonging to these sids. - * even though conceptually not quite clean, we use the - * RPC call lsa_lookup_sids for this since it can handle a + * even though conceptually not quite clean, we use the + * RPC call lsa_lookup_sids for this since it can handle a * list of sids. ldap calls can just resolve one sid at a time. * * At this stage, the sids are still hidden in the exetended dn @@ -988,7 +1050,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, * stated above: In extracting the sids from the member strings, * we try to resolve as many sids as possible from the * cache. Only the rest is passed to the lsa_lookup_sids call. */ - + if (num_members) { (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members); (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members); @@ -1015,11 +1077,23 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, char *name, *domain_name; DOM_SID sid; - if (!ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val, &sid)) { - status = NT_STATUS_INVALID_PARAMETER; - goto done; + rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val, + &sid); + if (!ADS_ERR_OK(rc)) { + if (NT_STATUS_EQUAL(ads_ntstatus(rc), + NT_STATUS_NOT_FOUND)) { + /* Group members can be objects, like Exchange + * Public Folders, that don't have a SID. Skip + * them. */ + continue; + } + else { + status = ads_ntstatus(rc); + goto done; + } } - if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name, &name_type)) { + if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name, + &name_type)) { DEBUG(10,("ads: lookup_groupmem: got sid %s from " "cache\n", sid_string_dbg(&sid))); sid_copy(&(*sid_mem)[*num_names], &sid); @@ -1052,23 +1126,46 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, goto done; } - status = rpccli_lsa_lookup_sids(cli, tmp_ctx, + status = rpccli_lsa_lookup_sids(cli, tmp_ctx, &lsa_policy, - num_nocache, - sid_mem_nocache, - &domains_nocache, - &names_nocache, + num_nocache, + sid_mem_nocache, + &domains_nocache, + &names_nocache, &name_types_nocache); + if (!(NT_STATUS_IS_OK(status) || + NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) || + NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) + { + DEBUG(1, ("lsa_lookupsids call failed with %s " + "- retrying...\n", nt_errstr(status))); + + status = cm_connect_lsa(domain, tmp_ctx, &cli, + &lsa_policy); + + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + status = rpccli_lsa_lookup_sids(cli, tmp_ctx, + &lsa_policy, + num_nocache, + sid_mem_nocache, + &domains_nocache, + &names_nocache, + &name_types_nocache); + } + if (NT_STATUS_IS_OK(status) || - NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) + NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) { - /* Copy the entries over from the "_nocache" arrays - * to the result arrays, skipping the gaps the + /* Copy the entries over from the "_nocache" arrays + * to the result arrays, skipping the gaps the * lookup_sids call left. */ for (i=0; i < num_nocache; i++) { - if (((names_nocache)[i] != NULL) && - ((name_types_nocache)[i] != SID_NAME_UNKNOWN)) + if (((names_nocache)[i] != NULL) && + ((name_types_nocache)[i] != SID_NAME_UNKNOWN)) { sid_copy(&(*sid_mem)[*num_names], &sid_mem_nocache[i]); @@ -1150,6 +1247,22 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq) return ads_ntstatus(rc); } +/* find the lockout policy of a domain - use rpc methods */ +static NTSTATUS lockout_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + struct samr_DomInfo12 *policy) +{ + return reconnect_methods.lockout_policy(domain, mem_ctx, policy); +} + +/* find the password policy of a domain - use rpc methods */ +static NTSTATUS password_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + struct samr_DomInfo1 *policy) +{ + return reconnect_methods.password_policy(domain, mem_ctx, policy); +} + /* get a list of trusted domains */ static NTSTATUS trusted_domains(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, @@ -1340,16 +1453,16 @@ struct winbindd_methods ads_methods = { query_user_list, enum_dom_groups, enum_local_groups, - msrpc_name_to_sid, - msrpc_sid_to_name, - msrpc_rids_to_names, + name_to_sid, + sid_to_name, + rids_to_names, query_user, lookup_usergroups, - msrpc_lookup_useraliases, + lookup_useraliases, lookup_groupmem, sequence_number, - msrpc_lockout_policy, - msrpc_password_policy, + lockout_policy, + password_policy, trusted_domains, }; diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c index 360e915bc4..2f4a6ffe56 100644 --- a/source3/winbindd/winbindd_cache.c +++ b/source3/winbindd/winbindd_cache.c @@ -4222,7 +4222,14 @@ do_query: nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg, homedir, shell, gecos, p_gid ); + DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status))); + if ( NT_STATUS_IS_OK(nt_status) ) { + DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir)); + DEBUGADD(10, ("\tshell = '%s'\n", *shell)); + DEBUGADD(10, ("\tgecos = '%s'\n", *gecos)); + DEBUGADD(10, ("\tgid = '%u'\n", *p_gid)); + wcache_save_user_pwinfo( domain, nt_status, user_sid, *homedir, *shell, *gecos, *p_gid ); } diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 03d1e043bf..9153585c26 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -1279,6 +1279,7 @@ static bool fork_domain_child(struct winbindd_child *child) } if (child->domain && child->domain->primary && + !lp_use_kerberos_keytab() && lp_server_role() == ROLE_DOMAIN_MEMBER) { struct timeval next_change; diff --git a/source3/winbindd/winbindd_group.c b/source3/winbindd/winbindd_group.c index 8e56138bb5..3422fdba1c 100644 --- a/source3/winbindd/winbindd_group.c +++ b/source3/winbindd/winbindd_group.c @@ -585,7 +585,7 @@ static bool fill_grent_mem(struct winbindd_domain *domain, } /* Real work goes here. Create a list of group names to - expand startign with the initial one. Pass that to + expand starting with the initial one. Pass that to expand_groups() which returns a list of more group names to expand. Do this up to the max search depth. */ @@ -922,7 +922,7 @@ static void getgrsid_lookupsid_recv( void *private_data, bool success, nt_status = normalize_name_unmap(s->state->mem_ctx, raw_name, &mapped_name); - /* basiuc whitespace reversal */ + /* basic whitespace reversal */ if (NT_STATUS_IS_OK(nt_status)) { s->group_name = talloc_asprintf(s->state->mem_ctx, "%s%c%s", diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c index d8c67dc21c..94a8c78a85 100644 --- a/source3/winbindd/winbindd_idmap.c +++ b/source3/winbindd/winbindd_idmap.c @@ -111,6 +111,65 @@ enum winbindd_result winbindd_dual_set_mapping(struct winbindd_domain *domain, return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; } +static void winbindd_remove_mapping_recv(TALLOC_CTX *mem_ctx, bool success, + struct winbindd_response *response, + void *c, void *private_data) +{ + void (*cont)(void *priv, bool succ) = (void (*)(void *, bool))c; + + if (!success) { + DEBUG(5, ("Could not trigger idmap_remove_mapping\n")); + cont(private_data, False); + return; + } + + if (response->result != WINBINDD_OK) { + DEBUG(5, ("idmap_remove_mapping returned an error\n")); + cont(private_data, False); + return; + } + + cont(private_data, True); +} + +void winbindd_remove_mapping_async(TALLOC_CTX *mem_ctx, + const struct id_map *map, + void (*cont)(void *private_data, bool success), + void *private_data) +{ + struct winbindd_request request; + ZERO_STRUCT(request); + request.cmd = WINBINDD_DUAL_REMOVE_MAPPING; + request.data.dual_idmapset.id = map->xid.id; + request.data.dual_idmapset.type = map->xid.type; + sid_to_fstring(request.data.dual_idmapset.sid, map->sid); + + do_async(mem_ctx, idmap_child(), &request, winbindd_remove_mapping_recv, + (void *)cont, private_data); +} + +enum winbindd_result winbindd_dual_remove_mapping( + struct winbindd_domain *domain, + struct winbindd_cli_state *state) +{ + struct id_map map; + DOM_SID sid; + NTSTATUS result; + + DEBUG(3, ("[%5lu]: dual_idmapremove\n", (unsigned long)state->pid)); + + if (!string_to_sid(&sid, state->request.data.dual_idmapset.sid)) + return WINBINDD_ERROR; + + map.sid = &sid; + map.xid.id = state->request.data.dual_idmapset.id; + map.xid.type = state->request.data.dual_idmapset.type; + map.status = ID_MAPPED; + + result = idmap_remove_mapping(&map); + return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; +} + static void winbindd_set_hwm_recv(TALLOC_CTX *mem_ctx, bool success, struct winbindd_response *response, void *c, void *private_data) @@ -486,6 +545,10 @@ static const struct winbindd_child_dispatch_table idmap_dispatch_table[] = { .struct_cmd = WINBINDD_DUAL_SET_MAPPING, .struct_fn = winbindd_dual_set_mapping, },{ + .name = "DUAL_REMOVE_MAPPING", + .struct_cmd = WINBINDD_DUAL_REMOVE_MAPPING, + .struct_fn = winbindd_dual_remove_mapping, + },{ .name = "DUAL_SET_HWMS", .struct_cmd = WINBINDD_DUAL_SET_HWM, .struct_fn = winbindd_dual_set_hwm, diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index 9ff3899661..597d48aad0 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1854,17 +1854,28 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain, if (state->request.data.auth_crap.lm_resp_len > sizeof(state->request.data.auth_crap.lm_resp) || state->request.data.auth_crap.nt_resp_len > sizeof(state->request.data.auth_crap.nt_resp)) { - DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n", - state->request.data.auth_crap.lm_resp_len, - state->request.data.auth_crap.nt_resp_len)); - result = NT_STATUS_INVALID_PARAMETER; - goto done; + if (!state->request.flags & WBFLAG_BIG_NTLMV2_BLOB || + state->request.extra_len != state->request.data.auth_crap.nt_resp_len) { + DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n", + state->request.data.auth_crap.lm_resp_len, + state->request.data.auth_crap.nt_resp_len)); + result = NT_STATUS_INVALID_PARAMETER; + goto done; + } } lm_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len); - nt_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.nt_resp, - state->request.data.auth_crap.nt_resp_len); + + if (state->request.flags & WBFLAG_BIG_NTLMV2_BLOB) { + nt_resp = data_blob_talloc(state->mem_ctx, + state->request.extra_data.data, + state->request.data.auth_crap.nt_resp_len); + } else { + nt_resp = data_blob_talloc(state->mem_ctx, + state->request.data.auth_crap.nt_resp, + state->request.data.auth_crap.nt_resp_len); + } /* what domain should we contact? */ @@ -2106,9 +2117,15 @@ enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact got_info = true; } + /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will + * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just + * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too + * short to comply with the samr_ChangePasswordUser3 idl - gd */ + /* only fallback when the chgpasswd_user3 call is not supported */ if ((NT_STATUS_EQUAL(result, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR))) || (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) || + (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) || (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED))) { DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n", diff --git a/source3/winbindd/winbindd_passdb.c b/source3/winbindd/winbindd_passdb.c index 5677c01be1..101854ae94 100644 --- a/source3/winbindd/winbindd_passdb.c +++ b/source3/winbindd/winbindd_passdb.c @@ -267,6 +267,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, } if ( !pdb_getsampwsid( user, user_sid ) ) { + TALLOC_FREE( user ); return NT_STATUS_NO_SUCH_USER; } @@ -638,13 +639,13 @@ static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain, sid_type_lookup(lsa_names[i].type))); continue; } - if (!((*names)[i] = talloc_strdup((*names), + if (!((*names)[num_mapped] = talloc_strdup((*names), lsa_names[i].name))) { TALLOC_FREE(tmp_ctx); return NT_STATUS_NO_MEMORY; } - (*name_types)[i] = lsa_names[i].type; + (*name_types)[num_mapped] = lsa_names[i].type; num_mapped += 1; } diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 65ad47dd03..9de385e3b3 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -353,6 +353,11 @@ void winbindd_set_mapping_async(TALLOC_CTX *mem_ctx, const struct id_map *map, void *private_data); enum winbindd_result winbindd_dual_set_mapping(struct winbindd_domain *domain, struct winbindd_cli_state *state); +void winbindd_remove_mapping_async(TALLOC_CTX *mem_ctx, const struct id_map *map, + void (*cont)(void *private_data, bool success), + void *private_data); +enum winbindd_result winbindd_dual_remove_mapping(struct winbindd_domain *domain, + struct winbindd_cli_state *state); void winbindd_set_hwm_async(TALLOC_CTX *mem_ctx, const struct unixid *xid, void (*cont)(void *private_data, bool success), void *private_data); @@ -462,40 +467,6 @@ enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domai /* The following definitions come from winbindd/winbindd_reconnect.c */ -/* The following definitions come from winbindd/winbindd_rpc.c */ - -NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - enum winbindd_cmd original_cmd, - const char *domain_name, - const char *name, - DOM_SID *sid, - enum lsa_SidType *type); -NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - const DOM_SID *sid, - char **domain_name, - char **name, - enum lsa_SidType *type); -NTSTATUS msrpc_rids_to_names(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - const DOM_SID *sid, - uint32 *rids, - size_t num_rids, - char **domain_name, - char ***names, - enum lsa_SidType **types); -NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - uint32 num_sids, const DOM_SID *sids, - uint32 *num_aliases, uint32 **alias_rids); -NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - struct samr_DomInfo12 *lockout_policy); -NTSTATUS msrpc_password_policy(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - struct samr_DomInfo1 *password_policy); - /* The following definitions come from winbindd/winbindd_sid.c */ void winbindd_lookupsid(struct winbindd_cli_state *state); @@ -505,6 +476,7 @@ void winbindd_sid_to_uid(struct winbindd_cli_state *state); void winbindd_sid_to_gid(struct winbindd_cli_state *state); void winbindd_sids_to_unixids(struct winbindd_cli_state *state); void winbindd_set_mapping(struct winbindd_cli_state *state); +void winbindd_remove_mapping(struct winbindd_cli_state *state); void winbindd_set_hwm(struct winbindd_cli_state *state); void winbindd_uid_to_sid(struct winbindd_cli_state *state); void winbindd_gid_to_sid(struct winbindd_cli_state *state); diff --git a/source3/winbindd/winbindd_rpc.c b/source3/winbindd/winbindd_rpc.c index d966e50159..0070bde2cc 100644 --- a/source3/winbindd/winbindd_rpc.c +++ b/source3/winbindd/winbindd_rpc.c @@ -265,13 +265,13 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain, } /* convert a single name to a sid in a domain */ -NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - enum winbindd_cmd original_cmd, - const char *domain_name, - const char *name, - DOM_SID *sid, - enum lsa_SidType *type) +static NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + enum winbindd_cmd original_cmd, + const char *domain_name, + const char *name, + DOM_SID *sid, + enum lsa_SidType *type) { NTSTATUS result; DOM_SID *sids = NULL; @@ -331,12 +331,12 @@ NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain, /* convert a domain SID to a user or group name */ -NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - const DOM_SID *sid, - char **domain_name, - char **name, - enum lsa_SidType *type) +static NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *sid, + char **domain_name, + char **name, + enum lsa_SidType *type) { char **domains; char **names; @@ -384,14 +384,14 @@ NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain, return NT_STATUS_OK; } -NTSTATUS msrpc_rids_to_names(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - const DOM_SID *sid, - uint32 *rids, - size_t num_rids, - char **domain_name, - char ***names, - enum lsa_SidType **types) +static NTSTATUS msrpc_rids_to_names(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *sid, + uint32 *rids, + size_t num_rids, + char **domain_name, + char ***names, + enum lsa_SidType **types) { char **domains; NTSTATUS result; @@ -636,10 +636,13 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, return NT_STATUS_OK; } -NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - uint32 num_sids, const DOM_SID *sids, - uint32 *num_aliases, uint32 **alias_rids) +#define MAX_SAM_ENTRIES_W2K 0x400 /* 1024 */ + +static NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint32 num_sids, const DOM_SID *sids, + uint32 *num_aliases, + uint32 **alias_rids) { NTSTATUS result = NT_STATUS_UNSUCCESSFUL; POLICY_HND dom_pol; @@ -1102,9 +1105,9 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, } /* find the lockout policy for a domain */ -NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - struct samr_DomInfo12 *lockout_policy) +static NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + struct samr_DomInfo12 *lockout_policy) { NTSTATUS result; struct rpc_pipe_client *cli; @@ -1143,9 +1146,9 @@ NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain, } /* find the password policy for a domain */ -NTSTATUS msrpc_password_policy(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - struct samr_DomInfo1 *password_policy) +static NTSTATUS msrpc_password_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + struct samr_DomInfo1 *password_policy) { NTSTATUS result; struct rpc_pipe_client *cli; diff --git a/source3/winbindd/winbindd_sid.c b/source3/winbindd/winbindd_sid.c index 274786fa63..641b18ebbd 100644 --- a/source3/winbindd/winbindd_sid.c +++ b/source3/winbindd/winbindd_sid.c @@ -370,7 +370,8 @@ void winbindd_sid_to_gid(struct winbindd_cli_state *state) range from random SIDs. */ backend: - winbindd_lookupsid_async( state->mem_ctx, &sid, sid2gid_lookupsid_recv, state ); + winbindd_lookupsid_async( state->mem_ctx, &sid, sid2gid_lookupsid_recv, + state ); } static void set_mapping_recv(void *private_data, bool success) @@ -415,6 +416,48 @@ void winbindd_set_mapping(struct winbindd_cli_state *state) set_mapping_recv, state); } +static void remove_mapping_recv(void *private_data, bool success) +{ + struct winbindd_cli_state *state = + talloc_get_type_abort(private_data, struct winbindd_cli_state); + + if (!success) { + DEBUG(5, ("Could not remove sid mapping\n")); + request_error(state); + return; + } + + request_ok(state); +} + +void winbindd_remove_mapping(struct winbindd_cli_state *state) +{ + struct id_map map; + DOM_SID sid; + + DEBUG(3, ("[%5lu]: remove id map\n", (unsigned long)state->pid)); + + if ( ! state->privileged) { + DEBUG(0, ("Only root is allowed to remove mappings!\n")); + request_error(state); + return; + } + + if (!string_to_sid(&sid, state->request.data.dual_idmapset.sid)) { + DEBUG(1, ("Could not get convert sid %s from string\n", + state->request.data.sid)); + request_error(state); + return; + } + + map.sid = &sid; + map.xid.id = state->request.data.dual_idmapset.id; + map.xid.type = state->request.data.dual_idmapset.type; + + winbindd_remove_mapping_async(state->mem_ctx, &map, + remove_mapping_recv, state); +} + static void set_hwm_recv(void *private_data, bool success) { struct winbindd_cli_state *state = |