pam/pam-0.99.8.1-sepermit-kill-user.patch
Tomáš Mráz b6b1e29706 - test for setkeycreatecon correctly
- add exclusive login mode of operation to pam_selinux_permit (original
    patch by Dan Walsh)
2008-01-28 17:59:35 +00:00

319 lines
9.7 KiB
Diff

diff -up Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.c.kill-user Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.c
--- Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.c.kill-user 2008-01-28 18:34:18.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.c 2008-01-28 18:34:18.000000000 +0100
@@ -1,7 +1,7 @@
/******************************************************************************
* A module for Linux-PAM that allows/denies acces based on SELinux state.
*
- * Copyright (c) 2007 Red Hat, Inc.
+ * Copyright (c) 2007, 2008 Red Hat, Inc.
* Written by Tomas Mraz <tmraz@redhat.com>
*
* Redistribution and use in source and binary forms, with or without
@@ -46,6 +46,14 @@
#include <string.h>
#include <syslog.h>
#include <ctype.h>
+#include <signal.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <dirent.h>
#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
@@ -57,6 +65,165 @@
#include <selinux/selinux.h>
+#define MODULE "pam_selinux_permit"
+#define OPT_DELIM ":"
+
+struct lockfd {
+ uid_t uid;
+ int fd;
+ int debug;
+};
+
+#define PROC_BASE "/proc"
+#define MAX_NAMES (int)(sizeof(unsigned long)*8)
+
+static int
+match_process_uid(pid_t pid, uid_t uid)
+{
+ char buf[128];
+ uid_t puid;
+ FILE *f;
+ int re = 0;
+
+ snprintf (buf, sizeof buf, PROC_BASE "/%d/status", pid);
+ if (!(f = fopen (buf, "r")))
+ return 0;
+
+ while (fgets(buf, sizeof buf, f)) {
+ if (sscanf (buf, "Uid:\t%d", &puid)) {
+ re = uid == puid;
+ break;
+ }
+ }
+ fclose(f);
+ return re;
+}
+
+static int
+check_running (pam_handle_t *pamh, uid_t uid, int killall, int debug)
+{
+ DIR *dir;
+ struct dirent *de;
+ pid_t *pid_table, pid, self;
+ int i;
+ int pids, max_pids;
+ int running = 0;
+ self = getpid();
+ if (!(dir = opendir(PROC_BASE))) {
+ pam_syslog(pamh, LOG_ERR, "Failed to open proc directory file %s:", PROC_BASE);
+ return -1;
+ }
+ max_pids = 256;
+ pid_table = malloc(max_pids * sizeof (pid_t));
+ if (!pid_table) {
+ pam_syslog(pamh, LOG_CRIT, "Memory allocation error");
+ return -1;
+ }
+ pids = 0;
+ while ((de = readdir (dir)) != NULL) {
+ if (!(pid = (pid_t)atoi(de->d_name)) || pid == self)
+ continue;
+
+ if (pids == max_pids) {
+ if (!(pid_table = realloc(pid_table, 2*pids*sizeof(pid_t)))) {
+ pam_syslog(pamh, LOG_CRIT, "Memory allocation error");
+ return -1;
+ }
+ max_pids *= 2;
+ }
+ pid_table[pids++] = pid;
+ }
+
+ (void)closedir(dir);
+
+ for (i = 0; i < pids; i++) {
+ pid_t id;
+
+ if (match_process_uid(pid_table[i], uid) == 0)
+ continue;
+ id = pid_table[i];
+
+ if (killall) {
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "Attempting to kill %d", id);
+ kill(id, SIGKILL);
+ }
+ running++;
+ }
+
+ free(pid_table);
+ return running;
+}
+
+static void
+sepermit_unlock(pam_handle_t *pamh, void *plockfd, int error_status UNUSED)
+{
+ struct lockfd *lockfd = plockfd;
+ struct flock fl;
+
+ memset(&fl, 0, sizeof(fl));
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+
+ if (lockfd->debug)
+ pam_syslog(pamh, LOG_ERR, "Unlocking fd: %d uid: %d", lockfd->fd, lockfd->uid);
+
+ /* Don't kill uid==0 */
+ if (lockfd->uid)
+ /* This is a DOS but it prevents an app from forking to prevent killing */
+ while(check_running(pamh, lockfd->uid, 1, lockfd->debug) > 0)
+ continue;
+
+ fcntl(lockfd->fd, F_SETLK, &fl);
+ close(lockfd->fd);
+ free(lockfd);
+}
+
+static int
+sepermit_lock(pam_handle_t *pamh, const char *user, int debug)
+{
+ char buf[PATH_MAX];
+ struct flock fl;
+
+ memset(&fl, 0, sizeof(fl));
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+
+ struct passwd *pw = pam_modutil_getpwnam( pamh, user );
+ if (!pw) {
+ pam_syslog(pamh, LOG_ERR, "Unable to find uid for user %s", user);
+ return -1;
+ }
+ if (check_running(pamh, pw->pw_uid, 0, debug) > 0) {
+ pam_syslog(pamh, LOG_ERR, "User %s processes are running. Exclusive login not allowed", user);
+ return -1;
+ }
+
+ snprintf(buf, sizeof(buf), "%s/%d.lock", SEPERMIT_LOCKDIR, pw->pw_uid);
+ int fd = open(buf, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ pam_syslog(pamh, LOG_ERR, "Unable to open lock file %s/%d.lock", SEPERMIT_LOCKDIR, pw->pw_uid);
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETLK, &fl) == -1) {
+ pam_syslog(pamh, LOG_ERR, "User %s with exclusive login already logged in", user);
+ close(fd);
+ return -1;
+ }
+ struct lockfd *lockfd=calloc(1, sizeof(struct lockfd));
+ if (!lockfd) {
+ close(fd);
+ pam_syslog(pamh, LOG_CRIT, "Memory allocation error");
+ return -1;
+ }
+ lockfd->uid = pw->pw_uid;
+ lockfd->debug = debug;
+ lockfd->fd=fd;
+ pam_set_data(pamh, "pam_selinux_permit", lockfd, sepermit_unlock);
+ return 0;
+}
+
/* return 0 when matched, -1 when unmatched, pam error otherwise */
static int
sepermit_match(pam_handle_t *pamh, const char *cfgfile, const char *user,
@@ -67,6 +234,7 @@ sepermit_match(pam_handle_t *pamh, const
char *start;
size_t len = 0;
int matched = 0;
+ int exclusive = 0;
f = fopen(cfgfile, "r");
@@ -77,6 +245,8 @@ sepermit_match(pam_handle_t *pamh, const
while (!matched && getline(&line, &len, f) != -1) {
size_t n;
+ char *sptr;
+ char *opt;
if (line[0] == '#')
continue;
@@ -92,6 +262,7 @@ sepermit_match(pam_handle_t *pamh, const
continue;
start[n] = '\0';
+ start = strtok_r(start, OPT_DELIM, &sptr);
switch (start[0]) {
case '@':
@@ -117,11 +288,22 @@ sepermit_match(pam_handle_t *pamh, const
matched = 1;
}
}
+ if (matched)
+ while ((opt=strtok_r(NULL, OPT_DELIM, &sptr)) != NULL) {
+ if (strcmp(opt, "exclusive") == 0)
+ exclusive = 1;
+ else if (debug) {
+ pam_syslog(pamh, LOG_NOTICE, "Unknown user option: %s", opt);
+ }
+ }
}
free(line);
fclose(f);
- return matched ? 0 : -1;
+ if (matched)
+ return exclusive ? sepermit_lock(pamh, user, debug) : 0;
+ else
+ return -1;
}
PAM_EXTERN int
diff -up Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.8.xml.kill-user Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.8.xml
--- Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.8.xml.kill-user 2008-01-28 18:34:18.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.8.xml 2008-01-28 18:34:18.000000000 +0100
@@ -30,8 +30,8 @@
<refsect1 id="pam_selinux_permit-description">
<title>DESCRIPTION</title>
<para>
- The pam_selinux module allows or denies login depending on SELinux enforcement
- state.
+ The pam_selinux_permit module allows or denies login depending on SELinux
+ enforcement state.
</para>
<para>
When the user which is logging in matches an entry in the config file
@@ -41,14 +41,21 @@
</para>
<para>
The config file contains a simple list of user names one per line. If the
- <replaceable>name</replaceable> is prefixed with @ character it means that all
+ <replaceable>name</replaceable> is prefixed with <emphasis>@</emphasis> character it means that all
users in the group <replaceable>name</replaceable> match. If it is prefixed
- with a % character the SELinux user is used to match against the <replaceable>name</replaceable>
+ with a <emphasis>%</emphasis> character the SELinux user is used to match against the <replaceable>name</replaceable>
instead of the account name. Note that when SELinux is disabled the
SELinux user assigned to the account cannot be determined. This means that
such entries are never matched when SELinux is disabled and pam_selinux_permit
will return PAM_IGNORE.
</para>
+ <para>
+ Each user name in the configuration file can have optional arguments separated
+ by <emphasis>:</emphasis> character. The only currently recognized argument is <emphasis>exclusive</emphasis>.
+ The pam_selinux_permit module will allow only single concurrent user session for
+ the user with this argument specified and it will attempt to kill all processes
+ of the user after logout.
+ </para>
</refsect1>
<refsect1 id="pam_selinux_permit-options">
diff -up Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am.kill-user Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am
--- Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am.kill-user 2008-01-28 18:34:18.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am 2008-01-28 18:35:01.000000000 +0100
@@ -16,10 +16,13 @@ XMLS = README.xml pam_selinux.8.xml pam_
securelibdir = $(SECUREDIR)
secureconfdir = $(SCONFIGDIR)
+sepermitlockdir = /var/run/sepermit
AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
-I$(top_srcdir)/libpam_misc/include \
- -D SEPERMIT_CONF_FILE=\"$(SCONFIGDIR)/sepermit.conf\"
+ -D SEPERMIT_CONF_FILE=\"$(SCONFIGDIR)/sepermit.conf\" \
+ -D SEPERMIT_LOCKDIR=\"$(sepermitlockdir)\"
+
AM_LDFLAGS = -no-undefined \
-L$(top_builddir)/libpam -lpam @LIBSELINUX@
@@ -34,6 +37,7 @@ endif
pam_selinux_permit_la_LDFLAGS= $(pam_selinux_la_LDFLAGS)
secureconf_DATA = sepermit.conf
+sepermitlock_DATA =
if HAVE_LIBSELINUX
securelib_LTLIBRARIES = pam_selinux.la pam_selinux_permit.la
diff -up Linux-PAM-0.99.8.1/modules/pam_selinux/sepermit.conf.kill-user Linux-PAM-0.99.8.1/modules/pam_selinux/sepermit.conf
--- Linux-PAM-0.99.8.1/modules/pam_selinux/sepermit.conf.kill-user 2008-01-28 18:34:18.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_selinux/sepermit.conf 2008-01-28 18:34:18.000000000 +0100
@@ -4,3 +4,8 @@
# - an user name
# - a group name, with @group syntax
# - a SELinux user name, with %seuser syntax
+# Each line can contain optional arguments separated by :
+# The possible arguments are:
+# - exclusive - only single login session will
+# be allowed for the user and the user's processes
+# will be killed on logout