acl.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:10k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * acl.c:
  3.  *****************************************************************************
  4.  * Copyright © 2005-2007 Rémi Denis-Courmont
  5.  * $Id: 37f21bcbbe1eeb57ee95fe9e675a7c4cdcde3ed2 $
  6.  *
  7.  * Authors: Rémi Denis-Courmont <rem # videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <ctype.h>
  31. #include <vlc_acl.h>
  32. #include <errno.h>
  33. #include <vlc_network.h>
  34. #include <vlc_charset.h>
  35. /* FIXME: rwlock on acl, but libvlc doesn't implement rwlock */
  36. typedef struct vlc_acl_entry_t
  37. {
  38.     uint8_t    host[17];
  39.     uint8_t    i_bytes_match;
  40.     uint8_t    i_bits_mask;
  41.     bool b_allow;
  42. } vlc_acl_entry_t;
  43. struct vlc_acl_t
  44. {
  45.     vlc_object_t    *p_owner;
  46.     unsigned         i_size;
  47.     vlc_acl_entry_t *p_entries;
  48.     bool       b_allow_default;
  49. };
  50. static int ACL_Resolve( vlc_object_t *p_this, uint8_t *p_bytes,
  51.                         const char *psz_ip )
  52. {
  53.     struct addrinfo hints, *res;
  54.     int i_family;
  55.     memset (&hints, 0, sizeof (hints));
  56.     hints.ai_socktype = SOCK_STREAM; /* doesn't matter */
  57.     hints.ai_flags = AI_NUMERICHOST;
  58.     if( vlc_getaddrinfo( p_this, psz_ip, 0, &hints, &res ) )
  59.     {
  60.         msg_Err( p_this, "invalid IP address %s", psz_ip );
  61.         return -1;
  62.     }
  63.     p_bytes[16] = 0; /* avoids overflowing when i_bytes_match = 16 */
  64.     i_family = res->ai_addr->sa_family;
  65.     switch( i_family )
  66.     {
  67.         case AF_INET:
  68.         {
  69.             struct sockaddr_in *addr;
  70.             addr = (struct sockaddr_in *)res->ai_addr;
  71.             memset( p_bytes, 0, 12 );
  72.             memcpy( p_bytes + 12, &addr->sin_addr, 4 );
  73.             break;
  74.         }
  75. #if defined (HAVE_GETADDRINFO) || defined (WIN32)
  76.         /* unfortunately many people define AF_INET6
  77.            though they don't have struct sockaddr_in6 */
  78.         case AF_INET6:
  79.         {
  80.             struct sockaddr_in6 *addr;
  81.             addr = (struct sockaddr_in6 *)res->ai_addr;
  82.             memcpy( p_bytes, &addr->sin6_addr, 16 );
  83.             break;
  84.         }
  85. #endif
  86.         default:
  87.             msg_Err( p_this, "unknown address family" );
  88.             vlc_freeaddrinfo( res );
  89.             return -1;
  90.     }
  91.     vlc_freeaddrinfo( res );
  92.     return i_family;
  93. }
  94. /**
  95.  * Check if a given address passes an access control list.
  96.  *
  97.  * @param p_acl pre-existing ACL to match the address against
  98.  * @param psz_ip numeric IPv4/IPv6 address
  99.  *
  100.  * @return 0 if the first matching ACL entry is an access grant,
  101.  * 1 if the first matching ACL entry is a denial of access,
  102.  * -1 on error.
  103.  */
  104. int ACL_Check( vlc_acl_t *p_acl, const char *psz_ip )
  105. {
  106.     const vlc_acl_entry_t *p_cur, *p_end;
  107.     uint8_t host[17];
  108.     if( p_acl == NULL )
  109.         return -1;
  110.     p_cur = p_acl->p_entries;
  111.     p_end = p_cur + p_acl->i_size;
  112.     if( ACL_Resolve( p_acl->p_owner, host, psz_ip ) < 0 )
  113.         return -1;
  114.     while (p_cur < p_end)
  115.     {
  116.         unsigned i;
  117.         i = p_cur->i_bytes_match;
  118.         if( (memcmp( p_cur->host, host, i ) == 0)
  119.          && (((p_cur->host[i] ^ host[i]) & p_cur->i_bits_mask) == 0) )
  120.             return !p_cur->b_allow;
  121.         p_cur++;
  122.     }
  123.     return !p_acl->b_allow_default;
  124. }
  125. /**
  126.  * Adds an item to an ACL.
  127.  * Items are always matched in the same order as they are added.
  128.  */
  129. int ACL_AddNet( vlc_acl_t *p_acl, const char *psz_ip, int i_len,
  130.                 bool b_allow )
  131. {
  132.     vlc_acl_entry_t *p_ent;
  133.     unsigned i_size;
  134.     div_t d;
  135.     int i_family;
  136.     i_size = p_acl->i_size;
  137.     p_ent = (vlc_acl_entry_t *)realloc( p_acl->p_entries,
  138.                                         ++p_acl->i_size * sizeof( *p_ent ) );
  139.     if( p_ent == NULL )
  140.         return -1;
  141.     p_acl->p_entries = p_ent;
  142.     p_ent += i_size;
  143.     i_family = ACL_Resolve( p_acl->p_owner, p_ent->host, psz_ip );
  144.     if( i_family < 0 )
  145.     {
  146.         /*
  147.          * I'm lazy : memory space will be re-used in the next ACL_Add call...
  148.          * or not.
  149.          */
  150.         p_acl->i_size--;
  151.         return -1;
  152.     }
  153.     if( i_len >= 0 )
  154.     {
  155.         if( i_family == AF_INET )
  156.             i_len += 96;
  157.         if( i_len > 128 )
  158.             i_len = 128;
  159.     }
  160.     else
  161.         i_len = 128; /* ACL_AddHost */
  162.     d = div( i_len, 8 );
  163.     p_ent->i_bytes_match = d.quot;
  164.     p_ent->i_bits_mask = 0xff << (8 - d.rem);
  165.     p_ent->b_allow = b_allow;
  166.     return 0;
  167. }
  168. /**
  169.  * Creates an empty ACL.
  170.  *
  171.  * @param b_allow whether to grant (true) or deny (false) access
  172.  * by default (ie if none of the ACL entries matched).
  173.  *
  174.  * @return an ACL object. NULL in case of error.
  175.  */
  176. vlc_acl_t *__ACL_Create( vlc_object_t *p_this, bool b_allow )
  177. {
  178.     vlc_acl_t *p_acl;
  179.     p_acl = (vlc_acl_t *)malloc( sizeof( *p_acl ) );
  180.     if( p_acl == NULL )
  181.         return NULL;
  182.     vlc_object_hold( p_this );
  183.     p_acl->p_owner = p_this;
  184.     p_acl->i_size = 0;
  185.     p_acl->p_entries = NULL;
  186.     p_acl->b_allow_default = b_allow;
  187.     return p_acl;
  188. }
  189. /**
  190.  * Perform a deep copy of an existing ACL.
  191.  *
  192.  * @param p_this object to attach the copy to.
  193.  * @param p_acl ACL object to be copied.
  194.  *
  195.  * @return a new ACL object, or NULL on error.
  196.  */
  197. vlc_acl_t *__ACL_Duplicate( vlc_object_t *p_this, const vlc_acl_t *p_acl )
  198. {
  199.     vlc_acl_t *p_dupacl;
  200.     if( p_acl == NULL )
  201.         return NULL;
  202.     p_dupacl = (vlc_acl_t *)malloc( sizeof( *p_dupacl ) );
  203.     if( p_dupacl == NULL )
  204.         return NULL;
  205.     if( p_acl->i_size )
  206.     {
  207.         p_dupacl->p_entries = (vlc_acl_entry_t *)
  208.             malloc( p_acl->i_size * sizeof( vlc_acl_entry_t ) );
  209.         if( p_dupacl->p_entries == NULL )
  210.         {
  211.             free( p_dupacl );
  212.             return NULL;
  213.         }
  214.         memcpy( p_dupacl->p_entries, p_acl->p_entries,
  215.                 p_acl->i_size * sizeof( vlc_acl_entry_t ) );
  216.     }
  217.     else
  218.         p_dupacl->p_entries = NULL;
  219.     vlc_object_hold( p_this );
  220.     p_dupacl->p_owner = p_this;
  221.     p_dupacl->i_size = p_acl->i_size;
  222.     p_dupacl->b_allow_default = p_acl->b_allow_default;
  223.     return p_dupacl;
  224. }
  225. /**
  226.  * Releases all resources associated with an ACL object.
  227.  */
  228. void ACL_Destroy( vlc_acl_t *p_acl )
  229. {
  230.     if( p_acl != NULL )
  231.     {
  232.         if( p_acl->p_entries != NULL )
  233.             free( p_acl->p_entries );
  234.         vlc_object_release( p_acl->p_owner );
  235.         free( p_acl );
  236.     }
  237. }
  238. /**
  239.  * Reads ACL entries from a file.
  240.  *
  241.  * @param p_acl ACL object in which to insert parsed entries.
  242.  * @param psz_patch filename from which to parse entries.
  243.  *
  244.  * @return 0 on success, -1 on error.
  245.  */
  246. int ACL_LoadFile( vlc_acl_t *p_acl, const char *psz_path )
  247. {
  248.     FILE *file;
  249.     if( p_acl == NULL )
  250.         return -1;
  251.     file = utf8_fopen( psz_path, "r" );
  252.     if( file == NULL )
  253.         return -1;
  254.     msg_Dbg( p_acl->p_owner, "find .hosts in dir=%s", psz_path );
  255.     while( !feof( file ) )
  256.     {
  257.         char line[1024], *psz_ip, *ptr;
  258.         if( fgets( line, sizeof( line ), file ) == NULL )
  259.         {
  260.             if( ferror( file ) )
  261.             {
  262.                 msg_Err( p_acl->p_owner, "error reading %s : %m", psz_path );
  263.                 goto error;
  264.             }
  265.             continue;
  266.         }
  267.         /* fgets() is cool : never overflow, always nul-terminate */
  268.         psz_ip = line;
  269.         /* skips blanks - cannot overflow given '' is not space */
  270.         while( isspace( *psz_ip ) )
  271.             psz_ip++;
  272.         if( *psz_ip == '' ) /* empty/blank line */
  273.             continue;
  274.         ptr = strchr( psz_ip, 'n' );
  275.         if( ptr == NULL && !feof(file) )
  276.         {
  277.             msg_Warn( p_acl->p_owner, "skipping overly long line in %s",
  278.                       psz_path);
  279.             do
  280.             {
  281.                 if( fgets( line, sizeof( line ), file ) == NULL )
  282.                 {
  283.                      if( ferror( file ) )
  284.                      {
  285.                          msg_Err( p_acl->p_owner, "error reading %s : %m",
  286.                                   psz_path );
  287.                      }
  288.                      goto error;
  289.                 }
  290.             }
  291.             while( strchr( line, 'n' ) == NULL);
  292.             continue; /* skip unusable line */
  293.         }
  294.         /* look for first space, CR, LF, etc. or comment character */
  295.         for( ptr = psz_ip; ( *ptr!='#' ) && !isspace( *ptr ) && *ptr; ++ptr );
  296.         *ptr = '';
  297.         /* skip lines without usable information */
  298.         if( ptr == psz_ip )
  299.             continue;
  300.         msg_Dbg( p_acl->p_owner, "restricted to %s", psz_ip );
  301.         ptr = strchr( psz_ip, '/' );
  302.         if( ptr != NULL )
  303.             *ptr++ = ''; /* separate address from mask length */
  304.         if( (ptr != NULL)
  305.             ? ACL_AddNet( p_acl, psz_ip, atoi( ptr ), true )
  306.             : ACL_AddHost( p_acl, psz_ip, true ) )
  307.         {
  308.             msg_Err( p_acl->p_owner, "cannot add ACL from %s", psz_path );
  309.             continue;
  310.         }
  311.     }
  312.     fclose( file );
  313.     return 0;
  314. error:
  315.     fclose( file );
  316.     return -1;
  317. }