diff options
author | Pavel Březina <pbrezina@redhat.com> | 2012-06-27 14:53:02 +0200 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2012-06-29 11:37:18 -0400 |
commit | 468f1c8d4763a65f24ab8d7523a5291ef6320db7 (patch) | |
tree | e00eae9a586acb92a817de7fd3da879c9ced2ee9 | |
parent | 1bb62d67c6d54a8ebd111ca08344f2d17b1f6f52 (diff) | |
download | sssd-468f1c8d4763a65f24ab8d7523a5291ef6320db7.tar.gz sssd-468f1c8d4763a65f24ab8d7523a5291ef6320db7.tar.xz sssd-468f1c8d4763a65f24ab8d7523a5291ef6320db7.zip |
sudo ldap provider: support autoconfiguration of IP addresses
sudoHost attribute may contain IPv4 or IPv6 host/network address.
This patch adds support for autoconfiguration of these information.
-rw-r--r-- | src/providers/ldap/sdap_async_sudo_hostinfo.c | 180 |
1 files changed, 179 insertions, 1 deletions
diff --git a/src/providers/ldap/sdap_async_sudo_hostinfo.c b/src/providers/ldap/sdap_async_sudo_hostinfo.c index 0b8f44056..d219d8830 100644 --- a/src/providers/ldap/sdap_async_sudo_hostinfo.c +++ b/src/providers/ldap/sdap_async_sudo_hostinfo.c @@ -21,12 +21,18 @@ #include <errno.h> #include <tevent.h> #include <talloc.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <ifaddrs.h> #include "util/util.h" #include "providers/ldap/sdap.h" #include "providers/ldap/sdap_id_op.h" #include "providers/ldap/sdap_sudo.h" +static int sdap_sudo_get_ip_addresses(TALLOC_CTX *mem_ctx, char ***_ip_addr); + struct sdap_sudo_get_hostinfo_state { char **hostnames; char **ip_addr; @@ -80,7 +86,13 @@ struct tevent_req * sdap_sudo_get_hostinfo_send(TALLOC_CTX *mem_ctx, } } - /* auto configuration will be supported later */ + /* if IP addresses are not specified, configure it automatically */ + if (state->ip_addr == NULL) { + ret = sdap_sudo_get_ip_addresses(state, &state->ip_addr); + if (ret != EOK) { + + } + } done: if (ret != EAGAIN) { @@ -109,3 +121,169 @@ int sdap_sudo_get_hostinfo_recv(TALLOC_CTX *mem_ctx, return EOK; } + +static int sdap_sudo_get_ip_addresses(TALLOC_CTX *mem_ctx, char ***_ip_addr_list) +{ + TALLOC_CTX *tmp_ctx = NULL; + char **ip_addr_list = NULL; + struct ifaddrs *ifaces = NULL; + struct ifaddrs *iface = NULL; + struct sockaddr_in *ip4_addr = NULL; + struct sockaddr_in *ip4_network = NULL; + struct sockaddr_in6 *ip6_addr = NULL; + struct sockaddr_in6 *ip6_network = NULL; + char ip_addr[INET6_ADDRSTRLEN + 1]; + char network_addr[INET6_ADDRSTRLEN + 1]; + in_addr_t ip4_netmask = 0; + uint32_t ip6_netmask = 0; + unsigned int netmask = 0; + void *sinx_addr = NULL; + void *sinx_network = NULL; + int addr_count = 0; + int ret; + int i; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + return ENOMEM; + } + + errno = 0; + ret = getifaddrs(&ifaces); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, ("Could not read interfaces [%d][%s]\n", + ret, strerror(ret))); + goto done; + } + + for (iface = ifaces; iface != NULL; iface = iface->ifa_next) { + netmask = 0; + switch (iface->ifa_addr->sa_family) { + case AF_INET: + ip4_addr = (struct sockaddr_in*)(iface->ifa_addr); + ip4_network = (struct sockaddr_in*)(iface->ifa_netmask); + + /* ignore loopback */ + if (inet_netof(ip4_addr->sin_addr) == IN_LOOPBACKNET) { + continue; + } + + /* ignore multicast */ + if (IN_MULTICAST(ip4_addr->sin_addr.s_addr)) { + continue; + } + + /* ignore broadcast */ + if (ntohl(ip4_addr->sin_addr.s_addr) == INADDR_BROADCAST) { + continue; + } + + /* get network mask length */ + ip4_netmask = ntohl(ip4_network->sin_addr.s_addr); + while (ip4_netmask) { + netmask++; + ip4_netmask <<= 1; + } + + /* get network address */ + ip4_network->sin_addr.s_addr = ip4_addr->sin_addr.s_addr + & ip4_network->sin_addr.s_addr; + + sinx_addr = &ip4_addr->sin_addr; + sinx_network = &ip4_network->sin_addr; + break; + case AF_INET6: + ip6_addr = (struct sockaddr_in6*)(iface->ifa_addr); + ip6_network = (struct sockaddr_in6*)(iface->ifa_netmask); + + /* ignore loopback */ + if (IN6_IS_ADDR_LOOPBACK(&ip6_addr->sin6_addr)) { + continue; + } + + /* ignore multicast */ + if (IN6_IS_ADDR_MULTICAST(&ip6_addr->sin6_addr)) { + continue; + } + + /* get network mask length */ + for (i = 0; i < 4; i++) { + ip6_netmask = ntohl(((uint32_t*)(&ip6_network->sin6_addr))[i]); + while (ip6_netmask) { + netmask++; + ip6_netmask <<= 1; + } + } + + /* get network address */ + for (i = 0; i < 4; i++) { + ((uint32_t*)(&ip6_network->sin6_addr))[i] = + ((uint32_t*)(&ip6_addr->sin6_addr))[i] + & ((uint32_t*)(&ip6_network->sin6_addr))[i]; + } + + sinx_addr = &ip6_addr->sin6_addr; + sinx_network = &ip6_network->sin6_addr; + break; + default: + /* skip other families */ + continue; + } + + /* ip address */ + errno = 0; + if (inet_ntop(iface->ifa_addr->sa_family, sinx_addr, + ip_addr, INET6_ADDRSTRLEN) == NULL) { + ret = errno; + DEBUG(SSSDBG_MINOR_FAILURE, ("inet_ntop() failed [%d]: %s\n", + ret, strerror(ret))); + goto done; + } + + /* network */ + errno = 0; + if (inet_ntop(iface->ifa_addr->sa_family, sinx_network, + network_addr, INET6_ADDRSTRLEN) == NULL) { + ret = errno; + DEBUG(SSSDBG_MINOR_FAILURE, ("inet_ntop() failed [%d]: %s\n", + ret, strerror(ret))); + goto done; + } + + addr_count += 2; + ip_addr_list = talloc_realloc(tmp_ctx, ip_addr_list, char*, + addr_count + 1); + if (ip_addr_list == NULL) { + ret = ENOMEM; + goto done; + } + + ip_addr_list[addr_count - 2] = talloc_strdup(ip_addr_list, ip_addr); + if (ip_addr_list[addr_count - 2] == NULL) { + ret = ENOMEM; + goto done; + } + + ip_addr_list[addr_count - 1] = talloc_asprintf(ip_addr_list, "%s/%d", + network_addr, netmask); + if (ip_addr_list[addr_count - 1] == NULL) { + ret = ENOMEM; + goto done; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, + ("Found IP address: %s in network %s/%d\n", + ip_addr, network_addr, netmask)); + } + + ip_addr_list[addr_count] = NULL; + *_ip_addr_list = talloc_steal(mem_ctx, ip_addr_list); + +done: + freeifaddrs(ifaces); + talloc_free(tmp_ctx); + + return ret; +} |