Compare commits

..

2 Commits

Author SHA1 Message Date
Vladimir Dubrovin
ed5103d176 Optimize sockgetchar functions
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Has been cancelled
2026-07-24 15:04:27 +03:00
Nirmal Khanal
75dedeff28 Fix: short CL cleartext passwords failed authentication
strongauth() compared short CL passwords over pwl_table.recsize-1 bytes,
reading past the client password buffer (strdup of pwlen+1) and rejecting
valid passwords whenever trailing heap bytes were non-zero. Zero-pad the
provided password to the record width and compare in constant time, like
the long-password BLAKE2 path.

Fixes #1254
2026-07-24 15:00:00 +03:00
2 changed files with 36 additions and 10 deletions

View File

@ -247,7 +247,9 @@ int strongauth(struct clientparam * param){
int pwlen = strlen((char *)param->password);
if(pwlen > 255) pwlen = 255;
if((unsigned)pwlen < pwl_table.recsize) {
if(strlen(pass + 1) == strlen((char *)param->password) && !ctmemcmp(pass + 1, param->password, pwl_table.recsize - 1)) return 0;
memset(buf, 0, pwl_table.recsize - 1);
memcpy(buf, param->password, pwlen);
if(!ctmemcmp(pass + 1, buf, pwl_table.recsize - 1)) return 0;
} else {
mdh_ctx *bctx;
unsigned hashsz;

View File

@ -16,15 +16,16 @@ int socksend(struct clientparam *param, SOCKET sock, unsigned char * buf, int bu
fds.events = POLLOUT;
do {
if(conf.timetoexit) return 0;
/* try to send first; poll only when the socket would block */
res = param?param->srv->so._send(param->sostate, sock, (char *)buf + sent, bufsize - sent, 0) : so._send(so.state, sock, (char *)buf + sent, bufsize - sent, 0);
if(res > 0) {
sent += res;
continue;
}
if(res < 0 && errno != EAGAIN && errno != EINTR) break;
res = param?param->srv->so._poll(param->sostate, &fds, 1, to*1000):so._poll(so.state, &fds, 1, to*1000);
if(res < 0 && (errno == EAGAIN || errno == EINTR)) continue;
if(res < 1) break;
res = param?param->srv->so._send(param->sostate, sock, (char *)buf + sent, bufsize - sent, 0) : so._send(so.state, sock, (char *)buf + sent, bufsize - sent, 0);
if(res < 0) {
if(errno == EAGAIN || errno == EINTR) continue;
break;
}
sent += res;
} while (sent < bufsize);
return sent;
}
@ -158,10 +159,33 @@ int sockgetlinebuf(struct clientparam * param, DIRECTION which, unsigned char *
int c;
int i=0;
while(i < bufsize && (c = (which)?sockgetcharsrv(param, to, 0):sockgetcharcli(param, to, 0)) != EOF){
for(;;){
unsigned char *base = which? param->srvbuf : param->clibuf;
unsigned *offp = which? &param->srvoffset : &param->clioffset;
unsigned *inp = which? &param->srvinbuf : &param->cliinbuf;
/* drain already-buffered bytes in bulk instead of one call per byte */
if(base && *offp < *inp && i < bufsize){
int avail = (int)(*inp - *offp);
int n = (bufsize - i < avail)? bufsize - i : avail;
if(delim != EOF){
unsigned char *d = (unsigned char *)memchr(base + *offp, delim, n);
if(d) n = (int)(d - (base + *offp)) + 1;
memcpy(buf + i, base + *offp, n);
i += n; *offp += n;
if(d || i >= bufsize) return i;
}
else {
memcpy(buf + i, base + *offp, n);
i += n; *offp += n;
if(i >= bufsize) return i;
}
}
if(i >= bufsize) return i;
/* buffer empty: one call forces a refill (with poll + accounting), then bulk-drain the rest */
if((c = which? sockgetcharsrv(param, to, 0) : sockgetcharcli(param, to, 0)) == EOF) return i;
buf[i++] = c;
if(delim != EOF && c == delim) break;
if((delim != EOF && c == delim) || i >= bufsize) return i;
}
return i;
}