Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

Commit 755452d7 authored by Rob Swindell's avatar Rob Swindell 💬

Give sysop more control over characters allowed in uploaded filenames

5 options:
- Safest Subset
- Most ASCII, Excluding Spaces (the default)
- Most ASCII, Including Spaces
- Most CP437, Excluding Spaces
- Most CP437, Including Spaces
parent 34bcbdf4
Pipeline #2355 passed with stage
in 9 minutes and 37 seconds
......@@ -145,7 +145,7 @@ bool sbbs_t::checkfname(const char *fname)
hacklog("Filename", fname);
return false;
}
return allowed_filename(fname);
return allowed_filename(&cfg, fname);
}
long sbbs_t::delfiles(const char *inpath, const char *spec, size_t keep)
......
......@@ -1250,31 +1250,49 @@ bool illegal_filename(const char *fname)
{
size_t len = strlen(fname);
if(*fname == '-')
if(len < 1)
return true;
if(strcspn(fname, ILLEGAL_FILENAME_CHARS) != len)
return true;
if(strstr(fname, "..") != NULL)
return true;
if(*fname == '-') // leading dash is a problem for argument parsing
return true;
if(*fname == '.') // leading dot hides files on *nix
return true;
if(*fname == ' ') // leading space is a problem for argument parsing (shells)
return true;
if(fname[len - 1] == '.') // a trailing dot is a problem for Windows
return true;
if(fname[len - 1] == ' ') // a trailing space is a problem for argument parsing (shells)
return true;
for(size_t i = 0; i < len; i++) {
if(IS_CONTROL(fname[i])) // control characters in filenames are evil
return true;
}
return false;
}
/*****************************************************************************/
/* Checks the filename 'fname' for invalid symbol or character sequences */
/*****************************************************************************/
bool allowed_filename(const char *fname)
/****************************************************************************/
/* Checks if the filename chars meet the system requirements for upload */
/* Assumes the filename has already been checked with illegal_filename() */
/****************************************************************************/
bool allowed_filename(scfg_t* cfg, const char *fname)
{
size_t len = strlen(fname);
if(len < 1)
return false;
if(cfg->file_misc & FM_SAFEST)
return safest_filename(fname);
uchar min = (cfg->file_misc & FM_SPACES) ? ' ' : '!';
uchar max = (cfg->file_misc & FM_EXASCII) ? 0xff : 0x7f;
for(size_t i = 0; i < len; i++) {
if(fname[i] <= ' ')
if((uchar)fname[i] < min || (uchar)fname[i] > max)
return false;
}
if(*fname == '.' // leading dot hides files on *nix
|| fname[len - 1] == '.') // a trailing dot is a problem for Win32
return false;
return true;
}
......@@ -59,7 +59,7 @@ DLLEXPORT bool removefile(scfg_t*, uint dirnum, const char* filename);
DLLEXPORT char* format_filename(const char* fname, char* buf, size_t, bool pad);
DLLEXPORT bool safest_filename(const char* fname);
DLLEXPORT bool illegal_filename(const char* fname);
DLLEXPORT bool allowed_filename(const char* fname);
DLLEXPORT bool allowed_filename(scfg_t*, const char* fname);
DLLEXPORT bool extract_diz(scfg_t*, file_t*, str_list_t diz_fname, char* path, size_t);
DLLEXPORT char* read_diz(const char* path, struct sauce_charinfo*);
DLLEXPORT char* format_diz(const char* src, char* dest, size_t maxlen, int width, bool ice_color);
......
......@@ -4573,7 +4573,7 @@ static void ctrl_thread(void* arg)
ftp_hacklog("FTP FILENAME", user.alias, cmd, host_name, &ftp.client_addr);
continue;
}
if(!allowed_filename(p)) {
if(!allowed_filename(&scfg, p)) {
lprintf(LOG_WARNING,"%04d <%s> !UNALLOWED FILENAME ATTEMPT by %s [%s]: %s"
,sock, user.alias, host_name, host_ip, p);
sockprintf(sock,sess,"553 Unallowed filename attempt");
......
......@@ -261,6 +261,10 @@
#define DIR_NOHASH (1<<22) /* Don't auto calculate/store file content hashes */
#define DIR_FILETAGS (1<<23) /* Allow files to have user-specified tags */
#define FM_SAFEST (1<<1) /* Allow safest filenames to be uploaded only */
#define FM_SPACES (1<<2) /* Allow spaces in uploaded filenames */
#define FM_EXASCII (1<<3) /* Allow extended-ASCII (or UTF-8) in uploaded filenames */
/* Bit values for cfg.msg_misc (upper 16-bits default to on) */
#define MM_REALNAME (1<<16) /* Allow receipt of e-mail using real names */
#define MM_EMAILSIG (1<<17) /* Include user signatures in e-mail msgs */
......
......@@ -69,6 +69,13 @@ void xfer_opts()
else
strcpy(str,"Disabled");
sprintf(opt[i++],"%-33.33s%s","Leech Protocol Detection",str);
if(cfg.file_misc & FM_SAFEST)
SAFECOPY(str, "Safest Subset");
else
SAFEPRINTF2(str, "Most %s, %scluding Spaces"
,cfg.file_misc & FM_EXASCII ? "CP437" : "ASCII"
,cfg.file_misc & FM_SPACES ? "In" : "Ex");
sprintf(opt[i++], "%-33.33s%s", "Allow Filename Characters", str);
strcpy(opt[i++],"Viewable Files...");
strcpy(opt[i++],"Testable Files...");
strcpy(opt[i++],"Download Events...");
......@@ -186,7 +193,7 @@ void xfer_opts()
"\n"
"This option allows you to adjust the sensitivity of the leech protocol\n"
"detection feature. This value is the minimum length of transfer time\n"
"(in seconds) that must elapse before an aborted tranfser will be\n"
"(in seconds) that must elapse before an aborted transfer will be\n"
"considered a possible leech attempt.\n"
;
uifc.input(WIN_MID,0,0
......@@ -194,6 +201,82 @@ void xfer_opts()
,ultoa(cfg.leech_sec,tmp,10),3,K_EDIT|K_NUMBER);
cfg.leech_sec=atoi(tmp);
break;
case __COUNTER__: /* Uploaded Filename characters allowed */
i = 0;
strcpy(opt[i++], "Safest Subset Only (A-Z, a-z, 0-9, -, _, and .)");
strcpy(opt[i++], "Most ASCII Characters, Excluding Spaces");
strcpy(opt[i++], "Most ASCII Characters, Including Spaces");
strcpy(opt[i++], "Most CP437 Characters, Excluding Spaces");
strcpy(opt[i++], "Most CP437 Characters, Including Spaces");
opt[i][0] = '\0';
if(cfg.file_misc & FM_SAFEST)
j = 0;
else {
j = 1;
if(cfg.file_misc & FM_EXASCII)
j = 3;
if(cfg.file_misc & FM_SPACES)
j++;
}
uifc.helpbuf=
"`Allowed Characters in Uploaded Filenames:`\n"
"\n"
"Here you can control which characters will be allowed in the names of\n"
"files uploaded by users (assuming you allow file uploads at all).\n"
"\n"
"The `Safest` (most compatible) filename characters to allow are:\n"
"`" SAFEST_FILENAME_CHARS "`\n"
"\n"
"`Spaces` may be allowed in filenames, but may cause issues with some file\n"
"transfer protocol drivers or clients (older/MS-DOS software).\n"
"\n"
"Filenames that are most often troublesome (including those in your\n"
"`text/file.can` file) are `always disallowed`:\n"
" Filenames beginning with dash (`-`)\n"
" Filenames beginning or ending in space\n"
" Filenames beginning or ending in period (`.`)\n"
" Filenames containing consecutive periods (`..`)\n"
" Filenames containing illegal characters (`" ILLEGAL_FILENAME_CHARS "`)\n"
" Filenames containing control characters (ASCII 0-31 and 127)\n"
;
i = uifc.list(0, 0, 0, 0, &j, NULL, "Allowed Characters in Uploaded Filenames", opt);
switch(i) {
case 0:
if(cfg.file_misc != FM_SAFEST) {
cfg.file_misc |= FM_SAFEST;
cfg.file_misc &= ~(FM_EXASCII | FM_SPACES);
uifc.changes = TRUE;
}
break;
case 1:
if(cfg.file_misc) {
cfg.file_misc &= ~(FM_SAFEST | FM_SPACES | FM_EXASCII);
uifc.changes = TRUE;
}
break;
case 2:
if(cfg.file_misc != FM_SPACES) {
cfg.file_misc &= ~(FM_SAFEST | FM_EXASCII);
cfg.file_misc |= FM_SPACES;
uifc.changes = TRUE;
}
break;
case 3:
if(cfg.file_misc != FM_EXASCII) {
cfg.file_misc &= ~(FM_SAFEST | FM_SPACES);
cfg.file_misc |= FM_EXASCII;
uifc.changes = TRUE;
}
break;
case 4:
if(cfg.file_misc != (FM_EXASCII | FM_SPACES)) {
cfg.file_misc &= ~(FM_SAFEST);
cfg.file_misc |= FM_EXASCII | FM_SPACES;
uifc.changes = TRUE;
}
break;
}
break;
case __COUNTER__: /* Viewable file types */
while(1) {
for(i=0;i<cfg.total_fviews && i<MAX_OPTS;i++)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment