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