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 #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) {