/* Validate URL */ bool validate_url(t_session *session) { if (valid_uri(session->uri, session->host->allow_dot_files)) { if (session->host->secure_url == false) { return true; } else if (strstr(session->request_uri, "%00") == NULL) { return true; } else { session->return_code = 403; } } else { session->return_code = (session->request_method == PUT) ? 403 : 404; } log_exploit_attempt(session, "invalid URL", NULL); #ifdef ENABLE_TOMAHAWK increment_counter(COUNTER_EXPLOIT); #endif #ifdef ENABLE_MONITOR if (session->config->monitor_enabled) { monitor_count_exploit(session); monitor_event("Invalid URL %s for %s", session->uri, session->host->hostname.item[0]); } #endif session->error_cause = ec_INVALID_URL; return false; }
int use_toolkit(char *url, char *toolkit_id, t_toolkit_options *options) { t_url_toolkit *toolkit; t_toolkit_rule *rule; bool condition_met, url_replaced = false; int result, skip = 0; char *file, *qmark, *header; regmatch_t pmatch[REGEXEC_NMATCH]; struct stat fileinfo; t_http_header *headers; if (options == NULL) { return UT_ERROR; } options->new_url = NULL; if ((toolkit = select_toolkit(toolkit_id, options->url_toolkit)) == NULL) { return UT_ERROR; } rule = toolkit->toolkit_rule; while (rule != NULL) { condition_met = false; /* Skip lines */ if (skip > 0) { skip--; rule = rule->next; continue; } /* Condition */ switch (rule->condition) { case tc_none: /* None */ condition_met = true; break; case tc_match: /* Match */ if (regexec(&(rule->pattern), url, REGEXEC_NMATCH, pmatch, 0) == 0) { condition_met = true; } if (rule->neg_match) { condition_met = (condition_met == false); } break; case tc_header: /* Header */ if (rule->header == NULL) { headers = options->http_headers; while (headers != NULL) { if (regexec(&(rule->pattern), headers->data + headers->value_offset, REGEXEC_NMATCH, pmatch, 0) == 0) { condition_met = true; } if (rule->neg_match) { condition_met = (condition_met == false); } if (condition_met) { break; } headers = headers->next; } } else { if ((header = get_http_header(rule->header, options->http_headers)) == NULL) { break; } if (regexec(&(rule->pattern), header, REGEXEC_NMATCH, pmatch, 0) == 0) { condition_met = true; } if (rule->neg_match) { condition_met = (condition_met == false); } } break; case tc_method: /* Request method */ if (strcmp(options->method, rule->parameter) == 0) { condition_met = true; } if (rule->neg_match) { condition_met = (condition_met == false); } break; case tc_request_uri: /* Request URI */ if (valid_uri(url, false) == false) { break; } if ((file = make_path(options->website_root, url)) == NULL) { return UT_ERROR; } if ((qmark = strchr(file, '?')) != NULL) { *qmark = '\0'; } url_decode(file); if (stat(file, &fileinfo) != -1) { switch (rule->value) { case IU_EXISTS: if (S_ISDIR(fileinfo.st_mode) || S_ISREG(fileinfo.st_mode)) { condition_met = true; } break; case IU_ISFILE: if (S_ISREG(fileinfo.st_mode)) { condition_met = true; } break; case IU_ISDIR: if (S_ISDIR(fileinfo.st_mode)) { condition_met = true; } break; } } free(file); break; case tc_total_connections: /* Total connections reached? */ condition_met = options->total_connections >= rule->value; break; #ifdef ENABLE_TLS case tc_use_tls: /* Client connections uses TLS? */ condition_met = options->use_tls; break; #endif } /* Condition not met */ if (condition_met == false) { rule = rule->next; continue; } /* Operation */ switch (rule->operation) { case to_none: /* None */ break; case to_ban: /* Ban client */ options->ban = rule->value; break; case to_deny_access: /* Deny access */ return UT_DENY_ACCESS; case to_omit_request_log: /* Omit requeest log */ options->log_request = false; break; case to_expire: /* Send Expire HTTP header */ options->expire = rule->value; options->caco_private = rule->caco_private; break; case to_fastcgi: /* Use FastCGI server */ options->fastcgi_server = rule->parameter; break; case to_redirect: /* Redirect client */ if (rule->neg_match) { if ((options->new_url = strdup(rule->parameter)) == NULL) { return UT_ERROR; } } else if (do_rewrite(url, &(rule->pattern), pmatch, rule->parameter, &(options->new_url), rule->match_loop) == -1) { if (options->new_url != NULL) { free(options->new_url); options->new_url = NULL; } return UT_ERROR; } if (options->new_url != NULL) { if (url_replaced) { free(url); } return UT_REDIRECT; } else if (url_replaced) { options->new_url = url; } break; case to_rewrite: /* Rewrite */ if (rule->neg_match) { if ((options->new_url = strdup(rule->parameter)) == NULL) { return UT_ERROR; } } else if (do_rewrite(url, &(rule->pattern), pmatch, rule->parameter, &(options->new_url), rule->match_loop) == -1) { if (options->new_url != NULL) { free(options->new_url); options->new_url = NULL; } return UT_ERROR; } if (options->new_url != NULL) { if (url_replaced) { free(url); } url = options->new_url; url_replaced = true; } else if (url_replaced) { options->new_url = url; } break; case to_skip: /* Skip */ skip = rule->value; break; case to_sub: /* Subroutine */ if (++(options->sub_depth) > MAX_SUB_DEPTH) { return UT_ERROR; } if ((result = use_toolkit(url, rule->parameter, options)) == UT_ERROR) { if (options->new_url != NULL) { free(options->new_url); options->new_url = NULL; } return UT_ERROR; } options->sub_depth--; if (options->new_url != NULL) { if (url_replaced) { free(url); } url = options->new_url; url_replaced = true; } else if (url_replaced) { options->new_url = url; } if (result != UT_RETURN) { return result; } break; case to_use: /* Replace URL */ if (url_replaced) { free(url); } if ((options->new_url = strdup(rule->parameter)) == NULL) { return UT_ERROR; } break; } /* Flow */ switch (rule->flow) { case tf_continue: /* Continue */ break; case tf_exit: /* Exit */ return UT_EXIT; case tf_return: /* Return */ return UT_RETURN; } rule = rule->next; } return UT_RETURN; }
static bool parse_parameters(t_toolkit_rule *new_rule, char *value, char **operation) { char *rest; bool allowed = false; int loop, time; split_string(value, &value, &rest, ' '); while (*operation != NULL) { if (strcasecmp(*operation, value) == 0) { allowed = true; break; } operation++; } if (allowed == false) { return false; } if (strcasecmp(value, "ban") == 0) { /* Ban */ new_rule->operation = to_ban; if ((new_rule->value = str_to_int(rest)) == false) { return false; } } else if (strcasecmp(value, "call") == 0) { /* Call */ new_rule->operation = to_sub; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "denyaccess") == 0) { /* Deny access */ new_rule->operation = to_deny_access; new_rule->flow = tf_exit; } else if (strcasecmp(value, "omitrequestlog") == 0) { /* Omit request log */ new_rule->operation = to_omit_request_log; } else if (strcasecmp(value, "exit") == 0) { /* Exit */ new_rule->flow = tf_exit; } else if (strcasecmp(value, "expire") == 0) { /* Expire */ new_rule->operation = to_expire; if (split_string(rest, &value, &rest, ' ') == -1) { return false; } if ((new_rule->value = str_to_int(value)) == -1) { return false; } time = new_rule->value; split_string(rest, &value, &rest, ' '); if (strcasecmp(value, "minutes") == 0) { new_rule->value *= MINUTE; } else if (strcasecmp(value, "hours") == 0) { new_rule->value *= HOUR; } else if (strcasecmp(value, "days") == 0) { new_rule->value *= DAY; } else if (strcasecmp(value, "weeks") == 0) { new_rule->value *= 7 * DAY; } else if (strcasecmp(value, "months") == 0) { new_rule->value *= 30.5 * DAY; } else if (strcasecmp(value, "seconds") != 0) { return false; } if (new_rule->value < time) { return false; } /* public / private */ if (rest == NULL) { return true; } split_string(rest, &value, &rest, ' '); if (strcasecmp(value, "private") == 0) { new_rule->caco_private = true; } else if (strcasecmp(value, "public") == 0) { new_rule->caco_private = false; } else if (rest == NULL) { rest = value; } else { return false; } /* exit / return */ if (rest == NULL) { return true; } if (strcasecmp(rest, "exit") == 0) { new_rule->flow = tf_exit; } else if (strcasecmp(rest, "return") == 0) { new_rule->flow = tf_return; } else { return false; } } else if (strcasecmp(value, "goto") == 0) { /* Goto */ new_rule->operation = to_sub; new_rule->flow = tf_exit; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "redirect") == 0) { /* Redirect */ new_rule->operation = to_redirect; new_rule->flow = tf_exit; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "return") == 0) { /* Return */ new_rule->flow = tf_return; } else if (strcasecmp(value, "rewrite") == 0) { /* Rewrite */ new_rule->operation = to_rewrite; new_rule->flow = tf_exit; split_string(rest, &value, &rest, ' '); if (value == NULL) { return false; } else if ((new_rule->parameter = strdup(value)) == NULL) { return false; } if (rest != NULL) { split_string(rest, &value, &rest, ' '); if ((loop = str_to_int(value)) > 0) { if (loop > MAX_MATCH_LOOP) { return false; } new_rule->match_loop = loop; if ((value = rest) == NULL) { return true; } } else if (rest != NULL) { return false; } if (strcasecmp(value, "continue") == 0) { new_rule->flow = tf_continue; } else if (strcasecmp(value, "return") == 0) { new_rule->flow = tf_return; } else { return false; } } } else if (strcasecmp(value, "skip") == 0) { /* Skip */ new_rule->operation = to_skip; if ((new_rule->value = str_to_int(rest)) < 1) { return false; } } else if (strcasecmp(value, "use") == 0) { /* Use */ new_rule->operation = to_use; new_rule->flow = tf_exit; if (valid_uri(rest, false) == false) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "usefastcgi") == 0) { /* Match UseFastCGI */ new_rule->operation = to_fastcgi; new_rule->flow = tf_exit; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else { /* Error */ return false; } return true; }
bool toolkit_setting(char *key, char *value, t_url_toolkit *toolkit) { t_toolkit_rule *new_rule, *rule; char *rest; int loop, time, cflags; size_t len; if ((key == NULL) || (value == NULL) || (toolkit == NULL)) { return false; } if (strcmp(key, "toolkitid") == 0) { return (toolkit->toolkit_id = strdup(value)) != NULL; } if ((new_rule = (t_toolkit_rule*)malloc(sizeof(t_toolkit_rule))) == NULL) { return false; } else if (toolkit->toolkit_rule == NULL) { toolkit->toolkit_rule = new_rule; } else { rule = toolkit->toolkit_rule; while (rule->next != NULL) { rule = rule->next; } rule->next = new_rule; } new_rule->condition = tc_none; new_rule->operation = to_none; new_rule->flow = tf_continue; new_rule->match_loop = 1; new_rule->neg_match = false; new_rule->parameter = NULL; new_rule->header = NULL; new_rule->value = 0; new_rule->case_insensitive = false; new_rule->next = NULL; if (strcmp(key, "matchci") == 0) { new_rule->case_insensitive = true; key = "match"; } if (strcasecmp(key, "call") == 0) { /* Call */ new_rule->operation = to_sub; if ((new_rule->parameter = strdup(value)) == NULL) { return false; } } else if (strcasecmp(key, "header") == 0) { /* Header */ new_rule->condition = tc_header; if (split_string(value, &value, &rest, ' ') == -1) { return false; } len = strlen(value); if ((new_rule->header = (char*)malloc(len + 2)) == NULL) { return false; } sprintf(new_rule->header, "%s:", value); if ((*rest == '\'') || (*rest == '"')) { value = rest + 1; if ((rest = strchr(rest + 1, *rest)) == NULL) { return false; } *rest = '\0'; rest = remove_spaces(rest + 1); } else if (split_string(rest, &value, &rest, ' ') == -1) { return false; } if (*value == '!') { new_rule->neg_match = true; value++; } if (regcomp(&(new_rule->pattern), value, REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0) { return false; } split_string(rest, &value, &rest, ' '); if (strcasecmp(value, "call") == 0) { /* Header Call */ new_rule->operation = to_sub; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "denyaccess") == 0) { /* Header Deny access */ new_rule->operation = to_deny_access; new_rule->flow = tf_exit; } else if (strcasecmp(value, "exit") == 0) { /* Header Exit */ new_rule->flow = tf_exit; } else if (strcasecmp(value, "goto") == 0) { /* Header Goto */ new_rule->operation = to_sub; new_rule->flow = tf_exit; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "redirect") == 0) { /* Header Redirect */ new_rule->operation = to_redirect; new_rule->flow = tf_exit; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "return") == 0) { /* Header Return */ new_rule->flow = tf_return; } else if (strcasecmp(value, "skip") == 0) { /* Header Skip */ if ((new_rule->value = str2int(rest)) < 1) { return false; } } else if (strcasecmp(value, "use") == 0) { /* Header Use */ new_rule->operation = to_replace; new_rule->flow = tf_exit; if (valid_uri(rest, false) == false) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else { return false; } } else if (strcmp(key, "match") == 0) { /* Match */ cflags = REG_EXTENDED; if (new_rule->case_insensitive) { cflags |= REG_ICASE; } new_rule->condition = tc_match; if (split_string(value, &value, &rest, ' ') == -1) { return false; } if (*value == '!') { new_rule->neg_match = true; value++; } if (regcomp(&(new_rule->pattern), value, cflags) != 0) { return false; } split_string(rest, &value, &rest, ' '); if (strcasecmp(value, "ban") == 0) { /* Match Ban */ new_rule->operation = to_ban; if ((new_rule->value = str2int(rest)) == false) { return false; } } else if (strcasecmp(value, "call") == 0) { /* Match Call */ new_rule->operation = to_sub; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "denyaccess") == 0) { /* Match DenyAccess */ new_rule->operation = to_deny_access; new_rule->flow = tf_exit; } else if (strcasecmp(value, "exit") == 0) { /* Match Exit */ new_rule->flow = tf_exit; } else if (strcasecmp(value, "expire") == 0) { /* Match Expire */ new_rule->operation = to_expire; if (split_string(rest, &value, &rest, ' ') == -1) { return false; } if ((new_rule->value = str2int(value)) == -1) { return false; } time = new_rule->value; split_string(rest, &value, &rest, ' '); if (strcasecmp(value, "minutes") == 0) { new_rule->value *= MINUTE; } else if (strcasecmp(value, "hours") == 0) { new_rule->value *= HOUR; } else if (strcasecmp(value, "days") == 0) { new_rule->value *= DAY; } else if (strcasecmp(value, "weeks") == 0) { new_rule->value *= 7 * DAY; } else if (strcasecmp(value, "months") == 0) { new_rule->value *= 30.5 * DAY; } else if (strcasecmp(value, "seconds") != 0) { return false; } if (new_rule->value < time) { return false; } if (rest != NULL) { if (strcasecmp(rest, "exit") == 0) { new_rule->flow = tf_exit; } else if (strcasecmp(rest, "return") == 0) { new_rule->flow = tf_return; } else { return false; } } } else if (strcasecmp(value, "goto") == 0) { /* Match Goto */ new_rule->operation = to_sub; new_rule->flow = tf_exit; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "redirect") == 0) { /* Match Redirect */ new_rule->operation = to_redirect; new_rule->flow = tf_exit; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "return") == 0) { /* Match Return */ new_rule->flow = tf_return; } else if (strcasecmp(value, "rewrite") == 0) { /* Match Rewrite */ new_rule->operation = to_rewrite; new_rule->flow = tf_exit; split_string(rest, &value, &rest, ' '); if (value == NULL) { return false; } else if ((new_rule->parameter = strdup(value)) == NULL) { return false; } if (rest != NULL) { split_string(rest, &value, &rest, ' '); if ((loop = str2int(value)) > 0) { if (loop > MAX_MATCH_LOOP) { return false; } new_rule->match_loop = loop; if ((value = rest) == NULL) { return true; } } else if (rest != NULL) { return false; } if (strcasecmp(value, "continue") == 0) { new_rule->flow = tf_continue; } else if (strcasecmp(value, "return") == 0) { new_rule->flow = tf_return; } else { return false; } } } else if (strcasecmp(value, "skip") == 0) { /* Match Skip */ new_rule->operation = to_skip; if ((new_rule->value = str2int(rest)) < 1) { return false; } } else if (strcasecmp(value, "usefastcgi") == 0) { /* Match UseFastCGI */ new_rule->operation = to_fastcgi; new_rule->flow = tf_exit; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else { return false; } } else if (strcasecmp(key, "requesturi") == 0) { /* RequestURI */ new_rule->condition = tc_request_uri; if (split_string(value, &value, &rest, ' ') == -1) { return false; } if (strcasecmp(value, "exists") == 0) { new_rule->value = IU_EXISTS; } else if (strcasecmp(value, "isfile") == 0) { new_rule->value = IU_ISFILE; } else if (strcasecmp(value, "isdir") == 0) { new_rule->value = IU_ISDIR; } else { return false; } if (strcasecmp(rest, "return") == 0) { new_rule->flow = tf_return; } else if (strcasecmp(rest, "exit") == 0) { new_rule->flow = tf_exit; } else { return false; } } else if (strcasecmp(key, "skip") == 0) { /* Skip */ new_rule->operation = to_skip; if ((new_rule->value = str2int(value)) < 1) { return false; } #ifdef ENABLE_SSL } else if (strcmp(key, "usessl") == 0) { /* UseSSL */ new_rule->condition = tc_use_ssl; split_string(value, &value, &rest, ' '); if (strcasecmp(value, "call") == 0) { /* UseSSL Call */ new_rule->operation = to_sub; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "exit") == 0) { /* UseSSL Exit */ new_rule->flow = tf_exit; } else if (strcasecmp(value, "goto") == 0) { /* UseSSL Goto */ new_rule->operation = to_sub; new_rule->flow = tf_exit; if (rest == NULL) { return false; } else if ((new_rule->parameter = strdup(rest)) == NULL) { return false; } } else if (strcasecmp(value, "return") == 0) { /* UseSSL Return */ new_rule->flow = tf_return; } else if (strcasecmp(value, "skip") == 0) { /* UseSSL Skip */ new_rule->operation = to_skip; if ((new_rule->value = str2int(rest)) < 1) { return false; } } else { return false; } #endif } else { /* Unknown condition */ return false; } return true; }