1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
3 * pam_ecryptfs.c: PAM module that sends the user's authentication
4 * tokens into the kernel keyring.
6 * Copyright (C) 2007 International Business Machines
7 * Author(s): Michael Halcrow <mhalcrow@us.ibm.com>
8 * Dustin Kirkland <kirkland@ubuntu.com>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
36 #include <sys/types.h>
38 #include <sys/types.h>
40 #include <sys/fsuid.h>
43 #include <security/pam_modules.h>
44 #include <security/pam_ext.h>
45 #include "../include/ecryptfs.h"
47 #define PRIVATE_DIR "Private"
49 /* returns: 0 if file does not exist, 1 if it exists, <0 for error */
50 static int file_exists_dotecryptfs(const char *homedir, char *filename)
55 if (asprintf(&file_path, "%s/.ecryptfs/%s", homedir, filename) == -1)
57 if (stat(file_path, &s) != 0) {
68 static int wrap_passphrase_if_necessary(const char *username, uid_t uid, char *wrapped_pw_filename, char *passphrase, char *salt)
70 char *unwrapped_pw_filename = NULL;
74 rc = asprintf(&unwrapped_pw_filename, "/dev/shm/.ecryptfs-%s", username);
76 syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n");
79 /* If /dev/shm/.ecryptfs-$USER exists and owned by the user
80 and ~/.ecryptfs/wrapped-passphrase does not exist
81 and a passphrase is set:
82 wrap the unwrapped passphrase file */
83 if (stat(unwrapped_pw_filename, &s) == 0 && (s.st_uid == uid) &&
84 stat(wrapped_pw_filename, &s) != 0 &&
85 passphrase != NULL && *passphrase != '\0' &&
86 username != NULL && *username != '\0') {
88 rc = ecryptfs_wrap_passphrase_file(wrapped_pw_filename, passphrase, salt, unwrapped_pw_filename);
90 syslog(LOG_ERR, "pam_ecryptfs: Error wrapping cleartext password; " "rc = [%d]\n", rc);
97 static int rewrap_passphrase_if_necessary(char *wrapped_pw_filename,
98 char *wrapping_passphrase, char *salt)
100 char passphrase[ECRYPTFS_MAX_PASSPHRASE_BYTES + 1];
104 memset(passphrase, 0, sizeof(passphrase));
106 rc = __ecryptfs_detect_wrapped_passphrase_file_version(
112 /* Only rewrap version 1 files */
116 rc = ecryptfs_unwrap_passphrase(passphrase, wrapped_pw_filename,
117 wrapping_passphrase, salt);
121 return ecryptfs_wrap_passphrase(wrapped_pw_filename,
122 wrapping_passphrase, NULL, passphrase);
125 PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
128 uid_t uid = 0, oeuid = 0;
129 long ngroups_max = sysconf(_SC_NGROUPS_MAX);
130 gid_t gid = 0, oegid = 0, groups[ngroups_max+1];
132 char *homedir = NULL;
133 const char *username;
134 char *passphrase = NULL;
135 char salt[ECRYPTFS_SALT_SIZE];
136 char salt_hex[ECRYPTFS_SALT_SIZE_HEX];
137 char *auth_tok_sig = NULL;
138 char *private_mnt = NULL;
139 pid_t child_pid, tmp_pid;
142 rc = pam_get_user(pamh, &username, NULL);
143 if (rc == PAM_SUCCESS) {
146 pwd = getpwnam(username);
150 homedir = pwd->pw_dir;
153 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
159 if ((ngids = getgroups(sizeof(groups)/sizeof(gid_t), groups)) < 0) {
160 syslog(LOG_ERR, "pam_ecryptfs: geteuid error");
164 if (setegid(gid) < 0 || setgroups(1, &gid) < 0 || seteuid(uid) < 0) {
165 syslog(LOG_ERR, "pam_ecryptfs: seteuid error");
169 if (!file_exists_dotecryptfs(homedir, "auto-mount"))
171 private_mnt = ecryptfs_fetch_private_mnt(homedir);
172 if (ecryptfs_private_is_mounted(NULL, private_mnt, NULL, 1)) {
173 syslog(LOG_DEBUG, "pam_ecryptfs: %s: %s is already mounted\n", __FUNCTION__, homedir);
174 /* If private/home is already mounted, then we can skip
175 costly loading of keys */
178 if(file_exists_dotecryptfs(homedir, "wrapping-independent") == 1)
179 rc = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &passphrase, "Encryption passphrase: ");
181 rc = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&passphrase);
182 if (rc != PAM_SUCCESS) {
183 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving passphrase; rc = [%ld]\n",
187 auth_tok_sig = malloc(ECRYPTFS_SIG_SIZE_HEX + 1);
190 syslog(LOG_ERR, "pam_ecryptfs: Out of memory\n");
193 rc = ecryptfs_read_salt_hex_from_rc(salt_hex);
195 from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
197 from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE);
198 if ((child_pid = fork()) == 0) {
199 /* temp regain uid 0 to drop privs */
201 /* setgroups() already called */
202 if (setgid(gid) < 0 || setuid(uid) < 0)
205 if (passphrase == NULL) {
206 syslog(LOG_ERR, "pam_ecryptfs: NULL passphrase; aborting\n");
210 if ((rc = ecryptfs_validate_keyring())) {
211 syslog(LOG_WARNING, "pam_ecryptfs: Cannot validate keyring integrity\n");
215 && (memcmp(argv[0], "unwrap\0", 7) == 0)) {
216 char *wrapped_pw_filename;
219 &wrapped_pw_filename, "%s/.ecryptfs/%s",
221 ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME);
223 syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n");
227 if (wrap_passphrase_if_necessary(username, uid, wrapped_pw_filename, passphrase, salt) == 0) {
228 syslog(LOG_DEBUG, "pam_ecryptfs: Passphrase file wrapped");
232 if (rewrap_passphrase_if_necessary(wrapped_pw_filename, passphrase, salt)) {
233 /* Non fatal condition. Log a warning. */
234 syslog(LOG_WARNING, "pam_ecryptfs: Unable to rewrap passphrase file\n");
236 rc = ecryptfs_insert_wrapped_passphrase_into_keyring(
237 auth_tok_sig, wrapped_pw_filename, passphrase,
239 free(wrapped_pw_filename);
241 rc = ecryptfs_add_passphrase_key_to_keyring(
242 auth_tok_sig, passphrase, salt);
248 syslog(LOG_ERR, "pam_ecryptfs: Error adding passphrase key token to user session keyring; rc = [%ld]\n", rc);
252 if ((rc = ecryptfs_set_zombie_session_placeholder())) {
253 syslog(LOG_ERR, "pam_ecryptfs: Error attempting to create and register zombie process; rc = [%ld]\n", rc);
260 tmp_pid = waitpid(child_pid, NULL, 0);
262 syslog(LOG_WARNING, "pam_ecryptfs: waitpid() returned with error condition\n");
267 setgroups(ngids, groups);
270 if (private_mnt != NULL)
272 if (auth_tok_sig != NULL)
277 PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
283 static struct passwd *fetch_pwd(pam_handle_t *pamh)
286 const char *username = NULL;
287 struct passwd *pwd = NULL;
289 rc = pam_get_user(pamh, &username, NULL);
290 if (rc != PAM_SUCCESS || username == NULL) {
291 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
294 pwd = getpwnam(username);
296 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
302 static int private_dir(pam_handle_t *pamh, int mount)
305 struct passwd *pwd = NULL;
306 char *sigfile = NULL;
307 char *autofile = NULL;
308 char *recorded = NULL;
310 char *automount = "auto-mount";
311 char *autoumount = "auto-umount";
315 if ((pwd = fetch_pwd(pamh)) == NULL) {
316 /* fetch_pwd() logged a message */
325 (asprintf(&autofile, "%s/.ecryptfs/%s", pwd->pw_dir, a) < 0)
326 || autofile == NULL) {
327 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for autofile name");
331 (asprintf(&sigfile, "%s/.ecryptfs/%s.sig", pwd->pw_dir,
332 PRIVATE_DIR) < 0) || sigfile == NULL) {
333 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for sigfile name");
336 if (stat(sigfile, &s) != 0) {
337 /* No sigfile, no need to mount private dir */
340 if (!S_ISREG(s.st_mode)) {
341 /* No sigfile, no need to mount private dir */
344 if ((pid = fork()) < 0) {
345 syslog(LOG_ERR, "pam_ecryptfs: Error setting up private mount");
350 if ((asprintf(&recorded,
351 "%s/.ecryptfs/.wrapped-passphrase.recorded",
352 pwd->pw_dir) < 0) || recorded == NULL) {
353 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for recorded name");
356 if (stat(recorded, &s) != 0 && stat("/usr/share/ecryptfs-utils/ecryptfs-record-passphrase", &s) == 0) {
357 /* User has not recorded their passphrase */
358 unlink("/var/lib/update-notifier/user.d/ecryptfs-record-passphrase");
359 symlink("/usr/share/ecryptfs-utils/ecryptfs-record-passphrase", "/var/lib/update-notifier/user.d/ecryptfs-record-passphrase");
360 fd = open("/var/lib/update-notifier/dpkg-run-stamp", O_WRONLY|O_CREAT|O_NONBLOCK, 0666);
364 if (stat(autofile, &s) != 0) {
365 /* User does not want to auto-mount */
366 syslog(LOG_DEBUG, "pam_ecryptfs: Skipping automatic eCryptfs mount");
370 if (setgroups(1, &pwd->pw_gid) < 0 || setgid(pwd->pw_gid) < 0)
372 /* run mount.ecryptfs_private as the user */
373 if (setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid) < 0)
375 execl("/sbin/mount.ecryptfs_private",
376 "mount.ecryptfs_private", NULL);
378 if (stat(autofile, &s) != 0) {
379 /* User does not want to auto-unmount */
380 syslog(LOG_DEBUG, "pam_ecryptfs: Skipping automatic eCryptfs unmount");
384 if (setgroups(1, &pwd->pw_gid) < 0 || setgid(pwd->pw_gid) < 0)
386 /* run umount.ecryptfs_private as the user */
387 if (setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid) < 0)
389 execl("/sbin/umount.ecryptfs_private",
390 "umount.ecryptfs_private", NULL);
395 waitpid(pid, &rc, 0);
401 static int mount_private_dir(pam_handle_t *pamh)
403 return private_dir(pamh, 1);
406 static int umount_private_dir(pam_handle_t *pamh)
408 return private_dir(pamh, 0);
412 pam_sm_open_session(pam_handle_t *pamh, int flags,
413 int argc, const char *argv[])
415 mount_private_dir(pamh);
420 pam_sm_close_session(pam_handle_t *pamh, int flags,
421 int argc, const char *argv[])
423 umount_private_dir(pamh);
427 PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
428 int argc, const char **argv)
430 uid_t uid = 0, oeuid = 0;
431 long ngroups_max = sysconf(_SC_NGROUPS_MAX);
432 gid_t gid = 0, oegid = 0, groups[ngroups_max+1];
434 char *homedir = NULL;
435 const char *username;
436 char *old_passphrase = NULL;
437 char *new_passphrase = NULL;
438 char *wrapped_pw_filename;
439 char salt[ECRYPTFS_SALT_SIZE];
440 char salt_hex[ECRYPTFS_SALT_SIZE_HEX];
441 pid_t child_pid, tmp_pid;
442 int rc = PAM_SUCCESS;
444 rc = pam_get_user(pamh, &username, NULL);
445 if (rc == PAM_SUCCESS) {
448 pwd = getpwnam(username);
452 homedir = pwd->pw_dir;
455 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%d]\n", username, rc);
461 if ((ngids = getgroups(sizeof(groups)/sizeof(gid_t), groups)) < 0) {
462 syslog(LOG_ERR, "pam_ecryptfs: geteuid error");
466 if (setegid(gid) < 0 || setgroups(1, &gid) < 0 || seteuid(uid) < 0) {
467 syslog(LOG_ERR, "pam_ecryptfs: seteuid error");
471 if ((rc = pam_get_item(pamh, PAM_OLDAUTHTOK,
472 (const void **)&old_passphrase))
474 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving old passphrase; rc = [%d]\n", rc);
477 /* On the first pass, do nothing except check that we have a password */
478 if ((flags & PAM_PRELIM_CHECK)) {
481 syslog(LOG_WARNING, "pam_ecryptfs: PAM passphrase change module retrieved a NULL passphrase; nothing to do\n");
482 rc = PAM_AUTHTOK_RECOVER_ERR;
486 if ((rc = pam_get_item(pamh, PAM_AUTHTOK,
487 (const void **)&new_passphrase))
489 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving new passphrase; rc = [%d]\n", rc);
492 if ((rc = asprintf(&wrapped_pw_filename, "%s/.ecryptfs/%s", homedir,
493 ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME))
495 syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n");
499 if ((rc = ecryptfs_read_salt_hex_from_rc(salt_hex))) {
500 from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
502 from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE);
504 if (wrap_passphrase_if_necessary(username, uid, wrapped_pw_filename, new_passphrase, salt) == 0) {
505 syslog(LOG_DEBUG, "pam_ecryptfs: Passphrase file wrapped");
510 if (!old_passphrase || !new_passphrase || *new_passphrase == '\0') {
511 syslog(LOG_WARNING, "pam_ecryptfs: PAM passphrase change module retrieved at least one NULL passphrase; nothing to do\n");
512 rc = PAM_AUTHTOK_RECOVER_ERR;
516 if ((child_pid = fork()) == 0) {
517 char passphrase[ECRYPTFS_MAX_PASSWORD_LENGTH + 1];
519 /* temp regain uid 0 to drop privs */
521 /* setgroups() already called */
522 if (setgid(gid) < 0 || setuid(uid) < 0)
525 if ((rc = ecryptfs_unwrap_passphrase(passphrase,
527 old_passphrase, salt))) {
528 syslog(LOG_ERR, "pam_ecryptfs: Error attempting to unwrap passphrase; rc = [%d]\n", rc);
531 if ((rc = ecryptfs_wrap_passphrase(wrapped_pw_filename,
532 new_passphrase, salt,
534 syslog(LOG_ERR, "pam_ecryptfs: Error attempting to wrap passphrase; rc = [%d]", rc);
540 if ((tmp_pid = waitpid(child_pid, NULL, 0)) == -1)
541 syslog(LOG_WARNING, "pam_ecryptfs: waitpid() returned with error condition\n");
542 free(wrapped_pw_filename);
547 setgroups(ngids, groups);