chiark / gitweb /
util: fix tty_is_vc_resolve() in a container where /sys/class/tty/console/active...
[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 "socket-util.h"
39 #include "missing.h"
40
41 int socket_address_parse(SocketAddress *a, const char *s) {
42         int r;
43         char *e, *n;
44         unsigned u;
45
46         assert(a);
47         assert(s);
48
49         zero(*a);
50         a->type = SOCK_STREAM;
51
52         if (*s == '[') {
53                 /* IPv6 in [x:.....:z]:p notation */
54
55                 if (!socket_ipv6_is_supported()) {
56                         log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
57                         return -EAFNOSUPPORT;
58                 }
59
60                 if (!(e = strchr(s+1, ']')))
61                         return -EINVAL;
62
63                 if (!(n = strndup(s+1, e-s-1)))
64                         return -ENOMEM;
65
66                 errno = 0;
67                 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) {
68                         free(n);
69                         return errno != 0 ? -errno : -EINVAL;
70                 }
71
72                 free(n);
73
74                 e++;
75                 if (*e != ':')
76                         return -EINVAL;
77
78                 e++;
79                 if ((r = safe_atou(e, &u)) < 0)
80                         return r;
81
82                 if (u <= 0 || u > 0xFFFF)
83                         return -EINVAL;
84
85                 a->sockaddr.in6.sin6_family = AF_INET6;
86                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
87                 a->size = sizeof(struct sockaddr_in6);
88
89         } else if (*s == '/') {
90                 /* AF_UNIX socket */
91
92                 size_t l;
93
94                 l = strlen(s);
95                 if (l >= sizeof(a->sockaddr.un.sun_path))
96                         return -EINVAL;
97
98                 a->sockaddr.un.sun_family = AF_UNIX;
99                 memcpy(a->sockaddr.un.sun_path, s, l);
100                 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
101
102         } else if (*s == '@') {
103                 /* Abstract AF_UNIX socket */
104                 size_t l;
105
106                 l = strlen(s+1);
107                 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
108                         return -EINVAL;
109
110                 a->sockaddr.un.sun_family = AF_UNIX;
111                 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
112                 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
113
114         } else {
115
116                 if ((e = strchr(s, ':'))) {
117
118                         if ((r = safe_atou(e+1, &u)) < 0)
119                                 return r;
120
121                         if (u <= 0 || u > 0xFFFF)
122                                 return -EINVAL;
123
124                         if (!(n = strndup(s, e-s)))
125                                 return -ENOMEM;
126
127                         /* IPv4 in w.x.y.z:p notation? */
128                         if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) {
129                                 free(n);
130                                 return -errno;
131                         }
132
133                         if (r > 0) {
134                                 /* Gotcha, it's a traditional IPv4 address */
135                                 free(n);
136
137                                 a->sockaddr.in4.sin_family = AF_INET;
138                                 a->sockaddr.in4.sin_port = htons((uint16_t) u);
139                                 a->size = sizeof(struct sockaddr_in);
140                         } else {
141                                 unsigned idx;
142
143                                 if (strlen(n) > IF_NAMESIZE-1) {
144                                         free(n);
145                                         return -EINVAL;
146                                 }
147
148                                 /* Uh, our last resort, an interface name */
149                                 idx = if_nametoindex(n);
150                                 free(n);
151
152                                 if (idx == 0)
153                                         return -EINVAL;
154
155                                 if (!socket_ipv6_is_supported()) {
156                                         log_warning("Binding to interface is not available since kernel does not support IPv6.");
157                                         return -EAFNOSUPPORT;
158                                 }
159
160                                 a->sockaddr.in6.sin6_family = AF_INET6;
161                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
162                                 a->sockaddr.in6.sin6_scope_id = idx;
163                                 a->sockaddr.in6.sin6_addr = in6addr_any;
164                                 a->size = sizeof(struct sockaddr_in6);
165                         }
166                 } else {
167
168                         /* Just a port */
169                         if ((r = safe_atou(s, &u)) < 0)
170                                 return r;
171
172                         if (u <= 0 || u > 0xFFFF)
173                                 return -EINVAL;
174
175                         if (socket_ipv6_is_supported()) {
176                                 a->sockaddr.in6.sin6_family = AF_INET6;
177                                 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
178                                 a->sockaddr.in6.sin6_addr = in6addr_any;
179                                 a->size = sizeof(struct sockaddr_in6);
180                         } else {
181                                 a->sockaddr.in4.sin_family = AF_INET;
182                                 a->sockaddr.in4.sin_port = htons((uint16_t) u);
183                                 a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY;
184                                 a->size = sizeof(struct sockaddr_in);
185                         }
186                 }
187         }
188
189         return 0;
190 }
191
192 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
193         int family;
194         unsigned group = 0;
195         char* sfamily = NULL;
196         assert(a);
197         assert(s);
198
199         zero(*a);
200         a->type = SOCK_RAW;
201
202         errno = 0;
203         if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
204                 return errno ? -errno : -EINVAL;
205
206         if ((family = netlink_family_from_string(sfamily)) < 0)
207                 if (safe_atoi(sfamily, &family) < 0) {
208                         free(sfamily);
209                         return -EINVAL;
210                 }
211
212         free(sfamily);
213
214         a->sockaddr.nl.nl_family = AF_NETLINK;
215         a->sockaddr.nl.nl_groups = group;
216
217         a->type = SOCK_RAW;
218         a->size = sizeof(struct sockaddr_nl);
219         a->protocol = family;
220
221         return 0;
222 }
223
224 int socket_address_verify(const SocketAddress *a) {
225         assert(a);
226
227         switch (socket_address_family(a)) {
228
229         case AF_INET:
230                 if (a->size != sizeof(struct sockaddr_in))
231                         return -EINVAL;
232
233                 if (a->sockaddr.in4.sin_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_INET6:
242                 if (a->size != sizeof(struct sockaddr_in6))
243                         return -EINVAL;
244
245                 if (a->sockaddr.in6.sin6_port == 0)
246                         return -EINVAL;
247
248                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
249                         return -EINVAL;
250
251                 return 0;
252
253         case AF_UNIX:
254                 if (a->size < offsetof(struct sockaddr_un, sun_path))
255                         return -EINVAL;
256
257                 if (a->size > offsetof(struct sockaddr_un, sun_path)) {
258
259                         if (a->sockaddr.un.sun_path[0] != 0) {
260                                 char *e;
261
262                                 /* path */
263                                 if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path))))
264                                         return -EINVAL;
265
266                                 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
267                                         return -EINVAL;
268                         }
269                 }
270
271                 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
272                         return -EINVAL;
273
274                 return 0;
275
276         case AF_NETLINK:
277
278                 if (a->size != sizeof(struct sockaddr_nl))
279                         return -EINVAL;
280
281                 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
282                         return -EINVAL;
283
284                 return 0;
285
286         default:
287                 return -EAFNOSUPPORT;
288         }
289 }
290
291 int socket_address_print(const SocketAddress *a, char **p) {
292         int r;
293         assert(a);
294         assert(p);
295
296         if ((r = socket_address_verify(a)) < 0)
297                 return r;
298
299         switch (socket_address_family(a)) {
300
301         case AF_INET: {
302                 char *ret;
303
304                 if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1)))
305                         return -ENOMEM;
306
307                 if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) {
308                         free(ret);
309                         return -errno;
310                 }
311
312                 sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port));
313                 *p = ret;
314                 return 0;
315         }
316
317         case AF_INET6: {
318                 char *ret;
319
320                 if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1)))
321                         return -ENOMEM;
322
323                 ret[0] = '[';
324                 if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) {
325                         free(ret);
326                         return -errno;
327                 }
328
329                 sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port));
330                 *p = ret;
331                 return 0;
332         }
333
334         case AF_UNIX: {
335                 char *ret;
336
337                 if (a->size <= offsetof(struct sockaddr_un, sun_path)) {
338
339                         if (!(ret = strdup("<unnamed>")))
340                                 return -ENOMEM;
341
342                 } else if (a->sockaddr.un.sun_path[0] == 0) {
343                         /* abstract */
344
345                         /* FIXME: We assume we can print the
346                          * socket path here and that it hasn't
347                          * more than one NUL byte. That is
348                          * actually an invalid assumption */
349
350                         if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1)))
351                                 return -ENOMEM;
352
353                         ret[0] = '@';
354                         memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1);
355                         ret[sizeof(a->sockaddr.un.sun_path)] = 0;
356
357                 } else {
358
359                         if (!(ret = strdup(a->sockaddr.un.sun_path)))
360                                 return -ENOMEM;
361                 }
362
363                 *p = ret;
364                 return 0;
365         }
366
367         case AF_NETLINK: {
368                 const char *sfamily;
369
370                 if ((sfamily = netlink_family_to_string(a->protocol)))
371                         r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
372                 else
373                         r = asprintf(p, "%i %u", a->protocol, a->sockaddr.nl.nl_groups);
374
375                 if (r < 0)
376                         return -ENOMEM;
377
378                 return 0;
379         }
380
381         default:
382                 return -EINVAL;
383         }
384 }
385
386 bool socket_address_can_accept(const SocketAddress *a) {
387         assert(a);
388
389         return
390                 a->type == SOCK_STREAM ||
391                 a->type == SOCK_SEQPACKET;
392 }
393
394 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
395         assert(a);
396         assert(b);
397
398         /* Invalid addresses are unequal to all */
399         if (socket_address_verify(a) < 0 ||
400             socket_address_verify(b) < 0)
401                 return false;
402
403         if (a->type != b->type)
404                 return false;
405
406         if (a->size != b->size)
407                 return false;
408
409         if (socket_address_family(a) != socket_address_family(b))
410                 return false;
411
412         switch (socket_address_family(a)) {
413
414         case AF_INET:
415                 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
416                         return false;
417
418                 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
419                         return false;
420
421                 break;
422
423         case AF_INET6:
424                 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
425                         return false;
426
427                 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
428                         return false;
429
430                 break;
431
432         case AF_UNIX:
433
434                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
435                         return false;
436
437                 if (a->sockaddr.un.sun_path[0]) {
438                         if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
439                                 return false;
440                 } else {
441                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
442                                 return false;
443                 }
444
445                 break;
446
447         case AF_NETLINK:
448
449                 if (a->protocol != b->protocol)
450                         return false;
451
452                 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
453                         return false;
454
455                 break;
456
457         default:
458                 /* Cannot compare, so we assume the addresses are different */
459                 return false;
460         }
461
462         return true;
463 }
464
465 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
466         struct SocketAddress b;
467
468         assert(a);
469         assert(s);
470
471         if (socket_address_parse(&b, s) < 0)
472                 return false;
473
474         b.type = type;
475
476         return socket_address_equal(a, &b);
477 }
478
479 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
480         struct SocketAddress b;
481
482         assert(a);
483         assert(s);
484
485         if (socket_address_parse_netlink(&b, s) < 0)
486                 return false;
487
488         return socket_address_equal(a, &b);
489 }
490
491 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
492         assert(a);
493
494         if (socket_address_family(a) != AF_UNIX)
495                 return false;
496
497         if (a->sockaddr.un.sun_path[0] == 0)
498                 return false;
499
500         return path_startswith(a->sockaddr.un.sun_path, prefix);
501 }
502
503 bool socket_ipv6_is_supported(void) {
504         char *l = 0;
505         bool enabled;
506
507         if (access("/sys/module/ipv6", F_OK) != 0)
508                 return 0;
509
510         /* If we can't check "disable" parameter, assume enabled */
511         if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
512                 return 1;
513
514         /* If module was loaded with disable=1 no IPv6 available */
515         enabled = l[0] == '0';
516         free(l);
517
518         return enabled;
519 }
520
521 static const char* const netlink_family_table[] = {
522         [NETLINK_ROUTE] = "route",
523         [NETLINK_FIREWALL] = "firewall",
524         [NETLINK_INET_DIAG] = "inet-diag",
525         [NETLINK_NFLOG] = "nflog",
526         [NETLINK_XFRM] = "xfrm",
527         [NETLINK_SELINUX] = "selinux",
528         [NETLINK_ISCSI] = "iscsi",
529         [NETLINK_AUDIT] = "audit",
530         [NETLINK_FIB_LOOKUP] = "fib-lookup",
531         [NETLINK_CONNECTOR] = "connector",
532         [NETLINK_NETFILTER] = "netfilter",
533         [NETLINK_IP6_FW] = "ip6-fw",
534         [NETLINK_DNRTMSG] = "dnrtmsg",
535         [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
536         [NETLINK_GENERIC] = "generic",
537         [NETLINK_SCSITRANSPORT] = "scsitransport",
538         [NETLINK_ECRYPTFS] = "ecryptfs"
539 };
540
541 DEFINE_STRING_TABLE_LOOKUP(netlink_family, int);
542
543 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
544         [SOCKET_ADDRESS_DEFAULT] = "default",
545         [SOCKET_ADDRESS_BOTH] = "both",
546         [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
547 };
548
549 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);