Newer
Older
if(session->js_cx==NULL || session->js_request==NULL)
return;
if(key==NULL || value==NULL)
return;
if((js_str=JS_NewStringCopyZ(session->js_cx, value))==NULL)
return;
JS_DefineProperty(session->js_cx, session->js_request, key, STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
}
static void js_add_header(http_session_t * session, char *key, char *value)
{
JSString* js_str;
char *lckey;
if((lckey=(char *)alloca(strlen(key)+1))==NULL)
return;
strcpy(lckey,key);
strlwr(lckey);
if((js_str=JS_NewStringCopyZ(session->js_cx, value))==NULL) {
return;
}
JS_DefineProperty(session->js_cx, session->js_header, lckey, STRING_TO_JSVAL(js_str)
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
}
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
#if 0
static void js_parse_multipart(http_session_t * session, char *p) {
size_t key_len;
size_t value_len;
char *lp;
char *key;
char *value;
if(p == NULL)
return;
lp=p;
while((key_len=strcspn(lp,"="))!=0) {
key=lp;
lp+=key_len;
if(*lp) {
*lp=0;
lp++;
}
value_len=strcspn(lp,"&");
value=lp;
lp+=value_len;
if(*lp) {
*lp=0;
lp++;
}
unescape(value);
unescape(key);
js_add_queryval(session, key, value);
}
}
#endif
static void js_parse_query(http_session_t * session, char *p) {
size_t key_len;
size_t value_len;
char *lp;
char *key;
char *value;
if(p == NULL)
return;
lp=p;
key=lp;
lp+=key_len;
value_len=strcspn(lp,"&");
value=lp;
unescape(value);
unescape(key);
js_add_queryval(session, key, value);
}
}
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
static char *get_token_value(char **p)
{
char *pos=*p;
char *start;
char *out;
BOOL escaped=FALSE;
start=pos;
out=start;
if(*pos=='"') {
for(pos++; *pos; pos++) {
if(escaped && *pos)
*(out++)=*pos;
else if(*pos=='"') {
pos++;
break;
}
else if(*pos=='\\')
escaped=TRUE;
else
*(out++)=*pos;
}
}
else {
for(; *pos; pos++) {
if(iscntrl(*pos))
break;
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
switch(*pos) {
case 0:
case '(':
case ')':
case '<':
case '>':
case '@':
case ',':
case ';':
case ':':
case '\\':
case '"':
case '/':
case '[':
case ']':
case '?':
case '=':
case '{':
case '}':
case ' ':
case '\t':
goto end_of_text;
}
*(out++)=*pos;
}
}
end_of_text:
while(*pos==',' || isspace(*pos))
pos++;
*out=0;
*p=pos;
return(start);
}
static int hexval(unsigned char ch)
{
ch-='0';
if(ch<10)
return(ch);
ch-=7;
if(ch<16 && ch>9)
return(ch);
if(ch>41) {
ch-=32;
if(ch<16 && ch>9)
return(ch);
}
return(0);
}
static BOOL parse_headers(http_session_t * session)
{
char *p;
int i;
size_t idx;
size_t content_len=0;
for(idx=0;session->req.headers[idx]!=NULL;idx++) {
/* TODO: strdup() is possibly too slow here... */
head_line=strdup(session->req.headers[idx]);
if((strtok_r(head_line,":",&last))!=NULL && (value=strtok_r(NULL,"",&last))!=NULL) {
i=get_header_type(head_line);
while(*value && *value<=' ') value++;
switch(i) {
case HEAD_AUTH:
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
if((p=strtok_r(value," ",&last))!=NULL) {
if(stricmp(p, "Basic")==0) {
p=strtok_r(NULL," ",&last);
if(p==NULL)
break;
while(*p && *p<' ') p++;
b64_decode(p,strlen(p),p,strlen(p));
p=strtok_r(p,":",&last);
if(p) {
if(strlen(p) >= sizeof(session->req.auth.username))
break;
SAFECOPY(session->req.auth.username, p);
p=strtok_r(NULL,":",&last);
if(p) {
if(strlen(p) >= sizeof(session->req.auth.password))
break;
SAFECOPY(session->req.auth.password, p);
session->req.auth.type=AUTHENTICATION_BASIC;
}
}
}
else if(stricmp(p, "Digest")==0) {
p=strtok_r(NULL, "", &last);
/* Defaults */
session->req.auth.algorithm=ALGORITHM_MD5;
session->req.auth.type=AUTHENTICATION_DIGEST;
/* Parse out values one at a time and store */
while(*p) {
while(isspace(*p))
p++;
if(strnicmp(p,"username=",9)==0) {
p+=9;
tvalue=get_token_value(&p);
if(strlen(tvalue) >= sizeof(session->req.auth.username))
break;
SAFECOPY(session->req.auth.username, tvalue);
}
else if(strnicmp(p,"realm=",6)==0) {
p+=6;
session->req.auth.realm=strdup(get_token_value(&p));
}
else if(strnicmp(p,"nonce=",6)==0) {
p+=6;
session->req.auth.nonce=strdup(get_token_value(&p));
}
else if(strnicmp(p,"uri=",4)==0) {
p+=4;
session->req.auth.digest_uri=strdup(get_token_value(&p));
}
else if(strnicmp(p,"response=",9)==0) {
p+=9;
tvalue=get_token_value(&p);
if(strlen(tvalue)==32) {
for(i=0; i<16; i++) {
session->req.auth.digest[i]=hexval(tvalue[i*2])<<4 | hexval(tvalue[i*2+1]);
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
}
}
}
else if(strnicmp(p,"algorithm=",10)==0) {
p+=10;
tvalue=get_token_value(&p);
if(stricmp(tvalue,"MD5")==0) {
session->req.auth.algorithm=ALGORITHM_MD5;
}
else {
session->req.auth.algorithm=ALGORITHM_UNKNOWN;
}
}
else if(strnicmp(p,"cnonce=",7)==0) {
p+=7;
session->req.auth.cnonce=strdup(get_token_value(&p));
}
else if(strnicmp(p,"qop=",4)==0) {
p+=4;
tvalue=get_token_value(&p);
if(stricmp(tvalue,"auth")==0) {
session->req.auth.qop_value=QOP_AUTH;
}
else if (stricmp(tvalue,"auth-int")==0) {
session->req.auth.qop_value=QOP_AUTH_INT;
}
else {
session->req.auth.qop_value=QOP_UNKNOWN;
}
}
else if(strnicmp(p,"nc=",3)==0) {
p+=3;
session->req.auth.nonce_count=strdup(get_token_value(&p));
}
else {
p++;
if(*p == '=')
get_token_value(&p);
}
if(session->req.auth.digest_uri==NULL)
session->req.auth.digest_uri=strdup(session->req.request_line);
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
/* Validate that we have the required values... */
switch(session->req.auth.qop_value) {
case QOP_NONE:
if(session->req.auth.realm==NULL
|| session->req.auth.nonce==NULL
|| session->req.auth.digest_uri==NULL)
send_error(session,"400 Bad Request");
break;
case QOP_AUTH:
case QOP_AUTH_INT:
if(session->req.auth.realm==NULL
|| session->req.auth.nonce==NULL
|| session->req.auth.nonce_count==NULL
|| session->req.auth.cnonce==NULL
|| session->req.auth.digest_uri==NULL)
send_error(session,"400 Bad Request");
break;
default:
send_error(session,"400 Bad Request");
break;
}
break;
case HEAD_LENGTH:
add_env(session,"CONTENT_LENGTH",value);
break;
case HEAD_IFMODIFIED:
session->req.if_modified_since=decode_date(value);
break;
case HEAD_CONNECTION:
if(!stricmp(value,"Keep-Alive")) {
session->req.keep_alive=TRUE;
}
if(!stricmp(value,"Close")) {
session->req.keep_alive=FALSE;
}
case HEAD_REFERER:
if(session->req.ld!=NULL) {
FREE_AND_NULL(session->req.ld->referrer);
/* FREE()d in http_logging_thread() */
session->req.ld->referrer=strdup(value);
break;
case HEAD_AGENT:
if(session->req.ld!=NULL) {
FREE_AND_NULL(session->req.ld->agent);
/* FREE()d in http_logging_thread() */
session->req.ld->agent=strdup(value);
break;
case HEAD_TRANSFER_ENCODING:
if(!stricmp(value,"chunked"))
session->req.read_chunked=TRUE;
else
send_error(session,"501 Not Implemented");
break;
if(!stricmp(value,"bytes=")) {
send_error(session,error_416);
break;
}
value+=6;
if(strchr(value,',')!=NULL) { /* We don't do multiple ranges yet - TODO */
send_error(session,error_416);
break;
}
/* Check for offset from end. */
if(*value=='-') {
session->req.range_start=strtol(value,NULL,10);
session->req.range_end=-1;
break;
}
if((p=strtok_r(value,"-",&last))!=NULL) {
session->req.range_start=strtol(p,NULL,10);
if((p=strtok_r(NULL,"-",&last))!=NULL)
session->req.range_end=strtol(p,NULL,10);
else
session->req.range_end=-1;
}
else {
send_error(session,error_416);
break;
case HEAD_IFRANGE:
session->req.if_range=decode_date(value);
break;
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
case HEAD_TYPE:
add_env(session,"CONTENT_TYPE",value);
break;
default:
break;
}
sprintf(env_name,"HTTP_%s",head_line);
add_env(session,env_name,value);
}
free(head_line);
}
if(content_len)
session->req.post_len = content_len;
add_env(session,"SERVER_NAME",session->req.host[0] ? session->req.host : startup->host_name );
return TRUE;
}
static BOOL parse_js_headers(http_session_t * session)
{
char *head_line;
char *value;
char *last;
char *p;
int i;
size_t idx;
for(idx=0;session->req.headers[idx]!=NULL;idx++) {
head_line=session->req.headers[idx];
if((strtok_r(head_line,":",&last))!=NULL && (value=strtok_r(NULL,"",&last))!=NULL) {
i=get_header_type(head_line);
while(*value && *value<=' ') value++;
js_add_header(session,head_line,value);
switch(i) {
case HEAD_TYPE:
if(session->req.dynamic==IS_SSJS || session->req.dynamic==IS_JS) {
/*
* We need to parse out the files based on RFC1867
*
* And example reponse looks like this:
* Content-type: multipart/form-data, boundary=AaB03x
*
* --AaB03x
* content-disposition: form-data; name="field1"
*
* Joe Blow
* --AaB03x
* content-disposition: form-data; name="pics"
* Content-type: multipart/mixed, boundary=BbC04y
*
* --BbC04y
* Content-disposition: attachment; filename="file1.txt"
*
* Content-Type: text/plain
*
* ... contents of file1.txt ...
* --BbC04y
* Content-disposition: attachment; filename="file2.gif"
* Content-type: image/gif
* Content-Transfer-Encoding: binary
*
* ...contents of file2.gif...
* --BbC04y--
* --AaB03x--
*/
}
break;
case HEAD_COOKIE:
if(session->req.dynamic==IS_SSJS || session->req.dynamic==IS_JS) {
char *key;
char *val;
p=value;
while((key=strtok_r(p,"=",&last))!=NULL) {
while(isspace(*key))
key++;
p=NULL;
if((val=strtok_r(p,";\t\n\v\f\r ",&last))!=NULL) { /* Whitespace */
js_add_cookieval(session,key,val);
}
}
}
break;
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
default:
break;
}
}
}
return TRUE;
}
static int get_version(char *p)
{
int i;
if(p==NULL)
return(0);
while(*p && *p<' ') p++;
if(*p==0)
return(0);
for(i=1;http_vers[i]!=NULL;i++) {
if(!stricmp(p,http_vers[i])) {
return(i);
}
}
return(i-1);
}
static int is_dynamic_req(http_session_t* session)
{
char drive[4];
char cgidrive[4];
char dir[MAX_PATH+1];
char cgidir[MAX_PATH+1];
char fname[MAX_PATH+1];
char ext[MAX_PATH+1];
check_extra_path(session);
_splitpath(session->req.physical_path, drive, dir, fname, ext);
if(stricmp(ext,startup->ssjs_ext)==0)
i=IS_SSJS;
else if(get_xjs_handler(ext,session))
i=IS_SSJS;
else if(stricmp(ext,startup->js_ext)==0)
i=IS_JS;
if(!(startup->options&BBS_OPT_NO_JAVASCRIPT) && i) {
lprintf(LOG_DEBUG,"%04d Setting up JavaScript support", session->socket);
if(!js_setup(session)) {
lprintf(LOG_ERR,"%04d !ERROR setting up JavaScript support", session->socket);
return(IS_STATIC);
}
if(!(startup->options&WEB_OPT_NO_CGI)) {
for(i=0; startup->cgi_ext!=NULL && startup->cgi_ext[i]!=NULL; i++) {
if(stricmp(ext,startup->cgi_ext[i])==0) {
return(IS_CGI);
}
}
_splitpath(session->req.cgi_dir?session->req.cgi_dir:cgi_dir, cgidrive, cgidir, fname, ext);
if(stricmp(dir,cgidir)==0 && stricmp(drive,cgidrive)==0) {
}
}
return(IS_STATIC);
}
static char *get_request(http_session_t * session, char *req_line)
char* p;
char* retval;
SKIP_WHITESPACE(req_line);
SAFECOPY(session->req.virtual_path,req_line);
if(strtok_r(session->req.virtual_path," \t",&last))
retval=strtok_r(NULL," \t",&last);
else
retval=NULL;
SAFECOPY(session->req.request_line,session->req.virtual_path);
if(strtok_r(session->req.virtual_path,"?",&last))
query=strtok_r(NULL,"",&last);
else
query=NULL;
/* Must initialize physical_path before calling is_dynamic_req() */
SAFECOPY(session->req.physical_path,session->req.virtual_path);
unescape(session->req.physical_path);
if(!strnicmp(session->req.physical_path,http_scheme,http_scheme_len)) {
/* Remove http:// from start of physical_path */
memmove(session->req.physical_path, session->req.physical_path+http_scheme_len, strlen(session->req.physical_path+http_scheme_len)+1);
/* Set HOST value... ignore HOST header */
SAFECOPY(session->req.host,session->req.physical_path);
/* Remove path if present (everything after the first /) */
strtok_r(session->req.host,"/",&last);
SAFECOPY(session->req.vhost,session->req.host);
/* Remove port specification from vhost (if present) */
strtok_r(session->req.vhost,":",&last);
/* Sets p to point to the first character after the first slash */
p=strchr(session->req.physical_path, '/');
* If we have a slash, make it the first char in the string.
* otherwise, set path to "/"
if(p==NULL) {
strcpy(session->req.physical_path, "/");
}
else {
offset=p-session->req.physical_path;
memmove(session->req.physical_path
,session->req.physical_path+offset
,strlen(session->req.physical_path+offset)+1 /* move '\0' terminator too */
);
}
}
SAFECOPY(session->req.query_str,query);
return(retval);
}
static char *get_method(http_session_t * session, char *req_line)
{
int i;
for(i=0;methods[i]!=NULL;i++) {
if(!strnicmp(req_line,methods[i],strlen(methods[i]))) {
session->req.method=i;
if(strlen(req_line)<strlen(methods[i])+2) {
send_error(session,"400 Bad Request");
return(NULL);
}
return(req_line+strlen(methods[i])+1);
}
}
if(req_line!=NULL && *req_line>=' ')
send_error(session,"501 Not Implemented");
return(NULL);
}
static BOOL get_request_headers(http_session_t * session)
{
char head_line[MAX_REQUEST_LINE+1];
char next_char;
char *value;
int i;
while(sockreadline(session,head_line,sizeof(head_line)-1)>0) {
/* Multi-line headers */
while((i=recv(session->socket,&next_char,1,MSG_PEEK))>0
&& (next_char=='\t' || next_char==' ')) {
if(i==-1 && ERROR_VALUE != EAGAIN)
close_socket(&session->socket);
i=strlen(head_line);
if(i>sizeof(head_line)-1) {
lprintf(LOG_ERR,"%04d !ERROR long multi-line header. The web server is broken!", session->socket);
i=sizeof(head_line)/2;
break;
}
sockreadline(session,head_line+i,sizeof(head_line)-i-1);
}
strListPush(&session->req.headers,head_line);
if((strtok_r(head_line,":",&last))!=NULL && (value=strtok_r(NULL,"",&last))!=NULL) {
i=get_header_type(head_line);
while(*value && *value<=' ') value++;
switch(i) {
case HEAD_HOST:
if(session->req.host[0]==0) {
SAFECOPY(session->req.host,value);
SAFECOPY(session->req.vhost,value);
/* Remove port part of host (Win32 doesn't allow : in dir names) */
/* Either an existing : will be replaced with a null, or nothing */
/* Will happen... the return value is not relevent here */
strtok_r(session->req.vhost,":",&last);
}
break;
default:
break;
}
}
}
if(!(session->req.vhost[0]))
SAFECOPY(session->req.vhost, startup->host_name);
if(!(session->req.host[0]))
SAFECOPY(session->req.host, startup->host_name);
return TRUE;
}
static BOOL get_fullpath(http_session_t * session)
{
char str[MAX_PATH+1];
if(session->req.vhost[0] && startup->options&WEB_OPT_VIRTUAL_HOSTS) {
safe_snprintf(str,sizeof(str),"%s/%s",root_dir,session->req.vhost);
safe_snprintf(str,sizeof(str),"%s/%s%s",root_dir,session->req.vhost,session->req.physical_path);
else
safe_snprintf(str,sizeof(str),"%s%s",root_dir,session->req.physical_path);
} else
safe_snprintf(str,sizeof(str),"%s%s",root_dir,session->req.physical_path);
if(FULLPATH(session->req.physical_path,str,sizeof(session->req.physical_path))==NULL)
return(isabspath(session->req.physical_path));
static BOOL get_req(http_session_t * session, char *request_line)
req_line[0]=0;
if(request_line == NULL) {
/* Eat leaing blank lines... as apache does...
* "This is a legacy issue. The CERN webserver required POST data to have an extra
* CRLF following it. Thus many clients send an extra CRLF that is not included in the
* Content-Length of the request. Apache works around this problem by eating any empty
* lines which appear before a request."
* http://httpd.apache.org/docs/misc/known_client_problems.html
*/
while((len=sockreadline(session,req_line,sizeof(req_line)-1))==0);
if(len<0)
return(FALSE);
lprintf(LOG_INFO,"%04d Request: %s",session->socket,req_line);
if(session->req.ld!=NULL && session->req.ld->request==NULL)
/* FREE()d in http_logging_thread() */
session->req.ld->request=strdup(req_line);
}
else {
lprintf(LOG_DEBUG,"%04d Handling Internal Redirect to: %s",session->socket,request_line);
SAFECOPY(req_line,request_line);
}
if(req_line[0]) {
p=NULL;
p=get_method(session,req_line);
if(p!=NULL) {
p=get_request(session,p);
session->http_ver=get_version(p);
if(session->http_ver>=HTTP_1_1)
session->req.keep_alive=TRUE;
if(!is_redir)
get_request_headers(session);
if(!get_fullpath(session)) {
send_error(session,error_500);
if(session->req.ld!=NULL && session->req.ld->vhost==NULL)
/* FREE()d in http_logging_thread() */
session->req.ld->vhost=strdup(session->req.vhost);
session->req.dynamic=is_dynamic_req(session);
if(session->req.query_str[0])
add_env(session,"QUERY_STRING",session->req.query_str);
add_env(session,"REQUEST_METHOD",methods[session->req.method]);
add_env(session,"SERVER_PROTOCOL",session->http_ver ?
http_vers[session->http_ver] : "HTTP/0.9");
send_error(session,"400 Bad Request");
return FALSE;
}
/* This may exist somewhere else - ToDo */
static char *find_last_slash(char *str)
{
#ifdef _WIN32
char * LastFSlash;
char * LastBSlash;
LastFSlash=strrchr(str,'/');
LastBSlash=strrchr(str,'\\');
if(LastFSlash==NULL)
return(LastBSlash);
if(LastBSlash==NULL)
return(LastFSlash);
if(LastBSlash < LastFSlash)
return(LastFSlash);
return(LastBSlash);
#else
return(strrchr(str,'/'));
#endif
}
/* This may exist somewhere else - ToDo */
static char *find_first_slash(char *str)
{
#ifdef _WIN32
char * FirstFSlash;
char * FirstBSlash;
FirstFSlash=strchr(str,'/');
FirstBSlash=strchr(str,'\\');
if(FirstFSlash==NULL)
return(FirstBSlash);
if(FirstBSlash==NULL)
return(FirstFSlash);
if(FirstBSlash > FirstFSlash)
return(FirstFSlash);
return(FirstBSlash);
#else
return(strchr(str,'/'));
#endif
}
static BOOL check_extra_path(http_session_t * session)
char *rp_slash;
char *vp_slash;
char rpath[MAX_PATH+1];
char vpath[MAX_PATH+1];
char epath[MAX_PATH+1];
char str[MAX_PATH+1];
struct stat sb;
int i;
char *end;
epath[1]=0;
if(IS_PATH_DELIM(*lastchar(session->req.physical_path)) || stat(session->req.physical_path,&sb)==-1 /* && errno==ENOTDIR */)
{
SAFECOPY(vpath,session->req.virtual_path);
SAFECOPY(rpath,session->req.physical_path);
while((vp_slash=find_last_slash(vpath))!=NULL)
*vp_slash=0;
if((rp_slash=find_last_slash(rpath))==NULL)
return(FALSE);
SAFECOPY(str,epath);
if(*rp_slash)
sprintf(epath,"%s%s",rp_slash,str);
*(rp_slash+1)=0;
/* Check if this contains an index */
end=strchr(rpath,0);
if(session->req.path_info_index) {
if(isdir(rpath) && !isdir(session->req.physical_path)) {
for(i=0; startup->index_file_name!=NULL && startup->index_file_name[i]!=NULL ;i++) {
*end=0;
strcat(rpath,startup->index_file_name[i]);
if(!stat(rpath,&sb)) {
SAFECOPY(session->req.extra_path_info,epath);
SAFECOPY(session->req.virtual_path,vpath);
strcat(session->req.virtual_path,"/");
SAFECOPY(session->req.physical_path,rpath);
return(TRUE);
}
/* rpath was an existing path and DID NOT contain an index. */
/* We do not allow scripts to mask existing dirs/files */
return(FALSE);
}
else {
if(isdir(rpath))
return(FALSE);
}
if(vp_slash==vpath)
return(FALSE);
/* Check if this is a script */
*rp_slash=0;
if(vp_slash!=vpath) {
if(stat(rpath,&sb)!=-1 && (!(sb.st_mode&S_IFDIR)))
{
SAFECOPY(session->req.extra_path_info,epath);
SAFECOPY(session->req.virtual_path,vpath);
SAFECOPY(session->req.physical_path,rpath);
return(TRUE);
}
}
}
}
return(FALSE);
}
static BOOL check_request(http_session_t * session)
{
char path[MAX_PATH+1];
char curdir[MAX_PATH+1];
char str[MAX_PATH+1];
char last_ch;
char* last_slash;
char filename[MAX_PATH+1];
char *spec;
str_list_t specs;
BOOL recheck_dynamic=FALSE;
if(session->req.finished)
return(FALSE);
SAFECOPY(path,session->req.physical_path);
lprintf(LOG_DEBUG,"%04d Path is: %s",session->socket,path);
if(isdir(path)) {
last_ch=*lastchar(path);
if(!IS_PATH_DELIM(last_ch)) {
strcat(session->req.physical_path,"/");
last_ch=*lastchar(session->req.virtual_path);
if(!IS_PATH_DELIM(last_ch)) {
strcat(session->req.virtual_path,"/");
}
last_slash=find_last_slash(path);
send_error(session,error_500);
last_slash++;
for(i=0; startup->index_file_name!=NULL && startup->index_file_name[i]!=NULL ;i++) {
*last_slash=0;
strcat(path,startup->index_file_name[i]);
lprintf(LOG_DEBUG,"%04d Checking for %s",session->socket,path);
SAFECOPY(path,session->req.physical_path);
/* Don't send 404 unless authourized... prevent info leak */
if(startup->index_file_name==NULL || startup->index_file_name[i] == NULL)
send404=1;
else {
strcat(session->req.virtual_path,startup->index_file_name[i]);
if(session->req.send_location != MOVED_PERM)
session->req.send_location=MOVED_STAT;
filename[0]=0;
}
else {
last_slash=find_last_slash(path);
if(last_slash==NULL)
last_slash=path;
else
last_slash++;
strcpy(filename,last_slash);
if(strnicmp(path,root_dir,strlen(root_dir))) {
session->req.keep_alive=FALSE;
send_error(session,"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*/
while((last_slash=find_first_slash(p+1))!=NULL) {
/* Terminate the path after the slash */
*(last_slash+1)=0;
sprintf(str,"%saccess.ars",curdir);
/* NEVER serve up an access.ars file */
lprintf(LOG_WARNING,"%04d !WARNING! access.ars support is depreciated and will be REMOVED very soon.",session->socket);
lprintf(LOG_WARNING,"%04d !WARNING! access.ars found at %s.",session->socket,str);
if(!strcmp(path,str)) {
send_error(session,"403 Forbidden");
return(FALSE);
}
/* 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;
}
/* Truncate at \r or \n - can use last_slash since I'm done with it.*/
truncsp(session->req.ars);
}
sprintf(str,"%swebctrl.ini",curdir);
if(!stat(str,&sb)) {
/* NEVER serve up a webctrl.ini file */
if(!strcmp(path,str)) {
send_error(session,"403 Forbidden");
return(FALSE);
}
if((file=fopen(str,"r"))!=NULL) {
specs=iniReadSectionList(file,NULL);
/* Read in globals */
if(iniReadString(file, NULL, "AccessRequirements", session->req.ars,str)==str)
SAFECOPY(session->req.ars,str);
if(iniReadString(file, NULL, "Realm", scfg.sys_name,str)==str) {
FREE_AND_NULL(session->req.realm);
/* FREE()d in close_request() */
session->req.realm=strdup(str);
if(iniReadString(file, NULL, "DigestRealm", scfg.sys_name,str)==str) {
FREE_AND_NULL(session->req.digest_realm);
/* FREE()d in close_request() */
session->req.digest_realm=strdup(str);
}
if(iniReadString(file, NULL, "ErrorDirectory", error_dir,str)==str) {
prep_dir(root_dir, str, sizeof(str));
/* FREE()d in close_request() */
session->req.error_dir=strdup(str);
}