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 \
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 \
# 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 */
--- /dev/null
+/*****************************************************************************
+ * 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 <rem # videolan.org>
+ *
+ * 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
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;
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 */
/* 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 * ) );
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 ) );
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);
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
# 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.
((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__ */
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 );
#include "vlc_httpd.h"
#include "vlc_vlm.h"
#include "vlc_tls.h"
+#include "vlc_acl.h"
#include "charset.h"
#ifdef HAVE_SYS_STAT_H
#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 ) )
}
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( ;; )
{
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 )
{
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;
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 )
{
}
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 )
{
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;
}
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 )
{
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 )
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;
#include "vlc_httpd.h"
#include "network.h"
#include "vlc_tls.h"
+#include "vlc_acl.h"
#include <string.h>
#include <errno.h>
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
{
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 );
{
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;
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 );
/* 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;
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;
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 */
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++ )
{
{
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 );
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 ){}
#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"
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;
-}
-
--- /dev/null
+/*****************************************************************************
+ * acl.c:
+ *****************************************************************************
+ * Copyright (C) 2005 Rémi Denis-Courmont
+ * $Id$
+ *
+ * Authors: Rémi Denis-Courmont <rem # videolan.org>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <vlc/vlc.h>
+
+#include "vlc_acl.h"
+
+#if defined( WIN32 ) || defined( UNDER_CE )
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <netdb.h>
+#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;
+}
+