home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1989, 1990, John F. Haugh II
- * All rights reserved.
- *
- * Use, duplication, and disclosure prohibited without
- * the express written permission of the author.
- */
-
- #include <sys/types.h>
- #include <stdio.h>
- #include <pwd.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <errno.h>
- #ifndef BSD
- #include <termio.h>
- #include <string.h>
- #include <memory.h>
- #else
- #include <sgtty.h>
- #include <strings.h>
- #define strchr index
- #define strrchr rindex
- #endif
- #include "config.h"
- #include "lastlog.h"
- #include "shadow.h"
-
- #ifdef SHADOW
- # ifndef AGING
- # define AGING
- # endif
- #endif
-
- #ifdef DBM
- #include <dbm.h>
- #endif
-
- #ifndef PASSLENGTH
- #define PASSLENGTH 5
- #endif
-
- #ifndef lint
- static char _sccsid[] = "@(#)pmain.c 2.8 07:55:00 11/8/90";
- #endif
-
- char name[BUFSIZ];
- char orig[BUFSIZ];
- char pass[BUFSIZ];
- char pass2[BUFSIZ];
-
- struct passwd pwent;
-
- #ifndef RETRIES
- #define RETRIES 3
- #endif
-
- char *l64a ();
- char *crypt ();
- extern int errno;
- long a64l ();
- void entry ();
- time_t time ();
-
- void
- usage ()
- {
- #ifdef OBSCURE
- fprintf (stderr, "usage: passwd { [ -f ] user | -g [ -r ] group }\n");
- #else
- fprintf (stderr, "usage: passwd { user | -g [ -r ] group }\n");
- #endif
- exit (1);
- }
-
- #ifdef DBM
- /*
- * update_dbm
- *
- * Updates the DBM password files, if they exist.
- */
-
- update_dbm (pw)
- struct passwd *pw;
- {
- datum key;
- datum content;
- char data[BUFSIZ];
- int len;
-
- strcpy (data, PWDFILE);
- strcat (data, ".pag");
- if (access (data, 0))
- return;
-
- len = pw_pack (pw, data);
- content.dsize = len;
- content.dptr = data;
-
- key.dsize = strlen (pw->pw_name);
- key.dptr = pw->pw_name;
- store (key, content);
-
- key.dsize = sizeof pw->pw_uid;
- key.dptr = (char *) &pw->pw_uid;
- store (key, content);
- }
- #endif
-
- int
- main (argc, argv)
- int argc;
- char **argv;
- {
- void die ();
- char *cp;
- char *getlogin ();
- int amroot;
- int lockfd = -1;
- #ifdef OBSCURE
- int force = 0;
- #endif
- int retries;
- #ifdef AGING
- long week;
- long lastweek;
- char newage[5];
- #endif
- long salttime;
- struct passwd *pw;
- struct passwd *getpwuid ();
- struct passwd *getpwnam ();
- struct passwd *sgetpwent ();
- FILE *npwd;
- #ifdef SHADOWPWD
- struct spwd *spwd;
- struct spwd tspwd;
- #else
- FILE *pwd;
- char buf[BUFSIZ];
- #endif
- char tmp[BUFSIZ];
-
- argc--; argv++; /* shift ... */
-
- if (! isatty (0) || ! isatty (1))
- exit (1);
-
- die (0); /* save tty modes */
-
- signal (SIGHUP, die); /* exit if SIGHUP */
- signal (SIGINT, die); /* exit if SIGINT */
- signal (SIGQUIT, die); /* exit if SIGQUIT */
- signal (SIGTERM, die); /* exit if SIGTERM */
-
- if (argc > 0 && strcmp (argv[0], "-g") == 0) {
- argv[0] = "gpasswd";
- execv ("/bin/gpasswd", &argv[0]);
- perror ("/bin/gpasswd");
- fprintf (stderr, "Unable to change group passwords\n");
- exit (-1);
- }
- #ifdef OBSCURE
- if (argc > 0 && strcmp (argv[0], "-f") == 0) {
- force = 1;
- argc--; argv++; /* shift ... */
- }
- #endif
- if (argc > 0 && argv[0][0] == '-')
- usage ();
-
- if (argc > 0)
- (void) strcpy (name, argv[0]);
- else if (cp = getlogin ()) /* need user name */
- (void) strcpy (name, cp);
- else { /* can't find user name! */
- fprintf (stderr, "unknown user: %s\n", argv[0]);
- exit (1);
- }
- printf ("Changing password for %s\n", name);
-
- if (! (pw = getpwnam (name)))
- goto failure; /* can't get my name ... */
-
- amroot = getuid () == 0; /* currently am super user */
- #ifdef OBSCURE
- if (! amroot)
- force = 0;
- #endif
- if (! amroot && (getuid () != pw->pw_uid ||
- strcmp (name, getlogin ())))
- goto failure;
-
- entry (name, &pwent); /* get password file entry */
-
- if (! pwent.pw_name) /* no entry for user??? */
- goto failure;
-
- if (! amroot) {
- if (! password ("Old Password:", orig))
- exit (1);
-
- if (! valid (orig, &pwent)) {
- puts ("Sorry.");
- exit (1);
- }
- }
- #ifdef AGING
- if (! amroot && pwent.pw_age) { /* check out the age */
- #ifdef SHADOWPWD
- (void) time (&week);
- week /= (24L * 60L * 60L); /* days since epoch */
- if (spwd = getspnam (name)) { /* use entries in shadow */
- if (spwd->sp_min > spwd->sp_max) {
- puts ("You may not change this password");
- exit (1);
- }
- if (spwd->sp_lstchg + spwd->sp_min > week) {
- printf ("Sorry, less than %d days since the last change\n", spwd->sp_min);
- exit (1);
- }
- } else {
- #endif /* SHADOWPWD */
- (void) time (&week);
- week /= (7L * 24L * 60L * 60L); /* weeks since epoch */
- lastweek = a64l (&pwent.pw_age[2]);
-
- if (c64i (pwent.pw_age[0]) < c64i (pwent.pw_age[1])) {
- puts ("You may not change this password");
- exit (1);
- }
- if (c64i (pwent.pw_age[1]) + lastweek > week) {
- printf ("Sorry, less than %d weeks since the last change\n", c64i (pwent.pw_age[1]));
- exit (1);
- }
- #ifdef SHADOWPWD
- }
- #endif
- }
- #endif
- printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH);
- #ifdef OBSCURE
- puts ("Please use a combination of upper and lowercase letters and numbers");
- #endif
- retries = RETRIES;
- retry:
- if (! password ("New Password:", pass))
- exit (1);
-
- #ifndef OBSCURE
- if (! obscure ()) {
- puts ("Password not changed.");
- exit (1);
- }
- #else
- if (! force && ! obscure ()) {
- if (retries-- > 0) {
- puts ("Please try again.");
- goto retry;
- } else
- goto toomany;
- }
- #endif
- if (! password ("Re-enter new password:", pass2))
- exit (1);
-
- if (strcmp (pass, pass2) != 0) {
- puts ("They don't match; try again");
-
- if (retries-- > 0)
- goto retry;
- else
- goto toomany;
- }
- #ifdef AGING
- if (pwent.pw_age && strlen (pwent.pw_age) >= 2) {
- strcpy (newage, pwent.pw_age);
- pwent.pw_age = newage;
-
- cp = l64a (week);
-
- if (pwent.pw_age[0] == '.' && pwent.pw_age[1] == '.')
- pwent.pw_age[0] = 'z';
-
- pwent.pw_age[2] = cp[0];
- pwent.pw_age[3] = cp[1];
- pwent.pw_age[4] = '\0';
- }
- #endif
- (void) time (&salttime);
- salttime = ((salttime & 07777) ^ ((salttime >> 14) & 07777)) & 07777;
- pwent.pw_passwd = tmp;
- strcpy (pwent.pw_passwd, crypt (pass, l64a (salttime)));
- #ifdef DOUBLESIZE
- if (strlen (pass) > 8) {
- strcpy (pwent.pw_passwd + 13,
- crypt (pass + 8, l64a (salttime)) + 2);
- }
- #endif
- /*
- * Now we get to race the bad guy. I don't think he can get us.
- *
- * Ignore most reasonable signals.
- * Maybe we should ignore more? He can't hurt us until the end.
- *
- * Get a lock file.
- *
- * Copy first part of password file to new file.
- * Illegal lines are copied verbatim.
- * File permissions are r--r--r--, owner root, group root.
- *
- * Output the new entry.
- * Only fields in struct passwd are output.
- *
- * Copy the rest of the file verbatim.
- *
- * Rename (link, unlink) password file to backup.
- * Kill me now and nothing changes or no one gets in.
- *
- * Rename (link, unlink) temporary file to password file.
- * Kill me now and no one gets in or lock is left.
- *
- * Remove locking file.
- *
- * That's all folks ...
- */
-
- signal (SIGHUP, SIG_IGN);
- signal (SIGINT, SIG_IGN);
- signal (SIGQUIT, SIG_IGN);
- signal (SIGTERM, SIG_IGN);
-
- ulimit (30000); /* prevent any funny business */
- umask (0); /* get new files modes correct */
- #ifndef NDEBUG
- if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
- #else
- if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
- #endif /* NDEBUG */
- {
- puts ("Can't get lock");
- exit (1);
- }
- umask (077); /* close security holes to come ... */
- #ifdef SHADOWPWD
- if (access (NSHADOW, 0) == 0 && unlink (NSHADOW) == -1)
- goto failure;
-
- if ((npwd = fopen (NSHADOW, "w")) == (FILE *) 0)
- goto failure;
-
- if (chmod (NSHADOW, 0400) || chown (NSHADOW, 0, 0))
- goto failure;
-
- setspent ();
-
- while (spwd = getspent ()) {
- if (strcmp (spwd->sp_namp, name) == 0)
- break;
-
- if (putspent (spwd, npwd))
- goto failure;
- }
- if (spwd == (struct spwd *) 0) { /* didn't find a match */
- spwd = &tspwd; /* use a local structure instead */
- spwd->sp_namp = pwent.pw_name;
- spwd->sp_max = 10000; /* about as big as possible */
- spwd->sp_min = 0; /* about as small as possible */
- }
- spwd->sp_pwdp = pwent.pw_passwd; /* fixup the password */
-
- (void) time (&lastweek); /* get the current time ... */
- lastweek /= (24L*60L*60L); /* ... turn it into days. */
- spwd->sp_lstchg = lastweek; /* save it as date of last change */
-
- if (spwd->sp_min == 0 && spwd->sp_max == 0)
- spwd->sp_max = 10000; /* don't force another passwd */
-
- (void) putspent (spwd, npwd); /* add the new entry */
-
- while (spwd = getspent ()) /* finish the other ones off */
- (void) putspent (spwd, npwd);
-
- endspent ();
-
- if (ferror (npwd)) {
- perror (NSHADOW);
- if (unlink (NPWDFILE) || unlink (PWDLOCK))
- fputs ("Help!\n", stderr);
-
- exit (1);
- }
- fflush (npwd);
- fclose (npwd);
-
- if (access (OSHADOW, 0) == 0) {
- if (unlink (OSHADOW)) {
- puts ("Can't remove backup file");
- goto unlock;
- }
- }
- if (link (SHADOW, OSHADOW) || unlink (SHADOW)) {
- puts ("Can't save backup file");
- goto unlock;
- }
- #ifndef BSD
- if (link (NSHADOW, SHADOW) || unlink (NSHADOW))
- #else
- if (rename (NSHADOW, SHADOW))
- #endif
- {
- (void) unlink (OSHADOW);
- puts ("Can't rename new file");
- goto unlock;
- }
- if (unlink (OSHADOW)) {
- puts ("Can't remove backup file");
- goto unlock;
- }
- #else /* ! SHADOWPWD */
- #ifdef DBM
- update_dbm (&pwent);
- #endif
- if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1)
- goto failure;
-
- #ifndef NDEBUG
- if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0)
- #else
- umask (077); /* no permissions for non-roots */
-
- if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0)
- #endif /* NDEBUG */
- goto failure;
-
- #ifndef NDEBUG
- chmod (NPWDFILE, 0444); /* lets have some security here ... */
- chown (NPWDFILE, 0, 0); /* ... and keep the bad guy away */
- #endif /* NDEBUG */
- if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0)
- goto failure;
-
- while (fgets (buf, BUFSIZ, pwd) != (char *) 0) {
- if (buf[0] == '#' || ! (pw = sgetpwent (buf))) {
- fputs (buf, npwd);
- } else if (strcmp (pw->pw_name, pwent.pw_name) != 0)
- fputs (buf, npwd);
- else
- break;
- }
- (void) fprintf (npwd, "%s:", pw->pw_name);
- if (pwent.pw_age && pwent.pw_age[0])
- (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age);
- else
- (void) fprintf (npwd, "%s:", pwent.pw_passwd);
-
- (void) fprintf (npwd, "%d:%d:%s:%s:%s\n",
- pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir,
- pwent.pw_shell ? pwent.pw_shell:"");
-
- while (fgets (buf, BUFSIZ, pwd) != (char *) 0)
- fputs (buf, npwd);
-
- if (ferror (npwd)) {
- perror (NPWDFILE);
- if (unlink (NPWDFILE) || unlink (PWDLOCK))
- fputs ("Help!\n", stderr);
-
- exit (1);
- }
- fflush (npwd);
- fclose (npwd);
- #ifdef NDEBUG
- chmod (NPWDFILE, 0644);
- if (unlink (OPWDFILE) == -1) {
- if (errno != ENOENT) {
- puts ("Can't unlink backup file");
- goto unlock;
- }
- }
- if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) {
- puts ("Can't save backup file");
- goto unlock;
- }
- #ifndef BSD
- if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE))
- #else
- if (rename (NPWDFILE, PWDFILE))
- #endif
- {
- puts ("Can't rename new file");
- goto unlock;
- }
- #endif /* NDEBUG */
- #endif /* SHADOW */
- #ifndef NDEBUG
- (void) unlink (".pwdlock");
- #else
- (void) unlink (PWDLOCK);
- #endif
- exit (0);
- /*NOTREACHED*/
-
- failure:
- puts ("Permission denied.");
- unlock:
- if (lockfd >= 0)
- (void) unlink (PWDLOCK);
-
- (void) unlink (NPWDFILE);
- exit (1);
- /*NOTREACHED*/
-
- toomany:
- puts ("Too many tries; try again later.");
- exit (1);
- /*NOTREACHED*/
- }
-
- /*
- * die - set or reset termio modes.
- *
- * die() is called before processing begins. signal() is then
- * called with die() as the signal handler. If signal later
- * calls die() with a signal number, the terminal modes are
- * then reset.
- */
-
- void die (killed)
- int killed;
- {
- #ifdef BSD
- static struct sgtty sgtty;
-
- if (killed)
- stty (0, &sgtty);
- else
- gtty (0, &sgtty);
- #else
- static struct termio sgtty;
-
- if (killed)
- ioctl (0, TCSETA, &sgtty);
- else
- ioctl (0, TCGETA, &sgtty);
- #endif
- if (killed) {
- putchar ('\n');
- fflush (stdout);
- exit (killed);
- }
- }
-