From 45408cd892bd098e8ac561c09a05766b152c2012 Mon Sep 17 00:00:00 2001 From: Roman Bogorodskiy Date: Sun, 27 Mar 2016 21:07:10 +0300 Subject: [PATCH] nss: FreeBSD support * tools/nss/libvirt_nss.[ch]: add BSD-comptabile wrappers and register via the nss_module_register() interface * m4/virt-nss.m4: add checks if we're building NSS for FreeBSD * tools/Makefile.am: handle target library name differences, as Linux needs libnss_libvirt.so.2 and FreeBSD needs nss_libvirt.so.1. Also, different syms files have to be used as Linux needs to export all the methods while FreeBSD only needs to have nss_module_register() * tests/nsstest.c, tests/nssmock.c: s/__linux__/NSS/ * tests/nssmock.c: pass int instead of mode_t to va_arg() to please gcc 4.8 * libvirt_nss_bsd.syms: FreeBSD syms file --- m4/virt-nss.m4 | 18 ++++- tests/nssmock.c | 6 +- tests/nsstest.c | 2 +- tools/Makefile.am | 16 +++- tools/nss/libvirt_nss.c | 139 ++++++++++++++++++++++++++++++++- tools/nss/libvirt_nss.h | 9 +++ tools/nss/libvirt_nss_bsd.syms | 9 +++ 7 files changed, 189 insertions(+), 10 deletions(-) create mode 100644 tools/nss/libvirt_nss_bsd.syms diff --git a/m4/virt-nss.m4 b/m4/virt-nss.m4 index 3fa4ad30cc..3d6e8f474f 100644 --- a/m4/virt-nss.m4 +++ b/m4/virt-nss.m4 @@ -23,6 +23,7 @@ AC_DEFUN([LIBVIRT_CHECK_NSS],[ [enable Name Servie Switch plugin for resolving guest IP addresses])], [], [with_nss_plugin=check]) + bsd_nss=no fail=0 if test "x$with_nss_plugin" != "xno" ; then AC_CHECK_HEADERS([nss.h], [ @@ -39,11 +40,26 @@ AC_DEFUN([LIBVIRT_CHECK_NSS],[ if test "x$with_nss_plugin" = "xyes" ; then AC_DEFINE_UNQUOTED([NSS], 1, [whether nss plugin is enabled]) + + AC_CHECK_TYPE([struct gaih_addrtuple], + [AC_DEFINE([HAVE_STRUCT_GAIH_ADDRTUPLE], [1], + [Defined if struct gaih_addrtuple exists in nss.h])], + [], [[#include + ]]) + + AC_CHECK_TYPES([ns_mtab, nss_module_unregister_fn], + [AC_DEFINE([HAVE_BSD_NSS], + [1], + [whether using BSD style NSS]) + bsd_nss=yes + ], + [], + [#include ]) fi fi AM_CONDITIONAL(WITH_NSS, [test "x$with_nss_plugin" = "xyes"]) - + AM_CONDITIONAL(WITH_BSD_NSS, [test "x$bsd_nss" = "xyes"]) ]) AC_DEFUN([LIBVIRT_RESULT_NSS],[ diff --git a/tests/nssmock.c b/tests/nssmock.c index b4a42604cb..31b1177ca3 100644 --- a/tests/nssmock.c +++ b/tests/nssmock.c @@ -20,7 +20,7 @@ #include -#ifdef __linux__ +#ifdef NSS # include # include # include @@ -107,7 +107,7 @@ open(const char *path, int flags, ...) va_list ap; mode_t mode; va_start(ap, flags); - mode = va_arg(ap, mode_t); + mode = va_arg(ap, int); va_end(ap); ret = realopen(newpath ? newpath : path, flags, mode); } else { @@ -136,5 +136,5 @@ opendir(const char *path) return ret; } #else -/* Nothing to override on non-__linux__ platforms */ +/* Nothing to override if NSS plugin is not enabled */ #endif diff --git a/tests/nsstest.c b/tests/nsstest.c index 7399d9a4b4..63c7162d37 100644 --- a/tests/nsstest.c +++ b/tests/nsstest.c @@ -22,7 +22,7 @@ #include "testutils.h" -#ifdef __linux__ +#ifdef NSS # include # include diff --git a/tools/Makefile.am b/tools/Makefile.am index 4320040dc0..6005b8b925 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -417,8 +417,22 @@ CLEANFILES += wireshark/src/plugin.c endif WITH_WIRESHARK_DISSECTOR +if WITH_BSD_NSS +LIBVIRT_NSS_SYMBOL_FILE = \ + $(srcdir)/nss/libvirt_nss_bsd.syms +NSS_SO_VER = 1 + +install-exec-hook: + cd $(DESTDIR)$(libdir) && \ + $(LN_S) libnss_libvirt.so.$(NSS_SO_VER) nss_libvirt.so.$(NSS_SO_VER) + +uninstall-local: + rm $(DESTDIR)$(libdir)/libnss_libvirt.so.$(NSS_SO_VER) +else ! WITH_BSD_NSS LIBVIRT_NSS_SYMBOL_FILE = \ $(srcdir)/nss/libvirt_nss.syms +NSS_SO_VER = 2 +endif ! WITH_BSD_NSS LIBVIRT_NSS_SOURCES = \ nss/libvirt_nss.c \ @@ -449,7 +463,7 @@ nss_libnss_libvirt_la_LDFLAGS = \ -export-dynamic \ -avoid-version \ -shared \ - -shrext .so.2 + -shrext .so.$(NSS_SO_VER) nss_libnss_libvirt_la_LIBADD = \ nss/libnss_libvirt_impl.la diff --git a/tools/nss/libvirt_nss.c b/tools/nss/libvirt_nss.c index 218c62a64c..de34bafbe6 100644 --- a/tools/nss/libvirt_nss.c +++ b/tools/nss/libvirt_nss.c @@ -29,11 +29,16 @@ #include "libvirt_nss.h" +#include #include #include #include #include +#if defined(HAVE_BSD_NSS) +# include +#endif + #include "virlease.h" #include "viralloc.h" #include "virfile.h" @@ -65,7 +70,7 @@ do { \ #define LEASEDIR LOCALSTATEDIR "/lib/libvirt/dnsmasq/" -#define ALIGN(x) (((x) + __SIZEOF_POINTER__ - 1) & ~(__SIZEOF_POINTER__ - 1)) +#define LIBVIRT_ALIGN(x) (((x) + __SIZEOF_POINTER__ - 1) & ~(__SIZEOF_POINTER__ - 1)) #define FAMILY_ADDRESS_SIZE(family) ((family) == AF_INET6 ? 16 : 4) typedef struct { @@ -256,7 +261,7 @@ static inline void * move_and_align(void *buf, size_t len, size_t *idx) { char *buffer = buf; - size_t move = ALIGN(len); + size_t move = LIBVIRT_ALIGN(len); if (!idx) return buffer + move; @@ -321,7 +326,7 @@ _nss_libvirt_gethostbyname3_r(const char *name, int af, struct hostent *result, * b) alias * c) addresses * d) NULL stem */ - need = ALIGN(nameLen + 1) + naddr * ALIGN(alen) + (naddr + 2) * sizeof(char*); + need = LIBVIRT_ALIGN(nameLen + 1) + naddr * LIBVIRT_ALIGN(alen) + (naddr + 2) * sizeof(char*); if (buflen < need) { *errnop = ENOMEM; @@ -383,6 +388,7 @@ _nss_libvirt_gethostbyname3_r(const char *name, int af, struct hostent *result, return ret; } +#ifdef HAVE_STRUCT_GAIH_ADDRTUPLE enum nss_status _nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat, char *buffer, size_t buflen, int *errnop, @@ -426,7 +432,7 @@ _nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat, /* We need space for: * a) name * b) addresses */ - need = ALIGN(nameLen + 1) + naddr * ALIGN(sizeof(struct gaih_addrtuple)); + need = LIBVIRT_ALIGN(nameLen + 1) + naddr * LIBVIRT_ALIGN(sizeof(struct gaih_addrtuple)); if (buflen < need) { *errnop = ENOMEM; @@ -474,3 +480,128 @@ _nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat, cleanup: return ret; } +#endif /* HAVE_STRUCT_GAIH_ADDRTUPLE */ + +#if defined(HAVE_BSD_NSS) +NSS_METHOD_PROTOTYPE(_nss_compat_getaddrinfo); +NSS_METHOD_PROTOTYPE(_nss_compat_gethostbyname2_r); + +ns_mtab methods[] = { + { NSDB_HOSTS, "getaddrinfo", _nss_compat_getaddrinfo, NULL }, + { NSDB_HOSTS, "gethostbyname", _nss_compat_gethostbyname2_r, NULL }, + { NSDB_HOSTS, "gethostbyname2_r", _nss_compat_gethostbyname2_r, NULL }, +}; + +static void +aiforaf(const char *name, int af, struct addrinfo *pai, struct addrinfo **aip) +{ + int ret; + struct hostent resolved; + char buf[1024] = { 0 }; + int err, herr; + struct addrinfo hints, *res0, *res; + char **addrList; + + if ((ret = _nss_libvirt_gethostbyname2_r(name, af, &resolved, + buf, sizeof(buf), + &err, &herr)) != NS_SUCCESS) + return; + + addrList = resolved.h_addr_list; + while (*addrList) { + virSocketAddr sa; + char *ipAddr = NULL; + void *address = *addrList; + + memset(&sa, 0, sizeof(sa)); + if (resolved.h_addrtype == AF_INET) { + virSocketAddrSetIPv4AddrNetOrder(&sa, *((uint32_t *) address)); + } else { + virSocketAddrSetIPv6AddrNetOrder(&sa, address); + } + + ipAddr = virSocketAddrFormat(&sa); + + hints = *pai; + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = af; + + if (getaddrinfo(ipAddr, NULL, &hints, &res0)) { + addrList++; + continue; + } + + for (res = res0; res; res = res->ai_next) + res->ai_flags = pai->ai_flags; + + (*aip)->ai_next = res0; + while ((*aip)->ai_next) + *aip = (*aip)->ai_next; + + addrList++; + } +} + +int +_nss_compat_getaddrinfo(void *retval, void *mdata ATTRIBUTE_UNUSED, va_list ap) +{ + struct addrinfo sentinel, *cur, *ai; + const char *name; + + name = va_arg(ap, char *); + ai = va_arg(ap, struct addrinfo *); + + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + if ((ai->ai_family == AF_UNSPEC) || (ai->ai_family == AF_INET6)) + aiforaf(name, AF_INET6, ai, &cur); + if ((ai->ai_family == AF_UNSPEC) || (ai->ai_family == AF_INET)) + aiforaf(name, AF_INET, ai, &cur); + + if (sentinel.ai_next == NULL) { + h_errno = HOST_NOT_FOUND; + return NS_NOTFOUND; + } + *((struct addrinfo **)retval) = sentinel.ai_next; + + return NS_SUCCESS; +} + +int +_nss_compat_gethostbyname2_r(void *retval, void *mdata ATTRIBUTE_UNUSED, va_list ap) +{ + int ret; + + const char *name; + int af; + struct hostent *result; + char *buffer; + size_t buflen; + int *errnop; + int *herrnop; + + name = va_arg(ap, const char *); + af = va_arg(ap, int); + result = va_arg(ap, struct hostent *); + buffer = va_arg(ap, char *); + buflen = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + herrnop = va_arg(ap, int *); + + ret = _nss_libvirt_gethostbyname2_r( + name, af, result, buffer, buflen, errnop, herrnop); + *(struct hostent **)retval = (ret == NS_SUCCESS) ? result : NULL; + + return ret; +} + +ns_mtab* +nss_module_register(const char *name ATTRIBUTE_UNUSED, unsigned int *size, + nss_module_unregister_fn *unregister) +{ + *size = sizeof(methods) / sizeof(methods[0]); + *unregister = NULL; + return methods; +} +#endif /* HAVE_BSD_NSS */ diff --git a/tools/nss/libvirt_nss.h b/tools/nss/libvirt_nss.h index 589c1e6e09..e025e6362c 100644 --- a/tools/nss/libvirt_nss.h +++ b/tools/nss/libvirt_nss.h @@ -45,8 +45,17 @@ enum nss_status _nss_libvirt_gethostbyname3_r(const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *herrnop, int32_t *ttlp, char **canonp); +# ifdef HAVE_STRUCT_GAIH_ADDRTUPLE enum nss_status _nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat, char *buffer, size_t buflen, int *errnop, int *herrnop, int32_t *ttlp); +# endif /* HAVE_STRUCT_GAIH_ADDRTUPLE */ + +# if defined(HAVE_BSD_NSS) +ns_mtab* +nss_module_register(const char *name, unsigned int *size, + nss_module_unregister_fn *unregister); +# endif /* HAVE_BSD_NSS */ + #endif /* __LIBVIRT_NSS_H__ */ diff --git a/tools/nss/libvirt_nss_bsd.syms b/tools/nss/libvirt_nss_bsd.syms new file mode 100644 index 0000000000..7da39262c1 --- /dev/null +++ b/tools/nss/libvirt_nss_bsd.syms @@ -0,0 +1,9 @@ +# +# Officially exported symbols. +# + +{ +global: + nss_module_register; +local: *; +};