153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 953a5a1b3Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of the 1053a5a1b3Sopenharmony_ci License, or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci Lesser General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public 1853a5a1b3Sopenharmony_ci License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#include <sys/types.h> 2653a5a1b3Sopenharmony_ci#include <sys/types.h> 2753a5a1b3Sopenharmony_ci#include <string.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 3053a5a1b3Sopenharmony_ci#include <netinet/in.h> 3153a5a1b3Sopenharmony_ci#endif 3253a5a1b3Sopenharmony_ci#ifdef HAVE_NETINET_IN_SYSTM_H 3353a5a1b3Sopenharmony_ci#include <netinet/in_systm.h> 3453a5a1b3Sopenharmony_ci#endif 3553a5a1b3Sopenharmony_ci#ifdef HAVE_NETINET_IP_H 3653a5a1b3Sopenharmony_ci#include <netinet/ip.h> 3753a5a1b3Sopenharmony_ci#endif 3853a5a1b3Sopenharmony_ci 3953a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 4053a5a1b3Sopenharmony_ci 4153a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 4253a5a1b3Sopenharmony_ci#include <pulsecore/llist.h> 4353a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 4453a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 4553a5a1b3Sopenharmony_ci#include <pulsecore/socket.h> 4653a5a1b3Sopenharmony_ci#include <pulsecore/arpa-inet.h> 4753a5a1b3Sopenharmony_ci 4853a5a1b3Sopenharmony_ci#include "ipacl.h" 4953a5a1b3Sopenharmony_ci 5053a5a1b3Sopenharmony_cistruct acl_entry { 5153a5a1b3Sopenharmony_ci PA_LLIST_FIELDS(struct acl_entry); 5253a5a1b3Sopenharmony_ci int family; 5353a5a1b3Sopenharmony_ci struct in_addr address_ipv4; 5453a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6 5553a5a1b3Sopenharmony_ci struct in6_addr address_ipv6; 5653a5a1b3Sopenharmony_ci#endif 5753a5a1b3Sopenharmony_ci int bits; 5853a5a1b3Sopenharmony_ci}; 5953a5a1b3Sopenharmony_ci 6053a5a1b3Sopenharmony_cistruct pa_ip_acl { 6153a5a1b3Sopenharmony_ci PA_LLIST_HEAD(struct acl_entry, entries); 6253a5a1b3Sopenharmony_ci}; 6353a5a1b3Sopenharmony_ci 6453a5a1b3Sopenharmony_cipa_ip_acl* pa_ip_acl_new(const char *s) { 6553a5a1b3Sopenharmony_ci const char *state = NULL; 6653a5a1b3Sopenharmony_ci char *a; 6753a5a1b3Sopenharmony_ci pa_ip_acl *acl; 6853a5a1b3Sopenharmony_ci 6953a5a1b3Sopenharmony_ci pa_assert(s); 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_ci acl = pa_xnew(pa_ip_acl, 1); 7253a5a1b3Sopenharmony_ci PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries); 7353a5a1b3Sopenharmony_ci 7453a5a1b3Sopenharmony_ci while ((a = pa_split(s, ";", &state))) { 7553a5a1b3Sopenharmony_ci char *slash; 7653a5a1b3Sopenharmony_ci struct acl_entry e, *n; 7753a5a1b3Sopenharmony_ci uint32_t bits; 7853a5a1b3Sopenharmony_ci 7953a5a1b3Sopenharmony_ci if ((slash = strchr(a, '/'))) { 8053a5a1b3Sopenharmony_ci *slash = 0; 8153a5a1b3Sopenharmony_ci slash++; 8253a5a1b3Sopenharmony_ci if (pa_atou(slash, &bits) < 0) { 8353a5a1b3Sopenharmony_ci pa_log_warn("Failed to parse number of bits: %s", slash); 8453a5a1b3Sopenharmony_ci goto fail; 8553a5a1b3Sopenharmony_ci } 8653a5a1b3Sopenharmony_ci } else 8753a5a1b3Sopenharmony_ci bits = (uint32_t) -1; 8853a5a1b3Sopenharmony_ci 8953a5a1b3Sopenharmony_ci if (inet_pton(AF_INET, a, &e.address_ipv4) > 0) { 9053a5a1b3Sopenharmony_ci 9153a5a1b3Sopenharmony_ci e.bits = bits == (uint32_t) -1 ? 32 : (int) bits; 9253a5a1b3Sopenharmony_ci 9353a5a1b3Sopenharmony_ci if (e.bits > 32) { 9453a5a1b3Sopenharmony_ci pa_log_warn("Number of bits out of range: %i", e.bits); 9553a5a1b3Sopenharmony_ci goto fail; 9653a5a1b3Sopenharmony_ci } 9753a5a1b3Sopenharmony_ci 9853a5a1b3Sopenharmony_ci e.family = AF_INET; 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0) 10153a5a1b3Sopenharmony_ci pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits); 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6 10453a5a1b3Sopenharmony_ci } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) { 10553a5a1b3Sopenharmony_ci 10653a5a1b3Sopenharmony_ci e.bits = bits == (uint32_t) -1 ? 128 : (int) bits; 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci if (e.bits > 128) { 10953a5a1b3Sopenharmony_ci pa_log_warn("Number of bits out of range: %i", e.bits); 11053a5a1b3Sopenharmony_ci goto fail; 11153a5a1b3Sopenharmony_ci } 11253a5a1b3Sopenharmony_ci e.family = AF_INET6; 11353a5a1b3Sopenharmony_ci 11453a5a1b3Sopenharmony_ci if (e.bits < 128) { 11553a5a1b3Sopenharmony_ci int t = 0, i; 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_ci for (i = 0, bits = (uint32_t) e.bits; i < 16; i++) { 11853a5a1b3Sopenharmony_ci 11953a5a1b3Sopenharmony_ci if (bits >= 8) 12053a5a1b3Sopenharmony_ci bits -= 8; 12153a5a1b3Sopenharmony_ci else { 12253a5a1b3Sopenharmony_ci if ((uint8_t) ((e.address_ipv6.s6_addr[i]) << bits) != 0) { 12353a5a1b3Sopenharmony_ci t = 1; 12453a5a1b3Sopenharmony_ci break; 12553a5a1b3Sopenharmony_ci } 12653a5a1b3Sopenharmony_ci bits = 0; 12753a5a1b3Sopenharmony_ci } 12853a5a1b3Sopenharmony_ci } 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci if (t) 13153a5a1b3Sopenharmony_ci pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits); 13253a5a1b3Sopenharmony_ci } 13353a5a1b3Sopenharmony_ci#endif 13453a5a1b3Sopenharmony_ci 13553a5a1b3Sopenharmony_ci } else { 13653a5a1b3Sopenharmony_ci pa_log_warn("Failed to parse address: %s", a); 13753a5a1b3Sopenharmony_ci goto fail; 13853a5a1b3Sopenharmony_ci } 13953a5a1b3Sopenharmony_ci 14053a5a1b3Sopenharmony_ci n = pa_xmemdup(&e, sizeof(struct acl_entry)); 14153a5a1b3Sopenharmony_ci PA_LLIST_PREPEND(struct acl_entry, acl->entries, n); 14253a5a1b3Sopenharmony_ci 14353a5a1b3Sopenharmony_ci pa_xfree(a); 14453a5a1b3Sopenharmony_ci } 14553a5a1b3Sopenharmony_ci 14653a5a1b3Sopenharmony_ci return acl; 14753a5a1b3Sopenharmony_ci 14853a5a1b3Sopenharmony_cifail: 14953a5a1b3Sopenharmony_ci pa_xfree(a); 15053a5a1b3Sopenharmony_ci pa_ip_acl_free(acl); 15153a5a1b3Sopenharmony_ci 15253a5a1b3Sopenharmony_ci return NULL; 15353a5a1b3Sopenharmony_ci} 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_civoid pa_ip_acl_free(pa_ip_acl *acl) { 15653a5a1b3Sopenharmony_ci pa_assert(acl); 15753a5a1b3Sopenharmony_ci 15853a5a1b3Sopenharmony_ci while (acl->entries) { 15953a5a1b3Sopenharmony_ci struct acl_entry *e = acl->entries; 16053a5a1b3Sopenharmony_ci PA_LLIST_REMOVE(struct acl_entry, acl->entries, e); 16153a5a1b3Sopenharmony_ci pa_xfree(e); 16253a5a1b3Sopenharmony_ci } 16353a5a1b3Sopenharmony_ci 16453a5a1b3Sopenharmony_ci pa_xfree(acl); 16553a5a1b3Sopenharmony_ci} 16653a5a1b3Sopenharmony_ci 16753a5a1b3Sopenharmony_ciint pa_ip_acl_check(pa_ip_acl *acl, int fd) { 16853a5a1b3Sopenharmony_ci struct sockaddr_storage sa; 16953a5a1b3Sopenharmony_ci struct acl_entry *e; 17053a5a1b3Sopenharmony_ci socklen_t salen; 17153a5a1b3Sopenharmony_ci 17253a5a1b3Sopenharmony_ci pa_assert(acl); 17353a5a1b3Sopenharmony_ci pa_assert(fd >= 0); 17453a5a1b3Sopenharmony_ci 17553a5a1b3Sopenharmony_ci salen = sizeof(sa); 17653a5a1b3Sopenharmony_ci if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0) 17753a5a1b3Sopenharmony_ci return -1; 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6 18053a5a1b3Sopenharmony_ci if (sa.ss_family != AF_INET && sa.ss_family != AF_INET6) 18153a5a1b3Sopenharmony_ci#else 18253a5a1b3Sopenharmony_ci if (sa.ss_family != AF_INET) 18353a5a1b3Sopenharmony_ci#endif 18453a5a1b3Sopenharmony_ci return -1; 18553a5a1b3Sopenharmony_ci 18653a5a1b3Sopenharmony_ci if (sa.ss_family == AF_INET && salen != sizeof(struct sockaddr_in)) 18753a5a1b3Sopenharmony_ci return -1; 18853a5a1b3Sopenharmony_ci 18953a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6 19053a5a1b3Sopenharmony_ci if (sa.ss_family == AF_INET6 && salen != sizeof(struct sockaddr_in6)) 19153a5a1b3Sopenharmony_ci return -1; 19253a5a1b3Sopenharmony_ci#endif 19353a5a1b3Sopenharmony_ci 19453a5a1b3Sopenharmony_ci for (e = acl->entries; e; e = e->next) { 19553a5a1b3Sopenharmony_ci 19653a5a1b3Sopenharmony_ci if (e->family != sa.ss_family) 19753a5a1b3Sopenharmony_ci continue; 19853a5a1b3Sopenharmony_ci 19953a5a1b3Sopenharmony_ci if (e->family == AF_INET) { 20053a5a1b3Sopenharmony_ci struct sockaddr_in *sai = (struct sockaddr_in*) &sa; 20153a5a1b3Sopenharmony_ci 20253a5a1b3Sopenharmony_ci if (e->bits == 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */ 20353a5a1b3Sopenharmony_ci (ntohl(sai->sin_addr.s_addr ^ e->address_ipv4.s_addr) >> (32 - e->bits)) == 0) 20453a5a1b3Sopenharmony_ci return 1; 20553a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6 20653a5a1b3Sopenharmony_ci } else if (e->family == AF_INET6) { 20753a5a1b3Sopenharmony_ci int i, bits; 20853a5a1b3Sopenharmony_ci struct sockaddr_in6 *sai = (struct sockaddr_in6*) &sa; 20953a5a1b3Sopenharmony_ci 21053a5a1b3Sopenharmony_ci if (e->bits == 128) 21153a5a1b3Sopenharmony_ci return memcmp(&sai->sin6_addr, &e->address_ipv6, 16) == 0; 21253a5a1b3Sopenharmony_ci 21353a5a1b3Sopenharmony_ci if (e->bits == 0) 21453a5a1b3Sopenharmony_ci return 1; 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_ci for (i = 0, bits = e->bits; i < 16; i++) { 21753a5a1b3Sopenharmony_ci 21853a5a1b3Sopenharmony_ci if (bits >= 8) { 21953a5a1b3Sopenharmony_ci if (sai->sin6_addr.s6_addr[i] != e->address_ipv6.s6_addr[i]) 22053a5a1b3Sopenharmony_ci break; 22153a5a1b3Sopenharmony_ci 22253a5a1b3Sopenharmony_ci bits -= 8; 22353a5a1b3Sopenharmony_ci } else { 22453a5a1b3Sopenharmony_ci if ((sai->sin6_addr.s6_addr[i] ^ e->address_ipv6.s6_addr[i]) >> (8 - bits) != 0) 22553a5a1b3Sopenharmony_ci break; 22653a5a1b3Sopenharmony_ci 22753a5a1b3Sopenharmony_ci bits = 0; 22853a5a1b3Sopenharmony_ci } 22953a5a1b3Sopenharmony_ci 23053a5a1b3Sopenharmony_ci if (bits == 0) 23153a5a1b3Sopenharmony_ci return 1; 23253a5a1b3Sopenharmony_ci } 23353a5a1b3Sopenharmony_ci#endif 23453a5a1b3Sopenharmony_ci } 23553a5a1b3Sopenharmony_ci } 23653a5a1b3Sopenharmony_ci 23753a5a1b3Sopenharmony_ci return 0; 23853a5a1b3Sopenharmony_ci} 239