1 /*
2 * pam_mount
3 * Copyright (C) Elvis Pfützenreuter <epx@conectiva.com>, 2000
4 * Copyright © Jan Engelhardt, 2005 - 2010
5 * Copyright © Bastian Kleineidam, 2005
6 *
7 * This file is part of pam_mount; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 2.1
10 * of the License, or (at your option) any later version.
11 */
12 #define PAM_SM_ACCOUNT 1
13 #define PAM_SM_AUTH 1
14 #define PAM_SM_SESSION 1
15 #define PAM_SM_PASSWORD 1
16
17 #include <security/pam_appl.h>
18 #include <security/pam_modules.h>
19 #include <sys/mman.h>
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <pthread.h>
25 #include <signal.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <libHX/defs.h>
32 #include <libHX/proc.h>
33 #include <libHX.h>
34 #include "pam_mount.h"
35
36 #ifndef PAM_EXTERN
37 # define PAM_EXTERN
38 #endif
39
40 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
41 # define CONFIGFILE "/etc/pam_mount.conf.xml"
42 #elif defined(__FreeBSD__) || defined(__DragonFly__)
43 # define CONFIGFILE "/usr/local/etc/security/pam_mount.conf.xml"
44 #else
45 # define CONFIGFILE "/etc/security/pam_mount.conf.xml"
46 #endif
47
48 struct pam_args {
49 bool get_pw_from_pam, get_pw_interactive, propagate_pw;
50 };
51
52 /* Functions */
53 static void clean_config(pam_handle_t *, void *, int);
54 static int converse(pam_handle_t *, int, const struct pam_message **,
55 struct pam_response **);
56 static int modify_pm_count(struct config *, char *, char *);
57 static void parse_pam_args(int, const char **);
58 static int read_password(pam_handle_t *, const char *, char **);
59
60 /* Variables */
61 static const char *envpath_saved;
62 struct config Config;
63 struct pam_args Args;
64
65 //-----------------------------------------------------------------------------
66 /**
67 * parse_pam_args -
68 * @argv: NULL-terminated argument vector
69 * @argc: number of elements in @argc
70 *
71 * Global @Args is initialized, based on @argv.
72 */
parse_pam_args(int argc,const char ** argv)73 static void parse_pam_args(int argc, const char **argv)
74 {
75 int i;
76
77 assert(argc >= 0);
78 for (i = 0; i < argc; i++)
79 assert(argv[i] != NULL);
80
81 /* first, set default values */
82 Args.get_pw_from_pam = true;
83 Args.get_pw_interactive = true;
84 Args.propagate_pw = true;
85
86 for (i = 0; i < argc; ++i) {
87 if (strcasecmp("enable_pam_password", argv[i]) == 0)
88 Args.get_pw_from_pam = true;
89 else if (strcasecmp("disable_pam_password", argv[i]) == 0)
90 Args.get_pw_from_pam = false;
91 else if (strcasecmp("enable_interactive", argv[i]) == 0)
92 Args.get_pw_interactive = true;
93 else if (strcasecmp("disable_interactive", argv[i]) == 0)
94 Args.get_pw_interactive = false;
95 else if (strcasecmp("enable_propagate_password", argv[i]) == 0)
96 Args.propagate_pw = true;
97 else if (strcasecmp("disable_propagate_password", argv[i]) == 0)
98 Args.propagate_pw = false;
99 else if (strcasecmp("debug", argv[i]) == 0)
100 Debug = true;
101 else
102 w4rn("unknown pam_mount option \"%s\"\n", argv[i]);
103 }
104 }
105
106 /**
107 * clean_config -
108 * @pamh: PAM handle
109 * @data: custom data pointer
110 * @err:
111 *
112 * Free data from a struct config variable.
113 * Note: This is registered as a PAM callback function and is called directly.
114 */
clean_config(pam_handle_t * pamh,void * data,int err)115 static void clean_config(pam_handle_t *pamh, void *data, int err)
116 {
117 w4rn("Clean global config (%d)\n", err);
118 freeconfig(data);
119 }
120
121 /**
122 * clean_system_authtok -
123 * @pamh: PAM handle
124 * @data: custom data pointer
125 * @err:
126 *
127 * Zero and free @data if it is not %NULL.
128 * Note: This is registered as a PAM callback function and is called directly.
129 *
130 * FIXME: Not binary-password safe.
131 */
clean_system_authtok(pam_handle_t * pamh,void * data,int errcode)132 static void clean_system_authtok(pam_handle_t *pamh, void *data, int errcode)
133 {
134 w4rn("clean system authtok=%p (%d)\n", data, errcode);
135
136 if (data != NULL) {
137 unsigned int len = strlen(data) + 1;
138 memset(data, 0, len);
139 munlock(data, len);
140 free(data);
141 }
142 }
143
144 /**
145 * converse -
146 * @pamh: PAM handle
147 * @nargs: number of messages
148 * @message: PAM message array
149 * @resp: user response array
150 *
151 * Note: Adapted from pam_unix/support.c.
152 */
converse(pam_handle_t * pamh,int nargs,const struct pam_message ** message,struct pam_response ** resp)153 static int converse(pam_handle_t *pamh, int nargs,
154 const struct pam_message **message, struct pam_response **resp)
155 {
156 int retval;
157 struct pam_conv *conv;
158
159 assert(pamh != NULL);
160 assert(nargs >= 0);
161 assert(resp != NULL);
162
163 *resp = NULL;
164 retval = pam_get_item(pamh, PAM_CONV, static_cast(const void **,
165 static_cast(void *, &conv)));
166
167 if (retval != PAM_SUCCESS) {
168 l0g("pam_get_item: %s\n", pam_strerror(pamh, retval));
169 } else if (conv == NULL || conv->conv == NULL) {
170 w4rn("No converse function available\n");
171 } else {
172 retval = conv->conv(nargs, message, resp, conv->appdata_ptr);
173 if (retval != PAM_SUCCESS)
174 l0g("conv->conv(...): %s\n", pam_strerror(pamh, retval));
175 }
176
177 if (resp == NULL || *resp == NULL || (*resp)->resp == NULL)
178 retval = PAM_AUTH_ERR;
179
180 assert(retval != PAM_SUCCESS || (resp != NULL && *resp != NULL &&
181 (*resp)->resp != NULL));
182 return retval; /* propagate error status */
183 }
184
185 /**
186 * read_password -
187 * @pamh: PAM handle
188 * @prompt: a prompt message
189 * @pass: space for entered password
190 *
191 * Returns PAM error code or %PAM_SUCCESS.
192 * Note: Adapted from pam_unix/support.c:_unix_read_password().
193 */
read_password(pam_handle_t * pamh,const char * prompt,char ** pass)194 static int read_password(pam_handle_t *pamh, const char *prompt, char **pass)
195 {
196 int retval;
197 struct pam_message msg;
198 const struct pam_message *pmsg = &msg;
199 struct pam_response *resp = NULL;
200
201 assert(pamh != NULL);
202 assert(pass != NULL);
203
204 *pass = NULL;
205 msg.msg_style = PAM_PROMPT_ECHO_OFF;
206 msg.msg = (prompt == NULL) ? "Password: " : prompt;
207 retval = converse(pamh, 1, &pmsg, &resp);
208 if (retval == PAM_SUCCESS)
209 *pass = xstrdup(resp->resp);
210
211 assert(retval != PAM_SUCCESS || (pass != NULL && *pass != NULL));
212 return retval;
213 }
214
pmt_sigpipe_setup(bool block_it)215 static void pmt_sigpipe_setup(bool block_it)
216 {
217 static pthread_mutex_t sp_lock = PTHREAD_MUTEX_INITIALIZER;
218 static int sp_blocked = 0;
219 static bool sp_previous;
220 sigset_t set, oldset;
221
222 pthread_mutex_lock(&sp_lock);
223 if (block_it) {
224 if (++sp_blocked == 1) {
225 sigemptyset(&set);
226 sigaddset(&set, SIGPIPE);
227 sigprocmask(SIG_BLOCK, &set, &oldset);
228 sp_previous = sigismember(&oldset, SIGPIPE);
229 }
230 } else {
231 if (--sp_blocked == 0 && sp_previous) {
232 sigemptyset(&set);
233 sigaddset(&set, SIGPIPE);
234 sigtimedwait(&set, NULL, &(struct timespec){0, 0});
235 sigprocmask(SIG_UNBLOCK, &set, NULL);
236 }
237 }
238
239 pthread_mutex_unlock(&sp_lock);
240 }
241
common_init(pam_handle_t * pamh,int argc,const char ** argv)242 static int common_init(pam_handle_t *pamh, int argc, const char **argv)
243 {
244 const char *pam_user;
245 char buf[8];
246 int ret;
247
248 pmtlog_prefix = "pam_mount";
249 pmtlog_path[PMTLOG_ERR][PMTLOG_SYSLOG] = true;
250 pmtlog_path[PMTLOG_ERR][PMTLOG_STDERR] = true;
251 pmtlog_path[PMTLOG_DBG][PMTLOG_SYSLOG] = Debug;
252 pmtlog_path[PMTLOG_DBG][PMTLOG_STDERR] = Debug;
253
254 ret = HX_init();
255 if (ret <= 0)
256 l0g("libHX init failed: %s\n", strerror(errno));
257
258 initconfig(&Config);
259 parse_pam_args(argc, argv);
260 /*
261 * call pam_get_user again because ssh calls PAM fns from seperate
262 * processes.
263 */
264 ret = pam_get_user(pamh, &pam_user, NULL);
265 if (ret != PAM_SUCCESS) {
266 l0g("could not get user");
267 /*
268 * do NOT return %PAM_SERVICE_ERR or root will not be able to
269 * su to other users.
270 * Also, if we could not get the user's info, an earlier auth
271 * module (like pam_unix2) likely blocked login already.
272 */
273 return PAM_SUCCESS;
274 }
275 /*
276 * FIXME: free me! the dup is requried because result of pam_get_user()
277 * disappears (valgrind)
278 */
279 Config.user = relookup_user(pam_user);
280 if (!readconfig(CONFIGFILE, true, &Config))
281 return PAM_SERVICE_ERR;
282
283 /* reinitialize after @Debug may have changed */
284 pmtlog_path[PMTLOG_DBG][PMTLOG_STDERR] = Debug;
285 pmtlog_path[PMTLOG_DBG][PMTLOG_SYSLOG] = Debug;
286
287 snprintf(buf, sizeof(buf), "%u", Debug);
288 setenv("_PMT_DEBUG_LEVEL", buf, true);
289
290 pmt_sigpipe_setup(true);
291 return -1;
292 }
293
common_exit(void)294 static void common_exit(void)
295 {
296 pmt_sigpipe_setup(false);
297 HX_exit();
298 }
299
auth_grab_authtok(pam_handle_t * pamh,struct config * config)300 static void auth_grab_authtok(pam_handle_t *pamh, struct config *config)
301 {
302 char *authtok = NULL;
303 int ret;
304
305 if (Args.get_pw_from_pam) {
306 char *ptr = NULL;
307
308 ret = pam_get_item(pamh, PAM_AUTHTOK, static_cast(const void **,
309 static_cast(void *, &ptr)));
310 if (ret == PAM_SUCCESS && ptr != NULL)
311 authtok = xstrdup(ptr);
312 }
313 if (authtok == NULL && Args.get_pw_interactive) {
314 ret = read_password(pamh, config->msg_authpw, &authtok);
315 if (ret == PAM_SUCCESS && Args.propagate_pw) {
316 /*
317 * pam_set_item() copies to PAM-internal memory.
318 *
319 * Using pam_set_item(PAM_AUTHTOK) here to make the
320 * password that was just entered available to further
321 * PAM modules.
322 */
323 ret = pam_set_item(pamh, PAM_AUTHTOK, authtok);
324 if (ret != PAM_SUCCESS)
325 l0g("warning: failure to export password (%s)\n",
326 pam_strerror(pamh, ret));
327 }
328 }
329
330 /*
331 * Save auth token for pam_mount itself, since PAM_AUTHTOK
332 * will be gone when the auth stage exits.
333 */
334 if (authtok != NULL) {
335 ret = pam_set_data(pamh, "pam_mount_system_authtok", authtok,
336 clean_system_authtok);
337 if (ret == PAM_SUCCESS) {
338 if (mlock(authtok, strlen(authtok) + 1) < 0)
339 w4rn("mlock authtok: %s\n", strerror(errno));
340 } else {
341 l0g("error trying to save authtok for session code\n");
342 }
343 }
344 }
345
346 /**
347 * pam_sm_authenticate -
348 * @pamh: PAM handle
349 * @flags: PAM flags
350 * @argc: number of elements in @argv
351 * @argv: NULL-terminated argument vector
352 *
353 * Called by the PAM layer. The user's system password is added to PAM's
354 * global module data. This is because pam_sm_open_session() does not allow
355 * access to the user's password. Returns the PAM error code or %PAM_SUCCESS.
356 */
pam_sm_authenticate(pam_handle_t * pamh,int flags,int argc,const char ** argv)357 PAM_EXTERN EXPORT_SYMBOL int pam_sm_authenticate(pam_handle_t *pamh, int flags,
358 int argc, const char **argv)
359 {
360 int ret = PAM_SUCCESS;
361
362 assert(pamh != NULL);
363
364 if ((ret = common_init(pamh, argc, argv)) != -1)
365 return ret;
366 w4rn(PACKAGE_STRING ": entering auth stage\n");
367 auth_grab_authtok(pamh, &Config);
368 common_exit();
369 /*
370 * pam_mount is not really meant to be an auth module. So we should not
371 * hinder the login process.
372 */
373 return PAM_SUCCESS;
374 }
375
376 /**
377 * On login, $PATH is correctly set to ENV_ROOTPATH (from /etc/login.defs),
378 * while on logout, it happens to be ENV_PATH only. This is problematic,
379 * since some programs are in /sbin and /usr/sbin which is
380 * often not contained in ENV_PATH.
381 *
382 * In short: Another workaround for coreutils.
383 */
envpath_init(const char * new_path)384 static void envpath_init(const char *new_path)
385 {
386 envpath_saved = getenv("PATH");
387 setenv("PATH", new_path, true);
388 }
389
envpath_restore(void)390 static void envpath_restore(void)
391 {
392 if (envpath_saved == NULL)
393 unsetenv("PATH");
394 else
395 setenv("PATH", envpath_saved, true);
396 }
397
398 /**
399 * modify_pm_count -
400 * @config:
401 * @user:
402 * @operation: string specifying numerical increment
403 *
404 * Calls out to the `pmvarrun` helper utility to adjust the mount reference
405 * count in /var/run/pam_mount/@user for the specified user.
406 * Returns the new reference count value on success, or -1 on error.
407 *
408 * Note: Modified version of pam_console.c:use_count()
409 */
modify_pm_count(struct config * config,char * user,char * operation)410 static int modify_pm_count(struct config *config, char *user,
411 char *operation)
412 {
413 FILE *fp = NULL;
414 struct HXformat_map *vinfo;
415 struct HXdeque *argv;
416 struct HXproc proc;
417 int ret = -1, use_count;
418
419 assert(user != NULL);
420 assert(operation != NULL);
421
422 if ((vinfo = HXformat_init()) == NULL)
423 goto out;
424 format_add(vinfo, "USER", user);
425 format_add(vinfo, "OPERATION", operation);
426 misc_add_ntdom(vinfo, user);
427
428 argv = arglist_build(config->command[CMD_PMVARRUN], vinfo);
429 memset(&proc, 0, sizeof(proc));
430 proc.p_flags = HXPROC_VERBOSE | HXPROC_STDOUT;
431 proc.p_ops = &pmt_dropprivs_ops;
432 if ((ret = pmt_spawn_dq(argv, &proc)) <= 0) {
433 l0g("error executing pmvarrun: %s\n", strerror(-ret));
434 goto out;
435 }
436 ret = -1;
437 if ((fp = fdopen(proc.p_stdout, "r")) == NULL)
438 goto out2;
439 if (fscanf(fp, "%d", &use_count) != 1)
440 w4rn("error reading login count from pmvarrun\n");
441 else
442 w4rn("pmvarrun says login count is %d\n", use_count);
443 out2:
444 if (fp != NULL)
445 fclose(fp);
446 else
447 close(proc.p_stdout);
448 if (HXproc_wait(&proc) >= 0 && proc.p_exited && proc.p_status == 0)
449 ret = use_count;
450 out:
451 if (vinfo != NULL)
452 HXformat_free(vinfo);
453 return ret;
454 }
455
456 /**
457 * ses_grab_authtok - get the password from PAM
458 *
459 * Session stage: reretrieve password that the auth stage stored.
460 * If that does not work, use interactive prompting if enabled.
461 */
ses_grab_authtok(pam_handle_t * pamh)462 static char *ses_grab_authtok(pam_handle_t *pamh)
463 {
464 char *authtok = NULL;
465 int ret;
466
467 ret = pam_get_data(pamh, "pam_mount_system_authtok",
468 static_cast(const void **, static_cast(void *, &authtok)));
469 if (ret == PAM_SUCCESS)
470 return authtok;
471
472 /* No stored password, get one, if allowed to. */
473 if (Args.get_pw_interactive) {
474 ret = read_password(pamh, Config.msg_sessionpw, &authtok);
475 if (ret != PAM_SUCCESS)
476 /* authtok is %NULL now */
477 l0g("warning: could not obtain password "
478 "interactively either\n");
479 }
480 if (authtok != NULL) {
481 ret = pam_set_data(pamh, "pam_mount_system_authtok",
482 authtok, clean_system_authtok);
483 if (ret == PAM_SUCCESS) {
484 if (mlock(authtok, strlen(authtok) + 1) < 0)
485 w4rn("mlock authtok: %s\n", strerror(errno));
486 } else {
487 l0g("error trying to save authtok for session code\n");
488 }
489 }
490 /*
491 * Always proceed, even if there is no password. Some volumes may not
492 * need one, e.g. bind mounts and networked/unencrypted volumes.
493 */
494 return authtok;
495 }
496
process_volumes(struct config * config,const char * authtok)497 static int process_volumes(struct config *config, const char *authtok)
498 {
499 int ret = PAM_SUCCESS;
500 struct vol *vol;
501
502 HXlist_for_each_entry(vol, &config->volume_list, list) {
503 /*
504 * Remember what we processed already - the function can
505 * be called multiple times.
506 */
507 if (vol->mnt_processed)
508 continue;
509 vol->mnt_processed = true;
510 /*
511 * luserconf_volume_record_sane() is called here so that a user
512 * can nest loopback images. otherwise ownership tests will
513 * fail if parent loopback image not yet mounted.
514 * volume_record_sane() is here to be consistent.
515 */
516 if (!volume_record_sane(config, vol))
517 continue;
518 if (!vol->globalconf &&
519 !luserconf_volume_record_sane(config, vol))
520 continue;
521
522 if (!mount_op(do_mount, config, vol, authtok)) {
523 l0g("mount of %s failed\n", znul(vol->volume));
524 ret = PAM_SERVICE_ERR;
525 }
526 }
527 return ret;
528 }
529
530 /**
531 * pam_sm_open_session -
532 * @pamh: PAM handle
533 * @flags: PAM flags
534 * @argc: number of elements in @argv
535 * @argv: NULL-terminated argument vector
536 *
537 * Entrypoint from the PAM layer. Starts the wheels and eventually mounts the
538 * user's directories according to pam_mount.conf.xml. Returns the PAM error
539 * code or %PAM_SUCCESS.
540 */
pam_sm_open_session(pam_handle_t * pamh,int flags,int argc,const char ** argv)541 PAM_EXTERN EXPORT_SYMBOL int pam_sm_open_session(pam_handle_t *pamh, int flags,
542 int argc, const char **argv)
543 {
544 int ret;
545 const char *krb5;
546 char *system_authtok = NULL;
547 const void *tmp;
548 int getval;
549
550 assert(pamh != NULL);
551
552 if ((ret = common_init(pamh, argc, argv)) != -1)
553 return ret;
554
555 w4rn(PACKAGE_STRING ": entering session stage\n");
556
557 /*
558 * Environment variables set with setenv() only last while PAM is
559 * active, i.e. disappear when the shell is started. On the other hand,
560 * variabled fed to pam_putenv() are only visible once the shell
561 * started.
562 */
563 /*
564 * Get the Kerberos CCNAME so we can make it available to the
565 * mount command later on.
566 */
567 krb5 = pam_getenv(pamh, "KRB5CCNAME");
568 if (krb5 != NULL && setenv("KRB5CCNAME", krb5, true) < 0)
569 l0g("KRB5CCNAME setenv failed\n");
570
571 /* Store initialized config as PAM data */
572 getval = pam_get_data(pamh, "pam_mount_config", &tmp);
573 if (getval == PAM_NO_MODULE_DATA) {
574 ret = pam_set_data(pamh, "pam_mount_config",
575 &Config, clean_config);
576 if (ret != PAM_SUCCESS) {
577 l0g("error trying to save config structure\n");
578 goto out;
579 }
580 /* Up the reference count by one, for freeconfig */
581 HX_init();
582 }
583
584 if (!expandconfig(&Config)) {
585 l0g("error expanding configuration\n");
586 ret = PAM_SERVICE_ERR;
587 goto out;
588 }
589 if (Config.volume_list.items > 0)
590 /* There are some volumes, so grab a password. */
591 system_authtok = ses_grab_authtok(pamh);
592
593 misc_dump_id("Session open");
594 envpath_init(Config.path);
595 ret = process_volumes(&Config, system_authtok);
596
597 /*
598 * Read luserconf after mounting of initial volumes. This makes it
599 * possible to store luserconfs on net volumes themselves.
600 */
601 if (Config.luserconf != NULL && *Config.luserconf != '\0' &&
602 pmt_fileop_exists(Config.luserconf)) {
603 w4rn("going to readconfig %s\n", Config.luserconf);
604 if (!pmt_fileop_owns(Config.user, Config.luserconf)) {
605 w4rn("%s does not exist or is not owned by user\n",
606 Config.luserconf);
607 } else if (!readconfig(Config.luserconf, false, &Config)) {
608 ret = PAM_SERVICE_ERR;
609 } else if (!expandconfig(&Config)) {
610 ret = PAM_SERVICE_ERR;
611 l0g("error expanding configuration\n");
612 }
613 }
614
615 if (Config.volume_list.items == 0) {
616 w4rn("no volumes to mount\n");
617 ret = PAM_SUCCESS;
618 } else {
619 /*
620 * If there are no global volumes, but luserconf volumes,
621 * and we still have no password, ask for one now.
622 */
623 if (system_authtok == NULL)
624 system_authtok = ses_grab_authtok(pamh);
625 ret = process_volumes(&Config, system_authtok);
626 }
627
628 modify_pm_count(&Config, Config.user, "1");
629 envpath_restore();
630 if (getuid() == 0)
631 /* Make sure root can always log in. */
632 /* NB: I don't even wanna think of SELINUX's ambiguous UIDs... */
633 ret = PAM_SUCCESS;
634
635 /*
636 * If mounting something failed, e.g. ret = %PAM_SERVICE_ERR, we have
637 * to unravel everything and umount all volumes. But *only* if
638 * pam_mount was configured as a "required" module. How can this info
639 * be obtained?
640 * For now, always assume "optional", so that the volumes are
641 * definitely unmounted when the user logs out again.
642 */
643 ret = PAM_SUCCESS;
644 out:
645 if (krb5 != NULL)
646 unsetenv("KRB5CCNAME");
647 w4rn("done opening session (ret=%d)\n", ret);
648 common_exit();
649 return ret;
650 }
651
652 /**
653 * pam_sm_chauthtok -
654 * @pamh: PAM handle
655 * @flags: PAM flags
656 * @argc: number of elements in @argv
657 * @argv: NULL-terminated argument vector
658 *
659 * This is a placeholder function so PAM does not get mad.
660 */
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char ** argv)661 PAM_EXTERN EXPORT_SYMBOL int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
662 int argc, const char **argv)
663 {
664 return pam_sm_authenticate(pamh, flags, argc, argv);
665 }
666
667 /**
668 * pam_sm_close_session -
669 * @pamh: PAM handle
670 * @flags: PAM flags
671 * @argc: number of elements in @argv
672 * @argv: NULL-terminated argument vector
673 *
674 * Entrypoint from the PAM layer. Stops all wheels and eventually unmounts the
675 * user's directories. Returns the PAM error code or %PAM_SUCCESS.
676 *
677 * FIXME: This function currently always returns %PAM_SUCCESS. Should it
678 * return soemthing else when errors occur and all unmounts have been
679 * attempted?
680 */
pam_sm_close_session(pam_handle_t * pamh,int flags,int argc,const char ** argv)681 PAM_EXTERN EXPORT_SYMBOL int pam_sm_close_session(pam_handle_t *pamh,
682 int flags, int argc, const char **argv)
683 {
684 const char *pam_user = NULL;
685 int ret;
686
687 assert(pamh != NULL);
688
689 ret = HX_init();
690 if (ret <= 0)
691 l0g("libHX init failed: %s\n", strerror(errno));
692 ret = PAM_SUCCESS;
693 w4rn("received order to close things\n");
694 if (Config.volume_list.items == 0) {
695 w4rn("No volumes to umount\n");
696 goto out;
697 }
698
699 misc_dump_id("Session close");
700 /*
701 * call pam_get_user() again because ssh calls PAM fns from seperate
702 * processes.
703 */
704 ret = pam_get_user(pamh, &pam_user, NULL);
705 if (ret != PAM_SUCCESS) {
706 l0g("could not get user\n");
707 goto out;
708 }
709 /*
710 * FIXME: free me! the dup is requried because result of pam_get_user
711 * disappears (valgrind)
712 */
713 Config.user = relookup_user(pam_user);
714 /* if our CWD is in the home directory, it might not get umounted */
715 if (chdir("/") != 0)
716 l0g("could not chdir\n");
717
718 out:
719 envpath_init(Config.path);
720 if (modify_pm_count(&Config, Config.user, "-1") > 0)
721 w4rn("%s seems to have other remaining open sessions\n",
722 Config.user);
723 else
724 umount_final(&Config);
725
726 envpath_restore();
727 /*
728 * Note that PMConfig is automatically freed later in clean_config()
729 */
730 w4rn("pam_mount execution complete\n");
731 HX_exit();
732 return ret;
733 }
734
735 /**
736 * pam_sm_setcred -
737 * @pamh: PAM handle
738 * @flags: PAM flags
739 * @argc: number of elements in @argv
740 * @argv: NULL-terminated argument vector
741 *
742 * This is a placeholder function so PAM does not get mad.
743 */
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char ** argv)744 PAM_EXTERN EXPORT_SYMBOL int pam_sm_setcred(pam_handle_t *pamh, int flags,
745 int argc, const char **argv)
746 {
747 return PAM_SUCCESS;
748 }
749
750 /**
751 * pam_sm_acct_mgmt -
752 * @pamh: PAM handle
753 * @flags: PAM flags
754 * @argc: number of elements in @argv
755 * @argv: NULL-terminated argument vector
756 *
757 * This is a placeholder function so PAM does not get mad.
758 */
pam_sm_acct_mgmt(pam_handle_t * pamh,int flags,int argc,const char ** argv)759 PAM_EXTERN EXPORT_SYMBOL int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
760 int argc, const char **argv)
761 {
762 return PAM_IGNORE;
763 }
764
765 #ifdef PAM_STATIC
766 /* static module data */
767
768 EXPORT_SYMBOL struct pam_module _pam_mount_modstruct = {
769 .name = "pam_mount",
770 .pam_sm_authenticate = pam_sm_authenticate,
771 .pam_sm_setcred = pam_sm_setcred,
772 .pam_sm_acct_mgmt = pam_sm_acct_mgmt,
773 .pam_sm_open_sesion = pam_sm_open_session,
774 .pam_sm_close_session = pam_sm_close_session,
775 .pam_sm_chauthtok = pam_sm_chauthtok,
776 };
777
778 #endif
779