131 lines
2.8 KiB
Text
131 lines
2.8 KiB
Text
/*
|
|
* 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 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 | O_CLOEXEC);
|
|
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 | O_CLOEXEC, 0600);
|
|
if(setfscreatecon_raw(NULL))
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
lockfd = open(LOCKFILE, O_CREAT | O_WRONLY | O_CLOEXEC, 0600);
|
|
if (lockfd == -1)
|
|
return -1;
|
|
|
|
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 */
|