summaryrefslogtreecommitdiff
path: root/Linux-PAM/modules/pam_namespace
diff options
context:
space:
mode:
Diffstat (limited to 'Linux-PAM/modules/pam_namespace')
-rw-r--r--Linux-PAM/modules/pam_namespace/Makefile.am9
-rw-r--r--Linux-PAM/modules/pam_namespace/argv_parse.c165
-rw-r--r--Linux-PAM/modules/pam_namespace/argv_parse.h43
-rw-r--r--Linux-PAM/modules/pam_namespace/namespace.conf.5116
-rw-r--r--Linux-PAM/modules/pam_namespace/namespace.conf.5.xml80
-rwxr-xr-xLinux-PAM/modules/pam_namespace/namespace.init40
-rw-r--r--Linux-PAM/modules/pam_namespace/pam_namespace.8100
-rw-r--r--Linux-PAM/modules/pam_namespace/pam_namespace.8.xml62
-rw-r--r--Linux-PAM/modules/pam_namespace/pam_namespace.c1056
-rw-r--r--Linux-PAM/modules/pam_namespace/pam_namespace.h40
10 files changed, 1268 insertions, 443 deletions
diff --git a/Linux-PAM/modules/pam_namespace/Makefile.am b/Linux-PAM/modules/pam_namespace/Makefile.am
index 002678ba..05d47cf3 100644
--- a/Linux-PAM/modules/pam_namespace/Makefile.am
+++ b/Linux-PAM/modules/pam_namespace/Makefile.am
@@ -15,13 +15,14 @@ endif
EXTRA_DIST = README namespace.conf namespace.init $(MAN5) $(MAN8) $(XMLS) tst-pam_namespace
-noinst_HEADERS = md5.h
+noinst_HEADERS = md5.h pam_namespace.h argv_parse.h
securelibdir = $(SECUREDIR)
secureconfdir = $(SCONFIGDIR)
+namespaceddir = $(SCONFIGDIR)/namespace.d
AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \
- -DPAM_NAMESPACE_CONFIG=\"$(SCONFIGDIR)/namespace.conf\"
+ -DSECURECONF_DIR=\"$(SCONFIGDIR)/\"
AM_LDFLAGS = -no-undefined -avoid-version -module
if HAVE_VERSIONING
AM_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map
@@ -29,11 +30,13 @@ endif
if HAVE_UNSHARE
securelib_LTLIBRARIES = pam_namespace.la
-pam_namespace_la_SOURCES = pam_namespace.c pam_namespace.h md5.c md5.h
+pam_namespace_la_SOURCES = pam_namespace.c md5.c argv_parse.c
pam_namespace_la_LIBADD = -L$(top_builddir)/libpam -lpam @LIBSELINUX@
secureconf_DATA = namespace.conf
secureconf_SCRIPTS = namespace.init
+namespaced_DATA =
+
TESTS = tst-pam_namespace
man_MANS = $(MAN5) $(MAN8)
endif
diff --git a/Linux-PAM/modules/pam_namespace/argv_parse.c b/Linux-PAM/modules/pam_namespace/argv_parse.c
new file mode 100644
index 00000000..acc76d74
--- /dev/null
+++ b/Linux-PAM/modules/pam_namespace/argv_parse.c
@@ -0,0 +1,165 @@
+/*
+ * argv_parse.c --- utility function for parsing a string into a
+ * argc, argv array.
+ *
+ * This file defines a function argv_parse() which parsing a
+ * passed-in string, handling double quotes and backslashes, and
+ * creates an allocated argv vector which can be freed using the
+ * argv_free() function.
+ *
+ * See argv_parse.h for the formal definition of the functions.
+ *
+ * Copyright 1999 by Theodore Ts'o.
+ *
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose with or without fee is hereby granted, provided that
+ * the above copyright notice and this permission notice appear in all
+ * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE
+ * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't
+ * it sick that the U.S. culture of lawsuit-happy lawyers requires
+ * this kind of disclaimer?)
+ *
+ * Version 1.1, modified 2/27/1999
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "argv_parse.h"
+
+#define STATE_WHITESPACE 1
+#define STATE_TOKEN 2
+#define STATE_QUOTED 3
+
+/*
+ * Returns 0 on success, -1 on failure.
+ */
+int argv_parse(const char *in_buf, int *ret_argc, char ***ret_argv)
+{
+ int argc = 0, max_argc = 0;
+ char **argv, **new_argv, *buf, ch;
+ const char *cp = 0;
+ char *outcp = 0;
+ int state = STATE_WHITESPACE;
+
+ buf = malloc(strlen(in_buf)+1);
+ if (!buf)
+ return -1;
+
+ max_argc = 0; argc = 0; argv = 0;
+ outcp = buf;
+ for (cp = in_buf; (ch = *cp); cp++) {
+ if (state == STATE_WHITESPACE) {
+ if (isspace((int) ch))
+ continue;
+ /* Not whitespace, so start a new token */
+ state = STATE_TOKEN;
+ if (argc >= max_argc) {
+ max_argc += 3;
+ new_argv = realloc(argv,
+ (max_argc+1)*sizeof(char *));
+ if (!new_argv) {
+ if (argv) free(argv);
+ free(buf);
+ return -1;
+ }
+ argv = new_argv;
+ }
+ argv[argc++] = outcp;
+ }
+ if (state == STATE_QUOTED) {
+ if (ch == '"')
+ state = STATE_TOKEN;
+ else
+ *outcp++ = ch;
+ continue;
+ }
+ /* Must be processing characters in a word */
+ if (isspace((int) ch)) {
+ /*
+ * Terminate the current word and start
+ * looking for the beginning of the next word.
+ */
+ *outcp++ = 0;
+ state = STATE_WHITESPACE;
+ continue;
+ }
+ if (ch == '"') {
+ state = STATE_QUOTED;
+ continue;
+ }
+ if (ch == '\\') {
+ ch = *++cp;
+ switch (ch) {
+ case '\0':
+ ch = '\\'; cp--; break;
+ case 'n':
+ ch = '\n'; break;
+ case 't':
+ ch = '\t'; break;
+ case 'b':
+ ch = '\b'; break;
+ }
+ }
+ *outcp++ = ch;
+ }
+ if (state != STATE_WHITESPACE)
+ *outcp++ = '\0';
+ if (argv == 0) {
+ argv = malloc(sizeof(char *));
+ free(buf);
+ }
+ argv[argc] = 0;
+ if (ret_argc)
+ *ret_argc = argc;
+ if (ret_argv)
+ *ret_argv = argv;
+ return 0;
+}
+
+void argv_free(char **argv)
+{
+ if (*argv)
+ free(*argv);
+ free(argv);
+}
+
+#ifdef DEBUG_ARGV_PARSE
+/*
+ * For debugging
+ */
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ int ac, ret;
+ char **av, **cpp;
+ char buf[256];
+
+ while (!feof(stdin)) {
+ if (fgets(buf, sizeof(buf), stdin) == NULL)
+ break;
+ ret = argv_parse(buf, &ac, &av);
+ if (ret != 0) {
+ printf("Argv_parse returned %d!\n", ret);
+ continue;
+ }
+ printf("Argv_parse returned %d arguments...\n", ac);
+ for (cpp = av; *cpp; cpp++) {
+ if (cpp != av)
+ printf(", ");
+ printf("'%s'", *cpp);
+ }
+ printf("\n");
+ argv_free(av);
+ }
+ exit(0);
+}
+#endif
diff --git a/Linux-PAM/modules/pam_namespace/argv_parse.h b/Linux-PAM/modules/pam_namespace/argv_parse.h
new file mode 100644
index 00000000..c7878fc1
--- /dev/null
+++ b/Linux-PAM/modules/pam_namespace/argv_parse.h
@@ -0,0 +1,43 @@
+/*
+ * argv_parse.h --- header file for the argv parser.
+ *
+ * This file defines the interface for the functions argv_parse() and
+ * argv_free().
+ *
+ ***********************************************************************
+ * int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv)
+ *
+ * This function takes as its first argument a string which it will
+ * parse into an argv argument vector, with each white-space separated
+ * word placed into its own slot in the argv. This function handles
+ * double quotes and backslashes so that the parsed words can contain
+ * special characters. The count of the number words found in the
+ * parsed string, as well as the argument vector, are returned into
+ * ret_argc and ret_argv, respectively.
+ ***********************************************************************
+ * extern void argv_free(char **argv);
+ *
+ * This function frees the argument vector created by argv_parse().
+ ***********************************************************************
+ *
+ * Copyright 1999 by Theodore Ts'o.
+ *
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose with or without fee is hereby granted, provided that
+ * the above copyright notice and this permission notice appear in all
+ * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE
+ * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't
+ * it sick that the U.S. culture of lawsuit-happy lawyers requires
+ * this kind of disclaimer?)
+ *
+ * Version 1.1, modified 2/27/1999
+ */
+
+extern int argv_parse(const char *in_buf, int *ret_argc, char ***ret_argv);
+extern void argv_free(char **argv);
diff --git a/Linux-PAM/modules/pam_namespace/namespace.conf.5 b/Linux-PAM/modules/pam_namespace/namespace.conf.5
index 0a4d98e4..6a3cc9e3 100644
--- a/Linux-PAM/modules/pam_namespace/namespace.conf.5
+++ b/Linux-PAM/modules/pam_namespace/namespace.conf.5
@@ -1,95 +1,133 @@
.\" Title: namespace.conf
.\" Author:
-.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
-.\" Date: 06/20/2007
-.\" Manual: Linux\-PAM Manual
-.\" Source: Linux\-PAM Manual
+.\" Generator: DocBook XSL Stylesheets v1.73.1 <http://docbook.sf.net/>
+.\" Date: 02/13/2008
+.\" Manual: Linux-PAM Manual
+.\" Source: Linux-PAM Manual
.\"
-.TH "NAMESPACE.CONF" "5" "06/20/2007" "Linux\-PAM Manual" "Linux\-PAM Manual"
+.TH "NAMESPACE\.CONF" "5" "02/13/2008" "Linux-PAM Manual" "Linux\-PAM Manual"
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.SH "NAME"
-namespace.conf \- the namespace configuration file
+namespace.conf - the namespace configuration file
.SH "DESCRIPTION"
.PP
-This module allows setup of private namespaces with polyinstantiated directories. Directories can be polyinstantiated based on user name or, in the case of SELinux, user name, sensitivity level or complete security context. If an executable script
-\fI/etc/security/namespace.init\fR
-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.
+The
+\fIpam_namespace\.so\fR
+module allows setup of private namespaces with polyinstantiated directories\. Directories can be polyinstantiated based on user name or, in the case of SELinux, user name, sensitivity level or complete security context\. If an executable script
+\fI/etc/security/namespace\.init\fR
+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\.
.PP
The
-\fI/etc/security/namespace.conf\fR
-file specifies which directories are polyinstantiated, how they are polyinstantiated, how instance directories would be named, and any users for whom polyinstantiation would not be performed.
+\fI/etc/security/namespace\.conf\fR
+file specifies which directories are polyinstantiated, how they are polyinstantiated, how instance directories would be named, and any users for whom polyinstantiation would not be performed\.
.PP
When someone logs in, the file
-\fInamespace.conf\fR
-is scanned where each non comment line represents one polyinstantiated directory with space separated fields as follows:
+\fInamespace\.conf\fR
+is scanned\. Comments are marked by
+\fI#\fR
+characters\. Each non comment line represents one polyinstantiated directory\. The fields are separated by spaces but can be quoted by
+\fI"\fR
+characters also escape sequences
+\fI\eb\fR,
+\fI\en\fR, and
+\fI\et\fR
+are recognized\. The fields are as follows:
.PP
-
\fIpolydir\fR
-\fI instance_prefix\fR
-\fI method\fR
-\fI list_of_uids\fR
+\fIinstance_prefix\fR
+\fImethod\fR
+\fIlist_of_uids\fR
.PP
The first field,
-\fIpolydir\fR, is the absolute pathname of the directory to polyinstantiate. Special entry $HOME is supported to designate user's home directory. This field cannot be blank.
+\fIpolydir\fR, is the absolute pathname of the directory to polyinstantiate\. The special string
+\fI$HOME\fR
+is replaced with the user\'s home directory, and
+\fI$USER\fR
+with the username\. This field cannot be blank\.
.PP
The second field,
\fIinstance_prefix\fR
-is the string prefix used to build the pathname for the instantiation of <polydir>. Depending on the polyinstantiation
+is the string prefix used to build the pathname for the instantiation of <polydir>\. Depending on the polyinstantiation
\fImethod\fR
-it is then appended with "instance differentiation string" to generate the final instance directory path. This directory is created if it did not exist already, and is then bind mounted on the <polydir> to provide an instance of <polydir> based on the <method> column. The special string $HOME is replaced with the user's home directory, and $USER with the username. This field cannot be blank. The directory where polyinstantiated instances are to be created, must exist and must have, by default, the mode of 000. The requirement that the instance parent be of mode 000 can be overridden with the command line option
-\fIignore_instance_parent_mode\fR
+it is then appended with "instance differentiation string" to generate the final instance directory path\. This directory is created if it did not exist already, and is then bind mounted on the <polydir> to provide an instance of <polydir> based on the <method> column\. The special string
+\fI$HOME\fR
+is replaced with the user\'s home directory, and
+\fI$USER\fR
+with the username\. This field cannot be blank\.
.PP
The third field,
-\fImethod\fR, is the method used for polyinstantiation. It can take 3 different 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 Methods "context" and "level" are only available with SELinux. This field cannot be blank.
+\fImethod\fR, is the method 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, "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\.
.PP
The fourth field,
-\fIlist_of_uids\fR, 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.
+\fIlist_of_uids\fR, 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\. If the list is preceded with a single "~" character, polyinstantiation is performed only for users in the list\.
+.PP
+The
+\fImethod\fR
+field can contain also following optional flags separated by
+\fI:\fR
+characters\.
+.PP
+\fIcreate\fR=\fImode\fR,\fIowner\fR,\fIgroup\fR
+\- create the polyinstantiated directory\. The mode, owner and group parameters are optional\. The default for mode is determined by umask, the default owner is the user whose session is opened, the default group is the primary group of the user\.
+.PP
+\fIiscript\fR=\fIpath\fR
+\- path to the instance directory init script\. The base directory for relative paths is
+\fI/etc/security/namespace\.d\fR\.
+.PP
+\fInoinit\fR
+\- instance directory init script will not be executed\.
+.PP
+\fIshared\fR
+\- the instance directories for "context" and "level" methods will not contain the user name and will be shared among all users\.
+.PP
+The directory where polyinstantiated instances are to be created, must exist and must have, by default, the mode of 0000\. The requirement that the instance parent be of mode 0000 can be overridden with the command line option
+\fIignore_instance_parent_mode\fR
.PP
-In case of context or level polyinstantiation the SELinux context which is used for polyinstantiation is the context used for executing a new process as obtained by getexeccon. This context must be set by the calling application or
-\fIpam_selinux.so\fR
-module. If this context is not set the polyinstatiation will be based just on user name.
+In case of context or level polyinstantiation the SELinux context which is used for polyinstantiation is the context used for executing a new process as obtained by getexeccon\. This context must be set by the calling application or
+\fIpam_selinux\.so\fR
+module\. If this context is not set the polyinstatiation will be based just on user name\.
.PP
-The "instance differentiation string" is <user name> for "user" method and <user name>_<raw directory context> for "context" and "level" methods. If the whole string is too long the end of it is replaced with md5sum of itself. Also when command line option
+The "instance differentiation string" is <user name> for "user" method and <user name>_<raw directory context> for "context" and "level" methods\. If the whole string is too long the end of it is replaced with md5sum of itself\. Also when command line option
\fIgen_hash\fR
-is used the whole string is replaced with md5sum of itself.
+is used the whole string is replaced with md5sum of itself\.
.SH "EXAMPLES"
.PP
These are some example lines which might be specified in
-\fI/etc/security/namespace.conf\fR.
+\fI/etc/security/namespace\.conf\fR\.
.sp
.RS 4
.nf
# The following three lines will polyinstantiate /tmp,
- # /var/tmp and user's home directories. /tmp and /var/tmp
+ # /var/tmp and user\'s home directories\. /tmp and /var/tmp
# will be polyinstantiated based on the security level
# as well as user name, whereas home directory will be
- # polyinstantiated based on the full security context and user name.
+ # polyinstantiated based on the full security context and user name\.
# Polyinstantiation will not be performed for user root
# and adm for directories /tmp and /var/tmp, whereas home
- # directories will be polyinstantiated for all users.
+ # directories will be polyinstantiated for all users\.
#
# Note that instance directories do not have to reside inside
- # the polyinstantiated directory. In the examples below,
+ # the polyinstantiated directory\. In the examples below,
# instances of /tmp will be created in /tmp\-inst directory,
# where as instances of /var/tmp and users home directories
# will reside within the directories that are being
- # polyinstantiated.
+ # polyinstantiated\.
#
/tmp /tmp\-inst/ level root,adm
/var/tmp /var/tmp/tmp\-inst/ level root,adm
- $HOME $HOME/$USER.inst/inst\- context
+ $HOME $HOME/$USER\.inst/inst\- context
.fi
.RE
.PP
-For the <service>s you need polyinstantiation (login for example) put the following line in /etc/pam.d/<service> as the last line for session group:
+For the <service>s you need polyinstantiation (login for example) put the following line in /etc/pam\.d/<service> as the last line for session group:
.PP
-session required pam_namespace.so [arguments]
+session required pam_namespace\.so [arguments]
.PP
-This module also depends on pam_selinux.so setting the context.
+This module also depends on pam_selinux\.so setting the context\.
.SH "SEE ALSO"
.PP
@@ -98,4 +136,4 @@ This module also depends on pam_selinux.so setting the context.
\fBpam\fR(8)
.SH "AUTHORS"
.PP
-The namespace.conf manual page was written by Janak Desai <janak@us.ibm.com>.
+The namespace\.conf manual page was written by Janak Desai <janak@us\.ibm\.com>\. More features added by Tomas Mraz <tmraz@redhat\.com>\.
diff --git a/Linux-PAM/modules/pam_namespace/namespace.conf.5.xml b/Linux-PAM/modules/pam_namespace/namespace.conf.5.xml
index db48cdcb..a1769600 100644
--- a/Linux-PAM/modules/pam_namespace/namespace.conf.5.xml
+++ b/Linux-PAM/modules/pam_namespace/namespace.conf.5.xml
@@ -20,8 +20,9 @@
<title>DESCRIPTION</title>
<para>
- This module allows setup of private namespaces with polyinstantiated
- directories. Directories can be polyinstantiated based on user name
+ The <emphasis>pam_namespace.so</emphasis> module allows setup of
+ private namespaces with polyinstantiated directories.
+ Directories can be polyinstantiated based on user name
or, in the case of SELinux, user name, sensitivity level or complete security context. If an
executable script <filename>/etc/security/namespace.init</filename>
exists, it is used to initialize the namespace every time a new instance
@@ -38,19 +39,23 @@
<para>
When someone logs in, the file <filename>namespace.conf</filename> is
- scanned where each non comment line represents one polyinstantiated
- directory with space separated fields as follows:
+ scanned. Comments are marked by <emphasis>#</emphasis> characters.
+ Each non comment line represents one polyinstantiated
+ directory. The fields are separated by spaces but can be quoted by
+ <emphasis>"</emphasis> characters also escape
+ sequences <emphasis>\b</emphasis>, <emphasis>\n</emphasis>, and
+ <emphasis>\t</emphasis> are recognized. The fields are as follows:
</para>
- <para>
- <replaceable>polydir</replaceable> <replaceable> instance_prefix</replaceable> <replaceable> method</replaceable> <replaceable> list_of_uids</replaceable>
+ <para><replaceable>polydir</replaceable> <replaceable>instance_prefix</replaceable> <replaceable>method</replaceable> <replaceable>list_of_uids</replaceable>
</para>
<para>
The first field, <replaceable>polydir</replaceable>, is the absolute
- pathname of the directory to polyinstantiate. Special entry $HOME is
- supported to designate user's home directory. This field cannot be
- blank.
+ pathname of the directory to polyinstantiate. The special string
+ <emphasis>$HOME</emphasis> is replaced with the user's home directory,
+ and <emphasis>$USER</emphasis> with the username. This field cannot
+ be blank.
</para>
<para>
@@ -62,20 +67,20 @@
instance directory path. This directory is created if it did not exist
already, and is then bind mounted on the &lt;polydir&gt; to provide an
instance of &lt;polydir&gt; based on the &lt;method&gt; column.
- The special string $HOME is replaced with the user's home directory,
- and $USER with the username. This field cannot be blank.
- The directory where polyinstantiated instances are to be
- created, must exist and must have, by default, the mode of 000. The
- requirement that the instance parent be of mode 000 can be overridden
- with the command line option <replaceable>ignore_instance_parent_mode</replaceable>
+ The special string <emphasis>$HOME</emphasis> is replaced with the
+ user's home directory, and <emphasis>$USER</emphasis> with the username.
+ This field cannot be blank.
</para>
<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 +89,41 @@
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>
+ The <replaceable>method</replaceable> field can contain also following
+ optional flags separated by <emphasis>:</emphasis> characters.
+ </para>
+
+ <para><emphasis>create</emphasis>=<replaceable>mode</replaceable>,<replaceable>owner</replaceable>,<replaceable>group</replaceable>
+ - create the polyinstantiated directory. The mode, owner and group parameters
+ are optional. The default for mode is determined by umask, the default
+ owner is the user whose session is opened, the default group is the
+ primary group of the user.
+ </para>
+
+ <para><emphasis>iscript</emphasis>=<replaceable>path</replaceable>
+ - path to the instance directory init script. The base directory for relative
+ paths is <filename>/etc/security/namespace.d</filename>.
+ </para>
+
+ <para><emphasis>noinit</emphasis>
+ - instance directory init script will not be executed.
+ </para>
+
+ <para><emphasis>shared</emphasis>
+ - the instance directories for "context" and "level" methods will not
+ contain the user name and will be shared among all users.
+ </para>
+
+ <para>
+ The directory where polyinstantiated instances are to be
+ created, must exist and must have, by default, the mode of 0000. The
+ requirement that the instance parent be of mode 0000 can be overridden
+ with the command line option <emphasis>ignore_instance_parent_mode</emphasis>
</para>
<para>
@@ -101,7 +140,7 @@
method and &lt;user name&gt;_&lt;raw directory context&gt; for "context"
and "level" methods. If the whole string is too long the end of it is
replaced with md5sum of itself. Also when command line option
- <replaceable>gen_hash</replaceable> is used the whole string is replaced
+ <emphasis>gen_hash</emphasis> is used the whole string is replaced
with md5sum of itself.
</para>
@@ -165,6 +204,7 @@
<title>AUTHORS</title>
<para>
The namespace.conf manual page was written by Janak Desai &lt;janak@us.ibm.com&gt;.
+ More features added by Tomas Mraz &lt;tmraz@redhat.com&gt;.
</para>
</refsect1>
</refentry>
diff --git a/Linux-PAM/modules/pam_namespace/namespace.init b/Linux-PAM/modules/pam_namespace/namespace.init
index 0e9be68f..424c6d0c 100755
--- a/Linux-PAM/modules/pam_namespace/namespace.init
+++ b/Linux-PAM/modules/pam_namespace/namespace.init
@@ -1,24 +1,24 @@
#!/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
-# 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
diff --git a/Linux-PAM/modules/pam_namespace/pam_namespace.8 b/Linux-PAM/modules/pam_namespace/pam_namespace.8
index 8d136c99..a318c57f 100644
--- a/Linux-PAM/modules/pam_namespace/pam_namespace.8
+++ b/Linux-PAM/modules/pam_namespace/pam_namespace.8
@@ -1,27 +1,27 @@
.\" Title: pam_namespace
.\" Author:
-.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
-.\" Date: 06/20/2007
-.\" Manual: Linux\-PAM Manual
-.\" Source: Linux\-PAM Manual
+.\" Generator: DocBook XSL Stylesheets v1.73.1 <http://docbook.sf.net/>
+.\" Date: 02/13/2008
+.\" Manual: Linux-PAM Manual
+.\" Source: Linux-PAM Manual
.\"
-.TH "PAM_NAMESPACE" "8" "06/20/2007" "Linux\-PAM Manual" "Linux\-PAM Manual"
+.TH "PAM_NAMESPACE" "8" "02/13/2008" "Linux-PAM Manual" "Linux-PAM Manual"
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.SH "NAME"
-pam_namespace \- PAM module for configuring namespace for a session
+pam_namespace - PAM module for configuring namespace for a session
.SH "SYNOPSIS"
.HP 17
-\fBpam_namespace.so\fR [debug] [unmnt_remnt] [unmnt_only] [require_selinux] [gen_hash] [ignore_config_error] [ignore_instance_parent_mode] [no_unmount_on_close]
+\fBpam_namespace\.so\fR [debug] [unmnt_remnt] [unmnt_only] [require_selinux] [gen_hash] [ignore_config_error] [ignore_instance_parent_mode] [no_unmount_on_close] [use_current_context] [use_default_context]
.SH "DESCRIPTION"
.PP
-The pam_namespace PAM module sets up a private namespace for a session with polyinstantiated directories. A polyinstantiated directory provides a different instance of itself based on user name, or when using SELinux, user name, security context or both. If an executable script
-\fI/etc/security/namespace.init\fR
-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.
+The pam_namespace PAM module sets up a private namespace for a session with polyinstantiated directories\. A polyinstantiated directory provides a different instance of itself based on user name, or when using SELinux, user name, security context or both\. If an executable script
+\fI/etc/security/namespace\.init\fR
+exists, it is used to initialize the namespace every time a new instance directory is setup\. The script receives the polyinstantiated 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\.
.PP
-The pam_namespace module disassociates the session namespace from the parent namespace. Any mounts/unmounts performed in the parent namespace, such as mounting of devices, are not reflected in the session namespace. To propagate selected mount/unmount events from the parent namespace into the disassociated session namespace, an administrator may use the special shared\-subtree feature. For additional information on shared\-subtree feature, please refer to the mount(8) man page and the shared\-subtree description at http://lwn.net/Articles/159077 and http://lwn.net/Articles/159092.
+The pam_namespace module disassociates the session namespace from the parent namespace\. Any mounts/unmounts performed in the parent namespace, such as mounting of devices, are not reflected in the session namespace\. To propagate selected mount/unmount events from the parent namespace into the disassociated session namespace, an administrator may use the special shared\-subtree feature\. For additional information on shared\-subtree feature, please refer to the mount(8) man page and the shared\-subtree description at http://lwn\.net/Articles/159077 and http://lwn\.net/Articles/159092\.
.SH "OPTIONS"
.PP
\fBdebug\fR
@@ -31,7 +31,7 @@ A lot of debug information is logged using syslog
.PP
\fBunmnt_remnt\fR
.RS 4
-For programs such as su and newrole, the login session has already setup a polyinstantiated namespace. For these programs, polyinstantiation is performed based on new user id or security context, however the command first needs to undo the polyinstantiation performed by login. This argument instructs the command to first undo previous polyinstantiation before proceeding with new polyinstantiation based on new id/context
+For programs such as su and newrole, the login session has already setup a polyinstantiated namespace\. For these programs, polyinstantiation is performed based on new user id or security context, however the command first needs to undo the polyinstantiation performed by login\. This argument instructs the command to first undo previous polyinstantiation before proceeding with new polyinstantiation based on new id/context
.RE
.PP
\fBunmnt_only\fR
@@ -46,81 +46,101 @@ If selinux is not enabled, return failure
.PP
\fBgen_hash\fR
.RS 4
-Instead of using the security context string for the instance name, generate and use its md5 hash.
+Instead of using the security context string for the instance name, generate and use its md5 hash\.
.RE
.PP
\fBignore_config_error\fR
.RS 4
-If a line in the configuration file corresponding to a polyinstantiated directory contains format error, skip that line process the next line. Without this option, pam will return an error to the calling program resulting in termination of the session.
+If a line in the configuration file corresponding to a polyinstantiated directory contains format error, skip that line process the next line\. Without this option, pam will return an error to the calling program resulting in termination of the session\.
.RE
.PP
\fBignore_instance_parent_mode\fR
.RS 4
-Instance parent directories by default are expected to have the restrictive mode of 000. Using this option, an administrator can choose to ignore the mode of the instance parent. This option should be used with caution as it will reduce security and isolation goals of the polyinstantiation mechanism.
+Instance parent directories by default are expected to have the restrictive mode of 000\. Using this option, an administrator can choose to ignore the mode of the instance parent\. This option should be used with caution as it will reduce security and isolation goals of the polyinstantiation mechanism\.
.RE
.PP
\fBno_unmount_on_close\fR
.RS 4
-For certain trusted programs such as newrole, open session is called from a child process while the parent perfoms close session and pam end functions. For these commands use this option to instruct pam_close_session to not unmount the bind mounted polyinstantiated directory in the parent.
+For certain trusted programs such as newrole, open session is called from a child process while the parent perfoms close session and pam end functions\. For these commands use this option to instruct pam_close_session to not unmount the bind mounted polyinstantiated directory in the parent\.
+.RE
+.PP
+\fBuse_current_context\fR
+.RS 4
+Useful for services which do not change the SELinux context with setexeccon call\. The module will use the current SELinux context of the calling process for the level and context polyinstantiation\.
+.RE
+.PP
+\fBuse_default_context\fR
+.RS 4
+Useful for services which do not use pam_selinux for changing the SELinux context with setexeccon call\. The module will use the default SELinux context of the user for the level and context polyinstantiation\.
.RE
.SH "MODULE SERVICES PROVIDED"
.PP
The
\fBsession\fR
-service is supported.
+service is supported\. The module must not be called from multithreaded processes\.
.SH "RETURN VALUES"
.PP
PAM_SUCCESS
.RS 4
-Namespace setup was successful.
+Namespace setup was successful\.
.RE
.PP
PAM_SERVICE_ERR
.RS 4
-Unexpected system error occurred while setting up namespace.
+Unexpected system error occurred while setting up namespace\.
.RE
.PP
PAM_SESSION_ERR
.RS 4
-Unexpected namespace configuration error occurred.
+Unexpected namespace configuration error occurred\.
.RE
.SH "FILES"
.PP
-\fI/etc/security/namespace.conf\fR
+\fI/etc/security/namespace\.conf\fR
+.RS 4
+Main configuration file
+.RE
+.PP
+\fI/etc/security/namespace\.d\fR
+.RS 4
+Directory for additional configuration files
+.RE
+.PP
+\fI/etc/security/namespace\.init\fR
.RS 4
-Configuration file
+Init script for instance directories
.RE
.SH "EXAMPLES"
.PP
-For the <service>s you need polyinstantiation (login for example) put the following line in /etc/pam.d/<service> as the last line for session group:
+For the <service>s you need polyinstantiation (login for example) put the following line in /etc/pam\.d/<service> as the last line for session group:
.PP
-session required pam_namespace.so [arguments]
+session required pam_namespace\.so [arguments]
.PP
To use polyinstantiation with graphical display manager gdm, insert the following line, before exit 0, in /etc/gdm/PostSession/Default:
.PP
/usr/sbin/gdm\-safe\-restart
.PP
-This allows gdm to restart after each session and appropriately adjust namespaces of display manager and the X server. If polyinstantiation of /tmp is desired along with the graphical environment, then additional configuration changes are needed to address the interaction of X server and font server namespaces with their use of /tmp to create communication sockets. Please use the initialization script
-\fI/etc/security/namespace.init\fR
-to ensure that the X server and its clients can appropriately access the communication socket X0. Please refer to the sample instructions provided in the comment section of the instance initialization script
-\fI/etc/security/namespace.init\fR. In addition, perform the following changes to use graphical environment with polyinstantiation of /tmp:
+This allows gdm to restart after each session and appropriately adjust namespaces of display manager and the X server\. If polyinstantiation of /tmp is desired along with the graphical environment, then additional configuration changes are needed to address the interaction of X server and font server namespaces with their use of /tmp to create communication sockets\. Please use the initialization script
+\fI/etc/security/namespace\.init\fR
+to ensure that the X server and its clients can appropriately access the communication socket X0\. Please refer to the sample instructions provided in the comment section of the instance initialization script
+\fI/etc/security/namespace\.init\fR\. In addition, perform the following changes to use graphical environment with polyinstantiation of /tmp:
.PP
.sp
.RS 4
.nf
- 1. Disable the use of font server by commenting out "FontPath"
- line in /etc/X11/xorg.conf. If you do want to use the font server
+ 1\. Disable the use of font server by commenting out "FontPath"
+ line in /etc/X11/xorg\.conf\. If you do want to use the font server
then you will have to augment the instance initialization
- script to appropriately provide /tmp/.font\-unix from the
- polyinstantiated /tmp.
- 2. Ensure that the gdm service is setup to use pam_namespace,
- as described above, by modifying /etc/pam.d/gdm.
- 3. Ensure that the display manager is configured to restart X server
- with each new session. This default setup can be verified by
- making sure that /usr/share/gdm/defaults.conf contains
+ script to appropriately provide /tmp/\.font\-unix from the
+ polyinstantiated /tmp\.
+ 2\. Ensure that the gdm service is setup to use pam_namespace,
+ as described above, by modifying /etc/pam\.d/gdm\.
+ 3\. Ensure that the display manager is configured to restart X server
+ with each new session\. This default setup can be verified by
+ making sure that /usr/share/gdm/defaults\.conf contains
"AlwaysRestartServer=true", and it is not overridden by
- /etc/gdm/custom.conf.
+ /etc/gdm/custom\.conf\.
.fi
.RE
@@ -131,7 +151,7 @@ to ensure that the X server and its clients can appropriately access the communi
\fBnamespace.conf\fR(5),
\fBpam.d\fR(8),
\fBmount\fR(8),
-\fBpam\fR(8).
+\fBpam\fR(8)\.
.SH "AUTHORS"
.PP
-The namespace setup scheme was designed by Stephen Smalley, Janak Desai and Chad Sellers. The pam_namespace PAM module was developed by Janak Desai <janak@us.ibm.com>, Chad Sellers <csellers@tresys.com> and Steve Grubb <sgrubb@redhat.com>.
+The namespace setup scheme was designed by Stephen Smalley, Janak Desai and Chad Sellers\. The pam_namespace PAM module was developed by Janak Desai <janak@us\.ibm\.com>, Chad Sellers <csellers@tresys\.com> and Steve Grubb <sgrubb@redhat\.com>\. Additional improvements by Xavier Toth <txtoth@gmail\.com> and Tomas Mraz <tmraz@redhat\.com>\.
diff --git a/Linux-PAM/modules/pam_namespace/pam_namespace.8.xml b/Linux-PAM/modules/pam_namespace/pam_namespace.8.xml
index e1b307ae..32c5359d 100644
--- a/Linux-PAM/modules/pam_namespace/pam_namespace.8.xml
+++ b/Linux-PAM/modules/pam_namespace/pam_namespace.8.xml
@@ -46,6 +46,12 @@
<arg choice="opt">
no_unmount_on_close
</arg>
+ <arg choice="opt">
+ use_current_context
+ </arg>
+ <arg choice="opt">
+ use_default_context
+ </arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -60,7 +66,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>
@@ -198,13 +206,42 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <option>use_current_context</option>
+ </term>
+ <listitem>
+ <para>
+ Useful for services which do not change the SELinux context
+ with setexeccon call. The module will use the current SELinux
+ context of the calling process for the level and context
+ polyinstantiation.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>use_default_context</option>
+ </term>
+ <listitem>
+ <para>
+ Useful for services which do not use pam_selinux for changing
+ the SELinux context with setexeccon call. The module will use
+ the default SELinux context of the user for the level and context
+ polyinstantiation.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
<refsect1 id="pam_namespace-services">
<title>MODULE SERVICES PROVIDED</title>
<para>
- The <option>session</option> service is supported.
+ The <option>session</option> service is supported. The module must not
+ be called from multithreaded processes.
</para>
</refsect1>
@@ -244,7 +281,21 @@
<varlistentry>
<term><filename>/etc/security/namespace.conf</filename></term>
<listitem>
- <para>Configuration file</para>
+ <para>Main configuration file</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/etc/security/namespace.d</filename></term>
+ <listitem>
+ <para>Directory for additional configuration files</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><filename>/etc/security/namespace.init</filename></term>
+ <listitem>
+ <para>Init script for instance directories</para>
</listitem>
</varlistentry>
</variablelist>
@@ -330,7 +381,10 @@
<para>
The namespace setup scheme was designed by Stephen Smalley, Janak Desai
and Chad Sellers.
- The pam_namespace PAM module was developed by Janak Desai &lt;janak@us.ibm.com&gt;, Chad Sellers &lt;csellers@tresys.com&gt; and Steve Grubb &lt;sgrubb@redhat.com&gt;.
+ The pam_namespace PAM module was developed by Janak Desai &lt;janak@us.ibm.com&gt;,
+ Chad Sellers &lt;csellers@tresys.com&gt; and Steve Grubb &lt;sgrubb@redhat.com&gt;.
+ Additional improvements by Xavier Toth &lt;txtoth@gmail.com&gt; and Tomas Mraz
+ &lt;tmraz@redhat.com&gt;.
</para>
</refsect1>
</refentry>
diff --git a/Linux-PAM/modules/pam_namespace/pam_namespace.c b/Linux-PAM/modules/pam_namespace/pam_namespace.c
index d3612f59..d0741fd2 100644
--- a/Linux-PAM/modules/pam_namespace/pam_namespace.c
+++ b/Linux-PAM/modules/pam_namespace/pam_namespace.c
@@ -3,11 +3,13 @@
* establishing a session via PAM.
*
* (C) Copyright IBM Corporation 2005
- * (C) Copyright Red Hat 2006
+ * (C) Copyright Red Hat, Inc. 2006, 2008
* All Rights Reserved.
*
* Written by: Janak Desai <janak@us.ibm.com>
* With Revisions by: Steve Grubb <sgrubb@redhat.com>
+ * Contributions by: Xavier Toth <txtoth@gmail.com>,
+ * Tomas Mraz <tmraz@redhat.com>
* Derived from a namespace setup patch by Chad Sellers <cdselle@tycho.nsa.gov>
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -31,79 +33,36 @@
*/
#include "pam_namespace.h"
-
-/*
- * Copies the contents of ent into pent
- */
-static int copy_ent(const struct polydir_s *ent, struct polydir_s *pent)
-{
- unsigned int i;
-
- strcpy(pent->dir, ent->dir);
- strcpy(pent->instance_prefix, ent->instance_prefix);
- pent->method = ent->method;
- pent->num_uids = ent->num_uids;
- if (ent->num_uids) {
- uid_t *pptr, *eptr;
-
- pent->uid = (uid_t *) malloc(ent->num_uids * sizeof(uid_t));
- if (!(pent->uid)) {
- return -1;
- }
- for (i = 0, pptr = pent->uid, eptr = ent->uid; i < ent->num_uids;
- i++, eptr++, pptr++)
- *pptr = *eptr;
- } else
- pent->uid = NULL;
- return 0;
-}
+#include "argv_parse.h"
/*
* Adds an entry for a polyinstantiated directory to the linked list of
* polyinstantiated directories. It is called from process_line() while
* parsing the namespace configuration file.
*/
-static int add_polydir_entry(struct instance_data *idata,
- const struct polydir_s *ent)
+static void add_polydir_entry(struct instance_data *idata,
+ struct polydir_s *ent)
{
- struct polydir_s *pent;
- int rc = 0;
-
- /*
- * Allocate an entry to hold information about a directory to
- * polyinstantiate, populate it with information from 2nd argument
- * and add the entry to the linked list of polyinstantiated
- * directories.
- */
- pent = (struct polydir_s *) malloc(sizeof(struct polydir_s));
- if (!pent) {
- rc = -1;
- goto out;
- }
- /* Make copy */
- rc = copy_ent(ent,pent);
- if(rc < 0)
- goto out_clean;
-
/* Now attach to linked list */
- pent->next = NULL;
+ ent->next = NULL;
if (idata->polydirs_ptr == NULL)
- idata->polydirs_ptr = pent;
+ idata->polydirs_ptr = ent;
else {
struct polydir_s *tail;
tail = idata->polydirs_ptr;
while (tail->next)
tail = tail->next;
- tail->next = pent;
+ tail->next = ent;
}
- goto out;
-out_clean:
- free(pent);
-out:
- return rc;
}
+static void del_polydir(struct polydir_s *poly)
+{
+ free(poly->uid);
+ free(poly->init_script);
+ free(poly);
+}
/*
* Deletes all the entries in the linked list.
@@ -115,11 +74,184 @@ static void del_polydir_list(struct polydir_s *polydirs_ptr)
while (dptr) {
struct polydir_s *tptr = dptr;
dptr = dptr->next;
- free(tptr->uid);
- free(tptr);
+ del_polydir(tptr);
+ }
+}
+
+static void cleanup_data(pam_handle_t *pamh UNUSED , void *data, int err UNUSED)
+{
+ del_polydir_list(data);
+}
+
+static char *expand_variables(const char *orig, const char *var_names[], const char *var_values[])
+{
+ const char *src = orig;
+ char *dst;
+ char *expanded;
+ char c;
+ size_t dstlen = 0;
+ while (*src) {
+ if (*src == '$') {
+ int i;
+ for (i = 0; var_names[i]; i++) {
+ int namelen = strlen(var_names[i]);
+ if (strncmp(var_names[i], src+1, namelen) == 0) {
+ dstlen += strlen(var_values[i]) - 1; /* $ */
+ src += namelen;
+ break;
+ }
+ }
+ }
+ ++dstlen;
+ ++src;
+ }
+ if ((dst=expanded=malloc(dstlen + 1)) == NULL)
+ return NULL;
+ src = orig;
+ while ((c=*src) != '\0') {
+ if (c == '$') {
+ int i;
+ for (i = 0; var_names[i]; i++) {
+ int namelen = strlen(var_names[i]);
+ if (strncmp(var_names[i], src+1, namelen) == 0) {
+ dst = stpcpy(dst, var_values[i]);
+ --dst;
+ c = *dst; /* replace $ */
+ src += namelen;
+ break;
+ }
+ }
+ }
+ *dst = c;
+ ++dst;
+ ++src;
+ }
+ *dst = '\0';
+ return expanded;
+}
+
+static int parse_create_params(char *params, struct polydir_s *poly)
+{
+ char *sptr;
+ struct passwd *pwd;
+ struct group *grp;
+
+ poly->mode = (mode_t)ULONG_MAX;
+ poly->owner = (uid_t)ULONG_MAX;
+ poly->group = (gid_t)ULONG_MAX;
+
+ if (*params != '=')
+ return 0;
+ params++;
+
+ params = strtok_r(params, ",", &sptr);
+ if (params == NULL)
+ return 0;
+
+ errno = 0;
+ poly->mode = (mode_t)strtoul(params, NULL, 0);
+ if (errno != 0) {
+ poly->mode = (mode_t)ULONG_MAX;
+ }
+
+ params = strtok_r(NULL, ",", &sptr);
+ if (params == NULL)
+ return 0;
+
+ pwd = getpwnam(params); /* session modules are not reentrant */
+ if (pwd == NULL)
+ return -1;
+ poly->owner = pwd->pw_uid;
+
+ params = strtok_r(NULL, ",", &sptr);
+ if (params == NULL) {
+ poly->group = pwd->pw_gid;
+ return 0;
+ }
+ grp = getgrnam(params);
+ if (grp == NULL)
+ return -1;
+ poly->group = grp->gr_gid;
+
+ return 0;
+}
+
+static int parse_iscript_params(char *params, struct polydir_s *poly)
+{
+ if (*params != '=')
+ return 0;
+ params++;
+
+ if (*params != '\0') {
+ if (*params != '/') { /* path is relative to NAMESPACE_D_DIR */
+ if (asprintf(&poly->init_script, "%s%s", NAMESPACE_D_DIR, params) == -1)
+ return -1;
+ } else {
+ poly->init_script = strdup(params);
}
+ if (poly->init_script == NULL)
+ return -1;
+ }
+ return 0;
}
+static int parse_method(char *method, struct polydir_s *poly,
+ struct instance_data *idata)
+{
+ enum polymethod pm;
+ char *sptr;
+ static const char *method_names[] = { "user", "context", "level", "tmpdir",
+ "tmpfs", NULL };
+ static const char *flag_names[] = { "create", "noinit", "iscript",
+ "shared", NULL };
+ static const unsigned int flag_values[] = { POLYDIR_CREATE, POLYDIR_NOINIT,
+ POLYDIR_ISCRIPT, POLYDIR_SHARED };
+ int i;
+ char *flag;
+
+ method = strtok_r(method, ":", &sptr);
+ pm = NONE;
+
+ for (i = 0; method_names[i]; i++) {
+ if (strcmp(method, method_names[i]) == 0) {
+ pm = i + 1; /* 0 = NONE */
+ }
+ }
+
+ if (pm == NONE) {
+ pam_syslog(idata->pamh, LOG_NOTICE, "Unknown method");
+ return -1;
+ }
+
+ poly->method = pm;
+
+ while ((flag=strtok_r(NULL, ":", &sptr)) != NULL) {
+ for (i = 0; flag_names[i]; i++) {
+ int namelen = strlen(flag_names[i]);
+
+ if (strncmp(flag, flag_names[i], namelen) == 0) {
+ poly->flags |= flag_values[i];
+ switch (flag_values[i]) {
+ case POLYDIR_CREATE:
+ if (parse_create_params(flag+namelen, poly) != 0) {
+ pam_syslog(idata->pamh, LOG_CRIT, "Invalid create parameters");
+ return -1;
+ }
+ break;
+
+ case POLYDIR_ISCRIPT:
+ if (parse_iscript_params(flag+namelen, poly) != 0) {
+ pam_syslog(idata->pamh, LOG_CRIT, "Memory allocation error");
+ return -1;
+ };
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
/*
* Called from parse_config_file, this function processes a single line
@@ -129,17 +261,23 @@ static void del_polydir_list(struct polydir_s *polydirs_ptr)
* polyinstatiated directory structure and then calling add_polydir_entry to
* add that entry to the linked list of polyinstantiated directories.
*/
-static int process_line(char *line, const char *home,
+static int process_line(char *line, const char *home, const char *rhome,
struct instance_data *idata)
{
- const char *dir, *instance_prefix;
- const char *method, *uids;
+ char *dir = NULL, *instance_prefix = NULL, *rdir = NULL;
+ char *method, *uids;
char *tptr;
- struct polydir_s poly;
+ struct polydir_s *poly;
int retval = 0;
+ char **config_options = NULL;
+ static const char *var_names[] = {"HOME", "USER", NULL};
+ const char *var_values[] = {home, idata->user};
+ const char *rvar_values[] = {rhome, idata->ruser};
+ int len;
- poly.uid = NULL;
- poly.num_uids = 0;
+ poly = calloc(1, sizeof(*poly));
+ if (poly == NULL)
+ goto erralloc;
/*
* skip the leading white space
@@ -171,19 +309,27 @@ static int process_line(char *line, const char *home,
* Initialize and scan the five strings from the line from the
* namespace configuration file.
*/
- dir = strtok_r(line, " \t", &tptr);
+ retval = argv_parse(line, NULL, &config_options);
+ if (retval != 0) {
+ goto erralloc;
+ }
+
+ dir = config_options[0];
if (dir == NULL) {
pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing polydir");
goto skipping;
}
- instance_prefix = strtok_r(NULL, " \t", &tptr);
+ instance_prefix = config_options[1];
if (instance_prefix == NULL) {
pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing instance_prefix");
+ instance_prefix = NULL;
goto skipping;
}
- method = strtok_r(NULL, " \t", &tptr);
+ method = config_options[2];
if (method == NULL) {
pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line missing method");
+ instance_prefix = NULL;
+ dir = NULL;
goto skipping;
}
@@ -193,81 +339,83 @@ static int process_line(char *line, const char *home,
* any of the other fields are blank, the line is incomplete so
* skip it.
*/
- uids = strtok_r(NULL, " \t", &tptr);
+ uids = config_options[3];
/*
- * If the directory being polyinstantiated is the home directory
- * of the user who is establishing a session, we have to swap
- * the "$HOME" string with the user's home directory that is
- * passed in as an argument.
+ * Expand $HOME and $USER in poly dir and instance dir prefix
*/
- if (strcmp(dir, "$HOME") == 0) {
- dir = home;
+ if ((rdir=expand_variables(dir, var_names, rvar_values)) == NULL) {
+ instance_prefix = NULL;
+ dir = NULL;
+ goto erralloc;
}
-
- /*
- * Expand $HOME and $USER in instance dir prefix
- */
- if ((tptr = strstr(instance_prefix, "$USER")) != 0) {
- /* FIXME: should only support this if method is USER or BOTH */
- char *expanded = alloca(strlen(idata->user) + strlen(instance_prefix)-5+1);
- *tptr = 0;
- sprintf(expanded, "%s%s%s", instance_prefix, idata->user, tptr+5);
- instance_prefix = expanded;
+
+ if ((dir=expand_variables(dir, var_names, var_values)) == NULL) {
+ instance_prefix = NULL;
+ goto erralloc;
}
- if ((tptr = strstr(instance_prefix, "$HOME")) != 0) {
- char *expanded = alloca(strlen(home)+strlen(instance_prefix)-5+1);
- *tptr = 0;
- sprintf(expanded, "%s%s%s", instance_prefix, home, tptr+5);
- instance_prefix = expanded;
+
+ if ((instance_prefix=expand_variables(instance_prefix, var_names, var_values))
+ == NULL) {
+ goto erralloc;
}
- /*
- * 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 (idata->flags & PAMNS_DEBUG) {
+ pam_syslog(idata->pamh, LOG_DEBUG, "Expanded polydir: '%s'", dir);
+ pam_syslog(idata->pamh, LOG_DEBUG, "Expanded ruser polydir: '%s'", rdir);
+ pam_syslog(idata->pamh, LOG_DEBUG, "Expanded instance prefix: '%s'", instance_prefix);
}
- if (strstr(dir, "..") || strstr(instance_prefix, "..")) {
- pam_syslog(idata->pamh, LOG_NOTICE,"Pathnames must not contain '..'");
- goto skipping;
+
+ len = strlen(dir);
+ if (len > 0 && dir[len-1] == '/') {
+ dir[len-1] = '\0';
}
+ len = strlen(rdir);
+ if (len > 0 && rdir[len-1] == '/') {
+ rdir[len-1] = '\0';
+ }
+
+ if (dir[0] == '\0' || rdir[0] == '\0') {
+ pam_syslog(idata->pamh, LOG_NOTICE, "Invalid polydir");
+ 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)) {
+ if (strlen(dir) >= sizeof(poly->dir)
+ || strlen(rdir) >= sizeof(poly->rdir)
+ || 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);
-
- poly.method = NONE;
- if (strcmp(method, "user") == 0)
- poly.method = USER;
+ strcpy(poly->dir, dir);
+ strcpy(poly->rdir, rdir);
+ strcpy(poly->instance_prefix, instance_prefix);
-#ifdef WITH_SELINUX
- if (strcmp(method, "level") == 0) {
- if (idata->flags & PAMNS_CTXT_BASED_INST)
- poly.method = LEVEL;
- else
- poly.method = USER;
+ if (parse_method(method, poly, idata) != 0) {
+ goto skipping;
}
- if (strcmp(method, "context") == 0) {
- if (idata->flags & PAMNS_CTXT_BASED_INST)
- poly.method = CONTEXT;
- else
- poly.method = USER;
+ if (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");
}
-#endif
-
- if ( poly.method == NONE) {
- pam_syslog(idata->pamh, LOG_NOTICE, "Illegal method");
+ /*
+ * Ensure that all pathnames are absolute path names.
+ */
+ if ((poly->dir[0] != '/') || (poly->method != TMPFS && poly->instance_prefix[0] != '/')) {
+ pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames must start with '/'");
+ goto skipping;
+ }
+ if (strstr(dir, "..") || strstr(poly->instance_prefix, "..")) {
+ pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames must not contain '..'");
goto skipping;
}
@@ -281,16 +429,19 @@ static int process_line(char *line, const char *home,
uid_t *uidptr;
const char *ustr, *sstr;
int count, i;
-
+
+ if (*uids == '~') {
+ poly->flags |= POLYDIR_EXCLUSIVE;
+ uids++;
+ }
for (count = 0, ustr = sstr = uids; sstr; ustr = sstr + 1, count++)
sstr = strchr(ustr, ',');
- poly.num_uids = count;
- poly.uid = (uid_t *) malloc(count * sizeof (uid_t));
- uidptr = poly.uid;
+ poly->num_uids = count;
+ poly->uid = (uid_t *) malloc(count * sizeof (uid_t));
+ uidptr = poly->uid;
if (uidptr == NULL) {
- pam_syslog(idata->pamh, LOG_NOTICE, "out of memory");
- goto skipping;
+ goto erralloc;
}
ustr = uids;
@@ -304,7 +455,7 @@ static int process_line(char *line, const char *home,
pwd = pam_modutil_getpwnam(idata->pamh, ustr);
if (pwd == NULL) {
pam_syslog(idata->pamh, LOG_ERR, "Unknown user %s in configuration", ustr);
- poly.num_uids--;
+ poly->num_uids--;
} else {
*uidptr = pwd->pw_uid;
uidptr++;
@@ -317,20 +468,24 @@ static int process_line(char *line, const char *home,
* Add polyinstantiated directory structure to the linked list
* of all polyinstantiated directory structures.
*/
- if (add_polydir_entry(idata, &poly) < 0) {
- pam_syslog(idata->pamh, LOG_ERR, "Allocation Error");
- retval = PAM_SERVICE_ERR;
- }
- free(poly.uid);
+ add_polydir_entry(idata, poly);
goto out;
+erralloc:
+ pam_syslog(idata->pamh, LOG_CRIT, "Memory allocation error");
+
skipping:
if (idata->flags & PAMNS_IGN_CONFIG_ERR)
retval = 0;
else
retval = PAM_SERVICE_ERR;
+ del_polydir(poly);
out:
+ free(rdir);
+ free(dir);
+ free(instance_prefix);
+ argv_free(config_options);
return retval;
}
@@ -344,15 +499,15 @@ out:
static int parse_config_file(struct instance_data *idata)
{
FILE *fil;
- char *home;
+ char *home, *rhome;
+ const char *confname;
struct passwd *cpwd;
- char *line = NULL;
+ char *line;
int retval;
size_t len = 0;
-
- if (idata->flags & PAMNS_DEBUG)
- pam_syslog(idata->pamh, LOG_DEBUG, "Parsing config file %s",
- PAM_NAMESPACE_CONFIG);
+ glob_t globbuf;
+ const char *oldlocale;
+ size_t n;
/*
* Extract the user's home directory to resolve $HOME entries
@@ -364,35 +519,86 @@ static int parse_config_file(struct instance_data *idata)
"Error getting home dir for '%s'", idata->user);
return PAM_SESSION_ERR;
}
- home = strdupa(cpwd->pw_dir);
+ if ((home=strdup(cpwd->pw_dir)) == NULL) {
+ pam_syslog(idata->pamh, LOG_CRIT,
+ "Memory allocation error");
+ return PAM_SESSION_ERR;
+ }
+
+ cpwd = pam_modutil_getpwnam(idata->pamh, idata->ruser);
+ if (!cpwd) {
+ pam_syslog(idata->pamh, LOG_ERR,
+ "Error getting home dir for '%s'", idata->ruser);
+ free(home);
+ return PAM_SESSION_ERR;
+ }
+
+ if ((rhome=strdup(cpwd->pw_dir)) == NULL) {
+ pam_syslog(idata->pamh, LOG_CRIT,
+ "Memory allocation error");
+ free(home);
+ return PAM_SESSION_ERR;
+ }
/*
* Open configuration file, read one line at a time and call
* process_line to process each line.
*/
- fil = fopen(PAM_NAMESPACE_CONFIG, "r");
- if (fil == NULL) {
- pam_syslog(idata->pamh, LOG_ERR, "Error opening config file");
- return PAM_SERVICE_ERR;
- }
- /* Use unlocked IO */
- __fsetlocking(fil, FSETLOCKING_BYCALLER);
+ memset(&globbuf, '\0', sizeof(globbuf));
+ oldlocale = setlocale(LC_COLLATE, "C");
+ glob(NAMESPACE_D_GLOB, 0, NULL, &globbuf);
+ if (oldlocale != NULL)
+ setlocale(LC_COLLATE, oldlocale);
- /* loop reading the file */
- while (getline(&line, &len, fil) > 0) {
- retval = process_line(line, home, idata);
- if (retval) {
- pam_syslog(idata->pamh, LOG_ERR,
- "Error processing conf file line %s", line);
- fclose(fil);
- free(line);
- return PAM_SERVICE_ERR;
- }
- }
- fclose(fil);
- free(line);
+ confname = PAM_NAMESPACE_CONFIG;
+ n = 0;
+ for (;;) {
+ if (idata->flags & PAMNS_DEBUG)
+ pam_syslog(idata->pamh, LOG_DEBUG, "Parsing config file %s",
+ confname);
+ fil = fopen(confname, "r");
+ if (fil == NULL) {
+ pam_syslog(idata->pamh, LOG_ERR, "Error opening config file %s",
+ confname);
+ globfree(&globbuf);
+ free(rhome);
+ free(home);
+ return PAM_SERVICE_ERR;
+ }
+
+ /* Use unlocked IO */
+ __fsetlocking(fil, FSETLOCKING_BYCALLER);
+
+ line = NULL;
+ /* loop reading the file */
+ while (getline(&line, &len, fil) > 0) {
+ retval = process_line(line, home, rhome, idata);
+ if (retval) {
+ pam_syslog(idata->pamh, LOG_ERR,
+ "Error processing conf file %s line %s", confname, line);
+ fclose(fil);
+ free(line);
+ globfree(&globbuf);
+ free(rhome);
+ free(home);
+ return PAM_SERVICE_ERR;
+ }
+ }
+ fclose(fil);
+ free(line);
+
+ if (n >= globbuf.gl_pathc)
+ break;
+ confname = globbuf.gl_pathv[n];
+ n++;
+ }
+
+ globfree(&globbuf);
+ free(rhome);
+ free(home);
+
/* All done...just some debug stuff */
if (idata->flags & PAMNS_DEBUG) {
struct polydir_s *dptr = idata->polydirs_ptr;
@@ -419,6 +625,7 @@ static int parse_config_file(struct instance_data *idata)
* 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 +639,11 @@ static int ns_override(struct polydir_s *polyptr, struct instance_data *idata,
for (i = 0; i < polyptr->num_uids; i++) {
if (uid == polyptr->uid[i]) {
- return 1;
+ return !(polyptr->flags & POLYDIR_EXCLUSIVE);
}
}
- return 0;
+ return !!(polyptr->flags & POLYDIR_EXCLUSIVE);
}
/*
@@ -490,7 +697,19 @@ static int form_context(const struct polydir_s *polyptr,
if (polyptr->method == USER) return PAM_SUCCESS;
- rc = getexeccon(&scon);
+ if (idata->flags & PAMNS_USE_CURRENT_CONTEXT) {
+ rc = getcon(&scon);
+ } else if (idata->flags & PAMNS_USE_DEFAULT_CONTEXT) {
+ char *seuser = NULL, *level = NULL;
+
+ if ((rc=getseuserbyname(idata->user, &seuser, &level)) == 0) {
+ rc = get_default_context_with_level(seuser, level, NULL, &scon);
+ free(seuser);
+ free(level);
+ }
+ } else {
+ rc = getexeccon(&scon);
+ }
if (rc < 0 || scon == NULL) {
pam_syslog(idata->pamh, LOG_ERR,
"Error getting exec context, %m");
@@ -565,7 +784,7 @@ static int form_context(const struct polydir_s *polyptr,
/*
* poly_name returns the name of the polyinstantiated instance directory
- * based on the method used for polyinstantiation (user, context or both)
+ * based on the method used for polyinstantiation (user, context or level)
* In addition, the function also returns the security contexts of the
* original directory to polyinstantiate and the polyinstantiated instance
* directory.
@@ -581,6 +800,7 @@ static int poly_name(const struct polydir_s *polyptr, char **i_name,
{
int rc;
char *hash = NULL;
+ enum polymethod pm;
#ifdef WITH_SELINUX
security_context_t rawcon = NULL;
#endif
@@ -600,7 +820,23 @@ static int poly_name(const struct polydir_s *polyptr, char **i_name,
* Set the name of the polyinstantiated instance dir based on the
* polyinstantiation method.
*/
- switch (polyptr->method) {
+
+ pm = polyptr->method;
+ if (pm == LEVEL || pm == USER) {
+#ifdef WITH_SELINUX
+ if (!(idata->flags & PAMNS_CTXT_BASED_INST))
+#else
+ pam_syslog(idata->pamh, LOG_NOTICE,
+ "Context and level methods not available, using user method");
+#endif
+ if (polyptr->flags & POLYDIR_SHARED) {
+ rc = PAM_IGNORE;
+ goto fail;
+ }
+ pm = USER;
+ }
+
+ switch (pm) {
case USER:
if (asprintf(i_name, "%s", idata->user) < 0) {
*i_name = NULL;
@@ -614,15 +850,28 @@ static int poly_name(const struct polydir_s *polyptr, char **i_name,
if (selinux_trans_to_raw_context(*i_context, &rawcon) < 0) {
pam_syslog(idata->pamh, LOG_ERR, "Error translating directory context");
goto fail;
- }
- if (asprintf(i_name, "%s_%s", rawcon, idata->user) < 0) {
- *i_name = NULL;
- goto fail;
+ }
+ if (polyptr->flags & POLYDIR_SHARED) {
+ if (asprintf(i_name, "%s", rawcon) < 0) {
+ *i_name = NULL;
+ goto fail;
+ }
+ } else {
+ if (asprintf(i_name, "%s_%s", rawcon, idata->user) < 0) {
+ *i_name = NULL;
+ goto fail;
+ }
}
break;
#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");
@@ -643,7 +892,7 @@ static int poly_name(const struct polydir_s *polyptr, char **i_name,
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;
}
@@ -726,12 +975,13 @@ static int check_inst_parent(char *ipath, struct instance_data *idata)
* execute it and pass directory to polyinstantiate and instance
* directory as arguments.
*/
-static int inst_init(const struct polydir_s *polyptr, char *ipath,
- struct instance_data *idata)
+static int inst_init(const struct polydir_s *polyptr, const char *ipath,
+ struct instance_data *idata, int newdir)
{
pid_t rc, pid;
sighandler_t osighand = NULL;
int status;
+ const char *init_script = NAMESPACE_INIT_SCRIPT;
osighand = signal(SIGCHLD, SIG_DFL);
if (osighand == SIG_ERR) {
@@ -740,8 +990,11 @@ static int inst_init(const struct polydir_s *polyptr, char *ipath,
goto out;
}
- if (access(NAMESPACE_INIT_SCRIPT, F_OK) == 0) {
- if (access(NAMESPACE_INIT_SCRIPT, X_OK) < 0) {
+ if ((polyptr->flags & POLYDIR_ISCRIPT) && polyptr->init_script)
+ init_script = polyptr->init_script;
+
+ if (access(init_script, F_OK) == 0) {
+ if (access(init_script, X_OK) < 0) {
if (idata->flags & PAMNS_DEBUG)
pam_syslog(idata->pamh, LOG_ERR,
"Namespace init script not executable");
@@ -756,8 +1009,8 @@ static int inst_init(const struct polydir_s *polyptr, char *ipath,
exit(1);
}
#endif
- if (execl(NAMESPACE_INIT_SCRIPT, NAMESPACE_INIT_SCRIPT,
- polyptr->dir, ipath, (char *)NULL) < 0)
+ if (execl(init_script, init_script,
+ 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) &&
@@ -788,46 +1041,116 @@ out:
return rc;
}
+static int create_polydir(struct polydir_s *polyptr,
+ struct instance_data *idata)
+{
+ mode_t mode;
+ int rc;
+#ifdef WITH_SELINUX
+ security_context_t dircon, oldcon = NULL;
+#endif
+ const char *dir = polyptr->dir;
+
+ if (polyptr->mode != (mode_t)ULONG_MAX)
+ mode = polyptr->mode;
+ else
+ mode = 0777;
+
+#ifdef WITH_SELINUX
+ if (idata->flags & PAMNS_SELINUX_ENABLED) {
+ getfscreatecon(&oldcon);
+ rc = matchpathcon(dir, S_IFDIR, &dircon);
+ if (rc) {
+ pam_syslog(idata->pamh, LOG_NOTICE,
+ "Unable to get default context for directory %s, check your policy: %m", dir);
+ } else {
+ if (idata->flags & PAMNS_DEBUG)
+ pam_syslog(idata->pamh, LOG_DEBUG,
+ "Polydir %s context: %s", dir, (char *)dircon);
+ if (setfscreatecon(dircon) != 0)
+ pam_syslog(idata->pamh, LOG_NOTICE,
+ "Error setting context for directory %s: %m", dir);
+ freecon(dircon);
+ }
+ matchpathcon_fini();
+ }
+#endif
+
+ rc = mkdir(dir, mode);
+ if (rc != 0) {
+ pam_syslog(idata->pamh, LOG_ERR,
+ "Error creating directory %s: %m", dir);
+ return PAM_SESSION_ERR;
+ }
+
+#ifdef WITH_SELINUX
+ if (idata->flags & PAMNS_SELINUX_ENABLED) {
+ if (setfscreatecon(oldcon) != 0)
+ pam_syslog(idata->pamh, LOG_NOTICE,
+ "Error resetting fs create context: %m");
+ freecon(oldcon);
+ }
+#endif
+
+ if (idata->flags & PAMNS_DEBUG)
+ pam_syslog(idata->pamh, LOG_DEBUG, "Created polydir %s", dir);
+
+ if (polyptr->mode != (mode_t)ULONG_MAX) {
+ /* explicit mode requested */
+ if (chmod(dir, mode) != 0) {
+ pam_syslog(idata->pamh, LOG_ERR,
+ "Error changing mode of directory %s: %m", dir);
+ rmdir(dir);
+ return PAM_SESSION_ERR;
+ }
+ }
+
+ if (polyptr->owner != (uid_t)ULONG_MAX) {
+ if (chown(dir, polyptr->owner, polyptr->group) != 0) {
+ pam_syslog(idata->pamh, LOG_ERR,
+ "Unable to change owner on directory %s: %m", dir);
+ rmdir(dir);
+ return PAM_SESSION_ERR;
+ }
+ if (idata->flags & PAMNS_DEBUG)
+ pam_syslog(idata->pamh, LOG_DEBUG,
+ "Polydir owner %u group %u from configuration", polyptr->owner, polyptr->group);
+ } else {
+ if (chown(dir, idata->uid, idata->gid) != 0) {
+ pam_syslog(idata->pamh, LOG_ERR,
+ "Unable to change owner on directory %s: %m", dir);
+ rmdir(dir);
+ return PAM_SESSION_ERR;
+ }
+ if (idata->flags & PAMNS_DEBUG)
+ pam_syslog(idata->pamh, LOG_DEBUG,
+ "Polydir owner %u group %u", idata->uid, idata->gid);
+ }
+
+ return PAM_SUCCESS;
+}
+
/*
* 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, struct stat *statbuf,
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 stat *statbuf,
struct instance_data *idata)
#endif
{
- struct stat statbuf, newstatbuf;
- int rc, fd;
+ struct stat newstatbuf;
+ int fd;
+ int newdir = 0;
/*
- * stat the directory to polyinstantiate, so its owner-group-mode
- * can be propagated to instance directory
+ * Check to make sure instance parent is valid.
*/
- rc = PAM_SUCCESS;
- if (stat(polyptr->dir, &statbuf) < 0) {
- pam_syslog(idata->pamh, LOG_ERR, "Error stating %s, %m",
- polyptr->dir);
- return PAM_SESSION_ERR;
- }
-
- /*
- * Make sure we are dealing with a directory
- */
- if (!S_ISDIR(statbuf.st_mode)) {
- pam_syslog(idata->pamh, LOG_ERR, "poly dir %s is not a dir",
- polyptr->dir);
- return PAM_SESSION_ERR;
- }
-
- /*
- * Check to make sure instance parent is valid.
- */
- if (check_inst_parent(ipath, idata))
- return PAM_SESSION_ERR;
+ if (check_inst_parent(ipath, idata))
+ return PAM_SESSION_ERR;
/*
* Create instance directory and set its security context to the context
@@ -835,7 +1158,17 @@ static int create_dirs(const struct polydir_s *polyptr, char *ipath,
* 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 {
@@ -845,6 +1178,7 @@ static int create_dirs(const struct polydir_s *polyptr, char *ipath,
}
}
+ newdir = 1;
/* Open a descriptor to it to prevent races */
fd = open(ipath, O_DIRECTORY | O_RDONLY);
if (fd < 0) {
@@ -881,9 +1215,9 @@ static int create_dirs(const struct polydir_s *polyptr, char *ipath,
rmdir(ipath);
return PAM_SESSION_ERR;
}
- if (newstatbuf.st_uid != statbuf.st_uid ||
- newstatbuf.st_gid != statbuf.st_gid) {
- if (fchown(fd, statbuf.st_uid, statbuf.st_gid) < 0) {
+ if (newstatbuf.st_uid != statbuf->st_uid ||
+ newstatbuf.st_gid != statbuf->st_gid) {
+ if (fchown(fd, statbuf->st_uid, statbuf->st_gid) < 0) {
pam_syslog(idata->pamh, LOG_ERR,
"Error changing owner for %s, %m",
ipath);
@@ -892,7 +1226,7 @@ static int create_dirs(const struct polydir_s *polyptr, char *ipath,
return PAM_SESSION_ERR;
}
}
- if (fchmod(fd, statbuf.st_mode & 07777) < 0) {
+ if (fchmod(fd, statbuf->st_mode & 07777) < 0) {
pam_syslog(idata->pamh, LOG_ERR, "Error changing mode for %s, %m",
ipath);
close(fd);
@@ -909,8 +1243,10 @@ static int create_dirs(const struct polydir_s *polyptr, char *ipath,
*/
inst_init:
- rc = inst_init(polyptr, ipath, idata);
- return rc;
+ if (polyptr->flags & POLYDIR_NOINIT)
+ return PAM_SUCCESS;
+
+ return inst_init(polyptr, ipath, idata, newdir);
}
@@ -921,13 +1257,13 @@ 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;
+ struct stat statbuf;
#ifdef WITH_SELINUX
security_context_t instcontext = NULL, origcontext = NULL;
#endif
@@ -936,9 +1272,36 @@ static int ns_setup(const struct polydir_s *polyptr,
pam_syslog(idata->pamh, LOG_DEBUG,
"Set namespace for directory %s", polyptr->dir);
- dir = strrchr(polyptr->dir, '/');
- if (dir && strlen(dir) > 1)
- dir++;
+ while (stat(polyptr->dir, &statbuf) < 0) {
+ if (retval || !(polyptr->flags & POLYDIR_CREATE)) {
+ pam_syslog(idata->pamh, LOG_ERR, "Error stating %s, %m",
+ polyptr->dir);
+ return PAM_SESSION_ERR;
+ } else {
+ if (create_polydir(polyptr, idata) != PAM_SUCCESS)
+ return PAM_SESSION_ERR;
+ retval = PAM_SESSION_ERR; /* bail out on next failed stat */
+ }
+ }
+
+ /*
+ * Make sure we are dealing with a directory
+ */
+ if (!S_ISDIR(statbuf.st_mode)) {
+ pam_syslog(idata->pamh, LOG_ERR, "Polydir %s is not a dir",
+ polyptr->dir);
+ return PAM_SESSION_ERR;
+ }
+
+ 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, 1);
+ }
/*
* Obtain the name of instance pathname based on the
@@ -952,9 +1315,10 @@ static int ns_setup(const struct polydir_s *polyptr,
retval = poly_name(polyptr, &instname, idata);
#endif
- if (retval) {
- pam_syslog(idata->pamh, LOG_ERR, "Error getting instance name");
- goto error_out;
+ if (retval != PAM_SUCCESS) {
+ if (retval != PAM_IGNORE)
+ pam_syslog(idata->pamh, LOG_ERR, "Error getting instance name");
+ goto cleanup;
} else {
#ifdef WITH_SELINUX
if ((idata->flags & PAMNS_DEBUG) &&
@@ -976,10 +1340,10 @@ static int ns_setup(const struct polydir_s *polyptr,
* contexts, owner, group and mode bits.
*/
#ifdef WITH_SELINUX
- retval = create_dirs(polyptr, inst_dir, instcontext,
+ retval = create_dirs(polyptr, inst_dir, &statbuf, instcontext,
origcontext, idata);
#else
- retval = create_dirs(polyptr, inst_dir, idata);
+ retval = create_dirs(polyptr, inst_dir, &statbuf, idata);
#endif
if (retval < 0) {
@@ -1044,6 +1408,58 @@ static int cwd_in(char *dir, struct instance_data *idata)
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
@@ -1056,34 +1472,18 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt)
int retval = 0, need_poly = 0, changing_dir = 0;
char *cptr, *fptr, poly_parent[PATH_MAX];
struct polydir_s *pptr;
- uid_t req_uid;
- const void *ruser_name;
- struct passwd *pwd;
if (idata->flags & PAMNS_DEBUG)
pam_syslog(idata->pamh, LOG_DEBUG, "Set up namespace for pid %d",
getpid());
- retval = pam_get_item(idata->pamh, PAM_RUSER, &ruser_name);
- if (ruser_name == NULL || retval != PAM_SUCCESS) {
- retval = PAM_SUCCESS;
- req_uid = getuid();
- } else {
- pwd = pam_modutil_getpwnam(idata->pamh, ruser_name);
- if (pwd != NULL) {
- req_uid = pwd->pw_uid;
- } else {
- req_uid = getuid();
- }
- }
-
/*
* Cycle through all polyinstantiated directory entries to see if
* polyinstantiation is needed at all.
*/
for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) {
if (ns_override(pptr, idata, idata->uid)) {
- if (unmnt == NO_UNMNT || ns_override(pptr, idata, req_uid)) {
+ if (unmnt == NO_UNMNT || ns_override(pptr, idata, idata->ruid)) {
if (idata->flags & PAMNS_DEBUG)
pam_syslog(idata->pamh, LOG_DEBUG,
"Overriding poly for user %d for dir %s",
@@ -1092,7 +1492,7 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt)
if (idata->flags & PAMNS_DEBUG)
pam_syslog(idata->pamh, LOG_DEBUG,
"Need unmount ns for user %d for dir %s",
- idata->uid, pptr->dir);
+ idata->ruid, pptr->dir);
need_poly = 1;
break;
}
@@ -1108,17 +1508,19 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt)
}
/*
- * If polyinstnatiation is needed, call the unshare system call to
+ * If polyinstantiation is needed, call the unshare system call to
* disassociate from the parent namespace.
*/
if (need_poly) {
if (unshare(CLONE_NEWNS) < 0) {
- pam_syslog(idata->pamh, LOG_ERR,
+ 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,
@@ -1127,7 +1529,7 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt)
for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) {
enum unmnt_op dir_unmnt = unmnt;
if (ns_override(pptr, idata, idata->uid)) {
- if (unmnt == NO_UNMNT || ns_override(pptr, idata, req_uid)) {
+ if (unmnt == NO_UNMNT || ns_override(pptr, idata, idata->ruid)) {
continue;
} else {
dir_unmnt = UNMNT_ONLY;
@@ -1144,8 +1546,9 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt)
* bind mounted instance_parent directory that we are trying to
* umount
*/
- if ((changing_dir = cwd_in(pptr->dir, idata)) < 0) {
- return PAM_SESSION_ERR;
+ if ((changing_dir = cwd_in(pptr->rdir, idata)) < 0) {
+ retval = PAM_SESSION_ERR;
+ goto out;
} else if (changing_dir) {
if (idata->flags & PAMNS_DEBUG)
pam_syslog(idata->pamh, LOG_DEBUG, "changing cwd");
@@ -1156,7 +1559,7 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt)
* directory where original contents of the polydir
* are available from
*/
- strcpy(poly_parent, pptr->dir);
+ strcpy(poly_parent, pptr->rdir);
fptr = strchr(poly_parent, '/');
cptr = strrchr(poly_parent, '/');
if (fptr && cptr && (fptr == cptr))
@@ -1169,24 +1572,36 @@ static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt)
}
}
- if (umount(pptr->dir) < 0) {
+ if (umount(pptr->rdir) < 0) {
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;
+ pptr->rdir);
+ 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);
+ pptr->rdir);
}
if (dir_unmnt != UNMNT_ONLY) {
retval = ns_setup(pptr, idata);
+ if (retval == PAM_IGNORE)
+ retval = PAM_SUCCESS;
if (retval != PAM_SUCCESS)
break;
}
}
-
+out:
+ if (retval != PAM_SUCCESS)
+ cleanup_tmpdirs(idata);
+ else 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");
+ cleanup_tmpdirs(idata);
+ return PAM_SYSTEM_ERR;
+ }
return retval;
}
@@ -1225,8 +1640,10 @@ static int orig_namespace(struct instance_data *idata)
} else if (idata->flags & PAMNS_DEBUG)
pam_syslog(idata->pamh, LOG_DEBUG, "Unmount of %s succeeded",
pptr->dir);
- }
+ }
}
+
+ cleanup_tmpdirs(idata);
return 0;
}
@@ -1239,7 +1656,7 @@ static int orig_namespace(struct instance_data *idata)
* The return value from this function is used when selecting the
* polyinstantiation method. If context change is not requested then
* the polyinstantiation method is set to USER, even if the configuration
- * file lists the method as "context" or "both".
+ * file lists the method as "context" or "level".
*/
static int ctxt_based_inst_needed(void)
{
@@ -1257,6 +1674,55 @@ static int ctxt_based_inst_needed(void)
#endif
+static int get_user_data(struct instance_data *idata)
+{
+ int retval;
+ char *user_name;
+ struct passwd *pwd;
+ /*
+ * Lookup user and fill struct items
+ */
+ retval = pam_get_item(idata->pamh, PAM_USER, (void*) &user_name );
+ if ( user_name == NULL || retval != PAM_SUCCESS ) {
+ pam_syslog(idata->pamh, LOG_ERR, "Error recovering pam user name");
+ return PAM_SESSION_ERR;
+ }
+
+ pwd = pam_modutil_getpwnam(idata->pamh, user_name);
+ if (!pwd) {
+ pam_syslog(idata->pamh, LOG_ERR, "user unknown '%s'", user_name);
+ return PAM_USER_UNKNOWN;
+ }
+
+ /*
+ * Add the user info to the instance data so we can refer to them later.
+ */
+ idata->user[0] = 0;
+ strncat(idata->user, user_name, sizeof(idata->user) - 1);
+ idata->uid = pwd->pw_uid;
+ idata->gid = pwd->pw_gid;
+
+ /* Fill in RUSER too */
+ retval = pam_get_item(idata->pamh, PAM_RUSER, (void*) &user_name );
+ if ( user_name != NULL && retval == PAM_SUCCESS && user_name[0] != '\0' ) {
+ strncat(idata->ruser, user_name, sizeof(idata->ruser) - 1);
+ pwd = pam_modutil_getpwnam(idata->pamh, user_name);
+ } else {
+ pwd = pam_modutil_getpwuid(idata->pamh, getuid());
+ }
+ if (!pwd) {
+ pam_syslog(idata->pamh, LOG_ERR, "user unknown '%s'", user_name);
+ return PAM_USER_UNKNOWN;
+ }
+ user_name = pwd->pw_name;
+
+ idata->ruser[0] = 0;
+ strncat(idata->ruser, user_name, sizeof(idata->ruser) - 1);
+ idata->ruid = pwd->pw_uid;
+
+ return PAM_SUCCESS;
+}
+
/*
* Entry point from pam_open_session call.
*/
@@ -1265,8 +1731,6 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
{
int i, retval;
struct instance_data idata;
- char *user_name;
- struct passwd *pwd;
enum unmnt_op unmnt = NO_UNMNT;
/* init instance data */
@@ -1290,6 +1754,14 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
idata.flags |= PAMNS_IGN_CONFIG_ERR;
if (strcmp(argv[i], "ignore_instance_parent_mode") == 0)
idata.flags |= PAMNS_IGN_INST_PARENT_MODE;
+ if (strcmp(argv[i], "use_current_context") == 0) {
+ idata.flags |= PAMNS_USE_CURRENT_CONTEXT;
+ idata.flags |= PAMNS_CTXT_BASED_INST;
+ }
+ if (strcmp(argv[i], "use_default_context") == 0) {
+ idata.flags |= PAMNS_USE_DEFAULT_CONTEXT;
+ idata.flags |= PAMNS_CTXT_BASED_INST;
+ }
if (strcmp(argv[i], "unmnt_remnt") == 0)
unmnt = UNMNT_REMNT;
if (strcmp(argv[i], "unmnt_only") == 0)
@@ -1305,27 +1777,9 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
if (idata.flags & PAMNS_DEBUG)
pam_syslog(idata.pamh, LOG_DEBUG, "open_session - start");
- /*
- * Lookup user and fill struct items
- */
- retval = pam_get_item(idata.pamh, PAM_USER, (void*) &user_name );
- if ( user_name == NULL || retval != PAM_SUCCESS ) {
- pam_syslog(idata.pamh, LOG_ERR, "Error recovering pam user name");
- return PAM_SESSION_ERR;
- }
-
- pwd = pam_modutil_getpwnam(idata.pamh, user_name);
- if (!pwd) {
- pam_syslog(idata.pamh, LOG_ERR, "user unknown '%s'", user_name);
- return PAM_SESSION_ERR;
- }
-
- /*
- * Add the user info to the instance data so we can refer to them later.
- */
- idata.user[0] = 0;
- strncat(idata.user, user_name, sizeof(idata.user) - 1);
- idata.uid = pwd->pw_uid;
+ retval = get_user_data(&idata);
+ if (retval != PAM_SUCCESS)
+ return retval;
/*
* Parse namespace configuration file which lists directories to
@@ -1351,7 +1805,8 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
} 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;
}
@@ -1364,8 +1819,7 @@ PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
{
int i, retval;
struct instance_data idata;
- char *user_name;
- struct passwd *pwd;
+ void *polyptr;
/* init instance data */
idata.flags = 0;
@@ -1407,38 +1861,16 @@ PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
return PAM_SUCCESS;
}
- /*
- * Lookup user and fill struct items
- */
- retval = pam_get_item(idata.pamh, PAM_USER, (void*) &user_name );
- if ( user_name == NULL || retval != PAM_SUCCESS ) {
- pam_syslog(idata.pamh, LOG_ERR, "Error recovering pam user name");
- return PAM_SESSION_ERR;
- }
-
- pwd = pam_modutil_getpwnam(idata.pamh, user_name);
- if (!pwd) {
- pam_syslog(idata.pamh, LOG_ERR, "user unknown '%s'", user_name);
- return PAM_SESSION_ERR;
- }
-
- /*
- * Add the user info to the instance data so we can refer to them later.
- */
- idata.user[0] = 0;
- strncat(idata.user, user_name, sizeof(idata.user) - 1);
- idata.uid = pwd->pw_uid;
+ retval = get_user_data(&idata);
+ if (retval != PAM_SUCCESS)
+ return retval;
- /*
- * 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, (const void **)&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",
@@ -1453,7 +1885,9 @@ PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
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;
}
diff --git a/Linux-PAM/modules/pam_namespace/pam_namespace.h b/Linux-PAM/modules/pam_namespace/pam_namespace.h
index 0847ec08..bfc0da17 100644
--- a/Linux-PAM/modules/pam_namespace/pam_namespace.h
+++ b/Linux-PAM/modules/pam_namespace/pam_namespace.h
@@ -47,6 +47,7 @@
#include <dlfcn.h>
#include <stdarg.h>
#include <pwd.h>
+#include <grp.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -56,6 +57,8 @@
#include <libgen.h>
#include <fcntl.h>
#include <sched.h>
+#include <glob.h>
+#include <locale.h>
#include "security/pam_modules.h"
#include "security/pam_modutil.h"
#include "security/pam_ext.h"
@@ -63,6 +66,7 @@
#ifdef WITH_SELINUX
#include <selinux/selinux.h>
+#include <selinux/get_context_list.h>
#include <selinux/context.h>
#endif
@@ -73,14 +77,16 @@
/*
* Module defines
*/
-#ifndef PAM_NAMESPACE_CONFIG
-#define PAM_NAMESPACE_CONFIG "/etc/security/namespace.conf"
+#ifndef SECURECONF_DIR
+#define SECURECONF_DIR "/etc/security/"
#endif
-#ifndef NAMESPACE_INIT_SCRIPT
-#define NAMESPACE_INIT_SCRIPT "/etc/security/namespace.init"
-#endif
+#define PAM_NAMESPACE_CONFIG (SECURECONF_DIR "namespace.conf")
+#define NAMESPACE_INIT_SCRIPT (SECURECONF_DIR "namespace.init")
+#define NAMESPACE_D_DIR (SECURECONF_DIR "namespace.d/")
+#define NAMESPACE_D_GLOB (SECURECONF_DIR "namespace.d/*.conf")
+/* module flags */
#define PAMNS_DEBUG 0x00000100 /* Running in debug mode */
#define PAMNS_SELINUX_ENABLED 0x00000400 /* SELinux is enabled */
#define PAMNS_CTXT_BASED_INST 0x00000800 /* Context based instance needed */
@@ -88,8 +94,19 @@
#define PAMNS_IGN_CONFIG_ERR 0x00004000 /* Ignore format error in conf file */
#define PAMNS_IGN_INST_PARENT_MODE 0x00008000 /* Ignore instance parent mode */
#define PAMNS_NO_UNMOUNT_ON_CLOSE 0x00010000 /* no unmount at session close */
+#define PAMNS_USE_CURRENT_CONTEXT 0x00020000 /* use getcon instead of getexeccon */
+#define PAMNS_USE_DEFAULT_CONTEXT 0x00040000 /* use get_default_context instead of getexeccon */
+
+/* polydir flags */
+#define POLYDIR_EXCLUSIVE 0x00000001 /* polyinstatiate exclusively for override uids */
+#define POLYDIR_CREATE 0x00000002 /* create the polydir */
+#define POLYDIR_NOINIT 0x00000004 /* no init script */
+#define POLYDIR_SHARED 0x00000008 /* share context/level instances among users */
+#define POLYDIR_ISCRIPT 0x00000010 /* non default init script */
+
#define NAMESPACE_MAX_DIR_LEN 80
+#define NAMESPACE_POLYDIR_DATA "pam_namespace:polydir_data"
/*
* Polyinstantiation method options, based on user, security context
@@ -100,6 +117,8 @@ enum polymethod {
USER,
CONTEXT,
LEVEL,
+ TMPDIR,
+ TMPFS
};
/*
@@ -124,10 +143,16 @@ enum unmnt_op {
*/
struct polydir_s {
char dir[PATH_MAX]; /* directory to polyinstantiate */
+ char rdir[PATH_MAX]; /* directory to unmount (based on RUSER) */
char instance_prefix[PATH_MAX]; /* prefix for instance dir path name */
enum polymethod method; /* method used to polyinstantiate */
unsigned int num_uids; /* number of override uids */
uid_t *uid; /* list of override uids */
+ unsigned int flags; /* polydir flags */
+ char *init_script; /* path to init script */
+ uid_t owner; /* user which should own the polydir */
+ gid_t group; /* group which should own the polydir */
+ mode_t mode; /* mode of the polydir */
struct polydir_s *next; /* pointer to the next polydir entry */
};
@@ -135,6 +160,9 @@ struct instance_data {
pam_handle_t *pamh; /* The pam handle for this instance */
struct polydir_s *polydirs_ptr; /* The linked list pointer */
char user[LOGIN_NAME_MAX]; /* User name */
+ char ruser[LOGIN_NAME_MAX]; /* Requesting user name */
uid_t uid; /* The uid of the user */
- unsigned long flags; /* Flags for debug, selinux etc */
+ gid_t gid; /* The gid of the user's primary group */
+ uid_t ruid; /* The uid of the requesting user */
+ unsigned long flags; /* Flags for debug, selinux etc */
};