]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/socket-util.c
honor SELinux labels, when creating and writing config files
[thirdparty/systemd.git] / src / shared / socket-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <assert.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <arpa/inet.h>
28 #include <stdio.h>
29 #include <net/if.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <stddef.h>
33 #include <sys/ioctl.h>
34
35 #include "macro.h"
36 #include "util.h"
37 #include "mkdir.h"
38 #include "path-util.h"
39 #include "socket-util.h"
40 #include "missing.h"
41 #include "fileio.h"
42
43 int socket_address_parse(SocketAddress *a, const char *s) {
44 int r;
45 char *e, *n;
46 unsigned u;
47
48 assert(a);
49 assert(s);
50
51 zero(*a);
52 a->type = SOCK_STREAM;
53
54 if (*s == '[') {
55 /* IPv6 in [x:.....:z]:p notation */
56
57 if (!socket_ipv6_is_supported()) {
58 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
59 return -EAFNOSUPPORT;
60 }
61
62 if (!(e = strchr(s+1, ']')))
63 return -EINVAL;
64
65 if (!(n = strndup(s+1, e-s-1)))
66 return -ENOMEM;
67
68 errno = 0;
69 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
70 free(n);
71 return errno != 0 ? -errno : -EINVAL;
72 }
73
74 free(n);
75
76 e++;
77 if (*e != ':')
78 return -EINVAL;
79
80 e++;
81 if ((r = safe_atou(e, &u)) < 0)
82 return r;
83
84 if (u <= 0 || u > 0xFFFF)
85 return -EINVAL;
86
87 a->sockaddr.in6.sin6_family = AF_INET6;
88 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
89 a->size = sizeof(struct sockaddr_in6);
90
91 } else if (*s == '/') {
92 /* AF_UNIX socket */
93
94 size_t l;
95
96 l = strlen(s);
97 if (l >= sizeof(a->sockaddr.un.sun_path))
98 return -EINVAL;
99
100 a->sockaddr.un.sun_family = AF_UNIX;
101 memcpy(a->sockaddr.un.sun_path, s, l);
102 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
103
104 } else if (*s == '@') {
105 /* Abstract AF_UNIX socket */
106 size_t l;
107
108 l = strlen(s+1);
109 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
110 return -EINVAL;
111
112 a->sockaddr.un.sun_family = AF_UNIX;
113 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
114 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
115
116 } else {
117
118 if ((e = strchr(s, ':'))) {
119
120 if ((r = safe_atou(e+1, &u)) < 0)
121 return r;
122
123 if (u <= 0 || u > 0xFFFF)
124 return -EINVAL;
125
126 if (!(n = strndup(s, e-s)))
127 return -ENOMEM;
128
129 /* IPv4 in w.x.y.z:p notation? */
130 if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
131 free(n);
132 return -errno;
133 }
134
135 if (r > 0) {
136 /* Gotcha, it's a traditional IPv4 address */
137 free(n);
138
139 a->sockaddr.in4.sin_family = AF_INET;
140 a->sockaddr.in4.sin_port = htons((uint16_t) u);
141 a->size = sizeof(struct sockaddr_in);
142 } else {
143 unsigned idx;
144
145 if (strlen(n) > IF_NAMESIZE-1) {
146 free(n);
147 return -EINVAL;
148 }
149
150 /* Uh, our last resort, an interface name */
151 idx = if_nametoindex(n);
152 free(n);
153
154 if (idx == 0)
155 return -EINVAL;
156
157 if (!socket_ipv6_is_supported()) {
158 log_warning("Binding to interface is not available since kernel does not support IPv6.");
159 return -EAFNOSUPPORT;
160 }
161
162 a->sockaddr.in6.sin6_family = AF_INET6;
163 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
164 a->sockaddr.in6.sin6_scope_id = idx;
165 a->sockaddr.in6.sin6_addr = in6addr_any;
166 a->size = sizeof(struct sockaddr_in6);
167 }
168 } else {
169
170 /* Just a port */
171 r = safe_atou(s, &u);
172 if (r < 0)
173 return r;
174
175 if (u <= 0 || u > 0xFFFF)
176 return -EINVAL;
177
178 if (socket_ipv6_is_supported()) {
179 a->sockaddr.in6.sin6_family = AF_INET6;
180 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
181 a->sockaddr.in6.sin6_addr = in6addr_any;
182 a->size = sizeof(struct sockaddr_in6);
183 } else {
184 a->sockaddr.in4.sin_family = AF_INET;
185 a->sockaddr.in4.sin_port = htons((uint16_t) u);
186 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
187 a->size = sizeof(struct sockaddr_in);
188 }
189 }
190 }
191
192 return 0;
193 }
194
195 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
196 int family;
197 unsigned group = 0;
198 _cleanup_free_ char *sfamily = NULL;
199 assert(a);
200 assert(s);
201
202 zero(*a);
203 a->type = SOCK_RAW;
204
205 errno = 0;
206 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
207 return errno ? -errno : -EINVAL;
208
209 family = netlink_family_from_string(sfamily);
210 if (family < 0)
211 return -EINVAL;
212
213 a->sockaddr.nl.nl_family = AF_NETLINK;
214 a->sockaddr.nl.nl_groups = group;
215
216 a->type = SOCK_RAW;
217 a->size = sizeof(struct sockaddr_nl);
218 a->protocol = family;
219
220 return 0;
221 }
222
223 int socket_address_verify(const SocketAddress *a) {
224 assert(a);
225
226 switch (socket_address_family(a)) {
227
228 case AF_INET:
229 if (a->size != sizeof(struct sockaddr_in))
230 return -EINVAL;
231
232 if (a->sockaddr.in4.sin_port == 0)
233 return -EINVAL;
234
235 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
236 return -EINVAL;
237
238 return 0;
239
240 case AF_INET6:
241 if (a->size != sizeof(struct sockaddr_in6))
242 return -EINVAL;
243
244 if (a->sockaddr.in6.sin6_port == 0)
245 return -EINVAL;
246
247 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
248 return -EINVAL;
249
250 return 0;
251
252 case AF_UNIX:
253 if (a->size < offsetof(struct sockaddr_un, sun_path))
254 return -EINVAL;
255
256 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
257
258 if (a->sockaddr.un.sun_path[0] != 0) {
259 char *e;
260
261 /* path */
262 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
263 return -EINVAL;
264
265 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
266 return -EINVAL;
267 }
268 }
269
270 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
271 return -EINVAL;
272
273 return 0;
274
275 case AF_NETLINK:
276
277 if (a->size != sizeof(struct sockaddr_nl))
278 return -EINVAL;
279
280 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
281 return -EINVAL;
282
283 return 0;
284
285 default:
286 return -EAFNOSUPPORT;
287 }
288 }
289
290 int socket_address_print(const SocketAddress *a, char **p) {
291 int r;
292 assert(a);
293 assert(p);
294
295 if ((r = socket_address_verify(a)) < 0)
296 return r;
297
298 switch (socket_address_family(a)) {
299
300 case AF_INET: {
301 char *ret;
302
303 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
304 return -ENOMEM;
305
306 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
307 free(ret);
308 return -errno;
309 }
310
311 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
312 *p = ret;
313 return 0;
314 }
315
316 case AF_INET6: {
317 char *ret;
318
319 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
320 return -ENOMEM;
321
322 ret[0] = '[';
323 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
324 free(ret);
325 return -errno;
326 }
327
328 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
329 *p = ret;
330 return 0;
331 }
332
333 case AF_UNIX: {
334 char *ret;
335
336 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
337
338 if (!(ret = strdup("<unnamed>")))
339 return -ENOMEM;
340
341 } else if (a->sockaddr.un.sun_path[0] == 0) {
342 /* abstract */
343
344 /* FIXME: We assume we can print the
345 * socket path here and that it hasn't
346 * more than one NUL byte. That is
347 * actually an invalid assumption */
348
349 if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
350 return -ENOMEM;
351
352 ret[0] = '@';
353 memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
354 ret[sizeof(a->sockaddr.un.sun_path)] = 0;
355
356 } else {
357
358 if (!(ret = strdup(a->sockaddr.un.sun_path)))
359 return -ENOMEM;
360 }
361
362 *p = ret;
363 return 0;
364 }
365
366 case AF_NETLINK: {
367 char _cleanup_free_ *sfamily = NULL;
368
369 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
370 if (r < 0)
371 return r;
372 r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
373 if (r < 0)
374 return -ENOMEM;
375
376 return 0;
377 }
378
379 default:
380 return -EINVAL;
381 }
382 }
383
384 bool socket_address_can_accept(const SocketAddress *a) {
385 assert(a);
386
387 return
388 a->type == SOCK_STREAM ||
389 a->type == SOCK_SEQPACKET;
390 }
391
392 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
393 assert(a);
394 assert(b);
395
396 /* Invalid addresses are unequal to all */
397 if (socket_address_verify(a) < 0 ||
398 socket_address_verify(b) < 0)
399 return false;
400
401 if (a->type != b->type)
402 return false;
403
404 if (a->size != b->size)
405 return false;
406
407 if (socket_address_family(a) != socket_address_family(b))
408 return false;
409
410 switch (socket_address_family(a)) {
411
412 case AF_INET:
413 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
414 return false;
415
416 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
417 return false;
418
419 break;
420
421 case AF_INET6:
422 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
423 return false;
424
425 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
426 return false;
427
428 break;
429
430 case AF_UNIX:
431
432 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
433 return false;
434
435 if (a->sockaddr.un.sun_path[0]) {
436 if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
437 return false;
438 } else {
439 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
440 return false;
441 }
442
443 break;
444
445 case AF_NETLINK:
446
447 if (a->protocol != b->protocol)
448 return false;
449
450 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
451 return false;
452
453 break;
454
455 default:
456 /* Cannot compare, so we assume the addresses are different */
457 return false;
458 }
459
460 return true;
461 }
462
463 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
464 struct SocketAddress b;
465
466 assert(a);
467 assert(s);
468
469 if (socket_address_parse(&b, s) < 0)
470 return false;
471
472 b.type = type;
473
474 return socket_address_equal(a, &b);
475 }
476
477 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
478 struct SocketAddress b;
479
480 assert(a);
481 assert(s);
482
483 if (socket_address_parse_netlink(&b, s) < 0)
484 return false;
485
486 return socket_address_equal(a, &b);
487 }
488
489 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
490 assert(a);
491
492 if (socket_address_family(a) != AF_UNIX)
493 return false;
494
495 if (a->sockaddr.un.sun_path[0] == 0)
496 return false;
497
498 return path_startswith(a->sockaddr.un.sun_path, prefix);
499 }
500
501 bool socket_ipv6_is_supported(void) {
502 char *l = 0;
503 bool enabled;
504
505 if (access("/sys/module/ipv6", F_OK) != 0)
506 return 0;
507
508 /* If we can't check "disable" parameter, assume enabled */
509 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
510 return 1;
511
512 /* If module was loaded with disable=1 no IPv6 available */
513 enabled = l[0] == '0';
514 free(l);
515
516 return enabled;
517 }
518
519 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
520 union sockaddr_union sa;
521 socklen_t salen = sizeof(sa), solen;
522 int protocol, type;
523
524 assert(a);
525 assert(fd >= 0);
526
527 if (getsockname(fd, &sa.sa, &salen) < 0)
528 return false;
529
530 if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
531 return false;
532
533 solen = sizeof(type);
534 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
535 return false;
536
537 if (type != a->type)
538 return false;
539
540 if (a->protocol != 0) {
541 solen = sizeof(protocol);
542 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
543 return false;
544
545 if (protocol != a->protocol)
546 return false;
547 }
548
549 switch (sa.sa.sa_family) {
550
551 case AF_INET:
552 return sa.in4.sin_port == a->sockaddr.in4.sin_port &&
553 sa.in4.sin_addr.s_addr == a->sockaddr.in4.sin_addr.s_addr;
554
555 case AF_INET6:
556 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
557 memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
558
559 case AF_UNIX:
560 return salen == a->size &&
561 memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
562
563 }
564
565 return false;
566 }
567
568 static const char* const netlink_family_table[] = {
569 [NETLINK_ROUTE] = "route",
570 [NETLINK_FIREWALL] = "firewall",
571 [NETLINK_INET_DIAG] = "inet-diag",
572 [NETLINK_NFLOG] = "nflog",
573 [NETLINK_XFRM] = "xfrm",
574 [NETLINK_SELINUX] = "selinux",
575 [NETLINK_ISCSI] = "iscsi",
576 [NETLINK_AUDIT] = "audit",
577 [NETLINK_FIB_LOOKUP] = "fib-lookup",
578 [NETLINK_CONNECTOR] = "connector",
579 [NETLINK_NETFILTER] = "netfilter",
580 [NETLINK_IP6_FW] = "ip6-fw",
581 [NETLINK_DNRTMSG] = "dnrtmsg",
582 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
583 [NETLINK_GENERIC] = "generic",
584 [NETLINK_SCSITRANSPORT] = "scsitransport",
585 [NETLINK_ECRYPTFS] = "ecryptfs"
586 };
587
588 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
589
590 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
591 [SOCKET_ADDRESS_DEFAULT] = "default",
592 [SOCKET_ADDRESS_BOTH] = "both",
593 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
594 };
595
596 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);