tweaked download rules to match mvdsv, by adding an allow_download_other cvar.

added log_enable_rcon (and enabled it by default), for feature parity with mvdsv. invalid requests, valid requests, and redirected prints are all logged.
tweaked server-side download code to not bug out with downloads larger than 2gb.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4697 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-06-24 03:02:32 +00:00
parent 1908310788
commit b1e3060648
12 changed files with 163 additions and 77 deletions

View file

@ -26,6 +26,7 @@ cvar_t cmd_maxbuffersize = SCVAR("cmd_maxbuffersize", "65536");
cvar_t dpcompat_set = SCVAR("dpcompat_set", "0"); cvar_t dpcompat_set = SCVAR("dpcompat_set", "0");
int Cmd_ExecLevel; int Cmd_ExecLevel;
qboolean cmd_didwait; qboolean cmd_didwait;
qboolean cmd_blockwait;
void Cmd_ForwardToServer (void); void Cmd_ForwardToServer (void);
@ -161,6 +162,9 @@ bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
*/ */
void Cmd_Wait_f (void) void Cmd_Wait_f (void)
{ {
if (cmd_blockwait)
return;
#ifndef CLIENTONLY #ifndef CLIENTONLY
if (cmd_didwait && sv.state) if (cmd_didwait && sv.state)
Con_DPrintf("waits without server frames\n"); Con_DPrintf("waits without server frames\n");

View file

@ -55,6 +55,7 @@ void Cbuf_Execute (void);
// Normally called once per frame, but may be explicitly invoked. // Normally called once per frame, but may be explicitly invoked.
// Do not call inside a command function! // Do not call inside a command function!
extern qboolean cmd_blockwait;
void Cbuf_ExecuteLevel(int level); void Cbuf_ExecuteLevel(int level);
//executes only a single cbuf level. can be used to restrict cbuf execution to some 'safe' set of commands, so there are no surprise 'map' commands. //executes only a single cbuf level. can be used to restrict cbuf execution to some 'safe' set of commands, so there are no surprise 'map' commands.
//will not magically make all commands safe to exec, but will prevent user commands slipping in too. //will not magically make all commands safe to exec, but will prevent user commands slipping in too.

View file

@ -570,6 +570,7 @@ void PO_Close(struct po_s *po);
typedef enum { typedef enum {
LOG_CONSOLE, LOG_CONSOLE,
LOG_PLAYER, LOG_PLAYER,
LOG_RCON,
LOG_TYPES LOG_TYPES
} logtype_t; } logtype_t;
void Log_Dir_Callback (struct cvar_s *var, char *oldvalue); void Log_Dir_Callback (struct cvar_s *var, char *oldvalue);

View file

@ -1051,7 +1051,7 @@ qboolean FS_GetPackageDownloadable(const char *package)
for (search = com_searchpaths ; search ; search = search->next) for (search = com_searchpaths ; search ; search = search->next)
{ {
if (!strcmp(package, search->purepath)) if (!Q_strcasecmp(package, search->purepath))
return !(search->flags & SPF_COPYPROTECTED); return !(search->flags & SPF_COPYPROTECTED);
} }
return false; return false;
@ -3944,6 +3944,10 @@ void FS_ChangeGame_f(void)
int i; int i;
char *arg = Cmd_Argv(1); char *arg = Cmd_Argv(1);
//don't execute this if we're executing rcon commands, as this can change game directories.
if (cmd_blockwait)
return;
if (!*arg) if (!*arg)
{ {
Con_Printf("Valid games are:\n"); Con_Printf("Valid games are:\n");

View file

@ -5691,6 +5691,10 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end,
if (0) if (0)
{ //treat *ALL* tests against the actual geometry instead of using any brushes. { //treat *ALL* tests against the actual geometry instead of using any brushes.
//also ignores the bsp etc. not fast. testing only. //also ignores the bsp etc. not fast. testing only.
trace_ispoint = trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0
&& trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0;
for (i = 0; i < mod->numsurfaces; i++) for (i = 0; i < mod->numsurfaces; i++)
{ {
CM_ClipBoxToMesh(trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, mod->surfaces[i].mesh); CM_ClipBoxToMesh(trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, mod->surfaces[i].mesh);
@ -5699,6 +5703,9 @@ static trace_t CM_BoxTrace (model_t *mod, vec3_t start, vec3_t end,
else else
if (0) if (0)
{ {
trace_ispoint = trace_mins[0] == 0 && trace_mins[1] == 0 && trace_mins[2] == 0
&& trace_maxs[0] == 0 && trace_maxs[1] == 0 && trace_maxs[2] == 0;
for (i = 0; i < mod->numleafs; i++) for (i = 0; i < mod->numleafs; i++)
CM_TraceToLeaf(&mod->leafs[i]); CM_TraceToLeaf(&mod->leafs[i]);
} }

View file

@ -9,9 +9,12 @@ void Log_Name_Callback (struct cvar_s *var, char *oldvalue);
// cvars // cvars
#define CONLOGGROUP "Console logging" #define CONLOGGROUP "Console logging"
cvar_t log_enable[LOG_TYPES] = { CVARF("log_enable", "0", CVAR_NOTFROMSERVER), cvar_t log_enable[LOG_TYPES] = { CVARF("log_enable", "0", CVAR_NOTFROMSERVER),
CVARF("log_enable_players", "0", CVAR_NOTFROMSERVER)}; CVARF("log_enable_players", "0", CVAR_NOTFROMSERVER),
CVARF("log_enable_rcon", "1", CVAR_NOTFROMSERVER)
};
cvar_t log_name[LOG_TYPES] = { CVARFC("log_name", "", CVAR_NOTFROMSERVER, Log_Name_Callback), cvar_t log_name[LOG_TYPES] = { CVARFC("log_name", "", CVAR_NOTFROMSERVER, Log_Name_Callback),
CVARFC("log_name_players", "", CVAR_NOTFROMSERVER, Log_Name_Callback)}; CVARFC("log_name_players", "", CVAR_NOTFROMSERVER, Log_Name_Callback),
CVARFC("log_name_rcon", "", CVAR_NOTFROMSERVER, Log_Name_Callback)};
cvar_t log_dir = CVARFC("log_dir", "", CVAR_NOTFROMSERVER, Log_Dir_Callback); cvar_t log_dir = CVARFC("log_dir", "", CVAR_NOTFROMSERVER, Log_Dir_Callback);
cvar_t log_readable = CVARFD("log_readable", "7", CVAR_NOTFROMSERVER, "Bitfield describing what to convert/strip. If 0, exact byte representation will be used.\n&1: Dequakify text.\n&2: Strip special markup.\n&4: Strip ansi control codes."); cvar_t log_readable = CVARFD("log_readable", "7", CVAR_NOTFROMSERVER, "Bitfield describing what to convert/strip. If 0, exact byte representation will be used.\n&1: Dequakify text.\n&2: Strip special markup.\n&4: Strip ansi control codes.");
cvar_t log_developer = CVARF("log_developer", "0", CVAR_NOTFROMSERVER); cvar_t log_developer = CVARF("log_developer", "0", CVAR_NOTFROMSERVER);
@ -88,6 +91,9 @@ void Log_String (logtype_t lognum, char *s)
case LOG_PLAYER: case LOG_PLAYER:
f = "players"; f = "players";
break; break;
case LOG_RCON:
f = "rcon";
break;
default: default:
break; break;
} }

View file

@ -19,8 +19,11 @@
#define FTE_WORDSIZE 64 #define FTE_WORDSIZE 64
#define quintptr_t unsigned qintptr_t #define quintptr_t unsigned qintptr_t
#elif defined(_WIN32) #elif defined(_WIN32)
typedef __int32 qintptr_t; //add __w64 if you need msvc to shut up about unsafe type conversions #ifndef _MSC_VER
typedef unsigned __int32 quintptr_t; #define __w64
#endif
typedef __int32 __w64 qintptr_t; //add __w64 if you need msvc to shut up about unsafe type conversions
typedef unsigned __int32 __w64 quintptr_t;
// #define qintptr_t __int32 // #define qintptr_t __int32
// #define quintptr_t unsigned qintptr_t // #define quintptr_t unsigned qintptr_t
#define FTE_WORDSIZE 32 #define FTE_WORDSIZE 32

View file

@ -8837,6 +8837,14 @@
<File <File
RelativePath="..\client\in_generic.c" RelativePath="..\client\in_generic.c"
> >
<FileConfiguration
Name="Release Dedicated Server|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration <FileConfiguration
Name="Debug Dedicated Server|Win32" Name="Debug Dedicated Server|Win32"
ExcludedFromBuild="true" ExcludedFromBuild="true"
@ -11183,6 +11191,14 @@
<File <File
RelativePath="..\client\pr_clcmd.c" RelativePath="..\client\pr_clcmd.c"
> >
<FileConfiguration
Name="Release Dedicated Server|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration <FileConfiguration
Name="Debug Dedicated Server|Win32" Name="Debug Dedicated Server|Win32"
ExcludedFromBuild="true" ExcludedFromBuild="true"
@ -16807,6 +16823,7 @@
</FileConfiguration> </FileConfiguration>
<FileConfiguration <FileConfiguration
Name="Release Dedicated Server|Win32" Name="Release Dedicated Server|Win32"
ExcludedFromBuild="true"
> >
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
@ -21320,7 +21337,6 @@
</FileConfiguration> </FileConfiguration>
<FileConfiguration <FileConfiguration
Name="Release Dedicated Server|Win32" Name="Release Dedicated Server|Win32"
ExcludedFromBuild="true"
> >
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"

View file

@ -457,11 +457,11 @@ typedef struct client_s
char downloadfn[MAX_QPATH]; char downloadfn[MAX_QPATH];
vfsfile_t *download; // file being downloaded vfsfile_t *download; // file being downloaded
unsigned int downloadsize; // total bytes qofs_t downloadsize; // total bytes
unsigned int downloadcount; // bytes sent qofs_t downloadcount; // bytes sent
int downloadacked; //DP-specific qofs_t downloadacked; //DP-specific
int downloadstarted; //DP-specific qofs_t downloadstarted; //DP-specific
int spec_track; // entnum of player tracking int spec_track; // entnum of player tracking
@ -1161,7 +1161,7 @@ void SVM_Think(int port);
// //
// svonly.c // svonly.c
// //
typedef enum {RD_NONE, RD_CLIENT, RD_PACKET, RD_OBLIVION, RD_MASTER} redirect_t; //oblivion is provided so people can read the output before the buffer is wiped. typedef enum {RD_NONE, RD_CLIENT, RD_PACKET, RD_PACKET_LOG, RD_OBLIVION, RD_MASTER} redirect_t; //oblivion is provided so people can read the output before the buffer is wiped.
void SV_BeginRedirect (redirect_t rd, int lang); void SV_BeginRedirect (redirect_t rd, int lang);
void SV_EndRedirect (void); void SV_EndRedirect (void);

View file

@ -124,6 +124,7 @@ cvar_t allow_download_refpackages = CVARD("allow_download_refpackages", "1", "If
cvar_t allow_download_wads = CVAR("allow_download_wads", "1"); cvar_t allow_download_wads = CVAR("allow_download_wads", "1");
cvar_t allow_download_configs = CVAR("allow_download_configs", "0"); cvar_t allow_download_configs = CVAR("allow_download_configs", "0");
cvar_t allow_download_copyrighted = CVAR("allow_download_copyrighted", "0"); cvar_t allow_download_copyrighted = CVAR("allow_download_copyrighted", "0");
cvar_t allow_download_other = CVAR("allow_download_other", "0");
cvar_t sv_serverip = CVARD("sv_serverip", "", "Set this cvar to the server's public ip address if the server is behind a firewall and cannot detect its own public address. Providing a port is required if the firewall/nat remaps it, but is otherwise optional."); cvar_t sv_serverip = CVARD("sv_serverip", "", "Set this cvar to the server's public ip address if the server is behind a firewall and cannot detect its own public address. Providing a port is required if the firewall/nat remaps it, but is otherwise optional.");
cvar_t sv_public = CVAR("sv_public", "0"); cvar_t sv_public = CVAR("sv_public", "0");
@ -3697,6 +3698,7 @@ void SVC_RemoteCommand (void)
if (!Rcon_Validate ()) if (!Rcon_Validate ())
{ {
/*
#ifdef SVRANKING #ifdef SVRANKING
if (cmd_allowaccess.value) //try and find a username, match the numeric password if (cmd_allowaccess.value) //try and find a username, match the numeric password
{ {
@ -3727,7 +3729,7 @@ void SVC_RemoteCommand (void)
Con_TPrintf ("Rcon from %s:\n%s\n" Con_TPrintf ("Rcon from %s:\n%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4); , NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4);
SV_BeginRedirect (RD_PACKET, svs.language); SV_BeginRedirect (RD_PACKET_LOG, svs.language);
remaining[0] = 0; remaining[0] = 0;
@ -3753,22 +3755,32 @@ void SVC_RemoteCommand (void)
} }
} }
#endif #endif
*/
Con_TPrintf ("Bad rcon from %s:\n%s\n" Log_String(LOG_RCON, va("Bad rcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4));
Con_TPrintf ("Bad rcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4); , NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4);
SV_BeginRedirect (RD_PACKET, svs.language); SV_BeginRedirect (RD_PACKET, svs.language);
Con_TPrintf ("Bad rcon_password.\n"); Con_TPrintf ("Bad rcon_password. Passwords might be logged. Be careful.\n");
} }
else else
{ {
//make sure stuff is flushed
cmd_blockwait = true;
Cbuf_ExecuteLevel(rcon_level.ival);
cmd_blockwait = false;
Con_TPrintf ("Rcon from %s:\n%s\n" Log_String(LOG_RCON, va("\n\nRcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4));
Con_TPrintf ("Rcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4); , NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4);
SV_BeginRedirect (RD_PACKET, svs.language); SV_BeginRedirect (RD_PACKET_LOG, svs.language);
remaining[0] = 0; remaining[0] = 0;
@ -3778,16 +3790,19 @@ void SVC_RemoteCommand (void)
{ {
Con_TPrintf("Rcon was too long\n"); Con_TPrintf("Rcon was too long\n");
SV_EndRedirect (); SV_EndRedirect ();
Con_TPrintf ("Rcon from %s:\n%s\n" Con_TPrintf ("Rcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), "Was too long - possible buffer overflow attempt"); , NET_AdrToString (adr, sizeof(adr), &net_from), "Was too long - possible buffer overflow attempt");
return; return;
} }
strcat (remaining, Cmd_Argv(i) ); Q_strncatz(remaining, Cmd_Argv(i), sizeof(remaining));
strcat (remaining, " "); Q_strncatz(remaining, " ", sizeof(remaining));
} }
Cmd_ExecuteString (remaining, rcon_level.ival); //make sure the wait command can't be used to fuck up our logs.
cmd_blockwait = true;
Cbuf_AddText(remaining, rcon_level.ival);
Cbuf_ExecuteLevel(rcon_level.ival);
cmd_blockwait = false;
} }
SV_EndRedirect (); SV_EndRedirect ();
@ -5278,6 +5293,7 @@ void SV_InitLocal (void)
Cvar_Register (&allow_download_wads, cvargroup_serverpermissions); Cvar_Register (&allow_download_wads, cvargroup_serverpermissions);
Cvar_Register (&allow_download_root, cvargroup_serverpermissions); Cvar_Register (&allow_download_root, cvargroup_serverpermissions);
Cvar_Register (&allow_download_copyrighted, cvargroup_serverpermissions); Cvar_Register (&allow_download_copyrighted, cvargroup_serverpermissions);
Cvar_Register (&allow_download_other, cvargroup_serverpermissions);
Cvar_Register (&secure, cvargroup_serverpermissions); Cvar_Register (&secure, cvargroup_serverpermissions);
Cvar_Register (&sv_highchars, cvargroup_servercontrol); Cvar_Register (&sv_highchars, cvargroup_servercontrol);

View file

@ -62,8 +62,12 @@ void SV_FlushRedirect (void)
Log_String(LOG_CONSOLE, va("{\n%s}\n", outputbuf)); Log_String(LOG_CONSOLE, va("{\n%s}\n", outputbuf));
if (sv_redirected == RD_PACKET) if (sv_redirected == RD_PACKET || sv_redirected == RD_PACKET_LOG)
{ {
//log it to the rcon log if its not just a status response
if (sv_redirected == RD_PACKET_LOG)
Log_String(LOG_RCON, outputbuf);
send[0] = 0xff; send[0] = 0xff;
send[1] = 0xff; send[1] = 0xff;
send[2] = 0xff; send[2] = 0xff;

View file

@ -2007,7 +2007,7 @@ void SV_DarkPlacesDownloadAck(client_t *cl)
} }
} }
void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezfilenum) static void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezfilenum, int chunks)
{ {
#define CHUNKSIZE 1024 #define CHUNKSIZE 1024
char buffer[CHUNKSIZE]; char buffer[CHUNKSIZE];
@ -2015,16 +2015,20 @@ void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezfilenum)
sizebuf_t *msg, msg_oob; sizebuf_t *msg, msg_oob;
int i; int i;
int error = false; int error = false;
//can't support this yet. at least forcing to 1 avoids too bad infinite loops. this can be a nasty dos attack on a server. if (chunks < 1)
chunks = 1;
msg = &host_client->datagram; msg = &host_client->datagram;
if (chunknum*CHUNKSIZE > host_client->downloadsize) if (chunknum == -1)
error = 2; //silent, don't report it
else if (chunknum*CHUNKSIZE > host_client->downloadsize)
{ {
SV_ClientTPrintf (host_client, PRINT_HIGH, "Warning: Invalid file chunk requested %u to %u of %u.\n", chunknum*CHUNKSIZE, (chunknum+1)*CHUNKSIZE, host_client->downloadsize); SV_ClientTPrintf (host_client, PRINT_HIGH, "Warning: Invalid file chunk requested %u to %u of %u.\n", chunknum*CHUNKSIZE, (chunknum+1)*CHUNKSIZE, host_client->downloadsize);
error = 2; error = 2;
} }
if (!error && VFS_SEEK (host_client->download, chunknum*CHUNKSIZE) == false) if (!error && VFS_SEEK (host_client->download, (qofs_t)chunknum*CHUNKSIZE) == false)
error = true; error = true;
else else
{ {
@ -2032,58 +2036,63 @@ void SV_NextChunkedDownload(unsigned int chunknum, int ezpercent, int ezfilenum)
host_client->downloadcount = chunknum*CHUNKSIZE; host_client->downloadcount = chunknum*CHUNKSIZE;
} }
if ((host_client->datagram.cursize + CHUNKSIZE+5+50 > host_client->datagram.maxsize) || (host_client->datagram.cursize + CHUNKSIZE+5 > 1400))
while (!error && chunks > 0)
{ {
//would overflow the packet, or result in (ethernet) fragmentation and high packet loss. if ((host_client->datagram.cursize + CHUNKSIZE+5+50 > host_client->datagram.maxsize) || (host_client->datagram.cursize + CHUNKSIZE+5 > 1400))
msg = &msg_oob; {
//would overflow the packet, or result in (ethernet) fragmentation and high packet loss.
msg = &msg_oob;
if (!ezfilenum) if (!ezfilenum) //can't oob it
return; return;
if (host_client->waschoked) if (host_client->waschoked)
return; //don't let chunked downloads flood out the standard packets. return; //don't let chunked downloads flood out the standard packets.
if (!Netchan_CanPacket(&host_client->netchan, SV_RateForClient(host_client))) if (!Netchan_CanPacket(&host_client->netchan, SV_RateForClient(host_client)))
return; return;
} }
if (error)
i = 0;
else
i = VFS_READ (host_client->download, buffer, CHUNKSIZE); i = VFS_READ (host_client->download, buffer, CHUNKSIZE);
if (i > 0) if (i > 0)
{
if (msg == &msg_oob)
{ {
msg = &msg_oob; if (msg == &msg_oob)
msg->cursize = 0; {
msg->maxsize = sizeof(oobdata); msg = &msg_oob;
msg->currentbit = 0; msg->cursize = 0;
msg->packing = SZ_RAWBYTES; msg->maxsize = sizeof(oobdata);
msg->allowoverflow = 0; msg->currentbit = 0;
msg->overflowed = 0; msg->packing = SZ_RAWBYTES;
msg->data = oobdata; msg->allowoverflow = 0;
MSG_WriteByte(msg, A2C_PRINT); msg->overflowed = 0;
SZ_Write(msg, "\\chunk", 6); msg->data = oobdata;
MSG_WriteLong(msg, ezfilenum); //echoing the file num is used so the packets don't go out of sync. MSG_WriteByte(msg, A2C_PRINT);
SZ_Write(msg, "\\chunk", 6);
MSG_WriteLong(msg, ezfilenum); //echoing the file num is used so the packets don't go out of sync.
}
if (i != CHUNKSIZE)
memset(buffer+i, 0, CHUNKSIZE-i);
MSG_WriteByte(msg, svc_download);
MSG_WriteLong(msg, chunknum);
SZ_Write(msg, buffer, CHUNKSIZE);
if (msg == &msg_oob)
{
Netchan_OutOfBand(NS_SERVER, &host_client->netchan.remote_address, msg_oob.cursize, msg_oob.data);
Netchan_Block(&host_client->netchan, msg_oob.cursize, SV_RateForClient(host_client));
host_client->netchan.bytesout += msg_oob.cursize;
}
} }
else if (i < 0)
error = true;
if (i != CHUNKSIZE) chunks--;
memset(buffer+i, 0, CHUNKSIZE-i); chunknum++;
MSG_WriteByte(msg, svc_download);
MSG_WriteLong(msg, chunknum);
SZ_Write(msg, buffer, CHUNKSIZE);
if (msg == &msg_oob)
{
Netchan_OutOfBand(NS_SERVER, &host_client->netchan.remote_address, msg_oob.cursize, msg_oob.data);
Netchan_Block(&host_client->netchan, msg_oob.cursize, SV_RateForClient(host_client));
}
} }
else if (i < 0)
error = true;
if (error) if (error)
{ {
@ -2122,9 +2131,9 @@ void SV_NextDownload_f (void)
if (host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS) if (host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS)
{ {
if (Cmd_Argc() < 2) if (Cmd_Argc() < 2)
SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3))); SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3)), atoi(Cmd_Argv(4)));
else else
SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3))); SV_NextChunkedDownload(atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)), atoi(Cmd_Argv(3)), atoi(Cmd_Argv(4)));
return; return;
} }
#endif #endif
@ -2596,6 +2605,7 @@ qboolean SV_AllowDownload (const char *name)
extern cvar_t allow_download_root; extern cvar_t allow_download_root;
extern cvar_t allow_download_configs; extern cvar_t allow_download_configs;
extern cvar_t allow_download_copyrighted; extern cvar_t allow_download_copyrighted;
extern cvar_t allow_download_other;
char cleanname[MAX_QPATH]; char cleanname[MAX_QPATH];
int i=0; int i=0;
if (strlen(name) >= MAX_QPATH) if (strlen(name) >= MAX_QPATH)
@ -2620,6 +2630,9 @@ qboolean SV_AllowDownload (const char *name)
if (strchr(name, '\\')) //no windows paths - grow up lame windows users. if (strchr(name, '\\')) //no windows paths - grow up lame windows users.
return false; return false;
if (!Q_strcasecmp("log", COM_FileExtension(name)))
return false;
if (!strncmp(name, "package/", 8)) if (!strncmp(name, "package/", 8))
{ {
if (!strcmp("pk4", COM_FileExtension(name)) || !strcmp("pk3", COM_FileExtension(name)) || !strcmp("pak", COM_FileExtension(name))) if (!strcmp("pk4", COM_FileExtension(name)) || !strcmp("pk3", COM_FileExtension(name)) || !strcmp("pak", COM_FileExtension(name)))
@ -2677,12 +2690,13 @@ qboolean SV_AllowDownload (const char *name)
//root of gamedir //root of gamedir
if (!strchr(name, '/') && !allow_download_root.value) if (!strchr(name, '/') && !allow_download_root.value)
{ {
if (strcmp(name, "csprogs.dat")) //we always allow csprogs.dat to be downloaded (if downloads are permitted). if (!strcmp(name, "csprogs.dat")) //we always allow csprogs.dat to be downloaded (if downloads are permitted).
return false; return true;
return false;
} }
//any other subdirs are allowed //any other subdirs are allowed
return true; return !!allow_download_other.value;;
} }
static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementname, qboolean redirectpaks) static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementname, qboolean redirectpaks)
@ -3036,9 +3050,16 @@ void SV_BeginDownload_f(void)
host_client->download = tmp; host_client->download = tmp;
} }
ClientReliableWrite_Begin (host_client, svc_download, 10+strlen(host_client->downloadfn)); ClientReliableWrite_Begin (host_client, svc_download, 18+strlen(host_client->downloadfn));
ClientReliableWrite_Long (host_client, -1); ClientReliableWrite_Long (host_client, -1);
ClientReliableWrite_Long (host_client, host_client->downloadsize); if (host_client->downloadsize >= 0x7fffffff)
{ //avoid unsigned values.
ClientReliableWrite_Long (host_client, 0x80000000); //signal that its 64bit
ClientReliableWrite_Long (host_client, qofs_Low(host_client->downloadsize));
ClientReliableWrite_Long (host_client, qofs_High(host_client->downloadsize));
}
else
ClientReliableWrite_Long (host_client, host_client->downloadsize);
ClientReliableWrite_String (host_client, host_client->downloadfn); ClientReliableWrite_String (host_client, host_client->downloadfn);
} }
else else
@ -5333,8 +5354,11 @@ void SV_ExecuteUserCommand (char *s, qboolean fromQC)
return; return;
} }
Log_String(LOG_RCON, va("cmd from %s - %s:\n%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), host_client->name, s));
Con_TPrintf ("cmd from %s:\n%s\n" Con_TPrintf ("cmd from %s:\n%s\n"
, host_client->name, net_message.data+4); , host_client->name, s);
SV_BeginRedirect (RD_CLIENT, host_client->language); SV_BeginRedirect (RD_CLIENT, host_client->language);
@ -5351,8 +5375,8 @@ void SV_ExecuteUserCommand (char *s, qboolean fromQC)
, NET_AdrToString (adr, sizeof(adr), &net_from), "Was too long - possible buffer overflow attempt"); , NET_AdrToString (adr, sizeof(adr), &net_from), "Was too long - possible buffer overflow attempt");
return; return;
} }
strcat (remaining, Cmd_Argv(i) ); Q_strncatz(remaining, Cmd_Argv(i), sizeof(remaining));
strcat (remaining, " "); Q_strncatz(remaining, " ", sizeof(remaining));
} }
Cmd_ExecuteString (remaining, stats.trustlevel); Cmd_ExecuteString (remaining, stats.trustlevel);