home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2082 / shadowio.c < prev   
Encoding:
C/C++ Source or Header  |  1990-12-28  |  9.6 KB  |  521 lines

  1. /*
  2.  * Copyright 1990, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Use, duplication, and disclosure prohibited without
  6.  * the express written permission of the author.
  7.  *
  8.  *    This file implements a transaction oriented password database
  9.  *    library.  The password file is updated one entry at a time.
  10.  *    After each transaction the file must be logically closed and
  11.  *    transferred to the existing password file.  The sequence of
  12.  *    events is
  13.  *
  14.  *    spw_lock            -- lock shadow file
  15.  *    spw_open            -- logically open shadow file
  16.  *    while transaction to process
  17.  *        spw_(locate,update,remove) -- perform transaction
  18.  *    done
  19.  *    spw_close            -- commit transactions
  20.  *    spw_unlock            -- remove shadow lock
  21.  */
  22.  
  23. #ifndef    lint
  24. static    char    sccsid[] = "@(#)shadowio.c    3.1 00:51:22 11/14/90";
  25. #endif
  26.  
  27. #include <sys/stat.h>
  28. #include <fcntl.h>
  29. #include <errno.h>
  30. #include <stdio.h>
  31. #include "shadow.h"
  32.  
  33. static    int    islocked;
  34. static    int    isopen;
  35. static    int    open_modes;
  36. static    FILE    *spwfp;
  37.  
  38. struct    spw_file_entry {
  39.     char    *spwf_line;
  40.     int    spwf_changed;
  41.     struct    spwd    *spwf_entry;
  42.     struct    spw_file_entry *spwf_next;
  43. };
  44.  
  45. static    struct    spw_file_entry    *spwf_head;
  46. static    struct    spw_file_entry    *spwf_tail;
  47. static    struct    spw_file_entry    *spwf_cursor;
  48. static    int    sp_changed;
  49.  
  50. #define    SPW_LOCK    "/etc/shadow.lock"
  51. #define    SPW_TEMP    "/etc/spwd.%d"
  52. #define    SHADOW        "/etc/shadow"
  53. #define    OSHADOW        "/etc/shadow-"
  54.  
  55. extern    char    *strdup();
  56. extern    struct    spwd    *sgetspent();
  57.  
  58. /*
  59.  * spw_dup - duplicate a shadow file entry
  60.  *
  61.  *    spw_dup() accepts a pointer to a shadow file entry and
  62.  *    returns a pointer to a shadow file entry in allocated
  63.  *    memory.
  64.  */
  65.  
  66. static struct spwd *
  67. spw_dup (spwd)
  68. struct    spwd    *spwd;
  69. {
  70.     struct    spwd    *spw;
  71.  
  72.     if (! (spw = (struct spwd *) malloc (sizeof *spw)))
  73.         return 0;
  74.  
  75.     *spw = *spwd;
  76.     if ((spw->sp_namp = strdup (spwd->sp_namp)) == 0 ||
  77.             (spw->sp_pwdp = strdup (spwd->sp_pwdp)) == 0)
  78.         return 0;
  79.  
  80.     return spw;
  81. }
  82.  
  83. /*
  84.  * spw_free - free a dynamically allocated shadow file entry
  85.  *
  86.  *    spw_free() frees up the memory which was allocated for the
  87.  *    pointed to entry.
  88.  */
  89.  
  90. static void
  91. spw_free (spwd)
  92. struct    spwd    *spwd;
  93. {
  94.     free (spwd->sp_namp);
  95.     free (spwd->sp_pwdp);
  96. }
  97.  
  98. /*
  99.  * spw_lock - lock a password file
  100.  *
  101.  *    spw_lock() encapsulates the lock operation.  it returns
  102.  *    TRUE or FALSE depending on the password file being
  103.  *    properly locked.  the lock is set by creating a semaphore
  104.  *    file, SPW_LOCK.
  105.  */
  106.  
  107. int
  108. spw_lock ()
  109. {
  110.     int    fd;
  111.     int    pid;
  112.     int    len;
  113.     char    file[BUFSIZ];
  114.     char    buf[32];
  115.     struct    stat    sb;
  116.  
  117.     if (islocked)
  118.         return 1;
  119.  
  120.     /*
  121.      * Create a lock file which can be switched into place
  122.      */
  123.  
  124.     sprintf (file, SPW_TEMP, getpid ());
  125.     if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
  126.         return 0;
  127.  
  128.     sprintf (buf, "%d", getpid ());
  129.     if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
  130.         (void) close (fd);
  131.         (void) unlink (file);
  132.         return 0;
  133.     }
  134.     close (fd);
  135.  
  136.     /*
  137.      * Simple case first -
  138.      *    Link fails (in a sane environment ...) if the target
  139.      *    exists already.  So we try to switch in a new lock
  140.      *    file.  If that succeeds, we assume we have the only
  141.      *    valid lock.  Needs work for NFS where this assumption
  142.      *    may not hold.  The simple hack is to check the link
  143.      *    count on the source file, which should be 2 iff the
  144.      *    link =really= worked.
  145.      */
  146.  
  147.     if (link (file, SPW_LOCK) == 0) {
  148.         if (stat (file, &sb) != 0)
  149.             return 0;
  150.  
  151.         if (sb.st_nlink != 2)
  152.             return 0;
  153.  
  154.         (void) unlink (file);
  155.         islocked = 1;
  156.         return 1;
  157.     }
  158.  
  159.     /*
  160.      * Invalid lock test -
  161.      *    Open the lock file and see if the lock is valid.
  162.      *    The PID of the lock file is checked, and if the PID
  163.      *    is not valid, the lock file is removed.  If the unlink
  164.      *    of the lock file fails, it should mean that someone
  165.      *    else is executing this code.  They will get success,
  166.      *    and we will fail.
  167.      */
  168.  
  169.     if ((fd = open (SPW_LOCK, O_RDWR)) == -1 ||
  170.             (len = read (fd, buf, BUFSIZ)) <= 0) {
  171.         errno = EINVAL;
  172.         return 0;
  173.     }
  174.     buf[len] = '\0';
  175.     if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  176.         errno = EINVAL;
  177.         return 0;
  178.     }
  179.     if (kill (pid, 0) == 0)  {
  180.         errno = EEXIST;
  181.         return 0;
  182.     }
  183.     if (unlink (SPW_LOCK)) {
  184.         (void) close (fd);
  185.         (void) unlink (file);
  186.  
  187.         return 0;
  188.     }
  189.  
  190.     /*
  191.      * Re-try lock -
  192.      *    The invalid lock has now been removed and I should
  193.      *    be able to acquire a lock for myself just fine.  If
  194.      *    this fails there will be no retry.  The link count
  195.      *    test here makes certain someone executing the previous
  196.      *    block of code didn't just remove the lock we just
  197.      *    linked to.
  198.      */
  199.  
  200.     if (link (file, SPW_LOCK) == 0) {
  201.         if (stat (file, &sb) != 0)
  202.             return 0;
  203.  
  204.         if (sb.st_nlink != 2)
  205.             return 0;
  206.  
  207.         (void) unlink (file);
  208.         islocked = 1;
  209.         return 1;
  210.     }
  211.     (void) unlink (file);
  212.     return 0;
  213. }
  214.  
  215. /*
  216.  * spw_unlock - logically unlock a shadow file
  217.  *
  218.  *    spw_unlock() removes the lock which was set by an earlier
  219.  *    invocation of spw_lock().
  220.  */
  221.  
  222. int
  223. spw_unlock ()
  224. {
  225.     if (islocked) {
  226.         if (isopen) {
  227.             open_modes = O_RDONLY;
  228.             (void) spw_close ();
  229.         }
  230.         unlink (SPW_LOCK);
  231.         islocked = 0;
  232.         return 1;
  233.     } else
  234.         return 0;
  235. }
  236.  
  237. /*
  238.  * spw_open - open a password file
  239.  *
  240.  *    spw_open() encapsulates the open operation.  it returns
  241.  *    TRUE or FALSE depending on the shadow file being
  242.  *    properly opened.
  243.  */
  244.  
  245. int
  246. spw_open (mode)
  247. int    mode;
  248. {
  249.     char    buf[8192];
  250.     struct    spw_file_entry    *spwf;
  251.     struct    spwd    *spwd;
  252.  
  253.     if (isopen || (mode != O_RDONLY && mode != O_RDWR))
  254.         return 0;
  255.  
  256.     if (mode != O_RDONLY && ! islocked)
  257.         return 0;
  258.  
  259.     if ((spwfp = fopen (SHADOW, mode == O_RDONLY ? "r":"r+")) == 0)
  260.         return 0;
  261.  
  262.     spwf_head = spwf_tail = spwf_cursor = 0;
  263.     sp_changed = 0;
  264.  
  265.     while (fgets (buf, sizeof buf, spwfp) != (char *) 0) {
  266.         if (! (spwf = (struct spw_file_entry *) malloc (sizeof *spwf)))
  267.             return 0;
  268.  
  269.         spwf->spwf_changed = 0;
  270.         spwf->spwf_line = strdup (buf);
  271.         if ((spwd = sgetspent (buf)) && ! (spwd = spw_dup (spwd)))
  272.             return 0;
  273.  
  274.         spwf->spwf_entry = spwd;
  275.  
  276.         if (spwf_head == 0) {
  277.             spwf_head = spwf_tail = spwf;
  278.             spwf->spwf_next = 0;
  279.         } else {
  280.             spwf_tail->spwf_next = spwf;
  281.             spwf->spwf_next = 0;
  282.             spwf_tail = spwf;
  283.         }
  284.     }
  285.     isopen++;
  286.     open_modes = mode;
  287.  
  288.     return 1;
  289. }
  290.  
  291. /*
  292.  * spw_close - close the password file
  293.  *
  294.  *    spw_close() outputs any modified password file entries and
  295.  *    frees any allocated memory.
  296.  */
  297.  
  298. int
  299. spw_close ()
  300. {
  301.     int    fd;
  302.     int    mask;
  303.     int    c;
  304.     int    i;
  305.     int    errors = 0;
  306.     FILE    *bkfp;
  307.     struct    spw_file_entry *spwf;
  308.     struct    spw_file_entry *ospwf;
  309.  
  310.     if (! isopen) {
  311.         errno = EINVAL;
  312.         return 0;
  313.     }
  314.     if (open_modes == O_RDWR && sp_changed) {
  315.         mask = umask (077);
  316.         if ((bkfp = fopen (OSHADOW, "w")) == 0) {
  317.             umask (mask);
  318.             return 0;
  319.         }
  320.         umask (mask);
  321.  
  322.         rewind (spwfp);
  323.         while ((c = getc (spwfp)) != EOF) {
  324.             if (putc (c, bkfp) == EOF) {
  325.                 fclose (bkfp);
  326.                 return 0;
  327.             }
  328.         }
  329.         if (fclose (bkfp))
  330.             return 0;
  331.  
  332.         isopen = 0;
  333.         (void) fclose (spwfp);
  334.  
  335.         mask = umask (077);
  336.         if (! (spwfp = fopen (SHADOW, "w"))) {
  337.             umask (mask);
  338.             return 0;
  339.         }
  340.         umask (mask);
  341.  
  342.         for (spwf = spwf_head;errors == 0 && spwf;
  343.                         spwf = spwf->spwf_next) {
  344.             if (spwf->spwf_changed) {
  345.                 if (putspent (spwf->spwf_entry, spwfp))
  346.                     errors++;
  347.             } else {
  348.                 if (fputs (spwf->spwf_line, spwfp) == EOF)
  349.                     errors++;
  350.             }
  351.         }
  352.         if (fflush (spwfp))
  353.             errors++;
  354.  
  355.         if (errors) {
  356.             unlink (SHADOW);
  357.             link (OSHADOW, SHADOW);
  358.             unlink (OSHADOW);
  359.             return 0;
  360.         }
  361.     }
  362.     if (fclose (spwfp))
  363.         return 0;
  364.  
  365.     spwfp = 0;
  366.  
  367.     while (spwf_head != 0) {
  368.         spwf = spwf_head;
  369.         spwf_head = spwf->spwf_next;
  370.  
  371.         if (spwf->spwf_entry) {
  372.             spw_free (spwf->spwf_entry);
  373.             free (spwf->spwf_entry);
  374.         }
  375.         if (spwf->spwf_line)
  376.             free (spwf->spwf_line);
  377.  
  378.         free (spwf);
  379.     }
  380.     spwf_tail = 0;
  381.     return 1;
  382. }
  383.  
  384. int
  385. spw_update (spwd)
  386. struct    spwd    *spwd;
  387. {
  388.     struct    spw_file_entry    *spwf;
  389.     struct    spwd    *nspwd;
  390.  
  391.     if (! isopen || open_modes == O_RDONLY) {
  392.         errno = EINVAL;
  393.         return 0;
  394.     }
  395.     for (spwf = spwf_head;spwf != 0;spwf = spwf->spwf_next) {
  396.         if (spwf->spwf_entry == 0)
  397.             continue;
  398.  
  399.         if (strcmp (spwd->sp_namp, spwf->spwf_entry->sp_namp) != 0)
  400.             continue;
  401.  
  402.         if (! (nspwd = spw_dup (spwd)))
  403.             return 0;
  404.         else {
  405.             spw_free (spwf->spwf_entry);
  406.             *(spwf->spwf_entry) = *nspwd;
  407.         }
  408.         spwf->spwf_changed = 1;
  409.         spwf_cursor = spwf;
  410.         return sp_changed = 1;
  411.     }
  412.     spwf = (struct spw_file_entry *) malloc (sizeof *spwf);
  413.     if (! (spwf->spwf_entry = spw_dup (spwd)))
  414.         return 0;
  415.  
  416.     spwf->spwf_changed = 1;
  417.     spwf->spwf_next = 0;
  418.     spwf->spwf_line = 0;
  419.  
  420.     if (spwf_tail)
  421.         spwf_tail->spwf_next = spwf;
  422.  
  423.     if (! spwf_head)
  424.         spwf_head = spwf;
  425.  
  426.     spwf_tail = spwf;
  427.  
  428.     return sp_changed = 1;
  429. }
  430.  
  431. int
  432. spw_remove (name)
  433. char    *name;
  434. {
  435.     struct    spw_file_entry    *spwf;
  436.     struct    spw_file_entry    *ospwf;
  437.  
  438.     if (! isopen || open_modes == O_RDONLY) {
  439.         errno = EINVAL;
  440.         return 0;
  441.     }
  442.     for (ospwf = 0, spwf = spwf_head;spwf != 0;
  443.             ospwf = spwf, spwf = spwf->spwf_next) {
  444.         if (! spwf->spwf_entry)
  445.             continue;
  446.  
  447.         if (strcmp (name, spwf->spwf_entry->sp_namp) != 0)
  448.             continue;
  449.  
  450.         if (spwf == spwf_cursor)
  451.             spwf_cursor = ospwf;
  452.  
  453.         if (ospwf != 0)
  454.             ospwf->spwf_next = spwf->spwf_next;
  455.         else
  456.             spwf_head = spwf->spwf_next;
  457.  
  458.         if (spwf == spwf_tail)
  459.             spwf_tail = ospwf;
  460.  
  461.         return sp_changed = 1;
  462.     }
  463.     errno = ENOENT;
  464.     return 0;
  465. }
  466.  
  467. struct spwd *
  468. spw_locate (name)
  469. char    *name;
  470. {
  471.     struct    spw_file_entry    *spwf;
  472.  
  473.     if (! isopen) {
  474.         errno = EINVAL;
  475.         return 0;
  476.     }
  477.     for (spwf = spwf_head;spwf != 0;spwf = spwf->spwf_next) {
  478.         if (spwf->spwf_entry == 0)
  479.             continue;
  480.  
  481.         if (strcmp (name, spwf->spwf_entry->sp_namp) == 0) {
  482.             spwf_cursor = spwf;
  483.             return spwf->spwf_entry;
  484.         }
  485.     }
  486.     errno = ENOENT;
  487.     return 0;
  488. }
  489.  
  490. int
  491. spw_rewind ()
  492. {
  493.     if (! isopen) {
  494.         errno = EINVAL;
  495.         return 0;
  496.     }
  497.     spwf_cursor = 0;
  498.     return 1;
  499. }
  500.  
  501. struct spwd *
  502. spw_next ()
  503. {
  504.     if (! isopen) {
  505.         errno = EINVAL;
  506.         return 0;
  507.     }
  508.     if (spwf_cursor == 0)
  509.         spwf_cursor = spwf_head;
  510.     else
  511.         spwf_cursor = spwf_cursor->spwf_next;
  512.  
  513.     while (spwf_cursor) {
  514.         if (spwf_cursor->spwf_entry)
  515.             return spwf_cursor->spwf_entry;
  516.  
  517.         spwf_cursor = spwf_cursor->spwf_next;
  518.     }
  519.     return 0;
  520. }
  521.