From 9ae05e84f25e8a6c1ef080934f7428b3213deca6 Mon Sep 17 00:00:00 2001
From: Jordan Bancino
Date: Wed, 10 Aug 2022 11:58:39 -0400
Subject: [PATCH] Implement user validation.
---
contrib/development.conf | 2 +-
site/index.html | 6 ++--
src/Telodendria.c | 72 ++++++++++++++++++++++++++++++++++++++++
src/TelodendriaConfig.c | 18 ++++++++--
tools/bin/td | 2 +-
5 files changed, 94 insertions(+), 6 deletions(-)
diff --git a/contrib/development.conf b/contrib/development.conf
index 4bda3ca..171c5cf 100644
--- a/contrib/development.conf
+++ b/contrib/development.conf
@@ -4,7 +4,7 @@
server-name "localhost";
chroot ".";
-id "_telodendria" "_telodendria";
+id "jordan";
data-dir "./data";
federation "true";
registration "true";
diff --git a/site/index.html b/site/index.html
index 401b5ae..6951d4d 100644
--- a/site/index.html
+++ b/site/index.html
@@ -227,8 +227,10 @@ you on a sufficiently complete operating system:
-
-A standards-compliant C compiler with a POSIX.1c standard library. Because
-Telodendria is written in ANSI C and sticks to POSIX.1c features, it
+A standards-compliant C compiler with a POSIX.1c standard library and
+access to a
chroot()
system call (which is available in all
+UNIX-like operating systems, but is not POSIX.) Because Telodendria
+is written in ANSI C and sticks almost entirely to POSIX.1c features, it
should compile on almost any compiler and operating system with minimal
effort, but the following compilers and operating systems are known to work:
diff --git a/src/Telodendria.c b/src/Telodendria.c
index 111ef26..506a6c2 100644
--- a/src/Telodendria.c
+++ b/src/Telodendria.c
@@ -26,6 +26,9 @@
#include
#include
+#include
+#include
+
#include
#include
@@ -88,6 +91,10 @@ main(int argc, char **argv)
/* Program configuration */
TelodendriaConfig *tConfig = NULL;
+ /* User validation */
+ struct passwd *userInfo;
+ struct group *groupInfo;
+
lc = LogConfigCreate();
if (!lc)
@@ -185,6 +192,71 @@ main(int argc, char **argv)
Log(lc, LOG_DEBUG, "Flags: %x", tConfig->flags);
LogConfigUnindent(lc);
+ Log(lc, LOG_TASK, "Evaluating permissions...");
+
+ if (chdir(tConfig->chroot) != 0)
+ {
+ Log(lc, LOG_ERROR, "Unable to change into directory: %s.", tConfig->chroot);
+ exit = EXIT_FAILURE;
+ goto finish;
+ }
+
+ Log(lc, LOG_DEBUG, "Running as uid/gid: %d/%d.", getuid(), getgid());
+
+ userInfo = getpwnam(tConfig->uid);
+ groupInfo = getgrnam(tConfig->gid);
+
+ if (!userInfo || !groupInfo)
+ {
+ Log(lc, LOG_ERROR, "Unable to locate the user/group specified in the configuration.");
+ exit = EXIT_FAILURE;
+ goto finish;
+ }
+
+ if (getuid() == 0)
+ {
+ if (chroot(tConfig->chroot) == 0)
+ {
+ Log(lc, LOG_MESSAGE, "Changed the root directory to: %s.", tConfig->chroot);
+ }
+ else
+ {
+ Log(lc, LOG_WARNING, "Unable to chroot into directory: %s.", tConfig->chroot);
+ }
+
+ if (setgid(groupInfo->gr_gid) != 0 || setuid(userInfo->pw_uid) != 0)
+ {
+ Log(lc, LOG_WARNING, "Unable to set process uid/gid.");
+ }
+ else
+ {
+ Log(lc, LOG_MESSAGE, "Set uid/gid to %s:%s.", tConfig->uid, tConfig->gid);
+ }
+ }
+ else
+ {
+ Log(lc, LOG_MESSAGE, "Not changing root directory, because we are not root.");
+
+ if (getuid() != userInfo->pw_uid || getgid() != groupInfo->gr_gid)
+ {
+ Log(lc, LOG_WARNING, "Not running as the uid/gid specified in the configuration.");
+ }
+ else
+ {
+ Log(lc, LOG_DEBUG, "Running as the uid/gid specified in the configuration.");
+ }
+ }
+
+ /* These config values are no longer needed; don't hold them in
+ * memory anymore */
+ free(tConfig->chroot);
+ free(tConfig->uid);
+ free(tConfig->gid);
+
+ tConfig->chroot = NULL;
+ tConfig->uid = NULL;
+ tConfig->gid = NULL;
+
finish:
Log(lc, LOG_DEBUG, "Exiting with code '%d'.", exit);
TelodendriaConfigFree(tConfig);
diff --git a/src/TelodendriaConfig.c b/src/TelodendriaConfig.c
index 292ab02..afc0f10 100644
--- a/src/TelodendriaConfig.c
+++ b/src/TelodendriaConfig.c
@@ -119,9 +119,23 @@ TelodendriaConfigParse(HashMap * config, LogConfig * lc)
GET_DIRECTIVE("id");
ASSERT_NO_CHILDREN("id");
- ASSERT_VALUES("id", 2);
COPY_VALUE(tConfig->uid, 0);
- COPY_VALUE(tConfig->gid, 1);
+
+ switch (ArraySize(value))
+ {
+ case 1:
+ Log(lc, LOG_WARNING, "No run group specified; assuming it's the same as the user.");
+ tConfig->gid = UtilStringDuplicate(tConfig->uid);
+ break;
+ case 2:
+ COPY_VALUE(tConfig->gid, 1);
+ break;
+ default:
+ Log(lc, LOG_ERROR,
+ "Wrong value count in directive 'id': got '%d', but expected 1 or 2.",
+ ArraySize(value));
+ break;
+ }
GET_DIRECTIVE("data-dir");
ASSERT_NO_CHILDREN("data-dir");
diff --git a/tools/bin/td b/tools/bin/td
index 7215e38..a77f864 100644
--- a/tools/bin/td
+++ b/tools/bin/td
@@ -22,7 +22,7 @@
: "${TELODENDRIA_VERSION:=0.0.0}"
: "${CVS_TAG:=Telodendria-$(echo $TELODENDRIA_VERSION | sed 's/\./_/g')}"
-: "${DEFINES:=-D_POSIX_C_SOURCE=199506L -DTELODENDRIA_VERSION=\"$TELODENDRIA_VERSION\"}"
+: "${DEFINES:=-D_BSD_SOURCE -D_POSIX_C_SOURCE=199506L -DTELODENDRIA_VERSION=\"$TELODENDRIA_VERSION\"}"
: "${INCLUDES:=-Isrc/include}"
: "${CC:=cc}"