- new upstream release

- add default soft limit for nproc of 1024 to prevent accidental fork bombs
    (#432903)
This commit is contained in:
Tomáš Mráz 2008-02-15 17:27:28 +00:00
parent 717cfde74b
commit 0533865ad8
20 changed files with 28 additions and 7730 deletions

View File

@ -1,5 +1,5 @@
*.src.rpm *.src.rpm
*.tar.bz2 *.tar.bz2
pam-redhat-0.99.8-1.tar.bz2 pam-redhat-0.99.8-1.tar.bz2
Linux-PAM-0.99.8.1.tar.bz2
db-4.6.19.tar.gz db-4.6.19.tar.gz
Linux-PAM-0.99.10.0.tar.bz2

5
90-nproc.conf Normal file
View File

@ -0,0 +1,5 @@
# Default limit for number of user's processes to prevent
# accidental fork bombs.
# See rhbz #432903 for reasoning.
* soft nproc 1024

View File

@ -2,7 +2,7 @@
Version: GnuPG v1.4.7 (GNU/Linux) Version: GnuPG v1.4.7 (GNU/Linux)
Comment: See http://www.kernel.org/signature.html for info Comment: See http://www.kernel.org/signature.html for info
iD8DBQBGneVeyGugalF9Dw4RAkclAJ4lTnGnONrVg01e1Zk5K2tfFZxhQACeITvP iD8DBQBHtBCvyGugalF9Dw4RAkscAKCAir9EhJ5VxjIog6Vs+N6Sr27n6ACcD0Iy
P+lEUXjXsjLVoZ1EOJn7Lts= ycgdOs9Ea8z8pqgPZMmocyY=
=Q5X1 =djTw
-----END PGP SIGNATURE----- -----END PGP SIGNATURE-----

View File

@ -1,8 +0,0 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: See http://www.kernel.org/signature.html for info
iD8DBQBFtgDAyGugalF9Dw4RArOyAJ0duc7/WqnlX1+LfjYsUOQsJhICOgCfdWDb
aMzAtzhCqvu+IxJTFwXx/kk=
=I+NT
-----END PGP SIGNATURE-----

View File

@ -1,47 +0,0 @@
diff -up Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.init.homedir Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.init
--- Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.init.homedir 2007-09-19 19:37:26.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.init 2007-09-21 14:13:52.000000000 +0200
@@ -1,26 +1,24 @@
#!/bin/sh -p
-# This is only a boilerplate for the instance initialization script.
# It receives polydir path as $1, the instance path as $2,
# a flag whether the instance dir was newly created (0 - no, 1 - yes) in $3,
# and user name in $4.
#
-# If you intend to polyinstantiate /tmp and you also want to use the X windows
-# environment, you will have to use this script to bind mount the socket that
-# is used by the X server to communicate with its clients. X server places
-# this socket in /tmp/.X11-unix directory, which will get obscured by
-# polyinstantiation. Uncommenting the following lines will bind mount
-# the relevant directory at an alternative location (/.tmp/.X11-unix) such
-# that the X server, window manager and X clients, can still find the
-# socket X0 at the polyinstanted /tmp/.X11-unix.
-#
-#if [ $1 = /tmp ]; then
-# if [ ! -f /.tmp/.X11-unix ]; then
-# mkdir -p /.tmp/.X11-unix
-# fi
-# mount --bind /tmp/.X11-unix /.tmp/.X11-unix
-# cp -fp -- /tmp/.X0-lock "$2/.X0-lock"
-# mkdir -- "$2/.X11-unix"
-# ln -fs -- /.tmp/.X11-unix/X0 "$2/.X11-unix/X0"
-#fi
+# The following section will copy the contents of /etc/skel if this is a
+# newly created home directory.
+if [ "$3" = 1 ]; then
+ # This line will fix the labeling on all newly created directories
+ [ -x /sbin/restorecon ] && /sbin/restorecon "$1"
+ user="$4"
+ passwd=$(getent passwd "$user")
+ homedir=$(echo "$passwd" | cut -f6 -d":")
+ if [ "$1" = "$homedir" ]; then
+ gid=$(echo "$passwd" | cut -f4 -d":")
+ cp -rT /etc/skel "$homedir"
+ chown -R "$user":"$gid" "$homedir"
+ mode=$(awk '/^UMASK/{gsub("#.*$", "", $2); printf "%o", and(0777,compl(strtonum("0" $2))); exit}' /etc/login.defs)
+ chmod ${mode:-700} "$homedir"
+ [ -x /sbin/restorecon ] && /sbin/restorecon -R "$homedir"
+ fi
+fi
exit 0

View File

@ -1,465 +0,0 @@
diff -up Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.conf.5.xml.temp-logon Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.conf.5.xml
--- Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.conf.5.xml.temp-logon 2007-06-18 12:46:47.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.conf.5.xml 2007-08-06 13:16:56.000000000 +0200
@@ -72,10 +72,13 @@
<para>
The third field, <replaceable>method</replaceable>, is the method
- used for polyinstantiation. It can take 3 different values; "user"
+ used for polyinstantiation. It can take these values; "user"
for polyinstantiation based on user name, "level" for
- polyinstantiation based on process MLS level and user name, and "context" for
- polyinstantiation based on process security context and user name
+ polyinstantiation based on process MLS level and user name, "context" for
+ polyinstantiation based on process security context and user name,
+ "tmpfs" for mounting tmpfs filesystem as an instance dir, and
+ "tmpdir" for creating temporary directory as an instance dir which is
+ removed when the user's session is closed.
Methods "context" and "level" are only available with SELinux. This
field cannot be blank.
</para>
@@ -84,7 +87,8 @@
The fourth field, <replaceable>list_of_uids</replaceable>, is
a comma separated list of user names for whom the polyinstantiation
is not performed. If left blank, polyinstantiation will be performed
- for all users.
+ for all users. If the list is preceded with a single "~" character,
+ polyinstantiation is performed only for users in the list.
</para>
<para>
diff -up Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.h.temp-logon Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.h
--- Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.h.temp-logon 2007-06-18 12:46:47.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.h 2007-08-06 11:41:46.000000000 +0200
@@ -90,6 +90,7 @@
#define PAMNS_NO_UNMOUNT_ON_CLOSE 0x00010000 /* no unmount at session close */
#define NAMESPACE_MAX_DIR_LEN 80
+#define NAMESPACE_POLYDIR_DATA "pam_namespace:polydir_data"
/*
* Polyinstantiation method options, based on user, security context
@@ -100,6 +101,8 @@ enum polymethod {
USER,
CONTEXT,
LEVEL,
+ TMPDIR,
+ TMPFS
};
/*
@@ -128,6 +131,7 @@ struct polydir_s {
enum polymethod method; /* method used to polyinstantiate */
unsigned int num_uids; /* number of override uids */
uid_t *uid; /* list of override uids */
+ int exclusive; /* polyinstatiate exclusively for override uids */
struct polydir_s *next; /* pointer to the next polydir entry */
};
diff -up Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c.temp-logon Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c
--- Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c.temp-logon 2007-06-18 12:46:47.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c 2007-08-06 11:41:46.000000000 +0200
@@ -43,6 +43,7 @@ static int copy_ent(const struct polydir
strcpy(pent->instance_prefix, ent->instance_prefix);
pent->method = ent->method;
pent->num_uids = ent->num_uids;
+ pent->exclusive = ent->exclusive;
if (ent->num_uids) {
uid_t *pptr, *eptr;
@@ -120,6 +121,10 @@ static void del_polydir_list(struct poly
}
}
+static void cleanup_data(pam_handle_t *pamh, void *data, int err)
+{
+ del_polydir_list(data);
+}
/*
* Called from parse_config_file, this function processes a single line
@@ -140,6 +145,7 @@ static int process_line(char *line, cons
poly.uid = NULL;
poly.num_uids = 0;
+ poly.exclusive = 0;
/*
* skip the leading white space
@@ -223,24 +229,13 @@ static int process_line(char *line, cons
}
/*
- * Ensure that all pathnames are absolute path names.
- */
- if ((dir[0] != '/') || (instance_prefix[0] != '/')) {
- pam_syslog(idata->pamh, LOG_NOTICE,"Pathnames must start with '/'");
- goto skipping;
- }
- if (strstr(dir, "..") || strstr(instance_prefix, "..")) {
- pam_syslog(idata->pamh, LOG_NOTICE,"Pathnames must not contain '..'");
- goto skipping;
- }
-
- /*
* Populate polyinstantiated directory structure with appropriate
* pathnames and the method with which to polyinstantiate.
*/
if (strlen(dir) >= sizeof(poly.dir)
|| strlen(instance_prefix) >= sizeof(poly.instance_prefix)) {
pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long");
+ goto skipping;
}
strcpy(poly.dir, dir);
strcpy(poly.instance_prefix, instance_prefix);
@@ -248,6 +243,18 @@ static int process_line(char *line, cons
poly.method = NONE;
if (strcmp(method, "user") == 0)
poly.method = USER;
+
+ if (strcmp(method, "tmpdir") == 0) {
+ poly.method = TMPDIR;
+ if (sizeof(poly.instance_prefix) - strlen(poly.instance_prefix) < 7) {
+ pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long");
+ goto skipping;
+ }
+ strcat(poly.instance_prefix, "XXXXXX");
+ }
+
+ if (strcmp(method, "tmpfs") == 0)
+ poly.method = TMPFS;
#ifdef WITH_SELINUX
if (strcmp(method, "level") == 0) {
@@ -266,12 +273,24 @@ static int process_line(char *line, cons
#endif
- if ( poly.method == NONE) {
+ if (poly.method == NONE) {
pam_syslog(idata->pamh, LOG_NOTICE, "Illegal method");
goto skipping;
}
/*
+ * Ensure that all pathnames are absolute path names.
+ */
+ if ((dir[0] != '/') || (poly.method != TMPFS && instance_prefix[0] != '/')) {
+ pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames must start with '/'");
+ goto skipping;
+ }
+ if (strstr(dir, "..") || strstr(instance_prefix, "..")) {
+ pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames must not contain '..'");
+ goto skipping;
+ }
+
+ /*
* If the line in namespace.conf for a directory to polyinstantiate
* contains a list of override users (users for whom polyinstantiation
* is not performed), read the user ids, convert names into uids, and
@@ -281,7 +300,11 @@ static int process_line(char *line, cons
uid_t *uidptr;
const char *ustr, *sstr;
int count, i;
-
+
+ if (*uids == '~') {
+ poly.exclusive = 1;
+ uids++;
+ }
for (count = 0, ustr = sstr = uids; sstr; ustr = sstr + 1, count++)
sstr = strchr(ustr, ',');
@@ -419,6 +442,7 @@ static int parse_config_file(struct inst
* directory's list of override uids. If the uid is one of the override
* uids for the polyinstantiated directory, polyinstantiation is not
* performed for that user for that directory.
+ * If exclusive is set the returned values are opposite.
*/
static int ns_override(struct polydir_s *polyptr, struct instance_data *idata,
uid_t uid)
@@ -432,11 +456,11 @@ static int ns_override(struct polydir_s
for (i = 0; i < polyptr->num_uids; i++) {
if (uid == polyptr->uid[i]) {
- return 1;
+ return !polyptr->exclusive;
}
}
- return 0;
+ return polyptr->exclusive;
}
/*
@@ -622,6 +646,12 @@ static int poly_name(const struct polydi
#endif /* WITH_SELINUX */
+ case TMPDIR:
+ case TMPFS:
+ if ((*i_name=strdup("")) == NULL)
+ goto fail;
+ return PAM_SUCCESS;
+
default:
if (idata->flags & PAMNS_DEBUG)
pam_syslog(idata->pamh, LOG_ERR, "Unknown method");
@@ -725,7 +755,7 @@ static int check_inst_parent(char *ipath
* execute it and pass directory to polyinstantiate and instance
* directory as arguments.
*/
-static int inst_init(const struct polydir_s *polyptr, char *ipath,
+static int inst_init(const struct polydir_s *polyptr, const char *ipath,
struct instance_data *idata)
{
pid_t rc, pid;
@@ -791,11 +821,11 @@ out:
* Create polyinstantiated instance directory (ipath).
*/
#ifdef WITH_SELINUX
-static int create_dirs(const struct polydir_s *polyptr, char *ipath,
+static int create_dirs(struct polydir_s *polyptr, char *ipath,
security_context_t icontext, security_context_t ocontext,
struct instance_data *idata)
#else
-static int create_dirs(const struct polydir_s *polyptr, char *ipath,
+static int create_dirs(struct polydir_s *polyptr, char *ipath,
struct instance_data *idata)
#endif
{
@@ -834,7 +864,17 @@ static int create_dirs(const struct poly
* attributes to match that of the original directory that is being
* polyinstantiated.
*/
- if (mkdir(ipath, S_IRUSR) < 0) {
+
+ if (polyptr->method == TMPDIR) {
+ if (mkdtemp(polyptr->instance_prefix) == NULL) {
+ pam_syslog(idata->pamh, LOG_ERR, "Error creating temporary instance %s, %m",
+ polyptr->instance_prefix);
+ polyptr->method = NONE; /* do not clean up! */
+ return PAM_SESSION_ERR;
+ }
+ /* copy the actual directory name to ipath */
+ strcpy(ipath, polyptr->instance_prefix);
+ } else if (mkdir(ipath, S_IRUSR) < 0) {
if (errno == EEXIST)
goto inst_init;
else {
@@ -920,13 +960,12 @@ inst_init:
* security attributes, and performs bind mount to setup the process
* namespace.
*/
-static int ns_setup(const struct polydir_s *polyptr,
+static int ns_setup(struct polydir_s *polyptr,
struct instance_data *idata)
{
int retval = 0;
char *inst_dir = NULL;
char *instname = NULL;
- char *dir;
#ifdef WITH_SELINUX
security_context_t instcontext = NULL, origcontext = NULL;
#endif
@@ -935,9 +974,15 @@ static int ns_setup(const struct polydir
pam_syslog(idata->pamh, LOG_DEBUG,
"Set namespace for directory %s", polyptr->dir);
- dir = strrchr(polyptr->dir, '/');
- if (dir && strlen(dir) > 1)
- dir++;
+ if (polyptr->method == TMPFS) {
+ if (mount("tmpfs", polyptr->dir, "tmpfs", 0, NULL) < 0) {
+ pam_syslog(idata->pamh, LOG_ERR, "Error mounting tmpfs on %s, %m",
+ polyptr->dir);
+ return PAM_SESSION_ERR;
+ }
+ /* we must call inst_init after the mount in this case */
+ return inst_init(polyptr, "tmpfs", idata);
+ }
/*
* Obtain the name of instance pathname based on the
@@ -1043,6 +1088,58 @@ static int cwd_in(char *dir, struct inst
return retval;
}
+static int cleanup_tmpdirs(struct instance_data *idata)
+{
+ struct polydir_s *pptr;
+ pid_t rc, pid;
+ sighandler_t osighand = NULL;
+ int status;
+
+ osighand = signal(SIGCHLD, SIG_DFL);
+ if (osighand == SIG_ERR) {
+ pam_syslog(idata->pamh, LOG_ERR, "Cannot set signal value");
+ rc = PAM_SESSION_ERR;
+ goto out;
+ }
+
+ for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) {
+ if (pptr->method == TMPDIR && access(pptr->instance_prefix, F_OK) == 0) {
+ pid = fork();
+ if (pid == 0) {
+#ifdef WITH_SELINUX
+ if (idata->flags & PAMNS_SELINUX_ENABLED) {
+ if (setexeccon(NULL) < 0)
+ exit(1);
+ }
+#endif
+ if (execl("/bin/rm", "/bin/rm", "-rf", pptr->instance_prefix, (char *)NULL) < 0)
+ exit(1);
+ } else if (pid > 0) {
+ while (((rc = waitpid(pid, &status, 0)) == (pid_t)-1) &&
+ (errno == EINTR));
+ if (rc == (pid_t)-1) {
+ pam_syslog(idata->pamh, LOG_ERR, "waitpid failed- %m");
+ rc = PAM_SESSION_ERR;
+ goto out;
+ }
+ if (!WIFEXITED(status) || WIFSIGNALED(status) > 0) {
+ pam_syslog(idata->pamh, LOG_ERR,
+ "Error removing %s", pptr->instance_prefix);
+ }
+ } else if (pid < 0) {
+ pam_syslog(idata->pamh, LOG_ERR,
+ "Cannot fork to run namespace init script, %m");
+ rc = PAM_SESSION_ERR;
+ goto out;
+ }
+ }
+ }
+
+ rc = PAM_SUCCESS;
+out:
+ signal(SIGCHLD, osighand);
+ return rc;
+}
/*
* This function checks to see if polyinstantiation is needed for any
@@ -1111,13 +1208,22 @@ static int setup_namespace(struct instan
* disassociate from the parent namespace.
*/
if (need_poly) {
+ if (pam_set_data(idata->pamh, NAMESPACE_POLYDIR_DATA, idata->polydirs_ptr,
+ cleanup_data) != PAM_SUCCESS) {
+ pam_syslog(idata->pamh, LOG_ERR,
+ "Unable to set namespace data");
+ return PAM_SYSTEM_ERR;
+ }
if (unshare(CLONE_NEWNS) < 0) {
- pam_syslog(idata->pamh, LOG_ERR,
+ pam_set_data(idata->pamh, NAMESPACE_POLYDIR_DATA, NULL, NULL);
+ pam_syslog(idata->pamh, LOG_ERR,
"Unable to unshare from parent namespace, %m");
return PAM_SESSION_ERR;
}
- } else
+ } else {
+ del_polydir_list(idata->polydirs_ptr);
return PAM_SUCCESS;
+ }
/*
* Again cycle through all polyinstantiated directories, this time,
@@ -1144,7 +1250,8 @@ static int setup_namespace(struct instan
* umount
*/
if ((changing_dir = cwd_in(pptr->dir, idata)) < 0) {
- return PAM_SESSION_ERR;
+ retval = PAM_SESSION_ERR;
+ goto out;
} else if (changing_dir) {
if (idata->flags & PAMNS_DEBUG)
pam_syslog(idata->pamh, LOG_DEBUG, "changing cwd");
@@ -1172,8 +1279,10 @@ static int setup_namespace(struct instan
int saved_errno = errno;
pam_syslog(idata->pamh, LOG_ERR, "Unmount of %s failed, %m",
pptr->dir);
- if (saved_errno != EINVAL)
- return PAM_SESSION_ERR;
+ if (saved_errno != EINVAL) {
+ retval = PAM_SESSION_ERR;
+ goto out;
+ }
} else if (idata->flags & PAMNS_DEBUG)
pam_syslog(idata->pamh, LOG_DEBUG, "Umount succeeded %s",
pptr->dir);
@@ -1185,7 +1294,9 @@ static int setup_namespace(struct instan
break;
}
}
-
+out:
+ if (retval != PAM_SUCCESS)
+ cleanup_tmpdirs(idata);
return retval;
}
@@ -1224,8 +1335,10 @@ static int orig_namespace(struct instanc
} else if (idata->flags & PAMNS_DEBUG)
pam_syslog(idata->pamh, LOG_DEBUG, "Unmount of %s succeeded",
pptr->dir);
- }
+ }
}
+
+ cleanup_tmpdirs(idata);
return 0;
}
@@ -1350,7 +1463,8 @@ PAM_EXTERN int pam_sm_open_session(pam_h
} else if (idata.flags & PAMNS_DEBUG)
pam_syslog(idata.pamh, LOG_DEBUG, "Nothing to polyinstantiate");
- del_polydir_list(idata.polydirs_ptr);
+ if (retval != PAM_SUCCESS)
+ del_polydir_list(idata.polydirs_ptr);
return retval;
}
@@ -1365,6 +1479,7 @@ PAM_EXTERN int pam_sm_close_session(pam_
struct instance_data idata;
char *user_name;
struct passwd *pwd;
+ const void *polyptr;
/* init instance data */
idata.flags = 0;
@@ -1428,16 +1543,12 @@ PAM_EXTERN int pam_sm_close_session(pam_
strncat(idata.user, user_name, sizeof(idata.user) - 1);
idata.uid = pwd->pw_uid;
- /*
- * Parse namespace configuration file which lists directories that
- * are polyinstantiated, directories where instance directories are
- * created and the method used for polyinstantiation.
- */
- retval = parse_config_file(&idata);
- if ((retval != PAM_SUCCESS) || !idata.polydirs_ptr) {
- del_polydir_list(idata.polydirs_ptr);
- return PAM_SESSION_ERR;
- }
+ retval = pam_get_data(idata.pamh, NAMESPACE_POLYDIR_DATA, &polyptr);
+ if (retval != PAM_SUCCESS || polyptr == NULL)
+ /* nothing to reset */
+ return PAM_SUCCESS;
+
+ idata.polydirs_ptr = polyptr;
if (idata.flags & PAMNS_DEBUG)
pam_syslog(idata.pamh, LOG_DEBUG, "Resetting namespace for pid %d",
@@ -1452,7 +1563,9 @@ PAM_EXTERN int pam_sm_close_session(pam_
pam_syslog(idata.pamh, LOG_DEBUG,
"resetting namespace ok for pid %d", getpid());
}
- del_polydir_list(idata.polydirs_ptr);
+
+ pam_set_data(idata.pamh, NAMESPACE_POLYDIR_DATA, NULL, NULL);
+
return PAM_SUCCESS;
}

View File

@ -1,838 +0,0 @@
diff -up Linux-PAM-0.99.8.1/libpam/libpam.map.audit-failed Linux-PAM-0.99.8.1/libpam/libpam.map
--- Linux-PAM-0.99.8.1/libpam/libpam.map.audit-failed 2006-06-14 17:28:44.000000000 +0200
+++ Linux-PAM-0.99.8.1/libpam/libpam.map 2008-01-22 22:24:05.000000000 +0100
@@ -45,3 +45,7 @@ LIBPAM_MODUTIL_1.0 {
pam_modutil_read;
pam_modutil_write;
};
+LIBPAM_MODUTIL_1.1 {
+ global:
+ pam_modutil_audit_write;
+} LIBPAM_MODUTIL_1.0;
diff -up Linux-PAM-0.99.8.1/libpam/pam_audit.c.audit-failed Linux-PAM-0.99.8.1/libpam/pam_audit.c
--- Linux-PAM-0.99.8.1/libpam/pam_audit.c.audit-failed 2008-01-22 22:24:05.000000000 +0100
+++ Linux-PAM-0.99.8.1/libpam/pam_audit.c 2008-01-22 22:24:05.000000000 +0100
@@ -42,39 +42,53 @@ _pam_audit_writelog(pam_handle_t *pamh,
best to fix it. */
errno = -rc;
+ if (rc < 0 && errno != old_errno)
+ {
+ old_errno = errno;
+ pam_syslog (pamh, LOG_CRIT, "audit_log_acct_message() failed: %m");
+ }
+
pamh->audit_state |= PAMAUDIT_LOGGED;
- if (rc < 0) {
- if (rc == -EPERM && getuid() != 0)
- return 0;
- if (errno != old_errno) {
- old_errno = errno;
- pam_syslog (pamh, LOG_CRIT, "audit_log_acct_message() failed: %m");
- }
- }
- return rc;
+ if (rc == -EPERM && getuid () != 0)
+ return 0;
+ else
+ return rc;
}
-int
-_pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags)
+static int
+_pam_audit_open(pam_handle_t *pamh)
{
- const char *message;
- int type;
int audit_fd;
-
audit_fd = audit_open();
if (audit_fd < 0) {
/* You get these error codes only when the kernel doesn't have
* audit compiled in. */
if (errno == EINVAL || errno == EPROTONOSUPPORT ||
errno == EAFNOSUPPORT)
- return retval;
+ return -2;
/* this should only fail in case of extreme resource shortage,
* need to prevent login in that case for CAPP compliance.
*/
pam_syslog(pamh, LOG_CRIT, "audit_open() failed: %m");
+ return -1;
+ }
+
+ return audit_fd;
+}
+
+int
+_pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags)
+{
+ const char *message;
+ int type;
+ int audit_fd;
+
+ if ((audit_fd=_pam_audit_open(pamh)) == -1) {
return PAM_SYSTEM_ERR;
+ } else if (audit_fd == -2) {
+ return retval;
}
switch (action) {
@@ -141,4 +155,30 @@ _pam_audit_end(pam_handle_t *pamh, int s
return 0;
}
+int
+pam_modutil_audit_write(pam_handle_t *pamh, int type,
+ const char *message, int retval)
+{
+ int audit_fd;
+ int rc;
+
+ if ((audit_fd=_pam_audit_open(pamh)) == -1) {
+ return PAM_SYSTEM_ERR;
+ } else if (audit_fd == -2) {
+ return retval;
+ }
+
+ rc = _pam_audit_writelog(pamh, audit_fd, type, message, retval);
+
+ audit_close(audit_fd);
+
+ return rc < 0 ? PAM_SYSTEM_ERR : PAM_SUCCESS;
+}
+
+#else
+int pam_modutil_audit_write(pam_handle_t *pamh UNUSED, int type UNUSED,
+ const char *message UNUSED, int retval UNUSED)
+{
+ return PAM_SUCCESS;
+}
#endif /* HAVE_LIBAUDIT */
diff -up Linux-PAM-0.99.8.1/modules/pam_access/pam_access.8.xml.audit-failed Linux-PAM-0.99.8.1/modules/pam_access/pam_access.8.xml
--- Linux-PAM-0.99.8.1/modules/pam_access/pam_access.8.xml.audit-failed 2007-06-22 10:03:29.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_access/pam_access.8.xml 2008-01-22 22:24:05.000000000 +0100
@@ -29,6 +29,9 @@
nodefgroup
</arg>
<arg choice="opt">
+ noaudit
+ </arg>
+ <arg choice="opt">
accessfile=<replaceable>file</replaceable>
</arg>
<arg choice="opt">
@@ -54,6 +57,10 @@
<filename>/etc/security/access.conf</filename> if you don't specify
another file.
</para>
+ <para>
+ If Linux PAM is compiled with audit support the module will report
+ when it denies access based on origin (host or tty).
+ </para>
</refsect1>
<refsect1 id="pam_access-options">
@@ -87,6 +94,17 @@
<varlistentry>
<term>
+ <option>noaudit</option>
+ </term>
+ <listitem>
+ <para>
+ Do not report logins from disallowed hosts and ttys to the audit subsystem.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
<option>fieldsep=<replaceable>separators</replaceable></option>
</term>
<listitem>
diff -up Linux-PAM-0.99.8.1/modules/pam_access/pam_access.c.audit-failed Linux-PAM-0.99.8.1/modules/pam_access/pam_access.c
--- Linux-PAM-0.99.8.1/modules/pam_access/pam_access.c.audit-failed 2007-06-25 11:59:11.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_access/pam_access.c 2008-01-22 22:24:05.000000000 +0100
@@ -46,6 +46,10 @@
#include <netdb.h>
#include <sys/socket.h>
+#ifdef HAVE_LIBAUDIT
+#include <libaudit.h>
+#endif
+
/*
* here, we make definitions for the externally accessible functions
* in this file (these definitions are required for static modules
@@ -81,17 +85,11 @@
/* Delimiters for fields and for lists of users, ttys or hosts. */
-static const char *fs = ":"; /* field separator */
-static const char *sep = ", \t"; /* list-element separator */
-
- /* Constants to be used in assignments only, not in comparisons... */
+#define ALL 2
#define YES 1
#define NO 0
-/* Only allow group entries of the form "(xyz)" */
-static int only_new_group_syntax = NO;
-
/*
* A structure to bundle up all login-related information to keep the
* functional interfaces as generic as possible.
@@ -100,12 +98,13 @@ struct login_info {
const struct passwd *user;
const char *from;
const char *config_file;
+ int debug; /* Print debugging messages. */
+ int only_new_group_syntax; /* Only allow group entries of the form "(xyz)" */
+ int noaudit; /* Do not audit denials */
+ const char *fs; /* field separator */
+ const char *sep; /* list-element separator */
};
-/* Print debugging messages.
- Default is NO which means don't print debugging messages. */
-static char pam_access_debug = NO;
-
/* Parse module config arguments */
static int
@@ -113,17 +112,22 @@ parse_args(pam_handle_t *pamh, struct lo
int argc, const char **argv)
{
int i;
-
+
+ loginfo->noaudit = NO;
+ loginfo->debug = NO;
+ loginfo->only_new_group_syntax = NO;
+ loginfo->fs = ":";
+ loginfo->sep = ", \t";
for (i=0; i<argc; ++i) {
if (!strncmp("fieldsep=", argv[i], 9)) {
/* the admin wants to override the default field separators */
- fs = argv[i]+9;
+ loginfo->fs = argv[i]+9;
} else if (!strncmp("listsep=", argv[i], 8)) {
/* the admin wants to override the default list separators */
- sep = argv[i]+8;
+ loginfo->sep = argv[i]+8;
} else if (!strncmp("accessfile=", argv[i], 11)) {
FILE *fp = fopen(11 + argv[i], "r");
@@ -138,9 +142,11 @@ parse_args(pam_handle_t *pamh, struct lo
}
} else if (strcmp (argv[i], "debug") == 0) {
- pam_access_debug = YES;
+ loginfo->debug = YES;
} else if (strcmp (argv[i], "nodefgroup") == 0) {
- only_new_group_syntax = YES;
+ loginfo->only_new_group_syntax = YES;
+ } else if (strcmp (argv[i], "noaudit") == 0) {
+ loginfo->noaudit = YES;
} else {
pam_syslog(pamh, LOG_ERR, "unrecognized option [%s]", argv[i]);
}
@@ -153,13 +159,13 @@ parse_args(pam_handle_t *pamh, struct lo
typedef int match_func (pam_handle_t *, char *, struct login_info *);
-static int list_match (pam_handle_t *, char *, struct login_info *,
+static int list_match (pam_handle_t *, char *, char *, struct login_info *,
match_func *);
static int user_match (pam_handle_t *, char *, struct login_info *);
-static int group_match (pam_handle_t *, const char *, const char *);
+static int group_match (pam_handle_t *, const char *, const char *, int);
static int from_match (pam_handle_t *, char *, struct login_info *);
-static int string_match (pam_handle_t *, const char *, const char *);
-static int network_netmask_match (pam_handle_t *, const char *, const char *);
+static int string_match (pam_handle_t *, const char *, const char *, int);
+static int network_netmask_match (pam_handle_t *, const char *, const char *, int);
/* isipaddr - find out if string provided is an IP address or not */
@@ -325,11 +331,12 @@ login_access (pam_handle_t *pamh, struct
char *users; /* becomes list of login names */
char *froms; /* becomes list of terminals or hosts */
int match = NO;
+ int nonall_match = NO;
int end;
int lineno = 0; /* for diagnostics */
char *sptr;
- if (pam_access_debug)
+ if (item->debug)
pam_syslog (pamh, LOG_DEBUG,
"login_access: user=%s, from=%s, file=%s",
item->user->pw_name,
@@ -361,8 +368,8 @@ login_access (pam_handle_t *pamh, struct
continue;
/* Allow field seperator in last field of froms */
- if (!(perm = strtok_r(line, fs, &sptr))
- || !(users = strtok_r(NULL, fs, &sptr))
+ if (!(perm = strtok_r(line, item->fs, &sptr))
+ || !(users = strtok_r(NULL, item->fs, &sptr))
|| !(froms = strtok_r(NULL, "\n", &sptr))) {
pam_syslog(pamh, LOG_ERR, "%s: line %d: bad field count",
item->config_file, lineno);
@@ -373,17 +380,22 @@ login_access (pam_handle_t *pamh, struct
item->config_file, lineno);
continue;
}
- if (pam_access_debug)
+ if (item->debug)
pam_syslog (pamh, LOG_DEBUG,
"line %d: %s : %s : %s", lineno, perm, users, froms);
- match = list_match(pamh, froms, item, from_match);
- if (pam_access_debug)
- pam_syslog (pamh, LOG_DEBUG,
- "from_match=%d, \"%s\"", match, item->from);
- match = match && list_match (pamh, users, item, user_match);
- if (pam_access_debug)
+ match = list_match(pamh, users, NULL, item, user_match);
+ if (item->debug)
pam_syslog (pamh, LOG_DEBUG, "user_match=%d, \"%s\"",
match, item->user->pw_name);
+ if (match) {
+ match = list_match(pamh, froms, NULL, item, from_match);
+ if (!match && perm[0] == '+') {
+ nonall_match = YES;
+ }
+ if (item->debug)
+ pam_syslog (pamh, LOG_DEBUG,
+ "from_match=%d, \"%s\"", match, item->from);
+ }
}
(void) fclose(fp);
} else if (errno == ENOENT) {
@@ -394,20 +406,27 @@ login_access (pam_handle_t *pamh, struct
pam_syslog(pamh, LOG_ERR, "cannot open %s: %m", item->config_file);
return NO;
}
+#ifdef HAVE_LIBAUDIT
+ if (!item->noaudit && line[0] == '-' && (match == YES || (match == ALL &&
+ nonall_match == YES))) {
+ pam_modutil_audit_write(pamh, AUDIT_ANOM_LOGIN_LOCATION,
+ "pam_access", 0);
+ }
+#endif
return (match == NO || (line[0] == '+'));
}
/* list_match - match an item against a list of tokens with exceptions */
-static int list_match(pam_handle_t *pamh,
- char *list, struct login_info *item, match_func *match_fn)
+static int
+list_match(pam_handle_t *pamh, char *list, char *sptr,
+ struct login_info *item, match_func *match_fn)
{
char *tok;
int match = NO;
- char *sptr;
- if (pam_access_debug)
+ if (item->debug && list != NULL)
pam_syslog (pamh, LOG_DEBUG,
"list_match: list=%s, item=%s", list, item->user->pw_name);
@@ -418,8 +437,8 @@ static int list_match(pam_handle_t *pamh
* the match is affected by any exceptions.
*/
- for (tok = strtok_r(list, sep, &sptr); tok != 0;
- tok = strtok_r(NULL, sep, &sptr)) {
+ for (tok = strtok_r(list, item->sep, &sptr); tok != 0;
+ tok = strtok_r(NULL, item->sep, &sptr)) {
if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */
break;
if ((match = (*match_fn) (pamh, tok, item))) /* YES */
@@ -428,10 +447,12 @@ static int list_match(pam_handle_t *pamh
/* Process exceptions to matches. */
if (match != NO) {
- while ((tok = strtok_r(NULL, sep, &sptr)) && strcasecmp(tok, "EXCEPT"))
+ while ((tok = strtok_r(NULL, item->sep, &sptr)) && strcasecmp(tok, "EXCEPT"))
/* VOID */ ;
- if (tok == 0 || list_match(pamh, sptr, item, match_fn) == NO)
- return (match);
+ if (tok == 0)
+ return match;
+ if (list_match(pamh, NULL, sptr, item, match_fn) == NO)
+ return YES; /* drop special meaning of ALL */
}
return (NO);
}
@@ -453,7 +474,7 @@ static char *myhostname(void)
static int
netgroup_match (pam_handle_t *pamh, const char *netgroup,
- const char *machine, const char *user)
+ const char *machine, const char *user, int debug)
{
char *mydomain = NULL;
int retval;
@@ -462,7 +483,7 @@ netgroup_match (pam_handle_t *pamh, cons
retval = innetgr (netgroup, machine, user, mydomain);
- if (pam_access_debug == YES)
+ if (debug == YES)
pam_syslog (pamh, LOG_DEBUG,
"netgroup_match: %d (netgroup=%s, machine=%s, user=%s, domain=%s)",
retval, netgroup ? netgroup : "NULL",
@@ -480,8 +501,9 @@ user_match (pam_handle_t *pamh, char *to
char *string = item->user->pw_name;
struct login_info fake_item;
char *at;
+ int rv;
- if (pam_access_debug)
+ if (item->debug)
pam_syslog (pamh, LOG_DEBUG,
"user_match: tok=%s, item=%s", tok, string);
@@ -500,12 +522,12 @@ user_match (pam_handle_t *pamh, char *to
return (user_match (pamh, tok, item) &&
from_match (pamh, at + 1, &fake_item));
} else if (tok[0] == '@') /* netgroup */
- return (netgroup_match (pamh, tok + 1, (char *) 0, string));
+ return (netgroup_match (pamh, tok + 1, (char *) 0, string, item->debug));
else if (tok[0] == '(' && tok[strlen(tok) - 1] == ')')
- return (group_match (pamh, tok, string));
- else if (string_match (pamh, tok, string)) /* ALL or exact match */
- return YES;
- else if (only_new_group_syntax == NO &&
+ return (group_match (pamh, tok, string, item->debug));
+ else if ((rv=string_match (pamh, tok, string, item->debug)) != NO) /* ALL or exact match */
+ return rv;
+ else if (item->only_new_group_syntax == NO &&
pam_modutil_user_in_group_nam_nam (pamh,
item->user->pw_name, tok))
/* try group membership */
@@ -518,11 +540,12 @@ user_match (pam_handle_t *pamh, char *to
/* group_match - match a username against token named group */
static int
-group_match (pam_handle_t *pamh, const char *tok, const char* usr)
+group_match (pam_handle_t *pamh, const char *tok, const char* usr,
+ int debug)
{
char grptok[BUFSIZ];
- if (pam_access_debug)
+ if (debug)
pam_syslog (pamh, LOG_DEBUG,
"group_match: grp=%s, user=%s", grptok, usr);
@@ -548,8 +571,9 @@ from_match (pam_handle_t *pamh UNUSED, c
const char *string = item->from;
int tok_len;
int str_len;
+ int rv;
- if (pam_access_debug)
+ if (item->debug)
pam_syslog (pamh, LOG_DEBUG,
"from_match: tok=%s, item=%s", tok, string);
@@ -565,10 +589,10 @@ from_match (pam_handle_t *pamh UNUSED, c
if (string == NULL) {
return NO;
} else if (tok[0] == '@') { /* netgroup */
- return (netgroup_match (pamh, tok + 1, string, (char *) 0));
- } else if (string_match(pamh, tok, string)) {
+ return (netgroup_match (pamh, tok + 1, string, (char *) 0, item->debug));
+ } else if ((rv = string_match(pamh, tok, string, item->debug)) != NO) {
/* ALL or exact match */
- return (YES);
+ return rv;
} else if (tok[0] == '.') { /* domain: match last fields */
if ((str_len = strlen(string)) > (tok_len = strlen(tok))
&& strcasecmp(tok, string + str_len - tok_len) == 0)
@@ -614,7 +638,7 @@ from_match (pam_handle_t *pamh UNUSED, c
}
} else if (isipaddr(string, NULL, NULL) == YES) {
/* Assume network/netmask with a IP of a host. */
- if (network_netmask_match(pamh, tok, string))
+ if (network_netmask_match(pamh, tok, string, item->debug))
return YES;
} else {
/* Assume network/netmask with a name of a host. */
@@ -641,7 +665,7 @@ from_match (pam_handle_t *pamh UNUSED, c
: (void *) &((struct sockaddr_in6 *) runp->ai_addr)->sin6_addr,
buf, sizeof (buf));
- if (network_netmask_match(pamh, tok, buf))
+ if (network_netmask_match(pamh, tok, buf, item->debug))
{
freeaddrinfo (res);
return YES;
@@ -658,10 +682,11 @@ from_match (pam_handle_t *pamh UNUSED, c
/* string_match - match a string against one token */
static int
-string_match (pam_handle_t *pamh, const char *tok, const char *string)
+string_match (pam_handle_t *pamh, const char *tok, const char *string,
+ int debug)
{
- if (pam_access_debug)
+ if (debug)
pam_syslog (pamh, LOG_DEBUG,
"string_match: tok=%s, item=%s", tok, string);
@@ -672,7 +697,7 @@ string_match (pam_handle_t *pamh, const
*/
if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */
- return (YES);
+ return (ALL);
} else if (string != NULL) {
if (strcasecmp(tok, string) == 0) { /* try exact match */
return (YES);
@@ -690,9 +715,9 @@ string_match (pam_handle_t *pamh, const
*/
static int
network_netmask_match (pam_handle_t *pamh,
- const char *tok, const char *string)
+ const char *tok, const char *string, int debug)
{
- if (pam_access_debug)
+ if (debug)
pam_syslog (pamh, LOG_DEBUG,
"network_netmask_match: tok=%s, item=%s", tok, string);
@@ -771,6 +796,22 @@ pam_sm_authenticate (pam_handle_t *pamh,
return PAM_USER_UNKNOWN;
}
+ if ((user_pw=pam_modutil_getpwnam(pamh, user))==NULL)
+ return (PAM_USER_UNKNOWN);
+
+ /*
+ * Bundle up the arguments to avoid unnecessary clumsiness later on.
+ */
+ loginfo.user = user_pw;
+ loginfo.config_file = PAM_ACCESS_CONFIG;
+
+ /* parse the argument list */
+
+ if (!parse_args(pamh, &loginfo, argc, argv)) {
+ pam_syslog(pamh, LOG_ERR, "failed to parse the module arguments");
+ return PAM_ABORT;
+ }
+
/* remote host name */
if (pam_get_item(pamh, PAM_RHOST, &void_from)
@@ -799,7 +840,7 @@ pam_sm_authenticate (pam_handle_t *pamh,
return PAM_ABORT;
}
from = void_from;
- if (pam_access_debug)
+ if (loginfo.debug)
pam_syslog (pamh, LOG_DEBUG,
"cannot determine tty or remote hostname, using service %s",
from);
@@ -817,22 +858,7 @@ pam_sm_authenticate (pam_handle_t *pamh,
}
}
- if ((user_pw=pam_modutil_getpwnam(pamh, user))==NULL)
- return (PAM_USER_UNKNOWN);
-
- /*
- * Bundle up the arguments to avoid unnecessary clumsiness later on.
- */
- loginfo.user = user_pw;
loginfo.from = from;
- loginfo.config_file = PAM_ACCESS_CONFIG;
-
- /* parse the argument list */
-
- if (!parse_args(pamh, &loginfo, argc, argv)) {
- pam_syslog(pamh, LOG_ERR, "failed to parse the module arguments");
- return PAM_ABORT;
- }
if (login_access(pamh, &loginfo)) {
return (PAM_SUCCESS);
diff -up Linux-PAM-0.99.8.1/modules/pam_time/pam_time.c.audit-failed Linux-PAM-0.99.8.1/modules/pam_time/pam_time.c
--- Linux-PAM-0.99.8.1/modules/pam_time/pam_time.c.audit-failed 2006-06-16 08:35:16.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_time/pam_time.c 2008-01-22 22:24:05.000000000 +0100
@@ -22,9 +22,16 @@
#include <fcntl.h>
#include <netdb.h>
+#ifdef HAVE_LIBAUDIT
+#include <libaudit.h>
+#endif
+
#define PAM_TIME_BUFLEN 1000
#define FIELD_SEPARATOR ';' /* this is new as of .02 */
+#define PAM_DEBUG_ARG 0x0001
+#define PAM_NO_AUDIT 0x0002
+
#ifndef TRUE
# define TRUE 1
#endif
@@ -46,6 +53,29 @@ typedef enum { AND, OR } operator;
#include <security/_pam_macros.h>
#include <security/pam_modules.h>
#include <security/pam_ext.h>
+#include <security/pam_modutil.h>
+
+static int
+_pam_parse (const pam_handle_t *pamh, int argc, const char **argv)
+{
+ int ctrl = 0;
+
+ /* step through arguments */
+ for (; argc-- > 0; ++argv) {
+
+ /* generic options */
+
+ if (!strcmp(*argv, "debug")) {
+ ctrl |= PAM_DEBUG_ARG;
+ } else if (!strcmp(*argv, "noaudit")) {
+ ctrl |= PAM_NO_AUDIT;
+ } else {
+ pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
+ }
+ }
+
+ return ctrl;
+}
/* --- static functions for checking whether the user should be let in --- */
@@ -59,7 +89,7 @@ shift_bytes(char *mem, int from, int by)
}
static int
-read_field(pam_handle_t *pamh, int fd, char **buf, int *from, int *to)
+read_field(const pam_handle_t *pamh, int fd, char **buf, int *from, int *to)
{
/* is buf set ? */
@@ -137,6 +167,7 @@ read_field(pam_handle_t *pamh, int fd, c
switch ((*buf)[i]) {
int j,c;
case '#':
+ c = 0;
for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j);
if (j >= *to) {
(*buf)[*to = ++i] = '\0';
@@ -324,6 +355,13 @@ is_same(pam_handle_t *pamh UNUSED, const
return FALSE;
}
}
+
+ /* Ok, we know that b is a substring from A and does not contain
+ wildcards, but now the length of both strings must be the same,
+ too. */
+ if (strlen (a) != strlen(b))
+ return FALSE;
+
return ( !len );
}
@@ -559,11 +597,15 @@ check_account(pam_handle_t *pamh, const
PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED,
- int argc UNUSED, const char **argv UNUSED)
+ int argc, const char **argv)
{
const void *service=NULL, *void_tty=NULL;
const char *tty;
const char *user=NULL;
+ int ctrl;
+ int rv;
+
+ ctrl = _pam_parse(pamh, argc, argv);
/* set service name */
@@ -612,7 +654,19 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int
D(("user=%s", user));
D(("tty=%s", tty));
- return check_account(pamh, service, tty, user);
+ rv = check_account(pamh, service, tty, user);
+ if (rv != PAM_SUCCESS) {
+#ifdef HAVE_LIBAUDIT
+ if (!(ctrl & PAM_NO_AUDIT)) {
+ pam_modutil_audit_write(pamh, AUDIT_ANOM_LOGIN_TIME,
+ "pam_time", rv); /* ignore return value as we fail anyway */
+ }
+#endif
+ if (ctrl & PAM_DEBUG_ARG) {
+ pam_syslog(pamh, LOG_DEBUG, "user %s rejected", user);
+ }
+ }
+ return rv;
}
/* end of module definition */
diff -up Linux-PAM-0.99.8.1/modules/pam_time/pam_time.8.xml.audit-failed Linux-PAM-0.99.8.1/modules/pam_time/pam_time.8.xml
--- Linux-PAM-0.99.8.1/modules/pam_time/pam_time.8.xml.audit-failed 2006-06-22 21:44:30.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_time/pam_time.8.xml 2008-01-22 22:24:05.000000000 +0100
@@ -22,6 +22,12 @@
<refsynopsisdiv>
<cmdsynopsis id="pam_time-cmdsynopsis">
<command>pam_time.so</command>
+ <arg choice="opt">
+ debug
+ </arg>
+ <arg choice="opt">
+ noaudit
+ </arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -41,11 +47,40 @@
By default rules for time/port access are taken from config file
<filename>/etc/security/time.conf</filename>.
</para>
+ <para>
+ If Linux PAM is compiled with audit support the module will report
+ when it denies access.
+ </para>
</refsect1>
<refsect1 id="pam_time-options">
<title>OPTIONS</title>
- <para>This module does not recognice any options.</para>
+ <variablelist>
+
+ <varlistentry>
+ <term>
+ <option>debug</option>
+ </term>
+ <listitem>
+ <para>
+ Some debug informations are printed with
+ <citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>noaudit</option>
+ </term>
+ <listitem>
+ <para>
+ Do not report logins at disallowed time to the audit subsystem.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
</refsect1>
<refsect1 id="pam_time-services">
diff -up Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.c.audit-failed Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.c
--- Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.c.audit-failed 2007-07-10 12:10:56.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.c 2008-01-22 22:41:40.000000000 +0100
@@ -41,6 +41,10 @@
#include <pwd.h>
#include <locale.h>
+#ifdef HAVE_LIBAUDIT
+#include <libaudit.h>
+#endif
+
/* Module defines */
#define LINE_LENGTH 1024
@@ -101,6 +105,7 @@ struct pam_limit_s {
#define PAM_DEBUG_ARG 0x0001
#define PAM_DO_SETREUID 0x0002
#define PAM_UTMP_EARLY 0x0004
+#define PAM_NO_AUDIT 0x0008
/* Limits from globbed files. */
#define LIMITS_CONF_GLOB LIMITS_FILE_DIR
@@ -126,6 +131,8 @@ _pam_parse (const pam_handle_t *pamh, in
ctrl |= PAM_DO_SETREUID;
} else if (!strcmp(*argv,"utmp_early")) {
ctrl |= PAM_UTMP_EARLY;
+ } else if (!strcmp(*argv,"noaudit")) {
+ ctrl |= PAM_NO_AUDIT;
} else {
pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
}
@@ -599,6 +606,13 @@ static int setup_limits(pam_handle_t *pa
D(("skip login limit check for uid=0"));
} else if (pl->login_limit > 0) {
if (check_logins(pamh, uname, pl->login_limit, ctrl, pl) == LOGIN_ERR) {
+#ifdef HAVE_LIBAUDIT
+ if (!(ctrl & PAM_NO_AUDIT)) {
+ pam_modutil_audit_write(pamh, AUDIT_ANOM_LOGIN_SESSIONS,
+ "pam_limits", PAM_PERM_DENIED);
+ /* ignore return value as we fail anyway */
+ }
+#endif
retval |= LOGIN_ERR;
}
} else if (pl->login_limit == 0) {
diff -up Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.8.xml.audit-failed Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.8.xml
--- Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.8.xml.audit-failed 2007-04-30 12:47:26.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.8.xml 2008-01-22 22:24:05.000000000 +0100
@@ -34,6 +34,9 @@
<arg choice="opt">
utmp_early
</arg>
+ <arg choice="opt">
+ noaudit
+ </arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -57,6 +60,11 @@
<para>
The module must not be called by a multithreaded application.
</para>
+ <para>
+ If Linux PAM is compiled with audit support the module will report
+ when it denies access based on limit of maximum number of concurrent
+ login sessions.
+ </para>
</refsect1>
<refsect1 id="pam_limits-options">
@@ -111,6 +119,16 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <option>noaudit</option>
+ </term>
+ <listitem>
+ <para>
+ Do not report exceeded maximum logins count to the audit subsystem.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>

View File

@ -1,91 +0,0 @@
diff -up Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c.ns-init Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c
--- Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c.ns-init 2007-08-06 13:57:56.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c 2007-08-06 14:06:52.000000000 +0200
@@ -672,7 +672,7 @@ static int poly_name(const struct polydi
hash = NULL;
} else {
char *newname;
- if (asprintf(&newname, "%.*s_%s", NAMESPACE_MAX_DIR_LEN-1-strlen(hash),
+ if (asprintf(&newname, "%.*s_%s", NAMESPACE_MAX_DIR_LEN-1-(int)strlen(hash),
*i_name, hash) < 0) {
goto fail;
}
@@ -756,7 +756,7 @@ static int check_inst_parent(char *ipath
* directory as arguments.
*/
static int inst_init(const struct polydir_s *polyptr, const char *ipath,
- struct instance_data *idata)
+ struct instance_data *idata, int newdir)
{
pid_t rc, pid;
sighandler_t osighand = NULL;
@@ -786,7 +786,7 @@ static int inst_init(const struct polydi
}
#endif
if (execl(NAMESPACE_INIT_SCRIPT, NAMESPACE_INIT_SCRIPT,
- polyptr->dir, ipath, (char *)NULL) < 0)
+ polyptr->dir, ipath, newdir?"1":"0", idata->user, (char *)NULL) < 0)
exit(1);
} else if (pid > 0) {
while (((rc = waitpid(pid, &status, 0)) == (pid_t)-1) &&
@@ -831,6 +831,7 @@ static int create_dirs(struct polydir_s
{
struct stat statbuf, newstatbuf;
int rc, fd;
+ int newdir = 0;
/*
* stat the directory to polyinstantiate, so its owner-group-mode
@@ -884,6 +885,7 @@ static int create_dirs(struct polydir_s
}
}
+ newdir = 1;
/* Open a descriptor to it to prevent races */
fd = open(ipath, O_DIRECTORY | O_RDONLY);
if (fd < 0) {
@@ -948,7 +950,7 @@ static int create_dirs(struct polydir_s
*/
inst_init:
- rc = inst_init(polyptr, ipath, idata);
+ rc = inst_init(polyptr, ipath, idata, newdir);
return rc;
}
@@ -981,7 +983,7 @@ static int ns_setup(struct polydir_s *po
return PAM_SESSION_ERR;
}
/* we must call inst_init after the mount in this case */
- return inst_init(polyptr, "tmpfs", idata);
+ return inst_init(polyptr, "tmpfs", idata, 1);
}
/*
diff -up Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.8.xml.ns-init Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.8.xml
--- Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.8.xml.ns-init 2007-06-18 12:46:47.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.8.xml 2007-08-06 13:57:56.000000000 +0200
@@ -60,7 +60,9 @@
script <filename>/etc/security/namespace.init</filename> exists, it
is used to initialize the namespace every time a new instance
directory is setup. The script receives the polyinstantiated
- directory path and the instance directory path as its arguments.
+ directory path, the instance directory path, flag whether the instance
+ directory was newly created (0 for no, 1 for yes), and the user name
+ as its arguments.
</para>
<para>
diff -up Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.init.ns-init Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.init
--- Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.init.ns-init 2007-06-18 12:46:47.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.init 2007-08-06 13:57:56.000000000 +0200
@@ -1,6 +1,8 @@
#!/bin/sh -p
# This is only a boilerplate for the instance initialization script.
-# It receives polydir path as $1 and the instance path as $2.
+# It receives polydir path as $1, the instance path as $2,
+# a flag whether the instance dir was newly created (0 - no, 1 - yes) in $3,
+# and user name in $4.
#
# If you intend to polyinstantiate /tmp and you also want to use the X windows
# environment, you will have to use this script to bind mount the socket that

View File

@ -1,473 +0,0 @@
Written-by: Tomas Mraz <tmraz@redhat.com>
Reviewed-by: Karel Zak <kzak@redhat.com>
diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.8.xml
--- /dev/null 2007-09-17 08:57:19.474470099 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.8.xml 2007-09-19 19:37:26.000000000 +0200
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding='UTF-8'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
+
+<refentry id="pam_selinux_permit">
+
+ <refmeta>
+ <refentrytitle>pam_selinux_permit</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="sectdesc">Linux-PAM Manual</refmiscinfo>
+ </refmeta>
+
+ <refnamediv id="pam_selinux_permit-name">
+ <refname>pam_selinux_permit</refname>
+ <refpurpose>PAM module to allow/deny login depending on SELinux enforcement state</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis id="pam_selinux_permit-cmdsynopsis">
+ <command>pam_selinux_permit.so</command>
+ <arg choice="opt">
+ debug
+ </arg>
+ <arg choice="opt">
+ conf=<replaceable>/path/to/config/file</replaceable>
+ </arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="pam_selinux_permit-description">
+ <title>DESCRIPTION</title>
+ <para>
+ The pam_selinux 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
+ he is allowed access only when the SELinux is in enforcing mode. Otherwise
+ he is denied access. For users not matching any entry in the config file
+ the pam_selinux_permit module returns PAM_IGNORE return value.
+ </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
+ 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>
+ 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>
+ </refsect1>
+
+ <refsect1 id="pam_selinux_permit-options">
+ <title>OPTIONS</title>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <option>debug</option>
+ </term>
+ <listitem>
+ <para>
+ Turns on debugging via
+ <citerefentry>
+ <refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum>
+ </citerefentry>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>conf=<replaceable>/path/to/config/file</replaceable></option>
+ </term>
+ <listitem>
+ <para>
+ Path to alternative config file overriding the default.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id="pam_selinux_permit-services">
+ <title>MODULE SERVICES PROVIDED</title>
+ <para>
+ Only the <option>auth</option> and <option>account</option>
+ services are supported.
+ </para>
+ </refsect1>
+
+ <refsect1 id='pam_selinux_permit-return_values'>
+ <title>RETURN VALUES</title>
+ <variablelist>
+ <varlistentry>
+ <term>PAM_AUTH_ERR</term>
+ <listitem>
+ <para>
+ SELinux is disabled or in the permissive mode and the user
+ matches.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PAM_SUCCESS</term>
+ <listitem>
+ <para>
+ SELinux is in the enforcing mode and the user matches.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PAM_IGNORE</term>
+ <listitem>
+ <para>
+ The user does not match any entry in the config file.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PAM_USER_UNKNOWN</term>
+ <listitem>
+ <para>
+ The module was unable to determine the user's name.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>PAM_SERVICE_ERR</term>
+ <listitem>
+ <para>
+ Error during reading or parsing the config file.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id="pam_selinux_permit-files">
+ <title>FILES</title>
+ <variablelist>
+ <varlistentry>
+ <term><filename>/etc/security/sepermit.conf</filename></term>
+ <listitem>
+ <para>Default configuration file</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id='pam_selinux_permit-examples'>
+ <title>EXAMPLES</title>
+ <programlisting>
+auth [success=done ignore=ignore default=bad] pam_selinux_permit.so
+auth required pam_unix.so
+account required pam_unix.so
+session required pam_permit.so
+ </programlisting>
+ </refsect1>
+
+ <refsect1 id='pam_selinux_permit-see_also'>
+ <title>SEE ALSO</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>pam.conf</refentrytitle><manvolnum>5</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>pam.d</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+
+ <refsect1 id='pam_selinux_permit-author'>
+ <title>AUTHOR</title>
+ <para>
+ pam_selinux_permit was written by Tomas Mraz &lt;tmraz@redhat.com&gt;.
+ </para>
+ </refsect1>
+
+</refentry>
diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.c
--- /dev/null 2007-09-17 08:57:19.474470099 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_selinux/pam_selinux_permit.c 2007-09-19 20:29:47.000000000 +0200
@@ -0,0 +1,222 @@
+/******************************************************************************
+ * A module for Linux-PAM that allows/denies acces based on SELinux state.
+ *
+ * Copyright (c) 2007 Red Hat, Inc.
+ * Written by Tomas Mraz <tmraz@redhat.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <ctype.h>
+
+#define PAM_SM_AUTH
+#define PAM_SM_ACCOUNT
+
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+#include <security/pam_modutil.h>
+#include <security/pam_ext.h>
+
+#include <selinux/selinux.h>
+
+/* return 0 when matched, -1 when unmatched, pam error otherwise */
+static int
+sepermit_match(pam_handle_t *pamh, const char *cfgfile, const char *user,
+ const char *seuser, int debug)
+{
+ FILE *f;
+ char *line = NULL;
+ char *start;
+ size_t len = 0;
+ int matched = 0;
+
+ f = fopen(cfgfile, "r");
+
+ if (!f) {
+ pam_syslog(pamh, LOG_ERR, "Failed to open config file %s: %m", cfgfile);
+ return PAM_SERVICE_ERR;
+ }
+
+ while (!matched && getline(&line, &len, f) != -1) {
+ size_t n;
+
+ if (line[0] == '#')
+ continue;
+
+ start = line;
+ while (isspace(*start))
+ ++start;
+ n = strlen(start);
+ while (n > 0 && isspace(start[n-1])) {
+ --n;
+ }
+ if (n == 0)
+ continue;
+
+ start[n] = '\0';
+
+ switch (start[0]) {
+ case '@':
+ ++start;
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "Matching user %s against group %s", user, start);
+ if (pam_modutil_user_in_group_nam_nam(pamh, user, start)) {
+ matched = 1;
+ }
+ break;
+ case '%':
+ ++start;
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "Matching seuser %s against seuser %s", seuser, start);
+ if (strcmp(seuser, start) == 0) {
+ matched = 1;
+ }
+ break;
+ default:
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "Matching user %s against user %s", user, start);
+ if (strcmp(user, start) == 0) {
+ matched = 1;
+ }
+ }
+ }
+
+ free(line);
+ fclose(f);
+ return matched ? 0 : -1;
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
+ int argc, const char **argv)
+{
+ int i;
+ int rv;
+ int debug = 0;
+ int sense = PAM_AUTH_ERR;
+ const char *user = NULL;
+ char *seuser = NULL;
+ char *level = NULL;
+ const char *cfgfile = SEPERMIT_CONF_FILE;
+
+ /* Parse arguments. */
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "debug") == 0) {
+ debug = 1;
+ }
+ if (strcmp(argv[i], "conf=") == 0) {
+ cfgfile = argv[i] + 5;
+ }
+ }
+
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "Parsing config file: %s", cfgfile);
+
+ if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || user == NULL
+ || *user == '\0') {
+ pam_syslog(pamh, LOG_ERR, "Cannot determine the user's name");
+ return PAM_USER_UNKNOWN;
+ }
+
+ if (is_selinux_enabled() > 0) {
+ if (security_getenforce() == 1) {
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "Enforcing mode, access will be allowed on match");
+ sense = PAM_SUCCESS;
+ }
+
+ if (getseuserbyname(user, &seuser, &level) != 0) {
+ seuser = NULL;
+ level = NULL;
+ pam_syslog(pamh, LOG_ERR, "getseuserbyname failed: %m");
+ }
+ }
+
+ if (debug && sense != PAM_SUCCESS)
+ pam_syslog(pamh, LOG_NOTICE, "Access will not be allowed on match");
+
+ rv = sepermit_match(pamh, cfgfile, user, seuser, debug);
+
+ if (debug)
+ pam_syslog(pamh, LOG_NOTICE, "sepermit_match returned: %d", rv);
+
+ free(seuser);
+ free(level);
+
+ switch (rv) {
+ case -1:
+ return PAM_IGNORE;
+ case 0:
+ return sense;
+ }
+
+ return rv;
+}
+
+PAM_EXTERN int
+pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
+ int argc UNUSED, const char **argv UNUSED)
+{
+ return PAM_IGNORE;
+}
+
+PAM_EXTERN int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ return pam_sm_authenticate(pamh, flags, argc, argv);
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_access_modstruct = {
+ "pam_access",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ pam_sm_acct_mgmt,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
+
diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_selinux/sepermit.conf
--- /dev/null 2007-09-17 08:57:19.474470099 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_selinux/sepermit.conf 2007-09-19 19:37:26.000000000 +0200
@@ -0,0 +1,6 @@
+# /etc/security/sepermit.conf
+#
+# Each line contains either:
+# - an user name
+# - a group name, with @group syntax
+# - a SELinux user name, with %seuser syntax
diff -up Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am.permit Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am
--- Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am.permit 2007-01-23 11:09:25.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_selinux/Makefile.am 2007-09-19 19:37:26.000000000 +0200
@@ -5,20 +5,21 @@
CLEANFILES = *~
EXTRA_DIST = README $(XMLS) pam_selinux.8 pam_selinux_check.8 \
- tst-pam_selinux
+ pam_seliux_permit.8 sepermit.conf tst-pam_selinux
if HAVE_LIBSELINUX
TESTS = tst-pam_selinux
- man_MANS = pam_selinux.8
+ man_MANS = pam_selinux.8 pam_selinux_permit.8
endif
-XMLS = README.xml pam_selinux.8.xml
+XMLS = README.xml pam_selinux.8.xml pam_selinux_permit.8.xml
securelibdir = $(SECUREDIR)
secureconfdir = $(SCONFIGDIR)
AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
- -I$(top_srcdir)/libpam_misc/include
+ -I$(top_srcdir)/libpam_misc/include \
+ -D SEPERMIT_CONF_FILE=\"$(SCONFIGDIR)/sepermit.conf\"
AM_LDFLAGS = -no-undefined \
-L$(top_builddir)/libpam -lpam @LIBSELINUX@
@@ -30,12 +31,16 @@ if HAVE_VERSIONING
-Wl,--version-script=$(srcdir)/../modules.map
endif
+pam_selinux_permit_la_LDFLAGS= $(pam_selinux_la_LDFLAGS)
+
+secureconf_DATA = sepermit.conf
+
if HAVE_LIBSELINUX
- securelib_LTLIBRARIES = pam_selinux.la
+ securelib_LTLIBRARIES = pam_selinux.la pam_selinux_permit.la
noinst_PROGRAMS = pam_selinux_check
endif
if ENABLE_REGENERATE_MAN
-noinst_DATA = README pam_selinux.8
+noinst_DATA = README pam_selinux.8 pam_selinux_permit.8
README: pam_selinux.8.xml
-include $(top_srcdir)/Make.xml.rules
endif

View File

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

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

@ -1,784 +0,0 @@
Index: libpam/pam_dispatch.c
===================================================================
RCS file: /cvsroot/pam/Linux-PAM/libpam/pam_dispatch.c,v
retrieving revision 1.11
diff -u -p -r1.11 pam_dispatch.c
--- libpam/pam_dispatch.c 1 Aug 2006 08:54:57 -0000 1.11
+++ libpam/pam_dispatch.c 12 Oct 2007 16:23:37 -0000
@@ -34,7 +34,8 @@
static int _pam_dispatch_aux(pam_handle_t *pamh, int flags, struct handler *h,
_pam_boolean resumed, int use_cached_chain)
{
- int depth, impression, status, skip_depth;
+ int depth, impression, status, skip_depth, prev_level, stack_level;
+ struct _pam_substack_state *substates = NULL;
IF_NO_PAMH("_pam_dispatch_aux", pamh, PAM_SYSTEM_ERR);
@@ -54,27 +55,51 @@ static int _pam_dispatch_aux(pam_handle_
skip_depth = pamh->former.depth;
status = pamh->former.status;
impression = pamh->former.impression;
+ substates = pamh->former.substates;
/* forget all that */
pamh->former.impression = _PAM_UNDEF;
pamh->former.status = PAM_MUST_FAIL_CODE;
pamh->former.depth = 0;
+ pamh->former.substates = NULL;
} else {
skip_depth = 0;
- impression = _PAM_UNDEF;
- status = PAM_MUST_FAIL_CODE;
+ substates = malloc(PAM_SUBSTACK_MAX_LEVEL * sizeof(*substates));
+ if (substates == NULL) {
+ pam_syslog(pamh, LOG_CRIT,
+ "_pam_dispatch_aux: no memory for substack states");
+ return PAM_BUF_ERR;
+ }
+ substates[0].impression = impression = _PAM_UNDEF;
+ substates[0].status = status = PAM_MUST_FAIL_CODE;
}
+ prev_level = 0;
+
/* Loop through module logic stack */
- for (depth=0 ; h != NULL ; h = h->next, ++depth) {
+ for (depth=0 ; h != NULL ; prev_level = stack_level, h = h->next, ++depth) {
int retval, cached_retval, action;
+ stack_level = h->stack_level;
+
/* skip leading modules if they have already returned */
if (depth < skip_depth) {
continue;
}
+ /* remember state if we are entering a substack */
+ if (prev_level < stack_level) {
+ substates[stack_level].impression = impression;
+ substates[stack_level].status = status;
+ }
+
/* attempt to call the module */
- if (h->func == NULL) {
+ if (h->handler_type == PAM_HT_MUST_FAIL) {
+ D(("module poorly listed in PAM config; forcing failure"));
+ retval = PAM_MUST_FAIL_CODE;
+ } else if (h->handler_type == PAM_HT_SUBSTACK) {
+ D(("skipping substack handler"));
+ continue;
+ } else if (h->func == NULL) {
D(("module function is not defined, indicating failure"));
retval = PAM_MODULE_UNKNOWN;
} else {
@@ -83,10 +108,6 @@ static int _pam_dispatch_aux(pam_handle_
retval = h->func(pamh, flags, h->argc, h->argv);
pamh->mod_name=NULL;
D(("module returned: %s", pam_strerror(pamh, retval)));
- if (h->must_fail) {
- D(("module poorly listed in PAM config; forcing failure"));
- retval = PAM_MUST_FAIL_CODE;
- }
}
/*
@@ -100,6 +121,7 @@ static int _pam_dispatch_aux(pam_handle_
pamh->former.impression = impression;
pamh->former.status = status;
pamh->former.depth = depth;
+ pamh->former.substates = substates;
D(("module %d returned PAM_INCOMPLETE", depth));
return retval;
@@ -176,8 +198,8 @@ static int _pam_dispatch_aux(pam_handle_
switch (action) {
case _PAM_ACTION_RESET:
- impression = _PAM_UNDEF;
- status = PAM_MUST_FAIL_CODE;
+ impression = substates[stack_level].impression;
+ status = substates[stack_level].status;
break;
case _PAM_ACTION_OK:
@@ -244,9 +266,13 @@ static int _pam_dispatch_aux(pam_handle_
}
/* this means that we need to skip #action stacked modules */
- do {
- h = h->next;
- } while ( --action > 0 && h != NULL );
+ while (h->next != NULL && h->next->stack_level >= stack_level && action > 0) {
+ do {
+ h = h->next;
+ ++depth;
+ } while (h->next != NULL && h->next->stack_level > stack_level);
+ --action;
+ }
/* note if we try to skip too many modules action is
still non-zero and we snag the next if. */
@@ -254,14 +280,19 @@ static int _pam_dispatch_aux(pam_handle_
/* this case is a syntax error: we can't succeed */
if (action) {
- D(("action syntax error"));
+ pam_syslog(pamh, LOG_ERR, "bad jump in stack");
impression = _PAM_NEGATIVE;
status = PAM_MUST_FAIL_CODE;
}
}
- }
-
+ continue;
+
decision_made: /* by getting here we have made a decision */
+ while (h->next != NULL && h->next->stack_level >= stack_level) {
+ h = h->next;
+ ++depth;
+ }
+ }
/* Sanity check */
if ( status == PAM_SUCCESS && impression != _PAM_POSITIVE ) {
@@ -269,6 +300,7 @@ decision_made: /* by getting here w
status = PAM_MUST_FAIL_CODE;
}
+ free(substates);
/* We have made a decision about the modules executed */
return status;
}
Index: libpam/pam_end.c
===================================================================
RCS file: /cvsroot/pam/Linux-PAM/libpam/pam_end.c,v
retrieving revision 1.4
diff -u -p -r1.4 pam_end.c
--- libpam/pam_end.c 12 Jan 2006 10:06:49 -0000 1.4
+++ libpam/pam_end.c 12 Oct 2007 16:23:37 -0000
@@ -71,6 +71,8 @@ int pam_end(pam_handle_t *pamh, int pam_
_pam_drop(pamh->pam_conversation);
pamh->fail_delay.delay_fn_ptr = NULL;
+ _pam_drop(pamh->former.substates);
+
/* and finally liberate the memory for the pam_handle structure */
_pam_drop(pamh);
Index: libpam/pam_handlers.c
===================================================================
RCS file: /cvsroot/pam/Linux-PAM/libpam/pam_handlers.c,v
retrieving revision 1.24
diff -u -p -r1.24 pam_handlers.c
--- libpam/pam_handlers.c 14 Jun 2006 11:41:47 -0000 1.24
+++ libpam/pam_handlers.c 12 Oct 2007 16:23:37 -0000
@@ -18,7 +18,7 @@
#define BUF_SIZE 1024
#define MODULE_CHUNK 4
-#define UNKNOWN_MODULE_PATH "<*unknown module path*>"
+#define UNKNOWN_MODULE "<*unknown module*>"
#ifndef _PAM_ISA
#define _PAM_ISA "."
#endif
@@ -28,7 +28,7 @@ static int _pam_assemble_line(FILE *f, c
static void _pam_free_handlers_aux(struct handler **hp);
static int _pam_add_handler(pam_handle_t *pamh
- , int must_fail, int other, int type
+ , int must_fail, int other, int stack_level, int type
, int *actions, const char *mod_path
, int argc, char **argv, int argvlen);
@@ -43,6 +43,7 @@ static int _pam_add_handler(pam_handle_t
static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
, const char *service /* specific file */
, int module_type /* specific type */
+ , int stack_level /* level of substack */
#ifdef PAM_READ_BOTH_CONFS
, int not_other
#endif /* PAM_READ_BOTH_CONFS */
@@ -51,6 +52,7 @@ static int _pam_load_conf_file(pam_handl
static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
, const char *known_service /* specific file */
, int requested_module_type /* specific type */
+ , int stack_level /* level of substack */
#ifdef PAM_READ_BOTH_CONFS
, int not_other
#endif /* PAM_READ_BOTH_CONFS */
@@ -68,7 +70,7 @@ static int _pam_parse_conf_file(pam_hand
int module_type, actions[_PAM_RETURN_VALUES];
int other; /* set if module is for PAM_DEFAULT_SERVICE */
int res; /* module added successfully? */
- int must_fail=0; /* a badly formatted line must fail when used */
+ int handler_type = PAM_HT_MODULE; /* regular handler from a module */
int argc;
char **argv;
int argvlen;
@@ -92,6 +94,7 @@ static int _pam_parse_conf_file(pam_hand
/* accept "service name" or PAM_DEFAULT_SERVICE modules */
if (!strcasecmp(this_service, pamh->service_name) || other) {
int pam_include = 0;
+ int substack = 0;
/* This is a service we are looking for */
D(("_pam_init_handlers: Found PAM config entry for: %s"
@@ -105,7 +108,7 @@ static int _pam_parse_conf_file(pam_hand
"(%s) empty module type", this_service);
module_type = (requested_module_type != PAM_T_ANY) ?
requested_module_type : PAM_T_AUTH; /* most sensitive */
- must_fail = 1; /* install as normal but fail when dispatched */
+ handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
} else if (!strcasecmp("auth", tok)) {
module_type = PAM_T_AUTH;
} else if (!strcasecmp("session", tok)) {
@@ -121,9 +124,9 @@ static int _pam_parse_conf_file(pam_hand
this_service, tok);
module_type = (requested_module_type != PAM_T_ANY) ?
requested_module_type : PAM_T_AUTH; /* most sensitive */
- must_fail = 1; /* install as normal but fail when dispatched */
+ handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
}
- D(("Using %s config entry: %s", must_fail?"BAD ":"", tok));
+ D(("Using %s config entry: %s", handler_type?"BAD ":"", tok));
if (requested_module_type != PAM_T_ANY &&
module_type != requested_module_type) {
D(("Skipping config entry: %s (requested=%d, found=%d)",
@@ -145,7 +148,7 @@ static int _pam_parse_conf_file(pam_hand
pam_syslog(pamh, LOG_ERR,
"(%s) no control flag supplied", this_service);
_pam_set_default_control(actions, _PAM_ACTION_BAD);
- must_fail = 1;
+ handler_type = PAM_HT_MUST_FAIL;
} else if (!strcasecmp("required", tok)) {
D(("*PAM_F_REQUIRED*"));
actions[PAM_SUCCESS] = _PAM_ACTION_OK;
@@ -171,6 +174,11 @@ static int _pam_parse_conf_file(pam_hand
} else if (!strcasecmp("include", tok)) {
D(("*PAM_F_INCLUDE*"));
pam_include = 1;
+ substack = 0;
+ } else if (!strcasecmp("substack", tok)) {
+ D(("*PAM_F_SUBSTACK*"));
+ pam_include = 1;
+ substack = 1;
} else {
D(("will need to parse %s", tok));
_pam_parse_control(actions, tok);
@@ -180,7 +188,18 @@ static int _pam_parse_conf_file(pam_hand
tok = _pam_StrTok(NULL, " \n\t", &nexttok);
if (pam_include) {
- if (_pam_load_conf_file(pamh, tok, this_service, module_type
+ if (substack) {
+ res = _pam_add_handler(pamh, PAM_HT_SUBSTACK, other,
+ stack_level, module_type, actions, tok,
+ 0, NULL, 0);
+ if (res != PAM_SUCCESS) {
+ pam_syslog(pamh, LOG_ERR, "error adding substack %s", tok);
+ D(("failed to load module - aborting"));
+ return PAM_ABORT;
+ }
+ }
+ if (_pam_load_conf_file(pamh, tok, this_service, module_type,
+ stack_level + substack
#ifdef PAM_READ_BOTH_CONFS
, !other
#endif /* PAM_READ_BOTH_CONFS */
@@ -188,7 +207,7 @@ static int _pam_parse_conf_file(pam_hand
continue;
_pam_set_default_control(actions, _PAM_ACTION_BAD);
mod_path = NULL;
- must_fail = 1;
+ handler_type = PAM_HT_MUST_FAIL;
nexttok = NULL;
} else if (tok != NULL) {
mod_path = tok;
@@ -199,7 +218,7 @@ static int _pam_parse_conf_file(pam_hand
pam_syslog(pamh, LOG_ERR,
"(%s) no module name supplied", this_service);
mod_path = NULL;
- must_fail = 1;
+ handler_type = PAM_HT_MUST_FAIL;
}
/* nexttok points to remaining arguments... */
@@ -219,7 +238,7 @@ static int _pam_parse_conf_file(pam_hand
int y;
D(("CONF%s: %s%s %d %s %d"
- , must_fail?"<*will fail*>":""
+ , handler_type==PAM_HT_MUST_FAIL?"<*will fail*>":""
, this_service, other ? "(backup)":""
, module_type
, mod_path, argc));
@@ -235,7 +254,7 @@ static int _pam_parse_conf_file(pam_hand
}
#endif
- res = _pam_add_handler(pamh, must_fail, other
+ res = _pam_add_handler(pamh, handler_type, other, stack_level
, module_type, actions, mod_path
, argc, argv, argvlen);
if (res != PAM_SUCCESS) {
@@ -252,6 +271,7 @@ static int _pam_parse_conf_file(pam_hand
static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
, const char *service /* specific file */
, int module_type /* specific type */
+ , int stack_level /* level of substack */
#ifdef PAM_READ_BOTH_CONFS
, int not_other
#endif /* PAM_READ_BOTH_CONFS */
@@ -263,6 +283,12 @@ static int _pam_load_conf_file(pam_handl
D(("_pam_load_conf_file called"));
+ if (stack_level >= PAM_SUBSTACK_MAX_LEVEL) {
+ D(("maximum level of substacks reached"));
+ pam_syslog(pamh, LOG_ERR, "maximum level of substacks reached");
+ return PAM_ABORT;
+ }
+
if (config_name == NULL) {
D(("no config file supplied"));
pam_syslog(pamh, LOG_ERR, "(%s) no config file supplied", service);
@@ -280,7 +306,7 @@ static int _pam_load_conf_file(pam_handl
D(("opening %s", config_name));
f = fopen(config_name, "r");
if (f != NULL) {
- retval = _pam_parse_conf_file(pamh, f, service, module_type
+ retval = _pam_parse_conf_file(pamh, f, service, module_type, stack_level
#ifdef PAM_READ_BOTH_CONFS
, not_other
#endif /* PAM_READ_BOTH_CONFS */
@@ -379,7 +405,8 @@ int _pam_init_handlers(pam_handle_t *pam
f = fopen(filename, "r");
if (f != NULL) {
/* would test magic here? */
- retval = _pam_parse_conf_file(pamh, f, pamh->service_name, PAM_T_ANY
+ retval = _pam_parse_conf_file(pamh, f, pamh->service_name,
+ PAM_T_ANY, 0
#ifdef PAM_READ_BOTH_CONFS
, 0
#endif /* PAM_READ_BOTH_CONFS */
@@ -400,7 +427,7 @@ int _pam_init_handlers(pam_handle_t *pam
D(("checking %s", PAM_CONFIG));
if ((f = fopen(PAM_CONFIG,"r")) != NULL) {
- retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 1);
+ retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0, 1);
fclose(f);
} else
#endif /* PAM_READ_BOTH_CONFS */
@@ -419,9 +446,8 @@ int _pam_init_handlers(pam_handle_t *pam
f = fopen(PAM_DEFAULT_SERVICE_FILE, "r");
if (f != NULL) {
/* would test magic here? */
- retval = _pam_parse_conf_file(pamh, f
- , PAM_DEFAULT_SERVICE
- , PAM_T_ANY
+ retval = _pam_parse_conf_file(pamh, f, PAM_DEFAULT_SERVICE,
+ PAM_T_ANY, 0
#ifdef PAM_READ_BOTH_CONFS
, 0
#endif /* PAM_READ_BOTH_CONFS */
@@ -454,7 +480,7 @@ int _pam_init_handlers(pam_handle_t *pam
return PAM_ABORT;
}
- retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY
+ retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0
#ifdef PAM_READ_BOTH_CONFS
, 0
#endif /* PAM_READ_BOTH_CONFS */
@@ -581,46 +607,19 @@ extract_modulename(const char *mod_path)
return retval;
}
-int _pam_add_handler(pam_handle_t *pamh
- , int must_fail, int other, int type
- , int *actions, const char *mod_path
- , int argc, char **argv, int argvlen)
+static struct loaded_module *
+_pam_load_module(pam_handle_t *pamh, const char *mod_path)
{
- struct loaded_module *mod;
int x = 0;
- struct handler **handler_p;
- struct handler **handler_p2;
- struct handlers *the_handlers;
- const char *sym, *sym2;
- char *mod_full_path=NULL;
+ int success;
#ifndef PAM_STATIC
char *mod_full_isa_path=NULL, *isa=NULL;
#endif
- servicefn func, func2;
- int success;
-
- D(("called."));
- IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
-
- /* if NULL set to something that can be searched for */
- switch (mod_path != NULL) {
- default:
- if (mod_path[0] == '/') {
- break;
- }
- if (asprintf(&mod_full_path, "%s%s",
- DEFAULT_MODULE_PATH, mod_path) >= 0) {
- mod_path = mod_full_path;
- break;
- }
- mod_full_path = NULL;
- pam_syslog(pamh, LOG_CRIT, "cannot malloc full mod path");
- case 0:
- mod_path = UNKNOWN_MODULE_PATH;
- }
+ struct loaded_module *mod;
- D(("_pam_add_handler: adding type %d, module `%s'",type,mod_path));
- mod = pamh->handlers.module;
+ D(("_pam_load_module: loading module `%s'", mod_path));
+
+ mod = pamh->handlers.module;
/* First, ensure the module is loaded */
while (x < pamh->handlers.modules_used) {
@@ -639,9 +638,8 @@ int _pam_add_handler(pam_handle_t *pamh
if (tmp == NULL) {
D(("cannot enlarge module pointer memory"));
pam_syslog(pamh, LOG_ERR,
- "realloc returned NULL in _pam_add_handler");
- _pam_drop(mod_full_path);
- return PAM_ABORT;
+ "realloc returned NULL in _pam_load_module");
+ return NULL;
}
pamh->handlers.module = tmp;
pamh->handlers.modules_allocated += MODULE_CHUNK;
@@ -654,10 +652,10 @@ int _pam_add_handler(pam_handle_t *pamh
/* Only load static function if function was not found dynamically.
* This code should work even if no dynamic loading is available. */
if (success != PAM_SUCCESS) {
- D(("_pam_add_handler: open static handler %s", mod_path));
+ D(("_pam_load_module: open static handler %s", mod_path));
mod->dl_handle = _pam_open_static_handler(pamh, mod_path);
if (mod->dl_handle == NULL) {
- D(("_pam_add_handler: unable to find static handler %s",
+ D(("_pam_load_module: unable to find static handler %s",
mod_path));
pam_syslog(pamh, LOG_ERR,
"unable to open static handler %s", mod_path);
@@ -670,15 +668,15 @@ int _pam_add_handler(pam_handle_t *pamh
}
}
#else
- D(("_pam_add_handler: _pam_dlopen(%s)", mod_path));
+ D(("_pam_load_module: _pam_dlopen(%s)", mod_path));
mod->dl_handle = _pam_dlopen(mod_path);
- D(("_pam_add_handler: _pam_dlopen'ed"));
- D(("_pam_add_handler: dlopen'ed"));
+ D(("_pam_load_module: _pam_dlopen'ed"));
+ D(("_pam_load_module: dlopen'ed"));
if (mod->dl_handle == NULL) {
if (strstr(mod_path, "$ISA")) {
mod_full_isa_path = malloc(strlen(mod_path) + strlen(_PAM_ISA) + 1);
if (mod_full_isa_path == NULL) {
- D(("_pam_handler: couldn't get memory for mod_path"));
+ D(("_pam_load_module: couldn't get memory for mod_path"));
pam_syslog(pamh, LOG_ERR, "no memory for module path");
success = PAM_ABORT;
} else {
@@ -694,9 +692,9 @@ int _pam_add_handler(pam_handle_t *pamh
}
}
if (mod->dl_handle == NULL) {
- D(("_pam_add_handler: _pam_dlopen(%s) failed", mod_path));
- pam_syslog(pamh, LOG_ERR, "unable to dlopen(%s)", mod_path);
- pam_syslog(pamh, LOG_ERR, "[error: %s]", _pam_dlerror());
+ D(("_pam_load_module: _pam_dlopen(%s) failed", mod_path));
+ pam_syslog(pamh, LOG_ERR, "unable to dlopen(%s): %s", mod_path,
+ _pam_dlerror());
/* Don't abort yet; static code may be able to find function.
* But defaults to abort if nothing found below... */
} else {
@@ -717,7 +715,7 @@ int _pam_add_handler(pam_handle_t *pamh
/* indicate its name - later we will search for it by this */
if ((mod->name = _pam_strdup(mod_path)) == NULL) {
- D(("_pam_handler: couldn't get memory for mod_path"));
+ D(("_pam_load_module: couldn't get memory for mod_path"));
pam_syslog(pamh, LOG_ERR, "no memory for module path");
success = PAM_ABORT;
}
@@ -726,18 +724,54 @@ int _pam_add_handler(pam_handle_t *pamh
mod += x; /* the located module */
success = PAM_SUCCESS;
}
+ return success == PAM_SUCCESS ? mod : NULL;
+}
+
+int _pam_add_handler(pam_handle_t *pamh
+ , int handler_type, int other, int stack_level, int type
+ , int *actions, const char *mod_path
+ , int argc, char **argv, int argvlen)
+{
+ struct loaded_module *mod = NULL;
+ struct handler **handler_p;
+ struct handler **handler_p2;
+ struct handlers *the_handlers;
+ const char *sym, *sym2;
+ char *mod_full_path;
+ servicefn func, func2;
+ int mod_type = PAM_MT_FAULTY_MOD;
+
+ D(("called."));
+ IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
- _pam_drop(mod_full_path);
- mod_path = NULL; /* no longer needed or trusted */
+ D(("_pam_add_handler: adding type %d, handler_type %d, module `%s'",
+ type, handler_type, mod_path));
- /* Now return error if necessary after trying all possible ways... */
- if (success != PAM_SUCCESS)
- return(success);
+ if (handler_type == PAM_HT_MODULE && mod_path != NULL) {
+ if (mod_path[0] == '/') {
+ mod = _pam_load_module(pamh, mod_path);
+ } else if (asprintf(&mod_full_path, "%s%s",
+ DEFAULT_MODULE_PATH, mod_path) >= 0) {
+ mod = _pam_load_module(pamh, mod_full_path);
+ _pam_drop(mod_full_path);
+ } else {
+ pam_syslog(pamh, LOG_CRIT, "cannot malloc full mod path");
+ return PAM_ABORT;
+ }
+
+ if (mod == NULL) {
+ /* if we get here with NULL it means allocation error */
+ return PAM_ABORT;
+ }
+
+ mod_type = mod->type;
+ }
+
+ if (mod_path == NULL)
+ mod_path = UNKNOWN_MODULE;
/*
- * At this point 'mod' points to the stored/loaded module. If its
- * dl_handle is unknown, then we must be able to indicate dispatch
- * failure with 'must_fail'
+ * At this point 'mod' points to the stored/loaded module.
*/
/* Now define the handler(s) based on mod->dlhandle and type */
@@ -780,43 +814,43 @@ int _pam_add_handler(pam_handle_t *pamh
/* are the modules reliable? */
if (
#ifdef PAM_STATIC
- mod->type != PAM_MT_STATIC_MOD
+ mod_type != PAM_MT_STATIC_MOD
&&
#else
- mod->type != PAM_MT_DYNAMIC_MOD
+ mod_type != PAM_MT_DYNAMIC_MOD
&&
#endif
- mod->type != PAM_MT_FAULTY_MOD
+ mod_type != PAM_MT_FAULTY_MOD
) {
- D(("_pam_add_handlers: illegal module library type; %d", mod->type));
+ D(("_pam_add_handlers: illegal module library type; %d", mod_type));
pam_syslog(pamh, LOG_ERR,
"internal error: module library type not known: %s;%d",
- sym, mod->type);
+ sym, mod_type);
return PAM_ABORT;
}
/* now identify this module's functions - for non-faulty modules */
#ifdef PAM_STATIC
- if ((mod->type == PAM_MT_STATIC_MOD) &&
+ if ((mod_type == PAM_MT_STATIC_MOD) &&
(func = (servicefn)_pam_get_static_sym(mod->dl_handle, sym)) == NULL) {
pam_syslog(pamh, LOG_ERR, "unable to resolve static symbol: %s", sym);
}
#else
- if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
+ if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
!(func = _pam_dlsym(mod->dl_handle, sym)) ) {
pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym);
}
#endif
if (sym2) {
#ifdef PAM_STATIC
- if ((mod->type == PAM_MT_STATIC_MOD) &&
+ if ((mod_type == PAM_MT_STATIC_MOD) &&
(func2 = (servicefn)_pam_get_static_sym(mod->dl_handle, sym2))
== NULL) {
pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym2);
}
#else
- if ((mod->type == PAM_MT_DYNAMIC_MOD) &&
+ if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
!(func2 = _pam_dlsym(mod->dl_handle, sym2)) ) {
pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym2);
}
@@ -835,14 +869,15 @@ int _pam_add_handler(pam_handle_t *pamh
return (PAM_ABORT);
}
- (*handler_p)->must_fail = must_fail; /* failure forced? */
+ (*handler_p)->handler_type = handler_type;
+ (*handler_p)->stack_level = stack_level;
(*handler_p)->func = func;
memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
(*handler_p)->cached_retval = _PAM_INVALID_RETVAL;
(*handler_p)->cached_retval_p = &((*handler_p)->cached_retval);
(*handler_p)->argc = argc;
(*handler_p)->argv = argv; /* not a copy */
- (*handler_p)->mod_name = extract_modulename(mod->name);
+ (*handler_p)->mod_name = extract_modulename(mod_path);
(*handler_p)->next = NULL;
/* some of the modules have a second calling function */
@@ -857,7 +892,8 @@ int _pam_add_handler(pam_handle_t *pamh
return (PAM_ABORT);
}
- (*handler_p2)->must_fail = must_fail; /* failure forced? */
+ (*handler_p2)->handler_type = handler_type;
+ (*handler_p2)->stack_level = stack_level;
(*handler_p2)->func = func2;
memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
(*handler_p2)->cached_retval = _PAM_INVALID_RETVAL; /* ignored */
@@ -873,7 +909,7 @@ int _pam_add_handler(pam_handle_t *pamh
} else {
(*handler_p2)->argv = NULL; /* no arguments */
}
- (*handler_p2)->mod_name = extract_modulename(mod->name);
+ (*handler_p2)->mod_name = extract_modulename(mod_path);
(*handler_p2)->next = NULL;
}
Index: libpam/pam_private.h
===================================================================
RCS file: /cvsroot/pam/Linux-PAM/libpam/pam_private.h,v
retrieving revision 1.19
diff -u -p -r1.19 pam_private.h
--- libpam/pam_private.h 24 Jul 2006 15:47:40 -0000 1.19
+++ libpam/pam_private.h 12 Oct 2007 16:23:37 -0000
@@ -44,7 +44,7 @@
#define _PAM_INVALID_RETVAL -1 /* default value for cached_retval */
struct handler {
- int must_fail;
+ int handler_type;
int (*func)(pam_handle_t *pamh, int flags, int argc, char **argv);
int actions[_PAM_RETURN_VALUES];
/* set by authenticate, open_session, chauthtok(1st)
@@ -54,8 +54,13 @@ struct handler {
char **argv;
struct handler *next;
char *mod_name;
+ int stack_level;
};
+#define PAM_HT_MODULE 0
+#define PAM_HT_MUST_FAIL 1
+#define PAM_HT_SUBSTACK 2
+
struct loaded_module {
char *name;
int type; /* PAM_STATIC_MOD or PAM_DYNAMIC_MOD */
@@ -76,7 +81,7 @@ struct handlers {
};
struct service {
- struct loaded_module *module; /* Only used for dynamic loading */
+ struct loaded_module *module; /* Array of modules */
int modules_allocated;
int modules_used;
int handlers_loaded;
@@ -111,6 +116,12 @@ struct _pam_fail_delay {
const void *delay_fn_ptr;
};
+/* initial state in substack */
+struct _pam_substack_state {
+ int impression;
+ int status;
+};
+
struct _pam_former_state {
/* this is known and set by _pam_dispatch() */
int choice; /* which flavor of module function did we call? */
@@ -119,6 +130,7 @@ struct _pam_former_state {
int depth; /* how deep in the stack were we? */
int impression; /* the impression at that time */
int status; /* the status before returning incomplete */
+ struct _pam_substack_state *substates; /* array of initial substack states */
/* state info used by pam_get_user() function */
int fail_user;
@@ -175,6 +187,8 @@ struct pam_handle {
#define _PAM_ACTION_UNDEF -6 /* this is treated as an error
( = _PAM_ACTION_BAD) */
+#define PAM_SUBSTACK_MAX_LEVEL 16 /* maximum level of substacks */
+
/* character tables for parsing config files */
extern const char * const _pam_token_actions[-_PAM_ACTION_UNDEF];
extern const char * const _pam_token_returns[_PAM_RETURN_VALUES+1];
Index: libpam/pam_start.c
===================================================================
RCS file: /cvsroot/pam/Linux-PAM/libpam/pam_start.c,v
retrieving revision 1.9
diff -u -p -r1.9 pam_start.c
--- libpam/pam_start.c 24 Jul 2006 15:47:40 -0000 1.9
+++ libpam/pam_start.c 12 Oct 2007 16:23:37 -0000
@@ -88,6 +88,7 @@ int pam_start (
(*pamh)->oldauthtok = NULL;
(*pamh)->fail_delay.delay_fn_ptr = NULL;
(*pamh)->former.choice = PAM_NOT_STACKED;
+ (*pamh)->former.substates = NULL;
#ifdef HAVE_LIBAUDIT
(*pamh)->audit_state = 0;
#endif
Index: doc/man/pam.conf-syntax.xml
===================================================================
RCS file: /cvsroot/pam/Linux-PAM/doc/man/pam.conf-syntax.xml,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- doc/man/pam.conf-syntax.xml 26 Aug 2007 22:44:51 -0000 1.4
+++ doc/man/pam.conf-syntax.xml 19 Oct 2007 17:06:30 -0000 1.5
@@ -180,6 +180,24 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>substack</term>
+ <listitem>
+ <para>
+ include all lines of given type from the configuration
+ file specified as an argument to this control. This differs from
+ <emphasis>include</emphasis> in that evaluation of the
+ <emphasis>done</emphasis> and <emphasis>die</emphasis> actions
+ in a substack does not cause skipping the rest of the complete
+ module stack, but only of the substack. Jumps in a substack
+ also can not make evaluation jump out of it, and the whole substack
+ is counted as one module when the jump is done in a parent stack.
+ The <emphasis>reset</emphasis> action will reset the state of a
+ module stack to the state it was in as of beginning of the substack
+ evaluation.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<para>

View File

@ -1,32 +0,0 @@
Written-by: Tomas Mraz <tmraz@redhat.com>
Reviewed-by: Karel Zak <kzak@redhat.com>
diff -up Linux-PAM-0.99.8.1/modules/pam_succeed_if/pam_succeed_if.c.in-operator Linux-PAM-0.99.8.1/modules/pam_succeed_if/pam_succeed_if.c
--- Linux-PAM-0.99.8.1/modules/pam_succeed_if/pam_succeed_if.c.in-operator 2006-08-31 12:20:39.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_succeed_if/pam_succeed_if.c 2007-09-19 19:36:22.000000000 +0200
@@ -191,13 +191,19 @@ static int
evaluate_inlist(const char *left, const char *right)
{
char *p;
- if ((p=strstr(right, left)) == NULL)
- return PAM_AUTH_ERR;
- if (p == right || *(p-1) == ':') { /* ':' is a list separator */
- p += strlen(left);
- if (*p == '\0' || *p == ':') {
- return PAM_SUCCESS;
+ /* Don't care about left containing ':'. */
+ while ((p=strstr(right, left)) != NULL) {
+ if (p == right || *(p-1) == ':') { /* ':' is a list separator */
+ p += strlen(left);
+ if (*p == '\0' || *p == ':') {
+ return PAM_SUCCESS;
+ }
}
+ right = strchr(p, ':');
+ if (right == NULL)
+ break;
+ else
+ ++right;
}
return PAM_AUTH_ERR;
}

View File

@ -1,590 +0,0 @@
Written-by: Miloslav Trmac <mitr@redhat.com>
Reviewed-by: Tomas Mraz <tmraz@redhat.com>
diff -urN Linux-PAM/configure.in Linux-PAM-0.99.8.1/configure.in
--- Linux-PAM/configure.in 2007-11-28 13:41:14.000000000 +0100
+++ Linux-PAM-0.99.8.1/configure.in 2007-11-28 14:35:30.000000000 +0100
@@ -331,7 +331,11 @@
WITH_LIBAUDIT=$enableval, WITH_LIBAUDIT=yes)
if test x"$WITH_LIBAUDIT" != xno ; then
AC_CHECK_HEADER([libaudit.h],
- [AC_CHECK_LIB(audit, audit_log_acct_message, LIBAUDIT=-laudit, LIBAUDIT="")]
+ [AC_CHECK_LIB(audit, audit_log_acct_message, LIBAUDIT=-laudit, LIBAUDIT="")
+ AC_CHECK_TYPE([struct audit_tty_status],
+ [HAVE_AUDIT_TTY_STATUS=yes],
+ [HAVE_AUDIT_TTY_STATUS=""],
+ [#include <libaudit.h>])]
)
if test ! -z "$LIBAUDIT" -a "ac_cv_header_libaudit_h" != "no" ; then
AC_DEFINE([HAVE_LIBAUDIT], 1, [Defined if audit support should be compiled in])
@@ -340,6 +344,8 @@
LIBAUDIT=""
fi
AC_SUBST(LIBAUDIT)
+AM_CONDITIONAL([HAVE_AUDIT_TTY_STATUS],
+ [test "x$HAVE_AUDIT_TTY_STATUS" = xyes])
BACKUP_LIBS=$LIBS
AC_SEARCH_LIBS([crypt],[xcrypt crypt], LIBCRYPT="-l$ac_lib", LIBCRYPT="")
@@ -517,7 +523,8 @@
modules/pam_securetty/Makefile modules/pam_selinux/Makefile \
modules/pam_shells/Makefile modules/pam_stress/Makefile \
modules/pam_succeed_if/Makefile modules/pam_tally/Makefile \
- modules/pam_time/Makefile modules/pam_umask/Makefile \
+ modules/pam_time/Makefile modules/pam_tty_audit/Makefile \
+ modules/pam_umask/Makefile \
modules/pam_unix/Makefile modules/pam_userdb/Makefile \
modules/pam_warn/Makefile modules/pam_wheel/Makefile \
modules/pam_xauth/Makefile doc/Makefile doc/specs/Makefile \
diff -urN Linux-PAM/modules/Makefile.am Linux-PAM-0.99.8.1/modules/Makefile.am
--- Linux-PAM/modules/Makefile.am 2007-11-28 13:41:13.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/Makefile.am 2007-11-28 14:02:48.000000000 +0100
@@ -9,8 +9,8 @@
pam_lastlog pam_limits pam_listfile pam_localuser pam_mail \
pam_mkhomedir pam_motd pam_nologin pam_permit pam_rhosts pam_rootok \
pam_securetty pam_selinux pam_shells pam_stress pam_succeed_if \
- pam_tally pam_time pam_umask pam_unix pam_userdb pam_warn \
- pam_wheel pam_xauth pam_exec pam_namespace pam_loginuid \
+ pam_tally pam_time pam_tty_audit pam_umask pam_unix pam_userdb \
+ pam_warn pam_wheel pam_xauth pam_exec pam_namespace pam_loginuid \
pam_faildelay
CLEANFILES = *~
diff -urN Linux-PAM/modules/pam_tty_audit/Makefile.am Linux-PAM-0.99.8.1/modules/pam_tty_audit/Makefile.am
--- Linux-PAM/modules/pam_tty_audit/Makefile.am 1970-01-01 01:00:00.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_tty_audit/Makefile.am 2007-11-28 16:05:00.000000000 +0100
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2005, 2006 Thorsten Kukuk <kukuk@suse.de>
+#
+
+CLEANFILES = *~
+
+EXTRA_DIST = README ${MANS} $(XMLS)
+
+man_MANS = pam_tty_audit.8
+XMLS = README.xml pam_tty_audit.8.xml
+
+securelibdir = $(SECUREDIR)
+
+AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include
+AM_LDFLAGS = -no-undefined -avoid-version -module \
+ -L$(top_builddir)/libpam -lpam
+if HAVE_VERSIONING
+ AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map
+endif
+
+if HAVE_AUDIT_TTY_STATUS
+ securelib_LTLIBRARIES = pam_tty_audit.la
+endif
+
+if ENABLE_REGENERATE_MAN
+noinst_DATA = README
+README: pam_tty_audit.8.xml
+-include $(top_srcdir)/Make.xml.rules
+endif
+
diff -urN Linux-PAM/modules/pam_tty_audit/pam_tty_audit.c Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.c
--- Linux-PAM/modules/pam_tty_audit/pam_tty_audit.c 1970-01-01 01:00:00.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.c 2007-11-28 16:10:43.000000000 +0100
@@ -0,0 +1,332 @@
+/* Copyright © 2007 Red Hat, Inc. All rights reserved.
+ Red Hat author: Miloslav Trmač <mitr@redhat.com>
+
+ Redistribution and use in source and binary forms of Linux-PAM, with
+ or without modification, are permitted provided that the following
+ conditions are met:
+
+ 1. Redistributions of source code must retain any existing copyright
+ notice, and this entire permission notice in its entirety,
+ including the disclaimer of warranties.
+
+ 2. Redistributions in binary form must reproduce all prior and current
+ copyright notices, this list of conditions, and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ 3. The name of any author may not be used to endorse or promote
+ products derived from this software without their specific prior
+ written permission.
+
+ ALTERNATIVELY, this product may be distributed under the terms of the
+ GNU General Public License, in which case the provisions of the GNU
+ GPL are required INSTEAD OF the above restrictions. (This clause is
+ necessary due to a potential conflict between the GNU GPL and the
+ restrictions contained in a BSD-style copyright.)
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE. */
+
+#include <errno.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <libaudit.h>
+#include <linux/netlink.h>
+#include <security/pam_ext.h>
+#include <security/pam_modules.h>
+#include <security/pam_modutil.h>
+
+#define DATANAME "pam_tty_audit_last_state"
+
+/* Open an audit netlink socket */
+static int
+nl_open (void)
+{
+ return socket (AF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
+}
+
+static int
+nl_send (int fd, unsigned type, unsigned flags, const void *data, size_t size)
+{
+ struct sockaddr_nl addr;
+ struct msghdr msg;
+ struct nlmsghdr nlm;
+ struct iovec iov[2];
+ ssize_t res;
+
+ nlm.nlmsg_len = NLMSG_LENGTH (size);
+ nlm.nlmsg_type = type;
+ nlm.nlmsg_flags = NLM_F_REQUEST | flags;
+ nlm.nlmsg_seq = 0;
+ nlm.nlmsg_pid = 0;
+ iov[0].iov_base = &nlm;
+ iov[0].iov_len = sizeof (nlm);
+ iov[1].iov_base = (void *)data;
+ iov[1].iov_len = size;
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = 0;
+ addr.nl_groups = 0;
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof (addr);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+ res = sendmsg (fd, &msg, 0);
+ if (res == -1)
+ return -1;
+ if ((size_t)res != nlm.nlmsg_len)
+ {
+ errno = EIO;
+ return -1;
+ }
+ return 0;
+}
+
+static int
+nl_recv (int fd, unsigned type, void *buf, size_t size)
+{
+ struct sockaddr_nl addr;
+ struct msghdr msg;
+ struct nlmsghdr nlm;
+ struct iovec iov[2];
+ ssize_t res;
+
+ again:
+ iov[0].iov_base = &nlm;
+ iov[0].iov_len = sizeof (nlm);
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof (addr);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ if (type != NLMSG_ERROR)
+ {
+ res = recvmsg (fd, &msg, MSG_PEEK);
+ if (res == -1)
+ return -1;
+ if (res != NLMSG_LENGTH (0))
+ {
+ errno = EIO;
+ return -1;
+ }
+ if (nlm.nlmsg_type == NLMSG_ERROR)
+ {
+ struct nlmsgerr err;
+
+ iov[1].iov_base = &err;
+ iov[1].iov_len = sizeof (err);
+ msg.msg_iovlen = 2;
+ res = recvmsg (fd, &msg, 0);
+ if (res == -1)
+ return -1;
+ if ((size_t)res != NLMSG_LENGTH (sizeof (err))
+ || nlm.nlmsg_type != NLMSG_ERROR)
+ {
+ errno = EIO;
+ return -1;
+ }
+ if (err.error == 0)
+ goto again;
+ errno = -err.error;
+ return -1;
+ }
+ }
+ if (size != 0)
+ {
+ iov[1].iov_base = buf;
+ iov[1].iov_len = size;
+ msg.msg_iovlen = 2;
+ }
+ res = recvmsg (fd, &msg, 0);
+ if (res == -1)
+ return -1;
+ if ((size_t)res != NLMSG_LENGTH (size)
+ || nlm.nlmsg_type != type)
+ {
+ errno = EIO;
+ return -1;
+ }
+ return 0;
+}
+
+static int
+nl_recv_ack (int fd)
+{
+ struct nlmsgerr err;
+
+ if (nl_recv (fd, NLMSG_ERROR, &err, sizeof (err)) != 0)
+ return -1;
+ if (err.error != 0)
+ {
+ errno = -err.error;
+ return -1;
+ }
+ return 0;
+}
+
+static void
+cleanup_old_status (pam_handle_t *pamh, void *data, int error_status)
+{
+ (void)pamh;
+ (void)error_status;
+ free (data);
+}
+
+int
+pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ enum command { CMD_NONE, CMD_ENABLE, CMD_DISABLE };
+
+ enum command command;
+ struct audit_tty_status *old_status, new_status;
+ const char *user;
+ uid_t user_uid;
+ struct passwd *pwd;
+ int i, fd;
+
+ (void)flags;
+
+ if (pam_get_user (pamh, &user, NULL) != PAM_SUCCESS)
+ {
+ pam_syslog (pamh, LOG_ERR, "error determining target user's name");
+ return PAM_SESSION_ERR;
+ }
+ pwd = pam_modutil_getpwnam (pamh, user);
+ if (pwd == NULL)
+ {
+ pam_syslog (pamh, LOG_ERR, "error determining target user's UID: %m");
+ return PAM_SESSION_ERR;
+ }
+ user_uid = pwd->pw_uid;
+
+ command = CMD_NONE;
+ for (i = 0; i < argc; i++)
+ {
+ if (strncmp (argv[i], "enable=", 7) == 0
+ || strncmp (argv[i], "disable=", 8) == 0)
+ {
+ enum command this_command;
+ char *copy, *tok_data, *tok;
+
+ this_command = *argv[i] == 'e' ? CMD_ENABLE : CMD_DISABLE;
+ copy = strdup (strchr (argv[i], '=') + 1);
+ if (copy == NULL)
+ return PAM_SESSION_ERR;
+ for (tok = strtok_r (copy, ",", &tok_data); tok != NULL;
+ tok = strtok_r (NULL, ",", &tok_data))
+ {
+ pwd = pam_modutil_getpwnam (pamh, tok);
+ if (pwd == NULL)
+ {
+ pam_syslog (pamh, LOG_WARNING, "unknown user %s", tok);
+ continue;
+ }
+ if (pwd->pw_uid == user_uid)
+ {
+ command = this_command;
+ break;
+ }
+ }
+ free (copy);
+ }
+ }
+ if (command == CMD_NONE)
+ return PAM_SUCCESS;
+
+ old_status = malloc (sizeof (*old_status));
+ if (old_status == NULL)
+ return PAM_SESSION_ERR;
+
+ fd = nl_open ();
+ if (fd == -1
+ || nl_send (fd, AUDIT_TTY_GET, 0, NULL, 0) != 0
+ || nl_recv (fd, AUDIT_TTY_GET, old_status, sizeof (*old_status)) != 0)
+ {
+ pam_syslog (pamh, LOG_ERR, "error reading current audit status: %m");
+ if (fd != -1)
+ close (fd);
+ free (old_status);
+ return PAM_SESSION_ERR;
+ }
+
+ if (old_status->enabled == (command == CMD_ENABLE ? 1 : 0))
+ {
+ free (old_status);
+ goto ok_fd;
+ }
+
+ if (pam_set_data (pamh, DATANAME, old_status, cleanup_old_status)
+ != PAM_SUCCESS)
+ {
+ pam_syslog (pamh, LOG_ERR, "error saving old audit status");
+ close (fd);
+ free (old_status);
+ return PAM_SESSION_ERR;
+ }
+
+ new_status.enabled = (command == CMD_ENABLE ? 1 : 0);
+ if (nl_send (fd, AUDIT_TTY_SET, NLM_F_ACK, &new_status,
+ sizeof (new_status)) != 0
+ || nl_recv_ack (fd) != 0)
+ {
+ pam_syslog (pamh, LOG_ERR, "error setting current audit status: %m");
+ close (fd);
+ return PAM_SESSION_ERR;
+ }
+ /* Fall through */
+ ok_fd:
+ close (fd);
+ pam_syslog (pamh, LOG_DEBUG, "changed status from %d to %d",
+ old_status->enabled, new_status.enabled);
+ return PAM_SUCCESS;
+}
+
+int
+pam_sm_close_session (pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ const void *status_;
+
+ (void)flags;
+ (void)argc;
+ (void)argv;
+ if (pam_get_data (pamh, DATANAME, &status_) == PAM_SUCCESS)
+ {
+ const struct audit_tty_status *status;
+ int fd;
+
+ status = status_;
+
+ fd = nl_open ();
+ if (fd == -1
+ || nl_send (fd, AUDIT_TTY_SET, NLM_F_ACK, status,
+ sizeof (*status)) != 0
+ || nl_recv_ack (fd) != 0)
+ {
+ pam_syslog (pamh, LOG_ERR, "error restoring audit status: %m");
+ if (fd != -1)
+ close (fd);
+ return PAM_SESSION_ERR;
+ }
+ close (fd);
+ pam_syslog (pamh, LOG_ERR, "restored status to %d", status->enabled);
+ }
+ return PAM_SUCCESS;
+}
diff -urN Linux-PAM/modules/pam_tty_audit/pam_tty_audit.8.xml Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.8.xml
--- Linux-PAM/modules/pam_tty_audit/pam_tty_audit.8.xml 1970-01-01 01:00:00.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.8.xml 2007-11-28 15:50:22.000000000 +0100
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding='UTF-8'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
+
+<refentry id="pam_tty_audit">
+
+ <refmeta>
+ <refentrytitle>pam_tty_audit</refentrytitle>
+ <manvolnum>8</manvolnum>
+ <refmiscinfo class="sectdesc">Linux-PAM Manual</refmiscinfo>
+ </refmeta>
+
+ <refnamediv id="pam_tty_audit-name">
+ <refname>pam_tty_audit</refname>
+ <refpurpose>Enable or disable TTY auditing for specified users</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis id="pam_tty_audit-cmdsynopsis">
+ <command>pam_tty_audit.so</command>
+ <arg choice="opt">
+ disable=<replaceable>usernames</replaceable>
+ </arg>
+ <arg choice="opt">
+ enable=<replaceable>usernames</replaceable>
+ </arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="pam_tty_audit-description">
+ <title>DESCRIPTION</title>
+ <para>
+ The pam_tty_audit PAM module is used to enable or disable TTY auditing.
+ By default, the kernel does not audit input on any TTY.
+ </para>
+ </refsect1>
+
+ <refsect1 id="pam_tty_audit-options">
+ <title>OPTIONS</title>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <option>disable=<replaceable>usernames</replaceable></option>
+ </term>
+ <listitem>
+ <para>
+ For each user matching one of comma-separated
+ <option><replaceable>usernames</replaceable></option>, disable
+ TTY auditing. This overrides any older <option>enable</option>
+ option for the same user name.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>enable=<replaceable>usernames</replaceable></option>
+ </term>
+ <listitem>
+ <para>
+ For each user matching one of comma-separated
+ <option><replaceable>usernames</replaceable></option>, enable
+ TTY auditing. This overrides any older <option>disable</option>
+ option for the same user name.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id="pam_tty_audit-services">
+ <title>MODULE SERVICES PROVIDED</title>
+ <para>
+ Only the <emphasis remap='B'>session</emphasis> service is supported.
+ </para>
+ </refsect1>
+
+ <refsect1 id='pam_tty_audit-return_values'>
+ <title>RETURN VALUES</title>
+ <variablelist>
+ <varlistentry>
+ <term>PAM_SESSION_ERR</term>
+ <listitem>
+ <para>
+ Error reading or modifying the TTY audit flag. See the system log
+ for more details.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>PAM_SUCCESS</term>
+ <listitem>
+ <para>
+ Success.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id='pam_tty_audit-examples'>
+ <title>EXAMPLES</title>
+ <para>
+ Audit all administrative actions.
+ <programlisting>
+login root required pam_tty_audit.so enable=root
+su root required pam_tty_audit.so enable=root
+su-l root required pam_tty_audit.so enable=root
+sudo root required pam_tty_audit.so enable=root
+sudo-l root required pam_tty_audit.so enable=root
+sshd root required pam_tty_audit.so enable=root
+ </programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1 id='pam_tty_audit-author'>
+ <title>AUTHOR</title>
+ <para>
+ pam_tty_audit was written by Miloslav Trma&ccaron;
+ &lt;mitr@redhat.com&gt;.
+ </para>
+ </refsect1>
+
+</refentry>
diff -urN Linux-PAM/modules/pam_tty_audit/README.xml Linux-PAM-0.99.8.1/modules/pam_tty_audit/README.xml
--- Linux-PAM/modules/pam_tty_audit/README.xml 1970-01-01 01:00:00.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_tty_audit/README.xml 2007-11-28 15:52:50.000000000 +0100
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding='UTF-8'?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+"http://www.docbook.org/xml/4.3/docbookx.dtd">
+
+<article>
+
+ <articleinfo>
+
+ <title>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="pam_tty_audit.8.xml" xpointer='xpointer(//refnamediv[@id = "pam_tty_audit-name"]/*)'/>
+ </title>
+
+ </articleinfo>
+
+ <section>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="pam_tty_audit.8.xml" xpointer='xpointer(//refsect1[@id = "pam_tty_audit-description"]/*)'/>
+ </section>
+
+ <section>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="pam_tty_audit.8.xml" xpointer='xpointer(//refsect1[@id = "pam_tty_audit-options"]/*)'/>
+ </section>
+
+ <section>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="pam_tty_audit.8.xml" xpointer='xpointer(//refsect1[@id = "pam_tty_audit-examples"]/*)'/>
+ </section>
+
+ <section>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="pam_tty_audit.8.xml" xpointer='xpointer(//refsect1[@id = "pam_tty_audit-author"]/*)'/>
+ </section>
+
+</article>

View File

@ -1,233 +0,0 @@
Written-by: Miloslav Trmac <mitr@redhat.com>
Reviewed-by: Tomas Mraz <tmraz@redhat.com>
diff -up Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.8.xml.tty-audit2 Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.8.xml
--- Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.8.xml.tty-audit2 2008-01-02 11:28:26.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.8.xml 2008-01-02 11:29:55.000000000 +0100
@@ -19,10 +19,10 @@
<cmdsynopsis id="pam_tty_audit-cmdsynopsis">
<command>pam_tty_audit.so</command>
<arg choice="opt">
- disable=<replaceable>usernames</replaceable>
+ disable=<replaceable>patterns</replaceable>
</arg>
<arg choice="opt">
- enable=<replaceable>usernames</replaceable>
+ enable=<replaceable>patterns</replaceable>
</arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -40,27 +40,40 @@
<variablelist>
<varlistentry>
<term>
- <option>disable=<replaceable>usernames</replaceable></option>
+ <option>disable=<replaceable>patterns</replaceable></option>
</term>
<listitem>
<para>
- For each user matching one of comma-separated
- <option><replaceable>usernames</replaceable></option>, disable
- TTY auditing. This overrides any older <option>enable</option>
- option for the same user name.
+ For each user matching one of comma-separated glob
+ <option><replaceable>patterns</replaceable></option>, disable
+ TTY auditing. This overrides any previous <option>enable</option>
+ option matchin the same user name on the command line.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
- <option>enable=<replaceable>usernames</replaceable></option>
+ <option>enable=<replaceable>patterns</replaceable></option>
</term>
<listitem>
<para>
- For each user matching one of comma-separated
- <option><replaceable>usernames</replaceable></option>, enable
- TTY auditing. This overrides any older <option>disable</option>
- option for the same user name.
+ For each user matching one of comma-separated glob
+ <option><replaceable>patterns</replaceable></option>, enable
+ TTY auditing. This overrides any previous <option>disable</option>
+ option matching the same user name on the command line.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <option>open_only</option>
+ </term>
+ <listitem>
+ <para>
+ Set the TTY audit flag when opening the session, but do not restore
+ it when closing the session. Using this option is necessary for
+ some services that don't <function>fork()</function> to run the
+ authenticated session, such as <command>sudo</command>.
</para>
</listitem>
</varlistentry>
@@ -99,17 +112,24 @@
</variablelist>
</refsect1>
+ <refsect1 id='pam_tty_audit-notes'>
+ <title>NOTES</title>
+ <para>
+ When TTY auditing is enabled, it is inherited by all processes started by
+ that user. In particular, daemons restarted by an user will still have
+ TTY auditing enabled, and audit TTY input even by other users unless
+ auditing for these users is explicitly disabled. Therefore, it is
+ recommended to use <option>disable=*</option> as the first option for
+ most daemons using PAM.
+ </para>
+ </refsect1>
+
<refsect1 id='pam_tty_audit-examples'>
<title>EXAMPLES</title>
<para>
Audit all administrative actions.
<programlisting>
-login root required pam_tty_audit.so enable=root
-su root required pam_tty_audit.so enable=root
-su-l root required pam_tty_audit.so enable=root
-sudo root required pam_tty_audit.so enable=root
-sudo-l root required pam_tty_audit.so enable=root
-sshd root required pam_tty_audit.so enable=root
+session required pam_tty_audit.so disable=* enable=root
</programlisting>
</para>
</refsect1>
diff -up Linux-PAM-0.99.8.1/modules/pam_tty_audit/README.xml.tty-audit2 Linux-PAM-0.99.8.1/modules/pam_tty_audit/README.xml
--- Linux-PAM-0.99.8.1/modules/pam_tty_audit/README.xml.tty-audit2 2008-01-02 11:28:26.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_tty_audit/README.xml 2008-01-02 11:28:26.000000000 +0100
@@ -25,6 +25,11 @@
<section>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
+ href="pam_tty_audit.8.xml" xpointer='xpointer(//refsect1[@id = "pam_tty_audit-notes"]/*)'/>
+ </section>
+
+ <section>
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
href="pam_tty_audit.8.xml" xpointer='xpointer(//refsect1[@id = "pam_tty_audit-examples"]/*)'/>
</section>
diff -up Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.c.tty-audit2 Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.c
--- Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.c.tty-audit2 2008-01-02 11:28:26.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_tty_audit/pam_tty_audit.c 2008-01-02 11:28:26.000000000 +0100
@@ -1,4 +1,4 @@
-/* Copyright © 2007 Red Hat, Inc. All rights reserved.
+/* Copyright © 2007, 2008 Red Hat, Inc. All rights reserved.
Red Hat author: Miloslav Trmač <mitr@redhat.com>
Redistribution and use in source and binary forms of Linux-PAM, with
@@ -37,7 +37,7 @@
DAMAGE. */
#include <errno.h>
-#include <pwd.h>
+#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
@@ -197,9 +197,7 @@ pam_sm_open_session (pam_handle_t *pamh,
enum command command;
struct audit_tty_status *old_status, new_status;
const char *user;
- uid_t user_uid;
- struct passwd *pwd;
- int i, fd;
+ int i, fd, open_only;
(void)flags;
@@ -208,15 +206,9 @@ pam_sm_open_session (pam_handle_t *pamh,
pam_syslog (pamh, LOG_ERR, "error determining target user's name");
return PAM_SESSION_ERR;
}
- pwd = pam_modutil_getpwnam (pamh, user);
- if (pwd == NULL)
- {
- pam_syslog (pamh, LOG_ERR, "error determining target user's UID: %m");
- return PAM_SESSION_ERR;
- }
- user_uid = pwd->pw_uid;
command = CMD_NONE;
+ open_only = 0;
for (i = 0; i < argc; i++)
{
if (strncmp (argv[i], "enable=", 7) == 0
@@ -232,13 +224,7 @@ pam_sm_open_session (pam_handle_t *pamh,
for (tok = strtok_r (copy, ",", &tok_data); tok != NULL;
tok = strtok_r (NULL, ",", &tok_data))
{
- pwd = pam_modutil_getpwnam (pamh, tok);
- if (pwd == NULL)
- {
- pam_syslog (pamh, LOG_WARNING, "unknown user %s", tok);
- continue;
- }
- if (pwd->pw_uid == user_uid)
+ if (fnmatch (tok, user, 0) == 0)
{
command = this_command;
break;
@@ -246,6 +232,13 @@ pam_sm_open_session (pam_handle_t *pamh,
}
free (copy);
}
+ else if (strcmp (argv[i], "open_only") == 0)
+ open_only = 1;
+ else
+ {
+ pam_syslog (pamh, LOG_ERR, "unknown option `%s'", argv[i]);
+ return PAM_SESSION_ERR;
+ }
}
if (command == CMD_NONE)
return PAM_SUCCESS;
@@ -266,13 +259,15 @@ pam_sm_open_session (pam_handle_t *pamh,
return PAM_SESSION_ERR;
}
- if (old_status->enabled == (command == CMD_ENABLE ? 1 : 0))
+ new_status.enabled = (command == CMD_ENABLE ? 1 : 0);
+ if (old_status->enabled == new_status.enabled)
{
free (old_status);
goto ok_fd;
}
- if (pam_set_data (pamh, DATANAME, old_status, cleanup_old_status)
+ if (open_only == 0
+ && pam_set_data (pamh, DATANAME, old_status, cleanup_old_status)
!= PAM_SUCCESS)
{
pam_syslog (pamh, LOG_ERR, "error saving old audit status");
@@ -281,13 +276,14 @@ pam_sm_open_session (pam_handle_t *pamh,
return PAM_SESSION_ERR;
}
- new_status.enabled = (command == CMD_ENABLE ? 1 : 0);
if (nl_send (fd, AUDIT_TTY_SET, NLM_F_ACK, &new_status,
sizeof (new_status)) != 0
|| nl_recv_ack (fd) != 0)
{
pam_syslog (pamh, LOG_ERR, "error setting current audit status: %m");
close (fd);
+ if (open_only != 0)
+ free (old_status);
return PAM_SESSION_ERR;
}
/* Fall through */
@@ -295,6 +291,8 @@ pam_sm_open_session (pam_handle_t *pamh,
close (fd);
pam_syslog (pamh, LOG_DEBUG, "changed status from %d to %d",
old_status->enabled, new_status.enabled);
+ if (open_only != 0)
+ free (old_status);
return PAM_SUCCESS;
}

View File

@ -1,50 +0,0 @@
diff -up Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h.unix-hpux-aging Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h
--- Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h.unix-hpux-aging 2008-01-08 14:43:36.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h 2008-01-08 15:49:43.000000000 +0100
@@ -13,7 +13,7 @@
#define OLD_PASSWORDS_FILE "/etc/security/opasswd"
int
-verify_pwd_hash(const char *p, const char *hash, unsigned int nullok);
+verify_pwd_hash(const char *p, char *hash, unsigned int nullok);
int
is_pwd_shadowed(const struct passwd *pwd);
diff -up Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c.unix-hpux-aging Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c
--- Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c.unix-hpux-aging 2008-01-08 14:43:36.000000000 +0100
+++ Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c 2008-01-08 15:49:02.000000000 +0100
@@ -44,14 +44,32 @@
# include "./lckpwdf.-c"
#endif
+static void
+strip_hpux_aging(char *p)
+{
+ const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789./";
+ if ((*p != '$') && (strlen(p) > 13)) {
+ for (p += 13; *p != '\0'; p++) {
+ if (strchr(valid, *p) == NULL) {
+ *p = '\0';
+ break;
+ }
+ }
+ }
+}
+
int
-verify_pwd_hash(const char *p, const char *hash, unsigned int nullok)
+verify_pwd_hash(const char *p, char *hash, unsigned int nullok)
{
- size_t hash_len = strlen(hash);
+ size_t hash_len;
char *pp = NULL;
int retval;
D(("called"));
+ strip_hpux_aging(hash);
+ hash_len = strlen(hash);
if (!hash_len) {
/* the stored password is NULL */
if (nullok) { /* this means we've succeeded */

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +0,0 @@
diff -up Linux-PAM-0.99.8.1/modules/pam_xauth/pam_xauth.c.no-free Linux-PAM-0.99.8.1/modules/pam_xauth/pam_xauth.c
--- Linux-PAM-0.99.8.1/modules/pam_xauth/pam_xauth.c.no-free 2007-09-21 16:02:06.000000000 +0200
+++ Linux-PAM-0.99.8.1/modules/pam_xauth/pam_xauth.c 2007-09-21 16:02:47.000000000 +0200
@@ -573,6 +573,7 @@ pam_sm_open_session (pam_handle_t *pamh,
"can't set environment variable '%s'",
xauthority);
putenv (xauthority); /* The environment owns this string now. */
+ xauthority = NULL;
/* set $DISPLAY in pam handle to make su - work */
{

View File

@ -4,8 +4,8 @@
Summary: A security tool which provides authentication for applications Summary: A security tool which provides authentication for applications
Name: pam Name: pam
Version: 0.99.8.1 Version: 0.99.10.0
Release: 18%{?dist} Release: 1%{?dist}
# The library is BSD licensed with option to relicense as GPLv2+ - this option is redundant # 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+, # as the BSD license allows that anyway. pam_timestamp and pam_console modules are GPLv2+,
# pam_rhosts_auth module is BSD with advertising # pam_rhosts_auth module is BSD with advertising
@ -21,28 +21,15 @@ Source7: config-util.pamd
Source8: dlopen.sh Source8: dlopen.sh
Source9: system-auth.5 Source9: system-auth.5
Source10: config-util.5 Source10: config-util.5
Source11: 90-nproc.conf
Patch1: pam-0.99.7.0-redhat-modules.patch Patch1: pam-0.99.7.0-redhat-modules.patch
Patch2: db-4.6.18-glibc.patch Patch2: db-4.6.18-glibc.patch
Patch4: pam-0.99.8.1-dbpam.patch Patch4: pam-0.99.8.1-dbpam.patch
Patch5: pam-0.99.8.1-audit-no-log.patch Patch5: pam-0.99.8.1-audit-no-log.patch
Patch24: pam-0.99.8.1-unix-update-helper.patch
Patch25: pam-0.99.8.1-unix-hpux-aging.patch
Patch31: pam-0.99.3.0-cracklib-try-first-pass.patch Patch31: pam-0.99.3.0-cracklib-try-first-pass.patch
Patch32: pam-0.99.3.0-tally-fail-close.patch Patch32: pam-0.99.3.0-tally-fail-close.patch
Patch40: pam-0.99.7.1-namespace-temp-logon.patch
Patch41: pam-0.99.8.1-namespace-init.patch
Patch42: pam-0.99.8.1-console-hal-handled.patch Patch42: pam-0.99.8.1-console-hal-handled.patch
Patch43: pam-0.99.8.1-console-mfd-scanners.patch Patch43: pam-0.99.8.1-console-mfd-scanners.patch
Patch44: pam-0.99.7.1-namespace-homedir.patch
Patch45: pam-0.99.8.1-selinux-permit.patch
Patch46: pam-0.99.8.1-succif-in-operator.patch
Patch47: pam-0.99.8.1-xauth-no-free.patch
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
%define _sbindir /sbin %define _sbindir /sbin
%define _moduledir /%{_lib}/security %define _moduledir /%{_lib}/security
@ -113,24 +100,10 @@ pushd db-%{db_version}
popd popd
%patch4 -p1 -b .dbpam %patch4 -p1 -b .dbpam
%patch5 -p1 -b .no-log %patch5 -p1 -b .no-log
%patch24 -p1 -b .update-helper
%patch25 -p1 -b .unix-hpux-aging
%patch31 -p1 -b .try-first-pass %patch31 -p1 -b .try-first-pass
%patch32 -p1 -b .fail-close %patch32 -p1 -b .fail-close
%patch40 -p1 -b .temp-logon
%patch41 -p1 -b .ns-init
%patch42 -p1 -b .hal-handled %patch42 -p1 -b .hal-handled
%patch43 -p1 -b .mfd-scanners %patch43 -p1 -b .mfd-scanners
%patch44 -p1 -b .homedir
%patch45 -p1 -b .permit
%patch46 -p1 -b .in-operator
%patch47 -p1 -b .no-free
%patch48 -p0 -b .substack
%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 autoreconf
@ -191,6 +164,11 @@ done
# Install the binaries, libraries, and modules. # Install the binaries, libraries, and modules.
make install DESTDIR=$RPM_BUILD_ROOT LDCONFIG=: make install DESTDIR=$RPM_BUILD_ROOT LDCONFIG=:
%if %{WITH_SELINUX}
# Temporary compat link
ln -sf pam_sepermit.so $RPM_BUILD_ROOT%{_moduledir}/pam_selinux_permit.so
%endif
# RPM uses docs from source tree # RPM uses docs from source tree
rm -rf $RPM_BUILD_ROOT%{_datadir}/doc/Linux-PAM rm -rf $RPM_BUILD_ROOT%{_datadir}/doc/Linux-PAM
# Included in setup package # Included in setup package
@ -201,6 +179,7 @@ install -d -m 755 $RPM_BUILD_ROOT%{_pamconfdir}
install -m 644 %{SOURCE5} $RPM_BUILD_ROOT%{_pamconfdir}/other install -m 644 %{SOURCE5} $RPM_BUILD_ROOT%{_pamconfdir}/other
install -m 644 %{SOURCE6} $RPM_BUILD_ROOT%{_pamconfdir}/system-auth install -m 644 %{SOURCE6} $RPM_BUILD_ROOT%{_pamconfdir}/system-auth
install -m 644 %{SOURCE7} $RPM_BUILD_ROOT%{_pamconfdir}/config-util install -m 644 %{SOURCE7} $RPM_BUILD_ROOT%{_pamconfdir}/config-util
install -m 644 %{SOURCE11} $RPM_BUILD_ROOT%{_secconfdir}/limits.d/90-nproc.conf
install -m 600 /dev/null $RPM_BUILD_ROOT%{_secconfdir}/opasswd install -m 600 /dev/null $RPM_BUILD_ROOT%{_secconfdir}/opasswd
install -d -m 755 $RPM_BUILD_ROOT/var/log install -d -m 755 $RPM_BUILD_ROOT/var/log
install -m 600 /dev/null $RPM_BUILD_ROOT/var/log/faillog install -m 600 /dev/null $RPM_BUILD_ROOT/var/log/faillog
@ -331,12 +310,12 @@ fi
%{_moduledir}/pam_permit.so %{_moduledir}/pam_permit.so
%{_moduledir}/pam_postgresok.so %{_moduledir}/pam_postgresok.so
%{_moduledir}/pam_rhosts.so %{_moduledir}/pam_rhosts.so
%{_moduledir}/pam_rhosts_auth.so
%{_moduledir}/pam_rootok.so %{_moduledir}/pam_rootok.so
%{_moduledir}/pam_rps.so %{_moduledir}/pam_rps.so
%if %{WITH_SELINUX} %if %{WITH_SELINUX}
%{_moduledir}/pam_selinux.so %{_moduledir}/pam_selinux.so
%{_moduledir}/pam_selinux_permit.so %{_moduledir}/pam_selinux_permit.so
%{_moduledir}/pam_sepermit.so
%endif %endif
%{_moduledir}/pam_securetty.so %{_moduledir}/pam_securetty.so
%{_moduledir}/pam_shells.so %{_moduledir}/pam_shells.so
@ -365,7 +344,10 @@ fi
%config(noreplace) %{_secconfdir}/console.handlers %config(noreplace) %{_secconfdir}/console.handlers
%config(noreplace) %{_secconfdir}/group.conf %config(noreplace) %{_secconfdir}/group.conf
%config(noreplace) %{_secconfdir}/limits.conf %config(noreplace) %{_secconfdir}/limits.conf
%dir %{_secconfdir}/limits.d
%config(noreplace) %{_secconfdir}/limits.d/90-nproc.conf
%config(noreplace) %{_secconfdir}/namespace.conf %config(noreplace) %{_secconfdir}/namespace.conf
%dir %{_secconfdir}/namespace.d
%attr(755,root,root) %config(noreplace) %{_secconfdir}/namespace.init %attr(755,root,root) %config(noreplace) %{_secconfdir}/namespace.init
%config(noreplace) %{_secconfdir}/pam_env.conf %config(noreplace) %{_secconfdir}/pam_env.conf
%config(noreplace) %{_secconfdir}/sepermit.conf %config(noreplace) %{_secconfdir}/sepermit.conf
@ -392,6 +374,11 @@ fi
%doc doc/adg/*.txt doc/adg/html %doc doc/adg/*.txt doc/adg/html
%changelog %changelog
* Fri Feb 15 2008 Tomas Mraz <tmraz@redhat.com> 0.99.10.0-1
- new upstream release
- add default soft limit for nproc of 1024 to prevent
accidental fork bombs (#432903)
* Mon Feb 4 2008 Tomas Mraz <tmraz@redhat.com> 0.99.8.1-18 * Mon Feb 4 2008 Tomas Mraz <tmraz@redhat.com> 0.99.8.1-18
- allow the package to build without SELinux and audit support (#431415) - allow the package to build without SELinux and audit support (#431415)
- macro usage cleanup - macro usage cleanup

View File

@ -1,3 +1,3 @@
2a23dc703b550223206021ff03b1e434 pam-redhat-0.99.8-1.tar.bz2 2a23dc703b550223206021ff03b1e434 pam-redhat-0.99.8-1.tar.bz2
a6472db4afe13850cb401922211bba4e Linux-PAM-0.99.8.1.tar.bz2
89c7390ff120d5ebf3eccc5f97249e79 db-4.6.19.tar.gz 89c7390ff120d5ebf3eccc5f97249e79 db-4.6.19.tar.gz
be4dd1d34ac5933408e13e48f3eb710a Linux-PAM-0.99.10.0.tar.bz2