Newer
Older
size_t i;
if(cgi_handlers==NULL || (ext=getfext(fname))==NULL)
return(NULL);
for(i=0;cgi_handlers[i]!=NULL;i++) {
if(stricmp(cgi_handlers[i]->name, ext+1)==0)
return(cgi_handlers[i]->value);
}
return(NULL);
}
static BOOL get_xjs_handler(char* ext, http_session_t* session)
{
size_t i;
if(ext==NULL || xjs_handlers==NULL || ext[0]==0)
return(FALSE);
for(i=0;xjs_handlers[i]!=NULL;i++) {
if(stricmp(xjs_handlers[i]->name, ext+1)==0) {
if(getfname(xjs_handlers[i]->value)==xjs_handlers[i]->value) /* no path specified */
SAFEPRINTF2(session->req.xjs_handler,"%s%s",scfg.exec_dir,xjs_handlers[i]->value);
else
SAFECOPY(session->req.xjs_handler,xjs_handlers[i]->value);
return(TRUE);
}
}
return(FALSE);
}
/* This function appends append plus a newline IF the final dst string would have a length less than maxlen */
static void safecat(char *dst, const char *append, size_t maxlen) {
size_t dstlen,appendlen;
dstlen=strlen(dst);
appendlen=strlen(append);
if(dstlen+appendlen+2 < maxlen) {
strcat(dst,append);
strcat(dst,newline);
}
}
/*************************************************/
/* Sends headers for the reply. */
/* HTTP/0.9 doesn't use headers, so just returns */
/*************************************************/
static BOOL send_headers(http_session_t *session, const char *status, int chunked)
int ret;
int stat_code;
size_t idx;
const char *status_line;
struct stat stats;
struct tm tm;
char *headers;
if(session->socket==INVALID_SOCKET) {
session->req.sent_headers=TRUE;
return(FALSE);
lprintf(LOG_DEBUG,"%04d Request resolved to: %s"
,session->socket,session->req.physical_path);
if(session->http_ver <= HTTP_0_9) {
if(session->req.ld != NULL)
session->req.ld->status=atoi(status);
headers=alloca(MAX_HEADERS_SIZE);
if(headers==NULL) {
lprintf(LOG_CRIT,"Could not allocate memory for response headers.");
return(FALSE);
}
*headers=0;
if(!session->req.sent_headers) {
status_line=status;
ret=stat(session->req.physical_path,&stats);
if(session->req.method==HTTP_OPTIONS)
ret=-1;
if(!ret && session->req.if_modified_since && (stats.st_mtime <= session->req.if_modified_since) && !session->req.dynamic) {
status_line="304 Not Modified";
ret=-1;
send_file=FALSE;
if(!ret && session->req.if_range && (stats.st_mtime > session->req.if_range || session->req.dynamic)) {
status_line="200 OK";
session->req.range_start=0;
session->req.range_end=0;
}
if(session->req.send_location==MOVED_PERM) {
status_line=error_301;
ret=-1;
send_file=FALSE;
}
if(session->req.send_location==MOVED_TEMP) {
status_line=error_302;
ret=-1;
send_file=FALSE;
}
stat_code=atoi(status_line);
if(session->req.ld!=NULL)
session->req.ld->status=stat_code;
if(stat_code==304 || stat_code==204 || (stat_code >= 100 && stat_code<=199)) {
send_file=FALSE;
chunked=FALSE;
}
/* Status-Line */
safe_snprintf(header,sizeof(header),"%s %s",http_vers[session->http_ver],status_line);
lprintf(LOG_DEBUG,"%04d Result: %s",session->socket,header);
safecat(headers,header,MAX_HEADERS_SIZE);
/* General Headers */
ti=time(NULL);
if(gmtime_r(&ti,&tm)==NULL)
memset(&tm,0,sizeof(tm));
safe_snprintf(header,sizeof(header),"%s: %s, %02d %s %04d %02d:%02d:%02d GMT"
,get_header(HEAD_DATE)
,days[tm.tm_wday],tm.tm_mday,months[tm.tm_mon]
,tm.tm_year+1900,tm.tm_hour,tm.tm_min,tm.tm_sec);
safecat(headers,header,MAX_HEADERS_SIZE);
if(session->req.keep_alive) {
safe_snprintf(header,sizeof(header),"%s: %s",get_header(HEAD_CONNECTION),"Keep-Alive");
safecat(headers,header,MAX_HEADERS_SIZE);
}
else {
safe_snprintf(header,sizeof(header),"%s: %s",get_header(HEAD_CONNECTION),"Close");
safecat(headers,header,MAX_HEADERS_SIZE);
}
/* Response Headers */
safe_snprintf(header,sizeof(header),"%s: %s",get_header(HEAD_SERVER),VERSION_NOTICE);
safecat(headers,header,MAX_HEADERS_SIZE);
/* 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);
if(session->req.send_location) {
safe_snprintf(header,sizeof(header),"%s: %s",get_header(HEAD_LOCATION),(session->req.virtual_path));
safecat(headers,header,MAX_HEADERS_SIZE);
}
if(chunked) {
safe_snprintf(header,sizeof(header),"%s: %s",get_header(HEAD_TRANSFER_ENCODING),"Chunked");
safecat(headers,header,MAX_HEADERS_SIZE);
}
/* DO NOT send a content-length for chunked */
if(send_entity) {
if(session->req.keep_alive && session->req.dynamic!=IS_CGI && (!chunked)) {
if(ret) {
safe_snprintf(header,sizeof(header),"%s: %s",get_header(HEAD_LENGTH),"0");
safecat(headers,header,MAX_HEADERS_SIZE);
}
else {
if((session->req.range_start || session->req.range_end) && atoi(status_line)==206) {
safe_snprintf(header,sizeof(header),"%s: %d",get_header(HEAD_LENGTH),session->req.range_end-session->req.range_start+1);
safecat(headers,header,MAX_HEADERS_SIZE);
}
else {
safe_snprintf(header,sizeof(header),"%s: %d",get_header(HEAD_LENGTH),(int)stats.st_size);
safecat(headers,header,MAX_HEADERS_SIZE);
}
if(!ret && !session->req.dynamic) {
safe_snprintf(header,sizeof(header),"%s: %s",get_header(HEAD_TYPE),session->req.mime_type);
safecat(headers,header,MAX_HEADERS_SIZE);
gmtime_r(&stats.st_mtime,&tm);
safe_snprintf(header,sizeof(header),"%s: %s, %02d %s %04d %02d:%02d:%02d GMT"
,get_header(HEAD_LASTMODIFIED)
,days[tm.tm_wday],tm.tm_mday,months[tm.tm_mon]
,tm.tm_year+1900,tm.tm_hour,tm.tm_min,tm.tm_sec);
safecat(headers,header,MAX_HEADERS_SIZE);
}
if(session->req.range_start || session->req.range_end) {
switch(atoi(status_line)) {
case 206: /* Partial reply */
safe_snprintf(header,sizeof(header),"%s: bytes %d-%d/%d",get_header(HEAD_CONTENT_RANGE),session->req.range_start,session->req.range_end,stats.st_size);
safecat(headers,header,MAX_HEADERS_SIZE);
break;
default:
safe_snprintf(header,sizeof(header),"%s: *",get_header(HEAD_CONTENT_RANGE));
safecat(headers,header,MAX_HEADERS_SIZE);
break;
}
if(session->req.dynamic) {
/* Dynamic headers */
/* Set up environment */
for(idx=0;session->req.dynamic_heads[idx]!=NULL;idx++)
safecat(headers,session->req.dynamic_heads[idx],MAX_HEADERS_SIZE);
/* free() the headers so they don't get sent again if more are sent at the end of the request (chunked) */
strListFreeStrings(session->req.dynamic_heads);
safecat(headers,"",MAX_HEADERS_SIZE);
send_file = (bufprint(session,headers) && send_file);
drain_outbuf(session);
session->req.write_chunked=chunked;
static int sock_sendfile(http_session_t *session,char *path,unsigned long start, unsigned long end)
int ret=0;
int i;
char buf[2048]; /* Input buffer */
if(startup->options&WEB_OPT_DEBUG_TX)
lprintf(LOG_DEBUG,"%04d Sending %s",session->socket,path);
if((file=open(path,O_RDONLY|O_BINARY))==-1)
lprintf(LOG_WARNING,"%04d !ERROR %d opening %s",session->socket,errno,path);
if(lseek(file, start, SEEK_SET)==-1) {
lprintf(LOG_WARNING,"%04d !ERROR %d seeking to position %lu in %s",session->socket,ERROR_VALUE,start,path);
}
else {
remain=-1L;
}
while((i=read(file, buf, remain>sizeof(buf)?sizeof(buf):remain))>0) {
if(writebuf(session,buf,i)!=i) {
lprintf(LOG_WARNING,"%04d !ERROR sending %s",session->socket,path);
return(0);
}
ret+=i;
}
close(file);
}
return(ret);
/********************************************************/
/* Sends a specified error message, closes the request, */
/* and marks the session to be closed */
/********************************************************/
static void send_error(http_session_t * session, const char* message)
{
char error_code[4];
char sbuf[MAX_PATH+1];
char sbuf2[MAX_PATH+1];
BOOL sent_ssjs=FALSE;
if(session->socket==INVALID_SOCKET)
return;
session->req.if_modified_since=0;
lprintf(LOG_INFO,"%04d !ERROR: %s",session->socket,message);
session->req.keep_alive=FALSE;
session->req.send_location=NO_LOCATION;
SAFECOPY(error_code,message);
SAFECOPY(session->req.status,message);
if(atoi(error_code)<500) {
/*
* Attempt to run SSJS error pages
* If this fails, do the standard error page instead,
* ie: Don't "upgrade" to a 500 error
*/
if(session->req.error_dir) {
/* We have a custom error directory from webctrl.ini look there first */
sprintf(sbuf,"%s%s%s",session->req.error_dir,error_code,startup->ssjs_ext);
if(stat(sbuf,&sb)) {
/* No custom .ssjs error message... check for custom .html */
sprintf(sbuf2,"%s%s.html",session->req.error_dir,error_code);
if(stat(sbuf2,&sb)) {
/* Nope, no custom .html error either, check for global ssjs one */
sprintf(sbuf,"%s%s%s",error_dir,error_code,startup->ssjs_ext);
}
}
}
else
sprintf(sbuf,"%s%s%s",error_dir,error_code,startup->ssjs_ext);
if(!stat(sbuf,&sb)) {
lprintf(LOG_INFO,"%04d Using SSJS error page",session->socket);
if(js_setup(session)) {
sent_ssjs=exec_ssjs(session,sbuf);
if(sent_ssjs) {
int snt=0;
lprintf(LOG_INFO,"%04d Sending generated error page",session->socket);
snt=sock_sendfile(session,session->req.physical_path,0,0);
if(snt<0)
snt=0;
if(session->req.ld!=NULL)
session->req.ld->size=snt;
}
else
session->req.dynamic=IS_STATIC;
}
else
session->req.dynamic=IS_STATIC;
}
}
if(!sent_ssjs) {
if(session->req.error_dir) {
sprintf(session->req.physical_path,"%s%s.html",session->req.error_dir,error_code);
if(stat(session->req.physical_path,&sb))
sprintf(session->req.physical_path,"%s%s.html",error_dir,error_code);
}
else
sprintf(session->req.physical_path,"%s%s.html",error_dir,error_code);
session->req.mime_type=get_mime_type(strrchr(session->req.physical_path,'.'));
send_headers(session,message,FALSE);
if(!stat(session->req.physical_path,&sb)) {
int snt=0;
snt=sock_sendfile(session,session->req.physical_path,0,0);
if(snt<0)
snt=0;
if(session->req.ld!=NULL)
session->req.ld->size=snt;
}
else {
lprintf(LOG_NOTICE,"%04d Error message file %s doesn't exist"
,session->socket,session->req.physical_path);
safe_snprintf(sbuf,sizeof(sbuf)
,"<HTML><HEAD><TITLE>%s Error</TITLE></HEAD>"
"<BODY><H1>%s Error</H1><BR><H3>In addition, "
"I can't seem to find the %s error file</H3><br>"
"please notify <a href=\"mailto:sysop@%s\">"
"%s</a></BODY></HTML>"
,error_code,error_code,error_code,scfg.sys_inetaddr,scfg.sys_op);
bufprint(session,sbuf);
if(session->req.ld!=NULL)
session->req.ld->size=strlen(sbuf);
}
}
drain_outbuf(session);
session->req.finished=TRUE;
void http_logon(http_session_t * session, user_t *usr)
{
char str[128];
if(usr==NULL)
getuserdat(&scfg, &session->user);
else
session->user=*usr;
if(session->user.number==session->last_user_num)
return;
lprintf(LOG_DEBUG,"%04d HTTP Logon (user #%d)",session->socket,session->user.number);
if(session->subscan!=NULL)
getmsgptrs(&scfg,session->user.number,session->subscan);
if(session->user.number==0)
SAFECOPY(session->username,unknown);
SAFECOPY(session->username,session->user.alias);
/* Adjust Connect and host */
putuserrec(&scfg,session->user.number,U_MODEM,LEN_MODEM,"HTTP");
putuserrec(&scfg,session->user.number,U_COMP,LEN_COMP,session->host_name);
putuserrec(&scfg,session->user.number,U_NOTE,LEN_NOTE,session->host_ip);
putuserrec(&scfg,session->user.number,U_LOGONTIME,0,ultoa((ulong)session->logon_time,str,16));
session->client.user=session->username;
client_on(session->socket, &session->client, /* update existing client record? */TRUE);
session->last_user_num=session->user.number;
}
void http_logoff(http_session_t* session, SOCKET socket, int line)
{
if(session->last_user_num<=0)
return;
lprintf(LOG_DEBUG,"%04d HTTP Logoff (user #%d) from line %d"
,socket,session->user.number, line);
SAFECOPY(session->username,unknown);
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));
session->last_user_num=session->user.number;
}
BOOL http_checkuser(http_session_t * session)
{
if(session->req.dynamic==IS_SSJS || session->req.dynamic==IS_JS) {
if(session->last_js_user_num==session->user.number)
return(TRUE);
lprintf(LOG_DEBUG,"%04d JavaScript: Initializing User Objects",session->socket);
JS_BEGINREQUEST(session->js_cx);
if(session->user.number>0) {
if(!js_CreateUserObjects(session->js_cx, session->js_glob, &scfg, &session->user, &session->client
,NULL /* ftp index file */, session->subscan /* subscan */)) {
JS_ENDREQUEST(session->js_cx);
lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user objects",session->socket);
send_error(session,"500 Error initializing JavaScript User Objects");
return(FALSE);
}
}
else {
if(!js_CreateUserObjects(session->js_cx, session->js_glob, &scfg, /* user: */NULL, &session->client
,NULL /* ftp index file */, session->subscan /* subscan */)) {
JS_ENDREQUEST(session->js_cx);
lprintf(LOG_ERR,"%04d !ERROR initializing JavaScript User Objects",session->socket);
send_error(session,"500 Error initializing JavaScript User Objects");
return(FALSE);
}
}
JS_ENDREQUEST(session->js_cx);
session->last_js_user_num=session->user.number;
}
return(TRUE);
}
static void calculate_digest(http_session_t * session, char *ha1, char *ha2, unsigned char digest[MD5_DIGEST_SIZE])
{
MD5 ctx;
MD5_open(&ctx);
MD5_digest(&ctx, ha1, strlen(ha1));
MD5_digest(&ctx, ":", 1);
/* exception on next line (session->req.auth.nonce==NULL) */
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
MD5_digest(&ctx, session->req.auth.nonce, strlen(session->req.auth.nonce));
MD5_digest(&ctx, ":", 1);
if(session->req.auth.qop_value != QOP_NONE) {
MD5_digest(&ctx, session->req.auth.nonce_count, strlen(session->req.auth.nonce_count));
MD5_digest(&ctx, ":", 1);
MD5_digest(&ctx, session->req.auth.cnonce, strlen(session->req.auth.cnonce));
MD5_digest(&ctx, ":", 1);
switch(session->req.auth.qop_value) {
case QOP_AUTH:
MD5_digest(&ctx, "auth", 4);
break;
case QOP_AUTH_INT:
MD5_digest(&ctx, "auth-int", 7);
break;
}
MD5_digest(&ctx, ":", 1);
}
MD5_digest(&ctx, ha2, strlen(ha2));
MD5_close(&ctx, digest);
}
static BOOL check_ars(http_session_t * session)
{
uchar *ar;
BOOL authorized;
int i;
user_t thisuser;
int auth_allowed=0;
unsigned *auth_list;
unsigned auth_list_len;
auth_list=parseEnumList(session->req.auth_list?session->req.auth_list:default_auth_list, ",", auth_type_names, &auth_list_len);
auth_allowed |= 1<<auth_list[i];
if(auth_list)
free(auth_list);
/* No authentication provided */
if(session->req.auth.type==AUTHENTICATION_UNKNOWN) {
/* No authentication information... */
if(session->last_user_num!=0) {
if(session->last_user_num>0)
http_logoff(session,session->socket,__LINE__);
session->user.number=0;
http_logon(session,NULL);
}
if(!http_checkuser(session))
return(FALSE);
if(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);
return(FALSE);
}
/* No auth required, allow */
return(TRUE);
}
/* Require a password */
i=matchuser(&scfg, session->req.auth.username, FALSE);
if(i==0) {
if(session->last_user_num!=0) {
if(session->last_user_num>0)
http_logoff(session,session->socket,__LINE__);
session->user.number=0;
http_logon(session,NULL);
}
if(!http_checkuser(session))
return(FALSE);
if(scfg.sys_misc&SM_ECHO_PW && session->req.auth.type==AUTHENTICATION_BASIC)
lprintf(LOG_NOTICE,"%04d !UNKNOWN USER: %s, Password: %s"
,session->socket,session->req.auth.username,session->req.auth.password);
else
lprintf(LOG_NOTICE,"%04d !UNKNOWN USER: %s"
,session->socket,session->req.auth.username);
return(FALSE);
}

deuce
committed
thisuser.number=i;
getuserdat(&scfg, &thisuser);
switch(session->req.auth.type) {
case AUTHENTICATION_BASIC:
if((auth_allowed & (1<<AUTHENTICATION_BASIC))==0)
return(FALSE);
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
if(thisuser.pass[0] && stricmp(thisuser.pass,session->req.auth.password)) {
if(session->last_user_num!=0) {
if(session->last_user_num>0)
http_logoff(session,session->socket,__LINE__);
session->user.number=0;
http_logon(session,NULL);
}
if(!http_checkuser(session))
return(FALSE);
/* Should go to the hack log? */
if(scfg.sys_misc&SM_ECHO_PW)
lprintf(LOG_WARNING,"%04d !PASSWORD FAILURE for user %s: '%s' expected '%s'"
,session->socket,session->req.auth.username,session->req.auth.password,thisuser.pass);
else
lprintf(LOG_WARNING,"%04d !PASSWORD FAILURE for user %s"
,session->socket,session->req.auth.username);
#ifdef _WIN32
if(startup->hack_sound[0] && !(startup->options&BBS_OPT_MUTE))
PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
#endif
return(FALSE);
}
break;
case AUTHENTICATION_DIGEST:
{
unsigned char digest[MD5_DIGEST_SIZE];
char ha1[MD5_DIGEST_SIZE*2+1];
char ha1l[MD5_DIGEST_SIZE*2+1];
char ha1u[MD5_DIGEST_SIZE*2+1];
char *pass;
char *p;
time32_t nonce_time;
time32_t now;
MD5 ctx;
if((auth_allowed & (1<<AUTHENTICATION_DIGEST))==0)
return(FALSE);
if(session->req.auth.qop_value==QOP_UNKNOWN)
return(FALSE);
if(session->req.auth.algorithm==ALGORITHM_UNKNOWN)
return(FALSE);
/* Validate rules from RFC-2617 */
if(session->req.auth.qop_value==QOP_AUTH
|| session->req.auth.qop_value==QOP_AUTH_INT) {
if(session->req.auth.cnonce==NULL)
return(FALSE);
if(session->req.auth.nonce_count==NULL)
return(FALSE);
}
else {
if(session->req.auth.cnonce!=NULL)
return(FALSE);
if(session->req.auth.nonce_count!=NULL)
return(FALSE);
}
/* H(A1) */
MD5_open(&ctx);
MD5_digest(&ctx, session->req.auth.username, strlen(session->req.auth.username));
MD5_digest(&ctx, ":", 1);
MD5_digest(&ctx, session->req.digest_realm?session->req.digest_realm:(session->req.realm?session->req.realm:scfg.sys_name), strlen(session->req.digest_realm?session->req.digest_realm:(session->req.realm?session->req.realm:scfg.sys_name)));
MD5_digest(&ctx, ":", 1);
MD5_digest(&ctx, thisuser.pass, strlen(thisuser.pass));
MD5_close(&ctx, digest);
MD5_hex(ha1, digest);
/* H(A1)l */
pass=strdup(thisuser.pass);
strlwr(pass);
MD5_open(&ctx);
MD5_digest(&ctx, session->req.auth.username, strlen(session->req.auth.username));
MD5_digest(&ctx, ":", 1);
MD5_digest(&ctx, session->req.digest_realm?session->req.digest_realm:(session->req.realm?session->req.realm:scfg.sys_name), strlen(session->req.digest_realm?session->req.digest_realm:(session->req.realm?session->req.realm:scfg.sys_name)));
MD5_digest(&ctx, ":", 1);
MD5_digest(&ctx, pass, strlen(pass));
MD5_close(&ctx, digest);
MD5_hex(ha1l, digest);
/* H(A1)u */
strupr(pass);
MD5_open(&ctx);
MD5_digest(&ctx, session->req.auth.username, strlen(session->req.auth.username));
MD5_digest(&ctx, ":", 1);
MD5_digest(&ctx, session->req.digest_realm?session->req.digest_realm:(session->req.realm?session->req.realm:scfg.sys_name), strlen(session->req.digest_realm?session->req.digest_realm:(session->req.realm?session->req.realm:scfg.sys_name)));
MD5_digest(&ctx, ":", 1);
MD5_digest(&ctx, thisuser.pass, strlen(thisuser.pass));
MD5_close(&ctx, digest);
MD5_hex(ha1u, digest);
free(pass);
/* H(A2) */
MD5_open(&ctx);
MD5_digest(&ctx, methods[session->req.method], strlen(methods[session->req.method]));
MD5_digest(&ctx, ":", 1);
/* exception here, session->req.auth.digest_uri==NULL */
MD5_digest(&ctx, session->req.auth.digest_uri, strlen(session->req.auth.digest_uri));
/* TODO QOP==AUTH_INT */
if(session->req.auth.qop_value == QOP_AUTH_INT)
return(FALSE);
MD5_close(&ctx, digest);
MD5_hex(ha2, digest);
/* Check password as in user.dat */
calculate_digest(session, ha1, ha2, digest);
if(thisuser.pass[0]) { // Zero-length password is "special" (any password will work)
if(memcmp(digest, session->req.auth.digest, sizeof(digest))) {
/* Check against lower-case password */
calculate_digest(session, ha1l, ha2, digest);
if(memcmp(digest, session->req.auth.digest, sizeof(digest))) {
/* Check against upper-case password */
calculate_digest(session, ha1u, ha2, digest);
if(memcmp(digest, session->req.auth.digest, sizeof(digest)))
return(FALSE);
}
/* Validate nonce */
p=strchr(session->req.auth.nonce, '@');
if(p==NULL) {
session->req.auth.stale=TRUE;
return(FALSE);
}
*p=0;
if(strcmp(session->req.auth.nonce, session->client.addr)) {
session->req.auth.stale=TRUE;
return(FALSE);
}
*p='@';
p++;
nonce_time=strtoul(p, &p, 10);
if(*p) {
session->req.auth.stale=TRUE;
return(FALSE);
}
now=(time32_t)time(NULL);
if(nonce_time > now) {
session->req.auth.stale=TRUE;
return(FALSE);
}
if(nonce_time < now-1800) {
session->req.auth.stale=TRUE;
return(FALSE);
}
if(i != session->last_user_num) {
http_logoff(session,session->socket,__LINE__);
session->user.number=i;
http_logon(session,&thisuser);
}
if(!http_checkuser(session))
return(FALSE);
if(session->req.ld!=NULL) {
FREE_AND_NULL(session->req.ld->user);
/* FREE()d in http_logging_thread */
session->req.ld->user=strdup(session->req.auth.username);
ar = arstr(NULL,session->req.ars,&scfg);
authorized=chk_ar(&scfg,ar,&session->user,&session->client);
if(ar!=NULL && ar!=nular)
switch(session->req.auth.type) {
case AUTHENTICATION_BASIC:
add_env(session,"AUTH_TYPE","Basic");
break;
case AUTHENTICATION_DIGEST:
add_env(session,"AUTH_TYPE","Digest");
break;
}
/* Should use real name if set to do so somewhere ToDo */
add_env(session,"REMOTE_USER",session->user.alias);
return(TRUE);
/* Should go to the hack log? */
lprintf(LOG_WARNING,"%04d !AUTHORIZATION FAILURE for user %s, ARS: %s"
,session->socket,session->req.auth.username,session->req.ars);
#ifdef _WIN32
if(startup->hack_sound[0] && !(startup->options&BBS_OPT_MUTE))
PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
#endif
return(FALSE);
}
static named_string_t** read_ini_list(char* path, char* section, char* desc
,named_string_t** list)
size_t i;
list=iniFreeNamedStringList(list);
if((fp=iniOpenFile(path, /* create? */FALSE))!=NULL) {
list=iniReadNamedStringList(fp,section);
iniCloseFile(fp);
COUNT_LIST_ITEMS(list,i);
if(i)
lprintf(LOG_DEBUG,"Read %u %s from %s section of %s"
,i,desc,section==NULL ? "root":section,path);
return(list);
static int sockreadline(http_session_t * session, char *buf, size_t length)
fd_set rd_set;
struct timeval tv;
if(session->socket==INVALID_SOCKET)
return(-1);
FD_ZERO(&rd_set);
FD_SET(session->socket,&rd_set);
/* Convert timeout from ms to sec/usec */
tv.tv_sec=startup->max_inactivity;
tv.tv_usec=0;
sel=select(session->socket+1,&rd_set,NULL,NULL,&tv);
switch(sel) {
case -1:
close_socket(&session->socket);
lprintf(LOG_DEBUG,"%04d !ERROR %d selecting socket for read",session->socket,ERROR_VALUE);
lprintf(LOG_NOTICE,"%04d Session timeout due to inactivity (%d seconds)",session->socket,startup->max_inactivity);
switch(recv(session->socket, &ch, 1, 0)) {
case -1:
if(ERROR_VALUE!=EAGAIN) {
if(startup->options&WEB_OPT_DEBUG_RX)
lprintf(LOG_DEBUG,"%04d !ERROR %d receiving on socket",session->socket,ERROR_VALUE);
close_socket(&session->socket);
return(-1);
}
break;
case 0:
close_socket(&session->socket);
return(-1);
}
if(ch=='\n')
break;
if(i<length)
buf[i++]=ch;
else
chucked++;
/* Terminate at length if longer */
if(i>length)
i=length;
while(i>0 && buf[i-1]=='\r')
i--;
buf[i]=0;
if(startup->options&WEB_OPT_DEBUG_RX) {
lprintf(LOG_DEBUG,"%04d RX: %s",session->socket,buf);
lprintf(LOG_DEBUG,"%04d Long header, chucked %d bytes",session->socket,chucked);
}
#if defined(_WIN32)
static int pipereadline(HANDLE pipe, char *buf, size_t length, char *fullbuf, size_t fullbuf_len)
#else
static int pipereadline(int pipe, char *buf, size_t length, char *fullbuf, size_t fullbuf_len)
#endif
{
char ch;
DWORD i;
#ifndef _WIN32
struct timeval tv={0,0};
fd_set read_set;
#endif
/* Terminate buffers */
if(buf != NULL)
buf[0]=0;
if(fullbuf != NULL)
fullbuf[0]=0;
for(i=0;TRUE;) {
#if defined(_WIN32)
ret=0;
ReadFile(pipe, &ch, 1, (DWORD*)&ret, NULL);
#else
tv.tv_sec=startup->max_cgi_inactivity;
tv.tv_usec=0;
FD_ZERO(&read_set);
FD_SET(pipe, &read_set);
if(select(pipe+1, &read_set, NULL, NULL, &tv)<1)
return(-1);
#endif
if(fullbuf != NULL && i < (fullbuf_len-1)) {
fullbuf[i]=ch;
fullbuf[i+1]=0;
}
if(ch=='\n')
break;
}
}
/* Terminate at length if longer */
if(i>length)
i=length;
int recvbufsocket(SOCKET *sock, char *buf, long count)
{
int rd=0;
if(count<1) {
errno=ERANGE;
return(0);
}
while(rd<count && socket_check(*sock,NULL,NULL,startup->max_inactivity*1000)) {
i=recv(*sock,buf+rd,count-rd,0);
switch(i) {
case -1:
if(ERROR_VALUE!=EAGAIN)
close_socket(sock);
case 0:
close_socket(sock);
*buf=0;
return(0);
}
rd+=i;
start=time(NULL);
}
if(rd==count) {
return(rd);
}
*buf=0;
}
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
static void unescape(char *p)
{
char * dst;
char code[3];
dst=p;
for(;*p;p++) {
if(*p=='%' && isxdigit(*(p+1)) && isxdigit(*(p+2))) {
sprintf(code,"%.2s",p+1);
*(dst++)=(char)strtol(code,NULL,16);
p+=2;
}
else {
if(*p=='+') {
*(dst++)=' ';
}
else {
*(dst++)=*p;
}
}
}
*(dst)=0;
}
static void js_add_queryval(http_session_t * session, char *key, char *value)
JSObject* keyarray;
jsval val;
int alen;
/* Return existing object if it's already been created */
if(JS_GetProperty(session->js_cx,session->js_query,key,&val) && val!=JSVAL_VOID) {
keyarray = JSVAL_TO_OBJECT(val);
alen=-1;
}
else {
keyarray = JS_NewArrayObject(session->js_cx, 0, NULL);
if(!JS_DefineProperty(session->js_cx, session->js_query, key, OBJECT_TO_JSVAL(keyarray)
, NULL, NULL, JSPROP_ENUMERATE))
return;
alen=0;
}
if(alen==-1) {
if(JS_GetArrayLength(session->js_cx, keyarray, &len)==JS_FALSE)
return;
}
lprintf(LOG_DEBUG,"%04d Adding query value %s=%s at pos %d",session->socket,key,value,alen);
val=STRING_TO_JSVAL(JS_NewStringCopyZ(session->js_cx,value));
JS_SetElement(session->js_cx, keyarray, alen, &val);
}
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
static void js_add_cookieval(http_session_t * session, char *key, char *value)
{
JSObject* keyarray;
jsval val;
jsuint len;
int alen;
/* Return existing object if it's already been created */
if(JS_GetProperty(session->js_cx,session->js_cookie,key,&val) && val!=JSVAL_VOID) {
keyarray = JSVAL_TO_OBJECT(val);
alen=-1;
}
else {
keyarray = JS_NewArrayObject(session->js_cx, 0, NULL);
if(!JS_DefineProperty(session->js_cx, session->js_cookie, key, OBJECT_TO_JSVAL(keyarray)
, NULL, NULL, JSPROP_ENUMERATE))
return;
alen=0;
}
if(alen==-1) {
if(JS_GetArrayLength(session->js_cx, keyarray, &len)==JS_FALSE)
return;
alen=len;
}