Index: param/loadparm.c =================================================================== --- param/loadparm.c (revision 10871) +++ param/loadparm.c (working copy) @@ -151,6 +151,7 @@ char *szNameResolveOrder; char *szPanicAction; char *szAddUserScript; + char *szRenameUserScript; char *szDelUserScript; char *szAddGroupScript; char *szDelGroupScript; @@ -1061,6 +1062,7 @@ {N_("Logon Options"), P_SEP, P_SEPARATOR}, {"add user script", P_STRING, P_GLOBAL, &Globals.szAddUserScript, NULL, NULL, FLAG_ADVANCED}, + {"rename user script", P_STRING, P_GLOBAL, &Globals.szRenameUserScript, NULL, NULL, FLAG_ADVANCED}, {"delete user script", P_STRING, P_GLOBAL, &Globals.szDelUserScript, NULL, NULL, FLAG_ADVANCED}, {"add group script", P_STRING, P_GLOBAL, &Globals.szAddGroupScript, NULL, NULL, FLAG_ADVANCED}, {"delete group script", P_STRING, P_GLOBAL, &Globals.szDelGroupScript, NULL, NULL, FLAG_ADVANCED}, @@ -1734,6 +1736,7 @@ FN_GLOBAL_LIST(lp_preload_modules, &Globals.szPreloadModules) FN_GLOBAL_STRING(lp_panic_action, &Globals.szPanicAction) FN_GLOBAL_STRING(lp_adduser_script, &Globals.szAddUserScript) +FN_GLOBAL_STRING(lp_renameuser_script, &Globals.szRenameUserScript) FN_GLOBAL_STRING(lp_deluser_script, &Globals.szDelUserScript) FN_GLOBAL_CONST_STRING(lp_guestaccount, &Globals.szGuestaccount) Index: rpc_server/srv_samr_nt.c =================================================================== --- rpc_server/srv_samr_nt.c (revision 10871) +++ rpc_server/srv_samr_nt.c (working copy) @@ -2424,6 +2424,32 @@ } /******************************************************************* + set_user_info_7 + ********************************************************************/ +static NTSTATUS set_user_info_7(const SAM_USER_INFO_7 *id7, SAM_ACCOUNT *pwd) +{ + fstring new_name; + NTSTATUS rc; + + if (id7 == NULL) { + DEBUG(5, ("set_user_info_7: NULL id7\n")); + pdb_free_sam(&pwd); + return NT_STATUS_ACCESS_DENIED; + } + + if(!rpcstr_pull(new_name, id7->uni_name.buffer, sizeof(new_name), id7->uni_name.uni_str_len*2, 0)) { + DEBUG(5, ("set_user_info_7: failed to get new username\n")); + pdb_free_sam(&pwd); + return NT_STATUS_ACCESS_DENIED; + } + + rc = pdb_rename_sam_account(pwd, new_name); + + pdb_free_sam(&pwd); + return rc; +} + +/******************************************************************* set_user_info_16 ********************************************************************/ @@ -2924,6 +2950,9 @@ /* ok! user info levels (lots: see MSDEV help), off we go... */ switch (switch_value) { + case 7: + r_u->status = set_user_info_7(ctr->info.id7, pwd); + break; case 16: if (!set_user_info_16(ctr->info.id16, pwd)) r_u->status = NT_STATUS_ACCESS_DENIED; Index: passdb/pdb_tdb.c =================================================================== --- passdb/pdb_tdb.c (revision 10871) +++ passdb/pdb_tdb.c (working copy) @@ -515,6 +515,32 @@ return tdbsam_getsampwrid(my_methods, user, rid); } +static BOOL tdb_delete_samacct_only(TDB_CONTEXT *pwd_tdb, + struct pdb_methods *my_methods, + SAM_ACCOUNT *sam_pass) +{ + TDB_DATA key; + fstring keystr; + fstring name; + + fstrcpy(name, pdb_get_username(sam_pass)); + strlower_m(name); + + /* set the search key */ + slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name); + key.dptr = keystr; + key.dsize = strlen (keystr) + 1; + + /* it's outaa here! 8^) */ + if (tdb_delete(pwd_tdb, key) != TDB_SUCCESS) { + DEBUG(5, ("Error deleting entry from tdb passwd database!\n")); + DEBUGADD(5, (" Error: %s\n", tdb_errorstr(pwd_tdb))); + tdb_close(pwd_tdb); + return False; + } + return True; +} + /*************************************************************************** Delete a SAM_ACCOUNT ****************************************************************************/ @@ -573,51 +599,20 @@ return NT_STATUS_OK; } + /*************************************************************************** - Update the TDB SAM + Update the TDB SAM account record only ****************************************************************************/ - -static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, int flag) +static BOOL tdb_update_samacct_only(TDB_CONTEXT *pwd_tdb, + struct pdb_methods *my_methods, + SAM_ACCOUNT* newpwd, int flag) { - struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; - TDB_CONTEXT *pwd_tdb = NULL; TDB_DATA key, data; uint8 *buf = NULL; fstring keystr; fstring name; BOOL ret = True; - uint32 user_rid; - /* invalidate the existing TDB iterator if it is open */ - - if (tdb_state->passwd_tdb) { - tdb_close(tdb_state->passwd_tdb); - tdb_state->passwd_tdb = NULL; - } - - /* open the account TDB passwd*/ - - pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR | O_CREAT); - - if (!pwd_tdb) { - DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", - tdb_state->tdbsam_location)); - return False; - } - - if (!pdb_get_group_rid(newpwd)) { - DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n", - pdb_get_username(newpwd))); - ret = False; - goto done; - } - - if ( !(user_rid = pdb_get_user_rid(newpwd)) ) { - DEBUG(0,("tdb_update_sam: SAM_ACCOUNT (%s) with no RID!\n", pdb_get_username(newpwd))); - ret = False; - goto done; - } - /* copy the SAM_ACCOUNT struct into a BYTE buffer for storage */ if ((data.dsize=init_buffer_from_sam (&buf, newpwd, False)) == -1) { DEBUG(0,("tdb_update_sam: ERROR - Unable to copy SAM_ACCOUNT info BYTE buffer!\n")); @@ -629,7 +624,9 @@ fstrcpy(name, pdb_get_username(newpwd)); strlower_m(name); - DEBUG(5, ("Storing %saccount %s with RID %d\n", flag == TDB_INSERT ? "(new) " : "", name, user_rid)); + DEBUG(5, ("Storing %saccount %s with RID %d\n", + flag == TDB_INSERT ? "(new) " : "", name, + pdb_get_user_rid(newpwd))); /* setup the USER index key */ slprintf(keystr, sizeof(keystr)-1, "%s%s", USERPREFIX, name); @@ -640,17 +637,40 @@ if (tdb_store(pwd_tdb, key, data, flag) != TDB_SUCCESS) { DEBUG(0, ("Unable to modify passwd TDB!")); DEBUGADD(0, (" Error: %s", tdb_errorstr(pwd_tdb))); - DEBUGADD(0, (" occured while storing the main record (%s)\n", keystr)); + DEBUGADD(0, (" occured while storing the main record (%s)\n", + keystr)); ret = False; goto done; } + +done: + /* cleanup */ + SAFE_FREE(buf); + return (ret); +} + +/*************************************************************************** + Update the TDB SAM RID record only +****************************************************************************/ +static BOOL tdb_update_ridrec_only(TDB_CONTEXT *pwd_tdb, + struct pdb_methods *my_methods, + SAM_ACCOUNT* newpwd, int flag) +{ + TDB_DATA key, data; + fstring keystr; + fstring name; + + fstrcpy(name, pdb_get_username(newpwd)); + strlower_m(name); + /* setup RID data */ data.dsize = strlen(name) + 1; data.dptr = name; /* setup the RID index key */ - slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, user_rid); + slprintf(keystr, sizeof(keystr)-1, "%s%.8x", RIDPREFIX, + pdb_get_user_rid(newpwd)); key.dptr = keystr; key.dsize = strlen (keystr) + 1; @@ -659,14 +679,63 @@ DEBUG(0, ("Unable to modify TDB passwd !")); DEBUGADD(0, (" Error: %s\n", tdb_errorstr(pwd_tdb))); DEBUGADD(0, (" occured while storing the RID index (%s)\n", keystr)); + return False; + } + + return True; + +} + +/*************************************************************************** + Update the TDB SAM +****************************************************************************/ + +static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, int flag) +{ + struct tdbsam_privates *tdb_state = (struct tdbsam_privates *)my_methods->private_data; + TDB_CONTEXT *pwd_tdb = NULL; + BOOL ret = True; + uint32 user_rid; + + /* invalidate the existing TDB iterator if it is open */ + + if (tdb_state->passwd_tdb) { + tdb_close(tdb_state->passwd_tdb); + tdb_state->passwd_tdb = NULL; + } + + /* open the account TDB passwd*/ + + pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR | O_CREAT); + + if (!pwd_tdb) { + DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", + tdb_state->tdbsam_location)); + return False; + } + + if (!pdb_get_group_rid(newpwd)) { + DEBUG (0,("tdb_update_sam: Failing to store a SAM_ACCOUNT for [%s] without a primary group RID\n", + pdb_get_username(newpwd))); ret = False; goto done; } + if ( !(user_rid = pdb_get_user_rid(newpwd)) ) { + DEBUG(0,("tdb_update_sam: SAM_ACCOUNT (%s) with no RID!\n", pdb_get_username(newpwd))); + ret = False; + goto done; + } + + if (!tdb_update_samacct_only(pwd_tdb, my_methods, newpwd, flag) || + !tdb_update_ridrec_only(pwd_tdb, my_methods, newpwd, flag)) { + ret = False; + goto done; + } + done: /* cleanup */ tdb_close (pwd_tdb); - SAFE_FREE(buf); return (ret); } @@ -695,6 +764,103 @@ return NT_STATUS_UNSUCCESSFUL; } +/*************************************************************************** + Renames a SAM_ACCOUNT + - check for the posix user/rename user script + - Add and lock the new user record + - rename the posix user + - rewrite the rid->username record + - delete the old user + - unlock the new user record +***************************************************************************/ +static NTSTATUS tdbsam_rename_sam_account(struct pdb_methods *my_methods, + SAM_ACCOUNT *oldname, const char *newname) +{ + struct tdbsam_privates *tdb_state = + (struct tdbsam_privates *)my_methods->private_data; + SAM_ACCOUNT *new_acct = NULL; + pstring rename_script; + TDB_CONTEXT *pwd_tdb = NULL; + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + BOOL interim_account = False; + + if (!*(lp_renameuser_script())) + goto done; + + if (!pdb_copy_sam_account(oldname, &new_acct) || + !pdb_set_username(new_acct, newname, PDB_CHANGED)) + goto done; + + /* invalidate the existing TDB iterator if it is open */ + + if (tdb_state->passwd_tdb) { + tdb_close(tdb_state->passwd_tdb); + tdb_state->passwd_tdb = NULL; + } + + /* open the account TDB passwd */ + + pwd_tdb = tdbsam_tdbopen(tdb_state->tdbsam_location, O_RDWR | O_CREAT); + + if (!pwd_tdb) { + DEBUG(0, ("tdb_update_sam: Unable to open TDB passwd (%s)!\n", + tdb_state->tdbsam_location)); + goto done; + } + + /* add the new account and lock it */ + if (!tdb_update_samacct_only(pwd_tdb, my_methods, new_acct, + TDB_INSERT)) + goto done; + interim_account = True; + + if (tdb_lock_bystring(pwd_tdb, newname, 30) == -1) { + goto done; + } + + /* rename the posix user */ + pstrcpy(rename_script, lp_renameuser_script()); + + if (*rename_script) { + int rename_ret; + + pstring_sub(rename_script, "%unew", newname); + pstring_sub(rename_script, "%uold", pdb_get_username(oldname)); + rename_ret = smbrun(rename_script, NULL); + + DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret)); + + if (rename_ret) + goto done; + } else { + goto done; + } + + /* rewrite the rid->username record */ + if (!tdb_update_ridrec_only(pwd_tdb, my_methods, new_acct, TDB_MODIFY)) + goto done; + interim_account = False; + tdb_unlock_bystring(pwd_tdb, newname); + + tdb_delete_samacct_only(pwd_tdb, my_methods, oldname); + + ret = NT_STATUS_OK; + + +done: + /* cleanup */ + if (interim_account) { + tdb_unlock_bystring(pwd_tdb, newname); + tdb_delete_samacct_only(pwd_tdb, my_methods, new_acct); + } + if (pwd_tdb) + tdb_close (pwd_tdb); + if (new_acct) + pdb_free_sam(&new_acct); + + return (ret); +} + static void free_private_data(void **vp) { struct tdbsam_privates **tdb_state = (struct tdbsam_privates **)vp; @@ -736,6 +902,7 @@ (*pdb_method)->add_sam_account = tdbsam_add_sam_account; (*pdb_method)->update_sam_account = tdbsam_update_sam_account; (*pdb_method)->delete_sam_account = tdbsam_delete_sam_account; + (*pdb_method)->rename_sam_account = tdbsam_rename_sam_account; tdb_state = TALLOC_ZERO_P(pdb_context->mem_ctx, struct tdbsam_privates); Index: passdb/pdb_interface.c =================================================================== --- passdb/pdb_interface.c (revision 10871) +++ passdb/pdb_interface.c (working copy) @@ -325,6 +325,41 @@ return sam_acct->methods->delete_sam_account(sam_acct->methods, sam_acct); } +static NTSTATUS context_rename_sam_account(struct pdb_context *context, SAM_ACCOUNT *oldname, const char *newname) +{ + NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; + + struct pdb_methods *pdb_selected; + if (!context) { + DEBUG(0, ("invalid pdb_context specified!\n")); + return ret; + } + + if (!oldname->methods){ + pdb_selected = context->pdb_methods; + /* There's no passdb backend specified for this account. + * Try to delete it in every passdb available + * Needed to delete accounts in smbpasswd that are not + * in /etc/passwd. + */ + while (pdb_selected){ + if (NT_STATUS_IS_OK(ret = pdb_selected->rename_sam_account(pdb_selected, oldname, newname))) { + return ret; + } + pdb_selected = pdb_selected->next; + } + return ret; + } + + if (!oldname->methods->rename_sam_account){ + DEBUG(0,("invalid oldname->methods->rename_sam_account\n")); + return ret; + } + + return oldname->methods->rename_sam_account(oldname->methods, oldname, newname); +} + + static NTSTATUS context_update_login_attempts(struct pdb_context *context, SAM_ACCOUNT *sam_acct, BOOL success) { @@ -850,6 +885,7 @@ (*context)->pdb_add_sam_account = context_add_sam_account; (*context)->pdb_update_sam_account = context_update_sam_account; (*context)->pdb_delete_sam_account = context_delete_sam_account; + (*context)->pdb_rename_sam_account = context_rename_sam_account; (*context)->pdb_update_login_attempts = context_update_login_attempts; (*context)->pdb_getgrsid = context_getgrsid; (*context)->pdb_getgrgid = context_getgrgid; @@ -1103,6 +1139,22 @@ return NT_STATUS_IS_OK(pdb_context->pdb_delete_sam_account(pdb_context, sam_acct)); } +NTSTATUS pdb_rename_sam_account(SAM_ACCOUNT *oldname, const char *newname) +{ + struct pdb_context *pdb_context = pdb_get_static_context(False); + + if (!pdb_context) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + if (sam_account_cache != NULL) { + pdb_free_sam(&sam_account_cache); + sam_account_cache = NULL; + } + + return pdb_context->pdb_rename_sam_account(pdb_context, oldname, newname); +} + NTSTATUS pdb_update_login_attempts(SAM_ACCOUNT *sam_acct, BOOL success) { struct pdb_context *pdb_context = pdb_get_static_context(False); @@ -1440,6 +1492,11 @@ return NT_STATUS_NOT_IMPLEMENTED; } +static NTSTATUS pdb_default_rename_sam_account (struct pdb_methods *methods, SAM_ACCOUNT *pwd, const char *newname) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + static NTSTATUS pdb_default_update_login_attempts (struct pdb_methods *methods, SAM_ACCOUNT *newpwd, BOOL success) { return NT_STATUS_OK; @@ -1983,6 +2040,7 @@ (*methods)->add_sam_account = pdb_default_add_sam_account; (*methods)->update_sam_account = pdb_default_update_sam_account; (*methods)->delete_sam_account = pdb_default_delete_sam_account; + (*methods)->rename_sam_account = pdb_default_rename_sam_account; (*methods)->update_login_attempts = pdb_default_update_login_attempts; (*methods)->getgrsid = pdb_default_getgrsid; Index: include/passdb.h =================================================================== --- include/passdb.h (revision 10871) +++ include/passdb.h (working copy) @@ -269,7 +269,7 @@ * this SAMBA will load. Increment this if *ANY* changes are made to the interface. */ -#define PASSDB_INTERFACE_VERSION 9 +#define PASSDB_INTERFACE_VERSION 10 typedef struct pdb_context { @@ -294,6 +294,8 @@ NTSTATUS (*pdb_update_sam_account)(struct pdb_context *, SAM_ACCOUNT *sampass); NTSTATUS (*pdb_delete_sam_account)(struct pdb_context *, SAM_ACCOUNT *username); + + NTSTATUS (*pdb_rename_sam_account)(struct pdb_context *, SAM_ACCOUNT *oldname, const char *newname); NTSTATUS (*pdb_update_login_attempts)(struct pdb_context *context, SAM_ACCOUNT *sam_acct, BOOL success); @@ -422,6 +424,8 @@ NTSTATUS (*delete_sam_account)(struct pdb_methods *, SAM_ACCOUNT *username); + NTSTATUS (*rename_sam_account)(struct pdb_methods *, SAM_ACCOUNT *oldname, const char *newname); + NTSTATUS (*update_login_attempts)(struct pdb_methods *methods, SAM_ACCOUNT *sam_acct, BOOL success); NTSTATUS (*getgrsid)(struct pdb_methods *methods, GROUP_MAP *map, DOM_SID sid);