home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume38 / shadow / part07 / sgroupio.c < prev    next >
C/C++ Source or Header  |  1993-08-14  |  12KB  |  613 lines

  1. /*
  2.  * Copyright 1990, 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.  *    This file implements a transaction oriented shadow group
  15.  *    database library.  The shadow group file is updated one
  16.  *    entry at a time.  After each transaction the file must be
  17.  *    logically closed and transferred to the existing shadow
  18.  *    group file.  The sequence of events is
  19.  *
  20.  *    sgr_lock            -- lock shadow group file
  21.  *    sgr_open            -- logically open shadow group file
  22.  *    while transaction to process
  23.  *        sgr_(locate,update,remove) -- perform transaction
  24.  *    done
  25.  *    sgr_close            -- commit transactions
  26.  *    sgr_unlock            -- remove shadow group lock
  27.  */
  28.  
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31. #include <fcntl.h>
  32. #include <errno.h>
  33. #include <stdio.h>
  34. #ifdef    BSD
  35. #include <strings.h>
  36. #define    strchr    index
  37. #define    strrchr    rindex
  38. #else
  39. #include <string.h>
  40. #endif
  41. #include "shadow.h"
  42.  
  43. #ifndef    lint
  44. static    char    sccsid[] = "@(#)sgroupio.c    3.7    07:49:53    06 May 1993";
  45. #endif
  46.  
  47. static    int    islocked;
  48. static    int    isopen;
  49. static    int    open_modes;
  50. static    FILE    *sgrfp;
  51.  
  52. struct    sg_file_entry {
  53.     char    *sgr_line;
  54.     int    sgr_changed;
  55.     struct    sgrp    *sgr_entry;
  56.     struct    sg_file_entry *sgr_next;
  57. };
  58.  
  59. struct    sg_file_entry    *__sgr_head;
  60. static    struct    sg_file_entry    *sgr_tail;
  61. static    struct    sg_file_entry    *sgr_cursor;
  62. int    __sg_changed;
  63. static    int    lock_pid;
  64.  
  65. #define    SG_LOCK    "/etc/gshadow.lock"
  66. #define    GR_TEMP "/etc/gshadow.%d"
  67. #define    SGROUP    "/etc/gshadow"
  68.  
  69. static    char    sg_filename[BUFSIZ] = SGROUP;
  70.  
  71. extern    char    *strdup();
  72. extern    struct    sgrp    *sgetsgent();
  73. extern    char    *fgetsx();
  74. extern    char    *malloc();
  75.  
  76. /*
  77.  * sgr_dup - duplicate a shadow group file entry
  78.  *
  79.  *    sgr_dup() accepts a pointer to a shadow group file entry and
  80.  *    returns a pointer to a shadow group file entry in allocated memory.
  81.  */
  82.  
  83. static struct sgrp *
  84. sgr_dup (sgrent)
  85. struct    sgrp    *sgrent;
  86. {
  87.     struct    sgrp    *sgr;
  88.     int    i;
  89.  
  90.     if (! (sgr = (struct sgrp *) malloc (sizeof *sgr)))
  91.         return 0;
  92.  
  93.     if ((sgr->sg_name = strdup (sgrent->sg_name)) == 0 ||
  94.             (sgr->sg_passwd = strdup (sgrent->sg_passwd)) == 0)
  95.         return 0;
  96.  
  97.     for (i = 0;sgrent->sg_mem[i];i++)
  98.         ;
  99.  
  100.     sgr->sg_mem = (char **) malloc (sizeof (char *) * (i + 1));
  101.     for (i = 0;sgrent->sg_mem[i];i++)
  102.         if (! (sgr->sg_mem[i] = strdup (sgrent->sg_mem[i])))
  103.             return 0;
  104.  
  105.     sgr->sg_mem[i] = 0;
  106.  
  107.     for (i = 0;sgrent->sg_adm[i];i++)
  108.         ;
  109.  
  110.     sgr->sg_adm = (char **) malloc (sizeof (char *) * (i + 1));
  111.     for (i = 0;sgrent->sg_adm[i];i++)
  112.         if (! (sgr->sg_adm[i] = strdup (sgrent->sg_adm[i])))
  113.             return 0;
  114.  
  115.     sgr->sg_adm[i] = 0;
  116.  
  117.     return sgr;
  118. }
  119.  
  120. /*
  121.  * sgr_free - free a dynamically allocated shadow group file entry
  122.  *
  123.  *    sgr_free() frees up the memory which was allocated for the
  124.  *    pointed to entry.
  125.  */
  126.  
  127. static void
  128. sgr_free (sgrent)
  129. struct    sgrp    *sgrent;
  130. {
  131.     int    i;
  132.  
  133.     free (sgrent->sg_name);
  134.     free (sgrent->sg_passwd);
  135.  
  136.     for (i = 0;sgrent->sg_mem[i];i++)
  137.         free (sgrent->sg_mem[i]);
  138.  
  139.     free (sgrent->sg_mem);
  140.  
  141.     for (i = 0;sgrent->sg_adm[i];i++)
  142.         free (sgrent->sg_adm[i]);
  143.  
  144.     free (sgrent->sg_adm);
  145. }
  146.  
  147. /*
  148.  * sgr_name - change the name of the shadow group file
  149.  */
  150.  
  151. int
  152. sgr_name (name)
  153. char    *name;
  154. {
  155.     if (isopen || strlen (name) > (BUFSIZ-10))
  156.         return -1;
  157.  
  158.     strcpy (sg_filename, name);
  159.     return 0;
  160. }
  161.  
  162. /*
  163.  * sgr_lock - lock a shadow group file
  164.  *
  165.  *    sgr_lock() encapsulates the lock operation.  it returns
  166.  *    TRUE or FALSE depending on the shadow group file being
  167.  *    properly locked.  the lock is set by creating a semaphore
  168.  *    file, SG_LOCK.
  169.  */
  170.  
  171. int
  172. sgr_lock ()
  173. {
  174.     int    fd;
  175.     int    pid;
  176.     int    len;
  177.     char    file[BUFSIZ];
  178.     char    buf[32];
  179.     struct    stat    sb;
  180.  
  181.     if (islocked)
  182.         return 1;
  183.  
  184.     if (strcmp (sg_filename, SGROUP) != 0)
  185.         return 0;
  186.  
  187.     /*
  188.      * Create a lock file which can be switched into place
  189.      */
  190.  
  191.     sprintf (file, GR_TEMP, lock_pid = getpid ());
  192.     if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
  193.         return 0;
  194.  
  195.     sprintf (buf, "%d", lock_pid);
  196.     if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
  197.         (void) close (fd);
  198.         (void) unlink (file);
  199.         return 0;
  200.     }
  201.     close (fd);
  202.  
  203.     /*
  204.      * Simple case first -
  205.      *    Link fails (in a sane environment ...) if the target
  206.      *    exists already.  So we try to switch in a new lock
  207.      *    file.  If that succeeds, we assume we have the only
  208.      *    valid lock.  Needs work for NFS where this assumption
  209.      *    may not hold.  The simple hack is to check the link
  210.      *    count on the source file, which should be 2 iff the
  211.      *    link =really= worked.
  212.      */
  213.  
  214.     if (link (file, SG_LOCK) == 0) {
  215.         if (stat (file, &sb) != 0)
  216.             return 0;
  217.  
  218.         if (sb.st_nlink != 2)
  219.             return 0;
  220.  
  221.         (void) unlink (file);
  222.         islocked = 1;
  223.         return 1;
  224.     }
  225.  
  226.     /*
  227.      * Invalid lock test -
  228.      *    Open the lock file and see if the lock is valid.
  229.      *    The PID of the lock file is checked, and if the PID
  230.      *    is not valid, the lock file is removed.  If the unlink
  231.      *    of the lock file fails, it should mean that someone
  232.      *    else is executing this code.  They will get success,
  233.      *    and we will fail.
  234.      */
  235.  
  236.     if ((fd = open (SG_LOCK, O_RDWR)) == -1 ||
  237.             (len = read (fd, buf, BUFSIZ)) <= 0) {
  238.         errno = EINVAL;
  239.         return 0;
  240.     }
  241.     buf[len] = '\0';
  242.     if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  243.         errno = EINVAL;
  244.         return 0;
  245.     }
  246.     if (kill (pid, 0) == 0)  {
  247.         errno = EEXIST;
  248.         return 0;
  249.     }
  250.     if (unlink (SG_LOCK)) {
  251.         (void) close (fd);
  252.         (void) unlink (file);
  253.  
  254.         return 0;
  255.     }
  256.  
  257.     /*
  258.      * Re-try lock -
  259.      *    The invalid lock has now been removed and I should
  260.      *    be able to acquire a lock for myself just fine.  If
  261.      *    this fails there will be no retry.  The link count
  262.      *    test here makes certain someone executing the previous
  263.      *    block of code didn't just remove the lock we just
  264.      *    linked to.
  265.      */
  266.  
  267.     if (link (file, SG_LOCK) == 0) {
  268.         if (stat (file, &sb) != 0)
  269.             return 0;
  270.  
  271.         if (sb.st_nlink != 2)
  272.             return 0;
  273.  
  274.         (void) unlink (file);
  275.         islocked = 1;
  276.         return 1;
  277.     }
  278.     (void) unlink (file);
  279.     return 0;
  280. }
  281.  
  282. /*
  283.  * sgr_unlock - logically unlock a shadow group file
  284.  *
  285.  *    sgr_unlock() removes the lock which was set by an earlier
  286.  *    invocation of sgr_lock().
  287.  */
  288.  
  289. int
  290. sgr_unlock ()
  291. {
  292.     if (isopen) {
  293.         open_modes = O_RDONLY;
  294.         if (! sgr_close ())
  295.             return 0;
  296.     }
  297.     if (islocked) {
  298.         islocked = 0;
  299.         if (lock_pid != getpid ())
  300.             return 0;
  301.  
  302.         (void) unlink (SG_LOCK);
  303.         return 1;
  304.     }
  305.     return 0;
  306. }
  307.  
  308. /*
  309.  * sgr_open - open a shadow group file
  310.  *
  311.  *    sgr_open() encapsulates the open operation.  it returns
  312.  *    TRUE or FALSE depending on the shadow group file being
  313.  *    properly opened.
  314.  */
  315.  
  316. int
  317. sgr_open (mode)
  318. int    mode;
  319. {
  320.     char    buf[8192];
  321.     char    *cp;
  322.     struct    sg_file_entry    *sgrf;
  323.     struct    sgrp    *sgrent;
  324.  
  325.     if (isopen || (mode != O_RDONLY && mode != O_RDWR))
  326.         return 0;
  327.  
  328.     if (mode != O_RDONLY && ! islocked &&
  329.             strcmp (sg_filename, SGROUP) == 0)
  330.         return 0;
  331.  
  332.     if ((sgrfp = fopen (sg_filename, mode == O_RDONLY ? "r":"r+")) == 0)
  333.         return 0;
  334.  
  335.     __sgr_head = sgr_tail = sgr_cursor = 0;
  336.     __sg_changed = 0;
  337.  
  338.     while (fgetsx (buf, sizeof buf, sgrfp) != (char *) 0) {
  339.         if (cp = strrchr (buf, '\n'))
  340.             *cp = '\0';
  341.  
  342.         if (! (sgrf = (struct sg_file_entry *) malloc (sizeof *sgrf)))
  343.             return 0;
  344.  
  345.         sgrf->sgr_changed = 0;
  346.         sgrf->sgr_line = strdup (buf);
  347.         if ((sgrent = sgetsgent (buf)) && ! (sgrent = sgr_dup (sgrent)))
  348.             return 0;
  349.  
  350.         sgrf->sgr_entry = sgrent;
  351.  
  352.         if (__sgr_head == 0) {
  353.             __sgr_head = sgr_tail = sgrf;
  354.             sgrf->sgr_next = 0;
  355.         } else {
  356.             sgr_tail->sgr_next = sgrf;
  357.             sgrf->sgr_next = 0;
  358.             sgr_tail = sgrf;
  359.         }
  360.     }
  361.     isopen++;
  362.     open_modes = mode;
  363.  
  364.     return 1;
  365. }
  366.  
  367. /*
  368.  * sgr_close - close the shadow group file
  369.  *
  370.  *    sgr_close() outputs any modified shadow group file entries and
  371.  *    frees any allocated memory.
  372.  */
  373.  
  374. int
  375. sgr_close ()
  376. {
  377.     char    backup[BUFSIZ];
  378.     int    mask;
  379.     int    c;
  380.     int    errors = 0;
  381.     FILE    *bkfp;
  382.     struct    sg_file_entry *sgrf;
  383.     struct    stat    sb;
  384.  
  385.     if (! isopen) {
  386.         errno = EINVAL;
  387.         return 0;
  388.     }
  389.     if (islocked && lock_pid != getpid ()) {
  390.         isopen = 0;
  391.         islocked = 0;
  392.         errno = EACCES;
  393.         return 0;
  394.     }
  395.     strcpy (backup, sg_filename);
  396.     strcat (backup, "-");
  397.  
  398.     if (open_modes == O_RDWR && __sg_changed) {
  399.         mask = umask (0377);
  400.         (void) unlink (backup);
  401.         if ((bkfp = fopen (backup, "w")) == 0) {
  402.             umask (mask);
  403.             return 0;
  404.         }
  405.         umask (mask);
  406.         (void) chmod (backup, 0400);
  407.         fstat (fileno (sgrfp), &sb);
  408.         chown (backup, sb.st_uid, sb.st_gid);
  409.  
  410.         rewind (sgrfp);
  411.         while ((c = getc (sgrfp)) != EOF) {
  412.             if (putc (c, bkfp) == EOF) {
  413.                 fclose (bkfp);
  414.                 return 0;
  415.             }
  416.         }
  417.         if (fclose (bkfp))
  418.             return 0;
  419.  
  420.         isopen = 0;
  421.         (void) fclose (sgrfp);
  422.  
  423.         mask = umask (0277);
  424.         (void) chmod (sg_filename, 0400);
  425.         if (! (sgrfp = fopen (sg_filename, "w"))) {
  426.             umask (mask);
  427.             return 0;
  428.         }
  429.         umask (mask);
  430.  
  431.         for (sgrf = __sgr_head;! errors && sgrf;sgrf = sgrf->sgr_next) {
  432.             if (sgrf->sgr_changed) {
  433.                 if (putsgent (sgrf->sgr_entry, sgrfp))
  434.                     errors++;
  435.             } else {
  436.                 if (fputsx (sgrf->sgr_line, sgrfp))
  437.                     errors++;
  438.  
  439.                 if (putc ('\n', sgrfp) == EOF)
  440.                     errors++;
  441.             }
  442.         }
  443.         if (fflush (sgrfp))
  444.             errors++;
  445.  
  446.         if (errors) {
  447.             unlink (sg_filename);
  448.             link (backup, sg_filename);
  449.             unlink (backup);
  450.             return 0;
  451.         }
  452.     }
  453.     if (fclose (sgrfp))
  454.         return 0;
  455.  
  456.     sgrfp = 0;
  457.  
  458.     while (__sgr_head != 0) {
  459.         sgrf = __sgr_head;
  460.         __sgr_head = sgrf->sgr_next;
  461.  
  462.         if (sgrf->sgr_entry) {
  463.             sgr_free (sgrf->sgr_entry);
  464.             free (sgrf->sgr_entry);
  465.         }
  466.         if (sgrf->sgr_line)
  467.             free (sgrf->sgr_line);
  468.  
  469.         free (sgrf);
  470.     }
  471.     sgr_tail = 0;
  472.     isopen = 0;
  473.     return 1;
  474. }
  475.  
  476. int
  477. sgr_update (sgrent)
  478. struct    sgrp    *sgrent;
  479. {
  480.     struct    sg_file_entry    *sgrf;
  481.     struct    sgrp    *nsgr;
  482.  
  483.     if (! isopen || open_modes == O_RDONLY) {
  484.         errno = EINVAL;
  485.         return 0;
  486.     }
  487.     for (sgrf = __sgr_head;sgrf != 0;sgrf = sgrf->sgr_next) {
  488.         if (sgrf->sgr_entry == 0)
  489.             continue;
  490.  
  491.         if (strcmp (sgrent->sg_name, sgrf->sgr_entry->sg_name) != 0)
  492.             continue;
  493.  
  494.         if (! (nsgr = sgr_dup (sgrent)))
  495.             return 0;
  496.         else {
  497.             sgr_free (sgrf->sgr_entry);
  498.             *(sgrf->sgr_entry) = *nsgr;
  499.         }
  500.         sgrf->sgr_changed = 1;
  501.         sgr_cursor = sgrf;
  502.         return __sg_changed = 1;
  503.     }
  504.     sgrf = (struct sg_file_entry *) malloc (sizeof *sgrf);
  505.     if (! (sgrf->sgr_entry = sgr_dup (sgrent)))
  506.         return 0;
  507.  
  508.     sgrf->sgr_changed = 1;
  509.     sgrf->sgr_next = 0;
  510.     sgrf->sgr_line = 0;
  511.  
  512.     if (sgr_tail)
  513.         sgr_tail->sgr_next = sgrf;
  514.  
  515.     if (! __sgr_head)
  516.         __sgr_head = sgrf;
  517.  
  518.     sgr_tail = sgrf;
  519.  
  520.     return __sg_changed = 1;
  521. }
  522.  
  523. int
  524. sgr_remove (name)
  525. char    *name;
  526. {
  527.     struct    sg_file_entry    *sgrf;
  528.     struct    sg_file_entry    *osgrf;
  529.  
  530.     if (! isopen || open_modes == O_RDONLY) {
  531.         errno = EINVAL;
  532.         return 0;
  533.     }
  534.     for (osgrf = 0, sgrf = __sgr_head;sgrf != 0;
  535.             osgrf = sgrf, sgrf = sgrf->sgr_next) {
  536.         if (! sgrf->sgr_entry)
  537.             continue;
  538.  
  539.         if (strcmp (name, sgrf->sgr_entry->sg_name) != 0)
  540.             continue;
  541.  
  542.         if (sgrf == sgr_cursor)
  543.             sgr_cursor = osgrf;
  544.  
  545.         if (osgrf != 0)
  546.             osgrf->sgr_next = sgrf->sgr_next;
  547.         else
  548.             __sgr_head = sgrf->sgr_next;
  549.  
  550.         if (sgrf == sgr_tail)
  551.             sgr_tail = osgrf;
  552.  
  553.         return __sg_changed = 1;
  554.     }
  555.     errno = ENOENT;
  556.     return 0;
  557. }
  558.  
  559. struct sgrp *
  560. sgr_locate (name)
  561. char    *name;
  562. {
  563.     struct    sg_file_entry    *sgrf;
  564.  
  565.     if (! isopen) {
  566.         errno = EINVAL;
  567.         return 0;
  568.     }
  569.     for (sgrf = __sgr_head;sgrf != 0;sgrf = sgrf->sgr_next) {
  570.         if (sgrf->sgr_entry == 0)
  571.             continue;
  572.  
  573.         if (strcmp (name, sgrf->sgr_entry->sg_name) == 0) {
  574.             sgr_cursor = sgrf;
  575.             return sgrf->sgr_entry;
  576.         }
  577.     }
  578.     errno = ENOENT;
  579.     return 0;
  580. }
  581.  
  582. int
  583. sgr_rewind ()
  584. {
  585.     if (! isopen) {
  586.         errno = EINVAL;
  587.         return 0;
  588.     }
  589.     sgr_cursor = 0;
  590.     return 1;
  591. }
  592.  
  593. struct sgrp *
  594. sgr_next ()
  595. {
  596.     if (! isopen) {
  597.         errno = EINVAL;
  598.         return 0;
  599.     }
  600.     if (sgr_cursor == 0)
  601.         sgr_cursor = __sgr_head;
  602.     else
  603.         sgr_cursor = sgr_cursor->sgr_next;
  604.  
  605.     while (sgr_cursor) {
  606.         if (sgr_cursor->sgr_entry)
  607.             return sgr_cursor->sgr_entry;
  608.  
  609.         sgr_cursor = sgr_cursor->sgr_next;
  610.     }
  611.     return 0;
  612. }
  613.