]> code.delx.au - pulseaudio/blob - src/pulsecore/ipacl.c
remap: Change remapping function argument type from void to int16_t / float as approp...
[pulseaudio] / src / pulsecore / ipacl.c
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 pa_ip_acl* pa_ip_acl_new(const char *s) {
67 const char *state = NULL;
68 char *a;
69 pa_ip_acl *acl;
70
71 pa_assert(s);
72
73 acl = pa_xnew(pa_ip_acl, 1);
74 PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries);
75
76 while ((a = pa_split(s, ";", &state))) {
77 char *slash;
78 struct acl_entry e, *n;
79 uint32_t bits;
80
81 if ((slash = strchr(a, '/'))) {
82 *slash = 0;
83 slash++;
84 if (pa_atou(slash, &bits) < 0) {
85 pa_log_warn("Failed to parse number of bits: %s", slash);
86 goto fail;
87 }
88 } else
89 bits = (uint32_t) -1;
90
91 if (inet_pton(AF_INET, a, &e.address_ipv4) > 0) {
92
93 e.bits = bits == (uint32_t) -1 ? 32 : (int) bits;
94
95 if (e.bits > 32) {
96 pa_log_warn("Number of bits out of range: %i", e.bits);
97 goto fail;
98 }
99
100 e.family = AF_INET;
101
102 if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0)
103 pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
104
105 #ifdef HAVE_IPV6
106 } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) {
107
108 e.bits = bits == (uint32_t) -1 ? 128 : (int) bits;
109
110 if (e.bits > 128) {
111 pa_log_warn("Number of bits out of range: %i", e.bits);
112 goto fail;
113 }
114 e.family = AF_INET6;
115
116 if (e.bits < 128) {
117 int t = 0, i;
118
119 for (i = 0, bits = (uint32_t) e.bits; i < 16; i++) {
120
121 if (bits >= 8)
122 bits -= 8;
123 else {
124 if ((uint8_t) ((e.address_ipv6.s6_addr[i]) << bits) != 0) {
125 t = 1;
126 break;
127 }
128 bits = 0;
129 }
130 }
131
132 if (t)
133 pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
134 }
135 #endif
136
137 } else {
138 pa_log_warn("Failed to parse address: %s", a);
139 goto fail;
140 }
141
142 n = pa_xmemdup(&e, sizeof(struct acl_entry));
143 PA_LLIST_PREPEND(struct acl_entry, acl->entries, n);
144
145 pa_xfree(a);
146 }
147
148 return acl;
149
150 fail:
151 pa_xfree(a);
152 pa_ip_acl_free(acl);
153
154 return NULL;
155 }
156
157 void pa_ip_acl_free(pa_ip_acl *acl) {
158 pa_assert(acl);
159
160 while (acl->entries) {
161 struct acl_entry *e = acl->entries;
162 PA_LLIST_REMOVE(struct acl_entry, acl->entries, e);
163 pa_xfree(e);
164 }
165
166 pa_xfree(acl);
167 }
168
169 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 pa_assert(acl);
175 pa_assert(fd >= 0);
176
177 salen = sizeof(sa);
178 if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0)
179 return -1;
180
181 #ifdef HAVE_IPV6
182 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 if (sa.ss_family == AF_INET && salen != sizeof(struct sockaddr_in))
189 return -1;
190
191 #ifdef HAVE_IPV6
192 if (sa.ss_family == AF_INET6 && salen != sizeof(struct sockaddr_in6))
193 return -1;
194 #endif
195
196 for (e = acl->entries; e; e = e->next) {
197
198 if (e->family != sa.ss_family)
199 continue;
200
201 if (e->family == AF_INET) {
202 struct sockaddr_in *sai = (struct sockaddr_in*) &sa;
203
204 if (e->bits == 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */
205 (ntohl(sai->sin_addr.s_addr ^ e->address_ipv4.s_addr) >> (32 - e->bits)) == 0)
206 return 1;
207 #ifdef HAVE_IPV6
208 } else if (e->family == AF_INET6) {
209 int i, bits;
210 struct sockaddr_in6 *sai = (struct sockaddr_in6*) &sa;
211
212 if (e->bits == 128)
213 return memcmp(&sai->sin6_addr, &e->address_ipv6, 16) == 0;
214
215 if (e->bits == 0)
216 return 1;
217
218 for (i = 0, bits = e->bits; i < 16; i++) {
219
220 if (bits >= 8) {
221 if (sai->sin6_addr.s6_addr[i] != e->address_ipv6.s6_addr[i])
222 break;
223
224 bits -= 8;
225 } else {
226 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 if (bits == 0)
233 return 1;
234 }
235 #endif
236 }
237 }
238
239 return 0;
240 }