1 /******************************************************************************
2 * A module for Linux-PAM that will set the default namespace after
3 * establishing a session via PAM.
4 *
5 * (C) Copyright IBM Corporation 2005
6 * (C) Copyright Red Hat 2006
7 * All Rights Reserved.
8 *
9 * Written by: Janak Desai <janak@us.ibm.com>
10 * With Revisions by: Steve Grubb <sgrubb@redhat.com>
11 * Derived from a namespace setup patch by Chad Sellers <cdselle@tycho.nsa.gov>
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a
14 * copy of this software and associated documentation files (the "Software"),
15 * to deal in the Software without restriction, including without limitation
16 * on the rights to use, copy, modify, merge, publish, distribute, sub
17 * license, and/or sell copies of the Software, and to permit persons to whom
18 * the Software is furnished to do so, subject to the following conditions:
19 *
20 * The above copyright notice and this permission notice (including the next
21 * paragraph) shall be included in all copies or substantial portions of the
22 * Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
27 * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 * DEALINGS IN THE SOFTWARE.
31 */
32
33 #ifndef __linux__
34 #error THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!!
35 #endif
36
37 #include "config.h"
38
39 #include <stdio.h>
40 #include <stdio_ext.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <ctype.h>
44 #include <stdlib.h>
45 #include <errno.h>
46 #include <syslog.h>
47 #include <dlfcn.h>
48 #include <stdarg.h>
49 #include <pwd.h>
50 #include <grp.h>
51 #include <limits.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <sys/resource.h>
55 #include <sys/mount.h>
56 #include <sys/wait.h>
57 #include <libgen.h>
58 #include <fcntl.h>
59 #include <sched.h>
60 #include <glob.h>
61 #include <locale.h>
62 #include "security/pam_modules.h"
63 #include "security/pam_modutil.h"
64 #include "security/pam_ext.h"
65 #include "md5.h"
66
67 #ifdef WITH_SELINUX
68 #include <selinux/selinux.h>
69 #include <selinux/get_context_list.h>
70 #include <selinux/context.h>
71 #include <selinux/label.h>
72 #endif
73
74 #ifndef CLONE_NEWNS
75 #define CLONE_NEWNS 0x00020000 /* Flag to create new namespace */
76 #endif
77
78 /* mount flags for mount_private */
79 #ifndef MS_REC
80 #define MS_REC (1<<14)
81 #endif
82 #ifndef MS_PRIVATE
83 #define MS_PRIVATE (1<<18)
84 #endif
85 #ifndef MS_SLAVE
86 #define MS_SLAVE (1<<19)
87 #endif
88
89
90 /*
91 * Module defines
92 */
93 #define PAM_NAMESPACE_CONFIG (SCONFIGDIR "/namespace.conf")
94 #define NAMESPACE_INIT_SCRIPT (SCONFIGDIR "/namespace.init")
95 #define NAMESPACE_D_DIR (SCONFIGDIR "/namespace.d/")
96 #define NAMESPACE_D_GLOB (SCONFIGDIR "/namespace.d/*.conf")
97 #ifdef VENDOR_SCONFIGDIR
98 #define VENDOR_NAMESPACE_INIT_SCRIPT (VENDOR_SCONFIGDIR "/namespace.init")
99 #define VENDOR_PAM_NAMESPACE_CONFIG (VENDOR_SCONFIGDIR "/namespace.conf")
100 #define VENDOR_NAMESPACE_D_DIR (VENDOR_SCONFIGDIR "/namespace.d/")
101 #define VENDOR_NAMESPACE_D_GLOB (VENDOR_SCONFIGDIR "/namespace.d/*.conf")
102 #endif
103
104 /* module flags */
105 #define PAMNS_DEBUG 0x00000100 /* Running in debug mode */
106 #define PAMNS_SELINUX_ENABLED 0x00000400 /* SELinux is enabled */
107 #define PAMNS_CTXT_BASED_INST 0x00000800 /* Context based instance needed */
108 #define PAMNS_GEN_HASH 0x00002000 /* Generate md5 hash for inst names */
109 #define PAMNS_IGN_CONFIG_ERR 0x00004000 /* Ignore format error in conf file */
110 #define PAMNS_IGN_INST_PARENT_MODE 0x00008000 /* Ignore instance parent mode */
111 #define PAMNS_UNMOUNT_ON_CLOSE 0x00010000 /* Unmount at session close */
112 #define PAMNS_USE_CURRENT_CONTEXT 0x00020000 /* use getcon instead of getexeccon */
113 #define PAMNS_USE_DEFAULT_CONTEXT 0x00040000 /* use get_default_context instead of getexeccon */
114 #define PAMNS_MOUNT_PRIVATE 0x00080000 /* Make the polydir mounts private */
115
116 /* polydir flags */
117 #define POLYDIR_EXCLUSIVE 0x00000001 /* polyinstatiate exclusively for override uids */
118 #define POLYDIR_CREATE 0x00000002 /* create the polydir */
119 #define POLYDIR_NOINIT 0x00000004 /* no init script */
120 #define POLYDIR_SHARED 0x00000008 /* share context/level instances among users */
121 #define POLYDIR_ISCRIPT 0x00000010 /* non default init script */
122 #define POLYDIR_MNTOPTS 0x00000020 /* mount options for tmpfs mount */
123
124
125 #define NAMESPACE_MAX_DIR_LEN 80
126 #define NAMESPACE_POLYDIR_DATA "pam_namespace:polydir_data"
127 #define NAMESPACE_PROTECT_DATA "pam_namespace:protect_data"
128
129 /*
130 * Polyinstantiation method options, based on user, security context
131 * or both
132 */
133 enum polymethod {
134 NONE,
135 USER,
136 CONTEXT,
137 LEVEL,
138 TMPDIR,
139 TMPFS
140 };
141
142 /*
143 * Depending on the application using this namespace module, we
144 * may need to unmount previously bind mounted instance directory.
145 * Applications such as login and sshd, that establish a new
146 * session unmount of instance directory is not needed. For applications
147 * such as su and newrole, that switch the identity, this module
148 * has to unmount previous instance directory first and re-mount
149 * based on the new identity. For other trusted applications that
150 * just want to undo polyinstantiation, only unmount of previous
151 * instance directory is needed.
152 */
153 enum unmnt_op {
154 NO_UNMNT,
155 UNMNT_REMNT,
156 UNMNT_ONLY,
157 };
158
159 /*
160 * Structure that holds information about a directory to polyinstantiate
161 */
162 struct polydir_s {
163 char dir[PATH_MAX]; /* directory to polyinstantiate */
164 char rdir[PATH_MAX]; /* directory to unmount (based on RUSER) */
165 char instance_prefix[PATH_MAX]; /* prefix for instance dir path name */
166 enum polymethod method; /* method used to polyinstantiate */
167 unsigned int num_uids; /* number of override uids */
168 uid_t *uid; /* list of override uids */
169 unsigned int flags; /* polydir flags */
170 char *init_script; /* path to init script */
171 char *mount_opts; /* mount options for tmpfs mount */
172 unsigned long mount_flags; /* mount flags for tmpfs mount */
173 uid_t owner; /* user which should own the polydir */
174 gid_t group; /* group which should own the polydir */
175 mode_t mode; /* mode of the polydir */
176 struct polydir_s *next; /* pointer to the next polydir entry */
177 };
178
179 struct protect_dir_s {
180 char *dir; /* protected directory */
181 struct protect_dir_s *next; /* next entry */
182 };
183
184 struct instance_data {
185 pam_handle_t *pamh; /* The pam handle for this instance */
186 struct polydir_s *polydirs_ptr; /* The linked list pointer */
187 struct protect_dir_s *protect_dirs; /* The pointer to stack of mount-protected dirs */
188 char user[LOGIN_NAME_MAX]; /* User name */
189 char ruser[LOGIN_NAME_MAX]; /* Requesting user name */
190 uid_t uid; /* The uid of the user */
191 gid_t gid; /* The gid of the user's primary group */
192 uid_t ruid; /* The uid of the requesting user */
193 unsigned long flags; /* Flags for debug, selinux etc */
194 };