home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume6
/
shadow-2.pt2
/
pmain.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-02-03
|
8KB
|
377 lines
#include <sys/types.h>
#include <stdio.h>
#include <pwd.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include "config.h"
#include "lastlog.h"
#include "shadow.h"
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 ();
int main (argc, argv)
int argc;
char **argv;
{
char *cp;
char *getlogin ();
int amroot;
int lockfd = -1;
#ifdef OBSCURE
int force = 0;
#endif
int retries;
#ifdef AGING
long week;
long lastweek;
#endif
long salttime;
struct passwd *pw;
struct passwd *getpwuid ();
struct passwd *sgetpwent ();
FILE *npwd;
#ifdef SHADOWPWD
struct spwd *spwd;
struct spwd tspwd;
#else
FILE *pwd;
char buf[BUFSIZ];
#endif
argc--; argv++; /* shift ... */
if (! (pw = getpwuid (getuid ())))
goto failure; /* can't get my name ... */
#ifdef OBSCURE
if (argc > 0 && strcmp (argv[0], "-f") == 0) {
force = 1;
argc--; argv++; /* shift ... */
}
#endif
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! */
goto failure;
printf ("Changing password for %s\n", name);
amroot = getuid () == 0; /* currently am super user */
if (! amroot)
force = 0;
if (! amroot && strcmp (name, pw->pw_name) != 0)
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);
if (!force && ! obscure ()) {
#ifdef OBSCURE
puts ("Password not changed.");
exit (1);
#else
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) {
cp = l64a (week);
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 = crypt (pass, l64a (salttime));
/*
* 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 (SIGINT, SIG_IGN);
signal (SIGQUIT, SIG_IGN);
signal (SIGTERM, SIG_IGN);
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;
(void) putspent (spwd, npwd);
}
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 */
(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;
}
if (link (NSHADOW, SHADOW) || unlink (NSHADOW)) {
(void) unlink (OSHADOW);
puts ("Can't rename new file");
goto unlock;
}
if (unlink (OSHADOW)) {
puts ("Can't remove backup file");
goto unlock;
}
#else /* ! SHADOWPWD */
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)
(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",
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
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;
}
if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE)) {
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*/
}