home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2288 / gpmain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  9.2 KB  |  465 lines

  1. /*
  2.  * Copyright 1990, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Non-commercial distribution permitted.  You must provide this source
  6.  * code in any distribution.  This notice must remain intact.
  7.  */
  8.  
  9. #include <sys/types.h>
  10. #include <stdio.h>
  11. #include <pwd.h>
  12. #include <grp.h>
  13. #include <fcntl.h>
  14. #include <signal.h>
  15. #include <errno.h>
  16. #ifndef    BSD
  17. #include <termio.h>
  18. #ifdef SYS3
  19. #include <sys/ioctl.h>
  20. #endif
  21. #include <string.h>
  22. #ifndef    SYS3
  23. #include <memory.h>
  24. #endif
  25. #else
  26. #include <sgtty.h>
  27. #include <strings.h>
  28. #define    strchr    index
  29. #define    strrchr    rindex
  30. #endif
  31. #include "config.h"
  32.  
  33. #ifndef    PASSLENGTH
  34. #define    PASSLENGTH    5
  35. #endif
  36.  
  37. #ifndef    lint
  38. static    char    _sccsid[] = "@(#)gpmain.c    2.1    00:44:03    11/28/90";
  39. #endif
  40.  
  41. char    name[BUFSIZ];
  42. char    pass[BUFSIZ];
  43. char    pass2[BUFSIZ];
  44.  
  45. struct    group    grent;
  46.  
  47. char    *myname;
  48. char    *user;
  49. char    *group;
  50. int    aflg;
  51. int    dflg;
  52. int    rflg;
  53.  
  54. #ifndef    RETRIES
  55. #define    RETRIES    3
  56. #endif
  57.  
  58. char    *l64a ();
  59. char    *crypt ();
  60. extern    int    errno;
  61. long    a64l ();
  62. void    entry ();
  63. time_t    time ();
  64.  
  65. /*
  66.  * usage - display usage message
  67.  */
  68.  
  69. void
  70. usage ()
  71. {
  72.     fprintf (stderr, "usage: %s [ -r ] group\n", myname);
  73.     fprintf (stderr, "       %s [ -a user ] group\n", myname);
  74.     fprintf (stderr, "       %s [ -d user ] group\n", myname);
  75.     exit (1);
  76. }
  77.  
  78. char **
  79. add_list (list, member)
  80. char    **list;
  81. char    *member;
  82. {
  83.     int    i;
  84.     int    found = 0;
  85.     char    **tmp;
  86.  
  87.     for (i = 0;!found && list[i] != (char *) 0;i++)
  88.         if (strcmp (list[i], member) == 0)
  89.             found++;
  90.  
  91.     tmp = (char **) malloc ((i + 2) * sizeof member);
  92.  
  93.     for (i = 0;list[i] != (char *) 0;i++)
  94.         tmp[i] = list[i];
  95.  
  96.     if (! found) {
  97.         tmp[i++] = strdup (member);
  98.         tmp[i] = (char *) 0;
  99.     }
  100.     return tmp;
  101. }
  102.  
  103. char **
  104. del_list (list, member)
  105. char    **list;
  106. char    *member;
  107. {
  108.     int    i, j;
  109.     char    **tmp;
  110.  
  111.     for (i = 0;list[i] != (char *) 0;i++)
  112.         ;
  113.  
  114.     tmp = (char **) malloc ((i + 1) * sizeof member);
  115.  
  116.     for (j = i = 0;list[i] != (char *) 0;i++)
  117.         if (strcmp (list[i], member) == 0)
  118.             tmp[j++] = list[i];
  119.  
  120.     tmp[j] = (char *) 0;
  121.  
  122.     return tmp;
  123. }
  124.  
  125. int
  126. main (argc, argv)
  127. int    argc;
  128. char    **argv;
  129. {
  130.     extern    int    optind;
  131.     extern    char    *optarg;
  132.     int    flag;
  133.     int    i;
  134.     void    die ();
  135.     char    *cp;
  136.     char    *getlogin ();
  137.     int    amroot;
  138.     int    lockfd = -1;
  139.     int    retries;
  140.     int    ruid = getuid();
  141.     int    suid = geteuid();
  142.     long    salttime;
  143.     struct    group    *gr;
  144.     struct    group    *getgrnam ();
  145.     struct    group    *sgetgrent ();
  146.     struct    passwd    *pw;
  147.     struct    passwd    *getpwuid ();
  148.     struct    passwd    *getpwnam ();
  149.     FILE    *ngrp;
  150.     FILE    *ogrp;
  151.     char    buf[BUFSIZ];
  152.     char    tmp[BUFSIZ];
  153.  
  154.     amroot = getuid () == 0;
  155.     setuid (geteuid ());
  156.     myname = argv[0];
  157.  
  158.     if (! isatty (0) || ! isatty (1))
  159.         exit (1);
  160.  
  161.     die (0);            /* save tty modes */
  162.  
  163.     signal (SIGHUP, die);
  164.     signal (SIGINT, die);
  165.     signal (SIGQUIT, die);
  166.     signal (SIGTERM, die);
  167.  
  168.     while ((flag = getopt (argc, argv, "a:d:gr")) != EOF) {
  169.         switch (flag) {
  170.             case 'a':    /* add a user */
  171.                 aflg++;
  172.                 user = optarg;
  173.                 break;
  174.             case 'd':
  175.                 dflg++;
  176.                 user = optarg;
  177.                 break;
  178.             case 'g':    /* no-op from normal password */
  179.                 break;
  180.             case 'r':    /* remove group password */
  181.                 rflg++;
  182.                 break;
  183.             default:
  184.                 usage ();
  185.         }
  186.     }
  187.     if (aflg + dflg + rflg > 1)
  188.         usage ();
  189.  
  190.     if ((cp = getlogin ()) && (pw = getpwnam (cp)) && pw->pw_uid == ruid) {
  191.                     /* need user name */
  192.         (void) strcpy (name, cp);
  193.     } else if (pw = getpwuid (ruid)) /* get it from password file */
  194.         strcpy (name, pw->pw_name);
  195.     else {                /* can't find user name! */
  196.         fprintf (stderr, "Who are you?\n");
  197.         exit (1);
  198.     }
  199.     if (! (pw = getpwnam (name)))
  200.         goto failure;        /* can't get my name ... */
  201.         
  202.     if (! (group = argv[optind]))
  203.         usage ();
  204.  
  205.     if (! (gr = getgrnam (group))) {
  206.         fprintf (stderr, "unknown group: %s\n", group);
  207.         exit (1);
  208.     }
  209.     grent = *gr;
  210.     grent.gr_name = strdup (gr->gr_name);
  211.     grent.gr_passwd = strdup (gr->gr_passwd);
  212.  
  213.     for (i = 0;gr->gr_mem[i];i++)
  214.         ;
  215.     grent.gr_mem = (char **) malloc ((i + 1) * sizeof (char *));
  216.     for (i = 0;gr->gr_mem[i];i++)
  217.         grent.gr_mem[i] = strdup (gr->gr_mem[i]);
  218.     grent.gr_mem[i] = (char *) 0;
  219.  
  220.     if (! amroot) {
  221.         if (gr->gr_mem[0] == (char *) 0)
  222.             goto failure;
  223.  
  224.         if (strcmp (gr->gr_mem[0], name) != 0)
  225.             goto failure;
  226.     }
  227.     if (rflg) {
  228.         if (! amroot && (gr->gr_mem[0] &&
  229.                 strcmp (name, gr->gr_mem[0]) != 0))
  230.             goto failure;
  231.  
  232.         gr->gr_passwd = "";
  233.         goto output;
  234.     }
  235.     if (aflg) {
  236.         if (! amroot && (gr->gr_mem[0] == (char *) 0 ||
  237.                 strcmp (name, gr->gr_mem[0]) != 0))
  238.             goto failure;
  239.  
  240.         printf ("Adding user %s to group %s\n", user, group);
  241.         grent.gr_mem = add_list (gr->gr_mem, user);
  242.         goto output;
  243.     }
  244.     if (dflg) {
  245.         if (! amroot && (gr->gr_mem[0] == (char *) 0 ||
  246.                 strcmp (name, gr->gr_mem[0]) != 0))
  247.             goto failure;
  248.  
  249.         printf ("Removing user %s from group %s\n", user, group);
  250.         grent.gr_mem = del_list (gr->gr_mem, user);
  251.         goto output;
  252.     }
  253.     printf ("Changing password for group %s\n", group);
  254.  
  255.     printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH);
  256.     retries = RETRIES;
  257. retry:
  258.     if (! password ("New Password:", pass))
  259.         exit (1);
  260.  
  261.     if (! password ("Re-enter new password:", pass2))
  262.         exit (1);
  263.  
  264.     if (strcmp (pass, pass2) != 0) {
  265.         puts ("They don't match; try again");
  266.  
  267.         if (retries-- > 0)
  268.             goto retry;
  269.         else
  270.             goto toomany;
  271.     }
  272.     (void) time (&salttime);
  273.     salttime = ((salttime & 07777) ^ ((salttime >> 12) & 07777)) & 07777;
  274.     grent.gr_passwd = tmp;
  275.     strcpy (grent.gr_passwd, crypt (pass, l64a (salttime)));
  276. #ifdef    DOUBLESIZE
  277.     if (strlen (pass) > 8) {
  278.         strcpy (grent.gr_passwd + 13,
  279.             crypt (pass + 8, l64a (salttime)) + 2);
  280.     }
  281. #endif
  282. output:
  283.  
  284.     /*
  285.      * Now we get to race the bad guy.  I don't think he can get us.
  286.      *
  287.      * Ignore most reasonable signals.
  288.      *    Maybe we should ignore more?  He can't hurt us until the end.
  289.      *
  290.      * Get a lock file.
  291.      *
  292.      * Copy first part of password file to new file.
  293.      *    Illegal lines are copied verbatim.
  294.      *    File permissions are r--r--r--, owner root, group root.
  295.      *
  296.      * Output the new entry.
  297.      *    Only fields in struct passwd are output.
  298.      *
  299.      * Copy the rest of the file verbatim.
  300.      *
  301.      * Rename (link, unlink) password file to backup.
  302.      *    Kill me now and nothing changes or no one gets in.
  303.      *
  304.      * Rename (link, unlink) temporary file to password file.
  305.      *    Kill me now and no one gets in or lock is left.
  306.      *
  307.      * Remove locking file.
  308.      *
  309.      * That's all folks ...
  310.      */
  311.  
  312.     signal (SIGHUP, SIG_IGN);
  313.     signal (SIGINT, SIG_IGN);
  314.     signal (SIGQUIT, SIG_IGN);
  315.     signal (SIGTERM, SIG_IGN);
  316.  
  317.     ulimit (30000);            /* prevent any funny business */
  318.     umask (0);            /* get new files modes correct */
  319. #ifndef    NDEBUG
  320.     if ((lockfd = open (".grplock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
  321. #else
  322.     for (retries = 0;retries < 30;retries++) {
  323.         if ((lockfd = open (GRPLOCK, O_RDONLY|O_CREAT|O_EXCL, 0)) != -1)
  324.             break;
  325.  
  326.         sleep (1);
  327.     }
  328.     if (lockfd == -1)
  329. #endif    /* NDEBUG */
  330.     {
  331.         puts ("Can't get lock");
  332.         exit (1);
  333.     }
  334.     umask (077);            /* close security holes to come ... */
  335.     if (access (NGRPFILE, 0) == 0 && unlink (NGRPFILE) == -1)
  336.         goto failure;
  337.  
  338. #ifndef    NDEBUG
  339.     if ((ngrp = fopen ("ngroup", "w")) == (FILE *) 0)
  340. #else
  341.     umask (077);        /* no permissions for non-roots */
  342.  
  343.     if ((ngrp = fopen (NGRPFILE, "w")) == (FILE *) 0)
  344. #endif    /* NDEBUG */
  345.         goto failure;
  346.  
  347. #ifndef    NDEBUG
  348.     chmod (NGRPFILE, 0444);        /* lets have some security here ... */
  349.     chown (NGRPFILE, 0, 0);        /* ... and keep the bad guy away */
  350. #endif    /* NDEBUG */
  351.     if ((ogrp = fopen (GRPFILE, "r")) == (FILE *) 0)
  352.         goto failure;
  353.  
  354.     while (fgets (buf, sizeof buf, ogrp) != (char *) 0) {
  355.         if (buf[0] == '#' || ! (gr = sgetgrent (buf))) {
  356.             fputs (buf, ngrp);
  357.         } else if (strcmp (gr->gr_name, group) != 0)
  358.             fputs (buf, ngrp);
  359.         else
  360.             break;
  361.     }
  362.     if (gr) {
  363.         (void) fprintf (ngrp, "%s:%s:%d:",
  364.             grent.gr_name, grent.gr_passwd ? grent.gr_passwd:"x",
  365.                 grent.gr_gid);
  366.  
  367.         for (i = 0;grent.gr_mem[i] != (char *) 0;i++) {
  368.             if (i)
  369.                 fputc (',', ngrp);
  370.             fputs (grent.gr_mem[i], ngrp);
  371.         }
  372.         fputc ('\n', ngrp);
  373.     }
  374.     while (fgets (buf, BUFSIZ, ogrp) != (char *) 0)
  375.         fputs (buf, ngrp);
  376.  
  377.     if (ferror (ngrp)) {
  378.         perror (NGRPFILE);
  379.         if (unlink (NGRPFILE) || unlink (GRPLOCK))
  380.             fputs ("Help!\n", stderr);
  381.  
  382.         exit (1);
  383.     }
  384.     fflush (ngrp);
  385.     fclose (ngrp);
  386. #ifdef    NDEBUG
  387.     chmod (NGRPFILE, 0644);
  388.     if (unlink (OGRPFILE) == -1) {
  389.         if (errno != ENOENT) {
  390.             puts ("Can't unlink backup file");
  391.             goto unlock;
  392.         }
  393.     }
  394.     if (link (GRPFILE, OGRPFILE) || unlink (GRPFILE)) {
  395.         puts ("Can't save backup file");
  396.         goto unlock;
  397.     }
  398. #ifndef    BSD
  399.     if (link (NGRPFILE, GRPFILE) || unlink (NGRPFILE))
  400. #else
  401.     if (rename (NGRPFILE, GRPFILE))
  402. #endif
  403.     {
  404.         puts ("Can't rename new file");
  405.         goto unlock;
  406.     }
  407. #endif    /* NDEBUG */
  408. #ifndef    NDEBUG
  409.     (void) unlink (".grplock");
  410. #else
  411.     (void) unlink (GRPLOCK);
  412. #endif
  413.     exit (0);
  414.     /*NOTREACHED*/
  415.  
  416. failure:
  417.     puts ("Permission denied.");
  418. unlock:
  419.     if (lockfd >= 0)
  420.         (void) unlink (GRPLOCK);
  421.  
  422.     (void) unlink (NGRPFILE);
  423.     exit (1);
  424.     /*NOTREACHED*/
  425.  
  426. toomany:
  427.     puts ("Too many tries; try again later.");
  428.     exit (1);
  429.     /*NOTREACHED*/
  430. }
  431.  
  432. /*
  433.  * die - set or reset termio modes.
  434.  *
  435.  *    die() is called before processing begins.  signal() is then
  436.  *    called with die() as the signal handler.  If signal later
  437.  *    calls die() with a signal number, the terminal modes are
  438.  *    then reset.
  439.  */
  440.  
  441. void    die (killed)
  442. int    killed;
  443. {
  444. #ifdef    BSD
  445.     static    struct    sgtty    sgtty;
  446.  
  447.     if (killed)
  448.         stty (0, &sgtty);
  449.     else
  450.         gtty (0, &sgtty);
  451. #else
  452.     static    struct    termio    sgtty;
  453.  
  454.     if (killed)
  455.         ioctl (0, TCSETA, &sgtty);
  456.     else
  457.         ioctl (0, TCGETA, &sgtty);
  458. #endif
  459.     if (killed) {
  460.         putchar ('\n');
  461.         fflush (stdout);
  462.         exit (killed);
  463.     }
  464. }
  465.