summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2012-06-27 14:53:02 +0200
committerStephen Gallagher <sgallagh@redhat.com>2012-06-29 11:37:18 -0400
commit468f1c8d4763a65f24ab8d7523a5291ef6320db7 (patch)
treee00eae9a586acb92a817de7fd3da879c9ced2ee9
parent1bb62d67c6d54a8ebd111ca08344f2d17b1f6f52 (diff)
downloadsssd-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.c180
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;
+}