about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2021-08-30 17:40:49 -0400
committerJune McEnroe <june@causal.agency>2021-08-30 17:40:49 -0400
commit5d72a1dd1e2fdaec676569559b6f483682495a4e (patch)
treed74ac0c42a02d30db79bbebca6c4a9563cb505d8
parentDeclare producer static (diff)
downloadpounce-5d72a1dd1e2fdaec676569559b6f483682495a4e.tar.gz
pounce-5d72a1dd1e2fdaec676569559b6f483682495a4e.zip
Correct handling of colons in SASL PLAIN
Only the first colon should be replaced with a null byte.
-rw-r--r--state.c23
1 files changed, 11 insertions, 12 deletions
diff --git a/state.c b/state.c
index edc4b92..e1b49c9 100644
--- a/state.c
+++ b/state.c
@@ -60,22 +60,21 @@ void stateLogin(
 	const char *pass, enum Cap blind, const char *plain,
 	const char *nick, const char *user, const char *real
 ) {
-	serverFormat("CAP LS 302\r\n");
-	if (pass) serverFormat("PASS :%s\r\n", pass);
-	if (blind) serverFormat("CAP REQ :%s\r\n", capList(blind, NULL));
 	if (plain) {
-		byte buf[AuthLen];
+		byte buf[AuthLen] = {0};
 		size_t len = 1 + strlen(plain);
-		if (sizeof(buf) < len) {
-			errx(EX_SOFTWARE, "SASL PLAIN is too long");
-		}
-		buf[0] = 0;
-		for (size_t i = 0; plain[i]; ++i) {
-			buf[1 + i] = (plain[i] == ':' ? 0 : plain[i]);
-		}
+		if (len > sizeof(buf)) errx(EX_CONFIG, "SASL PLAIN too long");
+		memcpy(&buf[1], plain, len - 1);
+		byte *sep = memchr(buf, ':', len);
+		if (!sep) errx(EX_CONFIG, "SASL PLAIN missing colon");
+		*sep = 0;
 		base64(plainBase64, buf, len);
-		explicit_bzero(buf, sizeof(buf));
+		explicit_bzero(buf, len);
 	}
+
+	serverFormat("CAP LS 302\r\n");
+	if (pass) serverFormat("PASS :%s\r\n", pass);
+	if (blind) serverFormat("CAP REQ :%s\r\n", capList(blind, NULL));
 	serverFormat("NICK %s\r\n", nick);
 	serverFormat("USER %s 0 * :%s\r\n", user, real);
 }