winbindd: Update the calls to ws_name_XX() to reflect API changes.
authorGerald (Jerry) Carter <jerry@samba.org>
Mon, 15 Sep 2008 20:50:15 +0000 (15:50 -0500)
committerJeremy Allison <jra@samba.org>
Tue, 16 Sep 2008 17:27:59 +0000 (10:27 -0700)
* Ensures that all points an which a name is received or returned
  to/from a client passes through the name aliases layer (users
  and groups).

source3/winbindd/winbindd_group.c
source3/winbindd/winbindd_pam.c
source3/winbindd/winbindd_rpc.c
source3/winbindd/winbindd_user.c

index 4d5026d158dabea21e5aa90c8ae2a72ecb886d92..088f946877824093a2c6896a795411e43b701cd8 100644 (file)
@@ -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; j<n_members; j++) {
+                       fstring name_domain, name_acct;
+                       fstring qualified_name;
+                       char *mapped_name = NULL;
+                       NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
+                       struct winbindd_domain *target_domain = NULL;
+
+                       if (parse_domain_user(members[j], name_domain, name_acct)) {
+                               target_domain = find_domain_from_name_noinit(name_domain);
+                               /* NOW WHAT ? */
+                       }
+                       if (!target_domain) {
+                               target_domain = domain;
+                       }
+
+                       name_map_status = normalize_name_map(members, target_domain,
+                                                            name_acct, &mapped_name);
+
+                       /* Basic whitespace replacement */
+                       if (NT_STATUS_IS_OK(name_map_status)) {
+                               fill_domain_username(qualified_name, name_domain,
+                                                    mapped_name, true);
+                               mapped_name = qualified_name;
+                       }
+                       /* no mapping at all */
+                       else if (!NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
+                               mapped_name = members[j];
+                       }
+
+                       nt_status = add_names_to_list( mem_ctx, &names,
+                                                      &num_names,
+                                                      &mapped_name, 1);
+                       if ( !NT_STATUS_IS_OK(nt_status) ) {
+                               result = False;
+                               goto done;
+                       }
                }
 
                TALLOC_FREE( members );
@@ -679,6 +752,7 @@ void winbindd_getgrnam(struct winbindd_cli_state *state)
        struct winbindd_domain *domain;
        fstring name_domain, name_group;
        char *tmp;
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
        /* Ensure null termination */
        state->request.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));
 
-       /* Parse domain and 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;
+       }
 
-       memset(name_group, 0, sizeof(fstring));
+       /* Parse domain and groupname */
 
-       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);
+
+       /* 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,
-                                     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 */
 
index d4a2e3ed7942f2a524856efebafad15d69fd9069..d9104ca600577fcade960cb0066596a4d11c0421 100644 (file)
@@ -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);
index bb79d7ec1269a24d54a7ff91c46f6d23a099e3e0..df80ad80297c8c3a2e5f18152aa0174581ba834f 100644 (file)
@@ -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; i<num_rids; i++) {
+               NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
+               char *mapped_name = NULL;
+
                if ((*types)[i] != SID_NAME_UNKNOWN) {
-                       ws_name_replace( ret_names[i], WB_REPLACE_CHAR );
+                       name_map_status = normalize_name_map(mem_ctx,
+                                                            domain,
+                                                            ret_names[i],
+                                                            &mapped_name);
+                       if (NT_STATUS_IS_OK(name_map_status) ||
+                           NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
+                       {
+                               ret_names[i] = mapped_name;
+                       }
+
                        *domain_name = domains[i];
                }
        }
index 3b6dfdda1c9db38dc07888e361d252f2e823048b..e5d0a22a7324e03c905d1832fa526de3121f8f56 100644 (file)
@@ -67,12 +67,15 @@ static bool fillup_pw_field(const char *lp_template,
 }
 /* Fill a pwent structure with information we have obtained */
 
-static bool winbindd_fill_pwent(char *dom_name, char *user_name,
+static bool winbindd_fill_pwent(TALLOC_CTX *ctx, char *dom_name, char *user_name,
                                DOM_SID *user_sid, DOM_SID *group_sid,
                                char *full_name, char *homedir, char *shell,
                                struct winbindd_pw *pw)
 {
        fstring output_username;
+       char *mapped_name = NULL;
+       struct winbindd_domain *domain = NULL;
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
        if (!pw || !dom_name || !user_name)
                return False;
@@ -99,7 +102,28 @@ static bool winbindd_fill_pwent(char *dom_name, char *user_name,
 
        /* Username */
 
-       fill_domain_username(output_username, dom_name, user_name, True);
+       domain = find_domain_from_name_noinit(dom_name);
+       if (domain) {
+               nt_status = normalize_name_map(ctx, domain, user_name,
+                                              &mapped_name);
+       } else {
+               DEBUG(5,("winbindd_fill_pwent: Failed to find domain for %s.  "
+                        "Disabling name alias support\n", dom_name));
+               nt_status = NT_STATUS_NO_SUCH_DOMAIN;
+       }
+
+       /* Basic removal of whitespace */
+       if (NT_STATUS_IS_OK(nt_status)) {
+               fill_domain_username(output_username, dom_name, mapped_name, True);
+       }
+       /* Complete name replacement */
+       else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED)) {
+               fstrcpy(output_username, mapped_name);
+       }
+       /* No change at all */
+       else {
+               fill_domain_username(output_username, dom_name, user_name, True);
+       }
 
        safe_strcpy(pw->pw_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 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(domuser, domname, username)) {
+       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,