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