2 * This is a hack, but until libc and glibc both include this function
3 * by default (libc only includes it if nys is not being used, at the
4 * moment, and glibc doesn't appear to have it at all) we need to have
7 * This should not become an official part of PAM.
13 * lckpwdf.c -- prevent simultaneous updates of password files
15 * Before modifying any of the password files, call lckpwdf(). It may block
16 * for up to 15 seconds trying to get the lock. Return value is 0 on success
17 * or -1 on failure. When you are done, call ulckpwdf() to release the lock.
18 * The lock is also released automatically when the process exits. Only one
19 * process at a time may hold the lock.
21 * These functions are supposed to be conformant with AT&T SVID Issue 3.
23 * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
30 #define LOCKFILE "/etc/.pwd.lock"
33 static int lockfd = -1;
35 static int set_close_on_exec(int fd)
37 int flags = fcntl(fd, F_GETFD, 0);
41 return fcntl(fd, F_SETFD, flags);
44 static int do_lock(int fd)
48 memset(&fl, 0, sizeof fl);
50 fl.l_whence = SEEK_SET;
51 return fcntl(fd, F_SETLKW, &fl);
54 static void alarm_catch(int sig)
56 /* does nothing, but fcntl F_SETLKW will fail with EINTR */
59 static int lckpwdf(void)
61 struct sigaction act, oldact;
67 lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
70 if (set_close_on_exec(lockfd) == -1)
73 memset(&act, 0, sizeof act);
74 act.sa_handler = alarm_catch;
76 sigfillset(&act.sa_mask);
77 if (sigaction(SIGALRM, &act, &oldact) == -1)
81 sigaddset(&set, SIGALRM);
82 if (sigprocmask(SIG_UNBLOCK, &set, &oldset) == -1)
86 if (do_lock(lockfd) == -1)
89 sigprocmask(SIG_SETMASK, &oldset, NULL);
90 sigaction(SIGALRM, &oldact, NULL);
95 sigprocmask(SIG_SETMASK, &oldset, NULL);
97 sigaction(SIGALRM, &oldact, NULL);
104 static int ulckpwdf(void)
110 if (close(lockfd) == -1) {