r10911: part of #2861: add rename support for usrmgr.exe when using tdbsam
authorJim McDonough <jmcd@samba.org>
Tue, 11 Oct 2005 20:14:04 +0000 (20:14 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:04:56 +0000 (11:04 -0500)
This gets it working before replacing tdb with the samba4 version.
(This used to be commit 8210b0503a050e12ee1b4335fa6e50d10ad06577)

source3/include/passdb.h
source3/param/loadparm.c
source3/passdb/pdb_interface.c
source3/passdb/pdb_tdb.c
source3/rpc_server/srv_samr_nt.c

index e985ab582dcbe666fd5b2a66563165d949ecd9af..4964ff37591fd66cd31927e3d701bd27ce801f91 100644 (file)
@@ -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);
index 126d70939c009516dddd279442fe5372d9798279..dc2784804d53c009690f40a733ee3435e58fcf48 100644 (file)
@@ -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)
index a9e41984c3d119eefaadac9276b32168f2b6eedd..485f4055682f415f61cca9f1a92bc7adcaba95fc 100644 (file)
@@ -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;
index 755e33940b8dedd492f76de9c814c8fce9cfb92b..f04c82a5b157c8708b6dcd7735b097dbfaf2c304 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) Gerald Carter     2000
  * Copyright (C) Jeremy Allison    2001
  * Copyright (C) Andrew Bartlett   2002
+ * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 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);
 
index b69f03a3a283cf0ac569d4029eb4dfa4a9e66709..26a691e9b40ee28414480680a4d6fc711cff0602 100644 (file)
@@ -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;