From 003fa4cf3780f7966f5522d159ea6eff0b07cd0f Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Tue, 5 Nov 2019 01:11:29 -0500 Subject: Implement SASL EXTERNAL --- bounce.c | 15 +++++++++------ bounce.h | 2 +- pounce.1 | 11 ++++++++--- state.c | 39 ++++++++++++++++++++++----------------- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/bounce.c b/bounce.c index 0e7e421..bb7e59c 100644 --- a/bounce.c +++ b/bounce.c @@ -195,7 +195,8 @@ int main(int argc, char *argv[]) { const char *host = NULL; const char *port = "6697"; char *pass = NULL; - char *auth = NULL; + bool sasl = false; + char *plain = NULL; const char *nick = NULL; const char *user = NULL; const char *real = NULL; @@ -203,7 +204,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:c:f:h:j:k:n:p:r:s:u:vw:x"; + const char *Opts = "!A:C:H:K:NP:Q:U:W:a:c:ef:h:j:k:n:p:r:s:u:vw:x"; const struct option LongOpts[] = { { "insecure", no_argument, NULL, '!' }, { "away", required_argument, NULL, 'A' }, @@ -215,8 +216,9 @@ int main(int argc, char *argv[]) { { "quit", required_argument, NULL, 'Q' }, { "bind-path", required_argument, NULL, 'U' }, { "client-pass", required_argument, NULL, 'W' }, - { "sasl", required_argument, NULL, 'a' }, + { "sasl-plain", required_argument, NULL, 'a' }, { "client-cert", required_argument, NULL, 'c' }, + { "sasl-external", no_argument, NULL, 'e' }, { "save", required_argument, NULL, 'f' }, { "host", required_argument, NULL, 'h' }, { "join", required_argument, NULL, 'j' }, @@ -244,8 +246,9 @@ int main(int argc, char *argv[]) { break; case 'Q': quit = optarg; break; case 'U': strlcpy(bindPath, optarg, sizeof(bindPath)); break; case 'W': clientPass = optarg; - break; case 'a': auth = optarg; + break; case 'a': sasl = true; plain = optarg; break; case 'c': clientCert = optarg; + break; case 'e': sasl = true; break; case 'f': save = optarg; break; case 'h': host = optarg; break; case 'j': join = optarg; @@ -333,9 +336,9 @@ int main(int argc, char *argv[]) { if (error) err(EX_OSERR, "cap_rights_limit"); #endif - stateLogin(pass, auth, nick, user, real); + stateLogin(pass, sasl, plain, nick, user, real); if (pass) explicit_bzero(pass, strlen(pass)); - if (auth) explicit_bzero(auth, strlen(auth)); + if (plain) explicit_bzero(plain, strlen(plain)); while (!stateReady()) serverRecv(); serverFormat("AWAY :%s\r\n", away); diff --git a/bounce.h b/bounce.h index 33c1fee..42b8ed5 100644 --- a/bounce.h +++ b/bounce.h @@ -99,7 +99,7 @@ void clientConsume(struct Client *client); bool stateJoinNames; void stateLogin( - const char *pass, const char *auth, + const char *pass, bool sasl, const char *plain, const char *nick, const char *user, const char *real ); bool stateReady(void); diff --git a/pounce.1 b/pounce.1 index 213575b..ee4451b 100644 --- a/pounce.1 +++ b/pounce.1 @@ -1,4 +1,4 @@ -.Dd November 4, 2019 +.Dd November 5, 2019 .Dt POUNCE 1 .Os . @@ -8,7 +8,7 @@ . .Sh SYNOPSIS .Nm -.Op Fl Nv +.Op Fl Nev .Op Fl A Ar mesg .Op Fl C Ar path .Op Fl H Ar host @@ -133,7 +133,7 @@ string must be hashed using the .Fl x flag. . -.It Fl a Ar user : Ns Ar pass , Cm sasl = Ar user : Ns Ar pass +.It Fl a Ar user : Ns Ar pass , Cm sasl-plain = Ar user : Ns Ar pass Authenticate as .Ar user with @@ -147,6 +147,11 @@ If the certificate key is in a separate file, set it with .Fl k . . +.It Fl e , Cm sasl-external +Authenticate using SASL EXTERNAL. +Set the client TLS client certificate path with +.Fl c . +. .It Fl f Ar path , Cm save = Ar path Load the contents of the buffer from .Ar path , diff --git a/state.c b/state.c index a0336dc..ba6f8d6 100644 --- a/state.c +++ b/state.c @@ -40,21 +40,23 @@ static void require(const struct Message *msg, bool origin, size_t len) { static char *plainBase64; void stateLogin( - const char *pass, const char *auth, + const char *pass, bool sasl, const char *plain, const char *nick, const char *user, const char *real ) { - if (auth) { - byte plain[1 + strlen(auth)]; - plain[0] = 0; - for (size_t i = 0; auth[i]; ++i) { - plain[1 + i] = (auth[i] == ':' ? 0 : auth[i]); - } - plainBase64 = malloc(BASE64_SIZE(sizeof(plain))); - if (!plainBase64) err(EX_OSERR, "malloc"); - base64(plainBase64, plain, sizeof(plain)); + if (pass) serverFormat("PASS :%s\r\n", pass); + if (sasl) { serverFormat("CAP REQ :sasl\r\n"); + if (plain) { + byte buf[1 + strlen(plain)]; + buf[0] = 0; + for (size_t i = 0; plain[i]; ++i) { + buf[1 + i] = (plain[i] == ':' ? 0 : plain[i]); + } + plainBase64 = malloc(BASE64_SIZE(sizeof(buf))); + if (!plainBase64) err(EX_OSERR, "malloc"); + base64(plainBase64, buf, sizeof(buf)); + } } - if (pass) serverFormat("PASS :%s\r\n", pass); serverFormat("NICK %s\r\n", nick); serverFormat("USER %s 0 * :%s\r\n", user, real); } @@ -64,16 +66,19 @@ static void handleCap(struct Message *msg) { if (strcmp(msg->params[1], "ACK") || strncmp(msg->params[2], "sasl", 4)) { errx(EX_CONFIG, "server does not support SASL"); } - serverFormat("AUTHENTICATE PLAIN\r\n"); + serverFormat("AUTHENTICATE %s\r\n", (plainBase64 ? "PLAIN" : "EXTERNAL")); } static void handleAuthenticate(struct Message *msg) { (void)msg; - if (!plainBase64) errx(EX_PROTOCOL, "unsolicited AUTHENTICATE"); - serverFormat("AUTHENTICATE %s\r\n", plainBase64); - explicit_bzero(plainBase64, strlen(plainBase64)); - free(plainBase64); - plainBase64 = NULL; + if (plainBase64) { + serverFormat("AUTHENTICATE %s\r\n", plainBase64); + explicit_bzero(plainBase64, strlen(plainBase64)); + free(plainBase64); + plainBase64 = NULL; + } else { + serverFormat("AUTHENTICATE +\r\n"); + } } static void handleReplyLoggedIn(struct Message *msg) { -- cgit 1.4.1