Commit 1ab2956b authored by Rob Swindell's avatar Rob Swindell 💬
Browse files

Add direct filebase access from the web server (optional)

By setting SCFG->File Options->Web File Virtual Path Prefix to something (e.g. "/files/"), all HTTP or HTTPS requests to the Synchronet Web Server with request paths beginning with this prefix will be interpreted as filebase access requests (with full access control enforcement). This is configured here (in SCFG) rather than, say, the [web] section of sbbs.ini, because I have plans for the terminal server to use this prefix to generate Web-URLs for files to display or email to users.

Currently, only requests to *files* (for download) are supported (no index generation, file information, etc. and definitely no upload support). Full access control (using HTTP auth, not cookies) is used for libraries and directories with controlled access. Credits are deducted and awarded and uploaders are notified of downloads, as one would expect. Requests to any dynamic-web-content files (e.g. .SSJS, .XJS, etc.) will be treated as static file download requests (no script will be executed).

I'm reusing the same virtual path parsing logic from the FTP server (moved to the userdat lib), so the virtual path to a file for download would be, for example, http://yourdomain/files/lib/dir-code/filename.ext

The main motivation for this feature is: FTP-links in email and web pages are just not useful to many users these days and I don't think that sysops should have to rely on a SSJS web UI (e.g. ecWebv4, cool as it is), to provide web-access to the filebases. Using this feature, you can share simpler/shorter web links to your files that will be more enduring.
parent d74c90dd
Pipeline #2579 passed with stage
in 13 minutes and 4 seconds
......@@ -377,54 +377,6 @@ static int sockprintf(SOCKET sock, CRYPT_SESSION sess, char *fmt, ...)
return(len);
}
/* Returns the directory index of a virtual lib/dir path (e.g. main/games/filename) */
int getdir(char* p, user_t* user, client_t* client)
{
char* tp;
char path[MAX_PATH+1];
uint dir;
uint lib;
SAFECOPY(path,p);
p=path;
if(*p=='/')
p++;
if(!strncmp(p,"./",2))
p+=2;
tp=strchr(p,'/');
if(tp) *tp=0;
for(lib=0;lib<scfg.total_libs;lib++) {
if(!chk_ar(&scfg,scfg.lib[lib]->ar,user,client))
continue;
if(!stricmp(scfg.lib[lib]->sname,p))
break;
}
if(lib>=scfg.total_libs)
return(-1);
if(tp!=NULL)
p=tp+1;
tp=strchr(p,'/');
if(tp) *tp=0;
for(dir=0;dir<scfg.total_dirs;dir++) {
if(scfg.dir[dir]->lib!=lib)
continue;
if(dir!=scfg.sysop_dir && dir!=scfg.upload_dir
&& !chk_ar(&scfg,scfg.dir[dir]->ar,user,client))
continue;
if(!stricmp(scfg.dir[dir]->code_suffix,p))
break;
}
if(dir>=scfg.total_dirs)
return(-1);
return(dir);
}
void recverror(SOCKET socket, int rd, int line)
{
if(rd==0)
......@@ -1509,7 +1461,7 @@ static BOOL ftpalias(char* fullalias, char* filename, user_t* user, client_t* cl
}
if(!strnicmp(p,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
if((dir=getdir(p+strlen(BBS_VIRTUAL_PATH),user,client))<0) {
if((dir=getdir_from_vpath(&scfg, p+strlen(BBS_VIRTUAL_PATH), user, client, true))<0) {
lprintf(LOG_WARNING,"0000 <%s> !Invalid virtual path: %s",user->alias, p);
/* invalid or no access */
continue;
......@@ -3637,7 +3589,7 @@ static void ctrl_thread(void* arg)
/* Virtual Path? */
aliaspath[0]=0;
if(!strnicmp(np,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
if((dir=getdir(np+strlen(BBS_VIRTUAL_PATH),&user,&client))<0) {
if((dir=getdir_from_vpath(&scfg, np+strlen(BBS_VIRTUAL_PATH), &user, &client, true))<0) {
lprintf(LOG_WARNING,"%04d <%s> !Invalid virtual path:%s",sock,user.alias,np);
continue; /* No access or invalid virtual path */
}
......@@ -3923,7 +3875,7 @@ static void ctrl_thread(void* arg)
/* Virtual Path? */
if(!strnicmp(np,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
if((dir=getdir(np+strlen(BBS_VIRTUAL_PATH),&user,&client))<0) {
if((dir=getdir_from_vpath(&scfg, np+strlen(BBS_VIRTUAL_PATH), &user, &client, true))<0) {
lprintf(LOG_WARNING,"%04d <%s> !Invalid virtual path: %s", sock, user.alias, np);
continue; /* No access or invalid virtual path */
}
......
......@@ -67,7 +67,7 @@ void xfer_opts()
sprintf(str,"%u%% after %u seconds"
,cfg.leech_pct,cfg.leech_sec);
else
strcpy(str,"Disabled");
strcpy(str,"<disabled>");
sprintf(opt[i++],"%-33.33s%s","Leech Protocol Detection",str);
if(cfg.file_misc & FM_SAFEST)
SAFECOPY(str, "Safest Subset");
......@@ -77,6 +77,8 @@ void xfer_opts()
,cfg.file_misc & FM_SPACES ? "In" : "Ex");
sprintf(opt[i++], "%-33.33s%u characters", "Allowed Filename Length", cfg.filename_maxlen);
sprintf(opt[i++], "%-33.33s%s", "Allowed Filename Characters", str);
sprintf(opt[i++], "%-33.33s%s", "Web File Virtual Path Prefix"
, cfg.web_file_prefix[0] ? cfg.web_file_prefix : "<disabled>");
strcpy(opt[i++],"Viewable Files...");
strcpy(opt[i++],"Testable Files...");
strcpy(opt[i++],"Download Events...");
......@@ -296,6 +298,24 @@ void xfer_opts()
break;
}
break;
case __COUNTER__:
uifc.helpbuf=
"`Web File Virtual Path Prefix:`\n"
"\n"
"The virtual path prefix to your file transfer areas (filebases)\n"
"accessible via HTTP or HTTPS using the Synchronet Web Server.\n"
"\n"
"A prefix beginning and ending in a slash (e.g. `/files/`) is recommended.\n"
"\n"
"A prefix of just '`/`' would interpret `all` web requests as filebase access\n"
"requests.\n"
"\n"
"Setting this to an empty string disables access to your filebases from\n"
"the Synchronet Web Server.\n"
;
uifc.input(WIN_MID,0,0,"Web File Virtual Path Prefix"
,cfg.web_file_prefix, sizeof(cfg.web_file_prefix)-1, K_EDIT);
break;
case __COUNTER__: /* Viewable file types */
while(1) {
for(i=0;i<cfg.total_fviews && i<MAX_OPTS;i++)
......
......@@ -463,6 +463,7 @@ typedef struct
int32_t file_misc; /* File Misc Settings */
int32_t xtrn_misc; /* External Programs Misc Settings */
uint16_t filename_maxlen; /* Maximum filename length */
char web_file_prefix[33];
char node_comspec[LEN_CMD+1]; /* DOS COMMAND.COM to use */
char node_editor[LEN_CMD+1]; /* Local text editor command line to use */
......
......@@ -60,8 +60,11 @@ BOOL read_file_cfg(scfg_t* cfg, char* error, size_t maxerrlen)
get_int(cfg->filename_maxlen, instream);
if(cfg->filename_maxlen == 0)
cfg->filename_maxlen = SMB_FILEIDX_NAMELEN;
get_str(cfg->web_file_prefix, instream);
for(i=0;i<29;i++)
// Padding (NULs):
get_int(c,instream);
for(i=0;i<12;i++)
get_int(n,instream);
/**************************/
......
......@@ -661,8 +661,12 @@ BOOL write_file_cfg(scfg_t* cfg, int backup_level)
put_int(cfg->leech_sec,stream);
put_int(cfg->file_misc,stream);
put_int(cfg->filename_maxlen, stream);
put_str(cfg->web_file_prefix, stream);
// Padding (NULs)
c=0;
put_int(c, stream);
n=0;
for(i=0;i<29;i++)
for(i=0;i<12;i++)
put_int(n,stream);
/* Extractable File Types */
......
......@@ -2495,14 +2495,15 @@ BOOL user_downloaded_file(scfg_t* cfg, user_t* user, client_t* client,
char tmp[128];
char prefix[128]="";
ultoac(mod,tmp);
const char* alias = user->alias[0] ? user->alias : cfg->text[UNKNOWN_USER];
char username[64];
if(client != NULL && uploader.level >= SYSOP_LEVEL) {
if(client->host[0] != '\0' && strcmp(client->host, STR_NO_HOSTNAME) != 0)
SAFEPRINTF2(username,"%s [%s]", user->alias, client->host);
SAFEPRINTF2(username,"%s [%s]", alias, client->host);
else
SAFEPRINTF2(username,"%s [%s]", user->alias, client->addr);
SAFEPRINTF2(username,"%s [%s]", alias, client->addr);
} else
SAFECOPY(username, user->alias);
SAFECOPY(username, alias);
if(strcmp(cfg->dir[dirnum]->code, "TEMP") == 0 || bytes < (ulong)f.size)
SAFECOPY(prefix, cfg->text[Partially]);
if(client != NULL) {
......@@ -3806,3 +3807,50 @@ int lookup_user(scfg_t* cfg, link_list_t* list, const char *inname)
}
return 0;
}
/* Returns the directory index of a virtual lib/dir path (e.g. main/games/filename) */
int getdir_from_vpath(scfg_t* cfg, const char* p, user_t* user, client_t* client, BOOL include_upload_only)
{
char* tp;
char path[MAX_PATH+1];
uint dir;
uint lib;
SAFECOPY(path,p);
p=path;
if(*p=='/')
p++;
if(!strncmp(p,"./",2))
p+=2;
tp=strchr(p,'/');
if(tp) *tp=0;
for(lib=0;lib<cfg->total_libs;lib++) {
if(!chk_ar(cfg,cfg->lib[lib]->ar,user,client))
continue;
if(!stricmp(cfg->lib[lib]->sname,p))
break;
}
if(lib>=cfg->total_libs)
return(-1);
if(tp!=NULL)
p=tp+1;
tp=strchr(p,'/');
if(tp) *tp=0;
for(dir=0;dir<cfg->total_dirs;dir++) {
if(cfg->dir[dir]->lib!=lib)
continue;
if((!include_upload_only || (dir!=cfg->sysop_dir && dir!=cfg->upload_dir))
&& !chk_ar(cfg,cfg->dir[dir]->ar,user,client))
continue;
if(!stricmp(cfg->dir[dir]->code_suffix,p))
break;
}
if(dir>=cfg->total_dirs)
return(-1);
return(dir);
}
......@@ -100,6 +100,7 @@ DLLEXPORT BOOL is_download_free(scfg_t*, uint dirnum, user_t*, client_t* client)
DLLEXPORT BOOL is_host_exempt(scfg_t*, const char* ip_addr, const char* host_name);
DLLEXPORT BOOL filter_ip(scfg_t*, const char* prot, const char* reason, const char* host
,const char* ip_addr, const char* username, const char* fname);
DLLEXPORT int getdir_from_vpath(scfg_t*, const char* p, user_t*, client_t*, BOOL include_upload_only);
/* user .ini file access */
DLLEXPORT BOOL user_get_property(scfg_t*, unsigned user_number, const char* section, const char* key, char* value, size_t maxlen);
......
......@@ -50,6 +50,7 @@
#undef SBBS /* this shouldn't be defined unless building sbbs.dll/libsbbs.so */
#include "sbbs.h"
#include "sbbsdefs.h"
#include "filedat.h"
#include "sockwrap.h" /* sendfilesocket() */
#include "multisock.h"
#include "threadwrap.h"
......@@ -252,6 +253,8 @@ typedef struct {
char host_name[128]; /* Resolved remote host */
int http_ver; /* Request HTTP version. 0 = HTTP/0.9, 1=HTTP/1.0, 2=HTTP/1.1 */
BOOL finished; /* Do not accept any more imput from client */
BOOL filebase_access;
file_t file;
user_t user;
int last_user_num;
time_t logon_time;
......@@ -1123,6 +1126,7 @@ static void close_request(http_session_t * session)
}
}
smb_freefilemem(&session->file);
memset(&session->req,0,sizeof(session->req));
}
......@@ -1617,6 +1621,7 @@ void http_logoff(http_session_t* session, SOCKET socket, int line)
if(!logoutuserdat(&scfg, &session->user, time(NULL), session->logon_time))
lprintf(LOG_ERR,"%04d !ERROR in logoutuserdat", socket);
memset(&session->user,0,sizeof(session->user));
SAFECOPY(session->user.alias, unknown);
session->last_user_num=session->user.number;
#ifdef _WIN32
......@@ -1888,7 +1893,9 @@ static BOOL check_ars(http_session_t * session)
}
if(!http_checkuser(session))
return(FALSE);
if(session->req.ars[0]) {
if((session->filebase_access
&& !can_user_download(&scfg, session->file.dir, &session->user, &session->client, NULL))
|| session->req.ars[0]) {
/* There *IS* an ARS string ie: Auth is required */
if(startup->options&WEB_OPT_DEBUG_RX)
lprintf(LOG_NOTICE,"%04d !No authentication information",session->socket);
......@@ -1983,11 +1990,18 @@ static BOOL check_ars(http_session_t * session)
session->req.ld->user=strdup(session->req.auth.username);
}
ar = arstr(NULL,session->req.ars,&scfg,NULL);
authorized=chk_ar(&scfg,ar,&session->user,&session->client);
if(ar!=NULL)
FREE_AND_NULL(ar);
if(session->filebase_access) {
  • This if/else block bothers me since the two are testing very different things. Both tests should be required to pass if both end up applicable somehow.

Please register or sign in to reply
if(is_download_free(&scfg, session->file.dir, &session->user, &session->client)
|| session->user.cdt >= session->file.cost)
authorized = can_user_download(&scfg, session->file.dir, &session->user, &session->client, NULL);
else
authorized = FALSE;
} else {
ar = arstr(NULL,session->req.ars,&scfg,NULL);
authorized=chk_ar(&scfg,ar,&session->user,&session->client);
if(ar!=NULL)
FREE_AND_NULL(ar);
}
if(authorized) {
switch(session->req.auth.type) {
case AUTHENTICATION_TLS_PSK:
......@@ -2872,6 +2886,9 @@ static int is_dynamic_req(http_session_t* session)
char fname[MAX_PATH+1];
char ext[MAX_PATH+1];
if(session->filebase_access)
return IS_STATIC;
  • This should be a new dynamic type. This is doing something very different than what a static webserver does. It would also get rid of the filebase_access session variable.

    Edited by Deucе
  • The return value of this function is assigned to session->req.dynamic which is then later most often tested as if it's a bool, e.g.

    			if(session->req.dynamic)	/* Need to re-copy path here in case of re-checked PathInfoIndex change */
    				SAFECOPY(path,session->req.physical_path);

    Many of these checks would have to be changed to specific range or value checks since the conditional blocks mostly do not apply to filebase/download requests.

    Since the content of a filebase response is not dynamically generated, I don't see why IS_STATIC is not the appropriate type.

  • Another example where a non-zero session->req.dynamic value would do the wrong thing for a filebase request:

    		/* Entity Headers */
    		if(session->req.dynamic) {
    			safe_snprintf(header,sizeof(header),"%s: %s",get_header(HEAD_ALLOW),"GET, HEAD, POST, OPTIONS");
    			safecat(headers,header,MAX_HEADERS_SIZE);
    			safe_snprintf(header,sizeof(header),"%s: %s",get_header(HEAD_ACCEPT_RANGES),"none");
    			safecat(headers,header,MAX_HEADERS_SIZE);
    		}
    		else {
    			safe_snprintf(header,sizeof(header),"%s: %s",get_header(HEAD_ALLOW),"GET, HEAD, OPTIONS");
    			safecat(headers,header,MAX_HEADERS_SIZE);
    			safe_snprintf(header,sizeof(header),"%s: %s",get_header(HEAD_ACCEPT_RANGES),"bytes");
    			safecat(headers,header,MAX_HEADERS_SIZE);
    		}
Please register or sign in to reply
check_extra_path(session);
_splitpath(session->req.physical_path, drive, dir, fname, ext);
......@@ -3112,6 +3129,10 @@ static BOOL get_fullpath(http_session_t * session)
{
char str[MAX_PATH+1];
if(scfg.web_file_prefix[0] && strncmp(session->req.physical_path, scfg.web_file_prefix, strlen(scfg.web_file_prefix)) == 0) {
session->filebase_access = TRUE;
return TRUE;
}
if(session->req.vhost[0] && startup->options&WEB_OPT_VIRTUAL_HOSTS) {
safe_snprintf(str,sizeof(str),"%s/%s",root_dir,session->req.vhost);
if(isdir(str))
......@@ -3493,6 +3514,20 @@ static void read_webctrl_section(FILE *file, char *section, http_session_t *sess
iniFreeNamedStringList(values);
}
static bool resolve_filebase_path(http_session_t* session, char* path)
{
uint dir = getdir_from_vpath(&scfg, path + strlen(scfg.web_file_prefix), &session->user, &session->client, false);
if(dir >= scfg.total_dirs)
return false;
char filename[MAX_PATH + 1];
SAFECOPY(filename, getfname(path));
session->file.dir = dir;
safe_snprintf(path, MAX_PATH, "%s%s", scfg.dir[dir]->path, filename);
if(!fexistcase(path))
return false;
return loadfile(&scfg, dir, filename, &session->file, file_detail_index);
}
static BOOL check_request(http_session_t * session)
{
char path[MAX_PATH+1];
......@@ -3522,6 +3557,13 @@ static BOOL check_request(http_session_t * session)
if(startup->options&WEB_OPT_DEBUG_TX)
lprintf(LOG_DEBUG,"%04d Path is: %s",session->socket,path);
if(session->filebase_access) {
if(!resolve_filebase_path(session, path)) {
send_error(session,__LINE__,error_404);
return FALSE;
}
}
if(isdir(path)) {
last_ch=*lastchar(path);
if(!IS_PATH_DELIM(last_ch)) {
......@@ -3569,118 +3611,121 @@ static BOOL check_request(http_session_t * session)
SAFECOPY(filename,last_slash);
}
if(strnicmp(path,root_dir,strlen(root_dir))) {
session->req.keep_alive=FALSE;
send_error(session,__LINE__,"400 Bad Request");
lprintf(LOG_NOTICE,"%04d !ERROR Request for %s is outside of web root %s"
,session->socket,path,root_dir);
return(FALSE);
}
/* Set default ARS to a 0-length string */
session->req.ars[0]=0;
/* Walk up from root_dir checking for access.ars and webctrl.ini */
SAFECOPY(curdir,path);
last_slash=curdir+strlen(root_dir)-1;
/* Loop while there's more /s in path*/
p=last_slash;
while((last_slash=find_first_slash(p+1))!=NULL) {
old_path_info_index = session->req.path_info_index;
p=last_slash;
/* Terminate the path after the slash */
*(last_slash+1)=0;
SAFEPRINTF(str,"%saccess.ars",curdir);
/* NEVER serve up an access.ars file */
if(!strcmp(path,str)) {
if(!stat(str,&sb)) {
lprintf(LOG_WARNING,"%04d !WARNING! access.ars support is deprecated and will be REMOVED very soon.",session->socket);
lprintf(LOG_WARNING,"%04d !WARNING! access.ars found at %s.",session->socket,str);
}
send_error(session,__LINE__,"403 Forbidden");
if(!session->filebase_access) {
  • This is a great time to refactor this block into a separate function that applies webctrl.ini. It may be a good time to remove access.ars support as well.

Please register or sign in to reply
if(strnicmp(path,root_dir,strlen(root_dir))) {
session->req.keep_alive=FALSE;
send_error(session,__LINE__,"400 Bad Request");
lprintf(LOG_NOTICE,"%04d !ERROR Request for %s is outside of web root %s"
,session->socket,path,root_dir);
return(FALSE);
}
if(!stat(str,&sb)) {
/* Read access.ars file */
if((file=fopen(str,"r"))!=NULL) {
fgets(session->req.ars,sizeof(session->req.ars),file);
fclose(file);
}
else {
/* If cannot open access.ars, only allow sysop access */
SAFECOPY(session->req.ars,"LEVEL 90");
break;
/* Walk up from root_dir checking for access.ars and webctrl.ini */
SAFECOPY(curdir,path);
last_slash=curdir+strlen(root_dir)-1;
/* Loop while there's more /s in path*/
p=last_slash;
while((last_slash=find_first_slash(p+1))!=NULL) {
old_path_info_index = session->req.path_info_index;
p=last_slash;
/* Terminate the path after the slash */
*(last_slash+1)=0;
SAFEPRINTF(str,"%saccess.ars",curdir);
/* NEVER serve up an access.ars file */
if(!strcmp(path,str)) {
if(!stat(str,&sb)) {
lprintf(LOG_WARNING,"%04d !WARNING! access.ars support is deprecated and will be REMOVED very soon.",session->socket);
lprintf(LOG_WARNING,"%04d !WARNING! access.ars found at %s.",session->socket,str);
}
send_error(session,__LINE__,"403 Forbidden");
return(FALSE);
}
/* Truncate at \r or \n - can use last_slash since I'm done with it.*/
truncsp(session->req.ars);
}
SAFEPRINTF(str,"%swebctrl.ini",curdir);
/* NEVER serve up a webctrl.ini file */
if(!strcmp(path,str)) {
send_error(session,__LINE__,"403 Forbidden");
return(FALSE);
}
if(!stat(str,&sb)) {
/* Read webctrl.ini file */
if((file=fopen(str,"r"))!=NULL) {
/* FREE()d in this block */
specs=iniReadSectionList(file,NULL);
/* Read in globals */
read_webctrl_section(file, NULL, session, curdir, &recheck_dynamic);
/* Now, PathInfoIndex may have been set, so we need to re-expand the index so it will match here. */
if (old_path_info_index != session->req.path_info_index) {
// Now that we may have gotten a new filename, we need to use that to compare with.
strcpy(filename, getfname(session->req.physical_path));
if(!stat(str,&sb)) {
/* Read access.ars file */
if((file=fopen(str,"r"))!=NULL) {
fgets(session->req.ars,sizeof(session->req.ars),file);
fclose(file);
}
else {
/* If cannot open access.ars, only allow sysop access */
SAFECOPY(session->req.ars,"LEVEL 90");
break;
}
/* Read in per-filespec */
while((spec=strListPop(&specs))!=NULL) {
len=strlen(spec);
if(spec[0] && IS_PATH_DELIM(spec[len-1])) {
/* Search for matching path elements... */
spath=strdup(path+(p-curdir+1));
pspec=strdup(spec);
pspec[len-1]=0;
for(sp=spath, nsp=find_first_slash(sp+1); nsp; nsp=find_first_slash(sp+1)) {
*nsp=0;
nsp++;
if(wildmatch(sp, pspec, TRUE, /* case_sensitive: */TRUE)) {
read_webctrl_section(file, spec, session, curdir, &recheck_dynamic);
/* Truncate at \r or \n - can use last_slash since I'm done with it.*/
truncsp(session->req.ars);
}
SAFEPRINTF(str,"%swebctrl.ini",curdir);
/* NEVER serve up a webctrl.ini file */
if(!strcmp(path,str)) {
send_error(session,__LINE__,"403 Forbidden");
return(FALSE);
}
if(!stat(str,&sb)) {
/* Read webctrl.ini file */
if((file=fopen(str,"r"))!=NULL) {
/* FREE()d in this block */
specs=iniReadSectionList(file,NULL);
/* Read in globals */
read_webctrl_section(file, NULL, session, curdir, &recheck_dynamic);
/* Now, PathInfoIndex may have been set, so we need to re-expand the index so it will match here. */
if (old_path_info_index != session->req.path_info_index) {
// Now that we may have gotten a new filename, we need to use that to compare with.
strcpy(filename, getfname(session->req.physical_path));
}
/* Read in per-filespec */
while((spec=strListPop(&specs))!=NULL) {
len=strlen(spec);
if(spec[0] && IS_PATH_DELIM(spec[len-1])) {
/* Search for matching path elements... */
spath=strdup(path+(p-curdir+1));
pspec=strdup(spec);
pspec[len-1]=0;
for(sp=spath, nsp=find_first_slash(sp+1); nsp; nsp=find_first_slash(sp+1)) {
*nsp=0;
nsp++;
if(wildmatch(sp, pspec, TRUE, /* case_sensitive: */TRUE)) {
read_webctrl_section(file, spec, session, curdir, &recheck_dynamic);
}
sp=nsp;
}
sp=nsp;
free(spath);
free(pspec);
}
free(spath);
free(pspec);
}
else if(wildmatch(filename,spec,TRUE, /* case_sensitive: */TRUE)) {
read_webctrl_section(file, spec, session, curdir, &recheck_dynamic);
else if(wildmatch(filename,spec,TRUE, /* case_sensitive: */TRUE)) {
read_webctrl_section(file, spec, session, curdir, &recheck_dynamic);
}
free(spec);
}
free(spec);
iniFreeStringList(specs);
fclose(file);
if(session->req.path_info_index)
recheck_dynamic=TRUE;
}
iniFreeStringList(specs);
fclose(file);
if(session->req.path_info_index)
recheck_dynamic=TRUE;
}
else {
/* If cannot open webctrl.ini, only allow sysop access */
SAFECOPY(session->req.ars,"LEVEL 90");
break;
else {
/* If cannot open webctrl.ini, only allow sysop access */
SAFECOPY(session->req.ars,"LEVEL 90");
break;
}
/* Truncate at \r or \n - can use last_slash since I'm done with it.*/
truncsp(session->req.ars);
}
/* Truncate at \r or \n - can use last_slash since I'm done with it.*/
truncsp(session->req.ars);
SAFECOPY(curdir,path);
}
SAFECOPY(curdir,path);
}
if(recheck_dynamic) {
session->req.dynamic=is_dynamic_req(session);
if(session->req.dynamic) /* Need to re-copy path here in case of re-checked PathInfoIndex change */
SAFECOPY(path,session->req.physical_path);
}
if(!session->req.dynamic && session->req.extra_path_info[0])
send404=TRUE;
if(recheck_dynamic) {
  • This should be outside of the if(), and with file access being a dynamic type, the test below it would naturally move out as well.

Please register or sign in to reply
session->req.dynamic=is_dynamic_req(session);
if(session->req.dynamic) /* Need to re-copy path here in case of re-checked PathInfoIndex change */
SAFECOPY(path,session->req.physical_path);
}
if(!session->req.dynamic && session->req.extra_path_info[0])
send404=TRUE;
}
if(!check_ars(session)) {
unsigned *auth_list;
unsigned auth_list_len;
......@@ -6028,6 +6073,8 @@ static void respond(http_session_t * session)
e = 1;
lprintf(LOG_INFO, "%04d Sent file: %s (%"PRIuOFF" bytes, %ld cps)"
,session->socket, session->req.physical_path, snt, (long)(snt / e));