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