chiark / gitweb /
logind: enable PowerOff/Reboot calls
[elogind.git] / src / 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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU 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 "socket-util.h"
38 #include "missing.h"
39 #include "label.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 int socket_address_listen(
387                 const SocketAddress *a,
388                 int backlog,
389                 SocketAddressBindIPv6Only only,
390                 const char *bind_to_device,
391                 bool free_bind,
392                 bool transparent,
393                 mode_t directory_mode,
394                 mode_t socket_mode,
395                 const char *label,
396                 int *ret) {
397
398         int r, fd, one;
399         assert(a);
400         assert(ret);
401
402         if ((r = socket_address_verify(a)) < 0)
403                 return r;
404
405         if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
406                 return -EAFNOSUPPORT;
407
408         r = label_socket_set(label);
409         if (r < 0)
410                 return r;
411
412         fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, a->protocol);
413         r = fd < 0 ? -errno : 0;
414
415         label_socket_clear();
416
417         if (r < 0)
418                 return r;
419
420         if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
421                 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
422
423                 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
424                         goto fail;
425         }
426
427         if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
428                 if (bind_to_device)
429                         if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
430                                 goto fail;
431
432                 if (free_bind) {
433                         one = 1;
434                         if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
435                                 log_warning("IP_FREEBIND failed: %m");
436                 }
437
438                 if (transparent) {
439                         one = 1;
440                         if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
441                                 log_warning("IP_TRANSPARENT failed: %m");
442                 }
443         }
444
445         one = 1;
446         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
447                 goto fail;
448
449         if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
450                 mode_t old_mask;
451
452                 /* Create parents */
453                 mkdir_parents(a->sockaddr.un.sun_path, directory_mode);
454
455                 /* Enforce the right access mode for the socket*/
456                 old_mask = umask(~ socket_mode);
457
458                 /* Include the original umask in our mask */
459                 umask(~socket_mode | old_mask);
460
461                 r = bind(fd, &a->sockaddr.sa, a->size);
462
463                 if (r < 0 && errno == EADDRINUSE) {
464                         /* Unlink and try again */
465                         unlink(a->sockaddr.un.sun_path);
466                         r = bind(fd, &a->sockaddr.sa, a->size);
467                 }
468
469                 umask(old_mask);
470         } else
471                 r = bind(fd, &a->sockaddr.sa, a->size);
472
473         if (r < 0)
474                 goto fail;
475
476         if (socket_address_can_accept(a))
477                 if (listen(fd, backlog) < 0)
478                         goto fail;
479
480         *ret = fd;
481         return 0;
482
483 fail:
484         r = -errno;
485         close_nointr_nofail(fd);
486         return r;
487 }
488
489 bool socket_address_can_accept(const SocketAddress *a) {
490         assert(a);
491
492         return
493                 a->type == SOCK_STREAM ||
494                 a->type == SOCK_SEQPACKET;
495 }
496
497 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
498         assert(a);
499         assert(b);
500
501         /* Invalid addresses are unequal to all */
502         if (socket_address_verify(a) < 0 ||
503             socket_address_verify(b) < 0)
504                 return false;
505
506         if (a->type != b->type)
507                 return false;
508
509         if (a->size != b->size)
510                 return false;
511
512         if (socket_address_family(a) != socket_address_family(b))
513                 return false;
514
515         switch (socket_address_family(a)) {
516
517         case AF_INET:
518                 if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr)
519                         return false;
520
521                 if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port)
522                         return false;
523
524                 break;
525
526         case AF_INET6:
527                 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
528                         return false;
529
530                 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
531                         return false;
532
533                 break;
534
535         case AF_UNIX:
536
537                 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
538                         return false;
539
540                 if (a->sockaddr.un.sun_path[0]) {
541                         if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0)
542                                 return false;
543                 } else {
544                         if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
545                                 return false;
546                 }
547
548                 break;
549
550         case AF_NETLINK:
551
552                 if (a->protocol != b->protocol)
553                         return false;
554
555                 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
556                         return false;
557
558                 break;
559
560         default:
561                 /* Cannot compare, so we assume the addresses are different */
562                 return false;
563         }
564
565         return true;
566 }
567
568 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
569         struct SocketAddress b;
570
571         assert(a);
572         assert(s);
573
574         if (socket_address_parse(&b, s) < 0)
575                 return false;
576
577         b.type = type;
578
579         return socket_address_equal(a, &b);
580 }
581
582 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
583         struct SocketAddress b;
584
585         assert(a);
586         assert(s);
587
588         if (socket_address_parse_netlink(&b, s) < 0)
589                 return false;
590
591         return socket_address_equal(a, &b);
592 }
593
594 bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) {
595         assert(a);
596
597         if (socket_address_family(a) != AF_UNIX)
598                 return false;
599
600         if (a->sockaddr.un.sun_path[0] == 0)
601                 return false;
602
603         return path_startswith(a->sockaddr.un.sun_path, prefix);
604 }
605
606 bool socket_ipv6_is_supported(void) {
607         char *l = 0;
608         bool enabled;
609
610         if (access("/sys/module/ipv6", F_OK) != 0)
611                 return 0;
612
613         /* If we can't check "disable" parameter, assume enabled */
614         if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
615                 return 1;
616
617         /* If module was loaded with disable=1 no IPv6 available */
618         enabled = l[0] == '0';
619         free(l);
620
621         return enabled;
622 }
623
624 static const char* const netlink_family_table[] = {
625         [NETLINK_ROUTE] = "route",
626         [NETLINK_FIREWALL] = "firewall",
627         [NETLINK_INET_DIAG] = "inet-diag",
628         [NETLINK_NFLOG] = "nflog",
629         [NETLINK_XFRM] = "xfrm",
630         [NETLINK_SELINUX] = "selinux",
631         [NETLINK_ISCSI] = "iscsi",
632         [NETLINK_AUDIT] = "audit",
633         [NETLINK_FIB_LOOKUP] = "fib-lookup",
634         [NETLINK_CONNECTOR] = "connector",
635         [NETLINK_NETFILTER] = "netfilter",
636         [NETLINK_IP6_FW] = "ip6-fw",
637         [NETLINK_DNRTMSG] = "dnrtmsg",
638         [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
639         [NETLINK_GENERIC] = "generic",
640         [NETLINK_SCSITRANSPORT] = "scsitransport",
641         [NETLINK_ECRYPTFS] = "ecryptfs"
642 };
643
644 DEFINE_STRING_TABLE_LOOKUP(netlink_family, int);
645
646 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
647         [SOCKET_ADDRESS_DEFAULT] = "default",
648         [SOCKET_ADDRESS_BOTH] = "both",
649         [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
650 };
651
652 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);