- test for setkeycreatecon correctly

- add exclusive login mode of operation to pam_selinux_permit (original
    patch by Dan Walsh)
This commit is contained in:
Tomáš Mráz 2008-01-28 17:59:35 +00:00
parent de90b38383
commit b6b1e29706
3 changed files with 360 additions and 1 deletions

View File

@ -0,0 +1,318 @@
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

View File

@ -0,0 +1,31 @@
diff -up Linux-PAM-0.99.8.1/configure.in.setkeycreatecon Linux-PAM-0.99.8.1/configure.in
--- Linux-PAM-0.99.8.1/configure.in.setkeycreatecon 2008-01-28 17:22:40.000000000 +0100
+++ Linux-PAM-0.99.8.1/configure.in 2008-01-28 17:26:25.000000000 +0100
@@ -379,6 +379,7 @@ AC_SUBST(LIBDB)
AM_CONDITIONAL([HAVE_LIBDB], [test ! -z "$LIBDB"])
AC_CHECK_LIB([nsl],[yp_get_default_domain], LIBNSL="-lnsl", LIBNSL="")
+BACKUP_LIBS=$LIBS
LIBS="$LIBS $LIBNSL"
AC_CHECK_FUNCS(yp_get_default_domain)
LIBS=$BACKUP_LIBS
@@ -396,6 +397,10 @@ AC_SUBST(LIBSELINUX)
AM_CONDITIONAL([HAVE_LIBSELINUX], [test ! -z "$LIBSELINUX"])
if test ! -z "$LIBSELINUX" ; then
AC_DEFINE([WITH_SELINUX], 1, [Defined if SE Linux support is compiled in])
+ BACKUP_LIBS=$LIBS
+ LIBS="$LIBS $LIBSELINUX"
+ AC_CHECK_FUNCS(setkeycreatecon)
+ LIBS=$BACKUP_LIBS
fi
dnl Checks for header files.
@@ -428,7 +433,7 @@ AC_CHECK_FUNCS(fseeko gethostname gettim
AC_CHECK_FUNCS(strcspn strdup strspn strstr strtol uname)
AC_CHECK_FUNCS(getpwnam_r getpwuid_r getgrnam_r getgrgid_r getspnam_r)
AC_CHECK_FUNCS(getgrouplist getline getdelim)
-AC_CHECK_FUNCS(inet_ntop inet_pton ruserok_af setkeycreatecon)
+AC_CHECK_FUNCS(inet_ntop inet_pton ruserok_af)
AC_CHECK_FUNCS(unshare, [UNSHARE=yes], [UNSHARE=no])
AM_CONDITIONAL([HAVE_UNSHARE], [test "$UNSHARE" = yes])

View File

@ -11,7 +11,7 @@
Summary: A security tool which provides authentication for applications
Name: pam
Version: 0.99.8.1
Release: 16%{?dist}
Release: 17%{?dist}
# The library is BSD licensed with option to relicense as GPLv2+ - this option is redundant
# as the BSD license allows that anyway. pam_timestamp and pam_console modules are GPLv2+,
# pam_rhosts_auth module is BSD with advertising
@ -47,6 +47,8 @@ Patch48: pam-0.99.8.1-substack.patch
Patch49: pam-0.99.8.1-tty-audit.patch
Patch50: pam-0.99.8.1-tty-audit2.patch
Patch51: pam-0.99.8.1-audit-failed.patch
Patch52: pam-0.99.8.1-setkeycreatecon.patch
Patch53: pam-0.99.8.1-sepermit-kill-user.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Requires: cracklib, cracklib-dicts >= 2.8
@ -119,6 +121,8 @@ popd
%patch49 -p1 -b .tty-audit
%patch50 -p1 -b .tty-audit2
%patch51 -p1 -b .audit-failed
%patch52 -p1 -b .setkeycreatecon
%patch53 -p1 -b .kill-user
autoreconf
@ -352,6 +356,7 @@ fi
%dir %{_sysconfdir}/security/console.perms.d
%config %{_sysconfdir}/security/console.perms.d/50-default.perms
%dir /var/run/console
%dir /var/run/sepermit
%ghost %verify(not md5 size mtime) /var/log/faillog
%ghost %verify(not md5 size mtime) /var/log/tallylog
%{_mandir}/man5/*
@ -368,6 +373,11 @@ fi
%doc doc/adg/*.txt doc/adg/html
%changelog
* Mon Jan 28 2008 Tomas Mraz <tmraz@redhat.com> 0.99.8.1-17
- test for setkeycreatecon correctly
- add exclusive login mode of operation to pam_selinux_permit (original
patch by Dan Walsh)
* Tue Jan 22 2008 Tomas Mraz <tmraz@redhat.com> 0.99.8.1-16
- add auditing to pam_access, pam_limits, and pam_time
- moved sanity testing code to check script