client->caps |= CAP_302;
copy_strf(&databuf, ":%s CAP * LS :cap-notify multi-prefix extended-join away-notify invite-notify extended-monitor chghost setname account-notify%s\r\n",
hostname,
- client->umode & UMODE_SECURE ? (client->caps & CAP_302 ? " sasl=PLAIN" : " sasl") : "");
+ client->umode & UMODE_SECURE ? (client->caps & CAP_302 ? " sasl=PLAIN,EXTERNAL" : " sasl") : "");
sendbuf(client);
if (!is_registered(client)) {
client->regstate = REG_CAPLS;
if (!(client->umode & UMODE_SECURE))
return copy_strf(&databuf, ":%s 904 * :SASL authentication failed\r\n", hostname), sendbuf(client), 0;
if (!client->saslbuf) {
- if (strcmp(args[0], "PLAIN") != 0)
- return copy_strf(&databuf, ":%s 908 * PLAIN :are available SASL mechanisms\r\n", hostname), sendbuf(client), 0;
+ if (strcmp(args[0], "PLAIN") != 0 && strcmp(args[0], "EXTERNAL") != 0)
+ return copy_strf(&databuf, ":%s 908 * PLAIN,EXTERNAL :are available SASL mechanisms\r\n", hostname), sendbuf(client), 0;
copy_strf(&databuf, ":%s AUTHENTICATE +\r\n", hostname), sendbuf(client);
// RFC 4616 spec says the three parts of the response can be up to 255 bytes long
// That's 255*3 + 2, but we'll add another NUL byte after the pass, so it's 768.
// Base64 encoding adds 4/3 overhead, so the total buffer size is 1024.
client->saslbuf = malloc(1024);
client->saslbufLen = 0;
+ client->saslexternal = !strcmp(args[0], "EXTERNAL");
if (!client->saslbuf)
abort();
} else {
memset(args[0], 0, len);
}
if (len != 400) {
- while (client->saslbufLen & 3)
- client->saslbuf[client->saslbufLen++] = '=';
- if (client->saslbufLen == 0)
- goto saslerr;
- int parity = 0;
- if (client->saslbuf[client->saslbufLen-1] == '=') {
- client->saslbuf[client->saslbufLen-1] = 'A';
- parity = 1;
- if (client->saslbuf[client->saslbufLen-2] == '=') {
- client->saslbuf[client->saslbufLen-2] = 'A';
- parity = 2;
+ if (client->saslbufLen != 0) {
+ while (client->saslbufLen & 3)
+ client->saslbuf[client->saslbufLen++] = '=';
+ int parity = 0;
+ if (client->saslbuf[client->saslbufLen-1] == '=') {
+ client->saslbuf[client->saslbufLen-1] = 'A';
+ parity = 1;
+ if (client->saslbuf[client->saslbufLen-2] == '=') {
+ client->saslbuf[client->saslbufLen-2] = 'A';
+ parity = 2;
+ }
+ }
+ unsigned char *p, *q;
+ p = (unsigned char *)client->saslbuf;
+ for (size_t i = 0; i < client->saslbufLen; i++) {
+ if (*p >= 'A' && *p <= 'Z') {
+ *p += 0-'A';
+ } else if (*p >= 'a' && *p <= 'z') {
+ *p += 26-'a';
+ } else if (*p >= '0' && *p <= '9') {
+ *p += 52-'0';
+ } else if (*p == '+') {
+ *p = 62;
+ } else if (*p == '/') {
+ *p = 63;
+ } else {
+ goto saslerr;
+ }
+ p++;
}
+ p = q = (unsigned char *)client->saslbuf;
+ for (size_t i = 0; i < client->saslbufLen; i += 4) {
+ *q++ = p[0]<<2 | p[1]>>4;
+ *q++ = p[1]<<4 | p[2]>>2;
+ *q++ = p[2]<<6 | p[3];
+ p += 4;
+ }
+ client->saslbufLen = q-(unsigned char *)client->saslbuf - parity;
}
- unsigned char *p, *q;
- p = (unsigned char *)client->saslbuf;
- for (size_t i = 0; i < client->saslbufLen; i++) {
- if (*p >= 'A' && *p <= 'Z') {
- *p += 0-'A';
- } else if (*p >= 'a' && *p <= 'z') {
- *p += 26-'a';
- } else if (*p >= '0' && *p <= '9') {
- *p += 52-'0';
- } else if (*p == '+') {
- *p = 62;
- } else if (*p == '/') {
- *p = 63;
- } else {
+ client->saslbuf[client->saslbufLen] = '\0';
+ const char *username;
+ int res = -1;
+ if (!client->saslexternal) {
+ username = strchr(client->saslbuf, '\0')+1;
+ if (username > client->saslbuf + client->saslbufLen)
+ goto saslerr;
+ char *password = strchr(username, '\0')+1;
+ if (password > client->saslbuf + client->saslbufLen)
goto saslerr;
+ res = password_check(username, password, getdatafile("users.txt"));
+ // we'll clear the whole buffer later, this is just in case username alloc fails
+ memset(password, 0, strlen(password));
+ } else {
+#ifdef HAS_TLS
+ if (client->cctx && tls_peer_cert_provided(client->cctx)) {
+ username = db_read_rhs(tls_peer_cert_hash(client->cctx), getdatafile("certfp.txt"));
+ res = -!username;
}
- p++;
- }
- p = q = (unsigned char *)client->saslbuf;
- for (size_t i = 0; i < client->saslbufLen; i += 4) {
- *q++ = p[0]<<2 | p[1]>>4;
- *q++ = p[1]<<4 | p[2]>>2;
- *q++ = p[2]<<6 | p[3];
- p += 4;
+#endif
}
- client->saslbufLen = q-(unsigned char *)client->saslbuf - parity;
- client->saslbuf[client->saslbufLen] = '\0';
- char *username = strchr(client->saslbuf, '\0')+1;
- if (username > client->saslbuf + client->saslbufLen)
- goto saslerr;
- char *password = strchr(username, '\0')+1;
- if (password > client->saslbuf + client->saslbufLen)
- goto saslerr;
- printf("hello %d %s:%s\n", parity, username, password);
- int res = password_check(username, password, getdatafile("users.txt"));
- // we'll clear the whole buffer later, this is just in case username alloc fails
- memset(password, 0, strlen(password));
if (res != -1) {
client->umode |= UMODE_REGISTERED;
free(client->username);