[Pkg-shadow-commits] r1564 - in upstream/trunk: . src
nekral-guest at alioth.debian.org
nekral-guest at alioth.debian.org
Mon Dec 31 04:29:31 UTC 2007
Author: nekral-guest
Date: 2007-12-31 04:29:30 +0000 (Mon, 31 Dec 2007)
New Revision: 1564
Modified:
upstream/trunk/ChangeLog
upstream/trunk/NEWS
upstream/trunk/src/chage.c
Log:
* src/chage.c: Fix typo: s/maximim/maximum/
* src/chage.c: New function: fail_exit(). Change most of the exit()
to a fail_exit, which makes sure the files are unlocked (new global
variables: pw_locked, spw_locked), the PAM transaction is ended, and
the failure is logged to libaudit (use a global user_name and user_uid
for logging).
* src/chage.c: Compilation fix for PAM support (pamh needs to be
global since the function split).
* src/chage.c: Document process_flags(), check_flags(), check_perms(),
open_files(), and close_files().
* src/chage.c: Split update_age() and get_defaults() out of main()
* src/chage.c: Drop the privileges just after opening the files.
* src/chage.c: Do not log to audit only if the user has an entry in
the shadow file.
* NEWS, src/chage.c (open_files): Also open the password file for
writing. This fix chage when the user only has a password entry (and
no shadow entries).
* src/chage.c (get_defaults): Use default values that don't change the
behavior of the account for the fields that are not specified when the
user has no shadow entry.
Modified: upstream/trunk/ChangeLog
===================================================================
--- upstream/trunk/ChangeLog 2007-12-30 21:48:55 UTC (rev 1563)
+++ upstream/trunk/ChangeLog 2007-12-31 04:29:30 UTC (rev 1564)
@@ -1,3 +1,24 @@
+2007-12-31 Nicolas François <nicolas.francois at centraliens.net>
+
+ * src/chage.c: Fix typo: s/maximim/maximum/
+ * src/chage.c: New function: fail_exit(). Change most of the exit()
+ to a fail_exit, which makes sure the files are unlocked (new global
+ variables: pw_locked, spw_locked), the PAM transaction is ended, and
+ the failure is logged to libaudit (use a global user_name and user_uid
+ for logging).
+ * src/chage.c: Compilation fix for PAM support (pamh needs to be
+ global since the function split).
+ * src/chage.c: Document process_flags(), check_flags(), check_perms(),
+ open_files(), and close_files().
+ * src/chage.c: Split update_age() and get_defaults() out of main()
+ * src/chage.c: Drop the privileges just after opening the files.
+ * src/chage.c: Do not log to audit only if the user has an entry in
+ the shadow file.
+ * NEWS, src/chage.c (open_files): Also open the password file for
+ writing. This fix chage when the user only has a password entry (and
+ no shadow entries). Use default values that don't change the behavior
+ of the account for the fields that are not specified.
+
2007-12-30 Nicolas François <nicolas.francois at centraliens.net>
* src/groupadd.c: Compilation fix for PAM support (pamh needs to be
Modified: upstream/trunk/NEWS
===================================================================
--- upstream/trunk/NEWS 2007-12-30 21:48:55 UTC (rev 1563)
+++ upstream/trunk/NEWS 2007-12-31 04:29:30 UTC (rev 1564)
@@ -32,6 +32,9 @@
* The new users are no more added to the list of members of their groups
because the membership is already set by their primary group.
* Added support for gshadow.
+- chage
+ * Fix bug which forbid to set the aging information of an account with a
+ passwd entry, but no shadow entry.
shadow-4.0.18.2 -> shadow-4.1.0 09-12-2008
Modified: upstream/trunk/src/chage.c
===================================================================
--- upstream/trunk/src/chage.c 2007-12-30 21:48:55 UTC (rev 1563)
+++ upstream/trunk/src/chage.c 2007-12-31 04:29:30 UTC (rev 1564)
@@ -63,10 +63,16 @@
Iflg = 0, /* set password inactive after expiration */
lflg = 0, /* show account aging information */
mflg = 0, /* set minimum number of days before password change */
- Mflg = 0, /* set maximim number of days before password change */
+ Mflg = 0, /* set maximum number of days before password change */
Wflg = 0; /* set expiration warning days */
static int amroot = 0;
+static int pw_locked = 0; /* Indicate if the password file is locked */
+static int spw_locked = 0; /* Indicate if the shadow file is locked */
+/* The name and UID of the user being worked on */
+static char user_name[BUFSIZ] = "";
+static uid_t user_uid = -1;
+
static long mindays;
static long maxdays;
static long lastday;
@@ -74,6 +80,10 @@
static long inactdays;
static long expdays;
+#ifdef USE_PAM
+static pam_handle_t *pamh = NULL;
+#endif
+
#define EPOCH "1969-12-31"
/* local function prototypes */
@@ -87,8 +97,42 @@
static void check_perms (void);
static void open_files (int readonly);
static void close_files (void);
+static void fail_exit (int code);
/*
+ * fail_exit - do some cleanup and exit with the given error code
+ */
+static void fail_exit (int code)
+{
+ if (spw_locked) {
+ spw_unlock ();
+ }
+ if (pw_locked) {
+ pw_unlock ();
+ }
+ closelog ();
+
+#ifdef WITH_AUDIT
+ if (E_SUCCESS != code) {
+ audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age",
+ user_name, user_uid, 0);
+ }
+#endif
+
+#ifdef USE_PAM
+ if (NULL != pamh) {
+ /* If there is a PAM error, pam_end will be called by the
+ * caller.
+ * We always end the pam transaction with PAM_SUCCESS here.
+ */
+ pam_end (pamh, PAM_SUCCESS);
+ }
+#endif
+
+ exit (code);
+}
+
+/*
* isnum - determine whether or not a string is a number
*/
int isnum (const char *s)
@@ -317,6 +361,11 @@
warndays);
}
+/*
+ * process_flags - parse the command line options
+ *
+ * It will not return if an error is encountered.
+ */
static void process_flags (int argc, char **argv)
{
/*
@@ -386,10 +435,13 @@
check_flags (argc, optind);
}
-
+/*
+ * check_flags - check flags and parameters consistency
+ *
+ * It will not return if an error is encountered.
+ */
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.
@@ -407,11 +459,23 @@
}
}
-/* Additional check done later */
+/*
+ * check_perms - check if the caller is allowed to add a group
+ *
+ * Non-root users are only allowed to display their aging information.
+ * (we will later make sure that the user is only listing her aging
+ * information)
+ *
+ * With PAM support, the setuid bit can be set on groupadd to allow
+ * non-root users to groups.
+ * Without PAM support, only users who can write in the group databases
+ * can add groups.
+ *
+ * It will not return if the user is not allowed.
+ */
static void check_perms (void)
{
#ifdef USE_PAM
- pam_handle_t *pamh = NULL;
struct passwd *pampw;
int retval;
#endif
@@ -424,11 +488,7 @@
if (!amroot && !lflg) {
fprintf (stderr, _("%s: Permission denied.\n"), Prog);
-#ifdef WITH_AUDIT
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age", NULL,
- getuid (), 0);
-#endif
- exit (E_NOPERM);
+ fail_exit (E_NOPERM);
}
#ifdef USE_PAM
@@ -459,23 +519,39 @@
if (retval != PAM_SUCCESS) {
fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
- exit (E_NOPERM);
+ pamh = NULL;
+ fail_exit (E_NOPERM);
}
#endif /* USE_PAM */
}
+/*
+ * open_files - open the shadow database
+ *
+ * The password database is also needed (only for reading).
+ * In read-only mode, the shadow database is not locked and is opened
+ * only for reading.
+ */
static void open_files (int readonly)
{
/*
- * open the password file. This loads all of the password
+ * Lock and 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.
*/
- if (pw_open (O_RDONLY) == 0) {
+ if (!readonly && (pw_lock () == 0)) {
+ fprintf (stderr,
+ _("%s: can't lock password file\n"), Prog);
+ SYSLOG ((LOG_ERR, "failed locking %s", PASSWD_FILE));
+ fail_exit (E_NOPERM);
+ }
+ if (!readonly) {
+ pw_locked = 1;
+ }
+ if (pw_open (readonly ? O_RDONLY: O_RDWR) == 0) {
fprintf (stderr, _("%s: can't open password file\n"), Prog);
SYSLOG ((LOG_ERR, "failed opening %s", PASSWD_FILE));
- closelog ();
- exit (E_NOPERM);
+ fail_exit (E_NOPERM);
}
/*
@@ -488,27 +564,22 @@
fprintf (stderr,
_("%s: can't lock shadow password file\n"), Prog);
SYSLOG ((LOG_ERR, "failed locking %s", SHADOW_FILE));
- closelog ();
-#ifdef WITH_AUDIT
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age", name,
- getuid (), 0);
-#endif
- exit (E_NOPERM);
+ fail_exit (E_NOPERM);
}
+ if (!readonly) {
+ spw_locked = 1;
+ }
if (spw_open (readonly ? O_RDONLY: O_RDWR) == 0) {
fprintf (stderr,
_("%s: can't open shadow password file\n"), Prog);
- spw_unlock ();
SYSLOG ((LOG_ERR, "failed opening %s", SHADOW_FILE));
- closelog ();
-#ifdef WITH_AUDIT
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age", name,
- getuid (), 0);
-#endif
- exit (E_NOPERM);
+ fail_exit (E_NOPERM);
}
}
+/*
+ * close_files - close and unlock the password/shadow databases
+ */
static void close_files (void)
{
/*
@@ -518,14 +589,8 @@
if (spw_close () == 0) {
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);
+ fail_exit (E_NOPERM);
}
/*
@@ -534,19 +599,126 @@
*/
if (pw_close () == 0) {
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);
+ fail_exit (E_NOPERM);
}
spw_unlock ();
+ spw_locked = 0;
+ pw_unlock ();
+ pw_locked = 0;
}
/*
+ * update_age - update the aging information in the database
+ *
+ * It will not return in case of error
+ */
+static void update_age (const struct spwd *sp, const struct passwd *pw)
+{
+ struct spwd spwent;
+
+ /*
+ * There was no shadow entry. The new entry will have the encrypted
+ * password transferred from the normal password file along with the
+ * aging information.
+ */
+ if (NULL == sp) {
+ struct passwd pwent = *pw;
+
+ memzero (&spwent, sizeof spwent);
+ spwent.sp_namp = xstrdup (pw->pw_name);
+ spwent.sp_pwdp = xstrdup (pw->pw_passwd);
+ spwent.sp_flag = -1;
+
+ pwent.pw_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */
+ if (pw_update (&pwent) == 0) {
+ fprintf (stderr,
+ _("%s: can't update password file\n"), Prog);
+ SYSLOG ((LOG_ERR, "failed updating %s", PASSWD_FILE));
+ fail_exit (E_NOPERM);
+ }
+ } else {
+ spwent.sp_namp = xstrdup (sp->sp_namp);
+ spwent.sp_pwdp = xstrdup (sp->sp_pwdp);
+ spwent.sp_flag = sp->sp_flag;
+ }
+
+ /*
+ * Copy the fields back to the shadow file entry and write the
+ * modified entry back to the shadow file. Closing the shadow and
+ * password files will commit any changes that have been made.
+ */
+ spwent.sp_max = maxdays;
+ spwent.sp_min = mindays;
+ spwent.sp_lstchg = lastday;
+ spwent.sp_warn = warndays;
+ spwent.sp_inact = inactdays;
+ spwent.sp_expire = expdays;
+
+ if (spw_update (&spwent) == 0) {
+ fprintf (stderr,
+ _("%s: can't update shadow password file\n"), Prog);
+ SYSLOG ((LOG_ERR, "failed updating %s", SHADOW_FILE));
+ fail_exit (E_NOPERM);
+ }
+
+}
+
+/*
+ * get_defaults - get the value of the fields not set from the command line
+ */
+static void get_defaults (const struct spwd *sp)
+{
+ /*
+ * Set the fields that aren't being set from the command line from
+ * the password file.
+ */
+ if (NULL != sp) {
+ if (!Mflg) {
+ maxdays = sp->sp_max;
+ }
+ if (!mflg) {
+ mindays = sp->sp_min;
+ }
+ if (!dflg) {
+ lastday = sp->sp_lstchg;
+ }
+ if (!Wflg) {
+ warndays = sp->sp_warn;
+ }
+ if (!Iflg) {
+ inactdays = sp->sp_inact;
+ }
+ if (!Eflg) {
+ expdays = sp->sp_expire;
+ }
+ } else {
+ /*
+ * Use default values that will not change the behavior of the
+ * account.
+ */
+ if (!Mflg) {
+ maxdays = -1;
+ }
+ if (!mflg) {
+ mindays = -1;
+ }
+ if (!dflg) {
+ lastday = 0;
+ }
+ if (!Wflg) {
+ warndays = -1;
+ }
+ if (!Iflg) {
+ inactdays = -1;
+ }
+ if (!Eflg) {
+ expdays = -1;
+ }
+ }
+}
+
+/*
* chage - change a user's password aging information
*
* This command controls the password aging information.
@@ -570,12 +742,9 @@
int main (int argc, char **argv)
{
const struct spwd *sp;
- struct spwd spwent;
uid_t ruid;
gid_t rgid;
const struct passwd *pw;
- struct passwd pwent;
- char name[BUFSIZ];
#ifdef WITH_AUDIT
audit_help_open ();
@@ -615,6 +784,12 @@
}
open_files (lflg);
+ /* Drop privileges */
+ if (lflg && (setregid (rgid, rgid) || setreuid (ruid, ruid))) {
+ fprintf (stderr, _("%s: failed to drop privileges (%s)\n"),
+ Prog, strerror (errno));
+ fail_exit (E_NOPERM);
+ }
pw = pw_locate (argv[optind]);
if (NULL == pw) {
@@ -624,104 +799,27 @@
exit (E_NOPERM);
}
- pwent = *pw;
- STRFCPY (name, pwent.pw_name);
+ STRFCPY (user_name, pw->pw_name);
+ user_uid = pw->pw_uid;
- /* Drop privileges */
- if (lflg && (setregid (rgid, rgid) || setreuid (ruid, ruid))) {
- fprintf (stderr, _("%s: failed to drop privileges (%s)\n"),
- Prog, strerror (errno));
-#ifdef WITH_AUDIT
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age", name,
- getuid (), 0);
-#endif
- exit (E_NOPERM);
- }
-
sp = spw_locate (argv[optind]);
+ get_defaults(sp);
/*
- * Set the fields that aren't being set from the command line from
- * the password file.
- */
- if (NULL != sp) {
- spwent = *sp;
-
- if (!Mflg) {
- maxdays = spwent.sp_max;
- }
- if (!mflg) {
- mindays = spwent.sp_min;
- }
- if (!dflg) {
- lastday = spwent.sp_lstchg;
- }
- if (!Wflg) {
- warndays = spwent.sp_warn;
- }
- if (!Iflg) {
- inactdays = spwent.sp_inact;
- }
- if (!Eflg) {
- expdays = spwent.sp_expire;
- }
-#ifdef WITH_AUDIT
- if (Mflg) {
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
- "change max age", pw->pw_name, pw->pw_uid,
- 1);
- }
- if (mflg) {
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
- "change min age", pw->pw_name, pw->pw_uid,
- 1);
- }
- if (dflg) {
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
- "change last change date", pw->pw_name,
- pw->pw_uid, 1);
- }
- if (Wflg) {
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
- "change passwd warning", pw->pw_name,
- pw->pw_uid, 1);
- }
- if (Iflg) {
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
- "change inactive days", pw->pw_name,
- pw->pw_uid, 1);
- }
- if (Eflg) {
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
- "change passwd expiration", pw->pw_name,
- pw->pw_uid, 1);
- }
-#endif
- }
-
- /*
* Print out the expiration fields if the user has requested the
* list option.
*/
-
if (lflg) {
- if (!amroot && (ruid != pwent.pw_uid)) {
-#ifdef WITH_AUDIT
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age",
- pw->pw_name, pw->pw_uid, 0);
-#endif
+ if (!amroot && (ruid != user_uid)) {
fprintf (stderr, _("%s: Permission denied.\n"), Prog);
- closelog ();
- exit (E_NOPERM);
+ fail_exit (E_NOPERM);
}
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "display aging info",
- pw->pw_name, pw->pw_uid, 1);
+ user_name, user_uid, 1);
#endif
list_fields ();
- spw_unlock ();
- closelog ();
- exit (E_SUCCESS);
+ fail_exit (E_SUCCESS);
}
/*
@@ -729,82 +827,60 @@
* user interactively change them.
*/
if (!mflg && !Mflg && !dflg && !Wflg && !Iflg && !Eflg) {
- printf (_("Changing the aging information for %s\n"), name);
+ printf (_("Changing the aging information for %s\n"),
+ user_name);
if (new_fields () == 0) {
fprintf (stderr, _("%s: error changing fields\n"),
Prog);
- spw_unlock ();
- closelog ();
-#ifdef WITH_AUDIT
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age",
- pw->pw_name, getuid (), 0);
-#endif
- exit (E_NOPERM);
+ fail_exit (E_NOPERM);
}
#ifdef WITH_AUDIT
else {
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
"change all aging information",
- pw->pw_name, getuid (), 1);
+ user_name, user_uid, 1);
}
#endif
- }
- /*
- * There was no shadow entry. The new entry will have the encrypted
- * password transferred from the normal password file along with the
- * aging information.
- */
- if (NULL == sp) {
- sp = &spwent;
- memzero (&spwent, sizeof spwent);
-
- spwent.sp_namp = xstrdup (pwent.pw_name);
- spwent.sp_pwdp = xstrdup (pwent.pw_passwd);
- spwent.sp_flag = -1;
-
- pwent.pw_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */
- if (pw_update (&pwent) == 0) {
- fprintf (stderr,
- _("%s: can't update password file\n"), Prog);
- spw_unlock ();
- SYSLOG ((LOG_ERR, "failed updating %s", PASSWD_FILE));
- closelog ();
+ } else {
#ifdef WITH_AUDIT
- audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age",
- pw->pw_name, getuid (), 0);
+ if (Mflg) {
+ audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+ "change max age", user_name,
+ user_uid, 1);
+ }
+ if (mflg) {
+ audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+ "change min age", user_name,
+ user_uid, 1);
+ }
+ if (dflg) {
+ audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+ "change last change date", user_name,
+ user_uid, 1);
+ }
+ if (Wflg) {
+ audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+ "change passwd warning", user_name,
+ user_uid, 1);
+ }
+ if (Iflg) {
+ audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+ "change inactive days", user_name,
+ user_uid, 1);
+ }
+ if (Eflg) {
+ audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
+ "change passwd expiration", user_name,
+ user_uid, 1);
+ }
#endif
- exit (E_NOPERM);
- }
}
- /*
- * Copy the fields back to the shadow file entry and write the
- * modified entry back to the shadow file. Closing the shadow and
- * password files will commit any changes that have been made.
- */
- spwent.sp_max = maxdays;
- spwent.sp_min = mindays;
- spwent.sp_lstchg = lastday;
- spwent.sp_warn = warndays;
- spwent.sp_inact = inactdays;
- spwent.sp_expire = expdays;
+ update_age (sp, pw);
- if (spw_update (&spwent) == 0) {
- fprintf (stderr,
- _("%s: can't update shadow password file\n"), Prog);
- spw_unlock ();
- SYSLOG ((LOG_ERR, "failed updating %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 ();
- SYSLOG ((LOG_INFO, "changed password expiry for %s", name));
+ SYSLOG ((LOG_INFO, "changed password expiry for %s", user_name));
#ifdef USE_PAM
pam_end (pamh, PAM_SUCCESS);
More information about the Pkg-shadow-commits
mailing list