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 #include <selinux/selinux.h>
33 #define LOCKFILE "/etc/.pwd.lock"
36 static int lockfd = -1;
38 static int set_close_on_exec(int fd)
40 int flags = fcntl(fd, F_GETFD, 0);
44 return fcntl(fd, F_SETFD, flags);
47 static int do_lock(int fd)
51 memset(&fl, 0, sizeof fl);
53 fl.l_whence = SEEK_SET;
54 return fcntl(fd, F_SETLKW, &fl);
57 static void alarm_catch(int sig)
59 /* does nothing, but fcntl F_SETLKW will fail with EINTR */
62 static int lckpwdf(void)
64 struct sigaction act, oldact;
71 if(is_selinux_enabled()>0)
73 lockfd = open(LOCKFILE, O_WRONLY);
74 if(lockfd == -1 && errno == ENOENT)
76 security_context_t create_context;
79 if(getfilecon("/etc/passwd", &create_context))
81 rc = setfscreatecon(create_context);
82 freecon(create_context);
85 lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
86 if(setfscreatecon(NULL))
92 lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
95 if (set_close_on_exec(lockfd) == -1)
98 memset(&act, 0, sizeof act);
99 act.sa_handler = alarm_catch;
101 sigfillset(&act.sa_mask);
102 if (sigaction(SIGALRM, &act, &oldact) == -1)
106 sigaddset(&set, SIGALRM);
107 if (sigprocmask(SIG_UNBLOCK, &set, &oldset) == -1)
111 if (do_lock(lockfd) == -1)
114 sigprocmask(SIG_SETMASK, &oldset, NULL);
115 sigaction(SIGALRM, &oldact, NULL);
120 sigprocmask(SIG_SETMASK, &oldset, NULL);
122 sigaction(SIGALRM, &oldact, NULL);
129 static int ulckpwdf(void)
135 if (close(lockfd) == -1) {