From 254938c636b6062630d54a598b2975d7a984f70d Mon Sep 17 00:00:00 2001 From: Jim McDonough Date: Tue, 11 Oct 2005 20:14:04 +0000 Subject: r10911: part of #2861: add rename support for usrmgr.exe when using tdbsam This gets it working before replacing tdb with the samba4 version. (This used to be commit 8210b0503a050e12ee1b4335fa6e50d10ad06577) --- source3/include/passdb.h | 6 +- source3/param/loadparm.c | 3 + source3/passdb/pdb_interface.c | 58 +++++++++ source3/passdb/pdb_tdb.c | 248 ++++++++++++++++++++++++++++++++------- source3/rpc_server/srv_samr_nt.c | 29 +++++ 5 files changed, 303 insertions(+), 41 deletions(-) (limited to 'source3') diff --git a/source3/include/passdb.h b/source3/include/passdb.h index e985ab582d..4964ff3759 100644 --- a/source3/include/passdb.h +++ b/source3/include/passdb.h @@ -269,7 +269,7 @@ struct pdb_search { * 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 @@ typedef struct pdb_context 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 @@ typedef struct pdb_methods 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); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 126d70939c..dc2784804d 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -151,6 +151,7 @@ typedef struct char *szNameResolveOrder; char *szPanicAction; char *szAddUserScript; + char *szRenameUserScript; char *szDelUserScript; char *szAddGroupScript; char *szDelGroupScript; @@ -1061,6 +1062,7 @@ static struct parm_struct parm_table[] = { {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_passdb_backend, &Globals.szPassdbBackend) 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) diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c index a9e41984c3..485f405568 100644 --- a/source3/passdb/pdb_interface.c +++ b/source3/passdb/pdb_interface.c @@ -325,6 +325,41 @@ static NTSTATUS context_delete_sam_account(struct pdb_context *context, SAM_ACCO 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 @@ static NTSTATUS make_pdb_context(struct pdb_context **context) (*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 @@ BOOL pdb_delete_sam_account(SAM_ACCOUNT *sam_acct) 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 @@ static NTSTATUS pdb_default_delete_sam_account (struct pdb_methods *methods, SAM 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 @@ NTSTATUS make_pdb_methods(TALLOC_CTX *mem_ctx, PDB_METHODS **methods) (*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; diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c index 755e33940b..f04c82a5b1 100644 --- a/source3/passdb/pdb_tdb.c +++ b/source3/passdb/pdb_tdb.c @@ -6,6 +6,7 @@ * Copyright (C) Gerald Carter 2000 * Copyright (C) Jeremy Allison 2001 * Copyright (C) Andrew Bartlett 2002 + * Copyright (C) Jim McDonough 2005 * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free @@ -515,6 +516,32 @@ static NTSTATUS tdbsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * 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,50 +600,19 @@ static NTSTATUS tdbsam_delete_sam_account(struct pdb_methods *my_methods, SAM_AC 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) { @@ -629,7 +625,9 @@ static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, 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 +638,40 @@ static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, 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,6 +680,56 @@ static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, 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; } @@ -666,7 +737,6 @@ static BOOL tdb_update_sam(struct pdb_methods *my_methods, SAM_ACCOUNT* newpwd, done: /* cleanup */ tdb_close (pwd_tdb); - SAFE_FREE(buf); return (ret); } @@ -695,6 +765,103 @@ static NTSTATUS tdbsam_add_sam_account (struct pdb_methods *my_methods, SAM_ACCO 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 +903,7 @@ static NTSTATUS pdb_init_tdbsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_meth (*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); diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index b69f03a3a2..26a691e9b4 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -2423,6 +2423,32 @@ NTSTATUS _samr_open_alias(pipes_struct *p, SAMR_Q_OPEN_ALIAS *q_u, SAMR_R_OPEN_A return r_u->status; } +/******************************************************************* + 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 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_ /* 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; -- cgit