diff --git a/source3/winbindd/winbindd_group.c b/source3/winbindd/winbindd_group.c index 4d5026d158d..088f9468778 100644 --- a/source3/winbindd/winbindd_group.c +++ b/source3/winbindd/winbindd_group.c @@ -179,12 +179,32 @@ static bool fill_passdb_alias_grmem(struct winbindd_domain *domain, /* Fill a grent structure from various other information */ -static bool fill_grent(struct winbindd_gr *gr, const char *dom_name, - const char *gr_name, gid_t unix_gid) +static bool fill_grent(TALLOC_CTX *mem_ctx, struct winbindd_gr *gr, + const char *dom_name, + char *gr_name, gid_t unix_gid) { fstring full_group_name; + char *mapped_name = NULL; + struct winbindd_domain *domain = find_domain_from_name_noinit(dom_name); + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - fill_domain_username( full_group_name, dom_name, gr_name, True ); + nt_status = normalize_name_map(mem_ctx, domain, gr_name, + &mapped_name); + + /* Basic whitespace replacement */ + if (NT_STATUS_IS_OK(nt_status)) { + fill_domain_username(full_group_name, dom_name, + mapped_name, true); + } + /* Mapped to an aliase */ + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) { + fstrcpy(full_group_name, mapped_name); + } + /* no change */ + else { + fill_domain_username( full_group_name, dom_name, + gr_name, True ); + } gr->gr_gid = unix_gid; @@ -280,7 +300,10 @@ static bool fill_grent_mem_domusers( TALLOC_CTX *mem_ctx, char *domainname = NULL; char *username = NULL; fstring name; + char *mapped_name = NULL; enum lsa_SidType type; + struct winbindd_domain *target_domain = NULL; + NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL; DEBUG(10,("fill_grent_mem_domain_users: " "sid %s in 'Domain Users' in domain %s\n", @@ -300,7 +323,24 @@ static bool fill_grent_mem_domusers( TALLOC_CTX *mem_ctx, nt_errstr(status))); return False; } - fill_domain_username(name, domain->name, username, True); + + target_domain = find_domain_from_name_noinit(domainname); + name_map_status = normalize_name_map(mem_ctx, target_domain, + username, &mapped_name); + + /* Basic whitespace replacement */ + if (NT_STATUS_IS_OK(name_map_status)) { + fill_domain_username(name, domainname, mapped_name, true); + } + /* Mapped to an alias */ + else if (NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) { + fstrcpy(name, mapped_name); + } + /* no mapping done...use original name */ + else { + fill_domain_username(name, domainname, username, true); + } + len = strlen(name); buf_len = len + 1; if (!(buf = (char *)SMB_MALLOC(buf_len))) { @@ -552,6 +592,7 @@ static bool fill_grent_mem(struct winbindd_domain *domain, uint32 n_members = 0; char **members = NULL; NTSTATUS nt_status; + int j; nt_status = expand_groups( mem_ctx, domain, glist, n_glist, @@ -562,13 +603,45 @@ static bool fill_grent_mem(struct winbindd_domain *domain, goto done; } - /* Add new group members to list */ + /* Add new group members to list. Pass through the + alias mapping function */ - nt_status = add_names_to_list( mem_ctx, &names, &num_names, - members, n_members ); - if ( !NT_STATUS_IS_OK(nt_status) ) { - result = False; - goto done; + for (j=0; jrequest.data.groupname[sizeof(state->request.data.groupname)-1]='\0'; @@ -686,11 +760,20 @@ void winbindd_getgrnam(struct winbindd_cli_state *state) DEBUG(3, ("[%5lu]: getgrnam %s\n", (unsigned long)state->pid, state->request.data.groupname)); + nt_status = normalize_name_unmap(state->mem_ctx, + state->request.data.groupname, + &tmp); + /* If we didn't map anything in the above call, just reset the + tmp pointer to the original string */ + if (!NT_STATUS_IS_OK(nt_status) && + !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) + { + tmp = state->request.data.groupname; + } + /* Parse domain and groupname */ - memset(name_group, 0, sizeof(fstring)); - - tmp = state->request.data.groupname; + memset(name_group, 0, sizeof(name_group)); name_domain[0] = '\0'; name_group[0] = '\0'; @@ -723,7 +806,7 @@ void winbindd_getgrnam(struct winbindd_cli_state *state) /* Get rid and name type from name */ - ws_name_replace( name_group, WB_REPLACE_CHAR ); + fstrcpy( name_group, tmp ); winbindd_lookupname_async( state->mem_ctx, domain->name, name_group, getgrnam_recv, WINBINDD_GETGRNAM, state ); @@ -771,7 +854,8 @@ static void getgrsid_sid2gid_recv(void *private_data, bool success, gid_t gid) return; } - if (!fill_grent(&s->state->response.data.gr, dom_name, group_name, gid) || + if (!fill_grent(s->state->mem_ctx, &s->state->response.data.gr, + dom_name, group_name, gid) || !fill_grent_mem(domain, s->state, &s->group_sid, s->group_type, &num_gr_mem, &gr_mem, &gr_mem_len)) { @@ -796,6 +880,9 @@ static void getgrsid_lookupsid_recv( void *private_data, bool success, enum lsa_SidType name_type ) { struct getgrsid_state *s = (struct getgrsid_state *)private_data; + char *mapped_name = NULL; + fstring raw_name; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; if (!success) { DEBUG(5,("getgrsid_lookupsid_recv: lookupsid failed!\n")); @@ -814,15 +901,39 @@ static void getgrsid_lookupsid_recv( void *private_data, bool success, dom_name, name, name_type)); request_error(s->state); return; -} + } - if ( (s->group_name = talloc_asprintf( s->state->mem_ctx, - "%s%c%s", - dom_name, - *lp_winbind_separator(), - name)) == NULL ) -{ - DEBUG(1, ("getgrsid_lookupsid_recv: talloc_asprintf() Failed!\n")); + /* normalize the name and ensure that we have the DOM\name + coming out of here */ + + fstrcpy(raw_name, name); + + nt_status = normalize_name_unmap(s->state->mem_ctx, raw_name, + &mapped_name); + + /* basiuc whitespace reversal */ + if (NT_STATUS_IS_OK(nt_status)) { + s->group_name = talloc_asprintf(s->state->mem_ctx, + "%s%c%s", + dom_name, + *lp_winbind_separator(), + mapped_name); + } + /* mapped from alias */ + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) { + s->group_name = mapped_name; + } + /* no mapping at all. use original string */ + else { + s->group_name = talloc_asprintf(s->state->mem_ctx, + "%s%c%s", + dom_name, + *lp_winbind_separator(), + raw_name); + } + + if (s->group_name == NULL) { + DEBUG(1, ("getgrsid_lookupsid_recv: group_name is NULL!\n")); request_error(s->state); return; } @@ -831,10 +942,10 @@ static void getgrsid_lookupsid_recv( void *private_data, bool success, winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid, getgrsid_sid2gid_recv, s); - } +} static void winbindd_getgrsid( struct winbindd_cli_state *state, const DOM_SID group_sid ) - { +{ struct getgrsid_state *s; if ( (s = TALLOC_ZERO_P(state->mem_ctx, struct getgrsid_state)) == NULL ) { @@ -1261,7 +1372,7 @@ void winbindd_getgrent(struct winbindd_cli_state *state) fill_domain_username(domain_group_name, ent->domain_name, name_list[ent->sam_entry_index].acct_name, True); - result = fill_grent(&group_list[group_list_ndx], + result = fill_grent(state->mem_ctx, &group_list[group_list_ndx], ent->domain_name, name_list[ent->sam_entry_index].acct_name, group_gid); @@ -1413,6 +1524,8 @@ static void getgroups_sid2gid_recv(void *private_data, bool success, gid_t gid); void winbindd_getgroups(struct winbindd_cli_state *state) { struct getgroups_state *s; + char *real_name = NULL; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; /* Ensure null termination */ state->request.data.username @@ -1432,13 +1545,22 @@ void winbindd_getgroups(struct winbindd_cli_state *state) s->state = state; - ws_name_return( state->request.data.username, WB_REPLACE_CHAR ); + nt_status = normalize_name_unmap(state->mem_ctx, + state->request.data.username, + &real_name); - if (!parse_domain_user_talloc(state->mem_ctx, - state->request.data.username, + /* Reset the real_name pointer if we didn't do anything + productive in the above call */ + if (!NT_STATUS_IS_OK(nt_status) && + !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) + { + real_name = state->request.data.username; + } + + if (!parse_domain_user_talloc(state->mem_ctx, real_name, &s->domname, &s->username)) { DEBUG(5, ("Could not parse domain user: %s\n", - state->request.data.username)); + real_name)); /* error out if we do not have nested group support */ diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index d4a2e3ed794..d9104ca6005 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -811,7 +811,9 @@ void winbindd_pam_auth(struct winbindd_cli_state *state) { struct winbindd_domain *domain; fstring name_domain, name_user; + char *mapped_user = NULL; NTSTATUS result; + NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL; /* Ensure null termination */ state->request.data.auth.user @@ -831,10 +833,20 @@ void winbindd_pam_auth(struct winbindd_cli_state *state) /* Parse domain and username */ - ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR ); + name_map_status = normalize_name_unmap(state->mem_ctx, + state->request.data.auth.user, + &mapped_user); - if (!canonicalize_username(state->request.data.auth.user, - name_domain, name_user)) { + /* If the name normalization didnt' actually do anything, + just use the original name */ + + if (!NT_STATUS_IS_OK(name_map_status) && + !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) + { + mapped_user = state->request.data.auth.user; + } + + if (!canonicalize_username(mapped_user, name_domain, name_user)) { result = NT_STATUS_NO_SUCH_USER; goto done; } @@ -1447,7 +1459,10 @@ 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; + char *mapped_user; + fstring domain_user; struct netr_SamInfo3 *info3 = NULL; + NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL; /* Ensure null termination */ state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0'; @@ -1465,9 +1480,26 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain, /* Parse domain and username */ - ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR ); + name_map_status = normalize_name_unmap(state->mem_ctx, + state->request.data.auth.user, + &mapped_user); - parse_domain_user(state->request.data.auth.user, name_domain, name_user); + /* If the name normalization didnt' actually do anything, + just use the original name */ + + if (!NT_STATUS_IS_OK(name_map_status) && + !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) + { + mapped_user = state->request.data.auth.user; + } + + parse_domain_user(mapped_user, name_domain, name_user); + + if ( mapped_user != state->request.data.auth.user ) { + fstr_sprintf( domain_user, "%s\\%s", name_domain, name_user ); + safe_strcpy( state->request.data.auth.user, domain_user, + sizeof(state->request.data.auth.user)-1 ); + } if (domain->online == false) { result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; @@ -1970,14 +2002,30 @@ done: void winbindd_pam_chauthtok(struct winbindd_cli_state *state) { fstring domain, user; + char *mapped_user; struct winbindd_domain *contact_domain; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid, state->request.data.chauthtok.user)); /* Setup crap */ - ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR ); + nt_status = normalize_name_unmap(state->mem_ctx, + state->request.data.chauthtok.user, + &mapped_user); + + /* Update the chauthtok name if we did any mapping */ + + if (NT_STATUS_IS_OK(nt_status) || + NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) + { + fstrcpy(state->request.data.chauthtok.user, mapped_user); + } + + /* Must pass in state->...chauthtok.user because + canonicalize_username() assumes an fstring(). Since + we have already copied it (if necessary), this is ok. */ if (!canonicalize_username(state->request.data.chauthtok.user, domain, user)) { set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER); diff --git a/source3/winbindd/winbindd_rpc.c b/source3/winbindd/winbindd_rpc.c index bb79d7ec126..df80ad80297 100644 --- a/source3/winbindd/winbindd_rpc.c +++ b/source3/winbindd/winbindd_rpc.c @@ -279,6 +279,8 @@ NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain, char *full_name = NULL; struct rpc_pipe_client *cli; POLICY_HND lsa_policy; + NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL; + char *mapped_name = NULL; if (name == NULL || *name=='\0') { full_name = talloc_asprintf(mem_ctx, "%s", domain_name); @@ -294,9 +296,19 @@ NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain, DEBUG(3,("rpc: name_to_sid name=%s\n", full_name)); - ws_name_return( full_name, WB_REPLACE_CHAR ); + name_map_status = normalize_name_unmap(mem_ctx, full_name, + &mapped_name); - DEBUG(3,("name_to_sid [rpc] %s for domain %s\n", full_name?full_name:"", domain_name )); + /* Reset the full_name pointer if we mapped anytthing */ + + if (NT_STATUS_IS_OK(name_map_status) || + NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) + { + full_name = mapped_name; + } + + DEBUG(3,("name_to_sid [rpc] %s for domain %s\n", + full_name?full_name:"", domain_name )); result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy); if (!NT_STATUS_IS_OK(result)) @@ -332,6 +344,8 @@ NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain, NTSTATUS result; struct rpc_pipe_client *cli; POLICY_HND lsa_policy; + NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL; + char *mapped_name = NULL; DEBUG(3,("sid_to_name [rpc] %s for domain %s\n", sid_string_dbg(sid), domain->name )); @@ -356,9 +370,17 @@ NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain, *domain_name = domains[0]; *name = names[0]; - ws_name_replace( *name, WB_REPLACE_CHAR ); - DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name)); + + name_map_status = normalize_name_map(mem_ctx, domain, *name, + &mapped_name); + if (NT_STATUS_IS_OK(name_map_status) || + NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) + { + *name = mapped_name; + DEBUG(5,("returning mapped name -- %s\n", *name)); + } + return NT_STATUS_OK; } @@ -411,8 +433,20 @@ NTSTATUS msrpc_rids_to_names(struct winbindd_domain *domain, ret_names = *names; for (i=0; ipw_name, output_username, sizeof(pw->pw_name) - 1); @@ -179,6 +203,7 @@ struct getpwsid_state { uid_t uid; DOM_SID group_sid; gid_t gid; + bool username_mapped; }; static void getpwsid_queryuser_recv(void *private_data, bool success, @@ -231,6 +256,8 @@ static void getpwsid_queryuser_recv(void *private_data, bool success, fstring username; struct getpwsid_state *s = talloc_get_type_abort(private_data, struct getpwsid_state); + char *mapped_name; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; if (!success) { DEBUG(5, ("Could not query domain %s SID %s\n", @@ -272,7 +299,23 @@ static void getpwsid_queryuser_recv(void *private_data, bool success, strlower_m( username ); s->username = talloc_strdup(s->state->mem_ctx, username); - ws_name_replace( s->username, WB_REPLACE_CHAR ); + nt_status = normalize_name_map(s->state->mem_ctx, s->domain, + s->username, &mapped_name); + + /* Basic removal of whitespace */ + if (NT_STATUS_IS_OK(nt_status)) { + s->username = mapped_name; + s->username_mapped = false; + } + /* Complete name replacement */ + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) { + s->username = mapped_name; + s->username_mapped = true; + } + /* No change at all */ + else { + s->username_mapped = false; + } s->fullname = talloc_strdup(s->state->mem_ctx, full_name); s->homedir = talloc_strdup(s->state->mem_ctx, homedir); @@ -330,8 +373,16 @@ static void getpwsid_sid2gid_recv(void *private_data, bool success, gid_t gid) pw = &s->state->response.data.pw; pw->pw_uid = s->uid; pw->pw_gid = s->gid; + + /* allow username to be overridden by the alias mapping */ + + if ( s->username_mapped ) { + fstrcpy( output_username, s->username ); + } else { fill_domain_username(output_username, s->domain->name, s->username, True); + } + safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1); safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1); @@ -370,8 +421,10 @@ void winbindd_getpwnam(struct winbindd_cli_state *state) { struct winbindd_domain *domain; fstring domname, username; + char *mapped_user = NULL; char *domuser; size_t dusize; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; domuser = state->request.data.username; dusize = sizeof(state->request.data.username); @@ -383,9 +436,19 @@ void winbindd_getpwnam(struct winbindd_cli_state *state) (unsigned long)state->pid, domuser)); - ws_name_return(domuser, WB_REPLACE_CHAR); + nt_status = normalize_name_unmap(state->mem_ctx, domuser, + &mapped_user); - if (!parse_domain_user(domuser, domname, username)) { + /* If we could not convert from an aliased name or a + normalized name, then just use the original name */ + + if (!NT_STATUS_IS_OK(nt_status) && + !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) + { + mapped_user = domuser; + } + + if (!parse_domain_user(mapped_user, domname, username)) { DEBUG(5, ("Could not parse domain user: %s\n", domuser)); request_error(state); return; @@ -743,6 +806,7 @@ void winbindd_getpwent(struct winbindd_cli_state *state) /* Lookup user info */ result = winbindd_fill_pwent( + state->mem_ctx, ent->domain_name, name_list[ent->sam_entry_index].name, &name_list[ent->sam_entry_index].user_sid,