summaryrefslogtreecommitdiffstats
path: root/src/chage.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/chage.c185
1 files changed, 100 insertions, 85 deletions
diff --git a/src/chage.c b/src/chage.c
index 01570d7..1edab47 100644
--- a/src/chage.c
+++ b/src/chage.c
@@ -25,21 +25,31 @@
#endif /* USE_PAM */
#endif /* ACCT_TOOLS_SETUID */
#include <pwd.h>
-#include "prototypes.h"
+
+#include "alloc.h"
+#include "atoi/str2i.h"
#include "defines.h"
+#include "memzero.h"
+#include "prototypes.h"
#include "pwio.h"
#include "shadowio.h"
#include "shadowlog.h"
+#include "string/sprintf.h"
+#include "string/strftime.h"
+#include "string/strtcpy.h"
+#include "time/day_to_str.h"
+/*@-exitarg@*/
+#include "exitcodes.h"
+
#ifdef WITH_TCB
#include "tcbfuncs.h"
#endif
-/*@-exitarg@*/
-#include "exitcodes.h"
+
/*
* Global variables
*/
-const char *Prog;
+static const char Prog[] = "chage";
static bool
dflg = false, /* set last password change date */
@@ -52,6 +62,8 @@ static bool
Wflg = false; /* set expiration warning days */
static bool amroot = false;
+static const char *prefix = "";
+
static bool pw_locked = false; /* Indicate if the password file is locked */
static bool spw_locked = false; /* Indicate if the shadow file is locked */
/* The name and UID of the user being worked on */
@@ -66,21 +78,23 @@ static long inactdays;
static long expdate;
/* local function prototypes */
-static /*@noreturn@*/void usage (int status);
+NORETURN static void usage (int status);
static int new_fields (void);
-static void print_date (time_t date);
+static void print_day_as_date (long day);
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 (bool readonly);
static void close_files (void);
-static /*@noreturn@*/void fail_exit (int code);
+NORETURN static void fail_exit (int code);
/*
* fail_exit - do some cleanup and exit with the given error code
*/
-static /*@noreturn@*/void fail_exit (int code)
+NORETURN
+static void
+fail_exit (int code)
{
if (spw_locked) {
if (spw_unlock () == 0) {
@@ -101,8 +115,7 @@ static /*@noreturn@*/void fail_exit (int code)
#ifdef WITH_AUDIT
if (E_SUCCESS != code) {
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
- "change age",
- user_name, (unsigned int) user_uid, 0);
+ "change age", user_name, user_uid, 0);
}
#endif
@@ -112,7 +125,9 @@ static /*@noreturn@*/void fail_exit (int code)
/*
* usage - print command line syntax and exit
*/
-static /*@noreturn@*/void usage (int status)
+NORETURN
+static void
+usage (int status)
{
FILE *usageout = (E_SUCCESS != status) ? stderr : stdout;
(void) fprintf (usageout,
@@ -132,6 +147,7 @@ static /*@noreturn@*/void usage (int status)
(void) fputs (_(" -M, --maxdays MAX_DAYS set maximum number of days before password\n"
" change to MAX_DAYS\n"), usageout);
(void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout);
+ (void) fputs (_(" -P, --prefix PREFIX_DIR directory prefix\n"), usageout);
(void) fputs (_(" -W, --warndays WARN_DAYS set expiration warning days to WARN_DAYS\n"), usageout);
(void) fputs ("\n", usageout);
exit (status);
@@ -148,30 +164,29 @@ static /*@noreturn@*/void usage (int status)
*/
static int new_fields (void)
{
- char buf[200];
+ char buf[200];
(void) puts (_("Enter the new value, or press ENTER for the default"));
(void) puts ("");
- (void) snprintf (buf, sizeof buf, "%ld", mindays);
+ SNPRINTF(buf, "%ld", mindays);
change_field (buf, sizeof buf, _("Minimum Password Age"));
- if ( (getlong (buf, &mindays) == 0)
+ if ( (str2sl(&mindays, buf) == -1)
|| (mindays < -1)) {
return 0;
}
- (void) snprintf (buf, sizeof buf, "%ld", maxdays);
+ SNPRINTF(buf, "%ld", maxdays);
change_field (buf, sizeof buf, _("Maximum Password Age"));
- if ( (getlong (buf, &maxdays) == 0)
+ if ( (str2sl(&maxdays, buf) == -1)
|| (maxdays < -1)) {
return 0;
}
- if (-1 == lstchgdate || lstchgdate > LONG_MAX / SCALE) {
- strcpy (buf, "-1");
- } else {
- date_to_str (sizeof(buf), buf, lstchgdate * SCALE);
- }
+ if (-1 == lstchgdate || lstchgdate > LONG_MAX / DAY)
+ strcpy(buf, "-1");
+ else
+ DAY_TO_STR(buf, lstchgdate);
change_field (buf, sizeof buf, _("Last Password Change (YYYY-MM-DD)"));
@@ -184,25 +199,24 @@ static int new_fields (void)
}
}
- (void) snprintf (buf, sizeof buf, "%ld", warndays);
+ SNPRINTF(buf, "%ld", warndays);
change_field (buf, sizeof buf, _("Password Expiration Warning"));
- if ( (getlong (buf, &warndays) == 0)
+ if ( (str2sl(&warndays, buf) == -1)
|| (warndays < -1)) {
return 0;
}
- (void) snprintf (buf, sizeof buf, "%ld", inactdays);
+ SNPRINTF(buf, "%ld", inactdays);
change_field (buf, sizeof buf, _("Password Inactive"));
- if ( (getlong (buf, &inactdays) == 0)
+ if ( (str2sl(&inactdays, buf) == -1)
|| (inactdays < -1)) {
return 0;
}
- if (-1 == expdate || LONG_MAX / SCALE < expdate) {
- strcpy (buf, "-1");
- } else {
- date_to_str (sizeof(buf), buf, expdate * SCALE);
- }
+ if (-1 == expdate || LONG_MAX / DAY < expdate)
+ strcpy(buf, "-1");
+ else
+ DAY_TO_STR(buf, expdate);
change_field (buf, sizeof buf,
_("Account Expiration Date (YYYY-MM-DD)"));
@@ -219,20 +233,33 @@ static int new_fields (void)
return 1;
}
-static void print_date (time_t date)
+
+static void
+print_day_as_date(long day)
{
- struct tm *tp;
- char buf[80];
+ char buf[80];
+ time_t date;
+ struct tm tm;
- tp = gmtime (&date);
- if (NULL == tp) {
+ if (day < 0) {
+ puts(_("never"));
+ return;
+ }
+ if (__builtin_mul_overflow(day, DAY, &date)) {
+ puts(_("future"));
+ return;
+ }
+
+ if (gmtime_r(&date, &tm) == NULL) {
(void) printf ("time_t: %lu\n", (unsigned long)date);
- } else {
- (void) strftime (buf, sizeof buf, iflg ? "%Y-%m-%d" : "%b %d, %Y", tp);
- (void) puts (buf);
+ return;
}
+
+ STRFTIME(buf, iflg ? "%Y-%m-%d" : "%b %d, %Y", &tm);
+ (void) puts (buf);
}
+
/*
* list_fields - display the current values of the expiration fields
*
@@ -242,21 +269,15 @@ static void print_date (time_t date)
*/
static void list_fields (void)
{
- long changed = 0;
- long expires;
-
/*
* The "last change" date is either "never" or the date the password
* was last modified. The date is the number of days since 1/1/1970.
*/
(void) fputs (_("Last password change\t\t\t\t\t: "), stdout);
- if (lstchgdate < 0 || lstchgdate > LONG_MAX / SCALE) {
- (void) puts (_("never"));
- } else if (lstchgdate == 0) {
+ if (lstchgdate == 0) {
(void) puts (_("password must be changed"));
} else {
- changed = lstchgdate * SCALE;
- print_date ((time_t) changed);
+ print_day_as_date(lstchgdate);
}
/*
@@ -267,13 +288,13 @@ static void list_fields (void)
if (lstchgdate == 0) {
(void) puts (_("password must be changed"));
} else if ( (lstchgdate < 0)
- || (maxdays >= (10000 * (DAY / SCALE)))
+ || (maxdays >= 10000)
|| (maxdays < 0)
- || ((LONG_MAX - changed) / SCALE < maxdays)) {
+ || (LONG_MAX - lstchgdate < maxdays))
+ {
(void) puts (_("never"));
} else {
- expires = changed + maxdays * SCALE;
- print_date ((time_t) expires);
+ print_day_as_date(lstchgdate + maxdays);
}
/*
@@ -287,14 +308,14 @@ static void list_fields (void)
(void) puts (_("password must be changed"));
} else if ( (lstchgdate < 0)
|| (inactdays < 0)
- || (maxdays >= (10000 * (DAY / SCALE)))
+ || (maxdays >= 10000)
|| (maxdays < 0)
- || (maxdays > LONG_MAX - inactdays)
- || ((LONG_MAX - changed) / SCALE < maxdays + inactdays)) {
+ || (LONG_MAX - inactdays < maxdays)
+ || (LONG_MAX - lstchgdate < maxdays + inactdays))
+ {
(void) puts (_("never"));
} else {
- expires = changed + (maxdays + inactdays) * SCALE;
- print_date ((time_t) expires);
+ print_day_as_date(lstchgdate + maxdays + inactdays);
}
/*
@@ -302,12 +323,7 @@ static void list_fields (void)
* password expiring or not.
*/
(void) fputs (_("Account expires\t\t\t\t\t\t: "), stdout);
- if (expdate < 0 || LONG_MAX / SCALE < expdate) {
- (void) puts (_("never"));
- } else {
- expires = expdate * SCALE;
- print_date ((time_t) expires);
- }
+ print_day_as_date(expdate);
/*
* Start with the easy numbers - the number of days before the
@@ -344,12 +360,13 @@ static void process_flags (int argc, char **argv)
{"mindays", required_argument, NULL, 'm'},
{"maxdays", required_argument, NULL, 'M'},
{"root", required_argument, NULL, 'R'},
+ {"prefix", required_argument, NULL, 'P'},
{"warndays", required_argument, NULL, 'W'},
{"iso8601", no_argument, NULL, 'i'},
{NULL, 0, NULL, '\0'}
};
- while ((c = getopt_long (argc, argv, "d:E:hiI:lm:M:R:W:",
+ while ((c = getopt_long (argc, argv, "d:E:hiI:lm:M:R:P:W:",
long_options, NULL)) != -1) {
switch (c) {
case 'd':
@@ -380,7 +397,7 @@ static void process_flags (int argc, char **argv)
break;
case 'I':
Iflg = true;
- if ( (getlong (optarg, &inactdays) == 0)
+ if ( (str2sl(&inactdays, optarg) == -1)
|| (inactdays < -1)) {
fprintf (stderr,
_("%s: invalid numeric argument '%s'\n"),
@@ -393,7 +410,7 @@ static void process_flags (int argc, char **argv)
break;
case 'm':
mflg = true;
- if ( (getlong (optarg, &mindays) == 0)
+ if ( (str2sl(&mindays, optarg) == -1)
|| (mindays < -1)) {
fprintf (stderr,
_("%s: invalid numeric argument '%s'\n"),
@@ -403,7 +420,7 @@ static void process_flags (int argc, char **argv)
break;
case 'M':
Mflg = true;
- if ( (getlong (optarg, &maxdays) == 0)
+ if ( (str2sl(&maxdays, optarg) == -1)
|| (maxdays < -1)) {
fprintf (stderr,
_("%s: invalid numeric argument '%s'\n"),
@@ -413,9 +430,11 @@ static void process_flags (int argc, char **argv)
break;
case 'R': /* no-op, handled in process_root_flag () */
break;
+ case 'P': /* no-op, handled in process_prefix_flag () */
+ break;
case 'W':
Wflg = true;
- if ( (getlong (optarg, &warndays) == 0)
+ if ( (str2sl(&warndays, optarg) == -1)
|| (warndays < -1)) {
fprintf (stderr,
_("%s: invalid numeric argument '%s'\n"),
@@ -500,7 +519,7 @@ static void check_perms (void)
exit (E_NOPERM);
}
- retval = pam_start ("chage", pampw->pw_name, &conv, &pamh);
+ retval = pam_start (Prog, pampw->pw_name, &conv, &pamh);
if (PAM_SUCCESS == retval) {
retval = pam_authenticate (pamh, 0);
@@ -751,24 +770,23 @@ int main (int argc, char **argv)
gid_t rgid;
const struct passwd *pw;
- /*
- * Get the program name so that error messages can use it.
- */
- Prog = Basename (argv[0]);
+ sanitize_env ();
+ check_fds ();
+
log_set_progname(Prog);
log_set_logfd(stderr);
- sanitize_env ();
(void) setlocale (LC_ALL, "");
(void) bindtextdomain (PACKAGE, LOCALEDIR);
(void) textdomain (PACKAGE);
process_root_flag ("-R", argc, argv);
+ prefix = process_prefix_flag ("-P", argc, argv);
#ifdef WITH_AUDIT
audit_help_open ();
#endif
- OPENLOG ("chage");
+ OPENLOG (Prog);
ruid = getuid ();
rgid = getgid ();
@@ -809,7 +827,7 @@ int main (int argc, char **argv)
fail_exit (E_NOPERM);
}
- STRFCPY (user_name, pw->pw_name);
+ STRTCPY(user_name, pw->pw_name);
#ifdef WITH_TCB
if (shadowtcb_set_user (pw->pw_name) == SHADOWTCB_FAILURE) {
fail_exit (E_NOPERM);
@@ -831,8 +849,7 @@ int main (int argc, char **argv)
}
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
- "display aging info",
- user_name, (unsigned int) user_uid, 1);
+ "display aging info", user_name, user_uid, 1);
#endif
list_fields ();
fail_exit (E_SUCCESS);
@@ -854,40 +871,38 @@ int main (int argc, char **argv)
else {
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"change all aging information",
- user_name, (unsigned int) user_uid, 1);
+ user_name, user_uid, 1);
}
#endif
} else {
#ifdef WITH_AUDIT
if (Mflg) {
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
- "change max age",
- user_name, (unsigned int) user_uid, 1);
+ "change max age", user_name, user_uid, 1);
}
if (mflg) {
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
- "change min age",
- user_name, (unsigned int) user_uid, 1);
+ "change min age", user_name, user_uid, 1);
}
if (dflg) {
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"change last change date",
- user_name, (unsigned int) user_uid, 1);
+ user_name, user_uid, 1);
}
if (Wflg) {
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"change passwd warning",
- user_name, (unsigned int) user_uid, 1);
+ user_name, user_uid, 1);
}
if (Iflg) {
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"change inactive days",
- user_name, (unsigned int) user_uid, 1);
+ user_name, user_uid, 1);
}
if (Eflg) {
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"change passwd expiration",
- user_name, (unsigned int) user_uid, 1);
+ user_name, user_uid, 1);
}
#endif
}