Add copyright notices to all relevant files. (based on svn log)
[profile/ivi/pulseaudio.git] / 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 }