9471b77
diff -up ecryptfs-utils-108/src/pam_ecryptfs/pam_ecryptfs.c.pamdata ecryptfs-utils-108/src/pam_ecryptfs/pam_ecryptfs.c
9471b77
--- ecryptfs-utils-108/src/pam_ecryptfs/pam_ecryptfs.c.pamdata	2015-08-11 14:44:00.963818440 +0200
9471b77
+++ ecryptfs-utils-108/src/pam_ecryptfs/pam_ecryptfs.c	2015-08-11 14:44:00.965818435 +0200
75b89e1
@@ -46,6 +46,26 @@
8b56955
 
8b56955
 #define PRIVATE_DIR "Private"
8b56955
 
8b56955
+#define ECRYPTFS_PAM_DATA "ecryptfs:passphrase"
8b56955
+
8b56955
+struct ecryptfs_pam_data {
8b56955
+	int unwrap;
8b56955
+	uid_t uid;
538c2f1
+	gid_t gid;
8b56955
+	char *passphrase;
8b56955
+	const char *homedir;
8b56955
+	const char *username;
8b56955
+	char salt[ECRYPTFS_SALT_SIZE];  
8b56955
+};
8b56955
+
8b56955
+static void pam_free_ecryptfsdata(pam_handle_t *pamh, void *data, int error_status)
8b56955
+{
7a13e78
+	if (data) {
7a13e78
+		free(((struct ecryptfs_pam_data *)data)->passphrase);
7a13e78
+		free(data);
7a13e78
+	}
8b56955
+}
8b56955
+
8b56955
 /* returns: 0 if file does not exist, 1 if it exists, <0 for error */
8b56955
 static int file_exists_dotecryptfs(const char *homedir, char *filename)
8b56955
 {
75b89e1
@@ -65,7 +85,7 @@ out:
8b56955
 	return rc;
8b56955
 }
8b56955
 
8b56955
-static int wrap_passphrase_if_necessary(const char *username, uid_t uid, char *wrapped_pw_filename, char *passphrase, char *salt)
8b56955
+static int wrap_passphrase_if_necessary(const char *username, uid_t uid, const char *wrapped_pw_filename, const char *passphrase, const char *salt)
8b56955
 {
8b56955
 	char *unwrapped_pw_filename = NULL;
8b56955
 	struct stat s;
0d13c93
@@ -93,7 +113,7 @@ static int wrap_passphrase_if_necessary(
0d13c93
 }
0d13c93
 
0d13c93
 static int rewrap_passphrase_if_necessary(char *wrapped_pw_filename,
0d13c93
-					  char *wrapping_passphrase, char *salt)
0d13c93
+					  char *wrapping_passphrase, const char *salt)
0d13c93
 {
0d13c93
 	char passphrase[ECRYPTFS_MAX_PASSPHRASE_BYTES + 1];
0d13c93
 	uint8_t version;
0d13c93
@@ -123,147 +143,68 @@ static int rewrap_passphrase_if_necessar
8b56955
 PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
8b56955
 				   const char **argv)
8b56955
 {
538c2f1
-	uid_t uid = 0, oeuid = 0;
538c2f1
-	long ngroups_max = sysconf(_SC_NGROUPS_MAX);
538c2f1
-	gid_t gid = 0, oegid = 0, groups[ngroups_max+1];
538c2f1
-	int ngids = 0;
8b56955
-	char *homedir = NULL;
8b56955
-	const char *username;
8b56955
-	char *passphrase = NULL;
8b56955
-	char salt[ECRYPTFS_SALT_SIZE];
8b56955
 	char salt_hex[ECRYPTFS_SALT_SIZE_HEX];
75b89e1
-	char *auth_tok_sig = NULL;
8b56955
 	char *private_mnt = NULL;
8b56955
-	pid_t child_pid, tmp_pid;
538c2f1
 	long rc;
bf34873
+	struct ecryptfs_pam_data *epd;
8b56955
 
8b56955
-	rc = pam_get_user(pamh, &username, NULL);
bf34873
+	if ((epd = calloc(1, sizeof(struct ecryptfs_pam_data))) == NULL) {
8b56955
+		syslog(LOG_ERR,"Memory allocation failed");
8b56955
+		rc = -ENOMEM;
8b56955
+		goto out;
8b56955
+	}
8b56955
+
8b56955
+	rc = pam_get_user(pamh, &epd->username, NULL);
8b56955
 	if (rc == PAM_SUCCESS) {
8b56955
 		struct passwd *pwd;
8b56955
 
8b56955
-		pwd = getpwnam(username);
bf34873
+		errno = 0;
8b56955
+		pwd = getpwnam(epd->username);
8b56955
 		if (pwd) {
8b56955
-			uid = pwd->pw_uid;
538c2f1
-			gid = pwd->pw_gid;
8b56955
-			homedir = pwd->pw_dir;
bf34873
-		}
bf34873
-	} else {
bf34873
-		syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user [%s]; rc = [%ld]\n", username, rc);
bf34873
-		goto out;
8b56955
+			epd->uid = pwd->pw_uid;
538c2f1
+			epd->gid = pwd->pw_gid;
8b56955
+			epd->homedir = pwd->pw_dir;
bf34873
+			rc = 0;
bf34873
+		} else rc = errno;
bcbcca7
 	}
bf34873
-
0d13c93
-	oeuid = geteuid();
0d13c93
-	oegid = getegid();
0d13c93
-	if ((ngids = getgroups(sizeof(groups)/sizeof(gid_t), groups)) < 0) {
0d13c93
-		syslog(LOG_ERR, "pam_ecryptfs: geteuid error");
0d13c93
-		goto outnouid;
0d13c93
-	}
0d13c93
-
538c2f1
-	if (setegid(gid) < 0 || setgroups(1, &gid) < 0 || seteuid(uid) < 0) {
538c2f1
-		syslog(LOG_ERR, "pam_ecryptfs: seteuid error");
bf34873
+	if (!epd->homedir) {
bf34873
+		syslog(LOG_ERR, "pam_ecryptfs: Error getting passwd info for user; rc = [%ld]\n", rc);
8b56955
 		goto out;
bf34873
 	}
bf34873
 
bcbcca7
-	if (!file_exists_dotecryptfs(homedir, "auto-mount"))
bf34873
+	if (!file_exists_dotecryptfs(epd->homedir, "auto-mount"))
bf34873
 		goto out;
8b56955
-	private_mnt = ecryptfs_fetch_private_mnt(homedir);
8b56955
+	private_mnt = ecryptfs_fetch_private_mnt(epd->homedir);
8b56955
 	if (ecryptfs_private_is_mounted(NULL, private_mnt, NULL, 1)) {
7731a01
-		syslog(LOG_DEBUG, "pam_ecryptfs: %s: %s is already mounted\n", __FUNCTION__, homedir);
7731a01
+		syslog(LOG_DEBUG, "pam_ecryptfs: %s: %s is already mounted\n", __FUNCTION__, epd->homedir);
8b56955
 		/* If private/home is already mounted, then we can skip
8b56955
 		   costly loading of keys */
8b56955
 		goto out;
7d5fb19
 	}
8b56955
-	if(file_exists_dotecryptfs(homedir, "wrapping-independent") == 1)
8b56955
-		rc = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &passphrase, "Encryption passphrase: ");
8b56955
+	if(file_exists_dotecryptfs(epd->homedir, "wrapping-independent") == 1)
8b56955
+		rc = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &epd->passphrase, "Encryption passphrase: ");
8b56955
 	else
8b56955
-		rc = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&passphrase);
8b56955
+		rc = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&epd->passphrase);
8b56955
 	if (rc != PAM_SUCCESS) {
7731a01
 		syslog(LOG_ERR, "pam_ecryptfs: Error retrieving passphrase; rc = [%ld]\n",
8b56955
 		       rc);
8b56955
 		goto out;
8b56955
 	}
8b56955
-	auth_tok_sig = malloc(ECRYPTFS_SIG_SIZE_HEX + 1);
8b56955
-	if (!auth_tok_sig) {
8b56955
-		rc = -ENOMEM;
7731a01
-		syslog(LOG_ERR, "pam_ecryptfs: Out of memory\n");
8b56955
-		goto out;
8b56955
-	}
0d13c93
+	epd->passphrase = strdup(epd->passphrase);
8b56955
 	rc = ecryptfs_read_salt_hex_from_rc(salt_hex);
8b56955
 	if (rc) {
8b56955
-		from_hex(salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
8b56955
+		from_hex(epd->salt, ECRYPTFS_DEFAULT_SALT_HEX, ECRYPTFS_SALT_SIZE);
8b56955
 	} else
8b56955
-		from_hex(salt, salt_hex, ECRYPTFS_SALT_SIZE);
8b56955
-	if ((child_pid = fork()) == 0) {
538c2f1
-		/* temp regain uid 0 to drop privs */
538c2f1
-		seteuid(oeuid);
538c2f1
-		/* setgroups() already called */
538c2f1
-		if (setgid(gid) < 0 || setuid(uid) < 0)
538c2f1
-			goto out_child;
538c2f1
-
8b56955
-		if (passphrase == NULL) {
7731a01
-			syslog(LOG_ERR, "pam_ecryptfs: NULL passphrase; aborting\n");
8b56955
-			rc = -EINVAL;
8b56955
-			goto out_child;
8b56955
-		}
8b56955
-		if ((rc = ecryptfs_validate_keyring())) {
7731a01
-			syslog(LOG_WARNING, "pam_ecryptfs: Cannot validate keyring integrity\n");
8b56955
-		}
8b56955
-		rc = 0;
8b56955
-		if ((argc == 1)
8b56955
-		    && (memcmp(argv[0], "unwrap\0", 7) == 0)) {
8b56955
-			char *wrapped_pw_filename;
7731a01
-
8b56955
-			rc = asprintf(
8b56955
-				&wrapped_pw_filename, "%s/.ecryptfs/%s",
8b56955
-				homedir,
8b56955
-				ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME);
8b56955
-			if (rc == -1) {
7731a01
-				syslog(LOG_ERR, "pam_ecryptfs: Unable to allocate memory\n");
8b56955
-				rc = -ENOMEM;
8b56955
-				goto out_child;
8b56955
-			}
8b56955
-			if (wrap_passphrase_if_necessary(username, uid, wrapped_pw_filename, passphrase, salt) == 0) {
7731a01
-				syslog(LOG_DEBUG, "pam_ecryptfs: Passphrase file wrapped");
8b56955
-			} else {
8b56955
-				goto out_child;
8b56955
-			}
0d13c93
-			if (rewrap_passphrase_if_necessary(wrapped_pw_filename, passphrase, salt)) {
0d13c93
-				/* Non fatal condition. Log a warning. */
0d13c93
-				syslog(LOG_WARNING, "pam_ecryptfs: Unable to rewrap passphrase file\n");
0d13c93
-			}
8b56955
-			rc = ecryptfs_insert_wrapped_passphrase_into_keyring(
8b56955
-				auth_tok_sig, wrapped_pw_filename, passphrase,
8b56955
-				salt);
8b56955
-			free(wrapped_pw_filename);
8b56955
-		} else {
8b56955
-			rc = ecryptfs_add_passphrase_key_to_keyring(
8b56955
-				auth_tok_sig, passphrase, salt);
8b56955
-		}
8b56955
-		if (rc == 1) {
8b56955
-			goto out_child;
8b56955
-		}
8b56955
-		if (rc) {
7731a01
-			syslog(LOG_ERR, "pam_ecryptfs: Error adding passphrase key token to user session keyring; rc = [%ld]\n", rc);
8b56955
-			goto out_child;
8b56955
-		}
8b56955
-out_child:
8b56955
-		free(auth_tok_sig);
8b56955
-		_exit(0);
7731a01
+		from_hex(epd->salt, salt_hex, ECRYPTFS_SALT_SIZE);
8b56955
+	epd->unwrap = ((argc == 1) && (memcmp(argv[0], "unwrap\0", 7) == 0));
7a13e78
+	if ((rc=pam_set_data(pamh, ECRYPTFS_PAM_DATA, epd, pam_free_ecryptfsdata)) != PAM_SUCCESS) {
7a13e78
+		syslog(LOG_ERR, "Unable to store ecryptfs pam data : %s", pam_strerror(pamh, rc));
8b56955
+		goto out;
8b56955
 	}
8b56955
-	tmp_pid = waitpid(child_pid, NULL, 0);
8b56955
-	if (tmp_pid == -1)
7731a01
-		syslog(LOG_WARNING, "pam_ecryptfs: waitpid() returned with error condition\n");
538c2f1
-out:
0d13c93
 
538c2f1
-	seteuid(oeuid);
538c2f1
-	setegid(oegid);
538c2f1
-	setgroups(ngids, groups);
0d13c93
-
538c2f1
-outnouid:
538c2f1
+out:
8b56955
 	if (private_mnt != NULL)
8b56955
 		free(private_mnt);
75b89e1
-	if (auth_tok_sig != NULL)
75b89e1
-		free(auth_tok_sig);
538c2f1
 	return PAM_SUCCESS;
75b89e1
 }
75b89e1
 
0d13c93
@@ -407,10 +348,124 @@ static int umount_private_dir(pam_handle
8b56955
 	return private_dir(pamh, 0);
8b56955
 }
8b56955
 
8b56955
+static int fill_keyring(pam_handle_t *pamh)
8b56955
+{
8b56955
+	pid_t child_pid,tmp_pid;
538c2f1
+	uid_t oeuid = 0;
538c2f1
+	long ngroups_max = sysconf(_SC_NGROUPS_MAX);
538c2f1
+	gid_t oegid = 0, groups[ngroups_max+1];
538c2f1
+	int ngids = 0;
8b56955
+	int rc = 0;
8b56955
+	const struct ecryptfs_pam_data *epd;
75b89e1
+	char *auth_tok_sig = NULL;
8b56955
+	auth_tok_sig = malloc(ECRYPTFS_SIG_SIZE_HEX + 1);
538c2f1
+	
7a13e78
+	if ((rc=pam_get_data(pamh, ECRYPTFS_PAM_DATA, (const void **)&epd)) != PAM_SUCCESS)
8b56955
+	{
7a13e78
+		syslog(LOG_ERR,"Unable to get ecryptfs pam data : %s", pam_strerror(pamh, rc));
8b56955
+		return -EINVAL;
8b56955
+	}
8b56955
+  
538c2f1
+	oeuid = geteuid();
538c2f1
+	oegid = getegid();
538c2f1
+	if ((ngids = getgroups(sizeof(groups)/sizeof(gid_t), groups)) < 0) {
538c2f1
+		syslog(LOG_ERR, "pam_ecryptfs: geteuid error");
538c2f1
+		goto outnouid;
538c2f1
+	}
538c2f1
+
538c2f1
+	if (setegid(epd->gid) < 0 || setgroups(1, &epd->gid) < 0 || seteuid(epd->uid) < 0) {
538c2f1
+		syslog(LOG_ERR, "pam_ecryptfs: seteuid error");
538c2f1
+		goto out;
538c2f1
+	}
538c2f1
+
538c2f1
+	if (!auth_tok_sig) {
538c2f1
+		syslog(LOG_ERR, "Out of memory\n");
538c2f1
+		return -ENOMEM;
538c2f1
+	}
538c2f1
+  
8b56955
+ 	if ((child_pid = fork()) == 0) {
538c2f1
+		/* temp regain uid 0 to drop privs */
bcbcca7
+		if (seteuid(oeuid) < 0)
bcbcca7
+		{
bcbcca7
+			syslog(LOG_ERR, "pam_ecryptfs: seteuid error");
bcbcca7
+			goto out_child;
bcbcca7
+		}
538c2f1
+		/* setgroups() already called */
538c2f1
+		if (setgid(epd->gid) < 0 || setuid(epd->uid) < 0)
538c2f1
+			goto out_child;
538c2f1
+	  
8b56955
+		if (epd->passphrase == NULL) {
8b56955
+			syslog(LOG_ERR, "NULL passphrase; aborting\n");
8b56955
+			rc = -EINVAL;
8b56955
+			goto out_child;
8b56955
+		}
8b56955
+		if ((rc = ecryptfs_validate_keyring())) {
8b56955
+			syslog(LOG_WARNING,
8b56955
+			       "Cannot validate keyring integrity\n");
8b56955
+		}
8b56955
+		rc = 0;
8b56955
+		if (epd->unwrap) {
8b56955
+			char *wrapped_pw_filename;
8b56955
+
8b56955
+			rc = asprintf(
8b56955
+				&wrapped_pw_filename, "%s/.ecryptfs/%s",
8b56955
+				epd->homedir,
8b56955
+				ECRYPTFS_DEFAULT_WRAPPED_PASSPHRASE_FILENAME);
8b56955
+			if (rc == -1) {
8b56955
+				syslog(LOG_ERR, "Unable to allocate memory\n");
8b56955
+				rc = -ENOMEM;
8b56955
+				goto out_child;
8b56955
+			}
8b56955
+			if (wrap_passphrase_if_necessary(epd->username, epd->uid, wrapped_pw_filename, epd->passphrase, epd->salt) == 0) {
8b56955
+				syslog(LOG_INFO, "Passphrase file wrapped");
8b56955
+			} else {
8b56955
+				goto out_child;
0d13c93
+			}
0d13c93
+			if (rewrap_passphrase_if_necessary(wrapped_pw_filename, epd->passphrase, epd->salt)) {
0d13c93
+				/* Non fatal condition. Log a warning. */
0d13c93
+				syslog(LOG_WARNING, "pam_ecryptfs: Unable to rewrap passphrase file\n");
8b56955
+			}
8b56955
+			rc = ecryptfs_insert_wrapped_passphrase_into_keyring(
8b56955
+				auth_tok_sig, wrapped_pw_filename, epd->passphrase,
8b56955
+				epd->salt);
8b56955
+			free(wrapped_pw_filename);
8b56955
+		} else {
8b56955
+			rc = ecryptfs_add_passphrase_key_to_keyring(
8b56955
+				auth_tok_sig, epd->passphrase, epd->salt);
8b56955
+		}
8b56955
+		if (rc == 1) {
8b56955
+			goto out_child;
8b56955
+		}
8b56955
+		if (rc) {
8b56955
+			syslog(LOG_ERR, "Error adding passphrase key token to "
8b56955
+			       "user session keyring; rc = [%d]\n", rc);
8b56955
+			goto out_child;
8b56955
+		}
8b56955
+out_child:
8b56955
+		free(auth_tok_sig);
8b56955
+		_exit(0);
8b56955
+	}
8b56955
+	tmp_pid = waitpid(child_pid, NULL, 0);
8b56955
+	if (tmp_pid == -1)
8b56955
+		syslog(LOG_WARNING,
8b56955
+		       "waitpid() returned with error condition\n"); 
538c2f1
+out:
bcbcca7
+	rc = seteuid(oeuid);
bcbcca7
+	rc = setegid(oegid);
bcbcca7
+	rc = setgroups(ngids, groups);
538c2f1
+
538c2f1
+outnouid:
75b89e1
+	if (auth_tok_sig != NULL)
75b89e1
+		free(auth_tok_sig);
8b56955
+  return 0;
8b56955
+}
8b56955
+
8b56955
+
8b56955
 PAM_EXTERN int
8b56955
 pam_sm_open_session(pam_handle_t *pamh, int flags,
8b56955
 		    int argc, const char *argv[])
8b56955
 {
8b56955
+	fill_keyring(pamh);
8b56955
 	mount_private_dir(pamh);
8b56955
 	return PAM_SUCCESS;
8b56955
 }