Fix: null pointer dereference in ftppr / smtpp

This commit is contained in:
Vladimir Dubrovin 2026-08-29 22:28:48 +03:00
parent f265ea0b52
commit 2b8845f65a
3 changed files with 42 additions and 10 deletions

View File

@ -64,6 +64,13 @@ void * ftpprchild(struct clientparam* param) {
}
else if (!strncasecmp((char *)buf, "PASS ", 5)){
/* The user name carries the server to log in to, and it arrives
with USER. Without it there is nothing to log in to, and what
follows would read the name and the host as if there were. */
if(!param->hostname || !param->extusername){
socksend(param, param->ctrlsock, (unsigned char *)"503 Login with USER first\r\n", 27, conf.timeouts[STRING_S]);
RETURN(805);
}
param->extpassword = (unsigned char *)strdup((char *)buf+5);
inbuf = BUFSIZE;
res = ftplogin(param, (char *)buf, &inbuf);

View File

@ -159,7 +159,10 @@ void * smtppchild(struct clientparam* param) {
i = de64(buf,username,255);
if(i < 1) {RETURN(664);}
username[i] = 0;
parseconnusername((char *)username, param, 0, 587);
/* The name has to carry the host to connect to, and the answer says
whether it did: without one there is nowhere to go, and what follows
reads the name as if there were. */
if(parseconnusername((char *)username, param, 0, 587)) {RETURN(669);}
socksend(param, param->clisock, (unsigned char *)"334 UGFzc3dvcmQ6\r\n", 18,conf.timeouts[STRING_S]);
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
if(i < 2) {RETURN(665);}
@ -184,7 +187,7 @@ void * smtppchild(struct clientparam* param) {
}
if(i < 3 || *username) {RETURN(668);}
username[i] = 0;
parseconnusername((char *)username+1, param, 0, 587);
if(parseconnusername((char *)username+1, param, 0, 587)) {RETURN(670);}
res = (int)strlen((char *)username+1) + 2;
if(res < i){
if(param->extpassword) free(param->extpassword);

View File

@ -22,6 +22,7 @@ configurations it needs, starts them, and states what it expects:
import base64
import http.client
import os
import random
import shutil
import socket
import ssl
@ -33,6 +34,11 @@ import threading
import time
# Ports handed out in this run: a service which has finished may still be
# in TIME_WAIT, and another case binding the same port would fail for it.
_PORTS_TAKEN = set()
class Response:
"""A reply, or the reason there wasn't one."""
@ -146,14 +152,30 @@ class Tester:
sock.close()
def free_port(self):
"""A port nothing is listening on. Closed again before it is used,
which is racy in principle and reliable enough in practice."""
s = socket.socket()
try:
s.bind(("127.0.0.1", 0))
return s.getsockname()[1]
finally:
s.close()
"""A port nothing is listening on, and nothing is likely to take.
Asking the system for an ephemeral port hands back one out of the
range it also draws outgoing connections from - 32768 up on Linux,
49152 up on Windows - so between the check here and the bind in the
service, a connection somewhere else in the suite can take it. That
shows up as a service which never listens, or a bind() error deep in
a case which has nothing to do with ports. Ports are taken from below
both ranges instead, and none is handed out twice in a run.
"""
for _ in range(200):
port = random.randint(10000, 19999)
if port in _PORTS_TAKEN:
continue
sock = socket.socket()
try:
sock.bind(("127.0.0.1", port))
except OSError:
continue
finally:
sock.close()
_PORTS_TAKEN.add(port)
return port
raise RuntimeError("no free port in the range the suite uses")
def write_config(self, name, config):
path = os.path.join(self.tmpdir, name + ".cfg")