diff options
author | Andreas Schneider <asn@samba.org> | 2018-04-26 12:17:12 +0200 |
---|---|---|
committer | Karolin Seeger <kseeger@samba.org> | 2018-05-24 11:29:23 +0200 |
commit | 124f0e4bdaabd082cffc403b747a8f5eb2b2a4ef (patch) | |
tree | 6f6afd48c67ae9558a689e02a4106d39e432a7a1 /source3 | |
parent | b5ba5da438c415d2542434e95463bad4519e6310 (diff) | |
download | samba-124f0e4bdaabd082cffc403b747a8f5eb2b2a4ef.tar.gz |
winbind: Fix UPN handling in parse_domain_user()
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13369
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Andreas Schneider <asn@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
(cherry picked from commit a05b63db627fdbe0bdea4d144dfaeedb39025592)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/winbindd/winbindd_cache.c | 5 | ||||
-rw-r--r-- | source3/winbindd/winbindd_ccache_access.c | 26 | ||||
-rw-r--r-- | source3/winbindd/winbindd_creds.c | 3 | ||||
-rw-r--r-- | source3/winbindd/winbindd_getgrnam.c | 15 | ||||
-rw-r--r-- | source3/winbindd/winbindd_getgroups.c | 10 | ||||
-rw-r--r-- | source3/winbindd/winbindd_getpwnam.c | 10 | ||||
-rw-r--r-- | source3/winbindd/winbindd_pam.c | 83 | ||||
-rw-r--r-- | source3/winbindd/winbindd_proto.h | 8 | ||||
-rw-r--r-- | source3/winbindd/winbindd_util.c | 47 |
9 files changed, 151 insertions, 56 deletions
diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c index 9f9e8781c21..2778e27374f 100644 --- a/source3/winbindd/winbindd_cache.c +++ b/source3/winbindd/winbindd_cache.c @@ -3221,7 +3221,8 @@ bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid, return NT_STATUS_IS_OK(status); } -bool lookup_cached_name(const char *domain_name, +bool lookup_cached_name(const char *namespace, + const char *domain_name, const char *name, struct dom_sid *sid, enum lsa_SidType *type) @@ -3230,7 +3231,7 @@ bool lookup_cached_name(const char *domain_name, NTSTATUS status; bool original_online_state; - domain = find_lookup_domain_from_name(domain_name); + domain = find_lookup_domain_from_name(namespace); if (domain == NULL) { return false; } diff --git a/source3/winbindd/winbindd_ccache_access.c b/source3/winbindd/winbindd_ccache_access.c index 039e6534013..6bcf9a3552c 100644 --- a/source3/winbindd/winbindd_ccache_access.c +++ b/source3/winbindd/winbindd_ccache_access.c @@ -43,8 +43,9 @@ static bool client_can_access_ccache_entry(uid_t client_uid, return False; } -static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username, +static NTSTATUS do_ntlm_auth_with_stored_pw(const char *namespace, const char *domain, + const char *username, const char *password, const DATA_BLOB initial_msg, const DATA_BLOB challenge_msg, @@ -182,11 +183,12 @@ static bool check_client_uid(struct winbindd_cli_state *state, uid_t uid) void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state) { struct winbindd_domain *domain; - fstring name_domain, name_user; + fstring name_namespace, name_domain, name_user; NTSTATUS result = NT_STATUS_NOT_SUPPORTED; struct WINBINDD_MEMORY_CREDS *entry; DATA_BLOB initial, challenge, auth; uint32_t initial_blob_len, challenge_blob_len, extra_len; + bool ok; /* Ensure null termination */ state->request->data.ccache_ntlm_auth.user[ @@ -238,7 +240,11 @@ void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state) } /* Parse domain and username */ - if (!parse_domain_user(state->request->data.ccache_ntlm_auth.user, name_domain, name_user)) { + ok = parse_domain_user(state->request->data.ccache_ntlm_auth.user, + name_namespace, + name_domain, + name_user); + if (!ok) { DEBUG(10,("winbindd_dual_ccache_ntlm_auth: cannot parse " "domain and user from name [%s]\n", state->request->data.ccache_ntlm_auth.user)); @@ -273,10 +279,16 @@ void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state) state->request->data.ccache_ntlm_auth.challenge_blob_len); result = do_ntlm_auth_with_stored_pw( - name_user, name_domain, entry->pass, - initial, challenge, talloc_tos(), &auth, - state->response->data.ccache_ntlm_auth.session_key, - &state->response->data.ccache_ntlm_auth.new_spnego); + name_namespace, + name_domain, + name_user, + entry->pass, + initial, + challenge, + talloc_tos(), + &auth, + state->response->data.ccache_ntlm_auth.session_key, + &state->response->data.ccache_ntlm_auth.new_spnego); if (!NT_STATUS_IS_OK(result)) { goto process_result; diff --git a/source3/winbindd/winbindd_creds.c b/source3/winbindd/winbindd_creds.c index 15cca554d45..2d7aacf36a9 100644 --- a/source3/winbindd/winbindd_creds.c +++ b/source3/winbindd/winbindd_creds.c @@ -76,7 +76,8 @@ NTSTATUS winbindd_store_creds(struct winbindd_domain *domain, enum lsa_SidType type; - if (!lookup_cached_name(domain->name, + if (!lookup_cached_name(domain->name, /* namespace */ + domain->name, user, &cred_sid, &type)) { diff --git a/source3/winbindd/winbindd_getgrnam.c b/source3/winbindd/winbindd_getgrnam.c index 1d9a8b94d48..37c205ddba4 100644 --- a/source3/winbindd/winbindd_getgrnam.c +++ b/source3/winbindd/winbindd_getgrnam.c @@ -22,7 +22,7 @@ struct winbindd_getgrnam_state { struct tevent_context *ev; - fstring name_domain, name_group; + fstring name_namespace, name_domain, name_group; struct dom_sid sid; const char *domname; const char *name; @@ -42,6 +42,7 @@ struct tevent_req *winbindd_getgrnam_send(TALLOC_CTX *mem_ctx, struct winbindd_getgrnam_state *state; char *tmp; NTSTATUS nt_status; + bool ok; req = tevent_req_create(mem_ctx, &state, struct winbindd_getgrnam_state); @@ -66,7 +67,15 @@ struct tevent_req *winbindd_getgrnam_send(TALLOC_CTX *mem_ctx, /* Parse domain and groupname */ - parse_domain_user(tmp, state->name_domain, state->name_group); + ok = parse_domain_user(tmp, + state->name_namespace, + state->name_domain, + state->name_group); + if (!ok) { + DBG_INFO("Could not parse domain user: %s\n", tmp); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } /* if no domain or our local domain and no local tdb group, default to * our local domain for aliases */ @@ -77,7 +86,7 @@ struct tevent_req *winbindd_getgrnam_send(TALLOC_CTX *mem_ctx, } subreq = wb_lookupname_send(state, ev, - state->name_domain, + state->name_namespace, state->name_domain, state->name_group, 0); diff --git a/source3/winbindd/winbindd_getgroups.c b/source3/winbindd/winbindd_getgroups.c index 68b470d6dad..f7f2df5f7b1 100644 --- a/source3/winbindd/winbindd_getgroups.c +++ b/source3/winbindd/winbindd_getgroups.c @@ -23,6 +23,7 @@ struct winbindd_getgroups_state { struct tevent_context *ev; + fstring namespace; fstring domname; fstring username; struct dom_sid sid; @@ -46,6 +47,7 @@ struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx, struct winbindd_getgroups_state *state; char *domuser, *mapped_user; NTSTATUS status; + bool ok; req = tevent_req_create(mem_ctx, &state, struct winbindd_getgroups_state); @@ -69,14 +71,18 @@ struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx, domuser = mapped_user; } - if (!parse_domain_user(domuser, state->domname, state->username)) { + ok = parse_domain_user(domuser, + state->namespace, + state->domname, + state->username); + if (!ok) { DEBUG(5, ("Could not parse domain user: %s\n", domuser)); tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } subreq = wb_lookupname_send(state, ev, - state->domname, + state->namespace, state->domname, state->username, LOOKUP_NAME_NO_NSS); diff --git a/source3/winbindd/winbindd_getpwnam.c b/source3/winbindd/winbindd_getpwnam.c index 26686bf9f0f..8da66c25141 100644 --- a/source3/winbindd/winbindd_getpwnam.c +++ b/source3/winbindd/winbindd_getpwnam.c @@ -23,6 +23,7 @@ struct winbindd_getpwnam_state { struct tevent_context *ev; + fstring namespace; fstring domname; fstring username; struct dom_sid sid; @@ -42,6 +43,7 @@ struct tevent_req *winbindd_getpwnam_send(TALLOC_CTX *mem_ctx, struct winbindd_getpwnam_state *state; char *domuser, *mapped_user; NTSTATUS status; + bool ok; req = tevent_req_create(mem_ctx, &state, struct winbindd_getpwnam_state); @@ -65,14 +67,18 @@ struct tevent_req *winbindd_getpwnam_send(TALLOC_CTX *mem_ctx, domuser = mapped_user; } - if (!parse_domain_user(domuser, state->domname, state->username)) { + ok = parse_domain_user(domuser, + state->namespace, + state->domname, + state->username); + if (!ok) { DEBUG(5, ("Could not parse domain user: %s\n", domuser)); tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } subreq = wb_lookupname_send(state, ev, - state->domname, + state->namespace, state->domname, state->username, LOOKUP_NAME_NO_NSS); diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index 8403d7d57b6..9c66c6bdb82 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -645,7 +645,7 @@ static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx, const char *principal_s = NULL; const char *service = NULL; char *realm = NULL; - fstring name_domain, name_user; + fstring name_namespace, name_domain, name_user; time_t ticket_lifetime = 0; time_t renewal_until = 0; ADS_STRUCT *ads; @@ -658,6 +658,7 @@ static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx, const char *local_service; uint32_t i; struct netr_SamInfo6 *info6_copy = NULL; + bool ok; *info6 = NULL; @@ -693,7 +694,10 @@ static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx, /* 3rd step: * do kerberos auth and setup ccache as the user */ - parse_domain_user(user, name_domain, name_user); + ok = parse_domain_user(user, name_namespace, name_domain, name_user); + if (!ok) { + return NT_STATUS_INVALID_PARAMETER; + } realm = talloc_strdup(mem_ctx, domain->alt_name); if (realm == NULL) { @@ -975,7 +979,7 @@ static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain, { NTSTATUS result = NT_STATUS_LOGON_FAILURE; uint16_t max_allowed_bad_attempts; - fstring name_domain, name_user; + fstring name_namespace, name_domain, name_user; struct dom_sid sid; enum lsa_SidType type; uchar new_nt_pass[NT_HASH_LEN]; @@ -996,10 +1000,14 @@ static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain, /* Parse domain and username */ - parse_domain_user(state->request->data.auth.user, name_domain, name_user); + parse_domain_user(state->request->data.auth.user, + name_namespace, + name_domain, + name_user); - if (!lookup_cached_name(name_domain, + if (!lookup_cached_name(name_namespace, + name_domain, name_user, &sid, &type)) { @@ -1244,19 +1252,28 @@ static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain, struct netr_SamInfo6 **info6) { struct winbindd_domain *contact_domain; - fstring name_domain, name_user; + fstring name_namespace, name_domain, name_user; NTSTATUS result; + bool ok; DEBUG(10,("winbindd_dual_pam_auth_kerberos\n")); /* Parse domain and username */ - parse_domain_user(state->request->data.auth.user, name_domain, name_user); + ok = parse_domain_user(state->request->data.auth.user, + name_namespace, + name_domain, + name_user); + if (!ok) { + result = NT_STATUS_INVALID_PARAMETER; + goto done; + } /* what domain should we contact? */ if ( IS_DC ) { - if (!(contact_domain = find_domain_from_name(name_domain))) { + contact_domain = find_domain_from_name(name_namespace); + if (contact_domain == NULL) { DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", state->request->data.auth.user, name_domain, name_user, name_domain)); result = NT_STATUS_NO_SUCH_USER; @@ -1270,7 +1287,7 @@ static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain, goto done; } - contact_domain = find_domain_from_name(name_domain); + contact_domain = find_domain_from_name(name_namespace); if (contact_domain == NULL) { DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", state->request->data.auth.user, name_domain, name_user, name_domain)); @@ -1662,19 +1679,23 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon( DATA_BLOB lm_resp; DATA_BLOB nt_resp; unsigned char local_nt_response[24]; - fstring name_domain, name_user; + fstring name_namespace, name_domain, name_user; NTSTATUS result; uint8_t authoritative = 0; uint32_t flags = 0; uint16_t validation_level; union netr_Validation *validation = NULL; struct netr_SamBaseInfo *base_info = NULL; + bool ok; DEBUG(10,("winbindd_dual_pam_auth_samlogon\n")); /* Parse domain and username */ - parse_domain_user(user, name_domain, name_user); + ok = parse_domain_user(user, name_namespace, name_domain, name_user); + if (!ok) { + return NT_STATUS_INVALID_PARAMETER; + } /* * We check against domain->name instead of @@ -1869,12 +1890,13 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain, { NTSTATUS result = NT_STATUS_LOGON_FAILURE; NTSTATUS krb5_result = NT_STATUS_OK; - fstring name_domain, name_user; + fstring name_namespace, name_domain, name_user; char *mapped_user; fstring domain_user; uint16_t validation_level = UINT16_MAX; union netr_Validation *validation = NULL; NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL; + bool ok; /* Ensure null termination */ state->request->data.auth.user[sizeof(state->request->data.auth.user)-1]='\0'; @@ -1900,7 +1922,14 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain, mapped_user = state->request->data.auth.user; } - parse_domain_user(mapped_user, name_domain, name_user); + ok = parse_domain_user(mapped_user, + name_namespace, + name_domain, + name_user); + if (!ok) { + result = NT_STATUS_INVALID_PARAMETER; + goto process_result; + } if ( mapped_user != state->request->data.auth.user ) { fstr_sprintf( domain_user, "%s%c%s", name_domain, @@ -2490,15 +2519,20 @@ enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact struct samr_DomInfo1 *info = NULL; struct userPwdChangeFailureInformation *reject = NULL; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - fstring domain, user; + fstring namespace, domain, user; struct dcerpc_binding_handle *b = NULL; + bool ok; ZERO_STRUCT(dom_pol); DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid, state->request->data.auth.user)); - if (!parse_domain_user(state->request->data.chauthtok.user, domain, user)) { + ok = parse_domain_user(state->request->data.chauthtok.user, + namespace, + domain, + user); + if (!ok) { goto done; } @@ -2707,7 +2741,7 @@ enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domai DATA_BLOB old_nt_hash_enc; DATA_BLOB new_lm_password; DATA_BLOB old_lm_hash_enc; - fstring domain,user; + fstring namespace, domain, user; struct policy_handle dom_pol; struct winbindd_domain *contact_domain = domainSt; struct rpc_pipe_client *cli = NULL; @@ -2720,8 +2754,9 @@ enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domai sizeof(state->request->data.chng_pswd_auth_crap.user)-1]=0; state->request->data.chng_pswd_auth_crap.domain[ sizeof(state->request->data.chng_pswd_auth_crap.domain)-1]=0; - *domain = 0; - *user = 0; + domain[0] = '\0'; + namespace[0] = '\0'; + user[0] = '\0'; DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n", (unsigned long)state->pid, @@ -2738,8 +2773,16 @@ enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domai if (*state->request->data.chng_pswd_auth_crap.domain) { fstrcpy(domain,state->request->data.chng_pswd_auth_crap.domain); } else { - parse_domain_user(state->request->data.chng_pswd_auth_crap.user, - domain, user); + bool ok; + + ok = parse_domain_user(state->request->data.chng_pswd_auth_crap.user, + namespace, + domain, + user); + if (!ok) { + result = NT_STATUS_INVALID_PARAMETER; + goto done; + } if(!*domain) { DEBUG(3,("no domain specified with username (%s) - " diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 0cbcbad2a96..c4b27575b32 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -134,7 +134,8 @@ void close_winbindd_cache(void); bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid, char **domain_name, char **name, enum lsa_SidType *type); -bool lookup_cached_name(const char *domain_name, +bool lookup_cached_name(const char *namespace, + const char *domain_name, const char *name, struct dom_sid *sid, enum lsa_SidType *type); @@ -476,7 +477,10 @@ struct winbindd_domain *find_our_domain(void); struct winbindd_domain *find_default_route_domain(void); struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid); struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name); -bool parse_domain_user(const char *domuser, fstring domain, fstring user); +bool parse_domain_user(const char *domuser, + fstring namespace, + fstring domain, + fstring user); bool canonicalize_username(fstring username_inout, fstring domain, fstring user); void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume); char *fill_domain_username_talloc(TALLOC_CTX *ctx, diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c index 1317dfe422d..068be91dca5 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -1575,28 +1575,37 @@ static bool assume_domain(const char *domain) return False; } -/* Parse a string of the form DOMAIN\user into a domain and a user */ - -bool parse_domain_user(const char *domuser, fstring domain, fstring user) +/* Parse a DOMAIN\user or UPN string into a domain, namespace and a user */ +bool parse_domain_user(const char *domuser, + fstring namespace, + fstring domain, + fstring user) { - char *p = strchr(domuser,*lp_winbind_separator()); + char *p = NULL; + + if (strlen(domuser) == 0) { + return false; + } - if ( !p ) { + p = strchr(domuser, *lp_winbind_separator()); + if (p != NULL) { + fstrcpy(user, p + 1); + fstrcpy(domain, domuser); + domain[PTR_DIFF(p, domuser)] = '\0'; + fstrcpy(namespace, domain); + } else { fstrcpy(user, domuser); - p = strchr(domuser, '@'); - if ( assume_domain(lp_workgroup()) && p == NULL) { + domain[0] = '\0'; + namespace[0] = '\0'; + p = strchr(domuser, '@'); + if (p != NULL) { + /* upn */ + fstrcpy(namespace, p + 1); + } else if (assume_domain(lp_workgroup())) { fstrcpy(domain, lp_workgroup()); - } else if (p != NULL) { - fstrcpy(domain, p + 1); - user[PTR_DIFF(p, domuser)] = 0; - } else { - return False; + fstrcpy(namespace, domain); } - } else { - fstrcpy(user, p+1); - fstrcpy(domain, domuser); - domain[PTR_DIFF(p, domuser)] = 0; } return strupper_m(domain); @@ -1613,7 +1622,11 @@ bool parse_domain_user(const char *domuser, fstring domain, fstring user) bool canonicalize_username(fstring username_inout, fstring domain, fstring user) { - if (!parse_domain_user(username_inout, domain, user)) { + fstring namespace; + bool ok; + + ok = parse_domain_user(username_inout, namespace, domain, user); + if (!ok) { return False; } slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s", |