chiark / gitweb /
exec: Add SELinuxContext configuration item
[elogind.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         char *e, *n;
45         unsigned u;
46         int r;
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                 e = strchr(s+1, ']');
63                 if (!e)
64                         return -EINVAL;
65
66                 n = strndupa(s+1, e-s-1);
67
68                 errno = 0;
69                 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
70                         return errno > 0 ? -errno : -EINVAL;
71
72                 e++;
73                 if (*e != ':')
74                         return -EINVAL;
75
76                 e++;
77                 r = safe_atou(e, &u);
78                 if (r < 0)
79                         return r;
80
81                 if (u <= 0 || u > 0xFFFF)
82                         return -EINVAL;
83
84                 a->sockaddr.in6.sin6_family = AF_INET6;
85                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
86                 a->size = sizeof(struct sockaddr_in6);
87
88         } else if (*s == '/') {
89                 /* AF_UNIX socket */
90
91                 size_t l;
92
93                 l = strlen(s);
94                 if (l >= sizeof(a->sockaddr.un.sun_path))
95                         return -EINVAL;
96
97                 a->sockaddr.un.sun_family = AF_UNIX;
98                 memcpy(a->sockaddr.un.sun_path, s, l);
99                 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
100
101         } else if (*s == '@') {
102                 /* Abstract AF_UNIX socket */
103                 size_t l;
104
105                 l = strlen(s+1);
106                 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
107                         return -EINVAL;
108
109                 a->sockaddr.un.sun_family = AF_UNIX;
110                 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
111                 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
112
113         } else {
114                 e = strchr(s, ':');
115                 if (e) {
116                         r = safe_atou(e+1, &u);
117                         if (r < 0)
118                                 return r;
119
120                         if (u <= 0 || u > 0xFFFF)
121                                 return -EINVAL;
122
123                         n = strndupa(s, e-s);
124
125                         /* IPv4 in w.x.y.z:p notation? */
126                         r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
127                         if (r < 0)
128                                 return -errno;
129
130                         if (r > 0) {
131                                 /* Gotcha, it's a traditional IPv4 address */
132                                 a->sockaddr.in.sin_family = AF_INET;
133                                 a->sockaddr.in.sin_port = htons((uint16_t) u);
134                                 a->size = sizeof(struct sockaddr_in);
135                         } else {
136                                 unsigned idx;
137
138                                 if (strlen(n) > IF_NAMESIZE-1)
139                                         return -EINVAL;
140
141                                 /* Uh, our last resort, an interface name */
142                                 idx = if_nametoindex(n);
143                                 if (idx == 0)
144                                         return -EINVAL;
145
146                                 if (!socket_ipv6_is_supported()) {
147                                         log_warning("Binding to interface is not available since kernel does not support IPv6.");
148                                         return -EAFNOSUPPORT;
149                                 }
150
151                                 a->sockaddr.in6.sin6_family = AF_INET6;
152                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
153                                 a->sockaddr.in6.sin6_scope_id = idx;
154                                 a->sockaddr.in6.sin6_addr = in6addr_any;
155                                 a->size = sizeof(struct sockaddr_in6);
156                         }
157                 } else {
158
159                         /* Just a port */
160                         r = safe_atou(s, &u);
161                         if (r < 0)
162                                 return r;
163
164                         if (u <= 0 || u > 0xFFFF)
165                                 return -EINVAL;
166
167                         if (socket_ipv6_is_supported()) {
168                                 a->sockaddr.in6.sin6_family = AF_INET6;
169                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
170                                 a->sockaddr.in6.sin6_addr = in6addr_any;
171                                 a->size = sizeof(struct sockaddr_in6);
172                         } else {
173                                 a->sockaddr.in.sin_family = AF_INET;
174                                 a->sockaddr.in.sin_port = htons((uint16_t) u);
175                                 a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
176                                 a->size = sizeof(struct sockaddr_in);
177                         }
178                 }
179         }
180
181         return 0;
182 }
183
184 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
185         int family;
186         unsigned group = 0;
187         _cleanup_free_ char *sfamily = NULL;
188         assert(a);
189         assert(s);
190
191         zero(*a);
192         a->type = SOCK_RAW;
193
194         errno = 0;
195         if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
196                 return errno > 0 ? -errno : -EINVAL;
197
198         family = netlink_family_from_string(sfamily);
199         if (family < 0)
200                 return -EINVAL;
201
202         a->sockaddr.nl.nl_family = AF_NETLINK;
203         a->sockaddr.nl.nl_groups = group;
204
205         a->type = SOCK_RAW;
206         a->size = sizeof(struct sockaddr_nl);
207         a->protocol = family;
208
209         return 0;
210 }
211
212 int socket_address_verify(const SocketAddress *a) {
213         assert(a);
214
215         switch (socket_address_family(a)) {
216
217         case AF_INET:
218                 if (a->size != sizeof(struct sockaddr_in))
219                         return -EINVAL;
220
221                 if (a->sockaddr.in.sin_port == 0)
222                         return -EINVAL;
223
224                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
225                         return -EINVAL;
226
227                 return 0;
228
229         case AF_INET6:
230                 if (a->size != sizeof(struct sockaddr_in6))
231                         return -EINVAL;
232
233                 if (a->sockaddr.in6.sin6_port == 0)
234                         return -EINVAL;
235
236                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
237                         return -EINVAL;
238
239                 return 0;
240
241         case AF_UNIX:
242                 if (a->size < offsetof(struct sockaddr_un, sun_path))
243                         return -EINVAL;
244
245                 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
246
247                         if (a->sockaddr.un.sun_path[0] != 0) {
248                                 char *e;
249
250                                 /* path */
251                                 e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
252                                 if (!e)
253                                         return -EINVAL;
254
255                                 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
256                                         return -EINVAL;
257                         }
258                 }
259
260                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
261                         return -EINVAL;
262
263                 return 0;
264
265         case AF_NETLINK:
266
267                 if (a->size != sizeof(struct sockaddr_nl))
268                         return -EINVAL;
269
270                 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
271                         return -EINVAL;
272
273                 return 0;
274
275         default:
276                 return -EAFNOSUPPORT;
277         }
278 }
279
280 int socket_address_print(const SocketAddress *a, char **ret) {
281         int r;
282
283         assert(a);
284         assert(ret);
285
286         r = socket_address_verify(a);
287         if (r < 0)
288                 return r;
289
290         if (socket_address_family(a) == AF_NETLINK) {
291                 _cleanup_free_ char *sfamily = NULL;
292
293                 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
294                 if (r < 0)
295                         return r;
296
297                 r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
298                 if (r < 0)
299                         return -ENOMEM;
300
301                 return 0;
302         }
303
304         return sockaddr_pretty(&a->sockaddr.sa, a->size, false, ret);
305 }
306
307 bool socket_address_can_accept(const SocketAddress *a) {
308         assert(a);
309
310         return
311                 a->type == SOCK_STREAM ||
312                 a->type == SOCK_SEQPACKET;
313 }
314
315 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
316         assert(a);
317         assert(b);
318
319         /* Invalid addresses are unequal to all */
320         if (socket_address_verify(a) < 0 ||
321             socket_address_verify(b) < 0)
322                 return false;
323
324         if (a->type != b->type)
325                 return false;
326
327         if (a->size != b->size)
328                 return false;
329
330         if (socket_address_family(a) != socket_address_family(b))
331                 return false;
332
333         switch (socket_address_family(a)) {
334
335         case AF_INET:
336                 if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
337                         return false;
338
339                 if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
340                         return false;
341
342                 break;
343
344         case AF_INET6:
345                 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
346                         return false;
347
348                 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
349                         return false;
350
351                 break;
352
353         case AF_UNIX:
354
355                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
356                         return false;
357
358                 if (a->sockaddr.un.sun_path[0]) {
359                         if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
360                                 return false;
361                 } else {
362                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
363                                 return false;
364                 }
365
366                 break;
367
368         case AF_NETLINK:
369
370                 if (a->protocol != b->protocol)
371                         return false;
372
373                 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
374                         return false;
375
376                 break;
377
378         default:
379                 /* Cannot compare, so we assume the addresses are different */
380                 return false;
381         }
382
383         return true;
384 }
385
386 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
387         struct SocketAddress b;
388
389         assert(a);
390         assert(s);
391
392         if (socket_address_parse(&b, s) < 0)
393                 return false;
394
395         b.type = type;
396
397         return socket_address_equal(a, &b);
398 }
399
400 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
401         struct SocketAddress b;
402
403         assert(a);
404         assert(s);
405
406         if (socket_address_parse_netlink(&b, s) < 0)
407                 return false;
408
409         return socket_address_equal(a, &b);
410 }
411
412 const char* socket_address_get_path(const SocketAddress *a) {
413         assert(a);
414
415         if (socket_address_family(a) != AF_UNIX)
416                 return NULL;
417
418         if (a->sockaddr.un.sun_path[0] == 0)
419                 return NULL;
420
421         return a->sockaddr.un.sun_path;
422 }
423
424 bool socket_ipv6_is_supported(void) {
425         _cleanup_free_ char *l = NULL;
426
427         if (access("/sys/module/ipv6", F_OK) != 0)
428                 return 0;
429
430         /* If we can't check "disable" parameter, assume enabled */
431         if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
432                 return 1;
433
434         /* If module was loaded with disable=1 no IPv6 available */
435         return l[0] == '0';
436 }
437
438 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
439         union sockaddr_union sa;
440         socklen_t salen = sizeof(sa), solen;
441         int protocol, type;
442
443         assert(a);
444         assert(fd >= 0);
445
446         if (getsockname(fd, &sa.sa, &salen) < 0)
447                 return false;
448
449         if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
450                 return false;
451
452         solen = sizeof(type);
453         if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
454                 return false;
455
456         if (type != a->type)
457                 return false;
458
459         if (a->protocol != 0)  {
460                 solen = sizeof(protocol);
461                 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
462                         return false;
463
464                 if (protocol != a->protocol)
465                         return false;
466         }
467
468         switch (sa.sa.sa_family) {
469
470         case AF_INET:
471                 return sa.in.sin_port == a->sockaddr.in.sin_port &&
472                         sa.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr;
473
474         case AF_INET6:
475                 return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
476                         memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
477
478         case AF_UNIX:
479                 return salen == a->size &&
480                         memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
481
482         }
483
484         return false;
485 }
486
487 int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) {
488         union sockaddr_union *sa = (union sockaddr_union*) _sa;
489         char *p;
490
491         assert(sa);
492         assert(salen >= sizeof(sa->sa.sa_family));
493
494         switch (sa->sa.sa_family) {
495
496         case AF_INET: {
497                 uint32_t a;
498
499                 a = ntohl(sa->in.sin_addr.s_addr);
500
501                 if (asprintf(&p,
502                              "%u.%u.%u.%u:%u",
503                              a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
504                              ntohs(sa->in.sin_port)) < 0)
505                         return -ENOMEM;
506
507                 break;
508         }
509
510         case AF_INET6: {
511                 static const unsigned char ipv4_prefix[] = {
512                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
513                 };
514
515                 if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
516                         const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
517
518                         if (asprintf(&p,
519                                      "%u.%u.%u.%u:%u",
520                                      a[0], a[1], a[2], a[3],
521                                      ntohs(sa->in6.sin6_port)) < 0)
522                                 return -ENOMEM;
523                 } else {
524                         char a[INET6_ADDRSTRLEN];
525
526                         if (asprintf(&p,
527                                      "[%s]:%u",
528                                      inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)),
529                                      ntohs(sa->in6.sin6_port)) < 0)
530                                 return -ENOMEM;
531                 }
532
533                 break;
534         }
535
536         case AF_UNIX:
537                 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
538                         p = strdup("<unnamed>");
539                         if (!p)
540                                 return -ENOMEM;
541
542                 } else if (sa->un.sun_path[0] == 0) {
543                         /* abstract */
544
545                         /* FIXME: We assume we can print the
546                          * socket path here and that it hasn't
547                          * more than one NUL byte. That is
548                          * actually an invalid assumption */
549
550                         p = new(char, sizeof(sa->un.sun_path)+1);
551                         if (!p)
552                                 return -ENOMEM;
553
554                         p[0] = '@';
555                         memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
556                         p[sizeof(sa->un.sun_path)] = 0;
557
558                 } else {
559                         p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
560                         if (!ret)
561                                 return -ENOMEM;
562                 }
563
564                 break;
565
566         default:
567                 return -ENOTSUP;
568         }
569
570
571         *ret = p;
572         return 0;
573 }
574
575 int getpeername_pretty(int fd, char **ret) {
576         union sockaddr_union sa;
577         socklen_t salen;
578         int r;
579
580         assert(fd >= 0);
581         assert(ret);
582
583         salen = sizeof(sa);
584         if (getpeername(fd, &sa.sa, &salen) < 0)
585                 return -errno;
586
587         if (sa.sa.sa_family == AF_UNIX) {
588                 struct ucred ucred;
589
590                 /* UNIX connection sockets are anonymous, so let's use
591                  * PID/UID as pretty credentials instead */
592
593                 r = getpeercred(fd, &ucred);
594                 if (r < 0)
595                         return r;
596
597                 if (asprintf(ret, "PID %lu/UID %lu", (unsigned long) ucred.pid, (unsigned long) ucred.uid) < 0)
598                         return -ENOMEM;
599
600                 return 0;
601         }
602
603         /* For remote sockets we translate IPv6 addresses back to IPv4
604          * if applicable, since that's nicer. */
605
606         return sockaddr_pretty(&sa.sa, salen, true, ret);
607 }
608
609 int getsockname_pretty(int fd, char **ret) {
610         union sockaddr_union sa;
611         socklen_t salen;
612
613         assert(fd >= 0);
614         assert(ret);
615
616         salen = sizeof(sa);
617         if (getsockname(fd, &sa.sa, &salen) < 0)
618                 return -errno;
619
620         /* For local sockets we do not translate IPv6 addresses back
621          * to IPv6 if applicable, since this is usually used for
622          * listening sockets where the difference between IPv4 and
623          * IPv6 matters. */
624
625         return sockaddr_pretty(&sa.sa, salen, false, ret);
626 }
627
628 static const char* const netlink_family_table[] = {
629         [NETLINK_ROUTE] = "route",
630         [NETLINK_FIREWALL] = "firewall",
631         [NETLINK_INET_DIAG] = "inet-diag",
632         [NETLINK_NFLOG] = "nflog",
633         [NETLINK_XFRM] = "xfrm",
634         [NETLINK_SELINUX] = "selinux",
635         [NETLINK_ISCSI] = "iscsi",
636         [NETLINK_AUDIT] = "audit",
637         [NETLINK_FIB_LOOKUP] = "fib-lookup",
638         [NETLINK_CONNECTOR] = "connector",
639         [NETLINK_NETFILTER] = "netfilter",
640         [NETLINK_IP6_FW] = "ip6-fw",
641         [NETLINK_DNRTMSG] = "dnrtmsg",
642         [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
643         [NETLINK_GENERIC] = "generic",
644         [NETLINK_SCSITRANSPORT] = "scsitransport",
645         [NETLINK_ECRYPTFS] = "ecryptfs"
646 };
647
648 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
649
650 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
651         [SOCKET_ADDRESS_DEFAULT] = "default",
652         [SOCKET_ADDRESS_BOTH] = "both",
653         [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
654 };
655
656 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);