home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume38 / shadow / part08 / groupmod.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-14  |  9.8 KB  |  516 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 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.  * This software is provided on an AS-IS basis and the author makes
  12.  * no warrantee of any kind.
  13.  */
  14.  
  15. #ifndef lint
  16. static    char    sccsid[] = "@(#)groupmod.c    3.5    08:43:14    29 Apr 1993";
  17. #endif
  18.  
  19. #include <sys/types.h>
  20. #include <stdio.h>
  21. #include <grp.h>
  22. #include <ctype.h>
  23. #include <fcntl.h>
  24.  
  25. #ifdef    BSD
  26. #include <strings.h>
  27. #else
  28. #include <string.h>
  29. #endif
  30.  
  31. #include "config.h"
  32. #include "shadow.h"
  33.  
  34. #ifdef    USE_SYSLOG
  35. #include <syslog.h>
  36. #endif
  37.  
  38. char    group_name[BUFSIZ];
  39. char    group_newname[BUFSIZ];
  40. GID_T    group_id;
  41. GID_T    group_newid;
  42.  
  43. char    *Prog;
  44.  
  45. int    oflg;    /* permit non-unique group ID to be specified with -g         */
  46. int    gflg;    /* new ID value for the group                                 */
  47. int    nflg;    /* a new name has been specified for the group                */
  48.  
  49. #ifdef    NDBM
  50. extern    int    gr_dbm_mode;
  51. extern    int    sg_dbm_mode;
  52. #endif
  53. extern    char    *malloc();
  54.  
  55. extern    struct    group    *getgrnam();
  56. extern    struct    group    *gr_next();
  57. extern    struct    group    *gr_locate();
  58. extern    int    gr_lock();
  59. extern    int    gr_unlock();
  60. extern    int    gr_rewind();
  61. extern    int    gr_open();
  62.  
  63. #ifdef    SHADOWGRP
  64. extern    struct    sgrp    *sgr_locate();
  65. extern    int    sgr_lock();
  66. extern    int    sgr_unlock();
  67. extern    int    sgr_open();
  68. #endif
  69.  
  70. /*
  71.  * usage - display usage message and exit
  72.  */
  73.  
  74. usage ()
  75. {
  76.     fprintf (stderr, "usage: groupmod [-g gid [-o]] [-n name] group\n");
  77.     exit (2);
  78. }
  79.  
  80. /*
  81.  * new_grent - updates the values in a group file entry
  82.  *
  83.  *    new_grent() takes all of the values that have been entered and
  84.  *    fills in a (struct group) with them.
  85.  */
  86.  
  87. void
  88. new_grent (grent)
  89. struct    group    *grent;
  90. {
  91.     if (nflg)
  92.         grent->gr_name = strdup (group_newname);
  93.  
  94.     if (gflg)
  95.         grent->gr_gid = group_newid;
  96. }
  97.  
  98. #ifdef    SHADOWGRP
  99. /*
  100.  * new_sgent - updates the values in a shadow group file entry
  101.  *
  102.  *    new_sgent() takes all of the values that have been entered and
  103.  *    fills in a (struct sgrp) with them.
  104.  */
  105.  
  106. void
  107. new_sgent (sgent)
  108. struct    sgrp    *sgent;
  109. {
  110.     if (nflg)
  111.         sgent->sg_name = strdup (group_newname);
  112. }
  113. #endif    /* SHADOWGRP */
  114.  
  115. /*
  116.  * grp_update - update group file entries
  117.  *
  118.  *    grp_update() writes the new records to the group files.
  119.  */
  120.  
  121. void
  122. grp_update ()
  123. {
  124.     struct    group    grp;
  125.     struct    group    *ogrp;
  126. #ifdef    SHADOWGRP
  127.     struct    sgrp    sgrp;
  128.     struct    sgrp    *osgrp;
  129. #endif    /* SHADOWGRP */
  130.  
  131.     /*
  132.      * Get the current settings for this group.
  133.      */
  134.  
  135.     grp = *(gr_locate (group_name));
  136.     new_grent (&grp);
  137. #ifdef    SHADOWGRP
  138.     if (osgrp = sgr_locate (group_name)) {
  139.         sgrp = *osgrp;
  140.         new_sgent (&sgrp);
  141.     }
  142. #endif    /* SHADOWGRP */
  143.  
  144.     /*
  145.      * Write out the new group file entry.
  146.      */
  147.  
  148.     if (! gr_update (&grp)) {
  149.         fprintf (stderr, "%s: error adding new group entry\n", Prog);
  150.         exit (1);
  151.     }
  152.     if (nflg && ! gr_remove (group_name)) {
  153.         fprintf (stderr, "%s: error removing group entry\n", Prog);
  154.         exit (1);
  155.     }
  156. #ifdef    NDBM
  157.  
  158.     /*
  159.      * Update the DBM group file with the new entry as well.
  160.      */
  161.  
  162.     if (access ("/etc/group.pag", 0) == 0) {
  163.         if (! gr_dbm_update (&grp)) {
  164.             fprintf (stderr, "%s: cannot add new dbm group entry\n",
  165.                 Prog);
  166.             exit (1);
  167.         }
  168.         if (nflg && (ogrp = getgrnam (group_name)) &&
  169.                 ! gr_dbm_remove (ogrp)) {
  170.             fprintf (stderr, "%s: error removing group dbm entry\n",
  171.                 Prog);
  172.             exit (1);
  173.         }
  174.         endgrent ();
  175.     }
  176. #endif    /* NDBM */
  177.  
  178. #ifdef    SHADOWGRP
  179.  
  180.     /*
  181.      * Make sure there was a shadow entry to begin with.  Skip
  182.      * down to "out" if there wasn't.  Can't just return because
  183.      * there might be some syslogging to do.
  184.      */
  185.  
  186.     if (! osgrp)
  187.         goto out;
  188.  
  189.     /*
  190.      * Write out the new shadow group entries as well.
  191.      */
  192.  
  193.     if (! sgr_update (&sgrp)) {
  194.         fprintf (stderr, "%s: error adding new group entry\n", Prog);
  195.         exit (1);
  196.     }
  197.     if (nflg && ! sgr_remove (group_name)) {
  198.         fprintf (stderr, "%s: error removing group entry\n", Prog);
  199.         exit (1);
  200.     }
  201. #ifdef    NDBM
  202.  
  203.     /*
  204.      * Update the DBM shadow group file with the new entry as well.
  205.      */
  206.  
  207.     if (access ("/etc/gshadow.pag", 0) == 0) {
  208.         if (! sg_dbm_update (&sgrp)) {
  209.             fprintf (stderr,
  210.                 "%s: cannot add new dbm shadow group entry\n",
  211.                 Prog);
  212.             exit (1);
  213.         }
  214.         if (nflg && ! sg_dbm_remove (group_name)) {
  215.             fprintf (stderr,
  216.                 "%s: error removing shadow group dbm entry\n",
  217.                 Prog);
  218.             exit (1);
  219.         }
  220.         endsgent ();
  221.     }
  222. #endif    /* NDBM */
  223. #endif    /* SHADOWGRP */
  224.  
  225. out:
  226. #ifdef    USE_SYSLOG
  227.     if (nflg)
  228.         syslog (LOG_INFO, "change group `%s' to `%s'\n",
  229.             group_name, group_newname);
  230.  
  231.     if (gflg)
  232.         syslog (LOG_INFO, "change gid for `%s' to %d\n",
  233.             nflg ? group_newname:group_name, group_newid);
  234. #endif    /* USE_SYSLOG */
  235. }
  236.  
  237. /*
  238.  * check_new_gid - check the new GID value for uniqueness
  239.  *
  240.  *    check_new_gid() insures that the new GID value is unique.
  241.  */
  242.  
  243. void
  244. check_new_gid ()
  245. {
  246.     /*
  247.      * First, the easy stuff.  If the ID can be duplicated, or if
  248.      * the ID didn't really change, just return.  If the ID didn't
  249.      * change, turn off those flags.  No sense doing needless work.
  250.      */
  251.  
  252.     if (oflg)
  253.         return;
  254.  
  255.     if (group_id == group_newid) {
  256.         gflg = 0;
  257.         return;
  258.     }
  259.     if (! getgrgid (group_newid))
  260.         return;
  261.  
  262.     /*
  263.      * Tell the user what they did wrong.
  264.      */
  265.  
  266.     fprintf (stderr, "%s: %d is not a unique gid\n", Prog, group_newid);
  267.     exit (4);
  268. }
  269.  
  270. /*
  271.  * check_new_name - check the new name for uniqueness
  272.  *
  273.  *    check_new_name() insures that the new name does not exist
  274.  *    already.  You can't have the same name twice, period.
  275.  */
  276.  
  277. void
  278. check_new_name ()
  279. {
  280.     int    i;
  281.  
  282.     /*
  283.      * Make sure they are actually changing the name.
  284.      */
  285.  
  286.     if (strcmp (group_name, group_newname) == 0) {
  287.         nflg = 0;
  288.         return;
  289.     }
  290.  
  291.     /*
  292.      * Check for validity.  The name must be at least 1 character in
  293.      * length, but not more than 10.  It must start with a letter and
  294.      * contain printable characters, not including ':' and '\n'
  295.      */
  296.  
  297.     if (strlen (group_newname) > 10)
  298.         goto bad_name;
  299.  
  300.     if (strlen (group_newname) >= 1 && isalpha (group_newname[0])) {
  301.         for (i = 1;group_newname[i] && isprint (group_newname[i]);i++)
  302.             if (group_newname[i] == ':' ||
  303.                     group_newname[i] == '\n')
  304.                 goto bad_name;
  305.  
  306.         /*
  307.          * Something was left over.  It must be a non-printable
  308.          * character.
  309.          */
  310.  
  311.         if (group_newname[i])
  312.             goto bad_name;
  313.  
  314.         /*
  315.          * If the entry is found, too bad.
  316.          */
  317.  
  318.         if (getgrnam (group_newname)) {
  319.             fprintf (stderr, "%s: %s is not a unique name\n",
  320.                 Prog, group_newname);
  321.             exit (9);
  322.         }
  323.         return;
  324.     }
  325.  
  326.     /*
  327.      * All invalid group names land here.
  328.      */
  329.  
  330. bad_name:
  331.     fprintf (stderr, "%s: %s is a not a valid group name\n",
  332.         Prog, group_newname);
  333.     exit (3);
  334. }
  335.  
  336. /*
  337.  * process_flags - perform command line argument setting
  338.  *
  339.  *    process_flags() interprets the command line arguments and sets
  340.  *    the values that the user will be created with accordingly.  The
  341.  *    values are checked for sanity.
  342.  */
  343.  
  344. void
  345. process_flags (argc, argv)
  346. int    argc;
  347. char    **argv;
  348. {
  349.     extern    int    optind;
  350.     extern    char    *optarg;
  351.     char    *end;
  352.     int    arg;
  353.  
  354.     while ((arg = getopt (argc, argv, "og:n:")) != EOF) {
  355.         switch (arg) {
  356.             case 'g':
  357.                 gflg++;
  358.                 group_newid = strtol (optarg, &end, 10);
  359.                 if (*end != '\0') {
  360.                     fprintf (stderr, "%s: invalid group %s\n",
  361.                         Prog, optarg);
  362.                     exit (3);
  363.                 }
  364.                 break;
  365.             case 'n':
  366.                 if (strcmp (group_name, optarg)) {
  367.                     nflg++;
  368.                     strncpy (group_newname, optarg, BUFSIZ);
  369.                 }
  370.                 break;
  371.             case 'o':
  372.                 if (! gflg)
  373.                     usage ();
  374.  
  375.                 oflg++;
  376.                 break;
  377.             default:
  378.                 usage ();
  379.         }
  380.     }
  381.     if (optind == argc - 1)
  382.         strcpy (group_name, argv[argc - 1]);
  383.     else
  384.         usage ();
  385. }
  386.  
  387. /*
  388.  * close_files - close all of the files that were opened
  389.  *
  390.  *    close_files() closes all of the files that were opened for this
  391.  *    new group.  This causes any modified entries to be written out.
  392.  */
  393.  
  394. close_files ()
  395. {
  396.     if (! gr_close ()) {
  397.         fprintf (stderr, "%s: cannot rewrite group file\n", Prog);
  398.         exit (1);
  399.     }
  400.     (void) gr_unlock ();
  401. #ifdef    SHADOWGRP
  402.     if (! sgr_close ()) {
  403.         fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  404.             Prog);
  405.         exit (1);
  406.     }
  407.     (void) sgr_unlock ();
  408. #endif    /* SHADOWGRP */
  409. }
  410.  
  411. /*
  412.  * open_files - lock and open the group files
  413.  *
  414.  *    open_files() opens the two group files.
  415.  */
  416.  
  417. open_files ()
  418. {
  419.     if (! gr_lock ()) {
  420.         fprintf (stderr, "%s: unable to lock group file\n", Prog);
  421.         exit (1);
  422.     }
  423.     if (! gr_open (O_RDWR)) {
  424.         fprintf (stderr, "%s: unable to open group file\n", Prog);
  425.         exit (1);
  426.     }
  427. #ifdef    SHADOWGRP
  428.     if (! sgr_lock ()) {
  429.         fprintf (stderr, "%s: unable to lock shadow group file\n",
  430.             Prog);
  431.         exit (1);
  432.     }
  433.     if (! sgr_open (O_RDWR)) {
  434.         fprintf (stderr, "%s: unable to open shadow group file\n",
  435.             Prog);
  436.         exit (1);
  437.     }
  438. #endif    /* SHADOWGRP */
  439. }
  440.  
  441. /*
  442.  * main - groupmod command
  443.  *
  444.  *    The syntax of the groupmod command is
  445.  *    
  446.  *    groupmod [ -g gid [ -o ]] [ -n name ] group
  447.  *
  448.  *    The flags are
  449.  *        -g - specify a new group ID value
  450.  *        -o - permit the group ID value to be non-unique
  451.  *        -n - specify a new group name
  452.  */
  453.  
  454. main (argc, argv)
  455. int    argc;
  456. char    **argv;
  457. {
  458.     struct    group    *grp;
  459.  
  460.     /*
  461.      * Get my name so that I can use it to report errors.
  462.      */
  463.  
  464.     if (Prog = strrchr (argv[0], '/'))
  465.         Prog++;
  466.     else
  467.         Prog = argv[0];
  468.  
  469. #ifdef    USE_SYSLOG
  470.     openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  471. #endif    /* USE_SYSLOG */
  472.  
  473.     /*
  474.      * The open routines for the DBM files don't use read-write
  475.      * as the mode, so we have to clue them in.
  476.      */
  477.  
  478. #ifdef    NDBM
  479.     gr_dbm_mode = O_RDWR;
  480. #ifdef    SHADOWGRP
  481.     sg_dbm_mode = O_RDWR;
  482. #endif    /* SHADOWGRP */
  483. #endif    /* NDBM */
  484.     process_flags (argc, argv);
  485.  
  486.     /*
  487.      * Start with a quick check to see if the group exists.
  488.      */
  489.  
  490.     if (! (grp = getgrnam (group_name))) {
  491.         fprintf (stderr, "%s: group %s does not exist\n",
  492.             Prog, group_name);
  493.         exit (9);
  494.     } else
  495.         group_id = grp->gr_gid;
  496.  
  497.     /*
  498.      * Do the hard stuff - open the files, create the group entries,
  499.      * then close and update the files.
  500.      */
  501.  
  502.     open_files ();
  503.  
  504.     if (gflg)
  505.         check_new_gid ();
  506.  
  507.     if (nflg)
  508.         check_new_name ();
  509.  
  510.     grp_update ();
  511.  
  512.     close_files ();
  513.     exit (0);
  514.     /*NOTREACHED*/
  515. }
  516.