diff -up ecryptfs-utils-93/src/pam_ecryptfs/pam_ecryptfs.c.pamdata ecryptfs-utils-93/src/pam_ecryptfs/pam_ecryptfs.c --- ecryptfs-utils-93/src/pam_ecryptfs/pam_ecryptfs.c.pamdata 2011-10-31 13:47:57.282750862 +0100 +++ ecryptfs-utils-93/src/pam_ecryptfs/pam_ecryptfs.c 2011-10-31 13:56:28.601144959 +0100 @@ -44,6 +44,25 @@ #define PRIVATE_DIR "Private" +#define ECRYPTFS_PAM_DATA "ecryptfs:passphrase" + +struct ecryptfs_pam_data { + int unwrap; + uid_t uid; + char *passphrase; + const char *homedir; + const char *username; + char salt[ECRYPTFS_SALT_SIZE]; +}; + +static void pam_free_ecryptfsdata(pam_handle_t *pamh, void *data, int error_status) +{ + if (data) { + free(((struct ecryptfs_pam_data *)data)->passphrase); + free(data); + } +} + /* returns: 0 if file does not exist, 1 if it exists, <0 for error */ static int file_exists_dotecryptfs(const char *homedir, char *filename) { @@ -63,7 +82,7 @@ out: return rc; } -static int wrap_passphrase_if_necessary(const char *username, uid_t uid, char *wrapped_pw_filename, char *passphrase, char *salt) +static int wrap_passphrase_if_necessary(const char *username, uid_t uid, const char *wrapped_pw_filename, const char *passphrase, const char *salt) { char *unwrapped_pw_filename = NULL; struct stat s; @@ -95,37 +114,37 @@ static int wrap_passphrase_if_necessary( PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { - uid_t uid = 0; - char *homedir = NULL; uid_t saved_uid = 0; - const char *username; - char *passphrase = NULL; - char salt[ECRYPTFS_SALT_SIZE]; char salt_hex[ECRYPTFS_SALT_SIZE_HEX]; - char *auth_tok_sig; char *private_mnt = NULL; - pid_t child_pid, tmp_pid; - long rc; + long rc = 0; uint32_t version; + struct ecryptfs_pam_data *epd = {0,}; - rc = pam_get_user(pamh, &username, NULL); + if ((epd = malloc(sizeof(struct ecryptfs_pam_data))) == NULL) { + syslog(LOG_ERR,"Memory allocation failed"); + rc = -ENOMEM; + goto out; + } + + rc = pam_get_user(pamh, &epd->username, NULL); if (rc == PAM_SUCCESS) { struct passwd *pwd; - pwd = getpwnam(username); + pwd = getpwnam(epd->username); if (pwd) { - uid = pwd->pw_uid; - homedir = pwd->pw_dir; + epd->uid = pwd->pw_uid; + epd->homedir = pwd->pw_dir; } } else { - syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc); + syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", epd->username, rc); goto out; } - if (!file_exists_dotecryptfs(homedir, "auto-mount")) + if (!file_exists_dotecryptfs(epd->homedir, "auto-mount")) goto out; - private_mnt = ecryptfs_fetch_private_mnt(homedir); + private_mnt = ecryptfs_fetch_private_mnt(epd->homedir); if (ecryptfs_private_is_mounted(NULL, private_mnt, NULL, 1)) { - syslog(LOG_DEBUG, "pam_ecryptfs: %s: %s is already mounted\n", __FUNCTION__, homedir); + syslog(LOG_DEBUG, "pam_ecryptfs: %s: %s is already mounted\n", __FUNCTION__, epd->homedir); /* If private/home is already mounted, then we can skip costly loading of keys */ goto out; @@ -135,79 +154,29 @@ PAM_EXTERN int pam_sm_authenticate(pam_h if (ecryptfs_get_version(&version) != 0) syslog(LOG_WARNING, "pam_ecryptfs: Can't check if kernel supports ecryptfs\n"); saved_uid = geteuid(); - seteuid(uid); - if(file_exists_dotecryptfs(homedir, "wrapping-independent") == 1) - rc = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &passphrase, "Encryption passphrase: "); + seteuid(epd->uid); + if(file_exists_dotecryptfs(epd->homedir, "wrapping-independent") == 1) + rc = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &epd->passphrase, "Encryption passphrase: "); else - rc = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&passphrase); + rc = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&epd->passphrase); + epd->passphrase = strdup(epd->passphrase); seteuid(saved_uid); if (rc != PAM_SUCCESS) { syslog(LOG_ERR, "pam_ecryptfs: Error retrieving passphrase; rc = [%ld]\n", rc); goto out; } - auth_tok_sig = malloc(ECRYPTFS_SIG_SIZE_HEX + 1); - if (!auth_tok_sig) { - rc = -ENOMEM; - syslog(LOG_ERR, "pam_ecryptfs: Out of memory\n"); - goto out; - } rc = ecryptfs_read_salt_hex_from_rc(salt_hex); if (rc) { - from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE); + from_hex(epd->salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE); } else - from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE); - if ((child_pid = fork()) == 0) { - setuid(uid); - if (passphrase == NULL) { - syslog(LOG_ERR, "pam_ecryptfs: NULL passphrase; aborting\n"); - rc = -EINVAL; - goto out_child; - } - if ((rc = ecryptfs_validate_keyring())) { - syslog(LOG_WARNING, "pam_ecryptfs: Cannot validate keyring integrity\n"); - } - rc = 0; - if ((argc == 1) - && (memcmp(argv[0], "unwrap\0", 7) == 0)) { - char *wrapped_pw_filename; - - rc = asprintf( - &wrapped_pw_filename, "%s/.ecryptfs/%s", - homedir, - ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME); - if (rc == -1) { - syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n"); - rc = -ENOMEM; - goto out_child; - } - if (wrap_passphrase_if_necessary(username, uid, wrapped_pw_filename, passphrase, salt) == 0) { - syslog(LOG_DEBUG, "pam_ecryptfs: Passphrase file wrapped"); - } else { - goto out_child; - } - rc = ecryptfs_insert_wrapped_passphrase_into_keyring( - auth_tok_sig, wrapped_pw_filename, passphrase, - salt); - free(wrapped_pw_filename); - } else { - rc = ecryptfs_add_passphrase_key_to_keyring( - auth_tok_sig, passphrase, salt); - } - if (rc == 1) { - goto out_child; - } - if (rc) { - syslog(LOG_ERR, "pam_ecryptfs: Error adding passphrase key token to user session keyring; rc = [%ld]\n", rc); - goto out_child; - } -out_child: - free(auth_tok_sig); - _exit(0); + from_hex(epd->salt, salt_hex, ECRYPTFS_SALT_SIZE); + epd->unwrap = ((argc == 1) && (memcmp(argv[0], "unwrap\0", 7) == 0)); + if ((rc=pam_set_data(pamh, ECRYPTFS_PAM_DATA, epd, pam_free_ecryptfsdata)) != PAM_SUCCESS) { + + syslog(LOG_ERR, "Unable to store ecryptfs pam data : %s", pam_strerror(pamh, rc)); + goto out; } - tmp_pid = waitpid(child_pid, NULL, 0); - if (tmp_pid == -1) - syslog(LOG_WARNING, "pam_ecryptfs: waitpid() returned with error condition\n"); out: if (private_mnt != NULL) free(private_mnt); @@ -347,10 +316,88 @@ static int umount_private_dir(pam_handle return private_dir(pamh, 0); } +static int fill_keyring(pam_handle_t *pamh) +{ + pid_t child_pid,tmp_pid; + int rc = 0; + const struct ecryptfs_pam_data *epd; + char *auth_tok_sig; + auth_tok_sig = malloc(ECRYPTFS_SIG_SIZE_HEX + 1); + if (!auth_tok_sig) { + syslog(LOG_ERR, "Out of memory\n"); + return -ENOMEM; + } + + if ((rc=pam_get_data(pamh, ECRYPTFS_PAM_DATA, (const void **)&epd)) != PAM_SUCCESS) + { + syslog(LOG_ERR,"Unable to get ecryptfs pam data : %s", pam_strerror(pamh, rc)); + return -EINVAL; + } + + if ((child_pid = fork()) == 0) { + setuid(epd->uid); + if (epd->passphrase == NULL) { + syslog(LOG_ERR, "NULL passphrase; aborting\n"); + rc = -EINVAL; + goto out_child; + } + if ((rc = ecryptfs_validate_keyring())) { + syslog(LOG_WARNING, + "Cannot validate keyring integrity\n"); + } + rc = 0; + if (epd->unwrap) { + char *wrapped_pw_filename; + + rc = asprintf( + &wrapped_pw_filename, "%s/.ecryptfs/%s", + epd->homedir, + ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME); + if (rc == -1) { + syslog(LOG_ERR, "Unable to allocate memory\n"); + rc = -ENOMEM; + goto out_child; + } + if (wrap_passphrase_if_necessary(epd->username, epd->uid, wrapped_pw_filename, epd->passphrase, epd->salt) == 0) { + syslog(LOG_INFO, "Passphrase file wrapped"); + } else { + goto out_child; + } + rc = ecryptfs_insert_wrapped_passphrase_into_keyring( + auth_tok_sig, wrapped_pw_filename, epd->passphrase, + epd->salt); + free(wrapped_pw_filename); + } else { + rc = ecryptfs_add_passphrase_key_to_keyring( + auth_tok_sig, epd->passphrase, epd->salt); + } + if (rc == 1) { + goto out_child; + } + if (rc) { + syslog(LOG_ERR, "Error adding passphrase key token to " + "user session keyring; rc = [%d]\n", rc); + goto out_child; + } +out_child: + free(auth_tok_sig); + _exit(0); + } + tmp_pid = waitpid(child_pid, NULL, 0); + if (tmp_pid == -1) + syslog(LOG_WARNING, + "waitpid() returned with error condition\n"); + + + return 0; +} + + PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { + fill_keyring(pamh); mount_private_dir(pamh); return PAM_SUCCESS; }