diff --git a/CHANGES b/CHANGES index 9e535ec0..b3c1a642 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,11 @@ -12 Aug 2009 - 2.5.10-dev3 +24 Aug 2009 - 2.5.10-dev3 ------------------------- + * Added SecAuditLogDirMode and SecAuditLogFileMode to allow fine tuning + auditlog permissions (especially with mpm-itk). + + * Cleaned up SecUploadFileMode implementation. + * Cleanup build scripts. diff --git a/apache2/apache2.h b/apache2/apache2.h index d8d61568..264fcf44 100644 --- a/apache2/apache2.h +++ b/apache2/apache2.h @@ -103,5 +103,6 @@ char DSOLOCAL *format_error_log_message(apr_pool_t *mp, error_message *em); const DSOLOCAL char *get_response_protocol(request_rec *r); + #endif diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 67e6e995..bbb51366 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -20,6 +20,7 @@ #include "modsecurity.h" #include "msc_logging.h" +#include "msc_util.h" #include "pdf_protect.h" #include "http_log.h" @@ -69,6 +70,8 @@ void *create_directory_config(apr_pool_t *mp, char *path) { /* audit log variables */ dcfg->auditlog_flag = NOT_SET; dcfg->auditlog_type = NOT_SET; + dcfg->auditlog_dirperms = NOT_SET; + dcfg->auditlog_fileperms = NOT_SET; dcfg->auditlog_name = NOT_SET_P; dcfg->auditlog2_name = NOT_SET_P; dcfg->auditlog_fd = NOT_SET_P; @@ -388,6 +391,10 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) { ? parent->auditlog_flag : child->auditlog_flag); merged->auditlog_type = (child->auditlog_type == NOT_SET ? parent->auditlog_type : child->auditlog_type); + merged->auditlog_dirperms = (child->auditlog_dirperms == NOT_SET + ? parent->auditlog_dirperms : child->auditlog_dirperms); + merged->auditlog_fileperms = (child->auditlog_fileperms == NOT_SET + ? parent->auditlog_fileperms : child->auditlog_fileperms); if (child->auditlog_fd != NOT_SET_P) { merged->auditlog_fd = child->auditlog_fd; merged->auditlog_name = child->auditlog_name; @@ -512,6 +519,8 @@ void init_directory_config(directory_config *dcfg) { /* audit log variables */ if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0; if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL; + if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR; + if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE; if (dcfg->auditlog_fd == NOT_SET_P) dcfg->auditlog_fd = NULL; if (dcfg->auditlog2_fd == NOT_SET_P) dcfg->auditlog2_fd = NULL; if (dcfg->auditlog_name == NOT_SET_P) dcfg->auditlog_name = NULL; @@ -525,7 +534,7 @@ void init_directory_config(directory_config *dcfg) { if (dcfg->upload_dir == NOT_SET_P) dcfg->upload_dir = NULL; if (dcfg->upload_keep_files == NOT_SET) dcfg->upload_keep_files = KEEP_FILES_OFF; if (dcfg->upload_validates_files == NOT_SET) dcfg->upload_validates_files = 0; - if (dcfg->upload_filemode == NOT_SET) dcfg->upload_filemode = 0600; + if (dcfg->upload_filemode == NOT_SET) dcfg->upload_filemode = mode2fileperms(0600); /* Misc */ if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL; @@ -1026,6 +1035,46 @@ static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg, const char *p return NULL; } +static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "default") == 0) { + dcfg->auditlog_dirperms = NOT_SET; + } + else { + long int mode = strtol(p1, NULL, 8); /* expects octal mode */ + if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogDirMode: %s", p1); + } + + dcfg->auditlog_dirperms = mode2fileperms((mode_t)mode); + } + + return NULL; +} + +static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg, const char *p1) { + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "default") == 0) { + dcfg->auditlog_fileperms = NOT_SET; + } + else { + long int mode = strtol(p1, NULL, 8); /* expects octal mode */ + if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogFileMode: %s", p1); + } + + dcfg->auditlog_fileperms = mode2fileperms((mode_t)mode); + } + + return NULL; +} + static const char *cmd_audit_log_storage_dir(cmd_parms *cmd, void *_dcfg, const char *p1) { directory_config *dcfg = _dcfg; @@ -1541,7 +1590,7 @@ static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg, const char * } else { long int mode = strtol(p1, NULL, 8); /* expects octal mode */ - if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 0777)) { + if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) { return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecUploadFileMode: %s", p1); } @@ -1854,6 +1903,22 @@ const command_rec module_directives[] = { "path to the audit log storage area; absolute, or relative to the root of the server" ), + AP_INIT_TAKE1 ( + "SecAuditLogDirMode", + cmd_audit_log_dirmode, + NULL, + CMD_SCOPE_ANY, + "octal permissions mode for concurrent audit log directories" + ), + + AP_INIT_TAKE1 ( + "SecAuditLogFileMode", + cmd_audit_log_filemode, + NULL, + CMD_SCOPE_ANY, + "octal permissions mode for concurrent audit log files" + ), + AP_INIT_TAKE12 ( "SecCacheTransformations", cmd_cache_transformations, diff --git a/apache2/configure b/apache2/configure index 95fef315..b70d0a71 100755 --- a/apache2/configure +++ b/apache2/configure @@ -3812,7 +3812,9 @@ done -for ac_header in fcntl.h limits.h stdlib.h string.h unistd.h + + +for ac_header in fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h do as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then @@ -4905,8 +4907,7 @@ esac - -for ac_func in atexit fchmod getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol +for ac_func in atexit getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 diff --git a/apache2/configure.in b/apache2/configure.in index d43da780..37241fa7 100644 --- a/apache2/configure.in +++ b/apache2/configure.in @@ -26,7 +26,7 @@ AC_PATH_PROGS(ENV_CMD, [env printenv], ) # Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h]) +AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -40,7 +40,7 @@ AC_TYPE_UINT8_T # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_MEMCMP -AC_CHECK_FUNCS([atexit fchmod getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol]) +AC_CHECK_FUNCS([atexit getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol]) # Some directories MSC_BASE_DIR=`pwd` diff --git a/apache2/mod_security2_config.h.in b/apache2/mod_security2_config.h.in index e6a70445..0d2ea15d 100644 --- a/apache2/mod_security2_config.h.in +++ b/apache2/mod_security2_config.h.in @@ -3,9 +3,6 @@ /* Define to 1 if you have the `atexit' function. */ #undef HAVE_ATEXIT -/* Define to 1 if you have the `fchmod' function. */ -#undef HAVE_FCHMOD - /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 61c301e9..489d50ad 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -392,6 +392,10 @@ struct directory_config { /* AUDITLOG_SERIAL (single file) or AUDITLOG_CONCURRENT (multiple files) */ int auditlog_type; + /* Mode for audit log directories and files */ + apr_fileperms_t auditlog_dirperms; + apr_fileperms_t auditlog_fileperms; + /* The name of the audit log file (for the old type), or the * name of the index file (for the new audit log type) */ @@ -425,7 +429,7 @@ struct directory_config { const char *upload_dir; int upload_keep_files; int upload_validates_files; - int upload_filemode; + int upload_filemode; /* int only so NOT_SET works */ /* Used only in the configuration phase. */ msre_rule *tmp_chain_starter; diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 4d1609bc..956f31b5 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -16,6 +16,9 @@ * directly using the email address support@breach.com. * */ +#include + +#include "mod_security2_config.h" #include "re.h" #include "msc_logging.h" #include "httpd.h" @@ -443,7 +446,7 @@ void sec_audit_logger(modsec_rec *msr) { * we could cache the time we last checked and don't check if we know * the folder is there. */ - rc = apr_dir_make_recursive(entry_basename, CREATEMODE_DIR, msr->mp); + rc = apr_dir_make_recursive(entry_basename, msr->txcfg->auditlog_dirperms, msr->mp); if (rc != APR_SUCCESS) { msr_log(msr, 1, "Audit log: Failed to create subdirectories: %s (%s)", entry_basename, get_apr_error(msr->mp, rc)); @@ -452,7 +455,7 @@ void sec_audit_logger(modsec_rec *msr) { rc = apr_file_open(&msr->new_auditlog_fd, entry_filename, APR_WRITE | APR_TRUNCATE | APR_CREATE | APR_BINARY | APR_FILE_NOCLEANUP, - CREATEMODE, msr->mp); + msr->txcfg->auditlog_fileperms, msr->mp); if (rc != APR_SUCCESS) { msr_log(msr, 1, "Audit log: Failed to create file: %s (%s)", entry_filename, get_apr_error(msr->mp, rc)); diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index d63acf86..c87f7d1b 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -396,7 +396,7 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) { /* construct temporary file name */ msr->mpd->mpp->tmp_file_name = apr_psprintf(msr->mp, "%s/%s-%s-file-XXXXXX", msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid); - msr->mpd->mpp->tmp_file_fd = msc_mkstemp(msr->mpd->mpp->tmp_file_name); + msr->mpd->mpp->tmp_file_fd = msc_mkstemp_ex(msr->mpd->mpp->tmp_file_name, msr->txcfg->upload_filemode); /* do we have an opened file? */ if (msr->mpd->mpp->tmp_file_fd < 0) { @@ -409,21 +409,6 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) { msr_log(msr, 4, "Multipart: Created temporary file: %s", log_escape_nq(msr->mp, msr->mpd->mpp->tmp_file_name)); } - - #ifdef HAVE_FCHMOD - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "Multipart: Changing file mode to %04o: %s", msr->txcfg->upload_filemode, log_escape_nq(msr->mp, msr->mpd->mpp->tmp_file_name)); - } - if (fchmod(msr->mpd->mpp->tmp_file_fd, msr->txcfg->upload_filemode) < 0) { - - char errbuf[256]; - if (msr->txcfg->debuglog_level >= 3) { - msr_log(msr, 3, "Multipart: Could not change mode on \"%s\" (%d): %s", - log_escape_nq(msr->mp, msr->mpd->mpp->tmp_file_name), - errno, apr_strerror(APR_FROM_OS_ERROR(errno), errbuf, 256)); - } - } - #endif } /* write the reserve first */ diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 637eebbb..c7e40c66 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -418,17 +418,24 @@ char *current_filetime(apr_pool_t *mp) { /** * */ -int msc_mkstemp(char *template) { +int msc_mkstemp_ex(char *template, mode_t mode) { /* ENH Use apr_file_mktemp instead. */ #if !(defined(WIN32)||defined(NETWARE)) return mkstemp(template); #else if (mktemp(template) == NULL) return -1; - return open(template, O_WRONLY | O_APPEND | O_CREAT | O_BINARY, CREATEMODE_UNISTD); + return open(template, O_WRONLY | O_APPEND | O_CREAT | O_BINARY, mode); #endif } +/** + * + */ +int msc_mkstemp(char *template) { + return msc_mkstemp_ex(template, CREATEMODE_UNISTD); +} + /** * Converts the input string to lowercase (in-place). */ @@ -1351,3 +1358,26 @@ int css_decode_inplace(unsigned char *input, long int input_len) { return count; } + +/** + * Translate UNIX octal umask/mode to APR apr_fileperms_t + */ +apr_fileperms_t mode2fileperms(mode_t mode) { + apr_fileperms_t perms = 0; + + if (mode & S_IXOTH) perms |= APR_WEXECUTE; + if (mode & S_IWOTH) perms |= APR_WWRITE; + if (mode & S_IROTH) perms |= APR_WREAD; + if (mode & S_IXGRP) perms |= APR_GEXECUTE; + if (mode & S_IWGRP) perms |= APR_GWRITE; + if (mode & S_IRGRP) perms |= APR_GREAD; + if (mode & S_IXUSR) perms |= APR_UEXECUTE; + if (mode & S_IWUSR) perms |= APR_UWRITE; + if (mode & S_IRUSR) perms |= APR_UREAD; + if (mode & S_ISVTX) perms |= APR_WSTICKY; + if (mode & S_ISGID) perms |= APR_GSETID; + if (mode & S_ISUID) perms |= APR_USETID; + + return perms; +} + diff --git a/apache2/msc_util.h b/apache2/msc_util.h index f2797362..6811cff1 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -19,6 +19,9 @@ #ifndef _UTIL_H_ #define _UTIL_H_ +#include +#include + #include "modsecurity.h" int DSOLOCAL normalise_path_inplace(unsigned char *input, int len, int win, int *changed); @@ -53,6 +56,8 @@ char DSOLOCAL *current_logtime(apr_pool_t *mp); char DSOLOCAL *current_filetime(apr_pool_t *mp); +int DSOLOCAL msc_mkstemp_ex(char *template, mode_t mode); + int DSOLOCAL msc_mkstemp(char *template); char DSOLOCAL *strtolower_inplace(unsigned char *str); @@ -94,4 +99,6 @@ char DSOLOCAL *resolve_relative_path(apr_pool_t *pool, const char *parent_filena int DSOLOCAL css_decode_inplace(unsigned char *input, long int input_len); +apr_fileperms_t DSOLOCAL mode2fileperms(mode_t mode); + #endif diff --git a/doc/modsecurity2-apache-reference.xml b/doc/modsecurity2-apache-reference.xml index 429b855b..798c7b34 100644 --- a/doc/modsecurity2-apache-reference.xml +++ b/doc/modsecurity2-apache-reference.xml @@ -6,7 +6,7 @@ Manual - Version 2.5.10-dev2 (Aug 12, 2009) + Version 2.5.10-dev3 (Aug 24, 2009) 2004-2009 @@ -698,6 +698,79 @@ SecAuditLogStorageDir logs/audit audit logging. +
+ <literal>SecAuditLogDirMode</literal> + + Description: Configures the mode + (permissions) of any directories created for concurrent audit logs using + an octal mode (as used in chmod). See SecAuditLogFileMode for controlling the mode + of audit log files. + + Syntax: SecAuditLogDirMode octal_mode|"default" + + Example Usage: SecAuditLogDirMode 02750 + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.10 + + Dependencies/Notes: This feature is not + available on operating systems not supporting octal file modes. The + default mode (0600) only grants read/write access to the account writing + the file. If access from another account is needed (using mpm-itk is a + good example), then this directive may be required. However, use this + directive with caution to avoid exposing potentially sensitive data to + unauthorized users. Using the value "default" will revert back to the + default setting. + + + The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive. + +
+ +
+ <literal>SecAuditLogFileMode</literal> + + Description: Configures the mode + (permissions) of any files created for concurrent audit logs using an + octal mode (as used in chmod). See SecAuditLogDirMode for controlling the mode of + created audit log directories. + + Syntax: SecAuditLogFileMode + octal_mode|"default" + + Example Usage: SecAuditLogFileMode 00640 + + Processing Phase: N/A + + Scope: Any + + Version: 2.5.10 + + Dependencies/Notes: This feature is not + available on operating systems not supporting octal file modes. The + default mode (0600) only grants read/write access to the account writing + the file. If access from another account is needed (using mpm-itk is a + good example), then this directive may be required. However, use this + directive with caution to avoid exposing potentially sensitive data to + unauthorized users. Using the value "default" will revert back to the + default setting. + + + The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive. + +
+
<literal>SecAuditLogParts</literal> @@ -2400,7 +2473,7 @@ SecRuleUpdateActionById 12345 "t:compressWhitespace,deny,status:403,msg:'A new m <literal>SecUploadFileMode</literal> Description: Configures the mode - (permissions) of any uploaded files using an octal number (as used in + (permissions) of any uploaded files using an octal mode (as used in chmod). Syntax: + + + The process umask may still limit the mode if it is being more + restrictive than the mode set using this directive. +
@@ -4757,9 +4835,9 @@ setvar:session.suspicious=1,expirevar:session.suspicious=3600Note - Normally you will want to use phase:1 - along with initcol so that the collection is - available in all phases. + Normally you will want to use phase:1 along + with initcol so that the collection is available in + all phases. Collections are loaded into memory when the initcol action is encountered. The collection in storage will be persisted (and the