summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--bounce.c14
-rw-r--r--bounce.h4
-rw-r--r--client.c19
-rw-r--r--pounce.114
-rw-r--r--state.c2
6 files changed, 41 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index a41d96d..19ccc0d 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ LIBRESSL_PREFIX = /usr/local
 CFLAGS += -std=c11 -Wall -Wextra -Wpedantic
 CFLAGS += -I${LIBRESSL_PREFIX}/include
 LDFLAGS += -L${LIBRESSL_PREFIX}/lib
-LDLIBS = -ltls
+LDLIBS = -lcrypt -ltls
 
 BINS = calico pounce
 MANS = ${BINS:=.1}
diff --git a/bounce.c b/bounce.c
index 537f539..889ed5b 100644
--- a/bounce.c
+++ b/bounce.c
@@ -29,6 +29,7 @@
 #include <string.h>
 #include <strings.h>
 #include <sys/file.h>
+#include <sys/random.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sysexits.h>
@@ -43,6 +44,16 @@
 #define SIGINFO SIGUSR2
 #endif
 
+static void hashPass(void) {
+	char *pass = getpass("Password: ");
+	byte rand[12];
+	ssize_t len = getrandom(rand, sizeof(rand), 0);
+	if (len < 0) err(EX_OSERR, "getrandom");
+	char salt[3 + BASE64_SIZE(sizeof(rand))] = "$6$";
+	base64(&salt[3], rand, sizeof(rand));
+	printf("%s\n", crypt(pass, salt));
+}
+
 static FILE *saveFile;
 
 static void saveExit(void) {
@@ -190,7 +201,7 @@ int main(int argc, char *argv[]) {
 	const char *away = "pounced :3";
 	const char *quit = "connection reset by purr";
 
-	const char *Opts = "!A:C:H:K:NP:Q:U:W:a:f:h:j:n:p:r:s:u:vw:";
+	const char *Opts = "!A:C:H:K:NP:Q:U:W:a:f:h:j:n:p:r:s:u:vw:x";
 	const struct option LongOpts[] = {
 		{ "insecure", no_argument, NULL, '!' },
 		{ "away", required_argument, NULL, 'A' },
@@ -244,6 +255,7 @@ int main(int argc, char *argv[]) {
 			break; case 'u': user = optarg;
 			break; case 'v': verbose = true;
 			break; case 'w': pass = optarg;
+			break; case 'x': hashPass(); return EX_OK;
 			break; default:  return EX_USAGE;
 		}
 	}
diff --git a/bounce.h b/bounce.h
index b8c2298..434a1f8 100644
--- a/bounce.h
+++ b/bounce.h
@@ -116,9 +116,7 @@ static const char Base64[64] = {
 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 };
 
-static inline size_t base64Size(size_t len) {
-	return 1 + (len + 2) / 3 * 4;
-}
+#define BASE64_SIZE(len) (1 + ((len) + 2) / 3 * 4)
 
 static inline void base64(char *dst, const byte *src, size_t len) {
 	size_t i = 0;
diff --git a/client.c b/client.c
index c951590..35faa4b 100644
--- a/client.c
+++ b/client.c
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <sysexits.h>
 #include <tls.h>
+#include <unistd.h>
 
 enum Need {
 	NeedNick = 1 << 0,
@@ -96,7 +97,7 @@ static void passRequired(struct Client *client) {
 	client->error = true;
 }
 
-static void sync(struct Client *client) {
+static void maybeSync(struct Client *client) {
 	if (client->need == NeedPass) passRequired(client);
 	if (!client->need) stateSync(client);
 }
@@ -106,7 +107,7 @@ typedef void Handler(struct Client *client, struct Message *msg);
 static void handleNick(struct Client *client, struct Message *msg) {
 	(void)msg;
 	client->need &= ~NeedNick;
-	sync(client);
+	maybeSync(client);
 }
 
 static void handleUser(struct Client *client, struct Message *msg) {
@@ -119,17 +120,21 @@ static void handleUser(struct Client *client, struct Message *msg) {
 	} else {
 		client->need &= ~NeedUser;
 		client->consumer = ringConsumer(msg->params[0]);
-		sync(client);
+		maybeSync(client);
 	}
 }
 
 static void handlePass(struct Client *client, struct Message *msg) {
 	if (!clientPass) return;
-	if (!msg->params[0] || strcmp(msg->params[0], clientPass)) {
+	if (!msg->params[0]) {
 		passRequired(client);
-	} else {
+		return;
+	}
+	if (!strcmp(crypt(msg->params[0], clientPass), clientPass)) {
 		client->need &= ~NeedPass;
-		sync(client);
+		maybeSync(client);
+	} else {
+		passRequired(client);
 	}
 }
 
@@ -139,7 +144,7 @@ static void handleCap(struct Client *client, struct Message *msg) {
 	if (!strcmp(msg->params[0], "END")) {
 		if (!client->need) return;
 		client->need &= ~NeedCapEnd;
-		sync(client);
+		maybeSync(client);
 
 	} else if (!strcmp(msg->params[0], "LS")) {
 		if (client->need) client->need |= NeedCapEnd;
diff --git a/pounce.1 b/pounce.1
index cbb5eaa..a18cb98 100644
--- a/pounce.1
+++ b/pounce.1
@@ -1,4 +1,4 @@
-.Dd November 3, 2019
+.Dd November 4, 2019
 .Dt POUNCE 1
 .Os
 .
@@ -28,6 +28,7 @@
 .Op Fl u Ar user
 .Op Fl w Ar pass
 .Op Ar config ...
+.Nm Fl x
 .
 .Sh DESCRIPTION
 The
@@ -124,6 +125,11 @@ and
 Require the server password
 .Ar pass
 for clients to connect.
+The
+.Ar pass
+string must be hashed using the
+.Fl x
+flag.
 .
 .It Fl a Ar user : Ns Ar pass , Cm sasl = Ar user : Ns Ar pass
 Authenticate as
@@ -187,6 +193,12 @@ and blue to clients.
 .It Fl w Ar pass , Cm pass = Ar pass
 Log in with the server password
 .Ar pass .
+.
+.It Fl x
+Prompt for a password
+and output a hash
+for use with
+.Fl W .
 .El
 .
 .Pp
diff --git a/state.c b/state.c
index 421c23f..a0336dc 100644
--- a/state.c
+++ b/state.c
@@ -49,7 +49,7 @@ void stateLogin(
 		for (size_t i = 0; auth[i]; ++i) {
 			plain[1 + i] = (auth[i] == ':' ? 0 : auth[i]);
 		}
-		plainBase64 = malloc(base64Size(sizeof(plain)));
+		plainBase64 = malloc(BASE64_SIZE(sizeof(plain)));
 		if (!plainBase64) err(EX_OSERR, "malloc");
 		base64(plainBase64, plain, sizeof(plain));
 		serverFormat("CAP REQ :sasl\r\n");