home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / shadow-3.1.4 / gpmain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-28  |  12.1 KB  |  577 lines

  1. /*
  2.  * Copyright 1990, 1991, 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 "shadow.h"
  16. #include <grp.h>
  17. #include <fcntl.h>
  18. #include <signal.h>
  19. #include <errno.h>
  20. #if defined(USG) || defined(SUN4)
  21. #include <termio.h>
  22. #ifdef SYS3
  23. # include <sys/ioctl.h>
  24. #endif    /* SYS3 */
  25. #include <string.h>
  26. #ifndef    SYS3
  27. # include <memory.h>
  28. #endif /* !SYS3 */
  29. #else /* SUN || BSD */
  30. #include <sgtty.h>
  31. #include <strings.h>
  32. #define    strchr    index
  33. #define    strrchr    rindex
  34. #endif /* !SUN && !BSD */
  35. #include "config.h"
  36.  
  37. #ifdef    USG
  38. #define    bzero(p,l) memset(p, 0, l)
  39. #endif
  40.  
  41. #ifndef    lint
  42. static    char    _sccsid[] = "@(#)gpmain.c    3.12    19:39:50    12/28/91";
  43. #endif
  44.  
  45. char    name[BUFSIZ];
  46. char    pass[BUFSIZ];
  47. char    pass2[BUFSIZ];
  48.  
  49. struct    group    grent;
  50.  
  51. char    *Prog;
  52. char    *user;
  53. char    *group;
  54. int    aflg;
  55. int    dflg;
  56. int    rflg;
  57. int    Rflg;
  58.  
  59. #ifndef    RETRIES
  60. #define    RETRIES    3
  61. #endif
  62.  
  63. extern    char    *l64a ();
  64. extern    char    *crypt ();
  65. extern    char    *pw_encrypt ();
  66. extern    int    errno;
  67. extern    long    a64l ();
  68. extern    void    entry ();
  69. extern    time_t    time ();
  70. extern    char    *malloc ();
  71. extern    char    *getpass ();
  72. #ifdef    NDBM
  73. extern    int    sg_dbm_mode;
  74. extern    int    gr_dbm_mode;
  75. #endif
  76.  
  77. /*
  78.  * usage - display usage message
  79.  */
  80.  
  81. void
  82. usage ()
  83. {
  84.     fprintf (stderr, "usage: %s [ -r|R ] group\n", Prog);
  85.     fprintf (stderr, "       %s [ -a user ] group\n", Prog);
  86.     fprintf (stderr, "       %s [ -d user ] group\n", Prog);
  87.     exit (1);
  88. }
  89.  
  90. /*
  91.  * add_list - add a member to a list of group members
  92.  *
  93.  *    the array of member names is searched for the new member
  94.  *    name, and if not present it is added to a freshly allocated
  95.  *    list of users.
  96.  */
  97.  
  98. char **
  99. add_list (list, member)
  100. char    **list;
  101. char    *member;
  102. {
  103.     int    i;
  104.     char    **tmp;
  105.  
  106.     for (i = 0;list[i] != (char *) 0;i++)
  107.         if (strcmp (list[i], member) == 0)
  108.             return list;
  109.  
  110.     if (! (tmp = (char **) malloc ((i + 2) * sizeof member)))
  111.         return 0;
  112.  
  113.     for (i = 0;list[i] != (char *) 0;i++)
  114.         tmp[i] = list[i];
  115.  
  116.     tmp[i++] = strdup (member);
  117.     tmp[i] = (char *) 0;
  118.  
  119.     return tmp;
  120. }
  121.  
  122. /*
  123.  * del_list - delete a group member from a list of members
  124.  *
  125.  *    del_list searches a list of group members, copying the
  126.  *    members which do not match "member" to a newly allocated
  127.  *    list.
  128.  */
  129.  
  130. char **
  131. del_list (list, member)
  132. char    **list;
  133. char    *member;
  134. {
  135.     int    i, j;
  136.     char    **tmp;
  137.  
  138.     for (j = i = 0;list[i] != (char *) 0;i++)
  139.         if (strcmp (list[i], member))
  140.             j++;
  141.  
  142.     tmp = (char **) malloc ((j + 1) * sizeof member);
  143.  
  144.     for (j = i = 0;list[i] != (char *) 0;i++)
  145.         if (strcmp (list[i], member) != 0)
  146.             tmp[j++] = list[i];
  147.  
  148.     tmp[j] = (char *) 0;
  149.  
  150.     return tmp;
  151. }
  152.  
  153. int
  154. main (argc, argv)
  155. int    argc;
  156. char    **argv;
  157. {
  158.     extern    int    optind;
  159.     extern    char    *optarg;
  160.     int    flag;
  161.     int    i;
  162.     void    die ();
  163.     char    *cp;
  164.     char    *getlogin ();
  165.     char    *getpass ();
  166.     int    amroot;
  167.     int    retries;
  168.     int    ruid = getuid();
  169.     struct    group    *gr = 0;
  170.     struct    group    *getgrnam ();
  171.     struct    group    *sgetgrent ();
  172. #ifdef    SHADOWGRP
  173.     struct    sgrp    *sg = 0;
  174.     struct    sgrp    sgent;
  175.     struct    sgrp    *getsgnam ();
  176. #endif
  177.     struct    passwd    *pw = 0;
  178.     struct    passwd    *getpwuid ();
  179.     struct    passwd    *getpwnam ();
  180.  
  181.     /*
  182.      * Make a note of whether or not this command was invoked
  183.      * by root.  This will be used to bypass certain checks
  184.      * later on.  Also, set the real user ID to match the
  185.      * effective user ID.  This will prevent the invoker from
  186.      * issuing signals which would interfer with this command.
  187.      */
  188.  
  189.     amroot = getuid () == 0;
  190. #ifdef    NDBM
  191.     sg_dbm_mode = O_RDWR;
  192.     gr_dbm_mode = O_RDWR;
  193. #endif
  194.     setuid (geteuid ());
  195.     Prog = argv[0];
  196.     setbuf (stdout, (char *) 0);
  197.     setbuf (stderr, (char *) 0);
  198.  
  199.     while ((flag = getopt (argc, argv, "a:d:grR")) != EOF) {
  200.         switch (flag) {
  201.             case 'a':    /* add a user */
  202.                 aflg++;
  203.                 user = optarg;
  204.                 break;
  205.             case 'd':    /* delete a user */
  206.                 dflg++;
  207.                 user = optarg;
  208.                 break;
  209.             case 'g':    /* no-op from normal password */
  210.                 break;
  211.             case 'r':    /* remove group password */
  212.                 rflg++;
  213.                 break;
  214.             case 'R':    /* restrict group password */
  215.                 Rflg++;
  216.                 break;
  217.             default:
  218.                 usage ();
  219.         }
  220.     }
  221.  
  222.     /*
  223.      * Make sure exclusive flags are exclusive
  224.      */
  225.  
  226.     if (aflg + dflg + rflg + Rflg > 1)
  227.         usage ();
  228.  
  229.     /*
  230.      * Unless the mode is -a, -d or -r, the input and output must
  231.      * both be a tty.  The typical keyboard signals are caught
  232.      * so the termio modes can be restored.
  233.      */
  234.  
  235.     if (! aflg && ! dflg && ! rflg && ! Rflg) {
  236.         if (! isatty (0) || ! isatty (1))
  237.             exit (1);
  238.  
  239.         die (0);            /* save tty modes */
  240.  
  241.         signal (SIGHUP, die);
  242.         signal (SIGINT, die);
  243.         signal (SIGQUIT, die);
  244.         signal (SIGTERM, die);
  245.     }
  246.  
  247.     /*
  248.      * Determine the name of the user that invoked this command.
  249.      * This is really hit or miss because there are so many ways
  250.      * that command can be executed and so many ways to trip up
  251.      * the routines that report the user name.
  252.      */
  253.  
  254.     if ((cp = getlogin ()) && (pw = getpwnam (cp)) && pw->pw_uid == ruid) {
  255.                     /* need user name */
  256.         (void) strcpy (name, cp);
  257.     } else if (pw = getpwuid (ruid)) /* get it from password file */
  258.         strcpy (name, pw->pw_name);
  259.     else {                /* can't find user name! */
  260.         fprintf (stderr, "Who are you?\n");
  261.         exit (1);
  262.     }
  263.     if (! (pw = getpwnam (name)))
  264.         goto failure;        /* can't get my name ... */
  265.         
  266.     /*
  267.      * Get the name of the group that is being affected.  The group
  268.      * entry will be completely replicated so it may be modified
  269.      * later on.
  270.      */
  271.  
  272.     if (! (group = argv[optind]))
  273.         usage ();
  274.  
  275.     if (! (gr = getgrnam (group))) {
  276.         fprintf (stderr, "unknown group: %s\n", group);
  277.         exit (1);
  278.     }
  279.     grent = *gr;
  280.     grent.gr_name = strdup (gr->gr_name);
  281.     grent.gr_passwd = strdup (gr->gr_passwd);
  282.  
  283.     for (i = 0;gr->gr_mem[i];i++)
  284.         ;
  285.     grent.gr_mem = (char **) malloc ((i + 1) * sizeof (char *));
  286.     for (i = 0;gr->gr_mem[i];i++)
  287.         grent.gr_mem[i] = strdup (gr->gr_mem[i]);
  288.     grent.gr_mem[i] = (char *) 0;
  289. #ifdef    SHADOWGRP
  290.     if (sg = getsgnam (group)) {
  291.         sgent = *sg;
  292.         sgent.sg_name = strdup (sg->sg_name);
  293.         sgent.sg_passwd = strdup (sg->sg_name);
  294.  
  295.         for (i = 0;sg->sg_mem[i];i++)
  296.             ;
  297.         sgent.sg_mem = (char **) malloc (sizeof (char *) * (i + 1));
  298.         for (i = 0;sg->sg_mem[i];i++)
  299.             sgent.sg_mem[i] = strdup (sg->sg_mem[i]);
  300.         sgent.sg_mem[i] = 0;
  301.  
  302.         for (i = 0;sg->sg_adm[i];i++)
  303.             ;
  304.         sgent.sg_adm = (char **) malloc (sizeof (char *) * (i + 1));
  305.         for (i = 0;sg->sg_adm[i];i++)
  306.             sgent.sg_adm[i] = strdup (sg->sg_adm[i]);
  307.         sgent.sg_adm[i] = 0;
  308.     } else {
  309.         sgent.sg_name = strdup (group);
  310.         sgent.sg_passwd = grent.gr_passwd;
  311.         grent.gr_passwd = "!";
  312.  
  313.         for (i = 0;grent.gr_mem[i];i++)
  314.             ;
  315.         sgent.sg_mem = (char **) malloc (sizeof (char *) * (i + 1));
  316.         for (i = 0;grent.gr_mem[i];i++)
  317.             sgent.sg_mem[i] = strdup (grent.gr_mem[i]);
  318.         sgent.sg_mem[i] = 0;
  319.  
  320.         sgent.sg_adm = (char **) malloc (sizeof (char *) * 2);
  321.         if (sgent.sg_mem[0]) {
  322.             sgent.sg_adm[0] = strdup (sgent.sg_mem[0]);
  323.             sgent.sg_adm[1] = 0;
  324.         } else
  325.             sgent.sg_adm[0] = 0;
  326.  
  327.         sg = &sgent;
  328.     }
  329. #endif
  330.  
  331.     /*
  332.      * The policy for changing a group is that 1) you must be root
  333.      * or 2) you must be the first listed member of the group.  The
  334.      * first listed member of a group can do anything to that group
  335.      * that the root user can.
  336.      */
  337.  
  338.     if (! amroot) {
  339.         if (grent.gr_mem[0] == (char *) 0)
  340.             goto failure;
  341.  
  342.         if (strcmp (grent.gr_mem[0], name) != 0)
  343.             goto failure;
  344.     }
  345.  
  346.     /*
  347.      * Removing a password is straight forward.  Just set the
  348.      * password field to a "".
  349.      */
  350.  
  351.     if (rflg) {
  352.         grent.gr_passwd = "";
  353. #ifdef    SHADOWGRP
  354.         sgent.sg_passwd = "";
  355. #endif
  356.         goto output;
  357.     } else if (Rflg) {
  358.         grent.gr_passwd = "!";
  359. #ifdef    SHADOWGRP
  360.         sgent.sg_passwd = "!";
  361. #endif
  362.         goto output;
  363.     }
  364.  
  365.     /*
  366.      * Adding a member to a member list is pretty straightforward
  367.      * as well.  Call the appropriate routine and split.
  368.      */
  369.  
  370.     if (aflg) {
  371.         if (getpwnam (user) == (struct passwd *) 0) {
  372.             fprintf (stderr, "%s: unknown user %s\n", Prog, user);
  373.             exit (1);
  374.         }
  375.         printf ("Adding user %s to group %s\n", user, group);
  376.         grent.gr_mem = add_list (grent.gr_mem, user);
  377. #ifdef    SHADOWGRP
  378.         sgent.sg_mem = add_list (sgent.sg_mem, user);
  379. #endif
  380.         goto output;
  381.     }
  382.  
  383.     /*
  384.      * Removing a member from the member list is the same deal
  385.      * as adding one, except the routine is different.
  386.      */
  387.  
  388.     if (dflg) {
  389.         int    removed = 0;
  390.  
  391.         for (i = 0;grent.gr_mem[i];i++)
  392.             if (strcmp (user, grent.gr_mem[i]) == 0)
  393.                 break;
  394.  
  395.         printf ("Removing user %s from group %s\n", user, group);
  396.  
  397.         if (grent.gr_mem[i] != (char *) 0) {
  398.             removed = 1;
  399.             grent.gr_mem = del_list (grent.gr_mem, user);
  400.         }
  401. #ifdef    SHADOWGRP
  402.         for (i = 0;sgent.sg_mem[i];i++)
  403.             if (strcmp (user, sgent.sg_mem[i]) == 0)
  404.                 break;
  405.  
  406.         if (sgent.sg_mem[i] != (char *) 0) {
  407.             removed = 1;
  408.             sgent.sg_mem = del_list (sgent.sg_mem, user);
  409.         }
  410. #endif
  411.         if (! removed) {
  412.             fprintf (stderr, "%s: unknown member %s\n", Prog, user);
  413.             exit (1);
  414.         }
  415.         goto output;
  416.     }
  417.  
  418.     /*
  419.      * A new password is to be entered and it must be encrypted,
  420.      * etc.  The password will be prompted for twice, and both
  421.      * entries must be identical.  There is no need to validate
  422.      * the old password since the invoker is either the group
  423.      * owner, or root.
  424.      */
  425.  
  426.     printf ("Changing the password for group %s\n", group);
  427.  
  428.     for (retries = 0;retries < RETRIES;retries++) {
  429.         if (! (cp = getpass ("New Password:")))
  430.             exit (1);
  431.         else {
  432.             strcpy (pass, cp);
  433.             bzero (cp, strlen (cp));
  434.         }
  435.         if (! (cp = getpass ("Re-enter new password:")))
  436.             exit (1);
  437.         else {
  438.             strcpy (pass2, cp);
  439.             bzero (cp, strlen (cp));
  440.         }
  441.         if (strcmp (pass, pass2) == 0)
  442.             break;
  443.  
  444.         bzero (pass, sizeof pass);
  445.         bzero (pass2, sizeof pass2);
  446.  
  447.         if (retries + 1 < RETRIES)
  448.             puts ("They don't match; try again");
  449.     }
  450.     bzero (pass2, sizeof pass2);
  451.  
  452.     if (retries == RETRIES) {
  453.         fprintf (stderr, "%s: Try again later\n", Prog);
  454.         exit (1);
  455.     }
  456. #ifdef    SHADOWGRP
  457.     sgent.sg_passwd = pw_encrypt (pass, (char *) 0);
  458. #else
  459.     grent.gr_passwd = pw_encrypt (pass, (char *) 0);
  460. #endif
  461.     bzero (pass, sizeof pass);
  462.  
  463.     /*
  464.      * This is the common arrival point to output the new group
  465.      * file.  The freshly crafted entry is in allocated space.
  466.      * The group file will be locked and opened for writing.  The
  467.      * new entry will be output, etc.
  468.      */
  469.  
  470. output:
  471.     signal (SIGHUP, SIG_IGN);
  472.     signal (SIGINT, SIG_IGN);
  473.     signal (SIGQUIT, SIG_IGN);
  474.  
  475.     if (! gr_lock ()) {
  476.         fprintf (stderr, "%s: can't get lock\n", Prog);
  477.         exit (1);
  478.     }
  479. #ifdef    SHADOWGRP
  480.     if (! sgr_lock ()) {
  481.         fprintf (stderr, "%s: can't get shadow lock\n", Prog);
  482.         exit (1);
  483.     }
  484. #endif
  485.     if (! gr_open (O_RDWR)) {
  486.         fprintf (stderr, "%s: can't open file\n", Prog);
  487.         exit (1);
  488.     }
  489. #ifdef    SHADOWGRP
  490.     if (! sgr_open (O_RDWR)) {
  491.         fprintf (stderr, "%s: can't open shadow file\n", Prog);
  492.         exit (1);
  493.     }
  494. #endif
  495.     if (! gr_update (&grent)) {
  496.         fprintf (stderr, "%s: can't update entry\n", Prog);
  497.         exit (1);
  498.     }
  499. #ifdef    SHADOWGRP
  500.     if (! sgr_update (&sgent)) {
  501.         fprintf (stderr, "%s: can't update shadow entry\n", Prog);
  502.         exit (1);
  503.     }
  504. #endif
  505.     if (! gr_close ()) {
  506.         fprintf (stderr, "%s: can't re-write file\n", Prog);
  507.         exit (1);
  508.     }
  509. #ifdef    SHADOWGRP
  510.     if (! sgr_close ()) {
  511.         fprintf (stderr, "%s: can't re-write shadow file\n", Prog);
  512.         exit (1);
  513.     }
  514.     (void) sgr_unlock ();
  515. #endif
  516.     if (! gr_unlock ()) {
  517.         fprintf (stderr, "%s: can't unlock file\n", Prog);
  518.         exit (1);
  519.     }
  520. #ifdef    NDBM
  521.     if (access ("/etc/group.pag", 0) == 0 && ! gr_dbm_update (&grent)) {
  522.         fprintf (stderr, "%s: can't update DBM files\n", Prog);
  523.         exit (1);
  524.     }
  525.     endgrent ();
  526. #ifdef    SHADOWGRP
  527.     if (access ("/etc/gshadow.pag", 0) == 0 && ! sgr_dbm_update (&sgent)) {
  528.         fprintf (stderr, "%s: can't update DBM shadow files\n", Prog);
  529.         exit (1);
  530.     }
  531.     endsgent ();
  532. #endif
  533. #endif
  534.     exit (0);
  535.     /*NOTREACHED*/
  536.  
  537. failure:
  538.     fprintf (stderr, "Permission denied.\n");
  539.     exit (1);
  540.     /*NOTREACHED*/
  541. }
  542.  
  543. /*
  544.  * die - set or reset termio modes.
  545.  *
  546.  *    die() is called before processing begins.  signal() is then
  547.  *    called with die() as the signal handler.  If signal later
  548.  *    calls die() with a signal number, the terminal modes are
  549.  *    then reset.
  550.  */
  551.  
  552. void
  553. die (killed)
  554. int    killed;
  555. {
  556. #if defined(BSD) || defined(SUN)
  557.     static    struct    sgtty    sgtty;
  558.  
  559.     if (killed)
  560.         stty (0, &sgtty);
  561.     else
  562.         gtty (0, &sgtty);
  563. #else
  564.     static    struct    termio    sgtty;
  565.  
  566.     if (killed)
  567.         ioctl (0, TCSETA, &sgtty);
  568.     else
  569.         ioctl (0, TCGETA, &sgtty);
  570. #endif
  571.     if (killed) {
  572.         putchar ('\n');
  573.         fflush (stdout);
  574.         exit (killed);
  575.     }
  576. }
  577.