about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2022-02-12 13:26:38 -0500
committerJune McEnroe <june@causal.agency>2022-02-12 13:26:38 -0500
commit397b4ce6bd9064aa36f8b9c264e4bbc226822d6f (patch)
treea8f45e286765c4bab90cf561cd7762ebed5114e7
parentTreat any amount of space and punctuation as word boundaries (diff)
downloadcatgirl-397b4ce6bd9064aa36f8b9c264e4bbc226822d6f.tar.gz
catgirl-397b4ce6bd9064aa36f8b9c264e4bbc226822d6f.zip
Prompt for empty server or SASL passwords
-rw-r--r--catgirl.113
-rw-r--r--chat.c24
-rw-r--r--chat.h3
-rw-r--r--handle.c18
4 files changed, 42 insertions, 16 deletions
diff --git a/catgirl.1 b/catgirl.1
index 34b9718..065002b 100644
--- a/catgirl.1
+++ b/catgirl.1
@@ -1,4 +1,4 @@
-.Dd February  3, 2022
+.Dd February 12, 2022
 .Dt CATGIRL 1
 .Os
 .
@@ -222,11 +222,9 @@ Authenticate as
 with
 .Ar pass
 using SASL PLAIN.
-Since this requires the account password
-in plain text,
-it is recommended to use CertFP instead.
-See
-.Sx Configuring CertFP .
+Leave
+.Ar pass
+blank to prompt for the password.
 .
 .It Fl c Ar path | Cm cert No = Ar path
 Load the TLS client certificate from
@@ -375,6 +373,9 @@ if it is not a terminal.
 .It Fl w Ar pass | Cm pass No = Ar pass
 Log in with the server password
 .Ar pass .
+Leave
+.Ar pass
+blank to prompt for the password.
 .El
 .
 .Ss Configuring CertFP
diff --git a/chat.c b/chat.c
index ba6c9a1..4898411 100644
--- a/chat.c
+++ b/chat.c
@@ -50,6 +50,8 @@
 #include <capsicum_helpers.h>
 #endif
 
+char *readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags);
+
 #include "chat.h"
 
 #ifndef OPENSSL_BIN
@@ -131,6 +133,12 @@ static void parseHash(char *str) {
 	if (*str) hashBound = strtoul(&str[1], NULL, 0);
 }
 
+static void parsePlain(char *str) {
+	self.plainUser = strsep(&str, ":");
+	if (!str) errx(EX_USAGE, "SASL PLAIN missing colon");
+	self.plainPass = str;
+}
+
 static volatile sig_atomic_t signals[NSIG];
 static void signalHandler(int signal) {
 	signals[signal] = 1;
@@ -288,7 +296,7 @@ int main(int argc, char *argv[]) {
 				uiTime.enable = true;
 				if (optarg) uiTime.format = optarg;
 			}
-			break; case 'a': sasl = true; self.plain = optarg;
+			break; case 'a': sasl = true; parsePlain(optarg);
 			break; case 'c': cert = optarg;
 			break; case 'e': sasl = true;
 			break; case 'g': genCert(optarg);
@@ -337,6 +345,20 @@ int main(int argc, char *argv[]) {
 		user = hash;
 	}
 
+	if (pass && !pass[0]) {
+		char *buf = malloc(512);
+		if (!buf) err(EX_OSERR, "malloc");
+		pass = readpassphrase("Server password: ", buf, 512, 0);
+		if (!pass) errx(EX_IOERR, "unable to read passphrase");
+	}
+
+	if (self.plainPass && !self.plainPass[0]) {
+		char *buf = malloc(512);
+		if (!buf) err(EX_OSERR, "malloc");
+		self.plainPass = readpassphrase("Account password: ", buf, 512, 0);
+		if (!self.plainPass) errx(EX_IOERR, "unable to read passphrase");
+	}
+
 	// Modes defined in RFC 1459:
 	set(&network.chanTypes, "#&");
 	set(&network.prefixes, "@+");
diff --git a/chat.h b/chat.h
index 19d2b18..753d1a3 100644
--- a/chat.h
+++ b/chat.h
@@ -193,7 +193,8 @@ extern struct Self {
 	bool restricted;
 	size_t pos;
 	enum Cap caps;
-	char *plain;
+	char *plainUser;
+	char *plainPass;
 	char *mode;
 	char *join;
 	char *nick;
diff --git a/handle.c b/handle.c
index e460c7c..d663ca1 100644
--- a/handle.c
+++ b/handle.c
@@ -164,7 +164,9 @@ static void handleCap(struct Message *msg) {
 	} else if (!strcmp(msg->params[1], "ACK")) {
 		self.caps |= caps;
 		if (caps & CapSASL) {
-			ircFormat("AUTHENTICATE %s\r\n", (self.plain ? "PLAIN" : "EXTERNAL"));
+			ircFormat(
+				"AUTHENTICATE %s\r\n", (self.plainUser ? "PLAIN" : "EXTERNAL")
+			);
 		}
 		if (!(self.caps & CapSASL)) ircFormat("CAP END\r\n");
 	} else if (!strcmp(msg->params[1], "NAK")) {
@@ -203,18 +205,18 @@ static void base64(char *dst, const byte *src, size_t len) {
 
 static void handleAuthenticate(struct Message *msg) {
 	(void)msg;
-	if (!self.plain) {
+	if (!self.plainUser) {
 		ircFormat("AUTHENTICATE +\r\n");
 		return;
 	}
 
 	byte buf[299] = {0};
-	size_t len = 1 + strlen(self.plain);
+	size_t userLen = strlen(self.plainUser);
+	size_t passLen = strlen(self.plainPass);
+	size_t len = 1 + userLen + 1 + passLen;
 	if (sizeof(buf) < len) errx(EX_USAGE, "SASL PLAIN is too long");
-	memcpy(&buf[1], self.plain, len - 1);
-	byte *sep = memchr(buf, ':', len);
-	if (!sep) errx(EX_USAGE, "SASL PLAIN missing colon");
-	*sep = 0;
+	memcpy(&buf[1], self.plainUser, userLen);
+	memcpy(&buf[1 + userLen + 1], self.plainPass, passLen);
 
 	char b64[BASE64_SIZE(sizeof(buf))];
 	base64(b64, buf, len);
@@ -224,7 +226,7 @@ static void handleAuthenticate(struct Message *msg) {
 
 	explicit_bzero(b64, sizeof(b64));
 	explicit_bzero(buf, sizeof(buf));
-	explicit_bzero(self.plain, strlen(self.plain));
+	explicit_bzero(self.plainPass, strlen(self.plainPass));
 }
 
 static void handleReplyLoggedIn(struct Message *msg) {