Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

acl.c

00001 /*****************************************************************************
00002  * acl.c:
00003  *****************************************************************************
00004  * Copyright (C) 2005 Rémi Denis-Courmont
00005  * $Id$
00006  *
00007  * Authors: Rémi Denis-Courmont <rem # videolan.org>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <ctype.h>
00030 #include <vlc/vlc.h>
00031 
00032 #include "vlc_acl.h"
00033 
00034 #include <errno.h>
00035 
00036 #include "network.h"
00037 
00038 /* FIXME: rwlock on acl, but libvlc doesn't implement rwlock */
00039 typedef struct vlc_acl_entry_t
00040 {
00041     uint8_t    host[17];
00042     uint8_t    i_bytes_match;
00043     uint8_t    i_bits_mask;
00044     vlc_bool_t b_allow;
00045 } vlc_acl_entry_t;
00046 
00047 struct vlc_acl_t
00048 {
00049     vlc_object_t    *p_owner;
00050     unsigned         i_size;
00051     vlc_acl_entry_t *p_entries;
00052     vlc_bool_t       b_allow_default;
00053 };
00054 
00055 static int ACL_Resolve( vlc_object_t *p_this, uint8_t *p_bytes,
00056                         const char *psz_ip )
00057 {
00058     struct addrinfo hints = { 0 }, *res;
00059     int i_family;
00060 
00061     hints.ai_socktype = SOCK_STREAM; /* doesn't matter */
00062     hints.ai_flags = AI_NUMERICHOST;
00063 
00064     if( vlc_getaddrinfo( p_this, psz_ip, 0, &hints, &res ) )
00065     {
00066         msg_Err( p_this, "invalid IP address %s", psz_ip );
00067         return -1;
00068     }
00069 
00070     p_bytes[16] = 0; /* avoids overflowing when i_bytes_match = 16 */
00071 
00072     i_family = res->ai_addr->sa_family;
00073     switch( i_family )
00074     {
00075         case AF_INET:
00076         {
00077             struct sockaddr_in *addr;
00078 
00079             addr = (struct sockaddr_in *)res->ai_addr;
00080             memset( p_bytes, 0, 12 );
00081             memcpy( p_bytes + 12, &addr->sin_addr, 4 );
00082             break;
00083         }
00084 
00085 #if defined (HAVE_GETADDRINFO) || defined (WIN32)
00086         /* unfortunately many people define AF_INET6
00087            though they don't have struct sockaddr_in6 */
00088         case AF_INET6:
00089         {
00090             struct sockaddr_in6 *addr;
00091 
00092             addr = (struct sockaddr_in6 *)res->ai_addr;
00093             memcpy( p_bytes, &addr->sin6_addr, 16 );
00094             break;
00095         }
00096 #endif
00097 
00098         default:
00099             msg_Err( p_this, "IMPOSSIBLE: unknown address family!" );
00100             vlc_freeaddrinfo( res );
00101             return -1;
00102     }
00103 
00104     vlc_freeaddrinfo( res );
00105     return i_family;
00106 }
00107 
00108 
00109 /*
00110  * Returns 0 if allowed, 1 if not, -1 on error.
00111  */
00112 int ACL_Check( vlc_acl_t *p_acl, const char *psz_ip )
00113 {
00114     const vlc_acl_entry_t *p_cur, *p_end;
00115     uint8_t host[17];
00116 
00117     if( p_acl == NULL )
00118         return -1;
00119 
00120     p_cur = p_acl->p_entries;
00121     p_end = p_cur + p_acl->i_size;
00122 
00123     if( ACL_Resolve( p_acl->p_owner, host, psz_ip ) < 0 )
00124         return -1;
00125 
00126     while (p_cur < p_end)
00127     {
00128         unsigned i;
00129 
00130         i = p_cur->i_bytes_match;
00131         if( (memcmp( p_cur->host, host, i ) == 0)
00132          && (((p_cur->host[i] ^ host[i]) & p_cur->i_bits_mask) == 0) )
00133             return !p_cur->b_allow;
00134 
00135         p_cur++;
00136     }
00137 
00138     return !p_acl->b_allow_default;
00139 }
00140 
00141 int ACL_AddNet( vlc_acl_t *p_acl, const char *psz_ip, int i_len,
00142                 vlc_bool_t b_allow )
00143 {
00144     vlc_acl_entry_t *p_ent;
00145     unsigned i_size;
00146     div_t d;
00147     int i_family;
00148 
00149     i_size = p_acl->i_size;
00150     p_ent = (vlc_acl_entry_t *)realloc( p_acl->p_entries,
00151                                         ++p_acl->i_size * sizeof( *p_ent ) );
00152 
00153     if( p_ent == NULL )
00154         return -1;
00155 
00156     p_acl->p_entries = p_ent;
00157     p_ent += i_size;
00158 
00159     i_family = ACL_Resolve( p_acl->p_owner, p_ent->host, psz_ip );
00160     if( i_family < 0 )
00161     {
00162         /*
00163          * I'm lazy : memory space will be re-used in the next ACL_Add call...
00164          * or not.
00165          */
00166         p_acl->i_size--;
00167         return -1;
00168     }
00169 
00170     if( i_len >= 0 )
00171     {
00172         if( i_family == AF_INET )
00173             i_len += 96;
00174 
00175         if( i_len > 128 )
00176             i_len = 128;
00177         else
00178         if( i_len < 0 )
00179             i_len = 0;
00180     }
00181     else
00182         i_len = 128; /* ACL_AddHost */
00183 
00184     d = div( i_len, 8 );
00185     p_ent->i_bytes_match = d.quot;
00186     p_ent->i_bits_mask = 0xff << (8 - d.rem);
00187 
00188     p_ent->b_allow = b_allow;
00189     return 0;
00190 }
00191 
00192 
00193 vlc_acl_t *__ACL_Create( vlc_object_t *p_this, vlc_bool_t b_allow )
00194 {
00195     vlc_acl_t *p_acl;
00196 
00197     p_acl = (vlc_acl_t *)malloc( sizeof( *p_acl ) );
00198     if( p_acl == NULL )
00199         return NULL;
00200 
00201     vlc_object_yield( p_this );
00202     p_acl->p_owner = p_this;
00203     p_acl->i_size = 0;
00204     p_acl->p_entries = NULL;
00205     p_acl->b_allow_default = b_allow;
00206 
00207     return p_acl;
00208 }
00209 
00210 
00211 vlc_acl_t *__ACL_Duplicate( vlc_object_t *p_this, const vlc_acl_t *p_acl )
00212 {
00213     vlc_acl_t *p_dupacl;
00214 
00215     if( p_acl == NULL )
00216         return NULL;
00217 
00218     p_dupacl = (vlc_acl_t *)malloc( sizeof( *p_dupacl ) );
00219     if( p_dupacl == NULL )
00220         return NULL;
00221 
00222     if( p_acl->i_size )
00223     {
00224         p_dupacl->p_entries = (vlc_acl_entry_t *)
00225             malloc( p_acl->i_size * sizeof( vlc_acl_entry_t ) );
00226 
00227         if( p_dupacl->p_entries == NULL )
00228         {
00229             free( p_dupacl );
00230             return NULL;
00231         }
00232 
00233         memcpy( p_dupacl->p_entries, p_acl->p_entries,
00234                 p_acl->i_size * sizeof( vlc_acl_entry_t ) );
00235     }
00236     else
00237         p_dupacl->p_entries = NULL;
00238 
00239     vlc_object_yield( p_this );
00240     p_dupacl->p_owner = p_this;
00241     p_dupacl->i_size = p_acl->i_size;
00242     p_dupacl->b_allow_default = p_acl->b_allow_default;
00243 
00244     return p_dupacl;
00245 }
00246 
00247 
00248 void ACL_Destroy( vlc_acl_t *p_acl )
00249 {
00250     if( p_acl != NULL )
00251     {
00252         if( p_acl->p_entries != NULL )
00253             free( p_acl->p_entries );
00254 
00255         vlc_object_release( p_acl->p_owner );
00256         free( p_acl );
00257     }
00258 }
00259 
00260 #ifndef isblank 
00261 #   define isblank(c) ((c) == ' ' || (c) == '\t')
00262 #endif
00263 
00264 int ACL_LoadFile( vlc_acl_t *p_acl, const char *psz_path )
00265 {
00266     FILE *file;
00267 
00268     if( p_acl == NULL )
00269         return -1;
00270 
00271     file = fopen( psz_path, "r" );
00272     if( file == NULL )
00273         return -1;
00274 
00275     msg_Dbg( p_acl->p_owner, "find .hosts in dir=%s", psz_path );
00276 
00277     while( !feof( file ) )
00278     {
00279         char line[1024], *psz_ip, *ptr;
00280 
00281         if( fgets( line, sizeof( line ), file ) == NULL )
00282         {
00283             if( ferror( file ) )
00284             {
00285                 msg_Err( p_acl->p_owner, "Error reading %s : %s\n", psz_path,
00286                         strerror( errno ) );
00287                 goto error;
00288             }
00289             continue;
00290         }
00291 
00292         /* fgets() is cool : never overflow, always nul-terminate */
00293         psz_ip = line;
00294 
00295         /* skips blanks - cannot overflow given '\0' is not space */
00296         while( isspace( *psz_ip ) )
00297             psz_ip++;
00298 
00299         if( *psz_ip == '\0' )
00300             continue;
00301 
00302         ptr = strchr( psz_ip, '\n' );
00303         if( ptr == NULL )
00304         {
00305             msg_Warn( p_acl->p_owner, "Skipping overly long line in %s\n",
00306                       psz_path);
00307             do
00308             {
00309                 fgets( line, sizeof( line ), file );
00310                 if( ferror( file ) || feof( file ) )
00311                 {
00312                     msg_Err( p_acl->p_owner, "Error reading %s : %s\n",
00313                              psz_path, strerror( errno ) );
00314                     goto error;
00315                 }
00316             }
00317             while( strchr( line, '\n' ) == NULL);
00318 
00319             continue; /* skip unusable line */
00320         }
00321 
00322         /* skips comment-only line */
00323         if( *psz_ip == '#' )
00324             continue;
00325 
00326         /* looks for first space, CR, LF, etc. or end-of-line comment */
00327         /* (there is at least a linefeed) */
00328         for( ptr = psz_ip; ( *ptr != '#' ) && !isspace( *ptr ); ptr++ );
00329 
00330         *ptr = '\0';
00331 
00332         msg_Dbg( p_acl->p_owner, "restricted to %s", psz_ip );
00333 
00334         ptr = strchr( psz_ip, '/' );
00335         if( ptr != NULL )
00336             *ptr++ = '\0'; /* separate address from mask length */
00337 
00338         if( (ptr != NULL)
00339             ? ACL_AddNet( p_acl, psz_ip, atoi( ptr ), VLC_TRUE ) 
00340             : ACL_AddHost( p_acl, psz_ip, VLC_TRUE ) )
00341         {
00342             msg_Err( p_acl->p_owner, "cannot add ACL from %s", psz_path );
00343             goto error;
00344         }
00345     }
00346 
00347     fclose( file );
00348     return 0;
00349 
00350 error:
00351     fclose( file );
00352     return -1;
00353 }
00354 

Generated on Tue Dec 20 10:15:01 2005 for vlc-0.8.4a by  doxygen 1.4.2