Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : : Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 : :
7 : : PulseAudio is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU Lesser General Public License as
9 : : published by the Free Software Foundation; either version 2.1 of the
10 : : License, or (at your option) any later version.
11 : :
12 : : PulseAudio is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : Lesser General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU Lesser General Public
18 : : License along with PulseAudio; if not, write to the Free Software
19 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 : : USA.
21 : : ***/
22 : :
23 : : #ifdef HAVE_CONFIG_H
24 : : #include <config.h>
25 : : #endif
26 : :
27 : : #include <sys/types.h>
28 : : #include <sys/types.h>
29 : : #include <string.h>
30 : :
31 : : #ifdef HAVE_NETINET_IN_H
32 : : #include <netinet/in.h>
33 : : #endif
34 : : #ifdef HAVE_NETINET_IN_SYSTM_H
35 : : #include <netinet/in_systm.h>
36 : : #endif
37 : : #ifdef HAVE_NETINET_IP_H
38 : : #include <netinet/ip.h>
39 : : #endif
40 : :
41 : : #include <pulse/xmalloc.h>
42 : :
43 : : #include <pulsecore/core-util.h>
44 : : #include <pulsecore/llist.h>
45 : : #include <pulsecore/log.h>
46 : : #include <pulsecore/macro.h>
47 : : #include <pulsecore/socket.h>
48 : : #include <pulsecore/arpa-inet.h>
49 : :
50 : : #include "ipacl.h"
51 : :
52 : : struct acl_entry {
53 : : PA_LLIST_FIELDS(struct acl_entry);
54 : : int family;
55 : : struct in_addr address_ipv4;
56 : : #ifdef HAVE_IPV6
57 : : struct in6_addr address_ipv6;
58 : : #endif
59 : : int bits;
60 : : };
61 : :
62 : : struct pa_ip_acl {
63 : : PA_LLIST_HEAD(struct acl_entry, entries);
64 : : };
65 : :
66 : 14 : pa_ip_acl* pa_ip_acl_new(const char *s) {
67 : 14 : const char *state = NULL;
68 : : char *a;
69 : : pa_ip_acl *acl;
70 : :
71 [ - + ]: 14 : pa_assert(s);
72 : :
73 : 14 : acl = pa_xnew(pa_ip_acl, 1);
74 : 14 : PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries);
75 : :
76 [ + + ]: 29 : while ((a = pa_split(s, ";", &state))) {
77 : : char *slash;
78 : : struct acl_entry e, *n;
79 : : uint32_t bits;
80 : :
81 [ + + ]: 15 : if ((slash = strchr(a, '/'))) {
82 : 12 : *slash = 0;
83 : 12 : slash++;
84 [ - + ]: 12 : if (pa_atou(slash, &bits) < 0) {
85 : 0 : pa_log_warn("Failed to parse number of bits: %s", slash);
86 : 0 : goto fail;
87 : : }
88 : : } else
89 : 3 : bits = (uint32_t) -1;
90 : :
91 [ + + ]: 15 : if (inet_pton(AF_INET, a, &e.address_ipv4) > 0) {
92 : :
93 [ + + ]: 8 : e.bits = bits == (uint32_t) -1 ? 32 : (int) bits;
94 : :
95 [ - + ]: 8 : if (e.bits > 32) {
96 : 0 : pa_log_warn("Number of bits out of range: %i", e.bits);
97 : 0 : goto fail;
98 : : }
99 : :
100 : 8 : e.family = AF_INET;
101 : :
102 [ + + ][ - + ]: 8 : if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0)
[ + + ]
103 : 3 : pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
104 : :
105 : : #ifdef HAVE_IPV6
106 [ + - ]: 7 : } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) {
107 : :
108 [ + + ]: 7 : e.bits = bits == (uint32_t) -1 ? 128 : (int) bits;
109 : :
110 [ - + ]: 7 : if (e.bits > 128) {
111 : 0 : pa_log_warn("Number of bits out of range: %i", e.bits);
112 : 0 : goto fail;
113 : : }
114 : 7 : e.family = AF_INET6;
115 : :
116 [ + + ]: 7 : if (e.bits < 128) {
117 : 5 : int t = 0, i;
118 : :
119 [ + + ]: 82 : for (i = 0, bits = (uint32_t) e.bits; i < 16; i++) {
120 : :
121 [ + + ]: 80 : if (bits >= 8)
122 : 32 : bits -= 8;
123 : : else {
124 [ + + ]: 48 : if ((uint8_t) ((e.address_ipv6.s6_addr[i]) << bits) != 0) {
125 : : t = 1;
126 : : break;
127 : : }
128 : 45 : bits = 0;
129 : : }
130 : : }
131 : :
132 [ + + ]: 5 : if (t)
133 : 3 : pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
134 : : }
135 : : #endif
136 : :
137 : : } else {
138 : 0 : pa_log_warn("Failed to parse address: %s", a);
139 : 0 : goto fail;
140 : : }
141 : :
142 : 15 : n = pa_xmemdup(&e, sizeof(struct acl_entry));
143 [ - + ][ + + ]: 15 : PA_LLIST_PREPEND(struct acl_entry, acl->entries, n);
144 : :
145 : 15 : pa_xfree(a);
146 : : }
147 : :
148 : : return acl;
149 : :
150 : : fail:
151 : 0 : pa_xfree(a);
152 : 0 : pa_ip_acl_free(acl);
153 : :
154 : 14 : return NULL;
155 : : }
156 : :
157 : 14 : void pa_ip_acl_free(pa_ip_acl *acl) {
158 [ + - ]: 14 : pa_assert(acl);
159 : :
160 [ + + ]: 29 : while (acl->entries) {
161 : 15 : struct acl_entry *e = acl->entries;
162 [ - + ][ + + ]: 15 : PA_LLIST_REMOVE(struct acl_entry, acl->entries, e);
[ - + ][ - + ]
163 : 15 : pa_xfree(e);
164 : : }
165 : :
166 : 14 : pa_xfree(acl);
167 : 14 : }
168 : :
169 : 14 : int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
170 : : struct sockaddr_storage sa;
171 : : struct acl_entry *e;
172 : : socklen_t salen;
173 : :
174 [ - + ]: 14 : pa_assert(acl);
175 [ - + ]: 14 : pa_assert(fd >= 0);
176 : :
177 : 14 : salen = sizeof(sa);
178 [ + - ]: 14 : if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0)
179 : : return -1;
180 : :
181 : : #ifdef HAVE_IPV6
182 [ + - ]: 14 : if (sa.ss_family != AF_INET && sa.ss_family != AF_INET6)
183 : : #else
184 : : if (sa.ss_family != AF_INET)
185 : : #endif
186 : : return -1;
187 : :
188 [ + + ][ + - ]: 14 : if (sa.ss_family == AF_INET && salen != sizeof(struct sockaddr_in))
189 : : return -1;
190 : :
191 : : #ifdef HAVE_IPV6
192 [ + + ][ + - ]: 14 : if (sa.ss_family == AF_INET6 && salen != sizeof(struct sockaddr_in6))
193 : : return -1;
194 : : #endif
195 : :
196 [ + + ]: 29 : for (e = acl->entries; e; e = e->next) {
197 : :
198 [ + + ]: 15 : if (e->family != sa.ss_family)
199 : 1 : continue;
200 : :
201 [ + + ]: 14 : if (e->family == AF_INET) {
202 : 8 : struct sockaddr_in *sai = (struct sockaddr_in*) &sa;
203 : :
204 [ + + ][ + + ]: 15 : if (e->bits == 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */
205 [ - + ]: 7 : (ntohl(sai->sin_addr.s_addr ^ e->address_ipv4.s_addr) >> (32 - e->bits)) == 0)
206 : : return 1;
207 : : #ifdef HAVE_IPV6
208 [ + - ]: 6 : } else if (e->family == AF_INET6) {
209 : : int i, bits;
210 : 6 : struct sockaddr_in6 *sai = (struct sockaddr_in6*) &sa;
211 : :
212 [ + + ]: 6 : if (e->bits == 128)
213 : 2 : return memcmp(&sai->sin6_addr, &e->address_ipv6, 16) == 0;
214 : :
215 [ + + ]: 4 : if (e->bits == 0)
216 : : return 1;
217 : :
218 [ + - ]: 34 : for (i = 0, bits = e->bits; i < 16; i++) {
219 : :
220 [ + + ]: 34 : if (bits >= 8) {
221 [ + - ]: 31 : if (sai->sin6_addr.s6_addr[i] != e->address_ipv6.s6_addr[i])
222 : : break;
223 : :
224 : 31 : bits -= 8;
225 : : } else {
226 [ + + ]: 3 : if ((sai->sin6_addr.s6_addr[i] ^ e->address_ipv6.s6_addr[i]) >> (8 - bits) != 0)
227 : : break;
228 : :
229 : : bits = 0;
230 : : }
231 : :
232 [ + + ]: 33 : if (bits == 0)
233 : : return 1;
234 : : }
235 : : #endif
236 : : }
237 : : }
238 : :
239 : : return 0;
240 : : }
|