123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- /*
- * This is a hack, but until libc and glibc both include this function
- * by default (libc only includes it if nys is not being used, at the
- * moment, and glibc doesn't appear to have it at all) we need to have
- * it here, too. :-(
- *
- * This should not become an official part of PAM.
- *
- * BEGIN_HACK
- */
- /*
- * lckpwdf.c -- prevent simultaneous updates of password files
- *
- * Before modifying any of the password files, call lckpwdf(). It may block
- * for up to 15 seconds trying to get the lock. Return value is 0 on success
- * or -1 on failure. When you are done, call ulckpwdf() to release the lock.
- * The lock is also released automatically when the process exits. Only one
- * process at a time may hold the lock.
- *
- * These functions are supposed to be conformant with AT&T SVID Issue 3.
- *
- * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
- * public domain.
- */
- #include <fcntl.h>
- #include <signal.h>
- #ifdef WITH_SELINUX
- #include <selinux/selinux.h>
- #endif
- #define LOCKFILE "/etc/.pwd.lock"
- #define TIMEOUT 15
- static int lockfd = -1;
- static int set_close_on_exec(int fd)
- {
- int flags = fcntl(fd, F_GETFD, 0);
- if (flags == -1)
- return -1;
- flags |= FD_CLOEXEC;
- return fcntl(fd, F_SETFD, flags);
- }
- static int do_lock(int fd)
- {
- struct flock fl;
- memset(&fl, 0, sizeof fl);
- fl.l_type = F_WRLCK;
- fl.l_whence = SEEK_SET;
- return fcntl(fd, F_SETLKW, &fl);
- }
- static void alarm_catch(int sig)
- {
- /* does nothing, but fcntl F_SETLKW will fail with EINTR */
- }
- static int lckpwdf(void)
- {
- struct sigaction act, oldact;
- sigset_t set, oldset;
- if (lockfd != -1)
- return -1;
- #ifdef WITH_SELINUX
- if(is_selinux_enabled()>0)
- {
- lockfd = open(LOCKFILE, O_WRONLY);
- if(lockfd == -1 && errno == ENOENT)
- {
- char *create_context_raw;
- int rc;
- if(getfilecon_raw("/etc/passwd", &create_context_raw))
- return -1;
- rc = setfscreatecon_raw(create_context_raw);
- freecon(create_context_raw);
- if(rc)
- return -1;
- lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
- if(setfscreatecon_raw(NULL))
- return -1;
- }
- }
- else
- #endif
- lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
- if (lockfd == -1)
- return -1;
- if (set_close_on_exec(lockfd) == -1)
- goto cleanup_fd;
- memset(&act, 0, sizeof act);
- act.sa_handler = alarm_catch;
- act.sa_flags = 0;
- sigfillset(&act.sa_mask);
- if (sigaction(SIGALRM, &act, &oldact) == -1)
- goto cleanup_fd;
- sigemptyset(&set);
- sigaddset(&set, SIGALRM);
- if (sigprocmask(SIG_UNBLOCK, &set, &oldset) == -1)
- goto cleanup_sig;
- alarm(TIMEOUT);
- if (do_lock(lockfd) == -1)
- goto cleanup_alarm;
- alarm(0);
- sigprocmask(SIG_SETMASK, &oldset, NULL);
- sigaction(SIGALRM, &oldact, NULL);
- return 0;
- cleanup_alarm:
- alarm(0);
- sigprocmask(SIG_SETMASK, &oldset, NULL);
- cleanup_sig:
- sigaction(SIGALRM, &oldact, NULL);
- cleanup_fd:
- close(lockfd);
- lockfd = -1;
- return -1;
- }
- static int ulckpwdf(void)
- {
- unlink(LOCKFILE);
- if (lockfd == -1)
- return -1;
- if (close(lockfd) == -1) {
- lockfd = -1;
- return -1;
- }
- lockfd = -1;
- return 0;
- }
- /* END_HACK */
|