diff --git a/cfg.mk b/cfg.mk index f1b50242c6..0d1a03ce80 100644 --- a/cfg.mk +++ b/cfg.mk @@ -1072,6 +1072,7 @@ sc_po_check: \ $(srcdir)/daemon/remote_dispatch.h \ $(srcdir)/daemon/qemu_dispatch.h \ $(srcdir)/src/remote/remote_client_bodies.h \ + $(srcdir)/daemon/admin_dispatch.h \ $(srcdir)/src/admin/admin_client.h $(srcdir)/daemon/remote_dispatch.h: $(srcdir)/src/remote/remote_protocol.x $(MAKE) -C daemon remote_dispatch.h @@ -1079,6 +1080,8 @@ $(srcdir)/daemon/qemu_dispatch.h: $(srcdir)/src/remote/qemu_protocol.x $(MAKE) -C daemon qemu_dispatch.h $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protocol.x $(MAKE) -C src remote/remote_client_bodies.h +$(srcdir)/daemon/admin_dispatch.h: $(srcdir)/src/admin/admin_protocol.x + $(MAKE) -C daemon admin_dispatch.h $(srcdir)/src/admin/admin_client.h: $(srcdir)/src/admin/admin_protocol.x $(MAKE) -C src admin/admin_client.h diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 42dec5d79c..3d45f2a804 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -## Copyright (C) 2005-2014 Red Hat, Inc. +## Copyright (C) 2005-2015 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 @@ -25,6 +25,7 @@ INCLUDES = \ -I$(top_srcdir)/src/conf \ -I$(top_srcdir)/src/rpc \ -I$(top_srcdir)/src/remote \ + -I$(top_srcdir)/src/admin \ -I$(top_srcdir)/src/access \ $(GETTEXT_CPPFLAGS) @@ -34,6 +35,7 @@ DAEMON_GENERATED = \ remote_dispatch.h \ lxc_dispatch.h \ qemu_dispatch.h \ + admin_dispatch.h \ $(NULL) DAEMON_SOURCES = \ @@ -49,6 +51,7 @@ EXTRA_DIST = \ remote_dispatch.h \ lxc_dispatch.h \ qemu_dispatch.h \ + admin_dispatch.h \ libvirtd.conf \ libvirtd.init.in \ libvirtd.upstart \ @@ -78,6 +81,7 @@ BUILT_SOURCES = REMOTE_PROTOCOL = $(top_srcdir)/src/remote/remote_protocol.x LXC_PROTOCOL = $(top_srcdir)/src/remote/lxc_protocol.x QEMU_PROTOCOL = $(top_srcdir)/src/remote/qemu_protocol.x +ADMIN_PROTOCOL = $(top_srcdir)/src/admin/admin_protocol.x remote_dispatch.h: $(top_srcdir)/src/rpc/gendispatch.pl \ $(REMOTE_PROTOCOL) @@ -97,6 +101,12 @@ qemu_dispatch.h: $(top_srcdir)/src/rpc/gendispatch.pl \ --mode=server qemu QEMU $(QEMU_PROTOCOL) \ > $(srcdir)/qemu_dispatch.h +admin_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \ + $(ADMIN_PROTOCOL) + $(AM_V_GEN)$(PERL) -w $(srcdir)/../src/rpc/gendispatch.pl \ + --mode=server admin ADMIN $(ADMIN_PROTOCOL) \ + > $(srcdir)/admin_dispatch.h + if WITH_LIBVIRTD # Build a convenience library, for reuse in tests/libvirtdconftest @@ -116,6 +126,25 @@ libvirtd_conf_la_LDFLAGS = \ $(NULL) libvirtd_conf_la_LIBADD = $(LIBXML_LIBS) +noinst_LTLIBRARIES += libvirtd_admin.la +libvirtd_admin_la_SOURCES = \ + admin_server.c \ + ../src/admin/admin_protocol.c + +libvirtd_admin_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(XDR_CFLAGS) \ + $(PIE_CFLAGS) \ + $(WARN_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(COVERAGE_CFLAGS) + +libvirtd_admin_la_LDFLAGS = \ + $(PIE_LDFLAGS) \ + $(RELRO_LDFLAGS) \ + $(COVERAGE_LDFLAGS) \ + $(NO_INDIRECT_LDFLAGS) + man8_MANS = libvirtd.8 sbin_PROGRAMS = libvirtd @@ -168,6 +197,7 @@ endif WITH_DTRACE_PROBES libvirtd_LDADD += \ libvirtd_conf.la \ + libvirtd_admin.la \ ../src/libvirt-lxc.la \ ../src/libvirt-qemu.la \ ../src/libvirt_driver_remote.la \ diff --git a/daemon/admin_server.c b/daemon/admin_server.c new file mode 100644 index 0000000000..712a44beca --- /dev/null +++ b/daemon/admin_server.c @@ -0,0 +1,117 @@ +/* + * admin_server.c: + * + * Copyright (C) 2014-2015 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 + * . + * + * Author: Martin Kletzander + */ + +#include + +#include "internal.h" +#include "libvirtd.h" +#include "libvirt_internal.h" + +#include "admin_protocol.h" +#include "admin_server.h" +#include "datatypes.h" +#include "viralloc.h" +#include "virerror.h" +#include "virlog.h" +#include "virnetdaemon.h" +#include "virnetserver.h" +#include "virstring.h" +#include "virthreadjob.h" + +#define VIR_FROM_THIS VIR_FROM_ADMIN + +VIR_LOG_INIT("daemon.admin"); + + +void +remoteAdmClientFreeFunc(void *data) +{ + struct daemonAdmClientPrivate *priv = data; + + virMutexDestroy(&priv->lock); + virObjectUnref(priv->dmn); + VIR_FREE(priv); +} + +void * +remoteAdmClientInitHook(virNetServerClientPtr client ATTRIBUTE_UNUSED, + void *opaque) +{ + struct daemonAdmClientPrivate *priv; + + if (VIR_ALLOC(priv) < 0) + return NULL; + + if (virMutexInit(&priv->lock) < 0) { + VIR_FREE(priv); + virReportSystemError(errno, "%s", _("unable to init mutex")); + return NULL; + } + + /* + * We don't necessarily need to ref this object right now as there + * must be one ref being held throughout the life of the daemon, + * but let's just be safe for future. + */ + priv->dmn = virObjectRef(opaque); + + return priv; +} + +/* Functions */ +static int +adminDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + struct admin_connect_open_args *args) +{ + unsigned int flags; + struct daemonAdmClientPrivate *priv = + virNetServerClientGetPrivateData(client); + int ret = -1; + + VIR_DEBUG("priv=%p dmn=%p", priv, priv->dmn); + virMutexLock(&priv->lock); + + flags = args->flags; + virCheckFlagsGoto(0, cleanup); + + ret = 0; + cleanup: + if (ret < 0) + virNetMessageSaveError(rerr); + virMutexUnlock(&priv->lock); + return ret; +} + +static int +adminDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED) +{ + virNetServerClientDelayedClose(client); + return 0; +} + +#include "admin_dispatch.h" diff --git a/daemon/admin_server.h b/daemon/admin_server.h new file mode 100644 index 0000000000..26721a6d58 --- /dev/null +++ b/daemon/admin_server.h @@ -0,0 +1,36 @@ +/* + * admin_server.h + * + * Copyright (C) 2014 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 + * . + * + * Author: Martin Kletzander + */ + +#ifndef __LIBVIRTD_ADMIN_H__ +# define __LIBVIRTD_ADMIN_H__ + +# include "rpc/virnetserverprogram.h" +# include "rpc/virnetserverclient.h" + + +extern virNetServerProgramProc adminProcs[]; +extern size_t adminNProcs; + +void remoteAdmClientFreeFunc(void *data); +void *remoteAdmClientInitHook(virNetServerClientPtr client, void *opaque); + +#endif /* __ADMIN_REMOTE_H__ */ diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 94103e2d0d..368e10ca35 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -44,6 +44,7 @@ #include "libvirtd.h" #include "libvirtd-config.h" +#include "admin_server.h" #include "viruuid.h" #include "remote_driver.h" #include "viralloc.h" @@ -112,6 +113,7 @@ VIR_LOG_INIT("daemon.libvirtd"); virNetSASLContextPtr saslCtxt = NULL; #endif virNetServerProgramPtr remoteProgram = NULL; +virNetServerProgramPtr adminProgram = NULL; virNetServerProgramPtr qemuProgram = NULL; virNetServerProgramPtr lxcProgram = NULL; @@ -253,18 +255,24 @@ static int daemonUnixSocketPaths(struct daemonConfig *config, bool privileged, char **sockfile, - char **rosockfile) + char **rosockfile, + char **admsockfile) { if (config->unix_sock_dir) { if (virAsprintf(sockfile, "%s/libvirt-sock", config->unix_sock_dir) < 0) goto error; - if (privileged && - virAsprintf(rosockfile, "%s/libvirt-sock-ro", config->unix_sock_dir) < 0) - goto error; + + if (privileged) { + if (virAsprintf(rosockfile, "%s/libvirt-sock-ro", config->unix_sock_dir) < 0) + goto error; + if (virAsprintf(admsockfile, "%s/libvirt-admin-sock", config->unix_sock_dir) < 0) + goto error; + } } else { if (privileged) { if (VIR_STRDUP(*sockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock") < 0 || - VIR_STRDUP(*rosockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro") < 0) + VIR_STRDUP(*rosockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro") < 0 || + VIR_STRDUP(*admsockfile, LOCALSTATEDIR "/run/libvirt/libvirt-admin-sock") < 0) goto error; } else { char *rundir = NULL; @@ -280,7 +288,8 @@ daemonUnixSocketPaths(struct daemonConfig *config, } umask(old_umask); - if (virAsprintf(sockfile, "%s/libvirt-sock", rundir) < 0) { + if (virAsprintf(sockfile, "%s/libvirt-sock", rundir) < 0 || + virAsprintf(admsockfile, "%s/libvirt-admin-sock", rundir) < 0) { VIR_FREE(rundir); goto error; } @@ -427,13 +436,16 @@ static void daemonInitialize(void) static int ATTRIBUTE_NONNULL(3) daemonSetupNetworking(virNetServerPtr srv, + virNetServerPtr srvAdm, struct daemonConfig *config, const char *sock_path, const char *sock_path_ro, + const char *sock_path_adm, bool ipsock, bool privileged) { virNetServerServicePtr svc = NULL; + virNetServerServicePtr svcAdm = NULL; virNetServerServicePtr svcRO = NULL; virNetServerServicePtr svcTCP = NULL; #if WITH_GNUTLS @@ -442,6 +454,7 @@ daemonSetupNetworking(virNetServerPtr srv, gid_t unix_sock_gid = 0; int unix_sock_ro_mask = 0; int unix_sock_rw_mask = 0; + int unix_sock_adm_mask = 0; unsigned int cur_fd = STDERR_FILENO + 1; unsigned int nfds = virGetListenFDs(); @@ -461,6 +474,11 @@ daemonSetupNetworking(virNetServerPtr srv, goto error; } + if (virStrToLong_i(config->unix_sock_admin_perms, NULL, 8, &unix_sock_adm_mask) != 0) { + VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_admin_perms); + goto error; + } + if (virStrToLong_i(config->unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) { VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_rw_perms); goto error; @@ -503,6 +521,24 @@ daemonSetupNetworking(virNetServerPtr srv, virNetServerAddService(srv, svcRO, NULL) < 0) goto error; + if (sock_path_adm) { + VIR_DEBUG("Registering unix socket %s", sock_path_adm); + if (!(svcAdm = virNetServerServiceNewUNIX(sock_path_adm, + unix_sock_adm_mask, + unix_sock_gid, + REMOTE_AUTH_NONE, +#if WITH_GNUTLS + NULL, +#endif + true, + config->admin_max_queued_clients, + config->admin_max_client_requests))) + goto error; + } + + if (virNetServerAddService(srvAdm, svcAdm, NULL) < 0) + goto error; + if (ipsock) { if (config->listen_tcp) { VIR_DEBUG("Registering TCP socket %s:%s", @@ -602,6 +638,7 @@ daemonSetupNetworking(virNetServerPtr srv, virObjectUnref(svcTCP); virObjectUnref(svc); virObjectUnref(svcRO); + virObjectUnref(svcAdm); return -1; } @@ -1102,6 +1139,7 @@ daemonUsage(const char *argv0, bool privileged) int main(int argc, char **argv) { virNetDaemonPtr dmn = NULL; virNetServerPtr srv = NULL; + virNetServerPtr srvAdm = NULL; char *remote_config_file = NULL; int statuswrite = -1; int ret = 1; @@ -1109,6 +1147,7 @@ int main(int argc, char **argv) { char *pid_file = NULL; char *sock_file = NULL; char *sock_file_ro = NULL; + char *sock_file_adm = NULL; int timeout = -1; /* -t: Shutdown timeout */ int verbose = 0; int godaemon = 0; @@ -1276,12 +1315,15 @@ int main(int argc, char **argv) { if (daemonUnixSocketPaths(config, privileged, &sock_file, - &sock_file_ro) < 0) { + &sock_file_ro, + &sock_file_adm) < 0) { VIR_ERROR(_("Can't determine socket paths")); exit(EXIT_FAILURE); } - VIR_DEBUG("Decided on socket paths '%s' and '%s'", - sock_file, NULLSTR(sock_file_ro)); + VIR_DEBUG("Decided on socket paths '%s', '%s' and '%s'", + sock_file, + NULLSTR(sock_file_ro), + NULLSTR(sock_file_adm)); if (godaemon) { char ebuf[1024]; @@ -1413,6 +1455,40 @@ int main(int argc, char **argv) { goto cleanup; } + if (!(srvAdm = virNetServerNew(config->admin_min_workers, + config->admin_max_workers, + 0, + config->admin_max_clients, + 0, + config->admin_keepalive_interval, + config->admin_keepalive_count, + !!config->admin_keepalive_required, + NULL, + remoteAdmClientInitHook, + NULL, + remoteAdmClientFreeFunc, + dmn))) { + ret = VIR_DAEMON_ERR_INIT; + goto cleanup; + } + + if (virNetDaemonAddServer(dmn, srvAdm) < 0) { + ret = VIR_DAEMON_ERR_INIT; + goto cleanup; + } + + if (!(adminProgram = virNetServerProgramNew(ADMIN_PROGRAM, + ADMIN_PROTOCOL_VERSION, + adminProcs, + adminNProcs))) { + ret = VIR_DAEMON_ERR_INIT; + goto cleanup; + } + if (virNetServerAddProgram(srvAdm, adminProgram) < 0) { + ret = VIR_DAEMON_ERR_INIT; + goto cleanup; + } + if (timeout != -1) { VIR_DEBUG("Registering shutdown timeout %d", timeout); virNetDaemonAutoShutdown(dmn, timeout); @@ -1453,8 +1529,11 @@ int main(int argc, char **argv) { virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_START, 0, "start", NULL, NULL); - if (daemonSetupNetworking(srv, config, - sock_file, sock_file_ro, + if (daemonSetupNetworking(srv, srvAdm, + config, + sock_file, + sock_file_ro, + sock_file_adm, ipsock, privileged) < 0) { ret = VIR_DAEMON_ERR_NETWORK; goto cleanup; @@ -1507,9 +1586,11 @@ int main(int argc, char **argv) { virObjectUnref(remoteProgram); virObjectUnref(lxcProgram); virObjectUnref(qemuProgram); + virObjectUnref(adminProgram); virNetDaemonClose(dmn); virObjectUnref(dmn); virObjectUnref(srv); + virObjectUnref(srvAdm); virNetlinkShutdown(); if (statuswrite != -1) { if (ret != 0) { @@ -1526,6 +1607,7 @@ int main(int argc, char **argv) { VIR_FREE(sock_file); VIR_FREE(sock_file_ro); + VIR_FREE(sock_file_adm); VIR_FREE(pid_file); VIR_FREE(remote_config_file); VIR_FREE(run_dir); diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index 02d4101742..8c1a904893 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -1,7 +1,7 @@ /* * libvirtd.h: daemon data structure definitions * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -30,9 +30,11 @@ # include # include # include "remote_protocol.h" +# include "admin_protocol.h" # include "lxc_protocol.h" # include "qemu_protocol.h" # include "virthread.h" + # if WITH_SASL # include "virnetsaslcontext.h" # endif @@ -42,6 +44,8 @@ typedef struct daemonClientStream daemonClientStream; typedef daemonClientStream *daemonClientStreamPtr; typedef struct daemonClientPrivate daemonClientPrivate; typedef daemonClientPrivate *daemonClientPrivatePtr; +typedef struct daemonAdmClientPrivate daemonAdmClientPrivate; +typedef daemonAdmClientPrivate *daemonAdmClientPrivatePtr; typedef struct daemonClientEventCallback daemonClientEventCallback; typedef daemonClientEventCallback *daemonClientEventCallbackPtr; @@ -71,6 +75,14 @@ struct daemonClientPrivate { bool keepalive_supported; }; +/* Separate private data for admin connection */ +struct daemonAdmClientPrivate { + /* Just a placeholder, not that there is anything to be locked */ + virMutex lock; + + virNetDaemonPtr dmn; +}; + # if WITH_SASL extern virNetSASLContextPtr saslCtxt; # endif diff --git a/po/POTFILES.in b/po/POTFILES.in index 4afa2f9208..189e2cc2f4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,3 +1,4 @@ +daemon/admin_server.c daemon/libvirtd-config.c daemon/libvirtd.c daemon/qemu_dispatch.h