PageRenderTime 58ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

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

http://vulture.googlecode.com/
C | 2656 lines | 1961 code | 459 blank | 236 comment | 607 complexity | 352f7e69bbf4a663c7588539ba0ab021 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 <limits.h>
  15. #include "modsecurity.h"
  16. #include "msc_logging.h"
  17. #include "msc_util.h"
  18. #include "http_log.h"
  19. #if defined(WITH_LUA)
  20. #include "msc_lua.h"
  21. #endif
  22. /* -- Directory context creation and initialisation -- */
  23. /**
  24. * Creates a fresh directory configuration.
  25. */
  26. void *create_directory_config(apr_pool_t *mp, char *path)
  27. {
  28. directory_config *dcfg = (directory_config *)apr_pcalloc(mp, sizeof(directory_config));
  29. if (dcfg == NULL) return NULL;
  30. #ifdef DEBUG_CONF
  31. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Created directory config %pp path %s", dcfg, path);
  32. #endif
  33. dcfg->mp = mp;
  34. dcfg->is_enabled = NOT_SET;
  35. dcfg->reqbody_access = NOT_SET;
  36. dcfg->reqintercept_oe = NOT_SET;
  37. dcfg->reqbody_buffering = NOT_SET;
  38. dcfg->reqbody_inmemory_limit = NOT_SET;
  39. dcfg->reqbody_limit = NOT_SET;
  40. dcfg->reqbody_no_files_limit = NOT_SET;
  41. dcfg->resbody_access = NOT_SET;
  42. dcfg->debuglog_name = NOT_SET_P;
  43. dcfg->debuglog_level = NOT_SET;
  44. dcfg->debuglog_fd = NOT_SET_P;
  45. dcfg->of_limit = NOT_SET;
  46. dcfg->if_limit_action = NOT_SET;
  47. dcfg->of_limit_action = NOT_SET;
  48. dcfg->of_mime_types = NOT_SET_P;
  49. dcfg->of_mime_types_cleared = NOT_SET;
  50. dcfg->cookie_format = NOT_SET;
  51. dcfg->argument_separator = NOT_SET;
  52. dcfg->rule_inheritance = NOT_SET;
  53. dcfg->rule_exceptions = apr_array_make(mp, 16, sizeof(rule_exception *));
  54. /* audit log variables */
  55. dcfg->auditlog_flag = NOT_SET;
  56. dcfg->auditlog_type = NOT_SET;
  57. dcfg->auditlog_dirperms = NOT_SET;
  58. dcfg->auditlog_fileperms = NOT_SET;
  59. dcfg->auditlog_name = NOT_SET_P;
  60. dcfg->auditlog2_name = NOT_SET_P;
  61. dcfg->auditlog_fd = NOT_SET_P;
  62. dcfg->auditlog2_fd = NOT_SET_P;
  63. dcfg->auditlog_storage_dir = NOT_SET_P;
  64. dcfg->auditlog_parts = NOT_SET_P;
  65. dcfg->auditlog_relevant_regex = NOT_SET_P;
  66. dcfg->ruleset = NULL;
  67. /* Upload */
  68. dcfg->tmp_dir = NOT_SET_P;
  69. dcfg->upload_dir = NOT_SET_P;
  70. dcfg->upload_keep_files = NOT_SET;
  71. dcfg->upload_validates_files = NOT_SET;
  72. dcfg->upload_filemode = NOT_SET;
  73. dcfg->upload_file_limit = NOT_SET;
  74. /* These are only used during the configuration process. */
  75. dcfg->tmp_chain_starter = NULL;
  76. dcfg->tmp_default_actionset = NULL;
  77. dcfg->tmp_rule_placeholders = NULL;
  78. /* Misc */
  79. dcfg->data_dir = NOT_SET_P;
  80. dcfg->webappid = NOT_SET_P;
  81. /* Content injection. */
  82. dcfg->content_injection_enabled = NOT_SET;
  83. /* Stream inspection */
  84. dcfg->stream_inbody_inspection = NOT_SET;
  85. dcfg->stream_outbody_inspection = NOT_SET;
  86. /* Geo Lookups */
  87. dcfg->geo = NOT_SET_P;
  88. /* Gsb Lookups */
  89. dcfg->gsb = NOT_SET_P;
  90. /* Unicode Map */
  91. dcfg->u_map = NOT_SET_P;
  92. /* Cache */
  93. dcfg->cache_trans = NOT_SET;
  94. dcfg->cache_trans_incremental = NOT_SET;
  95. dcfg->cache_trans_min = NOT_SET;
  96. dcfg->cache_trans_max = NOT_SET;
  97. dcfg->cache_trans_maxitems = NOT_SET;
  98. dcfg->component_signatures = apr_array_make(mp, 16, sizeof(char *));
  99. dcfg->request_encoding = NOT_SET_P;
  100. dcfg->disable_backend_compression = NOT_SET;
  101. return dcfg;
  102. }
  103. /**
  104. * Copies rules between one phase of two configuration contexts,
  105. * taking exceptions into account.
  106. */
  107. static void copy_rules_phase(apr_pool_t *mp,
  108. apr_array_header_t *parent_phase_arr,
  109. apr_array_header_t *child_phase_arr,
  110. apr_array_header_t *exceptions_arr)
  111. {
  112. rule_exception **exceptions;
  113. msre_rule **rules;
  114. int i, j;
  115. int mode = 0;
  116. rules = (msre_rule **)parent_phase_arr->elts;
  117. for(i = 0; i < parent_phase_arr->nelts; i++) {
  118. msre_rule *rule = (msre_rule *)rules[i];
  119. int copy = 1;
  120. if (mode == 0) {
  121. /* First rule in the chain. */
  122. exceptions = (rule_exception **)exceptions_arr->elts;
  123. for(j = 0; j < exceptions_arr->nelts; j++) {
  124. /* Process exceptions. */
  125. switch(exceptions[j]->type) {
  126. case RULE_EXCEPTION_REMOVE_ID :
  127. if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) {
  128. int ruleid = atoi(rule->actionset->id);
  129. if (rule_id_in_range(ruleid, exceptions[j]->param)) copy--;
  130. }
  131. break;
  132. case RULE_EXCEPTION_REMOVE_MSG :
  133. if ((rule->actionset != NULL)&&(rule->actionset->msg != NULL)) {
  134. char *my_error_msg = NULL;
  135. int rc = msc_regexec(exceptions[j]->param_data,
  136. rule->actionset->msg, strlen(rule->actionset->msg),
  137. &my_error_msg);
  138. if (rc >= 0) copy--;
  139. }
  140. break;
  141. case RULE_EXCEPTION_REMOVE_TAG :
  142. if ((rule->actionset != NULL)&&(apr_is_empty_table(rule->actionset->actions) == 0)) {
  143. char *my_error_msg = NULL;
  144. const apr_array_header_t *tarr = NULL;
  145. const apr_table_entry_t *telts = NULL;
  146. int c;
  147. tarr = apr_table_elts(rule->actionset->actions);
  148. telts = (const apr_table_entry_t*)tarr->elts;
  149. for (c = 0; c < tarr->nelts; c++) {
  150. msre_action *action = (msre_action *)telts[c].val;
  151. if(strcmp("tag", action->metadata->name) == 0) {
  152. int rc = msc_regexec(exceptions[j]->param_data,
  153. action->param, strlen(action->param),
  154. &my_error_msg);
  155. if (rc >= 0) copy--;
  156. }
  157. }
  158. }
  159. break;
  160. }
  161. }
  162. if (copy > 0) {
  163. #ifdef DEBUG_CONF
  164. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, rule->actionset->id);
  165. #endif
  166. /* Copy the rule. */
  167. *(msre_rule **)apr_array_push(child_phase_arr) = rule;
  168. if (rule->actionset->is_chained) mode = 2;
  169. } else {
  170. if (rule->actionset->is_chained) mode = 1;
  171. }
  172. } else {
  173. if (mode == 2) {
  174. #ifdef DEBUG_CONF
  175. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy chain %pp for rule %pp [id \"%s\"]", rule, rule->chain_starter, rule->chain_starter->actionset->id);
  176. #endif
  177. /* Copy the rule (it belongs to the chain we want to include. */
  178. *(msre_rule **)apr_array_push(child_phase_arr) = rule;
  179. }
  180. if ((rule->actionset == NULL)||(rule->actionset->is_chained == 0)) mode = 0;
  181. }
  182. }
  183. }
  184. /**
  185. * Copies rules between two configuration contexts,
  186. * taking exceptions into account.
  187. */
  188. static int copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset,
  189. msre_ruleset *child_ruleset,
  190. apr_array_header_t *exceptions_arr)
  191. {
  192. copy_rules_phase(mp, parent_ruleset->phase_request_headers,
  193. child_ruleset->phase_request_headers, exceptions_arr);
  194. copy_rules_phase(mp, parent_ruleset->phase_request_body,
  195. child_ruleset->phase_request_body, exceptions_arr);
  196. copy_rules_phase(mp, parent_ruleset->phase_response_headers,
  197. child_ruleset->phase_response_headers, exceptions_arr);
  198. copy_rules_phase(mp, parent_ruleset->phase_response_body,
  199. child_ruleset->phase_response_body, exceptions_arr);
  200. copy_rules_phase(mp, parent_ruleset->phase_logging,
  201. child_ruleset->phase_logging, exceptions_arr);
  202. return 1;
  203. }
  204. /**
  205. * Merges two directory configurations.
  206. */
  207. void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
  208. {
  209. directory_config *parent = (directory_config *)_parent;
  210. directory_config *child = (directory_config *)_child;
  211. directory_config *merged = create_directory_config(mp, NULL);
  212. #ifdef DEBUG_CONF
  213. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Merge parent %pp child %pp RESULT %pp", _parent, _child, merged);
  214. #endif
  215. if (merged == NULL) return NULL;
  216. /* Use values from the child configuration where possible,
  217. * otherwise use the parent's.
  218. */
  219. merged->is_enabled = (child->is_enabled == NOT_SET
  220. ? parent->is_enabled : child->is_enabled);
  221. /* IO parameters */
  222. merged->reqbody_access = (child->reqbody_access == NOT_SET
  223. ? parent->reqbody_access : child->reqbody_access);
  224. merged->reqbody_buffering = (child->reqbody_buffering == NOT_SET
  225. ? parent->reqbody_buffering : child->reqbody_buffering);
  226. merged->reqbody_inmemory_limit = (child->reqbody_inmemory_limit == NOT_SET
  227. ? parent->reqbody_inmemory_limit : child->reqbody_inmemory_limit);
  228. merged->reqbody_limit = (child->reqbody_limit == NOT_SET
  229. ? parent->reqbody_limit : child->reqbody_limit);
  230. merged->reqbody_no_files_limit = (child->reqbody_no_files_limit == NOT_SET
  231. ? parent->reqbody_no_files_limit : child->reqbody_no_files_limit);
  232. merged->resbody_access = (child->resbody_access == NOT_SET
  233. ? parent->resbody_access : child->resbody_access);
  234. merged->of_limit = (child->of_limit == NOT_SET
  235. ? parent->of_limit : child->of_limit);
  236. merged->if_limit_action = (child->if_limit_action == NOT_SET
  237. ? parent->if_limit_action : child->if_limit_action);
  238. merged->of_limit_action = (child->of_limit_action == NOT_SET
  239. ? parent->of_limit_action : child->of_limit_action);
  240. merged->reqintercept_oe = (child->reqintercept_oe == NOT_SET
  241. ? parent->reqintercept_oe : child->reqintercept_oe);
  242. if (child->of_mime_types != NOT_SET_P) {
  243. /* Child added to the table */
  244. if (child->of_mime_types_cleared == 1) {
  245. /* The list of MIME types was cleared in the child,
  246. * which means the parent's MIME types went away and
  247. * we should not take them into consideration here.
  248. */
  249. merged->of_mime_types = child->of_mime_types;
  250. merged->of_mime_types_cleared = 1;
  251. } else {
  252. /* Add MIME types defined in the child to those
  253. * defined in the parent context.
  254. */
  255. if (parent->of_mime_types == NOT_SET_P) {
  256. merged->of_mime_types = child->of_mime_types;
  257. merged->of_mime_types_cleared = NOT_SET;
  258. } else {
  259. merged->of_mime_types = apr_table_overlay(mp, parent->of_mime_types,
  260. child->of_mime_types);
  261. if (merged->of_mime_types == NULL) return NULL;
  262. }
  263. }
  264. } else {
  265. /* Child did not add to the table */
  266. if (child->of_mime_types_cleared == 1) {
  267. merged->of_mime_types_cleared = 1;
  268. } else {
  269. merged->of_mime_types = parent->of_mime_types;
  270. merged->of_mime_types_cleared = parent->of_mime_types_cleared;
  271. }
  272. }
  273. /* debug log */
  274. if (child->debuglog_fd == NOT_SET_P) {
  275. merged->debuglog_name = parent->debuglog_name;
  276. merged->debuglog_fd = parent->debuglog_fd;
  277. } else {
  278. merged->debuglog_name = child->debuglog_name;
  279. merged->debuglog_fd = child->debuglog_fd;
  280. }
  281. merged->debuglog_level = (child->debuglog_level == NOT_SET
  282. ? parent->debuglog_level : child->debuglog_level);
  283. merged->cookie_format = (child->cookie_format == NOT_SET
  284. ? parent->cookie_format : child->cookie_format);
  285. merged->argument_separator = (child->argument_separator == NOT_SET
  286. ? parent->argument_separator : child->argument_separator);
  287. /* rule inheritance */
  288. if ((child->rule_inheritance == NOT_SET)||(child->rule_inheritance == 1)) {
  289. merged->rule_inheritance = parent->rule_inheritance;
  290. if ((child->ruleset == NULL)&&(parent->ruleset == NULL)) {
  291. #ifdef DEBUG_CONF
  292. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "No rules in this context.");
  293. #endif
  294. /* Do nothing, there are no rules in either context. */
  295. } else
  296. if (child->ruleset == NULL) {
  297. #ifdef DEBUG_CONF
  298. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent rules in this context.");
  299. #endif
  300. /* Copy the rules from the parent context. */
  301. merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp);
  302. copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions);
  303. } else
  304. if (parent->ruleset == NULL) {
  305. #ifdef DEBUG_CONF
  306. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using child rules in this context.");
  307. #endif
  308. /* Copy child rules. */
  309. merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp);
  310. merged->ruleset->phase_request_headers = apr_array_copy(mp,
  311. child->ruleset->phase_request_headers);
  312. merged->ruleset->phase_request_body = apr_array_copy(mp,
  313. child->ruleset->phase_request_body);
  314. merged->ruleset->phase_response_headers = apr_array_copy(mp,
  315. child->ruleset->phase_response_headers);
  316. merged->ruleset->phase_response_body = apr_array_copy(mp,
  317. child->ruleset->phase_response_body);
  318. merged->ruleset->phase_logging = apr_array_copy(mp,
  319. child->ruleset->phase_logging);
  320. } else {
  321. #ifdef DEBUG_CONF
  322. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent then child rules in this context.");
  323. #endif
  324. /* Copy parent rules, then add child rules to it. */
  325. merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp);
  326. copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions);
  327. apr_array_cat(merged->ruleset->phase_request_headers,
  328. child->ruleset->phase_request_headers);
  329. apr_array_cat(merged->ruleset->phase_request_body,
  330. child->ruleset->phase_request_body);
  331. apr_array_cat(merged->ruleset->phase_response_headers,
  332. child->ruleset->phase_response_headers);
  333. apr_array_cat(merged->ruleset->phase_response_body,
  334. child->ruleset->phase_response_body);
  335. apr_array_cat(merged->ruleset->phase_logging,
  336. child->ruleset->phase_logging);
  337. }
  338. } else {
  339. merged->rule_inheritance = 0;
  340. if (child->ruleset != NULL) {
  341. /* Copy child rules. */
  342. merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp);
  343. merged->ruleset->phase_request_headers = apr_array_copy(mp,
  344. child->ruleset->phase_request_headers);
  345. merged->ruleset->phase_request_body = apr_array_copy(mp,
  346. child->ruleset->phase_request_body);
  347. merged->ruleset->phase_response_headers = apr_array_copy(mp,
  348. child->ruleset->phase_response_headers);
  349. merged->ruleset->phase_response_body = apr_array_copy(mp,
  350. child->ruleset->phase_response_body);
  351. merged->ruleset->phase_logging = apr_array_copy(mp,
  352. child->ruleset->phase_logging);
  353. }
  354. }
  355. /* Merge rule exceptions. */
  356. merged->rule_exceptions = apr_array_append(mp, parent->rule_exceptions,
  357. child->rule_exceptions);
  358. /* audit log variables */
  359. merged->auditlog_flag = (child->auditlog_flag == NOT_SET
  360. ? parent->auditlog_flag : child->auditlog_flag);
  361. merged->auditlog_type = (child->auditlog_type == NOT_SET
  362. ? parent->auditlog_type : child->auditlog_type);
  363. merged->auditlog_dirperms = (child->auditlog_dirperms == NOT_SET
  364. ? parent->auditlog_dirperms : child->auditlog_dirperms);
  365. merged->auditlog_fileperms = (child->auditlog_fileperms == NOT_SET
  366. ? parent->auditlog_fileperms : child->auditlog_fileperms);
  367. if (child->auditlog_fd != NOT_SET_P) {
  368. merged->auditlog_fd = child->auditlog_fd;
  369. merged->auditlog_name = child->auditlog_name;
  370. } else {
  371. merged->auditlog_fd = parent->auditlog_fd;
  372. merged->auditlog_name = parent->auditlog_name;
  373. }
  374. if (child->auditlog2_fd != NOT_SET_P) {
  375. merged->auditlog2_fd = child->auditlog2_fd;
  376. merged->auditlog2_name = child->auditlog2_name;
  377. } else {
  378. merged->auditlog2_fd = parent->auditlog2_fd;
  379. merged->auditlog2_name = parent->auditlog2_name;
  380. }
  381. merged->auditlog_storage_dir = (child->auditlog_storage_dir == NOT_SET_P
  382. ? parent->auditlog_storage_dir : child->auditlog_storage_dir);
  383. merged->auditlog_parts = (child->auditlog_parts == NOT_SET_P
  384. ? parent->auditlog_parts : child->auditlog_parts);
  385. merged->auditlog_relevant_regex = (child->auditlog_relevant_regex == NOT_SET_P
  386. ? parent->auditlog_relevant_regex : child->auditlog_relevant_regex);
  387. /* Upload */
  388. merged->tmp_dir = (child->tmp_dir == NOT_SET_P
  389. ? parent->tmp_dir : child->tmp_dir);
  390. merged->upload_dir = (child->upload_dir == NOT_SET_P
  391. ? parent->upload_dir : child->upload_dir);
  392. merged->upload_keep_files = (child->upload_keep_files == NOT_SET
  393. ? parent->upload_keep_files : child->upload_keep_files);
  394. merged->upload_validates_files = (child->upload_validates_files == NOT_SET
  395. ? parent->upload_validates_files : child->upload_validates_files);
  396. merged->upload_filemode = (child->upload_filemode == NOT_SET
  397. ? parent->upload_filemode : child->upload_filemode);
  398. merged->upload_file_limit = (child->upload_file_limit == NOT_SET
  399. ? parent->upload_file_limit : child->upload_file_limit);
  400. /* Misc */
  401. merged->data_dir = (child->data_dir == NOT_SET_P
  402. ? parent->data_dir : child->data_dir);
  403. merged->webappid = (child->webappid == NOT_SET_P
  404. ? parent->webappid : child->webappid);
  405. /* Content injection. */
  406. merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET
  407. ? parent->content_injection_enabled : child->content_injection_enabled);
  408. /* Stream inspection */
  409. merged->stream_inbody_inspection = (child->stream_inbody_inspection == NOT_SET
  410. ? parent->stream_inbody_inspection : child->stream_inbody_inspection);
  411. merged->stream_outbody_inspection = (child->stream_outbody_inspection == NOT_SET
  412. ? parent->stream_outbody_inspection : child->stream_outbody_inspection);
  413. /* Geo Lookup */
  414. merged->geo = (child->geo == NOT_SET_P
  415. ? parent->geo : child->geo);
  416. /* Gsb Lookup */
  417. merged->gsb = (child->gsb == NOT_SET_P
  418. ? parent->gsb : child->gsb);
  419. /* Unicode Map */
  420. merged->u_map = (child->u_map == NOT_SET_P
  421. ? parent->u_map : child->u_map);
  422. /* Cache */
  423. merged->cache_trans = (child->cache_trans == NOT_SET
  424. ? parent->cache_trans : child->cache_trans);
  425. merged->cache_trans_incremental = (child->cache_trans_incremental == NOT_SET
  426. ? parent->cache_trans_incremental : child->cache_trans_incremental);
  427. merged->cache_trans_min = (child->cache_trans_min == (apr_size_t)NOT_SET
  428. ? parent->cache_trans_min : child->cache_trans_min);
  429. merged->cache_trans_max = (child->cache_trans_max == (apr_size_t)NOT_SET
  430. ? parent->cache_trans_max : child->cache_trans_max);
  431. merged->cache_trans_maxitems = (child->cache_trans_maxitems == (apr_size_t)NOT_SET
  432. ? parent->cache_trans_maxitems : child->cache_trans_maxitems);
  433. /* Merge component signatures. */
  434. merged->component_signatures = apr_array_append(mp, parent->component_signatures,
  435. child->component_signatures);
  436. merged->request_encoding = (child->request_encoding == NOT_SET_P
  437. ? parent->request_encoding : child->request_encoding);
  438. merged->disable_backend_compression = (child->disable_backend_compression == NOT_SET
  439. ? parent->disable_backend_compression : child->disable_backend_compression);
  440. return merged;
  441. }
  442. /**
  443. * Initialise directory configuration. This function is *not* meant
  444. * to be called for directory configuration instances created during
  445. * the configuration phase. It can only be called on copies of those
  446. * (created fresh for every transaction).
  447. */
  448. void init_directory_config(directory_config *dcfg)
  449. {
  450. if (dcfg == NULL) return;
  451. if (dcfg->is_enabled == NOT_SET) dcfg->is_enabled = 0;
  452. if (dcfg->reqbody_access == NOT_SET) dcfg->reqbody_access = 0;
  453. if (dcfg->reqintercept_oe == NOT_SET) dcfg->reqintercept_oe = 0;
  454. if (dcfg->reqbody_buffering == NOT_SET) dcfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_OFF;
  455. if (dcfg->reqbody_inmemory_limit == NOT_SET)
  456. dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT;
  457. if (dcfg->reqbody_limit == NOT_SET) dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT;
  458. if (dcfg->reqbody_no_files_limit == NOT_SET) dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT;
  459. if (dcfg->resbody_access == NOT_SET) dcfg->resbody_access = 0;
  460. if (dcfg->of_limit == NOT_SET) dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT;
  461. if (dcfg->if_limit_action == NOT_SET) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT;
  462. if (dcfg->of_limit_action == NOT_SET) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
  463. if (dcfg->of_mime_types == NOT_SET_P) {
  464. dcfg->of_mime_types = apr_table_make(dcfg->mp, 3);
  465. if (dcfg->of_mime_types_cleared != 1) {
  466. apr_table_setn(dcfg->of_mime_types, "text/plain", "1");
  467. apr_table_setn(dcfg->of_mime_types, "text/html", "1");
  468. }
  469. }
  470. if (dcfg->debuglog_fd == NOT_SET_P) dcfg->debuglog_fd = NULL;
  471. if (dcfg->debuglog_name == NOT_SET_P) dcfg->debuglog_name = NULL;
  472. if (dcfg->debuglog_level == NOT_SET) dcfg->debuglog_level = 0;
  473. if (dcfg->cookie_format == NOT_SET) dcfg->cookie_format = 0;
  474. if (dcfg->argument_separator == NOT_SET) dcfg->argument_separator = '&';
  475. if (dcfg->rule_inheritance == NOT_SET) dcfg->rule_inheritance = 1;
  476. /* audit log variables */
  477. if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0;
  478. if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL;
  479. if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR;
  480. if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE;
  481. if (dcfg->auditlog_fd == NOT_SET_P) dcfg->auditlog_fd = NULL;
  482. if (dcfg->auditlog2_fd == NOT_SET_P) dcfg->auditlog2_fd = NULL;
  483. if (dcfg->auditlog_name == NOT_SET_P) dcfg->auditlog_name = NULL;
  484. if (dcfg->auditlog2_name == NOT_SET_P) dcfg->auditlog2_name = NULL;
  485. if (dcfg->auditlog_storage_dir == NOT_SET_P) dcfg->auditlog_storage_dir = NULL;
  486. if (dcfg->auditlog_parts == NOT_SET_P) dcfg->auditlog_parts = "ABCFHZ";
  487. if (dcfg->auditlog_relevant_regex == NOT_SET_P) dcfg->auditlog_relevant_regex = NULL;
  488. /* Upload */
  489. if (dcfg->tmp_dir == NOT_SET_P) dcfg->tmp_dir = guess_tmp_dir(dcfg->mp);
  490. if (dcfg->upload_dir == NOT_SET_P) dcfg->upload_dir = NULL;
  491. if (dcfg->upload_keep_files == NOT_SET) dcfg->upload_keep_files = KEEP_FILES_OFF;
  492. if (dcfg->upload_validates_files == NOT_SET) dcfg->upload_validates_files = 0;
  493. if (dcfg->upload_filemode == NOT_SET) dcfg->upload_filemode = 0600;
  494. if (dcfg->upload_file_limit == NOT_SET) dcfg->upload_file_limit = 100;
  495. /* Misc */
  496. if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL;
  497. if (dcfg->webappid == NOT_SET_P) dcfg->webappid = "default";
  498. /* Content injection. */
  499. if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0;
  500. /* Stream inspection */
  501. if (dcfg->stream_inbody_inspection == NOT_SET) dcfg->stream_inbody_inspection = 0;
  502. if (dcfg->stream_outbody_inspection == NOT_SET) dcfg->stream_outbody_inspection = 0;
  503. /* Geo Lookup */
  504. if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL;
  505. /* Gsb Lookup */
  506. if (dcfg->gsb == NOT_SET_P) dcfg->gsb = NULL;
  507. /* Unicode Map */
  508. if (dcfg->u_map == NOT_SET_P) dcfg->u_map = NULL;
  509. /* Cache */
  510. if (dcfg->cache_trans == NOT_SET) dcfg->cache_trans = MODSEC_CACHE_DISABLED;
  511. if (dcfg->cache_trans_incremental == NOT_SET) dcfg->cache_trans_incremental = 0;
  512. if (dcfg->cache_trans_min == (apr_size_t)NOT_SET) dcfg->cache_trans_min = 32;
  513. if (dcfg->cache_trans_max == (apr_size_t)NOT_SET) dcfg->cache_trans_max = 1024;
  514. if (dcfg->cache_trans_maxitems == (apr_size_t)NOT_SET) dcfg->cache_trans_maxitems = 512;
  515. if (dcfg->request_encoding == NOT_SET_P) dcfg->request_encoding = NULL;
  516. if (dcfg->disable_backend_compression == NOT_SET) dcfg->disable_backend_compression = 0;
  517. }
  518. /**
  519. *
  520. */
  521. static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
  522. const char *p1, const char *p2, const char *p3)
  523. {
  524. char *my_error_msg = NULL;
  525. msre_rule *rule = NULL;
  526. extern msc_engine *modsecurity;
  527. #ifdef DEBUG_CONF
  528. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
  529. "Rule: type=%d p1='%s' p2='%s' p3='%s'", type, p1, p2, p3);
  530. #endif
  531. /* Create a ruleset if one does not exist. */
  532. if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) {
  533. dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool);
  534. if (dcfg->ruleset == NULL) return FATAL_ERROR;
  535. }
  536. /* Create the rule now. */
  537. switch(type) {
  538. #if defined(WITH_LUA)
  539. case RULE_TYPE_LUA :
  540. rule = msre_rule_lua_create(dcfg->ruleset, cmd->directive->filename,
  541. cmd->directive->line_num, p1, p2, &my_error_msg);
  542. break;
  543. #endif
  544. default :
  545. rule = msre_rule_create(dcfg->ruleset, type, cmd->directive->filename,
  546. cmd->directive->line_num, p1, p2, p3, &my_error_msg);
  547. break;
  548. }
  549. if (rule == NULL) {
  550. return my_error_msg;
  551. }
  552. /* Create default actionset if one does not already exist. */
  553. if (dcfg->tmp_default_actionset == NULL) {
  554. dcfg->tmp_default_actionset = msre_actionset_create_default(modsecurity->msre);
  555. if (dcfg->tmp_default_actionset == NULL) return FATAL_ERROR;
  556. }
  557. /* Check some cases prior to merging so we know where it came from */
  558. /* Check syntax for chained rules */
  559. if ((rule->actionset != NULL) && (dcfg->tmp_chain_starter != NULL)) {
  560. /* Must NOT specify a disruptive action. */
  561. if (rule->actionset->intercept_action != NOT_SET) {
  562. return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions can only "
  563. "be specified by chain starter rules.");
  564. }
  565. /* Must NOT specify a skipafter action. */
  566. if (rule->actionset->skip_after != NOT_SET_P) {
  567. return apr_psprintf(cmd->pool, "ModSecurity: SkipAfter actions can only "
  568. "be specified by chain starter rules.");
  569. }
  570. /* Must NOT specify a phase. */
  571. if (rule->actionset->phase != NOT_SET) {
  572. return apr_psprintf(cmd->pool, "ModSecurity: Execution phases can only be "
  573. "specified by chain starter rules.");
  574. }
  575. /* Must NOT use metadata actions. */
  576. /* ENH: loop through to check for tags */
  577. if ((rule->actionset->id != NOT_SET_P)
  578. ||(rule->actionset->rev != NOT_SET_P)
  579. ||(rule->actionset->msg != NOT_SET_P)
  580. ||(rule->actionset->severity != NOT_SET)
  581. ||(rule->actionset->logdata != NOT_SET_P))
  582. {
  583. return apr_psprintf(cmd->pool, "ModSecurity: Metadata actions (id, rev, msg, tag, severity, logdata) "
  584. " can only be specified by chain starter rules.");
  585. }
  586. /* Must NOT use skip. */
  587. if (rule->actionset->skip_count != NOT_SET) {
  588. return apr_psprintf(cmd->pool, "ModSecurity: The skip action can only be used "
  589. " by chain starter rules. ");
  590. }
  591. }
  592. /* Merge actions with the parent.
  593. *
  594. * ENH Probably do not want this done fully for chained rules.
  595. */
  596. rule->actionset = msre_actionset_merge(modsecurity->msre, dcfg->tmp_default_actionset,
  597. rule->actionset, 1);
  598. /* Keep track of the parent action for "block" */
  599. rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec;
  600. rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action;
  601. /* Must NOT specify a disruptive action in logging phase. */
  602. if ((rule->actionset != NULL)
  603. && (rule->actionset->phase == PHASE_LOGGING)
  604. && (rule->actionset->intercept_action != ACTION_ALLOW)
  605. && (rule->actionset->intercept_action != ACTION_ALLOW_REQUEST)
  606. && (rule->actionset->intercept_action != ACTION_NONE)
  607. ) {
  608. return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions "
  609. "cannot be specified in the logging phase.");
  610. }
  611. if (dcfg->tmp_chain_starter != NULL) {
  612. rule->chain_starter = dcfg->tmp_chain_starter;
  613. rule->actionset->phase = rule->chain_starter->actionset->phase;
  614. }
  615. if (rule->actionset->is_chained != 1) {
  616. /* If this rule is part of the chain but does
  617. * not want more rules to follow in the chain
  618. * then cut it (the chain).
  619. */
  620. dcfg->tmp_chain_starter = NULL;
  621. } else {
  622. /* On the other hand, if this rule wants other
  623. * rules to follow it, then start a new chain
  624. * if there isn't one already.
  625. */
  626. if (dcfg->tmp_chain_starter == NULL) {
  627. dcfg->tmp_chain_starter = rule;
  628. }
  629. }
  630. /* Optimisation */
  631. if ((rule->op_name != NULL)&&(strcasecmp(rule->op_name, "inspectFile") == 0)) {
  632. dcfg->upload_validates_files = 1;
  633. }
  634. /* Create skip table if one does not already exist. */
  635. if (dcfg->tmp_rule_placeholders == NULL) {
  636. dcfg->tmp_rule_placeholders = apr_table_make(cmd->pool, 10);
  637. if (dcfg->tmp_rule_placeholders == NULL) return FATAL_ERROR;
  638. }
  639. /* Keep track of any rule IDs we need to skip after */
  640. if (rule->actionset->skip_after != NOT_SET_P) {
  641. char *tmp_id = apr_pstrdup(cmd->pool, rule->actionset->skip_after);
  642. apr_table_setn(dcfg->tmp_rule_placeholders, tmp_id, tmp_id);
  643. #ifdef DEBUG_CONF
  644. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
  645. "Watching for skipafter target rule id=\"%s\".", tmp_id);
  646. #endif
  647. }
  648. #ifdef DEBUG_CONF
  649. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
  650. "Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, (rule->actionset->id == NOT_SET_P
  651. ? "(none)" : rule->actionset->id));
  652. #endif
  653. /* Add rule to the recipe. */
  654. if (msre_ruleset_rule_add(dcfg->ruleset, rule, rule->actionset->phase) < 0) {
  655. return "Internal Error: Failed to add rule to the ruleset.";
  656. }
  657. /* Add an additional placeholder if this rule ID is on the list */
  658. if ((rule->actionset->id != NULL) && apr_table_get(dcfg->tmp_rule_placeholders, rule->actionset->id)) {
  659. msre_rule *phrule = apr_palloc(rule->ruleset->mp, sizeof(msre_rule));
  660. if (phrule == NULL) {
  661. return FATAL_ERROR;
  662. }
  663. #ifdef DEBUG_CONF
  664. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
  665. "Adding placeholder %pp for rule %pp id=\"%s\".", phrule, rule, rule->actionset->id);
  666. #endif
  667. /* shallow copy of original rule with placeholder marked as target */
  668. memcpy(phrule, rule, sizeof(msre_rule));
  669. phrule->placeholder = RULE_PH_SKIPAFTER;
  670. /* Add placeholder. */
  671. if (msre_ruleset_rule_add(dcfg->ruleset, phrule, phrule->actionset->phase) < 0) {
  672. return "Internal Error: Failed to add placeholder to the ruleset.";
  673. }
  674. /* No longer need to search for the ID */
  675. apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id);
  676. }
  677. /* Update the unparsed rule */
  678. rule->unparsed = msre_rule_generate_unparsed(dcfg->ruleset->mp, rule, NULL, NULL, NULL);
  679. return NULL;
  680. }
  681. /**
  682. *
  683. */
  684. static const char *add_marker(cmd_parms *cmd, directory_config *dcfg,
  685. const char *p1, const char *p2, const char *p3)
  686. {
  687. char *my_error_msg = NULL;
  688. msre_rule *rule = NULL;
  689. extern msc_engine *modsecurity;
  690. int p;
  691. #ifdef DEBUG_CONF
  692. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
  693. "Rule: type=%d p1='%s' p2='%s' p3='%s'", RULE_TYPE_MARKER, p1, p2, p3);
  694. #endif
  695. /* Create a ruleset if one does not exist. */
  696. if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) {
  697. dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool);
  698. if (dcfg->ruleset == NULL) return FATAL_ERROR;
  699. }
  700. /* Create the rule now. */
  701. rule = msre_rule_create(dcfg->ruleset, RULE_TYPE_MARKER, cmd->directive->filename, cmd->directive->line_num, p1, p2, p3, &my_error_msg);
  702. if (rule == NULL) {
  703. return my_error_msg;
  704. }
  705. /* This is a marker */
  706. rule->placeholder = RULE_PH_MARKER;
  707. /* Add placeholder to each phase */
  708. for (p = PHASE_FIRST; p <= PHASE_LAST; p++) {
  709. #ifdef DEBUG_CONF
  710. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
  711. "Adding marker %pp phase=%d id=\"%s\".", rule, p, (rule->actionset->id == NOT_SET_P
  712. ? "(none)" : rule->actionset->id));
  713. #endif
  714. if (msre_ruleset_rule_add(dcfg->ruleset, rule, p) < 0) {
  715. return "Internal Error: Failed to add marker to the ruleset.";
  716. }
  717. }
  718. /* No longer need to search for the ID */
  719. if (dcfg->tmp_rule_placeholders != NULL) {
  720. apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id);
  721. }
  722. return NULL;
  723. }
  724. /**
  725. *
  726. */
  727. static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg,
  728. const char *p1, const char *p2, int offset)
  729. {
  730. char *my_error_msg = NULL;
  731. msre_rule *rule = NULL;
  732. msre_actionset *new_actionset = NULL;
  733. msre_ruleset *ruleset = dcfg->ruleset;
  734. extern msc_engine *modsecurity;
  735. /* Get the ruleset if one exists */
  736. if ((ruleset == NULL)||(ruleset == NOT_SET_P)) {
  737. return NULL;
  738. }
  739. #ifdef DEBUG_CONF
  740. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
  741. "Update rule id=\"%s\" with action \"%s\".", p1, p2);
  742. #endif
  743. /* Fetch the rule */
  744. rule = msre_ruleset_fetch_rule(ruleset, p1, offset);
  745. if (rule == NULL) {
  746. #ifdef DEBUG_CONF
  747. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
  748. "Update rule id=\"%s\" with action \"%s\" failed: Rule not found.", p1, p2);
  749. #endif
  750. return NULL;
  751. }
  752. /* Check the rule actionset */
  753. /* ENH: Can this happen? */
  754. if (rule->actionset == NULL) {
  755. return apr_psprintf(cmd->pool, "ModSecurity: Attempt to update action for rule \"%s\" failed: Rule does not have an actionset.", p1);
  756. }
  757. /* Create a new actionset */
  758. new_actionset = msre_actionset_create(modsecurity->msre, p2, &my_error_msg);
  759. if (new_actionset == NULL) return FATAL_ERROR;
  760. if (my_error_msg != NULL) return my_error_msg;
  761. /* Must NOT change an id */
  762. if ((new_actionset->id != NOT_SET_P) && (rule->actionset->id != NULL) && (strcmp(rule->actionset->id, new_actionset->id) != 0)) {
  763. return apr_psprintf(cmd->pool, "ModSecurity: Rule IDs cannot be updated via SecRuleUpdateActionById.");
  764. }
  765. /* Must NOT alter the phase */
  766. if ((new_actionset->phase != NOT_SET) && (rule->actionset->phase != new_actionset->phase)) {
  767. return apr_psprintf(cmd->pool, "ModSecurity: Rule phases cannot be updated via SecRuleUpdateActionById.");
  768. }
  769. #ifdef DEBUG_CONF
  770. {
  771. char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
  772. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
  773. "Update rule %pp id=\"%s\" old action: \"%s\"",
  774. rule,
  775. (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
  776. actions);
  777. }
  778. #endif
  779. /* Merge new actions with the rule */
  780. /* ENH: Will this leak the old actionset? */
  781. rule->actionset = msre_actionset_merge(modsecurity->msre, rule->actionset,
  782. new_actionset, 1);
  783. msre_actionset_set_defaults(rule->actionset);
  784. /* Update the unparsed rule */
  785. rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, NULL, NULL, NULL);
  786. #ifdef DEBUG_CONF
  787. {
  788. char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
  789. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
  790. "Update rule %pp id=\"%s\" new action: \"%s\"",
  791. rule,
  792. (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
  793. actions);
  794. }
  795. #endif
  796. return NULL;
  797. }
  798. /* -- Configuration directives -- */
  799. static const char *cmd_action(cmd_parms *cmd, void *_dcfg, const char *p1)
  800. {
  801. return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_ACTION, SECACTION_TARGETS, SECACTION_ARGS, p1);
  802. }
  803. static const char *cmd_marker(cmd_parms *cmd, void *_dcfg, const char *p1)
  804. {
  805. directory_config *dcfg = (directory_config *)_dcfg;
  806. const char *action = apr_pstrcat(dcfg->mp, SECMARKER_BASE_ACTIONS, p1, NULL);
  807. return add_marker(cmd, (directory_config *)_dcfg, SECMARKER_TARGETS, SECMARKER_ARGS, action);
  808. }
  809. static const char *cmd_argument_separator(cmd_parms *cmd, void *_dcfg,
  810. const char *p1)
  811. {
  812. directory_config *dcfg = (directory_config *)_dcfg;
  813. if (strlen(p1) != 1) {
  814. return apr_psprintf(cmd->pool, "ModSecurity: Invalid argument separator: %s", p1);
  815. }
  816. dcfg->argument_separator = p1[0];
  817. return NULL;
  818. }
  819. static const char *cmd_audit_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
  820. {
  821. directory_config *dcfg = _dcfg;
  822. if (strcasecmp(p1, "On") == 0) dcfg->auditlog_flag = AUDITLOG_ON;
  823. else
  824. if (strcasecmp(p1, "Off") == 0) dcfg->auditlog_flag = AUDITLOG_OFF;
  825. else
  826. if (strcasecmp(p1, "RelevantOnly") == 0) dcfg->auditlog_flag = AUDITLOG_RELEVANT;
  827. else
  828. return (const char *)apr_psprintf(cmd->pool,
  829. "ModSecurity: Unrecognised parameter value for SecAuditEngine: %s", p1);
  830. return NULL;
  831. }
  832. static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1)
  833. {
  834. directory_config *dcfg = _dcfg;
  835. dcfg->auditlog_name = (char *)p1;
  836. if (dcfg->auditlog_name[0] == '|') {
  837. const char *pipe_name = dcfg->auditlog_name + 1;
  838. piped_log *pipe_log;
  839. pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
  840. if (pipe_log == NULL) {
  841. return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log pipe: %s",
  842. pipe_name);
  843. }
  844. dcfg->auditlog_fd = ap_piped_log_write_fd(pipe_log);
  845. }
  846. else {
  847. const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog_name);
  848. apr_status_t rc;
  849. rc = apr_file_open(&dcfg->auditlog_fd, file_name,
  850. APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
  851. CREATEMODE, cmd->pool);
  852. if (rc != APR_SUCCESS) {
  853. return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log file: %s",
  854. file_name);
  855. }
  856. }
  857. return NULL;
  858. }
  859. static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1)
  860. {
  861. directory_config *dcfg = _dcfg;
  862. if (dcfg->auditlog_name == NOT_SET_P) {
  863. return apr_psprintf(cmd->pool, "ModSecurity: Cannot configure a secondary audit log without a primary defined: %s", p1);
  864. }
  865. dcfg->auditlog2_name = (char *)p1;
  866. if (dcfg->auditlog2_name[0] == '|') {
  867. const char *pipe_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name + 1);
  868. piped_log *pipe_log;
  869. pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
  870. if (pipe_log == NULL) {
  871. return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log pipe: %s",
  872. pipe_name);
  873. }
  874. dcfg->auditlog2_fd = ap_piped_log_write_fd(pipe_log);
  875. }
  876. else {
  877. const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name);
  878. apr_status_t rc;
  879. rc = apr_file_open(&dcfg->auditlog2_fd, file_name,
  880. APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
  881. CREATEMODE, cmd->pool);
  882. if (rc != APR_SUCCESS) {
  883. return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log file: %s",
  884. file_name);
  885. }
  886. }
  887. return NULL;
  888. }
  889. static const char *cmd_audit_log_parts(cmd_parms *cmd, void *_dcfg,
  890. const char *p1)
  891. {
  892. directory_config *dcfg = _dcfg;
  893. if (is_valid_parts_specification((char *)p1) != 1) {
  894. return apr_psprintf(cmd->pool, "Invalid parts specification for SecAuditLogParts: %s", p1);
  895. }
  896. dcfg->auditlog_parts = (char *)p1;
  897. return NULL;
  898. }
  899. static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg,
  900. const char *p1)
  901. {
  902. directory_config *dcfg = _dcfg;
  903. dcfg->auditlog_relevant_regex = msc_pregcomp(cmd->pool, p1, PCRE_DOTALL, NULL, NULL);
  904. if (dcfg->auditlog_relevant_regex == NULL) {
  905. return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
  906. }
  907. return NULL;
  908. }
  909. static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg,
  910. const char *p1)
  911. {
  912. directory_config *dcfg = _dcfg;
  913. if (strcasecmp(p1, "Serial") == 0) dcfg->auditlog_type = AUDITLOG_SERIAL;
  914. else
  915. if (strcasecmp(p1, "Concurrent") == 0) dcfg->auditlog_type = AUDITLOG_CONCURRENT;
  916. else
  917. return (const char *)apr_psprintf(cmd->pool,
  918. "ModSecurity: Unrecognised parameter value for SecAuditLogType: %s", p1);
  919. return NULL;
  920. }
  921. static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg,
  922. const char *p1)
  923. {
  924. directory_config *dcfg = (directory_config *)_dcfg;
  925. if (dcfg == NULL) return NULL;
  926. if (strcasecmp(p1, "default") == 0) {
  927. dcfg->auditlog_dirperms = NOT_SET;
  928. }
  929. else {
  930. long int mode = strtol(p1, NULL, 8); /* expects octal mode */
  931. if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
  932. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogDirMode: %s", p1);
  933. }
  934. dcfg->auditlog_dirperms = mode2fileperms(mode);
  935. }
  936. return NULL;
  937. }
  938. static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg,
  939. const char *p1)
  940. {
  941. directory_config *dcfg = (directory_config *)_dcfg;
  942. if (dcfg == NULL) return NULL;
  943. if (strcasecmp(p1, "default") == 0) {
  944. dcfg->auditlog_fileperms = NOT_SET;
  945. }
  946. else {
  947. long int mode = strtol(p1, NULL, 8); /* expects octal mode */
  948. if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
  949. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogFileMode: %s", p1);
  950. }
  951. dcfg->auditlog_fileperms = mode2fileperms(mode);
  952. }
  953. return NULL;
  954. }
  955. static const char *cmd_audit_log_storage_dir(cmd_parms *cmd, void *_dcfg,
  956. const char *p1)
  957. {
  958. directory_config *dcfg = _dcfg;
  959. dcfg->auditlog_storage_dir = ap_server_root_relative(cmd->pool, p1);
  960. return NULL;
  961. }
  962. static const char *cmd_cookie_format(cmd_parms *cmd, void *_dcfg,
  963. const char *p1)
  964. {
  965. directory_config *dcfg = (directory_config *)_dcfg;
  966. if (strcmp(p1, "0") == 0) dcfg->cookie_format = COOKIES_V0;
  967. else
  968. if (strcmp(p1, "1") == 0) dcfg->cookie_format = COOKIES_V1;
  969. else {
  970. return apr_psprintf(cmd->pool, "ModSecurity: Invalid cookie format: %s", p1);
  971. }
  972. return NULL;
  973. }
  974. static const char *cmd_chroot_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
  975. {
  976. char cwd[1025] = "";
  977. if (cmd->server->is_virtual) {
  978. return "ModSecurity: SecChrootDir not allowed in VirtualHost";
  979. }
  980. chroot_dir = (char *)p1;
  981. if (getcwd(cwd, 1024) == NULL) {
  982. return "ModSecurity: Failed to get the current working directory";
  983. }
  984. if (chdir(chroot_dir) < 0) {
  985. return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)",
  986. chroot_dir, errno, strerror(errno));
  987. }
  988. if (chdir(cwd) < 0) {
  989. return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)",
  990. cwd, errno, strerror(errno));
  991. }
  992. return NULL;
  993. }
  994. /**
  995. * Adds component signature to the list of signatures kept in configuration.
  996. */
  997. static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg,
  998. const char *p1)
  999. {
  1000. directory_config *dcfg = (directory_config *)_dcfg;
  1001. /* ENH Enforce "Name/VersionX.Y.Z (comment)" format. */
  1002. *(char **)apr_array_push(dcfg->component_signatures) = (char *)p1;
  1003. return NULL;
  1004. }
  1005. static const char *cmd_content_injection(cmd_parms *cmd, void *_dcfg, int flag)
  1006. {
  1007. directory_config *dcfg = (directory_config *)_dcfg;
  1008. if (dcfg == NULL) return NULL;
  1009. dcfg->content_injection_enabled = flag;
  1010. return NULL;
  1011. }
  1012. static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
  1013. {
  1014. directory_config *dcfg = (directory_config *)_dcfg;
  1015. if (cmd->server->is_virtual) {
  1016. return "ModSecurity: SecDataDir not allowed in VirtualHost.";
  1017. }
  1018. dcfg->data_dir = ap_server_root_relative(cmd->pool, p1);
  1019. return NULL;
  1020. }
  1021. static const char *cmd_debug_log(cmd_parms *cmd, void *_dcfg, const char *p1)
  1022. {
  1023. directory_config *dcfg = (directory_config *)_dcfg;
  1024. apr_status_t rc;
  1025. dcfg->debuglog_name = ap_server_root_relative(cmd->pool, p1);
  1026. rc = apr_file_open(&dcfg->debuglog_fd, dcfg->debuglog_name,
  1027. APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
  1028. CREATEMODE, cmd->pool);
  1029. if (rc != APR_SUCCESS) {
  1030. return apr_psprintf(cmd->pool, "ModSecurity: Failed to open debug log file: %s",
  1031. dcfg->debuglog_name);
  1032. }
  1033. return NULL;
  1034. }
  1035. static const char *cmd_debug_log_level(cmd_parms *cmd, void *_dcfg,
  1036. const char *p1)
  1037. {
  1038. directory_config *dcfg = (directory_config *)_dcfg;
  1039. dcfg->debuglog_level = atoi(p1);
  1040. if ((dcfg->debuglog_level >= 0)&&(dcfg->debuglog_level <= 9)) return NULL;
  1041. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecDebugLogLevel: %s", p1);
  1042. }
  1043. static const char *cmd_default_action(cmd_parms *cmd, void *_dcfg,
  1044. const char *p1)
  1045. {
  1046. directory_config *dcfg = (directory_config *)_dcfg;
  1047. extern msc_engine *modsecurity;
  1048. char *my_error_msg = NULL;
  1049. dcfg->tmp_default_actionset = msre_actionset_create(modsecurity->msre, p1, &my_error_msg);
  1050. if (dcfg->tmp_default_actionset == NULL) {
  1051. if (my_error_msg != NULL) return my_error_msg;
  1052. else return FATAL_ERROR;
  1053. }
  1054. /* Must specify a disruptive action. */
  1055. /* ENH: Remove this requirement? */
  1056. if (dcfg->tmp_default_actionset->intercept_action == NOT_SET) {
  1057. return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a disruptive action.");
  1058. }
  1059. /* Must specify a phase. */
  1060. /* ENH: Remove this requirement? */
  1061. if (dcfg->tmp_default_actionset->phase == NOT_SET) {
  1062. return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a phase.");
  1063. }
  1064. /* Must not use metadata actions. */
  1065. /* ENH: loop through to check for tags */
  1066. if ((dcfg->tmp_default_actionset->id != NOT_SET_P)
  1067. ||(dcfg->tmp_default_actionset->rev != NOT_SET_P)
  1068. ||(dcfg->tmp_default_actionset->msg != NOT_SET_P))
  1069. {
  1070. return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
  1071. "contain any metadata actions (id, rev, msg, tag, severity, logdata).");
  1072. }
  1073. /* These are just a warning for now. */
  1074. if ((dcfg->tmp_default_actionset->severity != NOT_SET)
  1075. ||(dcfg->tmp_default_actionset->logdata != NOT_SET_P))
  1076. {
  1077. ap_log_perror(APLOG_MARK,
  1078. APLOG_STARTUP|APLOG_WARNING|APLOG_NOERRNO, 0, cmd->pool,
  1079. "ModSecurity: WARNING Using \"severity\" or \"logdata\" in "
  1080. "SecDefaultAction is deprecated (%s:%d).",
  1081. cmd->directive->filename, cmd->directive->line_num);
  1082. }
  1083. /* Must not use chain. */
  1084. if (dcfg->tmp_default_actionset->is_chained != NOT_SET) {
  1085. return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
  1086. "contain a chain action.");
  1087. }
  1088. /* Must not use skip. */
  1089. if (dcfg->tmp_default_actionset->skip_count != NOT_SET) {
  1090. return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
  1091. "contain a skip action.");
  1092. }
  1093. /* Must not use skipAfter. */
  1094. if (dcfg->tmp_default_actionset->skip_after != NOT_SET_P) {
  1095. return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not "
  1096. "contain a skipAfter action.");
  1097. }
  1098. return NULL;
  1099. }
  1100. static const char *cmd_disable_backend_compression(cmd_parms *cmd, void *_dcfg, int flag)
  1101. {
  1102. directory_config *dcfg = (directory_config *)_dcfg;
  1103. if (dcfg == NULL) return NULL;
  1104. dcfg->disable_backend_compression = flag;
  1105. return NULL;
  1106. }
  1107. static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg,
  1108. const char *p1, const char *p2)
  1109. {
  1110. extern char *guardianlog_name;
  1111. extern apr_file_t *guardianlog_fd;
  1112. extern char *guardianlog_condition;
  1113. if (cmd->server->is_virtual) {
  1114. return "ModSecurity: SecGuardianLog not allowed in VirtualHost";
  1115. }
  1116. if (p2 != NULL) {
  1117. if (strncmp(p2, "env=", 4) != 0) {
  1118. return "ModSecurity: Error in condition clause";
  1119. }
  1120. if ( (p2[4] == '\0') || ((p2[4] == '!')&&(p2[5] == '\0')) ) {
  1121. return "ModSecurity: Missing variable name";
  1122. }
  1123. guardianlog_condition = apr_pstrdup(cmd->pool, p2 + 4);
  1124. }
  1125. guardianlog_name = (char *)p1;
  1126. if (guardianlog_name[0] == '|') {
  1127. const char *pipe_name = ap_server_root_relative(cmd->pool, guardianlog_name + 1);
  1128. piped_log *pipe_log;
  1129. pipe_log = ap_open_piped_log(cmd->pool, pipe_name);
  1130. if (pipe_log == NULL) {
  1131. return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log pipe: %s",
  1132. pipe_name);
  1133. }
  1134. guardianlog_fd = ap_piped_log_write_fd(pipe_log);
  1135. }
  1136. else {
  1137. const char *file_name = ap_server_root_relative(cmd->pool, guardianlog_name);
  1138. apr_status_t rc;
  1139. rc = apr_file_open(&guardianlog_fd, file_name,
  1140. APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
  1141. CREATEMODE, cmd->pool);
  1142. if (rc != APR_SUCCESS) {
  1143. return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log file: %s",
  1144. file_name);
  1145. }
  1146. }
  1147. return NULL;
  1148. }
  1149. /*
  1150. * \brief Add SecStreamInBodyInspection configuration option
  1151. *
  1152. * \param cmd Pointer to configuration data
  1153. * \param _dcfg Pointer to directory configuration
  1154. * \param p1 Pointer to configuration option
  1155. *
  1156. * \retval NULL On failure
  1157. * \retval apr_psprintf On Success
  1158. */
  1159. static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int flag)
  1160. {
  1161. directory_config *dcfg = (directory_config *)_dcfg;
  1162. if (dcfg == NULL) return NULL;
  1163. dcfg->stream_inbody_inspection = flag;
  1164. return NULL;
  1165. }
  1166. /*
  1167. * \brief Add SecStreamOutBodyInspection configuration option
  1168. *
  1169. * \param cmd Pointer to configuration data
  1170. * \param _dcfg Pointer to directory configuration
  1171. * \param p1 Pointer to configuration option
  1172. *
  1173. * \retval NULL On failure
  1174. * \retval apr_psprintf On Success
  1175. */
  1176. static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, int flag)
  1177. {
  1178. directory_config *dcfg = (directory_config *)_dcfg;
  1179. if (dcfg == NULL) return NULL;
  1180. dcfg->stream_outbody_inspection = flag;
  1181. return NULL;
  1182. }
  1183. /*
  1184. * \brief Add SecReadStateLimit configuration option
  1185. *
  1186. * \param cmd Pointer to configuration data
  1187. * \param _dcfg Pointer to directory configuration
  1188. * \param p1 Pointer to configuration option
  1189. *
  1190. * \retval NULL On failure
  1191. * \retval apr_psprintf On Success
  1192. */
  1193. static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg,
  1194. const char *p1)
  1195. {
  1196. directory_config *dcfg = (directory_config *)_dcfg;
  1197. long int limit;
  1198. if (dcfg == NULL) return NULL;
  1199. limit = strtol(p1, NULL, 10);
  1200. if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
  1201. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecReadStateLimit: %s", p1);
  1202. }
  1203. conn_read_state_limit = limit;
  1204. return NULL;
  1205. }
  1206. /*
  1207. * \brief Add SecWriteStateLimit configuration option
  1208. *
  1209. * \param cmd Pointer to configuration data
  1210. * \param _dcfg Pointer to directory configuration
  1211. * \param p1 Pointer to configuration option
  1212. *
  1213. * \retval NULL On failure
  1214. * \retval apr_psprintf On Success
  1215. */
  1216. static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg,
  1217. const char *p1)
  1218. {
  1219. directory_config *dcfg = (directory_config *)_dcfg;
  1220. long int limit;
  1221. if (dcfg == NULL) return NULL;
  1222. limit = strtol(p1, NULL, 10);
  1223. if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
  1224. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecWriteStateLimit: %s", p1);
  1225. }
  1226. conn_write_state_limit = limit;
  1227. return NULL;
  1228. }
  1229. static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg,
  1230. const char *p1)
  1231. {
  1232. directory_config *dcfg = (directory_config *)_dcfg;
  1233. long int limit;
  1234. if (dcfg == NULL) return NULL;
  1235. limit = strtol(p1, NULL, 10);
  1236. if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
  1237. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyInMemoryLimit: %s", p1);
  1238. }
  1239. dcfg->reqbody_inmemory_limit = limit;
  1240. return NULL;
  1241. }
  1242. static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg,
  1243. const char *p1)
  1244. {
  1245. directory_config *dcfg = (directory_config *)_dcfg;
  1246. long int limit;
  1247. if (dcfg == NULL) return NULL;
  1248. limit = strtol(p1, NULL, 10);
  1249. if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
  1250. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimit: %s", p1);
  1251. }
  1252. dcfg->reqbody_limit = limit;
  1253. return NULL;
  1254. }
  1255. static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg,
  1256. const char *p1)
  1257. {
  1258. directory_config *dcfg = (directory_config *)_dcfg;
  1259. long int limit;
  1260. if (dcfg == NULL) return NULL;
  1261. limit = strtol(p1, NULL, 10);
  1262. if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
  1263. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyNoFilesLimit: %s", p1);
  1264. }
  1265. dcfg->reqbody_no_files_limit = limit;
  1266. return NULL;
  1267. }
  1268. static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg,
  1269. const char *p1)
  1270. {
  1271. directory_config *dcfg = (directory_config *)_dcfg;
  1272. if (dcfg == NULL) return NULL;
  1273. if (strcasecmp(p1, "on") == 0) dcfg->reqbody_access = 1;
  1274. else
  1275. if (strcasecmp(p1, "off") == 0) dcfg->reqbody_access = 0;
  1276. else
  1277. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyAccess: %s", p1);
  1278. return NULL;
  1279. }
  1280. static const char *cmd_request_intercept_on_error(cmd_parms *cmd, void *_dcfg,
  1281. const char *p1)
  1282. {
  1283. directory_config *dcfg = (directory_config *)_dcfg;
  1284. if (dcfg == NULL) return NULL;
  1285. if (strcasecmp(p1, "on") == 0) dcfg->reqintercept_oe = 1;
  1286. else
  1287. if (strcasecmp(p1, "off") == 0) dcfg->reqintercept_oe = 0;
  1288. else
  1289. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecInterceptOnError: %s", p1);
  1290. return NULL;
  1291. }
  1292. static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg,
  1293. const char *p1)
  1294. {
  1295. directory_config *dcfg = (directory_config *)_dcfg;
  1296. if (dcfg == NULL) return NULL;
  1297. /* ENH Validate encoding */
  1298. dcfg->request_encoding = p1;
  1299. return NULL;
  1300. }
  1301. static const char *cmd_response_body_access(cmd_parms *cmd, void *_dcfg,
  1302. const char *p1)
  1303. {
  1304. directory_config *dcfg = (directory_config *)_dcfg;
  1305. if (dcfg == NULL) return NULL;
  1306. if (strcasecmp(p1, "on") == 0) dcfg->resbody_access = 1;
  1307. else
  1308. if (strcasecmp(p1, "off") == 0) dcfg->resbody_access = 0;
  1309. else
  1310. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyAccess: %s", p1);
  1311. return NULL;
  1312. }
  1313. static const char *cmd_response_body_limit(cmd_parms *cmd, void *_dcfg,
  1314. const char *p1)
  1315. {
  1316. directory_config *dcfg = (directory_config *)_dcfg;
  1317. long int limit;
  1318. limit = strtol(p1, NULL, 10);
  1319. if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
  1320. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimit: %s", p1);
  1321. }
  1322. if (limit > RESPONSE_BODY_HARD_LIMIT) {
  1323. return apr_psprintf(cmd->pool, "ModSecurity: Response size limit can not exceed the hard limit: %li", RESPONSE_BODY_HARD_LIMIT);
  1324. }
  1325. dcfg->of_limit = limit;
  1326. return NULL;
  1327. }
  1328. static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg,
  1329. const char *p1)
  1330. {
  1331. directory_config *dcfg = (directory_config *)_dcfg;
  1332. if (dcfg == NULL) return NULL;
  1333. if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) {
  1334. dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
  1335. return NULL;
  1336. }
  1337. if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
  1338. else
  1339. if (strcasecmp(p1, "Reject") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT;
  1340. else
  1341. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimitAction: %s", p1);
  1342. return NULL;
  1343. }
  1344. static const char *cmd_resquest_body_limit_action(cmd_parms *cmd, void *_dcfg,
  1345. const char *p1)
  1346. {
  1347. directory_config *dcfg = (directory_config *)_dcfg;
  1348. if (dcfg == NULL) return NULL;
  1349. if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) {
  1350. dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
  1351. return NULL;
  1352. }
  1353. if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
  1354. else
  1355. if (strcasecmp(p1, "Reject") == 0) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT;
  1356. else
  1357. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimitAction: %s", p1);
  1358. return NULL;
  1359. }
  1360. static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg,
  1361. const char *_p1)
  1362. {
  1363. directory_config *dcfg = (directory_config *)_dcfg;
  1364. char *p1 = apr_pstrdup(cmd->pool, _p1);
  1365. /* TODO check whether the parameter is a valid MIME type of "???" */
  1366. if ((dcfg->of_mime_types == NULL)||(dcfg->of_mime_types == NOT_SET_P)) {
  1367. dcfg->of_mime_types = apr_table_make(cmd->pool, 10);
  1368. }
  1369. strtolower_inplace((unsigned char *)p1);
  1370. apr_table_setn(dcfg->of_mime_types, p1, "1");
  1371. return NULL;
  1372. }
  1373. static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd,
  1374. void *_dcfg)
  1375. {
  1376. directory_config *dcfg = (directory_config *)_dcfg;
  1377. if (dcfg == NULL) return NULL;
  1378. dcfg->of_mime_types_cleared = 1;
  1379. if ((dcfg->of_mime_types != NULL)&&(dcfg->of_mime_types != NOT_SET_P)) {
  1380. apr_table_clear(dcfg->of_mime_types);
  1381. }
  1382. return NULL;
  1383. }
  1384. /*
  1385. * \brief Add SecRuleUpdateTargetById
  1386. *
  1387. * \param cmd Pointer to configuration data
  1388. * \param _dcfg Pointer to directory configuration
  1389. * \param p1 Pointer to configuration option
  1390. * \param p2 Pointer to configuration option
  1391. * \param p3 Pointer to configuration option
  1392. *
  1393. * \retval NULL On failure|Success
  1394. */
  1395. static const char *cmd_rule_update_target_by_id(cmd_parms *cmd, void *_dcfg,
  1396. const char *p1, const char *p2, const char *p3)
  1397. {
  1398. return update_rule_target(cmd, (directory_config *)_dcfg, NULL, p1, p2, p3);
  1399. }
  1400. static const char *cmd_rule(cmd_parms *cmd, void *_dcfg,
  1401. const char *p1, const char *p2, const char *p3)
  1402. {
  1403. return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_NORMAL, p1, p2, p3);
  1404. }
  1405. static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1)
  1406. {
  1407. directory_config *dcfg = (directory_config *)_dcfg;
  1408. if (dcfg == NULL) return NULL;
  1409. if (strcasecmp(p1, "on") == 0) dcfg->is_enabled = MODSEC_ENABLED;
  1410. else
  1411. if (strcasecmp(p1, "off") == 0) dcfg->is_enabled = MODSEC_DISABLED;
  1412. else
  1413. if (strcasecmp(p1, "detectiononly") == 0) {
  1414. dcfg->is_enabled = MODSEC_DETECTION_ONLY;
  1415. dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
  1416. dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
  1417. } else
  1418. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRuleEngine: %s", p1);
  1419. return NULL;
  1420. }
  1421. static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag)
  1422. {
  1423. directory_config *dcfg = (directory_config *)_dcfg;
  1424. if (dcfg == NULL) return NULL;
  1425. dcfg->rule_inheritance = flag;
  1426. return NULL;
  1427. }
  1428. static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg,
  1429. const char *p1, const char *p2)
  1430. {
  1431. #if defined(WITH_LUA)
  1432. const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
  1433. return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL);
  1434. #else
  1435. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Ignoring SecRuleScript \"%s\" directive (%s:%d): No Lua scripting support.", p1, cmd->directive->filename, cmd->directive->line_num);
  1436. return NULL;
  1437. #endif
  1438. }
  1439. static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg,
  1440. const char *p1)
  1441. {
  1442. directory_config *dcfg = (directory_config *)_dcfg;
  1443. rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
  1444. if (dcfg == NULL) return NULL;
  1445. re->type = RULE_EXCEPTION_REMOVE_ID;
  1446. re->param = p1;
  1447. *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
  1448. /* Remove the corresponding rules from the context straight away. */
  1449. msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
  1450. return NULL;
  1451. }
  1452. static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg,
  1453. const char *p1)
  1454. {
  1455. directory_config *dcfg = (directory_config *)_dcfg;
  1456. rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
  1457. if (dcfg == NULL) return NULL;
  1458. re->type = RULE_EXCEPTION_REMOVE_TAG;
  1459. re->param = p1;
  1460. re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
  1461. if (re->param_data == NULL) {
  1462. return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
  1463. }
  1464. *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
  1465. /* Remove the corresponding rules from the context straight away. */
  1466. msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
  1467. #ifdef DEBUG_CONF
  1468. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Added exception %pp (%d %s) to dcfg %pp.", re, re->type, re->param, dcfg);
  1469. #endif
  1470. return NULL;
  1471. }
  1472. static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg,
  1473. const char *p1)
  1474. {
  1475. directory_config *dcfg = (directory_config *)_dcfg;
  1476. rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
  1477. if (dcfg == NULL) return NULL;
  1478. re->type = RULE_EXCEPTION_REMOVE_MSG;
  1479. re->param = p1;
  1480. re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL);
  1481. if (re->param_data == NULL) {
  1482. return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
  1483. }
  1484. *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re;
  1485. /* Remove the corresponding rules from the context straight away. */
  1486. msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re);
  1487. #ifdef DEBUG_CONF
  1488. ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Added exception %pp (%d %s) to dcfg %pp.", re, re->type, re->param, dcfg);
  1489. #endif
  1490. return NULL;
  1491. }
  1492. static const char *cmd_rule_update_action_by_id(cmd_parms *cmd, void *_dcfg,
  1493. const char *p1, const char *p2)
  1494. {
  1495. int offset = 0, rule_id = atoi(p1);
  1496. char *opt = strchr(p1,':');
  1497. char *savedptr = NULL;
  1498. char *param = apr_pstrdup(cmd->pool, p1);
  1499. if ((rule_id == LONG_MAX)||(rule_id == LONG_MIN)||(rule_id <= 0)) {
  1500. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for ID for update action: %s", p1);
  1501. }
  1502. if(opt != NULL) {
  1503. opt++;
  1504. offset = atoi(opt);
  1505. opt = apr_strtok(param,":", &savedptr);
  1506. return update_rule_action(cmd, (directory_config *)_dcfg, (const char *)opt, p2, offset);
  1507. }
  1508. return update_rule_action(cmd, (directory_config *)_dcfg, p1, p2, offset);
  1509. }
  1510. static const char *cmd_server_signature(cmd_parms *cmd, void *_dcfg,
  1511. const char *p1)
  1512. {
  1513. if (cmd->server->is_virtual) {
  1514. return "ModSecurity: SecServerSignature not allowed in VirtualHost";
  1515. }
  1516. new_server_signature = (char *)p1;
  1517. return NULL;
  1518. }
  1519. static const char *cmd_tmp_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
  1520. {
  1521. directory_config *dcfg = (directory_config *)_dcfg;
  1522. if (dcfg == NULL) return NULL;
  1523. if (strcasecmp(p1, "none") == 0) dcfg->tmp_dir = NULL;
  1524. else dcfg->tmp_dir = ap_server_root_relative(cmd->pool, p1);
  1525. return NULL;
  1526. }
  1527. static const char *cmd_upload_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
  1528. {
  1529. directory_config *dcfg = (directory_config *)_dcfg;
  1530. if (dcfg == NULL) return NULL;
  1531. if (strcasecmp(p1, "none") == 0) dcfg->upload_dir = NULL;
  1532. else dcfg->upload_dir = ap_server_root_relative(cmd->pool, p1);
  1533. return NULL;
  1534. }
  1535. static const char *cmd_upload_file_limit(cmd_parms *cmd, void *_dcfg,
  1536. const char *p1)
  1537. {
  1538. directory_config *dcfg = (directory_config *)_dcfg;
  1539. if (dcfg == NULL) return NULL;
  1540. if (strcasecmp(p1, "default") == 0) {
  1541. dcfg->upload_file_limit = NOT_SET;
  1542. }
  1543. else {
  1544. dcfg->upload_file_limit = atoi(p1);
  1545. }
  1546. return NULL;
  1547. }
  1548. static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg,
  1549. const char *p1)
  1550. {
  1551. directory_config *dcfg = (directory_config *)_dcfg;
  1552. if (dcfg == NULL) return NULL;
  1553. if (strcasecmp(p1, "default") == 0) {
  1554. dcfg->upload_filemode = NOT_SET;
  1555. }
  1556. else {
  1557. long int mode = strtol(p1, NULL, 8); /* expects octal mode */
  1558. if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) {
  1559. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecUploadFileMode: %s", p1);
  1560. }
  1561. dcfg->upload_filemode = (int)mode;
  1562. }
  1563. return NULL;
  1564. }
  1565. static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg,
  1566. const char *p1)
  1567. {
  1568. directory_config *dcfg = (directory_config *)_dcfg;
  1569. if (dcfg == NULL) return NULL;
  1570. if (strcasecmp(p1, "on") == 0) {
  1571. dcfg->upload_keep_files = KEEP_FILES_ON;
  1572. } else
  1573. if (strcasecmp(p1, "off") == 0) {
  1574. dcfg->upload_keep_files = KEEP_FILES_OFF;
  1575. } else
  1576. if (strcasecmp(p1, "relevantonly") == 0) {
  1577. dcfg->upload_keep_files = KEEP_FILES_RELEVANT_ONLY;
  1578. } else {
  1579. return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for SecUploadKeepFiles: %s",
  1580. p1);
  1581. }
  1582. return NULL;
  1583. }
  1584. static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1)
  1585. {
  1586. directory_config *dcfg = (directory_config *)_dcfg;
  1587. /* ENH enforce format (letters, digits, ., _, -) */
  1588. dcfg->webappid = p1;
  1589. return NULL;
  1590. }
  1591. /* PCRE Limits */
  1592. static const char *cmd_pcre_match_limit(cmd_parms *cmd,
  1593. void *_dcfg, const char *p1)
  1594. {
  1595. long val;
  1596. if (cmd->server->is_virtual) {
  1597. return "ModSecurity: SecPcreMatchLimit not allowed in VirtualHost";
  1598. }
  1599. val = atol(p1);
  1600. if (val <= 0) {
  1601. return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
  1602. "SecPcreMatchLimit: %s", p1);
  1603. }
  1604. msc_pcre_match_limit = (unsigned long int)val;
  1605. return NULL;
  1606. }
  1607. static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd,
  1608. void *_dcfg, const char *p1)
  1609. {
  1610. long val;
  1611. if (cmd->server->is_virtual) {
  1612. return "ModSecurity: SecPcreMatchLimitRecursion not allowed in VirtualHost";
  1613. }
  1614. val = atol(p1);
  1615. if (val <= 0) {
  1616. return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
  1617. "SecPcreMatchLimitRecursion: %s", p1);
  1618. }
  1619. msc_pcre_match_limit_recursion = (unsigned long int)val;
  1620. return NULL;
  1621. }
  1622. /* -- Geo Lookup configuration -- */
  1623. static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg,
  1624. const char *p1)
  1625. {
  1626. const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
  1627. char *error_msg;
  1628. directory_config *dcfg = (directory_config *)_dcfg;
  1629. if (dcfg == NULL) return NULL;
  1630. if (geo_init(dcfg, filename, &error_msg) <= 0) {
  1631. return error_msg;
  1632. }
  1633. return NULL;
  1634. }
  1635. /* Unicode CodePage */
  1636. static const char *cmd_unicode_codepage(cmd_parms *cmd,
  1637. void *_dcfg, const char *p1)
  1638. {
  1639. long val;
  1640. val = atol(p1);
  1641. if (val <= 0) {
  1642. return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for "
  1643. "SecUnicodeCodePage: %s", p1);
  1644. }
  1645. unicode_codepage = (unsigned long int)val;
  1646. return NULL;
  1647. }
  1648. /* Unicode Map */
  1649. static const char *cmd_unicode_map(cmd_parms *cmd, void *_dcfg,
  1650. const char *p1)
  1651. {
  1652. const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
  1653. char *error_msg;
  1654. directory_config *dcfg = (directory_config *)_dcfg;
  1655. if (dcfg == NULL) return NULL;
  1656. if (unicode_map_init(dcfg, filename, &error_msg) <= 0) {
  1657. return error_msg;
  1658. }
  1659. return NULL;
  1660. }
  1661. /* Google safe browsing */
  1662. static const char *cmd_gsb_lookup_db(cmd_parms *cmd, void *_dcfg,
  1663. const char *p1)
  1664. {
  1665. const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1);
  1666. char *error_msg;
  1667. directory_config *dcfg = (directory_config *)_dcfg;
  1668. if (dcfg == NULL) return NULL;
  1669. if (gsb_db_init(dcfg, filename, &error_msg) <= 0) {
  1670. return error_msg;
  1671. }
  1672. return NULL;
  1673. }
  1674. /* -- Cache -- */
  1675. static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg,
  1676. const char *p1, const char *p2)
  1677. {
  1678. directory_config *dcfg = (directory_config *)_dcfg;
  1679. if (dcfg == NULL) return NULL;
  1680. if (strcasecmp(p1, "on") == 0)
  1681. dcfg->cache_trans = MODSEC_CACHE_ENABLED;
  1682. else if (strcasecmp(p1, "off") == 0)
  1683. dcfg->cache_trans = MODSEC_CACHE_DISABLED;
  1684. else
  1685. return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecCacheTransformations: %s", p1);
  1686. /* Process options */
  1687. if (p2 != NULL) {
  1688. apr_table_t *vartable = apr_table_make(cmd->pool, 4);
  1689. apr_status_t rc;
  1690. char *error_msg = NULL;
  1691. const char *charval = NULL;
  1692. apr_int64_t intval = 0;
  1693. if (vartable == NULL) {
  1694. return apr_psprintf(cmd->pool, "ModSecurity: Unable to process options for SecCacheTransformations");
  1695. }
  1696. rc = msre_parse_generic(cmd->pool, p2, vartable, &error_msg);
  1697. if (rc < 0) {
  1698. return apr_psprintf(cmd->pool, "ModSecurity: Unable to parse options for SecCacheTransformations: %s", error_msg);
  1699. }
  1700. /* incremental */
  1701. charval = apr_table_get(vartable, "incremental");
  1702. if (charval != NULL) {
  1703. if (strcasecmp(charval, "on") == 0)
  1704. dcfg->cache_trans_incremental = 1;
  1705. else if (strcasecmp(charval, "off") == 0)
  1706. dcfg->cache_trans_incremental = 0;
  1707. else
  1708. return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations invalid incremental value: %s", charval);
  1709. }
  1710. /* minlen */
  1711. charval = apr_table_get(vartable, "minlen");
  1712. if (charval != NULL) {
  1713. intval = apr_atoi64(charval);
  1714. if (errno == ERANGE) {
  1715. return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen out of range: %s", charval);
  1716. }
  1717. if (intval < 0) {
  1718. return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be positive: %s", charval);
  1719. }
  1720. /* The NOT_SET indicator is -1, a signed long, and therfore
  1721. * we cannot be >= the unsigned value of NOT_SET.
  1722. */
  1723. if ((unsigned long)intval >= (unsigned long)NOT_SET) {
  1724. return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be less than: %lu", (unsigned long)NOT_SET);
  1725. }
  1726. dcfg->cache_trans_min = (apr_size_t)intval;
  1727. }
  1728. /* maxlen */
  1729. charval = apr_table_get(vartable, "maxlen");
  1730. if (charval != NULL) {
  1731. intval = apr_atoi64(charval);
  1732. if (errno == ERANGE) {
  1733. return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen out of range: %s", charval);
  1734. }
  1735. if (intval < 0) {
  1736. return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be positive: %s", charval);
  1737. }
  1738. /* The NOT_SET indicator is -1, a signed long, and therfore
  1739. * we cannot be >= the unsigned value of NOT_SET.
  1740. */
  1741. if ((unsigned long)intval >= (unsigned long)NOT_SET) {
  1742. return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be less than: %lu", (unsigned long)NOT_SET);
  1743. }
  1744. if ((intval != 0) && ((apr_size_t)intval < dcfg->cache_trans_min)) {
  1745. return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must not be less than minlen: %lu < %" APR_SIZE_T_FMT, (unsigned long)intval, dcfg->cache_trans_min);
  1746. }
  1747. dcfg->cache_trans_max = (apr_size_t)intval;
  1748. }
  1749. /* maxitems */
  1750. charval = apr_table_get(vartable, "maxitems");
  1751. if (charval != NULL) {
  1752. intval = apr_atoi64(charval);
  1753. if (errno == ERANGE) {
  1754. return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems out of range: %s", charval);
  1755. }
  1756. if (intval < 0) {
  1757. return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems must be positive: %s", charval);
  1758. }
  1759. dcfg->cache_trans_maxitems = (apr_size_t)intval;
  1760. }
  1761. }
  1762. return NULL;
  1763. }
  1764. /* -- Configuration directives definitions -- */
  1765. #define CMD_SCOPE_MAIN (RSRC_CONF)
  1766. #define CMD_SCOPE_ANY (RSRC_CONF | ACCESS_CONF)
  1767. const command_rec module_directives[] = {
  1768. AP_INIT_TAKE1 (
  1769. "SecAction",
  1770. cmd_action,
  1771. NULL,
  1772. CMD_SCOPE_ANY,
  1773. "an action list"
  1774. ),
  1775. AP_INIT_TAKE1 (
  1776. "SecArgumentSeparator",
  1777. cmd_argument_separator,
  1778. NULL,
  1779. CMD_SCOPE_MAIN,
  1780. "character that will be used as separator when parsing application/x-www-form-urlencoded content."
  1781. ),
  1782. AP_INIT_TAKE1 (
  1783. "SecAuditEngine",
  1784. cmd_audit_engine,
  1785. NULL,
  1786. CMD_SCOPE_ANY,
  1787. "On, Off or RelevantOnly to determine the level of audit logging"
  1788. ),
  1789. AP_INIT_TAKE1 (
  1790. "SecAuditLog",
  1791. cmd_audit_log,
  1792. NULL,
  1793. CMD_SCOPE_ANY,
  1794. "filename of the primary audit log file"
  1795. ),
  1796. AP_INIT_TAKE1 (
  1797. "SecAuditLog2",
  1798. cmd_audit_log2,
  1799. NULL,
  1800. CMD_SCOPE_ANY,
  1801. "filename of the secondary audit log file"
  1802. ),
  1803. AP_INIT_TAKE1 (
  1804. "SecAuditLogParts",
  1805. cmd_audit_log_parts,
  1806. NULL,
  1807. CMD_SCOPE_ANY,
  1808. "list of audit log parts that go into the log."
  1809. ),
  1810. AP_INIT_TAKE1 (
  1811. "SecAuditLogRelevantStatus",
  1812. cmd_audit_log_relevant_status,
  1813. NULL,
  1814. CMD_SCOPE_ANY,
  1815. "regular expression that will be used to determine if the response status is relevant for audit logging"
  1816. ),
  1817. AP_INIT_TAKE1 (
  1818. "SecAuditLogType",
  1819. cmd_audit_log_type,
  1820. NULL,
  1821. CMD_SCOPE_ANY,
  1822. "whether to use the old audit log format (Serial) or new (Concurrent)"
  1823. ),
  1824. AP_INIT_TAKE1 (
  1825. "SecAuditLogStorageDir",
  1826. cmd_audit_log_storage_dir,
  1827. NULL,
  1828. CMD_SCOPE_ANY,
  1829. "path to the audit log storage area; absolute, or relative to the root of the server"
  1830. ),
  1831. AP_INIT_TAKE1 (
  1832. "SecAuditLogDirMode",
  1833. cmd_audit_log_dirmode,
  1834. NULL,
  1835. CMD_SCOPE_ANY,
  1836. "octal permissions mode for concurrent audit log directories"
  1837. ),
  1838. AP_INIT_TAKE1 (
  1839. "SecAuditLogFileMode",
  1840. cmd_audit_log_filemode,
  1841. NULL,
  1842. CMD_SCOPE_ANY,
  1843. "octal permissions mode for concurrent audit log files"
  1844. ),
  1845. AP_INIT_TAKE12 (
  1846. "SecCacheTransformations",
  1847. cmd_cache_transformations,
  1848. NULL,
  1849. CMD_SCOPE_ANY,
  1850. "whether or not to cache transformations. Defaults to true."
  1851. ),
  1852. AP_INIT_TAKE1 (
  1853. "SecChrootDir",
  1854. cmd_chroot_dir,
  1855. NULL,
  1856. CMD_SCOPE_MAIN,
  1857. "path of the directory to which server will be chrooted"
  1858. ),
  1859. AP_INIT_TAKE1 (
  1860. "SecComponentSignature",
  1861. cmd_component_signature,
  1862. NULL,
  1863. CMD_SCOPE_MAIN,
  1864. "component signature to add to ModSecurity signature."
  1865. ),
  1866. AP_INIT_FLAG (
  1867. "SecContentInjection",
  1868. cmd_content_injection,
  1869. NULL,
  1870. CMD_SCOPE_ANY,
  1871. "On or Off"
  1872. ),
  1873. AP_INIT_FLAG (
  1874. "SecStreamOutBodyInspection",
  1875. cmd_stream_outbody_inspection,
  1876. NULL,
  1877. CMD_SCOPE_ANY,
  1878. "On or Off"
  1879. ),
  1880. AP_INIT_FLAG (
  1881. "SecStreamInBodyInspection",
  1882. cmd_stream_inbody_inspection,
  1883. NULL,
  1884. CMD_SCOPE_ANY,
  1885. "On or Off"
  1886. ),
  1887. AP_INIT_TAKE1 (
  1888. "SecCookieFormat",
  1889. cmd_cookie_format,
  1890. NULL,
  1891. CMD_SCOPE_ANY,
  1892. "version of the Cookie specification to use for parsing. Possible values are 0 and 1."
  1893. ),
  1894. AP_INIT_TAKE1 (
  1895. "SecDataDir",
  1896. cmd_data_dir,
  1897. NULL,
  1898. CMD_SCOPE_MAIN,
  1899. "path to the persistent data storage area" // TODO
  1900. ),
  1901. AP_INIT_TAKE1 (
  1902. "SecDebugLog",
  1903. cmd_debug_log,
  1904. NULL,
  1905. CMD_SCOPE_ANY,
  1906. "path to the debug log file"
  1907. ),
  1908. AP_INIT_TAKE1 (
  1909. "SecDebugLogLevel",
  1910. cmd_debug_log_level,
  1911. NULL,
  1912. CMD_SCOPE_ANY,
  1913. "debug log level, which controls the verbosity of logging."
  1914. " Use values from 0 (no logging) to 9 (a *lot* of logging)."
  1915. ),
  1916. AP_INIT_TAKE1 (
  1917. "SecDefaultAction",
  1918. cmd_default_action,
  1919. NULL,
  1920. CMD_SCOPE_ANY,
  1921. "default action list"
  1922. ),
  1923. AP_INIT_FLAG (
  1924. "SecDisableBackendCompression",
  1925. cmd_disable_backend_compression,
  1926. NULL,
  1927. CMD_SCOPE_ANY,
  1928. "When set to On, removes the compression headers from the backend requests."
  1929. ),
  1930. AP_INIT_TAKE1 (
  1931. "SecGsbLookupDB",
  1932. cmd_gsb_lookup_db,
  1933. NULL,
  1934. RSRC_CONF,
  1935. "database google safe browsing"
  1936. ),
  1937. AP_INIT_TAKE1 (
  1938. "SecUnicodeCodePage",
  1939. cmd_unicode_codepage,
  1940. NULL,
  1941. CMD_SCOPE_MAIN,
  1942. "Unicode CodePage"
  1943. ),
  1944. AP_INIT_TAKE1 (
  1945. "SecUnicodeMapFile",
  1946. cmd_unicode_map,
  1947. NULL,
  1948. CMD_SCOPE_MAIN,
  1949. "Unicode Map file"
  1950. ),
  1951. AP_INIT_TAKE1 (
  1952. "SecGeoLookupDB",
  1953. cmd_geo_lookup_db,
  1954. NULL,
  1955. RSRC_CONF,
  1956. "database for geographical lookups module."
  1957. ),
  1958. AP_INIT_TAKE12 (
  1959. "SecGuardianLog",
  1960. cmd_guardian_log,
  1961. NULL,
  1962. CMD_SCOPE_MAIN,
  1963. "The filename of the filter debugging log file"
  1964. ),
  1965. AP_INIT_TAKE1 (
  1966. "SecMarker",
  1967. cmd_marker,
  1968. NULL,
  1969. CMD_SCOPE_ANY,
  1970. "marker for a skipAfter target"
  1971. ),
  1972. AP_INIT_TAKE1 (
  1973. "SecPcreMatchLimit",
  1974. cmd_pcre_match_limit,
  1975. NULL,
  1976. CMD_SCOPE_MAIN,
  1977. "PCRE match limit"
  1978. ),
  1979. AP_INIT_TAKE1 (
  1980. "SecPcreMatchLimitRecursion",
  1981. cmd_pcre_match_limit_recursion,
  1982. NULL,
  1983. CMD_SCOPE_MAIN,
  1984. "PCRE match limit recursion"
  1985. ),
  1986. AP_INIT_TAKE1 (
  1987. "SecRequestBodyAccess",
  1988. cmd_request_body_access,
  1989. NULL,
  1990. CMD_SCOPE_ANY,
  1991. "On or Off"
  1992. ),
  1993. AP_INIT_TAKE1 (
  1994. "SecInterceptOnError",
  1995. cmd_request_intercept_on_error,
  1996. NULL,
  1997. CMD_SCOPE_ANY,
  1998. "On or Off"
  1999. ),
  2000. AP_INIT_TAKE1 (
  2001. "SecReadStateLimit",
  2002. cmd_conn_read_state_limit,
  2003. NULL,
  2004. CMD_SCOPE_ANY,
  2005. "maximum number of threads in READ_BUSY state per ip address"
  2006. ),
  2007. AP_INIT_TAKE1 (
  2008. "SecWriteStateLimit",
  2009. cmd_conn_write_state_limit,
  2010. NULL,
  2011. CMD_SCOPE_ANY,
  2012. "maximum number of threads in WRITE_BUSY state per ip address"
  2013. ),
  2014. AP_INIT_TAKE1 (
  2015. "SecRequestBodyInMemoryLimit",
  2016. cmd_request_body_inmemory_limit,
  2017. NULL,
  2018. CMD_SCOPE_ANY,
  2019. "maximum request body size that will be placed in memory (except for POST urlencoded requests)."
  2020. ),
  2021. AP_INIT_TAKE1 (
  2022. "SecRequestBodyLimit",
  2023. cmd_request_body_limit,
  2024. NULL,
  2025. CMD_SCOPE_ANY,
  2026. "maximum request body size ModSecurity will accept."
  2027. ),
  2028. AP_INIT_TAKE1 (
  2029. "SecRequestBodyNoFilesLimit",
  2030. cmd_request_body_no_files_limit,
  2031. NULL,
  2032. CMD_SCOPE_ANY,
  2033. "maximum request body size ModSecurity will accept, but excluding the size of uploaded files."
  2034. ),
  2035. AP_INIT_TAKE1 (
  2036. "SecRequestEncoding",
  2037. cmd_request_encoding,
  2038. NULL,
  2039. CMD_SCOPE_ANY,
  2040. "character encoding used in request."
  2041. ),
  2042. AP_INIT_TAKE1 (
  2043. "SecResponseBodyAccess",
  2044. cmd_response_body_access,
  2045. NULL,
  2046. CMD_SCOPE_ANY,
  2047. "On or Off"
  2048. ),
  2049. AP_INIT_TAKE1 (
  2050. "SecResponseBodyLimit",
  2051. cmd_response_body_limit,
  2052. NULL,
  2053. CMD_SCOPE_ANY,
  2054. "byte limit for response body"
  2055. ),
  2056. AP_INIT_TAKE1 (
  2057. "SecResponseBodyLimitAction",
  2058. cmd_response_body_limit_action,
  2059. NULL,
  2060. CMD_SCOPE_ANY,
  2061. "what happens when the response body limit is reached"
  2062. ),
  2063. AP_INIT_TAKE1 (
  2064. "SecRequestBodyLimitAction",
  2065. cmd_resquest_body_limit_action,
  2066. NULL,
  2067. CMD_SCOPE_ANY,
  2068. "what happens when the request body limit is reached"
  2069. ),
  2070. AP_INIT_ITERATE (
  2071. "SecResponseBodyMimeType",
  2072. cmd_response_body_mime_type,
  2073. NULL,
  2074. CMD_SCOPE_ANY,
  2075. "adds given MIME types to the list of types that will be buffered on output"
  2076. ),
  2077. AP_INIT_NO_ARGS (
  2078. "SecResponseBodyMimeTypesClear",
  2079. cmd_response_body_mime_types_clear,
  2080. NULL,
  2081. CMD_SCOPE_ANY,
  2082. "clears the list of MIME types that will be buffered on output"
  2083. ),
  2084. AP_INIT_TAKE23 (
  2085. "SecRule",
  2086. cmd_rule,
  2087. NULL,
  2088. CMD_SCOPE_ANY,
  2089. "rule target, operator and optional action list"
  2090. ),
  2091. AP_INIT_TAKE1 (
  2092. "SecRuleEngine",
  2093. cmd_rule_engine,
  2094. NULL,
  2095. CMD_SCOPE_ANY,
  2096. "On or Off"
  2097. ),
  2098. AP_INIT_FLAG (
  2099. "SecRuleInheritance",
  2100. cmd_rule_inheritance,
  2101. NULL,
  2102. CMD_SCOPE_ANY,
  2103. "On or Off"
  2104. ),
  2105. AP_INIT_TAKE12 (
  2106. "SecRuleScript",
  2107. cmd_rule_script,
  2108. NULL,
  2109. CMD_SCOPE_ANY,
  2110. "rule script and optional actionlist"
  2111. ),
  2112. AP_INIT_ITERATE (
  2113. "SecRuleRemoveById",
  2114. cmd_rule_remove_by_id,
  2115. NULL,
  2116. CMD_SCOPE_ANY,
  2117. "rule ID for removal"
  2118. ),
  2119. AP_INIT_ITERATE (
  2120. "SecRuleRemoveByTag",
  2121. cmd_rule_remove_by_tag,
  2122. NULL,
  2123. CMD_SCOPE_ANY,
  2124. "rule tag for removal"
  2125. ),
  2126. AP_INIT_ITERATE (
  2127. "SecRuleRemoveByMsg",
  2128. cmd_rule_remove_by_msg,
  2129. NULL,
  2130. CMD_SCOPE_ANY,
  2131. "rule message for removal"
  2132. ),
  2133. AP_INIT_TAKE2 (
  2134. "SecRuleUpdateActionById",
  2135. cmd_rule_update_action_by_id,
  2136. NULL,
  2137. CMD_SCOPE_ANY,
  2138. "updated action list"
  2139. ),
  2140. AP_INIT_TAKE23 (
  2141. "SecRuleUpdateTargetById",
  2142. cmd_rule_update_target_by_id,
  2143. NULL,
  2144. CMD_SCOPE_ANY,
  2145. "updated target list"
  2146. ),
  2147. AP_INIT_TAKE1 (
  2148. "SecServerSignature",
  2149. cmd_server_signature,
  2150. NULL,
  2151. CMD_SCOPE_MAIN,
  2152. "the new signature of the server"
  2153. ),
  2154. AP_INIT_TAKE1 (
  2155. "SecTmpDir",
  2156. cmd_tmp_dir,
  2157. NULL,
  2158. CMD_SCOPE_ANY,
  2159. "path to the temporary storage area"
  2160. ),
  2161. AP_INIT_TAKE1 (
  2162. "SecUploadDir",
  2163. cmd_upload_dir,
  2164. NULL,
  2165. CMD_SCOPE_ANY,
  2166. "path to the file upload area"
  2167. ),
  2168. AP_INIT_TAKE1 (
  2169. "SecUploadFileLimit",
  2170. cmd_upload_file_limit,
  2171. NULL,
  2172. CMD_SCOPE_ANY,
  2173. "limit the number of uploaded files processed"
  2174. ),
  2175. AP_INIT_TAKE1 (
  2176. "SecUploadFileMode",
  2177. cmd_upload_filemode,
  2178. NULL,
  2179. CMD_SCOPE_ANY,
  2180. "octal permissions mode for uploaded files"
  2181. ),
  2182. AP_INIT_TAKE1 (
  2183. "SecUploadKeepFiles",
  2184. cmd_upload_keep_files,
  2185. NULL,
  2186. CMD_SCOPE_ANY,
  2187. "On or Off"
  2188. ),
  2189. AP_INIT_TAKE1 (
  2190. "SecWebAppId",
  2191. cmd_web_app_id,
  2192. NULL,
  2193. CMD_SCOPE_ANY,
  2194. "id"
  2195. ),
  2196. { NULL }
  2197. };