commit 5a43139f7520c2168c39dc9792aa9ecef510a89a
parent f52d54ccc7383af9d029fb75efb91b7e20540c5f
Author: emmett1 <me@emmett1.my>
Date: Tue, 7 Apr 2026 08:08:37 +0800
fix sasl authenticate again
Diffstat:
| M | sirc.c | | | 59 | +++++++++++++++++++++++++++++++++++++++-------------------- |
1 file changed, 39 insertions(+), 20 deletions(-)
diff --git a/sirc.c b/sirc.c
@@ -196,6 +196,7 @@ typedef struct {
int reconnect_pending;
pthread_t reconnect_tid;
+ int sasl_auth_sent; /* guard: only send AUTHENTICATE once per session */
/* per-server event pipe */
int evpipe[2];
@@ -579,17 +580,18 @@ static const char b64tab[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static void base64_encode(const unsigned char *in, int inlen, char *out) {
- int i=0, j=0;
- while (i < inlen) {
- unsigned int a=i<inlen?(unsigned char)in[i++]:0;
- unsigned int b=i<inlen?(unsigned char)in[i++]:0;
- unsigned int c=i<inlen?(unsigned char)in[i++]:0;
- unsigned int n=(a<<16)|(b<<8)|c;
- out[j++]=b64tab[(n>>18)&63]; out[j++]=b64tab[(n>>12)&63];
- out[j++]=(i-2<=inlen)?b64tab[(n>>6)&63]:'=';
- out[j++]=(i-1<=inlen)?b64tab[n&63]:'=';
- }
- out[j]='\0';
+ int j = 0;
+ for (int i = 0; i < inlen; i += 3) {
+ unsigned int a = (unsigned char)in[i];
+ unsigned int b = (i+1 < inlen) ? (unsigned char)in[i+1] : 0;
+ unsigned int c = (i+2 < inlen) ? (unsigned char)in[i+2] : 0;
+ unsigned int n = (a << 16) | (b << 8) | c;
+ out[j++] = b64tab[(n >> 18) & 63];
+ out[j++] = b64tab[(n >> 12) & 63];
+ out[j++] = (i+1 < inlen) ? b64tab[(n >> 6) & 63] : '=';
+ out[j++] = (i+2 < inlen) ? b64tab[n & 63] : '=';
+ }
+ out[j] = '\0';
}
/* ── IRC line handler (net thread — uses si to tag every event) ────────────── */
@@ -604,18 +606,33 @@ static void handle_irc_line(int si, const char *raw) {
return;
}
- /* SASL */
+ /* SASL / CAP negotiation */
if (strcmp(m.cmd,"CAP")==0) {
char sub[16]="";
if (m.nparams>=2) str_upper(sub, m.params[1], sizeof(sub));
- if (strcmp(sub,"ACK")==0) {
- /* trail or last param may contain "sasl" */
- const char *caps = m.trail[0] ? m.trail : m.params[m.nparams-1];
+ else if (m.nparams>=1) str_upper(sub, m.params[0], sizeof(sub));
+
+ /* log all CAP lines to status for visibility */
+ char capdbg[MAX_LINE];
+ snprintf(capdbg,sizeof(capdbg),"[CAP] %s",raw);
+ ev_simple(EV_STATUS, si, NULL, NULL, capdbg);
+
+ if (strcmp(sub,"LS")==0) {
+ /* server advertising capabilities -- request sasl */
+ srv_send_raw(si, "CAP REQ :sasl");
+ } else if (strcmp(sub,"ACK")==0) {
+ const char *caps = m.trail[0] ? m.trail : (m.nparams>0?m.params[m.nparams-1]:"");
if (strstr(caps,"sasl")) {
- srv_send_raw(si, "AUTHENTICATE PLAIN");
+ if (!s->sasl_auth_sent) {
+ s->sasl_auth_sent = 1;
+ srv_send_raw(si, "AUTHENTICATE PLAIN");
+ }
+ } else {
+ srv_send_raw(si, "CAP END");
}
} else if (strcmp(sub,"NAK")==0) {
- ev_simple(EV_ERROR, si, NULL, NULL, "Server rejected SASL CAP.");
+ ev_simple(EV_ERROR, si, NULL, NULL, "Server rejected SASL CAP -- connecting without SASL.");
+ srv_send_raw(si, "CAP END");
srv_sendf(si, "NICK %s", s->nick);
srv_sendf(si, "USER %s 0 * :sirc", s->nick);
}
@@ -991,9 +1008,11 @@ static void *net_thread(void *arg) {
}
int sasl_pending=(s->sasl_user[0]&&s->sasl_pass[0])?1:0;
- if (sasl_pending)
- srv_send_raw(si,"CAP REQ :sasl");
- else {
+ s->sasl_auth_sent = 0;
+ if (sasl_pending) {
+ /* CAP LS 302: proper negotiation, handler sends CAP REQ :sasl on LS reply */
+ srv_send_raw(si,"CAP LS 302");
+ } else {
srv_sendf(si,"NICK %s",s->nick);
srv_sendf(si,"USER %s 0 * :sirc",s->nick);
}