daemon: add nice value in service file to improve performance
[platform/upstream/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, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <sys/types.h>
26 #include <sys/types.h>
27 #include <string.h>
28
29 #ifdef HAVE_NETINET_IN_H
30 #include <netinet/in.h>
31 #endif
32 #ifdef HAVE_NETINET_IN_SYSTM_H
33 #include <netinet/in_systm.h>
34 #endif
35 #ifdef HAVE_NETINET_IP_H
36 #include <netinet/ip.h>
37 #endif
38
39 #include <pulse/xmalloc.h>
40
41 #include <pulsecore/core-util.h>
42 #include <pulsecore/llist.h>
43 #include <pulsecore/log.h>
44 #include <pulsecore/macro.h>
45 #include <pulsecore/socket.h>
46 #include <pulsecore/arpa-inet.h>
47
48 #include "ipacl.h"
49
50 struct acl_entry {
51     PA_LLIST_FIELDS(struct acl_entry);
52     int family;
53     struct in_addr address_ipv4;
54 #ifdef HAVE_IPV6
55     struct in6_addr address_ipv6;
56 #endif
57     int bits;
58 };
59
60 struct pa_ip_acl {
61     PA_LLIST_HEAD(struct acl_entry, entries);
62 };
63
64 pa_ip_acl* pa_ip_acl_new(const char *s) {
65     const char *state = NULL;
66     char *a;
67     pa_ip_acl *acl;
68
69     pa_assert(s);
70
71     acl = pa_xnew(pa_ip_acl, 1);
72     PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries);
73
74     while ((a = pa_split(s, ";", &state))) {
75         char *slash;
76         struct acl_entry e, *n;
77         uint32_t bits;
78
79         if ((slash = strchr(a, '/'))) {
80             *slash = 0;
81             slash++;
82             if (pa_atou(slash, &bits) < 0) {
83                 pa_log_warn("Failed to parse number of bits: %s", slash);
84                 goto fail;
85             }
86         } else
87             bits = (uint32_t) -1;
88
89         if (inet_pton(AF_INET, a, &e.address_ipv4) > 0) {
90
91             e.bits = bits == (uint32_t) -1 ? 32 : (int) bits;
92
93             if (e.bits > 32) {
94                 pa_log_warn("Number of bits out of range: %i", e.bits);
95                 goto fail;
96             }
97
98             e.family = AF_INET;
99
100             if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0)
101                 pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
102
103 #ifdef HAVE_IPV6
104         } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) {
105
106             e.bits = bits == (uint32_t) -1 ? 128 : (int) bits;
107
108             if (e.bits > 128) {
109                 pa_log_warn("Number of bits out of range: %i", e.bits);
110                 goto fail;
111             }
112             e.family = AF_INET6;
113
114             if (e.bits < 128) {
115                 int t = 0, i;
116
117                 for (i = 0, bits = (uint32_t) e.bits; i < 16; i++) {
118
119                     if (bits >= 8)
120                         bits -= 8;
121                     else {
122                         if ((uint8_t) ((e.address_ipv6.s6_addr[i]) << bits) != 0) {
123                             t = 1;
124                             break;
125                         }
126                         bits = 0;
127                     }
128                 }
129
130                 if (t)
131                     pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
132             }
133 #endif
134
135         } else {
136             pa_log_warn("Failed to parse address: %s", a);
137             goto fail;
138         }
139
140         n = pa_xmemdup(&e, sizeof(struct acl_entry));
141         PA_LLIST_PREPEND(struct acl_entry, acl->entries, n);
142
143         pa_xfree(a);
144     }
145
146     return acl;
147
148 fail:
149     pa_xfree(a);
150     pa_ip_acl_free(acl);
151
152     return NULL;
153 }
154
155 void pa_ip_acl_free(pa_ip_acl *acl) {
156     pa_assert(acl);
157
158     while (acl->entries) {
159         struct acl_entry *e = acl->entries;
160         PA_LLIST_REMOVE(struct acl_entry, acl->entries, e);
161         pa_xfree(e);
162     }
163
164     pa_xfree(acl);
165 }
166
167 int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
168     struct sockaddr_storage sa;
169     struct acl_entry *e;
170     socklen_t salen;
171
172     pa_assert(acl);
173     pa_assert(fd >= 0);
174
175     salen = sizeof(sa);
176     if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0)
177         return -1;
178
179 #ifdef HAVE_IPV6
180     if (sa.ss_family != AF_INET && sa.ss_family != AF_INET6)
181 #else
182     if (sa.ss_family != AF_INET)
183 #endif
184         return -1;
185
186     if (sa.ss_family == AF_INET && salen != sizeof(struct sockaddr_in))
187         return -1;
188
189 #ifdef HAVE_IPV6
190     if (sa.ss_family == AF_INET6 && salen != sizeof(struct sockaddr_in6))
191         return -1;
192 #endif
193
194     for (e = acl->entries; e; e = e->next) {
195
196         if (e->family != sa.ss_family)
197             continue;
198
199         if (e->family == AF_INET) {
200             struct sockaddr_in *sai = (struct sockaddr_in*) &sa;
201
202             if (e->bits == 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */
203                 (ntohl(sai->sin_addr.s_addr ^ e->address_ipv4.s_addr) >> (32 - e->bits)) == 0)
204                 return 1;
205 #ifdef HAVE_IPV6
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 #endif
234         }
235     }
236
237     return 0;
238 }