summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2021-01-23 00:03:58 -0500
committerJune McEnroe <june@causal.agency>2021-01-23 00:48:15 -0500
commit95bb627ffbb5fcbf9462b5957d0cb25072d8c64e (patch)
treed1da30e906765df8f4f61ef886936270e80f1539
parentSimplify windowUpdate loops and factor out windowTop (diff)
downloadcatgirl-95bb627ffbb5fcbf9462b5957d0cb25072d8c64e.tar.gz
catgirl-95bb627ffbb5fcbf9462b5957d0cb25072d8c64e.zip
Separate kiosk mode from restrict mode
Restrict mode will focus on sandboxing, while kiosk will continue
to restrict IRC access through a public kiosk. Kiosk mode without
restrict mode allows execution of man 1 catgirl with /help, assuming
external sandboxing.

The /list and /part commands are also added to the list of disabled
commands in kiosk mode, since they are pointless without access to
/join.
-rw-r--r--catgirl.139
-rw-r--r--chat.c8
-rw-r--r--chat.h1
-rw-r--r--command.c38
4 files changed, 58 insertions, 28 deletions
diff --git a/catgirl.1 b/catgirl.1
index b632317..f0dddfe 100644
--- a/catgirl.1
+++ b/catgirl.1
@@ -1,4 +1,4 @@
-.Dd January 16, 2021
+.Dd January 22, 2021
 .Dt CATGIRL 1
 .Os
 .
@@ -8,7 +8,7 @@
 .
 .Sh SYNOPSIS
 .Nm
-.Op Fl Relv
+.Op Fl KRelv
 .Op Fl C Ar copy
 .Op Fl H Ar hash
 .Op Fl I Ar highlight
@@ -123,6 +123,20 @@ The commands which can be filtered are:
 .Sy QUIT ,
 .Sy SETNAME .
 .
+.It Fl K , Cm kiosk
+Disable the
+.Ic /copy ,
+.Ic /debug ,
+.Ic /exec ,
+.Ic /join ,
+.Ic /list ,
+.Ic /msg ,
+.Ic /open ,
+.Ic /part ,
+.Ic /query ,
+.Ic /quote
+commands.
+.
 .It Fl N Ar util , Cm notify = Ar util
 Send notifications using a utility.
 Use more than once to add arguments to
@@ -145,14 +159,19 @@ The default is the first available of
 .It Fl R , Cm restrict
 Disable the
 .Ic /copy ,
-.Ic /debug ,
-.Ic /exec ,
-.Ic /join ,
-.Ic /msg ,
-.Ic /open ,
-.Ic /query ,
-.Ic /quote
-commands.
+.Ic /exec
+and
+.Ic /open
+commands,
+as well as viewing this manual with
+.Ic /help .
+On
+.Ox ,
+restrict system operations
+and filesystem access with
+.Xr pledge 2
+and
+.Xr unveil 2 .
 .
 .It Fl S Ar host , Cm bind = Ar host
 Bind to source address
diff --git a/chat.c b/chat.c
index ebffe46..f455b35 100644
--- a/chat.c
+++ b/chat.c
@@ -159,7 +159,6 @@ static void sandbox(const char *trust, const char *cert, const char *priv) {
 		const char *path;
 		const char *perm;
 	} paths[] = {
-		{ "/usr/bin/man", "x" },
 		{ "/usr/share/terminfo", "r" },
 		{ tls_default_ca_cert_file(), "r" },
 		{ NULL, NULL },
@@ -200,6 +199,7 @@ int main(int argc, char *argv[]) {
 		{ .val = 'C', .name = "copy", required_argument },
 		{ .val = 'H', .name = "hash", required_argument },
 		{ .val = 'I', .name = "highlight", required_argument },
+		{ .val = 'K', .name = "kiosk", no_argument },
 		{ .val = 'N', .name = "notify", required_argument },
 		{ .val = 'O', .name = "open", required_argument },
 		{ .val = 'R', .name = "restrict", no_argument },
@@ -236,6 +236,7 @@ int main(int argc, char *argv[]) {
 			break; case 'C': utilPush(&urlCopyUtil, optarg);
 			break; case 'H': parseHash(optarg);
 			break; case 'I': filterAdd(Hot, optarg);
+			break; case 'K': self.kiosk = true;
 			break; case 'N': utilPush(&uiNotifyUtil, optarg);
 			break; case 'O': utilPush(&urlOpenUtil, optarg);
 			break; case 'R': self.restricted = true;
@@ -325,7 +326,8 @@ int main(int argc, char *argv[]) {
 	sig_t cursesWinch = signal(SIGWINCH, signalHandler);
 
 	fcntl(irc, F_SETFD, FD_CLOEXEC);
-	if (!self.restricted) {
+	bool pipes = !self.kiosk && !self.restricted;
+	if (pipes) {
 		int error = pipe(utilPipe);
 		if (error) err(EX_OSERR, "pipe");
 
@@ -345,7 +347,7 @@ int main(int argc, char *argv[]) {
 		{ .events = POLLIN, .fd = execPipe[0] },
 	};
 	while (!self.quit) {
-		int nfds = poll(fds, (self.restricted ? 2 : ARRAY_LEN(fds)), -1);
+		int nfds = poll(fds, (pipes ? ARRAY_LEN(fds) : 2), -1);
 		if (nfds < 0 && errno != EINTR) err(EX_IOERR, "poll");
 		if (nfds > 0) {
 			if (fds[0].revents) uiRead();
diff --git a/chat.h b/chat.h
index 1b1c338..4c9b32b 100644
--- a/chat.h
+++ b/chat.h
@@ -183,6 +183,7 @@ enum Cap {
 
 extern struct Self {
 	bool debug;
+	bool kiosk;
 	bool restricted;
 	size_t pos;
 	enum Cap caps;
diff --git a/command.c b/command.c
index 998d9a2..655b32d 100644
--- a/command.c
+++ b/command.c
@@ -457,6 +457,10 @@ static void commandHelp(uint id, char *params) {
 		replies[ReplyHelp]++;
 		return;
 	}
+	if (self.restricted) {
+		uiFormat(id, Warm, NULL, "See catgirl(1) or /help index");
+		return;
+	}
 
 	uiHide();
 	pid_t pid = fork();
@@ -474,7 +478,8 @@ static void commandHelp(uint id, char *params) {
 
 enum Flag {
 	BIT(Multiline),
-	BIT(Restricted),
+	BIT(Restrict),
+	BIT(Kiosk),
 };
 
 static const struct Handler {
@@ -485,37 +490,37 @@ static const struct Handler {
 	{ "/away", commandAway, 0 },
 	{ "/ban", commandBan, 0 },
 	{ "/close", commandClose, 0 },
-	{ "/copy", commandCopy, Restricted },
+	{ "/copy", commandCopy, Restrict | Kiosk },
 	{ "/cs", commandCS, 0 },
-	{ "/debug", commandDebug, Restricted },
+	{ "/debug", commandDebug, Kiosk },
 	{ "/deop", commandDeop, 0 },
 	{ "/devoice", commandDevoice, 0 },
 	{ "/except", commandExcept, 0 },
-	{ "/exec", commandExec, Multiline | Restricted },
-	{ "/help", commandHelp, 0 },
+	{ "/exec", commandExec, Multiline | Restrict },
+	{ "/help", commandHelp, 0 }, // Restrict special case.
 	{ "/highlight", commandHighlight, 0 },
 	{ "/ignore", commandIgnore, 0 },
 	{ "/invex", commandInvex, 0 },
 	{ "/invite", commandInvite, 0 },
-	{ "/join", commandJoin, Restricted },
+	{ "/join", commandJoin, Kiosk },
 	{ "/kick", commandKick, 0 },
-	{ "/list", commandList, 0 },
+	{ "/list", commandList, Kiosk },
 	{ "/me", commandMe, 0 },
 	{ "/mode", commandMode, 0 },
 	{ "/move", commandMove, 0 },
-	{ "/msg", commandMsg, Multiline | Restricted },
+	{ "/msg", commandMsg, Multiline | Kiosk },
 	{ "/names", commandNames, 0 },
 	{ "/nick", commandNick, 0 },
 	{ "/notice", commandNotice, Multiline },
 	{ "/ns", commandNS, 0 },
-	{ "/o", commandOpen, Restricted },
+	{ "/o", commandOpen, Restrict | Kiosk },
 	{ "/op", commandOp, 0 },
-	{ "/open", commandOpen, Restricted },
+	{ "/open", commandOpen, Restrict | Kiosk },
 	{ "/ops", commandOps, 0 },
-	{ "/part", commandPart, 0 },
-	{ "/query", commandQuery, Restricted },
+	{ "/part", commandPart, Kiosk },
+	{ "/query", commandQuery, Kiosk },
 	{ "/quit", commandQuit, 0 },
-	{ "/quote", commandQuote, Multiline | Restricted },
+	{ "/quote", commandQuote, Multiline | Kiosk },
 	{ "/say", commandPrivmsg, Multiline },
 	{ "/setname", commandSetname, 0 },
 	{ "/topic", commandTopic, 0 },
@@ -584,8 +589,11 @@ void command(uint id, char *input) {
 		uiFormat(id, Warm, NULL, "No such command %s", cmd);
 		return;
 	}
-	if (self.restricted && handler->flags & Restricted) {
-		uiFormat(id, Warm, NULL, "Command %s is restricted", cmd);
+	if (
+		(self.restricted && handler->flags & Restrict) ||
+		(self.kiosk && handler->flags & Kiosk)
+	) {
+		uiFormat(id, Warm, NULL, "Command %s is unavailable", cmd);
 		return;
 	}