string cvs_version = "$Id: configuration.pike,v 1.87 1997/11/29 19:48:02 grubba Exp $"; |
#include <module.h> |
#include <roxen.h> |
|
|
|
inherit "roxenlib"; |
|
import Array; |
|
|
function store = roxen->store; |
function retrieve = roxen->retrieve; |
function remove = roxen->remove; |
function do_dest = roxen->do_dest; |
function create_listen_socket = roxen->create_listen_socket; |
|
|
|
object parse_module; |
object types_module; |
object auth_module; |
object dir_module; |
|
function types_fun; |
function auth_fun; |
|
string name; |
|
|
|
|
|
mapping variables = ([]); |
|
public mixed query(string var) |
{ |
if(var && variables[var]) |
return variables[var][ VAR_VALUE ]; |
if(!var) return variables; |
error("query("+var+"): Unknown variable.\n"); |
} |
|
mixed set(string var, mixed val) |
{ |
#if DEBUG_LEVEL > 30 |
perror(sprintf("MAIN: set(\"%s\", %O)\n", var, val)); |
#endif |
if(variables[var]) |
{ |
#if DEBUG_LEVEL > 28 |
perror("MAIN: Setting global variable.\n"); |
#endif |
return variables[var][VAR_VALUE] = val; |
} |
error("set("+var+"). Unknown variable.\n"); |
} |
|
int setvars( mapping (string:mixed) vars ) |
{ |
string v; |
|
foreach( indices( vars ), v ) |
if(variables[v]) |
variables[v][ VAR_VALUE ] = vars[ v ]; |
return 1; |
} |
|
|
|
void killvar(string name) |
{ |
m_delete(variables, name); |
} |
|
varargs int defvar(string var, mixed value, string name, int type, |
string doc_str, mixed misc, int|function not_in_config) |
{ |
variables[var] = allocate( VAR_SIZE ); |
variables[var][ VAR_VALUE ] = value; |
variables[var][ VAR_TYPE ] = type & VAR_TYPE_MASK; |
variables[var][ VAR_DOC_STR ] = doc_str; |
variables[var][ VAR_NAME ] = name; |
variables[var][ VAR_MISC ] = misc; |
|
if((type&~VAR_TYPE_MASK) & VAR_EXPERT) |
variables[var][ VAR_CONFIGURABLE ] = VAR_EXPERT; |
else if((type&~VAR_TYPE_MASK) & VAR_MORE) |
variables[var][ VAR_CONFIGURABLE ] = VAR_MORE; |
else |
if(intp(not_in_config)) |
variables[var][ VAR_CONFIGURABLE ]= !not_in_config; |
else if(functionp(not_in_config)) |
variables[var][ VAR_CONFIGURABLE ]= not_in_config; |
variables[var][ VAR_SHORTNAME ] = var; |
} |
|
int definvisvar(string var, mixed value, int type) |
{ |
return defvar(var, value, "", type, "", 0, 1); |
} |
|
|
string query_name() |
{ |
if(strlen(QUERY(name))) return QUERY(name); |
return name; |
} |
|
string comment() |
{ |
return QUERY(comment); |
} |
|
class Priority |
{ |
array (object) url_modules = ({ }); |
array (object) logger_modules = ({ }); |
array (object) location_modules = ({ }); |
array (object) filter_modules = ({ }); |
array (object) last_modules = ({ }); |
array (object) first_modules = ({ }); |
|
mapping (string:array(object)) extension_modules = ([ ]); |
mapping (string:array(object)) file_extension_modules = ([ ]); |
|
|
void stop() |
{ |
foreach(url_modules, object m) catch { m->stop(); }; |
foreach(logger_modules, object m) catch { m->stop(); }; |
foreach(filter_modules, object m) catch { m->stop(); }; |
foreach(location_modules, object m)catch { m->stop(); }; |
foreach(last_modules, object m) catch { m->stop(); }; |
foreach(first_modules, object m) catch { m->stop(); }; |
} |
} |
|
|
|
|
|
|
|
|
array (object) allocate_pris() |
{ |
int a; |
array (object) tmp; |
tmp=allocate(10); |
for(a=0; a<10; a++) tmp[a]=Priority(); |
return tmp; |
} |
|
class Bignum { |
|
|
#if efun(Mpz) && 0 // FIXME: Need #if module(Gmp.mpz) |
inherit Gmp.mpz; |
float mb() |
{ |
return (float)this_object()/(1024.0*1024.0); |
} |
#else |
int msb; |
int lsb=-0x7ffffffe; |
|
object `-(int i); |
object `+(int i) |
{ |
if(!i) return this_object(); |
if(i<0) return `-(-i); |
object res = object_program(this_object())(lsb+i,msb,2); |
if(res->lsb < lsb) res->msb++; |
return res; |
} |
|
object `-(int i) |
{ |
if(!i) return this_object(); |
if(i<0) return `+(-i); |
object res = object_program(this_object())(lsb-i,msb,2); |
if(res->lsb > lsb) res->msb--; |
return res; |
} |
|
float mb() |
{ |
return ((((float)lsb/1024.0/1024.0)+2048.0)+(msb*4096.0)); |
} |
|
void create(int|void num, int|void bnum, int|void d) |
{ |
if(!d) |
lsb = num-0x7ffffffe; |
else |
lsb = num; |
msb = bnum; |
} |
#endif |
} |
|
|
|
|
int requests; |
|
mapping(string:mixed) extra_statistics = ([]); |
mapping(string:mixed) misc = ([]); |
|
object sent=Bignum(); |
object hsent=Bignum(); |
object received=Bignum(); |
|
object this = this_object(); |
|
|
|
|
|
private object *_toparse_modules = ({}); |
|
|
|
|
|
private function log_function; |
|
|
|
private mapping (string:string) log_format = ([]); |
|
|
private array (object) pri = allocate_pris(); |
|
|
|
public mapping (string:mapping(string:mixed)) modules = ([]); |
|
|
public mapping (object:string) otomod = ([]); |
|
|
|
|
|
private array (function) url_module_cache, last_module_cache; |
private array (function) logger_module_cache, first_module_cache; |
private array (function) filter_module_cache; |
private array (array (string|function)) location_module_cache; |
private mapping (string:array (function)) extension_module_cache=([]); |
private mapping (string:array (function)) file_extension_module_cache=([]); |
|
|
|
void stop() |
{ |
catch { parse_module->stop(); }; |
catch { types_module->stop(); }; |
catch { auth_module->stop(); }; |
catch { dir_module->stop(); }; |
for(int i=0; i<10; i++) catch { pri[i]->stop(); }; |
} |
|
public varargs string type_from_filename( string file, int to ) |
{ |
mixed tmp; |
object current_configuration; |
string ext=extension(file); |
|
if(!types_fun) |
return to?({ "application/octet-stream", 0 }):"application/octet-stream"; |
|
while(file[-1] == '/') |
file = file[0..strlen(file)-2]; |
|
if(tmp = types_fun(ext)) |
{ |
mixed tmp2,nx; |
if(tmp[0] == "strip") |
{ |
tmp2=file/"."; |
if(sizeof(tmp2) > 2) |
nx=tmp2[-2]; |
if(nx && (tmp2=types_fun(nx))) |
tmp[0] = tmp2[0]; |
else |
if(tmp2=types_fun("default")) |
tmp[0] = tmp2[0]; |
else |
tmp[0]="application/octet-stream"; |
} |
return to?tmp:tmp[0]; |
} else { |
if(!(tmp=types_fun("default"))) |
tmp=({ "application/octet-stream", 0 }); |
} |
return 0; |
} |
|
|
|
array (function) extension_modules(string ext, object id) |
{ |
if(!extension_module_cache[ext]) |
{ |
int i; |
extension_module_cache[ext] = ({ }); |
for(i=9; i>=0; i--) |
{ |
object *d, p; |
if(d = pri[i]->extension_modules[ext]) |
foreach(d, p) |
extension_module_cache[ext] += ({ p->handle_extension }); |
} |
} |
return extension_module_cache[ext]; |
} |
|
array (function) file_extension_modules(string ext, object id) |
{ |
if(!file_extension_module_cache[ext]) |
{ |
int i; |
file_extension_module_cache[ext] = ({ }); |
for(i=9; i>=0; i--) |
{ |
object *d, p; |
if(d = pri[i]->file_extension_modules[ext]) |
foreach(d, p) |
file_extension_module_cache[ext] += ({ p->handle_file_extension }); |
} |
} |
return file_extension_module_cache[ext]; |
} |
|
array (function) url_modules(object id) |
{ |
if(!url_module_cache) |
{ |
int i; |
url_module_cache=({ }); |
for(i=9; i>=0; i--) |
{ |
object *d, p; |
if(d=pri[i]->url_modules) |
foreach(d, p) |
url_module_cache += ({ p->remap_url }); |
} |
} |
return url_module_cache; |
} |
|
array (function) logger_modules(object id) |
{ |
if(!logger_module_cache) |
{ |
int i; |
logger_module_cache=({ }); |
for(i=9; i>=0; i--) |
{ |
object *d, p; |
if(d=pri[i]->logger_modules) |
foreach(d, p) |
if(p->log) |
logger_module_cache += ({ p->log }); |
} |
} |
return logger_module_cache; |
} |
|
array (function) last_modules(object id) |
{ |
if(!last_module_cache) |
{ |
int i; |
last_module_cache=({ }); |
for(i=9; i>=0; i--) |
{ |
object *d, p; |
if(d=pri[i]->last_modules) |
foreach(d, p) |
if(p->last_resort) |
last_module_cache += ({ p->last_resort }); |
} |
} |
return last_module_cache; |
} |
|
array (function) first_modules(object id) |
{ |
if(!first_module_cache) |
{ |
int i; |
first_module_cache=({ }); |
for(i=9; i>=0; i--) |
{ |
object *d, p; |
if(d=pri[i]->first_modules) { |
foreach(d, p) { |
if(p->first_try) { |
first_module_cache += ({ p->first_try }); |
} |
} |
} |
} |
} |
|
return first_module_cache; |
} |
|
|
array location_modules(object id) |
{ |
if(!location_module_cache) |
{ |
int i; |
array new_location_module_cache=({ }); |
for(i=9; i>=0; i--) |
{ |
object *d, p; |
if(d=pri[i]->location_modules) { |
array level_find_files = ({}); |
array level_locations = ({}); |
foreach(d, p) { |
string location; |
|
if(p->find_file && (location = p->query_location())) { |
level_find_files += ({ p->find_file }); |
level_locations += ({ location }); |
} |
} |
sort(level_locations, level_find_files); |
int j; |
for (j = sizeof(level_locations); j--;) { |
|
new_location_module_cache += ({ ({ level_locations[j], |
level_find_files[j] }) }); |
} |
} |
} |
location_module_cache = new_location_module_cache; |
} |
return location_module_cache; |
} |
|
array filter_modules(object id) |
{ |
if(!filter_module_cache) |
{ |
int i; |
filter_module_cache=({ }); |
for(i=9; i>=0; i--) |
{ |
object *d, p; |
if(d=pri[i]->filter_modules) |
foreach(d, p) |
if(p->filter) |
filter_module_cache+=({ p->filter }); |
} |
} |
return filter_module_cache; |
} |
|
|
|
|
|
void init_log_file() |
{ |
remove_call_out(init_log_file); |
|
if(log_function) |
{ |
destruct(function_object(log_function)); |
|
} |
|
if(query("Log")) |
{ |
mapping m = localtime(time()); |
string logfile = query("LogFile"); |
if(m->mday < 10) m->mday = "0"+m->mday; |
if(m->mon < 10) m->mon = "0"+m->mon; |
if(m->hour < 10) m->hour = "0"+m->hour; |
logfile = replace(logfile,({"%d","%m","%y","%h" }), |
({ (string)m->mday, (string)(m->mon+1), |
(string)(m->year+1900),(string)m->hour,})); |
if(strlen(logfile)) |
{ |
do { |
object privs = Privs("Opening logfile \""+logfile+"\""); |
object lf=open( logfile, "wac"); |
if(!lf) { |
mkdirhier(logfile); |
if(!(lf=open( logfile, "wac"))) { |
privs = 0; |
report_error("Failed to open logfile. ("+logfile+")\n" + |
"No logging will take place!\n"); |
log_function=0; |
break; |
} |
} |
privs=0; |
mark_fd(lf->query_fd(), "Roxen log file ("+logfile+")"); |
log_function=lf->write; |
|
lf=0; |
} while(0); |
} else |
log_function=0; |
call_out(init_log_file, 60); |
} else |
log_function=0; |
} |
|
|
private inline string fix_logging(string s) |
{ |
string pre, post, c; |
sscanf(s, "%*[\t ]", s); |
s = replace(s, ({"\\t", "\\n", "\\r" }), ({"\t", "\n", "\r" })); |
|
|
|
|
while(s[0] == ' ') s = s[1..]; |
while(s[0] == '\t') s = s[1..]; |
while(sscanf(s, "%s$char(%d)%s", pre, c, post)==3) |
s=sprintf("%s%c%s", pre, c, post); |
while(sscanf(s, "%s$wchar(%d)%s", pre, c, post)==3) |
s=sprintf("%s%2c%s", pre, c, post); |
while(sscanf(s, "%s$int(%d)%s", pre, c, post)==3) |
s=sprintf("%s%4c%s", pre, c, post); |
if(!sscanf(s, "%s$^%s", pre, post)) |
s+="\n"; |
else |
s=pre+post; |
return s; |
} |
|
private void parse_log_formats() |
{ |
string b; |
array foo=query("LogFormat")/"\n"; |
foreach(foo, b) |
if(strlen(b) && b[0] != '#' && sizeof(b/":")>1) |
log_format[(b/":")[0]] = fix_logging((b/":")[1..]*":"); |
} |
|
|
|
|
private void write_to_log( string host, string rest, string oh, function fun ) |
{ |
int s; |
if(!host) host=oh; |
if(!stringp(host)) |
host = "error:no_host"; |
if(fun) fun(replace(rest, "$host", host)); |
} |
|
|
nomask private inline string host_ip_to_int(string s) |
{ |
int a, b, c, d; |
sscanf(s, "%d.%d.%d.%d", a, b, c, d); |
return sprintf("%c%c%c%c",a, b, c, d); |
} |
|
nomask private inline string unsigned_to_bin(int a) |
{ |
return sprintf("%4c", a); |
} |
|
nomask private inline string unsigned_short_to_bin(int a) |
{ |
return sprintf("%2c", a); |
} |
|
nomask private inline string extract_user(string from) |
{ |
array tmp; |
if (!from || sizeof(tmp = from/":")<2) |
return "-"; |
|
return tmp[0]; |
} |
|
public void log(mapping file, object request_id) |
{ |
string a; |
string form; |
function f; |
|
foreach(logger_modules(request_id), f) |
if(f(request_id,file))return; |
|
if(!log_function) return; |
|
|
if(QUERY(NoLog) && _match(request_id->remoteaddr, QUERY(NoLog))) |
return; |
|
if(!(form=log_format[(string)file->error])) |
form = log_format["*"]; |
|
if(!form) return; |
|
form=replace(form, |
({ |
"$ip_number", "$bin-ip_number", "$cern_date", |
"$bin-date", "$method", "$resource", "$protocol", |
"$response", "$bin-response", "$length", "$bin-length", |
"$referer", "$user_agent", "$user", "$user_id", |
}), ({ |
(string)request_id->remoteaddr, |
host_ip_to_int(request_id->remoteaddr), |
cern_http_date(time(1)), |
unsigned_to_bin(time(1)), |
(string)request_id->method, |
http_encode_string((string)request_id->not_query), |
(string)request_id->prot, |
(string)(file->error||200), |
unsigned_short_to_bin(file->error||200), |
(string)(file->len>=0?file->len:"?"), |
unsigned_to_bin(file->len), |
(string) |
(sizeof(request_id->referer)?request_id->referer[0]:"-"), |
http_encode_string(sizeof(request_id->client)?request_id->client*" ":"-"), |
extract_user(request_id->realauth), |
(string)request_id->cookies->RoxenUserID, |
})); |
|
if(search(form, "host") != -1) |
roxen->ip_to_host(request_id->remoteaddr, write_to_log, form, |
request_id->remoteaddr, log_function); |
else |
log_function(form); |
} |
|
|
public string status() |
{ |
float tmp; |
string res=""; |
|
if(!sent||!received||!hsent) |
return "Fatal error in status(): Bignum object gone.\n"; |
|
tmp = (sent->mb()/(float)(time(1)-roxen->start_time+1)); |
res = sprintf("<table><tr align=right><td><b>Sent data:</b></td><td>%.2fMB" |
"</td><td>%.2f Kbit/sec</td>", |
sent->mb(),tmp * 8192.0); |
|
res += sprintf("<td><b>Sent headers:</b></td><td>%.2fMB</td></tr>\n", |
hsent->mb()); |
|
tmp=(((float)requests*(float)600)/ |
(float)((time(1)-roxen->start_time)+1)); |
|
res += sprintf("<tr align=right><td><b>Number of requests:</b></td>" |
"<td>%8d</td><td>%.2f/min</td>" |
"<td><b>Received data:</b></td><td>%.2fMB</td></tr>\n", |
requests, (float)tmp/(float)10, received->mb()); |
|
if (!zero_type(misc->ftp_users)) { |
tmp = (((float)misc->ftp_users*(float)600)/ |
(float)((time(1)-roxen->start_time)+1)); |
|
res += sprintf("<tr align=right><td><b>FTP users (total):</b></td>" |
"<td>%8d</td><td>%.2f/min</td>" |
"<td><b>FTP users (now):</b></td><td>%d</td></tr>\n", |
misc->ftp_users, (float)tmp/(float)10, misc->ftp_users_now); |
} |
res += "</table><p>\n\n"; |
|
if ((roxen->configuration_interface()->more_mode) && |
(extra_statistics->ftp) && (extra_statistics->ftp->commands)) { |
|
res += "<b>FTP statistics:</b><br>\n" |
"<ul><table>\n"; |
foreach(sort(indices(extra_statistics->ftp->commands)), string cmd) { |
res += sprintf("<tr align=right><td><b>%s</b></td>" |
"<td align=right>%d</td><td> time%s</td></tr>\n", |
upper_case(cmd), extra_statistics->ftp->commands[cmd], |
(extra_statistics->ftp->commands[cmd] == 1)?"":"s"); |
} |
res += "</table></ul>\n"; |
} |
|
return res; |
} |
|
public string *userinfo(string u, object|void id) |
{ |
if(auth_module) return auth_module->userinfo(u); |
} |
|
public string *userlist(object|void id) |
{ |
if(auth_module) return auth_module->userlist(); |
} |
|
public string *user_from_uid(int u, object|void id) |
{ |
if(auth_module) |
return auth_module->user_from_uid(u); |
} |
|
|
|
|
|
private mapping internal_gopher_image(string from) |
{ |
sscanf(from, "%s.gif", from); |
sscanf(from, "%s.jpg", from); |
from -= "."; |
|
|
|
return (["file":open("roxen-images/dir/"+from+".gif","r"), |
"type":"image/gif"]); |
} |
|
private static int nest = 0; |
|
#ifdef MODULE_LEVEL_SECURITY |
private mapping misc_cache=([]); |
|
int|mapping check_security(function a, object id, void|int slevel) |
{ |
array level; |
array seclevels; |
int ip_ok = 0; |
int auth_ok = 0; |
|
|
|
|
|
|
|
if(!(seclevels = misc_cache[ a ])) |
misc_cache[ a ] = seclevels = ({ |
function_object(a)->query_seclevels(), |
function_object(a)->query("_seclvl"), |
function_object(a)->query("_sec_group") |
}); |
|
if(slevel && (seclevels[1] > slevel)) |
return 1; |
|
if(!sizeof(seclevels[0])) |
return 0; |
|
catch { |
foreach(seclevels[0], level) { |
switch(level[0]) { |
case MOD_ALLOW: |
if(level[1](id->remoteaddr)) { |
ip_ok = ~0; |
} else { |
ip_ok |= 1; |
} |
break; |
|
case MOD_DENY: |
if(level[1](id->remoteaddr)) |
return http_low_answer(403, "<h2>Access forbidden</h2>"); |
break; |
|
case MOD_USER: |
if(id->auth && id->auth[0] && level[1](id->auth[1])) { |
auth_ok = ~0; |
} else { |
auth_ok |= 1; |
} |
break; |
|
case MOD_PROXY_USER: |
if (ip_ok != 1) { |
|
if(id->misc->proxyauth && id->misc->proxyauth[0] && |
level[1](id->misc->proxyauth[1])) return 0; |
return http_proxy_auth_required(seclevels[2]); |
} else { |
|
return(1); |
} |
} |
} |
}; |
if (ip_ok == 1) { |
|
return(1); |
} else { |
|
if (auth_ok == 1) { |
|
|
return(http_auth_failed(seclevels[2])); |
} else { |
|
return(0); |
} |
} |
} |
#endif |
|
void invalidate_cache() |
{ |
last_module_cache = 0; |
filter_module_cache = 0; |
first_module_cache = 0; |
url_module_cache = 0; |
location_module_cache = 0; |
logger_module_cache = 0; |
extension_module_cache = ([]); |
file_extension_module_cache = ([]); |
#ifdef MODULE_LEVEL_SECURITY |
if(misc_cache) |
misc_cache = ([ ]); |
#endif |
} |
|
|
string draw_saturation_bar(int hue,int brightness, int where) |
{ |
object bar=Image.image(30,256); |
|
for(int i=0;i<128;i++) |
{ |
int j = i*2; |
bar->line(0,j,29,j,@hsv_to_rgb(hue,255-j,brightness)); |
bar->line(0,j+1,29,j+1,@hsv_to_rgb(hue,255-j,brightness)); |
} |
|
where = 255-where; |
bar->line(0,where,29,where, 255,255,255); |
|
return bar->togif(255,255,255); |
} |
|
|
|
|
private mapping internal_roxen_image(string from) |
{ |
sscanf(from, "%s.gif", from); |
sscanf(from, "%s.jpg", from); |
|
|
|
|
|
|
from -= "."; |
|
|
|
|
int hue,bright,w; |
if(sscanf(from, "%*s:%d,%d,%d", hue, bright,w)==4) |
return http_string_answer(draw_saturation_bar(hue,bright,w),"image/gif"); |
|
if(object f=open("roxen-images/"+from+".gif", "r")) |
return (["file":f,"type":"image/gif"]); |
else |
return (["file":open("roxen-images/"+from+".jpg", "r"),"type":"image/jpeg"]); |
} |
|
|
|
|
|
mapping (mixed:function|int) locks = ([]); |
|
public mapping|int get_file(object id, int|void no_magic); |
|
#ifdef THREADS |
import Thread; |
|
mapping locked = ([]), thread_safe = ([]); |
|
object _lock(object|function f) |
{ |
object key; |
function|int l; |
|
if (functionp(f)) { |
f = function_object(f); |
} |
if (l = locks[f]) |
{ |
if (l != -1) |
{ |
|
catch |
{ |
|
locked[f]++; |
key = l(); |
}; |
} else |
thread_safe[f]++; |
} else if (f->thread_safe) { |
locks[f]=-1; |
thread_safe[f]++; |
} else { |
if (!locks[f]) |
{ |
|
l = Mutex()->lock; |
if (!locks[f]) { |
locks[f]=l; |
} |
} |
|
locked[f]++; |
key = l(); |
} |
return key; |
} |
|
#define LOCK(X) key=_lock(X) |
#define UNLOCK() do{key=0;}while(0) |
#else |
#define LOCK(X) |
#define UNLOCK(X) |
#endif |
|
mapping|int low_get_file(object id, int|void no_magic) |
{ |
#ifdef MODULE_LEVEL_SECURITY |
int slevel; |
#endif |
|
#ifdef THREADS |
object key; |
#endif |
|
string file=id->not_query; |
string loc; |
function funp; |
mixed tmp, tmp2; |
mapping|object fid; |
|
if(!no_magic) |
{ |
#ifndef NO_INTERNAL_HACK |
|
if(sizeof(id->not_query) && (id->not_query[0] == '/') && |
sscanf(id->not_query, "%*s/internal-%s", loc)) |
{ |
if(sscanf(loc, "gopher-%[^/]", loc)) |
return internal_gopher_image(loc); |
|
if(sscanf(loc, "spinner-%[^/]", loc) |
||sscanf(loc, "roxen-%[^/]", loc)) |
return internal_roxen_image(loc); |
} |
#endif |
|
if(id->prestate->diract && dir_module) |
{ |
LOCK(dir_module); |
tmp = dir_module->parse_directory(id); |
UNLOCK(); |
if(mappingp(tmp)) return tmp; |
} |
} |
|
|
|
|
#ifdef URL_MODULES |
|
foreach(url_modules(id), funp) |
{ |
LOCK(funp); |
tmp=funp( id, file ); |
UNLOCK(); |
|
if(mappingp(tmp)) |
return tmp; |
if(objectp( tmp )) |
{ |
array err; |
|
nest ++; |
err = catch { |
if( nest < 20 ) |
tmp = (id->conf || this_object())->low_get_file( tmp, no_magic ); |
else |
error("Too deep recursion in roxen::get_file() while mapping " |
+file+".\n"); |
}; |
nest = 0; |
if(err) |
throw(err); |
return tmp; |
} |
} |
#endif |
#ifdef EXTENSION_MODULES |
if(tmp=extension_modules(loc=extension(file), id)) |
{ |
foreach(tmp, funp) |
{ |
LOCK(funp); |
tmp=funp(loc, id); |
UNLOCK(); |
if(tmp) |
{ |
if(!objectp(tmp)) |
return tmp; |
fid = tmp; |
#ifdef MODULE_LEVEL_SECURITY |
slevel = function_object(funp)->query("_seclvl"); |
id->misc->seclevel = slevel; |
#endif |
break; |
} |
} |
} |
#endif |
|
foreach(location_modules(id), tmp) |
{ |
loc = tmp[0]; |
if(!search(file, loc)) |
{ |
#ifdef MODULE_LEVEL_SECURITY |
if(tmp2 = check_security(tmp[1], id, slevel)) |
if(intp(tmp2)) |
{ |
continue; |
} else { |
return tmp2; |
} |
#endif |
LOCK(tmp[1]); |
fid=tmp[1]( file[ strlen(loc) ..] + id->extra_extension, id); |
UNLOCK(); |
if(fid) |
{ |
id->virtfile = loc; |
|
if(mappingp(fid)) |
return fid; |
else |
{ |
#ifdef MODULE_LEVEL_SECURITY |
slevel = misc_cache[ tmp[1] ][1]; |
id->misc->seclevel = slevel; |
#endif |
break; |
} |
} |
} else if(strlen(loc)-1==strlen(file)) { |
|
|
if(file+"/" == loc) |
return http_redirect(id->not_query + "/", id); |
} |
} |
|
if(fid == -1) |
{ |
if(no_magic) return -1; |
if(dir_module) |
{ |
LOCK(dir_module); |
fid = dir_module->parse_directory(id); |
UNLOCK(); |
} |
else |
return 0; |
if(mappingp(fid)) return (mapping)fid; |
} |
|
|
if(objectp(fid)&& |
(tmp=file_extension_modules(loc=extension(id->not_query), id))) |
foreach(tmp, funp) |
{ |
#ifdef MODULE_LEVEL_SECURITY |
if(tmp=check_security(funp, id, slevel)) |
if(intp(tmp)) |
{ |
continue; |
} |
else |
return tmp; |
#endif |
LOCK(funp); |
tmp=funp(fid, loc, id); |
UNLOCK(); |
if(tmp) |
{ |
if(!objectp(tmp)) |
return tmp; |
if(fid) |
destruct(fid); |
fid = tmp; |
break; |
} |
} |
|
if(objectp(fid)) |
{ |
if(stringp(id->extension)) |
id->not_query += id->extension; |
|
tmp=type_from_filename(id->not_query, 1); |
|
if(tmp) |
return ([ "file":fid, "type":tmp[0], "encoding":tmp[1] ]); |
|
return ([ "file":fid, ]); |
} |
return fid; |
} |
|
mixed get_file(object id, int|void no_magic) |
{ |
mixed res, res2; |
function tmp; |
res = low_get_file(id, no_magic); |
|
|
|
foreach(filter_modules(id), tmp) |
if(res2=tmp(res,id)) |
{ |
if(res && res->file && (res2->file != res->file)) |
destruct(res->file); |
res=res2; |
} |
return res; |
} |
|
public array find_dir(string file, object id) |
{ |
string loc; |
array dir = ({ }), d, tmp; |
|
file=replace(file, "//", "/"); |
|
if(file[0] != '/') |
file = "/" + file; |
|
#ifdef URL_MODULES |
#ifdef THREADS |
object key; |
#endif |
|
foreach(url_modules(id), function funp) |
{ |
string of = id->not_query; |
id->not_query = file; |
LOCK(funp); |
tmp=funp( id, file ); |
UNLOCK(); |
|
if(mappingp( tmp )) |
{ |
id->not_query=of; |
return 0; |
} |
if(objectp( tmp )) |
{ |
array err; |
nest ++; |
|
file = id->not_query; |
err = catch { |
if( nest < 20 ) |
tmp = (id->conf || this_object())->find_dir( file, id ); |
else |
error("Too deep recursion in roxen::find_dir() while mapping " |
+file+".\n"); |
}; |
nest = 0; |
if(err) |
throw(err); |
return tmp; |
} |
id->not_query=of; |
} |
#endif /* URL_MODULES */ |
|
foreach(location_modules(id), tmp) |
{ |
loc = tmp[0]; |
|
if(!search(file, loc)) { |
|
#ifdef MODULE_LEVEL_SECURITY |
if(check_security(tmp[1], id)) continue; |
#endif |
if(d=function_object(tmp[1])->find_dir(file[strlen(loc)..], id)) |
dir |= d; |
} else if((search(loc, file)==0) && (loc[strlen(file)-1]=='/') && |
(loc[0]==loc[-1]) && (loc[-1]=='/') && |
(sizeof(function_object(tmp[1])->find_dir("", id) || ({})))) { |
|
|
|
loc=loc[strlen(file)..]; |
sscanf(loc, "%s/", loc); |
dir += ({ loc }); |
} |
} |
if(sizeof(dir)) |
return dir; |
} |
|
|
|
public array stat_file(string file, object id) |
{ |
string loc; |
array s, tmp; |
|
file=replace(file, "//", "/"); |
|
#ifdef URL_MODULES |
#ifdef THREADS |
object key; |
#endif |
|
foreach(url_modules(id), function funp) |
{ |
string of = id->not_query; |
id->not_query = file; |
|
LOCK(funp); |
tmp=funp( id, file ); |
UNLOCK(); |
|
if(mappingp( tmp )) { |
id->not_query = of; |
return 0; |
} |
if(objectp( tmp )) |
{ |
file = id->not_query; |
|
array err; |
nest ++; |
err = catch { |
if( nest < 20 ) |
tmp = (id->conf || this_object())->stat_file( file, id ); |
else |
error("Too deep recursion in roxen::stat_file() while mapping " |
+file+".\n"); |
}; |
nest = 0; |
if(err) |
throw(err); |
return tmp; |
} |
id->not_query = of; |
} |
#endif |
|
|
foreach(location_modules(id), tmp) |
{ |
loc = tmp[0]; |
if((file == loc) || ((file+"/")==loc)) |
return ({ 0775, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); |
if(!search(file, loc)) |
{ |
#ifdef MODULE_LEVEL_SECURITY |
if(check_security(tmp[1], id)) continue; |
#endif |
if(s=function_object(tmp[1])->stat_file(file[strlen(loc)..], id)) |
return s; |
} |
} |
} |
|
public mapping(string:array(mixed)) find_dir_stat(string file, object id) |
{ |
string loc; |
mapping(string:array(mixed)) dir = ([]); |
mixed d, tmp; |
|
file=replace(file, "//", "/"); |
|
if(file[0] != '/') |
file = "/" + file; |
|
#ifdef URL_MODULES |
#ifdef THREADS |
object key; |
#endif |
|
foreach(url_modules(id), function funp) |
{ |
string of = id->not_query; |
id->not_query = file; |
LOCK(funp); |
tmp=funp( id, file ); |
UNLOCK(); |
|
if(mappingp( tmp )) |
{ |
id->not_query=of; |
#ifdef MODULE_DEBUG |
roxen_perror(sprintf("conf->find_dir_stat(\"%s\"): url_module returned mapping:%O\n", |
file, tmp)); |
#endif /* MODULE_DEBUG */ |
return 0; |
} |
if(objectp( tmp )) |
{ |
array err; |
nest ++; |
|
file = id->not_query; |
err = catch { |
if( nest < 20 ) |
tmp = (id->conf || this_object())->find_dir_stat( file, id ); |
else |
error("Too deep recursion in roxen::find_dir_stat() while mapping " |
+file+".\n"); |
}; |
nest = 0; |
if(err) |
throw(err); |
#ifdef MODULE_DEBUG |
roxen_perror(sprintf("conf->find_dir_stat(\"%s\"): url_module returned object:\n", |
file)); |
#endif /* MODULE_DEBUG */ |
return tmp; |
} |
id->not_query=of; |
} |
#endif /* URL_MODULES */ |
|
foreach(location_modules(id), tmp) |
{ |
loc = tmp[0]; |
|
|
if(!search(file, loc)) |
{ |
|
#ifdef MODULE_LEVEL_SECURITY |
if(check_security(tmp[1], id)) continue; |
#endif |
object c = function_object(tmp[1]); |
string f = file[strlen(loc)..]; |
if (c->find_dir_stat) { |
if (d = c->find_dir_stat(f, id)) { |
dir = d | dir; |
} |
} else if(d = c->find_dir(f, id)) { |
dir = mkmapping(d, map(d, lambda(string f, string base, |
object c, object id) { |
return(c->stat_file(base + f, id)); |
}, f, c, id)) | dir; |
} |
} else if(search(loc, file)==0 && loc[strlen(file)-1]=='/' && |
(loc[0]==loc[-1]) && loc[-1]=='/' && |
sizeof(function_object(tmp[1])->find_dir("", id)||({}))) { |
|
|
|
loc=loc[strlen(file)..]; |
sscanf(loc, "%s/", loc); |
if (!dir[loc]) { |
dir[loc] = ({ 0775, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); |
} |
} |
} |
if(sizeof(dir)) |
return dir; |
} |
|
|
|
|
public array access(string file, object id) |
{ |
string loc; |
array s, tmp; |
|
file=replace(file, "//", "/"); |
|
|
foreach(location_modules(id), tmp) |
{ |
loc = tmp[0]; |
if((file+"/")==loc) |
return file+="/"; |
if(!search(file, loc)) |
{ |
#ifdef MODULE_LEVEL_SECURITY |
if(check_security(tmp[1], id)) continue; |
#endif |
if(s=function_object(tmp[1])->access(file[strlen(loc)..], id)) |
return s; |
} |
} |
} |
|
|
|
public string real_file(string file, object id) |
{ |
string loc; |
string s; |
array tmp; |
file=replace(file, "//", "/"); |
|
if(!id) error("No id passed to real_file"); |
|
|
foreach(location_modules(id), tmp) |
{ |
loc = tmp[0]; |
if(!search(file, loc)) |
{ |
#ifdef MODULE_LEVEL_SECURITY |
if(check_security(tmp[1], id)) continue; |
#endif |
|
|
if(s=function_object(tmp[1])->real_file(file[strlen(loc)..1000000], id)) |
return s; |
} |
} |
} |
|
|
|
|
|
|
|
public mixed try_get_file(string s, object id, int|void status, int|void nocache) |
{ |
string res, q; |
object fake_id; |
mapping m; |
|
|
if(objectp(id)) |
fake_id = id->clone_me(); |
else |
error("No ID passed to 'try_get_file'\n"); |
|
if(!id->pragma["no-cache"] ) |
if(res = cache_lookup("file:"+id->conf->name, s)) |
return res; |
|
if(sscanf(s, "%s?%s", s, q)) |
{ |
string v, name, value; |
foreach(q/"&", v) |
if(sscanf(v, "%s=%s", name, value)) |
fake_id->variables[http_decode_string(name)]=value; |
fake_id->query=q; |
} |
|
fake_id->raw_url=s; |
fake_id->not_query=s; |
fake_id->misc->internal_get=1; |
|
if(!(m = get_file(fake_id))) |
{ |
fake_id->end(); |
return 0; |
} |
fake_id->end(); |
|
if (!(< 0, 200, 201, 202, 203 >)[m->error]) return 0; |
|
if(status) return 1; |
|
#ifdef COMPAT |
if(m["string"]) res = m["string"]; |
#endif |
else if(m->data) res = m->data; |
else res=""; |
m->data = 0; |
|
if(m->file) |
{ |
res += m->file->read(); |
destruct(m->file); |
m->file = 0; |
} |
|
if(m->raw) |
{ |
res -= "\r"; |
if(!sscanf(res, "%*s\n\n%s", res)) |
sscanf(res, "%*s\n%s", res); |
} |
cache_set("file:"+id->conf->name, s, res); |
return res; |
} |
|
|
public int is_file(string what, object id) |
{ |
return !!stat_file(what, id); |
} |
|
mapping (object:array) open_ports = ([]); |
|
void start(int num) |
{ |
array port; |
int err=0; |
object lf; |
mapping new=([]), o2; |
|
parse_log_formats(); |
init_log_file(); |
map(indices(open_ports), do_dest); |
|
perror("Opening ports for "+query_name()+"... "); |
foreach(query("Ports"), port ) { |
array old = port; |
mixed erro; |
erro = catch { |
array tmp; |
function rp; |
object o; |
|
if ((< "ssl", "ssleay" >)[port[1]]) { |
|
report_warning("Obsolete SSL protocol-module \""+port[1]+"\".\n" |
"Converted to SSL3.\n"); |
|
port[1] = "ssl3"; |
|
} |
perror(port[0]+" "+port[2]+" ("+port[1]+")... "); |
if(rp = ((object)("protocols/"+port[1]))->real_port) { |
if(tmp = rp(port, this_object())) |
port = tmp; |
} |
object privs; |
if(port[0] < 1024) |
privs = Privs("Opening listen port below 1024"); |
if(!(o=create_listen_socket(port[0], this, port[2], |
(program)("protocols/"+port[1])))) |
{ |
report_error("I failed to open the port "+old[0]+" at "+old[2]+ |
" ("+old[1]+")\n"); |
err++; |
} else |
open_ports[o]=old; |
}; |
if(erro) { |
report_error("Failed to open port "+old[0]+" at "+old[2]+ |
" ("+old[1]+"): "+ |
(stringp(erro)?erro:describe_backtrace(erro))); |
} |
perror("\n"); |
} |
if(!num && sizeof(query("Ports"))) |
{ |
if(err == sizeof(query("Ports"))) |
{ |
report_error("No ports available for "+name+"\n" |
"Tried:\n" |
"Port Protocol IP-Number \n" |
"---------------------------\n" |
+ map(query("Ports"), lambda(array p) { |
return sprintf("%5d %-10s %-20s\n", @p); |
})*""); |
} |
} |
} |
|
|
|
|
|
void save(int|void all) |
{ |
mapping mod; |
if(all) |
{ |
store("spider.lpc#0", variables, 0, this); |
start(2); |
} |
|
foreach(values(modules), mod) |
{ |
if(mod->enabled) |
{ |
store(mod->sname+"#0", mod->master->query(), 0, this); |
mod->enabled->start(2, this); |
} else if(mod->copies) { |
int i; |
foreach(indices(mod->copies), i) |
{ |
store(mod->sname+"#"+i, mod->copies[i]->query(), 0, this); |
mod->copies[i]->start(2, this); |
} |
} |
} |
invalidate_cache(); |
} |
|
|
int save_one( object o ) |
{ |
mapping mod; |
if(!o) |
{ |
store("spider#0", variables, 0, this); |
start(2); |
return 1; |
} |
foreach(values(modules), mod) |
{ |
if( mod->enabled == o) |
{ |
store(mod->sname+"#0", o->query(), 0, this); |
o->start(2, this); |
invalidate_cache(); |
return 1; |
} else if(mod->copies) { |
int i; |
foreach(indices(mod->copies), i) |
{ |
if(mod->copies[i] == o) |
{ |
store(mod->sname+"#"+i, o->query(), 0, this); |
o->start(2, this); |
invalidate_cache(); |
return 1; |
} |
} |
} |
} |
} |
|
mapping _hooks=([ ]); |
|
|
void hooks_for( string modname, object mod ) |
{ |
array hook; |
if(_hooks[modname]) |
{ |
#ifdef MODULE_DEBUG |
perror("Module hooks..."); |
#endif |
foreach(_hooks[modname], hook) |
hook[0]( @hook[1], mod ); |
} |
} |
|
|
int unload_module( string modname ); |
int load_module( string modname ); |
|
object enable_module( string modname ) |
{ |
string id; |
mapping module; |
mapping enabled_modules; |
|
roxen->current_configuration = this_object(); |
modname = replace(modname, ".lpc#","#"); |
|
sscanf(modname, "%s#%s", modname, id ); |
|
module = modules[ modname ]; |
if(!module) |
{ |
load_module(modname); |
module = modules[ modname ]; |
} |
|
if( module ) |
{ |
object me; |
mapping tmp; |
int pr; |
array err; |
|
#ifdef MODULE_DEBUG |
perror("Modules: Enabling "+module->name+" # "+id+" ... "); |
#endif |
|
if(module->copies) |
{ |
if (err = catch(me = module["program"]())) { |
report_error("Couldn't clone module \"" + module->name + "\"\n" + |
describe_backtrace(err)); |
if (module->copies[id]) { |
#ifdef MODULE_DEBUG |
perror("Keeping old copy\n"); |
#endif |
} |
return(module->copies[id]); |
} |
if(module->copies[id]) { |
#ifdef MODULE_DEBUG |
perror("Disabling old copy ... "); |
#endif |
if (err = catch{ |
module->copies[id]->stop(); |
}) { |
report_error("Error during disabling of module \"" + module->name + |
"\"\n" + describe_backtrace(err)); |
} |
destruct(module->copies[id]); |
} |
} else { |
if(objectp(module->master)) { |
me = module->master; |
} else { |
if (err = catch(me = module["program"]())) { |
report_error("Couldn't clone module \"" + module->name + "\"\n" + |
describe_backtrace(err)); |
return(0); |
} |
} |
} |
|
#ifdef MODULE_DEBUG |
perror("Initializing "); |
#endif |
|
if (module->type & (MODULE_LOCATION | MODULE_EXTENSION | |
MODULE_FILE_EXTENSION | MODULE_LOGGER | |
MODULE_URL | MODULE_LAST | |
MODULE_FILTER | MODULE_PARSER | MODULE_FIRST)) |
{ |
me->defvar("_priority", 5, "Priority", TYPE_INT_LIST, |
"The priority of the module. 9 is highest and 0 is lowest." |
" Modules with the same priority can be assumed to be " |
"called in random order", |
({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); |
|
if(module->type != MODULE_LOGGER) |
{ |
if(!(module->type & MODULE_PROXY)) |
{ |
me->defvar("_sec_group", "user", "Security: Realm", TYPE_STRING, |
"The realm to use when requesting password from the " |
"client. Usually used as an informative message to the " |
"user."); |
me->defvar("_seclvl", 0, "Security: Trust level", TYPE_INT, |
"When a location module find a file, that file will get " |
"a 'Trust level' that equals the level of the module." |
" This file will then only be sent to modules with a higher " |
" or equal 'Trust level'. <p>As an example: If the trust " |
" level of a User filesystem is one, and the CGI module" |
" have trust level two, the file will never get passed to" |
" the CGI module. A trust level of zero is the same thing as" |
" free access.\n"); |
|
me->defvar("_seclevels", "", "Security: Patterns", TYPE_TEXT_FIELD, |
"This is the 'security level=value' list.<br>" |
"Each security level can be any or more from this list:" |
"<hr noshade>" |
"allow ip=<i>IP</i>/<i>bits</i><br>" |
"allow ip=<i>IP</i>:<i>mask</i><br>" |
"allow ip=<i>pattern</i><br>" |
"allow user=<i>username</i>,...<br>" |
"deny ip=<i>IP</i>/<i>bits</i><br>" |
"deny ip=<i>IP</i>:<i>mask</i><br>" |
"deny ip=<i>pattern</i><br>" |
"<hr noshade>" |
"In patterns: * matches one or more characters, " |
"and ? matches one character.<p>" |
"In username: 'any' stands for any valid account " |
"(from .htaccess" |
" or auth-module. The default (used when _no_ " |
"entries are present) is 'allow ip=*', allowing" |
" everyone to access the module"); |
|
} else { |
me->definvisvar("_seclvl", -10, TYPE_INT); |
|
me->defvar("_sec_group", "user", "Proxy Security: Realm", TYPE_STRING, |
"The realm to use when requesting password from the " |
"client. Usually used as an informative message to the " |
"user."); |
me->defvar("_seclevels", "", "Proxy security: Patterns", |
TYPE_TEXT_FIELD, |
"This is the 'security level=value' list.<br>" |
"Each security level can be any or more from " |
"this list:<br>" |
"<hr noshade>" |
"allow ip=pattern<br>" |
"allow user=username,...<br>" |
"deny ip=pattern<br>" |
"<hr noshade>" |
"In patterns: * is on or more characters, ? is one " |
" character.<p>" |
"In username: 'any' stands for any valid account" |
" (from .htaccess" |
" or auth-module. The default is 'deny ip=*'"); |
} |
} |
} else { |
me->defvar("_priority", 0, "", TYPE_INT, "", 0, 1); |
} |
|
me->defvar("_comment", "", " Comment", TYPE_TEXT_FIELD|VAR_MORE, |
"An optional comment. This has no effect on the module, it " |
"is only a text field for comments that the administrator " |
"might have (why the module are here, etc.)"); |
|
me->defvar("_name", "", " Module name", TYPE_STRING|VAR_MORE, |
"An optional name. Set to something to remaind you what " |
"the module really does."); |
|
me->setvars(retrieve(modname + "#" + id, this)); |
|
mixed err; |
if((me->start) && (err = catch{ |
me->start(0, this); |
})) { |
report_error("Error while initiating module copy of " + |
module->name + "\n" + describe_backtrace(err)); |
destruct(me); |
return 0; |
} |
|
if (err = catch(pr = me->query("_priority"))) { |
report_error("Error while initiating module copy of " + |
module->name + "\n" + describe_backtrace(err)); |
pr = 3; |
} |
|
if(module->type & MODULE_EXTENSION) { |
if (err = catch { |
array arr = me->query_extensions(); |
if (arrayp(arr)) { |
string foo; |
foreach( arr, foo ) |
if(pri[pr]->extension_modules[ foo ]) |
pri[pr]->extension_modules[foo] += ({ me }); |
else |
pri[pr]->extension_modules[foo] = ({ me }); |
} |
}) { |
report_error("Error while initiating module copy of " + |
module->name + "\n" + describe_backtrace(err)); |
} |
} |
|
if(module->type & MODULE_FILE_EXTENSION) { |
if (err = catch { |
array arr = me->query_file_extensions(); |
if (arrayp(arr)) { |
string foo; |
foreach( me->query_file_extensions(), foo ) |
if(pri[pr]->file_extension_modules[foo] ) |
pri[pr]->file_extension_modules[foo]+=({me}); |
else |
pri[pr]->file_extension_modules[foo]=({me}); |
} |
}) { |
report_error("Error while initiating module copy of " + |
module->name + "\n" + describe_backtrace(err)); |
} |
} |
|
if(module->type & MODULE_TYPES) |
{ |
types_module = me; |
types_fun = me->type_from_extension; |
} |
|
if((module->type & MODULE_MAIN_PARSER)) |
{ |
parse_module = me; |
if (_toparse_modules) { |
map(_toparse_modules, lambda(object o, object me, mapping module) { |
array err; |
if (err = catch{me->add_parse_module(o);}) { |
report_error("Error while initiating module copy of " + |
module->name + "\n" + describe_backtrace(err)); |
} |
}, me, module); |
} |
} |
|
if(module->type & MODULE_PARSER) |
{ |
if(parse_module) { |
if (err = catch { |
parse_module->add_parse_module( me ); |
}) { |
report_error("Error while initiating module copy of " + |
module->name + "\n" + describe_backtrace(err)); |
} |
} |
_toparse_modules += ({ me }); |
} |
|
if(module->type & MODULE_AUTH) |
{ |
auth_module = me; |
auth_fun = me->auth; |
} |
|
if(module->type & MODULE_DIRECTORIES) |
dir_module = me; |
|
if(module->type & MODULE_LOCATION) |
pri[pr]->location_modules += ({ me }); |
|
if(module->type & MODULE_LOGGER) |
pri[pr]->logger_modules += ({ me }); |
|
if(module->type & MODULE_URL) |
pri[pr]->url_modules += ({ me }); |
|
if(module->type & MODULE_LAST) |
pri[pr]->last_modules += ({ me }); |
|
if(module->type & MODULE_FILTER) |
pri[pr]->filter_modules += ({ me }); |
|
if(module->type & MODULE_FIRST) { |
pri[pr]->first_modules += ({ me }); |
} |
|
if(module->copies) |
module->copies[(int)id] = me; |
else |
module->enabled = me; |
|
hooks_for(module->sname+"#"+id, me); |
|
|
otomod[ me ] = modname; |
enabled_modules=retrieve("EnabledModules", this); |
|
if(!enabled_modules[modname+"#"+id]) |
{ |
#ifdef MODULE_DEBUG |
perror("New module..."); |
#endif |
enabled_modules[modname+"#"+id] = 1; |
store( "EnabledModules", enabled_modules, 1, this); |
} |
#ifdef MODULE_DEBUG |
perror(" Done.\n"); |
#endif |
invalidate_cache(); |
return me; |
} |
return 0; |
} |
|
|
string check_variable(string name, string value) |
{ |
switch(name) |
{ |
case "MyWorldLocation": |
if(strlen(value)<7 || value[-1] != '/' || |
!(sscanf(value,"%*s://%*s/")==2)) |
return "The URL should follow this format: protocol://computer[:port]/"; |
} |
} |
|
|
|
|
|
|
|
|
|
|
#define perr(X) do { report += X; perror(X); } while(0) |
|
private void update_vars(int from) |
{ |
string report = ""; |
int i; |
string modname; |
mapping redir; |
mapping enabled_modules = retrieve("EnabledModules"); |
array p, res=({}); |
|
perr("Updating configuration file....\n"); |
perr("----------------------------------------------------\n"); |
switch(from) |
{ |
case 0: |
|
|
|
case 1: |
case 2: |
perr("The 'No directory lists' variable is yet again available.\n"); |
case 3: |
|
if(query(".htaccess")) |
{ |
perr("The 'HTACCESS' support has been moved to a module.\n"); |
enable_module("htaccess#0"); |
} |
case 4: |
case 5: |
|
while(sizeof(redir = retrieve(modname = "lpcscript#"+i))) |
{ |
remove( modname, this ); |
if(search(redir->exts, "pike") == -1) |
redir->exts += ({"pike"}); |
if(enabled_modules[modname] ) |
m_delete( enabled_modules, modname ); |
store("pikescript#"+i, redir, 1); |
enable_module("pikescript#"+i); |
perr("Renaming "+modname+" to pikescript#"+i+"\n"); |
i++; |
} |
store( "EnabledModules", enabled_modules, 1 ); |
|
case 6: |
} |
|
perr("----------------------------------------------------\n"); |
report_debug(report); |
} |
|
|
|
|
|
|
int log_is_not_enabled() |
{ |
return !query("Log"); |
} |
|
|
|
|
|
private string get_domain(int|void l) |
{ |
array f; |
string t, s; |
|
|
if (!l) { |
f = (roxen->QUERY(ConfigurationURL)/"://"); |
if (sizeof(f) > 1) { |
t = (replace(f[1], ({ ":", "/" }), ({ "\0", "\0" }))/"\0")[0]; |
f = t/"."; |
if (sizeof(f) > 1) { |
s = f[1..]*"."; |
} |
} |
} |
#if efun(gethostbyname) && efun(gethostname) |
if(!s) { |
f = gethostbyname(gethostname()); |
if(f) |
foreach(f, f) { |
if (arrayp(f)) { |
foreach(f, t) { |
f = t/"."; |
if ((sizeof(f) > 1) && |
(replace(t, ({ "0", "1", "2", "3", "4", "5", |
"6", "7", "8", "9", "." }), |
({ "","","","","","","","","","","" })) != "")) { |
t = f[1..]*"."; |
if(!s || strlen(s) < strlen(t)) |
s=t; |
} |
} |
} |
} |
} |
#endif |
if(!s) { |
t = Stdio.read_bytes("/etc/resolv.conf"); |
if(t) { |
if(!sscanf(t, "domain %s\n", s)) |
if(!sscanf(t, "search %s%*[ \t\n]", s)) |
s="nowhere"; |
} else { |
s="nowhere"; |
} |
} |
if(s && strlen(s)) |
{ |
if(s[-1] == '.') s=s[..strlen(s)-2]; |
if(s[0] == '.') s=s[1..]; |
} else { |
s="unknown"; |
} |
return s; |
} |
|
int disable_module( string modname ) |
{ |
mapping module; |
mapping enabled_modules; |
object me; |
int pr; |
int id; |
|
sscanf(modname, "%s#%d", modname, id ); |
|
module = modules[ modname ]; |
|
if(!module) |
{ |
report_error("Modules: Failed to disable module\n" |
"Modules: No module by that name: \""+modname+"\".\n"); |
return 0; |
} |
|
if(module->copies) |
{ |
me = module->copies[id]; |
m_delete(module->copies, id); |
if(!sizeof(module->copies)) |
unload_module(modname); |
} else { |
me = module->enabled || module->master; |
module->enabled=module->master = 0; |
unload_module(modname); |
} |
|
invalidate_cache(); |
|
if(!me) |
{ |
report_error("Modules: Failed to Disable "+module->name+" # "+id+"\n"); |
return 0; |
} |
|
if(me->stop) me->stop(); |
|
#ifdef MODULE_DEBUG |
perror("Modules: Disabling "+module->name+" # "+id+"\n"); |
#endif |
|
if(module["type"] & MODULE_EXTENSION |
&& arrayp( me -> query_extensions())) |
{ |
string foo; |
foreach( me -> query_extensions(), foo ) |
for(pr=0; pr<10; pr++) |
if( pri[pr]->extension_modules[ foo ] ) |
pri[pr]->extension_modules[ foo ]-= ({ me }); |
} |
|
if(module["type"] & MODULE_FILE_EXTENSION |
&& arrayp( me -> query_file_extensions())) |
{ |
string foo; |
foreach( me -> query_file_extensions(), foo ) |
for(pr=0; pr<10; pr++) |
if(pri[pr]->file_extension_modules[ foo ] ) |
pri[pr]->file_extension_modules[foo]-=({me}); |
} |
|
if(module["type"] & MODULE_TYPES) |
{ |
types_module = 0; |
types_fun = 0; |
} |
|
if(module->type & MODULE_MAIN_PARSER) |
parse_module = 0; |
|
if(module->type & MODULE_PARSER) |
{ |
if(parse_module) |
parse_module->remove_parse_module( me ); |
_toparse_modules -= ({ me, 0 }); |
} |
|
if( module->type & MODULE_AUTH ) |
{ |
auth_module = 0; |
auth_fun = 0; |
} |
|
if( module->type & MODULE_DIRECTORIES ) |
dir_module = 0; |
|
|
if( module->type & MODULE_LOCATION ) |
for(pr=0; pr<10; pr++) |
pri[pr]->location_modules -= ({ me }); |
|
if( module->type & MODULE_URL ) |
for(pr=0; pr<10; pr++) |
pri[pr]->url_modules -= ({ me }); |
|
if( module->type & MODULE_LAST ) |
for(pr=0; pr<10; pr++) |
pri[pr]->last_modules -= ({ me }); |
|
if( module->type & MODULE_FILTER ) |
for(pr=0; pr<10; pr++) |
pri[pr]->filter_modules -= ({ me }); |
|
if( module->type & MODULE_FIRST ) { |
for(pr=0; pr<10; pr++) |
pri[pr]->first_modules -= ({ me }); |
} |
|
if( module->type & MODULE_LOGGER ) |
for(pr=0; pr<10; pr++) |
pri[pr]->logger_modules -= ({ me }); |
|
enabled_modules=retrieve("EnabledModules", this); |
|
if(enabled_modules[modname+"#"+id]) |
{ |
m_delete( enabled_modules, modname + "#" + id ); |
store( "EnabledModules",enabled_modules, 1, this); |
} |
destruct(me); |
return 1; |
} |
|
object|string find_module(string name) |
{ |
int id; |
sscanf(name, "%s#%d", name, id); |
if(modules[name]) |
{ |
if(modules[name]->copies) |
return modules[name]->copies[id]; |
else |
if(modules[name]->enabled) |
return modules[name]->enabled; |
} |
return 0; |
} |
|
void register_module_load_hook( string modname, function fun, mixed ... args ) |
{ |
object o; |
#ifdef MODULE_DEBUG |
perror("Registering a hook for the module "+modname+"\n"); |
#endif |
if(o=find_module(modname)) |
{ |
#ifdef MODULE_DEBUG |
perror("Already there!\n"); |
#endif |
fun( @args, o ); |
} else |
if(!_hooks[modname]) |
_hooks[modname] = ({ ({ fun, args }) }); |
else |
_hooks[modname] += ({ ({ fun, args }) }); |
} |
|
|
int load_module(string module_file) |
{ |
int foo, disablep; |
mixed err; |
mixed *module_data; |
mapping loaded_modules; |
object obj; |
program prog; |
|
|
roxen->current_configuration = this_object(); |
#ifdef MODULE_DEBUG |
perror("Modules: Loading " + module_file + "... "); |
#endif |
|
if(prog=cache_lookup("modules", module_file)) { |
err = catch { |
obj = prog(this_object()); |
}; |
} else { |
string dir; |
|
_master->set_inhibit_compile_errors(""); |
|
err = catch { |
obj = roxen->load_from_dirs(roxen->QUERY(ModuleDirs), module_file, |
this_object()); |
}; |
|
string errors = _master->errors; |
|
_master->set_inhibit_compile_errors(0); |
|
if (sizeof(errors)) { |
report_error(sprintf("While compiling module (\"%s\"):\n%s\n", |
module_file, errors)); |
return(0); |
} |
|
prog = roxen->last_loaded(); |
} |
|
if (err) { |
report_error("While enabling module (" + module_file + "):\n" + |
describe_backtrace(err) + "\n"); |
return(0); |
} |
|
if(!obj) |
{ |
report_error("Module load failed (" + module_file + ") (not found).\n"); |
return 0; |
} |
|
if (err = catch (module_data = obj->register_module(this_object()))) { |
#ifdef MODULE_DEBUG |
perror("FAILED\n" + describe_backtrace( err )); |
#endif |
report_error("Module loaded, but register_module() failed (" |
+ module_file + ").\n" + |
describe_backtrace( err )); |
return 0; |
} |
|
err = ""; |
roxen->somemodules[module_file]= |
({ module_data[1], module_data[2]+"<p><i>"+ |
replace(obj->file_name_and_stuff(),"0<br>", module_file+"<br>") |
+"</i>", module_data[0] }); |
if (!arrayp( module_data )) |
err = "Register_module didn't return an array.\n"; |
else |
switch (sizeof( module_data )) |
{ |
case 5: |
foo=module_data[4]; |
module_data=module_data[0..3]; |
case 4: |
if (module_data[3] && !arrayp( module_data[3] )) |
err = "The fourth element of the array register_module returned " |
"(extra_buttons) wasn't an array.\n" + err; |
case 3: |
if (!stringp( module_data[2] )) |
err = "The third element of the array register_module returned " |
"(documentation) wasn't a string.\n" + err; |
if (!stringp( module_data[1] )) |
err = "The second element of the array register_module returned " |
"(name) wasn't a string.\n" + err; |
if (!intp( module_data[0] )) |
err = "The first element of the array register_module returned " |
"(type) wasn't an integer.\n" + err; |
break; |
|
default: |
err = "The array register_module returned was too small/large. " |
"It should have been three or four elements (type, name, " |
"documentation and extra buttons (optional))\n"; |
} |
if (err != "") |
{ |
#ifdef MODULE_DEBUG |
perror("FAILED\n"+err); |
#endif |
report_error( "Tried to load module " + module_file + ", but:\n" + err ); |
if(obj) |
destruct( obj ); |
return 0; |
} |
|
if (sizeof(module_data) == 3) |
module_data += ({ 0 }); |
|
if(!foo) |
{ |
destruct(obj); |
obj=0; |
} else { |
otomod[obj] = module_file; |
} |
|
if(!modules[ module_file ]) |
modules[ module_file ] = ([]); |
mapping tmpp = modules[ module_file ]; |
|
tmpp->type=module_data[0]; |
tmpp->name=module_data[1]; |
tmpp->doc=module_data[2]; |
tmpp->extra=module_data[3]; |
tmpp["program"]=prog; |
tmpp->master=obj; |
tmpp->copies=(foo ? 0 : (tmpp->copies||([]))); |
tmpp->sname=module_file; |
|
#ifdef MODULE_DEBUG |
perror(" Done ("+search(_master->programs,prog)+").\n"); |
#endif |
cache_set("modules", module_file, modules[module_file]["program"]); |
|
|
return 1; |
} |
|
int unload_module(string module_file) |
{ |
mapping module; |
int id; |
|
module = modules[ module_file ]; |
|
if(!module) |
return 0; |
|
if(objectp(module->master)) |
destruct(module->master); |
|
cache_remove("modules", module_file); |
|
m_delete(modules, module_file); |
|
return 1; |
} |
|
int port_open(array prt) |
{ |
array v; |
foreach(values(open_ports), v) |
if(equal(v, prt)) return 1; |
return 0; |
} |
|
|
string desc() |
{ |
string res=""; |
array (string|int) port; |
|
if(!sizeof(QUERY(Ports))) |
{ |
|
|
|
|
|
|
|
|
array handlers = ({}); |
foreach(roxen->configurations, object c) |
if(c->modules["ip-less_hosts"]) |
handlers+=({({http_encode_string("/Configurations/"+c->name), |
strlen(c->query("name"))?c->query("name"):c->name})}); |
|
|
if(sizeof(handlers)==1) |
{ |
res = "This server is handled by the ports in <a href=\""+handlers[0][0]+ |
"\">"+handlers[0][1]+"</a><br>\n"; |
} else if(sizeof(handlers)) { |
res = "This server is handled by the ports in any of the following servers:<br>"; |
foreach(handlers, array h) |
res += "<a href=\""+h[0]+"\">"+h[1]+"</a><br>\n"; |
} else |
res=("There are no ports configured, and no virtual server seems " |
"to have support for ip-less virtual hosting enabled<br>\n"); |
} |
|
foreach(QUERY(Ports), port) |
{ |
string prt; |
|
switch(port[1][0..2]) |
{ |
case "ssl": |
prt = "https://"; |
break; |
|
default: |
prt = port[1]+"://"; |
} |
if(port[2] && port[2]!="ANY") |
prt += port[2]; |
else |
prt += (gethostname()/".")[0] + "." + QUERY(Domain); |
prt += ":"+port[0]+"/"; |
if(port_open( port )) |
res += "<font color=darkblue><b>Open:</b></font> <a target=server_view href=\""+prt+"\">"+prt+"</a> \n<br>"; |
else |
res += "<font color=red><b>Not open:</b> <a target=server_view href=\""+ |
prt+"\">"+prt+"</a></font> <br>\n"; |
} |
return (res+"<font color=darkgreen>Server URL:</font> <a target=server_view " |
"href=\""+query("MyWorldLocation")+"\">"+query("MyWorldLocation")+"</a><p>"); |
} |
|
|
|
|
mapping(string:string) sql_urls = ([]); |
|
object sql_connect(string db) |
{ |
if (sql_urls[db]) { |
return(Sql.sql(sql_urls[db])); |
} else { |
return(Sql.sql(db)); |
} |
} |
|
|
|
|
|
private string get_my_url() |
{ |
string s; |
s = (gethostname()/".")[0] + "." + query("Domain"); |
s -= "\n"; |
return "http://" + s + "/"; |
} |
|
void enable_all_modules() |
{ |
array modules_to_process=sort(indices(retrieve("EnabledModules",this))); |
string tmp_string; |
perror("\nEnabling all modules for "+query_name()+"... \n"); |
|
|
if(search(modules_to_process, "userdb#0")>-1) |
modules_to_process = (({"userdb#0"})+(modules_to_process-({"userdb#0"}))); |
|
|
array err; |
foreach( modules_to_process, tmp_string ) |
if(err = catch( enable_module( tmp_string ) )) |
report_error("Failed to enable the module "+tmp_string+". Skipping\n" |
#ifdef MODULE_DEBUG |
+describe_backtrace(err)+"\n" |
#endif |
); |
roxen->current_configuration = 0; |
} |
|
void create(string config) |
{ |
roxen->current_configuration = this; |
name=config; |
|
perror("Creating virtual server '"+config+"'\n"); |
|
defvar("ZNoSuchFile", "<title>Sorry. I cannot find this resource</title>\n" |
"<body bgcolor='#ffffff' text='#000000' alink='#ff0000' " |
"vlink='#00007f' link='#0000ff'>\n" |
"<h2 align=center><configimage src=roxen.gif alt=\"File not found\">\n" |
"<p><hr noshade>" |
"\n<i>Sorry</i></h2>\n" |
"<br clear>\n<font size=\"+2\">The resource requested " |
"<i>$File</i>\ncannot be found.<p>\n\nIf you feel that this is a " |
"configuration error, please contact " |
"the administrators or the author of the\n" |
"<if referrer>" |
"<a href=\"<referrer>\">referring</a>" |
"</if>\n" |
"<else>referring</else>\n" |
"page." |
"<p>\n</font>\n" |
"<hr noshade>" |
"<version>, at <a href=\"$Me\">$Me</a>.\n" |
"</body>\n", |
|
"Messages: No such file", TYPE_TEXT_FIELD, |
"What to return when there is no resource or file available " |
"at a certain location. $File will be replaced with the name " |
"of the resource requested, and $Me with the URL of this server "); |
|
|
defvar("comment", "", "Virtual server comment", |
TYPE_TEXT_FIELD|VAR_MORE, |
"This text will be visible in the configuration interface, it " |
" can be quite useful to use as a memory helper."); |
|
defvar("name", "", "Virtual server name", |
TYPE_STRING|VAR_MORE, |
"This is the name that will be used in the configuration " |
"interface. If this is left empty, the actual name of the " |
"virtual server will be used"); |
|
defvar("LogFormat", |
"404: $host $referer - [$cern_date] \"$method $resource $protocol\" 404 -\n" |
"500: $host $referer ERROR [$cern_date] \"$method $resource $protocol\" 500 -\n" |
"*: $host - - [$cern_date] \"$method $resource $protocol\" $response $length" |
, |
|
"Logging: Format", |
TYPE_TEXT_FIELD|VAR_MORE, |
|
"What format to use for logging. The syntax is:\n" |
"<pre>" |
"response-code or *: Log format for that response acode\n\n" |
"Log format is normal characters, or one or more of the " |
"variables below:\n" |
"\n" |
"\\n \\t \\r -- As in C, newline, tab and linefeed\n" |
"$char(int) -- Insert the (1 byte) character specified by the integer.\n" |
"$wchar(int) -- Insert the (2 byte) word specified by the integer.\n" |
"$int(int) -- Insert the (4 byte) word specified by the integer.\n" |
"$^ -- Supress newline at the end of the logentry\n" |
"$host -- The remote host name, or ip number.\n" |
"$ip_number -- The remote ip number.\n" |
"$bin-ip_number -- The remote host id as a binary integer number.\n" |
"\n" |
"$cern_date -- Cern Common Log file format date.\n" |
"$bin-date -- Time, but as an 32 bit iteger in network byteorder\n" |
"\n" |
"$method -- Request method\n" |
"$resource -- Resource identifier\n" |
"$protocol -- The protocol used (normally HTTP/1.0)\n" |
"$response -- The response code sent\n" |
"$bin-response -- The response code sent as a binary short number\n" |
"$length -- The length of the data section of the reply\n" |
"$bin-length -- Same, but as an 32 bit iteger in network byteorder\n" |
"$referer -- the header 'referer' from the request, or '-'.\n" |
"$user_agent -- the header 'User-Agent' from the request, or '-'.\n\n" |
"$user -- the name of the auth user used, if any\n" |
"$user_id -- A unique user ID, if cookies are supported,\n" |
" by the client, otherwise '0'\n" |
"</pre>", 0, log_is_not_enabled); |
|
defvar("Log", 1, "Logging: Enabled", TYPE_FLAG, "Log requests"); |
|
defvar("LogFile", roxen->QUERY(logdirprefix)+ |
short_name(name)+"/Log", |
|
"Logging: Log file", TYPE_FILE, "The log file. " |
"" |
"A file name. May be relative to "+getcwd()+"." |
" Some substitutions will be done:" |
"<pre>" |
"%y Year (i.e. '1997')\n" |
"%m Month (i.e. '08')\n" |
"%d Date (i.e. '10' for the tenth)\n" |
"%h Hour (i.e. '00')\n</pre>" |
,0, log_is_not_enabled); |
|
defvar("NoLog", ({ }), |
"Logging: No Logging for", TYPE_STRING_LIST|VAR_MORE, |
"Don't log requests from hosts with an IP number which matches any " |
"of the patterns in this list. This also affects the access counter " |
"log.\n",0, log_is_not_enabled); |
|
defvar("Domain", get_domain(), "Domain", TYPE_STRING, |
"Your domainname, should be set automatically, if not, " |
"enter the correct domain name here, and send a bug report to " |
"<a href=\"mailto:roxen-bugs@infovav.se\">roxen-bugs@infovav.se" |
"</a>"); |
|
|
defvar("Ports", ({ }), |
"Listen ports", TYPE_PORTS, |
"The ports this virtual instance of Roxen will bind to.\n"); |
|
defvar("MyWorldLocation", get_my_url(), |
"Server URL", TYPE_STRING, |
"This is where your start page is located."); |
|
|
|
|
defvar("FTPWelcome", |
" +-------------------------------------------------\n" |
" +-- Welcome to the Roxen Challenger FTP server ---\n" |
" +-------------------------------------------------\n", |
"Messages: FTP Welcome", |
TYPE_TEXT_FIELD|VAR_MORE, |
"FTP Welcome answer; transmitted to new FTP connections if the file " |
"<i>/welcome.msg</i> doesn't exist.\n"); |
|
defvar("named_ftp", 0, "Allow named FTP", TYPE_FLAG|VAR_MORE, |
"Allow ftp to normal user-accounts (requires auth-module).\n"); |
|
defvar("anonymous_ftp", 1, "Allow anonymous FTP", TYPE_FLAG|VAR_MORE, |
"Allows anonymous ftp.\n"); |
|
defvar("shells", "/etc/shells", "Shell database", TYPE_FILE|VAR_MORE, |
"File which contains a list of all valid shells.\n" |
"Usually /etc/shells\n"); |
|
defvar("_v", CONFIGURATION_FILE_LEVEL, 0, TYPE_INT, 0, 0, 1); |
setvars(retrieve("spider#0", this)); |
|
if((sizeof(retrieve("spider#0", this)) && |
(!retrieve("spider#0",this)->_v) |
|| (query("_v") < CONFIGURATION_FILE_LEVEL))) |
{ |
update_vars(retrieve("spider#0",this)->_v?query("_v"):0); |
killvar("PEther"); |
variables->_v[VAR_VALUE] = CONFIGURATION_FILE_LEVEL; |
store("spider#0", variables, 0); |
} |
|
set("_v", CONFIGURATION_FILE_LEVEL); |
} |
|
|
|
|
|