chage cleanups
* src/chage.c: Before pam_end(), the return value of the previous pam API was already checked. No need to validate it again. * src/chage.c: main() split in new functions: process_flags(), check_flags(), check_perms(), open_files(), and close_files().
This commit is contained in:
parent
8563319b8b
commit
388dcee3e4
@ -1,3 +1,11 @@
|
||||
2007-12-29 Nicolas François <nicolas.francois@centraliens.net>
|
||||
|
||||
chage cleanups
|
||||
* src/chage.c: Before pam_end(), the return value of the previous
|
||||
pam API was already checked. No need to validate it again.
|
||||
* src/chage.c: main() split in new functions: process_flags(),
|
||||
check_flags(), check_perms(), open_files(), and close_files().
|
||||
|
||||
2007-12-28 Nicolas François <nicolas.francois@centraliens.net>
|
||||
|
||||
Same changes for chgpasswd:
|
||||
|
389
src/chage.c
389
src/chage.c
@ -65,8 +65,7 @@ static int
|
||||
mflg = 0, /* set minimum number of days before password change */
|
||||
Mflg = 0, /* set maximim number of days before password change */
|
||||
Wflg = 0; /* set expiration warning days */
|
||||
|
||||
static int locks;
|
||||
static int amroot = 0;
|
||||
|
||||
static long mindays;
|
||||
static long maxdays;
|
||||
@ -83,6 +82,11 @@ static void date_to_str (char *, size_t, time_t);
|
||||
static int new_fields (void);
|
||||
static void print_date (time_t);
|
||||
static void list_fields (void);
|
||||
static void process_flags (int argc, char **argv);
|
||||
static void check_flags (int argc, int opt_index);
|
||||
static void check_perms (void);
|
||||
static void open_files (int readonly);
|
||||
static void close_files (void);
|
||||
|
||||
/*
|
||||
* isnum - determine whether or not a string is a number
|
||||
@ -296,135 +300,85 @@ static void list_fields (void)
|
||||
warndays);
|
||||
}
|
||||
|
||||
/*
|
||||
* chage - change a user's password aging information
|
||||
*
|
||||
* This command controls the password aging information.
|
||||
*
|
||||
* The valid options are
|
||||
*
|
||||
* -d set last password change date (*)
|
||||
* -E set account expiration date (*)
|
||||
* -I set password inactive after expiration (*)
|
||||
* -l show account aging information
|
||||
* -M set maximim number of days before password change (*)
|
||||
* -m set minimum number of days before password change (*)
|
||||
* -W set expiration warning days (*)
|
||||
*
|
||||
* (*) requires root permission to execute.
|
||||
*
|
||||
* All of the time fields are entered in the internal format which is
|
||||
* either seconds or days.
|
||||
*/
|
||||
|
||||
int main (int argc, char **argv)
|
||||
static void process_flags (int argc, char **argv)
|
||||
{
|
||||
const struct spwd *sp;
|
||||
struct spwd spwd;
|
||||
uid_t ruid;
|
||||
gid_t rgid;
|
||||
int amroot;
|
||||
const struct passwd *pw;
|
||||
struct passwd pwent;
|
||||
char name[BUFSIZ];
|
||||
|
||||
#ifdef USE_PAM
|
||||
pam_handle_t *pamh = NULL;
|
||||
int retval;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_AUDIT
|
||||
audit_help_open ();
|
||||
#endif
|
||||
sanitize_env ();
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
ruid = getuid ();
|
||||
rgid = getgid ();
|
||||
amroot = (ruid == 0);
|
||||
#ifdef WITH_SELINUX
|
||||
if (amroot && is_selinux_enabled () > 0)
|
||||
amroot = (selinux_check_passwd_access (PASSWD__ROOTOK) == 0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get the program name so that error messages can use it.
|
||||
* Parse the command line options.
|
||||
*/
|
||||
Prog = Basename (argv[0]);
|
||||
int option_index = 0;
|
||||
int c;
|
||||
static struct option long_options[] = {
|
||||
{"lastday", required_argument, NULL, 'd'},
|
||||
{"expiredate", required_argument, NULL, 'E'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"inactive", required_argument, NULL, 'I'},
|
||||
{"list", no_argument, NULL, 'l'},
|
||||
{"mindays", required_argument, NULL, 'm'},
|
||||
{"maxdays", required_argument, NULL, 'M'},
|
||||
{"warndays", required_argument, NULL, 'W'},
|
||||
{NULL, 0, NULL, '\0'}
|
||||
};
|
||||
|
||||
{
|
||||
/*
|
||||
* Parse the command line options.
|
||||
*/
|
||||
int option_index = 0;
|
||||
int c;
|
||||
static struct option long_options[] = {
|
||||
{"lastday", required_argument, NULL, 'd'},
|
||||
{"expiredate", required_argument, NULL, 'E'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"inactive", required_argument, NULL, 'I'},
|
||||
{"list", no_argument, NULL, 'l'},
|
||||
{"mindays", required_argument, NULL, 'm'},
|
||||
{"maxdays", required_argument, NULL, 'M'},
|
||||
{"warndays", required_argument, NULL, 'W'},
|
||||
{NULL, 0, NULL, '\0'}
|
||||
};
|
||||
|
||||
while ((c =
|
||||
getopt_long (argc, argv, "d:E:hI:lm:M:W:", long_options,
|
||||
&option_index)) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
dflg++;
|
||||
if (!isnum (optarg))
|
||||
lastday = strtoday (optarg);
|
||||
else
|
||||
lastday = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'E':
|
||||
Eflg++;
|
||||
if (!isnum (optarg))
|
||||
expdays = strtoday (optarg);
|
||||
else
|
||||
expdays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'h':
|
||||
usage ();
|
||||
break;
|
||||
case 'I':
|
||||
Iflg++;
|
||||
inactdays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'l':
|
||||
lflg++;
|
||||
break;
|
||||
case 'm':
|
||||
mflg++;
|
||||
mindays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'M':
|
||||
Mflg++;
|
||||
maxdays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'W':
|
||||
Wflg++;
|
||||
warndays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
while ((c =
|
||||
getopt_long (argc, argv, "d:E:hI:lm:M:W:", long_options,
|
||||
&option_index)) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
dflg++;
|
||||
if (!isnum (optarg))
|
||||
lastday = strtoday (optarg);
|
||||
else
|
||||
lastday = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'E':
|
||||
Eflg++;
|
||||
if (!isnum (optarg))
|
||||
expdays = strtoday (optarg);
|
||||
else
|
||||
expdays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'h':
|
||||
usage ();
|
||||
break;
|
||||
case 'I':
|
||||
Iflg++;
|
||||
inactdays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'l':
|
||||
lflg++;
|
||||
break;
|
||||
case 'm':
|
||||
mflg++;
|
||||
mindays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'M':
|
||||
Mflg++;
|
||||
maxdays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
case 'W':
|
||||
Wflg++;
|
||||
warndays = strtol (optarg, 0, 10);
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
|
||||
check_flags (argc, optind);
|
||||
}
|
||||
|
||||
|
||||
static void check_flags (int argc, int opt_index)
|
||||
{
|
||||
|
||||
/*
|
||||
* Make certain the flags do not conflict and that there is a user
|
||||
* name on the command line.
|
||||
*/
|
||||
|
||||
if (argc != optind + 1)
|
||||
if (argc != opt_index + 1) {
|
||||
usage ();
|
||||
}
|
||||
|
||||
if (lflg && (mflg || Mflg || dflg || Wflg || Iflg || Eflg)) {
|
||||
fprintf (stderr,
|
||||
@ -432,6 +386,15 @@ int main (int argc, char **argv)
|
||||
Prog);
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Additional check done later */
|
||||
static void check_perms (void)
|
||||
{
|
||||
#ifdef USE_PAM
|
||||
pam_handle_t *pamh = NULL;
|
||||
int retval;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* An unprivileged user can ask for their own aging information, but
|
||||
@ -448,8 +411,6 @@ int main (int argc, char **argv)
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
|
||||
OPENLOG ("chage");
|
||||
|
||||
#ifdef USE_PAM
|
||||
retval = PAM_SUCCESS;
|
||||
|
||||
@ -485,15 +446,12 @@ int main (int argc, char **argv)
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
#endif /* USE_PAM */
|
||||
}
|
||||
|
||||
static void open_files (int readonly)
|
||||
{
|
||||
/*
|
||||
* We use locks for read-write accesses only (locks implies amroot,
|
||||
* but amroot doesn't imply locks).
|
||||
*/
|
||||
locks = !lflg;
|
||||
|
||||
/*
|
||||
* Lock and open the password file. This loads all of the password
|
||||
* open the password file. This loads all of the password
|
||||
* file entries into memory. Then we get a pointer to the password
|
||||
* file entry for the requested user.
|
||||
*/
|
||||
@ -503,24 +461,6 @@ int main (int argc, char **argv)
|
||||
closelog ();
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
if (!(pw = pw_locate (argv[optind]))) {
|
||||
fprintf (stderr, _("%s: unknown user %s\n"), Prog,
|
||||
argv[optind]);
|
||||
closelog ();
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
|
||||
pwent = *pw;
|
||||
STRFCPY (name, pwent.pw_name);
|
||||
|
||||
if (!spw_file_present ()) {
|
||||
fprintf (stderr,
|
||||
_("%s: the shadow password file is not present\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_ERR, "can't find the shadow password file"));
|
||||
closelog ();
|
||||
exit (E_SHADOW_NOTFOUND);
|
||||
}
|
||||
|
||||
/*
|
||||
* For shadow password files we have to lock the file and read in
|
||||
@ -528,7 +468,7 @@ int main (int argc, char **argv)
|
||||
* does not have to exist in this case; a new entry will be created
|
||||
* for this user if one does not exist already.
|
||||
*/
|
||||
if (locks && !spw_lock ()) {
|
||||
if (!readonly && !spw_lock ()) {
|
||||
fprintf (stderr,
|
||||
_("%s: can't lock shadow password file\n"), Prog);
|
||||
SYSLOG ((LOG_ERR, "failed locking %s", SHADOW_FILE));
|
||||
@ -539,7 +479,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
if (!spw_open (locks ? O_RDWR : O_RDONLY)) {
|
||||
if (!spw_open (readonly ? O_RDONLY: O_RDWR)) {
|
||||
fprintf (stderr,
|
||||
_("%s: can't open shadow password file\n"), Prog);
|
||||
spw_unlock ();
|
||||
@ -551,7 +491,125 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
}
|
||||
|
||||
static void close_files (void)
|
||||
{
|
||||
/*
|
||||
* Now close the shadow password file, which will cause all of the
|
||||
* entries to be re-written.
|
||||
*/
|
||||
if (!spw_close ()) {
|
||||
fprintf (stderr,
|
||||
_("%s: can't rewrite shadow password file\n"), Prog);
|
||||
spw_unlock ();
|
||||
SYSLOG ((LOG_ERR, "failed rewriting %s", SHADOW_FILE));
|
||||
closelog ();
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age",
|
||||
pw->pw_name, getuid (), 0);
|
||||
#endif
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the password file. If any entries were modified, the file
|
||||
* will be re-written.
|
||||
*/
|
||||
if (!pw_close ()) {
|
||||
fprintf (stderr, _("%s: can't rewrite password file\n"), Prog);
|
||||
spw_unlock ();
|
||||
SYSLOG ((LOG_ERR, "failed rewriting %s", PASSWD_FILE));
|
||||
closelog ();
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age",
|
||||
pw->pw_name, getuid (), 0);
|
||||
#endif
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
spw_unlock ();
|
||||
}
|
||||
|
||||
/*
|
||||
* chage - change a user's password aging information
|
||||
*
|
||||
* This command controls the password aging information.
|
||||
*
|
||||
* The valid options are
|
||||
*
|
||||
* -d set last password change date (*)
|
||||
* -E set account expiration date (*)
|
||||
* -I set password inactive after expiration (*)
|
||||
* -l show account aging information
|
||||
* -M set maximim number of days before password change (*)
|
||||
* -m set minimum number of days before password change (*)
|
||||
* -W set expiration warning days (*)
|
||||
*
|
||||
* (*) requires root permission to execute.
|
||||
*
|
||||
* All of the time fields are entered in the internal format which is
|
||||
* either seconds or days.
|
||||
*/
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
const struct spwd *sp;
|
||||
struct spwd spwd;
|
||||
uid_t ruid;
|
||||
gid_t rgid;
|
||||
const struct passwd *pw;
|
||||
struct passwd pwent;
|
||||
char name[BUFSIZ];
|
||||
|
||||
#ifdef WITH_AUDIT
|
||||
audit_help_open ();
|
||||
#endif
|
||||
sanitize_env ();
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
ruid = getuid ();
|
||||
rgid = getgid ();
|
||||
amroot = (ruid == 0);
|
||||
#ifdef WITH_SELINUX
|
||||
if (amroot && is_selinux_enabled () > 0)
|
||||
amroot = (selinux_check_passwd_access (PASSWD__ROOTOK) == 0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get the program name so that error messages can use it.
|
||||
*/
|
||||
Prog = Basename (argv[0]);
|
||||
|
||||
process_flags (argc, argv);
|
||||
|
||||
OPENLOG ("chage");
|
||||
|
||||
check_perms ();
|
||||
|
||||
if (!spw_file_present ()) {
|
||||
fprintf (stderr,
|
||||
_("%s: the shadow password file is not present\n"),
|
||||
Prog);
|
||||
SYSLOG ((LOG_ERR, "can't find the shadow password file"));
|
||||
closelog ();
|
||||
exit (E_SHADOW_NOTFOUND);
|
||||
}
|
||||
|
||||
open_files (lflg);
|
||||
|
||||
if (!(pw = pw_locate (argv[optind]))) {
|
||||
fprintf (stderr, _("%s: unknown user %s\n"), Prog,
|
||||
argv[optind]);
|
||||
closelog ();
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
|
||||
pwent = *pw;
|
||||
STRFCPY (name, pwent.pw_name);
|
||||
|
||||
/* Drop privileges */
|
||||
if (lflg && (setregid (rgid, rgid) || setreuid (ruid, ruid))) {
|
||||
fprintf (stderr, _("%s: failed to drop privileges (%s)\n"),
|
||||
Prog, strerror (errno));
|
||||
@ -730,46 +788,15 @@ int main (int argc, char **argv)
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now close the shadow password file, which will cause all of the
|
||||
* entries to be re-written.
|
||||
*/
|
||||
if (!spw_close ()) {
|
||||
fprintf (stderr,
|
||||
_("%s: can't rewrite shadow password file\n"), Prog);
|
||||
spw_unlock ();
|
||||
SYSLOG ((LOG_ERR, "failed rewriting %s", SHADOW_FILE));
|
||||
closelog ();
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age",
|
||||
pw->pw_name, getuid (), 0);
|
||||
#endif
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
close_files ();
|
||||
|
||||
/*
|
||||
* Close the password file. If any entries were modified, the file
|
||||
* will be re-written.
|
||||
*/
|
||||
if (!pw_close ()) {
|
||||
fprintf (stderr, _("%s: can't rewrite password file\n"), Prog);
|
||||
spw_unlock ();
|
||||
SYSLOG ((LOG_ERR, "failed rewriting %s", PASSWD_FILE));
|
||||
closelog ();
|
||||
#ifdef WITH_AUDIT
|
||||
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age",
|
||||
pw->pw_name, getuid (), 0);
|
||||
#endif
|
||||
exit (E_NOPERM);
|
||||
}
|
||||
spw_unlock ();
|
||||
SYSLOG ((LOG_INFO, "changed password expiry for %s", name));
|
||||
|
||||
#ifdef USE_PAM
|
||||
if (retval == PAM_SUCCESS)
|
||||
pam_end (pamh, PAM_SUCCESS);
|
||||
pam_end (pamh, PAM_SUCCESS);
|
||||
#endif /* USE_PAM */
|
||||
|
||||
closelog ();
|
||||
exit (E_SUCCESS);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user