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