Back to index

glibc  2.9
lckpwdf.c
Go to the documentation of this file.
00001 /* Handle locking of password file.
00002    Copyright (C) 1996, 1998, 2000, 2002, 2007 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <fcntl.h>
00022 #include <bits/libc-lock.h>
00023 #include <shadow.h>
00024 #include <signal.h>
00025 #include <string.h>
00026 #include <unistd.h>
00027 #include <sys/file.h>
00028 
00029 #include <kernel-features.h>
00030 
00031 
00032 /* Name of the lock file.  */
00033 #define PWD_LOCKFILE "/etc/.pwd.lock"
00034 
00035 /* How long to wait for getting the lock before returning with an
00036    error.  */
00037 #define TIMEOUT 15 /* sec */
00038 
00039 
00040 /* File descriptor for lock file.  */
00041 static int lock_fd = -1;
00042 
00043 /* Prevent problems in multithreaded program by using mutex.  */
00044 __libc_lock_define_initialized (static, lock)
00045 
00046 
00047 /* Prototypes for local functions.  */
00048 static void noop_handler (int __sig);
00049 
00050 
00051 /* We cannot simply return in error cases.  We have to close the file
00052    and perhaps restore the signal handler.  */
00053 #define RETURN_CLOSE_FD(code)                                               \
00054   do {                                                               \
00055     if ((code) < 0 && lock_fd >= 0)                                         \
00056       {                                                                     \
00057        __close (lock_fd);                                            \
00058        lock_fd = -1;                                                 \
00059       }                                                                     \
00060     __libc_lock_unlock (lock);                                              \
00061     return (code);                                                   \
00062   } while (0)
00063 
00064 #define RETURN_RESTORE_HANDLER(code)                                        \
00065   do {                                                               \
00066     /* Restore old action handler for alarm.  We don't need to know         \
00067        about the current one.  */                                    \
00068     __sigaction (SIGALRM, &saved_act, NULL);                                \
00069     RETURN_CLOSE_FD (code);                                          \
00070   } while (0)
00071 
00072 #define RETURN_CLEAR_ALARM(code)                                     \
00073   do {                                                               \
00074     /* Clear alarm.  */                                                     \
00075     alarm (0);                                                              \
00076     /* Restore old set of handled signals.  We don't need to know           \
00077        about the current one.*/                                             \
00078     __sigprocmask (SIG_SETMASK, &saved_set, NULL);                          \
00079     RETURN_RESTORE_HANDLER (code);                                   \
00080   } while (0)
00081 
00082 
00083 int
00084 __lckpwdf (void)
00085 {
00086   int flags;
00087   sigset_t saved_set;                     /* Saved set of caught signals.  */
00088   struct sigaction saved_act;             /* Saved signal action.  */
00089   sigset_t new_set;                /* New set of caught signals.  */
00090   struct sigaction new_act;        /* New signal action.  */
00091   struct flock fl;                 /* Information struct for locking.  */
00092   int result;
00093 
00094   if (lock_fd != -1)
00095     /* Still locked by own process.  */
00096     return -1;
00097 
00098   /* Prevent problems caused by multiple threads.  */
00099   __libc_lock_lock (lock);
00100 
00101   int oflags = O_WRONLY | O_CREAT;
00102 #ifdef O_CLOEXEC
00103   oflags |= O_CLOEXEC;
00104 #endif
00105   lock_fd = __open (PWD_LOCKFILE, oflags, 0600);
00106   if (lock_fd == -1)
00107     /* Cannot create lock file.  */
00108     RETURN_CLOSE_FD (-1);
00109 
00110 #ifndef __ASSUME_O_CLOEXEC
00111 # ifdef O_CLOEXEC
00112   if (__have_o_cloexec <= 0)
00113 # endif
00114     {
00115       /* Make sure file gets correctly closed when process finished.  */
00116       flags = __fcntl (lock_fd, F_GETFD, 0);
00117       if (flags == -1)
00118        /* Cannot get file flags.  */
00119        RETURN_CLOSE_FD (-1);
00120 # ifdef O_CLOEXEC
00121       if (__have_o_cloexec == 0)
00122        __have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1;
00123       if (__have_o_cloexec < 0)
00124 # endif
00125        {
00126          flags |= FD_CLOEXEC;             /* Close on exit.  */
00127          if (__fcntl (lock_fd, F_SETFD, flags) < 0)
00128            /* Cannot set new flags.  */
00129            RETURN_CLOSE_FD (-1);
00130        }
00131     }
00132 #endif
00133 
00134   /* Now we have to get exclusive write access.  Since multiple
00135      process could try this we won't stop when it first fails.
00136      Instead we set a timeout for the system call.  Once the timer
00137      expires it is likely that there are some problems which cannot be
00138      resolved by waiting.
00139 
00140      It is important that we don't change the signal state.  We must
00141      restore the old signal behaviour.  */
00142   memset (&new_act, '\0', sizeof (struct sigaction));
00143   new_act.sa_handler = noop_handler;
00144   __sigfillset (&new_act.sa_mask);
00145   new_act.sa_flags = 0ul;
00146 
00147   /* Install new action handler for alarm and save old.  */
00148   if (__sigaction (SIGALRM, &new_act, &saved_act) < 0)
00149     /* Cannot install signal handler.  */
00150     RETURN_CLOSE_FD (-1);
00151 
00152   /* Now make sure the alarm signal is not blocked.  */
00153   __sigemptyset (&new_set);
00154   __sigaddset (&new_set, SIGALRM);
00155   if (__sigprocmask (SIG_UNBLOCK, &new_set, &saved_set) < 0)
00156     RETURN_RESTORE_HANDLER (-1);
00157 
00158   /* Start timer.  If we cannot get the lock in the specified time we
00159      get a signal.  */
00160   alarm (TIMEOUT);
00161 
00162   /* Try to get the lock.  */
00163   memset (&fl, '\0', sizeof (struct flock));
00164   fl.l_type = F_WRLCK;
00165   fl.l_whence = SEEK_SET;
00166   result = __fcntl (lock_fd, F_SETLKW, &fl);
00167 
00168   RETURN_CLEAR_ALARM (result);
00169 }
00170 weak_alias (__lckpwdf, lckpwdf)
00171 
00172 
00173 int
00174 __ulckpwdf (void)
00175 {
00176   int result;
00177 
00178   if (lock_fd == -1)
00179     /* There is no lock set.  */
00180     result = -1;
00181   else
00182     {
00183       /* Prevent problems caused by multiple threads.  */
00184       __libc_lock_lock (lock);
00185 
00186       result = __close (lock_fd);
00187 
00188       /* Mark descriptor as unused.  */
00189       lock_fd = -1;
00190 
00191       /* Clear mutex.  */
00192       __libc_lock_unlock (lock);
00193     }
00194 
00195   return result;
00196 }
00197 weak_alias (__ulckpwdf, ulckpwdf)
00198 
00199 
00200 static void
00201 noop_handler (int sig)
00202 {
00203   /* We simply return which makes the `fcntl' call return with an error.  */
00204 }