diff --git a/pam-0.99.8.1-sepermit-kill-user.patch b/pam-0.99.8.1-sepermit-kill-user.patch new file mode 100644 index 0000000..b33d81a --- /dev/null +++ b/pam-0.99.8.1-sepermit-kill-user.patch @@ -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 + * + * Redistribution and use in source and binary forms, with or without +@@ -46,6 +46,14 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + + #define PAM_SM_AUTH + #define PAM_SM_ACCOUNT +@@ -57,6 +65,165 @@ + + #include + ++#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 @@ + + DESCRIPTION + +- 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. + + + When the user which is logging in matches an entry in the config file +@@ -41,14 +41,21 @@ + + + The config file contains a simple list of user names one per line. If the +- name is prefixed with @ character it means that all ++ name is prefixed with @ character it means that all + users in the group name match. If it is prefixed +- with a % character the SELinux user is used to match against the name ++ with a % character the SELinux user is used to match against the name + 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. + ++ ++ Each user name in the configuration file can have optional arguments separated ++ by : character. The only currently recognized argument is exclusive. ++ 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. ++ + + + +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 diff --git a/pam-0.99.8.1-setkeycreatecon.patch b/pam-0.99.8.1-setkeycreatecon.patch new file mode 100644 index 0000000..a9bedff --- /dev/null +++ b/pam-0.99.8.1-setkeycreatecon.patch @@ -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]) diff --git a/pam.spec b/pam.spec index b8f8962..c9240bc 100644 --- a/pam.spec +++ b/pam.spec @@ -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 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 0.99.8.1-16 - add auditing to pam_access, pam_limits, and pam_time - moved sanity testing code to check script