From 94a109ca3acb0db20f314926da2109d252c27155 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Deuc=D0=B5?= <shurd@sasktel.net>
Date: Sun, 2 Feb 2025 22:03:54 -0500
Subject: [PATCH] Support uid/pw only auth

There are now two ways to authenticate with the broker:
1) TLS PSK with a sysop account, and set the password field at the
   MQTT level to the system password (user field, if present is
   ignored).  This is the prefered method as it provides mutual
   authentication and you simply can't steal credentials with MITM.
2) Synchronet TLS certificate, sysop username and the users password
   followed by a colon, followed by the system password.  The server
   authentication will now depend on the appropriate trust chain in
   the client.  If using a Let's Encrypt certificate for example,
   you can' securely connect to localhost with this method.

tools and libraries tend to allow TLS-PSK with password at the MQTT
level, many GUI tools do not allow TLS-PSK.
---
 exec/broker.js | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/exec/broker.js b/exec/broker.js
index f02c3b1fe1..df4e476099 100644
--- a/exec/broker.js
+++ b/exec/broker.js
@@ -1130,12 +1130,33 @@ MQTT.Connection.prototype.handleCONNECT = function() {
 		this.request_problem_information = (pkt.properties[23] ? true : false);
 	var syspass = null;
 
-	if (pkt.connect_flags.password_flag) {
-		if (!system.check_syspass(pkt.password))
+	if (this.sock.tls_psk_id !== undefined) {
+		if (pkt.connect_flags.password_flag) {
+			if (!system.check_syspass(pkt.password))
+				throw new Error('0x87 Not Authenticated');
+		}
+		else
+			throw new Error('0x87 Not Authenticated');
+	}
+	else {
+		if (!(pkt.connect_flags.user_name_flag && pkt.connect_flags.password_flag))
+			throw new Error('0x87 Not Authenticated');
+		var unum = system.matchuser(pkt.user_name, false);
+		if (unum === 0)
+			throw new Error('0x87 Not Authenticated');
+		var usr = new User(unum);
+		if (typeof usr.number != 'number' || usr.number <= 0)
+			throw new Error('0x87 Not Authenticated');
+		if (!usr.is_sysop)
+			throw new Error('0x87 Not Authenticated');
+		if (usr.settings & (USER_DELETED | USER_INACTIVE))
+			throw new Error('0x87 Not Authenticated');
+		var uplen = usr.security.password.length + 1;
+		if (pkt.password.substr(0, uplen).toLowerCase() !== usr.security.password.toLowerCase() + ':')
+			throw new Error('0x87 Not Authenticated');
+		if (!system.check_syspass(pkt.password.substr(uplen)))
 			throw new Error('0x87 Not Authenticated');
 	}
-	else
-		throw new Error('0x87 Not Authenticated');
 
 	// Set up the last will
 	if (pkt.connect_flags.will_flag) {
-- 
GitLab