]> code.delx.au - pulseaudio/blob - src/pulsecore/ipacl.c
Fix up according to Coding Style
[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 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
42 #endif
43
44 #include <pulse/xmalloc.h>
45
46 #include <pulsecore/core-util.h>
47 #include <pulsecore/llist.h>
48 #include <pulsecore/log.h>
49 #include <pulsecore/macro.h>
50 #include <pulsecore/socket.h>
51
52 #ifndef HAVE_INET_PTON
53 #include <pulsecore/inet_pton.h>
54 #endif
55
56 #include "ipacl.h"
57
58 struct acl_entry {
59 PA_LLIST_FIELDS(struct acl_entry);
60 int family;
61 struct in_addr address_ipv4;
62 #ifdef HAVE_IPV6
63 struct in6_addr address_ipv6;
64 #endif
65 int bits;
66 };
67
68 struct pa_ip_acl {
69 PA_LLIST_HEAD(struct acl_entry, entries);
70 };
71
72 pa_ip_acl* pa_ip_acl_new(const char *s) {
73 const char *state = NULL;
74 char *a;
75 pa_ip_acl *acl;
76
77 pa_assert(s);
78
79 acl = pa_xnew(pa_ip_acl, 1);
80 PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries);
81
82 while ((a = pa_split(s, ";", &state))) {
83 char *slash;
84 struct acl_entry e, *n;
85 uint32_t bits;
86
87 if ((slash = strchr(a, '/'))) {
88 *slash = 0;
89 slash++;
90 if (pa_atou(slash, &bits) < 0) {
91 pa_log_warn("Failed to parse number of bits: %s", slash);
92 goto fail;
93 }
94 } else
95 bits = (uint32_t) -1;
96
97 if (inet_pton(AF_INET, a, &e.address_ipv4) > 0) {
98
99 e.bits = bits == (uint32_t) -1 ? 32 : (int) bits;
100
101 if (e.bits > 32) {
102 pa_log_warn("Number of bits out of range: %i", e.bits);
103 goto fail;
104 }
105
106 e.family = AF_INET;
107
108 if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0)
109 pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
110
111 #ifdef HAVE_IPV6
112 } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) {
113
114 e.bits = bits == (uint32_t) -1 ? 128 : (int) bits;
115
116 if (e.bits > 128) {
117 pa_log_warn("Number of bits out of range: %i", e.bits);
118 goto fail;
119 }
120 e.family = AF_INET6;
121
122 if (e.bits < 128) {
123 int t = 0, i;
124
125 for (i = 0, bits = (uint32_t) e.bits; i < 16; i++) {
126
127 if (bits >= 8)
128 bits -= 8;
129 else {
130 if ((uint8_t) ((e.address_ipv6.s6_addr[i]) << bits) != 0) {
131 t = 1;
132 break;
133 }
134 bits = 0;
135 }
136 }
137
138 if (t)
139 pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
140 }
141 #endif
142
143 } else {
144 pa_log_warn("Failed to parse address: %s", a);
145 goto fail;
146 }
147
148 n = pa_xmemdup(&e, sizeof(struct acl_entry));
149 PA_LLIST_PREPEND(struct acl_entry, acl->entries, n);
150
151 pa_xfree(a);
152 }
153
154 return acl;
155
156 fail:
157 pa_xfree(a);
158 pa_ip_acl_free(acl);
159
160 return NULL;
161 }
162
163 void pa_ip_acl_free(pa_ip_acl *acl) {
164 pa_assert(acl);
165
166 while (acl->entries) {
167 struct acl_entry *e = acl->entries;
168 PA_LLIST_REMOVE(struct acl_entry, acl->entries, e);
169 pa_xfree(e);
170 }
171
172 pa_xfree(acl);
173 }
174
175 int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
176 struct sockaddr_storage sa;
177 struct acl_entry *e;
178 socklen_t salen;
179
180 pa_assert(acl);
181 pa_assert(fd >= 0);
182
183 salen = sizeof(sa);
184 if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0)
185 return -1;
186
187 #ifdef HAVE_IPV6
188 if (sa.ss_family != AF_INET && sa.ss_family != AF_INET6)
189 #else
190 if (sa.ss_family != AF_INET)
191 #endif
192 return -1;
193
194 if (sa.ss_family == AF_INET && salen != sizeof(struct sockaddr_in))
195 return -1;
196
197 #ifdef HAVE_IPV6
198 if (sa.ss_family == AF_INET6 && salen != sizeof(struct sockaddr_in6))
199 return -1;
200 #endif
201
202 for (e = acl->entries; e; e = e->next) {
203
204 if (e->family != sa.ss_family)
205 continue;
206
207 if (e->family == AF_INET) {
208 struct sockaddr_in *sai = (struct sockaddr_in*) &sa;
209
210 if (e->bits == 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */
211 (ntohl(sai->sin_addr.s_addr ^ e->address_ipv4.s_addr) >> (32 - e->bits)) == 0)
212 return 1;
213 #ifdef HAVE_IPV6
214 } else if (e->family == AF_INET6) {
215 int i, bits;
216 struct sockaddr_in6 *sai = (struct sockaddr_in6*) &sa;
217
218 if (e->bits == 128)
219 return memcmp(&sai->sin6_addr, &e->address_ipv6, 16) == 0;
220
221 if (e->bits == 0)
222 return 1;
223
224 for (i = 0, bits = e->bits; i < 16; i++) {
225
226 if (bits >= 8) {
227 if (sai->sin6_addr.s6_addr[i] != e->address_ipv6.s6_addr[i])
228 break;
229
230 bits -= 8;
231 } else {
232 if ((sai->sin6_addr.s6_addr[i] ^ e->address_ipv6.s6_addr[i]) >> (8 - bits) != 0)
233 break;
234
235 bits = 0;
236 }
237
238 if (bits == 0)
239 return 1;
240 }
241 #endif
242 }
243 }
244
245 return 0;
246 }