[Pkg-shadow-commits] r1568 - in upstream/trunk: . src
nekral-guest at alioth.debian.org
nekral-guest at alioth.debian.org
Mon Dec 31 13:43:05 UTC 2007
Author: nekral-guest
Date: 2007-12-31 13:43:04 +0000 (Mon, 31 Dec 2007)
New Revision: 1568
Modified:
upstream/trunk/ChangeLog
upstream/trunk/src/chfn.c
Log:
* New function: process_flags() split out of main().
The flags variables are now global.
* New functions: check_perms(), update_gecos(),
get_old_fields(), and check_fields() split out of main().
* Before pam_end(), the return value of the previous
pam API was already checked. No need to validate it again.
Modified: upstream/trunk/ChangeLog
===================================================================
--- upstream/trunk/ChangeLog 2007-12-31 04:57:54 UTC (rev 1567)
+++ upstream/trunk/ChangeLog 2007-12-31 13:43:04 UTC (rev 1568)
@@ -1,5 +1,14 @@
2007-12-31 Nicolas François <nicolas.francois at centraliens.net>
+ * src/chfn.c: New function: process_flags() split out of main().
+ The flags variables are now global.
+ * src/chfn.c: New functions: check_perms(), update_gecos(),
+ get_old_fields(), and check_fields() split out of main().
+ * src/chfn.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 <nicolas.francois at centraliens.net>
+
* src/newusers.c: Compilation fix for PAM support (pamh needs to be
global since the function split).
* src/chpasswd.c: Likewise.
Modified: upstream/trunk/src/chfn.c
===================================================================
--- upstream/trunk/src/chfn.c 2007-12-31 04:57:54 UTC (rev 1567)
+++ upstream/trunk/src/chfn.c 2007-12-31 13:43:04 UTC (rev 1568)
@@ -63,6 +63,15 @@
static char homeph[BUFSIZ];
static char slop[BUFSIZ];
static int amroot;
+/* Flags */
+static int fflg = 0; /* -f - set full name */
+static int rflg = 0; /* -r - set room number */
+static int wflg = 0; /* -w - set work phone number */
+static int hflg = 0; /* -h - set home phone number */
+static int oflg = 0; /* -o - set other information */
+#ifdef USE_PAM
+static pam_handle_t *pamh = NULL;
+#endif
/*
* External identifiers
@@ -73,6 +82,10 @@
static int may_change_field (int);
static void new_fields (void);
static char *copy_field (char *, char *, char *);
+static void process_flags (int argc, char **argv);
+static void check_perms (const struct passwd *pw);
+static void update_gecos (const char *user, char *gecos);
+static void get_old_fields (const char *gecos);
/*
* usage - print command line syntax and exit
@@ -197,60 +210,14 @@
}
/*
- * chfn - change a user's password file information
+ * process_flags - parse the command line options
*
- * This command controls the GECOS field information in the password
- * file entry.
- *
- * The valid options are
- *
- * -f full name
- * -r room number
- * -w work phone number
- * -h home phone number
- * -o other information (*)
- *
- * (*) requires root permission to execute.
+ * It will not return if an error is encountered.
*/
-int main (int argc, char **argv)
+static void process_flags (int argc, char **argv)
{
- char *cp; /* temporary character pointer */
- const struct passwd *pw; /* password file entry */
- struct passwd pwent; /* modified password file entry */
- char old_gecos[BUFSIZ]; /* buffer for old GECOS fields */
- char new_gecos[BUFSIZ]; /* buffer for new GECOS fields */
int flag; /* flag currently being processed */
- int fflg = 0; /* -f - set full name */
- int rflg = 0; /* -r - set room number */
- int wflg = 0; /* -w - set work phone number */
- int hflg = 0; /* -h - set home phone number */
- int oflg = 0; /* -o - set other information */
- char *user;
-#ifdef USE_PAM
- pam_handle_t *pamh = NULL;
- int retval;
-#endif
-
- sanitize_env ();
- setlocale (LC_ALL, "");
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
-
- /*
- * This command behaves different for root and non-root
- * users.
- */
- amroot = (getuid () == 0);
-
- /*
- * Get the program name. The program name is used as a
- * prefix to most error messages.
- */
- Prog = Basename (argv[0]);
-
- OPENLOG ("chfn");
-
/*
* The remaining arguments will be processed one by one and executed
* by this command. The name is the last argument if it does not
@@ -309,52 +276,23 @@
usage ();
}
}
+}
- /*
- * Get the name of the user to check. It is either the command line
- * name, or the name getlogin() returns.
- */
- if (optind < argc) {
- user = argv[optind];
- pw = xgetpwnam (user);
- if (!pw) {
- fprintf (stderr, _("%s: unknown user %s\n"), Prog,
- user);
- exit (E_NOPERM);
- }
- } else {
- pw = get_my_pwent ();
- if (!pw) {
- fprintf (stderr,
- _
- ("%s: Cannot determine your user name.\n"),
- Prog);
- exit (E_NOPERM);
- }
- user = xstrdup (pw->pw_name);
- }
-
-#ifdef USE_NIS
- /*
- * Now we make sure this is a LOCAL password entry for this user ...
- */
- if (__ispwNIS ()) {
- char *nis_domain;
- char *nis_master;
-
- fprintf (stderr,
- _("%s: cannot change user '%s' on NIS client.\n"),
- Prog, user);
-
- if (!yp_get_default_domain (&nis_domain) &&
- !yp_master (nis_domain, "passwd.byname", &nis_master)) {
- fprintf (stderr,
- _
- ("%s: '%s' is the NIS master for this client.\n"),
- Prog, nis_master);
- }
- exit (E_NOPERM);
- }
+/*
+ * check_perms - check if the caller is allowed to add a group
+ *
+ * Non-root users are only allowed to change their gecos field.
+ * (see also may_change_field())
+ *
+ * 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
+ int retval;
+ struct passwd *pampw;
#endif
/*
@@ -393,17 +331,13 @@
#else /* !USE_PAM */
retval = PAM_SUCCESS;
- {
- struct passwd *pampw;
- pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
- if (pampw == NULL) {
- retval = PAM_USER_UNKNOWN;
- }
+ pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
+ if (pampw == NULL) {
+ retval = PAM_USER_UNKNOWN;
+ }
- if (retval == PAM_SUCCESS) {
- retval = pam_start ("chfn", pampw->pw_name,
- &conv, &pamh);
- }
+ if (retval == PAM_SUCCESS) {
+ retval = pam_start ("chfn", pampw->pw_name, &conv, &pamh);
}
if (retval == PAM_SUCCESS) {
@@ -425,12 +359,117 @@
exit (E_NOPERM);
}
#endif /* USE_PAM */
+}
+/*
+ * update_gecos - update the gecos fields in the password database
+ *
+ * Commit the user's entry after changing her gecos field.
+ */
+static void update_gecos (const char *user, char *gecos)
+{
+ const struct passwd *pw; /* The user's password file entry */
+ struct passwd pwent; /* modified password file 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)) {
+ fprintf (stderr, _("Cannot change ID to root.\n"));
+ SYSLOG ((LOG_ERR, "can't setuid(0)"));
+ closelog ();
+ exit (E_NOPERM);
+ }
+ 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 ()) {
+ fprintf (stderr,
+ _
+ ("Cannot lock the password file; try again later.\n"));
+ SYSLOG ((LOG_WARN, "can't lock /etc/passwd"));
+ closelog ();
+ exit (E_NOPERM);
+ }
+ if (!pw_open (O_RDWR)) {
+ fprintf (stderr, _("Cannot open the password file.\n"));
+ pw_unlock ();
+ SYSLOG ((LOG_ERR, "can't open /etc/passwd"));
+ closelog ();
+ exit (E_NOPERM);
+ }
+
+ /*
+ * 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 (E_NOPERM);
+ }
+
+ /*
+ * Make a copy of the entry, then change the gecos field. The other
+ * fields remain unchanged.
+ */
+ pwent = *pw;
+ pwent.pw_gecos = gecos;
+
+ /*
+ * Update the passwd file entry. If there is a DBM file, update that
+ * entry as well.
+ */
+ if (!pw_update (&pwent)) {
+ fprintf (stderr, _("Error updating the password entry.\n"));
+ pw_unlock ();
+ SYSLOG ((LOG_ERR, "error updating passwd entry"));
+ closelog ();
+ exit (E_NOPERM);
+ }
+
+ /*
+ * Changes have all been made, so commit them and unlock the file.
+ */
+ if (!pw_close ()) {
+ fprintf (stderr, _("Cannot commit password file changes.\n"));
+ pw_unlock ();
+ SYSLOG ((LOG_ERR, "can't rewrite /etc/passwd"));
+ closelog ();
+ exit (E_NOPERM);
+ }
+ if (!pw_unlock ()) {
+ fprintf (stderr, _("Cannot unlock the password file.\n"));
+ SYSLOG ((LOG_ERR, "can't unlock /etc/passwd"));
+ closelog ();
+ exit (E_NOPERM);
+ }
+}
+
+/*
+ * get_old_fields - parse the old gecos and use the old value for the fields
+ * which are not set on the command line
+ */
+static void get_old_fields (const char *gecos)
+{
+ char *cp; /* temporary character pointer */
+ char old_gecos[BUFSIZ]; /* buffer for old GECOS fields */
+ STRFCPY (old_gecos, gecos);
+
+ /*
* Now get the full name. It is the first comma separated field in
* the GECOS field.
*/
- STRFCPY (old_gecos, pw->pw_gecos);
cp = copy_field (old_gecos, fflg ? (char *) 0 : fullnm, slop);
/*
@@ -461,19 +500,15 @@
strcat (slop, cp);
}
+}
- /*
- * If none of the fields were changed from the command line, let the
- * user interactively change them.
- */
- if (!fflg && !rflg && !wflg && !hflg && !oflg) {
- printf (_("Changing the user information for %s\n"), user);
- new_fields ();
- }
-
- /*
- * Check all of the fields for valid information
- */
+/*
+ * check_fields - check all of the fields for valid information
+ *
+ * It will not return if a field is not valid.
+ */
+static void check_fields (void)
+{
if (valid_field (fullnm, ":,=")) {
fprintf (stderr, _("%s: invalid name: '%s'\n"), Prog, fullnm);
closelog ();
@@ -504,110 +539,143 @@
closelog ();
exit (E_NOPERM);
}
+}
+/*
+ * chfn - change a user's password file information
+ *
+ * This command controls the GECOS field information in the password
+ * file entry.
+ *
+ * The valid options are
+ *
+ * -f full name
+ * -r room number
+ * -w work phone number
+ * -h home phone number
+ * -o other information (*)
+ *
+ * (*) requires root permission to execute.
+ */
+int main (int argc, char **argv)
+{
+ const struct passwd *pw; /* password file entry */
+ char new_gecos[BUFSIZ]; /* buffer for new GECOS fields */
+ char *user;
+
+ sanitize_env ();
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
/*
- * Build the new GECOS field by plastering all the pieces together,
- * if they will fit ...
+ * This command behaves different for root and non-root
+ * users.
*/
- if (strlen (fullnm) + strlen (roomno) + strlen (workph) +
- strlen (homeph) + strlen (slop) > (unsigned int) 80) {
- fprintf (stderr, _("%s: fields too long\n"), Prog);
- closelog ();
- exit (E_NOPERM);
- }
- snprintf (new_gecos, sizeof new_gecos, "%s,%s,%s,%s%s%s",
- fullnm, roomno, workph, homeph, slop[0] ? "," : "", slop);
+ amroot = (getuid () == 0);
/*
- * 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.
+ * Get the program name. The program name is used as a
+ * prefix to most error messages.
*/
- if (setuid (0)) {
- fprintf (stderr, _("Cannot change ID to root.\n"));
- SYSLOG ((LOG_ERR, "can't setuid(0)"));
- closelog ();
- exit (E_NOPERM);
- }
- pwd_init ();
+ Prog = Basename (argv[0]);
+ OPENLOG ("chfn");
+
+ /* parse the command line options */
+ process_flags (argc, argv);
+
/*
- * The passwd entry is now ready to be committed back to the
- * password file. Get a lock on the file and open it.
+ * Get the name of the user to check. It is either the command line
+ * name, or the name getlogin() returns.
*/
- if (!pw_lock ()) {
- fprintf (stderr,
- _
- ("Cannot lock the password file; try again later.\n"));
- SYSLOG ((LOG_WARN, "can't lock /etc/passwd"));
- closelog ();
- exit (E_NOPERM);
+ if (optind < argc) {
+ user = argv[optind];
+ pw = xgetpwnam (user);
+ if (!pw) {
+ fprintf (stderr, _("%s: unknown user %s\n"), Prog,
+ user);
+ exit (E_NOPERM);
+ }
+ } else {
+ pw = get_my_pwent ();
+ if (!pw) {
+ fprintf (stderr,
+ _
+ ("%s: Cannot determine your user name.\n"),
+ Prog);
+ exit (E_NOPERM);
+ }
+ user = xstrdup (pw->pw_name);
}
- if (!pw_open (O_RDWR)) {
- fprintf (stderr, _("Cannot open the password file.\n"));
- pw_unlock ();
- SYSLOG ((LOG_ERR, "can't open /etc/passwd"));
- closelog ();
- exit (E_NOPERM);
- }
+#ifdef USE_NIS
/*
- * 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
+ * Now we make sure this is a LOCAL password entry for this user ...
*/
- pw = pw_locate (user);
- if (!pw) {
- pw_unlock ();
+ if (__ispwNIS ()) {
+ char *nis_domain;
+ char *nis_master;
+
fprintf (stderr,
- _("%s: %s not found in /etc/passwd\n"), Prog, user);
+ _("%s: cannot change user '%s' on NIS client.\n"),
+ Prog, user);
+
+ if (!yp_get_default_domain (&nis_domain) &&
+ !yp_master (nis_domain, "passwd.byname", &nis_master)) {
+ fprintf (stderr,
+ _
+ ("%s: '%s' is the NIS master for this client.\n"),
+ Prog, nis_master);
+ }
exit (E_NOPERM);
}
+#endif
+ /* Check that the caller is allowed to change the gecos of the
+ * specified user */
+ check_perms (pw);
+
+ /* If some fields were not set on the command line, load the value from
+ * the old gecos fields. */
+ get_old_fields (pw->pw_gecos);
+
/*
- * Make a copy of the entry, then change the gecos field. The other
- * fields remain unchanged.
+ * If none of the fields were changed from the command line, let the
+ * user interactively change them.
*/
- pwent = *pw;
- pwent.pw_gecos = new_gecos;
+ if (!fflg && !rflg && !wflg && !hflg && !oflg) {
+ printf (_("Changing the user information for %s\n"), user);
+ new_fields ();
+ }
/*
- * Update the passwd file entry. If there is a DBM file, update that
- * entry as well.
+ * Check all of the fields for valid information
*/
- if (!pw_update (&pwent)) {
- fprintf (stderr, _("Error updating the password entry.\n"));
- pw_unlock ();
- SYSLOG ((LOG_ERR, "error updating passwd entry"));
- closelog ();
- exit (E_NOPERM);
- }
+ check_fields ();
/*
- * Changes have all been made, so commit them and unlock the file.
+ * Build the new GECOS field by plastering all the pieces together,
+ * if they will fit ...
*/
- if (!pw_close ()) {
- fprintf (stderr, _("Cannot commit password file changes.\n"));
- pw_unlock ();
- SYSLOG ((LOG_ERR, "can't rewrite /etc/passwd"));
+ if (strlen (fullnm) + strlen (roomno) + strlen (workph) +
+ strlen (homeph) + strlen (slop) > (unsigned int) 80) {
+ fprintf (stderr, _("%s: fields too long\n"), Prog);
closelog ();
exit (E_NOPERM);
}
- if (!pw_unlock ()) {
- fprintf (stderr, _("Cannot unlock the password file.\n"));
- SYSLOG ((LOG_ERR, "can't unlock /etc/passwd"));
- closelog ();
- exit (E_NOPERM);
- }
+ snprintf (new_gecos, sizeof new_gecos, "%s,%s,%s,%s%s%s",
+ fullnm, roomno, workph, homeph, slop[0] ? "," : "", slop);
+
+ /* Rewrite the user's gecos in the passwd file */
+ update_gecos (user, new_gecos);
+
SYSLOG ((LOG_INFO, "changed user `%s' information", user));
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 ();
More information about the Pkg-shadow-commits
mailing list