Fix mixed indentation.
This file uses a mix of tab styles, which gcc6 will warn about because it sees "misleading indentation". Fix the function where this happens. Fixes #12759.
This commit is contained in:
@@ -201,168 +201,168 @@ static long long atoll( const char* str );
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
check_options( void )
|
check_options( void )
|
||||||
{
|
{
|
||||||
#if defined(TILDE_MAP_1) && defined(TILDE_MAP_2)
|
#if defined(TILDE_MAP_1) && defined(TILDE_MAP_2)
|
||||||
// syslog( LOG_CRIT, "both TILDE_MAP_1 and TILDE_MAP_2 are defined" );
|
// syslog( LOG_CRIT, "both TILDE_MAP_1 and TILDE_MAP_2 are defined" );
|
||||||
exit( 1 );
|
exit( 1 );
|
||||||
#endif /* both */
|
#endif /* both */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_httpd_server( httpd_server* hs )
|
free_httpd_server( httpd_server* hs )
|
||||||
{
|
{
|
||||||
if ( hs->binding_hostname != (char*) 0 )
|
if ( hs->binding_hostname != (char*) 0 )
|
||||||
free( (void*) hs->binding_hostname );
|
free( (void*) hs->binding_hostname );
|
||||||
if ( hs->cwd != (char*) 0 )
|
if ( hs->cwd != (char*) 0 )
|
||||||
free( (void*) hs->cwd );
|
free( (void*) hs->cwd );
|
||||||
if ( hs->cgi_pattern != (char*) 0 )
|
if ( hs->cgi_pattern != (char*) 0 )
|
||||||
free( (void*) hs->cgi_pattern );
|
free( (void*) hs->cgi_pattern );
|
||||||
if ( hs->charset != (char*) 0 )
|
if ( hs->charset != (char*) 0 )
|
||||||
free( (void*) hs->charset );
|
free( (void*) hs->charset );
|
||||||
if ( hs->p3p != (char*) 0 )
|
if ( hs->p3p != (char*) 0 )
|
||||||
free( (void*) hs->p3p );
|
free( (void*) hs->p3p );
|
||||||
if ( hs->url_pattern != (char*) 0 )
|
if ( hs->url_pattern != (char*) 0 )
|
||||||
free( (void*) hs->url_pattern );
|
free( (void*) hs->url_pattern );
|
||||||
if ( hs->local_pattern != (char*) 0 )
|
if ( hs->local_pattern != (char*) 0 )
|
||||||
free( (void*) hs->local_pattern );
|
free( (void*) hs->local_pattern );
|
||||||
free( (void*) hs );
|
free( (void*) hs );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
httpd_server*
|
httpd_server*
|
||||||
httpd_initialize(
|
httpd_initialize(
|
||||||
char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P,
|
char* hostname, httpd_sockaddr* sa4P, httpd_sockaddr* sa6P,
|
||||||
unsigned short port, char* cgi_pattern, int cgi_limit, char* charset,
|
unsigned short port, char* cgi_pattern, int cgi_limit, char* charset,
|
||||||
char* p3p, int max_age, char* cwd, int no_log, FILE* logfp,
|
char* p3p, int max_age, char* cwd, int no_log, FILE* logfp,
|
||||||
int no_symlink_check, int vhost, int global_passwd, char* url_pattern,
|
int no_symlink_check, int vhost, int global_passwd, char* url_pattern,
|
||||||
char* local_pattern, int no_empty_referers )
|
char* local_pattern, int no_empty_referers )
|
||||||
{
|
{
|
||||||
httpd_server* hs;
|
httpd_server* hs;
|
||||||
static char ghnbuf[256];
|
static char ghnbuf[256];
|
||||||
char* cp;
|
char* cp;
|
||||||
|
|
||||||
check_options();
|
check_options();
|
||||||
|
|
||||||
hs = NEW( httpd_server, 1 );
|
hs = NEW( httpd_server, 1 );
|
||||||
if ( hs == (httpd_server*) 0 )
|
if ( hs == (httpd_server*) 0 )
|
||||||
{
|
{
|
||||||
// syslog( LOG_CRIT, "out of memory allocating an httpd_server" );
|
// syslog( LOG_CRIT, "out of memory allocating an httpd_server" );
|
||||||
return (httpd_server*) 0;
|
return (httpd_server*) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( hostname != (char*) 0 )
|
if ( hostname != (char*) 0 )
|
||||||
{
|
{
|
||||||
hs->binding_hostname = strdup( hostname );
|
hs->binding_hostname = strdup( hostname );
|
||||||
if ( hs->binding_hostname == (char*) 0 )
|
if ( hs->binding_hostname == (char*) 0 )
|
||||||
{
|
{
|
||||||
// syslog( LOG_CRIT, "out of memory copying hostname" );
|
// syslog( LOG_CRIT, "out of memory copying hostname" );
|
||||||
return (httpd_server*) 0;
|
return (httpd_server*) 0;
|
||||||
}
|
}
|
||||||
hs->server_hostname = hs->binding_hostname;
|
hs->server_hostname = hs->binding_hostname;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hs->binding_hostname = (char*) 0;
|
hs->binding_hostname = (char*) 0;
|
||||||
hs->server_hostname = (char*) 0;
|
hs->server_hostname = (char*) 0;
|
||||||
if ( gethostname( ghnbuf, sizeof(ghnbuf) ) < 0 )
|
if ( gethostname( ghnbuf, sizeof(ghnbuf) ) < 0 )
|
||||||
ghnbuf[0] = '\0';
|
ghnbuf[0] = '\0';
|
||||||
#ifdef SERVER_NAME_LIST
|
#ifdef SERVER_NAME_LIST
|
||||||
if ( ghnbuf[0] != '\0' )
|
if ( ghnbuf[0] != '\0' )
|
||||||
hs->server_hostname = hostname_map( ghnbuf );
|
hs->server_hostname = hostname_map( ghnbuf );
|
||||||
#endif /* SERVER_NAME_LIST */
|
#endif /* SERVER_NAME_LIST */
|
||||||
if ( hs->server_hostname == (char*) 0 )
|
if ( hs->server_hostname == (char*) 0 )
|
||||||
{
|
{
|
||||||
#ifdef SERVER_NAME
|
#ifdef SERVER_NAME
|
||||||
hs->server_hostname = SERVER_NAME;
|
hs->server_hostname = SERVER_NAME;
|
||||||
#else /* SERVER_NAME */
|
#else /* SERVER_NAME */
|
||||||
if ( ghnbuf[0] != '\0' )
|
if ( ghnbuf[0] != '\0' )
|
||||||
hs->server_hostname = ghnbuf;
|
hs->server_hostname = ghnbuf;
|
||||||
#endif /* SERVER_NAME */
|
#endif /* SERVER_NAME */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hs->port = port;
|
hs->port = port;
|
||||||
if ( cgi_pattern == (char*) 0 )
|
if ( cgi_pattern == (char*) 0 )
|
||||||
hs->cgi_pattern = (char*) 0;
|
hs->cgi_pattern = (char*) 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Nuke any leading slashes. */
|
/* Nuke any leading slashes. */
|
||||||
if ( cgi_pattern[0] == '/' )
|
if ( cgi_pattern[0] == '/' )
|
||||||
++cgi_pattern;
|
++cgi_pattern;
|
||||||
hs->cgi_pattern = strdup( cgi_pattern );
|
hs->cgi_pattern = strdup( cgi_pattern );
|
||||||
if ( hs->cgi_pattern == (char*) 0 )
|
if ( hs->cgi_pattern == (char*) 0 )
|
||||||
{
|
{
|
||||||
// syslog( LOG_CRIT, "out of memory copying cgi_pattern" );
|
// syslog( LOG_CRIT, "out of memory copying cgi_pattern" );
|
||||||
return (httpd_server*) 0;
|
return (httpd_server*) 0;
|
||||||
}
|
}
|
||||||
/* Nuke any leading slashes in the cgi pattern. */
|
/* Nuke any leading slashes in the cgi pattern. */
|
||||||
while ( ( cp = strstr( hs->cgi_pattern, "|/" ) ) != (char*) 0 )
|
while ( ( cp = strstr( hs->cgi_pattern, "|/" ) ) != (char*) 0 )
|
||||||
(void) strcpy( cp + 1, cp + 2 );
|
(void) strcpy( cp + 1, cp + 2 );
|
||||||
}
|
}
|
||||||
hs->cgi_limit = cgi_limit;
|
hs->cgi_limit = cgi_limit;
|
||||||
hs->cgi_count = 0;
|
hs->cgi_count = 0;
|
||||||
hs->charset = strdup( charset );
|
hs->charset = strdup( charset );
|
||||||
hs->p3p = strdup( p3p );
|
hs->p3p = strdup( p3p );
|
||||||
hs->max_age = max_age;
|
hs->max_age = max_age;
|
||||||
hs->cwd = strdup( cwd );
|
hs->cwd = strdup( cwd );
|
||||||
if ( hs->cwd == (char*) 0 )
|
if ( hs->cwd == (char*) 0 )
|
||||||
{
|
{
|
||||||
// syslog( LOG_CRIT, "out of memory copying cwd" );
|
// syslog( LOG_CRIT, "out of memory copying cwd" );
|
||||||
return (httpd_server*) 0;
|
return (httpd_server*) 0;
|
||||||
}
|
}
|
||||||
if ( url_pattern == (char*) 0 )
|
if ( url_pattern == (char*) 0 )
|
||||||
hs->url_pattern = (char*) 0;
|
hs->url_pattern = (char*) 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hs->url_pattern = strdup( url_pattern );
|
hs->url_pattern = strdup( url_pattern );
|
||||||
if ( hs->url_pattern == (char*) 0 )
|
if ( hs->url_pattern == (char*) 0 )
|
||||||
{
|
{
|
||||||
// syslog( LOG_CRIT, "out of memory copying url_pattern" );
|
// syslog( LOG_CRIT, "out of memory copying url_pattern" );
|
||||||
return (httpd_server*) 0;
|
return (httpd_server*) 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( local_pattern == (char*) 0 )
|
if ( local_pattern == (char*) 0 )
|
||||||
hs->local_pattern = (char*) 0;
|
hs->local_pattern = (char*) 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hs->local_pattern = strdup( local_pattern );
|
hs->local_pattern = strdup( local_pattern );
|
||||||
if ( hs->local_pattern == (char*) 0 )
|
if ( hs->local_pattern == (char*) 0 )
|
||||||
{
|
{
|
||||||
// syslog( LOG_CRIT, "out of memory copying local_pattern" );
|
// syslog( LOG_CRIT, "out of memory copying local_pattern" );
|
||||||
return (httpd_server*) 0;
|
return (httpd_server*) 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hs->no_log = no_log;
|
hs->no_log = no_log;
|
||||||
hs->logfp = (FILE*) 0;
|
hs->logfp = (FILE*) 0;
|
||||||
httpd_set_logfp( hs, logfp );
|
httpd_set_logfp( hs, logfp );
|
||||||
hs->no_symlink_check = no_symlink_check;
|
hs->no_symlink_check = no_symlink_check;
|
||||||
hs->vhost = vhost;
|
hs->vhost = vhost;
|
||||||
hs->global_passwd = global_passwd;
|
hs->global_passwd = global_passwd;
|
||||||
hs->no_empty_referers = no_empty_referers;
|
hs->no_empty_referers = no_empty_referers;
|
||||||
|
|
||||||
/* Initialize listen sockets. Try v6 first because of a Linux peculiarity;
|
/* Initialize listen sockets. Try v6 first because of a Linux peculiarity;
|
||||||
** like some other systems, it has magical v6 sockets that also listen for
|
** like some other systems, it has magical v6 sockets that also listen for
|
||||||
** v4, but in Linux if you bind a v4 socket first then the v6 bind fails.
|
** v4, but in Linux if you bind a v4 socket first then the v6 bind fails.
|
||||||
*/
|
*/
|
||||||
/*if ( sa6P == (httpd_sockaddr*) 0 )
|
/*if ( sa6P == (httpd_sockaddr*) 0 )
|
||||||
hs->listen6_fd = -1;
|
hs->listen6_fd = -1;
|
||||||
else
|
else
|
||||||
hs->listen6_fd = initialize_listen_socket( sa6P );
|
hs->listen6_fd = initialize_listen_socket( sa6P );
|
||||||
if ( sa4P == (httpd_sockaddr*) 0 )
|
if ( sa4P == (httpd_sockaddr*) 0 )
|
||||||
hs->listen4_fd = -1;
|
hs->listen4_fd = -1;
|
||||||
else
|
else
|
||||||
hs->listen4_fd = initialize_listen_socket( sa4P );*/
|
hs->listen4_fd = initialize_listen_socket( sa4P );*/
|
||||||
/* If we didn't get any valid sockets, fail. */
|
/* If we didn't get any valid sockets, fail. */
|
||||||
/*if ( hs->listen4_fd == -1 && hs->listen6_fd == -1 )
|
/*if ( hs->listen4_fd == -1 && hs->listen6_fd == -1 )
|
||||||
{
|
{
|
||||||
free_httpd_server( hs );
|
free_httpd_server( hs );
|
||||||
return (httpd_server*) 0;
|
return (httpd_server*) 0;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
init_mime();
|
init_mime();
|
||||||
|
|
||||||
/* Done initializing. */
|
/* Done initializing. */
|
||||||
// if ( hs->binding_hostname == (char*) 0 )
|
// if ( hs->binding_hostname == (char*) 0 )
|
||||||
// syslog(
|
// syslog(
|
||||||
// LOG_NOTICE, "%.80s starting on port %d", SERVER_SOFTWARE,
|
// LOG_NOTICE, "%.80s starting on port %d", SERVER_SOFTWARE,
|
||||||
@@ -372,96 +372,96 @@ httpd_initialize(
|
|||||||
// LOG_NOTICE, "%.80s starting on %.80s, port %d", SERVER_SOFTWARE,
|
// LOG_NOTICE, "%.80s starting on %.80s, port %d", SERVER_SOFTWARE,
|
||||||
// httpd_ntoa( hs->listen4_fd != -1 ? sa4P : sa6P ),
|
// httpd_ntoa( hs->listen4_fd != -1 ? sa4P : sa6P ),
|
||||||
// (int) hs->port );
|
// (int) hs->port );
|
||||||
return hs;
|
return hs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
httpd_initialize_listen_socket( httpd_sockaddr* saP )
|
httpd_initialize_listen_socket( httpd_sockaddr* saP )
|
||||||
{
|
{
|
||||||
int listen_fd;
|
int listen_fd;
|
||||||
int on/*, flags*/;
|
int on/*, flags*/;
|
||||||
|
|
||||||
/* Check sockaddr. */
|
/* Check sockaddr. */
|
||||||
if ( ! sockaddr_check( saP ) )
|
if ( ! sockaddr_check( saP ) )
|
||||||
{
|
{
|
||||||
// syslog( LOG_CRIT, "unknown sockaddr family on listen socket" );
|
// syslog( LOG_CRIT, "unknown sockaddr family on listen socket" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create socket. */
|
/* Create socket. */
|
||||||
listen_fd = socket( saP->sa.sa_family, SOCK_STREAM, 0 );
|
listen_fd = socket( saP->sa.sa_family, SOCK_STREAM, 0 );
|
||||||
if ( listen_fd < 0 )
|
if ( listen_fd < 0 )
|
||||||
{
|
{
|
||||||
// syslog( LOG_CRIT, "socket %.80s - %m", httpd_ntoa( saP ) );
|
// syslog( LOG_CRIT, "socket %.80s - %m", httpd_ntoa( saP ) );
|
||||||
poorman_log("can't create socket.\n", false, INADDR_NONE, RED);
|
poorman_log("can't create socket.\n", false, INADDR_NONE, RED);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
(void) fcntl( listen_fd, F_SETFD, 1 );
|
(void) fcntl( listen_fd, F_SETFD, 1 );
|
||||||
|
|
||||||
/* Allow reuse of local addresses. */
|
/* Allow reuse of local addresses. */
|
||||||
on = 1;
|
on = 1;
|
||||||
if ( setsockopt(
|
if ( setsockopt(
|
||||||
listen_fd, SOL_SOCKET, SO_REUSEADDR, (char*) &on,
|
listen_fd, SOL_SOCKET, SO_REUSEADDR, (char*) &on,
|
||||||
sizeof(on) ) < 0 )
|
sizeof(on) ) < 0 )
|
||||||
/*syslog( LOG_CRIT, "setsockopt SO_REUSEADDR - %m" )*/;
|
/*syslog( LOG_CRIT, "setsockopt SO_REUSEADDR - %m" )*/;
|
||||||
|
|
||||||
/* Bind to it. */
|
/* Bind to it. */
|
||||||
if ( bind( listen_fd, &saP->sa, sockaddr_len( saP ) ) < 0 )
|
if ( bind( listen_fd, &saP->sa, sockaddr_len( saP ) ) < 0 )
|
||||||
{
|
{
|
||||||
// syslog(
|
// syslog(
|
||||||
// LOG_CRIT, "bind %.80s - %m", httpd_ntoa( saP ) );
|
// LOG_CRIT, "bind %.80s - %m", httpd_ntoa( saP ) );
|
||||||
poorman_log("can't bind to socket.\n", false, INADDR_NONE, RED);
|
poorman_log("can't bind to socket.\n", false, INADDR_NONE, RED);
|
||||||
(void) close( listen_fd );
|
(void) close( listen_fd );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start a listen going. */
|
/* Start a listen going. */
|
||||||
if ( listen( listen_fd, LISTEN_BACKLOG ) < 0 )
|
if ( listen( listen_fd, LISTEN_BACKLOG ) < 0 )
|
||||||
{
|
{
|
||||||
// syslog( LOG_CRIT, "listen - %m" );
|
// syslog( LOG_CRIT, "listen - %m" );
|
||||||
poorman_log("can't listen to socket.\n", false, INADDR_NONE, RED);
|
poorman_log("can't listen to socket.\n", false, INADDR_NONE, RED);
|
||||||
(void) close( listen_fd );
|
(void) close( listen_fd );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use accept filtering, if available. */
|
/* Use accept filtering, if available. */
|
||||||
#ifdef SO_ACCEPTFILTER
|
#ifdef SO_ACCEPTFILTER
|
||||||
{
|
{
|
||||||
#if ( __FreeBSD_version >= 411000 )
|
#if ( __FreeBSD_version >= 411000 )
|
||||||
#define ACCEPT_FILTER_NAME "httpready"
|
#define ACCEPT_FILTER_NAME "httpready"
|
||||||
#else
|
#else
|
||||||
#define ACCEPT_FILTER_NAME "dataready"
|
#define ACCEPT_FILTER_NAME "dataready"
|
||||||
#endif
|
#endif
|
||||||
struct accept_filter_arg af;
|
struct accept_filter_arg af;
|
||||||
(void) bzero( &af, sizeof(af) );
|
(void) bzero( &af, sizeof(af) );
|
||||||
(void) strcpy( af.af_name, ACCEPT_FILTER_NAME );
|
(void) strcpy( af.af_name, ACCEPT_FILTER_NAME );
|
||||||
(void) setsockopt(
|
(void) setsockopt(
|
||||||
listen_fd, SOL_SOCKET, SO_ACCEPTFILTER, (char*) &af, sizeof(af) );
|
listen_fd, SOL_SOCKET, SO_ACCEPTFILTER, (char*) &af, sizeof(af) );
|
||||||
}
|
}
|
||||||
#endif /* SO_ACCEPTFILTER */
|
#endif /* SO_ACCEPTFILTER */
|
||||||
|
|
||||||
return listen_fd;
|
return listen_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
httpd_set_logfp( httpd_server* hs, FILE* logfp )
|
httpd_set_logfp( httpd_server* hs, FILE* logfp )
|
||||||
{
|
{
|
||||||
if ( hs->logfp != (FILE*) 0 )
|
if ( hs->logfp != (FILE*) 0 )
|
||||||
(void) fclose( hs->logfp );
|
(void) fclose( hs->logfp );
|
||||||
hs->logfp = logfp;
|
hs->logfp = logfp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
httpd_terminate( httpd_server* hs )
|
httpd_terminate( httpd_server* hs )
|
||||||
{
|
{
|
||||||
httpd_unlisten( hs );
|
httpd_unlisten( hs );
|
||||||
if ( hs->logfp != (FILE*) 0 )
|
if ( hs->logfp != (FILE*) 0 )
|
||||||
(void) fclose( hs->logfp );
|
(void) fclose( hs->logfp );
|
||||||
free_httpd_server( hs );
|
free_httpd_server( hs );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1437,231 +1437,231 @@ vhost_map( httpd_conn* hc )
|
|||||||
*/
|
*/
|
||||||
static char*
|
static char*
|
||||||
expand_symlinks( char* path, char** freethis, char** restP, int no_symlink_check, int tildemapped )
|
expand_symlinks( char* path, char** freethis, char** restP, int no_symlink_check, int tildemapped )
|
||||||
{
|
{
|
||||||
char* checked;
|
char* checked;
|
||||||
char* rest;
|
char* rest;
|
||||||
char link[5000];
|
char link[5000];
|
||||||
size_t maxchecked = 0, maxrest = 0;
|
size_t maxchecked = 0, maxrest = 0;
|
||||||
size_t checkedlen , restlen, prevcheckedlen, prevrestlen;
|
size_t checkedlen , restlen, prevcheckedlen, prevrestlen;
|
||||||
ssize_t linklen;
|
ssize_t linklen;
|
||||||
int nlinks, i;
|
int nlinks, i;
|
||||||
char* r;
|
char* r;
|
||||||
char* cp1;
|
char* cp1;
|
||||||
char* cp2;
|
char* cp2;
|
||||||
|
|
||||||
if ( no_symlink_check )
|
if ( no_symlink_check )
|
||||||
{
|
{
|
||||||
/* If we are chrooted, we can actually skip the symlink-expansion,
|
/* If we are chrooted, we can actually skip the symlink-expansion,
|
||||||
** since it's impossible to get out of the tree. However, we still
|
** since it's impossible to get out of the tree. However, we still
|
||||||
** need to do the pathinfo check, and the existing symlink expansion
|
** need to do the pathinfo check, and the existing symlink expansion
|
||||||
** code is a pretty reasonable way to do this. So, what we do is
|
** code is a pretty reasonable way to do this. So, what we do is
|
||||||
** a single stat() of the whole filename - if it exists, then we
|
** a single stat() of the whole filename - if it exists, then we
|
||||||
** return it as is with nothing in restP. If it doesn't exist, we
|
** return it as is with nothing in restP. If it doesn't exist, we
|
||||||
** fall through to the existing code.
|
** fall through to the existing code.
|
||||||
**
|
**
|
||||||
** One side-effect of this is that users can't symlink to central
|
** One side-effect of this is that users can't symlink to central
|
||||||
** approved CGIs any more. The workaround is to use the central
|
** approved CGIs any more. The workaround is to use the central
|
||||||
** URL for the CGI instead of a local symlinked one.
|
** URL for the CGI instead of a local symlinked one.
|
||||||
*/
|
*/
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
if ( stat( path, &sb ) != -1 )
|
if ( stat( path, &sb ) != -1 )
|
||||||
{
|
|
||||||
checkedlen = strlen( path );
|
|
||||||
httpd_realloc_str( &checked, &maxchecked, checkedlen );
|
|
||||||
(void) strcpy( checked, path );
|
|
||||||
/* Trim trailing slashes. */
|
|
||||||
while ( checked[checkedlen - 1] == '/' )
|
|
||||||
{
|
{
|
||||||
checked[checkedlen - 1] = '\0';
|
checkedlen = strlen( path );
|
||||||
--checkedlen;
|
httpd_realloc_str( &checked, &maxchecked, checkedlen );
|
||||||
|
(void) strcpy( checked, path );
|
||||||
|
/* Trim trailing slashes. */
|
||||||
|
while ( checked[checkedlen - 1] == '/' )
|
||||||
|
{
|
||||||
|
checked[checkedlen - 1] = '\0';
|
||||||
|
--checkedlen;
|
||||||
|
}
|
||||||
|
httpd_realloc_str( &rest, &maxrest, 0 );
|
||||||
|
rest[0] = '\0';
|
||||||
|
*restP = rest;
|
||||||
|
*freethis = rest;
|
||||||
|
return checked;
|
||||||
}
|
}
|
||||||
httpd_realloc_str( &rest, &maxrest, 0 );
|
|
||||||
rest[0] = '\0';
|
|
||||||
*restP = rest;
|
|
||||||
*freethis = rest;
|
|
||||||
return checked;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start out with nothing in checked and the whole filename in rest. */
|
/* Start out with nothing in checked and the whole filename in rest. */
|
||||||
httpd_realloc_str( &checked, &maxchecked, 1 );
|
httpd_realloc_str( &checked, &maxchecked, 1 );
|
||||||
checked[0] = '\0';
|
checked[0] = '\0';
|
||||||
checkedlen = 0;
|
checkedlen = 0;
|
||||||
restlen = strlen( path );
|
restlen = strlen( path );
|
||||||
httpd_realloc_str( &rest, &maxrest, restlen );
|
httpd_realloc_str( &rest, &maxrest, restlen );
|
||||||
(void) strcpy( rest, path );
|
(void) strcpy( rest, path );
|
||||||
if ( rest[restlen - 1] == '/' )
|
if ( rest[restlen - 1] == '/' )
|
||||||
rest[--restlen] = '\0'; /* trim trailing slash */
|
rest[--restlen] = '\0'; /* trim trailing slash */
|
||||||
if ( ! tildemapped )
|
if ( ! tildemapped )
|
||||||
/* Remove any leading slashes. */
|
/* Remove any leading slashes. */
|
||||||
while ( rest[0] == '/' )
|
while ( rest[0] == '/' )
|
||||||
{
|
{
|
||||||
(void) strcpy( rest, &(rest[1]) );
|
(void) strcpy( rest, &(rest[1]) );
|
||||||
--restlen;
|
--restlen;
|
||||||
}
|
}
|
||||||
r = rest;
|
r = rest;
|
||||||
nlinks = 0;
|
nlinks = 0;
|
||||||
|
|
||||||
/* While there are still components to check... */
|
/* While there are still components to check... */
|
||||||
while ( restlen > 0 )
|
while ( restlen > 0 )
|
||||||
{
|
{
|
||||||
/* Save current checkedlen in case we get a symlink. Save current
|
/* Save current checkedlen in case we get a symlink. Save current
|
||||||
** restlen in case we get a non-existant component.
|
** restlen in case we get a non-existant component.
|
||||||
*/
|
*/
|
||||||
prevcheckedlen = checkedlen;
|
prevcheckedlen = checkedlen;
|
||||||
prevrestlen = restlen;
|
prevrestlen = restlen;
|
||||||
|
|
||||||
/* Grab one component from r and transfer it to checked. */
|
/* Grab one component from r and transfer it to checked. */
|
||||||
cp1 = strchr( r, '/' );
|
cp1 = strchr( r, '/' );
|
||||||
if ( cp1 != (char*) 0 )
|
if ( cp1 != (char*) 0 )
|
||||||
{
|
|
||||||
i = cp1 - r;
|
|
||||||
if ( i == 0 )
|
|
||||||
{
|
{
|
||||||
/* Special case for absolute paths. */
|
i = cp1 - r;
|
||||||
httpd_realloc_str( &checked, &maxchecked, checkedlen + 1 );
|
if ( i == 0 )
|
||||||
(void) strncpy( &checked[checkedlen], r, 1 );
|
{
|
||||||
checkedlen += 1;
|
/* Special case for absolute paths. */
|
||||||
|
httpd_realloc_str( &checked, &maxchecked, checkedlen + 1 );
|
||||||
|
(void) strncpy( &checked[checkedlen], r, 1 );
|
||||||
|
checkedlen += 1;
|
||||||
|
}
|
||||||
|
else if ( strncmp( r, "..", MAX( i, 2 ) ) == 0 )
|
||||||
|
{
|
||||||
|
/* Ignore ..'s that go above the start of the path. */
|
||||||
|
if ( checkedlen != 0 )
|
||||||
|
{
|
||||||
|
cp2 = strrchr( checked, '/' );
|
||||||
|
if ( cp2 == (char*) 0 )
|
||||||
|
checkedlen = 0;
|
||||||
|
else if ( cp2 == checked )
|
||||||
|
checkedlen = 1;
|
||||||
|
else
|
||||||
|
checkedlen = cp2 - checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
httpd_realloc_str( &checked, &maxchecked, checkedlen + 1 + i );
|
||||||
|
if ( checkedlen > 0 && checked[checkedlen-1] != '/' )
|
||||||
|
checked[checkedlen++] = '/';
|
||||||
|
(void) strncpy( &checked[checkedlen], r, i );
|
||||||
|
checkedlen += i;
|
||||||
|
}
|
||||||
|
checked[checkedlen] = '\0';
|
||||||
|
r += i + 1;
|
||||||
|
restlen -= i + 1;
|
||||||
}
|
}
|
||||||
else if ( strncmp( r, "..", MAX( i, 2 ) ) == 0 )
|
|
||||||
{
|
|
||||||
/* Ignore ..'s that go above the start of the path. */
|
|
||||||
if ( checkedlen != 0 )
|
|
||||||
{
|
|
||||||
cp2 = strrchr( checked, '/' );
|
|
||||||
if ( cp2 == (char*) 0 )
|
|
||||||
checkedlen = 0;
|
|
||||||
else if ( cp2 == checked )
|
|
||||||
checkedlen = 1;
|
|
||||||
else
|
|
||||||
checkedlen = cp2 - checked;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
httpd_realloc_str( &checked, &maxchecked, checkedlen + 1 + i );
|
|
||||||
if ( checkedlen > 0 && checked[checkedlen-1] != '/' )
|
|
||||||
checked[checkedlen++] = '/';
|
|
||||||
(void) strncpy( &checked[checkedlen], r, i );
|
|
||||||
checkedlen += i;
|
|
||||||
}
|
|
||||||
checked[checkedlen] = '\0';
|
|
||||||
r += i + 1;
|
|
||||||
restlen -= i + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* No slashes remaining, r is all one component. */
|
|
||||||
if ( strcmp( r, ".." ) == 0 )
|
|
||||||
{
|
|
||||||
/* Ignore ..'s that go above the start of the path. */
|
|
||||||
if ( checkedlen != 0 )
|
|
||||||
{
|
|
||||||
cp2 = strrchr( checked, '/' );
|
|
||||||
if ( cp2 == (char*) 0 )
|
|
||||||
checkedlen = 0;
|
|
||||||
else if ( cp2 == checked )
|
|
||||||
checkedlen = 1;
|
|
||||||
else
|
|
||||||
checkedlen = cp2 - checked;
|
|
||||||
checked[checkedlen] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
httpd_realloc_str(
|
|
||||||
&checked, &maxchecked, checkedlen + 1 + restlen );
|
|
||||||
if ( checkedlen > 0 && checked[checkedlen-1] != '/' )
|
|
||||||
checked[checkedlen++] = '/';
|
|
||||||
(void) strcpy( &checked[checkedlen], r );
|
|
||||||
checkedlen += restlen;
|
|
||||||
}
|
|
||||||
r += restlen;
|
|
||||||
restlen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try reading the current filename as a symlink */
|
|
||||||
if ( checked[0] == '\0' )
|
|
||||||
continue;
|
|
||||||
linklen = readlink( checked, link, sizeof(link) - 1 );
|
|
||||||
if ( linklen == -1 )
|
|
||||||
{
|
|
||||||
if ( errno == EINVAL )
|
|
||||||
continue; /* not a symlink */
|
|
||||||
if ( errno == EACCES || errno == ENOENT || errno == ENOTDIR )
|
|
||||||
{
|
|
||||||
/* That last component was bogus. Restore and return. */
|
|
||||||
*restP = r - ( prevrestlen - restlen );
|
|
||||||
if ( prevcheckedlen == 0 )
|
|
||||||
(void) strcpy( checked, "." );
|
|
||||||
else
|
else
|
||||||
checked[prevcheckedlen] = '\0';
|
{
|
||||||
*freethis = rest;
|
/* No slashes remaining, r is all one component. */
|
||||||
return checked;
|
if ( strcmp( r, ".." ) == 0 )
|
||||||
|
{
|
||||||
|
/* Ignore ..'s that go above the start of the path. */
|
||||||
|
if ( checkedlen != 0 )
|
||||||
|
{
|
||||||
|
cp2 = strrchr( checked, '/' );
|
||||||
|
if ( cp2 == (char*) 0 )
|
||||||
|
checkedlen = 0;
|
||||||
|
else if ( cp2 == checked )
|
||||||
|
checkedlen = 1;
|
||||||
|
else
|
||||||
|
checkedlen = cp2 - checked;
|
||||||
|
checked[checkedlen] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
httpd_realloc_str(
|
||||||
|
&checked, &maxchecked, checkedlen + 1 + restlen );
|
||||||
|
if ( checkedlen > 0 && checked[checkedlen-1] != '/' )
|
||||||
|
checked[checkedlen++] = '/';
|
||||||
|
(void) strcpy( &checked[checkedlen], r );
|
||||||
|
checkedlen += restlen;
|
||||||
|
}
|
||||||
|
r += restlen;
|
||||||
|
restlen = 0;
|
||||||
}
|
}
|
||||||
// syslog( LOG_ERR, "readlink %.80s - %m", checked );
|
|
||||||
free(checked);
|
|
||||||
free(rest);
|
|
||||||
*freethis = 0;
|
|
||||||
return (char*) 0;
|
|
||||||
}
|
|
||||||
++nlinks;
|
|
||||||
if ( nlinks > MAX_LINKS )
|
|
||||||
{
|
|
||||||
// syslog( LOG_ERR, "too many symlinks in %.80s", path );
|
|
||||||
free(checked);
|
|
||||||
free(rest);
|
|
||||||
*freethis = 0;
|
|
||||||
return (char*) 0;
|
|
||||||
}
|
|
||||||
link[linklen] = '\0';
|
|
||||||
if ( link[linklen - 1] == '/' )
|
|
||||||
link[--linklen] = '\0'; /* trim trailing slash */
|
|
||||||
|
|
||||||
/* Insert the link contents in front of the rest of the filename. */
|
/* Try reading the current filename as a symlink */
|
||||||
if ( restlen != 0 )
|
if ( checked[0] == '\0' )
|
||||||
{
|
continue;
|
||||||
(void) strcpy( rest, r );
|
linklen = readlink( checked, link, sizeof(link) - 1 );
|
||||||
httpd_realloc_str( &rest, &maxrest, restlen + linklen + 1 );
|
if ( linklen == -1 )
|
||||||
for ( i = restlen; i >= 0; --i )
|
{
|
||||||
rest[i + linklen + 1] = rest[i];
|
if ( errno == EINVAL )
|
||||||
(void) strcpy( rest, link );
|
continue; /* not a symlink */
|
||||||
rest[linklen] = '/';
|
if ( errno == EACCES || errno == ENOENT || errno == ENOTDIR )
|
||||||
restlen += linklen + 1;
|
{
|
||||||
r = rest;
|
/* That last component was bogus. Restore and return. */
|
||||||
}
|
*restP = r - ( prevrestlen - restlen );
|
||||||
else
|
if ( prevcheckedlen == 0 )
|
||||||
{
|
(void) strcpy( checked, "." );
|
||||||
/* There's nothing left in the filename, so the link contents
|
else
|
||||||
** becomes the rest.
|
checked[prevcheckedlen] = '\0';
|
||||||
*/
|
*freethis = rest;
|
||||||
httpd_realloc_str( &rest, &maxrest, linklen );
|
return checked;
|
||||||
(void) strcpy( rest, link );
|
}
|
||||||
restlen = linklen;
|
// syslog( LOG_ERR, "readlink %.80s - %m", checked );
|
||||||
r = rest;
|
free(checked);
|
||||||
}
|
free(rest);
|
||||||
|
*freethis = 0;
|
||||||
|
return (char*) 0;
|
||||||
|
}
|
||||||
|
++nlinks;
|
||||||
|
if ( nlinks > MAX_LINKS )
|
||||||
|
{
|
||||||
|
// syslog( LOG_ERR, "too many symlinks in %.80s", path );
|
||||||
|
free(checked);
|
||||||
|
free(rest);
|
||||||
|
*freethis = 0;
|
||||||
|
return (char*) 0;
|
||||||
|
}
|
||||||
|
link[linklen] = '\0';
|
||||||
|
if ( link[linklen - 1] == '/' )
|
||||||
|
link[--linklen] = '\0'; /* trim trailing slash */
|
||||||
|
|
||||||
if ( rest[0] == '/' )
|
/* Insert the link contents in front of the rest of the filename. */
|
||||||
{
|
if ( restlen != 0 )
|
||||||
/* There must have been an absolute symlink - zero out checked. */
|
{
|
||||||
checked[0] = '\0';
|
(void) strcpy( rest, r );
|
||||||
checkedlen = 0;
|
httpd_realloc_str( &rest, &maxrest, restlen + linklen + 1 );
|
||||||
}
|
for ( i = restlen; i >= 0; --i )
|
||||||
else
|
rest[i + linklen + 1] = rest[i];
|
||||||
{
|
(void) strcpy( rest, link );
|
||||||
/* Re-check this component. */
|
rest[linklen] = '/';
|
||||||
checkedlen = prevcheckedlen;
|
restlen += linklen + 1;
|
||||||
checked[checkedlen] = '\0';
|
r = rest;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* There's nothing left in the filename, so the link contents
|
||||||
|
** becomes the rest.
|
||||||
|
*/
|
||||||
|
httpd_realloc_str( &rest, &maxrest, linklen );
|
||||||
|
(void) strcpy( rest, link );
|
||||||
|
restlen = linklen;
|
||||||
|
r = rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( rest[0] == '/' )
|
||||||
|
{
|
||||||
|
/* There must have been an absolute symlink - zero out checked. */
|
||||||
|
checked[0] = '\0';
|
||||||
|
checkedlen = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Re-check this component. */
|
||||||
|
checkedlen = prevcheckedlen;
|
||||||
|
checked[checkedlen] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ok. */
|
/* Ok. */
|
||||||
*restP = r;
|
*restP = r;
|
||||||
if ( checked[0] == '\0' )
|
if ( checked[0] == '\0' )
|
||||||
(void) strcpy( checked, "." );
|
(void) strcpy( checked, "." );
|
||||||
*freethis = rest;
|
*freethis = rest;
|
||||||
return checked;
|
return checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
Reference in New Issue
Block a user