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