From 5d253df7db09250a4c2812891e7f151e4dbb95be Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Wed, 26 May 2021 13:44:47 +0100
Subject: [PATCH] imap-download: fix perms & temp dir

---
 images/imap-download/Dockerfile |  1 -
 images/imap-download/run.sh     | 56 +++++++++++++++++++++++++++------
 2 files changed, 47 insertions(+), 10 deletions(-)

diff --git a/images/imap-download/Dockerfile b/images/imap-download/Dockerfile
index c215a1a..780f6c2 100644
--- a/images/imap-download/Dockerfile
+++ b/images/imap-download/Dockerfile
@@ -6,7 +6,6 @@ FROM ${REPO_LOCATION}minideb
 RUN install_packages ca-certificates fetchmail procmail inotify-tools mpack
 RUN mkdir /srv/home \
 	&& ln -s /mnt/fetchmailrc /srv/home/.fetchmailrc \
-	&& mkdir /tmp/maildir \
 	&& groupadd --gid 10000 fetchmail \
 	&& usermod --uid 10000 --gid 10000 --home=/srv/home --uid=10000 --gi=10000 fetchmail \
 	&& chown fetchmail:fetchmail /srv/home
diff --git a/images/imap-download/run.sh b/images/imap-download/run.sh
index b3e8ce6..c1587d3 100755
--- a/images/imap-download/run.sh
+++ b/images/imap-download/run.sh
@@ -1,5 +1,17 @@
 #!/usr/bin/env bash
 
+if [[ -z "${TARGET_UID}" ]]; then
+	echo "Error: The TARGET_UID environment variable was not specified.";
+	exit 1;
+fi
+if [[ -z "${TARGET_GID}" ]]; then
+	echo "Error: The TARGET_GID environment variable was not specified.";
+	exit 1;
+fi
+if [[ "${EUID}" -ne 0 ]]; then
+	echo "Error: This Docker container must run as root because fetchmail is a pain, and to allow customisation of the target UID/GID (although all possible actions are run as non-root users)";
+	exit 1;
+fi
 
 dir_newmail="/tmp/maildir/Mail/new";
 target_dir="/mnt/output";
@@ -13,17 +25,34 @@ on_exit() {
 }
 trap on_exit EXIT;
 
+run_as_user() {
+	run_as_uid="${1}"; shift;
+	run_as_gid="${1}"; shift;
+	if [[ -z "${run_as_uid}" ]]; then
+		echo "run_as_user: No target UID specified.";
+		return 1;
+	fi
+	if [[ -z "${run_as_gid}" ]]; then
+		echo "run_as_user: No target GID specified.";
+		return 2;
+	fi
+	
+	# Ref https://github.com/SinusBot/docker/pull/40
+	# WORKAROUND for `setpriv: libcap-ng is too old for "all" caps`, previously "-all" was used here
+	# create a list to drop all capabilities supported by current kernel
+	cap_prefix="-cap_";
+	caps="$cap_prefix$(seq -s ",$cap_prefix" 0 "$(cat /proc/sys/kernel/cap_last_cap)")";
+
+	setpriv --inh-caps="${caps}" --reuid "${run_as_uid}" --clear-groups --regid "${run_as_gid}" "$@";
+	return "$?";
+}
+
 do_fetchmail() {
 	log_msg "Starting fetchmail";
 	
 	while :; do
-		# Ref https://github.com/SinusBot/docker/pull/40
-		# WORKAROUND for `setpriv: libcap-ng is too old for "all" caps`, previously "-all" was used here
-		# create a list to drop all capabilities supported by current kernel
-		cap_prefix="-cap_";
-		caps="$cap_prefix$(seq -s ",$cap_prefix" 0 "$(cat /proc/sys/kernel/cap_last_cap)")";
-
-		setpriv --inh-caps="${caps}" --reuid "${fetchmail_uid}" --clear-groups --regid "${fetchmail_gid}" fetchmail --mda "/usr/bin/procmail -m /srv/procmail.conf";
+		run_as_user "${fetchmail_uid}" "${fetchmail_gid}" fetchmail --mda "/usr/bin/procmail -m /srv/procmail.conf";
+		
 		exit_code="$?";
 		if [[ "$exit_code" -eq 127 ]]; then
 			log_msg "setpriv failed, exiting with code 127";
@@ -42,6 +71,16 @@ log_msg() {
 
 mkdir -p "${dir_newmail}";
 
+# Moves an attachment to the output directory as the target uid/gid.
+# chowns the file before moving.
+# $1	The path to the file to move.
+move_attachment() {
+	local filename="${1}";
+	
+	chown "${TARGET_UID}:${TARGET_GID}" "${filename}";
+	run_as_user "${TARGET_UID}" "${TARGET_GID}" mv "${filename}" "${target_dir}";
+}
+
 do_attachments() {
 	while :; do # : = infinite loop
 		# Wait for an update
@@ -64,8 +103,7 @@ do_attachments() {
 			while read -r attachment; do
 				log_msg "Extracted attachment ${attachment}";
 				chmod 0775 "${temp_dir}/${attachment}";
-				mv "${attachment}" "${target_dir}";
-				
+				move_attachment "${attachment}";
 			done < <(find "${temp_dir}" -type f);
 		done < <(find "${dir_newmail}" -type f);
 	done
