PageRenderTime 32ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/modsecurity-apache_2.6.1/apache2/re_operators.c

http://vulture.googlecode.com/
C | 3908 lines | 2693 code | 706 blank | 509 comment | 915 complexity | 05d1cb24dc3e8fcd1044bde4468344d8 MD5 | raw file
Possible License(s): Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * ModSecurity for Apache 2.x, http://www.modsecurity.org/
  3. * Copyright (c) 2004-2011 Trustwave Holdings, Inc. (http://www.trustwave.com/)
  4. *
  5. * You may not use this file except in compliance with
  6. * the License.  You may obtain a copy of the License at
  7. *
  8. *     http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * If any of the files related to licensing are missing or if you have any
  11. * other questions related to licensing please contact Trustwave Holdings, Inc.
  12. * directly using the email address security@modsecurity.org.
  13. */
  14. #include "re.h"
  15. #include "msc_pcre.h"
  16. #include "msc_geo.h"
  17. #include "msc_gsb.h"
  18. #include "apr_lib.h"
  19. #include "apr_strmatch.h"
  20. #include "acmp.h"
  21. #include "msc_util.h"
  22. #if !defined(WIN32) || !defined(WINNT)
  23. #include <regex.h>
  24. #include <arpa/inet.h>
  25. #endif
  26. /**
  27. *
  28. */
  29. void msre_engine_op_register(msre_engine *engine, const char *name,
  30. fn_op_param_init_t fn1, fn_op_execute_t fn2)
  31. {
  32. msre_op_metadata *metadata = (msre_op_metadata *)apr_pcalloc(engine->mp,
  33. sizeof(msre_op_metadata));
  34. if (metadata == NULL) return;
  35. metadata->name = name;
  36. metadata->param_init = fn1;
  37. metadata->execute = fn2;
  38. apr_table_setn(engine->operators, name, (void *)metadata);
  39. }
  40. /**
  41. *
  42. */
  43. msre_op_metadata *msre_engine_op_resolve(msre_engine *engine, const char *name) {
  44. return (msre_op_metadata *)apr_table_get(engine->operators, name);
  45. }
  46. /* -- Operators -- */
  47. /* unconditionalMatch */
  48. static int msre_op_unconditionalmatch_execute(modsec_rec *msr, msre_rule *rule,
  49. msre_var *var, char **error_msg)
  50. {
  51. *error_msg = "Unconditional match in SecAction.";
  52. /* Always match. */
  53. return 1;
  54. }
  55. /* noMatch */
  56. static int msre_op_nomatch_execute(modsec_rec *msr, msre_rule *rule,
  57. msre_var *var, char **error_msg)
  58. {
  59. *error_msg = "No match.";
  60. /* Never match. */
  61. return 0;
  62. }
  63. /* ipmatch */
  64. /*
  65. * \brief Init function to ipmatch operator
  66. *
  67. * \param rule Pointer to the rule
  68. * \param error_msg Pointer to error msg
  69. *
  70. * \retval 1 On Success
  71. * \retval 0 On Fail
  72. */
  73. static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) {
  74. apr_status_t rv;
  75. char *str = NULL;
  76. char *saved = NULL;
  77. char *param = NULL;
  78. msre_ipmatch *current;
  79. msre_ipmatch **last = &rule->ip_op;
  80. if (error_msg == NULL)
  81. return -1;
  82. else
  83. *error_msg = NULL;
  84. param = apr_pstrdup(rule->ruleset->mp, rule->op_param);
  85. str = apr_strtok(param, ",", &saved);
  86. while( str != NULL) {
  87. const char *ipstr, *mask, *sep;
  88. /* get the IP address and mask strings */
  89. sep = strchr(str, '/');
  90. if (sep) {
  91. ipstr = apr_pstrndup(rule->ruleset->mp, str, (sep - str) );
  92. mask = apr_pstrdup(rule->ruleset->mp, (sep + 1) );
  93. }
  94. else {
  95. ipstr = apr_pstrdup(rule->ruleset->mp, str);
  96. mask = NULL;
  97. }
  98. /* create a new msre_ipmatch containing a new apr_ipsubnet_t*, and add it to the linked list */
  99. current = apr_pcalloc(rule->ruleset->mp, sizeof(msre_ipmatch));
  100. rv = apr_ipsubnet_create(&current->ipsubnet, ipstr, mask, rule->ruleset->mp);
  101. if ( rv != APR_SUCCESS ) {
  102. char msgbuf[120];
  103. apr_strerror(rv, msgbuf, sizeof msgbuf);
  104. *error_msg = apr_pstrcat(rule->ruleset->mp, "Error: ", msgbuf, NULL);
  105. return -1;
  106. }
  107. current->address = str;
  108. current->next = NULL;
  109. *last = current;
  110. last = &current->next;
  111. str = apr_strtok(NULL, ",",&saved);
  112. }
  113. return 1;
  114. }
  115. /*
  116. * \brief Execution function to ipmatch operator
  117. *
  118. * \param msr Pointer internal modsec request structure
  119. * \param rule Pointer to the rule
  120. * \param var Pointer to variable structure
  121. * \param error_msg Pointer to error msg
  122. *
  123. * \retval -1 On Failure
  124. * \retval 1 On Match
  125. * \retval 0 On No Match
  126. */
  127. static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  128. msre_ipmatch *current = rule->ip_op;
  129. apr_sockaddr_t *sa;
  130. if (error_msg == NULL)
  131. return -1;
  132. else
  133. *error_msg = NULL;
  134. if(current == NULL) {
  135. msr_log(msr, 1, "ipMatch Internal Error: ipmatch value is null.");
  136. return 0;
  137. }
  138. /* create an apr_sockaddr_t for the value string */
  139. if ( apr_sockaddr_info_get(&sa, var->value, APR_UNSPEC, 0, 0, msr->mp) != APR_SUCCESS ) {
  140. msr_log(msr, 1, "ipMatch Internal Error: Invalid ip address.");
  141. return 0;
  142. }
  143. /* look through the linked list for a match */
  144. while (current) {
  145. if (apr_ipsubnet_test(current->ipsubnet, sa)) {
  146. *error_msg = apr_psprintf(msr->mp, "IPmatch \"%s\" matched \"%s\" at %s.", var->value, current->address, var->name);
  147. return 1;
  148. }
  149. current = current->next;
  150. }
  151. return 0;
  152. }
  153. /* rsub */
  154. static char *param_remove_escape(msre_rule *rule, char *str, int len) {
  155. char *parm = apr_palloc(rule->ruleset->mp, len);
  156. char *ret = parm;
  157. for(;*str!='\0';str++) {
  158. if(*str != '\\') {
  159. *parm++ = *str;
  160. } else {
  161. str++;
  162. if(*str != '/') {
  163. str--;
  164. *parm++ = *str;
  165. } else {
  166. *parm++ = *str;
  167. }
  168. }
  169. }
  170. *parm = '\0';
  171. return ret;
  172. }
  173. /*
  174. * \brief Init function to rsub operator
  175. *
  176. * \param rule Pointer to the rule
  177. * \param error_msg Pointer to error msg
  178. *
  179. * \retval 1 On Success
  180. * \retval 0 On Fail
  181. */
  182. #if !defined(MSC_TEST)
  183. static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) {
  184. ap_regex_t *regex;
  185. const char *pattern = NULL;
  186. const char *line = NULL;
  187. char *reg_pattern = NULL;
  188. char *replace = NULL;
  189. char *e_pattern = NULL;
  190. char *e_replace = NULL;
  191. char *flags = NULL;
  192. char *data = NULL;
  193. char delim;
  194. int ignore_case = 0;
  195. if (error_msg == NULL) return -1;
  196. *error_msg = NULL;
  197. line = rule->op_param;
  198. if (apr_tolower(*line) != 's') {
  199. *error_msg = apr_psprintf(rule->ruleset->mp, "Error rsub operator format, must be s/ pattern");
  200. return 0;
  201. }
  202. data = apr_pstrdup(rule->ruleset->mp, line);
  203. delim = *++data;
  204. if (delim)
  205. reg_pattern = ++data;
  206. if (reg_pattern) {
  207. if (*data != delim) {
  208. for(;*data != '\0' ;data++) {
  209. if(*data == delim) {
  210. data--;
  211. if(*data == '\\') {
  212. data++;
  213. continue;
  214. }
  215. break;
  216. }
  217. }
  218. }
  219. if (*data) {
  220. *++data = '\0';
  221. ++data;
  222. replace = data;
  223. }
  224. }
  225. if (replace) {
  226. if (*data != delim) {
  227. for(;*data != '\0' ;data++) {
  228. if(*data == delim) {
  229. data--;
  230. if(*data == '\\') {
  231. data++;
  232. continue;
  233. }
  234. break;
  235. }
  236. }
  237. }
  238. if (*data) {
  239. *++data = '\0';
  240. flags = ++data;
  241. }
  242. }
  243. if (!delim || !reg_pattern || !replace) {
  244. *error_msg = apr_psprintf(rule->ruleset->mp, "Error rsub operator format - must be s/regex/str/[flags]");
  245. return -1;
  246. }
  247. e_replace = param_remove_escape(rule, replace, strlen(replace));
  248. rule->sub_str = apr_pstrmemdup(rule->ruleset->mp, e_replace, strlen(e_replace));
  249. if (flags) {
  250. while (*flags) {
  251. delim = apr_tolower(*flags);
  252. if (delim == 'i')
  253. ignore_case = 1;
  254. else if (delim == 'd')
  255. rule->escape_re = 1;
  256. else
  257. *error_msg = apr_psprintf(rule->ruleset->mp, "Regex flag not supported");
  258. flags++;
  259. }
  260. }
  261. e_pattern = param_remove_escape(rule, reg_pattern, strlen(reg_pattern));
  262. pattern = apr_pstrndup(rule->ruleset->mp, e_pattern, strlen(e_pattern));
  263. if(strstr(pattern,"%{") == NULL) {
  264. regex = ap_pregcomp(rule->ruleset->mp, pattern, AP_REG_EXTENDED |
  265. (ignore_case ? AP_REG_ICASE : 0));
  266. rule->sub_regex = regex;
  267. } else {
  268. rule->re_precomp = 1;
  269. rule->re_str = apr_pstrndup(rule->ruleset->mp, pattern, strlen(pattern));
  270. rule->sub_regex = NULL;
  271. }
  272. return 1; /* OK */
  273. }
  274. /*
  275. * \brief Execution function to rsub operator
  276. *
  277. * \param msr Pointer internal modsec request structure
  278. * \param rule Pointer to the rule
  279. * \param var Pointer to variable structure
  280. * \param error_msg Pointer to error msg
  281. *
  282. * \retval -1 On Failure
  283. * \retval 1 On Match
  284. * \retval 0 On No Match
  285. */
  286. static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  287. msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  288. msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  289. char *offset = NULL;
  290. int sub = 0, so = 0, p_len = 0;
  291. char *replace = NULL;
  292. char *data = NULL, *pattern = NULL;
  293. unsigned int size = var->value_len;
  294. int output_body = 0, input_body = 0, count = 0;
  295. ap_regmatch_t pmatch[AP_MAX_REG_MATCH];
  296. if (error_msg == NULL) return -1;
  297. *error_msg = NULL;
  298. if(strcmp(var->name,"STREAM_OUTPUT_BODY") == 0 ) {
  299. output_body = 1;
  300. } else if(strcmp(var->name,"STREAM_INPUT_BODY") == 0 ) {
  301. input_body = 1;
  302. } else {
  303. msr_log(msr,9,"Operator rsub only works with STREAM_* variables");
  304. return -1;
  305. }
  306. if(rule->re_precomp == 1) {
  307. re_pattern->value = apr_pstrndup(msr->mp, rule->re_str, strlen(rule->re_str));
  308. re_pattern->value_len = strlen(re_pattern->value);
  309. expand_macros(msr, re_pattern, rule, msr->mp);
  310. if(strlen(re_pattern->value) > 0) {
  311. if(rule->escape_re == 1) {
  312. pattern = log_escape_re(msr->mp, re_pattern->value);
  313. if (msr->txcfg->debuglog_level >= 6) {
  314. msr_log(msr, 6, "Escaping pattern [%s]",pattern);
  315. }
  316. rule->sub_regex = ap_pregcomp(msr->mp, pattern, AP_REG_EXTENDED);
  317. } else {
  318. rule->sub_regex = ap_pregcomp(msr->mp, re_pattern->value, AP_REG_EXTENDED);
  319. }
  320. }
  321. else {
  322. rule->sub_regex = NULL;
  323. }
  324. }
  325. if(rule->sub_regex == NULL) {
  326. *error_msg = "Internal Error: regex data is null.";
  327. return 0;
  328. }
  329. str->value = apr_pstrndup(msr->mp, rule->sub_str, strlen(rule->sub_str));
  330. str->value_len = strlen(str->value);
  331. if(strstr(rule->sub_str,"%{") != NULL)
  332. expand_macros(msr, str, rule, msr->mp);
  333. replace = apr_pstrndup(msr->mp, str->value, str->value_len);
  334. data = apr_pcalloc(msr->mp, var->value_len+(AP_MAX_REG_MATCH*strlen(replace))+1);
  335. if(replace == NULL || data == NULL) {
  336. *error_msg = "Internal Error: cannot allocate memory";
  337. return -1;
  338. }
  339. memcpy(data,var->value,var->value_len);
  340. size += (AP_MAX_REG_MATCH*strlen(replace)+2);
  341. if (ap_regexec(rule->sub_regex, data ,AP_MAX_REG_MATCH, pmatch, 0)) return 0;
  342. for (offset = replace; *offset; offset++)
  343. if (*offset == '\\' && *(offset + 1) > '0' && *(offset + 1) <= '9') {
  344. so = pmatch [*(offset + 1) - 48].rm_so;
  345. p_len = pmatch [*(offset + 1) - 48].rm_eo - so;
  346. if (so < 0 || strlen (replace) + p_len - 1 > size) return 0;
  347. memmove (offset + p_len, offset + 2, strlen (offset) - 1);
  348. memmove (offset, data + so, p_len);
  349. offset = offset + p_len - 2;
  350. }
  351. sub = -1;
  352. for (offset = data; !ap_regexec(rule->sub_regex, offset, 1, pmatch, 0); ) {
  353. p_len = pmatch [0].rm_eo - pmatch [0].rm_so;
  354. count++;
  355. offset += pmatch [0].rm_so;
  356. if (var->value_len - p_len + strlen(replace) + 1 > size) return 0;
  357. memmove (offset + strlen (replace), offset + p_len, strlen (offset) - p_len + 1);
  358. memmove (offset, replace, strlen (replace));
  359. offset += strlen (replace);
  360. if (sub >= 0) break;
  361. }
  362. size -= (((AP_MAX_REG_MATCH - count)*(strlen(replace))) + p_len+2);
  363. if(msr->stream_output_data != NULL && output_body == 1) {
  364. char *stream_output_data = NULL;
  365. stream_output_data = (char *)realloc(msr->stream_output_data, size+1);
  366. msr->stream_output_length = size;
  367. if(stream_output_data == NULL) {
  368. free (msr->stream_output_data);
  369. msr->stream_output_data = NULL;
  370. return -1;
  371. }
  372. var->value_len = size;
  373. msr->of_stream_changed = 1;
  374. msr->stream_output_data = (char *)stream_output_data;
  375. if(msr->stream_output_data != NULL)
  376. apr_cpystrn(msr->stream_output_data, data, size);
  377. }
  378. if(msr->stream_input_data != NULL && input_body == 1) {
  379. char *stream_input_data = NULL;
  380. stream_input_data = (char *)realloc(msr->stream_input_data, size+1);
  381. msr->stream_input_length = size;
  382. if(stream_input_data == NULL) {
  383. free (msr->stream_input_data);
  384. msr->stream_input_data = NULL;
  385. return -1;
  386. }
  387. var->value_len = size;
  388. msr->stream_input_data = (char *)stream_input_data;
  389. if(msr->stream_input_data != NULL)
  390. apr_cpystrn(msr->stream_input_data, data, size);
  391. msr->if_stream_changed = 1;
  392. }
  393. if (! *error_msg) {
  394. *error_msg = apr_psprintf(msr->mp, "Operator rsub succeeded.");
  395. }
  396. return 1;
  397. }
  398. #endif /* MSC_TEST */
  399. /* rx */
  400. static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) {
  401. const char *errptr = NULL;
  402. int erroffset;
  403. msc_regex_t *regex;
  404. const char *pattern = rule->op_param;
  405. if (error_msg == NULL) return -1;
  406. *error_msg = NULL;
  407. /* Compile pattern */
  408. regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
  409. if (regex == NULL) {
  410. *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s",
  411. erroffset, errptr);
  412. return 0;
  413. }
  414. rule->op_param_data = regex;
  415. return 1; /* OK */
  416. }
  417. static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  418. msc_regex_t *regex = (msc_regex_t *)rule->op_param_data;
  419. const char *target;
  420. unsigned int target_length;
  421. char *my_error_msg = NULL;
  422. int ovector[33];
  423. int capture = 0;
  424. int matched_bytes = 0;
  425. int matched = 0;
  426. int rc;
  427. char *qspos = NULL;
  428. const char *parm = NULL;
  429. msc_parm *mparm = NULL;
  430. if (error_msg == NULL) return -1;
  431. *error_msg = NULL;
  432. if (regex == NULL) {
  433. *error_msg = "Internal Error: regex data is null.";
  434. return -1;
  435. }
  436. /* If the given target is null run against an empty
  437. * string. This is a behaviour consistent with previous
  438. * releases.
  439. */
  440. if (var->value == NULL) {
  441. target = "";
  442. target_length = 0;
  443. } else {
  444. target = var->value;
  445. target_length = var->value_len;
  446. }
  447. /* Are we supposed to capture subexpressions? */
  448. capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0;
  449. matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0;
  450. matched = apr_table_get(rule->actionset->actions, "sanitizeMatched") ? 1 : 0;
  451. /* Show when the regex captures but "capture" is not set */
  452. if (msr->txcfg->debuglog_level >= 6) {
  453. int capcount = 0;
  454. rc = msc_fullinfo(regex, PCRE_INFO_CAPTURECOUNT, &capcount);
  455. if (msr->txcfg->debuglog_level >= 6) {
  456. if ((capture == 0) && (capcount > 0)) {
  457. msr_log(msr, 6, "Ignoring regex captures since \"capture\" action is not enabled.");
  458. }
  459. }
  460. }
  461. /* We always use capture so that ovector can be used as working space
  462. * and no memory has to be allocated for any backreferences.
  463. */
  464. rc = msc_regexec_capture(regex, target, target_length, ovector, 30, &my_error_msg);
  465. if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) {
  466. msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  467. if (s == NULL) return -1;
  468. s->name = apr_pstrdup(msr->mp, "MSC_PCRE_LIMITS_EXCEEDED");
  469. s->name_len = strlen(s->name);
  470. s->value = apr_pstrdup(msr->mp, "1");
  471. s->value_len = 1;
  472. if ((s->name == NULL)||(s->value == NULL)) return -1;
  473. apr_table_setn(msr->tx_vars, s->name, (void *)s);
  474. *error_msg = apr_psprintf(msr->mp,
  475. "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - "
  476. "Execution error - "
  477. "PCRE limits exceeded (%d): %s",
  478. rule,((rule->actionset != NULL)&&(rule->actionset->id != NULL)) ? rule->actionset->id : "-",
  479. rule->filename != NULL ? rule->filename : "-",
  480. rule->line_num,rc, my_error_msg);
  481. msr_log(msr, 3, "%s.", *error_msg);
  482. return 0; /* No match. */
  483. }
  484. else if (rc < -1) {
  485. *error_msg = apr_psprintf(msr->mp, "Regex execution failed (%d): %s",
  486. rc, my_error_msg);
  487. return -1;
  488. }
  489. /* Handle captured subexpressions. */
  490. if (capture && rc > 0) {
  491. int i;
  492. /* Unset any of the previously set capture variables. */
  493. apr_table_unset(msr->tx_vars, "0");
  494. apr_table_unset(msr->tx_vars, "1");
  495. apr_table_unset(msr->tx_vars, "2");
  496. apr_table_unset(msr->tx_vars, "3");
  497. apr_table_unset(msr->tx_vars, "4");
  498. apr_table_unset(msr->tx_vars, "5");
  499. apr_table_unset(msr->tx_vars, "6");
  500. apr_table_unset(msr->tx_vars, "7");
  501. apr_table_unset(msr->tx_vars, "8");
  502. apr_table_unset(msr->tx_vars, "9");
  503. /* Use the available captures. */
  504. for(i = 0; i < rc; i++) {
  505. msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  506. if (s == NULL) return -1;
  507. s->name = apr_psprintf(msr->mp, "%d", i);
  508. s->name_len = strlen(s->name);
  509. s->value = apr_pstrmemdup(msr->mp,
  510. target + ovector[2 * i], ovector[2 * i + 1] - ovector[2 * i]);
  511. s->value_len = (ovector[2 * i + 1] - ovector[2 * i]);
  512. if ((s->name == NULL)||(s->value == NULL)) return -1;
  513. apr_table_addn(msr->tx_vars, s->name, (void *)s);
  514. if(((matched == 1) || (matched_bytes == 1)) && (var != NULL) && (var->name != NULL)) {
  515. qspos = apr_psprintf(msr->mp, "%s", var->name);
  516. parm = strstr(qspos, ":");
  517. if (parm != NULL) {
  518. parm++;
  519. mparm = apr_palloc(msr->mp, sizeof(msc_parm));
  520. if (mparm == NULL)
  521. continue;
  522. mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len);
  523. mparm->pad_1 = rule->actionset->arg_min;
  524. mparm->pad_2 = rule->actionset->arg_max;
  525. apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm);
  526. } else {
  527. mparm = apr_palloc(msr->mp, sizeof(msc_parm));
  528. if (mparm == NULL)
  529. continue;
  530. mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len);
  531. apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm);
  532. }
  533. }
  534. if (msr->txcfg->debuglog_level >= 9) {
  535. msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i,
  536. log_escape_nq_ex(msr->mp, s->value, s->value_len));
  537. }
  538. }
  539. }
  540. if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
  541. /* We no longer escape the pattern here as it is done when logging */
  542. char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>"));
  543. /* This message will be logged. */
  544. if (strlen(pattern) > 252) {
  545. *error_msg = apr_psprintf(msr->mp, "Pattern match \"%.252s ...\" at %s.",
  546. pattern, var->name);
  547. } else {
  548. *error_msg = apr_psprintf(msr->mp, "Pattern match \"%s\" at %s.",
  549. pattern, var->name);
  550. }
  551. return 1;
  552. }
  553. /* No match. */
  554. return 0;
  555. }
  556. /* pm */
  557. static char *parse_pm_content(const char *op_parm, unsigned short int op_len, msre_rule *rule, char **error_msg) {
  558. char *parm = NULL;
  559. char *content = NULL;
  560. unsigned short int offset = 0;
  561. char converted = 0;
  562. int i, x;
  563. unsigned char bin = 0, esc = 0, bin_offset = 0;
  564. unsigned char bin_parm[3], c = 0;
  565. char *processed = NULL;
  566. content = apr_pstrdup(rule->ruleset->mp, op_parm);
  567. if (content == NULL) {
  568. *error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
  569. return NULL;
  570. }
  571. while (offset < op_len && apr_isspace(content[offset])) {
  572. offset++;
  573. };
  574. op_len = strlen(content);
  575. if (content[offset] == '\"' && content[op_len-1] == '\"') {
  576. parm = apr_pstrdup(rule->ruleset->mp, content + offset + 1);
  577. if (parm == NULL) {
  578. *error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
  579. return NULL;
  580. }
  581. parm[op_len - offset - 2] = '\0';
  582. } else {
  583. parm = apr_pstrdup(rule->ruleset->mp, content + offset);
  584. if (parm == NULL) {
  585. *error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
  586. return NULL;
  587. }
  588. }
  589. op_len = strlen(parm);
  590. if (op_len == 0) {
  591. *error_msg = apr_psprintf(rule->ruleset->mp, "Content length is 0.");
  592. return NULL;
  593. }
  594. for (i = 0, x = 0; i < op_len; i++) {
  595. if (parm[i] == '|') {
  596. if (bin) {
  597. bin = 0;
  598. } else {
  599. bin = 1;
  600. }
  601. } else if(!esc && parm[i] == '\\') {
  602. esc = 1;
  603. } else {
  604. if (bin) {
  605. if (apr_isdigit(parm[i]) ||
  606. parm[i] == 'A' || parm[i] == 'a' ||
  607. parm[i] == 'B' || parm[i] == 'b' ||
  608. parm[i] == 'C' || parm[i] == 'c' ||
  609. parm[i] == 'D' || parm[i] == 'd' ||
  610. parm[i] == 'E' || parm[i] == 'e' ||
  611. parm[i] == 'F' || parm[i] == 'f')
  612. {
  613. bin_parm[bin_offset] = (char)parm[i];
  614. bin_offset++;
  615. if (bin_offset == 2) {
  616. c = strtol((char *)bin_parm, (char **) NULL, 16) & 0xFF;
  617. bin_offset = 0;
  618. parm[x] = c;
  619. x++;
  620. converted = 1;
  621. }
  622. } else if (parm[i] == ' ') {
  623. }
  624. } else if (esc) {
  625. if (parm[i] == ':' ||
  626. parm[i] == ';' ||
  627. parm[i] == '\\' ||
  628. parm[i] == '\"')
  629. {
  630. parm[x] = parm[i];
  631. x++;
  632. } else {
  633. *error_msg = apr_psprintf(rule->ruleset->mp, "Unsupported escape sequence.");
  634. return NULL;
  635. }
  636. esc = 0;
  637. converted = 1;
  638. } else {
  639. parm[x] = parm[i];
  640. x++;
  641. }
  642. }
  643. }
  644. if (converted) {
  645. op_len = x;
  646. }
  647. processed = apr_pstrmemdup(rule->ruleset->mp, parm, op_len);
  648. if (processed == NULL) {
  649. *error_msg = apr_psprintf(rule->ruleset->mp, "Error allocating memory for pattern matching content.");
  650. return NULL;
  651. }
  652. return processed;
  653. }
  654. static int msre_op_pm_param_init(msre_rule *rule, char **error_msg) {
  655. ACMP *p;
  656. const char *phrase;
  657. const char *next;
  658. unsigned short int op_len;
  659. if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) {
  660. *error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'pm'.");
  661. return 0; /* ERROR */
  662. }
  663. op_len = strlen(rule->op_param);
  664. p = acmp_create(0, rule->ruleset->mp);
  665. if (p == NULL) return 0;
  666. phrase = apr_pstrdup(rule->ruleset->mp, parse_pm_content(rule->op_param, op_len, rule, error_msg));
  667. if(phrase == NULL)
  668. phrase = apr_pstrdup(rule->ruleset->mp, rule->op_param);
  669. /* Loop through phrases */
  670. /* ENH: Need to allow quoted phrases w/space */
  671. for (;;) {
  672. while((apr_isspace(*phrase) != 0) && (*phrase != '\0')) phrase++;
  673. if (*phrase == '\0') break;
  674. next = phrase;
  675. while((apr_isspace(*next) == 0) && (*next != 0)) next++;
  676. acmp_add_pattern(p, phrase, NULL, NULL, next - phrase);
  677. phrase = next;
  678. }
  679. acmp_prepare(p);
  680. rule->op_param_data = p;
  681. return 1;
  682. }
  683. /* pmFromFile */
  684. static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) {
  685. char errstr[1024];
  686. char buf[HUGE_STRING_LEN + 1];
  687. char *fn;
  688. char *next;
  689. char *start;
  690. char *end;
  691. const char *rulefile_path;
  692. char *processed = NULL;
  693. unsigned short int op_len;
  694. apr_status_t rc;
  695. apr_file_t *fd;
  696. ACMP *p;
  697. if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) {
  698. *error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'pmFromFile'.");
  699. return 0; /* ERROR */
  700. }
  701. p = acmp_create(0, rule->ruleset->mp);
  702. if (p == NULL) return 0;
  703. fn = apr_pstrdup(rule->ruleset->mp, rule->op_param);
  704. /* Get the path of the rule filename to use as a base */
  705. rulefile_path = apr_pstrndup(rule->ruleset->mp, rule->filename, strlen(rule->filename) - strlen(apr_filepath_name_get(rule->filename)));
  706. #ifdef DEBUG_CONF
  707. fprintf(stderr, "Rulefile path: \"%s\"\n", rulefile_path);
  708. #endif
  709. /* Loop through filenames */
  710. /* ENH: Need to allow quoted filenames w/space */
  711. for (;;) {
  712. const char *rootpath = NULL;
  713. const char *filepath = NULL;
  714. int line = 0;
  715. /* Trim whitespace */
  716. while((apr_isspace(*fn) != 0) && (*fn != '\0')) fn++;
  717. if (*fn == '\0') break;
  718. next = fn;
  719. while((apr_isspace(*next) == 0) && (*next != '\0')) next++;
  720. while((apr_isspace(*next) != 0) && (*next != '\0')) *(next++) = '\0';
  721. /* Add path of the rule filename for a relative phrase filename */
  722. filepath = fn;
  723. if (apr_filepath_root(&rootpath, &filepath, APR_FILEPATH_TRUENAME, rule->ruleset->mp) != APR_SUCCESS) {
  724. /* We are not an absolute path. It could mean an error, but
  725. * let that pass through to the open call for a better error */
  726. apr_filepath_merge(&fn, rulefile_path, fn, APR_FILEPATH_TRUENAME, rule->ruleset->mp);
  727. }
  728. /* Open file and read */
  729. rc = apr_file_open(&fd, fn, APR_READ | APR_BUFFERED | APR_FILE_NOCLEANUP, 0, rule->ruleset->mp);
  730. if (rc != APR_SUCCESS) {
  731. *error_msg = apr_psprintf(rule->ruleset->mp, "Could not open phrase file \"%s\": %s", fn, apr_strerror(rc, errstr, 1024));
  732. return 0;
  733. }
  734. #ifdef DEBUG_CONF
  735. fprintf(stderr, "Loading phrase file: \"%s\"\n", fn);
  736. #endif
  737. /* Read one pattern per line skipping empty/commented */
  738. for(;;) {
  739. line++;
  740. rc = apr_file_gets(buf, HUGE_STRING_LEN, fd);
  741. if (rc == APR_EOF) break;
  742. if (rc != APR_SUCCESS) {
  743. *error_msg = apr_psprintf(rule->ruleset->mp, "Could not read \"%s\" line %d: %s", fn, line, apr_strerror(rc, errstr, 1024));
  744. return 0;
  745. }
  746. op_len = strlen(buf);
  747. processed = apr_pstrdup(rule->ruleset->mp, parse_pm_content(buf, op_len, rule, error_msg));
  748. /* Trim Whitespace */
  749. if(processed != NULL)
  750. start = processed;
  751. else
  752. start = buf;
  753. while ((apr_isspace(*start) != 0) && (*start != '\0')) start++;
  754. if(processed != NULL)
  755. end = processed + strlen(processed);
  756. else
  757. end = buf + strlen(buf);
  758. if (end > start) end--;
  759. while ((end > start) && (apr_isspace(*end) != 0)) end--;
  760. if (end > start) {
  761. *(++end) = '\0';
  762. }
  763. /* Ignore empty lines and comments */
  764. if ((start == end) || (*start == '#')) continue;
  765. acmp_add_pattern(p, start, NULL, NULL, (end - start));
  766. }
  767. fn = next;
  768. }
  769. if (fd != NULL) apr_file_close(fd);
  770. acmp_prepare(p);
  771. rule->op_param_data = p;
  772. return 1;
  773. }
  774. static int msre_op_pm_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  775. const char *match = NULL;
  776. apr_status_t rc = 0;
  777. int capture;
  778. ACMPT pt;
  779. /* Nothing to read */
  780. if ((var->value == NULL) || (var->value_len == 0)) return 0;
  781. /* Are we supposed to capture subexpressions? */
  782. capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0;
  783. pt.parser = (ACMP *)rule->op_param_data;
  784. pt.ptr = NULL;
  785. rc = acmp_process_quick(&pt, &match, var->value, var->value_len);
  786. if (rc) {
  787. char *match_escaped = log_escape(msr->mp, match ? match : "<Unknown Match>");
  788. /* This message will be logged. */
  789. if (strlen(match_escaped) > 252) {
  790. *error_msg = apr_psprintf(msr->mp, "Matched phrase \"%.252s ...\" at %s.",
  791. match_escaped, var->name);
  792. } else {
  793. *error_msg = apr_psprintf(msr->mp, "Matched phrase \"%s\" at %s.",
  794. match_escaped, var->name);
  795. }
  796. /* Handle capture as tx.0=match */
  797. if (capture) {
  798. int i;
  799. msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  800. if (s == NULL) return -1;
  801. s->name = "0";
  802. s->name_len = strlen(s->name);
  803. s->value = apr_pstrdup(msr->mp, match);
  804. if (s->value == NULL) return -1;
  805. s->value_len = strlen(s->value);
  806. apr_table_setn(msr->tx_vars, s->name, (void *)s);
  807. if (msr->txcfg->debuglog_level >= 9) {
  808. msr_log(msr, 9, "Added phrase match to TX.0: %s",
  809. log_escape_nq_ex(msr->mp, s->value, s->value_len));
  810. }
  811. /* Unset the remaining ones (from previous invocations). */
  812. for(i = rc; i <= 9; i++) {
  813. char buf[2];
  814. apr_snprintf(buf, sizeof(buf), "%d", i);
  815. apr_table_unset(msr->tx_vars, buf);
  816. }
  817. }
  818. return 1;
  819. }
  820. return rc;
  821. }
  822. /* gsbLookup */
  823. /*
  824. * \brief Reduce /./ to /
  825. *
  826. * \param pool Pointer to the memory pool
  827. * \param domain Input data
  828. *
  829. * \retval domain On Failure
  830. * \retval url On Success
  831. */
  832. static const char *gsb_replace_tpath(apr_pool_t *pool, const char *domain, int len) {
  833. char *pos = NULL, *data = NULL;
  834. char *url = NULL;
  835. int match = 0;
  836. url = apr_palloc(pool, len + 1);
  837. data = apr_palloc(pool, len + 1);
  838. memset(data, 0, len+1);
  839. memset(url, 0, len+1);
  840. memcpy(url, domain, len);
  841. while(( pos = strstr(url , "/./" )) != NULL) {
  842. match = 1;
  843. data[0] = '\0';
  844. strncat(data, url, pos - url);
  845. strcat(data , "/");
  846. strcat(data ,pos + strlen("/./"));
  847. strncpy(url , data, len);
  848. }
  849. if(match == 0)
  850. return domain;
  851. return url;
  852. }
  853. /*
  854. * \brief Reduce doble dot to single dot
  855. *
  856. * \param msr Pointer to the modsec resource
  857. * \param domain Input data
  858. *
  859. * \retval domain On Failure
  860. * \retval reduced On Success
  861. */
  862. static const char *gsb_reduce_char(apr_pool_t *pool, const char *domain) {
  863. char *ptr = apr_pstrdup(pool, domain);
  864. char *data = NULL;
  865. char *reduced = NULL;
  866. int skip = 0;
  867. if(ptr == NULL)
  868. return domain;
  869. data = apr_pcalloc(pool, strlen(ptr));
  870. if(data == NULL)
  871. return domain;
  872. reduced = data;
  873. while(*ptr != '\0') {
  874. switch(*ptr) {
  875. case '.':
  876. ptr++;
  877. if(*ptr == '.')
  878. skip = 1;
  879. ptr--;
  880. break;
  881. case '/':
  882. ptr++;
  883. if(*ptr == '/')
  884. skip = 1;
  885. ptr--;
  886. break;
  887. }
  888. if(skip == 0) {
  889. *data = *ptr;
  890. data++;
  891. }
  892. ptr++;
  893. skip = 0;
  894. }
  895. *data = '\0'; --data;
  896. if(*data == '.')
  897. *data = '\0';
  898. else
  899. ++data;
  900. return reduced;
  901. }
  902. /*
  903. * \brief Verify function to gsbLookup operator
  904. *
  905. * \param msr Pointer to the modsec resource
  906. * \param match Pointer to input data
  907. * \param match_length Input size
  908. *
  909. * \retval -1 On Failure
  910. * \retval 1 On Match
  911. * \retval 0 On No Match
  912. */
  913. static int verify_gsb(gsb_db *gsb, modsec_rec *msr, const char *match, unsigned int match_length) {
  914. apr_md5_ctx_t ctx;
  915. apr_status_t rc;
  916. unsigned char digest[APR_MD5_DIGESTSIZE];
  917. const char *hash = NULL;
  918. const char *search = NULL;
  919. memset(digest, 0, sizeof(digest));
  920. apr_md5_init(&ctx);
  921. if ((rc = apr_md5_update(&ctx, match, match_length)) != APR_SUCCESS)
  922. return -1;
  923. apr_md5_final(digest, &ctx);
  924. hash = apr_psprintf(msr->mp, "%s", bytes2hex(msr->mp, digest, 16));
  925. if ((hash != NULL) && (gsb->gsb_table != NULL)) {
  926. search = apr_hash_get(gsb->gsb_table, hash, APR_HASH_KEY_STRING);
  927. if (search != NULL)
  928. return 1;
  929. }
  930. return 0;
  931. }
  932. /*
  933. * \brief Init function to gsbLookup operator
  934. *
  935. * \param rule Pointer to the rule
  936. * \param error_msg Pointer to error msg
  937. *
  938. * \retval 1 On Success
  939. * \retval 0 On Fail
  940. */
  941. static int msre_op_gsbLookup_param_init(msre_rule *rule, char **error_msg) {
  942. const char *errptr = NULL;
  943. int erroffset;
  944. msc_regex_t *regex;
  945. if (error_msg == NULL) return -1;
  946. *error_msg = NULL;
  947. /* Compile rule->op_param */
  948. regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, PCRE_DOTALL | PCRE_MULTILINE, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
  949. if (regex == NULL) {
  950. *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s",
  951. erroffset, errptr);
  952. return 0;
  953. }
  954. rule->op_param_data = regex;
  955. return 1; /* OK */
  956. }
  957. /*
  958. * \brief Execution function to gsbLookup operator
  959. *
  960. * \param msr Pointer internal modsec request structure
  961. * \param rule Pointer to the rule
  962. * \param var Pointer to variable structure
  963. * \param error_msg Pointer to error msg
  964. *
  965. * \retval -1 On Failure
  966. * \retval 1 On Match
  967. * \retval 0 On No Match
  968. */
  969. static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  970. msc_regex_t *regex = (msc_regex_t *)rule->op_param_data;
  971. char *my_error_msg = NULL;
  972. int ovector[33];
  973. unsigned int offset = 0;
  974. gsb_db *gsb = msr->txcfg->gsb;
  975. const char *match = NULL;
  976. unsigned int match_length;
  977. unsigned int canon_length;
  978. int rv, i, ret, count_slash;
  979. unsigned int j = 0;
  980. unsigned int size = var->value_len;
  981. char *base = NULL, *domain = NULL, *savedptr = NULL;
  982. char *str = NULL, *canon = NULL, *dot = NULL;
  983. char *data = NULL, *ptr = NULL, *url = NULL;
  984. int capture, domain_len;
  985. int d_pos = -1;
  986. int s_pos = -1;
  987. if (error_msg == NULL) return -1;
  988. *error_msg = NULL;
  989. if(regex == NULL) {
  990. *error_msg = "Internal Error: regex is null.";
  991. return 0;
  992. }
  993. if(gsb == NULL) {
  994. msr_log(msr, 1, "GSB lookup failed without a database. Set SecGsbLookupDB.");
  995. return 0;
  996. }
  997. data = apr_pcalloc(rule->ruleset->mp, var->value_len+1);
  998. if(data == NULL) {
  999. *error_msg = "Internal Error: cannot allocate memory for data.";
  1000. return -1;
  1001. }
  1002. capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0;
  1003. memcpy(data,var->value,var->value_len);
  1004. while (offset < size && (rv = msc_regexec_ex(regex, data, size, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg)) >= 0)
  1005. {
  1006. for(i = 0; i < rv; ++i)
  1007. {
  1008. match = apr_psprintf(rule->ruleset->mp, "%.*s", ovector[2*i+1] - ovector[2*i], data + ovector[2*i]);
  1009. if (match == NULL) {
  1010. *error_msg = "Internal Error: cannot allocate memory for match.";
  1011. return -1;
  1012. }
  1013. match = remove_escape(rule->ruleset->mp, match, strlen(match));
  1014. match = gsb_replace_tpath(rule->ruleset->mp, match, strlen(match));
  1015. match = gsb_reduce_char(rule->ruleset->mp, match);
  1016. match_length = strlen(match);
  1017. strtolower_inplace((unsigned char *)match);
  1018. if((strstr(match,"http") == NULL) && (match_length > 0) && (strchr(match,'.'))) {
  1019. /* full url */
  1020. if (msr->txcfg->debuglog_level >= 4) {
  1021. msr_log(msr, 4, "GSB: Successfully extracted url: %s", match);
  1022. }
  1023. ret = verify_gsb(gsb, msr, match, match_length);
  1024. if(ret > 0) {
  1025. set_match_to_tx(msr, capture, match, 0);
  1026. if (! *error_msg) {
  1027. *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.",
  1028. log_escape_nq(msr->mp, match));
  1029. }
  1030. str = apr_pstrdup(rule->ruleset->mp,match);
  1031. base = apr_strtok(str,"/",&savedptr);
  1032. if(base != NULL)
  1033. set_match_to_tx(msr, capture, base, 1);
  1034. return 1;
  1035. }
  1036. /* append / in the end of full url */
  1037. if ((match[match_length -1] != '/') && (strchr(match,'?') == NULL)) {
  1038. canon = apr_psprintf(rule->ruleset->mp, "%s/", match);
  1039. if (canon != NULL) {
  1040. canon_length = strlen(canon);
  1041. ret = verify_gsb(gsb, msr, canon, canon_length);
  1042. if(ret > 0) {
  1043. set_match_to_tx(msr, capture, match, 0);
  1044. if (! *error_msg) {
  1045. *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.",
  1046. log_escape_nq(msr->mp, canon));
  1047. }
  1048. str = apr_pstrdup(rule->ruleset->mp,match);
  1049. base = apr_strtok(str,"/",&savedptr);
  1050. if(base != NULL)
  1051. set_match_to_tx(msr, capture, base, 1);
  1052. return 1;
  1053. }
  1054. }
  1055. }
  1056. /* Parsing full url */
  1057. domain = apr_pstrdup(rule->ruleset->mp, match);
  1058. domain_len = strlen(domain);
  1059. if(*domain != '/') {
  1060. if(domain[domain_len-1] == '.')
  1061. domain[domain_len-1] = '\0';
  1062. if(domain[domain_len-1] == '/' && domain[domain_len-2] == '.') {
  1063. domain[domain_len-2] = '/';
  1064. domain[domain_len-1] = '\0';
  1065. }
  1066. dot = strchr(domain,'.');
  1067. if(dot != NULL) {
  1068. canon = apr_pstrdup(rule->ruleset->mp, domain);
  1069. ret = verify_gsb(gsb, msr, canon, strlen(canon));
  1070. if(ret > 0) {
  1071. set_match_to_tx(msr, capture, canon, 0);
  1072. if (! *error_msg) {
  1073. *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.",
  1074. log_escape_nq(msr->mp, canon));
  1075. }
  1076. str = apr_pstrdup(rule->ruleset->mp,match);
  1077. base = apr_strtok(str,"/",&savedptr);
  1078. if(base != NULL)
  1079. set_match_to_tx(msr, capture, base, 1);
  1080. return 1;
  1081. }
  1082. base = apr_strtok(canon,"?",&savedptr);
  1083. if(base != NULL) {
  1084. ret = verify_gsb(gsb, msr, base, strlen(base));
  1085. if(ret > 0) {
  1086. set_match_to_tx(msr, capture, base, 0);
  1087. if (! *error_msg) {
  1088. *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.",
  1089. log_escape_nq(msr->mp, base));
  1090. }
  1091. str = apr_pstrdup(rule->ruleset->mp,match);
  1092. base = apr_strtok(str,"/",&savedptr);
  1093. if(base != NULL)
  1094. set_match_to_tx(msr, capture, base, 1);
  1095. return 1;
  1096. }
  1097. }
  1098. url = apr_palloc(rule->ruleset->mp, strlen(canon));
  1099. count_slash = 0;
  1100. while(*canon != '\0') {
  1101. switch (*canon) {
  1102. case '/':
  1103. ptr = apr_psprintf(rule->ruleset->mp,"%s/",url);
  1104. ret = verify_gsb(gsb, msr, ptr, strlen(ptr));
  1105. if(ret > 0) {
  1106. set_match_to_tx(msr, capture, ptr, 0);
  1107. if (! *error_msg) {
  1108. *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.",
  1109. log_escape_nq(msr->mp, ptr));
  1110. }
  1111. str = apr_pstrdup(rule->ruleset->mp,match);
  1112. base = apr_strtok(str,"/",&savedptr);
  1113. if(base != NULL)
  1114. set_match_to_tx(msr, capture, base, 1);
  1115. return 1;
  1116. }
  1117. break;
  1118. }
  1119. url[count_slash] = *canon;
  1120. count_slash++;
  1121. canon++;
  1122. }
  1123. }
  1124. }
  1125. /* Do the same for subdomains */
  1126. for(j=0; j<strlen(match); j++) {
  1127. if(match[j] == '/') {
  1128. s_pos = j;
  1129. break;
  1130. }
  1131. }
  1132. str = apr_pstrdup(rule->ruleset->mp, match);
  1133. while (*str != '\0') {
  1134. switch(*str) {
  1135. case '.':
  1136. domain++;
  1137. domain_len = strlen(domain);
  1138. d_pos = strchr(domain,'.') - domain;
  1139. if(s_pos >= 0 && d_pos >= 0 && d_pos > s_pos)
  1140. break;
  1141. if(*domain != '/') {
  1142. if(domain[domain_len-1] == '.')
  1143. domain[domain_len-1] = '\0';
  1144. if(domain[domain_len-1] == '/' && domain[domain_len-2] == '.') {
  1145. domain[domain_len-2] = '/';
  1146. domain[domain_len-1] = '\0';
  1147. }
  1148. dot = strchr(domain,'.');
  1149. if(dot != NULL) {
  1150. canon = apr_pstrdup(rule->ruleset->mp, domain);
  1151. ret = verify_gsb(gsb, msr, canon, strlen(canon));
  1152. if(ret > 0) {
  1153. set_match_to_tx(msr, capture, canon, 0);
  1154. if (! *error_msg) {
  1155. *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.",
  1156. log_escape_nq(msr->mp, canon));
  1157. }
  1158. str = apr_pstrdup(rule->ruleset->mp,match);
  1159. base = apr_strtok(str,"/",&savedptr);
  1160. if(base != NULL)
  1161. set_match_to_tx(msr, capture, base, 1);
  1162. return 1;
  1163. }
  1164. base = apr_strtok(canon,"?",&savedptr);
  1165. if(base != NULL) {
  1166. ret = verify_gsb(gsb, msr, base, strlen(base));
  1167. if(ret > 0) {
  1168. set_match_to_tx(msr, capture, base, 0);
  1169. if (! *error_msg) {
  1170. *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.",
  1171. log_escape_nq(msr->mp, base));
  1172. }
  1173. str = apr_pstrdup(rule->ruleset->mp,match);
  1174. base = apr_strtok(str,"/",&savedptr);
  1175. if(base != NULL)
  1176. set_match_to_tx(msr, capture, base, 1);
  1177. return 1;
  1178. }
  1179. }
  1180. url = apr_palloc(rule->ruleset->mp, strlen(canon));
  1181. count_slash = 0;
  1182. while(*canon != '\0') {
  1183. switch (*canon) {
  1184. case '/':
  1185. ptr = apr_psprintf(rule->ruleset->mp,"%s/",url);
  1186. ret = verify_gsb(gsb, msr, ptr, strlen(ptr));
  1187. if(ret > 0) {
  1188. set_match_to_tx(msr, capture, ptr, 0);
  1189. if (! *error_msg) {
  1190. *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.",
  1191. log_escape_nq(msr->mp, ptr));
  1192. }
  1193. str = apr_pstrdup(rule->ruleset->mp,match);
  1194. base = apr_strtok(str,"/",&savedptr);
  1195. if(base != NULL)
  1196. set_match_to_tx(msr, capture, base, 1);
  1197. return 1;
  1198. }
  1199. break;
  1200. }
  1201. url[count_slash] = *canon;
  1202. count_slash++;
  1203. canon++;
  1204. }
  1205. }
  1206. }
  1207. break;
  1208. }
  1209. domain = str;
  1210. domain++;
  1211. str++;
  1212. }
  1213. }
  1214. }
  1215. offset = ovector[1];
  1216. }
  1217. return 0;
  1218. }
  1219. /* within */
  1220. static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  1221. msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  1222. const char *match = NULL;
  1223. const char *target;
  1224. unsigned int match_length;
  1225. unsigned int target_length = 0;
  1226. unsigned int i, i_max;
  1227. str->value = (char *)rule->op_param;
  1228. str->value_len = strlen(str->value);
  1229. if (error_msg == NULL) return -1;
  1230. *error_msg = NULL;
  1231. if (str->value == NULL) {
  1232. *error_msg = "Internal Error: match string is null.";
  1233. return -1;
  1234. }
  1235. expand_macros(msr, str, rule, msr->mp);
  1236. match = (const char *)str->value;
  1237. match_length = str->value_len;
  1238. /* If the given target is null we give up without a match */
  1239. if (var->value == NULL) {
  1240. /* No match. */
  1241. return 0;
  1242. }
  1243. target = var->value;
  1244. target_length = var->value_len;
  1245. /* The empty string always matches */
  1246. if (target_length == 0) {
  1247. /* Match. */
  1248. *error_msg = apr_psprintf(msr->mp, "String match within \"\" at %s.",
  1249. var->name);
  1250. return 1;
  1251. }
  1252. /* This is impossible to match */
  1253. if (target_length > match_length) {
  1254. /* No match. */
  1255. return 0;
  1256. }
  1257. /* scan for first character, then compare from there until we

Large files files are truncated, but you can click here to view the full file