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