[Remove entries to the current 2.0 section below, when backported]
+ *) SECURITY [CAN-2003-0020]: Escape arbitrary data before writing
+ into the errorlog. [André Malo]
+
*) mod_expires: Initialize ExpiresDefault to NULL instead of "" to
avoid reporting an Internal Server error if it is used without
having been set in the httpd.conf file. PR: 23748, 24459
* handler
* 20030821 (2.1.0-dev) bumped mod_include's entire API
* 20030821.1 (2.1.0-dev) added XHTML doctypes
+ * 20030821.2 (2.1.0-dev) added ap_escape_errorlog_item
*/
#define MODULE_MAGIC_COOKIE 0x41503230UL /* "AP20" */
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20030821
#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
/**
* Escape a string for logging
* @param p The pool to allocate from
- * @param s The string to escape
+ * @param str The string to escape
* @return The escaped string
*/
AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str);
+/**
+ * Escape a string for logging into the error log (without a pool)
+ * @param dest The buffer to write to
+ * @param source The string to escape
+ * @param maxlen The buffer size for the escaped string (including \0)
+ * @return The len of the escaped string (always < maxlen)
+ */
+AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
+ apr_size_t buflen);
+
/**
* Construct a full hostname
* @param p The pool to allocate from
const request_rec *r, apr_pool_t *pool,
const char *fmt, va_list args)
{
- char errstr[MAX_STRING_LEN];
+ char errstr[MAX_STRING_LEN], scratch[MAX_STRING_LEN];
apr_size_t len, errstrlen;
apr_file_t *logf = NULL;
const char *referer;
errstr[len] = '\0';
}
}
+
errstrlen = len;
- len += apr_vsnprintf(errstr + len, MAX_STRING_LEN - len, fmt, args);
+ if (apr_vsnprintf(scratch, MAX_STRING_LEN - len, fmt, args)) {
+ len += ap_escape_errorlog_item(errstr + len, scratch,
+ MAX_STRING_LEN - len);
+ }
- if (r && (referer = apr_table_get(r->headers_in, "Referer"))) {
+ if ( r && (referer = apr_table_get(r->headers_in, "Referer"))
+ && ap_escape_errorlog_item(scratch, referer, MAX_STRING_LEN - len)) {
len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
- ", referer: %s", referer);
+ ", referer: %s", scratch);
}
/* NULL if we are logging to syslog */
return ret;
}
+AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source,
+ apr_size_t buflen)
+{
+ unsigned char *d, *ep;
+ const unsigned char *s;
+
+ if (!source || !buflen) { /* be safe */
+ return 0;
+ }
+
+ d = (unsigned char *)dest;
+ s = (const unsigned char *)source;
+ ep = d + buflen - 1;
+
+ for (; d < ep && *s; ++s) {
+
+ if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) {
+ *d++ = '\\';
+ if (d >= ep) {
+ --d;
+ break;
+ }
+
+ switch(*s) {
+ case '\b':
+ *d++ = 'b';
+ break;
+ case '\n':
+ *d++ = 'n';
+ break;
+ case '\r':
+ *d++ = 'r';
+ break;
+ case '\t':
+ *d++ = 't';
+ break;
+ case '\v':
+ *d++ = 'v';
+ break;
+ case '\\':
+ *d++ = *s;
+ break;
+ case '"': /* no need for this in error log */
+ d[-1] = *s;
+ break;
+ default:
+ if (d >= ep - 2) {
+ ep = --d; /* break the for loop as well */
+ break;
+ }
+ c2x(*s, d);
+ *d = 'x';
+ d += 3;
+ }
+ }
+ else {
+ *d++ = *s;
+ }
+ }
+ *d = '\0';
+
+ return (d - (unsigned char *)dest);
+}
+
AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path)
{
apr_finfo_t finfo;