mirror of https://gitee.com/openkylin/libvirt.git
nss: Implement _nss_libvirt_gethostbyname3_r
The implementation is pretty straightforward. Moreover, because of the nature of things, gethostbyname_r and gethostbyname2_r can be implemented at the same time too. Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
8054706c3f
commit
7dbcb26f7f
|
@ -43,3 +43,27 @@
|
|||
# undef WITH_YAJL
|
||||
# undef WITH_YAJL2
|
||||
#endif
|
||||
|
||||
/*
|
||||
* With the NSS module it's the same story as virt-login-shell. See the
|
||||
* explanation above.
|
||||
*/
|
||||
#ifdef LIBVIRT_NSS
|
||||
# undef HAVE_LIBDEVMAPPER_H
|
||||
# undef HAVE_LIBNL
|
||||
# undef HAVE_LIBNL3
|
||||
# undef HAVE_LIBSASL2
|
||||
# undef WITH_CAPNG
|
||||
# undef WITH_CURL
|
||||
# undef WITH_DTRACE_PROBES
|
||||
# undef WITH_GNUTLS
|
||||
# undef WITH_GNUTLS_GCRYPT
|
||||
# undef WITH_MACVTAP
|
||||
# undef WITH_NUMACTL
|
||||
# undef WITH_SASL
|
||||
# undef WITH_SSH2
|
||||
# undef WITH_VIRTUALPORT
|
||||
# undef WITH_SECDRIVER_SELINUX
|
||||
# undef WITH_SECDRIVER_APPARMOR
|
||||
# undef WITH_CAPNG
|
||||
#endif /* LIBVIRT_NSS */
|
||||
|
|
|
@ -2946,6 +2946,63 @@ endif WITH_LIBVIRTD
|
|||
endif WITH_SECDRIVER_APPARMOR
|
||||
EXTRA_DIST += $(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES)
|
||||
|
||||
noinst_LTLIBRARIES += libvirt-nss.la
|
||||
|
||||
libvirt_nss_la_SOURCES = \
|
||||
util/viralloc.c \
|
||||
util/viralloc.h \
|
||||
util/virbitmap.c \
|
||||
util/virbitmap.h \
|
||||
util/virbuffer.c \
|
||||
util/virbuffer.h \
|
||||
util/vircommand.c \
|
||||
util/vircommand.h \
|
||||
util/virerror.c \
|
||||
util/virerror.h \
|
||||
util/virfile.c \
|
||||
util/virfile.h \
|
||||
util/virjson.c \
|
||||
util/virjson.h \
|
||||
util/virkmod.c \
|
||||
util/virkmod.h \
|
||||
util/virlease.c \
|
||||
util/virlease.h \
|
||||
util/virlog.c \
|
||||
util/virlog.h \
|
||||
util/virobject.c \
|
||||
util/virobject.h \
|
||||
util/virpidfile.c \
|
||||
util/virpidfile.h \
|
||||
util/virprocess.c \
|
||||
util/virprocess.h \
|
||||
util/virsocketaddr.c \
|
||||
util/virsocketaddr.h \
|
||||
util/virstring.c \
|
||||
util/virstring.h \
|
||||
util/virthread.c \
|
||||
util/virthread.h \
|
||||
util/virthreadjob.c \
|
||||
util/virthreadjob.h \
|
||||
util/virtime.c \
|
||||
util/virtime.h \
|
||||
util/virutil.c \
|
||||
util/virutil.h \
|
||||
$(NULL)
|
||||
|
||||
libvirt_nss_la_CFLAGS = \
|
||||
-DLIBVIRT_NSS \
|
||||
$(AM_CFLAGS) \
|
||||
$(YAJL_CFLAGS) \
|
||||
$(NULL)
|
||||
libvirt_nss_la_LDFLAGS = \
|
||||
$(AM_LDFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
libvirt_nss_la_LIBADD = \
|
||||
$(YAJL_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
|
||||
install-data-local: install-init install-systemd
|
||||
if WITH_LIBVIRTD
|
||||
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd"
|
||||
|
|
|
@ -67,7 +67,6 @@
|
|||
#include "virlog.h"
|
||||
#include "virprocess.h"
|
||||
#include "virstring.h"
|
||||
#include "virstoragefile.h"
|
||||
#include "virutil.h"
|
||||
|
||||
#include "c-ctype.h"
|
||||
|
@ -554,7 +553,7 @@ int virFileUpdatePerm(const char *path,
|
|||
|
||||
|
||||
#if defined(__linux__) && HAVE_DECL_LO_FLAGS_AUTOCLEAR && \
|
||||
!defined(LIBVIRT_SETUID_RPC_CLIENT)
|
||||
!defined(LIBVIRT_SETUID_RPC_CLIENT) && !defined(LIBVIRT_NSS)
|
||||
|
||||
# if HAVE_DECL_LOOP_CTL_GET_FREE
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "virstring.h"
|
||||
#include "virerror.h"
|
||||
#include "viralloc.h"
|
||||
#include "virutil.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_NETWORK
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ GNULIB_LIBS = \
|
|||
../gnulib/lib/libgnu.la
|
||||
|
||||
LDADDS = \
|
||||
$(WARN_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(NO_INDIRECT_LDFLAGS) \
|
||||
$(PROBES_O) \
|
||||
$(GNULIB_LIBS) \
|
||||
|
|
|
@ -429,10 +429,16 @@ nss_libnss_libvirt_impl_la_SOURCES = \
|
|||
$(LIBVIRT_NSS_SOURCES)
|
||||
|
||||
nss_libnss_libvirt_impl_la_CFLAGS = \
|
||||
-DLIBVIRT_NSS \
|
||||
$(AM_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(PIE_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS)
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(LIBXML_CFLAGS)
|
||||
|
||||
nss_libnss_libvirt_impl_la_LIBADD = \
|
||||
../gnulib/lib/libgnu.la \
|
||||
../src/libvirt-nss.la
|
||||
|
||||
if WITH_NSS
|
||||
nss_libnss_libvirt_la_SOURCES =
|
||||
|
|
|
@ -29,8 +29,338 @@
|
|||
|
||||
#include "libvirt_nss.h"
|
||||
|
||||
int
|
||||
blah(int c)
|
||||
#include <resolv.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "virlease.h"
|
||||
#include "viralloc.h"
|
||||
#include "virfile.h"
|
||||
#include "virerror.h"
|
||||
#include "virstring.h"
|
||||
#include "virsocketaddr.h"
|
||||
#include "configmake.h"
|
||||
|
||||
#if 0
|
||||
# define ERROR(...) \
|
||||
do { \
|
||||
char ebuf[1024]; \
|
||||
fprintf(stderr, "ERROR %s:%d : ", __FUNCTION__, __LINE__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, " : %s\n", virStrerror(errno, ebuf, sizeof(ebuf))); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} while (0)
|
||||
|
||||
# define DEBUG(...) \
|
||||
do { \
|
||||
fprintf(stderr, "DEBUG %s:%d : ", __FUNCTION__, __LINE__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} while (0)
|
||||
#else
|
||||
# define ERROR(...) do { } while (0)
|
||||
# define DEBUG(...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define LEASEDIR LOCALSTATEDIR "/lib/libvirt/dnsmasq/"
|
||||
|
||||
#define ALIGN(x) (((x) + __SIZEOF_POINTER__ - 1) & ~(__SIZEOF_POINTER__ - 1))
|
||||
#define FAMILY_ADDRESS_SIZE(family) ((family) == AF_INET6 ? 16 : 4)
|
||||
|
||||
typedef struct {
|
||||
unsigned char addr[16];
|
||||
int af;
|
||||
} leaseAddress;
|
||||
|
||||
/**
|
||||
* findLease:
|
||||
* @name: domain name to lookup
|
||||
* @af: address family
|
||||
* @address: all the addresses found for selected @af
|
||||
* @naddress: number of elements in @address array
|
||||
* @found: whether @name has been found
|
||||
* @errnop: errno pointer
|
||||
*
|
||||
* Lookup @name in libvirt's IP database, parse it and store all
|
||||
* addresses found in @address array. Callers can choose which
|
||||
* address family (@af) should be returned. Currently only
|
||||
* AF_INET (IPv4) and AF_INET6 (IPv6) are supported. As a corner
|
||||
* case, AF_UNSPEC may be passed to @af in which case no address
|
||||
* filtering is done and addresses from both families are
|
||||
* returned.
|
||||
*
|
||||
* Returns -1 on error
|
||||
* 0 on success
|
||||
*/
|
||||
static int
|
||||
findLease(const char *name,
|
||||
int af,
|
||||
leaseAddress **address,
|
||||
size_t *naddress,
|
||||
bool *found,
|
||||
int *errnop)
|
||||
{
|
||||
return c;
|
||||
DIR *dir = NULL;
|
||||
int ret = -1;
|
||||
const char *leaseDir = LEASEDIR;
|
||||
struct dirent *entry;
|
||||
virJSONValuePtr leases_array = NULL;
|
||||
ssize_t i, nleases;
|
||||
leaseAddress *tmpAddress = NULL;
|
||||
size_t ntmpAddress = 0;
|
||||
|
||||
*address = NULL;
|
||||
*naddress = 0;
|
||||
*found = false;
|
||||
|
||||
if (af != AF_UNSPEC && af != AF_INET && af != AF_INET6) {
|
||||
errno = EAFNOSUPPORT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
if (!(dir = opendir(leaseDir))) {
|
||||
ERROR("Failed to open dir '%s'", leaseDir);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(leases_array = virJSONValueNewArray())) {
|
||||
ERROR("Failed to create json array");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
DEBUG("Dir: %s", leaseDir);
|
||||
while ((ret = virDirRead(dir, &entry, leaseDir)) > 0) {
|
||||
char *path;
|
||||
|
||||
if (entry->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (!virFileHasSuffix(entry->d_name, ".status"))
|
||||
continue;
|
||||
|
||||
if (!(path = virFileBuildPath(leaseDir, entry->d_name, NULL)))
|
||||
goto cleanup;
|
||||
|
||||
DEBUG("Processing %s", path);
|
||||
|
||||
if (virLeaseReadCustomLeaseFile(leases_array, path, NULL, NULL) < 0) {
|
||||
ERROR("Unable to parse %s", path);
|
||||
VIR_FREE(path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
VIR_FREE(path);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
dir = NULL;
|
||||
|
||||
nleases = virJSONValueArraySize(leases_array);
|
||||
DEBUG("Read %zd leases", nleases);
|
||||
|
||||
for (i = 0; i < nleases; i++) {
|
||||
virJSONValuePtr lease;
|
||||
const char *lease_name;
|
||||
virSocketAddr sa;
|
||||
const char *ipAddr;
|
||||
int family;
|
||||
|
||||
lease = virJSONValueArrayGet(leases_array, i);
|
||||
|
||||
if (!lease) {
|
||||
/* This should never happen (TM) */
|
||||
ERROR("Unable to get element %zd of %zd", i, nleases);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
lease_name = virJSONValueObjectGetString(lease, "hostname");
|
||||
|
||||
if (STRNEQ_NULLABLE(name, lease_name))
|
||||
continue;
|
||||
|
||||
DEBUG("Found record for %s", lease_name);
|
||||
*found = true;
|
||||
|
||||
if (!(ipAddr = virJSONValueObjectGetString(lease, "ip-address"))) {
|
||||
ERROR("ip-address field missing for %s", name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
DEBUG("IP address: %s", ipAddr);
|
||||
|
||||
if (virSocketAddrParse(&sa, ipAddr, AF_UNSPEC) < 0) {
|
||||
ERROR("Unable to parse %s", ipAddr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
family = VIR_SOCKET_ADDR_FAMILY(&sa);
|
||||
if (af != AF_UNSPEC && af != family) {
|
||||
DEBUG("Skipping address which family is %d, %d requested", family, af);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (VIR_REALLOC_N_QUIET(tmpAddress, ntmpAddress + 1) < 0) {
|
||||
ERROR("Out of memory");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
tmpAddress[ntmpAddress].af = family;
|
||||
memcpy(tmpAddress[ntmpAddress].addr,
|
||||
(family == AF_INET ?
|
||||
(void *) &sa.data.inet4.sin_addr.s_addr :
|
||||
(void *) &sa.data.inet6.sin6_addr.s6_addr),
|
||||
FAMILY_ADDRESS_SIZE(family));
|
||||
ntmpAddress++;
|
||||
}
|
||||
|
||||
*address = tmpAddress;
|
||||
*naddress = ntmpAddress;
|
||||
tmpAddress = NULL;
|
||||
ntmpAddress = 0;
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
*errnop = errno;
|
||||
VIR_FREE(tmpAddress);
|
||||
virJSONValueFree(leases_array);
|
||||
if (dir)
|
||||
closedir(dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
enum nss_status
|
||||
_nss_libvirt_gethostbyname_r(const char *name, struct hostent *result,
|
||||
char *buffer, size_t buflen, int *errnop,
|
||||
int *herrnop)
|
||||
{
|
||||
int af = ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET);
|
||||
|
||||
return _nss_libvirt_gethostbyname3_r(name, af, result, buffer, buflen,
|
||||
errnop, herrnop, NULL, NULL);
|
||||
}
|
||||
|
||||
enum nss_status
|
||||
_nss_libvirt_gethostbyname2_r(const char *name, int af, struct hostent *result,
|
||||
char *buffer, size_t buflen, int *errnop,
|
||||
int *herrnop)
|
||||
{
|
||||
return _nss_libvirt_gethostbyname3_r(name, af, result, buffer, buflen,
|
||||
errnop, herrnop, NULL, NULL);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
enum nss_status ret = NSS_STATUS_UNAVAIL;
|
||||
char *r_name, **r_aliases, *r_addr, **r_addr_list;
|
||||
leaseAddress *addr = NULL;
|
||||
size_t naddr, i;
|
||||
bool found = false;
|
||||
size_t nameLen, need, idx;
|
||||
int alen;
|
||||
int r;
|
||||
|
||||
/* findLease is capable of returning both IPv4 and IPv6.
|
||||
* However, this function has no way of telling user back the
|
||||
* family per each address returned. Therefore, if @af ==
|
||||
* AF_UNSPEC return just one family instead of a mixture of
|
||||
* both. Dice picked the former one. */
|
||||
if (af == AF_UNSPEC)
|
||||
af = AF_INET;
|
||||
|
||||
if ((r = findLease(name, af, &addr, &naddr, &found, errnop)) < 0) {
|
||||
/* Error occurred. Return immediately. */
|
||||
if (*errnop == EAGAIN) {
|
||||
*herrnop = TRY_AGAIN;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
} else {
|
||||
*herrnop = NO_RECOVERY;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
/* NOT found */
|
||||
*errnop = ESRCH;
|
||||
*herrnop = HOST_NOT_FOUND;
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
} else if (!naddr) {
|
||||
/* Found, but no data */
|
||||
*errnop = ENXIO;
|
||||
*herrnop = NO_DATA;
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
/* Found and have data */
|
||||
|
||||
alen = FAMILY_ADDRESS_SIZE(addr[0].af);
|
||||
|
||||
nameLen = strlen(name);
|
||||
/* We need space for:
|
||||
* a) name
|
||||
* b) alias
|
||||
* c) addresses
|
||||
* d) NULL stem */
|
||||
need = ALIGN(nameLen + 1) + naddr * ALIGN(alen) + (naddr + 2) * sizeof(char*);
|
||||
|
||||
if (buflen < need) {
|
||||
*errnop = ENOMEM;
|
||||
*herrnop = TRY_AGAIN;
|
||||
ret = NSS_STATUS_TRYAGAIN;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* First, append name */
|
||||
r_name = buffer;
|
||||
memcpy(r_name, name, nameLen + 1);
|
||||
idx = ALIGN(nameLen + 1);
|
||||
|
||||
/* Second, create aliases array */
|
||||
r_aliases = (char **) buffer + idx;
|
||||
r_aliases[0] = NULL;
|
||||
idx += sizeof(char*);
|
||||
|
||||
/* Third, append address */
|
||||
r_addr = buffer + idx;
|
||||
for (i = 0; i < naddr; i++)
|
||||
memcpy(r_addr + i * ALIGN(alen), addr[i].addr, alen);
|
||||
idx += naddr * ALIGN(alen);
|
||||
|
||||
/* Third, append address pointer array */
|
||||
r_addr_list = (char **) buffer + idx;
|
||||
for (i = 0; i < naddr; i++)
|
||||
r_addr_list[i] = r_addr + i * ALIGN(alen);
|
||||
r_addr_list[i] = NULL;
|
||||
idx += (naddr + 1) * sizeof(char*);
|
||||
|
||||
/* At this point, idx == need */
|
||||
DEBUG("Done idx:%zd need:%zd", idx, need);
|
||||
|
||||
result->h_name = r_name;
|
||||
result->h_aliases = r_aliases;
|
||||
result->h_addrtype = af;
|
||||
result->h_length = alen;
|
||||
result->h_addr_list = r_addr_list;
|
||||
|
||||
if (ttlp)
|
||||
*ttlp = 0;
|
||||
|
||||
if (canonp)
|
||||
*canonp = r_name;
|
||||
|
||||
/* Explicitly reset all error variables */
|
||||
*errnop = 0;
|
||||
*herrnop = NETDB_SUCCESS;
|
||||
h_errno = 0;
|
||||
|
||||
ret = NSS_STATUS_SUCCESS;
|
||||
cleanup:
|
||||
VIR_FREE(addr);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -32,5 +32,17 @@
|
|||
# include <nss.h>
|
||||
# include <netdb.h>
|
||||
|
||||
int blah(int c);
|
||||
enum nss_status
|
||||
_nss_libvirt_gethostbyname_r(const char *name, struct hostent *result,
|
||||
char *buffer, size_t buflen, int *errnop,
|
||||
int *herrnop);
|
||||
|
||||
enum nss_status
|
||||
_nss_libvirt_gethostbyname2_r(const char *name, int af, struct hostent *result,
|
||||
char *buffer, size_t buflen, int *errnop,
|
||||
int *herrnop);
|
||||
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);
|
||||
#endif /* __LIBVIRT_NSS_H__ */
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
{
|
||||
global:
|
||||
blah;
|
||||
_nss_libvirt_gethostbyname_r;
|
||||
_nss_libvirt_gethostbyname2_r;
|
||||
_nss_libvirt_gethostbyname3_r;
|
||||
local: *;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue