PageRenderTime 79ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  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
  1258. * have a match or there is no room left in the target
  1259. */
  1260. i_max = match_length - target_length;
  1261. for (i = 0; i <= i_max; i++) {
  1262. if (match[i] == target[0]) {
  1263. if (memcmp((target + 1), (match + i + 1), (target_length - 1)) == 0) {
  1264. /* match. */
  1265. *error_msg = apr_psprintf(msr->mp, "String match within \"%s\" at %s.",
  1266. log_escape_ex(msr->mp, match, match_length),
  1267. var->name);
  1268. return 1;
  1269. }
  1270. }
  1271. }
  1272. /* No match. */
  1273. return 0;
  1274. }
  1275. /* contains */
  1276. static int msre_op_contains_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  1277. msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  1278. const char *match = NULL;
  1279. const char *target;
  1280. unsigned int match_length;
  1281. unsigned int target_length = 0;
  1282. unsigned int i, i_max;
  1283. str->value = (char *)rule->op_param;
  1284. str->value_len = strlen(str->value);
  1285. if (error_msg == NULL) return -1;
  1286. *error_msg = NULL;
  1287. if (str->value == NULL) {
  1288. *error_msg = "Internal Error: match string is null.";
  1289. return -1;
  1290. }
  1291. expand_macros(msr, str, rule, msr->mp);
  1292. match = (const char *)str->value;
  1293. match_length = str->value_len;
  1294. /* If the given target is null run against an empty
  1295. * string. This is a behaviour consistent with previous
  1296. * releases.
  1297. */
  1298. if (var->value == NULL) {
  1299. target = "";
  1300. target_length = 0;
  1301. } else {
  1302. target = var->value;
  1303. target_length = var->value_len;
  1304. }
  1305. /* The empty string always matches */
  1306. if (match_length == 0) {
  1307. /* Match. */
  1308. *error_msg = apr_psprintf(msr->mp, "String match \"\" at %s.", var->name);
  1309. return 1;
  1310. }
  1311. /* This is impossible to match */
  1312. if (match_length > target_length) {
  1313. /* No match. */
  1314. return 0;
  1315. }
  1316. /* scan for first character, then compare from there until we
  1317. * have a match or there is no room left in the target
  1318. */
  1319. i_max = target_length - match_length;
  1320. for (i = 0; i <= i_max; i++) {
  1321. /* First character matched - avoid func call */
  1322. if (target[i] == match[0]) {
  1323. /* See if remaining matches */
  1324. if ( (match_length == 1)
  1325. || (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0))
  1326. {
  1327. /* Match. */
  1328. *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.",
  1329. log_escape_ex(msr->mp, match, match_length),
  1330. var->name);
  1331. return 1;
  1332. }
  1333. }
  1334. }
  1335. /* No match. */
  1336. return 0;
  1337. }
  1338. /* containsWord */
  1339. static int msre_op_containsWord_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  1340. msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  1341. const char *match = NULL;
  1342. const char *target;
  1343. unsigned int match_length;
  1344. unsigned int target_length = 0;
  1345. unsigned int i, i_max;
  1346. int rc = 0;
  1347. str->value = (char *)rule->op_param;
  1348. str->value_len = strlen(str->value);
  1349. if (error_msg == NULL) return -1;
  1350. *error_msg = NULL;
  1351. if (str->value == NULL) {
  1352. *error_msg = "Internal Error: match string is null.";
  1353. return -1;
  1354. }
  1355. expand_macros(msr, str, rule, msr->mp);
  1356. match = (const char *)str->value;
  1357. match_length = str->value_len;
  1358. /* If the given target is null run against an empty
  1359. * string. This is a behaviour consistent with previous
  1360. * releases.
  1361. */
  1362. if (var->value == NULL) {
  1363. target = "";
  1364. target_length = 0;
  1365. } else {
  1366. target = var->value;
  1367. target_length = var->value_len;
  1368. }
  1369. /* The empty string always matches */
  1370. if (match_length == 0) {
  1371. /* Match. */
  1372. *error_msg = apr_psprintf(msr->mp, "String match \"\" at %s.", var->name);
  1373. return 1;
  1374. }
  1375. /* This is impossible to match */
  1376. if (match_length > target_length) {
  1377. /* No match. */
  1378. return 0;
  1379. }
  1380. /* scan for first character, then compare from there until we
  1381. * have a match or there is no room left in the target
  1382. */
  1383. i_max = target_length - match_length;
  1384. for (i = 0; i <= i_max; i++) {
  1385. /* Previous char must have been a start or non-word */
  1386. if ((i > 0) && (apr_isalnum(target[i-1])||(target[i-1] == '_')))
  1387. continue;
  1388. /* First character matched - avoid func call */
  1389. if (target[i] == match[0]) {
  1390. /* See if remaining matches */
  1391. if ( (match_length == 1)
  1392. || (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0))
  1393. {
  1394. /* check boundaries */
  1395. if (i == i_max) {
  1396. /* exact/end word match */
  1397. rc = 1;
  1398. }
  1399. else if (!(apr_isalnum(target[i + match_length])||(target[i + match_length] == '_'))) {
  1400. /* start/mid word match */
  1401. rc = 1;
  1402. }
  1403. }
  1404. }
  1405. }
  1406. if (rc == 1) {
  1407. /* Maybe a match. */
  1408. *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.",
  1409. log_escape_ex(msr->mp, match, match_length),
  1410. var->name);
  1411. return 1;
  1412. }
  1413. /* No match. */
  1414. *error_msg = NULL;
  1415. return 0;
  1416. }
  1417. /* streq */
  1418. static int msre_op_streq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  1419. msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  1420. const char *match = NULL;
  1421. const char *target;
  1422. unsigned int match_length;
  1423. unsigned int target_length;
  1424. str->value = (char *)rule->op_param;
  1425. str->value_len = strlen(str->value);
  1426. if (error_msg == NULL) return -1;
  1427. *error_msg = NULL;
  1428. if (str->value == NULL) {
  1429. *error_msg = "Internal Error: match string is null.";
  1430. return -1;
  1431. }
  1432. expand_macros(msr, str, rule, msr->mp);
  1433. match = (const char *)str->value;
  1434. match_length = str->value_len;
  1435. /* If the given target is null run against an empty
  1436. * string. This is a behaviour consistent with previous
  1437. * releases.
  1438. */
  1439. if (var->value == NULL) {
  1440. target = "";
  1441. target_length = 0;
  1442. } else {
  1443. target = var->value;
  1444. target_length = var->value_len;
  1445. }
  1446. /* These are impossible to match */
  1447. if (match_length != target_length) {
  1448. /* No match. */
  1449. return 0;
  1450. }
  1451. if (memcmp(match, target, target_length) == 0) {
  1452. /* Match. */
  1453. *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.",
  1454. log_escape_ex(msr->mp, match, match_length),
  1455. var->name);
  1456. return 1;
  1457. }
  1458. /* No match. */
  1459. return 0;
  1460. }
  1461. /* beginsWith */
  1462. static int msre_op_beginsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  1463. msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  1464. const char *match = NULL;
  1465. const char *target;
  1466. unsigned int match_length;
  1467. unsigned int target_length;
  1468. str->value = (char *)rule->op_param;
  1469. str->value_len = strlen(str->value);
  1470. if (error_msg == NULL) return -1;
  1471. *error_msg = NULL;
  1472. if (str->value == NULL) {
  1473. *error_msg = "Internal Error: match string is null.";
  1474. return -1;
  1475. }
  1476. expand_macros(msr, str, rule, msr->mp);
  1477. match = (const char *)str->value;
  1478. match_length = str->value_len;
  1479. /* If the given target is null run against an empty
  1480. * string. This is a behaviour consistent with previous
  1481. * releases.
  1482. */
  1483. if (var->value == NULL) {
  1484. target = "";
  1485. target_length = 0;
  1486. } else {
  1487. target = var->value;
  1488. target_length = var->value_len;
  1489. }
  1490. /* The empty string always matches */
  1491. if (match_length == 0) {
  1492. /* Match. */
  1493. *error_msg = apr_psprintf(msr->mp, "String match \"\" at %s.", var->name);
  1494. return 1;
  1495. }
  1496. /* This is impossible to match */
  1497. if (match_length > target_length) {
  1498. /* No match. */
  1499. return 0;
  1500. }
  1501. if (memcmp(match, target, match_length) == 0) {
  1502. /* Match. */
  1503. *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.",
  1504. log_escape_ex(msr->mp, match, match_length),
  1505. var->name);
  1506. return 1;
  1507. }
  1508. /* No match. */
  1509. return 0;
  1510. }
  1511. /* endsWith */
  1512. static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  1513. msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  1514. const char *match = NULL;
  1515. const char *target;
  1516. unsigned int match_length;
  1517. unsigned int target_length;
  1518. str->value = (char *)rule->op_param;
  1519. str->value_len = strlen(str->value);
  1520. if (error_msg == NULL) return -1;
  1521. *error_msg = NULL;
  1522. if (str->value == NULL) {
  1523. *error_msg = "Internal Error: match string is null.";
  1524. return -1;
  1525. }
  1526. expand_macros(msr, str, rule, msr->mp);
  1527. match = (const char *)str->value;
  1528. match_length = str->value_len;
  1529. /* If the given target is null run against an empty
  1530. * string. This is a behaviour consistent with previous
  1531. * releases.
  1532. */
  1533. if (var->value == NULL) {
  1534. target = "";
  1535. target_length = 0;
  1536. } else {
  1537. target = var->value;
  1538. target_length = var->value_len;
  1539. }
  1540. /* The empty string always matches */
  1541. if (match_length == 0) {
  1542. /* Match. */
  1543. *error_msg = apr_psprintf(msr->mp, "String match \"\" at %s.", var->name);
  1544. return 1;
  1545. }
  1546. /* This is impossible to match */
  1547. if (match_length > target_length) {
  1548. /* No match. */
  1549. return 0;
  1550. }
  1551. if (memcmp(match, (target + (target_length - match_length)), match_length) == 0) {
  1552. /* Match. */
  1553. *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.",
  1554. log_escape_ex(msr->mp, match, match_length),
  1555. var->name);
  1556. return 1;
  1557. }
  1558. /* No match. */
  1559. return 0;
  1560. }
  1561. /* strmatch */
  1562. static int msre_op_strmatch_param_init(msre_rule *rule, char **error_msg) {
  1563. const apr_strmatch_pattern *compiled_pattern;
  1564. const char *pattern = rule->op_param;
  1565. unsigned short int op_len;
  1566. if (error_msg == NULL) return -1;
  1567. *error_msg = NULL;
  1568. op_len = strlen(pattern);
  1569. /* Compile pattern */
  1570. compiled_pattern = apr_strmatch_precompile(rule->ruleset->mp, parse_pm_content(pattern, op_len, rule, error_msg), 1);
  1571. if (compiled_pattern == NULL) {
  1572. *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern: %s", pattern);
  1573. return 0;
  1574. }
  1575. rule->op_param_data = (void *)compiled_pattern;
  1576. return 1; /* OK */
  1577. }
  1578. static int msre_op_strmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  1579. apr_strmatch_pattern *compiled_pattern = (apr_strmatch_pattern *)rule->op_param_data;
  1580. const char *target;
  1581. unsigned int target_length;
  1582. const char *rc;
  1583. if (error_msg == NULL) return -1;
  1584. *error_msg = NULL;
  1585. if (compiled_pattern == NULL) {
  1586. *error_msg = "Internal Error: strnmatch data is null.";
  1587. return -1;
  1588. }
  1589. /* If the given target is null run against an empty
  1590. * string. This is a behaviour consistent with previous
  1591. * releases.
  1592. */
  1593. if (var->value == NULL) {
  1594. target = "";
  1595. target_length = 0;
  1596. } else {
  1597. target = var->value;
  1598. target_length = var->value_len;
  1599. }
  1600. rc = apr_strmatch(compiled_pattern, target, target_length);
  1601. if (rc == NULL) {
  1602. /* No match. */
  1603. return 0;
  1604. }
  1605. *error_msg = apr_psprintf(msr->mp, "Pattern match \"%s\" at %s.",
  1606. log_escape(msr->mp, rule->op_param), var->name);
  1607. /* Match. */
  1608. return 1;
  1609. }
  1610. /* validateDTD */
  1611. static int msre_op_validateDTD_init(msre_rule *rule, char **error_msg) {
  1612. /* ENH Verify here the file actually exists. */
  1613. return 1;
  1614. }
  1615. static int msre_op_validateDTD_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  1616. char **error_msg)
  1617. {
  1618. xmlValidCtxtPtr cvp;
  1619. xmlDtdPtr dtd;
  1620. if ((msr->xml == NULL)||(msr->xml->doc == NULL)) {
  1621. *error_msg = apr_psprintf(msr->mp,
  1622. "XML document tree could not be found for DTD validation.");
  1623. return -1;
  1624. }
  1625. if (msr->xml->well_formed != 1) {
  1626. *error_msg = apr_psprintf(msr->mp,
  1627. "XML: DTD validation failed because content is not well formed.");
  1628. return 1;
  1629. }
  1630. /* Make sure there were no other generic processing errors */
  1631. if (msr->msc_reqbody_error) {
  1632. *error_msg = apr_psprintf(msr->mp,
  1633. "XML: DTD validation could not proceed due to previous"
  1634. " processing errors.");
  1635. return 1;
  1636. }
  1637. dtd = xmlParseDTD(NULL, (const xmlChar *)rule->op_param); /* EHN support relative filenames */
  1638. if (dtd == NULL) {
  1639. *error_msg = apr_psprintf(msr->mp, "XML: Failed to load DTD: %s", rule->op_param);
  1640. return -1;
  1641. }
  1642. cvp = xmlNewValidCtxt();
  1643. if (cvp == NULL) {
  1644. *error_msg = "XML: Failed to create a validation context.";
  1645. xmlFreeDtd(dtd);
  1646. return -1;
  1647. }
  1648. /* Send validator errors/warnings to msr_log */
  1649. /* NOTE: No xmlDtdSetValidErrors()? */
  1650. cvp->error = (xmlSchemaValidityErrorFunc)msr_log_error;
  1651. cvp->warning = (xmlSchemaValidityErrorFunc)msr_log_warn;
  1652. cvp->userData = msr;
  1653. if (!xmlValidateDtd(cvp, msr->xml->doc, dtd)) {
  1654. *error_msg = "XML: DTD validation failed.";
  1655. xmlFreeValidCtxt(cvp);
  1656. xmlFreeDtd(dtd);
  1657. return 1; /* No match. */
  1658. }
  1659. if (msr->txcfg->debuglog_level >= 4) {
  1660. msr_log(msr, 4, "XML: Successfully validated payload against DTD: %s", rule->op_param);
  1661. }
  1662. xmlFreeValidCtxt(cvp);
  1663. xmlFreeDtd(dtd);
  1664. /* Match. */
  1665. return 0;
  1666. }
  1667. /* validateSchema */
  1668. static int msre_op_validateSchema_init(msre_rule *rule, char **error_msg) {
  1669. /* ENH Verify here the file actually exists. */
  1670. return 1;
  1671. }
  1672. static int msre_op_validateSchema_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  1673. char **error_msg)
  1674. {
  1675. xmlSchemaParserCtxtPtr parserCtx;
  1676. xmlSchemaValidCtxtPtr validCtx;
  1677. xmlSchemaPtr schema;
  1678. int rc;
  1679. if ((msr->xml == NULL)||(msr->xml->doc == NULL)) {
  1680. *error_msg = apr_psprintf(msr->mp,
  1681. "XML document tree could not be found for schema validation.");
  1682. return -1;
  1683. }
  1684. if (msr->xml->well_formed != 1) {
  1685. *error_msg = apr_psprintf(msr->mp,
  1686. "XML: Schema validation failed because content is not well formed.");
  1687. return 1;
  1688. }
  1689. /* Make sure there were no other generic processing errors */
  1690. if (msr->msc_reqbody_error) {
  1691. *error_msg = apr_psprintf(msr->mp,
  1692. "XML: Schema validation could not proceed due to previous"
  1693. " processing errors.");
  1694. return 1;
  1695. }
  1696. parserCtx = xmlSchemaNewParserCtxt(rule->op_param); /* ENH support relative filenames */
  1697. if (parserCtx == NULL) {
  1698. *error_msg = apr_psprintf(msr->mp, "XML: Failed to load Schema from file: %s",
  1699. rule->op_param);
  1700. return -1;
  1701. }
  1702. /* Send parser errors/warnings to msr_log */
  1703. xmlSchemaSetParserErrors(parserCtx, (xmlSchemaValidityErrorFunc)msr_log_error, (xmlSchemaValidityWarningFunc)msr_log_warn, msr);
  1704. schema = xmlSchemaParse(parserCtx);
  1705. if (schema == NULL) {
  1706. *error_msg = apr_psprintf(msr->mp, "XML: Failed to load Schema: %s", rule->op_param);
  1707. xmlSchemaFreeParserCtxt(parserCtx);
  1708. return -1;
  1709. }
  1710. validCtx = xmlSchemaNewValidCtxt(schema);
  1711. if (validCtx == NULL) {
  1712. *error_msg = "XML: Failed to create validation context.";
  1713. xmlSchemaFree(schema);
  1714. xmlSchemaFreeParserCtxt(parserCtx);
  1715. return -1;
  1716. }
  1717. /* Send validator errors/warnings to msr_log */
  1718. xmlSchemaSetValidErrors(validCtx, (xmlSchemaValidityErrorFunc)msr_log_error, (xmlSchemaValidityWarningFunc)msr_log_warn, msr);
  1719. rc = xmlSchemaValidateDoc(validCtx, msr->xml->doc);
  1720. if (rc != 0) {
  1721. *error_msg = "XML: Schema validation failed.";
  1722. xmlSchemaFree(schema);
  1723. xmlSchemaFreeParserCtxt(parserCtx);
  1724. return 1; /* No match. */
  1725. }
  1726. if (msr->txcfg->debuglog_level >= 4) {
  1727. msr_log(msr, 4, "XML: Successfully validated payload against Schema: %s", rule->op_param);
  1728. }
  1729. xmlSchemaFree(schema);
  1730. xmlSchemaFreeValidCtxt(validCtx);
  1731. return 0;
  1732. }
  1733. /* verifyCC */
  1734. /**
  1735. * Luhn Mod-10 Method (ISO 2894/ANSI 4.13)
  1736. */
  1737. static int luhn_verify(const char *ccnumber, int len) {
  1738. int sum[2] = { 0, 0 };
  1739. int odd = 0;
  1740. int digits = 0;
  1741. int i;
  1742. /* Weighted lookup table which is just a precalculated (i = index):
  1743. * i*2 + (( (i*2) > 9 ) ? -9 : 0)
  1744. */
  1745. static const int wtable[10] = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9}; /* weight lookup table */
  1746. /* Add up only digits (weighted digits via lookup table)
  1747. * for both odd and even CC numbers to avoid 2 passes.
  1748. */
  1749. for (i = 0; i < len; i++) {
  1750. if (apr_isdigit(ccnumber[i])) {
  1751. sum[0] += (!odd ? wtable[ccnumber[i] - '0'] : (ccnumber[i] - '0'));
  1752. sum[1] += (odd ? wtable[ccnumber[i] - '0'] : (ccnumber[i] - '0'));
  1753. odd = 1 - odd; /* alternate weights */
  1754. digits++;
  1755. }
  1756. }
  1757. /* No digits extracted */
  1758. if (digits == 0) return 0;
  1759. /* Do a mod 10 on the sum */
  1760. sum[odd] %= 10;
  1761. /* If the result is a zero the card is valid. */
  1762. return sum[odd] ? 0 : 1;
  1763. }
  1764. static int msre_op_verifyCC_init(msre_rule *rule, char **error_msg) {
  1765. const char *errptr = NULL;
  1766. int erroffset;
  1767. msc_regex_t *regex;
  1768. if (error_msg == NULL) return -1;
  1769. *error_msg = NULL;
  1770. /* Compile rule->op_param */
  1771. 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);
  1772. if (regex == NULL) {
  1773. *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s",
  1774. erroffset, errptr);
  1775. return 0;
  1776. }
  1777. rule->op_param_data = regex;
  1778. return 1; /* OK */
  1779. }
  1780. static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  1781. msc_regex_t *regex = (msc_regex_t *)rule->op_param_data;
  1782. const char *target;
  1783. unsigned int target_length;
  1784. char *my_error_msg = NULL;
  1785. int ovector[33];
  1786. int rc;
  1787. int is_cc = 0;
  1788. int offset;
  1789. if (error_msg == NULL) return -1;
  1790. *error_msg = NULL;
  1791. if (regex == NULL) {
  1792. *error_msg = "Internal Error: regex data is null.";
  1793. return -1;
  1794. }
  1795. memset(ovector, 0, sizeof(ovector));
  1796. /* If the given target is null run against an empty
  1797. * string. This is a behaviour consistent with previous
  1798. * releases.
  1799. */
  1800. if (var->value == NULL) {
  1801. target = "";
  1802. target_length = 0;
  1803. } else {
  1804. target = var->value;
  1805. target_length = var->value_len;
  1806. }
  1807. for (offset = 0; ((unsigned int)offset < target_length) && (is_cc == 0); offset++) {
  1808. if (msr->txcfg->debuglog_level >= 9) {
  1809. if (offset > 0) {
  1810. msr_log(msr, 9, "Continuing CC# search at target offset %d.", offset);
  1811. }
  1812. }
  1813. rc = msc_regexec_ex(regex, target, target_length, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg);
  1814. /* If there was no match, then we are done. */
  1815. if (rc == PCRE_ERROR_NOMATCH) {
  1816. break;
  1817. }
  1818. if (rc < -1) {
  1819. *error_msg = apr_psprintf(msr->mp, "CC# regex execution failed: %s", my_error_msg);
  1820. return -1;
  1821. }
  1822. /* Verify a match. */
  1823. if (rc > 0) {
  1824. const char *match = target + ovector[0];
  1825. int length = ovector[1] - ovector[0];
  1826. int i = 0;
  1827. offset = ovector[2*i];
  1828. /* Check the Luhn using the match string */
  1829. is_cc = luhn_verify(match, length);
  1830. /* Not a CC number, then try another match where we left off. */
  1831. if (!is_cc) {
  1832. if (msr->txcfg->debuglog_level >= 9) {
  1833. msr_log(msr, 9, "CC# Luhn check failed at target offset %d: \"%.*s\"", offset, length, match);
  1834. }
  1835. continue;
  1836. }
  1837. /* We have a potential CC number and need to set any captures
  1838. * and we are done.
  1839. */
  1840. if (apr_table_get(rule->actionset->actions, "capture")) {
  1841. for(; i < rc; i++) {
  1842. msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  1843. if (s == NULL) return -1;
  1844. s->name = apr_psprintf(msr->mp, "%d", i);
  1845. s->name_len = strlen(s->name);
  1846. s->value = apr_pstrmemdup(msr->mp, match, length);
  1847. s->value_len = length;
  1848. if ((s->name == NULL)||(s->value == NULL)) return -1;
  1849. apr_table_setn(msr->tx_vars, s->name, (void *)s);
  1850. if (msr->txcfg->debuglog_level >= 9) {
  1851. msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i,
  1852. log_escape_nq_ex(msr->mp, s->value, s->value_len));
  1853. }
  1854. }
  1855. }
  1856. /* Unset the remaining TX vars (from previous invocations). */
  1857. for(; i <= 9; i++) {
  1858. char buf[24];
  1859. apr_snprintf(buf, sizeof(buf), "%i", i);
  1860. apr_table_unset(msr->tx_vars, buf);
  1861. }
  1862. break;
  1863. }
  1864. }
  1865. if (is_cc) {
  1866. /* Match. */
  1867. /* This message will be logged. */
  1868. *error_msg = apr_psprintf(msr->mp, "CC# match \"%s\" at %s. [offset \"%d\"]",
  1869. regex->pattern, var->name, offset);
  1870. return 1;
  1871. }
  1872. /* No match. */
  1873. return 0;
  1874. }
  1875. /*
  1876. * \brief Check for a valid CPF
  1877. *
  1878. * \param cpfnumber Pointer to cpf
  1879. * \param len cpf length
  1880. *
  1881. * \retval 0 On Invalid CPF
  1882. * \retval 1 On Valid CPF
  1883. */
  1884. static int cpf_verify(const char *cpfnumber, int len) {
  1885. int factor, part_1, part_2, var_len = len;
  1886. unsigned int sum = 0, i = 0, cpf_len = 11, c;
  1887. int cpf[11];
  1888. char s_cpf[11];
  1889. char bad_cpf[11][11] = { "00000000000",
  1890. "01234567890",
  1891. "11111111111",
  1892. "22222222222",
  1893. "33333333333",
  1894. "44444444444",
  1895. "55555555555",
  1896. "66666666666",
  1897. "77777777777",
  1898. "88888888888",
  1899. "99999999999"};
  1900. while((*cpfnumber != '\0') && ( var_len >= 0)) {
  1901. if(*cpfnumber != '-' || *cpfnumber != '.') {
  1902. if(i < cpf_len && isdigit(*cpfnumber)) {
  1903. s_cpf[i] = *cpfnumber;
  1904. cpf[i] = convert_to_int(*cpfnumber);
  1905. i++;
  1906. }
  1907. }
  1908. cpfnumber++;
  1909. var_len--;
  1910. }
  1911. if (strlen(s_cpf) != cpf_len || i != cpf_len-1)
  1912. return 0;
  1913. else {
  1914. for(i = 0; i< cpf_len; i++) {
  1915. if(strncmp(s_cpf,bad_cpf[i],cpf_len) == 0) {
  1916. return 0;
  1917. }
  1918. }
  1919. }
  1920. part_1 = convert_to_int(s_cpf[cpf_len-2]);
  1921. part_2 = convert_to_int(s_cpf[cpf_len-1]);
  1922. c = cpf_len;
  1923. for(i = 0; i < 9; i++) {
  1924. sum += (cpf[i] * --c);
  1925. }
  1926. factor = (sum % cpf_len);
  1927. if(factor < 2) {
  1928. cpf[9] = 0;
  1929. } else {
  1930. cpf[9] = cpf_len-factor;
  1931. }
  1932. sum = 0;
  1933. c = cpf_len;
  1934. for(i = 0;i < 10; i++)
  1935. sum += (cpf[i] * c--);
  1936. factor = (sum % cpf_len);
  1937. if(factor < 2) {
  1938. cpf[10] = 0;
  1939. } else {
  1940. cpf[10] = cpf_len-factor;
  1941. }
  1942. if(part_1 == cpf[9] && part_2 == cpf[10])
  1943. return 1;
  1944. return 0;
  1945. }
  1946. /*
  1947. * \brief Init function to CPF operator
  1948. *
  1949. * \param rule Pointer to the rule
  1950. * \param error_msg Pointer to error msg
  1951. *
  1952. * \retval 0 On Failure
  1953. * \retval 1 On Success
  1954. */
  1955. static int msre_op_verifyCPF_init(msre_rule *rule, char **error_msg) {
  1956. const char *errptr = NULL;
  1957. int erroffset;
  1958. msc_regex_t *regex;
  1959. if (error_msg == NULL) return -1;
  1960. *error_msg = NULL;
  1961. /* Compile rule->op_param */
  1962. 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);
  1963. if (regex == NULL) {
  1964. *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s",
  1965. erroffset, errptr);
  1966. return 0;
  1967. }
  1968. rule->op_param_data = regex;
  1969. return 1; /* OK */
  1970. }
  1971. /*
  1972. * \brief Execution function to CPF operator
  1973. *
  1974. * \param msr Pointer internal modsec request structure
  1975. * \param rule Pointer to the rule
  1976. * \param var Pointer to variable structure
  1977. * \param error_msg Pointer to error msg
  1978. *
  1979. * \retval -1 On Failure
  1980. * \retval 1 On Match
  1981. * \retval 0 On No Match
  1982. */
  1983. static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  1984. msc_regex_t *regex = (msc_regex_t *)rule->op_param_data;
  1985. const char *target;
  1986. unsigned int target_length;
  1987. char *my_error_msg = NULL;
  1988. int ovector[33];
  1989. int rc;
  1990. int is_cpf = 0;
  1991. int offset;
  1992. if (error_msg == NULL) return -1;
  1993. *error_msg = NULL;
  1994. if (regex == NULL) {
  1995. *error_msg = "Internal Error: regex data is null.";
  1996. return -1;
  1997. }
  1998. memset(ovector, 0, sizeof(ovector));
  1999. /* If the given target is null run against an empty
  2000. * string. This is a behaviour consistent with previous
  2001. * releases.
  2002. */
  2003. if (var->value == NULL) {
  2004. target = "";
  2005. target_length = 0;
  2006. } else {
  2007. target = var->value;
  2008. target_length = var->value_len;
  2009. }
  2010. for (offset = 0; ((unsigned int)offset < target_length) && (is_cpf == 0); offset++) {
  2011. if (msr->txcfg->debuglog_level >= 9) {
  2012. if (offset > 0) {
  2013. msr_log(msr, 9, "Continuing CPF# search at target offset %d.", offset);
  2014. }
  2015. }
  2016. rc = msc_regexec_ex(regex, target, target_length, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg);
  2017. /* If there was no match, then we are done. */
  2018. if (rc == PCRE_ERROR_NOMATCH) {
  2019. break;
  2020. }
  2021. if (rc < -1) {
  2022. *error_msg = apr_psprintf(msr->mp, "CPF# regex execution failed: %s", my_error_msg);
  2023. return -1;
  2024. }
  2025. /* Verify a match. */
  2026. if (rc > 0) {
  2027. const char *match = target + ovector[0];
  2028. int length = ovector[1] - ovector[0];
  2029. int i = 0;
  2030. offset = ovector[2*i];
  2031. /* Check CPF using the match string */
  2032. is_cpf = cpf_verify(match, length);
  2033. /* Not a CPF number, then try another match where we left off. */
  2034. if (!is_cpf) {
  2035. if (msr->txcfg->debuglog_level >= 9) {
  2036. msr_log(msr, 9, "CPF# check failed at target offset %d: \"%.*s\"", offset, length, match);
  2037. }
  2038. continue;
  2039. }
  2040. /* We have a potential CPF number and need to set any captures
  2041. * and we are done.
  2042. */
  2043. if (apr_table_get(rule->actionset->actions, "capture")) {
  2044. for(; i < rc; i++) {
  2045. msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2046. if (s == NULL) return -1;
  2047. s->name = apr_psprintf(msr->mp, "%d", i);
  2048. s->name_len = strlen(s->name);
  2049. s->value = apr_pstrmemdup(msr->mp, match, length);
  2050. s->value_len = length;
  2051. if ((s->name == NULL)||(s->value == NULL)) return -1;
  2052. apr_table_setn(msr->tx_vars, s->name, (void *)s);
  2053. if (msr->txcfg->debuglog_level >= 9) {
  2054. msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i,
  2055. log_escape_nq_ex(msr->mp, s->value, s->value_len));
  2056. }
  2057. }
  2058. }
  2059. /* Unset the remaining TX vars (from previous invocations). */
  2060. for(; i <= 9; i++) {
  2061. char buf[24];
  2062. apr_snprintf(buf, sizeof(buf), "%i", i);
  2063. apr_table_unset(msr->tx_vars, buf);
  2064. }
  2065. break;
  2066. }
  2067. }
  2068. if (is_cpf) {
  2069. /* Match. */
  2070. /* This message will be logged. */
  2071. *error_msg = apr_psprintf(msr->mp, "CPF# match \"%s\" at %s. [offset \"%d\"]",
  2072. regex->pattern, var->name, offset);
  2073. return 1;
  2074. }
  2075. /* No match. */
  2076. return 0;
  2077. }
  2078. /*
  2079. * \brief Check for a valid SSN
  2080. *
  2081. * \param msr Pointer to the modsec resource
  2082. * \param ssnumber Pointer to ssn
  2083. * \param len ssn length
  2084. *
  2085. * \retval 0 On Invalid SSN
  2086. * \retval 1 On Valid SSN
  2087. */
  2088. static int ssn_verify(modsec_rec *msr, const char *ssnumber, int len) {
  2089. int i;
  2090. int num[9];
  2091. int digits = 0;
  2092. int area, serial, grp;
  2093. int sequencial = 0;
  2094. int repetitions = 0;
  2095. int progression = 0;
  2096. char *str_area;
  2097. char *str_grp;
  2098. char *str_serial;
  2099. for (i = 0; i < len; i++) {
  2100. if (apr_isdigit(ssnumber[i])) {
  2101. num[i] = convert_to_int(ssnumber[i]);
  2102. digits++;
  2103. }
  2104. }
  2105. /* Not a valid number */
  2106. if (digits != 9)
  2107. goto invalid;
  2108. digits = 0;
  2109. for (i=0; i < len-1; i++) {
  2110. progression = (num[i] - (num[i+1]-1));
  2111. repetitions = (num[i] - num[i+1]);
  2112. if (repetitions != 0 )
  2113. sequencial = 1;
  2114. if (progression == 0)
  2115. digits++;
  2116. }
  2117. /* We are blocking when all numbers were repeated */
  2118. if (sequencial == 0)
  2119. goto invalid;
  2120. if (digits == 8)
  2121. goto invalid;
  2122. str_area = apr_psprintf(msr->mp,"%d%d%d",num[0],num[1],num[2]);
  2123. str_grp = apr_psprintf(msr->mp,"%d%d",num[3],num[4]);
  2124. str_serial = apr_psprintf(msr->mp,"%d%d%d%d",num[5],num[6],num[7],num[8]);
  2125. if(str_area == NULL || str_grp == NULL || str_serial == NULL)
  2126. goto invalid;
  2127. area = atoi(str_area);
  2128. grp = atoi(str_grp);
  2129. serial = atoi(str_serial);
  2130. /* Cannot has seroed fields */
  2131. if (area == 0 || serial == 0 || grp == 0)
  2132. goto invalid;
  2133. /* More tests */
  2134. if (area >= 740 || area == 666)
  2135. goto invalid;
  2136. return 1;
  2137. invalid:
  2138. return 0;
  2139. }
  2140. /*
  2141. * \brief Init function to SSN operator
  2142. *
  2143. * \param rule Pointer to the rule
  2144. * \param error_msg Pointer to error msg
  2145. *
  2146. * \retval 0 On Failure
  2147. * \retval 1 On Success
  2148. */
  2149. static int msre_op_verifySSN_init(msre_rule *rule, char **error_msg) {
  2150. const char *errptr = NULL;
  2151. int erroffset;
  2152. msc_regex_t *regex;
  2153. if (error_msg == NULL) return -1;
  2154. *error_msg = NULL;
  2155. /* Compile rule->op_param */
  2156. 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);
  2157. if (regex == NULL) {
  2158. *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s",
  2159. erroffset, errptr);
  2160. return 0;
  2161. }
  2162. rule->op_param_data = regex;
  2163. return 1; /* OK */
  2164. }
  2165. /*
  2166. * \brief Execution function to SSN operator
  2167. *
  2168. * \param msr Pointer internal modsec request structure
  2169. * \param rule Pointer to the rule
  2170. * \param var Pointer to variable structure
  2171. * \param error_msg Pointer to error msg
  2172. *
  2173. * \retval -1 On Failure
  2174. * \retval 1 On Match
  2175. * \retval 0 On No Match
  2176. */
  2177. static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  2178. msc_regex_t *regex = (msc_regex_t *)rule->op_param_data;
  2179. const char *target;
  2180. unsigned int target_length;
  2181. char *my_error_msg = NULL;
  2182. int ovector[33];
  2183. int rc;
  2184. int is_ssn = 0;
  2185. int offset;
  2186. if (error_msg == NULL) return -1;
  2187. *error_msg = NULL;
  2188. if (regex == NULL) {
  2189. *error_msg = "Internal Error: regex data is null.";
  2190. return -1;
  2191. }
  2192. memset(ovector, 0, sizeof(ovector));
  2193. /* If the given target is null run against an empty
  2194. * string. This is a behaviour consistent with previous
  2195. * releases.
  2196. */
  2197. if (var->value == NULL) {
  2198. target = "";
  2199. target_length = 0;
  2200. } else {
  2201. target = var->value;
  2202. target_length = var->value_len;
  2203. }
  2204. for (offset = 0; ((unsigned int)offset < target_length) && (is_ssn == 0); offset++) {
  2205. if (msr->txcfg->debuglog_level >= 9) {
  2206. if (offset > 0) {
  2207. msr_log(msr, 9, "Continuing SSN# search at target offset %d.", offset);
  2208. }
  2209. }
  2210. rc = msc_regexec_ex(regex, target, target_length, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg);
  2211. /* If there was no match, then we are done. */
  2212. if (rc == PCRE_ERROR_NOMATCH) {
  2213. break;
  2214. }
  2215. if (rc < -1) {
  2216. *error_msg = apr_psprintf(msr->mp, "SSN# regex execution failed: %s", my_error_msg);
  2217. return -1;
  2218. }
  2219. /* Verify a match. */
  2220. if (rc > 0) {
  2221. const char *match = target + ovector[0];
  2222. int length = ovector[1] - ovector[0];
  2223. int i = 0;
  2224. offset = ovector[2*i];
  2225. /* Check SSN using the match string */
  2226. is_ssn = ssn_verify(msr, match, length);
  2227. /* Not a SSN number, then try another match where we left off. */
  2228. if (!is_ssn) {
  2229. if (msr->txcfg->debuglog_level >= 9) {
  2230. msr_log(msr, 9, "SSN# check failed at target offset %d: \"%.*s\"", offset, length, match);
  2231. }
  2232. continue;
  2233. }
  2234. /* We have a potential SSN number and need to set any captures
  2235. * and we are done.
  2236. */
  2237. if (apr_table_get(rule->actionset->actions, "capture")) {
  2238. for(; i < rc; i++) {
  2239. msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2240. if (s == NULL) return -1;
  2241. s->name = apr_psprintf(msr->mp, "%d", i);
  2242. s->name_len = strlen(s->name);
  2243. s->value = apr_pstrmemdup(msr->mp, match, length);
  2244. s->value_len = length;
  2245. if ((s->name == NULL)||(s->value == NULL)) return -1;
  2246. apr_table_setn(msr->tx_vars, s->name, (void *)s);
  2247. if (msr->txcfg->debuglog_level >= 9) {
  2248. msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i,
  2249. log_escape_nq_ex(msr->mp, s->value, s->value_len));
  2250. }
  2251. }
  2252. }
  2253. /* Unset the remaining TX vars (from previous invocations). */
  2254. for(; i <= 9; i++) {
  2255. char buf[24];
  2256. apr_snprintf(buf, sizeof(buf), "%i", i);
  2257. apr_table_unset(msr->tx_vars, buf);
  2258. }
  2259. break;
  2260. }
  2261. }
  2262. if (is_ssn) {
  2263. /* Match. */
  2264. /* This message will be logged. */
  2265. *error_msg = apr_psprintf(msr->mp, "SSN# match \"%s\" at %s. [offset \"%d\"]",
  2266. regex->pattern, var->name, offset);
  2267. return 1;
  2268. }
  2269. /* No match. */
  2270. return 0;
  2271. }
  2272. /**
  2273. * Perform geograpical lookups on an IP/Host.
  2274. */
  2275. static int msre_op_geoLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  2276. char **error_msg)
  2277. {
  2278. geo_rec rec;
  2279. geo_db *geo = msr->txcfg->geo;
  2280. const char *geo_host = var->value;
  2281. msc_string *s = NULL;
  2282. int rc;
  2283. *error_msg = NULL;
  2284. if (geo == NULL) {
  2285. msr_log(msr, 1, "Geo lookup for \"%s\" attempted without a database. Set SecGeoLookupDB.", log_escape(msr->mp, geo_host));
  2286. return 0;
  2287. }
  2288. rc = geo_lookup(msr, &rec, geo_host, error_msg);
  2289. if (rc <= 0) {
  2290. if (! *error_msg) {
  2291. *error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" failed at %s.", log_escape_nq(msr->mp, geo_host), var->name);
  2292. }
  2293. apr_table_clear(msr->geo_vars);
  2294. return rc;
  2295. }
  2296. if (! *error_msg) {
  2297. *error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" succeeded at %s.",
  2298. log_escape_nq(msr->mp, geo_host), var->name);
  2299. }
  2300. if (msr->txcfg->debuglog_level >= 9) {
  2301. msr_log(msr, 9, "GEO: %s={country_code=%s, country_code3=%s, country_name=%s, country_continent=%s, region=%s, city=%s, postal_code=%s, latitude=%f, longitude=%f, dma_code=%d, area_code=%d}",
  2302. geo_host,
  2303. rec.country_code,
  2304. rec.country_code3,
  2305. rec.country_name,
  2306. rec.country_continent,
  2307. rec.region,
  2308. rec.city,
  2309. rec.postal_code,
  2310. rec.latitude,
  2311. rec.longitude,
  2312. rec.dma_code,
  2313. rec.area_code);
  2314. }
  2315. s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2316. s->name = apr_pstrdup(msr->mp, "COUNTRY_CODE");
  2317. s->name_len = strlen(s->name);
  2318. s->value = apr_pstrdup(msr->mp, rec.country_code ? rec.country_code : "");
  2319. s->value_len = strlen(s->value);
  2320. apr_table_setn(msr->geo_vars, s->name, (void *)s);
  2321. s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2322. s->name = apr_pstrdup(msr->mp, "COUNTRY_CODE3");
  2323. s->name_len = strlen(s->name);
  2324. s->value = apr_pstrdup(msr->mp, rec.country_code3 ? rec.country_code3 : "");
  2325. s->value_len = strlen(s->value);
  2326. apr_table_setn(msr->geo_vars, s->name, (void *)s);
  2327. s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2328. s->name = apr_pstrdup(msr->mp, "COUNTRY_NAME");
  2329. s->name_len = strlen(s->name);
  2330. s->value = apr_pstrdup(msr->mp, rec.country_name ? rec.country_name : "");
  2331. s->value_len = strlen(s->value);
  2332. apr_table_setn(msr->geo_vars, s->name, (void *)s);
  2333. s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2334. s->name = apr_pstrdup(msr->mp, "COUNTRY_CONTINENT");
  2335. s->name_len = strlen(s->name);
  2336. s->value = apr_pstrdup(msr->mp, rec.country_continent ? rec.country_continent : "");
  2337. s->value_len = strlen(s->value);
  2338. apr_table_setn(msr->geo_vars, s->name, (void *)s);
  2339. s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2340. s->name = apr_pstrdup(msr->mp, "REGION");
  2341. s->name_len = strlen(s->name);
  2342. s->value = apr_pstrdup(msr->mp, rec.region ? rec.region : "");
  2343. s->value_len = strlen(s->value);
  2344. apr_table_setn(msr->geo_vars, s->name, (void *)s);
  2345. s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2346. s->name = apr_pstrdup(msr->mp, "CITY");
  2347. s->name_len = strlen(s->name);
  2348. s->value = apr_pstrdup(msr->mp, rec.city ? rec.city : "");
  2349. s->value_len = strlen(s->value);
  2350. apr_table_setn(msr->geo_vars, s->name, (void *)s);
  2351. s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2352. s->name = apr_pstrdup(msr->mp, "POSTAL_CODE");
  2353. s->name_len = strlen(s->name);
  2354. s->value = apr_pstrdup(msr->mp, rec.postal_code ? rec.postal_code : "");
  2355. s->value_len = strlen(s->value);
  2356. apr_table_setn(msr->geo_vars, s->name, (void *)s);
  2357. s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2358. s->name = apr_pstrdup(msr->mp, "LATITUDE");
  2359. s->name_len = strlen(s->name);
  2360. s->value = apr_psprintf(msr->mp, "%f", rec.latitude);
  2361. s->value_len = strlen(s->value);
  2362. apr_table_setn(msr->geo_vars, s->name, (void *)s);
  2363. s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2364. s->name = apr_pstrdup(msr->mp, "LONGITUDE");
  2365. s->name_len = strlen(s->name);
  2366. s->value = apr_psprintf(msr->mp, "%f", rec.longitude);
  2367. s->value_len = strlen(s->value);
  2368. apr_table_setn(msr->geo_vars, s->name, (void *)s);
  2369. s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2370. s->name = apr_pstrdup(msr->mp, "DMA_CODE");
  2371. s->name_len = strlen(s->name);
  2372. s->value = apr_psprintf(msr->mp, "%d", rec.dma_code);
  2373. s->value_len = strlen(s->value);
  2374. apr_table_setn(msr->geo_vars, s->name, (void *)s);
  2375. s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
  2376. s->name = apr_pstrdup(msr->mp, "AREA_CODE");
  2377. s->name_len = strlen(s->name);
  2378. s->value = apr_psprintf(msr->mp, "%d", rec.area_code);
  2379. s->value_len = strlen(s->value);
  2380. apr_table_setn(msr->geo_vars, s->name, (void *)s);
  2381. return 1;
  2382. }
  2383. /* rbl */
  2384. static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
  2385. unsigned int h0, h1, h2, h3;
  2386. unsigned int high8bits = 0;
  2387. char *name_to_check = NULL;
  2388. char *target = NULL;
  2389. apr_sockaddr_t *sa = NULL;
  2390. apr_status_t rc;
  2391. int capture = 0;
  2392. if (error_msg == NULL) return -1;
  2393. *error_msg = NULL;
  2394. capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0;
  2395. /* ENH Add IPv6 support. */
  2396. target = apr_pstrmemdup(msr->mp, var->value, var->value_len);
  2397. if (target == NULL) return -1;
  2398. /* Construct the host name we want to resolve. */
  2399. if (sscanf(target, "%d.%d.%d.%d", &h0, &h1, &h2, &h3) == 4) {
  2400. /* IPv4 address */
  2401. name_to_check = apr_psprintf(msr->mp, "%d.%d.%d.%d.%s", h3, h2, h1, h0, rule->op_param);
  2402. } else {
  2403. /* Assume the input is a domain name. */
  2404. name_to_check = apr_psprintf(msr->mp, "%s.%s", target, rule->op_param);
  2405. }
  2406. if (name_to_check == NULL) return -1;
  2407. rc = apr_sockaddr_info_get(&sa, name_to_check,
  2408. APR_UNSPEC/*msr->r->connection->remote_addr->family*/, 0, 0, msr->mp);
  2409. if (rc == APR_SUCCESS) {
  2410. high8bits = sa->sa.sin.sin_addr.s_addr >> 24;
  2411. /* multi.uribl.com */
  2412. if(strstr(rule->op_param,"uribl.com")) {
  2413. switch(high8bits) {
  2414. case 2:
  2415. *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (BLACK).",
  2416. log_escape_nq(msr->mp, name_to_check), var->name);
  2417. break;
  2418. case 4:
  2419. *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (GREY).",
  2420. log_escape_nq(msr->mp, name_to_check), var->name);
  2421. break;
  2422. case 8:
  2423. *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (RED).",
  2424. log_escape_nq(msr->mp, name_to_check), var->name);
  2425. break;
  2426. case 14:
  2427. *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (BLACK,GREY,RED).",
  2428. log_escape_nq(msr->mp, name_to_check), var->name);
  2429. break;
  2430. case 255:
  2431. *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (DNS IS BLOCKED).",
  2432. log_escape_nq(msr->mp, name_to_check), var->name);
  2433. break;
  2434. default:
  2435. *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s.",
  2436. log_escape_nq(msr->mp, name_to_check), var->name);
  2437. break;
  2438. }
  2439. set_match_to_tx(msr, capture, *error_msg, 0);
  2440. } else
  2441. if(strstr(rule->op_param,"spamhaus.org")) {
  2442. switch(high8bits) {
  2443. case 2:
  2444. case 3:
  2445. *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (Static UBE sources).",
  2446. log_escape_nq(msr->mp, name_to_check), var->name);
  2447. break;
  2448. case 4:
  2449. case 5:
  2450. case 6:
  2451. case 7:
  2452. *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (Illegal 3rd party exploits).",
  2453. log_escape_nq(msr->mp, name_to_check), var->name);
  2454. break;
  2455. case 10:
  2456. case 11:
  2457. *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (Delivering unauthenticated SMTP email).",
  2458. log_escape_nq(msr->mp, name_to_check), var->name);
  2459. break;
  2460. default:
  2461. *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s.",
  2462. log_escape_nq(msr->mp, name_to_check), var->name);
  2463. break;
  2464. }
  2465. set_match_to_tx(msr, capture, *error_msg, 0);
  2466. } else {
  2467. *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s.",
  2468. log_escape_nq(msr->mp, name_to_check), var->name);
  2469. set_match_to_tx(msr, capture, *error_msg, 0);
  2470. }
  2471. return 1; /* Match. */
  2472. }
  2473. if (msr->txcfg->debuglog_level >= 5) {
  2474. msr_log(msr, 5, "RBL lookup of %s failed at %s.", log_escape_nq(msr->mp, name_to_check), var->name);
  2475. }
  2476. /* No match. */
  2477. return 0;
  2478. }
  2479. /* inspectFile */
  2480. static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) {
  2481. char *filename = (char *)rule->op_param;
  2482. if (error_msg == NULL) return -1;
  2483. *error_msg = NULL;
  2484. if ((filename == NULL)||(is_empty_string(filename))) {
  2485. *error_msg = apr_psprintf(rule->ruleset->mp, "Operator @inspectFile requires parameter.");
  2486. return -1;
  2487. }
  2488. filename = resolve_relative_path(rule->ruleset->mp, rule->filename, filename);
  2489. #if defined(WITH_LUA)
  2490. /* ENH Write & use string_ends(s, e). */
  2491. if (strlen(rule->op_param) > 4) {
  2492. char *p = filename + strlen(filename) - 4;
  2493. if ((p[0] == '.')&&(p[1] == 'l')&&(p[2] == 'u')&&(p[3] == 'a'))
  2494. {
  2495. msc_script *script = NULL;
  2496. /* Compile script. */
  2497. *error_msg = lua_compile(&script, filename, rule->ruleset->mp);
  2498. if (*error_msg != NULL) return -1;
  2499. rule->op_param_data = script;
  2500. }
  2501. }
  2502. #endif
  2503. if (rule->op_param_data == NULL) {
  2504. /* ENH Verify the script exists and that we have
  2505. * the rights to execute it.
  2506. */
  2507. }
  2508. return 1;
  2509. }
  2510. static int msre_op_inspectFile_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  2511. char **error_msg)
  2512. {
  2513. if (error_msg == NULL) return -1;
  2514. *error_msg = NULL;
  2515. if (rule->op_param_data == NULL) {
  2516. /* Execute externally, as native binary/shell script. */
  2517. char *script_output = NULL;
  2518. char const *argv[5];
  2519. const char *approver_script = rule->op_param;
  2520. const char *target_file = apr_pstrmemdup(msr->mp, var->value, var->value_len);
  2521. if (msr->txcfg->debuglog_level >= 4) {
  2522. msr_log(msr, 4, "Executing %s to inspect %s.", approver_script, target_file);
  2523. }
  2524. argv[0] = approver_script;
  2525. argv[1] = target_file;
  2526. argv[2] = NULL;
  2527. if (apache2_exec(msr, approver_script, (const char **)argv, &script_output) <= 0) {
  2528. *error_msg = apr_psprintf(msr->mp, "Execution of the approver script \"%s\" failed (invocation failed).",
  2529. log_escape(msr->mp, approver_script));
  2530. return -1;
  2531. }
  2532. if (script_output == NULL) {
  2533. *error_msg = apr_psprintf(msr->mp, "Execution of the approver script \"%s\" failed (no output).",
  2534. log_escape(msr->mp, approver_script));
  2535. return -1;
  2536. }
  2537. if (script_output[0] != '1') {
  2538. *error_msg = apr_psprintf(msr->mp, "File \"%s\" rejected by the approver script \"%s\": %s",
  2539. log_escape(msr->mp, target_file), log_escape(msr->mp, approver_script),
  2540. log_escape_nq(msr->mp, script_output));
  2541. return 1; /* Match. */
  2542. }
  2543. }
  2544. #if defined(WITH_LUA)
  2545. else {
  2546. /* Execute internally, as Lua script. */
  2547. char *target = apr_pstrmemdup(msr->mp, var->value, var->value_len);
  2548. msc_script *script = (msc_script *)rule->op_param_data;
  2549. int rc;
  2550. rc = lua_execute(script, target, msr, rule, error_msg);
  2551. if (rc < 0) {
  2552. /* Error. */
  2553. return -1;
  2554. }
  2555. return rc;
  2556. }
  2557. #endif
  2558. /* No match. */
  2559. return 0;
  2560. }
  2561. /* validateByteRange */
  2562. static int msre_op_validateByteRange_init(msre_rule *rule, char **error_msg) {
  2563. char *p = NULL, *saveptr = NULL;
  2564. char *table = NULL, *data = NULL;
  2565. if (error_msg == NULL) return -1;
  2566. *error_msg = NULL;
  2567. if (rule->op_param == NULL) {
  2568. *error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for validateByteRange.");
  2569. return -1;
  2570. }
  2571. /* Initialise. */
  2572. data = apr_pstrdup(rule->ruleset->mp, rule->op_param);
  2573. rule->op_param_data = apr_pcalloc(rule->ruleset->mp, 32);
  2574. if ((data == NULL)||(rule->op_param_data == NULL)) return -1;
  2575. table = rule->op_param_data;
  2576. /* Extract parameters and update table. */
  2577. p = apr_strtok(data, ",", &saveptr);
  2578. while(p != NULL) {
  2579. char *s = strstr(p, "-");
  2580. if (s == NULL) {
  2581. /* Single value. */
  2582. int x = atoi(p);
  2583. if ((x < 0)||(x > 255)) {
  2584. *error_msg = apr_psprintf(rule->ruleset->mp, "Invalid range value: %d", x);
  2585. return 0;
  2586. }
  2587. table[x>>3] = (table[x>>3] | (1 << (x & 0x7)));
  2588. } else {
  2589. /* Range. */
  2590. int start = atoi(p);
  2591. int end = atoi(s + 1);
  2592. if ((start < 0)||(start > 255)) {
  2593. *error_msg = apr_psprintf(rule->ruleset->mp, "Invalid range start value: %d",
  2594. start);
  2595. return 0;
  2596. }
  2597. if ((end < 0)||(end > 255)) {
  2598. *error_msg = apr_psprintf(rule->ruleset->mp, "Invalid range end value: %d", end);
  2599. return 0;
  2600. }
  2601. if (start > end) {
  2602. *error_msg = apr_psprintf(rule->ruleset->mp, "Invalid range: %d-%d", start, end);
  2603. return 0;
  2604. }
  2605. while(start <= end) {
  2606. table[start >> 3] = (table[start >> 3] | (1 << (start & 0x7)));
  2607. start++;
  2608. }
  2609. }
  2610. p = apr_strtok(NULL, ",", &saveptr);
  2611. }
  2612. return 1;
  2613. }
  2614. static int msre_op_validateByteRange_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  2615. char **error_msg)
  2616. {
  2617. char *table = rule->op_param_data;
  2618. unsigned int i, count;
  2619. if (error_msg == NULL) return -1;
  2620. *error_msg = NULL;
  2621. if (table == NULL) {
  2622. *error_msg = apr_psprintf(msr->mp, "Internal Error: validateByteRange table not "
  2623. "initialised.");
  2624. return -1;
  2625. }
  2626. /* Check every byte of the target to detect characters that are not allowed. */
  2627. count = 0;
  2628. for(i = 0; i < var->value_len; i++) {
  2629. int x = ((unsigned char *)var->value)[i];
  2630. if (!(table[x >> 3] & (1 << (x & 0x7)))) {
  2631. if (msr->txcfg->debuglog_level >= 9) {
  2632. msr_log(msr, 9, "Value %d in %s outside range: %s", x, var->name, rule->op_param);
  2633. }
  2634. count++;
  2635. }
  2636. }
  2637. if (count == 0) return 0; /* Valid - no match. */
  2638. *error_msg = apr_psprintf(msr->mp, "Found %d byte(s) in %s outside range: %s.",
  2639. count, var->name, rule->op_param);
  2640. return 1; /* Invalid - match.*/
  2641. }
  2642. /* validateUrlEncoding */
  2643. static int validate_url_encoding(const char *input, long int input_length) {
  2644. int i;
  2645. if ((input == NULL)||(input_length < 0)) return -1;
  2646. i = 0;
  2647. while (i < input_length) {
  2648. if (input[i] == '%') {
  2649. if (i + 2 >= input_length) {
  2650. /* Not enough bytes. */
  2651. return -3;
  2652. }
  2653. else {
  2654. /* Here we only decode a %xx combination if it is valid,
  2655. * leaving it as is otherwise.
  2656. */
  2657. char c1 = input[i + 1];
  2658. char c2 = input[i + 2];
  2659. if ( (((c1 >= '0')&&(c1 <= '9')) || ((c1 >= 'a')&&(c1 <= 'f')) || ((c1 >= 'A')&&(c1 <= 'F')))
  2660. && (((c2 >= '0')&&(c2 <= '9')) || ((c2 >= 'a')&&(c2 <= 'f')) || ((c2 >= 'A')&&(c2 <= 'F'))) )
  2661. {
  2662. i += 3;
  2663. } else {
  2664. /* Non-hexadecimal characters used in encoding. */
  2665. return -2;
  2666. }
  2667. }
  2668. } else {
  2669. i++;
  2670. }
  2671. }
  2672. return 1;
  2673. }
  2674. static int msre_op_validateUrlEncoding_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  2675. char **error_msg)
  2676. {
  2677. int rc = validate_url_encoding(var->value, var->value_len);
  2678. switch(rc) {
  2679. case 1 :
  2680. /* Encoding is valid */
  2681. *error_msg = apr_psprintf(msr->mp, "Valid URL Encoding at %s.", var->name);
  2682. break;
  2683. case -2 :
  2684. *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Non-hexadecimal "
  2685. "digits used at %s.", var->name);
  2686. return 1; /* Invalid match. */
  2687. break;
  2688. case -3 :
  2689. *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Not enough characters "
  2690. "at the end of input at %s.", var->name);
  2691. return 1; /* Invalid match. */
  2692. break;
  2693. case -1 :
  2694. default :
  2695. *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Internal Error (rc = %d) at %s", rc, var->name);
  2696. return -1;
  2697. break;
  2698. }
  2699. /* No match. */
  2700. return 0;
  2701. }
  2702. /* validateUtf8Encoding */
  2703. #define UNICODE_ERROR_CHARACTERS_MISSING -1
  2704. #define UNICODE_ERROR_INVALID_ENCODING -2
  2705. #define UNICODE_ERROR_OVERLONG_CHARACTER -3
  2706. #define UNICODE_ERROR_RESTRICTED_CHARACTER -4
  2707. #define UNICODE_ERROR_DECODING_ERROR -5
  2708. /* NOTE: This is over-commented for ease of verification */
  2709. static int detect_utf8_character(const unsigned char *p_read, unsigned int length) {
  2710. int unicode_len = 0;
  2711. unsigned int d = 0;
  2712. unsigned char c;
  2713. if (p_read == NULL) return UNICODE_ERROR_DECODING_ERROR;
  2714. c = *p_read;
  2715. /* If first byte begins with binary 0 it is single byte encoding */
  2716. if ((c & 0x80) == 0) {
  2717. /* single byte unicode (7 bit ASCII equivilent) has no validation */
  2718. return 1;
  2719. }
  2720. /* If first byte begins with binary 110 it is two byte encoding*/
  2721. else if ((c & 0xE0) == 0xC0) {
  2722. /* check we have at least two bytes */
  2723. if (length < 2) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING;
  2724. /* check second byte starts with binary 10 */
  2725. else if (((*(p_read + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
  2726. else {
  2727. unicode_len = 2;
  2728. /* compute character number */
  2729. d = ((c & 0x1F) << 6) | (*(p_read + 1) & 0x3F);
  2730. }
  2731. }
  2732. /* If first byte begins with binary 1110 it is three byte encoding */
  2733. else if ((c & 0xF0) == 0xE0) {
  2734. /* check we have at least three bytes */
  2735. if (length < 3) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING;
  2736. /* check second byte starts with binary 10 */
  2737. else if (((*(p_read + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
  2738. /* check third byte starts with binary 10 */
  2739. else if (((*(p_read + 2)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
  2740. else {
  2741. unicode_len = 3;
  2742. /* compute character number */
  2743. d = ((c & 0x0F) << 12) | ((*(p_read + 1) & 0x3F) << 6) | (*(p_read + 2) & 0x3F);
  2744. }
  2745. }
  2746. /* If first byte begins with binary 11110 it is four byte encoding */
  2747. else if ((c & 0xF8) == 0xF0) {
  2748. /* restrict characters to UTF-8 range (U+0000 - U+10FFFF)*/
  2749. if (c >= 0xF5) {
  2750. return UNICODE_ERROR_RESTRICTED_CHARACTER;
  2751. }
  2752. /* check we have at least four bytes */
  2753. if (length < 4) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING;
  2754. /* check second byte starts with binary 10 */
  2755. else if (((*(p_read + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
  2756. /* check third byte starts with binary 10 */
  2757. else if (((*(p_read + 2)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
  2758. /* check forth byte starts with binary 10 */
  2759. else if (((*(p_read + 3)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING;
  2760. else {
  2761. unicode_len = 4;
  2762. /* compute character number */
  2763. d = ((c & 0x07) << 18) | ((*(p_read + 1) & 0x3F) << 12) | ((*(p_read + 2) & 0x3F) < 6) | (*(p_read + 3) & 0x3F);
  2764. }
  2765. }
  2766. /* any other first byte is invalid (RFC 3629) */
  2767. else {
  2768. return UNICODE_ERROR_INVALID_ENCODING;
  2769. }
  2770. /* invalid UTF-8 character number range (RFC 3629) */
  2771. if ((d >= 0xD800) && (d <= 0xDFFF)) {
  2772. return UNICODE_ERROR_RESTRICTED_CHARACTER;
  2773. }
  2774. /* check for overlong */
  2775. if ((unicode_len == 4) && (d < 0x010000)) {
  2776. /* four byte could be represented with less bytes */
  2777. return UNICODE_ERROR_OVERLONG_CHARACTER;
  2778. }
  2779. else if ((unicode_len == 3) && (d < 0x0800)) {
  2780. /* three byte could be represented with less bytes */
  2781. return UNICODE_ERROR_OVERLONG_CHARACTER;
  2782. }
  2783. else if ((unicode_len == 2) && (d < 0x80)) {
  2784. /* two byte could be represented with less bytes */
  2785. return UNICODE_ERROR_OVERLONG_CHARACTER;
  2786. }
  2787. return unicode_len;
  2788. }
  2789. static int msre_op_validateUtf8Encoding_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  2790. char **error_msg)
  2791. {
  2792. unsigned int i, bytes_left;
  2793. bytes_left = var->value_len;
  2794. for(i = 0; i < var->value_len;) {
  2795. int rc = detect_utf8_character((unsigned char *)&var->value[i], bytes_left);
  2796. switch(rc) {
  2797. case UNICODE_ERROR_CHARACTERS_MISSING :
  2798. *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: "
  2799. "not enough bytes in character "
  2800. "at %s. [offset \"%d\"]", var->name, i);
  2801. return 1;
  2802. break;
  2803. case UNICODE_ERROR_INVALID_ENCODING :
  2804. *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: "
  2805. "invalid byte value in character "
  2806. "at %s. [offset \"%d\"]", var->name, i);
  2807. return 1;
  2808. break;
  2809. case UNICODE_ERROR_OVERLONG_CHARACTER :
  2810. *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: "
  2811. "overlong character detected "
  2812. "at %s. [offset \"%d\"]", var->name, i);
  2813. return 1;
  2814. break;
  2815. case UNICODE_ERROR_RESTRICTED_CHARACTER :
  2816. *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: "
  2817. "use of restricted character "
  2818. "at %s. [offset \"%d\"]", var->name, i);
  2819. return 1;
  2820. break;
  2821. case UNICODE_ERROR_DECODING_ERROR :
  2822. *error_msg = apr_psprintf(msr->mp, "Error validating UTF-8 decoding "
  2823. "at %s. [offset \"%d\"]", var->name, i);
  2824. return 1;
  2825. break;
  2826. }
  2827. if (rc <= 0) {
  2828. *error_msg = apr_psprintf(msr->mp, "Internal error during UTF-8 validation "
  2829. "at %s.", var->name);
  2830. return 1;
  2831. }
  2832. i += rc;
  2833. bytes_left -= rc;
  2834. }
  2835. return 0;
  2836. }
  2837. /* eq */
  2838. static int msre_op_eq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  2839. char **error_msg)
  2840. {
  2841. msc_string str;
  2842. int left, right;
  2843. char *target = NULL;
  2844. if (error_msg == NULL) return -1;
  2845. *error_msg = NULL;
  2846. if ((var->value == NULL)||(rule->op_param == NULL)) {
  2847. /* NULL values do not match anything. */
  2848. return 0;
  2849. }
  2850. str.value = (char *)rule->op_param;
  2851. str.value_len = strlen(str.value);
  2852. expand_macros(msr, &str, rule, msr->mp);
  2853. target = apr_pstrmemdup(msr->mp, var->value, var->value_len);
  2854. if (target == NULL) return -1;
  2855. left = atoi(target);
  2856. right = atoi(str.value);
  2857. if (left != right) {
  2858. /* No match. */
  2859. return 0;
  2860. }
  2861. else {
  2862. *error_msg = apr_psprintf(msr->mp, "Operator EQ matched %d at %s.", right, var->name);
  2863. /* Match. */
  2864. return 1;
  2865. }
  2866. }
  2867. /* gt */
  2868. static int msre_op_gt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  2869. char **error_msg)
  2870. {
  2871. msc_string str;
  2872. int left, right;
  2873. char *target = NULL;
  2874. if ((var->value == NULL)||(rule->op_param == NULL)) {
  2875. /* NULL values do not match anything. */
  2876. return 0;
  2877. }
  2878. if (error_msg == NULL) return -1;
  2879. *error_msg = NULL;
  2880. if ((var->value == NULL)||(rule->op_param == NULL)) {
  2881. /* NULL values do not match anything. */
  2882. return 0;
  2883. }
  2884. str.value = (char *)rule->op_param;
  2885. str.value_len = strlen(str.value);
  2886. expand_macros(msr, &str, rule, msr->mp);
  2887. target = apr_pstrmemdup(msr->mp, var->value, var->value_len);
  2888. if (target == NULL) return -1;
  2889. left = atoi(target);
  2890. right = atoi(str.value);
  2891. if (left <= right) {
  2892. /* No match. */
  2893. return 0;
  2894. }
  2895. else {
  2896. *error_msg = apr_psprintf(msr->mp, "Operator GT matched %d at %s.", right, var->name);
  2897. /* Match. */
  2898. return 1;
  2899. }
  2900. }
  2901. /* lt */
  2902. static int msre_op_lt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  2903. char **error_msg)
  2904. {
  2905. msc_string str;
  2906. int left, right;
  2907. char *target = NULL;
  2908. if ((var->value == NULL)||(rule->op_param == NULL)) {
  2909. /* NULL values do not match anything. */
  2910. return 0;
  2911. }
  2912. if (error_msg == NULL) return -1;
  2913. *error_msg = NULL;
  2914. if ((var->value == NULL)||(rule->op_param == NULL)) {
  2915. /* NULL values do not match anything. */
  2916. return 0;
  2917. }
  2918. str.value = (char *)rule->op_param;
  2919. str.value_len = strlen(str.value);
  2920. expand_macros(msr, &str, rule, msr->mp);
  2921. target = apr_pstrmemdup(msr->mp, var->value, var->value_len);
  2922. if (target == NULL) return -1;
  2923. left = atoi(target);
  2924. right = atoi(str.value);
  2925. if (left >= right) {
  2926. /* No match. */
  2927. return 0;
  2928. }
  2929. else {
  2930. *error_msg = apr_psprintf(msr->mp, "Operator LT matched %d at %s.", right, var->name);
  2931. /* Match. */
  2932. return 1;
  2933. }
  2934. }
  2935. /* ge */
  2936. static int msre_op_ge_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  2937. char **error_msg)
  2938. {
  2939. msc_string str;
  2940. int left, right;
  2941. char *target = NULL;
  2942. if ((var->value == NULL)||(rule->op_param == NULL)) {
  2943. /* NULL values do not match anything. */
  2944. return 0;
  2945. }
  2946. if (error_msg == NULL) return -1;
  2947. *error_msg = NULL;
  2948. if ((var->value == NULL)||(rule->op_param == NULL)) {
  2949. /* NULL values do not match anything. */
  2950. return 0;
  2951. }
  2952. str.value = (char *)rule->op_param;
  2953. str.value_len = strlen(str.value);
  2954. expand_macros(msr, &str, rule, msr->mp);
  2955. target = apr_pstrmemdup(msr->mp, var->value, var->value_len);
  2956. if (target == NULL) return -1;
  2957. left = atoi(target);
  2958. right = atoi(str.value);
  2959. if (left < right) {
  2960. /* No match. */
  2961. return 0;
  2962. }
  2963. else {
  2964. *error_msg = apr_psprintf(msr->mp, "Operator GE matched %d at %s.", right, var->name);
  2965. /* Match. */
  2966. return 1;
  2967. }
  2968. }
  2969. /* le */
  2970. static int msre_op_le_execute(modsec_rec *msr, msre_rule *rule, msre_var *var,
  2971. char **error_msg)
  2972. {
  2973. msc_string str;
  2974. int left, right;
  2975. char *target = NULL;
  2976. if ((var->value == NULL)||(rule->op_param == NULL)) {
  2977. /* NULL values do not match anything. */
  2978. return 0;
  2979. }
  2980. if (error_msg == NULL) return -1;
  2981. *error_msg = NULL;
  2982. if ((var->value == NULL)||(rule->op_param == NULL)) {
  2983. /* NULL values do not match anything. */
  2984. return 0;
  2985. }
  2986. str.value = (char *)rule->op_param;
  2987. str.value_len = strlen(str.value);
  2988. expand_macros(msr, &str, rule, msr->mp);
  2989. target = apr_pstrmemdup(msr->mp, var->value, var->value_len);
  2990. if (target == NULL) return -1;
  2991. left = atoi(target);
  2992. right = atoi(str.value);
  2993. if (left > right) {
  2994. /* No match. */
  2995. return 0;
  2996. }
  2997. else {
  2998. *error_msg = apr_psprintf(msr->mp, "Operator LE matched %d at %s.", right, var->name);
  2999. /* Match. */
  3000. return 1;
  3001. }
  3002. }
  3003. /* -------------------------------------------------------------------------- */
  3004. /**
  3005. *
  3006. */
  3007. void msre_engine_register_default_operators(msre_engine *engine) {
  3008. /* unconditionalMatch */
  3009. msre_engine_op_register(engine,
  3010. "unconditionalMatch",
  3011. NULL,
  3012. msre_op_unconditionalmatch_execute
  3013. );
  3014. /* noMatch */
  3015. msre_engine_op_register(engine,
  3016. "noMatch",
  3017. NULL,
  3018. msre_op_nomatch_execute
  3019. );
  3020. /* ipmatch */
  3021. msre_engine_op_register(engine,
  3022. "ipmatch",
  3023. msre_op_ipmatch_param_init,
  3024. msre_op_ipmatch_execute
  3025. );
  3026. /* rsub */
  3027. #if !defined(MSC_TEST)
  3028. msre_engine_op_register(engine,
  3029. "rsub",
  3030. msre_op_rsub_param_init,
  3031. msre_op_rsub_execute
  3032. );
  3033. #endif /* MSC_TEST */
  3034. /* rx */
  3035. msre_engine_op_register(engine,
  3036. "rx",
  3037. msre_op_rx_param_init,
  3038. msre_op_rx_execute
  3039. );
  3040. /* pm */
  3041. msre_engine_op_register(engine,
  3042. "pm",
  3043. msre_op_pm_param_init,
  3044. msre_op_pm_execute
  3045. );
  3046. /* pmFromFile */
  3047. msre_engine_op_register(engine,
  3048. "pmFromFile",
  3049. msre_op_pmFromFile_param_init,
  3050. msre_op_pm_execute
  3051. );
  3052. /* pmf */
  3053. msre_engine_op_register(engine,
  3054. "pmf",
  3055. msre_op_pmFromFile_param_init,
  3056. msre_op_pm_execute
  3057. );
  3058. /* within */
  3059. msre_engine_op_register(engine,
  3060. "within",
  3061. NULL, /* ENH init function to flag var substitution */
  3062. msre_op_within_execute
  3063. );
  3064. /* contains */
  3065. msre_engine_op_register(engine,
  3066. "contains",
  3067. NULL, /* ENH init function to flag var substitution */
  3068. msre_op_contains_execute
  3069. );
  3070. /* containsWord */
  3071. msre_engine_op_register(engine,
  3072. "containsWord",
  3073. NULL, /* ENH init function to flag var substitution */
  3074. msre_op_containsWord_execute
  3075. );
  3076. /* is */
  3077. msre_engine_op_register(engine,
  3078. "streq",
  3079. NULL, /* ENH init function to flag var substitution */
  3080. msre_op_streq_execute
  3081. );
  3082. /* beginsWith */
  3083. msre_engine_op_register(engine,
  3084. "beginsWith",
  3085. NULL, /* ENH init function to flag var substitution */
  3086. msre_op_beginsWith_execute
  3087. );
  3088. /* endsWith */
  3089. msre_engine_op_register(engine,
  3090. "endsWith",
  3091. NULL, /* ENH init function to flag var substitution */
  3092. msre_op_endsWith_execute
  3093. );
  3094. /* strmatch */
  3095. msre_engine_op_register(engine,
  3096. "strmatch",
  3097. msre_op_strmatch_param_init,
  3098. msre_op_strmatch_execute
  3099. );
  3100. /* validateDTD */
  3101. msre_engine_op_register(engine,
  3102. "validateDTD",
  3103. msre_op_validateDTD_init,
  3104. msre_op_validateDTD_execute
  3105. );
  3106. /* validateSchema */
  3107. msre_engine_op_register(engine,
  3108. "validateSchema",
  3109. msre_op_validateSchema_init,
  3110. msre_op_validateSchema_execute
  3111. );
  3112. /* verifyCC */
  3113. msre_engine_op_register(engine,
  3114. "verifyCC",
  3115. msre_op_verifyCC_init,
  3116. msre_op_verifyCC_execute
  3117. );
  3118. /* verifyCPF */
  3119. msre_engine_op_register(engine,
  3120. "verifyCPF",
  3121. msre_op_verifyCPF_init,
  3122. msre_op_verifyCPF_execute
  3123. );
  3124. /* verifySSN */
  3125. msre_engine_op_register(engine,
  3126. "verifySSN",
  3127. msre_op_verifySSN_init,
  3128. msre_op_verifySSN_execute
  3129. );
  3130. /* geoLookup */
  3131. msre_engine_op_register(engine,
  3132. "geoLookup",
  3133. NULL,
  3134. msre_op_geoLookup_execute
  3135. );
  3136. /* gsbLookup */
  3137. msre_engine_op_register(engine,
  3138. "gsbLookup",
  3139. msre_op_gsbLookup_param_init,
  3140. msre_op_gsbLookup_execute
  3141. );
  3142. /* rbl */
  3143. msre_engine_op_register(engine,
  3144. "rbl",
  3145. NULL, /* ENH init function to validate DNS server */
  3146. msre_op_rbl_execute
  3147. );
  3148. /* inspectFile */
  3149. msre_engine_op_register(engine,
  3150. "inspectFile",
  3151. msre_op_inspectFile_init,
  3152. msre_op_inspectFile_execute
  3153. );
  3154. /* validateByteRange */
  3155. msre_engine_op_register(engine,
  3156. "validateByteRange",
  3157. msre_op_validateByteRange_init,
  3158. msre_op_validateByteRange_execute
  3159. );
  3160. /* validateUrlEncoding */
  3161. msre_engine_op_register(engine,
  3162. "validateUrlEncoding",
  3163. NULL,
  3164. msre_op_validateUrlEncoding_execute
  3165. );
  3166. /* validateUtf8Encoding */
  3167. msre_engine_op_register(engine,
  3168. "validateUtf8Encoding",
  3169. NULL,
  3170. msre_op_validateUtf8Encoding_execute
  3171. );
  3172. /* eq */
  3173. msre_engine_op_register(engine,
  3174. "eq",
  3175. NULL,
  3176. msre_op_eq_execute
  3177. );
  3178. /* gt */
  3179. msre_engine_op_register(engine,
  3180. "gt",
  3181. NULL,
  3182. msre_op_gt_execute
  3183. );
  3184. /* lt */
  3185. msre_engine_op_register(engine,
  3186. "lt",
  3187. NULL,
  3188. msre_op_lt_execute
  3189. );
  3190. /* le */
  3191. msre_engine_op_register(engine,
  3192. "le",
  3193. NULL,
  3194. msre_op_le_execute
  3195. );
  3196. /* ge */
  3197. msre_engine_op_register(engine,
  3198. "ge",
  3199. NULL,
  3200. msre_op_ge_execute
  3201. );
  3202. }