Also split update_shell() out of main().

This commit is contained in:
nekral-guest 2007-12-31 15:06:22 +00:00
parent f031095d9f
commit ca035a53a0
2 changed files with 101 additions and 84 deletions

View File

@ -1,6 +1,7 @@
2007-12-31 Nicolas François <nicolas.francois@centraliens.net>
* src/chsh.c: Split process_flags(), and check_perms() out of main().
* src/chsh.c: Split process_flags(), check_perms(), and update_shell()
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.

View File

@ -73,6 +73,7 @@ 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);
static void update_shell (const char *user, char *loginsh);
/*
* usage - print command line syntax and exit
@ -310,6 +311,103 @@ static void check_perms (const struct passwd *pw)
#endif /* USE_PAM */
}
/*
* update_shell - update the user's shell in the passwd database
*
* Commit the user's entry after changing her shell field.
*
* It will not return in case of error.
*/
static void update_shell (const char *user, char *loginsh)
{
const struct passwd *pw; /* Password entry from /etc/passwd */
struct passwd pwent; /* New password entry */
/*
* Before going any further, raise the ulimit to prevent
* colliding into a lowered ulimit, and set the real UID
* to root to protect against unexpected signals. Any
* keyboard signals are set to be ignored.
*/
if (setuid (0) != 0) {
SYSLOG ((LOG_ERR, "can't setuid(0)"));
closelog ();
fprintf (stderr, _("Cannot change ID to root.\n"));
exit (1);
}
pwd_init ();
/*
* The passwd entry is now ready to be committed back to
* the password file. Get a lock on the file and open it.
*/
if (pw_lock () == 0) {
SYSLOG ((LOG_WARN, "can't lock /etc/passwd"));
closelog ();
fprintf (stderr,
_
("Cannot lock the password file; try again later.\n"));
exit (1);
}
if (pw_open (O_RDWR) == 0) {
SYSLOG ((LOG_ERR, "can't open /etc/passwd"));
closelog ();
fprintf (stderr, _("Cannot open the password file.\n"));
pw_unlock ();
exit (1);
}
/*
* Get the entry to update using pw_locate() - we want the real
* one from /etc/passwd, not the one from getpwnam() which could
* contain the shadow password if (despite the warnings) someone
* enables AUTOSHADOW (or SHADOW_COMPAT in libc). --marekm
*/
pw = pw_locate (user);
if (NULL == pw) {
pw_unlock ();
fprintf (stderr,
_("%s: %s not found in /etc/passwd\n"), Prog, user);
exit (1);
}
/*
* Make a copy of the entry, then change the shell field. The other
* fields remain unchanged.
*/
pwent = *pw;
pwent.pw_shell = loginsh;
/*
* Update the passwd file entry. If there is a DBM file, update
* that entry as well.
*/
if (pw_update (&pwent) == 0) {
SYSLOG ((LOG_ERR, "error updating passwd entry"));
closelog ();
fprintf (stderr, _("Error updating the password entry.\n"));
pw_unlock ();
exit (1);
}
/*
* Changes have all been made, so commit them and unlock the file.
*/
if (pw_close () == 0) {
SYSLOG ((LOG_ERR, "can't rewrite /etc/passwd"));
closelog ();
fprintf (stderr, _("Cannot commit password file changes.\n"));
pw_unlock ();
exit (1);
}
if (pw_unlock () == 0) {
SYSLOG ((LOG_ERR, "can't unlock /etc/passwd"));
closelog ();
fprintf (stderr, _("Cannot unlock the password file.\n"));
exit (1);
}
}
/*
* chsh - this command controls changes to the user's shell
*
@ -321,7 +419,6 @@ int main (int argc, char **argv)
char *user; /* User name */
int sflg = 0; /* -s - set shell from command line */
const struct passwd *pw; /* Password entry from /etc/passwd */
struct passwd pwent; /* New password entry */
sanitize_env ();
@ -427,89 +524,8 @@ int main (int argc, char **argv)
exit (1);
}
/*
* Before going any further, raise the ulimit to prevent
* colliding into a lowered ulimit, and set the real UID
* to root to protect against unexpected signals. Any
* keyboard signals are set to be ignored.
*/
if (setuid (0)) {
SYSLOG ((LOG_ERR, "can't setuid(0)"));
closelog ();
fprintf (stderr, _("Cannot change ID to root.\n"));
exit (1);
}
pwd_init ();
update_shell (user, loginsh);
/*
* The passwd entry is now ready to be committed back to
* the password file. Get a lock on the file and open it.
*/
if (!pw_lock ()) {
SYSLOG ((LOG_WARN, "can't lock /etc/passwd"));
closelog ();
fprintf (stderr,
_
("Cannot lock the password file; try again later.\n"));
exit (1);
}
if (!pw_open (O_RDWR)) {
SYSLOG ((LOG_ERR, "can't open /etc/passwd"));
closelog ();
fprintf (stderr, _("Cannot open the password file.\n"));
pw_unlock ();
exit (1);
}
/*
* Get the entry to update using pw_locate() - we want the real
* one from /etc/passwd, not the one from getpwnam() which could
* contain the shadow password if (despite the warnings) someone
* enables AUTOSHADOW (or SHADOW_COMPAT in libc). --marekm
*/
pw = pw_locate (user);
if (!pw) {
pw_unlock ();
fprintf (stderr,
_("%s: %s not found in /etc/passwd\n"), Prog, user);
exit (1);
}
/*
* Make a copy of the entry, then change the shell field. The other
* fields remain unchanged.
*/
pwent = *pw;
pwent.pw_shell = loginsh;
/*
* Update the passwd file entry. If there is a DBM file, update
* that entry as well.
*/
if (!pw_update (&pwent)) {
SYSLOG ((LOG_ERR, "error updating passwd entry"));
closelog ();
fprintf (stderr, _("Error updating the password entry.\n"));
pw_unlock ();
exit (1);
}
/*
* Changes have all been made, so commit them and unlock the file.
*/
if (!pw_close ()) {
SYSLOG ((LOG_ERR, "can't rewrite /etc/passwd"));
closelog ();
fprintf (stderr, _("Cannot commit password file changes.\n"));
pw_unlock ();
exit (1);
}
if (!pw_unlock ()) {
SYSLOG ((LOG_ERR, "can't unlock /etc/passwd"));
closelog ();
fprintf (stderr, _("Cannot unlock the password file.\n"));
exit (1);
}
SYSLOG ((LOG_INFO, "changed user `%s' shell to `%s'", user, loginsh));
nscd_flush_cache ("passwd");