From 5f9a5f7ccf3c9e630d4f098ab9aa90dff0dc56d2 Mon Sep 17 00:00:00 2001 From: Christophe Massiot Date: Fri, 17 Jun 2005 12:43:46 +0000 Subject: [PATCH] * modules/control/http.c: Added support for .hosts files detailing hosts allowed to connect. The format is : 192.168.0.0/24 172.16.12.42/32 * src/misc/net.c: New function net_CheckIP to check that an IP is in a given range. * OTHERS: Changed prototypes to allow for two new arguments for the hosts list. --- include/network.h | 3 ++ include/vlc_httpd.h | 8 ++-- modules/access_output/http.c | 2 +- modules/control/http.c | 47 ++++++++++++++++++++++- modules/misc/rtsp.c | 6 ++- modules/stream_out/rtp.c | 6 +-- src/misc/httpd.c | 74 +++++++++++++++++++++++++++++++----- src/misc/net.c | 56 +++++++++++++++++++++++++++ 8 files changed, 181 insertions(+), 21 deletions(-) diff --git a/include/network.h b/include/network.h index 4661d0f7ae..f4b363d9f6 100644 --- a/include/network.h +++ b/include/network.h @@ -314,6 +314,9 @@ VLC_EXPORT( int, net_Printf, ( vlc_object_t *p_this, int fd, v_socket_t *, const #define net_vaPrintf(a,b,c,d,e) __net_vaPrintf(VLC_OBJECT(a),b,c,d,e) VLC_EXPORT( int, __net_vaPrintf, ( vlc_object_t *p_this, int fd, v_socket_t *, const char *psz_fmt, va_list args ) ); +#define net_CheckIP(a,b,c,d) __net_CheckIP(VLC_OBJECT(a),b,c,d) +VLC_EXPORT( int, __net_CheckIP, ( vlc_object_t *p_this, char *psz_ip, char **ppsz_hosts, int i_hosts ) ); + /* Portable network names/addresses resolution layer */ /* GAI error codes */ diff --git a/include/vlc_httpd.h b/include/vlc_httpd.h index aa04c76a13..c1ea92d0f0 100644 --- a/include/vlc_httpd.h +++ b/include/vlc_httpd.h @@ -119,8 +119,8 @@ VLC_EXPORT( httpd_host_t *, httpd_TLSHostNew, ( vlc_object_t *, const char *, in VLC_EXPORT( void, httpd_HostDelete, ( httpd_host_t * ) ); /* register a new url */ -VLC_EXPORT( httpd_url_t *, httpd_UrlNew, ( httpd_host_t *, char *psz_url, char *psz_user, char *psz_password ) ); -VLC_EXPORT( httpd_url_t *, httpd_UrlNewUnique, ( httpd_host_t *, char *psz_url, char *psz_user, char *psz_password ) ); +VLC_EXPORT( httpd_url_t *, httpd_UrlNew, ( httpd_host_t *, char *psz_url, char *psz_user, char *psz_password, char **ppsz_hosts, int i_hosts ) ); +VLC_EXPORT( httpd_url_t *, httpd_UrlNewUnique, ( httpd_host_t *, char *psz_url, char *psz_user, char *psz_password, char **ppsz_hosts, int i_hosts ) ); /* register callback on a url */ VLC_EXPORT( int, httpd_UrlCatch, ( httpd_url_t *, int i_msg, httpd_callback_t, httpd_callback_sys_t * ) ); /* delete an url */ @@ -133,7 +133,7 @@ VLC_EXPORT( char*, httpd_ClientIP, ( httpd_client_t *cl ) ); /* High level */ -VLC_EXPORT( httpd_file_t *, httpd_FileNew, ( httpd_host_t *, char *psz_url, char *psz_mime, char *psz_user, char *psz_password, httpd_file_callback_t pf_fill, httpd_file_sys_t * ) ); +VLC_EXPORT( httpd_file_t *, httpd_FileNew, ( httpd_host_t *, char *psz_url, char *psz_mime, char *psz_user, char *psz_password, char **ppsz_hosts, int i_hosts, httpd_file_callback_t pf_fill, httpd_file_sys_t * ) ); VLC_EXPORT( void, httpd_FileDelete, ( httpd_file_t * ) ); @@ -141,7 +141,7 @@ VLC_EXPORT( httpd_redirect_t *, httpd_RedirectNew, ( httpd_host_t *, char *psz_u VLC_EXPORT( void, httpd_RedirectDelete, ( httpd_redirect_t * ) ); -VLC_EXPORT( httpd_stream_t *, httpd_StreamNew, ( httpd_host_t *, char *psz_url, char *psz_mime, char *psz_user, char *psz_password ) ); +VLC_EXPORT( httpd_stream_t *, httpd_StreamNew, ( httpd_host_t *, char *psz_url, char *psz_mime, char *psz_user, char *psz_password, char **ppsz_hosts, int i_hosts ) ); VLC_EXPORT( void, httpd_StreamDelete, ( httpd_stream_t * ) ); VLC_EXPORT( int, httpd_StreamHeader, ( httpd_stream_t *, uint8_t *p_data, int i_data ) ); VLC_EXPORT( int, httpd_StreamSend, ( httpd_stream_t *, uint8_t *p_data, int i_data ) ); diff --git a/modules/access_output/http.c b/modules/access_output/http.c index 8555030d51..3d2bfbb8e8 100644 --- a/modules/access_output/http.c +++ b/modules/access_output/http.c @@ -255,7 +255,7 @@ static int Open( vlc_object_t *p_this ) p_sys->p_httpd_stream = httpd_StreamNew( p_sys->p_httpd_host, psz_file_name, psz_mime, - psz_user, psz_pwd ); + psz_user, psz_pwd, NULL, 0 ); if( psz_user ) free( psz_user ); if( psz_pwd ) free( psz_pwd ); if( psz_mime ) free( psz_mime ); diff --git a/modules/control/http.c b/modules/control/http.c index e4ce72a570..f5f83a6047 100644 --- a/modules/control/http.c +++ b/modules/control/http.c @@ -522,6 +522,10 @@ static int ParseDirectory( intf_thread_t *p_intf, char *psz_root, char *user = NULL; char *password = NULL; + char **ppsz_hosts = NULL; + int i_hosts = 0; + + int i; #ifdef HAVE_SYS_STAT_H if( stat( psz_dir, &stat_info ) == -1 || !S_ISDIR( stat_info.st_mode ) ) @@ -572,6 +576,43 @@ static int ParseDirectory( intf_thread_t *p_intf, char *psz_root, fclose( file ); } + sprintf( dir, "%s/.hosts", psz_dir ); + if( ( file = fopen( dir, "r" ) ) != NULL ) + { + char line[1024]; + int i_size; + + msg_Dbg( p_intf, "find .hosts in dir=%s", psz_dir ); + + while( !feof( file ) ) + { + fgets( line, 1023, file ); + i_size = strlen(line); + if( i_size > 0 && line[0] != '#' ) + { + while( i_size > 0 && ( line[i_size-1] == '\n' || + line[i_size-1] == '\r' ) ) + { + i_size--; + } + if( !i_size ) continue; + + line[i_size] = '\0'; + + msg_Dbg( p_intf, "restricted to %s (read=%d)", + line, i_size ); + TAB_APPEND( i_hosts, ppsz_hosts, strdup( line ) ); + } + } + + fclose( file ); + + if( net_CheckIP( p_intf, "0.0.0.0", ppsz_hosts, i_hosts ) < 0 ) + { + msg_Err( p_intf, ".hosts file is invalid in dir=%s", psz_dir ); + } + } + for( ;; ) { /* parse psz_src dir */ @@ -611,7 +652,7 @@ static int ParseDirectory( intf_thread_t *p_intf, char *psz_root, f->p_file = httpd_FileNew( p_sys->p_httpd_host, f->name, f->b_html ? p_sys->psz_html_type : NULL, - user, password, + user, password, ppsz_hosts, i_hosts, HttpCallback, f ); if( f->p_file ) @@ -653,6 +694,10 @@ static int ParseDirectory( intf_thread_t *p_intf, char *psz_root, { free( password ); } + for( i = 0; i < i_hosts; i++ ) + { + TAB_REMOVE( i_hosts, ppsz_hosts, ppsz_hosts[0] ); + } closedir( p_dir ); diff --git a/modules/misc/rtsp.c b/modules/misc/rtsp.c index 403d4807ae..9b048cef35 100644 --- a/modules/misc/rtsp.c +++ b/modules/misc/rtsp.c @@ -276,7 +276,8 @@ static vod_media_t *MediaNew( vod_t *p_vod, char *psz_name, asprintf( &p_media->psz_rtsp_path, "%s%s", p_sys->psz_path, psz_name ); p_media->p_rtsp_url = - httpd_UrlNewUnique( p_sys->p_rtsp_host, p_media->psz_rtsp_path, 0, 0 ); + httpd_UrlNewUnique( p_sys->p_rtsp_host, p_media->psz_rtsp_path, 0, 0, + NULL, 0 ); if( !p_media->p_rtsp_url ) { @@ -452,7 +453,8 @@ static int MediaAddES( vod_t *p_vod, vod_media_t *p_media, es_format_t *p_fmt ) } p_es->p_rtsp_url = - httpd_UrlNewUnique( p_vod->p_sys->p_rtsp_host, psz_urlc, 0, 0 ); + httpd_UrlNewUnique( p_vod->p_sys->p_rtsp_host, psz_urlc, 0, 0, NULL, + 0 ); if( !p_es->p_rtsp_url ) { diff --git a/modules/stream_out/rtp.c b/modules/stream_out/rtp.c index 5563c28576..1dec3642dc 100644 --- a/modules/stream_out/rtp.c +++ b/modules/stream_out/rtp.c @@ -1032,7 +1032,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) sprintf( psz_urlc, "%s/trackid=%d", p_sys->psz_rtsp_path, p_sys->i_es ); fprintf( stderr, "rtsp: adding %s\n", psz_urlc ); - id->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, psz_urlc, NULL, NULL ); + id->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, psz_urlc, NULL, NULL, NULL, 0 ); if( id->p_rtsp_url ) { @@ -1296,7 +1296,7 @@ static int HttpSetup( sout_stream_t *p_stream, vlc_url_t *url) p_sys->p_httpd_file = httpd_FileNew( p_sys->p_httpd_host, url->psz_path ? url->psz_path : "/", "application/sdp", - NULL, NULL, + NULL, NULL, NULL, 0, HttpCallback, (void*)p_sys ); } if( p_sys->p_httpd_file == NULL ) @@ -1394,7 +1394,7 @@ static int RtspSetup( sout_stream_t *p_stream, vlc_url_t *url ) sprintf( p_sys->psz_rtsp_control, "rtsp://%s:%d%s", url->psz_host, url->i_port > 0 ? url->i_port : 554, p_sys->psz_rtsp_path ); - p_sys->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, p_sys->psz_rtsp_path, NULL, NULL ); + p_sys->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, p_sys->psz_rtsp_path, NULL, NULL, NULL, 0 ); if( p_sys->p_rtsp_url == 0 ) { return VLC_EGENERIC; diff --git a/src/misc/httpd.c b/src/misc/httpd.c index c06d3651ed..230808c9a7 100644 --- a/src/misc/httpd.c +++ b/src/misc/httpd.c @@ -237,6 +237,8 @@ struct httpd_url_t char *psz_url; char *psz_user; char *psz_password; + char **ppsz_hosts; + int i_hosts; struct { @@ -489,13 +491,15 @@ static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_file_t *httpd_FileNew( httpd_host_t *host, char *psz_url, char *psz_mime, char *psz_user, char *psz_password, + char **ppsz_hosts, int i_hosts, httpd_file_callback_t pf_fill, httpd_file_sys_t *p_sys ) { httpd_file_t *file = malloc( sizeof( httpd_file_t ) ); if( ( file->url = httpd_UrlNewUnique( host, psz_url, psz_user, - psz_password ) ) == NULL ) + psz_password, ppsz_hosts, i_hosts ) + ) == NULL ) { free( file ); return NULL; @@ -586,7 +590,8 @@ httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, char *psz_url_dst, { httpd_redirect_t *rdir = malloc( sizeof( httpd_redirect_t ) ); - if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL ) ) ) + if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL, + NULL, 0 ) ) ) { free( rdir ); return NULL; @@ -761,12 +766,14 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys, httpd_stream_t *httpd_StreamNew( httpd_host_t *host, char *psz_url, char *psz_mime, - char *psz_user, char *psz_password ) + char *psz_user, char *psz_password, + char **ppsz_hosts, int i_hosts ) { httpd_stream_t *stream = malloc( sizeof( httpd_stream_t ) ); if( ( stream->url = httpd_UrlNewUnique( host, psz_url, psz_user, - psz_password ) ) == NULL ) + psz_password, ppsz_hosts, i_hosts ) + ) == NULL ) { free( stream ); return NULL; @@ -1090,6 +1097,7 @@ void httpd_HostDelete( httpd_host_t *host ) /* register a new url */ static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, char *psz_user, char *psz_password, + char **ppsz_hosts, int i_hosts, vlc_bool_t b_check ) { httpd_url_t *url; @@ -1117,6 +1125,12 @@ static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, url->psz_url = strdup( psz_url ); url->psz_user = strdup( psz_user ? psz_user : "" ); url->psz_password = strdup( psz_password ? psz_password : "" ); + url->i_hosts = 0; + url->ppsz_hosts = NULL; + for( i = 0; i < i_hosts; i++ ) + { + TAB_APPEND( url->i_hosts, url->ppsz_hosts, strdup(ppsz_hosts[i]) ); + } for( i = 0; i < HTTPD_MSG_MAX; i++ ) { url->catch[i].cb = NULL; @@ -1130,17 +1144,19 @@ static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, } httpd_url_t *httpd_UrlNew( httpd_host_t *host, char *psz_url, - char *psz_user, char *psz_password ) + char *psz_user, char *psz_password, + char **ppsz_hosts, int i_hosts ) { return httpd_UrlNewPrivate( host, psz_url, psz_user, - psz_password, VLC_FALSE ); + psz_password, ppsz_hosts, i_hosts, VLC_FALSE ); } httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url, - char *psz_user, char *psz_password ) + char *psz_user, char *psz_password, + char **ppsz_hosts, int i_hosts ) { return httpd_UrlNewPrivate( host, psz_url, psz_user, - psz_password, VLC_TRUE ); + psz_password, ppsz_hosts, i_hosts, VLC_TRUE ); } /* register callback on a url */ @@ -1169,6 +1185,10 @@ void httpd_UrlDelete( httpd_url_t *url ) free( url->psz_url ); free( url->psz_user ); free( url->psz_password ); + for( i = 0; i < url->i_hosts; i++ ) + { + TAB_REMOVE( url->i_hosts, url->ppsz_hosts, url->ppsz_hosts[0] ); + } for( i = 0; i < host->i_client; i++ ) { @@ -2073,6 +2093,7 @@ static void httpd_HostThread( httpd_host_t *host ) else { vlc_bool_t b_auth_failed = VLC_FALSE; + vlc_bool_t b_hosts_failed = VLC_FALSE; int i; /* Search the url and trigger callbacks */ @@ -2084,6 +2105,23 @@ static void httpd_HostThread( httpd_host_t *host ) { if( url->catch[i_msg].cb ) { + if( answer && url->i_hosts ) + { + char *ip = httpd_ClientIP( cl ); + if( ip != NULL ) + { + if( net_CheckIP( host, ip, + url->ppsz_hosts, + url->i_hosts ) <= 0 ) + { + b_hosts_failed = VLC_TRUE; + free( ip ); + break; + } + free( ip ); + } + } + if( answer && ( *url->psz_user || *url->psz_password ) ) { /* create the headers */ @@ -2142,7 +2180,23 @@ static void httpd_HostThread( httpd_host_t *host ) answer->i_version= 0; p = answer->p_body = malloc( 1000 + strlen(query->psz_url) ); - if( b_auth_failed ) + if( b_hosts_failed ) + { + answer->i_status = 403; + answer->psz_status = strdup( "Forbidden" ); + + p += sprintf( p, "\n" ); + p += sprintf( p, "\n" ); + p += sprintf( p, "Error 403\n" ); + p += sprintf( p, "\n" ); + p += sprintf( p, "\n" ); + p += sprintf( p, "

403 Forbidden (%s)

\n", query->psz_url ); + p += sprintf( p, "
\n" ); + p += sprintf( p, "VideoLAN\n" ); + p += sprintf( p, "\n" ); + p += sprintf( p, "\n" ); + } + else if( b_auth_failed ) { answer->i_status = 401; answer->psz_status = strdup( "Authorization Required" ); @@ -2354,7 +2408,7 @@ static void httpd_HostThread( httpd_host_t *host ) ip = httpd_ClientIP( cl ); msg_Dbg( host, "new connection (%s)", ip != NULL ? ip : "unknown" ); - if( ip != NULL) + if( ip != NULL ) free( ip ); } } diff --git a/src/misc/net.c b/src/misc/net.c index 95d76d3940..a090d5d9ec 100644 --- a/src/misc/net.c +++ b/src/misc/net.c @@ -1171,3 +1171,59 @@ static int SocksHandshakeTCP( vlc_object_t *p_obj, return VLC_SUCCESS; } + +/***************************************************************************** + * __net_CheckIP + ***************************************************************************** + * Check that a given IP is within a set of IP/netmask. + *****************************************************************************/ +int __net_CheckIP( vlc_object_t *p_this, char *psz_ip, char **ppsz_hosts, + int i_hosts ) +{ + struct in_addr ip; + int i; + + if( !inet_aton( psz_ip, &ip ) ) + { + return VLC_EGENERIC; + } + + for( i = 0; i < i_hosts; i++ ) + { + struct in_addr base, mask; + char *psz_host = strdup( ppsz_hosts[i] ); + char *p = strchr( psz_host, '/' ); + + if( p != NULL ) + { + int i_mask; + *p++ = '\0'; + i_mask = atoi(p); + if( i_mask < 0 || i_mask > 32 ) + { + msg_Err( p_this, "invalid netmask %s", p ); + mask.s_addr = INADDR_NONE; + } + else if( i_mask == 0 ) + mask.s_addr = INADDR_ANY; + else + mask.s_addr = htons( ntohs(INADDR_NONE) << (32 - i_mask) ); + } + else + mask.s_addr = INADDR_NONE; + + if( !inet_aton( psz_host, &base ) ) + { + msg_Err( p_this, "invalid base address %s", psz_host ); + free( psz_host ); + continue; + } + free( psz_host ); + + if( !((ip.s_addr ^ base.s_addr) & mask.s_addr) ) + return VLC_TRUE; + } + + return VLC_FALSE; +} + -- 2.39.2