From 539b1be3507abdf8ac235b06eeed5011b0b5cde2 Mon Sep 17 00:00:00 2001 From: Ondrej Kos Date: Mar 27 2013 19:15:52 +0000 Subject: Provide libnl3 support https://fedorahosted.org/sssd/ticket/812 Update the monitor code to be using the new libnl3 API. Changed configure option --with-libnl By default, it tries to build with libnl3, if not found, then with libnl1, if this isn't found either, build proceeds without libnl, just with warning. Specifing --with-libnl= checks for the specific given version, if not found, configure ends with error. --- diff --git a/BUILD.txt b/BUILD.txt index 0eb3f46..2631292 100644 --- a/BUILD.txt +++ b/BUILD.txt @@ -26,7 +26,7 @@ yum install openldap-devel gettext libtool pcre-devel c-ares-devel \ libxml2 pam-devel nss-devel libtevent python-devel \ libtevent-devel libtdb libtdb-devel libtalloc libtalloc-devel \ libldb libldb-devel popt-devel c-ares-devel check-devel \ - doxygen libselinux-devel libsemanage-devel bind-utils libnl-devel \ + doxygen libselinux-devel libsemanage-devel bind-utils libnl3-devel \ gettext-devel glib2-devel ding-libs are available in Fedora 14 and later version: diff --git a/configure.ac b/configure.ac index 0d81084..5d47c4e 100644 --- a/configure.ac +++ b/configure.ac @@ -114,7 +114,6 @@ WITH_PYTHON_BINDINGS WITH_SELINUX WITH_NSCD WITH_SEMANAGE -WITH_LIBNL WITH_NOLOGIN_SHELL WITH_APP_LIBS WITH_SUDO @@ -164,6 +163,8 @@ else AC_SUBST(UNICODE_LIBS) fi +WITH_LIBNL + WITH_INITSCRIPT if test x$initscript = xsystemd; then WITH_SYSTEMD_UNIT_DIR @@ -231,10 +232,6 @@ if test x$HAVE_SEMANAGE != x -a x$HAVE_SELINUX != x; then AM_CHECK_SEMANAGE fi -if test x$BUILD_LIBNL != x; then - AM_CHECK_LIBNL -fi - if test x$HAVE_SYSTEMD_UNIT != x; then AM_CHECK_SYSTEMD fi diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index de3059b..478247f 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -122,7 +122,6 @@ BuildRequires: libselinux-devel BuildRequires: libsemanage-devel BuildRequires: bind-utils BuildRequires: keyutils-libs-devel -BuildRequires: libnl-devel BuildRequires: gettext-devel BuildRequires: pkgconfig BuildRequires: findutils @@ -130,6 +129,9 @@ BuildRequires: glib2-devel BuildRequires: selinux-policy-targeted %if (0%{?fedora} >= 18) BuildRequires: libcmocka-devel +BuildRequires: libnl3-devel +%else +BuildRequires: libnl-devel %endif # RHEL 5 is too old to support samba4 and the PAC responder diff --git a/src/conf_macros.m4 b/src/conf_macros.m4 index 65f4d6c..4ea4e93 100644 --- a/src/conf_macros.m4 +++ b/src/conf_macros.m4 @@ -371,15 +371,40 @@ AC_DEFUN([WITH_SEMANAGE], AC_DEFUN([WITH_LIBNL], [ AC_ARG_WITH([libnl], [AC_HELP_STRING([--with-libnl], - [Whether to build with libnetlink support [AUTO]] + [Whether to build with libnetlink support (libnl3, libnl1, no) [auto]] ) ], [], with_libnl=yes ) + if test x"$with_libnl" = xyes; then - BUILD_LIBNL=1 - AC_SUBST(BUILD_LIBNL) + + AM_CHECK_LIBNL3 + + if test x"$HAVE_LIBNL" != x1; then + AM_CHECK_LIBNL1 + fi + + if test x"$HAVE_LIBNL" != x1; then + AC_MSG_WARN([Building without netlink]) + fi + + elif test x"$with_libnl" = xlibnl3; then + + AM_CHECK_LIBNL3 + + if test x"$HAVE_LIBNL" != x1; then + AC_MSG_ERROR([Libnl3 required, but not available]) + fi + + elif test x"$with_libnl" = xlibnl1; then + + AM_CHECK_LIBNL1 + + if test x"$HAVE_LIBNL" != x1; then + AC_MSG_ERROR([Libnl required, but not available]) + fi fi ]) diff --git a/src/external/libnl.m4 b/src/external/libnl.m4 index 36619ff..d468a49 100644 --- a/src/external/libnl.m4 +++ b/src/external/libnl.m4 @@ -1,34 +1,82 @@ +dnl A macro to check if this particular version of libnl supports particular common libnl functions +AC_DEFUN([AM_CHECK_LIBNL_FCS], +[ + AC_CHECK_LIB($1, + [nl_socket_add_membership], + [AC_DEFINE([HAVE_NL_SOCKET_ADD_MEMBERSHIP], 1, [Does libnl have nl_socket_add_membership?]) + ], + ) + + AC_CHECK_LIB($1, + [nl_socket_modify_cb], + [AC_DEFINE([HAVE_NL_SOCKET_MODIFY_CB], 1, [Does libnl have nl_socket_modify_cb?]) + ], + ) + + AC_CHECK_LIB($1, + [rtnl_route_get_oif], + [AC_DEFINE([HAVE_RTNL_ROUTE_GET_OIF], 1, [Does libnl have rtnl_route_get_oif?]) + ], + ) + + AC_CHECK_LIB($1, + [nl_set_passcred], + [AC_DEFINE([HAVE_NL_SET_PASSCRED], 1, [Does libnl have nl_set_passcred?]) + ], + ) + + AC_CHECK_LIB($1, + [nl_socket_set_passcred], + [AC_DEFINE([HAVE_NL_SOCKET_SET_PASSCRED], 1, [Does libnl have nl_socket_set_passcred?]) + ], + ) +]) + dnl A macro to check the availability and version of libnetlink +AC_DEFUN([AM_CHECK_LIBNL1], +[ + PKG_CHECK_MODULES(LIBNL, libnl-1 >= 1.1,[ + + HAVE_LIBNL=1 + HAVE_LIBNL1=1 + + AC_DEFINE_UNQUOTED(HAVE_LIBNL, 1, [Build with libnetlink support]) + AC_DEFINE_UNQUOTED(HAVE_LIBNL1, 1, [Libnetlink version = 1]) + + AC_MSG_NOTICE([Building with libnl]) + + AC_CHECK_HEADERS(netlink.h) + AC_CHECK_LIB(nl, nl_connect, [ LIBNL_LIBS="-lnl" ], [AC_MSG_ERROR([libnl is required])]) -AC_DEFUN([AM_CHECK_LIBNL], + AM_CHECK_LIBNL_FCS(nl) + + + ],[AC_MSG_WARN([Netlink v1 support unavailable or too old])]) + + AC_SUBST(LIBNL_CFLAGS) + AC_SUBST(LIBNL_LIBS) +]) + +dnl A macro to check the availability of libnetlink version 3 + +AC_DEFUN([AM_CHECK_LIBNL3], [ - PKG_CHECK_MODULES(libnl, libnl-1 >= 1.1,[ + PKG_CHECK_MODULES(LIBNL, [ + libnl-3.0 >= 3.0 + libnl-route-3.0 >= 3.0], [ + HAVE_LIBNL=1 - AC_SUBST(HAVE_LIBNL) + HAVE_LIBNL3=1 + + AC_DEFINE_UNQUOTED(HAVE_LIBNL, 1, [Build with libnetlink support]) + AC_DEFINE_UNQUOTED(HAVE_LIBNL3, 1, [Libnetlink version = 3]) + + AC_MSG_NOTICE([Building with libnl3]) + + AM_CHECK_LIBNL_FCS(nl-3) - AC_CHECK_HEADERS(netlink.h) - AC_CHECK_LIB(nl, nl_connect, [ LIBNL_LIBS="-lnl" ], [AC_MSG_ERROR([libnl is required])]) - - dnl Check if this particular version of libnl supports particular functions - AC_CHECK_LIB([nl], - [nl_socket_add_membership], - [AC_DEFINE([HAVE_NL_SOCKET_ADD_MEMBERSHIP], 1, [Does libnl have nl_socket_add_membership?]) - ], - ) - - AC_CHECK_LIB([nl], - [nl_socket_modify_cb], - [AC_DEFINE([HAVE_NL_SOCKET_MODIFY_CB], 1, [Does libnl have nl_socket_modify_cb?]) - ], - ) - - AC_CHECK_LIB([nl], - [nl_set_passcred], - [AC_DEFINE([HAVE_NL_SET_PASSCRED], 1, [Does libnl have nl_set_passcred?]) - ], - ) - ],[AC_MSG_WARN([Netlink support unavailable or too old])]) + ],[AC_MSG_WARN([Netlink v3 support unavailable or too old])]) AC_SUBST(LIBNL_CFLAGS) AC_SUBST(LIBNL_LIBS) diff --git a/src/monitor/monitor_netlink.c b/src/monitor/monitor_netlink.c index 3842c4f..932a6bf 100644 --- a/src/monitor/monitor_netlink.c +++ b/src/monitor/monitor_netlink.c @@ -47,6 +47,7 @@ #include #include #include +#include #endif /* Linux header file confusion causes this to be undefined. */ @@ -54,12 +55,6 @@ #define SOL_NETLINK 270 #endif -#define nlw_get_fd nl_socket_get_fd -#define nlw_recvmsgs_default nl_recvmsgs_default -#define nlw_get_pid nl_socket_get_local_port -#define nlw_object_match nl_object_match_filter -#define NLW_OK NL_OK - #define SYSFS_IFACE_TEMPLATE "/sys/class/net/%s" #define SYSFS_IFACE_PATH_MAX (16+IFNAMSIZ) @@ -73,6 +68,32 @@ #define BUFSIZE 8 +#ifdef HAVE_LIBNL +/* Wrappers determining use of libnl version 1 or 3 */ +#ifdef HAVE_LIBNL3 + +#define nlw_destroy_handle nl_socket_free +#define nlw_alloc nl_socket_alloc +#define nlw_disable_seq_check nl_socket_disable_seq_check + +#define nlw_geterror(error) nl_geterror(error) + +#define nlw_handle nl_sock + +#elif HAVE_LIBNL1 + +#define nlw_destroy_handle nl_handle_destroy +#define nlw_alloc nl_handle_alloc +#define nlw_disable_seq_check nl_disable_sequence_check + +#define nlw_geterror(error) nl_geterror() + +#define nlw_handle nl_handle + +#endif /* HAVE_LIBNL3 */ + +#endif /* HAVE_LIBNL */ + enum nlw_msg_type { NLW_LINK, NLW_ROUTE, @@ -82,7 +103,7 @@ enum nlw_msg_type { struct netlink_ctx { #ifdef HAVE_LIBNL - struct nl_handle *nlh; + struct nlw_handle *nlp; #endif struct tevent_fd *tefd; @@ -96,7 +117,7 @@ static int netlink_ctx_destructor(void *ptr) struct netlink_ctx *nlctx; nlctx = talloc_get_type(ptr, struct netlink_ctx); - nl_handle_destroy(nlctx->nlh); + nlw_destroy_handle(nlctx->nlp); return 0; } @@ -104,6 +125,27 @@ static int netlink_ctx_destructor(void *ptr) * Utility functions *******************************************************************/ +/* rtnl_route_get_oif removed from libnl3 */ +int +rtnlw_route_get_oif(struct rtnl_route * route) +{ +#ifndef HAVE_RTNL_ROUTE_GET_OIF + struct rtnl_nexthop * nh; + int hops; + + hops = rtnl_route_get_nnexthops(route); + if (hops <= 0) { + return 0; + } + + nh = rtnl_route_nexthop_n(route, 0); + + return rtnl_route_nh_get_ifindex(nh); +#else + return rtnl_route_get_oif(route); +#endif +} + static bool has_wireless_extension(const char *ifname) { int s; @@ -270,7 +312,7 @@ static void nladdr_to_string(struct nl_addr *nl, char *buf, size_t bufsize) * Wrappers for different capabilities of different libnl versions *******************************************************************/ -static bool nlw_accept_message(struct nl_handle *nlh, +static bool nlw_accept_message(struct nlw_handle *nlp, const struct sockaddr_nl *snl, struct nlmsghdr *hdr) { @@ -290,7 +332,7 @@ static bool nlw_accept_message(struct nl_handle *nlh, /* And any multicast message directed to our netlink PID, since multicast * currently requires CAP_ADMIN to use. */ - local_port = nlw_get_pid(nlh); + local_port = nl_socket_get_local_port(nlp); if ((hdr->nlmsg_pid == local_port) && snl->nl_groups) { accept_msg = true; } @@ -315,7 +357,7 @@ static bool nlw_is_addr_object(struct nl_object *obj) } /* Ensure it's an addr object */ - if (!nlw_object_match(obj, OBJ_CAST(filter))) { + if (!nl_object_match_filter(obj, OBJ_CAST(filter))) { DEBUG(SSSDBG_MINOR_FAILURE, ("Not an addr object\n")); is_addr_object = false; } @@ -336,7 +378,7 @@ static bool nlw_is_route_object(struct nl_object *obj) } /* Ensure it's a route object */ - if (!nlw_object_match(obj, OBJ_CAST(filter))) { + if (!nl_object_match_filter(obj, OBJ_CAST(filter))) { DEBUG(SSSDBG_MINOR_FAILURE, ("Not a route object\n")); is_route_object = false; } @@ -357,7 +399,7 @@ static bool nlw_is_link_object(struct nl_object *obj) } /* Ensure it's a link object */ - if (!nlw_object_match(obj, OBJ_CAST(filter))) { + if (!nl_object_match_filter(obj, OBJ_CAST(filter))) { DEBUG(2, ("Not a link object\n")); is_link_object = false; } @@ -366,27 +408,30 @@ static bool nlw_is_link_object(struct nl_object *obj) return is_link_object; } -static int nlw_enable_passcred(struct nl_handle *nlh) +static int nlw_enable_passcred(struct nlw_handle *nlp) { -#ifndef HAVE_NL_SET_PASSCRED - return EOK; /* not available in this version */ +#ifdef HAVE_NL_SET_PASSCRED + return nl_set_passcred(nlp, 1); /* 1 = enabled */ +#elif HAVE_NL_SOCKET_SET_PASSCRED + return nl_socket_set_passcred(nlp, 1); #else - return nl_set_passcred(nlh, 1); /* 1 = enabled */ + return EOK; /* not available in this version */ #endif } -static int nlw_group_subscribe(struct nl_handle *nlh, int group) +static int nlw_group_subscribe(struct nlw_handle *nlp, int group) { int ret; #ifdef HAVE_NL_SOCKET_ADD_MEMBERSHIP - ret = nl_socket_add_membership(nlh, group); + ret = nl_socket_add_membership(nlp, group); if (ret != 0) { - DEBUG(1, ("Unable to add membership: %s\n", nl_geterror())); + DEBUG(SSSDBG_CRIT_FAILURE, + ("Unable to add membership: %s\n", nlw_geterror(ret))); return ret; } #else - int nlfd = nlw_get_fd(nlh); + int nlfd = nl_socket_get_fd(nlp); errno = 0; ret = setsockopt(nlfd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, @@ -401,13 +446,13 @@ static int nlw_group_subscribe(struct nl_handle *nlh, int group) return 0; } -static int nlw_groups_subscribe(struct nl_handle *nlh, int *groups) +static int nlw_groups_subscribe(struct nlw_handle *nlp, int *groups) { int ret; int i; for (i=0; groups[i]; i++) { - ret = nlw_group_subscribe(nlh, groups[i]); + ret = nlw_group_subscribe(nlp, groups[i]); if (ret != EOK) return ret; } @@ -435,11 +480,11 @@ static int event_msg_recv(struct nl_msg *msg, void *arg) hdr = nlmsg_hdr(msg); snl = nlmsg_get_src(msg); - if (!nlw_accept_message(ctx->nlh, snl, hdr)) { + if (!nlw_accept_message(ctx->nlp, snl, hdr)) { return NL_SKIP; } - return NLW_OK; + return NL_OK; } static void link_msg_handler(struct nl_object *obj, void *arg); @@ -487,28 +532,30 @@ static int event_msg_ready(struct nl_msg *msg, void *arg) return EOK; /* Don't care */ } - return NLW_OK; + return NL_OK; } -static int nlw_set_callbacks(struct nl_handle *nlh, void *data) +static int nlw_set_callbacks(struct nlw_handle *nlp, void *data) { int ret = EIO; -#ifndef HAVE_NL_SOCKET_MODIFY_CB - struct nl_cb *cb = nl_handle_get_cb(nlh); - ret = nl_cb_set(cb, NL_CB_MSG_IN, NL_CB_CUSTOM, event_msg_recv, data); +#ifdef HAVE_NL_SOCKET_MODIFY_CB + ret = nl_socket_modify_cb(nlp, NL_CB_MSG_IN, NL_CB_CUSTOM, event_msg_recv, + data); #else - ret = nl_socket_modify_cb(nlh, NL_CB_MSG_IN, NL_CB_CUSTOM, event_msg_recv, data); + struct nl_cb *cb = nl_handle_get_cb(nlp); + ret = nl_cb_set(cb, NL_CB_MSG_IN, NL_CB_CUSTOM, event_msg_recv, data); #endif if (ret != 0) { DEBUG(1, ("Unable to set validation callback\n")); return ret; } -#ifndef HAVE_NL_SOCKET_MODIFY_CB - ret = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, event_msg_ready, data); +#ifdef HAVE_NL_SOCKET_MODIFY_CB + ret = nl_socket_modify_cb(nlp, NL_CB_VALID, NL_CB_CUSTOM, event_msg_ready, + data); #else - ret = nl_socket_modify_cb(nlh, NL_CB_VALID, NL_CB_CUSTOM, event_msg_ready, data); + ret = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, event_msg_ready, data); #endif if (ret != 0) { DEBUG(1, ("Unable to set receive callback\n")); @@ -534,8 +581,9 @@ static void route_msg_debug_print(struct rtnl_route *route_obj) } DEBUG(SSSDBG_TRACE_LIBS, ("route idx %d flags %#X family %d addr %s/%d\n", - rtnl_route_get_oif(route_obj), rtnl_route_get_flags(route_obj), + rtnlw_route_get_oif(route_obj), rtnl_route_get_flags(route_obj), rtnl_route_get_family(route_obj), buf, prefixlen)); + } /* @@ -665,12 +713,12 @@ static void netlink_fd_handler(struct tevent_context *ev, struct tevent_fd *fde, struct netlink_ctx *nlctx = talloc_get_type(data, struct netlink_ctx); int ret; - if (!nlctx || !nlctx->nlh) { + if (!nlctx || !nlctx->nlp) { DEBUG(1, ("Invalid netlink handle, this is most likely a bug!\n")); return; } - ret = nlw_recvmsgs_default(nlctx->nlh); + ret = nl_recvmsgs_default(nlctx->nlp); if (ret != EOK) { DEBUG(1, ("Error while reading from netlink fd\n")); return; @@ -699,17 +747,17 @@ int setup_netlink(TALLOC_CTX *mem_ctx, struct tevent_context *ev, nlctx->change_cb = change_cb; nlctx->cb_data = cb_data; - /* allocate the libnl handle and register the default filter set */ - nlctx->nlh = nl_handle_alloc(); - if (!nlctx->nlh) { - DEBUG(1, (("unable to allocate netlink handle: %s"), - nl_geterror())); + /* allocate the libnl handle/socket and register the default filter set */ + nlctx->nlp = nlw_alloc(); + if (!nlctx->nlp) { + DEBUG(SSSDBG_CRIT_FAILURE, (("unable to allocate netlink handle: %s"), + nlw_geterror(ENOMEM))); ret = ENOMEM; goto fail; } /* Register our custom message validation filter */ - ret = nlw_set_callbacks(nlctx->nlh, nlctx); + ret = nlw_set_callbacks(nlctx->nlp, nlctx); if (ret != 0) { DEBUG(1, ("Unable to set callbacks\n")); ret = EIO; @@ -717,31 +765,33 @@ int setup_netlink(TALLOC_CTX *mem_ctx, struct tevent_context *ev, } /* Try to start talking to netlink */ - ret = nl_connect(nlctx->nlh, NETLINK_ROUTE); + ret = nl_connect(nlctx->nlp, NETLINK_ROUTE); if (ret != 0) { - DEBUG(1, ("Unable to connect to netlink: %s\n", nl_geterror())); + DEBUG(SSSDBG_CRIT_FAILURE, + ("Unable to connect to netlink: %s\n", nlw_geterror(ret))); ret = EIO; goto fail; } - ret = nlw_enable_passcred(nlctx->nlh); + ret = nlw_enable_passcred(nlctx->nlp); if (ret != 0) { - DEBUG(1, ("Cannot enable credential passing: %s\n", nl_geterror())); + DEBUG(SSSDBG_CRIT_FAILURE, + ("Cannot enable credential passing: %s\n", nlw_geterror(ret))); ret = EIO; goto fail; } /* Subscribe to the LINK group for internal carrier signals */ - ret = nlw_groups_subscribe(nlctx->nlh, groups); + ret = nlw_groups_subscribe(nlctx->nlp, groups); if (ret != 0) { DEBUG(1, ("Unable to subscribe to netlink monitor\n")); ret = EIO; goto fail; } - nl_disable_sequence_check(nlctx->nlh); + nlw_disable_seq_check(nlctx->nlp); - nlfd = nlw_get_fd(nlctx->nlh); + nlfd = nl_socket_get_fd(nlctx->nlp); flags = fcntl(nlfd, F_GETFL, 0); errno = 0;