Index: passdb/pdb_ldap.c =================================================================== --- passdb/pdb_ldap.c (revision 12844) +++ passdb/pdb_ldap.c (working copy) @@ -1893,8 +1893,9 @@ DEBUG (3, ("ldapsam_rename_sam_account: Renaming user %s to %s.\n", oldname, newname)); - pstring_sub(rename_script, "%unew", newname); - pstring_sub(rename_script, "%uold", oldname); + /* we have to allow the account name to end with a '$' */ + string_sub2(rename_script, "%unew", newname, sizeof(pstring), False, False); + string_sub2(rename_script, "%uold", oldname, sizeof(pstring), False, False); rc = smbrun(rename_script, NULL); DEBUG(rc ? 0 : 3,("Running the command `%s' gave %d\n", Index: rpc_server/srv_samr_nt.c =================================================================== --- rpc_server/srv_samr_nt.c (revision 12844) +++ rpc_server/srv_samr_nt.c (working copy) @@ -3024,14 +3024,49 @@ set_user_info_21 ********************************************************************/ -static BOOL set_user_info_21(SAM_USER_INFO_21 *id21, SAM_ACCOUNT *pwd) +static NTSTATUS set_user_info_21(TALLOC_CTX *mem_ctx, SAM_USER_INFO_21 *id21, SAM_ACCOUNT *pwd) { - + fstring new_name; + NTSTATUS status; + if (id21 == NULL) { DEBUG(5, ("set_user_info_21: NULL id21\n")); - return False; + return NT_STATUS_ACCESS_DENIED; } - + + /* we need to separately check for an account rename first */ + if (rpcstr_pull(new_name, id21->uni_user_name.buffer, + sizeof(new_name), id21->uni_user_name.uni_str_len*2, 0) && + (!strequal(new_name, pdb_get_username(pwd)))) { + + /* check to see if the new username already exists. Note: we can't + reliably lock all backends, so there is potentially the + possibility that a user can be created in between this check and + the rename. The rename should fail, but may not get the + exact same failure status code. I think this is small enough + of a window for this type of operation and the results are + simply that the rename fails with a slightly different status + code (like UNSUCCESSFUL instead of ALREADY_EXISTS). */ + + status = can_create(mem_ctx, new_name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = pdb_rename_sam_account(pwd, new_name); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("set_user_info_21: failed to rename account: %s\n", + nt_errstr(status))); + pdb_free_sam(&pwd); + return status; + } + + /* set the new username so that later + functions can work on the new account */ + pdb_set_username(pwd, new_name, PDB_SET); + } + copy_id21_to_sam_passwd(pwd, id21); /* @@ -3047,12 +3082,12 @@ /* write the change out */ if(!pdb_update_sam_account(pwd)) { pdb_free_sam(&pwd); - return False; + return NT_STATUS_ACCESS_DENIED; } pdb_free_sam(&pwd); - return True; + return NT_STATUS_OK; } /******************************************************************* @@ -3423,8 +3458,8 @@ r_u->status = NT_STATUS_ACCESS_DENIED; break; case 21: - if (!set_user_info_21(ctr->info.id21, pwd)) - return NT_STATUS_ACCESS_DENIED; + r_u->status = set_user_info_21(p->mem_ctx, + ctr->info.id21, pwd); break; default: r_u->status = NT_STATUS_INVALID_INFO_CLASS;