From 0d02cd5c6d1276db4d425ca186ad28fffcb3ad24 Mon Sep 17 00:00:00 2001 From: Jeff Trawick Date: Sat, 10 Aug 2013 19:50:58 +0000 Subject: [PATCH] Add ap_log_data(), ap_log_rdata(), etc. for logging buffers. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1512819 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 + include/ap_mmn.h | 3 +- include/http_log.h | 173 +++++++++++++++++++++++++++++++++++++++++++++ server/log.c | 135 +++++++++++++++++++++++++++++++++++ 4 files changed, 313 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index a3f31c2e7e..19ed92e886 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) core: Add ap_log_data(), ap_log_rdata(), etc. for logging buffers. + [Jeff Trawick] + *) ab: Fix potential buffer overflows when processing the T and X command-line options. PR 55360. [Mike Rumph ] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index c4f97fb486..608da2caee 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -436,6 +436,7 @@ * 20121222.16 (2.5.0-dev) AP_DEFAULT_HANDLER_NAME/AP_IS_DEAULT_HANDLER_NAME * 20130702.0 (2.5.0-dev) Remove pre_htaccess hook, add open_htaccess hook. * 20130702.1 (2.5.0-dev) Restore AUTH_HANDLED to mod_auth.h + * 20130702.2 (2.5.0-dev) Add ap_log_data(), ap_log_rdata(), etc. */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -443,7 +444,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20130702 #endif -#define MODULE_MAGIC_NUMBER_MINOR 1 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 2 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/http_log.h b/include/http_log.h index 55a883f352..0309bdeefb 100644 --- a/include/http_log.h +++ b/include/http_log.h @@ -552,6 +552,179 @@ AP_DECLARE(void) ap_log_cserror_(const char *file, int line, int module_index, __attribute__((format(printf,8,9))); #endif +/* + * The buffer logging functions, ap_log_data, ap_log_rdata, ap_log_cdata, + * and ap_log_csdata log a buffer in printable and hex format. The exact + * format is controlled by processing flags, describe next. + */ + +/** + * Processing flags for ap_log_data() et al + * + * AP_LOG_DATA_DEFAULT - default formatting, with printable chars and hex + * AP_LOG_DATA_SHOW_OFFSET - prefix each line with hex offset from the start + * of the buffer + */ +#define AP_LOG_DATA_DEFAULT 0 +#define AP_LOG_DATA_SHOW_OFFSET 1 + +/** + * ap_log_data() - log buffers which are not related to a particular request + * or connection. + * @param file The file in which this function is called + * @param line The line number on which this function is called + * @param module_index The module_index of the module logging this buffer + * @param level The log level + * @param s The server on which we are logging + * @param label A label for the buffer, to be logged preceding the buffer + * @param data The buffer to be logged + * @param len The length of the buffer + * @param flags Special processing flags like AP_LOG_DATA_SHOW_OFFSET + * @note ap_log_data is implemented as a macro. + * @note Use APLOG_MARK to fill out file, line, and module_index + * @note If a request_rec is available, use that with ap_log_rerror() + * in preference to calling this function. Otherwise, if a conn_rec is + * available, use that with ap_log_cerror() in preference to calling + * this function. + */ +#ifdef DOXYGEN +AP_DECLARE(void) ap_log_data(const char *file, int line, int module_index, + int level, const server_rec *s, const char *label, + const void *data, apr_size_t len, unsigned int flags); +#else +#ifdef AP_HAVE_C99 +/* need additional step to expand APLOG_MARK first */ +#define ap_log_data(...) ap_log_data__(__VA_ARGS__) +/* need server_rec *sr = ... for the case if s is verbatim NULL */ +#define ap_log_data__(file, line, mi, level, s, ...) \ + do { const server_rec *sr__ = s; if (APLOG_MODULE_IS_LEVEL(sr__, mi, level)) \ + ap_log_data_(file, line, mi, level, sr__, __VA_ARGS__); \ + } while(0) +#else +#define ap_log_data ap_log_data_ +#endif +AP_DECLARE(void) ap_log_data_(const char *file, int line, int module_index, + int level, const server_rec *s, const char *label, + const void *data, apr_size_t len, unsigned int flags); +#endif + +/** + * ap_log_rdata() - log buffers which are related to a particular request. + * @param file The file in which this function is called + * @param line The line number on which this function is called + * @param module_index The module_index of the module logging this buffer + * @param level The log level + * @param r The request which we are logging for + * @param label A label for the buffer, to be logged preceding the buffer + * @param data The buffer to be logged + * @param len The length of the buffer + * @param flags Special processing flags like AP_LOG_DATA_SHOW_OFFSET + * @note ap_log_rdata is implemented as a macro. + * @note Use APLOG_MARK to fill out file, line, and module_index + * @note If a request_rec is available, use that with ap_log_rerror() + * in preference to calling this function. Otherwise, if a conn_rec is + * available, use that with ap_log_cerror() in preference to calling + * this function. + */ +#ifdef DOXYGEN +AP_DECLARE(void) ap_log_rdata(const char *file, int line, int module_index, + int level, const request_rec *r, const char *label, + const void *data, apr_size_t len, unsigned int flags); +#else +#ifdef AP_HAVE_C99 +/* need additional step to expand APLOG_MARK first */ +#define ap_log_rdata(...) ap_log_rdata__(__VA_ARGS__) +#define ap_log_rdata__(file, line, mi, level, s, ...) \ + do { if (APLOG_R_MODULE_IS_LEVEL(r, mi, level)) \ + ap_log_rdata_(file, line, mi, level, r, __VA_ARGS__); \ + } while(0) +#else +#define ap_log_rdata ap_log_rdata_ +#endif +AP_DECLARE(void) ap_log_rdata_(const char *file, int line, int module_index, + int level, const request_rec *r, const char *label, + const void *data, apr_size_t len, unsigned int flags); +#endif + +/** + * ap_log_cdata() - log buffers which are related to a particular connection. + * @param file The file in which this function is called + * @param line The line number on which this function is called + * @param module_index The module_index of the module logging this buffer + * @param level The log level + * @param c The connection which we are logging for + * @param label A label for the buffer, to be logged preceding the buffer + * @param data The buffer to be logged + * @param len The length of the buffer + * @param flags Special processing flags like AP_LOG_DATA_SHOW_OFFSET + * @note ap_log_cdata is implemented as a macro + * @note Use APLOG_MARK to fill out file, line, and module_index + * @note If a request_rec is available, use that with ap_log_rerror() + * in preference to calling this function. Otherwise, if a conn_rec is + * available, use that with ap_log_cerror() in preference to calling + * this function. + */ +#ifdef DOXYGEN +AP_DECLARE(void) ap_log_cdata(const char *file, int line, int module_index, + int level, const conn_rec *c, const char *label, + const void *data, apr_size_t len, unsigned int flags); +#else +#ifdef AP_HAVE_C99 +/* need additional step to expand APLOG_MARK first */ +#define ap_log_cdata(...) ap_log_cdata__(__VA_ARGS__) +#define ap_log_cdata__(file, line, mi, level, c, ...) \ + do { if (APLOG_C_MODULE_IS_LEVEL(c, mi, level)) \ + ap_log_cdata_(file, line, mi, level, c, __VA_ARGS__); \ + } while(0) +#else +#define ap_log_cdata ap_log_cdata_ +#endif +AP_DECLARE(void) ap_log_cdata_(const char *file, int line, int module_index, + int level, const conn_rec *c, const char *label, + const void *data, apr_size_t len, unsigned int flags); +#endif + +/** + * ap_log_csdata() - log buffers which are related to a particular connection + * and to a vhost other than c->base_server. + * @param file The file in which this function is called + * @param line The line number on which this function is called + * @param module_index The module_index of the module logging this buffer + * @param level The log level + * @param c The connection which we are logging for + * @param label A label for the buffer, to be logged preceding the buffer + * @param data The buffer to be logged + * @param len The length of the buffer + * @param flags Special processing flags like AP_LOG_DATA_SHOW_OFFSET + * @note ap_log_csdata is implemented as a macro + * @note Use APLOG_MARK to fill out file, line, and module_index + * @note If a request_rec is available, use that with ap_log_rerror() + * in preference to calling this function. Otherwise, if a conn_rec is + * available, use that with ap_log_cerror() in preference to calling + * this function. + */ +#ifdef DOXYGEN +AP_DECLARE(void) ap_log_csdata(const char *file, int line, int module_index, + int level, const conn_rec *c, const server_rec *s, + const char *label, const void *data, + apr_size_t len, unsigned int flags); +#else +#ifdef AP_HAVE_C99 +/* need additional step to expand APLOG_MARK first */ +#define ap_log_csdata(...) ap_log_csdata__(__VA_ARGS__) +#define ap_log_csdata__(file, line, mi, level, c, s, ...) \ + do { if (APLOG_CS_MODULE_IS_LEVEL(c, s, mi, level)) \ + ap_log_csdata_(file, line, mi, level, c, s, __VA_ARGS__); \ + } while(0) +#else +#define ap_log_cdata ap_log_cdata_ +#endif +AP_DECLARE(void) ap_log_csdata_(const char *file, int line, int module_index, + int level, const conn_rec *c, const server_rec *s, + const char *label, const void *data, + apr_size_t len, unsigned int flags); +#endif + /** * Convert stderr to the error log * @param s The current server diff --git a/server/log.c b/server/log.c index 5b905c62d1..161cc9d334 100644 --- a/server/log.c +++ b/server/log.c @@ -1288,6 +1288,21 @@ static void log_error_core(const char *file, int line, int module_index, } } +/* For internal calls to log_error_core with self-composed arg lists */ +static void log_error_va_glue(const char *file, int line, int module_index, + int level, apr_status_t status, + const server_rec *s, const conn_rec *c, + const request_rec *r, apr_pool_t *pool, + const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + log_error_core(file, line, module_index, level, status, s, c, r, pool, + fmt, args); + va_end(args); +} + AP_DECLARE(void) ap_log_error_(const char *file, int line, int module_index, int level, apr_status_t status, const server_rec *s, const char *fmt, ...) @@ -1366,6 +1381,126 @@ AP_DECLARE(void) ap_log_cerror_(const char *file, int line, int module_index, va_end(args); } +#define BYTES_LOGGED_PER_LINE 16 +#define LOG_BYTES_BUFFER_SIZE (BYTES_LOGGED_PER_LINE * 3 + 2) + +static void fmt_data(unsigned char *buf, const void *vdata, apr_size_t len, apr_size_t *off) +{ + const unsigned char *data = (const unsigned char *)vdata; + unsigned char *chars; + unsigned char *hex; + apr_size_t this_time = 0; + + memset(buf, ' ', LOG_BYTES_BUFFER_SIZE - 1); + buf[LOG_BYTES_BUFFER_SIZE - 1] = '\0'; + + chars = buf; /* start character dump here */ + hex = buf + BYTES_LOGGED_PER_LINE + 1; /* start hex dump here */ + while (*off < len && this_time < BYTES_LOGGED_PER_LINE) { + unsigned char c = data[*off]; + + if (apr_isprint(c)) { + *chars = c; + } + else { + *chars = '.'; + } + + if ((c >> 4) >= 10) { + *hex = 'a' + ((c >> 4) - 10); + } + else { + *hex = '0' + (c >> 4); + } + + if ((c & 0x0F) >= 10) { + *(hex + 1) = 'a' + ((c & 0x0F) - 10); + } + else { + *(hex + 1) = '0' + (c & 0x0F); + } + + chars += 1; + hex += 2; + *off += 1; + ++this_time; + } +} + +static void log_data_core(const char *file, int line, int module_index, + int level, const server_rec *s, + const conn_rec *c, const request_rec *r, + const char *label, const void *data, apr_size_t len, + unsigned int flags) +{ + unsigned char buf[LOG_BYTES_BUFFER_SIZE]; + apr_size_t off; + char prefix[20]; + + if (!(flags & AP_LOG_DATA_SHOW_OFFSET)) { + prefix[0] = '\0'; + } + + if (len > 0xffff) { /* bug in caller? */ + len = 0xffff; + } + + if (label) { + log_error_va_glue(file, line, module_index, level, APR_SUCCESS, s, + c, r, NULL, "%s (%" APR_SIZE_T_FMT " bytes)", + label, len); + } + + off = 0; + while (off < len) { + if (flags & AP_LOG_DATA_SHOW_OFFSET) { + apr_snprintf(prefix, sizeof prefix, "%04x: ", (unsigned int)off); + } + fmt_data(buf, data, len, &off); + log_error_va_glue(file, line, module_index, level, APR_SUCCESS, s, + c, r, NULL, "%s%s", prefix, buf); + } +} + +AP_DECLARE(void) ap_log_data_(const char *file, int line, + int module_index, int level, + const server_rec *s, const char *label, + const void *data, apr_size_t len, + unsigned int flags) +{ + log_data_core(file, line, module_index, level, s, NULL, NULL, label, + data, len, flags); +} + +AP_DECLARE(void) ap_log_rdata_(const char *file, int line, + int module_index, int level, + const request_rec *r, const char *label, + const void *data, apr_size_t len, + unsigned int flags) +{ + log_data_core(file, line, module_index, level, r->server, NULL, r, label, + data, len, flags); +} + +AP_DECLARE(void) ap_log_cdata_(const char *file, int line, + int module_index, int level, + const conn_rec *c, const char *label, + const void *data, apr_size_t len, + unsigned int flags) +{ + log_data_core(file, line, module_index, level, c->base_server, c, NULL, + label, data, len, flags); +} + +AP_DECLARE(void) ap_log_csdata_(const char *file, int line, int module_index, + int level, const conn_rec *c, const server_rec *s, + const char *label, const void *data, + apr_size_t len, unsigned int flags) +{ + log_data_core(file, line, module_index, level, s, c, NULL, label, data, + len, flags); +} + AP_DECLARE(void) ap_log_command_line(apr_pool_t *plog, server_rec *s) { int i; -- 2.50.1