winbind: Fix UPN handling in parse_domain_user()
authorAndreas Schneider <asn@samba.org>
Thu, 26 Apr 2018 10:17:12 +0000 (12:17 +0200)
committerAndreas Schneider <asn@cryptomilk.org>
Fri, 11 May 2018 07:07:37 +0000 (09:07 +0200)
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>
selftest/knownfail.d/upn_handling
source3/winbindd/winbindd_cache.c
source3/winbindd/winbindd_ccache_access.c
source3/winbindd/winbindd_creds.c
source3/winbindd/winbindd_getgrnam.c
source3/winbindd/winbindd_getgroups.c
source3/winbindd/winbindd_getpwnam.c
source3/winbindd/winbindd_pam.c
source3/winbindd/winbindd_proto.h
source3/winbindd/winbindd_util.c

index 0fa2aa35f307d59358d7f193f483f0da740728de..bcbedb4f90311a8fabb62ed3c704df6ed1a8fa1e 100644 (file)
@@ -1,4 +1,3 @@
-^samba3\.wbinfo_user_info\.user_info\.upn\.jane\.doe.ad_member
 ^samba3\.wbinfo_user_info\.name_to_sid\.upn\.testdenied_upn.ad_member
 ^samba3\.wbinfo_user_info\.user_info\.upn\.testdenied_upn.ad_member
 ^samba3\.wbinfo_user_info\.user_info\.domain\.alice.fl2008r2dc
index 9f9e8781c2177d569160c73878b1a2827e79a4f8..2778e27374fd9c8d96023b0ce65670e22fca3f7d 100644 (file)
@@ -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;
        }
index 039e653401322dc21809f83846de7420277982ae..6bcf9a3552cbb6b6a7919132ac2b22bf00de2eea 100644 (file)
@@ -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;
index 15cca554d45e64d7fbf0b3600927e1e452b31511..2d7aacf36a9bd139e173efe00727a5979a2de25f 100644 (file)
@@ -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)) {
index 1d9a8b94d48f8eac89d7a9867a6319604eefc1e5..37c205ddba4dd6b8b078e845b0a205aa275cc540 100644 (file)
@@ -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);
index 68b470d6dad64091f5400f506d7962ea85d7b094..f7f2df5f7b1208e9287cb53618f456ff08fa05b9 100644 (file)
@@ -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);
index 26686bf9f0f6960e9739e5c199e371b7ba9346d5..8da66c251417bbbc6d6d7ec4f1c2d080111b0424 100644 (file)
@@ -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);
index e273ab3b8bee8f1ebe10e04ace8536908c652af7..ff40ab54a70894700a354f3290c399bb70a2b686 100644 (file)
@@ -646,7 +646,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;
@@ -659,6 +659,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;
 
@@ -694,7 +695,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) {
@@ -976,7 +980,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];
@@ -997,10 +1001,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)) {
@@ -1245,19 +1253,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;
@@ -1271,7 +1288,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));
@@ -1663,19 +1680,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
@@ -1870,12 +1891,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';
@@ -1901,7 +1923,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,
@@ -2491,15 +2520,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;
        }
 
@@ -2708,7 +2742,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;
@@ -2721,8 +2755,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,
@@ -2739,8 +2774,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) - "
index 8e5b35c14a90fa8f2d0e4b285bc110ac4828799b..4740d88b744c4f33356b774e52b331ee7ccbfcb2 100644 (file)
@@ -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,
index 9d67b4b1507d7fb688705b0faa1088f27684e6f3..fd4d2b1f9dea094100e5db2b57876cdb367c79fe 100644 (file)
@@ -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",