Roxen.git / server / base_server / roxen.pike

version» Context lines:

Roxen.git/server/base_server/roxen.pike:1:   // This file is part of Roxen WebServer.   // Copyright © 1996 - 2001, Roxen IS.   //   // The Roxen WebServer main program.   //   // Per Hedbor, Henrik Grubbström, Pontus Hagland, David Hedbor and others.   // ABS and suicide systems contributed freely by Francesco Chemolli    - constant cvs_version="$Id: roxen.pike,v 1.825 2003/03/05 15:51:50 mast Exp $"; + constant cvs_version="$Id: roxen.pike,v 1.826 2003/03/26 15:27:04 grubba Exp $";      //! @appears roxen   //!   //! The Roxen WebServer main program.      // The argument cache. Used by the image cache.   ArgCache argcache;      // Some headerfiles   #define IN_ROXEN
Roxen.git/server/base_server/roxen.pike:4787:    con->query("INSERT INTO compiled_formats (md5,full,enc) VALUES (%s,%s,%s)",    kmd5, fmt, enc);    con = 0;       return compiled_formats[ fmt ] = res()->log;   }      // This array contains the compilation information for the different   // security checks for e.g. htaccess. The layout of the top array is   // triplet of sscanf string that the security command should match, - // the number of arugments that it takes and an array with the actual + // the number of arguments that it takes and an array with the actual   // compilation information.   // - // ({ command_sscanf_string, number_of_arguments, actual_tests })*n + // ({ command_sscanf_string, number_of_arguments, actual_tests, + // state_symbol_string, + // })   //      // In the tests array the following types has the following meaning:   // function   // The function will be run during compilation. It gets the values   // aquired though sscanf-ing the command as input and should return   // an array with corresponding data.   // string   // The string will be compiled into the actual test code. It is   // first modified as   // str = sprintf(str, @args)   // where args are the arguments from the command after it has been   // processed by the provided function, if any.   // multiset   // Strings in a multiset will be added before the string above.   // should typically be used for variable declarations.   // int - // Signals that a authentication request should be sent to the user + // Signals that an authentication request should be sent to the user   // upon failure.   //   //   // NOTE: It's up to the security checks in this file to ensure that   // nothing is overcached. All patterns that perform checks using   // information from the client (such as remote address, referer etc)   // _have_ to use NOCACHE() or NO_PROTO_CACHE(). It's not nessesary, however,   // to do that for checks that use the authentication module API, since   // then it's up to the user database and authentication modules to ensure   // that nothing is overcached in that case. - array security_checks = ({ -  "ip=%s:%s",2,({ + array(array(string|int|array)) security_checks = ({ +  ({ "ip=%s:%s",2,({    lambda( string a, string b ){    int net = Roxen.ip_to_int( a );    int mask = Roxen.ip_to_int( b );    net &= mask;    return ({ net, sprintf("%c",mask)[0] });    }, -  " NO_PROTO_CACHE();\n" -  " if( (Roxen.ip_to_int( id->remoteaddr ) & %[1]d) == %[0]d ) ", -  }), -  "ip=%s/%d",2,({ +  " if ((Roxen.ip_to_int(id->remoteaddr) & %[1]d) == %[0]d)", +  (<" NO_PROTO_CACHE()" >), +  }), "ip" }), +  ({ "ip=%s/%d",2,({    lambda( string a, int b ){    int net = Roxen.ip_to_int( a );    int mask = ((~0<<(32-b))&0xffffffff);    net &= mask;    return ({ net, sprintf("%c",mask)[0] });    }, -  " NO_PROTO_CACHE();\n" -  " if( (Roxen.ip_to_int( id->remoteaddr ) & %[1]d) == %[0]d ) ", -  }), -  "ip=%s",1,({ -  " NO_PROTO_CACHE();\n" -  " if( sizeof(filter(%[0]O/\",\",lambda(string q){\n" -  " return glob(q,id->remoteaddr);\n" -  " })) )" -  }), -  "user=%s",1,({ 1, +  " if ((Roxen.ip_to_int(id->remoteaddr) & %[1]d) == %[0]d) ", +  (<" NO_PROTO_CACHE()" >), +  }), "ip", }), +  ({ "ip=%s",1,({ +  " if (sizeof(filter(%[0]O/\",\",\n" +  " lambda(string q){\n" +  " return glob(q,id->remoteaddr);\n" +  " })))", +  (<" NO_PROTO_CACHE()" >), +  }), "ip", }), +  ({ "user=%s",1,({ 1,    lambda( string x ) {    return ({sprintf("(< %{%O, %}>)", x/"," )});    },    -  +  " if ((user || (user = authmethod->authenticate(id, userdb_module)))\n" +  " && ((%[0]s->any) || (%[0]s[user->name()]))) ", +  (<" User user" >),    // No need to NOCACHE () here, since it's up to the    // auth-modules to do that. -  " if( (user || (user = authmethod->authenticate( id, userdb_module )))\n" -  " && ((%[0]s->any) || (%[0]s[user->name()])) ) ", -  (< " User user" >), -  }), -  "group=%s",1,({ 1, +  }), "user", }), +  ({ "group=%s",1,({ 1,    lambda( string x ) {    return ({sprintf("(< %{%O, %}>)", x/"," )});    }, -  +  " if ((user || (user = authmethod->authenticate(id, userdb_module)))\n" +  " && ((%[0]s->any) || sizeof(mkmultiset(user->groups())&%[0]s)))", +  (<" User user" >),    // No need to NOCACHE () here, since it's up to the    // auth-modules to do that. -  " if( (user || (user = authmethod->authenticate( id, userdb_module )))\n" -  " && ((%[0]s->any) || sizeof(mkmultiset(user->groups())&%[0]s)))", -  (<" User user" >), -  }), -  "dns=%s",1,({ -  "NO_PROTO_CACHE();" -  " if(!dns && \n" -  " ((dns=roxen.quick_ip_to_host(id->remoteaddr))!=id->remoteaddr))\n" -  " if( (id->misc->delayed+=0.1) < 1.0 )\n" -  " return Roxen.http_try_again( 0.1 );\n" -  " if( sizeof(filter(%[0]O/\",\",lambda(string q){return glob(q,dns);})) )", +  }), "group", }), +  ({ "dns=%s",1,({ +  " if(!dns && \n" +  " ((dns=roxen.quick_ip_to_host(id->remoteaddr))!=id->remoteaddr))\n" +  " if( (id->misc->delayed+=0.1) < 1.0 )\n" +  " return Roxen.http_try_again( 0.1 );\n" +  " if (sizeof(filter(%[0]O/\",\",\n" +  " lambda(string q){return glob(q,dns);})))",    (< " string dns" >), -  }), -  "time=%d:%d-%d:%d",4,({ +  (<" NO_PROTO_CACHE()" >), +  }), "ip", }), +  ({ "time=%d:%d-%d:%d",4,({    (< " mapping l = localtime(time(1))" >),    (< " int th = l->hour, tm = l->min" >),    // No need to NOCACHE() here, does not depend on client. -  " if( ((th >= %[0]d) && (tm >= %[1]d)) &&\n" -  " ((th <= %[2]d) && (tm <= %[3]d)) )", -  }), -  "referer=%s", 1, ({ +  " if (((th >= %[0]d) && (tm >= %[1]d)) &&\n" +  " ((th <= %[2]d) && (tm <= %[3]d)))", +  }), "time", }), +  ({ "referer=%s", 1, ({    (<    " string referer = sizeof(id->referer||({}))?"    "id->referer[0]:\"\"; "    >), -  " NO_PROTO_CACHE();" -  " if( sizeof(filter(%[0]O/\",\",lambda(string q){\n" -  " return glob(q,referer);\n" -  " })) )" -  }), -  "day=%s",1,({ +  " if( sizeof(filter(%[0]O/\",\",\n" +  " lambda(string q){return glob(q,referer);})))", +  (<" NO_PROTO_CACHE()" >), +  }), "referer", }), +  ({ "day=%s",1,({    lambda( string q ) {    multiset res = (<>);    foreach( q/",", string w ) if( (int)w )    res[((int)w % 7)] = 1;    else    res[ (["monday":1,"thuesday":2,"wednesday":3,"thursday":4,"friday":5,    "saturday":6,"sunday":0,"mon":1, "thu":2, "wed":3, "thu":4,    "fri":5, "sat":6, "sun":0, ])[ lower_case(w) ] ] = 1;    return ({sprintf("(< %{%O, %}>)", (array)res)});    },    (< " mapping l = localtime(time(1))" >),    // No need to NOCACHE() here, does not depend on client. -  " if( %[0]s[l->wday] )" -  }), -  "accept_language=%s",1,({ -  " NO_PROTO_CACHE(); " -  " if( has_value(id->misc->pref_languages->get_languages(), %O))" -  }), -  "luck=%d%%",1,({ +  " if (%[0]s[l->wday])" +  }), "day", }), +  ({ "accept_language=%s",1,({ +  " if (has_value(id->misc->pref_languages->get_languages(), %O))", +  (<" NO_PROTO_CACHE()" >), +  }), "language", }), +  ({ "luck=%d%%",1,({    lambda(int luck) { return ({ 100-luck }); },    // Not really any need to NOCACHE() here, since it does not depend    // on client. However, it's supposed to be totally random. -  " NOCACHE();" -  " if( random(100)<%d )", -  }), +  " if( random(100)<%d )", +  (<" NOCACHE()" >), +  }), "luck", }),   });      #define DENY 0   #define ALLOW 1      function(RequestID:mapping|int) compile_security_pattern( string pattern,    RoxenModule m )   //! Parse a security pattern and return a function that when called   //! will do the checks required by the format.   //!
Roxen.git/server/base_server/roxen.pike:4995:    describe_backtrace(err));   // #endif    }             string code = "";    array variables = ({ " object userdb_module",    " object authmethod = id->conf",    " string realm = \"User\"", -  " int|mapping fail" }); +  " mapping(string:int|mapping) state = ([])", +  });    int shorted, patterns, cmd;       foreach( pattern / "\n", string line )    {    line = String.trim_all_whites( line );    if( !strlen(line) || line[0] == '#' )    continue;    sscanf( line, "%[^#]#", line );       if( sscanf( line, "allow %s", line ) )    cmd = ALLOW;    else if( sscanf( line, "deny %s", line ) )    cmd = DENY;    else if( sscanf( line, "userdb %s", line ) )    {    line = String.trim_all_whites( line );    if( line == "config_userdb" ) -  code += " userdb_module = roxen.config_userdb_module;\n"; +  code += " userdb_module = roxen.config_userdb_module;\n";    else if( line == "all" ) -  code += " userdb_module = 0;\n"; +  code += " userdb_module = 0;\n";    else if( !m->my_configuration()->find_user_database( line ) )    m->report_notice( LOC_M( 58,"Syntax error in security patterns: "    "Cannot find the user database '%s'")+"'\n",    line);    else    code += -  sprintf(" userdb_module = id->conf->find_user_database( %O );\n", +  sprintf(" userdb_module = id->conf->find_user_database( %O );\n",    line);    continue;    }    else if( sscanf( line, "authmethod %s", line ) )    {    line = String.trim_all_whites( line );    if( line == "all" ) -  code += " authmethod = id->conf;\n"; +  code += " authmethod = id->conf;\n";    else if( !m->my_configuration()->find_auth_module( line ) )    m->report_notice( LOC_M( 59,"Syntax error in security patterns: "    "Cannot find the auth method '%s'")+"\n",    line);    else    code += -  sprintf(" authmethod = id->conf->find_auth_module( %O );\n", +  sprintf(" authmethod = id->conf->find_auth_module( %O );\n",    line);    continue;    }    else if( sscanf( line, "realm %s", line ) )    {    line = String.trim_all_whites( line );    code += sprintf( " realm = %O;\n", line );    }    else    m->report_notice( LOC_M( 60,"Syntax error in security patterns: "    "Expected 'allow' or 'deny'\n" ));    shorted = sscanf( line, "%s return", line );       -  for( int i = 0; i<sizeof( security_checks ); i+=3 ) +  foreach(security_checks, array(string|int|array) check)    { -  string check = security_checks[i]; +     array args; -  if( sizeof( args = array_sscanf( line, check ) ) -  == security_checks[i+1] ) +  if (sizeof(args = array_sscanf(line, check[0])) == check[1])    {    patterns++; -  int thr; +  string thr_code = "1";    // run instructions. -  foreach( security_checks[ i+2 ], mixed instr ) +  foreach(check[2], mixed instr )    {    if( functionp( instr ) )    args = instr( @args );    else if( multisetp( instr ) )    {    foreach( (array)instr, string v )    if( !has_value( variables, v ) )    variables += ({ v });    }    else if( intp( instr ) ) -  thr = instr; +  thr_code = "authmethod->authenticate_throw( id, realm )";    else if( stringp( instr ) )    {    code += sprintf( instr, @args )+"\n";    if( cmd == DENY )    { -  if( thr ) -  code += " return authmethod->authenticate_throw( id, realm );\n"; -  else -  code += " return 1;\n"; +  code += " return " + thr_code + ";\n";    }    else    { -  if( shorted ) -  { -  code += " return fail;\n"; -  code += " else\n"; -  if( thr ) -  code += " return authmethod->authenticate_throw( id, realm );\n"; -  else -  code += " return fail || 1;\n"; +  code += sprintf(" {\n" +  " state->%s = 0;\n" + +  (shorted?" break;\n":"") + +  " } else if (zero_type(state->%s)) {\n" +  " state->%s = %s;\n" +  " }\n", +  check[3], +  check[3], +  check[3], thr_code);    } -  else -  { -  code += " ;\n"; -  code += " else\n"; -  if( thr ) -  code += " fail=authmethod->authenticate_throw( id, realm );\n"; -  else -  code += " if( !fail ) fail=1;\n"; +     }    } -  } -  } +     break;    }    }    }    if( !patterns ) return 0; -  +  code = (" do {\n" + +  code + +  " } while(0);\n");    code = ("#include <module.h>\n"    "int|mapping f( RequestID id )\n" -  "{\n" +variables *";\n" + ";\n" + +  "{\n" + +  (variables * ";\n") + +  ";\n" +   #if defined(SECURITY_PATTERN_DEBUG) || defined(HTACCESS_DEBUG)    sprintf(" report_debug(\"Verifying against pattern:\\n\"\n"    "%{ \" \" %O \"\\n\"\n%}"    " \"...\\n\");\n"    "%s" -  " report_debug(sprintf(\" Result: %%O\\n\", fail));\n", +  " report_debug(sprintf(\" Result: %%O\\n\",\n" +  " state));\n",    pattern/"\n", code) +   #else /* !SECURITY_PATTERN_DEBUG && !HTACCESS_DEBUG */    code +   #endif /* SECURITY_PATTERN_DEBUG || HTACCESS_DEBUG */ -  " return fail;\n}\n" ); +  " int fail;\n" +  " foreach(state; string field; int|mapping value) {\n" +  " if (mappingp(value)) return value;\n" +  " fail = fail || value;\n" +  " }\n" +  " return fail;\n" +  "}\n");   #if defined(SECURITY_PATTERN_DEBUG) || defined(HTACCESS_DEBUG)    report_debug(sprintf("Compiling security pattern:\n"    "%{ %s\n%}\n"    "Code:\n"    "%{ %s\n%}\n",    pattern/"\n",    code/"\n"));   #endif /* SECURITY_PATTERN_DEBUG || HTACCESS_DEBUG */    mixed res = compile_string( code );