home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1990, John F. Haugh II
- * All rights reserved.
- *
- * Non-commercial distribution permitted. You must provide this source
- * code in any distribution. This notice must remain intact.
- */
-
- #include <sys/types.h>
- #include <stdio.h>
- #include <pwd.h>
- #include <grp.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <errno.h>
- #ifndef BSD
- #include <termio.h>
- #ifdef SYS3
- #include <sys/ioctl.h>
- #endif
- #include <string.h>
- #ifndef SYS3
- #include <memory.h>
- #endif
- #else
- #include <sgtty.h>
- #include <strings.h>
- #define strchr index
- #define strrchr rindex
- #endif
- #include "config.h"
-
- #ifndef PASSLENGTH
- #define PASSLENGTH 5
- #endif
-
- #ifndef lint
- static char _sccsid[] = "@(#)gpmain.c 1.3 09:19:10 6/26/90";
- #endif
-
- char name[BUFSIZ];
- char pass[BUFSIZ];
- char pass2[BUFSIZ];
-
- struct group grent;
-
- char *myname;
-
- #ifndef RETRIES
- #define RETRIES 3
- #endif
-
- char *l64a ();
- char *crypt ();
- extern int errno;
- long a64l ();
- void entry ();
- time_t time ();
-
- /*
- * usage - display usage message
- */
-
- void
- usage ()
- {
- fprintf (stderr, "usage: %s [ -r ] group\n", myname);
- exit (1);
- }
-
- int
- main (argc, argv)
- int argc;
- char **argv;
- {
- extern int optind;
- extern char *optarg;
- char *group;
- int flag;
- int i;
- void die ();
- char *cp;
- char *getlogin ();
- int amroot;
- int lockfd = -1;
- int remove = 0;
- int retries;
- int ruid = getuid();
- int suid = geteuid();
- long salttime;
- struct group *gr;
- struct group *getgrnam ();
- struct group *sgetgrent ();
- struct passwd *pw;
- struct passwd *getpwuid ();
- struct passwd *getpwnam ();
- FILE *ngrp;
- FILE *ogrp;
- char buf[BUFSIZ];
- char tmp[BUFSIZ];
-
- amroot = getuid () == 0;
- setuid (geteuid ());
- myname = argv[0];
-
- if (! isatty (0) || ! isatty (1))
- exit (1);
-
- die (0); /* save tty modes */
-
- signal (SIGHUP, die);
- signal (SIGINT, die);
- signal (SIGQUIT, die);
- signal (SIGTERM, die);
-
- while ((flag = getopt (argc, argv, "gr")) != EOF) {
- switch (flag) {
- case 'g': /* no-op from normal password */
- break;
- case 'r': /* remove group password */
- remove = 1;
- break;
- default:
- usage ();
- }
- }
- if (cp = getlogin ()) /* need user name */
- (void) strcpy (name, cp);
- else if (pw = getpwuid (ruid)) /* get it from password file */
- strcpy (name, pw->pw_name);
- else { /* can't find user name! */
- fprintf (stderr, "Who are you?\n");
- exit (1);
- }
- if (! (pw = getpwnam (name)))
- goto failure; /* can't get my name ... */
-
- if (! (group = argv[optind]))
- usage ();
-
- if (! (gr = getgrnam (group))) {
- fprintf (stderr, "unknown group: %s\n", group);
- exit (1);
- }
- if (! amroot) {
- if (gr->gr_mem[0] == (char *) 0)
- goto failure;
-
- if (strcmp (gr->gr_mem[0], name) != 0)
- goto failure;
- }
- if (remove) {
- if (! amroot && (gr->gr_mem[0] &&
- strcmp (name, gr->gr_mem[0]) != 0))
- goto failure;
-
- gr->gr_passwd = "";
- goto output;
- }
- printf ("Changing password for group %s\n", group);
-
- printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH);
- retries = RETRIES;
- retry:
- if (! password ("New Password:", pass))
- exit (1);
-
- 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;
- }
- (void) time (&salttime);
- salttime = ((salttime & 07777) ^ ((salttime >> 12) & 07777)) & 07777;
- grent.gr_passwd = tmp;
- strcpy (grent.gr_passwd, crypt (pass, l64a (salttime)));
- #ifdef DOUBLESIZE
- if (strlen (pass) > 8) {
- strcpy (grent.gr_passwd + 13,
- crypt (pass + 8, l64a (salttime)) + 2);
- }
- #endif
- output:
-
- /*
- * 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 (".grplock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
- #else
- if ((lockfd = open (GRPLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
- #endif /* NDEBUG */
- {
- puts ("Can't get lock");
- exit (1);
- }
- umask (077); /* close security holes to come ... */
- if (access (NGRPFILE, 0) == 0 && unlink (NGRPFILE) == -1)
- goto failure;
-
- #ifndef NDEBUG
- if ((ngrp = fopen ("ngroup", "w")) == (FILE *) 0)
- #else
- umask (077); /* no permissions for non-roots */
-
- if ((ngrp = fopen (NGRPFILE, "w")) == (FILE *) 0)
- #endif /* NDEBUG */
- goto failure;
-
- #ifndef NDEBUG
- chmod (NGRPFILE, 0444); /* lets have some security here ... */
- chown (NGRPFILE, 0, 0); /* ... and keep the bad guy away */
- #endif /* NDEBUG */
- if ((ogrp = fopen (GRPFILE, "r")) == (FILE *) 0)
- goto failure;
-
- while (fgets (buf, sizeof buf, ogrp) != (char *) 0) {
- if (buf[0] == '#' || ! (gr = sgetgrent (buf))) {
- fputs (buf, ngrp);
- } else if (strcmp (gr->gr_name, group) != 0)
- fputs (buf, ngrp);
- else
- break;
- }
- if (gr) {
- (void) fprintf (ngrp, "%s:%s:%d%s",
- gr->gr_name,
- grent.gr_passwd ? grent.gr_passwd:"x",
- gr->gr_gid, strrchr (buf, ':'));
-
- while (fgets (buf, BUFSIZ, ogrp) != (char *) 0)
- fputs (buf, ngrp);
- }
- if (ferror (ngrp)) {
- perror (NGRPFILE);
- if (unlink (NGRPFILE) || unlink (GRPLOCK))
- fputs ("Help!\n", stderr);
-
- exit (1);
- }
- fflush (ngrp);
- fclose (ngrp);
- #ifdef NDEBUG
- chmod (NGRPFILE, 0644);
- if (unlink (OGRPFILE) == -1) {
- if (errno != ENOENT) {
- puts ("Can't unlink backup file");
- goto unlock;
- }
- }
- if (link (GRPFILE, OGRPFILE) || unlink (GRPFILE)) {
- puts ("Can't save backup file");
- goto unlock;
- }
- #ifndef BSD
- if (link (NGRPFILE, GRPFILE) || unlink (NGRPFILE))
- #else
- if (rename (NGRPFILE, GRPFILE))
- #endif
- {
- puts ("Can't rename new file");
- goto unlock;
- }
- #endif /* NDEBUG */
- #ifndef NDEBUG
- (void) unlink (".grplock");
- #else
- (void) unlink (GRPLOCK);
- #endif
- exit (0);
- /*NOTREACHED*/
-
- failure:
- puts ("Permission denied.");
- unlock:
- if (lockfd >= 0)
- (void) unlink (GRPLOCK);
-
- (void) unlink (NGRPFILE);
- 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);
- }
- }
-