home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3343 / gpmain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-17  |  9.2 KB  |  449 lines

  1. /*
  2.  * Copyright 1990, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Permission is granted to copy and create derivative works for any
  6.  * non-commercial purpose, provided this copyright notice is preserved
  7.  * in all copies of source code, or included in human readable form
  8.  * and conspicuously displayed on all copies of object code or
  9.  * distribution media.
  10.  */
  11.  
  12. #include <sys/types.h>
  13. #include <stdio.h>
  14. #include "pwd.h"
  15. #include <grp.h>
  16. #include <fcntl.h>
  17. #include <signal.h>
  18. #include <errno.h>
  19. #ifndef    BSD
  20. #include <termio.h>
  21. #ifdef SYS3
  22. #include <sys/ioctl.h>
  23. #endif
  24. #include <string.h>
  25. #ifndef    SYS3
  26. #include <memory.h>
  27. #endif
  28. #else
  29. #include <sgtty.h>
  30. #include <strings.h>
  31. #define    strchr    index
  32. #define    strrchr    rindex
  33. #endif
  34. #include "config.h"
  35.  
  36. #ifndef    PASSLENGTH
  37. #define    PASSLENGTH    5
  38. #endif
  39.  
  40. #ifndef    lint
  41. static    char    _sccsid[] = "@(#)gpmain.c    3.4    12:30:43    12/12/90";
  42. #endif
  43.  
  44. char    name[BUFSIZ];
  45. char    pass[BUFSIZ];
  46. char    pass2[BUFSIZ];
  47.  
  48. struct    group    grent;
  49.  
  50. char    *Prog;
  51. char    *user;
  52. char    *group;
  53. int    aflg;
  54. int    dflg;
  55. int    rflg;
  56. int    Rflg;
  57.  
  58. #ifndef    RETRIES
  59. #define    RETRIES    3
  60. #endif
  61.  
  62. extern    char    *l64a ();
  63. extern    char    *crypt ();
  64. extern    char    *pw_encrypt ();
  65. extern    int    errno;
  66. extern    long    a64l ();
  67. extern    void    entry ();
  68. extern    time_t    time ();
  69.  
  70. /*
  71.  * usage - display usage message
  72.  */
  73.  
  74. void
  75. usage ()
  76. {
  77.     fprintf (stderr, "usage: %s [ -r|R ] group\n", Prog);
  78.     fprintf (stderr, "       %s [ -a user ] group\n", Prog);
  79.     fprintf (stderr, "       %s [ -d user ] group\n", Prog);
  80.     exit (1);
  81. }
  82.  
  83. /*
  84.  * add_list - add a member to a list of group members
  85.  *
  86.  *    the array of member names is searched for the new member
  87.  *    name, and if not present it is added to a freshly allocated
  88.  *    list of users.
  89.  */
  90.  
  91. char **
  92. add_list (list, member)
  93. char    **list;
  94. char    *member;
  95. {
  96.     int    i;
  97.     int    found = 0;
  98.     char    **tmp;
  99.  
  100.     for (i = 0;!found && list[i] != (char *) 0;i++)
  101.         if (strcmp (list[i], member) == 0)
  102.             found++;
  103.  
  104.     tmp = (char **) malloc ((i + 2) * sizeof member);
  105.  
  106.     for (i = 0;list[i] != (char *) 0;i++)
  107.         tmp[i] = list[i];
  108.  
  109.     if (! found)
  110.         tmp[i++] = strdup (member);
  111.  
  112.     tmp[i] = (char *) 0;
  113.     return tmp;
  114. }
  115.  
  116. /*
  117.  * del_list - delete a group member from a list of members
  118.  *
  119.  *    del_list searches a list of group members, copying the
  120.  *    members which do not match "member" to a newly allocated
  121.  *    list.
  122.  */
  123.  
  124. char **
  125. del_list (list, member)
  126. char    **list;
  127. char    *member;
  128. {
  129.     int    i, j;
  130.     char    **tmp;
  131.  
  132.     for (j = i = 0;list[i] != (char *) 0;i++)
  133.         if (strcmp (list[i], member))
  134.             j++;
  135.  
  136.     tmp = (char **) malloc ((j + 1) * sizeof member);
  137.  
  138.     for (j = i = 0;list[i] != (char *) 0;i++)
  139.         if (strcmp (list[i], member) != 0)
  140.             tmp[j++] = list[i];
  141.  
  142.     tmp[j] = (char *) 0;
  143.  
  144.     return tmp;
  145. }
  146.  
  147. int
  148. main (argc, argv)
  149. int    argc;
  150. char    **argv;
  151. {
  152.     extern    int    optind;
  153.     extern    char    *optarg;
  154.     int    flag;
  155.     int    i;
  156.     void    die ();
  157.     char    *cp;
  158.     char    *getlogin ();
  159.     int    amroot;
  160.     int    retries;
  161.     int    ruid = getuid();
  162.     struct    group    *gr;
  163.     struct    group    *getgrnam ();
  164.     struct    group    *sgetgrent ();
  165.     struct    passwd    *pw;
  166.     struct    passwd    *getpwuid ();
  167.     struct    passwd    *getpwnam ();
  168.  
  169.     /*
  170.      * Make a note of whether or not this command was invoked
  171.      * by root.  This will be used to bypass certain checks
  172.      * later on.  Also, set the real user ID to match the
  173.      * effective user ID.  This will prevent the invoker from
  174.      * issuing signals which would interfer with this command.
  175.      */
  176.  
  177.     amroot = getuid () == 0;
  178.     setuid (geteuid ());
  179.     Prog = argv[0];
  180.     setbuf (stdout, (char *) 0);
  181.     setbuf (stderr, (char *) 0);
  182.  
  183.     while ((flag = getopt (argc, argv, "a:d:grR")) != EOF) {
  184.         switch (flag) {
  185.             case 'a':    /* add a user */
  186.                 aflg++;
  187.                 user = optarg;
  188.                 break;
  189.             case 'd':    /* delete a user */
  190.                 dflg++;
  191.                 user = optarg;
  192.                 break;
  193.             case 'g':    /* no-op from normal password */
  194.                 break;
  195.             case 'r':    /* remove group password */
  196.                 rflg++;
  197.                 break;
  198.             case 'R':    /* restrict group password */
  199.                 Rflg++;
  200.                 break;
  201.             default:
  202.                 usage ();
  203.         }
  204.     }
  205.  
  206.     /*
  207.      * Make sure exclusive flags are exclusive
  208.      */
  209.  
  210.     if (aflg + dflg + rflg + Rflg > 1)
  211.         usage ();
  212.  
  213.     /*
  214.      * Unless the mode is -a, -d or -r, the input and output must
  215.      * both be a tty.  The typical keyboard signals are caught
  216.      * so the termio modes can be restored.
  217.      */
  218.  
  219.     if (! aflg && ! dflg && ! rflg && ! Rflg) {
  220.         if (! isatty (0) || ! isatty (1))
  221.             exit (1);
  222.  
  223.         die (0);            /* save tty modes */
  224.  
  225.         signal (SIGHUP, die);
  226.         signal (SIGINT, die);
  227.         signal (SIGQUIT, die);
  228.         signal (SIGTERM, die);
  229.     }
  230.  
  231.     /*
  232.      * Determine the name of the user that invoked this command.
  233.      * This is really hit or miss because there are so many ways
  234.      * that command can be executed and so many ways to trip up
  235.      * the routines that report the user name.
  236.      */
  237.  
  238.     if ((cp = getlogin ()) && (pw = getpwnam (cp)) && pw->pw_uid == ruid) {
  239.                     /* need user name */
  240.         (void) strcpy (name, cp);
  241.     } else if (pw = getpwuid (ruid)) /* get it from password file */
  242.         strcpy (name, pw->pw_name);
  243.     else {                /* can't find user name! */
  244.         fprintf (stderr, "Who are you?\n");
  245.         exit (1);
  246.     }
  247.     if (! (pw = getpwnam (name)))
  248.         goto failure;        /* can't get my name ... */
  249.         
  250.     /*
  251.      * Get the name of the group that is being affected.  The group
  252.      * entry will be completely replicated so it may be modified
  253.      * later on.
  254.      */
  255.  
  256.     if (! (group = argv[optind]))
  257.         usage ();
  258.  
  259.     if (! (gr = getgrnam (group))) {
  260.         fprintf (stderr, "unknown group: %s\n", group);
  261.         exit (1);
  262.     }
  263.     grent = *gr;
  264.     grent.gr_name = strdup (gr->gr_name);
  265.     grent.gr_passwd = strdup (gr->gr_passwd);
  266.  
  267.     for (i = 0;gr->gr_mem[i];i++)
  268.         ;
  269.     grent.gr_mem = (char **) malloc ((i + 1) * sizeof (char *));
  270.     for (i = 0;gr->gr_mem[i];i++)
  271.         grent.gr_mem[i] = strdup (gr->gr_mem[i]);
  272.     grent.gr_mem[i] = (char *) 0;
  273.  
  274.     /*
  275.      * The policy for changing a group is that 1) you must be root
  276.      * or 2) you must be the first listed member of the group.  The
  277.      * first listed member of a group can do anything to that group
  278.      * that the root user can.
  279.      */
  280.  
  281.     if (! amroot) {
  282.         if (grent.gr_mem[0] == (char *) 0)
  283.             goto failure;
  284.  
  285.         if (strcmp (grent.gr_mem[0], name) != 0)
  286.             goto failure;
  287.     }
  288.  
  289.     /*
  290.      * Removing a password is straight forward.  Just set the
  291.      * password field to a "".
  292.      */
  293.  
  294.     if (rflg) {
  295.         grent.gr_passwd = "";
  296.         goto output;
  297.     } else if (Rflg) {
  298.         grent.gr_passwd = "!";
  299.         goto output;
  300.     }
  301.  
  302.     /*
  303.      * Adding a member to a member list is pretty straightforward
  304.      * as well.  Call the appropriate routine and split.
  305.      */
  306.  
  307.     if (aflg) {
  308.         if (getpwnam (user) == (struct passwd *) 0) {
  309.             fprintf (stderr, "%s: unknown user %s\n", Prog, user);
  310.             exit (1);
  311.         }
  312.         printf ("Adding user %s to group %s\n", user, group);
  313.         grent.gr_mem = add_list (grent.gr_mem, user);
  314.         goto output;
  315.     }
  316.  
  317.     /*
  318.      * Removing a member from the member list is the same deal
  319.      * as adding one, except the routine is different.
  320.      */
  321.  
  322.     if (dflg) {
  323.         for (i = 0;grent.gr_mem[i];i++)
  324.             if (strcmp (user, grent.gr_mem[i]) == 0)
  325.                 break;
  326.  
  327.         if (grent.gr_mem[i] == (char *) 0) {
  328.             fprintf (stderr, "%s: unknown member %s\n", Prog, user);
  329.             exit (1);
  330.         }
  331.         printf ("Removing user %s from group %s\n", user, group);
  332.         grent.gr_mem = del_list (grent.gr_mem, user);
  333.         goto output;
  334.     }
  335.  
  336.     /*
  337.      * A new password is to be entered and it must be encrypted,
  338.      * etc.  The password will be prompted for twice, and both
  339.      * entries must be identical.  There is no need to validate
  340.      * the old password since the invoker is either the group
  341.      * owner, or root.
  342.      */
  343.  
  344.     printf ("Changing the password for group %s\n", group);
  345.  
  346.     for (retries = 0;retries < RETRIES;retries++) {
  347.         if (! (cp = getpass ("New Password:")))
  348.             exit (1);
  349.         else
  350.             strcpy (pass, cp);
  351.  
  352.         if (! (cp = getpass ("Re-enter new password:")))
  353.             exit (1);
  354.         else
  355.             strcpy (pass2, cp);
  356.  
  357.         if (strcmp (pass, pass2) == 0)
  358.             break;
  359.  
  360.         if (retries + 1 < RETRIES)
  361.             puts ("They don't match; try again");
  362.     }
  363.     if (retries == RETRIES) {
  364.         fprintf (stderr, "%s: Try again later\n", Prog);
  365.         exit (1);
  366.     }
  367.     grent.gr_passwd = pw_encrypt (pass, (char *) 0);
  368.  
  369.     /*
  370.      * This is the common arrival point to output the new group
  371.      * file.  The freshly crafted entry is in allocated space.
  372.      * The group file will be locked and opened for writing.  The
  373.      * new entry will be output, etc.
  374.      */
  375.  
  376. output:
  377.     signal (SIGHUP, SIG_IGN);
  378.     signal (SIGINT, SIG_IGN);
  379.     signal (SIGQUIT, SIG_IGN);
  380.  
  381.     if (! gr_lock ()) {
  382.         fprintf (stderr, "%s: can't get lock\n", Prog);
  383.         exit (1);
  384.     }
  385.     if (! gr_open (O_RDWR)) {
  386.         fprintf (stderr, "%s: can't open file\n", Prog);
  387.         exit (1);
  388.     }
  389.     if (! gr_update (&grent)) {
  390.         fprintf (stderr, "%s: can't update entry\n", Prog);
  391.         exit (1);
  392.     }
  393.     if (! gr_close ()) {
  394.         fprintf (stderr, "%s: can't re-write file\n", Prog);
  395.         exit (1);
  396.     }
  397.     if (! gr_unlock ()) {
  398.         fprintf (stderr, "%s: can't unlock file\n", Prog);
  399.         exit (1);
  400.     }
  401. #ifdef    NDBM
  402.     if (! gr_dbm_update (&grent)) {
  403.         fprintf (stderr, "%s: can't update DBM files\n", Prog);
  404.         exit (1);
  405.     }
  406. #endif
  407.     exit (0);
  408.     /*NOTREACHED*/
  409.  
  410. failure:
  411.     fprintf (stderr, "Permission denied.\n");
  412.     exit (1);
  413.     /*NOTREACHED*/
  414. }
  415.  
  416. /*
  417.  * die - set or reset termio modes.
  418.  *
  419.  *    die() is called before processing begins.  signal() is then
  420.  *    called with die() as the signal handler.  If signal later
  421.  *    calls die() with a signal number, the terminal modes are
  422.  *    then reset.
  423.  */
  424.  
  425. void    die (killed)
  426. int    killed;
  427. {
  428. #ifdef    BSD
  429.     static    struct    sgtty    sgtty;
  430.  
  431.     if (killed)
  432.         stty (0, &sgtty);
  433.     else
  434.         gtty (0, &sgtty);
  435. #else
  436.     static    struct    termio    sgtty;
  437.  
  438.     if (killed)
  439.         ioctl (0, TCSETA, &sgtty);
  440.     else
  441.         ioctl (0, TCGETA, &sgtty);
  442. #endif
  443.     if (killed) {
  444.         putchar ('\n');
  445.         fflush (stdout);
  446.         exit (killed);
  447.     }
  448. }
  449.