~ubuntu-branches/ubuntu/trusty/libpam-mount/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/check_authtok_retcode/src/pam_mount.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Kleineidam
  • Date: 2010-05-19 04:05:25 UTC
  • mfrom: (1.4.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20100519040525-yym18fn8k070smfe
Tags: 2.3-1
* New upstream release.
  + mount.crypt passes keyfile info to open LUKS volumes
    (Closes: #528366)
  + umount.crypt works again (Closes: #581713)

Show diffs side-by-side

added added

removed removed

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