]>
Commit | Line | Data |
---|---|---|
bd9a1e0d JR |
1 | support for temporary logons |
2 | ||
3 | diff -up Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.conf.5.xml.temp-logon Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.conf.5.xml | |
4 | --- Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.conf.5.xml.temp-logon 2007-06-18 12:46:47.000000000 +0200 | |
5 | +++ Linux-PAM-0.99.8.1/modules/pam_namespace/namespace.conf.5.xml 2007-08-06 13:16:56.000000000 +0200 | |
6 | @@ -72,10 +72,13 @@ | |
7 | ||
8 | <para> | |
9 | The third field, <replaceable>method</replaceable>, is the method | |
10 | - used for polyinstantiation. It can take 3 different values; "user" | |
11 | + used for polyinstantiation. It can take these values; "user" | |
12 | for polyinstantiation based on user name, "level" for | |
13 | - polyinstantiation based on process MLS level and user name, and "context" for | |
14 | - polyinstantiation based on process security context and user name | |
15 | + polyinstantiation based on process MLS level and user name, "context" for | |
16 | + polyinstantiation based on process security context and user name, | |
17 | + "tmpfs" for mounting tmpfs filesystem as an instance dir, and | |
18 | + "tmpdir" for creating temporary directory as an instance dir which is | |
19 | + removed when the user's session is closed. | |
20 | Methods "context" and "level" are only available with SELinux. This | |
21 | field cannot be blank. | |
22 | </para> | |
23 | @@ -84,7 +87,8 @@ | |
24 | The fourth field, <replaceable>list_of_uids</replaceable>, is | |
25 | a comma separated list of user names for whom the polyinstantiation | |
26 | is not performed. If left blank, polyinstantiation will be performed | |
27 | - for all users. | |
28 | + for all users. If the list is preceded with a single "~" character, | |
29 | + polyinstantiation is performed only for users in the list. | |
30 | </para> | |
31 | ||
32 | <para> | |
33 | diff -up Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.h.temp-logon Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.h | |
34 | --- Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.h.temp-logon 2007-06-18 12:46:47.000000000 +0200 | |
35 | +++ Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.h 2007-08-06 11:41:46.000000000 +0200 | |
36 | @@ -90,6 +90,7 @@ | |
37 | #define PAMNS_NO_UNMOUNT_ON_CLOSE 0x00010000 /* no unmount at session close */ | |
38 | ||
39 | #define NAMESPACE_MAX_DIR_LEN 80 | |
40 | +#define NAMESPACE_POLYDIR_DATA "pam_namespace:polydir_data" | |
41 | ||
42 | /* | |
43 | * Polyinstantiation method options, based on user, security context | |
44 | @@ -100,6 +101,8 @@ enum polymethod { | |
45 | USER, | |
46 | CONTEXT, | |
47 | LEVEL, | |
48 | + TMPDIR, | |
49 | + TMPFS | |
50 | }; | |
51 | ||
52 | /* | |
53 | @@ -128,6 +131,7 @@ struct polydir_s { | |
54 | enum polymethod method; /* method used to polyinstantiate */ | |
55 | unsigned int num_uids; /* number of override uids */ | |
56 | uid_t *uid; /* list of override uids */ | |
57 | + int exclusive; /* polyinstatiate exclusively for override uids */ | |
58 | struct polydir_s *next; /* pointer to the next polydir entry */ | |
59 | }; | |
60 | ||
61 | diff -up Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c.temp-logon Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c | |
62 | --- Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c.temp-logon 2007-06-18 12:46:47.000000000 +0200 | |
63 | +++ Linux-PAM-0.99.8.1/modules/pam_namespace/pam_namespace.c 2007-08-06 11:41:46.000000000 +0200 | |
64 | @@ -43,6 +43,7 @@ static int copy_ent(const struct polydir | |
65 | strcpy(pent->instance_prefix, ent->instance_prefix); | |
66 | pent->method = ent->method; | |
67 | pent->num_uids = ent->num_uids; | |
68 | + pent->exclusive = ent->exclusive; | |
69 | if (ent->num_uids) { | |
70 | uid_t *pptr, *eptr; | |
71 | ||
72 | @@ -120,6 +121,10 @@ static void del_polydir_list(struct poly | |
73 | } | |
74 | } | |
75 | ||
76 | +static void cleanup_data(pam_handle_t *pamh, void *data, int err) | |
77 | +{ | |
78 | + del_polydir_list(data); | |
79 | +} | |
80 | ||
81 | /* | |
82 | * Called from parse_config_file, this function processes a single line | |
83 | @@ -140,6 +145,7 @@ static int process_line(char *line, cons | |
84 | ||
85 | poly.uid = NULL; | |
86 | poly.num_uids = 0; | |
87 | + poly.exclusive = 0; | |
88 | ||
89 | /* | |
90 | * skip the leading white space | |
91 | @@ -223,24 +229,13 @@ static int process_line(char *line, cons | |
92 | } | |
93 | ||
94 | /* | |
95 | - * Ensure that all pathnames are absolute path names. | |
96 | - */ | |
97 | - if ((dir[0] != '/') || (instance_prefix[0] != '/')) { | |
98 | - pam_syslog(idata->pamh, LOG_NOTICE,"Pathnames must start with '/'"); | |
99 | - goto skipping; | |
100 | - } | |
101 | - if (strstr(dir, "..") || strstr(instance_prefix, "..")) { | |
102 | - pam_syslog(idata->pamh, LOG_NOTICE,"Pathnames must not contain '..'"); | |
103 | - goto skipping; | |
104 | - } | |
105 | - | |
106 | - /* | |
107 | * Populate polyinstantiated directory structure with appropriate | |
108 | * pathnames and the method with which to polyinstantiate. | |
109 | */ | |
110 | if (strlen(dir) >= sizeof(poly.dir) | |
111 | || strlen(instance_prefix) >= sizeof(poly.instance_prefix)) { | |
112 | pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long"); | |
113 | + goto skipping; | |
114 | } | |
115 | strcpy(poly.dir, dir); | |
116 | strcpy(poly.instance_prefix, instance_prefix); | |
117 | @@ -248,6 +243,18 @@ static int process_line(char *line, cons | |
118 | poly.method = NONE; | |
119 | if (strcmp(method, "user") == 0) | |
120 | poly.method = USER; | |
121 | + | |
122 | + if (strcmp(method, "tmpdir") == 0) { | |
123 | + poly.method = TMPDIR; | |
124 | + if (sizeof(poly.instance_prefix) - strlen(poly.instance_prefix) < 7) { | |
125 | + pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames too long"); | |
126 | + goto skipping; | |
127 | + } | |
128 | + strcat(poly.instance_prefix, "XXXXXX"); | |
129 | + } | |
130 | + | |
131 | + if (strcmp(method, "tmpfs") == 0) | |
132 | + poly.method = TMPFS; | |
133 | ||
134 | #ifdef WITH_SELINUX | |
135 | if (strcmp(method, "level") == 0) { | |
136 | @@ -266,12 +273,24 @@ static int process_line(char *line, cons | |
137 | ||
138 | #endif | |
139 | ||
140 | - if ( poly.method == NONE) { | |
141 | + if (poly.method == NONE) { | |
142 | pam_syslog(idata->pamh, LOG_NOTICE, "Illegal method"); | |
143 | goto skipping; | |
144 | } | |
145 | ||
146 | /* | |
147 | + * Ensure that all pathnames are absolute path names. | |
148 | + */ | |
149 | + if ((dir[0] != '/') || (poly.method != TMPFS && instance_prefix[0] != '/')) { | |
150 | + pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames must start with '/'"); | |
151 | + goto skipping; | |
152 | + } | |
153 | + if (strstr(dir, "..") || strstr(instance_prefix, "..")) { | |
154 | + pam_syslog(idata->pamh, LOG_NOTICE, "Pathnames must not contain '..'"); | |
155 | + goto skipping; | |
156 | + } | |
157 | + | |
158 | + /* | |
159 | * If the line in namespace.conf for a directory to polyinstantiate | |
160 | * contains a list of override users (users for whom polyinstantiation | |
161 | * is not performed), read the user ids, convert names into uids, and | |
162 | @@ -281,7 +300,11 @@ static int process_line(char *line, cons | |
163 | uid_t *uidptr; | |
164 | const char *ustr, *sstr; | |
165 | int count, i; | |
166 | - | |
167 | + | |
168 | + if (*uids == '~') { | |
169 | + poly.exclusive = 1; | |
170 | + uids++; | |
171 | + } | |
172 | for (count = 0, ustr = sstr = uids; sstr; ustr = sstr + 1, count++) | |
173 | sstr = strchr(ustr, ','); | |
174 | ||
175 | @@ -419,6 +442,7 @@ static int parse_config_file(struct inst | |
176 | * directory's list of override uids. If the uid is one of the override | |
177 | * uids for the polyinstantiated directory, polyinstantiation is not | |
178 | * performed for that user for that directory. | |
179 | + * If exclusive is set the returned values are opposite. | |
180 | */ | |
181 | static int ns_override(struct polydir_s *polyptr, struct instance_data *idata, | |
182 | uid_t uid) | |
183 | @@ -432,11 +456,11 @@ static int ns_override(struct polydir_s | |
184 | ||
185 | for (i = 0; i < polyptr->num_uids; i++) { | |
186 | if (uid == polyptr->uid[i]) { | |
187 | - return 1; | |
188 | + return !polyptr->exclusive; | |
189 | } | |
190 | } | |
191 | ||
192 | - return 0; | |
193 | + return polyptr->exclusive; | |
194 | } | |
195 | ||
196 | /* | |
197 | @@ -622,6 +646,12 @@ static int poly_name(const struct polydi | |
198 | ||
199 | #endif /* WITH_SELINUX */ | |
200 | ||
201 | + case TMPDIR: | |
202 | + case TMPFS: | |
203 | + if ((*i_name=strdup("")) == NULL) | |
204 | + goto fail; | |
205 | + return PAM_SUCCESS; | |
206 | + | |
207 | default: | |
208 | if (idata->flags & PAMNS_DEBUG) | |
209 | pam_syslog(idata->pamh, LOG_ERR, "Unknown method"); | |
210 | @@ -725,7 +755,7 @@ static int check_inst_parent(char *ipath | |
211 | * execute it and pass directory to polyinstantiate and instance | |
212 | * directory as arguments. | |
213 | */ | |
214 | -static int inst_init(const struct polydir_s *polyptr, char *ipath, | |
215 | +static int inst_init(const struct polydir_s *polyptr, const char *ipath, | |
216 | struct instance_data *idata) | |
217 | { | |
218 | pid_t rc, pid; | |
219 | @@ -791,11 +821,11 @@ out: | |
220 | * Create polyinstantiated instance directory (ipath). | |
221 | */ | |
222 | #ifdef WITH_SELINUX | |
223 | -static int create_dirs(const struct polydir_s *polyptr, char *ipath, | |
224 | +static int create_dirs(struct polydir_s *polyptr, char *ipath, | |
225 | security_context_t icontext, security_context_t ocontext, | |
226 | struct instance_data *idata) | |
227 | #else | |
228 | -static int create_dirs(const struct polydir_s *polyptr, char *ipath, | |
229 | +static int create_dirs(struct polydir_s *polyptr, char *ipath, | |
230 | struct instance_data *idata) | |
231 | #endif | |
232 | { | |
233 | @@ -834,7 +864,17 @@ static int create_dirs(const struct poly | |
234 | * attributes to match that of the original directory that is being | |
235 | * polyinstantiated. | |
236 | */ | |
237 | - if (mkdir(ipath, S_IRUSR) < 0) { | |
238 | + | |
239 | + if (polyptr->method == TMPDIR) { | |
240 | + if (mkdtemp(polyptr->instance_prefix) == NULL) { | |
241 | + pam_syslog(idata->pamh, LOG_ERR, "Error creating temporary instance %s, %m", | |
242 | + polyptr->instance_prefix); | |
243 | + polyptr->method = NONE; /* do not clean up! */ | |
244 | + return PAM_SESSION_ERR; | |
245 | + } | |
246 | + /* copy the actual directory name to ipath */ | |
247 | + strcpy(ipath, polyptr->instance_prefix); | |
248 | + } else if (mkdir(ipath, S_IRUSR) < 0) { | |
249 | if (errno == EEXIST) | |
250 | goto inst_init; | |
251 | else { | |
252 | @@ -920,13 +960,12 @@ inst_init: | |
253 | * security attributes, and performs bind mount to setup the process | |
254 | * namespace. | |
255 | */ | |
256 | -static int ns_setup(const struct polydir_s *polyptr, | |
257 | +static int ns_setup(struct polydir_s *polyptr, | |
258 | struct instance_data *idata) | |
259 | { | |
260 | int retval = 0; | |
261 | char *inst_dir = NULL; | |
262 | char *instname = NULL; | |
263 | - char *dir; | |
264 | #ifdef WITH_SELINUX | |
265 | security_context_t instcontext = NULL, origcontext = NULL; | |
266 | #endif | |
267 | @@ -935,9 +974,15 @@ static int ns_setup(const struct polydir | |
268 | pam_syslog(idata->pamh, LOG_DEBUG, | |
269 | "Set namespace for directory %s", polyptr->dir); | |
270 | ||
271 | - dir = strrchr(polyptr->dir, '/'); | |
272 | - if (dir && strlen(dir) > 1) | |
273 | - dir++; | |
274 | + if (polyptr->method == TMPFS) { | |
275 | + if (mount("tmpfs", polyptr->dir, "tmpfs", 0, NULL) < 0) { | |
276 | + pam_syslog(idata->pamh, LOG_ERR, "Error mounting tmpfs on %s, %m", | |
277 | + polyptr->dir); | |
278 | + return PAM_SESSION_ERR; | |
279 | + } | |
280 | + /* we must call inst_init after the mount in this case */ | |
281 | + return inst_init(polyptr, "tmpfs", idata); | |
282 | + } | |
283 | ||
284 | /* | |
285 | * Obtain the name of instance pathname based on the | |
286 | @@ -1043,6 +1088,58 @@ static int cwd_in(char *dir, struct inst | |
287 | return retval; | |
288 | } | |
289 | ||
290 | +static int cleanup_tmpdirs(struct instance_data *idata) | |
291 | +{ | |
292 | + struct polydir_s *pptr; | |
293 | + pid_t rc, pid; | |
294 | + sighandler_t osighand = NULL; | |
295 | + int status; | |
296 | + | |
297 | + osighand = signal(SIGCHLD, SIG_DFL); | |
298 | + if (osighand == SIG_ERR) { | |
299 | + pam_syslog(idata->pamh, LOG_ERR, "Cannot set signal value"); | |
300 | + rc = PAM_SESSION_ERR; | |
301 | + goto out; | |
302 | + } | |
303 | + | |
304 | + for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) { | |
305 | + if (pptr->method == TMPDIR && access(pptr->instance_prefix, F_OK) == 0) { | |
306 | + pid = fork(); | |
307 | + if (pid == 0) { | |
308 | +#ifdef WITH_SELINUX | |
309 | + if (idata->flags & PAMNS_SELINUX_ENABLED) { | |
310 | + if (setexeccon(NULL) < 0) | |
311 | + exit(1); | |
312 | + } | |
313 | +#endif | |
314 | + if (execl("/bin/rm", "/bin/rm", "-rf", pptr->instance_prefix, (char *)NULL) < 0) | |
315 | + exit(1); | |
316 | + } else if (pid > 0) { | |
317 | + while (((rc = waitpid(pid, &status, 0)) == (pid_t)-1) && | |
318 | + (errno == EINTR)); | |
319 | + if (rc == (pid_t)-1) { | |
320 | + pam_syslog(idata->pamh, LOG_ERR, "waitpid failed- %m"); | |
321 | + rc = PAM_SESSION_ERR; | |
322 | + goto out; | |
323 | + } | |
324 | + if (!WIFEXITED(status) || WIFSIGNALED(status) > 0) { | |
325 | + pam_syslog(idata->pamh, LOG_ERR, | |
326 | + "Error removing %s", pptr->instance_prefix); | |
327 | + } | |
328 | + } else if (pid < 0) { | |
329 | + pam_syslog(idata->pamh, LOG_ERR, | |
330 | + "Cannot fork to run namespace init script, %m"); | |
331 | + rc = PAM_SESSION_ERR; | |
332 | + goto out; | |
333 | + } | |
334 | + } | |
335 | + } | |
336 | + | |
337 | + rc = PAM_SUCCESS; | |
338 | +out: | |
339 | + signal(SIGCHLD, osighand); | |
340 | + return rc; | |
341 | +} | |
342 | ||
343 | /* | |
344 | * This function checks to see if polyinstantiation is needed for any | |
345 | @@ -1111,13 +1208,22 @@ static int setup_namespace(struct instan | |
346 | * disassociate from the parent namespace. | |
347 | */ | |
348 | if (need_poly) { | |
349 | + if (pam_set_data(idata->pamh, NAMESPACE_POLYDIR_DATA, idata->polydirs_ptr, | |
350 | + cleanup_data) != PAM_SUCCESS) { | |
351 | + pam_syslog(idata->pamh, LOG_ERR, | |
352 | + "Unable to set namespace data"); | |
353 | + return PAM_SYSTEM_ERR; | |
354 | + } | |
355 | if (unshare(CLONE_NEWNS) < 0) { | |
356 | - pam_syslog(idata->pamh, LOG_ERR, | |
357 | + pam_set_data(idata->pamh, NAMESPACE_POLYDIR_DATA, NULL, NULL); | |
358 | + pam_syslog(idata->pamh, LOG_ERR, | |
359 | "Unable to unshare from parent namespace, %m"); | |
360 | return PAM_SESSION_ERR; | |
361 | } | |
362 | - } else | |
363 | + } else { | |
364 | + del_polydir_list(idata->polydirs_ptr); | |
365 | return PAM_SUCCESS; | |
366 | + } | |
367 | ||
368 | /* | |
369 | * Again cycle through all polyinstantiated directories, this time, | |
370 | @@ -1144,7 +1250,8 @@ static int setup_namespace(struct instan | |
371 | * umount | |
372 | */ | |
373 | if ((changing_dir = cwd_in(pptr->dir, idata)) < 0) { | |
374 | - return PAM_SESSION_ERR; | |
375 | + retval = PAM_SESSION_ERR; | |
376 | + goto out; | |
377 | } else if (changing_dir) { | |
378 | if (idata->flags & PAMNS_DEBUG) | |
379 | pam_syslog(idata->pamh, LOG_DEBUG, "changing cwd"); | |
380 | @@ -1172,8 +1279,10 @@ static int setup_namespace(struct instan | |
381 | int saved_errno = errno; | |
382 | pam_syslog(idata->pamh, LOG_ERR, "Unmount of %s failed, %m", | |
383 | pptr->dir); | |
384 | - if (saved_errno != EINVAL) | |
385 | - return PAM_SESSION_ERR; | |
386 | + if (saved_errno != EINVAL) { | |
387 | + retval = PAM_SESSION_ERR; | |
388 | + goto out; | |
389 | + } | |
390 | } else if (idata->flags & PAMNS_DEBUG) | |
391 | pam_syslog(idata->pamh, LOG_DEBUG, "Umount succeeded %s", | |
392 | pptr->dir); | |
393 | @@ -1185,7 +1294,9 @@ static int setup_namespace(struct instan | |
394 | break; | |
395 | } | |
396 | } | |
397 | - | |
398 | +out: | |
399 | + if (retval != PAM_SUCCESS) | |
400 | + cleanup_tmpdirs(idata); | |
401 | return retval; | |
402 | } | |
403 | ||
404 | @@ -1224,8 +1335,10 @@ static int orig_namespace(struct instanc | |
405 | } else if (idata->flags & PAMNS_DEBUG) | |
406 | pam_syslog(idata->pamh, LOG_DEBUG, "Unmount of %s succeeded", | |
407 | pptr->dir); | |
408 | - } | |
409 | + } | |
410 | } | |
411 | + | |
412 | + cleanup_tmpdirs(idata); | |
413 | return 0; | |
414 | } | |
415 | ||
416 | @@ -1350,7 +1463,8 @@ PAM_EXTERN int pam_sm_open_session(pam_h | |
417 | } else if (idata.flags & PAMNS_DEBUG) | |
418 | pam_syslog(idata.pamh, LOG_DEBUG, "Nothing to polyinstantiate"); | |
419 | ||
420 | - del_polydir_list(idata.polydirs_ptr); | |
421 | + if (retval != PAM_SUCCESS) | |
422 | + del_polydir_list(idata.polydirs_ptr); | |
423 | return retval; | |
424 | } | |
425 | ||
426 | @@ -1365,6 +1479,7 @@ PAM_EXTERN int pam_sm_close_session(pam_ | |
427 | struct instance_data idata; | |
428 | char *user_name; | |
429 | struct passwd *pwd; | |
430 | + const void *polyptr; | |
431 | ||
432 | /* init instance data */ | |
433 | idata.flags = 0; | |
434 | @@ -1428,16 +1543,12 @@ PAM_EXTERN int pam_sm_close_session(pam_ | |
435 | strncat(idata.user, user_name, sizeof(idata.user) - 1); | |
436 | idata.uid = pwd->pw_uid; | |
437 | ||
438 | - /* | |
439 | - * Parse namespace configuration file which lists directories that | |
440 | - * are polyinstantiated, directories where instance directories are | |
441 | - * created and the method used for polyinstantiation. | |
442 | - */ | |
443 | - retval = parse_config_file(&idata); | |
444 | - if ((retval != PAM_SUCCESS) || !idata.polydirs_ptr) { | |
445 | - del_polydir_list(idata.polydirs_ptr); | |
446 | - return PAM_SESSION_ERR; | |
447 | - } | |
448 | + retval = pam_get_data(idata.pamh, NAMESPACE_POLYDIR_DATA, &polyptr); | |
449 | + if (retval != PAM_SUCCESS || polyptr == NULL) | |
450 | + /* nothing to reset */ | |
451 | + return PAM_SUCCESS; | |
452 | + | |
453 | + idata.polydirs_ptr = polyptr; | |
454 | ||
455 | if (idata.flags & PAMNS_DEBUG) | |
456 | pam_syslog(idata.pamh, LOG_DEBUG, "Resetting namespace for pid %d", | |
457 | @@ -1452,7 +1563,9 @@ PAM_EXTERN int pam_sm_close_session(pam_ | |
458 | pam_syslog(idata.pamh, LOG_DEBUG, | |
459 | "resetting namespace ok for pid %d", getpid()); | |
460 | } | |
461 | - del_polydir_list(idata.polydirs_ptr); | |
462 | + | |
463 | + pam_set_data(idata.pamh, NAMESPACE_POLYDIR_DATA, NULL, NULL); | |
464 | + | |
465 | return PAM_SUCCESS; | |
466 | } | |
467 |