[libvirt] [PATCH] nss: FreeBSD support
Michal Privoznik
mprivozn at redhat.com
Fri Mar 25 10:19:17 UTC 2016
On 25.03.2016 08:43, Roman Bogorodskiy wrote:
> * 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()
> * libvirt_nss_bsd.syms: FreeBSD syms file
> ---
> m4/virt-nss.m4 | 12 +++-
> tools/Makefile.am | 16 ++++-
> tools/nss/libvirt_nss.c | 140 +++++++++++++++++++++++++++++++++++++++--
> tools/nss/libvirt_nss.h | 9 +++
> tools/nss/libvirt_nss_bsd.syms | 9 +++
> 5 files changed, 179 insertions(+), 7 deletions(-)
> create mode 100644 tools/nss/libvirt_nss_bsd.syms
>
> diff --git a/m4/virt-nss.m4 b/m4/virt-nss.m4
> index 3fa4ad3..a8ed8b9 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,20 @@ 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_TYPES([ns_mtab, nss_module_unregister_fn],
> + [AC_DEFINE([HAVE_BSD_NSS],
> + [1],
> + [whether using BSD style NSS])
> + bsd_nss=yes
> + ],
> + [],
> + [#include <nsswitch.h>])
> 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/tools/Makefile.am b/tools/Makefile.am
> index 4320040..6005b8b 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)
> +
Yeah, very similar link exists on my linux machine too (except for the
version at EOL). Maybe one day I'll add the link for Linux too.
> +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 218c62a..0ff1348 100644
> --- a/tools/nss/libvirt_nss.c
> +++ b/tools/nss/libvirt_nss.c
> @@ -1,5 +1,4 @@
> /*
> - * libvirt_nss: Name Service Switch plugin
This is unintended, right?
> *
> * The aim is to enable users and applications to translate
> * domain names into IP addresses. However, this is currently
> @@ -29,11 +28,16 @@
>
> #include "libvirt_nss.h"
>
> +#include <netinet/in.h>
> #include <resolv.h>
> #include <sys/types.h>
> #include <dirent.h>
> #include <arpa/inet.h>
>
> +#if defined(HAVE_BSD_NSS)
> +# include <nsswitch.h>
> +#endif
> +
> #include "virlease.h"
> #include "viralloc.h"
> #include "virfile.h"
> @@ -65,7 +69,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))
Yeah, I've seen the name clash with some header file when trying to
compile on my freebsd machine too.
> #define FAMILY_ADDRESS_SIZE(family) ((family) == AF_INET6 ? 16 : 4)
>
> typedef struct {
> @@ -256,7 +260,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 +325,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 +387,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 +431,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 +479,128 @@ _nss_libvirt_gethostbyname4_r(const char *name, struct gaih_addrtuple **pat,
> cleanup:
> return ret;
> }
> +#endif /* HAVE_STRUCT_GAIH_ADDRTUPLE */
I guess this will not fly. I mean, the symbol is exported so I guess we
need an #else branch providing a dummy implementation, don't we?
Honestly, I don't know. Maybe we don't as long as we don't run
check-symfile whether all symbols are exported I guess we are good. Or
we can just introduce yet another symbol file that would be included
conditionally.
BUT, you forgot to include bit that checks for struct gaih_ddrtuple and
defines HAVE_STRUCT_..?
> +
> +#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)) {
Interesting. I don't know how NSS works on *bsd but this function is
called from getaddrinfo() and it is calling getaddrinfo yet again. Is
that okay?
> + 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;
> +
Trailing space.
> + 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 589c1e6..e025e63 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 0000000..7da3926
> --- /dev/null
> +++ b/tools/nss/libvirt_nss_bsd.syms
> @@ -0,0 +1,9 @@
> +#
> +# Officially exported symbols.
> +#
> +
> +{
> +global:
> + nss_module_register;
> +local: *;
> +};
>
Michal
More information about the libvir-list
mailing list