diff -up ecryptfs-utils-87/src/pam_ecryptfs/pam_ecryptfs.c.pamdata ecryptfs-utils-87/src/pam_ecryptfs/pam_ecryptfs.c --- ecryptfs-utils-87/src/pam_ecryptfs/pam_ecryptfs.c.pamdata 2011-08-03 15:40:01.743949759 +0200 +++ ecryptfs-utils-87/src/pam_ecryptfs/pam_ecryptfs.c 2011-08-03 15:52:05.676388743 +0200 @@ -45,6 +45,22 @@ #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) +{ + 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) { @@ -64,7 +80,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; @@ -96,42 +112,43 @@ 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,}; syslog(LOG_INFO, "%s: Called\n", __FUNCTION__); - 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; syslog(LOG_INFO, "%s: username = [%s]\n", __FUNCTION__, - username); - pwd = getpwnam(username); + epd->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, "Error getting passwd info for user [%s]; " - "rc = [%ld]\n", username, rc); + "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_INFO, "%s: %s is already mounted\n", __FUNCTION__, - homedir); + epd->homedir); /* If private/home is already mounted, then we can skip costly loading of keys */ goto out; @@ -141,82 +158,31 @@ PAM_EXTERN int pam_sm_authenticate(pam_h if (ecryptfs_get_version(&version) != 0) syslog(LOG_WARNING, "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); seteuid(saved_uid); if (rc != PAM_SUCCESS) { syslog(LOG_ERR, "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, "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, "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 ((argc == 1) - && (memcmp(argv[0], "unwrap\0", 7) == 0)) { - char *wrapped_pw_filename; + from_hex(epd->salt, salt_hex, ECRYPTFS_SALT_SIZE); - rc = asprintf( - &wrapped_pw_filename, "%s/.ecryptfs/%s", - 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(username, uid, wrapped_pw_filename, passphrase, 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, 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, "Error adding passphrase key token to " - "user session keyring; rc = [%ld]\n", rc); - goto out_child; - } -out_child: - free(auth_tok_sig); - _exit(0); + epd->unwrap = ((argc == 1) && (memcmp(argv[0], "unwrap\0", 7) == 0)); + if (pam_set_data(pamh, ECRYPTFS_PAM_DATA, epd, pam_free_ecryptfsdata) != PAM_SUCCESS) { + + syslog(LOG_ERR, "Unable to store ecryptfs pam data : %m"); + goto out; } - tmp_pid = waitpid(child_pid, NULL, 0); - if (tmp_pid == -1) - syslog(LOG_WARNING, - "waitpid() returned with error condition\n"); + out: if (private_mnt != NULL) free(private_mnt); @@ -361,10 +327,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 (pam_get_data(pamh, ECRYPTFS_PAM_DATA, (const void **)&epd) != PAM_SUCCESS) + { + syslog(LOG_ERR,"Unable to get ecryptfs pam data : %m"); + 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; }