]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/socket-util.c
user-util: move UID/GID related macros from macro.h to user-util.h
[thirdparty/systemd.git] / src / basic / 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 <arpa/inet.h>
23 #include <errno.h>
24 #include <net/if.h>
25 #include <netdb.h>
26 #include <netinet/ip.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32
33 #include "fd-util.h"
34 #include "fileio.h"
35 #include "formats-util.h"
36 #include "macro.h"
37 #include "missing.h"
38 #include "parse-util.h"
39 #include "path-util.h"
40 #include "socket-util.h"
41 #include "string-table.h"
42 #include "string-util.h"
43 #include "user-util.h"
44 #include "util.h"
45
46 int socket_address_parse(SocketAddress *a, const char *s) {
47 char *e, *n;
48 unsigned u;
49 int r;
50
51 assert(a);
52 assert(s);
53
54 zero(*a);
55 a->type = SOCK_STREAM;
56
57 if (*s == '[') {
58 /* IPv6 in [x:.....:z]:p notation */
59
60 e = strchr(s+1, ']');
61 if (!e)
62 return -EINVAL;
63
64 n = strndupa(s+1, e-s-1);
65
66 errno = 0;
67 if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
68 return errno > 0 ? -errno : -EINVAL;
69
70 e++;
71 if (*e != ':')
72 return -EINVAL;
73
74 e++;
75 r = safe_atou(e, &u);
76 if (r < 0)
77 return r;
78
79 if (u <= 0 || u > 0xFFFF)
80 return -EINVAL;
81
82 a->sockaddr.in6.sin6_family = AF_INET6;
83 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
84 a->size = sizeof(struct sockaddr_in6);
85
86 } else if (*s == '/') {
87 /* AF_UNIX socket */
88
89 size_t l;
90
91 l = strlen(s);
92 if (l >= sizeof(a->sockaddr.un.sun_path))
93 return -EINVAL;
94
95 a->sockaddr.un.sun_family = AF_UNIX;
96 memcpy(a->sockaddr.un.sun_path, s, l);
97 a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
98
99 } else if (*s == '@') {
100 /* Abstract AF_UNIX socket */
101 size_t l;
102
103 l = strlen(s+1);
104 if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
105 return -EINVAL;
106
107 a->sockaddr.un.sun_family = AF_UNIX;
108 memcpy(a->sockaddr.un.sun_path+1, s+1, l);
109 a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
110
111 } else {
112 e = strchr(s, ':');
113 if (e) {
114 r = safe_atou(e+1, &u);
115 if (r < 0)
116 return r;
117
118 if (u <= 0 || u > 0xFFFF)
119 return -EINVAL;
120
121 n = strndupa(s, e-s);
122
123 /* IPv4 in w.x.y.z:p notation? */
124 r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
125 if (r < 0)
126 return -errno;
127
128 if (r > 0) {
129 /* Gotcha, it's a traditional IPv4 address */
130 a->sockaddr.in.sin_family = AF_INET;
131 a->sockaddr.in.sin_port = htons((uint16_t) u);
132 a->size = sizeof(struct sockaddr_in);
133 } else {
134 unsigned idx;
135
136 if (strlen(n) > IF_NAMESIZE-1)
137 return -EINVAL;
138
139 /* Uh, our last resort, an interface name */
140 idx = if_nametoindex(n);
141 if (idx == 0)
142 return -EINVAL;
143
144 a->sockaddr.in6.sin6_family = AF_INET6;
145 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
146 a->sockaddr.in6.sin6_scope_id = idx;
147 a->sockaddr.in6.sin6_addr = in6addr_any;
148 a->size = sizeof(struct sockaddr_in6);
149 }
150 } else {
151
152 /* Just a port */
153 r = safe_atou(s, &u);
154 if (r < 0)
155 return r;
156
157 if (u <= 0 || u > 0xFFFF)
158 return -EINVAL;
159
160 if (socket_ipv6_is_supported()) {
161 a->sockaddr.in6.sin6_family = AF_INET6;
162 a->sockaddr.in6.sin6_port = htons((uint16_t) u);
163 a->sockaddr.in6.sin6_addr = in6addr_any;
164 a->size = sizeof(struct sockaddr_in6);
165 } else {
166 a->sockaddr.in.sin_family = AF_INET;
167 a->sockaddr.in.sin_port = htons((uint16_t) u);
168 a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
169 a->size = sizeof(struct sockaddr_in);
170 }
171 }
172 }
173
174 return 0;
175 }
176
177 int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
178 SocketAddress b;
179 int r;
180
181 /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
182
183 r = socket_address_parse(&b, s);
184 if (r < 0)
185 return r;
186
187 if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
188 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
189 return -EAFNOSUPPORT;
190 }
191
192 *a = b;
193 return 0;
194 }
195
196 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
197 int family;
198 unsigned group = 0;
199 _cleanup_free_ char *sfamily = NULL;
200 assert(a);
201 assert(s);
202
203 zero(*a);
204 a->type = SOCK_RAW;
205
206 errno = 0;
207 if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
208 return errno > 0 ? -errno : -EINVAL;
209
210 family = netlink_family_from_string(sfamily);
211 if (family < 0)
212 return -EINVAL;
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.in.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 e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
264 if (!e)
265 return -EINVAL;
266
267 if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
268 return -EINVAL;
269 }
270 }
271
272 if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
273 return -EINVAL;
274
275 return 0;
276
277 case AF_NETLINK:
278
279 if (a->size != sizeof(struct sockaddr_nl))
280 return -EINVAL;
281
282 if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
283 return -EINVAL;
284
285 return 0;
286
287 default:
288 return -EAFNOSUPPORT;
289 }
290 }
291
292 int socket_address_print(const SocketAddress *a, char **ret) {
293 int r;
294
295 assert(a);
296 assert(ret);
297
298 r = socket_address_verify(a);
299 if (r < 0)
300 return r;
301
302 if (socket_address_family(a) == AF_NETLINK) {
303 _cleanup_free_ char *sfamily = NULL;
304
305 r = netlink_family_to_string_alloc(a->protocol, &sfamily);
306 if (r < 0)
307 return r;
308
309 r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
310 if (r < 0)
311 return -ENOMEM;
312
313 return 0;
314 }
315
316 return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, ret);
317 }
318
319 bool socket_address_can_accept(const SocketAddress *a) {
320 assert(a);
321
322 return
323 a->type == SOCK_STREAM ||
324 a->type == SOCK_SEQPACKET;
325 }
326
327 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
328 assert(a);
329 assert(b);
330
331 /* Invalid addresses are unequal to all */
332 if (socket_address_verify(a) < 0 ||
333 socket_address_verify(b) < 0)
334 return false;
335
336 if (a->type != b->type)
337 return false;
338
339 if (socket_address_family(a) != socket_address_family(b))
340 return false;
341
342 switch (socket_address_family(a)) {
343
344 case AF_INET:
345 if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
346 return false;
347
348 if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
349 return false;
350
351 break;
352
353 case AF_INET6:
354 if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
355 return false;
356
357 if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
358 return false;
359
360 break;
361
362 case AF_UNIX:
363 if (a->size <= offsetof(struct sockaddr_un, sun_path) ||
364 b->size <= offsetof(struct sockaddr_un, sun_path))
365 return false;
366
367 if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
368 return false;
369
370 if (a->sockaddr.un.sun_path[0]) {
371 if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
372 return false;
373 } else {
374 if (a->size != b->size)
375 return false;
376
377 if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
378 return false;
379 }
380
381 break;
382
383 case AF_NETLINK:
384 if (a->protocol != b->protocol)
385 return false;
386
387 if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
388 return false;
389
390 break;
391
392 default:
393 /* Cannot compare, so we assume the addresses are different */
394 return false;
395 }
396
397 return true;
398 }
399
400 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
401 struct SocketAddress b;
402
403 assert(a);
404 assert(s);
405
406 if (socket_address_parse(&b, s) < 0)
407 return false;
408
409 b.type = type;
410
411 return socket_address_equal(a, &b);
412 }
413
414 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
415 struct SocketAddress b;
416
417 assert(a);
418 assert(s);
419
420 if (socket_address_parse_netlink(&b, s) < 0)
421 return false;
422
423 return socket_address_equal(a, &b);
424 }
425
426 const char* socket_address_get_path(const SocketAddress *a) {
427 assert(a);
428
429 if (socket_address_family(a) != AF_UNIX)
430 return NULL;
431
432 if (a->sockaddr.un.sun_path[0] == 0)
433 return NULL;
434
435 return a->sockaddr.un.sun_path;
436 }
437
438 bool socket_ipv6_is_supported(void) {
439 _cleanup_free_ char *l = NULL;
440
441 if (access("/sys/module/ipv6", F_OK) != 0)
442 return false;
443
444 /* If we can't check "disable" parameter, assume enabled */
445 if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
446 return true;
447
448 /* If module was loaded with disable=1 no IPv6 available */
449 return l[0] == '0';
450 }
451
452 bool socket_address_matches_fd(const SocketAddress *a, int fd) {
453 SocketAddress b;
454 socklen_t solen;
455
456 assert(a);
457 assert(fd >= 0);
458
459 b.size = sizeof(b.sockaddr);
460 if (getsockname(fd, &b.sockaddr.sa, &b.size) < 0)
461 return false;
462
463 if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family)
464 return false;
465
466 solen = sizeof(b.type);
467 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0)
468 return false;
469
470 if (b.type != a->type)
471 return false;
472
473 if (a->protocol != 0) {
474 solen = sizeof(b.protocol);
475 if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0)
476 return false;
477
478 if (b.protocol != a->protocol)
479 return false;
480 }
481
482 return socket_address_equal(a, &b);
483 }
484
485 int sockaddr_port(const struct sockaddr *_sa) {
486 union sockaddr_union *sa = (union sockaddr_union*) _sa;
487
488 assert(sa);
489
490 if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6))
491 return -EAFNOSUPPORT;
492
493 return ntohs(sa->sa.sa_family == AF_INET6 ?
494 sa->in6.sin6_port :
495 sa->in.sin_port);
496 }
497
498 int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) {
499 union sockaddr_union *sa = (union sockaddr_union*) _sa;
500 char *p;
501 int r;
502
503 assert(sa);
504 assert(salen >= sizeof(sa->sa.sa_family));
505
506 switch (sa->sa.sa_family) {
507
508 case AF_INET: {
509 uint32_t a;
510
511 a = ntohl(sa->in.sin_addr.s_addr);
512
513 if (include_port)
514 r = asprintf(&p,
515 "%u.%u.%u.%u:%u",
516 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
517 ntohs(sa->in.sin_port));
518 else
519 r = asprintf(&p,
520 "%u.%u.%u.%u",
521 a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF);
522 if (r < 0)
523 return -ENOMEM;
524 break;
525 }
526
527 case AF_INET6: {
528 static const unsigned char ipv4_prefix[] = {
529 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
530 };
531
532 if (translate_ipv6 &&
533 memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
534 const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
535 if (include_port)
536 r = asprintf(&p,
537 "%u.%u.%u.%u:%u",
538 a[0], a[1], a[2], a[3],
539 ntohs(sa->in6.sin6_port));
540 else
541 r = asprintf(&p,
542 "%u.%u.%u.%u",
543 a[0], a[1], a[2], a[3]);
544 if (r < 0)
545 return -ENOMEM;
546 } else {
547 char a[INET6_ADDRSTRLEN];
548
549 inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
550
551 if (include_port) {
552 r = asprintf(&p,
553 "[%s]:%u",
554 a,
555 ntohs(sa->in6.sin6_port));
556 if (r < 0)
557 return -ENOMEM;
558 } else {
559 p = strdup(a);
560 if (!p)
561 return -ENOMEM;
562 }
563 }
564
565 break;
566 }
567
568 case AF_UNIX:
569 if (salen <= offsetof(struct sockaddr_un, sun_path)) {
570 p = strdup("<unnamed>");
571 if (!p)
572 return -ENOMEM;
573
574 } else if (sa->un.sun_path[0] == 0) {
575 /* abstract */
576
577 /* FIXME: We assume we can print the
578 * socket path here and that it hasn't
579 * more than one NUL byte. That is
580 * actually an invalid assumption */
581
582 p = new(char, sizeof(sa->un.sun_path)+1);
583 if (!p)
584 return -ENOMEM;
585
586 p[0] = '@';
587 memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
588 p[sizeof(sa->un.sun_path)] = 0;
589
590 } else {
591 p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
592 if (!p)
593 return -ENOMEM;
594 }
595
596 break;
597
598 default:
599 return -EOPNOTSUPP;
600 }
601
602
603 *ret = p;
604 return 0;
605 }
606
607 int getpeername_pretty(int fd, char **ret) {
608 union sockaddr_union sa;
609 socklen_t salen = sizeof(sa);
610 int r;
611
612 assert(fd >= 0);
613 assert(ret);
614
615 if (getpeername(fd, &sa.sa, &salen) < 0)
616 return -errno;
617
618 if (sa.sa.sa_family == AF_UNIX) {
619 struct ucred ucred = {};
620
621 /* UNIX connection sockets are anonymous, so let's use
622 * PID/UID as pretty credentials instead */
623
624 r = getpeercred(fd, &ucred);
625 if (r < 0)
626 return r;
627
628 if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
629 return -ENOMEM;
630
631 return 0;
632 }
633
634 /* For remote sockets we translate IPv6 addresses back to IPv4
635 * if applicable, since that's nicer. */
636
637 return sockaddr_pretty(&sa.sa, salen, true, true, ret);
638 }
639
640 int getsockname_pretty(int fd, char **ret) {
641 union sockaddr_union sa;
642 socklen_t salen = sizeof(sa);
643
644 assert(fd >= 0);
645 assert(ret);
646
647 if (getsockname(fd, &sa.sa, &salen) < 0)
648 return -errno;
649
650 /* For local sockets we do not translate IPv6 addresses back
651 * to IPv6 if applicable, since this is usually used for
652 * listening sockets where the difference between IPv4 and
653 * IPv6 matters. */
654
655 return sockaddr_pretty(&sa.sa, salen, false, true, ret);
656 }
657
658 int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
659 int r;
660 char host[NI_MAXHOST], *ret;
661
662 assert(_ret);
663
664 r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
665 NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
666 if (r != 0) {
667 int saved_errno = errno;
668
669 r = sockaddr_pretty(&sa->sa, salen, true, true, &ret);
670 if (r < 0)
671 return r;
672
673 log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
674 } else {
675 ret = strdup(host);
676 if (!ret)
677 return -ENOMEM;
678 }
679
680 *_ret = ret;
681 return 0;
682 }
683
684 int getnameinfo_pretty(int fd, char **ret) {
685 union sockaddr_union sa;
686 socklen_t salen = sizeof(sa);
687
688 assert(fd >= 0);
689 assert(ret);
690
691 if (getsockname(fd, &sa.sa, &salen) < 0)
692 return -errno;
693
694 return socknameinfo_pretty(&sa, salen, ret);
695 }
696
697 int socket_address_unlink(SocketAddress *a) {
698 assert(a);
699
700 if (socket_address_family(a) != AF_UNIX)
701 return 0;
702
703 if (a->sockaddr.un.sun_path[0] == 0)
704 return 0;
705
706 if (unlink(a->sockaddr.un.sun_path) < 0)
707 return -errno;
708
709 return 1;
710 }
711
712 static const char* const netlink_family_table[] = {
713 [NETLINK_ROUTE] = "route",
714 [NETLINK_FIREWALL] = "firewall",
715 [NETLINK_INET_DIAG] = "inet-diag",
716 [NETLINK_NFLOG] = "nflog",
717 [NETLINK_XFRM] = "xfrm",
718 [NETLINK_SELINUX] = "selinux",
719 [NETLINK_ISCSI] = "iscsi",
720 [NETLINK_AUDIT] = "audit",
721 [NETLINK_FIB_LOOKUP] = "fib-lookup",
722 [NETLINK_CONNECTOR] = "connector",
723 [NETLINK_NETFILTER] = "netfilter",
724 [NETLINK_IP6_FW] = "ip6-fw",
725 [NETLINK_DNRTMSG] = "dnrtmsg",
726 [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
727 [NETLINK_GENERIC] = "generic",
728 [NETLINK_SCSITRANSPORT] = "scsitransport",
729 [NETLINK_ECRYPTFS] = "ecryptfs"
730 };
731
732 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
733
734 static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
735 [SOCKET_ADDRESS_DEFAULT] = "default",
736 [SOCKET_ADDRESS_BOTH] = "both",
737 [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
738 };
739
740 DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
741
742 bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
743 assert(a);
744 assert(b);
745
746 if (a->sa.sa_family != b->sa.sa_family)
747 return false;
748
749 if (a->sa.sa_family == AF_INET)
750 return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
751
752 if (a->sa.sa_family == AF_INET6)
753 return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
754
755 return false;
756 }
757
758 int fd_inc_sndbuf(int fd, size_t n) {
759 int r, value;
760 socklen_t l = sizeof(value);
761
762 r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
763 if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
764 return 0;
765
766 /* If we have the privileges we will ignore the kernel limit. */
767
768 value = (int) n;
769 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
770 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
771 return -errno;
772
773 return 1;
774 }
775
776 int fd_inc_rcvbuf(int fd, size_t n) {
777 int r, value;
778 socklen_t l = sizeof(value);
779
780 r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
781 if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
782 return 0;
783
784 /* If we have the privileges we will ignore the kernel limit. */
785
786 value = (int) n;
787 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
788 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
789 return -errno;
790 return 1;
791 }
792
793 static const char* const ip_tos_table[] = {
794 [IPTOS_LOWDELAY] = "low-delay",
795 [IPTOS_THROUGHPUT] = "throughput",
796 [IPTOS_RELIABILITY] = "reliability",
797 [IPTOS_LOWCOST] = "low-cost",
798 };
799
800 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
801
802 int getpeercred(int fd, struct ucred *ucred) {
803 socklen_t n = sizeof(struct ucred);
804 struct ucred u;
805 int r;
806
807 assert(fd >= 0);
808 assert(ucred);
809
810 r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
811 if (r < 0)
812 return -errno;
813
814 if (n != sizeof(struct ucred))
815 return -EIO;
816
817 /* Check if the data is actually useful and not suppressed due
818 * to namespacing issues */
819 if (u.pid <= 0)
820 return -ENODATA;
821 if (u.uid == UID_INVALID)
822 return -ENODATA;
823 if (u.gid == GID_INVALID)
824 return -ENODATA;
825
826 *ucred = u;
827 return 0;
828 }
829
830 int getpeersec(int fd, char **ret) {
831 socklen_t n = 64;
832 char *s;
833 int r;
834
835 assert(fd >= 0);
836 assert(ret);
837
838 s = new0(char, n);
839 if (!s)
840 return -ENOMEM;
841
842 r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
843 if (r < 0) {
844 free(s);
845
846 if (errno != ERANGE)
847 return -errno;
848
849 s = new0(char, n);
850 if (!s)
851 return -ENOMEM;
852
853 r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
854 if (r < 0) {
855 free(s);
856 return -errno;
857 }
858 }
859
860 if (isempty(s)) {
861 free(s);
862 return -EOPNOTSUPP;
863 }
864
865 *ret = s;
866 return 0;
867 }
868
869 int send_one_fd(int transport_fd, int fd, int flags) {
870 union {
871 struct cmsghdr cmsghdr;
872 uint8_t buf[CMSG_SPACE(sizeof(int))];
873 } control = {};
874 struct msghdr mh = {
875 .msg_control = &control,
876 .msg_controllen = sizeof(control),
877 };
878 struct cmsghdr *cmsg;
879
880 assert(transport_fd >= 0);
881 assert(fd >= 0);
882
883 cmsg = CMSG_FIRSTHDR(&mh);
884 cmsg->cmsg_level = SOL_SOCKET;
885 cmsg->cmsg_type = SCM_RIGHTS;
886 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
887 memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
888
889 mh.msg_controllen = CMSG_SPACE(sizeof(int));
890 if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0)
891 return -errno;
892
893 return 0;
894 }
895
896 int receive_one_fd(int transport_fd, int flags) {
897 union {
898 struct cmsghdr cmsghdr;
899 uint8_t buf[CMSG_SPACE(sizeof(int))];
900 } control = {};
901 struct msghdr mh = {
902 .msg_control = &control,
903 .msg_controllen = sizeof(control),
904 };
905 struct cmsghdr *cmsg, *found = NULL;
906
907 assert(transport_fd >= 0);
908
909 /*
910 * Receive a single FD via @transport_fd. We don't care for
911 * the transport-type. We retrieve a single FD at most, so for
912 * packet-based transports, the caller must ensure to send
913 * only a single FD per packet. This is best used in
914 * combination with send_one_fd().
915 */
916
917 if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0)
918 return -errno;
919
920 CMSG_FOREACH(cmsg, &mh) {
921 if (cmsg->cmsg_level == SOL_SOCKET &&
922 cmsg->cmsg_type == SCM_RIGHTS &&
923 cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
924 assert(!found);
925 found = cmsg;
926 break;
927 }
928 }
929
930 if (!found) {
931 cmsg_close_all(&mh);
932 return -EIO;
933 }
934
935 return *(int*) CMSG_DATA(found);
936 }