From f031095d9fd9da38d09ec758dcf1d1c1d791fc57 Mon Sep 17 00:00:00 2001 From: nekral-guest Date: Mon, 31 Dec 2007 14:54:46 +0000 Subject: [PATCH] * Split also check_perms() out of main(). * Before pam_end(), the return value of the previous pam API was already checked. No need to validate it again. --- ChangeLog | 4 +- src/chsh.c | 195 ++++++++++++++++++++++++++++------------------------- 2 files changed, 107 insertions(+), 92 deletions(-) diff --git a/ChangeLog b/ChangeLog index f18bac43..5823054a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,8 @@ 2007-12-31 Nicolas François - * src/chsh.c: Split process_flags() out of main(). + * src/chsh.c: Split process_flags(), and check_perms() out of main(). + * src/chsh.c: Before pam_end(), the return value of the previous + pam API was already checked. No need to validate it again. 2007-12-31 Nicolas François diff --git a/src/chsh.c b/src/chsh.c index 008da868..d554a4e0 100644 --- a/src/chsh.c +++ b/src/chsh.c @@ -72,6 +72,7 @@ static void new_fields (void); static int check_shell (const char *); static int restricted_shell (const char *); static void process_flags (int argc, char **argv); +static void check_perms (const struct passwd *pw); /* * usage - print command line syntax and exit @@ -208,6 +209,107 @@ static void process_flags (int argc, char **argv) } } +/* + * check_perms - check if the caller is allowed to add a group + * + * Non-root users are only allowed to change their shell, if their current + * shell is not a restricted shell. + * + * Non-root users must be authenticated. + * + * It will not return if the user is not allowed. + */ +static void check_perms (const struct passwd *pw) +{ +#ifdef USE_PAM + pam_handle_t *pamh = NULL; + int retval; + struct passwd *pampw; +#endif + + /* + * Non-privileged users are only allowed to change the shell if the + * UID of the user matches the current real UID. + */ + if (!amroot && pw->pw_uid != getuid ()) { + SYSLOG ((LOG_WARN, "can't change shell for `%s'", user)); + closelog (); + fprintf (stderr, + _("You may not change the shell for %s.\n"), user); + exit (1); + } + + /* + * Non-privileged users are only allowed to change the shell if it + * is not a restricted one. + */ + if (!amroot && restricted_shell (pw->pw_shell)) { + SYSLOG ((LOG_WARN, "can't change shell for `%s'", user)); + closelog (); + fprintf (stderr, + _("You may not change the shell for %s.\n"), user); + exit (1); + } +#ifdef WITH_SELINUX + /* + * If the UID of the user does not match the current real UID, + * check if the change is allowed by SELinux policy. + */ + if ((pw->pw_uid != getuid ()) + && (is_selinux_enabled () > 0) + && (selinux_check_passwd_access (PASSWD__CHSH) != 0)) { + SYSLOG ((LOG_WARN, "can't change shell for `%s'", user)); + closelog (); + fprintf (stderr, + _("You may not change the shell for %s.\n"), user); + exit (1); + } +#endif + +#ifndef USE_PAM + /* + * Non-privileged users are optionally authenticated (must enter + * the password of the user whose information is being changed) + * before any changes can be made. Idea from util-linux + * chfn/chsh. --marekm + */ + if (!amroot && getdef_bool ("CHSH_AUTH")) { + passwd_check (pw->pw_name, pw->pw_passwd, "chsh"); + } + +#else /* !USE_PAM */ + retval = PAM_SUCCESS; + + pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */ + if (pampw == NULL) { + retval = PAM_USER_UNKNOWN; + } + + if (retval == PAM_SUCCESS) { + retval = pam_start ("chsh", pampw->pw_name, &conv, &pamh); + } + + if (retval == PAM_SUCCESS) { + retval = pam_authenticate (pamh, 0); + if (retval != PAM_SUCCESS) { + pam_end (pamh, retval); + } + } + + if (retval == PAM_SUCCESS) { + retval = pam_acct_mgmt (pamh, 0); + if (retval != PAM_SUCCESS) { + pam_end (pamh, retval); + } + } + + if (retval != PAM_SUCCESS) { + fprintf (stderr, _("%s: PAM authentication failed\n"), Prog); + exit (E_NOPERM); + } +#endif /* USE_PAM */ +} + /* * chsh - this command controls changes to the user's shell * @@ -221,11 +323,6 @@ int main (int argc, char **argv) const struct passwd *pw; /* Password entry from /etc/passwd */ struct passwd pwent; /* New password entry */ -#ifdef USE_PAM - pam_handle_t *pamh = NULL; - int retval; -#endif - sanitize_env (); setlocale (LC_ALL, ""); @@ -295,90 +392,7 @@ int main (int argc, char **argv) } #endif - /* - * Non-privileged users are only allowed to change the shell if the - * UID of the user matches the current real UID. - */ - if (!amroot && pw->pw_uid != getuid ()) { - SYSLOG ((LOG_WARN, "can't change shell for `%s'", user)); - closelog (); - fprintf (stderr, - _("You may not change the shell for %s.\n"), user); - exit (1); - } - - /* - * Non-privileged users are only allowed to change the shell if it - * is not a restricted one. - */ - if (!amroot && restricted_shell (pw->pw_shell)) { - SYSLOG ((LOG_WARN, "can't change shell for `%s'", user)); - closelog (); - fprintf (stderr, - _("You may not change the shell for %s.\n"), user); - exit (1); - } -#ifdef WITH_SELINUX - /* - * If the UID of the user does not match the current real UID, - * check if the change is allowed by SELinux policy. - */ - if ((pw->pw_uid != getuid ()) - && (is_selinux_enabled () > 0) - && (selinux_check_passwd_access (PASSWD__CHSH) != 0)) { - SYSLOG ((LOG_WARN, "can't change shell for `%s'", user)); - closelog (); - fprintf (stderr, - _("You may not change the shell for %s.\n"), user); - exit (1); - } -#endif - -#ifndef USE_PAM - /* - * Non-privileged users are optionally authenticated (must enter - * the password of the user whose information is being changed) - * before any changes can be made. Idea from util-linux - * chfn/chsh. --marekm - */ - if (!amroot && getdef_bool ("CHSH_AUTH")) - passwd_check (pw->pw_name, pw->pw_passwd, "chsh"); - -#else /* !USE_PAM */ - retval = PAM_SUCCESS; - - { - struct passwd *pampw; - pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */ - if (pampw == NULL) { - retval = PAM_USER_UNKNOWN; - } - - if (retval == PAM_SUCCESS) { - retval = pam_start ("chsh", pampw->pw_name, - &conv, &pamh); - } - } - - if (retval == PAM_SUCCESS) { - retval = pam_authenticate (pamh, 0); - if (retval != PAM_SUCCESS) { - pam_end (pamh, retval); - } - } - - if (retval == PAM_SUCCESS) { - retval = pam_acct_mgmt (pamh, 0); - if (retval != PAM_SUCCESS) { - pam_end (pamh, retval); - } - } - - if (retval != PAM_SUCCESS) { - fprintf (stderr, _("%s: PAM authentication failed\n"), Prog); - exit (E_NOPERM); - } -#endif /* USE_PAM */ + check_perms (pw); /* * Now get the login shell. Either get it from the password @@ -501,8 +515,7 @@ int main (int argc, char **argv) nscd_flush_cache ("passwd"); #ifdef USE_PAM - if (retval == PAM_SUCCESS) - pam_end (pamh, PAM_SUCCESS); + pam_end (pamh, PAM_SUCCESS); #endif /* USE_PAM */ closelog ();