(__lckpwdf): Use O_CLOEXEC if possible.
[kopensolaris-gnu/glibc.git] / shadow / lckpwdf.c
1 /* Handle locking of password file.
2    Copyright (C) 1996, 1998, 2000, 2002, 2007 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <fcntl.h>
22 #include <bits/libc-lock.h>
23 #include <shadow.h>
24 #include <signal.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/file.h>
28
29 #include <kernel-features.h>
30
31
32 /* Name of the lock file.  */
33 #define PWD_LOCKFILE "/etc/.pwd.lock"
34
35 /* How long to wait for getting the lock before returning with an
36    error.  */
37 #define TIMEOUT 15 /* sec */
38
39
40 /* File descriptor for lock file.  */
41 static int lock_fd = -1;
42
43 /* Prevent problems in multithreaded program by using mutex.  */
44 __libc_lock_define_initialized (static, lock)
45
46
47 /* Prototypes for local functions.  */
48 static void noop_handler (int __sig);
49
50
51 /* We cannot simply return in error cases.  We have to close the file
52    and perhaps restore the signal handler.  */
53 #define RETURN_CLOSE_FD(code)                                                 \
54   do {                                                                        \
55     if ((code) < 0 && lock_fd >= 0)                                           \
56       {                                                                       \
57         __close (lock_fd);                                                    \
58         lock_fd = -1;                                                         \
59       }                                                                       \
60     __libc_lock_unlock (lock);                                                \
61     return (code);                                                            \
62   } while (0)
63
64 #define RETURN_RESTORE_HANDLER(code)                                          \
65   do {                                                                        \
66     /* Restore old action handler for alarm.  We don't need to know           \
67        about the current one.  */                                             \
68     __sigaction (SIGALRM, &saved_act, NULL);                                  \
69     RETURN_CLOSE_FD (code);                                                   \
70   } while (0)
71
72 #define RETURN_CLEAR_ALARM(code)                                              \
73   do {                                                                        \
74     /* Clear alarm.  */                                                       \
75     alarm (0);                                                                \
76     /* Restore old set of handled signals.  We don't need to know             \
77        about the current one.*/                                               \
78     __sigprocmask (SIG_SETMASK, &saved_set, NULL);                            \
79     RETURN_RESTORE_HANDLER (code);                                            \
80   } while (0)
81
82
83 int
84 __lckpwdf (void)
85 {
86   int flags;
87   sigset_t saved_set;                   /* Saved set of caught signals.  */
88   struct sigaction saved_act;           /* Saved signal action.  */
89   sigset_t new_set;                     /* New set of caught signals.  */
90   struct sigaction new_act;             /* New signal action.  */
91   struct flock fl;                      /* Information struct for locking.  */
92   int result;
93
94   if (lock_fd != -1)
95     /* Still locked by own process.  */
96     return -1;
97
98   /* Prevent problems caused by multiple threads.  */
99   __libc_lock_lock (lock);
100
101   int oflags = O_WRONLY | O_CREAT;
102 #ifdef O_CLOEXEC
103   oflags |= O_CLOEXEC;
104 #endif
105   lock_fd = __open (PWD_LOCKFILE, oflags, 0600);
106   if (lock_fd == -1)
107     /* Cannot create lock file.  */
108     RETURN_CLOSE_FD (-1);
109
110 #ifndef __ASSUME_O_CLOEXEC
111 # ifdef O_CLOEXEC
112   if (__have_o_cloexec <= 0)
113 # endif
114     {
115       /* Make sure file gets correctly closed when process finished.  */
116       flags = __fcntl (lock_fd, F_GETFD, 0);
117       if (flags == -1)
118         /* Cannot get file flags.  */
119         RETURN_CLOSE_FD (-1);
120 # ifdef O_CLOEXEC
121       if (__have_o_cloexec == 0)
122         __have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1;
123       if (__have_o_cloexec < 0)
124 # endif
125         {
126           flags |= FD_CLOEXEC;          /* Close on exit.  */
127           if (__fcntl (lock_fd, F_SETFD, flags) < 0)
128             /* Cannot set new flags.  */
129             RETURN_CLOSE_FD (-1);
130         }
131     }
132 #endif
133
134   /* Now we have to get exclusive write access.  Since multiple
135      process could try this we won't stop when it first fails.
136      Instead we set a timeout for the system call.  Once the timer
137      expires it is likely that there are some problems which cannot be
138      resolved by waiting.
139
140      It is important that we don't change the signal state.  We must
141      restore the old signal behaviour.  */
142   memset (&new_act, '\0', sizeof (struct sigaction));
143   new_act.sa_handler = noop_handler;
144   __sigfillset (&new_act.sa_mask);
145   new_act.sa_flags = 0ul;
146
147   /* Install new action handler for alarm and save old.  */
148   if (__sigaction (SIGALRM, &new_act, &saved_act) < 0)
149     /* Cannot install signal handler.  */
150     RETURN_CLOSE_FD (-1);
151
152   /* Now make sure the alarm signal is not blocked.  */
153   __sigemptyset (&new_set);
154   __sigaddset (&new_set, SIGALRM);
155   if (__sigprocmask (SIG_UNBLOCK, &new_set, &saved_set) < 0)
156     RETURN_RESTORE_HANDLER (-1);
157
158   /* Start timer.  If we cannot get the lock in the specified time we
159      get a signal.  */
160   alarm (TIMEOUT);
161
162   /* Try to get the lock.  */
163   memset (&fl, '\0', sizeof (struct flock));
164   fl.l_type = F_WRLCK;
165   fl.l_whence = SEEK_SET;
166   result = __fcntl (lock_fd, F_SETLKW, &fl);
167
168   RETURN_CLEAR_ALARM (result);
169 }
170 weak_alias (__lckpwdf, lckpwdf)
171
172
173 int
174 __ulckpwdf (void)
175 {
176   int result;
177
178   if (lock_fd == -1)
179     /* There is no lock set.  */
180     result = -1;
181   else
182     {
183       /* Prevent problems caused by multiple threads.  */
184       __libc_lock_lock (lock);
185
186       result = __close (lock_fd);
187
188       /* Mark descriptor as unused.  */
189       lock_fd = -1;
190
191       /* Clear mutex.  */
192       __libc_lock_unlock (lock);
193     }
194
195   return result;
196 }
197 weak_alias (__ulckpwdf, ulckpwdf)
198
199
200 static void
201 noop_handler (int sig)
202 {
203   /* We simply return which makes the `fcntl' call return with an error.  */
204 }