remove all occurences of
[pulseaudio.git] / src / pulsecore / ipacl.c
blob36159fabf3888a0cccd9beafd28478e6c08ebffa
1 /* $Id$ */
3 /***
4 This file is part of PulseAudio.
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <sys/types.h>
27 #include <sys/types.h>
28 #include <string.h>
30 #ifdef HAVE_SYS_SOCKET_H
31 #include <sys/socket.h>
32 #endif
33 #ifdef HAVE_NETINET_IN_H
34 #include <netinet/in.h>
35 #endif
36 #ifdef HAVE_NETINET_IN_SYSTM_H
37 #include <netinet/in_systm.h>
38 #endif
39 #ifdef HAVE_NETINET_IP_H
40 #include <netinet/ip.h>
41 #endif
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
46 #include "winsock.h"
48 #include <pulse/xmalloc.h>
50 #include <pulsecore/core-util.h>
51 #include <pulsecore/llist.h>
52 #include <pulsecore/log.h>
54 #ifndef HAVE_INET_PTON
55 #include "inet_pton.h"
56 #endif
58 #include "ipacl.h"
60 struct acl_entry {
61 PA_LLIST_FIELDS(struct acl_entry);
62 int family;
63 struct in_addr address_ipv4;
64 struct in6_addr address_ipv6;
65 int bits;
68 struct pa_ip_acl {
69 PA_LLIST_HEAD(struct acl_entry, entries);
72 pa_ip_acl* pa_ip_acl_new(const char *s) {
73 const char *state = NULL;
74 char *a;
75 pa_ip_acl *acl;
77 assert(s);
79 acl = pa_xnew(pa_ip_acl, 1);
80 PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries);
82 while ((a = pa_split(s, ";", &state))) {
83 char *slash;
84 struct acl_entry e, *n;
85 uint32_t bits;
87 if ((slash = strchr(a, '/'))) {
88 *slash = 0;
89 slash++;
90 if (pa_atou(slash, &bits) < 0) {
91 pa_log("failed to parse number of bits: %s", slash);
92 goto fail;
94 } else
95 bits = (uint32_t) -1;
97 if (inet_pton(AF_INET, a, &e.address_ipv4) > 0) {
99 e.bits = bits == (uint32_t) -1 ? 32 : (int) bits;
101 if (e.bits > 32) {
102 pa_log("number of bits out of range: %i", e.bits);
103 goto fail;
106 e.family = AF_INET;
108 if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0)
109 pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
111 } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) {
113 e.bits = bits == (uint32_t) -1 ? 128 : (int) bits;
115 if (e.bits > 128) {
116 pa_log("number of bits out of range: %i", e.bits);
117 goto fail;
119 e.family = AF_INET6;
121 if (e.bits < 128) {
122 int t = 0, i;
124 for (i = 0, bits = e.bits; i < 16; i++) {
126 if (bits >= 8)
127 bits -= 8;
128 else {
129 if ((uint8_t) ((e.address_ipv6.s6_addr[i]) << bits) != 0) {
130 t = 1;
131 break;
133 bits = 0;
137 if (t)
138 pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
141 } else {
142 pa_log("failed to parse address: %s", a);
143 goto fail;
146 n = pa_xmemdup(&e, sizeof(struct acl_entry));
147 PA_LLIST_PREPEND(struct acl_entry, acl->entries, n);
149 pa_xfree(a);
152 return acl;
154 fail:
155 pa_xfree(a);
156 pa_ip_acl_free(acl);
158 return NULL;
161 void pa_ip_acl_free(pa_ip_acl *acl) {
162 assert(acl);
164 while (acl->entries) {
165 struct acl_entry *e = acl->entries;
166 PA_LLIST_REMOVE(struct acl_entry, acl->entries, e);
167 pa_xfree(e);
170 pa_xfree(acl);
173 int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
174 struct sockaddr_storage sa;
175 struct acl_entry *e;
176 socklen_t salen;
178 assert(acl);
179 assert(fd >= 0);
181 salen = sizeof(sa);
182 if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0)
183 return -1;
185 if (sa.ss_family != AF_INET && sa.ss_family != AF_INET6)
186 return -1;
188 if (sa.ss_family == AF_INET && salen != sizeof(struct sockaddr_in))
189 return -1;
191 if (sa.ss_family == AF_INET6 && salen != sizeof(struct sockaddr_in6))
192 return -1;
194 for (e = acl->entries; e; e = e->next) {
196 if (e->family != sa.ss_family)
197 continue;
199 if (e->family == AF_INET) {
200 struct sockaddr_in *sai = (struct sockaddr_in*) &sa;
202 if (e->bits == 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */
203 (ntohl(sai->sin_addr.s_addr ^ e->address_ipv4.s_addr) >> (32 - e->bits)) == 0)
204 return 1;
205 } else if (e->family == AF_INET6) {
206 int i, bits ;
207 struct sockaddr_in6 *sai = (struct sockaddr_in6*) &sa;
209 if (e->bits == 128)
210 return memcmp(&sai->sin6_addr, &e->address_ipv6, 16) == 0;
212 if (e->bits == 0)
213 return 1;
215 for (i = 0, bits = e->bits; i < 16; i++) {
217 if (bits >= 8) {
218 if (sai->sin6_addr.s6_addr[i] != e->address_ipv6.s6_addr[i])
219 break;
221 bits -= 8;
222 } else {
223 if ((sai->sin6_addr.s6_addr[i] ^ e->address_ipv6.s6_addr[i]) >> (8 - bits) != 0)
224 break;
226 bits = 0;
229 if (bits == 0)
230 return 1;
235 return 0;