diff --git a/Makefile.am b/Makefile.am index 38fd1faf53..fb349c8a66 100644 --- a/Makefile.am +++ b/Makefile.am @@ -88,6 +88,7 @@ HEADERS_include = \ include/variables.h \ include/video_output.h \ include/vlc_access.h \ + include/vlc_acl.h \ include/vlc_bits.h \ include/vlc_block.h \ include/vlc_block_helper.h \ @@ -374,6 +375,7 @@ SOURCES_libvlc_common = \ src/stream_output/stream_output.c \ src/stream_output/announce.c \ src/stream_output/sap.c \ + src/stream_output/acl.c \ src/misc/charset.c \ src/misc/httpd.c \ src/misc/tls.c \ diff --git a/include/network.h b/include/network.h index bbada0f4a0..4fcf4a741f 100644 --- a/include/network.h +++ b/include/network.h @@ -371,9 +371,6 @@ VLC_EXPORT( int, __net_vaPrintf, ( vlc_object_t *p_this, int fd, v_socket_t *, c # define net_StopRecv( fd ) (void)0 #endif -#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_acl.h b/include/vlc_acl.h new file mode 100644 index 0000000000..be4d42f9f8 --- /dev/null +++ b/include/vlc_acl.h @@ -0,0 +1,39 @@ +/***************************************************************************** + * vlc_acl.h: interface to the network Access Control List internal API + ***************************************************************************** + * Copyright (C) 2005 Rémi Denis-Courmont + * $Id$ + * + * Authors: Rémi Denis-Courmont + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#ifndef __VLC_ACL_H +# define __VLC_ACL_H + +#define ACL_Create(a, b) __ACL_Create(VLC_OBJECT(a), b) +#define ACL_Duplicate(a,b) __ACL_Duplicate(VLC_OBJECT(a),b) + +VLC_EXPORT( int, ACL_Check, ( vlc_acl_t *p_acl, const char *psz_ip ) ); +VLC_EXPORT( vlc_acl_t *, __ACL_Create, ( vlc_object_t *p_this, vlc_bool_t b_allow ) ); +VLC_EXPORT( vlc_acl_t *, __ACL_Duplicate, ( vlc_object_t *p_this, const vlc_acl_t *p_acl ) ); +VLC_EXPORT( void, ACL_Destroy, ( vlc_acl_t *p_acl ) ); + +#define ACL_AddHost(a,b,c) ACL_AddNet(a,b,-1,c) +VLC_EXPORT( int, ACL_AddNet, ( vlc_acl_t *p_acl, const char *psz_ip, int i_len, vlc_bool_t b_allow ) ); +VLC_EXPORT( int, ACL_LoadFile, ( vlc_acl_t *p_acl, const char *path ) ); + +#endif diff --git a/include/vlc_common.h b/include/vlc_common.h index 8186b9e9a3..8d2ac57f87 100644 --- a/include/vlc_common.h +++ b/include/vlc_common.h @@ -362,6 +362,7 @@ typedef struct virtual_socket_t v_socket_t; typedef struct iso639_lang_t iso639_lang_t; typedef struct sockaddr sockaddr; typedef struct addrinfo addrinfo; +typedef struct vlc_acl_t vlc_acl_t; /* block */ typedef struct block_t block_t; diff --git a/include/vlc_httpd.h b/include/vlc_httpd.h index d716fbe40d..7947d679cf 100644 --- a/include/vlc_httpd.h +++ b/include/vlc_httpd.h @@ -121,8 +121,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, 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 ) ); +VLC_EXPORT( httpd_url_t *, httpd_UrlNew, ( httpd_host_t *, char *psz_url, char *psz_user, char *psz_password, const vlc_acl_t *p_acl ) ); +VLC_EXPORT( httpd_url_t *, httpd_UrlNewUnique, ( httpd_host_t *, char *psz_url, char *psz_user, char *psz_password, const vlc_acl_t *p_acl ) ); /* 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 */ @@ -135,7 +135,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, char **ppsz_hosts, int i_hosts, 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, const vlc_acl_t *p_acl, httpd_file_callback_t pf_fill, httpd_file_sys_t * ) ); VLC_EXPORT( void, httpd_FileDelete, ( httpd_file_t * ) ); @@ -143,7 +143,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, char **ppsz_hosts, int i_hosts ) ); +VLC_EXPORT( httpd_stream_t *, httpd_StreamNew, ( httpd_host_t *, char *psz_url, char *psz_mime, char *psz_user, char *psz_password, const vlc_acl_t *p_acl ) ); 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/include/vlc_symbols.h b/include/vlc_symbols.h index 4af77d556d..f144cc7ae2 100644 --- a/include/vlc_symbols.h +++ b/include/vlc_symbols.h @@ -195,18 +195,18 @@ struct module_symbols_t httpd_host_t * (*httpd_HostNew_inner) (vlc_object_t *, const char *psz_host, int i_port); httpd_host_t * (*httpd_TLSHostNew_inner) (vlc_object_t *, const char *, int, const char *, const char *, const char *, const char *); void (*httpd_HostDelete_inner) (httpd_host_t *); - httpd_url_t * (*httpd_UrlNew_inner) (httpd_host_t *, char *psz_url, char *psz_user, char *psz_password, char **ppsz_hosts, int i_hosts); - httpd_url_t * (*httpd_UrlNewUnique_inner) (httpd_host_t *, char *psz_url, char *psz_user, char *psz_password, char **ppsz_hosts, int i_hosts); + httpd_url_t * (*httpd_UrlNew_inner) (httpd_host_t *, char *psz_url, char *psz_user, char *psz_password, const vlc_acl_t *p_acl); + httpd_url_t * (*httpd_UrlNewUnique_inner) (httpd_host_t *, char *psz_url, char *psz_user, char *psz_password, const vlc_acl_t *p_acl); int (*httpd_UrlCatch_inner) (httpd_url_t *, int i_msg, httpd_callback_t, httpd_callback_sys_t *); void (*httpd_UrlDelete_inner) (httpd_url_t *); void (*httpd_ClientModeStream_inner) (httpd_client_t *cl); void (*httpd_ClientModeBidir_inner) (httpd_client_t *cl); char* (*httpd_ClientIP_inner) (httpd_client_t *cl); - httpd_file_t * (*httpd_FileNew_inner) (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 *); + httpd_file_t * (*httpd_FileNew_inner) (httpd_host_t *, char *psz_url, char *psz_mime, char *psz_user, char *psz_password, const vlc_acl_t *p_acl, httpd_file_callback_t pf_fill, httpd_file_sys_t *); void (*httpd_FileDelete_inner) (httpd_file_t *); httpd_redirect_t * (*httpd_RedirectNew_inner) (httpd_host_t *, char *psz_url_dst, char *psz_url_src); void (*httpd_RedirectDelete_inner) (httpd_redirect_t *); - httpd_stream_t * (*httpd_StreamNew_inner) (httpd_host_t *, char *psz_url, char *psz_mime, char *psz_user, char *psz_password, char **ppsz_hosts, int i_hosts); + httpd_stream_t * (*httpd_StreamNew_inner) (httpd_host_t *, char *psz_url, char *psz_mime, char *psz_user, char *psz_password, const vlc_acl_t *p_acl); void (*httpd_StreamDelete_inner) (httpd_stream_t *); int (*httpd_StreamHeader_inner) (httpd_stream_t *, uint8_t *p_data, int i_data); int (*httpd_StreamSend_inner) (httpd_stream_t *, uint8_t *p_data, int i_data); @@ -375,8 +375,13 @@ struct module_symbols_t const char * (*vlc_gai_strerror_inner) (int); void (*net_ListenClose_inner) (int *fd); void (*DigestMD5_inner) (struct md5_s *, uint32_t *); - int (*__net_CheckIP_inner) (vlc_object_t *p_this, char *psz_ip, char **ppsz_hosts, int i_hosts); + int (*ACL_Check_inner) (vlc_acl_t *p_acl, const char *psz_ip); int (*playlist_NodeRemoveParent_inner) (playlist_t *,playlist_item_t*,playlist_item_t *); + vlc_acl_t * (*__ACL_Duplicate_inner) (vlc_object_t *p_this, const vlc_acl_t *p_acl); + vlc_acl_t * (*__ACL_Create_inner) (vlc_object_t *p_this, vlc_bool_t b_allow); + int (*ACL_LoadFile_inner) (vlc_acl_t *p_acl, const char *path); + int (*ACL_AddNet_inner) (vlc_acl_t *p_acl, const char *psz_ip, int i_len, vlc_bool_t b_allow); + void (*ACL_Destroy_inner) (vlc_acl_t *p_acl); }; # if defined (__PLUGIN__) # define aout_FiltersCreatePipeline (p_symbols)->aout_FiltersCreatePipeline_inner @@ -737,8 +742,13 @@ struct module_symbols_t # define vlc_gai_strerror (p_symbols)->vlc_gai_strerror_inner # define net_ListenClose (p_symbols)->net_ListenClose_inner # define DigestMD5 (p_symbols)->DigestMD5_inner -# define __net_CheckIP (p_symbols)->__net_CheckIP_inner +# define ACL_Check (p_symbols)->ACL_Check_inner # define playlist_NodeRemoveParent (p_symbols)->playlist_NodeRemoveParent_inner +# define __ACL_Duplicate (p_symbols)->__ACL_Duplicate_inner +# define __ACL_Create (p_symbols)->__ACL_Create_inner +# define ACL_LoadFile (p_symbols)->ACL_LoadFile_inner +# define ACL_AddNet (p_symbols)->ACL_AddNet_inner +# define ACL_Destroy (p_symbols)->ACL_Destroy_inner # elif defined (HAVE_DYNAMIC_PLUGINS) && !defined (__BUILTIN__) /****************************************************************** * STORE_SYMBOLS: store VLC APIs into p_symbols for plugin access. @@ -1102,8 +1112,13 @@ struct module_symbols_t ((p_symbols)->vlc_gai_strerror_inner) = vlc_gai_strerror; \ ((p_symbols)->net_ListenClose_inner) = net_ListenClose; \ ((p_symbols)->DigestMD5_inner) = DigestMD5; \ - ((p_symbols)->__net_CheckIP_inner) = __net_CheckIP; \ + ((p_symbols)->ACL_Check_inner) = ACL_Check; \ ((p_symbols)->playlist_NodeRemoveParent_inner) = playlist_NodeRemoveParent; \ + ((p_symbols)->__ACL_Duplicate_inner) = __ACL_Duplicate; \ + ((p_symbols)->__ACL_Create_inner) = __ACL_Create; \ + ((p_symbols)->ACL_LoadFile_inner) = ACL_LoadFile; \ + ((p_symbols)->ACL_AddNet_inner) = ACL_AddNet; \ + ((p_symbols)->ACL_Destroy_inner) = ACL_Destroy; \ (p_symbols)->net_ConvertIPv4_deprecated = NULL; \ # endif /* __PLUGIN__ */ diff --git a/modules/access_output/http.c b/modules/access_output/http.c index b411dd843a..32ba5c1b22 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, NULL, 0 ); + psz_user, psz_pwd, NULL ); 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 a923d1140f..ffca4b8230 100644 --- a/modules/control/http.c +++ b/modules/control/http.c @@ -40,6 +40,7 @@ #include "vlc_httpd.h" #include "vlc_vlm.h" #include "vlc_tls.h" +#include "vlc_acl.h" #include "charset.h" #ifdef HAVE_SYS_STAT_H @@ -518,14 +519,13 @@ static int ParseDirectory( intf_thread_t *p_intf, char *psz_root, #endif DIR *p_dir; struct dirent *p_dir_content; + vlc_acl_t *p_acl; FILE *file; char *user = NULL; char *password = NULL; - char **ppsz_hosts = NULL; - int i_hosts = 0; - int i, i_dirlen; + int i_dirlen; #ifdef HAVE_SYS_STAT_H if( stat( psz_dir, &stat_info ) == -1 || !S_ISDIR( stat_info.st_mode ) ) @@ -584,41 +584,9 @@ static int ParseDirectory( intf_thread_t *p_intf, char *psz_root, } 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 ); - } - } + p_acl = ACL_Create( p_intf, VLC_FALSE ); + ACL_LoadFile( p_acl, dir ); + for( ;; ) { @@ -659,7 +627,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, ppsz_hosts, i_hosts, + user, password, p_acl, HttpCallback, f ); if( f->p_file ) @@ -701,11 +669,8 @@ 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] ); - } + ACL_Destroy( p_acl ); closedir( p_dir ); return VLC_SUCCESS; diff --git a/modules/misc/rtsp.c b/modules/misc/rtsp.c index 54950c3aec..fe2e8b4902 100644 --- a/modules/misc/rtsp.c +++ b/modules/misc/rtsp.c @@ -276,8 +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, - NULL, 0 ); + httpd_UrlNewUnique( p_sys->p_rtsp_host, p_media->psz_rtsp_path, NULL, + NULL, NULL ); if( !p_media->p_rtsp_url ) { @@ -465,8 +465,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, NULL, - 0 ); + httpd_UrlNewUnique( p_vod->p_sys->p_rtsp_host, psz_urlc, NULL, NULL, + NULL ); if( !p_es->p_rtsp_url ) { @@ -637,7 +637,7 @@ static int RtspCallback( httpd_callback_sys_t *p_args, httpd_client_t *cl, answer->psz_status = strdup( "OK" ); httpd_MsgAdd( answer, "Content-type", "%s", "application/sdp" ); - answer->p_body = psz_sdp; + answer->p_body = (uint8_t *)psz_sdp; answer->i_body = strlen( psz_sdp ); break; } diff --git a/modules/stream_out/rtp.c b/modules/stream_out/rtp.c index a93c832b75..19ed74197d 100644 --- a/modules/stream_out/rtp.c +++ b/modules/stream_out/rtp.c @@ -1049,7 +1049,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, NULL, 0 ); + id->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, psz_urlc, NULL, NULL, NULL ); if( id->p_rtsp_url ) { @@ -1313,7 +1313,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, 0, + NULL, NULL, NULL, HttpCallback, (void*)p_sys ); } if( p_sys->p_httpd_file == NULL ) @@ -1411,7 +1411,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, NULL, 0 ); + p_sys->p_rtsp_url = httpd_UrlNewUnique( p_sys->p_rtsp_host, p_sys->psz_rtsp_path, NULL, NULL, NULL ); if( p_sys->p_rtsp_url == 0 ) { return VLC_EGENERIC; diff --git a/src/misc/httpd.c b/src/misc/httpd.c index 54955ec53e..b3e4d001be 100644 --- a/src/misc/httpd.c +++ b/src/misc/httpd.c @@ -30,6 +30,7 @@ #include "vlc_httpd.h" #include "network.h" #include "vlc_tls.h" +#include "vlc_acl.h" #include #include @@ -234,11 +235,10 @@ struct httpd_url_t vlc_mutex_t lock; - char *psz_url; - char *psz_user; - char *psz_password; - char **ppsz_hosts; - int i_hosts; + char *psz_url; + char *psz_user; + char *psz_password; + vlc_acl_t *p_acl; struct { @@ -491,14 +491,13 @@ 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, + const vlc_acl_t *p_acl, 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, ppsz_hosts, i_hosts ) + psz_password, p_acl ) ) == NULL ) { free( file ); @@ -596,8 +595,7 @@ 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, - NULL, 0 ) ) ) + if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL, NULL ) ) ) { free( rdir ); return NULL; @@ -773,12 +771,12 @@ 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 **ppsz_hosts, int i_hosts ) + const vlc_acl_t *p_acl ) { httpd_stream_t *stream = malloc( sizeof( httpd_stream_t ) ); if( ( stream->url = httpd_UrlNewUnique( host, psz_url, psz_user, - psz_password, ppsz_hosts, i_hosts ) + psz_password, p_acl ) ) == NULL ) { free( stream ); @@ -1103,8 +1101,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 ) + const vlc_acl_t *p_acl, vlc_bool_t b_check ) { httpd_url_t *url; int i; @@ -1131,12 +1128,7 @@ 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]) ); - } + url->p_acl = ACL_Duplicate( host, p_acl ); for( i = 0; i < HTTPD_MSG_MAX; i++ ) { url->catch[i].cb = NULL; @@ -1151,18 +1143,18 @@ 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 **ppsz_hosts, int i_hosts ) + const vlc_acl_t *p_acl ) { return httpd_UrlNewPrivate( host, psz_url, psz_user, - psz_password, ppsz_hosts, i_hosts, VLC_FALSE ); + psz_password, p_acl, VLC_FALSE ); } httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url, char *psz_user, char *psz_password, - char **ppsz_hosts, int i_hosts ) + const vlc_acl_t *p_acl ) { return httpd_UrlNewPrivate( host, psz_url, psz_user, - psz_password, ppsz_hosts, i_hosts, VLC_TRUE ); + psz_password, p_acl, VLC_TRUE ); } /* register callback on a url */ @@ -1191,10 +1183,7 @@ 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] ); - } + ACL_Destroy( url->p_acl ); for( i = 0; i < host->i_client; i++ ) { @@ -2085,14 +2074,12 @@ static void httpd_HostThread( httpd_host_t *host ) { if( url->catch[i_msg].cb ) { - if( answer && url->i_hosts ) + if( answer && ( url->p_acl != NULL ) ) { char *ip = httpd_ClientIP( cl ); if( ip != NULL ) { - if( net_CheckIP( host, ip, - url->ppsz_hosts, - url->i_hosts ) <= 0 ) + if( ACL_Check( url->p_acl, ip ) ) { b_hosts_failed = VLC_TRUE; free( ip ); @@ -2454,10 +2441,21 @@ httpd_host_t *httpd_HostNew( vlc_object_t *a, char *b, int c ) msg_Err( a, "HTTP daemon support is disabled" ); return 0; } -void httpd_HostDelete( httpd_host_t *a ){} -httpd_url_t *httpd_UrlNew( httpd_host_t *a, char *b ){ return 0; } -httpd_url_t *httpd_UrlNewUnique( httpd_host_t *a, char *b, char *c, - char *d ){ return 0; } +void httpd_HostDelete( httpd_host_t *a ) +{ +} +httpd_url_t *httpd_UrlNew( httpd_host_t *host, char *psz_url, + char *psz_user, char *psz_password, + const vlc_acl_t *p_acl ) +{ + return NULL; +} +httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url, + char *psz_user, char *psz_password, + const vlc_acl_t *p_acl ) +{ + return NULL; +} int httpd_UrlCatch( httpd_url_t *a, int b, httpd_callback_t c, httpd_callback_sys_t *d ){ return 0; } void httpd_UrlDelete( httpd_url_t *a ){} diff --git a/src/misc/modules.c b/src/misc/modules.c index bea7566a48..443d88526e 100644 --- a/src/misc/modules.c +++ b/src/misc/modules.c @@ -94,6 +94,7 @@ #include "stream_output.h" #include "osd.h" #include "vlc_httpd.h" +#include "vlc_acl.h" #include "vlc_tls.h" #include "vlc_md5.h" #include "vlc_xml.h" diff --git a/src/misc/net.c b/src/misc/net.c index 6735748724..a34877d027 100644 --- a/src/misc/net.c +++ b/src/misc/net.c @@ -1156,58 +1156,3 @@ 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( (ip.s_addr = inet_addr( psz_ip )) == INADDR_NONE ) - { - 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 = htonl( ntohl(INADDR_NONE) << (32 - i_mask) ); - } - else - mask.s_addr = INADDR_NONE; - - if( (base.s_addr = inet_addr( psz_host )) == INADDR_NONE ) - { - 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; -} - diff --git a/src/stream_output/acl.c b/src/stream_output/acl.c new file mode 100644 index 0000000000..386071baa7 --- /dev/null +++ b/src/stream_output/acl.c @@ -0,0 +1,346 @@ +/***************************************************************************** + * acl.c: + ***************************************************************************** + * Copyright (C) 2005 Rémi Denis-Courmont + * $Id$ + * + * Authors: Rémi Denis-Courmont + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include +#include + +#include "vlc_acl.h" + +#if defined( WIN32 ) || defined( UNDER_CE ) +# include +# include +#else +# include +# include +# include +#endif + +#include "network.h" + +/* FIXME: rwlock on acl, but libvlc doesn't implement rwlock */ +/* FIXME: move to src/stream_output/whatever */ +typedef struct vlc_acl_entry_t +{ + uint8_t host[17]; + uint8_t i_bytes_match; + uint8_t i_bits_mask; + vlc_bool_t b_allow; +} vlc_acl_entry_t; + +struct vlc_acl_t +{ + vlc_object_t *p_owner; + unsigned i_size; + vlc_acl_entry_t *p_entries; + vlc_bool_t b_allow_default; +}; + +static int ACL_Resolve( vlc_object_t *p_this, uint8_t *p_bytes, + const char *psz_ip ) +{ + struct addrinfo hints = { }, *res; + int i_family; + + hints.ai_socktype = SOCK_STREAM; /* doesn't matter */ + hints.ai_flags = AI_NUMERICHOST; + + if( vlc_getaddrinfo( p_this, psz_ip, 0, &hints, &res ) ) + { + msg_Err( p_this, "invalid IP address %s", psz_ip ); + return -1; + } + + p_bytes[16] = 0; /* avoids overflowing when i_bytes_match = 16 */ + + i_family = res->ai_addr->sa_family; + switch( i_family ) + { + case AF_INET: + { + struct sockaddr_in *addr; + + addr = (struct sockaddr_in *)res->ai_addr; + memset( p_bytes, 0, 12 ); + memcpy( p_bytes + 12, &addr->sin_addr, 4 ); + break; + } + +#if defined (HAVE_GETADDRINFO) || defined (WIN32) + /* unfortunately many people define AF_INET6 + though they don't have struct sockaddr_in6 */ + case AF_INET6: + { + struct sockaddr_in6 *addr; + + addr = (struct sockaddr_in6 *)res->ai_addr; + memcpy( p_bytes, &addr->sin6_addr, 16 ); + break; + } +#endif + + default: + msg_Err( p_this, "IMPOSSIBLE: unknown address family!" ); + vlc_freeaddrinfo( res ); + return -1; + } + + vlc_freeaddrinfo( res ); + return i_family; +} + + +/* + * Returns 0 if allowed, 1 if not, -1 on error. + */ +int ACL_Check( vlc_acl_t *p_acl, const char *psz_ip ) +{ + const vlc_acl_entry_t *p_cur, *p_end; + uint8_t host[17]; + + if( p_acl == NULL ) + return -1; + + p_cur = p_acl->p_entries; + p_end = p_cur + p_acl->i_size; + + if( ACL_Resolve( p_acl->p_owner, host, psz_ip ) < 0 ) + return -1; + + while (p_cur < p_end) + { + unsigned i; + + i = p_cur->i_bytes_match; + if( (memcmp( p_cur->host, host, i ) == 0) + && (((p_cur->host[i] ^ host[i]) & p_cur->i_bits_mask) == 0) ) + return !p_cur->b_allow; + + p_cur++; + } + + return !p_acl->b_allow_default; +} + +int ACL_AddNet( vlc_acl_t *p_acl, const char *psz_ip, int i_len, + vlc_bool_t b_allow ) +{ + vlc_acl_entry_t *p_ent; + unsigned i_size; + div_t d; + int i_family; + + i_size = p_acl->i_size; + p_ent = (vlc_acl_entry_t *)realloc( p_acl->p_entries, + ++p_acl->i_size * sizeof( *p_ent ) ); + + if( p_ent == NULL ) + return -1; + + i_family = ACL_Resolve( p_acl->p_owner, p_ent->host, psz_ip ); + if( i_family < 0 ) + { + /* + * I'm lazy : memory space will be re-used in the next ACL_Add call... + * or not. + */ + p_acl->i_size--; + return -1; + } + + if( i_len >= 0 ) + { + if( i_family == AF_INET ) + i_len += 96; + + p_acl->p_entries = p_ent; + p_ent += i_size; + + if( i_len > 128 ) + i_len = 128; + else + if( i_len < 0 ) + i_len = 0; + } + else + i_len = 128; /* ACL_AddHost */ + + d = div( i_len, 8 ); + p_ent->i_bytes_match = d.quot; + p_ent->i_bits_mask = 0xff << (8 - d.rem); + + p_ent->b_allow = b_allow; + return 0; +} + + +vlc_acl_t *__ACL_Create( vlc_object_t *p_this, vlc_bool_t b_allow ) +{ + vlc_acl_t *p_acl; + + p_acl = (vlc_acl_t *)malloc( sizeof( *p_acl ) ); + if( p_acl == NULL ) + return NULL; + + vlc_object_yield( p_this ); + p_acl->p_owner = p_this; + p_acl->i_size = 0; + p_acl->p_entries = NULL; + p_acl->b_allow_default = b_allow; + + return p_acl; +} + + +vlc_acl_t *__ACL_Duplicate( vlc_object_t *p_this, const vlc_acl_t *p_acl ) +{ + vlc_acl_t *p_dupacl; + + if( p_acl == NULL ) + return NULL; + + p_dupacl = (vlc_acl_t *)malloc( sizeof( *p_dupacl ) ); + if( p_dupacl == NULL ) + return NULL; + + p_dupacl->p_entries = (vlc_acl_entry_t *) + malloc( p_acl->i_size * sizeof( vlc_acl_entry_t ) ); + if( p_dupacl->p_entries == NULL ) + { + free( p_dupacl ); + return NULL; + } + + vlc_object_yield( p_this ); + p_dupacl->p_owner = p_this; + p_dupacl->i_size = p_acl->i_size; + memcpy( p_dupacl->p_entries, p_acl->p_entries, + p_dupacl->i_size * sizeof( vlc_acl_entry_t ) ); + + return p_dupacl; +} + + +void ACL_Destroy( vlc_acl_t *p_acl ) +{ + if( p_acl != NULL ) + { + if( p_acl->p_entries != NULL ) + free( p_acl->p_entries ); + + vlc_object_release( p_acl->p_owner ); + free( p_acl ); + } +} + + +int ACL_LoadFile( vlc_acl_t *p_acl, const char *psz_path ) +{ + FILE *file; + + if( p_acl == NULL ) + return -1; + + file = fopen( psz_path, "r" ); + if( file == NULL ) + return -1; + + msg_Dbg( p_acl->p_owner, "find .hosts in dir=%s", psz_path ); + + while( !feof( file ) ) + { + char line[1024], *psz_ip, *ptr; + + if( fgets( line, sizeof( line ) - 1, file ) == NULL ) + { + if( ferror( file ) ) + { + msg_Err( p_acl->p_owner, "Error reading %s : %s\n", psz_path, + strerror( errno ) ); + goto error; + } + continue; + } + + psz_ip = line; + + /* skips blanks */ + while( isblank( *psz_ip ) ) + psz_ip++; + + ptr = strchr( psz_ip, '\n' ); + if( ptr == NULL ) + { + msg_Warn( p_acl->p_owner, "Skipping overly long line in %s\n", + psz_path); + do + { + fgets( line, sizeof( line ) - 1, file ); + if( ferror( file ) || feof( file ) ) + { + msg_Err( p_acl->p_owner, "Error reading %s : %s\n", + psz_path, strerror( errno ) ); + goto error; + } + } + while( strchr( line, '\n' ) == NULL); + + continue; /* skip unusable line */ + } + + /* skips comment-only line */ + if( *psz_ip == '#' ) + continue; + + /* looks for first space, CR, LF, etc. or end-of-line comment */ + /* (there is at least a linefeed) */ + for( ptr = psz_ip; ( *ptr != '#' ) && !isspace( *ptr ); ptr++ ); + + *ptr = '\0'; + + msg_Dbg( p_acl->p_owner, "restricted to %s", psz_ip ); + + ptr = strchr( psz_ip, '/' ); + if( ptr != NULL ) + *ptr++ = '\0'; /* separate address from mask length */ + + if( (ptr != NULL) + ? ACL_AddNet( p_acl, psz_ip, atoi( ptr ), VLC_TRUE ) + : ACL_AddHost( p_acl, psz_ip, VLC_TRUE ) ) + { + msg_Err( p_acl->p_owner, "cannot add ACL from %s", psz_path ); + goto error; + } + } + + fclose( file ); + return 0; + +error: + fclose( file ); + return -1; +} +