Consolidate user create/delete paths in smbpasswd
authorSimo Sorce <idra@samba.org>
Sat, 16 May 2009 22:10:39 +0000 (18:10 -0400)
committerGünther Deschner <gd@samba.org>
Fri, 29 May 2009 16:03:42 +0000 (18:03 +0200)
This patch changes the way smbpasswd behaves when adding/deleting users.
smbpasswd now calls pdb_create_user/pdb_delete_user, this means that if
add/delete user scripts are configured then they are used to create or
delete unix users as well. If the scripts are not defined the behavioris
unchanged.
This also allow to use smbpasswd -a/-x with ldapsam:editposix to allow
automatic creation/deletion of users.

Signed-off-by: Günther Deschner <gd@samba.org>
source3/passdb/passdb.c
source3/utils/smbpasswd.c

index 6aab5e377c0763e23340d87ab70880fb7c37155a..9654e79d7a5f47b0f141ab5e87fbcadc34ade829 100644 (file)
@@ -627,7 +627,14 @@ bool lookup_global_sam_name(const char *name, int flags, uint32_t *rid,
 }
 
 /*************************************************************
- Change a password entry in the local smbpasswd file.
+ Change a password entry in the local passdb backend.
+
+ Assumptions:
+  - always called as root
+  - ignores the account type except when adding a new account
+  - will create/delete the unix account if the relative
+    add/delete user script is configured
+
  *************************************************************/
 
 NTSTATUS local_password_change(const char *user_name,
@@ -636,133 +643,135 @@ NTSTATUS local_password_change(const char *user_name,
                                char **pp_err_str,
                                char **pp_msg_str)
 {
-       struct samu *sam_pass=NULL;
-       uint32 other_acb;
+       TALLOC_CTX *tosctx;
+       struct samu *sam_pass;
+       uint32_t acb;
+       uint32_t rid;
        NTSTATUS result;
+       bool user_exists;
+       int ret;
 
        *pp_err_str = NULL;
        *pp_msg_str = NULL;
 
-       /* Get the smb passwd entry for this user */
-
-       if ( !(sam_pass = samu_new( NULL )) ) {
+       tosctx = talloc_tos();
+       if (!tosctx) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       become_root();
-       if(!pdb_getsampwnam(sam_pass, user_name)) {
-               unbecome_root();
-               TALLOC_FREE(sam_pass);
-
-               if ((local_flags & LOCAL_ADD_USER) || (local_flags & LOCAL_DELETE_USER)) {
-                       int tmp_debug = DEBUGLEVEL;
-                       struct passwd *pwd;
-
-                       /* Might not exist in /etc/passwd. */
-
-                       if (tmp_debug < 1) {
-                               DEBUGLEVEL = 1;
-                       }
+       sam_pass = samu_new(tosctx);
+       if (!sam_pass) {
+               result = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
 
-                       if ( !(pwd = getpwnam_alloc(talloc_autofree_context(), user_name)) ) {
-                               return NT_STATUS_NO_SUCH_USER;
+       /* Get the smb passwd entry for this user */
+       user_exists = pdb_getsampwnam(sam_pass, user_name);
+
+       /* Check delete first, we don't need to do anything else if we
+        * are going to delete the acocunt */
+       if (user_exists && (local_flags & LOCAL_DELETE_USER)) {
+
+               result = pdb_delete_user(tosctx, sam_pass);
+               if (!NT_STATUS_IS_OK(result)) {
+                       ret = asprintf(pp_err_str,
+                                       "Failed to delete entry for user %s.\n",
+                                       user_name);
+                       if (ret < 0) {
+                               *pp_err_str = NULL;
                        }
-
-                       /* create the struct samu and initialize the basic Unix properties */
-
-                       if ( !(sam_pass = samu_new( NULL )) ) {
-                               return NT_STATUS_NO_MEMORY;
+                       result = NT_STATUS_UNSUCCESSFUL;
+               } else {
+                       ret = asprintf(pp_msg_str,
+                                       "Deleted user %s.\n",
+                                       user_name);
+                       if (ret < 0) {
+                               *pp_msg_str = NULL;
                        }
+               }
+               goto done;
+       }
 
-                       result = samu_set_unix( sam_pass, pwd );
-
-                       DEBUGLEVEL = tmp_debug;
+       if (user_exists && (local_flags & LOCAL_ADD_USER)) {
+               /* the entry already existed */
+               local_flags &= ~LOCAL_ADD_USER;
+       }
 
-                       TALLOC_FREE( pwd );
+       if (!user_exists && !(local_flags & LOCAL_ADD_USER)) {
+               ret = asprintf(pp_err_str,
+                               "Failed to find entry for user %s.\n",
+                               user_name);
+               if (ret < 0) {
+                       *pp_err_str = NULL;
+               }
+               result = NT_STATUS_NO_SUCH_USER;
+               goto done;
+       }
 
-                       if (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PRIMARY_GROUP)) {
-                               return result;
-                       }
+       /* First thing add the new user if we are required to do so */
+       if (local_flags & LOCAL_ADD_USER) {
 
-                       if (!NT_STATUS_IS_OK(result)) {
-                               if (asprintf(pp_err_str, "Failed to " "initialize account for user %s: %s\n",
-                                               user_name, nt_errstr(result)) < 0) {
-                                       *pp_err_str = NULL;
-                               }
-                               return result;
-                       }
+               if (local_flags & LOCAL_TRUST_ACCOUNT) {
+                       acb = ACB_WSTRUST;
+               } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) {
+                       acb = ACB_DOMTRUST;
                } else {
-                       if (asprintf(pp_err_str, "Failed to find entry for user %s.\n", user_name) < 0) {
-                               *pp_err_str = NULL;
-                       }
-                       return NT_STATUS_NO_SUCH_USER;
+                       acb = ACB_NORMAL;
                }
-       } else {
-               unbecome_root();
-               /* the entry already existed */
-               local_flags &= ~LOCAL_ADD_USER;
-       }
 
-       /* the 'other' acb bits not being changed here */
-       other_acb =  (pdb_get_acct_ctrl(sam_pass) & (~(ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST|ACB_NORMAL)));
-       if (local_flags & LOCAL_TRUST_ACCOUNT) {
-               if (!pdb_set_acct_ctrl(sam_pass, ACB_WSTRUST | other_acb, PDB_CHANGED) ) {
-                       if (asprintf(pp_err_str, "Failed to set 'trusted workstation account' flags for user %s.\n", user_name) < 0) {
+               result = pdb_create_user(tosctx, user_name, acb, &rid);
+               if (!NT_STATUS_IS_OK(result)) {
+                       ret = asprintf(pp_err_str,
+                                       "Failed to add entry for user %s.\n",
+                                       user_name);
+                       if (ret < 0) {
                                *pp_err_str = NULL;
                        }
-                       TALLOC_FREE(sam_pass);
-                       return NT_STATUS_UNSUCCESSFUL;
+                       result = NT_STATUS_UNSUCCESSFUL;
+                       goto done;
                }
-       } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) {
-               if (!pdb_set_acct_ctrl(sam_pass, ACB_DOMTRUST | other_acb, PDB_CHANGED)) {
-                       if (asprintf(pp_err_str, "Failed to set 'domain trust account' flags for user %s.\n", user_name) < 0) {
-                               *pp_err_str = NULL;
-                       }
-                       TALLOC_FREE(sam_pass);
-                       return NT_STATUS_UNSUCCESSFUL;
+
+               sam_pass = samu_new(tosctx);
+               if (!sam_pass) {
+                       result = NT_STATUS_NO_MEMORY;
+                       goto done;
                }
-       } else {
-               if (!pdb_set_acct_ctrl(sam_pass, ACB_NORMAL | other_acb, PDB_CHANGED)) {
-                       if (asprintf(pp_err_str, "Failed to set 'normal account' flags for user %s.\n", user_name) < 0) {
+
+               /* Now get back the smb passwd entry for this new user */
+               user_exists = pdb_getsampwnam(sam_pass, user_name);
+               if (!user_exists) {
+                       ret = asprintf(pp_err_str,
+                                       "Failed to add entry for user %s.\n",
+                                       user_name);
+                       if (ret < 0) {
                                *pp_err_str = NULL;
                        }
-                       TALLOC_FREE(sam_pass);
-                       return NT_STATUS_UNSUCCESSFUL;
+                       result = NT_STATUS_UNSUCCESSFUL;
+                       goto done;
                }
        }
 
+       acb = pdb_get_acct_ctrl(sam_pass);
+
        /*
         * We are root - just write the new password
         * and the valid last change time.
         */
-
-       if (local_flags & LOCAL_DISABLE_USER) {
-               if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_DISABLED, PDB_CHANGED)) {
-                       if (asprintf(pp_err_str, "Failed to set 'disabled' flag for user %s.\n", user_name) < 0) {
-                               *pp_err_str = NULL;
-                       }
-                       TALLOC_FREE(sam_pass);
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
-       } else if (local_flags & LOCAL_ENABLE_USER) {
-               if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED), PDB_CHANGED)) {
-                       if (asprintf(pp_err_str, "Failed to unset 'disabled' flag for user %s.\n", user_name) < 0) {
+       if ((local_flags & LOCAL_SET_NO_PASSWORD) && !(acb & ACB_PWNOTREQ)) {
+               acb |= ACB_PWNOTREQ;
+               if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
+                       ret = asprintf(pp_err_str,
+                                       "Failed to set 'no password required' "
+                                       "flag for user %s.\n", user_name);
+                       if (ret < 0) {
                                *pp_err_str = NULL;
                        }
-                       TALLOC_FREE(sam_pass);
-                       return NT_STATUS_UNSUCCESSFUL;
+                       result = NT_STATUS_UNSUCCESSFUL;
+                       goto done;
                }
        }
 
-       if (local_flags & LOCAL_SET_NO_PASSWORD) {
-               if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)|ACB_PWNOTREQ, PDB_CHANGED)) {
-                       if (asprintf(pp_err_str, "Failed to set 'no password required' flag for user %s.\n", user_name) < 0) {
-                               *pp_err_str = NULL;
-                       }
-                       TALLOC_FREE(sam_pass);
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
-       } else if (local_flags & LOCAL_SET_PASSWORD) {
+       if (local_flags & LOCAL_SET_PASSWORD) {
                /*
                 * If we're dealing with setting a completely empty user account
                 * ie. One with a password of 'XXXX', but not set disabled (like
@@ -772,83 +781,106 @@ NTSTATUS local_password_change(const char *user_name,
                 * and the decision hasn't really been made to disable them (ie.
                 * don't create them disabled). JRA.
                 */
-               if ((pdb_get_lanman_passwd(sam_pass)==NULL) && (pdb_get_acct_ctrl(sam_pass)&ACB_DISABLED)) {
-                       if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_DISABLED), PDB_CHANGED)) {
-                               if (asprintf(pp_err_str, "Failed to unset 'disabled' flag for user %s.\n", user_name) < 0) {
+               if ((pdb_get_lanman_passwd(sam_pass) == NULL) &&
+                   (acb & ACB_DISABLED)) {
+                       acb &= (~ACB_DISABLED);
+                       if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
+                               ret = asprintf(pp_err_str,
+                                               "Failed to unset 'disabled' "
+                                               "flag for user %s.\n",
+                                               user_name);
+                               if (ret < 0) {
                                        *pp_err_str = NULL;
                                }
-                               TALLOC_FREE(sam_pass);
-                               return NT_STATUS_UNSUCCESSFUL;
-                       }
-               }
-               if (!pdb_set_acct_ctrl (sam_pass, pdb_get_acct_ctrl(sam_pass)&(~ACB_PWNOTREQ), PDB_CHANGED)) {
-                       if (asprintf(pp_err_str, "Failed to unset 'no password required' flag for user %s.\n", user_name) < 0) {
-                               *pp_err_str = NULL;
+                               result = NT_STATUS_UNSUCCESSFUL;
+                               goto done;
                        }
-                       TALLOC_FREE(sam_pass);
-                       return NT_STATUS_UNSUCCESSFUL;
                }
 
-               if (!pdb_set_plaintext_passwd (sam_pass, new_passwd)) {
-                       if (asprintf(pp_err_str, "Failed to set password for user %s.\n", user_name) < 0) {
+               acb &= (~ACB_PWNOTREQ);
+               if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
+                       ret = asprintf(pp_err_str,
+                                       "Failed to unset 'no password required'"
+                                       " flag for user %s.\n", user_name);
+                       if (ret < 0) {
                                *pp_err_str = NULL;
                        }
-                       TALLOC_FREE(sam_pass);
-                       return NT_STATUS_UNSUCCESSFUL;
+                       result = NT_STATUS_UNSUCCESSFUL;
+                       goto done;
                }
-       }       
 
-       if (local_flags & LOCAL_ADD_USER) {
-               if (NT_STATUS_IS_OK(pdb_add_sam_account(sam_pass))) {
-                       if (asprintf(pp_msg_str, "Added user %s.\n", user_name) < 0) {
-                               *pp_msg_str = NULL;
-                       }
-                       TALLOC_FREE(sam_pass);
-                       return NT_STATUS_OK;
-               } else {
-                       if (asprintf(pp_err_str, "Failed to add entry for user %s.\n", user_name) < 0) {
+               if (!pdb_set_plaintext_passwd(sam_pass, new_passwd)) {
+                       ret = asprintf(pp_err_str,
+                                       "Failed to set password for "
+                                       "user %s.\n", user_name);
+                               if (ret < 0) {
                                *pp_err_str = NULL;
                        }
-                       TALLOC_FREE(sam_pass);
-                       return NT_STATUS_UNSUCCESSFUL;
+                       result = NT_STATUS_UNSUCCESSFUL;
+                       goto done;
                }
-       } else if (local_flags & LOCAL_DELETE_USER) {
-               if (!NT_STATUS_IS_OK(pdb_delete_sam_account(sam_pass))) {
-                       if (asprintf(pp_err_str, "Failed to delete entry for user %s.\n", user_name) < 0) {
+       }
+
+       if ((local_flags & LOCAL_DISABLE_USER) && !(acb & ACB_DISABLED)) {
+               acb |= ACB_DISABLED;
+               if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
+                       ret = asprintf(pp_err_str,
+                                       "Failed to set 'disabled' flag for "
+                                       "user %s.\n", user_name);
+                       if (ret < 0) {
                                *pp_err_str = NULL;
                        }
-                       TALLOC_FREE(sam_pass);
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
-               if (asprintf(pp_msg_str, "Deleted user %s.\n", user_name) < 0) {
-                       *pp_msg_str = NULL;
+                       result = NT_STATUS_UNSUCCESSFUL;
+                       goto done;
                }
-       } else {
-               result = pdb_update_sam_account(sam_pass);
-               if(!NT_STATUS_IS_OK(result)) {
-                       if (asprintf(pp_err_str, "Failed to modify entry for user %s.\n", user_name) < 0) {
+       }
+
+       if ((local_flags & LOCAL_ENABLE_USER) && (acb & ACB_DISABLED)) {
+               acb &= (~ACB_DISABLED);
+               if (!pdb_set_acct_ctrl(sam_pass, acb, PDB_CHANGED)) {
+                       ret = asprintf(pp_err_str,
+                                       "Failed to unset 'disabled' flag for "
+                                       "user %s.\n", user_name);
+                       if (ret < 0) {
                                *pp_err_str = NULL;
                        }
-                       TALLOC_FREE(sam_pass);
-                       return result;
+                       result = NT_STATUS_UNSUCCESSFUL;
+                       goto done;
                }
-               if(local_flags & LOCAL_DISABLE_USER) {
-                       if (asprintf(pp_msg_str, "Disabled user %s.\n", user_name) < 0) {
-                               *pp_msg_str = NULL;
-                       }
-               } else if (local_flags & LOCAL_ENABLE_USER) {
-                       if (asprintf(pp_msg_str, "Enabled user %s.\n", user_name) < 0) {
-                               *pp_msg_str = NULL;
-                       }
-               } else if (local_flags & LOCAL_SET_NO_PASSWORD) {
-                       if (asprintf(pp_msg_str, "User %s password set to none.\n", user_name) < 0) {
-                               *pp_msg_str = NULL;
-                       }
+       }
+
+       /* now commit changes if any */
+       result = pdb_update_sam_account(sam_pass);
+       if (!NT_STATUS_IS_OK(result)) {
+               ret = asprintf(pp_err_str,
+                               "Failed to modify entry for user %s.\n",
+                               user_name);
+               if (ret < 0) {
+                       *pp_err_str = NULL;
                }
+               goto done;
+       }
+
+       if (local_flags & LOCAL_ADD_USER) {
+               ret = asprintf(pp_msg_str, "Added user %s.\n", user_name);
+       } else if (local_flags & LOCAL_DISABLE_USER) {
+               ret = asprintf(pp_msg_str, "Disabled user %s.\n", user_name);
+       } else if (local_flags & LOCAL_ENABLE_USER) {
+               ret = asprintf(pp_msg_str, "Enabled user %s.\n", user_name);
+       } else if (local_flags & LOCAL_SET_NO_PASSWORD) {
+               ret = asprintf(pp_msg_str,
+                               "User %s password set to none.\n", user_name);
        }
 
+       if (ret < 0) {
+               *pp_msg_str = NULL;
+       }
+
+       result = NT_STATUS_OK;
+
+done:
        TALLOC_FREE(sam_pass);
-       return NT_STATUS_OK;
+       return result;
 }
 
 /**********************************************************************
index 8cca93f5defd0a2a8be3ed18f21f0e1e64b7f705..c0b2cac18a106bce399797d37be54492cad5618d 100644 (file)
@@ -242,26 +242,29 @@ static NTSTATUS password_change(const char *remote_mach, char *username,
        char *msg_str = NULL;
 
        if (remote_mach != NULL) {
-               if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|
-                                                       LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) {
+               if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|
+                                  LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|
+                                  LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) {
                        /* these things can't be done remotely yet */
+                       fprintf(stderr, "Invalid remote operation!\n");
                        return NT_STATUS_UNSUCCESSFUL;
                }
-               ret = remote_password_change(remote_mach, username, 
+               ret = remote_password_change(remote_mach, username,
                                             old_passwd, new_pw, &err_str);
-               if (err_str != NULL)
-                       fprintf(stderr, "%s", err_str);
-               SAFE_FREE(err_str);
-               return ret;
+       } else {
+               ret = local_password_change(username, local_flags, new_pw,
+                                           &err_str, &msg_str);
        }
 
-       ret = local_password_change(username, local_flags, new_pw, 
-                                    &err_str, &msg_str);
-
-       if(msg_str)
+       if (msg_str) {
                printf("%s", msg_str);
-       if(err_str)
+       }
+       if (err_str) {
                fprintf(stderr, "%s", err_str);
+       }
+       if (!NT_STATUS_IS_OK(ret) && !err_str) {
+               fprintf(stderr, "Failed to change password!\n");
+       }
 
        SAFE_FREE(msg_str);
        SAFE_FREE(err_str);
@@ -430,21 +433,8 @@ static int process_root(int local_flags)
                }
 
                if((local_flags & LOCAL_SET_PASSWORD) && (new_passwd == NULL)) {
-                       struct passwd *passwd;
-
-                       if (remote_machine == NULL) {
-                               passwd = getpwnam_alloc(NULL, user_name);
-
-                               if (!passwd) {
-                                       fprintf(stderr, "Cannot locate Unix account for "
-                                               "'%s'!\n", user_name);
-                                       exit(1);
-                               }
-                               TALLOC_FREE(passwd);
-                       }
 
                        new_passwd = prompt_for_new_password(stdin_passwd_get);
-
                        if(!new_passwd) {
                                fprintf(stderr, "Unable to get new password.\n");
                                exit(1);
@@ -455,7 +445,6 @@ static int process_root(int local_flags)
        if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name,
                                             old_passwd, new_passwd,
                                             local_flags))) {
-               fprintf(stderr,"Failed to modify password entry for user %s\n", user_name);
                result = 1;
                goto done;
        } 
@@ -550,7 +539,6 @@ static int process_nonroot(int local_flags)
 
        if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name, old_pw,
                                             new_pw, 0))) {
-               fprintf(stderr,"Failed to change password for %s\n", user_name);
                result = 1;
                goto done;
        }