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 PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
100 uid_t uid = 0, oeuid = 0;
101 long ngroups_max = sysconf(_SC_NGROUPS_MAX);
102 gid_t gid = 0, oegid = 0, groups[ngroups_max+1];
104 char *homedir = NULL;
105 const char *username;
106 char *passphrase = NULL;
107 char salt[ECRYPTFS_SALT_SIZE];
108 char salt_hex[ECRYPTFS_SALT_SIZE_HEX];
109 char *auth_tok_sig = NULL;
110 char *private_mnt = NULL;
111 pid_t child_pid, tmp_pid;
114 rc = pam_get_user(pamh, &username, NULL);
115 if (rc == PAM_SUCCESS) {
118 pwd = getpwnam(username);
122 homedir = pwd->pw_dir;
125 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
131 if ((ngids = getgroups(sizeof(groups)/sizeof(gid_t), groups)) < 0) {
132 syslog(LOG_ERR, "pam_ecryptfs: geteuid error");
136 if (setegid(gid) < 0 || setgroups(1, &gid) < 0 || seteuid(uid) < 0) {
137 syslog(LOG_ERR, "pam_ecryptfs: seteuid error");
141 if (!file_exists_dotecryptfs(homedir, "auto-mount"))
143 private_mnt = ecryptfs_fetch_private_mnt(homedir);
144 if (ecryptfs_private_is_mounted(NULL, private_mnt, NULL, 1)) {
145 syslog(LOG_DEBUG, "pam_ecryptfs: %s: %s is already mounted\n", __FUNCTION__, homedir);
146 /* If private/home is already mounted, then we can skip
147 costly loading of keys */
150 if(file_exists_dotecryptfs(homedir, "wrapping-independent") == 1)
151 rc = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &passphrase, "Encryption passphrase: ");
153 rc = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&passphrase);
154 if (rc != PAM_SUCCESS) {
155 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving passphrase; rc = [%ld]\n",
159 auth_tok_sig = malloc(ECRYPTFS_SIG_SIZE_HEX + 1);
162 syslog(LOG_ERR, "pam_ecryptfs: Out of memory\n");
165 rc = ecryptfs_read_salt_hex_from_rc(salt_hex);
167 from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
169 from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE);
170 if ((child_pid = fork()) == 0) {
171 /* temp regain uid 0 to drop privs */
173 /* setgroups() already called */
174 if (setgid(gid) < 0 || setuid(uid) < 0)
177 if (passphrase == NULL) {
178 syslog(LOG_ERR, "pam_ecryptfs: NULL passphrase; aborting\n");
182 if ((rc = ecryptfs_validate_keyring())) {
183 syslog(LOG_WARNING, "pam_ecryptfs: Cannot validate keyring integrity\n");
187 && (memcmp(argv[0], "unwrap\0", 7) == 0)) {
188 char *wrapped_pw_filename;
191 &wrapped_pw_filename, "%s/.ecryptfs/%s",
193 ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME);
195 syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n");
199 if (wrap_passphrase_if_necessary(username, uid, wrapped_pw_filename, passphrase, salt) == 0) {
200 syslog(LOG_DEBUG, "pam_ecryptfs: Passphrase file wrapped");
204 rc = ecryptfs_insert_wrapped_passphrase_into_keyring(
205 auth_tok_sig, wrapped_pw_filename, passphrase,
207 free(wrapped_pw_filename);
209 rc = ecryptfs_add_passphrase_key_to_keyring(
210 auth_tok_sig, passphrase, salt);
216 syslog(LOG_ERR, "pam_ecryptfs: Error adding passphrase key token to user session keyring; rc = [%ld]\n", rc);
220 if ((rc = ecryptfs_set_zombie_session_placeholder())) {
221 syslog(LOG_ERR, "pam_ecryptfs: Error attempting to create and register zombie process; rc = [%ld]\n", rc);
228 tmp_pid = waitpid(child_pid, NULL, 0);
230 syslog(LOG_WARNING, "pam_ecryptfs: waitpid() returned with error condition\n");
235 setgroups(ngids, groups);
238 if (private_mnt != NULL)
240 if (auth_tok_sig != NULL)
245 PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
251 static struct passwd *fetch_pwd(pam_handle_t *pamh)
254 const char *username = NULL;
255 struct passwd *pwd = NULL;
257 rc = pam_get_user(pamh, &username, NULL);
258 if (rc != PAM_SUCCESS || username == NULL) {
259 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
262 pwd = getpwnam(username);
264 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
270 static int private_dir(pam_handle_t *pamh, int mount)
273 struct passwd *pwd = NULL;
274 char *sigfile = NULL;
275 char *autofile = NULL;
276 char *recorded = NULL;
278 char *automount = "auto-mount";
279 char *autoumount = "auto-umount";
283 if ((pwd = fetch_pwd(pamh)) == NULL) {
284 /* fetch_pwd() logged a message */
293 (asprintf(&autofile, "%s/.ecryptfs/%s", pwd->pw_dir, a) < 0)
294 || autofile == NULL) {
295 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for autofile name");
299 (asprintf(&sigfile, "%s/.ecryptfs/%s.sig", pwd->pw_dir,
300 PRIVATE_DIR) < 0) || sigfile == NULL) {
301 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for sigfile name");
304 if (stat(sigfile, &s) != 0) {
305 /* No sigfile, no need to mount private dir */
308 if (!S_ISREG(s.st_mode)) {
309 /* No sigfile, no need to mount private dir */
312 if ((pid = fork()) < 0) {
313 syslog(LOG_ERR, "pam_ecryptfs: Error setting up private mount");
318 if ((asprintf(&recorded,
319 "%s/.ecryptfs/.wrapped-passphrase.recorded",
320 pwd->pw_dir) < 0) || recorded == NULL) {
321 syslog(LOG_ERR, "pam_ecryptfs: Error allocating memory for recorded name");
324 if (stat(recorded, &s) != 0 && stat("/usr/share/ecryptfs-utils/ecryptfs-record-passphrase", &s) == 0) {
325 /* User has not recorded their passphrase */
326 unlink("/var/lib/update-notifier/user.d/ecryptfs-record-passphrase");
327 symlink("/usr/share/ecryptfs-utils/ecryptfs-record-passphrase", "/var/lib/update-notifier/user.d/ecryptfs-record-passphrase");
328 fd = open("/var/lib/update-notifier/dpkg-run-stamp", O_WRONLY|O_CREAT|O_NONBLOCK, 0666);
332 if (stat(autofile, &s) != 0) {
333 /* User does not want to auto-mount */
334 syslog(LOG_DEBUG, "pam_ecryptfs: Skipping automatic eCryptfs mount");
338 if (setgroups(1, &pwd->pw_gid) < 0 || setgid(pwd->pw_gid) < 0)
340 /* run mount.ecryptfs_private as the user */
341 if (setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid) < 0)
343 execl("/sbin/mount.ecryptfs_private",
344 "mount.ecryptfs_private", NULL);
346 if (stat(autofile, &s) != 0) {
347 /* User does not want to auto-unmount */
348 syslog(LOG_DEBUG, "pam_ecryptfs: Skipping automatic eCryptfs unmount");
352 if (setgroups(1, &pwd->pw_gid) < 0 || setgid(pwd->pw_gid) < 0)
354 /* run umount.ecryptfs_private as the user */
355 if (setresuid(pwd->pw_uid, pwd->pw_uid, pwd->pw_uid) < 0)
357 execl("/sbin/umount.ecryptfs_private",
358 "umount.ecryptfs_private", NULL);
363 waitpid(pid, &rc, 0);
369 static int mount_private_dir(pam_handle_t *pamh)
371 return private_dir(pamh, 1);
374 static int umount_private_dir(pam_handle_t *pamh)
376 return private_dir(pamh, 0);
380 pam_sm_open_session(pam_handle_t *pamh, int flags,
381 int argc, const char *argv[])
383 mount_private_dir(pamh);
388 pam_sm_close_session(pam_handle_t *pamh, int flags,
389 int argc, const char *argv[])
391 umount_private_dir(pamh);
395 PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
396 int argc, const char **argv)
398 uid_t uid = 0, oeuid = 0;
399 long ngroups_max = sysconf(_SC_NGROUPS_MAX);
400 gid_t gid = 0, oegid = 0, groups[ngroups_max+1];
402 char *homedir = NULL;
403 const char *username;
404 char *old_passphrase = NULL;
405 char *new_passphrase = NULL;
406 char *wrapped_pw_filename;
407 char salt[ECRYPTFS_SALT_SIZE];
408 char salt_hex[ECRYPTFS_SALT_SIZE_HEX];
409 pid_t child_pid, tmp_pid;
410 int rc = PAM_SUCCESS;
412 rc = pam_get_user(pamh, &username, NULL);
413 if (rc == PAM_SUCCESS) {
416 pwd = getpwnam(username);
420 homedir = pwd->pw_dir;
423 syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%d]\n", username, rc);
429 if ((ngids = getgroups(sizeof(groups)/sizeof(gid_t), groups)) < 0) {
430 syslog(LOG_ERR, "pam_ecryptfs: geteuid error");
434 if (setegid(gid) < 0 || setgroups(1, &gid) < 0 || seteuid(uid) < 0) {
435 syslog(LOG_ERR, "pam_ecryptfs: seteuid error");
439 if ((rc = pam_get_item(pamh, PAM_OLDAUTHTOK,
440 (const void **)&old_passphrase))
442 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving old passphrase; rc = [%d]\n", rc);
445 /* On the first pass, do nothing except check that we have a password */
446 if ((flags & PAM_PRELIM_CHECK)) {
449 syslog(LOG_WARNING, "pam_ecryptfs: PAM passphrase change module retrieved a NULL passphrase; nothing to do\n");
450 rc = PAM_AUTHTOK_RECOVER_ERR;
454 if ((rc = pam_get_item(pamh, PAM_AUTHTOK,
455 (const void **)&new_passphrase))
457 syslog(LOG_ERR, "pam_ecryptfs: Error retrieving new passphrase; rc = [%d]\n", rc);
460 if ((rc = asprintf(&wrapped_pw_filename, "%s/.ecryptfs/%s", homedir,
461 ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME))
463 syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n");
467 if ((rc = ecryptfs_read_salt_hex_from_rc(salt_hex))) {
468 from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
470 from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE);
472 if (wrap_passphrase_if_necessary(username, uid, wrapped_pw_filename, new_passphrase, salt) == 0) {
473 syslog(LOG_DEBUG, "pam_ecryptfs: Passphrase file wrapped");
478 if (!old_passphrase || !new_passphrase || *new_passphrase == '\0') {
479 syslog(LOG_WARNING, "pam_ecryptfs: PAM passphrase change module retrieved at least one NULL passphrase; nothing to do\n");
480 rc = PAM_AUTHTOK_RECOVER_ERR;
484 if ((child_pid = fork()) == 0) {
485 char passphrase[ECRYPTFS_MAX_PASSWORD_LENGTH + 1];
487 /* temp regain uid 0 to drop privs */
489 /* setgroups() already called */
490 if (setgid(gid) < 0 || setuid(uid) < 0)
493 if ((rc = ecryptfs_unwrap_passphrase(passphrase,
495 old_passphrase, salt))) {
496 syslog(LOG_ERR, "pam_ecryptfs: Error attempting to unwrap passphrase; rc = [%d]\n", rc);
499 if ((rc = ecryptfs_wrap_passphrase(wrapped_pw_filename,
500 new_passphrase, salt,
502 syslog(LOG_ERR, "pam_ecryptfs: Error attempting to wrap passphrase; rc = [%d]", rc);
508 if ((tmp_pid = waitpid(child_pid, NULL, 0)) == -1)
509 syslog(LOG_WARNING, "pam_ecryptfs: waitpid() returned with error condition\n");
510 free(wrapped_pw_filename);
515 setgroups(ngids, groups);