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