~mrooney/ecryptfs/nautilus-integration

« back to all changes in this revision

Viewing changes to src/pam_ecryptfs/pam_ecryptfs.c

  • Committer: mhalcrow@us.ibm.com
  • Date: 2007-11-06 22:56:01 UTC
  • Revision ID: git-v1:f8357de9d554b274497b5cce9db4347254b7e7eb
Initial import of eCryptfs filesystem userspace utilities (mount helper, daemon component,
etc.)

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
 *
5
5
 * Copyright (C) 2007 International Business Machines
6
6
 * Author(s): Michael Halcrow <mhalcrow@us.ibm.com>
7
 
 *            Dustin Kirkland <kirkland@canonical.com>
8
7
 *
9
8
 * This program is free software; you can redistribute it and/or
10
9
 * modify it under the terms of the GNU General Public License as
22
21
 * 02111-1307, USA.
23
22
 */
24
23
 
25
 
#include "config.h"
26
24
#include <stdio.h>
27
25
#include <stdlib.h>
28
26
#include <stdint.h>
38
36
#include <sys/stat.h>
39
37
#include <fcntl.h>
40
38
#include <security/pam_modules.h>
 
39
#include "config.h"
41
40
#include "../include/ecryptfs.h"
42
41
 
43
 
#define PRIVATE_DIR "Private"
44
 
 
45
42
static void error(const char *msg)
46
43
{
47
 
        syslog(LOG_ERR, "errno = [%i]; strerror = [%m]\n", errno);
 
44
        syslog(LOG_ERR, "errno = [%i]; strerror = [%s]\n", errno,
 
45
               strerror(errno));
48
46
        switch (errno) {
49
47
        case ENOKEY:
50
48
                syslog(LOG_ERR, "%s: Requested key not available\n", msg);
67
65
        }
68
66
}
69
67
 
70
 
/* returns: 0 for pam automounting not set, 1 for set, <0 for error */
71
 
static int ecryptfs_pam_automount_set(const char *homedir)
72
 
{
73
 
        char *file_path;
74
 
        int rc = 0;
75
 
        struct stat s;
76
 
        if (asprintf(
77
 
                &file_path, "%s/.ecryptfs/%s",
78
 
                homedir,
79
 
                ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME) == -1)
80
 
                return -ENOMEM;
81
 
        if (stat(file_path, &s) != 0) {
82
 
                if (errno != ENOENT)
83
 
                        rc = -errno;
84
 
                goto out;
85
 
        } 
86
 
        free(file_path);
87
 
        if (asprintf(&file_path, "%s/.ecryptfs/auto-mount", homedir) == -1)
88
 
                return -ENOMEM;
89
 
        if (stat(file_path, &s) != 0) {
90
 
                if (errno != ENOENT)
91
 
                        rc = -errno;
92
 
                goto out;
93
 
        } 
94
 
        rc = 1;
95
 
out:
96
 
        free(file_path);
97
 
        return rc;
98
 
}
99
 
 
100
68
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
101
69
                                   const char **argv)
102
70
{
128
96
                       "rc = [%ld]\n", username, rc);
129
97
                goto out;
130
98
        }
131
 
        if (!ecryptfs_pam_automount_set(homedir))
132
 
                goto out;
133
99
        saved_uid = geteuid();
134
100
        seteuid(uid);
135
101
        rc = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&passphrase);
136
102
        seteuid(saved_uid);
137
103
        if (rc != PAM_SUCCESS) {
138
 
                syslog(LOG_ERR, "Error retrieving passphrase; rc = [%ld]\n",
 
104
                syslog(LOG_ERR, "Error retrieving passphrase; rc = [%d]\n",
139
105
                       rc);
140
106
                goto out;
141
107
        }
147
113
        }
148
114
        rc = ecryptfs_read_salt_hex_from_rc(salt_hex);
149
115
        if (rc) {
 
116
                syslog(LOG_WARNING, "Unable to read salt value from user's "
 
117
                       ".ecryptfsrc file; using default\n");
150
118
                from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
151
119
        } else
152
120
                from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE);
184
152
                                auth_tok_sig, passphrase, salt);
185
153
                }
186
154
                if (rc == 1) {
187
 
                        goto out_child;
 
155
                        syslog(LOG_WARNING, "There is already a key in the "
 
156
                               "user session keyring for the given "
 
157
                               "passphrase.\n");
 
158
                        rc = 0;
188
159
                }
189
160
                if (rc) {
190
161
                        syslog(LOG_ERR, "Error adding passphrase key token to "
191
 
                               "user session keyring; rc = [%ld]\n", rc);
 
162
                               "user session keyring; rc = [%d]\n", rc);
192
163
                        goto out_child;
193
164
                }
194
165
                if (fork() == 0) {
195
166
                        if ((rc = ecryptfs_set_zombie_session_placeholder())) {
196
167
                                syslog(LOG_ERR, "Error attempting to create "
197
168
                                       "and register zombie process; "
198
 
                                       "rc = [%ld]\n", rc);
 
169
                                       "rc = [%d]\n", rc);
199
170
                        }
200
171
                }
201
172
out_child:
216
187
        return PAM_SUCCESS;
217
188
}
218
189
 
219
 
static struct passwd *fetch_pwd(pam_handle_t *pamh)
220
 
{
221
 
        long rc;
222
 
        const char *username = NULL;
223
 
        struct passwd *pwd = NULL;
224
 
 
225
 
        rc = pam_get_user(pamh, &username, NULL);
226
 
        if (rc != PAM_SUCCESS || username == NULL) {
227
 
                syslog(LOG_ERR, "Error getting passwd info for user [%s]; "
228
 
                                "rc = [%ld]\n", username, rc);
229
 
                return NULL;
230
 
        }
231
 
        pwd = getpwnam(username);
232
 
        if (pwd == NULL) {
233
 
                syslog(LOG_ERR, "Error getting passwd info for user [%s]; "
234
 
                                "rc = [%ld]\n", username, rc);
235
 
                return NULL;
236
 
        }
237
 
        return pwd;
238
 
}
239
 
 
240
 
static int private_dir(pam_handle_t *pamh, int mount)
241
 
{
242
 
        int rc, fd;
243
 
        struct passwd *pwd = NULL;
244
 
        char *sigfile = NULL;
245
 
        char *autofile = NULL;
246
 
        char *recorded = NULL;
247
 
        char *a;
248
 
        char *automount = "auto-mount";
249
 
        char *autoumount = "auto-umount";
250
 
        struct stat s;
251
 
        pid_t pid;
252
 
        struct utmp *u;
253
 
        int count = 0;
254
 
 
255
 
        if ((pwd = fetch_pwd(pamh)) == NULL) {
256
 
                /* fetch_pwd() logged a message */
257
 
                return 1;
258
 
        }
259
 
        if (mount == 1) {
260
 
                a = automount;
261
 
        } else {
262
 
                a = autoumount;
263
 
        }
264
 
        if (
265
 
            (asprintf(&autofile, "%s/.ecryptfs/%s", pwd->pw_dir, a) < 0)
266
 
             || autofile == NULL) {
267
 
                syslog(LOG_ERR, "Error allocating memory for autofile name");
268
 
                return 1;
269
 
        }
270
 
        if (
271
 
            (asprintf(&sigfile, "%s/.ecryptfs/%s.sig", pwd->pw_dir, 
272
 
             PRIVATE_DIR) < 0) || sigfile == NULL) {
273
 
                syslog(LOG_ERR, "Error allocating memory for sigfile name");
274
 
                return 1;
275
 
        }
276
 
        if (stat(sigfile, &s) != 0) {
277
 
                /* No sigfile, no need to mount private dir */
278
 
                goto out;
279
 
        }
280
 
        if (!S_ISREG(s.st_mode)) {
281
 
                /* No sigfile, no need to mount private dir */
282
 
                goto out;
283
 
        }
284
 
        if ((pid = fork()) < 0) {
285
 
                syslog(LOG_ERR, "Error setting up private mount");
286
 
                return 1;
287
 
        } 
288
 
        if (pid == 0) {
289
 
                if (mount == 1) {
290
 
                        if ((asprintf(&recorded,
291
 
                            "%s/.ecryptfs/.wrapped-passphrase.recorded",
292
 
                            pwd->pw_dir) < 0) || recorded == NULL) {
293
 
                                syslog(LOG_ERR,
294
 
                                   "Error allocating memory for recorded name");
295
 
                                return 1;
296
 
                        }
297
 
                        if (stat(recorded, &s) != 0 && stat("/usr/share/ecryptfs-utils/ecryptfs-record-passphrase", &s) == 0) {
298
 
                                /* User has not recorded their passphrase */
299
 
                                unlink("/var/lib/update-notifier/user.d/ecryptfs-record-passphrase");
300
 
                                symlink("/usr/share/ecryptfs-utils/ecryptfs-record-passphrase", "/var/lib/update-notifier/user.d/ecryptfs-record-passphrase");
301
 
                                fd = open("/var/lib/update-notifier/dpkg-run-stamp", O_WRONLY|O_CREAT|O_NONBLOCK, 0666);
302
 
                                close(fd);
303
 
                        }
304
 
                        if (stat(autofile, &s) != 0) {
305
 
                                /* User does not want to auto-mount */
306
 
                                syslog(LOG_INFO,
307
 
                                        "Skipping automatic eCryptfs mount");
308
 
                                return 0;
309
 
                        }
310
 
                        /* run mount.ecryptfs_private as the user */
311
 
                        setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid);
312
 
                        execl("/sbin/mount.ecryptfs_private", 
313
 
                              "mount.ecryptfs_private", NULL);
314
 
                } else {
315
 
                        if (stat(autofile, &s) != 0) {
316
 
                                /* User does not want to auto-unmount */
317
 
                                syslog(LOG_INFO,
318
 
                                        "Skipping automatic eCryptfs unmount");
319
 
                                return 0;
320
 
                        }
321
 
                        /* run umount.ecryptfs_private as the user */
322
 
                        setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid);
323
 
                        execl("/sbin/umount.ecryptfs_private", 
324
 
                              "umount.ecryptfs_private", NULL);
325
 
                }
326
 
                return 1;
327
 
        } else {
328
 
                waitpid(pid, &rc, 0);
329
 
                syslog(LOG_INFO, 
330
 
                       "Mount of private directory return code [%d]", rc);
331
 
                goto out;
332
 
        }
333
 
out:
334
 
        return 0;
335
 
}
336
 
 
337
 
static int mount_private_dir(pam_handle_t *pamh)
338
 
{
339
 
        return private_dir(pamh, 1);
340
 
}
341
 
 
342
 
static int umount_private_dir(pam_handle_t *pamh)
343
 
{
344
 
        return private_dir(pamh, 0);
345
 
}
346
 
 
347
190
PAM_EXTERN int
348
191
pam_sm_open_session(pam_handle_t *pamh, int flags,
349
192
                    int argc, const char *argv[])
350
193
{
351
 
        mount_private_dir(pamh);
352
194
        return PAM_SUCCESS;
353
195
}
354
196
 
356
198
pam_sm_close_session(pam_handle_t *pamh, int flags,
357
199
                     int argc, const char *argv[])
358
200
{
359
 
        umount_private_dir(pamh);
360
201
        return PAM_SUCCESS;
361
202
}
362
203
 
370
211
        char *old_passphrase = NULL;
371
212
        char *new_passphrase = NULL;
372
213
        char *wrapped_pw_filename;
373
 
        char *unwrapped_pw_filename;
374
 
        char *name = NULL;
375
214
        char salt[ECRYPTFS_SALT_SIZE];
376
215
        char salt_hex[ECRYPTFS_SALT_SIZE_HEX];
377
216
        pid_t child_pid, tmp_pid;
378
 
        struct stat s;
379
217
        int rc = PAM_SUCCESS;
380
218
 
381
219
        rc = pam_get_user(pamh, &username, NULL);
386
224
                if (pwd) {
387
225
                        uid = pwd->pw_uid;
388
226
                        homedir = pwd->pw_dir;
389
 
                        name = pwd->pw_name;
390
227
                }
391
228
        } else {
392
229
                syslog(LOG_ERR, "Error getting passwd info for user [%s]; "
403
240
                seteuid(saved_uid);
404
241
                goto out;
405
242
        }
406
 
        /* On the first pass, do nothing except check that we have a password */
407
 
        if ((flags & PAM_PRELIM_CHECK)) {
408
 
                if (!old_passphrase)
409
 
                {
410
 
                        syslog(LOG_WARNING, "eCryptfs PAM passphrase change "
411
 
                               "module retrieved a NULL passphrase; nothing to "
412
 
                               "do\n");
413
 
                        rc = PAM_AUTHTOK_RECOVER_ERR;
414
 
                }
415
 
                seteuid(saved_uid);
416
 
                goto out;
417
 
        }
418
243
        if ((rc = pam_get_item(pamh, PAM_AUTHTOK,
419
244
                               (const void **)&new_passphrase))
420
245
            != PAM_SUCCESS) {
423
248
                seteuid(saved_uid);
424
249
                goto out;
425
250
        }
 
251
        seteuid(saved_uid);
 
252
        if (!old_passphrase || !new_passphrase) {
 
253
                syslog(LOG_WARNING, "eCryptfs PAM passphrase change module "
 
254
                       "retrieved at least one NULL passphrase; nothing to "
 
255
                       "do\n");
 
256
                goto out;
 
257
        }
426
258
        if ((rc = asprintf(&wrapped_pw_filename, "%s/.ecryptfs/%s", homedir,
427
259
                           ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME))
428
260
            == -1) {
430
262
                rc = -ENOMEM;
431
263
                goto out;
432
264
        }
433
 
        rc = asprintf(&unwrapped_pw_filename, "/dev/shm/.ecryptfs-%s", name);
434
 
        if (rc == -1) {
435
 
                syslog(LOG_ERR, "Unable to allocate memory\n");
436
 
                rc = -ENOMEM;
437
 
                goto out;
438
 
        }
439
265
        if ((rc = ecryptfs_read_salt_hex_from_rc(salt_hex))) {
 
266
                syslog(LOG_WARNING, "Unable to read salt value from user's "
 
267
                       ".ecryptfsrc file; using default\n");
440
268
                from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
441
 
        } else {
 
269
        } else
442
270
                from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE);
443
 
        }
444
 
        /* If /dev/shm/.ecryptfs-$USER exists and owned by the user
445
 
           and ~/.ecryptfs/wrapped-passphrase does not exist
446
 
           and a new_passphrase is set:
447
 
           wrap the unwrapped passphrase file */
448
 
        if (stat(unwrapped_pw_filename, &s) == 0 && (s.st_uid == uid) &&
449
 
            stat(wrapped_pw_filename, &s) != 0  &&
450
 
            new_passphrase != NULL && *new_passphrase != '\0' &&
451
 
            name != NULL && *name != '\0') {
452
 
                setuid(uid);
453
 
                rc = ecryptfs_wrap_passphrase_file(wrapped_pw_filename,
454
 
                        new_passphrase, salt, unwrapped_pw_filename);
455
 
                if (rc != 0) {
456
 
                        syslog(LOG_ERR,
457
 
                          "Error wrapping cleartext password; "
458
 
                          "rc = [%d]\n", rc);
459
 
                }
460
 
                goto out;
461
 
        }
462
 
        seteuid(saved_uid);
463
 
        if (!old_passphrase || !new_passphrase || *new_passphrase == '\0') {
464
 
                syslog(LOG_WARNING, "eCryptfs PAM passphrase change module "
465
 
                       "retrieved at least one NULL passphrase; nothing to "
466
 
                       "do\n");
467
 
                rc = PAM_AUTHTOK_RECOVER_ERR;
468
 
                goto out;
469
 
        }
470
271
        rc = PAM_SUCCESS;
471
272
        if ((child_pid = fork()) == 0) {
472
273
                char passphrase[ECRYPTFS_MAX_PASSWORD_LENGTH + 1];