You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Dean Gaudet <dg...@hotwired.com> on 1995/12/18 21:46:06 UTC
Re: Possible security problem in referer_log_transaction... ? (fwd)
In HotWired's server I use a hacked up mod_log_common called
mod_log_unified. It's more or less identical except for the actual
routine which writes the log entry. I deal with:
- unprintable characters
- use of field delimiters in client-supplied data
- limiting length of client-supplied data
Sorry, it's not a patch.
It also assumes that sprintf returns the number of bytes written.
Just say NO to lame extern char *sprintf();. But you might find the
sanitize_string routine useful.
Dean
/* I've used this routine under this name since I learned how to program in
C under Lattice C for the Amiga. I don't know if they're the original
source of the routine... but anyhow, it's strcpy that returns a
pointer to the zero byte of dest, which is way more useful than
returning dest itself. -djg */
char *stpcpy( char *dest, const char *src )
{
while( *dest = *src ) {
++dest;
++src;
}
return( dest );
}
char *sanitize_string( char *dest, const char *src, size_t len )
{
static const char hex[] = "0123456789ABCDEF";
char *d;
d = dest;
while( *src ) {
if( !isprint( *src ) || *src == '"' || *src == '%' || *src == '*' ) {
/* use % escape to write it, we need at least 3 characters to
do the escape, and possibly one more if there's more to src */
if( d - dest >= len - 3 - ( src[1] != 0 ) ) break;
*d++ = '%';
*d++ = hex[ (unsigned)*src / 16 ];
*d++ = hex[ (unsigned)*src % 16 ];
} else {
if( d - dest >= len - 1 - ( src[1] != 0 ) ) break;
*d++ = *src;
}
++src;
}
if( *src ) {
*d++ = '*';
}
*d = 0;
return( d );
}
int unified_log_transaction(request_rec *orig)
{
unified_log_state *cls = get_module_config (orig->server->module_config,
&unified_log_module);
char str[HUGE_STRING_LEN];
long timz;
struct tm *t;
char sign;
char tstr[MAX_STRING_LEN];
conn_rec *c = orig->connection;
request_rec *r;
char *p;
char *header;
size_t l;
/* Common log format records an unholy melange of the original request
* and whatever it was that we actually served. Just stay compatible
* here; the whole point of the module scheme is to allow people to
* create better alternatives, but screwing up is an option we wish
* to preserve...
*/
for (r = orig; r->next; r = r->next)
continue;
t = get_gmtoff(&timz);
sign = (timz < 0 ? '-' : '+');
if(timz < 0)
timz = -timz;
strftime(tstr,MAX_STRING_LEN,"%d/%b/%Y:%H:%M:%S",t);
p = stpcpy( str, c->remote_name );
*p++ = ' ';
p = stpcpy( p, (c->remote_logname ? c->remote_logname : "-") );
*p++ = ' ';
p = stpcpy( p, (c->user ? c->user : "-") );
*p++ = ' ';
*p++ = '[';
p = stpcpy( p, tstr );
*p++ = ' ';
*p++ = sign;
p += sprintf( p, "%02ld%02ld] \"", timz/3600, timz%3600 );
if( orig->the_request ) p = sanitize_string( p, orig->the_request, 512 );
*p++ = '"';
*p++ = ' ';
if (r->status != -1) {
p += sprintf(p,"%d ",r->status);
} else {
*p++ = '-';
*p++ = ' ';
}
if(r->bytes_sent != -1) {
p += sprintf(p,"%d ",r->bytes_sent);
} else {
*p++ = '-';
*p++ = ' ';
}
header = table_get( orig->headers_in, "Referer" );
if( header ) {
l = strlen( r->uri );
/* we don't want to record refers due to <IMG> tags */
if( ( l >= 4 && strcmp( r->uri + l - 4, ".gif" ) == 0 )
|| ( l >= 4 && strcmp( r->uri + l - 4, ".jpg" ) == 0 )
|| ( l >= 5 && strcmp( r->uri + l - 5, ".jpeg" ) == 0 ) ) {
header = NULL;
} else if( strncmp( header, "file:", 5 ) == 0 ) {
header = NULL;
}
}
if( header ) {
*p++ = '"';
p = sanitize_string( p, header, 512 );
*p++ = '"';
} else {
*p++ = '-';
}
*p++ = ' ';
#if 0
header = table_get( orig->headers_in, "User-Agent" );
if( header ) {
*p++ = '"';
p = sanitize_string( p, header, 512 );
*p++ = '"';
} else {
*p++ = '-';
}
#else
*p++ = '-';
#endif
*p++ = '\n';
write(cls->log_fd, str, p - str);
return OK;
}