Git init
[framework/multimedia/pulseaudio.git] / 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 #ifdef HAVE_IPV6
66     struct in6_addr address_ipv6;
67 #endif
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     pa_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_warn("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_warn("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("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
113
114 #ifdef HAVE_IPV6
115         } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) {
116
117             e.bits = bits == (uint32_t) -1 ? 128 : (int) bits;
118
119             if (e.bits > 128) {
120                 pa_log_warn("Number of bits out of range: %i", e.bits);
121                 goto fail;
122             }
123             e.family = AF_INET6;
124
125             if (e.bits < 128) {
126                 int t = 0, i;
127
128                 for (i = 0, bits = (uint32_t) e.bits; i < 16; i++) {
129
130                     if (bits >= 8)
131                         bits -= 8;
132                     else {
133                         if ((uint8_t) ((e.address_ipv6.s6_addr[i]) << bits) != 0) {
134                             t = 1;
135                             break;
136                         }
137                         bits = 0;
138                     }
139                 }
140
141                 if (t)
142                     pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
143             }
144 #endif
145
146         } else {
147             pa_log_warn("Failed to parse address: %s", a);
148             goto fail;
149         }
150
151         n = pa_xmemdup(&e, sizeof(struct acl_entry));
152         PA_LLIST_PREPEND(struct acl_entry, acl->entries, n);
153
154         pa_xfree(a);
155     }
156
157     return acl;
158
159 fail:
160     pa_xfree(a);
161     pa_ip_acl_free(acl);
162
163     return NULL;
164 }
165
166 void pa_ip_acl_free(pa_ip_acl *acl) {
167     pa_assert(acl);
168
169     while (acl->entries) {
170         struct acl_entry *e = acl->entries;
171         PA_LLIST_REMOVE(struct acl_entry, acl->entries, e);
172         pa_xfree(e);
173     }
174
175     pa_xfree(acl);
176 }
177
178 int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
179     struct sockaddr_storage sa;
180     struct acl_entry *e;
181     socklen_t  salen;
182
183     pa_assert(acl);
184     pa_assert(fd >= 0);
185
186     salen = sizeof(sa);
187     if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0)
188         return -1;
189
190 #ifdef HAVE_IPV6
191     if (sa.ss_family != AF_INET && sa.ss_family != AF_INET6)
192 #else
193     if (sa.ss_family != AF_INET)
194 #endif
195         return -1;
196
197     if (sa.ss_family == AF_INET && salen != sizeof(struct sockaddr_in))
198         return -1;
199
200 #ifdef HAVE_IPV6
201     if (sa.ss_family == AF_INET6 && salen != sizeof(struct sockaddr_in6))
202         return -1;
203 #endif
204
205     for (e = acl->entries; e; e = e->next) {
206
207         if (e->family != sa.ss_family)
208             continue;
209
210         if (e->family == AF_INET) {
211             struct sockaddr_in *sai = (struct sockaddr_in*) &sa;
212
213             if (e->bits == 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */
214                 (ntohl(sai->sin_addr.s_addr ^ e->address_ipv4.s_addr) >> (32 - e->bits)) == 0)
215                 return 1;
216 #ifdef HAVE_IPV6
217         } else if (e->family == AF_INET6) {
218             int i, bits ;
219             struct sockaddr_in6 *sai = (struct sockaddr_in6*) &sa;
220
221             if (e->bits == 128)
222                 return memcmp(&sai->sin6_addr, &e->address_ipv6, 16) == 0;
223
224             if (e->bits == 0)
225                 return 1;
226
227             for (i = 0, bits = e->bits; i < 16; i++) {
228
229                 if (bits >= 8) {
230                     if (sai->sin6_addr.s6_addr[i] != e->address_ipv6.s6_addr[i])
231                         break;
232
233                     bits -= 8;
234                 } else {
235                     if ((sai->sin6_addr.s6_addr[i] ^ e->address_ipv6.s6_addr[i]) >> (8 - bits) != 0)
236                         break;
237
238                     bits = 0;
239                 }
240
241                 if (bits == 0)
242                     return 1;
243             }
244 #endif
245         }
246     }
247
248     return 0;
249 }