diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/util/system.c | 72 | ||||
-rw-r--r-- | lib/util/util.h | 14 | ||||
-rw-r--r-- | lib/util/util_net.c | 155 | ||||
-rw-r--r-- | lib/util/util_net.h | 35 |
4 files changed, 275 insertions, 1 deletions
diff --git a/lib/util/system.c b/lib/util/system.c index 9bf5de1a83..17c0553102 100644 --- a/lib/util/system.c +++ b/lib/util/system.c @@ -117,3 +117,75 @@ _PUBLIC_ pid_t sys_getpid(void) return mypid; } + + +_PUBLIC_ int sys_getpeereid( int s, uid_t *uid) +{ +#if defined(HAVE_PEERCRED) + struct ucred cred; + socklen_t cred_len = sizeof(struct ucred); + int ret; + + ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len); + if (ret != 0) { + return -1; + } + + if (cred_len != sizeof(struct ucred)) { + errno = EINVAL; + return -1; + } + + *uid = cred.uid; + return 0; +#else +#if defined(HAVE_GETPEEREID) + gid_t gid; + return getpeereid(s, uid, &gid); +#endif + errno = ENOSYS; + return -1; +#endif +} + +_PUBLIC_ int sys_getnameinfo(const struct sockaddr *psa, + int salen, + char *host, + size_t hostlen, + char *service, + size_t servlen, + int flags) +{ + /* + * For Solaris we must make sure salen is the + * correct length for the incoming sa_family. + */ + + if (salen == sizeof(struct sockaddr_storage)) { + salen = sizeof(struct sockaddr_in); +#if defined(HAVE_IPV6) + if (psa->sa_family == AF_INET6) { + salen = sizeof(struct sockaddr_in6); + } +#endif + } + return getnameinfo(psa, salen, host, hostlen, service, servlen, flags); +} + +_PUBLIC_ int sys_connect(int fd, const struct sockaddr * addr) +{ + socklen_t salen = (socklen_t)-1; + + if (addr->sa_family == AF_INET) { + salen = sizeof(struct sockaddr_in); + } else if (addr->sa_family == AF_UNIX) { + salen = sizeof(struct sockaddr_un); + } +#if defined(HAVE_IPV6) + else if (addr->sa_family == AF_INET6) { + salen = sizeof(struct sockaddr_in6); + } +#endif + + return connect(fd, addr, salen); +} diff --git a/lib/util/util.h b/lib/util/util.h index 8dffece0da..5ed8427498 100644 --- a/lib/util/util.h +++ b/lib/util/util.h @@ -131,8 +131,20 @@ _PUBLIC_ pid_t sys_fork(void); **/ _PUBLIC_ pid_t sys_getpid(void); -/* The following definitions come from lib/util/genrand.c */ +_PUBLIC_ int sys_getpeereid( int s, uid_t *uid); + +struct sockaddr; +_PUBLIC_ int sys_getnameinfo(const struct sockaddr *psa, + int salen, + char *host, + size_t hostlen, + char *service, + size_t servlen, + int flags); +_PUBLIC_ int sys_connect(int fd, const struct sockaddr * addr); + +/* The following definitions come from lib/util/genrand.c */ /** Copy any user given reseed data. **/ diff --git a/lib/util/util_net.c b/lib/util/util_net.c index 9c8f5c6d47..e80447128f 100644 --- a/lib/util/util_net.c +++ b/lib/util/util_net.c @@ -540,3 +540,158 @@ void set_sockaddr_port(struct sockaddr *psa, uint16_t port) } +/**************************************************************************** + Get a port number in host byte order from a sockaddr_storage. +****************************************************************************/ + +uint16_t get_sockaddr_port(const struct sockaddr_storage *pss) +{ + uint16_t port = 0; + + if (pss->ss_family != AF_INET) { +#if defined(HAVE_IPV6) + /* IPv6 */ + const struct sockaddr_in6 *sa6 = + (const struct sockaddr_in6 *)pss; + port = ntohs(sa6->sin6_port); +#endif + } else { + const struct sockaddr_in *sa = + (const struct sockaddr_in *)pss; + port = ntohs(sa->sin_port); + } + return port; +} + +/**************************************************************************** + Print out an IPv4 or IPv6 address from a struct sockaddr_storage. +****************************************************************************/ + +char *print_sockaddr_len(char *dest, + size_t destlen, + const struct sockaddr *psa, + socklen_t psalen) +{ + if (destlen > 0) { + dest[0] = '\0'; + } + (void)sys_getnameinfo(psa, + psalen, + dest, destlen, + NULL, 0, + NI_NUMERICHOST); + return dest; +} + +/**************************************************************************** + Print out an IPv4 or IPv6 address from a struct sockaddr_storage. +****************************************************************************/ + +char *print_sockaddr(char *dest, + size_t destlen, + const struct sockaddr_storage *psa) +{ + return print_sockaddr_len(dest, destlen, (struct sockaddr *)psa, + sizeof(struct sockaddr_storage)); +} + +/**************************************************************************** + Print out a canonical IPv4 or IPv6 address from a struct sockaddr_storage. +****************************************************************************/ + +char *print_canonical_sockaddr(TALLOC_CTX *ctx, + const struct sockaddr_storage *pss) +{ + char addr[INET6_ADDRSTRLEN]; + char *dest = NULL; + int ret; + + /* Linux getnameinfo() man pages says port is unitialized if + service name is NULL. */ + + ret = sys_getnameinfo((const struct sockaddr *)pss, + sizeof(struct sockaddr_storage), + addr, sizeof(addr), + NULL, 0, + NI_NUMERICHOST); + if (ret != 0) { + return NULL; + } + + if (pss->ss_family != AF_INET) { +#if defined(HAVE_IPV6) + dest = talloc_asprintf(ctx, "[%s]", addr); +#else + return NULL; +#endif + } else { + dest = talloc_asprintf(ctx, "%s", addr); + } + + return dest; +} + +/**************************************************************************** + Return the port number we've bound to on a socket. +****************************************************************************/ + +int get_socket_port(int fd) +{ + struct sockaddr_storage sa; + socklen_t length = sizeof(sa); + + if (fd == -1) { + return -1; + } + + if (getsockname(fd, (struct sockaddr *)&sa, &length) < 0) { + int level = (errno == ENOTCONN) ? 2 : 0; + DEBUG(level, ("getsockname failed. Error was %s\n", + strerror(errno))); + return -1; + } + +#if defined(HAVE_IPV6) + if (sa.ss_family == AF_INET6) { + return ntohs(((struct sockaddr_in6 *)&sa)->sin6_port); + } +#endif + if (sa.ss_family == AF_INET) { + return ntohs(((struct sockaddr_in *)&sa)->sin_port); + } + return -1; +} + +/**************************************************************************** + Return the string of an IP address (IPv4 or IPv6). +****************************************************************************/ + +static const char *get_socket_addr(int fd, char *addr_buf, size_t addr_len) +{ + struct sockaddr_storage sa; + socklen_t length = sizeof(sa); + + /* Ok, returning a hard coded IPv4 address + * is bogus, but it's just as bogus as a + * zero IPv6 address. No good choice here. + */ + + strlcpy(addr_buf, "0.0.0.0", addr_len); + + if (fd == -1) { + return addr_buf; + } + + if (getsockname(fd, (struct sockaddr *)&sa, &length) < 0) { + DEBUG(0,("getsockname failed. Error was %s\n", + strerror(errno) )); + return addr_buf; + } + + return print_sockaddr_len(addr_buf, addr_len, (struct sockaddr *)&sa, length); +} + +const char *client_socket_addr(int fd, char *addr, size_t addr_len) +{ + return get_socket_addr(fd, addr, addr_len); +} diff --git a/lib/util/util_net.h b/lib/util/util_net.h index 530311e5c8..71d1d1a6bd 100644 --- a/lib/util/util_net.h +++ b/lib/util/util_net.h @@ -50,6 +50,15 @@ void set_sockaddr_port(struct sockaddr *psa, uint16_t port); **/ _PUBLIC_ bool is_zero_ip_v4(struct in_addr ip); +void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss, + struct in_addr ip); +#if defined(HAVE_IPV6) +/** + * Convert an IPv6 struct in_addr to a struct sockaddr_storage. + */ +void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss, + struct in6_addr ip); +#endif /** Are two IPs on the same subnet? **/ @@ -60,6 +69,11 @@ _PUBLIC_ bool same_net_v4(struct in_addr ip1,struct in_addr ip2,struct in_addr m **/ _PUBLIC_ bool is_ipaddress(const char *str); +bool is_broadcast_addr(const struct sockaddr *pss); +bool is_loopback_ip_v4(struct in_addr ip); +bool is_loopback_addr(const struct sockaddr *pss); +bool is_zero_addr(const struct sockaddr_storage *pss); +void zero_ip_v4(struct in_addr *ip); /** Interpret an internet address or name into an IP address in 4 byte form. **/ @@ -72,5 +86,26 @@ _PUBLIC_ struct in_addr interpret_addr2(const char *str); _PUBLIC_ bool is_ipaddress_v4(const char *str); +bool is_address_any(const struct sockaddr *psa); +bool same_net(const struct sockaddr *ip1, + const struct sockaddr *ip2, + const struct sockaddr *mask); +bool sockaddr_equal(const struct sockaddr *ip1, + const struct sockaddr *ip2); + +bool is_address_any(const struct sockaddr *psa); +uint16_t get_sockaddr_port(const struct sockaddr_storage *pss); +char *print_sockaddr_len(char *dest, + size_t destlen, + const struct sockaddr *psa, + socklen_t psalen); +char *print_sockaddr(char *dest, + size_t destlen, + const struct sockaddr_storage *psa); +char *print_canonical_sockaddr(TALLOC_CTX *ctx, + const struct sockaddr_storage *pss); +const char *client_name(int fd); +int get_socket_port(int fd); +const char *client_socket_addr(int fd, char *addr, size_t addr_len); #endif /* _SAMBA_UTIL_NET_H_ */ |