diff options
Diffstat (limited to 'src/systemd/src/basic/socket-util.c')
| -rw-r--r-- | src/systemd/src/basic/socket-util.c | 163 |
1 files changed, 66 insertions, 97 deletions
diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c index 8ae68b6f..798ab16e 100644 --- a/src/systemd/src/basic/socket-util.c +++ b/src/systemd/src/basic/socket-util.c @@ -1,4 +1,3 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -43,7 +42,6 @@ #include "missing.h" #include "parse-util.h" #include "path-util.h" -#include "process-util.h" #include "socket-util.h" #include "string-table.h" #include "string-util.h" @@ -54,24 +52,14 @@ #if 0 /* NM_IGNORED */ #if ENABLE_IDN -# define IDN_FLAGS NI_IDN +# define IDN_FLAGS (NI_IDN|NI_IDN_USE_STD3_ASCII_RULES) #else # define IDN_FLAGS 0 #endif -static const char* const socket_address_type_table[] = { - [SOCK_STREAM] = "Stream", - [SOCK_DGRAM] = "Datagram", - [SOCK_RAW] = "Raw", - [SOCK_RDM] = "ReliableDatagram", - [SOCK_SEQPACKET] = "SequentialPacket", - [SOCK_DCCP] = "DatagramCongestionControl", -}; - -DEFINE_STRING_TABLE_LOOKUP(socket_address_type, int); - int socket_address_parse(SocketAddress *a, const char *s) { char *e, *n; + unsigned u; int r; assert(a); @@ -81,8 +69,6 @@ int socket_address_parse(SocketAddress *a, const char *s) { a->type = SOCK_STREAM; if (*s == '[') { - uint16_t port; - /* IPv6 in [x:.....:z]:p notation */ e = strchr(s+1, ']'); @@ -100,12 +86,15 @@ int socket_address_parse(SocketAddress *a, const char *s) { return -EINVAL; e++; - r = parse_ip_port(e, &port); + r = safe_atou(e, &u); if (r < 0) return r; + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htobe16(port); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->size = sizeof(struct sockaddr_in6); } else if (*s == '/') { @@ -135,14 +124,13 @@ int socket_address_parse(SocketAddress *a, const char *s) { } else if (startswith(s, "vsock:")) { /* AF_VSOCK socket in vsock:cid:port notation */ - const char *cid_start = s + STRLEN("vsock:"); - unsigned port; + const char *cid_start = s + strlen("vsock:"); e = strchr(cid_start, ':'); if (!e) return -EINVAL; - r = safe_atou(e+1, &port); + r = safe_atou(e+1, &u); if (r < 0) return r; @@ -155,18 +143,19 @@ int socket_address_parse(SocketAddress *a, const char *s) { a->sockaddr.vm.svm_cid = VMADDR_CID_ANY; a->sockaddr.vm.svm_family = AF_VSOCK; - a->sockaddr.vm.svm_port = port; + a->sockaddr.vm.svm_port = u; a->size = sizeof(struct sockaddr_vm); } else { - uint16_t port; - e = strchr(s, ':'); if (e) { - r = parse_ip_port(e + 1, &port); + r = safe_atou(e+1, &u); if (r < 0) return r; + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + n = strndupa(s, e-s); /* IPv4 in w.x.y.z:p notation? */ @@ -177,7 +166,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { if (r > 0) { /* Gotcha, it's a traditional IPv4 address */ a->sockaddr.in.sin_family = AF_INET; - a->sockaddr.in.sin_port = htobe16(port); + a->sockaddr.in.sin_port = htobe16((uint16_t)u); a->size = sizeof(struct sockaddr_in); } else { unsigned idx; @@ -191,7 +180,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { return -EINVAL; a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htobe16(port); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->sockaddr.in6.sin6_scope_id = idx; a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); @@ -199,18 +188,21 @@ int socket_address_parse(SocketAddress *a, const char *s) { } else { /* Just a port */ - r = parse_ip_port(s, &port); + r = safe_atou(s, &u); if (r < 0) return r; + if (u <= 0 || u > 0xFFFF) + return -EINVAL; + if (socket_ipv6_is_supported()) { a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htobe16(port); + a->sockaddr.in6.sin6_port = htobe16((uint16_t)u); a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); } else { a->sockaddr.in.sin_family = AF_INET; - a->sockaddr.in.sin_port = htobe16(port); + a->sockaddr.in.sin_port = htobe16((uint16_t)u); a->sockaddr.in.sin_addr.s_addr = INADDR_ANY; a->size = sizeof(struct sockaddr_in); } @@ -538,25 +530,22 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) { return socket_address_equal(a, &b); } -int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) { +int sockaddr_port(const struct sockaddr *_sa, unsigned *port) { union sockaddr_union *sa = (union sockaddr_union*) _sa; - /* Note, this returns the port as 'unsigned' rather than 'uint16_t', as AF_VSOCK knows larger ports */ - assert(sa); switch (sa->sa.sa_family) { - case AF_INET: - *ret_port = be16toh(sa->in.sin_port); + *port = be16toh(sa->in.sin_port); return 0; case AF_INET6: - *ret_port = be16toh(sa->in6.sin6_port); + *port = be16toh(sa->in6.sin6_port); return 0; case AF_VSOCK: - *ret_port = sa->vm.svm_port; + *port = sa->vm.svm_port; return 0; default: @@ -761,6 +750,19 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) return 0; } +int getnameinfo_pretty(int fd, char **ret) { + union sockaddr_union sa; + socklen_t salen = sizeof(sa); + + assert(fd >= 0); + assert(ret); + + if (getsockname(fd, &sa.sa, &salen) < 0) + return -errno; + + return socknameinfo_pretty(&sa, salen, ret); +} + int socket_address_unlink(SocketAddress *a) { assert(a); @@ -807,18 +809,6 @@ static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIN DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); -SocketAddressBindIPv6Only parse_socket_address_bind_ipv6_only_or_bool(const char *n) { - int r; - - r = parse_boolean(n); - if (r > 0) - return SOCKET_ADDRESS_IPV6_ONLY; - if (r == 0) - return SOCKET_ADDRESS_BOTH; - - return socket_address_bind_ipv6_only_from_string(n); -} - bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) { assert(a); assert(b); @@ -953,77 +943,56 @@ int getpeercred(int fd, struct ucred *ucred) { if (n != sizeof(struct ucred)) return -EIO; - /* Check if the data is actually useful and not suppressed due to namespacing issues */ - if (!pid_is_valid(u.pid)) + /* Check if the data is actually useful and not suppressed due + * to namespacing issues */ + if (u.pid <= 0) + return -ENODATA; + if (u.uid == UID_INVALID) + return -ENODATA; + if (u.gid == GID_INVALID) return -ENODATA; - - /* Note that we don't check UID/GID here, as namespace translation works differently there: instead of - * receiving in "invalid" user/group we get the overflow UID/GID. */ *ucred = u; return 0; } int getpeersec(int fd, char **ret) { - _cleanup_free_ char *s = NULL; socklen_t n = 64; + char *s; + int r; assert(fd >= 0); assert(ret); - for (;;) { - s = new0(char, n+1); - if (!s) - return -ENOMEM; + s = new0(char, n); + if (!s) + return -ENOMEM; - if (getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n) >= 0) - break; + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); if (errno != ERANGE) return -errno; - s = mfree(s); - } - - if (isempty(s)) - return -EOPNOTSUPP; - - *ret = TAKE_PTR(s); - - return 0; -} - -int getpeergroups(int fd, gid_t **ret) { - socklen_t n = sizeof(gid_t) * 64; - _cleanup_free_ gid_t *d = NULL; - - assert(fd >= 0); - assert(ret); - - for (;;) { - d = malloc(n); - if (!d) + s = new0(char, n); + if (!s) return -ENOMEM; - if (getsockopt(fd, SOL_SOCKET, SO_PEERGROUPS, d, &n) >= 0) - break; - - if (errno != ERANGE) + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); return -errno; - - d = mfree(d); + } } - assert_se(n % sizeof(gid_t) == 0); - n /= sizeof(gid_t); - - if ((socklen_t) (int) n != n) - return -E2BIG; - - *ret = d; - d = NULL; + if (isempty(s)) { + free(s); + return -EOPNOTSUPP; + } - return (int) n; + *ret = s; + return 0; } int send_one_fd_sa( |