#include "virlease.h"
#include "viralloc.h"
#include "virtime.h"
-#include "virerror.h"
#include "virsocketaddr.h"
#include "configmake.h"
-#include "virmacmap.h"
-#include "virobject.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
+
+#if defined(LIBVIRT_NSS_GUEST)
+# include "libvirt_nss_macs.h"
+#endif /* !LIBVIRT_NSS_GUEST */
#define LEASEDIR LOCALSTATEDIR "/lib/libvirt/dnsmasq/"
size_t nleases,
const char *name,
const char **macs,
+ size_t nmacs,
int af,
bool *found)
{
size_t i;
+ size_t j;
long long expirytime;
time_t currtime;
}
if (macs) {
- const char **macstmp = macs;
const char *macAddr;
bool match = false;
if (!macAddr)
continue;
- while (*macstmp && !match) {
- if (STREQ(*macstmp, macAddr))
+ for (j = 0; j < nmacs && !match; j++) {
+ if (STREQ(macs[j], macAddr))
match = true;
- macstmp++;
}
if (!match)
continue;
ssize_t nleases;
VIR_AUTOFREE(leaseAddress *) tmpAddress = NULL;
size_t ntmpAddress = 0;
- virMacMapPtr map = NULL;
char **macs = NULL;
size_t nmacs = 0;
size_t i;
VIR_FREE(path);
#if defined(LIBVIRT_NSS_GUEST)
} else if (dlen >= 5 && STREQ(entry->d_name + dlen - 5, ".macs")) {
- const char * const *newmacs;
if (asprintf(&path, "%s/%s", leaseDir, entry->d_name) < 0)
goto cleanup;
DEBUG("Processing %s", path);
- if (!(map = virMacMapNew(path))) {
- ERROR("Unable to parse %s", path);
+ if (findMACs(path, name, &macs, &nmacs) < 0) {
VIR_FREE(path);
goto cleanup;
}
VIR_FREE(path);
-
- DEBUG("Looking up macs in %p for %s", map, name);
- newmacs = virMacMapLookup(map, name);
- for (i = 0; newmacs && newmacs[i] != NULL; i++)
- ;
-
- DEBUG("Got %zu macs", i);
- if (i > 0) {
- if (VIR_REALLOC_N_QUIET(macs, nmacs + i + 1) < 0)
- goto cleanup;
-
- for (i = 0; newmacs[i] != NULL; i++) {
- char *macdup;
- if (!(macdup = strdup(newmacs[i])))
- goto cleanup;
- DEBUG("Capture mac %s", macdup);
- macs[nmacs++] = macdup;
- }
- macs[nmacs] = NULL;
- }
-
- virObjectUnref(map);
- map = NULL;
#endif /* LIBVIRT_NSS_GUEST */
}
DEBUG("Finding with %zu macs", nmacs);
if (!nmacs)
goto cleanup;
+ for (i = 0; i < nmacs; i++)
+ DEBUG(" %s", macs[i]);
#endif
if (findLeaseInJSON(&tmpAddress, &ntmpAddress,
leases_array, nleases,
- name, (const char**)macs, af, found) < 0)
+ name, (const char**)macs, nmacs,
+ af, found) < 0)
goto cleanup;
DEBUG("Found %zu addresses", ntmpAddress);
ret = 0;
cleanup:
- virObjectUnref(map);
*errnop = errno;
for (i = 0; i < nmacs; i++)
free(macs[i]);
--- /dev/null
+/*
+ * libvirt_nss_macs.c: Name Service Switch plugin MAC file parser
+ *
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <yajl/yajl_gen.h>
+#include <yajl/yajl_parse.h>
+
+#include "internal.h"
+
+#include "libvirt_nss.h"
+#include "libvirt_nss_macs.h"
+
+enum {
+ FIND_MACS_STATE_START,
+ FIND_MACS_STATE_LIST,
+ FIND_MACS_STATE_ENTRY,
+ FIND_MACS_STATE_ENTRY_MACS,
+};
+
+typedef struct {
+ const char *name;
+ char ***macs;
+ size_t *nmacs;
+ int state;
+
+ char *key;
+ struct {
+ char *name;
+ char **macs;
+ size_t nmacs;
+ } entry;
+} findMACsParser;
+
+
+static int
+findMACsParserString(void *ctx,
+ const unsigned char *stringVal,
+ size_t stringLen)
+{
+ findMACsParser *parser = ctx;
+
+ DEBUG("Parse string state=%d '%.*s' (map key '%s')",
+ parser->state, (int)stringLen, (const char *)stringVal,
+ NULLSTR(parser->key));
+ if (!parser->key)
+ return 0;
+
+ if (parser->state == FIND_MACS_STATE_ENTRY) {
+ if (STRNEQ(parser->key, "domain"))
+ return 0;
+
+ free(parser->entry.name);
+ if (!(parser->entry.name = strndup((char *)stringVal, stringLen)))
+ return 0;
+ } else if (parser->state == FIND_MACS_STATE_ENTRY_MACS) {
+ char **macs;
+ if (STRNEQ(parser->key, "macs"))
+ return 0;
+
+ if (!(macs = realloc(parser->entry.macs,
+ sizeof(char *) * (parser->entry.nmacs + 1))))
+ return 0;
+
+ parser->entry.macs = macs;
+ if (!(macs[parser->entry.nmacs++] = strndup((char *)stringVal, stringLen)))
+ return 0;
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+
+static int
+findMACsParserMapKey(void *ctx,
+ const unsigned char *stringVal,
+ size_t stringLen)
+{
+ findMACsParser *parser = ctx;
+
+ DEBUG("Parse map key state=%d '%.*s'",
+ parser->state, (int)stringLen, (const char *)stringVal);
+
+ free(parser->key);
+ if (!(parser->key = strndup((char *)stringVal, stringLen)))
+ return 0;
+
+ return 1;
+}
+
+
+static int
+findMACsParserStartMap(void *ctx)
+{
+ findMACsParser *parser = ctx;
+
+ DEBUG("Parse start map state=%d", parser->state);
+
+ if (parser->state != FIND_MACS_STATE_LIST)
+ return 0;
+
+ free(parser->key);
+ parser->key = NULL;
+ parser->state = FIND_MACS_STATE_ENTRY;
+
+ return 1;
+}
+
+
+static int
+findMACsParserEndMap(void *ctx)
+{
+ findMACsParser *parser = ctx;
+ size_t i;
+
+ DEBUG("Parse end map state=%d", parser->state);
+
+ if (parser->entry.name == NULL)
+ return 0;
+
+ if (parser->state != FIND_MACS_STATE_ENTRY)
+ return 0;
+
+ if (STREQ(parser->entry.name, parser->name)) {
+ char **macs = realloc(*parser->macs,
+ sizeof(char *) * ((*parser->nmacs) + parser->entry.nmacs));
+ if (!macs)
+ return 0;
+
+ *parser->macs = macs;
+ for (i = 0; i < parser->entry.nmacs; i++)
+ (*parser->macs)[(*parser->nmacs)++] = parser->entry.macs[i];
+ } else {
+ for (i = 0; i < parser->entry.nmacs; i++)
+ free(parser->entry.macs[i]);
+ }
+ free(parser->entry.macs);
+ parser->entry.macs = NULL;
+ parser->entry.nmacs = 0;
+
+ parser->state = FIND_MACS_STATE_LIST;
+
+ return 1;
+}
+
+
+static int
+findMACsParserStartArray(void *ctx)
+{
+ findMACsParser *parser = ctx;
+
+ DEBUG("Parse start array state=%d", parser->state);
+
+ if (parser->state == FIND_MACS_STATE_START)
+ parser->state = FIND_MACS_STATE_LIST;
+ else if (parser->state == FIND_MACS_STATE_ENTRY)
+ parser->state = FIND_MACS_STATE_ENTRY_MACS;
+ else
+ return 0;
+
+ return 1;
+}
+
+
+static int
+findMACsParserEndArray(void *ctx)
+{
+ findMACsParser *parser = ctx;
+
+ DEBUG("Parse end array state=%d", parser->state);
+
+ if (parser->state == FIND_MACS_STATE_LIST)
+ parser->state = FIND_MACS_STATE_START;
+ else if (parser->state == FIND_MACS_STATE_ENTRY_MACS)
+ parser->state = FIND_MACS_STATE_ENTRY;
+ else
+ return 0;
+
+ return 1;
+}
+
+
+int
+findMACs(const char *file,
+ const char *name,
+ char ***macs,
+ size_t *nmacs)
+{
+ int fd = -1;
+ int ret = -1;
+ const yajl_callbacks parserCallbacks = {
+ NULL, /* null */
+ NULL, /* bool */
+ NULL, /* integer */
+ NULL, /* double */
+ NULL, /* number */
+ findMACsParserString,
+ findMACsParserStartMap,
+ findMACsParserMapKey,
+ findMACsParserEndMap,
+ findMACsParserStartArray,
+ findMACsParserEndArray,
+ };
+ findMACsParser parserState = {
+ .name = name,
+ .macs = macs,
+ .nmacs = nmacs,
+ };
+ yajl_handle parser = NULL;
+ char line[1024];
+ size_t i;
+ int rv;
+
+ if ((fd = open(file, O_RDONLY)) < 0) {
+ ERROR("Cannot open %s", file);
+ goto cleanup;
+ }
+
+ parser = yajl_alloc(&parserCallbacks, NULL, &parserState);
+ if (!parser) {
+ ERROR("Unable to create JSON parser");
+ goto cleanup;
+ }
+
+ while (1) {
+ rv = read(fd, line, sizeof(line));
+ if (rv < 0)
+ goto cleanup;
+ if (rv == 0)
+ break;
+
+ if (yajl_parse(parser, (const unsigned char *)line, rv) !=
+ yajl_status_ok) {
+ ERROR("Parse failed %s",
+ yajl_get_error(parser, 1,
+ (const unsigned char*)line, rv));
+ goto cleanup;
+ }
+ }
+
+ if (yajl_complete_parse(parser) != yajl_status_ok) {
+ ERROR("Parse failed %s",
+ yajl_get_error(parser, 1, NULL, 0));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (ret != 0) {
+ for (i = 0; i < *nmacs; i++) {
+ char *mac = (*macs)[i];
+ free(mac);
+ }
+ free(*macs);
+ *macs = NULL;
+ *nmacs = 0;
+ }
+ yajl_free(parser);
+ for (i = 0; i < parserState.entry.nmacs; i++)
+ free(parserState.entry.macs[i]);
+ free(parserState.entry.macs);
+ free(parserState.entry.name);
+ free(parserState.key);
+ if (fd != -1)
+ close(fd);
+ return ret;
+}