mirror of
https://github.com/rejetto/hfs2.git
synced 2025-12-19 10:03:56 +01:00
fix: possible DoS, as reported by John Page (aka hyp3rlinx) ApparitionSec (CVE-2020-13432)
This commit is contained in:
parent
16744d7c6c
commit
a3056ccfd4
@ -39,7 +39,7 @@ COMMENT with the ones above you can disable some features of the template. They
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="wrapper">
|
<div id="wrapper">
|
||||||
<!--{.comment|--><h1 style='margin-bottom:100em'>WARNING: this template is only to be used with HFS 2.3 (and macros enabled)</h1> <!--.} -->
|
<!--{.comment|--><h1 style='margin-bottom:100em'>WARNING: this template is only to be used with HFS 2.4 (and macros enabled)</h1> <!--.} -->
|
||||||
{.$menu panel.}
|
{.$menu panel.}
|
||||||
{.$folder panel.}
|
{.$folder panel.}
|
||||||
{.$list panel.}
|
{.$list panel.}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ Copyright (C) 2002-2014 Massimo Melina (www.rejetto.com)
|
|||||||
HTTP Server Lib
|
HTTP Server Lib
|
||||||
|
|
||||||
==== TO DO
|
==== TO DO
|
||||||
|
* https
|
||||||
* upload bandwidth control (can it be done without multi-threading?)
|
* upload bandwidth control (can it be done without multi-threading?)
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -292,7 +293,7 @@ const
|
|||||||
MINIMUM_CHUNK_SIZE = 2*1024;
|
MINIMUM_CHUNK_SIZE = 2*1024;
|
||||||
MAXIMUM_CHUNK_SIZE = 1024*1024;
|
MAXIMUM_CHUNK_SIZE = 1024*1024;
|
||||||
HRM2CODE: array [ThttpReplyMode] of integer = (200, 200, 403, 401, 404, 400,
|
HRM2CODE: array [ThttpReplyMode] of integer = (200, 200, 403, 401, 404, 400,
|
||||||
500, 0, 0, 405, 302, 503, 413, 301, 304 );
|
500, 0, 0, 405, 302, 429, 413, 301, 304 );
|
||||||
METHOD2STR: array [ThttpMethod] of ansistring = ('UNK','GET','POST','HEAD');
|
METHOD2STR: array [ThttpMethod] of ansistring = ('UNK','GET','POST','HEAD');
|
||||||
HRM2STR: array [ThttpReplyMode] of ansistring = ('Head+Body', 'Head only', 'Deny',
|
HRM2STR: array [ThttpReplyMode] of ansistring = ('Head+Body', 'Head only', 'Deny',
|
||||||
'Unauthorized', 'Not found', 'Bad request', 'Internal error', 'Close',
|
'Unauthorized', 'Not found', 'Bad request', 'Internal error', 'Close',
|
||||||
@ -352,7 +353,7 @@ const
|
|||||||
'',
|
'',
|
||||||
'405 - Method not allowed',
|
'405 - Method not allowed',
|
||||||
'<html><head><meta http-equiv="refresh" content="url=%url%" /></head><body onload=''window.location="%url%"''>302 - <a href="%url%">Redirection to %url%</a></body></html>',
|
'<html><head><meta http-equiv="refresh" content="url=%url%" /></head><body onload=''window.location="%url%"''>302 - <a href="%url%">Redirection to %url%</a></body></html>',
|
||||||
'503 - Server is overloaded, retry later',
|
'429 - Server is overloaded, retry later',
|
||||||
'413 - The request has exceeded the max length allowed',
|
'413 - The request has exceeded the max length allowed',
|
||||||
'301 - Moved permanently to <a href="%url%">%url%</a>',
|
'301 - Moved permanently to <a href="%url%">%url%</a>',
|
||||||
'' // RFC2616: The 304 response MUST NOT contain a message-body
|
'' // RFC2616: The 304 response MUST NOT contain a message-body
|
||||||
@ -875,7 +876,6 @@ end; // timerEvent
|
|||||||
procedure ThttpSrv.notify(ev:ThttpEvent; conn:ThttpConn);
|
procedure ThttpSrv.notify(ev:ThttpEvent; conn:ThttpConn);
|
||||||
begin
|
begin
|
||||||
if not assigned(onEvent) then exit;
|
if not assigned(onEvent) then exit;
|
||||||
//if assigned(sock) then sock.pause();
|
|
||||||
if assigned(conn) then
|
if assigned(conn) then
|
||||||
begin
|
begin
|
||||||
inc(conn.lockCount);
|
inc(conn.lockCount);
|
||||||
|
|||||||
63
main.pas
63
main.pas
@ -36,7 +36,7 @@ uses
|
|||||||
HSlib, traylib, monoLib, progFrmLib, classesLib;
|
HSlib, traylib, monoLib, progFrmLib, classesLib;
|
||||||
|
|
||||||
const
|
const
|
||||||
VERSION = '2.4.0 beta10';
|
VERSION = '2.4.0 RC1';
|
||||||
VERSION_BUILD = '312';
|
VERSION_BUILD = '312';
|
||||||
VERSION_STABLE = {$IFDEF STABLE } TRUE {$ELSE} FALSE {$ENDIF};
|
VERSION_STABLE = {$IFDEF STABLE } TRUE {$ELSE} FALSE {$ENDIF};
|
||||||
CURRENT_VFS_FORMAT :integer = 1;
|
CURRENT_VFS_FORMAT :integer = 1;
|
||||||
@ -3458,7 +3458,6 @@ end; // shouldRecur
|
|||||||
|
|
||||||
function Tmainfrm.getFolderPage(folder:Tfile; cd:TconnData; otpl:Tobject):string;
|
function Tmainfrm.getFolderPage(folder:Tfile; cd:TconnData; otpl:Tobject):string;
|
||||||
// we pass the Tpl parameter as Tobject because symbol Ttpl is not defined yet
|
// we pass the Tpl parameter as Tobject because symbol Ttpl is not defined yet
|
||||||
|
|
||||||
var
|
var
|
||||||
baseurl, list, fileTpl, folderTpl, linkTpl: string;
|
baseurl, list, fileTpl, folderTpl, linkTpl: string;
|
||||||
table: TStringDynArray;
|
table: TStringDynArray;
|
||||||
@ -3606,6 +3605,39 @@ var
|
|||||||
fast.append(s);
|
fast.append(s);
|
||||||
end; // handleItem
|
end; // handleItem
|
||||||
|
|
||||||
|
const ip2availability: Tdictionary<string,Tdatetime> = NIL;
|
||||||
|
const folderConcurrents: integer = 0;
|
||||||
|
|
||||||
|
procedure updateAvailability();
|
||||||
|
var
|
||||||
|
pair: Tpair<string,Tdatetime>;
|
||||||
|
t: Tdatetime;
|
||||||
|
begin
|
||||||
|
dec(folderConcurrents);
|
||||||
|
t:=now();
|
||||||
|
ip2availability[cd.address]:=t+1/SECONDS;
|
||||||
|
// purge leftovers
|
||||||
|
for pair in ip2availability do
|
||||||
|
if pair.Value < t then
|
||||||
|
ip2availability.Remove(pair.Key);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function available():boolean;
|
||||||
|
begin
|
||||||
|
if ip2availability = NIL then
|
||||||
|
ip2availability:=Tdictionary<string,Tdatetime>.create();
|
||||||
|
try
|
||||||
|
if ip2availability[cd.address] > now() then // this specific address has to wait?
|
||||||
|
exit(FALSE);
|
||||||
|
except
|
||||||
|
end;
|
||||||
|
if folderConcurrents >= 3 then // max number of concurrent folder loading, others are postponed
|
||||||
|
exit(FALSE);
|
||||||
|
inc(folderConcurrents);
|
||||||
|
ip2availability.AddOrSetValue(cd.address, now()+1);
|
||||||
|
result:=TRUE;
|
||||||
|
end; // available
|
||||||
|
|
||||||
var
|
var
|
||||||
i, n: integer;
|
i, n: integer;
|
||||||
f: Tfile;
|
f: Tfile;
|
||||||
@ -3613,6 +3645,12 @@ begin
|
|||||||
result:='';
|
result:='';
|
||||||
if (folder = NIL) or not folder.isFolder() then exit;
|
if (folder = NIL) or not folder.isFolder() then exit;
|
||||||
|
|
||||||
|
if not available() then
|
||||||
|
begin
|
||||||
|
cd.conn.reply.mode:=HRM_OVERLOAD;
|
||||||
|
cd.conn.addHeader('Refresh: '+intToStr(1+random(2))); // random for less collisions
|
||||||
|
exit('Please wait, server busy');
|
||||||
|
end;
|
||||||
if macrosLogChk.checked and not appendmacroslog1.checked then
|
if macrosLogChk.checked and not appendmacroslog1.checked then
|
||||||
resetLog();
|
resetLog();
|
||||||
diffTpl:=Ttpl.create();
|
diffTpl:=Ttpl.create();
|
||||||
@ -3735,6 +3773,7 @@ try
|
|||||||
result:=replaceText(result, '%build-time%',
|
result:=replaceText(result, '%build-time%',
|
||||||
floatToStrF((now()-buildTime)*SECONDS, ffFixed, 7,3) );
|
floatToStrF((now()-buildTime)*SECONDS, ffFixed, 7,3) );
|
||||||
finally
|
finally
|
||||||
|
updateAvailability();
|
||||||
folder.unlock();
|
folder.unlock();
|
||||||
diffTpl.free;
|
diffTpl.free;
|
||||||
end;
|
end;
|
||||||
@ -5184,6 +5223,7 @@ var
|
|||||||
|
|
||||||
if conn.reply.contentType = '' then
|
if conn.reply.contentType = '' then
|
||||||
conn.reply.contentType:=ansistring(if_(trim(getTill('<', s))='', 'text/html', 'text/plain'))+'; charset=utf-8';
|
conn.reply.contentType:=ansistring(if_(trim(getTill('<', s))='', 'text/html', 'text/plain'))+'; charset=utf-8';
|
||||||
|
if conn.reply.mode = HRM_IGNORE then
|
||||||
conn.reply.mode:=HRM_REPLY;
|
conn.reply.mode:=HRM_REPLY;
|
||||||
conn.reply.bodyMode:=RBM_STRING;
|
conn.reply.bodyMode:=RBM_STRING;
|
||||||
conn.reply.body:=UTF8encode(s);
|
conn.reply.body:=UTF8encode(s);
|
||||||
@ -5427,6 +5467,12 @@ var
|
|||||||
if conn.reply.mode = HRM_REDIRECT then
|
if conn.reply.mode = HRM_REDIRECT then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
|
lastActivityTime:=now();
|
||||||
|
if conn.request.method = HM_HEAD then
|
||||||
|
conn.reply.mode:=HRM_REPLY_HEADER
|
||||||
|
else
|
||||||
|
conn.reply.mode:=HRM_REPLY;
|
||||||
|
|
||||||
if ansiStartsStr('/~img', url) then
|
if ansiStartsStr('/~img', url) then
|
||||||
begin
|
begin
|
||||||
if not sendPic(data) then
|
if not sendPic(data) then
|
||||||
@ -5579,6 +5625,8 @@ var
|
|||||||
if ansiStartsStr('~files.lst', urlCmd)
|
if ansiStartsStr('~files.lst', urlCmd)
|
||||||
or f.isFolder() and (data.urlvars.values['tpl'] = 'list') then
|
or f.isFolder() and (data.urlvars.values['tpl'] = 'list') then
|
||||||
begin
|
begin
|
||||||
|
if conn.reply.mode=HRM_REPLY_HEADER then
|
||||||
|
exit;
|
||||||
// load from external file
|
// load from external file
|
||||||
s:=cfgPath+FILELIST_TPL_FILE;
|
s:=cfgPath+FILELIST_TPL_FILE;
|
||||||
if newMtime(s, lastFilelistTpl) then
|
if newMtime(s, lastFilelistTpl) then
|
||||||
@ -5605,19 +5653,12 @@ var
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
case conn.request.method of
|
|
||||||
HM_GET, HM_POST:
|
|
||||||
begin
|
|
||||||
conn.reply.mode:=HRM_REPLY;
|
|
||||||
lastActivityTime:=now();
|
|
||||||
end;
|
|
||||||
HM_HEAD: conn.reply.mode:=HRM_REPLY_HEADER;
|
|
||||||
end;
|
|
||||||
|
|
||||||
data.lastFile:=f; // auto-freeing
|
data.lastFile:=f; // auto-freeing
|
||||||
|
|
||||||
if f.isFolder() then
|
if f.isFolder() then
|
||||||
begin
|
begin
|
||||||
|
if conn.reply.mode=HRM_REPLY_HEADER then
|
||||||
|
exit;
|
||||||
deletion();
|
deletion();
|
||||||
if sessionRedirect() then
|
if sessionRedirect() then
|
||||||
exit;
|
exit;
|
||||||
|
|||||||
33
utillib.pas
33
utillib.pas
@ -166,7 +166,7 @@ function replaceString(var ss:TStringDynArray; old, new:string):integer;
|
|||||||
function popString(var ss:TstringDynArray):string;
|
function popString(var ss:TstringDynArray):string;
|
||||||
procedure insertString(s:string; idx:integer; var ss:TStringDynArray);
|
procedure insertString(s:string; idx:integer; var ss:TStringDynArray);
|
||||||
function removeString(var a:TStringDynArray; idx:integer; l:integer=1):boolean; overload;
|
function removeString(var a:TStringDynArray; idx:integer; l:integer=1):boolean; overload;
|
||||||
function removeString(find:string; var a:TStringDynArray):boolean; overload;
|
function removeString(s:string; var a:TStringDynArray; onlyOnce:boolean=TRUE; ci:boolean=TRUE; keepOrder:boolean=TRUE):boolean; overload;
|
||||||
procedure removeStrings(find:string; var a:TStringDynArray);
|
procedure removeStrings(find:string; var a:TStringDynArray);
|
||||||
procedure toggleString(s:string; var ss:TStringDynArray);
|
procedure toggleString(s:string; var ss:TStringDynArray);
|
||||||
function onlyString(s:string; ss:TStringDynArray):boolean;
|
function onlyString(s:string; ss:TStringDynArray):boolean;
|
||||||
@ -669,10 +669,6 @@ begin
|
|||||||
until false;
|
until false;
|
||||||
end; // removeStrings
|
end; // removeStrings
|
||||||
|
|
||||||
// remove first instance of the specified string
|
|
||||||
function removeString(find:string; var a:TStringDynArray):boolean;
|
|
||||||
begin result:=removeString(a, idxOf(find,a)) end;
|
|
||||||
|
|
||||||
function removeArray(var src:TstringDynArray; toRemove:array of string):integer;
|
function removeArray(var src:TstringDynArray; toRemove:array of string):integer;
|
||||||
var
|
var
|
||||||
i, l, ofs: integer;
|
i, l, ofs: integer;
|
||||||
@ -746,6 +742,33 @@ while idx+l < length(a) do
|
|||||||
setLength(a, idx);
|
setLength(a, idx);
|
||||||
end; // removestring
|
end; // removestring
|
||||||
|
|
||||||
|
function removeString(s:string; var a:TStringDynArray; onlyOnce:boolean=TRUE; ci:boolean=TRUE; keepOrder:boolean=TRUE):boolean; overload;
|
||||||
|
var i, lessen:integer;
|
||||||
|
begin
|
||||||
|
result:=FALSE;
|
||||||
|
lessen:=0;
|
||||||
|
try
|
||||||
|
for i:=length(a)-1 to 0 do
|
||||||
|
if ci and sameText(a[i], s)
|
||||||
|
or not ci and (a[i]=s) then
|
||||||
|
begin
|
||||||
|
result:=TRUE;
|
||||||
|
if keepOrder then
|
||||||
|
removeString(a, i)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
inc(lessen);
|
||||||
|
a[i]:=a[length(a)-lessen];
|
||||||
|
end;
|
||||||
|
if onlyOnce then
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
if lessen > 0 then
|
||||||
|
setLength(a, length(a)-lessen);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function dotted(i:int64):string;
|
function dotted(i:int64):string;
|
||||||
begin
|
begin
|
||||||
result:=intToStr(i);
|
result:=intToStr(i);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user