2007-02-14 01:40:09 +00:00
|
|
|
/*
|
2009-09-16 11:37:26 +00:00
|
|
|
* libvirtd.c: daemon start of day, guest process & i/o management
|
2007-02-14 01:40:09 +00:00
|
|
|
*
|
2010-02-02 10:27:25 +00:00
|
|
|
* Copyright (C) 2006-2010 Red Hat, Inc.
|
2007-02-14 01:40:09 +00:00
|
|
|
* Copyright (C) 2006 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2008-01-29 18:15:54 +00:00
|
|
|
#include <config.h>
|
2007-02-14 15:42:55 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <sys/poll.h>
|
|
|
|
#include <netinet/in.h>
|
2007-06-11 12:04:54 +00:00
|
|
|
#include <netinet/tcp.h>
|
2007-02-14 01:40:09 +00:00
|
|
|
#include <netdb.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <stdio.h>
|
2007-02-16 18:30:55 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <syslog.h>
|
2007-02-14 01:40:09 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <getopt.h>
|
2007-06-11 12:04:54 +00:00
|
|
|
#include <fnmatch.h>
|
2007-09-19 02:28:01 +00:00
|
|
|
#include <grp.h>
|
2008-01-23 14:54:41 +00:00
|
|
|
#include <signal.h>
|
2008-10-28 17:46:00 +00:00
|
|
|
#include <netdb.h>
|
2007-04-10 23:17:46 +00:00
|
|
|
|
2008-11-04 23:22:06 +00:00
|
|
|
#include "libvirt_internal.h"
|
2009-02-05 16:28:30 +00:00
|
|
|
#include "virterror_internal.h"
|
2010-11-09 20:48:48 +00:00
|
|
|
#include "files.h"
|
Standardize use of header files, making internal.h primary.
* qemud/internal.h, qemud/qemud.h: Rename this file so it
doesn't conflict with src/internal.h.
* HACKING: Document how header files should be used.
* qemud/Makefile.am: Add src/ directory to includes.
* qemud/event.c, qemud/mdns.c, qemud/qemud.c, qemud/remote.c,
qemud/remote_protocol.c, qemud/remote_protocol.h,
qemud/remote_protocol.x, src/buf.c, src/libvirt.c,
src/nodeinfo.c, src/qemu_conf.c, src/qemu_driver.c,
src/stats_linux.c, src/storage_backend.c, src/storage_backend_fs.c,
src/storage_backend_iscsi.c, src/storage_backend_logical.c,
src/storage_conf.c, src/storage_driver.c, src/util.c,
src/util.h, src/virsh.c, src/virterror.c, src/xend_internal.c,
src/xml.c, tests/reconnect.c, tests/xmlrpctest.c,
tests/qparamtest.c: Standardize use of header files.
* docs/*, po/*: Rebuild docs.
2008-05-23 08:24:41 +00:00
|
|
|
|
2009-02-09 17:52:38 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
2009-09-16 11:37:26 +00:00
|
|
|
#include "libvirtd.h"
|
2009-07-10 11:20:03 +00:00
|
|
|
#include "dispatch.h"
|
|
|
|
|
Standardize use of header files, making internal.h primary.
* qemud/internal.h, qemud/qemud.h: Rename this file so it
doesn't conflict with src/internal.h.
* HACKING: Document how header files should be used.
* qemud/Makefile.am: Add src/ directory to includes.
* qemud/event.c, qemud/mdns.c, qemud/qemud.c, qemud/remote.c,
qemud/remote_protocol.c, qemud/remote_protocol.h,
qemud/remote_protocol.x, src/buf.c, src/libvirt.c,
src/nodeinfo.c, src/qemu_conf.c, src/qemu_driver.c,
src/stats_linux.c, src/storage_backend.c, src/storage_backend_fs.c,
src/storage_backend_iscsi.c, src/storage_backend_logical.c,
src/storage_conf.c, src/storage_driver.c, src/util.c,
src/util.h, src/virsh.c, src/virterror.c, src/xend_internal.c,
src/xml.c, tests/reconnect.c, tests/xmlrpctest.c,
tests/qparamtest.c: Standardize use of header files.
* docs/*, po/*: Rebuild docs.
2008-05-23 08:24:41 +00:00
|
|
|
#include "util.h"
|
2010-05-25 14:33:51 +00:00
|
|
|
#include "uuid.h"
|
2009-09-16 15:55:16 +00:00
|
|
|
#include "remote_driver.h"
|
Standardize use of header files, making internal.h primary.
* qemud/internal.h, qemud/qemud.h: Rename this file so it
doesn't conflict with src/internal.h.
* HACKING: Document how header files should be used.
* qemud/Makefile.am: Add src/ directory to includes.
* qemud/event.c, qemud/mdns.c, qemud/qemud.c, qemud/remote.c,
qemud/remote_protocol.c, qemud/remote_protocol.h,
qemud/remote_protocol.x, src/buf.c, src/libvirt.c,
src/nodeinfo.c, src/qemu_conf.c, src/qemu_driver.c,
src/stats_linux.c, src/storage_backend.c, src/storage_backend_fs.c,
src/storage_backend_iscsi.c, src/storage_backend_logical.c,
src/storage_conf.c, src/storage_driver.c, src/util.c,
src/util.h, src/virsh.c, src/virterror.c, src/xend_internal.c,
src/xml.c, tests/reconnect.c, tests/xmlrpctest.c,
tests/qparamtest.c: Standardize use of header files.
* docs/*, po/*: Rebuild docs.
2008-05-23 08:24:41 +00:00
|
|
|
#include "conf.h"
|
2007-06-26 19:11:00 +00:00
|
|
|
#include "event.h"
|
2008-06-06 10:52:01 +00:00
|
|
|
#include "memory.h"
|
2009-07-10 12:06:36 +00:00
|
|
|
#include "stream.h"
|
2010-03-26 14:53:32 +00:00
|
|
|
#include "hooks.h"
|
2010-09-15 13:44:11 +00:00
|
|
|
#include "virtaudit.h"
|
2007-09-19 01:56:55 +00:00
|
|
|
#ifdef HAVE_AVAHI
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "mdns.h"
|
2007-09-19 01:56:55 +00:00
|
|
|
#endif
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-11-21 12:16:08 +00:00
|
|
|
#ifdef WITH_DRIVER_MODULES
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "driver.h"
|
2008-11-21 12:16:08 +00:00
|
|
|
#else
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifdef WITH_QEMU
|
|
|
|
# include "qemu/qemu_driver.h"
|
|
|
|
# endif
|
|
|
|
# ifdef WITH_LXC
|
|
|
|
# include "lxc/lxc_driver.h"
|
|
|
|
# endif
|
|
|
|
# ifdef WITH_UML
|
|
|
|
# include "uml/uml_driver.h"
|
|
|
|
# endif
|
|
|
|
# ifdef WITH_ONE
|
|
|
|
# include "opennebula/one_driver.h"
|
|
|
|
# endif
|
|
|
|
# ifdef WITH_NETWORK
|
|
|
|
# include "network/bridge_driver.h"
|
|
|
|
# endif
|
|
|
|
# ifdef WITH_NETCF
|
|
|
|
# include "interface/netcf_driver.h"
|
|
|
|
# endif
|
|
|
|
# ifdef WITH_STORAGE_DIR
|
|
|
|
# include "storage/storage_driver.h"
|
|
|
|
# endif
|
|
|
|
# ifdef WITH_NODE_DEVICES
|
|
|
|
# include "node_device/node_device_driver.h"
|
|
|
|
# endif
|
|
|
|
# ifdef WITH_SECRETS
|
|
|
|
# include "secret/secret_driver.h"
|
|
|
|
# endif
|
2010-03-25 17:46:09 +00:00
|
|
|
# ifdef WITH_NWFILTER
|
|
|
|
# include "nwfilter/nwfilter_driver.h"
|
|
|
|
# endif
|
2009-12-22 13:50:50 +00:00
|
|
|
#endif
|
2008-11-17 12:18:18 +00:00
|
|
|
|
|
|
|
|
2009-01-22 17:49:41 +00:00
|
|
|
#ifdef __sun
|
2010-03-09 18:22:22 +00:00
|
|
|
# include <ucred.h>
|
|
|
|
# include <priv.h>
|
2009-01-22 17:49:41 +00:00
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifndef PRIV_VIRT_MANAGE
|
|
|
|
# define PRIV_VIRT_MANAGE ((const char *)"virt_manage")
|
|
|
|
# endif
|
2009-01-22 17:49:41 +00:00
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifndef PRIV_XVM_CONTROL
|
|
|
|
# define PRIV_XVM_CONTROL ((const char *)"xvm_control")
|
|
|
|
# endif
|
2009-01-22 17:49:41 +00:00
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# define PU_RESETGROUPS 0x0001 /* Remove supplemental groups */
|
|
|
|
# define PU_CLEARLIMITSET 0x0008 /* L=0 */
|
2009-01-22 17:49:41 +00:00
|
|
|
|
|
|
|
extern int __init_daemon_priv(int, uid_t, gid_t, ...);
|
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# define SYSTEM_UID 60
|
2009-01-22 17:49:41 +00:00
|
|
|
|
|
|
|
static gid_t unix_sock_gid = 60; /* Not used */
|
|
|
|
static int unix_sock_rw_mask = 0666;
|
|
|
|
static int unix_sock_ro_mask = 0666;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static gid_t unix_sock_gid = 0; /* Only root by default */
|
|
|
|
static int unix_sock_rw_mask = 0700; /* Allow user only */
|
|
|
|
static int unix_sock_ro_mask = 0777; /* Allow world */
|
|
|
|
|
|
|
|
#endif /* __sun */
|
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
static int godaemon = 0; /* -d: Be a daemon */
|
|
|
|
static int verbose = 0; /* -v: Verbose mode */
|
2007-06-26 23:48:46 +00:00
|
|
|
static int timeout = -1; /* -t: Shutdown timeout */
|
2007-06-11 12:04:54 +00:00
|
|
|
static int sigwrite = -1; /* Signal handler pipe */
|
2007-06-26 23:48:46 +00:00
|
|
|
static int ipsock = 0; /* -l Listen for TCP/IP */
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
/* Defaults for configuration file elements */
|
2007-06-11 12:04:54 +00:00
|
|
|
static int listen_tls = 1;
|
|
|
|
static int listen_tcp = 0;
|
2008-05-14 20:57:20 +00:00
|
|
|
static char *listen_addr = (char *) LIBVIRTD_LISTEN_ADDR;
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
static char *tls_port = (char *) LIBVIRTD_TLS_PORT;
|
|
|
|
static char *tcp_port = (char *) LIBVIRTD_TCP_PORT;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-02-09 17:52:38 +00:00
|
|
|
static char *unix_sock_dir = NULL;
|
|
|
|
|
2007-12-05 18:21:27 +00:00
|
|
|
#if HAVE_POLKIT
|
|
|
|
static int auth_unix_rw = REMOTE_AUTH_POLKIT;
|
|
|
|
static int auth_unix_ro = REMOTE_AUTH_POLKIT;
|
|
|
|
#else
|
2007-12-05 15:34:05 +00:00
|
|
|
static int auth_unix_rw = REMOTE_AUTH_NONE;
|
|
|
|
static int auth_unix_ro = REMOTE_AUTH_NONE;
|
2007-12-05 18:21:27 +00:00
|
|
|
#endif /* HAVE_POLKIT */
|
2007-12-05 15:34:05 +00:00
|
|
|
#if HAVE_SASL
|
|
|
|
static int auth_tcp = REMOTE_AUTH_SASL;
|
|
|
|
#else
|
|
|
|
static int auth_tcp = REMOTE_AUTH_NONE;
|
|
|
|
#endif
|
|
|
|
static int auth_tls = REMOTE_AUTH_NONE;
|
|
|
|
|
2007-09-19 01:56:55 +00:00
|
|
|
static int mdns_adv = 1;
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
static char *mdns_name = NULL;
|
2007-09-19 01:56:55 +00:00
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
static int tls_no_verify_certificate = 0;
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
static char **tls_allowed_dn_list = NULL;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
static char *key_file = (char *) LIBVIRT_SERVERKEY;
|
|
|
|
static char *cert_file = (char *) LIBVIRT_SERVERCERT;
|
|
|
|
static char *ca_file = (char *) LIBVIRT_CACERT;
|
|
|
|
static char *crl_file = (char *) "";
|
2007-06-11 12:04:54 +00:00
|
|
|
|
|
|
|
static gnutls_certificate_credentials_t x509_cred;
|
|
|
|
static gnutls_dh_params_t dh_params;
|
|
|
|
|
2008-12-04 22:18:44 +00:00
|
|
|
static int min_workers = 5;
|
|
|
|
static int max_workers = 20;
|
|
|
|
static int max_clients = 20;
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Total number of 'in-process' RPC calls allowed across all clients */
|
|
|
|
static int max_requests = 20;
|
|
|
|
/* Total number of 'in-process' RPC calls allowed by a single client*/
|
|
|
|
static int max_client_requests = 5;
|
|
|
|
|
2010-09-15 13:44:11 +00:00
|
|
|
static int audit_level = 1;
|
|
|
|
static int audit_logging = 0;
|
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
#define DH_BITS 1024
|
2007-02-16 18:28:17 +00:00
|
|
|
|
2007-03-27 10:28:45 +00:00
|
|
|
static sig_atomic_t sig_errors = 0;
|
|
|
|
static int sig_lasterrno = 0;
|
2010-05-20 19:40:54 +00:00
|
|
|
static const char *argv0;
|
2007-03-27 10:28:45 +00:00
|
|
|
|
2009-10-16 11:14:54 +00:00
|
|
|
enum {
|
|
|
|
VIR_DAEMON_ERR_NONE = 0,
|
|
|
|
VIR_DAEMON_ERR_PIDFILE,
|
|
|
|
VIR_DAEMON_ERR_RUNDIR,
|
|
|
|
VIR_DAEMON_ERR_INIT,
|
|
|
|
VIR_DAEMON_ERR_SIGNAL,
|
|
|
|
VIR_DAEMON_ERR_PRIVS,
|
|
|
|
VIR_DAEMON_ERR_NETWORK,
|
|
|
|
VIR_DAEMON_ERR_CONFIG,
|
2010-03-26 14:53:32 +00:00
|
|
|
VIR_DAEMON_ERR_HOOKS,
|
2010-09-15 13:44:11 +00:00
|
|
|
VIR_DAEMON_ERR_AUDIT,
|
2009-10-16 11:14:54 +00:00
|
|
|
|
|
|
|
VIR_DAEMON_ERR_LAST
|
|
|
|
};
|
|
|
|
|
|
|
|
VIR_ENUM_DECL(virDaemonErr)
|
|
|
|
VIR_ENUM_IMPL(virDaemonErr, VIR_DAEMON_ERR_LAST,
|
|
|
|
"Initialization successful",
|
|
|
|
"Unable to obtain pidfile",
|
|
|
|
"Unable to create rundir",
|
|
|
|
"Unable to initialize libvirt",
|
|
|
|
"Unable to setup signal handlers",
|
|
|
|
"Unable to drop privileges",
|
|
|
|
"Unable to initialize network sockets",
|
2010-03-26 14:53:32 +00:00
|
|
|
"Unable to load configuration file",
|
2010-09-15 13:44:11 +00:00
|
|
|
"Unable to look for hook scripts",
|
|
|
|
"Unable to initialize audit system")
|
2009-10-16 11:14:54 +00:00
|
|
|
|
2008-05-13 06:30:58 +00:00
|
|
|
static void sig_handler(int sig, siginfo_t * siginfo,
|
|
|
|
void* context ATTRIBUTE_UNUSED) {
|
2007-02-16 18:28:17 +00:00
|
|
|
int origerrno;
|
2007-03-27 10:28:45 +00:00
|
|
|
int r;
|
2007-02-16 18:28:17 +00:00
|
|
|
|
2008-05-13 06:30:58 +00:00
|
|
|
/* set the sig num in the struct */
|
|
|
|
siginfo->si_signo = sig;
|
2007-02-16 18:28:17 +00:00
|
|
|
|
|
|
|
origerrno = errno;
|
2008-05-13 06:30:58 +00:00
|
|
|
r = safewrite(sigwrite, siginfo, sizeof(*siginfo));
|
2007-03-27 10:28:45 +00:00
|
|
|
if (r == -1) {
|
|
|
|
sig_errors++;
|
|
|
|
sig_lasterrno = errno;
|
|
|
|
}
|
2007-02-16 18:28:17 +00:00
|
|
|
errno = origerrno;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2007-02-16 18:28:17 +00:00
|
|
|
|
2008-11-19 16:19:36 +00:00
|
|
|
static void qemudDispatchClientEvent(int watch, int fd, int events, void *opaque);
|
|
|
|
static void qemudDispatchServerEvent(int watch, int fd, int events, void *opaque);
|
2009-01-20 19:27:11 +00:00
|
|
|
static int qemudStartWorker(struct qemud_server *server, struct qemud_worker *worker);
|
2009-01-20 19:25:15 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
qemudClientMessageQueuePush(struct qemud_client_message **queue,
|
|
|
|
struct qemud_client_message *msg)
|
|
|
|
{
|
|
|
|
struct qemud_client_message *tmp = *queue;
|
|
|
|
|
|
|
|
if (tmp) {
|
|
|
|
while (tmp->next)
|
|
|
|
tmp = tmp->next;
|
|
|
|
tmp->next = msg;
|
|
|
|
} else {
|
|
|
|
*queue = msg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-10 11:20:03 +00:00
|
|
|
struct qemud_client_message *
|
2009-01-20 19:25:15 +00:00
|
|
|
qemudClientMessageQueueServe(struct qemud_client_message **queue)
|
|
|
|
{
|
|
|
|
struct qemud_client_message *tmp = *queue;
|
|
|
|
|
|
|
|
if (tmp) {
|
|
|
|
*queue = tmp->next;
|
|
|
|
tmp->next = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
}
|
2007-06-26 19:11:00 +00:00
|
|
|
|
2007-07-12 14:54:45 +00:00
|
|
|
static int
|
|
|
|
remoteCheckCertFile(const char *type, const char *file)
|
|
|
|
{
|
|
|
|
struct stat sb;
|
|
|
|
if (stat(file, &sb) < 0) {
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
|
|
|
VIR_ERROR(_("Cannot access %s '%s': %s"),
|
|
|
|
type, file, virStrerror(errno, ebuf, sizeof ebuf));
|
2007-07-12 14:54:45 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
static int
|
|
|
|
remoteInitializeGnuTLS (void)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* Initialise GnuTLS. */
|
|
|
|
gnutls_global_init ();
|
|
|
|
|
|
|
|
err = gnutls_certificate_allocate_credentials (&x509_cred);
|
|
|
|
if (err) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("gnutls_certificate_allocate_credentials: %s"),
|
2007-06-11 12:04:54 +00:00
|
|
|
gnutls_strerror (err));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ca_file && ca_file[0] != '\0') {
|
2007-07-12 14:54:45 +00:00
|
|
|
if (remoteCheckCertFile("CA certificate", ca_file) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
qemudDebug ("loading CA cert from %s", ca_file);
|
|
|
|
err = gnutls_certificate_set_x509_trust_file (x509_cred, ca_file,
|
|
|
|
GNUTLS_X509_FMT_PEM);
|
|
|
|
if (err < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("gnutls_certificate_set_x509_trust_file: %s"),
|
2007-06-11 12:04:54 +00:00
|
|
|
gnutls_strerror (err));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (crl_file && crl_file[0] != '\0') {
|
2007-11-21 23:16:11 +00:00
|
|
|
if (remoteCheckCertFile("CA revocation list", crl_file) < 0)
|
2007-07-12 14:54:45 +00:00
|
|
|
return -1;
|
|
|
|
|
2008-12-22 12:53:26 +00:00
|
|
|
DEBUG("loading CRL from %s", crl_file);
|
2007-06-11 12:04:54 +00:00
|
|
|
err = gnutls_certificate_set_x509_crl_file (x509_cred, crl_file,
|
|
|
|
GNUTLS_X509_FMT_PEM);
|
|
|
|
if (err < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("gnutls_certificate_set_x509_crl_file: %s"),
|
2007-06-11 12:04:54 +00:00
|
|
|
gnutls_strerror (err));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cert_file && cert_file[0] != '\0' && key_file && key_file[0] != '\0') {
|
2007-07-12 14:54:45 +00:00
|
|
|
if (remoteCheckCertFile("server certificate", cert_file) < 0)
|
|
|
|
return -1;
|
|
|
|
if (remoteCheckCertFile("server key", key_file) < 0)
|
|
|
|
return -1;
|
2008-12-22 12:53:26 +00:00
|
|
|
DEBUG("loading cert and key from %s and %s", cert_file, key_file);
|
2007-06-11 12:04:54 +00:00
|
|
|
err =
|
|
|
|
gnutls_certificate_set_x509_key_file (x509_cred,
|
|
|
|
cert_file, key_file,
|
|
|
|
GNUTLS_X509_FMT_PEM);
|
|
|
|
if (err < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("gnutls_certificate_set_x509_key_file: %s"),
|
2007-06-11 12:04:54 +00:00
|
|
|
gnutls_strerror (err));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate Diffie Hellman parameters - for use with DHE
|
|
|
|
* kx algorithms. These should be discarded and regenerated
|
|
|
|
* once a day, once a week or once a month. Depending on the
|
|
|
|
* security requirements.
|
|
|
|
*/
|
|
|
|
err = gnutls_dh_params_init (&dh_params);
|
|
|
|
if (err < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("gnutls_dh_params_init: %s"), gnutls_strerror (err));
|
2007-06-11 12:04:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
err = gnutls_dh_params_generate2 (dh_params, DH_BITS);
|
|
|
|
if (err < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("gnutls_dh_params_generate2: %s"), gnutls_strerror (err));
|
2007-06-11 12:04:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
gnutls_certificate_set_dh_params (x509_cred, dh_params);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
static void
|
2008-11-19 16:19:36 +00:00
|
|
|
qemudDispatchSignalEvent(int watch ATTRIBUTE_UNUSED,
|
|
|
|
int fd ATTRIBUTE_UNUSED,
|
2008-10-23 13:18:18 +00:00
|
|
|
int events ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque) {
|
2007-06-26 19:11:00 +00:00
|
|
|
struct qemud_server *server = (struct qemud_server *)opaque;
|
2008-05-13 06:30:58 +00:00
|
|
|
siginfo_t siginfo;
|
2007-02-16 18:28:17 +00:00
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&server->lock);
|
2008-12-04 22:16:40 +00:00
|
|
|
|
2008-05-13 06:30:58 +00:00
|
|
|
if (saferead(server->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
|
|
|
VIR_ERROR(_("Failed to read from signal pipe: %s"),
|
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&server->lock);
|
2007-06-26 19:11:00 +00:00
|
|
|
return;
|
2007-02-16 18:30:55 +00:00
|
|
|
}
|
|
|
|
|
2008-05-13 06:30:58 +00:00
|
|
|
switch (siginfo.si_signo) {
|
2007-02-16 18:28:17 +00:00
|
|
|
case SIGHUP:
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_INFO0(_("Reloading configuration on SIGHUP"));
|
2010-03-26 14:53:32 +00:00
|
|
|
virHookCall(VIR_HOOK_DRIVER_DAEMON, "-",
|
|
|
|
VIR_HOOK_DAEMON_OP_RELOAD, SIGHUP, "SIGHUP", NULL);
|
2007-06-26 22:56:14 +00:00
|
|
|
if (virStateReload() < 0)
|
2010-05-19 10:00:18 +00:00
|
|
|
VIR_WARN0("Error while reloading drivers");
|
2010-03-26 14:53:32 +00:00
|
|
|
|
2007-02-16 18:28:17 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGINT:
|
2007-02-19 16:59:15 +00:00
|
|
|
case SIGQUIT:
|
2007-02-16 18:28:17 +00:00
|
|
|
case SIGTERM:
|
2010-05-19 10:00:18 +00:00
|
|
|
VIR_WARN("Shutting down on signal %d", siginfo.si_signo);
|
2009-10-16 15:34:37 +00:00
|
|
|
server->quitEventThread = 1;
|
2007-02-16 18:28:17 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_INFO(_("Received unexpected signal %d"), siginfo.si_signo);
|
2007-02-16 18:28:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&server->lock);
|
2007-02-16 18:28:17 +00:00
|
|
|
}
|
|
|
|
|
2007-02-16 18:30:55 +00:00
|
|
|
|
2009-10-16 11:14:54 +00:00
|
|
|
static int daemonForkIntoBackground(void) {
|
|
|
|
int statuspipe[2];
|
|
|
|
if (pipe(statuspipe) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
int pid = fork();
|
|
|
|
switch (pid) {
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
int stdinfd = -1;
|
|
|
|
int stdoutfd = -1;
|
2007-02-16 18:26:18 +00:00
|
|
|
int nextpid;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(statuspipe[0]);
|
2009-10-16 11:14:54 +00:00
|
|
|
|
2008-12-17 18:04:55 +00:00
|
|
|
if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto cleanup;
|
2008-12-17 18:04:55 +00:00
|
|
|
if ((stdoutfd = open("/dev/null", O_WRONLY)) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto cleanup;
|
|
|
|
if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
|
|
|
|
goto cleanup;
|
|
|
|
if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
|
|
|
|
goto cleanup;
|
|
|
|
if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
|
|
|
|
goto cleanup;
|
2010-11-09 20:48:48 +00:00
|
|
|
if (VIR_CLOSE(stdinfd) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto cleanup;
|
2010-11-09 20:48:48 +00:00
|
|
|
if (VIR_CLOSE(stdoutfd) < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (setsid() < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
nextpid = fork();
|
|
|
|
switch (nextpid) {
|
|
|
|
case 0:
|
2009-10-16 11:14:54 +00:00
|
|
|
return statuspipe[1];
|
2007-02-14 01:40:09 +00:00
|
|
|
case -1:
|
|
|
|
return -1;
|
|
|
|
default:
|
2008-03-11 14:22:12 +00:00
|
|
|
_exit(0);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(stdoutfd);
|
|
|
|
VIR_FORCE_CLOSE(stdinfd);
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case -1:
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2009-10-16 11:14:54 +00:00
|
|
|
int got, exitstatus = 0;
|
|
|
|
int ret;
|
|
|
|
char status;
|
|
|
|
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(statuspipe[1]);
|
2009-10-16 11:14:54 +00:00
|
|
|
|
|
|
|
/* We wait to make sure the first child forked successfully */
|
|
|
|
if ((got = waitpid(pid, &exitstatus, 0)) < 0 ||
|
2007-02-14 01:40:09 +00:00
|
|
|
got != pid ||
|
2009-10-16 11:14:54 +00:00
|
|
|
exitstatus != 0) {
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2009-10-16 11:14:54 +00:00
|
|
|
|
|
|
|
/* Now block until the second child initializes successfully */
|
|
|
|
again:
|
|
|
|
ret = read(statuspipe[0], &status, 1);
|
|
|
|
if (ret == -1 && errno == EINTR)
|
|
|
|
goto again;
|
|
|
|
|
|
|
|
if (ret == 1 && status != 0) {
|
2010-02-24 16:29:35 +00:00
|
|
|
fprintf(stderr,
|
2010-05-20 19:40:54 +00:00
|
|
|
_("%s: error: %s. Check /var/log/messages or run without "
|
|
|
|
"--daemon for more info.\n"), argv0,
|
2010-02-24 16:29:35 +00:00
|
|
|
virDaemonErrTypeToString(status));
|
2009-10-16 11:14:54 +00:00
|
|
|
}
|
|
|
|
_exit(ret == 1 && status == 0 ? 0 : 1);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-23 12:48:36 +00:00
|
|
|
static int qemudWritePidFile(const char *pidFile) {
|
|
|
|
int fd;
|
|
|
|
FILE *fh;
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
2007-02-23 12:48:36 +00:00
|
|
|
|
|
|
|
if (pidFile[0] == '\0')
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((fd = open(pidFile, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Failed to open pid file '%s' : %s"),
|
2009-02-05 16:28:03 +00:00
|
|
|
pidFile, virStrerror(errno, ebuf, sizeof ebuf));
|
2007-02-23 12:48:36 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(fh = fdopen(fd, "w"))) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Failed to fdopen pid file '%s' : %s"),
|
2009-02-05 16:28:03 +00:00
|
|
|
pidFile, virStrerror(errno, ebuf, sizeof ebuf));
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2007-02-23 12:48:36 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fprintf(fh, "%lu\n", (unsigned long)getpid()) < 0) {
|
2010-05-20 19:40:54 +00:00
|
|
|
VIR_ERROR(_("%s: Failed to write to pid file '%s' : %s"),
|
|
|
|
argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf));
|
2009-03-16 10:41:37 +00:00
|
|
|
fclose(fh);
|
2007-02-23 12:48:36 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fclose(fh) == EOF) {
|
2010-05-20 19:40:54 +00:00
|
|
|
VIR_ERROR(_("%s: Failed to close pid file '%s' : %s"),
|
|
|
|
argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf));
|
2007-02-23 12:48:36 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
static int qemudListenUnix(struct qemud_server *server,
|
2010-06-03 13:36:34 +00:00
|
|
|
char *path, int readonly, int auth) {
|
2008-06-06 10:52:01 +00:00
|
|
|
struct qemud_socket *sock;
|
2007-02-14 01:40:09 +00:00
|
|
|
mode_t oldmask;
|
2007-09-19 02:28:01 +00:00
|
|
|
gid_t oldgrp;
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-06-06 10:52:01 +00:00
|
|
|
if (VIR_ALLOC(sock) < 0) {
|
2010-05-20 06:10:38 +00:00
|
|
|
VIR_ERROR0(_("Failed to allocate memory for struct qemud_socket"));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
2007-02-16 18:30:55 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
sock->readonly = readonly;
|
2007-12-05 15:27:08 +00:00
|
|
|
sock->type = QEMUD_SOCK_TYPE_UNIX;
|
2007-12-05 15:34:05 +00:00
|
|
|
sock->auth = auth;
|
2010-06-03 13:36:34 +00:00
|
|
|
sock->path = path;
|
2010-10-21 14:45:12 +00:00
|
|
|
sock->addr.len = sizeof(sock->addr.data.un);
|
|
|
|
if (!(sock->addrstr = strdup(path))) {
|
|
|
|
VIR_ERROR(_("Failed to copy socket address: %s"),
|
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-02-16 18:30:55 +00:00
|
|
|
if ((sock->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Failed to create socket: %s"),
|
2009-02-05 16:28:03 +00:00
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
2007-06-26 19:11:00 +00:00
|
|
|
goto cleanup;
|
2007-02-16 18:30:55 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-05-12 15:43:07 +00:00
|
|
|
if (virSetCloseExec(sock->fd) < 0 ||
|
|
|
|
virSetNonBlock(sock->fd) < 0)
|
2007-06-26 19:11:00 +00:00
|
|
|
goto cleanup;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2010-10-21 14:45:12 +00:00
|
|
|
sock->addr.data.un.sun_family = AF_UNIX;
|
|
|
|
if (virStrcpyStatic(sock->addr.data.un.sun_path, path) == NULL) {
|
2009-08-03 12:37:44 +00:00
|
|
|
VIR_ERROR(_("Path %s too long for unix socket"), path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-10-21 14:45:12 +00:00
|
|
|
if (sock->addr.data.un.sun_path[0] == '@')
|
|
|
|
sock->addr.data.un.sun_path[0] = '\0';
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-09-19 02:28:01 +00:00
|
|
|
oldgrp = getgid();
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
oldmask = umask(readonly ? ~unix_sock_ro_mask : ~unix_sock_rw_mask);
|
2010-02-26 09:42:14 +00:00
|
|
|
if (server->privileged && setgid(unix_sock_gid)) {
|
|
|
|
VIR_ERROR(_("Failed to set group ID to %d"), unix_sock_gid);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-09-19 02:28:01 +00:00
|
|
|
|
2010-10-21 14:45:12 +00:00
|
|
|
if (bind(sock->fd, &sock->addr.data.sa, sock->addr.len) < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Failed to bind socket to '%s': %s"),
|
2009-02-05 16:28:03 +00:00
|
|
|
path, virStrerror(errno, ebuf, sizeof ebuf));
|
2007-06-26 19:11:00 +00:00
|
|
|
goto cleanup;
|
2007-02-16 18:30:55 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
umask(oldmask);
|
2010-02-26 09:42:14 +00:00
|
|
|
if (server->privileged && setgid(oldgrp)) {
|
|
|
|
VIR_ERROR(_("Failed to restore group ID to %d"), oldgrp);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-02-16 18:30:55 +00:00
|
|
|
if (listen(sock->fd, 30) < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Failed to listen for connections on '%s': %s"),
|
2009-02-05 16:28:03 +00:00
|
|
|
path, virStrerror(errno, ebuf, sizeof ebuf));
|
2007-06-26 19:11:00 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock->next = server->sockets;
|
|
|
|
server->sockets = sock;
|
|
|
|
server->nsockets++;
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
return 0;
|
2007-06-26 19:11:00 +00:00
|
|
|
|
|
|
|
cleanup:
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(sock->fd);
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(sock);
|
2007-06-26 19:11:00 +00:00
|
|
|
return -1;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
// See: http://people.redhat.com/drepper/userapi-ipv6.html
|
|
|
|
static int
|
2008-05-14 20:57:20 +00:00
|
|
|
remoteMakeSockets (int *fds, int max_fds, int *nfds_r, const char *node, const char *service)
|
2007-06-11 12:04:54 +00:00
|
|
|
{
|
|
|
|
struct addrinfo *ai;
|
|
|
|
struct addrinfo hints;
|
|
|
|
memset (&hints, 0, sizeof hints);
|
|
|
|
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
|
2008-05-14 20:57:20 +00:00
|
|
|
int e = getaddrinfo (node, service, &hints, &ai);
|
2007-06-11 12:04:54 +00:00
|
|
|
if (e != 0) {
|
2010-01-19 13:17:20 +00:00
|
|
|
VIR_ERROR(_("getaddrinfo: %s"), gai_strerror (e));
|
2007-06-11 12:04:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct addrinfo *runp = ai;
|
|
|
|
while (runp && *nfds_r < max_fds) {
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
2007-06-11 12:04:54 +00:00
|
|
|
fds[*nfds_r] = socket (runp->ai_family, runp->ai_socktype,
|
|
|
|
runp->ai_protocol);
|
|
|
|
if (fds[*nfds_r] == -1) {
|
2009-02-05 16:28:03 +00:00
|
|
|
VIR_ERROR(_("socket: %s"), virStrerror (errno, ebuf, sizeof ebuf));
|
2007-06-11 12:04:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int opt = 1;
|
|
|
|
setsockopt (fds[*nfds_r], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
|
|
|
|
|
2009-11-11 15:19:50 +00:00
|
|
|
#ifdef IPV6_V6ONLY
|
|
|
|
if (runp->ai_family == PF_INET6) {
|
|
|
|
int on = 1;
|
|
|
|
/*
|
|
|
|
* Normally on Linux an INET6 socket will bind to the INET4
|
|
|
|
* address too. If getaddrinfo returns results with INET4
|
|
|
|
* first though, this will result in INET6 binding failing.
|
|
|
|
* We can trivially cope with multiple server sockets, so
|
|
|
|
* we force it to only listen on IPv6
|
|
|
|
*/
|
|
|
|
setsockopt(fds[*nfds_r], IPPROTO_IPV6,IPV6_V6ONLY,
|
|
|
|
(void*)&on, sizeof on);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
if (bind (fds[*nfds_r], runp->ai_addr, runp->ai_addrlen) == -1) {
|
|
|
|
if (errno != EADDRINUSE) {
|
2009-02-05 16:28:03 +00:00
|
|
|
VIR_ERROR(_("bind: %s"), virStrerror (errno, ebuf, sizeof ebuf));
|
2007-06-11 12:04:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fds[*nfds_r]);
|
2009-10-16 10:24:01 +00:00
|
|
|
} else {
|
2007-06-11 12:04:54 +00:00
|
|
|
++*nfds_r;
|
|
|
|
}
|
|
|
|
runp = runp->ai_next;
|
|
|
|
}
|
2007-02-23 09:10:28 +00:00
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
freeaddrinfo (ai);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Listen on the named/numbered TCP port. On a machine with IPv4 and
|
|
|
|
* IPv6 interfaces this may generate several sockets.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
remoteListenTCP (struct qemud_server *server,
|
2008-05-14 21:23:02 +00:00
|
|
|
const char *addr,
|
2007-06-11 12:04:54 +00:00
|
|
|
const char *port,
|
2007-12-05 15:27:08 +00:00
|
|
|
int type,
|
2007-12-05 15:24:15 +00:00
|
|
|
int auth)
|
2007-06-11 12:04:54 +00:00
|
|
|
{
|
|
|
|
int fds[2];
|
|
|
|
int nfds = 0;
|
2007-02-23 09:10:28 +00:00
|
|
|
int i;
|
2007-06-11 12:04:54 +00:00
|
|
|
struct qemud_socket *sock;
|
|
|
|
|
2008-05-14 20:57:20 +00:00
|
|
|
if (remoteMakeSockets (fds, 2, &nfds, addr, port) == -1)
|
2007-06-11 12:04:54 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; i < nfds; ++i) {
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
2007-09-19 01:56:55 +00:00
|
|
|
|
2008-06-06 10:52:01 +00:00
|
|
|
if (VIR_ALLOC(sock) < 0) {
|
2009-02-05 16:28:03 +00:00
|
|
|
VIR_ERROR(_("remoteListenTCP: calloc: %s"),
|
|
|
|
virStrerror (errno, ebuf, sizeof ebuf));
|
2008-06-06 10:52:01 +00:00
|
|
|
goto cleanup;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
2010-10-21 14:45:12 +00:00
|
|
|
sock->addr.len = sizeof(sock->addr.data.stor);
|
2007-06-11 12:04:54 +00:00
|
|
|
sock->readonly = 0;
|
|
|
|
sock->next = server->sockets;
|
|
|
|
server->sockets = sock;
|
|
|
|
server->nsockets++;
|
|
|
|
|
|
|
|
sock->fd = fds[i];
|
2007-12-05 15:27:08 +00:00
|
|
|
sock->type = type;
|
2007-12-05 15:24:15 +00:00
|
|
|
sock->auth = auth;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2010-10-21 14:45:12 +00:00
|
|
|
if (getsockname(sock->fd, &sock->addr.data.sa, &sock->addr.len) < 0)
|
2008-06-06 10:52:01 +00:00
|
|
|
goto cleanup;
|
2007-09-19 01:56:55 +00:00
|
|
|
|
2010-10-21 14:45:12 +00:00
|
|
|
if (!(sock->addrstr = virSocketFormatAddrFull(&sock->addr, true, ";")))
|
|
|
|
goto cleanup;
|
2007-09-19 01:56:55 +00:00
|
|
|
|
2009-05-12 15:43:07 +00:00
|
|
|
if (virSetCloseExec(sock->fd) < 0 ||
|
|
|
|
virSetNonBlock(sock->fd) < 0)
|
2008-06-06 10:52:01 +00:00
|
|
|
goto cleanup;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
|
|
|
if (listen (sock->fd, 30) < 0) {
|
2009-02-05 16:28:03 +00:00
|
|
|
VIR_ERROR(_("remoteListenTCP: listen: %s"),
|
|
|
|
virStrerror (errno, ebuf, sizeof ebuf));
|
2008-06-06 10:52:01 +00:00
|
|
|
goto cleanup;
|
2007-02-20 09:04:27 +00:00
|
|
|
}
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2008-06-06 10:52:01 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
for (i = 0; i < nfds; ++i)
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fds[i]);
|
2008-06-06 10:52:01 +00:00
|
|
|
return -1;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int qemudInitPaths(struct qemud_server *server,
|
2010-06-03 13:36:34 +00:00
|
|
|
char **sockname,
|
|
|
|
char **roSockname)
|
2009-01-22 17:49:41 +00:00
|
|
|
{
|
2010-06-03 13:36:34 +00:00
|
|
|
char *base_dir_prefix = NULL;
|
2009-02-09 17:52:38 +00:00
|
|
|
char *sock_dir_prefix = NULL;
|
2010-06-03 13:36:34 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
/* The base_dir_prefix is the base under which all libvirtd
|
|
|
|
* files live */
|
|
|
|
if (server->privileged) {
|
|
|
|
if (!(base_dir_prefix = strdup (LOCAL_STATE_DIR)))
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
|
|
|
uid_t uid = geteuid();
|
|
|
|
if (!(base_dir_prefix = virGetUserDirectory(uid)))
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-02-09 17:52:38 +00:00
|
|
|
|
2010-06-03 13:36:34 +00:00
|
|
|
/* The unix_sock_dir is the location under which all
|
|
|
|
* unix domain sockets live */
|
2009-10-16 10:29:01 +00:00
|
|
|
if (unix_sock_dir) {
|
2010-06-03 13:36:34 +00:00
|
|
|
if (!(sock_dir_prefix = strdup(unix_sock_dir)))
|
|
|
|
goto no_memory;
|
|
|
|
|
2009-10-16 10:29:01 +00:00
|
|
|
/* Change the group ownership of /var/run/libvirt to unix_sock_gid */
|
|
|
|
if (server->privileged) {
|
|
|
|
if (chown(unix_sock_dir, -1, unix_sock_gid) < 0)
|
|
|
|
VIR_ERROR(_("Failed to change group ownership of %s"),
|
|
|
|
unix_sock_dir);
|
|
|
|
}
|
|
|
|
} else {
|
2009-06-12 13:20:13 +00:00
|
|
|
if (server->privileged) {
|
2010-06-03 13:36:34 +00:00
|
|
|
if (virAsprintf(&sock_dir_prefix, "%s/run/libvirt",
|
|
|
|
base_dir_prefix) < 0)
|
|
|
|
goto no_memory;
|
2009-02-09 17:52:38 +00:00
|
|
|
} else {
|
2010-06-03 13:36:34 +00:00
|
|
|
if (virAsprintf(&sock_dir_prefix, "%s/.libvirt",
|
|
|
|
base_dir_prefix) < 0)
|
|
|
|
goto no_memory;
|
2009-02-09 17:52:38 +00:00
|
|
|
}
|
|
|
|
}
|
2007-02-16 18:30:55 +00:00
|
|
|
|
2009-06-12 13:20:13 +00:00
|
|
|
if (server->privileged) {
|
2010-06-03 13:36:34 +00:00
|
|
|
if (virAsprintf(sockname, "%s/libvirt-sock",
|
|
|
|
sock_dir_prefix) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
if (virAsprintf(roSockname, "%s/libvirt-sock-ro",
|
|
|
|
sock_dir_prefix) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
unlink(*sockname);
|
|
|
|
unlink(*roSockname);
|
2007-02-14 01:40:09 +00:00
|
|
|
} else {
|
2010-06-03 13:36:34 +00:00
|
|
|
if (virAsprintf(sockname, "@%s/libvirt-sock",
|
|
|
|
sock_dir_prefix) < 0)
|
|
|
|
goto no_memory;
|
|
|
|
/* There is no RO socket in unprivileged mode,
|
|
|
|
* since the user always has full RW access
|
|
|
|
* to their private instance */
|
2009-02-09 17:52:38 +00:00
|
|
|
}
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-10-16 10:09:13 +00:00
|
|
|
if (server->privileged) {
|
2010-06-03 13:36:34 +00:00
|
|
|
if (virAsprintf(&server->logDir, "%s/log/libvirt",
|
|
|
|
base_dir_prefix) < 0)
|
|
|
|
goto no_memory;
|
2009-10-16 10:09:13 +00:00
|
|
|
} else {
|
2010-06-03 13:36:34 +00:00
|
|
|
if (virAsprintf(&server->logDir, "%s/.libvirt/log",
|
|
|
|
base_dir_prefix) < 0)
|
|
|
|
goto no_memory;
|
2009-10-16 10:09:13 +00:00
|
|
|
}
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-02-09 17:52:38 +00:00
|
|
|
ret = 0;
|
2007-02-16 18:30:55 +00:00
|
|
|
|
2010-06-03 13:36:34 +00:00
|
|
|
no_memory:
|
|
|
|
if (ret != 0)
|
|
|
|
virReportOOMError();
|
2009-02-09 17:52:38 +00:00
|
|
|
|
|
|
|
cleanup:
|
2010-06-03 13:36:34 +00:00
|
|
|
VIR_FREE(base_dir_prefix);
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(sock_dir_prefix);
|
2009-02-09 17:52:38 +00:00
|
|
|
return ret;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2009-10-19 17:28:28 +00:00
|
|
|
static void virshErrorHandler(void *opaque ATTRIBUTE_UNUSED, virErrorPtr err ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
/* Don't do anything, since logging infrastructure already
|
|
|
|
* took care of reporting the error */
|
|
|
|
}
|
|
|
|
|
2009-10-16 10:48:50 +00:00
|
|
|
static struct qemud_server *qemudInitialize(void) {
|
2007-02-14 01:40:09 +00:00
|
|
|
struct qemud_server *server;
|
|
|
|
|
2008-06-06 10:52:01 +00:00
|
|
|
if (VIR_ALLOC(server) < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR0(_("Failed to allocate struct qemud_server"));
|
2007-02-14 01:40:09 +00:00
|
|
|
return NULL;
|
2007-02-16 18:30:55 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-10-16 10:48:50 +00:00
|
|
|
server->privileged = geteuid() == 0 ? 1 : 0;
|
|
|
|
server->sigread = server->sigwrite = -1;
|
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
if (virMutexInit(&server->lock) < 0) {
|
2010-05-20 06:10:38 +00:00
|
|
|
VIR_ERROR0(_("cannot initialize mutex"));
|
2009-01-15 19:56:05 +00:00
|
|
|
VIR_FREE(server);
|
2009-10-16 10:48:50 +00:00
|
|
|
return NULL;
|
2009-01-15 19:56:05 +00:00
|
|
|
}
|
|
|
|
if (virCondInit(&server->job) < 0) {
|
2010-05-20 06:10:38 +00:00
|
|
|
VIR_ERROR0(_("cannot initialize condition variable"));
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexDestroy(&server->lock);
|
2008-12-04 22:16:40 +00:00
|
|
|
VIR_FREE(server);
|
2009-10-16 10:48:50 +00:00
|
|
|
return NULL;
|
2008-12-04 22:16:40 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 22:14:15 +00:00
|
|
|
if (virEventInit() < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR0(_("Failed to initialize event system"));
|
2009-10-16 10:48:50 +00:00
|
|
|
virMutexDestroy(&server->lock);
|
|
|
|
if (virCondDestroy(&server->job) < 0)
|
|
|
|
{}
|
2008-12-04 22:14:15 +00:00
|
|
|
VIR_FREE(server);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-12-02 11:37:55 +00:00
|
|
|
/*
|
|
|
|
* Note that the order is important: the first ones have a higher
|
|
|
|
* priority when calling virStateInitialize. We must register
|
|
|
|
* the network, storage and nodedev drivers before any domain
|
|
|
|
* drivers, since their resources must be auto-started before
|
|
|
|
* any domains can be auto-started.
|
|
|
|
*/
|
2008-11-21 12:16:08 +00:00
|
|
|
#ifdef WITH_DRIVER_MODULES
|
|
|
|
/* We don't care if any of these fail, because the whole point
|
|
|
|
* is to allow users to only install modules they want to use.
|
2009-10-26 23:02:46 +00:00
|
|
|
* If they try to open a connection for a module that
|
2008-11-21 12:16:08 +00:00
|
|
|
* is not loaded they'll get a suitable error at that point
|
|
|
|
*/
|
|
|
|
virDriverLoadModule("network");
|
|
|
|
virDriverLoadModule("storage");
|
2008-11-21 12:27:11 +00:00
|
|
|
virDriverLoadModule("nodedev");
|
2009-08-14 19:48:55 +00:00
|
|
|
virDriverLoadModule("secret");
|
2008-12-02 11:37:55 +00:00
|
|
|
virDriverLoadModule("qemu");
|
|
|
|
virDriverLoadModule("lxc");
|
|
|
|
virDriverLoadModule("uml");
|
2009-05-25 11:56:00 +00:00
|
|
|
virDriverLoadModule("one");
|
2010-03-25 17:46:09 +00:00
|
|
|
virDriverLoadModule("nwfilter");
|
2008-11-21 12:16:08 +00:00
|
|
|
#else
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifdef WITH_NETWORK
|
2008-11-17 12:18:18 +00:00
|
|
|
networkRegister();
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
|
|
|
# ifdef WITH_NETCF
|
2009-07-21 14:02:16 +00:00
|
|
|
interfaceRegister();
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
|
|
|
# ifdef WITH_STORAGE_DIR
|
2008-11-17 12:18:18 +00:00
|
|
|
storageRegister();
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
|
|
|
# if defined(WITH_NODE_DEVICES)
|
2008-11-21 12:27:11 +00:00
|
|
|
nodedevRegister();
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
|
|
|
# ifdef WITH_SECRETS
|
2009-08-14 19:48:55 +00:00
|
|
|
secretRegister();
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
2010-03-25 17:46:09 +00:00
|
|
|
# ifdef WITH_NWFILTER
|
|
|
|
nwfilterRegister();
|
|
|
|
# endif
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifdef WITH_QEMU
|
2008-12-02 11:37:55 +00:00
|
|
|
qemuRegister();
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
|
|
|
# ifdef WITH_LXC
|
2008-12-02 11:37:55 +00:00
|
|
|
lxcRegister();
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
|
|
|
# ifdef WITH_UML
|
2008-12-02 11:37:55 +00:00
|
|
|
umlRegister();
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
|
|
|
# ifdef WITH_ONE
|
2009-05-25 11:56:00 +00:00
|
|
|
oneRegister();
|
2010-03-09 18:22:22 +00:00
|
|
|
# endif
|
2008-11-17 12:18:18 +00:00
|
|
|
#endif
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
virEventRegisterImpl(virEventAddHandleImpl,
|
|
|
|
virEventUpdateHandleImpl,
|
|
|
|
virEventRemoveHandleImpl,
|
|
|
|
virEventAddTimeoutImpl,
|
|
|
|
virEventUpdateTimeoutImpl,
|
|
|
|
virEventRemoveTimeoutImpl);
|
2007-06-26 23:48:46 +00:00
|
|
|
|
2007-12-05 15:34:05 +00:00
|
|
|
return server;
|
|
|
|
}
|
|
|
|
|
2009-10-16 10:24:01 +00:00
|
|
|
static int qemudNetworkInit(struct qemud_server *server) {
|
2010-06-03 13:36:34 +00:00
|
|
|
char *sockname = NULL;
|
|
|
|
char *roSockname = NULL;
|
2007-12-05 15:24:15 +00:00
|
|
|
#if HAVE_SASL
|
2007-12-05 15:34:05 +00:00
|
|
|
int err;
|
|
|
|
#endif /* HAVE_SASL */
|
|
|
|
|
2010-06-03 13:36:34 +00:00
|
|
|
if (qemudInitPaths(server, &sockname, &roSockname) < 0)
|
2007-12-05 15:34:05 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (qemudListenUnix(server, sockname, 0, auth_unix_rw) < 0)
|
2007-12-05 15:24:15 +00:00
|
|
|
goto cleanup;
|
2010-06-03 13:36:34 +00:00
|
|
|
sockname = NULL;
|
2007-12-05 15:34:05 +00:00
|
|
|
|
2010-06-03 13:36:34 +00:00
|
|
|
if (roSockname != NULL && qemudListenUnix(server, roSockname, 1, auth_unix_ro) < 0)
|
2007-12-05 15:34:05 +00:00
|
|
|
goto cleanup;
|
2010-06-03 13:36:34 +00:00
|
|
|
roSockname = NULL;
|
2007-12-05 15:34:05 +00:00
|
|
|
|
|
|
|
#if HAVE_SASL
|
|
|
|
if (auth_unix_rw == REMOTE_AUTH_SASL ||
|
|
|
|
auth_unix_ro == REMOTE_AUTH_SASL ||
|
|
|
|
auth_tcp == REMOTE_AUTH_SASL ||
|
|
|
|
auth_tls == REMOTE_AUTH_SASL) {
|
|
|
|
if ((err = sasl_server_init(NULL, "libvirt")) != SASL_OK) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Failed to initialize SASL authentication %s"),
|
|
|
|
sasl_errstring(err, NULL, NULL));
|
2007-12-05 15:34:05 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-12-05 15:24:15 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-08-06 12:54:08 +00:00
|
|
|
#if HAVE_POLKIT0
|
2007-12-05 18:21:27 +00:00
|
|
|
if (auth_unix_rw == REMOTE_AUTH_POLKIT ||
|
|
|
|
auth_unix_ro == REMOTE_AUTH_POLKIT) {
|
|
|
|
DBusError derr;
|
2009-03-02 11:13:37 +00:00
|
|
|
|
|
|
|
dbus_connection_set_change_sigpipe(FALSE);
|
|
|
|
dbus_threads_init_default();
|
|
|
|
|
2007-12-05 18:21:27 +00:00
|
|
|
dbus_error_init(&derr);
|
|
|
|
server->sysbus = dbus_bus_get(DBUS_BUS_SYSTEM, &derr);
|
|
|
|
if (!(server->sysbus)) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Failed to connect to system bus for PolicyKit auth: %s"),
|
|
|
|
derr.message);
|
2007-12-05 18:21:27 +00:00
|
|
|
dbus_error_free(&derr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-03-02 11:13:37 +00:00
|
|
|
dbus_connection_set_exit_on_disconnect(server->sysbus, FALSE);
|
2007-12-05 18:21:27 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-06-26 23:48:46 +00:00
|
|
|
if (ipsock) {
|
2008-05-14 20:57:20 +00:00
|
|
|
if (listen_tcp && remoteListenTCP (server, listen_addr, tcp_port, QEMUD_SOCK_TYPE_TCP, auth_tcp) < 0)
|
2007-06-11 12:04:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (listen_tls) {
|
|
|
|
if (remoteInitializeGnuTLS () < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2008-05-14 20:57:20 +00:00
|
|
|
if (remoteListenTCP (server, listen_addr, tls_port, QEMUD_SOCK_TYPE_TLS, auth_tls) < 0)
|
2007-06-11 12:04:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-09-19 01:56:55 +00:00
|
|
|
#ifdef HAVE_AVAHI
|
2009-06-12 13:20:13 +00:00
|
|
|
if (server->privileged && mdns_adv) {
|
2007-09-19 01:56:55 +00:00
|
|
|
struct libvirtd_mdns_group *group;
|
2009-10-16 10:24:01 +00:00
|
|
|
struct qemud_socket *sock;
|
2007-09-19 01:56:55 +00:00
|
|
|
int port = 0;
|
2010-03-23 13:01:37 +00:00
|
|
|
int ret;
|
2007-09-19 01:56:55 +00:00
|
|
|
|
|
|
|
server->mdns = libvirtd_mdns_new();
|
|
|
|
|
|
|
|
if (!mdns_name) {
|
2010-03-23 13:01:37 +00:00
|
|
|
char *groupname, *localhost, *tmp;
|
|
|
|
|
2009-10-23 17:01:22 +00:00
|
|
|
localhost = virGetHostname(NULL);
|
|
|
|
if (localhost == NULL)
|
2010-03-23 13:01:37 +00:00
|
|
|
/* we couldn't resolve the hostname; assume that we are
|
|
|
|
* running in disconnected operation, and report a less
|
|
|
|
* useful Avahi string
|
|
|
|
*/
|
|
|
|
ret = virAsprintf(&groupname, "Virtualization Host");
|
|
|
|
else {
|
|
|
|
/* Extract the host part of the potentially FQDN */
|
|
|
|
if ((tmp = strchr(localhost, '.')))
|
|
|
|
*tmp = '\0';
|
|
|
|
ret = virAsprintf(&groupname, "Virtualization Host %s",
|
|
|
|
localhost);
|
|
|
|
}
|
|
|
|
VIR_FREE(localhost);
|
|
|
|
if (ret < 0) {
|
|
|
|
virReportOOMError();
|
2009-10-23 10:05:01 +00:00
|
|
|
goto cleanup;
|
2010-03-23 13:01:37 +00:00
|
|
|
}
|
2007-09-19 01:56:55 +00:00
|
|
|
group = libvirtd_mdns_add_group(server->mdns, groupname);
|
2010-03-23 13:01:37 +00:00
|
|
|
VIR_FREE(groupname);
|
2007-09-19 01:56:55 +00:00
|
|
|
} else {
|
|
|
|
group = libvirtd_mdns_add_group(server->mdns, mdns_name);
|
|
|
|
}
|
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
/*
|
2007-09-19 01:56:55 +00:00
|
|
|
* See if there's a TLS enabled port we can advertise. Cowardly
|
|
|
|
* don't bother to advertise TCP since we don't want people using
|
|
|
|
* them for real world apps
|
|
|
|
*/
|
|
|
|
sock = server->sockets;
|
|
|
|
while (sock) {
|
2010-10-21 14:45:12 +00:00
|
|
|
if (virSocketGetPort(&sock->addr) != -1 &&
|
|
|
|
sock->type == QEMUD_SOCK_TYPE_TLS) {
|
|
|
|
port = virSocketGetPort(&sock->addr);
|
2007-09-19 01:56:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
sock = sock->next;
|
|
|
|
}
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
|
2007-09-19 01:56:55 +00:00
|
|
|
/*
|
|
|
|
* Add the primary entry - we choose SSH because its most likely to always
|
|
|
|
* be available
|
|
|
|
*/
|
|
|
|
libvirtd_mdns_add_entry(group, "_libvirt._tcp", port);
|
|
|
|
libvirtd_mdns_start(server->mdns);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-10-16 10:24:01 +00:00
|
|
|
return 0;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
cleanup:
|
2010-06-03 13:36:34 +00:00
|
|
|
VIR_FREE(sockname);
|
|
|
|
VIR_FREE(roSockname);
|
2009-10-16 10:24:01 +00:00
|
|
|
return -1;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2009-10-16 15:34:37 +00:00
|
|
|
static int qemudNetworkEnable(struct qemud_server *server) {
|
|
|
|
struct qemud_socket *sock;
|
|
|
|
|
|
|
|
sock = server->sockets;
|
|
|
|
while (sock) {
|
|
|
|
if ((sock->watch = virEventAddHandleImpl(sock->fd,
|
|
|
|
VIR_EVENT_HANDLE_READABLE |
|
|
|
|
VIR_EVENT_HANDLE_ERROR |
|
|
|
|
VIR_EVENT_HANDLE_HANGUP,
|
|
|
|
qemudDispatchServerEvent,
|
|
|
|
server, NULL)) < 0) {
|
|
|
|
VIR_ERROR0(_("Failed to add server event callback"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock = sock->next;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2009-10-16 10:24:01 +00:00
|
|
|
|
2010-06-03 13:36:34 +00:00
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
static gnutls_session_t
|
|
|
|
remoteInitializeTLSSession (void)
|
|
|
|
{
|
|
|
|
gnutls_session_t session;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = gnutls_init (&session, GNUTLS_SERVER);
|
|
|
|
if (err != 0) goto failed;
|
|
|
|
|
|
|
|
/* avoid calling all the priority functions, since the defaults
|
|
|
|
* are adequate.
|
|
|
|
*/
|
|
|
|
err = gnutls_set_default_priority (session);
|
|
|
|
if (err != 0) goto failed;
|
|
|
|
|
|
|
|
err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
|
|
|
|
if (err != 0) goto failed;
|
|
|
|
|
|
|
|
/* request client certificate if any.
|
|
|
|
*/
|
|
|
|
gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
|
|
|
|
|
|
|
|
gnutls_dh_set_prime_bits (session, DH_BITS);
|
|
|
|
|
|
|
|
return session;
|
|
|
|
|
|
|
|
failed:
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("remoteInitializeTLSSession: %s"),
|
2007-06-11 12:04:54 +00:00
|
|
|
gnutls_strerror (err));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check DN is on tls_allowed_dn_list. */
|
|
|
|
static int
|
2010-09-14 16:50:25 +00:00
|
|
|
remoteCheckDN (const char *dname)
|
2007-06-11 12:04:54 +00:00
|
|
|
{
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
char **wildcards;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
|
|
|
/* If the list is not set, allow any DN. */
|
|
|
|
wildcards = tls_allowed_dn_list;
|
|
|
|
if (!wildcards)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
while (*wildcards) {
|
2010-09-14 16:50:25 +00:00
|
|
|
if (fnmatch (*wildcards, dname, 0) == 0)
|
2007-06-11 12:04:54 +00:00
|
|
|
return 1;
|
|
|
|
wildcards++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print the client's DN. */
|
2010-09-14 16:50:25 +00:00
|
|
|
DEBUG(_("remoteCheckDN: failed: client DN is %s"), dname);
|
2007-06-11 12:04:54 +00:00
|
|
|
|
|
|
|
return 0; // Not found.
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2010-09-14 16:50:25 +00:00
|
|
|
remoteCheckCertificate(struct qemud_client *client)
|
2007-06-11 12:04:54 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
unsigned int status;
|
|
|
|
const gnutls_datum_t *certs;
|
|
|
|
unsigned int nCerts, i;
|
|
|
|
time_t now;
|
2010-09-14 16:50:25 +00:00
|
|
|
char name[256];
|
|
|
|
size_t namesize = sizeof name;
|
|
|
|
|
|
|
|
memset(name, 0, namesize);
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2010-09-14 16:50:25 +00:00
|
|
|
if ((ret = gnutls_certificate_verify_peers2 (client->tlssession, &status)) < 0){
|
|
|
|
VIR_ERROR(_("Failed to verify certificate peers: %s"),
|
2007-06-11 12:04:54 +00:00
|
|
|
gnutls_strerror (ret));
|
2010-09-14 16:50:25 +00:00
|
|
|
goto authdeny;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (status != 0) {
|
|
|
|
if (status & GNUTLS_CERT_INVALID)
|
2010-09-14 16:50:25 +00:00
|
|
|
VIR_ERROR0(_("The client certificate is not trusted."));
|
2007-06-11 12:04:54 +00:00
|
|
|
|
|
|
|
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
|
2010-09-14 16:50:25 +00:00
|
|
|
VIR_ERROR0(_("The client certificate has unknown issuer."));
|
2007-06-11 12:04:54 +00:00
|
|
|
|
|
|
|
if (status & GNUTLS_CERT_REVOKED)
|
2010-09-14 16:50:25 +00:00
|
|
|
VIR_ERROR0(_("The client certificate has been revoked."));
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2007-08-07 13:02:35 +00:00
|
|
|
#ifndef GNUTLS_1_0_COMPAT
|
2007-06-11 12:04:54 +00:00
|
|
|
if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
|
2010-09-14 16:50:25 +00:00
|
|
|
VIR_ERROR0(_("The client certificate uses an insecure algorithm."));
|
2007-08-07 13:02:35 +00:00
|
|
|
#endif
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2010-09-14 16:50:25 +00:00
|
|
|
goto authdeny;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
2010-09-14 16:50:25 +00:00
|
|
|
if (gnutls_certificate_type_get(client->tlssession) != GNUTLS_CRT_X509) {
|
|
|
|
VIR_ERROR0(_("Only x509 certificates are supported"));
|
|
|
|
goto authdeny;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
2010-09-14 16:50:25 +00:00
|
|
|
if (!(certs = gnutls_certificate_get_peers(client->tlssession, &nCerts))) {
|
|
|
|
VIR_ERROR0(_("The certificate has no peers"));
|
|
|
|
goto authdeny;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
now = time (NULL);
|
|
|
|
|
|
|
|
for (i = 0; i < nCerts; i++) {
|
|
|
|
gnutls_x509_crt_t cert;
|
|
|
|
|
|
|
|
if (gnutls_x509_crt_init (&cert) < 0) {
|
2010-09-14 16:50:25 +00:00
|
|
|
VIR_ERROR0(_("Unable to initialize certificate"));
|
|
|
|
goto authfail;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
|
2010-09-14 16:50:25 +00:00
|
|
|
VIR_ERROR0(_("Unable to load certificate"));
|
2007-06-11 12:04:54 +00:00
|
|
|
gnutls_x509_crt_deinit (cert);
|
2010-09-14 16:50:25 +00:00
|
|
|
goto authfail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
ret = gnutls_x509_crt_get_dn (cert, name, &namesize);
|
|
|
|
if (ret != 0) {
|
|
|
|
VIR_ERROR(_("Failed to get certificate distinguished name: %s"),
|
|
|
|
gnutls_strerror(ret));
|
|
|
|
gnutls_x509_crt_deinit (cert);
|
|
|
|
goto authfail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!remoteCheckDN (name)) {
|
|
|
|
/* This is the most common error: make it informative. */
|
|
|
|
VIR_ERROR0(_("Client's Distinguished Name is not on the list "
|
|
|
|
"of allowed clients (tls_allowed_dn_list). Use "
|
|
|
|
"'certtool -i --infile clientcert.pem' to view the"
|
|
|
|
"Distinguished Name field in the client certificate,"
|
|
|
|
"or run this daemon with --verbose option."));
|
|
|
|
gnutls_x509_crt_deinit (cert);
|
|
|
|
goto authdeny;
|
|
|
|
}
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
if (gnutls_x509_crt_get_expiration_time (cert) < now) {
|
2010-09-14 16:50:25 +00:00
|
|
|
VIR_ERROR0(_("The client certificate has expired"));
|
2007-06-11 12:04:54 +00:00
|
|
|
gnutls_x509_crt_deinit (cert);
|
2010-09-14 16:50:25 +00:00
|
|
|
goto authdeny;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
if (gnutls_x509_crt_get_activation_time (cert) > now) {
|
2010-09-14 16:50:25 +00:00
|
|
|
VIR_ERROR0(_("The client certificate is not yet active"));
|
2007-06-11 12:04:54 +00:00
|
|
|
gnutls_x509_crt_deinit (cert);
|
2010-09-14 16:50:25 +00:00
|
|
|
goto authdeny;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-22 21:36:42 +00:00
|
|
|
PROBE(CLIENT_TLS_ALLOW, "fd=%d, name=%s", client->fd, (char *)name);
|
2007-06-11 12:04:54 +00:00
|
|
|
return 0;
|
2010-09-14 16:50:25 +00:00
|
|
|
|
|
|
|
authdeny:
|
2010-10-22 21:36:42 +00:00
|
|
|
PROBE(CLIENT_TLS_DENY, "fd=%d, name=%s", client->fd, (char *)name);
|
2010-09-14 16:50:25 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
authfail:
|
Add dtrace static probes in libvirtd
Adds initial support for dtrace static probes in libvirtd
daemon, assuming use of systemtap dtrace compat shim on
Linux. The probes are inserted for network client connect,
disconnect, TLS handshake states and authentication protocol
states.
This can be tested by running the xample program and then
attempting to connect with any libvirt client (virsh,
virt-manager, etc).
# stap examples/systemtap/client.stp
Client fd=44 connected readonly=0
Client fd=44 auth polkit deny pid:24997,uid:500
Client fd=44 disconnected
Client fd=46 connected readonly=1
Client fd=46 auth sasl allow test
Client fd=46 disconnected
The libvirtd.stp file should also really not be required,
since it is duplicated info that is already available in
the main probes.d definition file. A script to autogenerate
the .stp file is needed, either in libvirtd tree, or better
as part of systemtap itself.
* Makefile.am: Add examples/systemtap subdir
* autobuild.sh: Disable dtrace for mingw32
* configure.ac: Add check for dtrace
* daemon/.gitignore: Ignore generated dtrace probe file
* daemon/Makefile.am: Build dtrace probe header & object
files
* daemon/libvirtd.stp: SystemTAP convenience probeset
* daemon/libvirtd.c: Add connect/disconnect & TLS probes
* daemon/remote.c: Add SASL and PolicyKit auth probes
* daemon/probes.d: Master probe definition
* daemon/libvirtd.h: Add convenience macro for probes
so that compilation is a no-op when dtrace is not available
* examples/systemtap/Makefile.am, examples/systemtap/client.stp
Example systemtap script using dtrace probe markers
* libvirt.spec.in: Enable dtrace on F13/RHEL6
* mingw32-libvirt.spec.in: Force disable dtrace
2010-09-14 16:30:32 +00:00
|
|
|
PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd);
|
2010-09-14 16:50:25 +00:00
|
|
|
return -1;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the client's access. */
|
|
|
|
static int
|
|
|
|
remoteCheckAccess (struct qemud_client *client)
|
|
|
|
{
|
2009-01-20 19:25:15 +00:00
|
|
|
struct qemud_client_message *confirm;
|
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
/* Verify client certificate. */
|
2010-09-14 16:50:25 +00:00
|
|
|
if (remoteCheckCertificate (client) == -1) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR0(_("remoteCheckCertificate: "
|
|
|
|
"failed to verify client's certificate"));
|
2007-06-11 12:04:54 +00:00
|
|
|
if (!tls_no_verify_certificate) return -1;
|
2009-01-06 18:32:03 +00:00
|
|
|
else VIR_INFO0(_("remoteCheckCertificate: tls_no_verify_certificate "
|
|
|
|
"is set so the bad certificate is ignored"));
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
if (client->tx) {
|
|
|
|
VIR_INFO("%s",
|
|
|
|
_("client had unexpected data pending tx after access check"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(confirm) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
/* Checks have succeeded. Write a '\1' byte back to the client to
|
|
|
|
* indicate this (otherwise the socket is abruptly closed).
|
|
|
|
* (NB. The '\1' byte is sent in an encrypted record).
|
|
|
|
*/
|
2009-01-20 19:25:15 +00:00
|
|
|
confirm->async = 1;
|
|
|
|
confirm->bufferLength = 1;
|
|
|
|
confirm->bufferOffset = 0;
|
|
|
|
confirm->buffer[0] = '\1';
|
|
|
|
|
|
|
|
client->tx = confirm;
|
2007-06-11 12:04:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-04-04 15:09:19 +00:00
|
|
|
#if HAVE_POLKIT
|
|
|
|
int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid) {
|
2010-03-09 18:22:22 +00:00
|
|
|
# ifdef SO_PEERCRED
|
2008-04-04 15:09:19 +00:00
|
|
|
struct ucred cr;
|
|
|
|
unsigned int cr_len = sizeof (cr);
|
|
|
|
|
|
|
|
if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) < 0) {
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Failed to verify client credentials: %s"),
|
2009-02-05 16:28:03 +00:00
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
2008-04-04 15:09:19 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pid = cr.pid;
|
|
|
|
*uid = cr.uid;
|
2010-03-09 18:22:22 +00:00
|
|
|
# else
|
2008-04-04 15:09:19 +00:00
|
|
|
/* XXX Many more OS support UNIX socket credentials we could port to. See dbus ....*/
|
2010-03-09 18:22:22 +00:00
|
|
|
# error "UNIX socket credentials not supported/implemented on this platform yet..."
|
|
|
|
# endif
|
2008-04-04 15:09:19 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket *sock) {
|
|
|
|
int fd;
|
2010-10-21 14:45:12 +00:00
|
|
|
virSocketAddr addr;
|
|
|
|
char *addrstr = NULL;
|
2010-09-14 16:50:25 +00:00
|
|
|
struct qemud_client *client = NULL;
|
2007-06-11 12:04:54 +00:00
|
|
|
int no_slow_start = 1;
|
Remote driver & daemon impl of new event API
This wires up the remote driver to handle the new events APIs.
The public API allows an application to request a callback filters
events to a specific domain object, and register multiple callbacks
for the same event type. On the wire there are two strategies for
this
- Register multiple callbacks with the remote daemon, each
with filtering as needed
- Register only one callback per event type, with no filtering
Both approaches have potential inefficiency. In the first scheme,
the same event gets sent over the wire many times if multiple
callbacks are registered. With the second scheme, unneccessary
events get sent over the wire if a per-domain filter is set on
the client. The second scheme is far easier to implement though,
so this patch takes that approach.
* daemon/dispatch.h: Don't export remoteRelayDomainEvent since it
is no longer needed for unregistering callbacks, instead the
unique callback ID is used
* daemon/libvirtd.c, daemon/libvirtd.h: Track and unregister
callbacks based on callback ID, instead of function pointer
* daemon/remote.c: Switch over to using virConnectDomainEventRegisterAny
instead of legacy virConnectDomainEventRegister function. Refactor
remoteDispatchDomainEventSend() to cope with arbitrary event types
* src/driver.h, src/driver.c: Move verify() call into source file
instead of header, to avoid polluting the global namespace with
the verify function name
* src/remote/remote_driver.c: Implement new APIs for event
registration. Refactor processCallDispatchMessage() to cope
with arbitrary incoming event types. Merge remoteDomainQueueEvent()
into processCallDispatchMessage() to avoid duplication of code.
Rename remoteDomainReadEvent() to remoteDomainReadEventLifecycle()
* src/remote/remote_protocol.x: Define wire format for the new
virConnectDomainEventRegisterAny and virConnectDomainEventDeregisterAny
functions
2010-03-18 14:56:56 +00:00
|
|
|
int i;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2010-10-21 14:45:12 +00:00
|
|
|
addr.len = sizeof(addr.data.stor);
|
|
|
|
if ((fd = accept(sock->fd, &addr.data.sa, &addr.len)) < 0) {
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
2007-02-14 01:40:09 +00:00
|
|
|
if (errno == EAGAIN)
|
|
|
|
return 0;
|
2009-02-05 16:28:03 +00:00
|
|
|
VIR_ERROR(_("Failed to accept connection: %s"),
|
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2010-10-21 14:45:12 +00:00
|
|
|
if (!(addrstr = virSocketFormatAddrFull(&addr, true, ";"))) {
|
|
|
|
VIR_ERROR0(_("Failed to format addresss: out of memory"));
|
|
|
|
goto error;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2010-10-21 14:45:12 +00:00
|
|
|
PROBE(CLIENT_CONNECT, "fd=%d, readonly=%d localAddr=%s remoteAddr=%s",
|
|
|
|
fd, sock->readonly, sock->addrstr, addrstr);
|
Add dtrace static probes in libvirtd
Adds initial support for dtrace static probes in libvirtd
daemon, assuming use of systemtap dtrace compat shim on
Linux. The probes are inserted for network client connect,
disconnect, TLS handshake states and authentication protocol
states.
This can be tested by running the xample program and then
attempting to connect with any libvirt client (virsh,
virt-manager, etc).
# stap examples/systemtap/client.stp
Client fd=44 connected readonly=0
Client fd=44 auth polkit deny pid:24997,uid:500
Client fd=44 disconnected
Client fd=46 connected readonly=1
Client fd=46 auth sasl allow test
Client fd=46 disconnected
The libvirtd.stp file should also really not be required,
since it is duplicated info that is already available in
the main probes.d definition file. A script to autogenerate
the .stp file is needed, either in libvirtd tree, or better
as part of systemtap itself.
* Makefile.am: Add examples/systemtap subdir
* autobuild.sh: Disable dtrace for mingw32
* configure.ac: Add check for dtrace
* daemon/.gitignore: Ignore generated dtrace probe file
* daemon/Makefile.am: Build dtrace probe header & object
files
* daemon/libvirtd.stp: SystemTAP convenience probeset
* daemon/libvirtd.c: Add connect/disconnect & TLS probes
* daemon/remote.c: Add SASL and PolicyKit auth probes
* daemon/probes.d: Master probe definition
* daemon/libvirtd.h: Add convenience macro for probes
so that compilation is a no-op when dtrace is not available
* examples/systemtap/Makefile.am, examples/systemtap/client.stp
Example systemtap script using dtrace probe markers
* libvirt.spec.in: Enable dtrace on F13/RHEL6
* mingw32-libvirt.spec.in: Force disable dtrace
2010-09-14 16:30:32 +00:00
|
|
|
|
2008-12-04 22:18:44 +00:00
|
|
|
if (server->nclients >= max_clients) {
|
2010-10-21 14:45:12 +00:00
|
|
|
VIR_ERROR(_("Too many active clients (%d), dropping connection from %s"),
|
|
|
|
max_clients, addrstr);
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2008-12-04 22:18:44 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 22:09:35 +00:00
|
|
|
if (VIR_REALLOC_N(server->clients, server->nclients+1) < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR0(_("Out of memory allocating clients"));
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2008-12-04 22:09:35 +00:00
|
|
|
}
|
|
|
|
|
2009-01-22 17:49:41 +00:00
|
|
|
#ifdef __sun
|
|
|
|
{
|
|
|
|
ucred_t *ucred = NULL;
|
|
|
|
const priv_set_t *privs;
|
|
|
|
|
|
|
|
if (getpeerucred (fd, &ucred) == -1 ||
|
|
|
|
(privs = ucred_getprivset (ucred, PRIV_EFFECTIVE)) == NULL) {
|
|
|
|
if (ucred != NULL)
|
|
|
|
ucred_free (ucred);
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2009-01-22 17:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!priv_ismember (privs, PRIV_VIRT_MANAGE)) {
|
|
|
|
ucred_free (ucred);
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2009-01-22 17:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ucred_free (ucred);
|
|
|
|
}
|
|
|
|
#endif /* __sun */
|
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
/* Disable Nagle. Unix sockets will ignore this. */
|
|
|
|
setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
|
|
|
|
sizeof no_slow_start);
|
|
|
|
|
2009-05-12 15:43:07 +00:00
|
|
|
if (virSetCloseExec(fd) < 0 ||
|
|
|
|
virSetNonBlock(fd) < 0) {
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2008-06-06 10:52:01 +00:00
|
|
|
if (VIR_ALLOC(client) < 0)
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2009-01-15 19:56:05 +00:00
|
|
|
if (virMutexInit(&client->lock) < 0) {
|
2010-05-20 06:10:38 +00:00
|
|
|
VIR_ERROR0(_("cannot initialize mutex"));
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2009-01-15 19:56:05 +00:00
|
|
|
}
|
2008-12-04 22:16:40 +00:00
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
client->magic = QEMUD_CLIENT_MAGIC;
|
2007-02-14 01:40:09 +00:00
|
|
|
client->fd = fd;
|
|
|
|
client->readonly = sock->readonly;
|
2007-12-05 15:27:08 +00:00
|
|
|
client->type = sock->type;
|
2007-12-05 15:24:15 +00:00
|
|
|
client->auth = sock->auth;
|
2010-10-21 14:45:12 +00:00
|
|
|
client->addr = addr;
|
|
|
|
client->addrstr = addrstr;
|
|
|
|
addrstr = NULL;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
Remote driver & daemon impl of new event API
This wires up the remote driver to handle the new events APIs.
The public API allows an application to request a callback filters
events to a specific domain object, and register multiple callbacks
for the same event type. On the wire there are two strategies for
this
- Register multiple callbacks with the remote daemon, each
with filtering as needed
- Register only one callback per event type, with no filtering
Both approaches have potential inefficiency. In the first scheme,
the same event gets sent over the wire many times if multiple
callbacks are registered. With the second scheme, unneccessary
events get sent over the wire if a per-domain filter is set on
the client. The second scheme is far easier to implement though,
so this patch takes that approach.
* daemon/dispatch.h: Don't export remoteRelayDomainEvent since it
is no longer needed for unregistering callbacks, instead the
unique callback ID is used
* daemon/libvirtd.c, daemon/libvirtd.h: Track and unregister
callbacks based on callback ID, instead of function pointer
* daemon/remote.c: Switch over to using virConnectDomainEventRegisterAny
instead of legacy virConnectDomainEventRegister function. Refactor
remoteDispatchDomainEventSend() to cope with arbitrary event types
* src/driver.h, src/driver.c: Move verify() call into source file
instead of header, to avoid polluting the global namespace with
the verify function name
* src/remote/remote_driver.c: Implement new APIs for event
registration. Refactor processCallDispatchMessage() to cope
with arbitrary incoming event types. Merge remoteDomainQueueEvent()
into processCallDispatchMessage() to avoid duplication of code.
Rename remoteDomainReadEvent() to remoteDomainReadEventLifecycle()
* src/remote/remote_protocol.x: Define wire format for the new
virConnectDomainEventRegisterAny and virConnectDomainEventDeregisterAny
functions
2010-03-18 14:56:56 +00:00
|
|
|
for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
|
|
|
|
client->domainEventCallbackID[i] = -1;
|
|
|
|
}
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Prepare one for packet receive */
|
|
|
|
if (VIR_ALLOC(client->rx) < 0)
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2009-01-20 19:25:15 +00:00
|
|
|
client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
|
|
|
|
|
|
|
|
|
2008-04-04 15:09:19 +00:00
|
|
|
#if HAVE_POLKIT
|
|
|
|
/* Only do policy checks for non-root - allow root user
|
|
|
|
through with no checks, as a fail-safe - root can easily
|
|
|
|
change policykit policy anyway, so its pointless trying
|
|
|
|
to restrict root */
|
|
|
|
if (client->auth == REMOTE_AUTH_POLKIT) {
|
|
|
|
uid_t uid;
|
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
if (qemudGetSocketIdentity(client->fd, &uid, &pid) < 0)
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2008-04-04 15:09:19 +00:00
|
|
|
|
2008-05-15 06:12:32 +00:00
|
|
|
/* Client is running as root, so disable auth */
|
2008-04-04 15:09:19 +00:00
|
|
|
if (uid == 0) {
|
2010-10-21 14:45:12 +00:00
|
|
|
VIR_INFO(_("Turn off polkit auth for privileged client pid %d from %s"),
|
|
|
|
pid, addrstr);
|
2008-04-04 15:09:19 +00:00
|
|
|
client->auth = REMOTE_AUTH_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-12-05 15:27:08 +00:00
|
|
|
if (client->type != QEMUD_SOCK_TYPE_TLS) {
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Plain socket, so prepare to read first message */
|
2009-07-10 11:48:50 +00:00
|
|
|
if (qemudRegisterClientEvent (server, client) < 0)
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2007-06-11 12:04:54 +00:00
|
|
|
} else {
|
|
|
|
int ret;
|
|
|
|
|
2007-12-05 15:27:08 +00:00
|
|
|
client->tlssession = remoteInitializeTLSSession ();
|
|
|
|
if (client->tlssession == NULL)
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2007-12-05 15:27:08 +00:00
|
|
|
gnutls_transport_set_ptr (client->tlssession,
|
2007-06-11 12:04:54 +00:00
|
|
|
(gnutls_transport_ptr_t) (long) fd);
|
|
|
|
|
|
|
|
/* Begin the TLS handshake. */
|
2007-12-05 15:27:08 +00:00
|
|
|
ret = gnutls_handshake (client->tlssession);
|
2007-06-11 12:04:54 +00:00
|
|
|
if (ret == 0) {
|
2009-03-03 08:25:50 +00:00
|
|
|
client->handshake = 0;
|
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
/* Unlikely, but ... Next step is to check the certificate. */
|
|
|
|
if (remoteCheckAccess (client) == -1)
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2007-06-26 19:11:00 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Handshake & cert check OK, so prepare to read first message */
|
2009-07-10 11:48:50 +00:00
|
|
|
if (qemudRegisterClientEvent(server, client) < 0)
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2007-06-11 12:04:54 +00:00
|
|
|
} else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Most likely, need to do more handshake data */
|
|
|
|
client->handshake = 1;
|
2007-06-26 19:11:00 +00:00
|
|
|
|
2009-07-10 11:48:50 +00:00
|
|
|
if (qemudRegisterClientEvent (server, client) < 0)
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2007-06-11 12:04:54 +00:00
|
|
|
} else {
|
Add dtrace static probes in libvirtd
Adds initial support for dtrace static probes in libvirtd
daemon, assuming use of systemtap dtrace compat shim on
Linux. The probes are inserted for network client connect,
disconnect, TLS handshake states and authentication protocol
states.
This can be tested by running the xample program and then
attempting to connect with any libvirt client (virsh,
virt-manager, etc).
# stap examples/systemtap/client.stp
Client fd=44 connected readonly=0
Client fd=44 auth polkit deny pid:24997,uid:500
Client fd=44 disconnected
Client fd=46 connected readonly=1
Client fd=46 auth sasl allow test
Client fd=46 disconnected
The libvirtd.stp file should also really not be required,
since it is duplicated info that is already available in
the main probes.d definition file. A script to autogenerate
the .stp file is needed, either in libvirtd tree, or better
as part of systemtap itself.
* Makefile.am: Add examples/systemtap subdir
* autobuild.sh: Disable dtrace for mingw32
* configure.ac: Add check for dtrace
* daemon/.gitignore: Ignore generated dtrace probe file
* daemon/Makefile.am: Build dtrace probe header & object
files
* daemon/libvirtd.stp: SystemTAP convenience probeset
* daemon/libvirtd.c: Add connect/disconnect & TLS probes
* daemon/remote.c: Add SASL and PolicyKit auth probes
* daemon/probes.d: Master probe definition
* daemon/libvirtd.h: Add convenience macro for probes
so that compilation is a no-op when dtrace is not available
* examples/systemtap/Makefile.am, examples/systemtap/client.stp
Example systemtap script using dtrace probe markers
* libvirt.spec.in: Enable dtrace on F13/RHEL6
* mingw32-libvirt.spec.in: Force disable dtrace
2010-09-14 16:30:32 +00:00
|
|
|
PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd);
|
2010-10-21 14:45:12 +00:00
|
|
|
VIR_ERROR(_("TLS handshake failed for client %s: %s"),
|
|
|
|
addrstr, gnutls_strerror (ret));
|
2010-09-14 16:50:25 +00:00
|
|
|
goto error;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-12-04 22:09:35 +00:00
|
|
|
server->clients[server->nclients++] = client;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-01-20 19:27:11 +00:00
|
|
|
if (server->nclients > server->nactiveworkers &&
|
|
|
|
server->nactiveworkers < server->nworkers) {
|
|
|
|
for (i = 0 ; i < server->nworkers ; i++) {
|
|
|
|
if (!server->workers[i].hasThread) {
|
|
|
|
if (qemudStartWorker(server, &server->workers[i]) < 0)
|
|
|
|
return -1;
|
|
|
|
server->nactiveworkers++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
return 0;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2010-09-14 16:50:25 +00:00
|
|
|
error:
|
|
|
|
if (client) {
|
|
|
|
if (client->tlssession) gnutls_deinit (client->tlssession);
|
2010-10-21 14:45:12 +00:00
|
|
|
if (client) {
|
|
|
|
VIR_FREE(client->addrstr);
|
2010-09-14 16:50:25 +00:00
|
|
|
VIR_FREE(client->rx);
|
2010-10-21 14:45:12 +00:00
|
|
|
}
|
2010-09-14 16:50:25 +00:00
|
|
|
VIR_FREE(client);
|
|
|
|
}
|
2010-10-21 14:45:12 +00:00
|
|
|
VIR_FREE(addrstr);
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
Add dtrace static probes in libvirtd
Adds initial support for dtrace static probes in libvirtd
daemon, assuming use of systemtap dtrace compat shim on
Linux. The probes are inserted for network client connect,
disconnect, TLS handshake states and authentication protocol
states.
This can be tested by running the xample program and then
attempting to connect with any libvirt client (virsh,
virt-manager, etc).
# stap examples/systemtap/client.stp
Client fd=44 connected readonly=0
Client fd=44 auth polkit deny pid:24997,uid:500
Client fd=44 disconnected
Client fd=46 connected readonly=1
Client fd=46 auth sasl allow test
Client fd=46 disconnected
The libvirtd.stp file should also really not be required,
since it is duplicated info that is already available in
the main probes.d definition file. A script to autogenerate
the .stp file is needed, either in libvirtd tree, or better
as part of systemtap itself.
* Makefile.am: Add examples/systemtap subdir
* autobuild.sh: Disable dtrace for mingw32
* configure.ac: Add check for dtrace
* daemon/.gitignore: Ignore generated dtrace probe file
* daemon/Makefile.am: Build dtrace probe header & object
files
* daemon/libvirtd.stp: SystemTAP convenience probeset
* daemon/libvirtd.c: Add connect/disconnect & TLS probes
* daemon/remote.c: Add SASL and PolicyKit auth probes
* daemon/probes.d: Master probe definition
* daemon/libvirtd.h: Add convenience macro for probes
so that compilation is a no-op when dtrace is not available
* examples/systemtap/Makefile.am, examples/systemtap/client.stp
Example systemtap script using dtrace probe markers
* libvirt.spec.in: Enable dtrace on F13/RHEL6
* mingw32-libvirt.spec.in: Force disable dtrace
2010-09-14 16:30:32 +00:00
|
|
|
PROBE(CLIENT_DISCONNECT, "fd=%d", fd);
|
2007-06-11 12:04:54 +00:00
|
|
|
return -1;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-04 22:16:40 +00:00
|
|
|
/*
|
|
|
|
* You must hold lock for at least the client
|
|
|
|
* We don't free stuff here, merely disconnect the client's
|
|
|
|
* network socket & resources.
|
|
|
|
* We keep the libvirt connection open until any async
|
|
|
|
* jobs have finished, then clean it up elsehwere
|
|
|
|
*/
|
2009-01-20 19:25:15 +00:00
|
|
|
void qemudDispatchClientFailure(struct qemud_client *client) {
|
2009-05-29 14:34:35 +00:00
|
|
|
if (client->watch != -1) {
|
|
|
|
virEventRemoveHandleImpl(client->watch);
|
|
|
|
client->watch = -1;
|
|
|
|
}
|
2007-06-26 19:11:00 +00:00
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
/* Deregister event delivery callback */
|
Remote driver & daemon impl of new event API
This wires up the remote driver to handle the new events APIs.
The public API allows an application to request a callback filters
events to a specific domain object, and register multiple callbacks
for the same event type. On the wire there are two strategies for
this
- Register multiple callbacks with the remote daemon, each
with filtering as needed
- Register only one callback per event type, with no filtering
Both approaches have potential inefficiency. In the first scheme,
the same event gets sent over the wire many times if multiple
callbacks are registered. With the second scheme, unneccessary
events get sent over the wire if a per-domain filter is set on
the client. The second scheme is far easier to implement though,
so this patch takes that approach.
* daemon/dispatch.h: Don't export remoteRelayDomainEvent since it
is no longer needed for unregistering callbacks, instead the
unique callback ID is used
* daemon/libvirtd.c, daemon/libvirtd.h: Track and unregister
callbacks based on callback ID, instead of function pointer
* daemon/remote.c: Switch over to using virConnectDomainEventRegisterAny
instead of legacy virConnectDomainEventRegister function. Refactor
remoteDispatchDomainEventSend() to cope with arbitrary event types
* src/driver.h, src/driver.c: Move verify() call into source file
instead of header, to avoid polluting the global namespace with
the verify function name
* src/remote/remote_driver.c: Implement new APIs for event
registration. Refactor processCallDispatchMessage() to cope
with arbitrary incoming event types. Merge remoteDomainQueueEvent()
into processCallDispatchMessage() to avoid duplication of code.
Rename remoteDomainReadEvent() to remoteDomainReadEventLifecycle()
* src/remote/remote_protocol.x: Define wire format for the new
virConnectDomainEventRegisterAny and virConnectDomainEventDeregisterAny
functions
2010-03-18 14:56:56 +00:00
|
|
|
if (client->conn) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
|
|
|
|
if (client->domainEventCallbackID[i] != -1) {
|
|
|
|
DEBUG("Deregistering to relay remote events %d", i);
|
|
|
|
virConnectDomainEventDeregisterAny(client->conn,
|
|
|
|
client->domainEventCallbackID[i]);
|
|
|
|
}
|
|
|
|
client->domainEventCallbackID[i] = -1;
|
|
|
|
}
|
2008-10-23 13:18:18 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 15:24:15 +00:00
|
|
|
#if HAVE_SASL
|
2009-05-29 14:34:35 +00:00
|
|
|
if (client->saslconn) {
|
|
|
|
sasl_dispose(&client->saslconn);
|
|
|
|
client->saslconn = NULL;
|
|
|
|
}
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(client->saslUsername);
|
2007-12-05 15:24:15 +00:00
|
|
|
#endif
|
2009-05-29 14:34:35 +00:00
|
|
|
if (client->tlssession) {
|
|
|
|
gnutls_deinit (client->tlssession);
|
|
|
|
client->tlssession = NULL;
|
|
|
|
}
|
|
|
|
if (client->fd != -1) {
|
Add dtrace static probes in libvirtd
Adds initial support for dtrace static probes in libvirtd
daemon, assuming use of systemtap dtrace compat shim on
Linux. The probes are inserted for network client connect,
disconnect, TLS handshake states and authentication protocol
states.
This can be tested by running the xample program and then
attempting to connect with any libvirt client (virsh,
virt-manager, etc).
# stap examples/systemtap/client.stp
Client fd=44 connected readonly=0
Client fd=44 auth polkit deny pid:24997,uid:500
Client fd=44 disconnected
Client fd=46 connected readonly=1
Client fd=46 auth sasl allow test
Client fd=46 disconnected
The libvirtd.stp file should also really not be required,
since it is duplicated info that is already available in
the main probes.d definition file. A script to autogenerate
the .stp file is needed, either in libvirtd tree, or better
as part of systemtap itself.
* Makefile.am: Add examples/systemtap subdir
* autobuild.sh: Disable dtrace for mingw32
* configure.ac: Add check for dtrace
* daemon/.gitignore: Ignore generated dtrace probe file
* daemon/Makefile.am: Build dtrace probe header & object
files
* daemon/libvirtd.stp: SystemTAP convenience probeset
* daemon/libvirtd.c: Add connect/disconnect & TLS probes
* daemon/remote.c: Add SASL and PolicyKit auth probes
* daemon/probes.d: Master probe definition
* daemon/libvirtd.h: Add convenience macro for probes
so that compilation is a no-op when dtrace is not available
* examples/systemtap/Makefile.am, examples/systemtap/client.stp
Example systemtap script using dtrace probe markers
* libvirt.spec.in: Enable dtrace on F13/RHEL6
* mingw32-libvirt.spec.in: Force disable dtrace
2010-09-14 16:30:32 +00:00
|
|
|
PROBE(CLIENT_DISCONNECT, "fd=%d", client->fd);
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(client->fd);
|
2009-05-29 14:34:35 +00:00
|
|
|
}
|
2010-10-21 14:45:12 +00:00
|
|
|
VIR_FREE(client->addrstr);
|
2008-12-04 22:16:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Caller must hold server lock */
|
|
|
|
static struct qemud_client *qemudPendingJob(struct qemud_server *server)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0 ; i < server->nclients ; i++) {
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&server->clients[i]->lock);
|
2009-01-20 19:25:15 +00:00
|
|
|
if (server->clients[i]->dx) {
|
2008-12-04 22:16:40 +00:00
|
|
|
/* Delibrately don't unlock client - caller wants the lock */
|
|
|
|
return server->clients[i];
|
|
|
|
}
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&server->clients[i]->lock);
|
2008-12-04 22:16:40 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2008-12-04 22:16:40 +00:00
|
|
|
static void *qemudWorker(void *data)
|
|
|
|
{
|
2009-01-20 19:27:11 +00:00
|
|
|
struct qemud_worker *worker = data;
|
|
|
|
struct qemud_server *server = worker->server;
|
2008-12-04 22:16:40 +00:00
|
|
|
|
|
|
|
while (1) {
|
2009-01-20 19:25:15 +00:00
|
|
|
struct qemud_client *client = NULL;
|
2009-07-10 11:45:37 +00:00
|
|
|
struct qemud_client_message *msg;
|
2009-01-20 19:25:15 +00:00
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&server->lock);
|
2010-03-01 18:59:43 +00:00
|
|
|
while ((client = qemudPendingJob(server)) == NULL) {
|
|
|
|
if (worker->quitRequest ||
|
|
|
|
virCondWait(&server->job, &server->lock) < 0) {
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&server->lock);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2009-01-20 19:27:11 +00:00
|
|
|
if (worker->quitRequest) {
|
2010-03-01 18:59:43 +00:00
|
|
|
virMutexUnlock(&client->lock);
|
2009-01-20 19:27:11 +00:00
|
|
|
virMutexUnlock(&server->lock);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
worker->processingCall = 1;
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&server->lock);
|
2008-12-04 22:16:40 +00:00
|
|
|
|
|
|
|
/* We own a locked client now... */
|
|
|
|
client->refs++;
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Remove our message from dispatch queue while we use it */
|
2009-07-10 11:45:37 +00:00
|
|
|
msg = qemudClientMessageQueueServe(&client->dx);
|
2009-01-20 19:25:15 +00:00
|
|
|
|
|
|
|
/* This function drops the lock during dispatch,
|
|
|
|
* and re-acquires it before returning */
|
2009-07-10 11:58:22 +00:00
|
|
|
if (remoteDispatchClientRequest (server, client, msg) < 0) {
|
2009-07-10 11:45:37 +00:00
|
|
|
VIR_FREE(msg);
|
2009-01-20 19:25:15 +00:00
|
|
|
qemudDispatchClientFailure(client);
|
|
|
|
client->refs--;
|
|
|
|
virMutexUnlock(&client->lock);
|
|
|
|
continue;
|
|
|
|
}
|
2008-12-04 22:16:40 +00:00
|
|
|
|
|
|
|
client->refs--;
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&client->lock);
|
2009-01-20 19:27:11 +00:00
|
|
|
|
|
|
|
virMutexLock(&server->lock);
|
|
|
|
worker->processingCall = 0;
|
|
|
|
virMutexUnlock(&server->lock);
|
2008-12-04 22:16:40 +00:00
|
|
|
}
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-01-20 19:27:11 +00:00
|
|
|
static int qemudStartWorker(struct qemud_server *server,
|
|
|
|
struct qemud_worker *worker) {
|
|
|
|
pthread_attr_t attr;
|
|
|
|
pthread_attr_init(&attr);
|
|
|
|
/* We want to join workers, so don't detach them */
|
|
|
|
/*pthread_attr_setdetachstate(&attr, 1);*/
|
|
|
|
|
|
|
|
if (worker->hasThread)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
worker->server = server;
|
|
|
|
worker->hasThread = 1;
|
|
|
|
worker->quitRequest = 0;
|
|
|
|
worker->processingCall = 0;
|
|
|
|
|
|
|
|
if (pthread_create(&worker->thread,
|
|
|
|
&attr,
|
|
|
|
qemudWorker,
|
|
|
|
worker) != 0) {
|
|
|
|
worker->hasThread = 0;
|
|
|
|
worker->server = NULL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/*
|
|
|
|
* Read data into buffer using wire decoding (plain or TLS)
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* -1 on error or EOF
|
|
|
|
* 0 on EAGAIN
|
|
|
|
* n number of bytes
|
|
|
|
*/
|
|
|
|
static ssize_t qemudClientReadBuf(struct qemud_client *client,
|
|
|
|
char *data, ssize_t len) {
|
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
if (len < 0) {
|
2009-01-28 11:31:39 +00:00
|
|
|
VIR_ERROR(_("unexpected negative length request %lld"),
|
|
|
|
(long long int) len);
|
2009-01-20 19:25:15 +00:00
|
|
|
qemudDispatchClientFailure(client);
|
|
|
|
return -1;
|
|
|
|
}
|
2007-06-11 12:04:54 +00:00
|
|
|
|
|
|
|
/*qemudDebug ("qemudClientRead: len = %d", len);*/
|
|
|
|
|
2007-12-05 15:27:08 +00:00
|
|
|
if (!client->tlssession) {
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
2009-01-20 19:25:15 +00:00
|
|
|
ret = read (client->fd, data, len);
|
|
|
|
if (ret == -1 && (errno == EAGAIN ||
|
|
|
|
errno == EINTR))
|
|
|
|
return 0;
|
|
|
|
if (ret <= 0) {
|
|
|
|
if (ret != 0)
|
2009-02-05 16:28:03 +00:00
|
|
|
VIR_ERROR(_("read: %s"),
|
|
|
|
virStrerror (errno, ebuf, sizeof ebuf));
|
2009-01-20 19:25:15 +00:00
|
|
|
qemudDispatchClientFailure(client);
|
2007-06-11 12:04:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
2007-12-05 15:27:08 +00:00
|
|
|
ret = gnutls_record_recv (client->tlssession, data, len);
|
2009-01-20 19:25:15 +00:00
|
|
|
|
|
|
|
if (ret < 0 && (ret == GNUTLS_E_AGAIN ||
|
|
|
|
ret == GNUTLS_E_INTERRUPTED))
|
|
|
|
return 0;
|
|
|
|
if (ret <= 0) {
|
|
|
|
if (ret != 0)
|
|
|
|
VIR_ERROR(_("gnutls_record_recv: %s"),
|
|
|
|
gnutls_strerror (ret));
|
|
|
|
qemudDispatchClientFailure(client);
|
2007-06-11 12:04:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2007-12-05 15:27:08 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/*
|
|
|
|
* Read data into buffer without decoding
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* -1 on error or EOF
|
|
|
|
* 0 on EAGAIN
|
|
|
|
* n number of bytes
|
|
|
|
*/
|
|
|
|
static ssize_t qemudClientReadPlain(struct qemud_client *client) {
|
|
|
|
ssize_t ret;
|
|
|
|
ret = qemudClientReadBuf(client,
|
|
|
|
client->rx->buffer + client->rx->bufferOffset,
|
|
|
|
client->rx->bufferLength - client->rx->bufferOffset);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret; /* -1 error, 0 eagain */
|
|
|
|
|
|
|
|
client->rx->bufferOffset += ret;
|
|
|
|
return ret;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 15:27:08 +00:00
|
|
|
#if HAVE_SASL
|
2009-01-20 19:25:15 +00:00
|
|
|
/*
|
|
|
|
* Read data into buffer decoding with SASL
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* -1 on error or EOF
|
|
|
|
* 0 on EAGAIN
|
|
|
|
* n number of bytes
|
|
|
|
*/
|
|
|
|
static ssize_t qemudClientReadSASL(struct qemud_client *client) {
|
|
|
|
ssize_t got, want;
|
2007-12-05 15:27:08 +00:00
|
|
|
|
|
|
|
/* We're doing a SSF data read, so now its times to ensure
|
|
|
|
* future writes are under SSF too.
|
|
|
|
*
|
|
|
|
* cf remoteSASLCheckSSF in remote.c
|
|
|
|
*/
|
|
|
|
client->saslSSF |= QEMUD_SASL_SSF_WRITE;
|
|
|
|
|
|
|
|
/* Need to read some more data off the wire */
|
|
|
|
if (client->saslDecoded == NULL) {
|
2009-01-20 19:25:15 +00:00
|
|
|
int ret;
|
2007-12-05 15:27:08 +00:00
|
|
|
char encoded[8192];
|
2009-01-20 19:25:15 +00:00
|
|
|
ssize_t encodedLen = sizeof(encoded);
|
|
|
|
encodedLen = qemudClientReadBuf(client, encoded, encodedLen);
|
|
|
|
|
|
|
|
if (encodedLen <= 0)
|
|
|
|
return encodedLen;
|
|
|
|
|
|
|
|
ret = sasl_decode(client->saslconn, encoded, encodedLen,
|
|
|
|
&client->saslDecoded, &client->saslDecodedLength);
|
|
|
|
if (ret != SASL_OK) {
|
|
|
|
VIR_ERROR(_("failed to decode SASL data %s"),
|
|
|
|
sasl_errstring(ret, NULL, NULL));
|
|
|
|
qemudDispatchClientFailure(client);
|
2007-12-05 15:27:08 +00:00
|
|
|
return -1;
|
2009-01-20 19:25:15 +00:00
|
|
|
}
|
2007-12-05 15:27:08 +00:00
|
|
|
|
|
|
|
client->saslDecodedOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Some buffered decoded data to return now */
|
|
|
|
got = client->saslDecodedLength - client->saslDecodedOffset;
|
2009-01-20 19:25:15 +00:00
|
|
|
want = client->rx->bufferLength - client->rx->bufferOffset;
|
2007-12-05 15:27:08 +00:00
|
|
|
|
|
|
|
if (want > got)
|
|
|
|
want = got;
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
memcpy(client->rx->buffer + client->rx->bufferOffset,
|
2007-12-05 15:27:08 +00:00
|
|
|
client->saslDecoded + client->saslDecodedOffset, want);
|
|
|
|
client->saslDecodedOffset += want;
|
2009-01-20 19:25:15 +00:00
|
|
|
client->rx->bufferOffset += want;
|
2007-12-05 15:27:08 +00:00
|
|
|
|
|
|
|
if (client->saslDecodedOffset == client->saslDecodedLength) {
|
|
|
|
client->saslDecoded = NULL;
|
|
|
|
client->saslDecodedOffset = client->saslDecodedLength = 0;
|
|
|
|
}
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
return want;
|
2007-12-05 15:27:08 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/*
|
|
|
|
* Read as much data off wire as possible till we fill our
|
|
|
|
* buffer, or would block on I/O
|
|
|
|
*/
|
|
|
|
static ssize_t qemudClientRead(struct qemud_client *client) {
|
2007-12-05 15:27:08 +00:00
|
|
|
#if HAVE_SASL
|
|
|
|
if (client->saslSSF & QEMUD_SASL_SSF_READ)
|
2009-01-20 19:25:15 +00:00
|
|
|
return qemudClientReadSASL(client);
|
2007-12-05 15:27:08 +00:00
|
|
|
else
|
|
|
|
#endif
|
2009-01-20 19:25:15 +00:00
|
|
|
return qemudClientReadPlain(client);
|
2007-12-05 15:27:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/*
|
|
|
|
* Read data until we get a complete message to process
|
|
|
|
*/
|
|
|
|
static void qemudDispatchClientRead(struct qemud_server *server,
|
|
|
|
struct qemud_client *client) {
|
2007-06-11 12:04:54 +00:00
|
|
|
/*qemudDebug ("qemudDispatchClientRead: mode = %d", client->mode);*/
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
readmore:
|
|
|
|
if (qemudClientRead(client) < 0)
|
|
|
|
return; /* Error */
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
if (client->rx->bufferOffset < client->rx->bufferLength)
|
|
|
|
return; /* Still not read enough */
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Either done with length word header */
|
|
|
|
if (client->rx->bufferLength == REMOTE_MESSAGE_HEADER_XDR_LEN) {
|
|
|
|
unsigned int len;
|
|
|
|
XDR x;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
xdrmem_create(&x, client->rx->buffer, client->rx->bufferLength, XDR_DECODE);
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2007-11-17 11:17:48 +00:00
|
|
|
if (!xdr_u_int(&x, &len)) {
|
|
|
|
xdr_destroy (&x);
|
2008-12-22 12:53:26 +00:00
|
|
|
DEBUG0("Failed to decode packet length");
|
2009-01-20 19:25:15 +00:00
|
|
|
qemudDispatchClientFailure(client);
|
2007-02-14 01:40:09 +00:00
|
|
|
return;
|
|
|
|
}
|
2007-11-17 11:17:48 +00:00
|
|
|
xdr_destroy (&x);
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) {
|
|
|
|
DEBUG("Packet length %u too small", len);
|
|
|
|
qemudDispatchClientFailure(client);
|
2007-06-11 12:04:54 +00:00
|
|
|
return;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Length includes the size of the length word itself */
|
|
|
|
len -= REMOTE_MESSAGE_HEADER_XDR_LEN;
|
|
|
|
|
|
|
|
if (len > REMOTE_MESSAGE_MAX) {
|
|
|
|
DEBUG("Packet length %u too large", len);
|
|
|
|
qemudDispatchClientFailure(client);
|
2007-06-11 12:04:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Prepare to read rest of message */
|
|
|
|
client->rx->bufferLength += len;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-07-10 11:48:50 +00:00
|
|
|
qemudUpdateClientEvent(client);
|
2007-06-26 19:11:00 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Try and read payload immediately instead of going back
|
|
|
|
into poll() because chances are the data is already
|
|
|
|
waiting for us */
|
|
|
|
goto readmore;
|
|
|
|
} else {
|
2009-07-10 11:58:22 +00:00
|
|
|
/* Grab the completed message */
|
|
|
|
struct qemud_client_message *msg = qemudClientMessageQueueServe(&client->rx);
|
|
|
|
struct qemud_client_filter *filter;
|
|
|
|
|
|
|
|
/* Decode the header so we can use it for routing decisions */
|
|
|
|
if (remoteDecodeClientMessageHeader(msg) < 0) {
|
|
|
|
VIR_FREE(msg);
|
|
|
|
qemudDispatchClientFailure(client);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if any filters match this message */
|
|
|
|
filter = client->filters;
|
|
|
|
while (filter) {
|
2009-07-10 12:06:36 +00:00
|
|
|
int ret;
|
|
|
|
ret = (filter->query)(client, msg, filter->opaque);
|
|
|
|
if (ret == 1) {
|
2009-07-10 11:58:22 +00:00
|
|
|
msg = NULL;
|
|
|
|
break;
|
2009-07-10 12:06:36 +00:00
|
|
|
} else if (ret == -1) {
|
|
|
|
VIR_FREE(msg);
|
|
|
|
qemudDispatchClientFailure(client);
|
|
|
|
return;
|
2009-07-10 11:58:22 +00:00
|
|
|
}
|
|
|
|
filter = filter->next;
|
|
|
|
}
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Move completed message to the end of the dispatch queue */
|
2009-07-10 11:58:22 +00:00
|
|
|
if (msg)
|
|
|
|
qemudClientMessageQueuePush(&client->dx, msg);
|
2009-01-20 19:25:15 +00:00
|
|
|
client->nrequests++;
|
|
|
|
|
|
|
|
/* Possibly need to create another receive buffer */
|
|
|
|
if ((client->nrequests < max_client_requests &&
|
|
|
|
VIR_ALLOC(client->rx) < 0)) {
|
|
|
|
qemudDispatchClientFailure(client);
|
2007-06-26 19:11:00 +00:00
|
|
|
} else {
|
2009-01-20 19:25:15 +00:00
|
|
|
if (client->rx)
|
|
|
|
client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
|
|
|
|
|
2009-07-10 11:48:50 +00:00
|
|
|
qemudUpdateClientEvent(client);
|
|
|
|
|
|
|
|
/* Tell one of the workers to get on with it... */
|
|
|
|
virCondSignal(&server->job);
|
2007-06-26 19:11:00 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/*
|
|
|
|
* Send a chunk of data using wire encoding (plain or TLS)
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* -1 on error
|
|
|
|
* 0 on EAGAIN
|
|
|
|
* n number of bytes
|
|
|
|
*/
|
|
|
|
static ssize_t qemudClientWriteBuf(struct qemud_client *client,
|
|
|
|
const char *data, ssize_t len) {
|
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
if (len < 0) {
|
2009-01-28 11:31:39 +00:00
|
|
|
VIR_ERROR(_("unexpected negative length request %lld"),
|
|
|
|
(long long int) len);
|
2009-01-20 19:25:15 +00:00
|
|
|
qemudDispatchClientFailure(client);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-12-05 15:27:08 +00:00
|
|
|
if (!client->tlssession) {
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
2009-01-20 19:25:15 +00:00
|
|
|
if ((ret = write(client->fd, data, len)) == -1) {
|
|
|
|
if (errno == EAGAIN || errno == EINTR)
|
|
|
|
return 0;
|
2009-02-05 16:28:03 +00:00
|
|
|
VIR_ERROR(_("write: %s"), virStrerror (errno, ebuf, sizeof ebuf));
|
2009-01-20 19:25:15 +00:00
|
|
|
qemudDispatchClientFailure(client);
|
2007-06-11 12:04:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
2007-12-05 15:27:08 +00:00
|
|
|
ret = gnutls_record_send (client->tlssession, data, len);
|
2009-01-20 19:25:15 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
if (ret == GNUTLS_E_INTERRUPTED ||
|
|
|
|
ret == GNUTLS_E_AGAIN)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
VIR_ERROR(_("gnutls_record_send: %s"), gnutls_strerror (ret));
|
|
|
|
qemudDispatchClientFailure(client);
|
2007-06-11 12:04:54 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2007-12-05 15:27:08 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2007-12-05 15:27:08 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/*
|
|
|
|
* Send client->tx using no encoding
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* -1 on error or EOF
|
|
|
|
* 0 on EAGAIN
|
|
|
|
* n number of bytes
|
|
|
|
*/
|
|
|
|
static int qemudClientWritePlain(struct qemud_client *client) {
|
|
|
|
int ret = qemudClientWriteBuf(client,
|
|
|
|
client->tx->buffer + client->tx->bufferOffset,
|
|
|
|
client->tx->bufferLength - client->tx->bufferOffset);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret; /* -1 error, 0 = egain */
|
|
|
|
client->tx->bufferOffset += ret;
|
|
|
|
return ret;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-12-05 15:27:08 +00:00
|
|
|
#if HAVE_SASL
|
2009-01-20 19:25:15 +00:00
|
|
|
/*
|
|
|
|
* Send client->tx using SASL encoding
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* -1 on error
|
|
|
|
* 0 on EAGAIN
|
|
|
|
* n number of bytes
|
|
|
|
*/
|
|
|
|
static int qemudClientWriteSASL(struct qemud_client *client) {
|
2007-12-05 15:27:08 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Not got any pending encoded data, so we need to encode raw stuff */
|
|
|
|
if (client->saslEncoded == NULL) {
|
2009-01-20 19:25:15 +00:00
|
|
|
ret = sasl_encode(client->saslconn,
|
|
|
|
client->tx->buffer + client->tx->bufferOffset,
|
|
|
|
client->tx->bufferLength - client->tx->bufferOffset,
|
2007-12-05 15:27:08 +00:00
|
|
|
&client->saslEncoded,
|
|
|
|
&client->saslEncodedLength);
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
if (ret != SASL_OK) {
|
|
|
|
VIR_ERROR(_("failed to encode SASL data %s"),
|
|
|
|
sasl_errstring(ret, NULL, NULL));
|
|
|
|
qemudDispatchClientFailure(client);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-12-05 15:27:08 +00:00
|
|
|
client->saslEncodedOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send some of the encoded stuff out on the wire */
|
2009-01-20 19:25:15 +00:00
|
|
|
ret = qemudClientWriteBuf(client,
|
2007-12-05 15:27:08 +00:00
|
|
|
client->saslEncoded + client->saslEncodedOffset,
|
|
|
|
client->saslEncodedLength - client->saslEncodedOffset);
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
if (ret <= 0)
|
|
|
|
return ret; /* -1 error, 0 == egain */
|
2007-12-05 15:27:08 +00:00
|
|
|
|
|
|
|
/* Note how much we sent */
|
|
|
|
client->saslEncodedOffset += ret;
|
|
|
|
|
|
|
|
/* Sent all encoded, so update raw buffer to indicate completion */
|
|
|
|
if (client->saslEncodedOffset == client->saslEncodedLength) {
|
|
|
|
client->saslEncoded = NULL;
|
|
|
|
client->saslEncodedOffset = client->saslEncodedLength = 0;
|
2009-01-20 19:25:15 +00:00
|
|
|
|
|
|
|
/* Mark as complete, so caller detects completion */
|
|
|
|
client->tx->bufferOffset = client->tx->bufferLength;
|
2007-12-05 15:27:08 +00:00
|
|
|
}
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
return ret;
|
2007-12-05 15:27:08 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/*
|
|
|
|
* Send as much data in the client->tx as possible
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* -1 on error or EOF
|
|
|
|
* 0 on EAGAIN
|
|
|
|
* n number of bytes
|
|
|
|
*/
|
|
|
|
static ssize_t qemudClientWrite(struct qemud_client *client) {
|
2007-12-05 15:27:08 +00:00
|
|
|
#if HAVE_SASL
|
|
|
|
if (client->saslSSF & QEMUD_SASL_SSF_WRITE)
|
2009-01-20 19:25:15 +00:00
|
|
|
return qemudClientWriteSASL(client);
|
2007-12-05 15:27:08 +00:00
|
|
|
else
|
|
|
|
#endif
|
2009-01-20 19:25:15 +00:00
|
|
|
return qemudClientWritePlain(client);
|
2007-12-05 15:27:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-10 12:06:36 +00:00
|
|
|
void
|
|
|
|
qemudClientMessageRelease(struct qemud_client *client,
|
|
|
|
struct qemud_client_message *msg)
|
|
|
|
{
|
2009-08-24 19:57:16 +00:00
|
|
|
if (msg->streamTX) {
|
|
|
|
remoteStreamMessageFinished(client, msg);
|
|
|
|
} else if (!msg->async)
|
2009-07-10 12:06:36 +00:00
|
|
|
client->nrequests--;
|
|
|
|
|
|
|
|
/* See if the recv queue is currently throttled */
|
|
|
|
if (!client->rx &&
|
|
|
|
client->nrequests < max_client_requests) {
|
|
|
|
/* Reset message record for next RX attempt */
|
|
|
|
memset(msg, 0, sizeof(*msg));
|
|
|
|
client->rx = msg;
|
|
|
|
/* Get ready to receive next message */
|
|
|
|
client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
|
|
|
|
} else {
|
|
|
|
VIR_FREE(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
qemudUpdateClientEvent(client);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/*
|
|
|
|
* Process all queued client->tx messages until
|
|
|
|
* we would block on I/O
|
|
|
|
*/
|
|
|
|
static void
|
2009-07-10 11:48:50 +00:00
|
|
|
qemudDispatchClientWrite(struct qemud_client *client) {
|
2009-01-20 19:25:15 +00:00
|
|
|
while (client->tx) {
|
|
|
|
ssize_t ret;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
ret = qemudClientWrite(client);
|
|
|
|
if (ret < 0) {
|
|
|
|
qemudDispatchClientFailure(client);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (ret == 0)
|
|
|
|
return; /* Would block on write EAGAIN */
|
|
|
|
|
|
|
|
if (client->tx->bufferOffset == client->tx->bufferLength) {
|
|
|
|
struct qemud_client_message *reply;
|
|
|
|
|
|
|
|
/* Get finished reply from head of tx queue */
|
|
|
|
reply = qemudClientMessageQueueServe(&client->tx);
|
|
|
|
|
2009-07-10 12:06:36 +00:00
|
|
|
qemudClientMessageRelease(client, reply);
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-07-10 11:48:50 +00:00
|
|
|
if (client->closing)
|
|
|
|
qemudDispatchClientFailure(client);
|
2009-01-20 19:25:15 +00:00
|
|
|
}
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
2009-01-20 19:25:15 +00:00
|
|
|
}
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
static void
|
2009-07-10 11:48:50 +00:00
|
|
|
qemudDispatchClientHandshake(struct qemud_client *client) {
|
2009-01-20 19:25:15 +00:00
|
|
|
int ret;
|
|
|
|
/* Continue the handshake. */
|
|
|
|
ret = gnutls_handshake (client->tlssession);
|
|
|
|
if (ret == 0) {
|
2009-03-03 08:25:50 +00:00
|
|
|
client->handshake = 0;
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Finished. Next step is to check the certificate. */
|
|
|
|
if (remoteCheckAccess (client) == -1)
|
|
|
|
qemudDispatchClientFailure(client);
|
2009-07-10 11:48:50 +00:00
|
|
|
else
|
|
|
|
qemudUpdateClientEvent(client);
|
2009-01-20 19:25:15 +00:00
|
|
|
} else if (ret == GNUTLS_E_AGAIN ||
|
|
|
|
ret == GNUTLS_E_INTERRUPTED) {
|
|
|
|
/* Carry on waiting for more handshake. Update
|
|
|
|
the events just in case handshake data flow
|
|
|
|
direction has changed */
|
2009-07-10 11:48:50 +00:00
|
|
|
qemudUpdateClientEvent (client);
|
2009-01-20 19:25:15 +00:00
|
|
|
} else {
|
Add dtrace static probes in libvirtd
Adds initial support for dtrace static probes in libvirtd
daemon, assuming use of systemtap dtrace compat shim on
Linux. The probes are inserted for network client connect,
disconnect, TLS handshake states and authentication protocol
states.
This can be tested by running the xample program and then
attempting to connect with any libvirt client (virsh,
virt-manager, etc).
# stap examples/systemtap/client.stp
Client fd=44 connected readonly=0
Client fd=44 auth polkit deny pid:24997,uid:500
Client fd=44 disconnected
Client fd=46 connected readonly=1
Client fd=46 auth sasl allow test
Client fd=46 disconnected
The libvirtd.stp file should also really not be required,
since it is duplicated info that is already available in
the main probes.d definition file. A script to autogenerate
the .stp file is needed, either in libvirtd tree, or better
as part of systemtap itself.
* Makefile.am: Add examples/systemtap subdir
* autobuild.sh: Disable dtrace for mingw32
* configure.ac: Add check for dtrace
* daemon/.gitignore: Ignore generated dtrace probe file
* daemon/Makefile.am: Build dtrace probe header & object
files
* daemon/libvirtd.stp: SystemTAP convenience probeset
* daemon/libvirtd.c: Add connect/disconnect & TLS probes
* daemon/remote.c: Add SASL and PolicyKit auth probes
* daemon/probes.d: Master probe definition
* daemon/libvirtd.h: Add convenience macro for probes
so that compilation is a no-op when dtrace is not available
* examples/systemtap/Makefile.am, examples/systemtap/client.stp
Example systemtap script using dtrace probe markers
* libvirt.spec.in: Enable dtrace on F13/RHEL6
* mingw32-libvirt.spec.in: Force disable dtrace
2010-09-14 16:30:32 +00:00
|
|
|
PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd);
|
2009-01-20 19:25:15 +00:00
|
|
|
/* Fatal error in handshake */
|
|
|
|
VIR_ERROR(_("TLS handshake failed: %s"),
|
|
|
|
gnutls_strerror (ret));
|
|
|
|
qemudDispatchClientFailure(client);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
static void
|
2008-11-19 16:19:36 +00:00
|
|
|
qemudDispatchClientEvent(int watch, int fd, int events, void *opaque) {
|
2007-06-26 19:11:00 +00:00
|
|
|
struct qemud_server *server = (struct qemud_server *)opaque;
|
2008-12-04 22:09:35 +00:00
|
|
|
struct qemud_client *client = NULL;
|
|
|
|
int i;
|
2007-02-23 08:39:49 +00:00
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&server->lock);
|
2008-12-04 22:16:40 +00:00
|
|
|
|
2008-12-04 22:09:35 +00:00
|
|
|
for (i = 0 ; i < server->nclients ; i++) {
|
2009-01-20 19:25:15 +00:00
|
|
|
virMutexLock(&server->clients[i]->lock);
|
2008-12-04 22:09:35 +00:00
|
|
|
if (server->clients[i]->watch == watch) {
|
|
|
|
client = server->clients[i];
|
2007-06-26 19:11:00 +00:00
|
|
|
break;
|
2008-12-04 22:09:35 +00:00
|
|
|
}
|
2009-01-20 19:25:15 +00:00
|
|
|
virMutexUnlock(&server->clients[i]->lock);
|
2007-06-26 19:11:00 +00:00
|
|
|
}
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
virMutexUnlock(&server->lock);
|
|
|
|
|
2008-12-04 22:16:40 +00:00
|
|
|
if (!client) {
|
2007-06-26 19:11:00 +00:00
|
|
|
return;
|
2008-12-04 22:16:40 +00:00
|
|
|
}
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
if (client->fd != fd) {
|
|
|
|
virMutexUnlock(&client->lock);
|
2008-11-19 16:19:36 +00:00
|
|
|
return;
|
2009-01-20 19:25:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (events & (VIR_EVENT_HANDLE_WRITABLE |
|
|
|
|
VIR_EVENT_HANDLE_READABLE)) {
|
|
|
|
if (client->handshake) {
|
2009-07-10 11:48:50 +00:00
|
|
|
qemudDispatchClientHandshake(client);
|
2009-01-20 19:25:15 +00:00
|
|
|
} else {
|
|
|
|
if (events & VIR_EVENT_HANDLE_WRITABLE)
|
2009-07-10 11:48:50 +00:00
|
|
|
qemudDispatchClientWrite(client);
|
2009-01-20 19:25:15 +00:00
|
|
|
if (events & VIR_EVENT_HANDLE_READABLE)
|
|
|
|
qemudDispatchClientRead(server, client);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NB, will get HANGUP + READABLE at same time upon
|
|
|
|
* disconnect */
|
|
|
|
if (events & (VIR_EVENT_HANDLE_ERROR |
|
|
|
|
VIR_EVENT_HANDLE_HANGUP))
|
|
|
|
qemudDispatchClientFailure(client);
|
2008-11-19 16:19:36 +00:00
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&client->lock);
|
2007-06-26 19:11:00 +00:00
|
|
|
}
|
|
|
|
|
2009-07-10 11:48:50 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* @client: a locked client object
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
qemudCalculateHandleMode(struct qemud_client *client) {
|
2009-01-20 19:25:15 +00:00
|
|
|
int mode = 0;
|
|
|
|
|
|
|
|
if (client->handshake) {
|
2007-12-05 15:27:08 +00:00
|
|
|
if (gnutls_record_get_direction (client->tlssession) == 0)
|
2009-01-20 19:25:15 +00:00
|
|
|
mode |= VIR_EVENT_HANDLE_READABLE;
|
2007-12-05 15:27:08 +00:00
|
|
|
else
|
2009-01-20 19:25:15 +00:00
|
|
|
mode |= VIR_EVENT_HANDLE_WRITABLE;
|
|
|
|
} else {
|
|
|
|
/* If there is a message on the rx queue then
|
|
|
|
* we're wanting more input */
|
|
|
|
if (client->rx)
|
|
|
|
mode |= VIR_EVENT_HANDLE_READABLE;
|
2008-12-04 22:16:40 +00:00
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
/* If there are one or more messages to send back to client,
|
|
|
|
then monitor for writability on socket */
|
|
|
|
if (client->tx)
|
|
|
|
mode |= VIR_EVENT_HANDLE_WRITABLE;
|
2007-12-05 15:27:08 +00:00
|
|
|
}
|
|
|
|
|
2009-07-10 11:48:50 +00:00
|
|
|
return mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @server: a locked or unlocked server object
|
|
|
|
* @client: a locked client object
|
|
|
|
*/
|
|
|
|
int qemudRegisterClientEvent(struct qemud_server *server,
|
|
|
|
struct qemud_client *client) {
|
|
|
|
int mode;
|
|
|
|
|
|
|
|
mode = qemudCalculateHandleMode(client);
|
|
|
|
|
|
|
|
if ((client->watch = virEventAddHandleImpl(client->fd,
|
|
|
|
mode,
|
|
|
|
qemudDispatchClientEvent,
|
|
|
|
server, NULL)) < 0)
|
|
|
|
return -1;
|
2007-06-26 19:11:00 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-07-10 11:48:50 +00:00
|
|
|
/*
|
|
|
|
* @client: a locked client object
|
|
|
|
*/
|
|
|
|
void qemudUpdateClientEvent(struct qemud_client *client) {
|
|
|
|
int mode;
|
|
|
|
|
|
|
|
mode = qemudCalculateHandleMode(client);
|
|
|
|
|
|
|
|
virEventUpdateHandleImpl(client->watch, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-23 13:18:18 +00:00
|
|
|
static void
|
2008-11-19 16:19:36 +00:00
|
|
|
qemudDispatchServerEvent(int watch, int fd, int events, void *opaque) {
|
2007-06-26 19:11:00 +00:00
|
|
|
struct qemud_server *server = (struct qemud_server *)opaque;
|
2008-12-04 22:16:40 +00:00
|
|
|
struct qemud_socket *sock;
|
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&server->lock);
|
2008-12-04 22:16:40 +00:00
|
|
|
|
|
|
|
sock = server->sockets;
|
2007-06-26 19:11:00 +00:00
|
|
|
|
2007-03-05 17:15:20 +00:00
|
|
|
while (sock) {
|
2008-11-19 16:19:36 +00:00
|
|
|
if (sock->watch == watch)
|
2007-06-26 19:11:00 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
sock = sock->next;
|
2007-03-05 17:15:20 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2008-12-04 22:16:40 +00:00
|
|
|
if (sock && sock->fd == fd && events)
|
2007-06-26 19:11:00 +00:00
|
|
|
qemudDispatchServer(server, sock);
|
2008-12-04 22:16:40 +00:00
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&server->lock);
|
2007-06-26 19:11:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-06-26 20:51:00 +00:00
|
|
|
static int qemudOneLoop(void) {
|
2007-03-27 10:28:45 +00:00
|
|
|
sig_atomic_t errors;
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2007-06-26 19:11:00 +00:00
|
|
|
if (virEventRunOnce() < 0)
|
2007-02-14 01:40:09 +00:00
|
|
|
return -1;
|
|
|
|
|
2007-03-27 10:28:45 +00:00
|
|
|
/* Check for any signal handling errors and log them. */
|
|
|
|
errors = sig_errors;
|
|
|
|
if (errors) {
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
2007-03-27 10:28:45 +00:00
|
|
|
sig_errors -= errors;
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Signal handler reported %d errors: last error: %s"),
|
2009-02-05 16:28:03 +00:00
|
|
|
errors, virStrerror (sig_lasterrno, ebuf, sizeof ebuf));
|
2007-03-27 10:28:45 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-02-06 14:43:52 +00:00
|
|
|
static void qemudInactiveTimer(int timerid, void *data) {
|
2007-06-26 22:56:14 +00:00
|
|
|
struct qemud_server *server = (struct qemud_server *)data;
|
2009-02-06 14:43:52 +00:00
|
|
|
|
|
|
|
if (virStateActive() ||
|
|
|
|
server->clients) {
|
|
|
|
DEBUG0("Timer expired but still active, not shutting down");
|
|
|
|
virEventUpdateTimeoutImpl(timerid, -1);
|
|
|
|
} else {
|
|
|
|
DEBUG0("Timer expired and inactive, shutting down");
|
2009-10-16 15:34:37 +00:00
|
|
|
server->quitEventThread = 1;
|
2007-06-26 22:56:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
static void qemudFreeClient(struct qemud_client *client) {
|
|
|
|
while (client->rx) {
|
|
|
|
struct qemud_client_message *msg
|
|
|
|
= qemudClientMessageQueueServe(&client->rx);
|
|
|
|
VIR_FREE(msg);
|
|
|
|
}
|
|
|
|
while (client->dx) {
|
|
|
|
struct qemud_client_message *msg
|
|
|
|
= qemudClientMessageQueueServe(&client->dx);
|
|
|
|
VIR_FREE(msg);
|
|
|
|
}
|
|
|
|
while (client->tx) {
|
|
|
|
struct qemud_client_message *msg
|
|
|
|
= qemudClientMessageQueueServe(&client->tx);
|
|
|
|
VIR_FREE(msg);
|
|
|
|
}
|
|
|
|
|
2009-07-10 12:06:36 +00:00
|
|
|
while (client->streams)
|
|
|
|
remoteRemoveClientStream(client, client->streams);
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
if (client->conn)
|
|
|
|
virConnectClose(client->conn);
|
|
|
|
virMutexDestroy(&client->lock);
|
|
|
|
VIR_FREE(client);
|
|
|
|
}
|
|
|
|
|
2009-10-16 15:34:37 +00:00
|
|
|
static void *qemudRunLoop(void *opaque) {
|
|
|
|
struct qemud_server *server = opaque;
|
2007-06-26 22:56:14 +00:00
|
|
|
int timerid = -1;
|
2009-10-16 15:34:37 +00:00
|
|
|
int i;
|
2009-02-06 14:43:52 +00:00
|
|
|
int timerActive = 0;
|
2008-12-04 22:16:40 +00:00
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&server->lock);
|
2008-12-04 22:16:40 +00:00
|
|
|
|
2009-02-06 14:43:52 +00:00
|
|
|
if (timeout > 0 &&
|
|
|
|
(timerid = virEventAddTimeoutImpl(-1,
|
|
|
|
qemudInactiveTimer,
|
|
|
|
server, NULL)) < 0) {
|
|
|
|
VIR_ERROR0(_("Failed to register shutdown timeout"));
|
2009-10-16 15:34:37 +00:00
|
|
|
return NULL;
|
2009-02-06 14:43:52 +00:00
|
|
|
}
|
|
|
|
|
2009-01-20 19:27:11 +00:00
|
|
|
if (min_workers > max_workers)
|
|
|
|
max_workers = min_workers;
|
|
|
|
|
|
|
|
server->nworkers = max_workers;
|
2008-12-04 22:16:40 +00:00
|
|
|
if (VIR_ALLOC_N(server->workers, server->nworkers) < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR0(_("Failed to allocate workers"));
|
2009-10-16 15:34:37 +00:00
|
|
|
return NULL;
|
2008-12-04 22:16:40 +00:00
|
|
|
}
|
|
|
|
|
2009-01-20 19:27:11 +00:00
|
|
|
for (i = 0 ; i < min_workers ; i++) {
|
|
|
|
if (qemudStartWorker(server, &server->workers[i]) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
server->nactiveworkers++;
|
2008-12-04 22:16:40 +00:00
|
|
|
}
|
2007-06-26 22:56:14 +00:00
|
|
|
|
2009-10-16 15:34:37 +00:00
|
|
|
for (;!server->quitEventThread;) {
|
2007-06-26 22:56:14 +00:00
|
|
|
/* A shutdown timeout is specified, so check
|
|
|
|
* if any drivers have active state, if not
|
|
|
|
* shutdown after timeout seconds
|
|
|
|
*/
|
2009-02-06 14:43:52 +00:00
|
|
|
if (timeout > 0) {
|
|
|
|
if (timerActive) {
|
|
|
|
if (server->clients) {
|
|
|
|
DEBUG("Deactivating shutdown timer %d", timerid);
|
|
|
|
virEventUpdateTimeoutImpl(timerid, -1);
|
|
|
|
timerActive = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!virStateActive() &&
|
|
|
|
!server->clients) {
|
|
|
|
DEBUG("Activating shutdown timer %d", timerid);
|
|
|
|
virEventUpdateTimeoutImpl(timerid, timeout * 1000);
|
|
|
|
timerActive = 1;
|
|
|
|
}
|
|
|
|
}
|
2007-06-26 22:56:14 +00:00
|
|
|
}
|
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&server->lock);
|
2009-01-20 19:25:15 +00:00
|
|
|
if (qemudOneLoop() < 0) {
|
|
|
|
virMutexLock(&server->lock);
|
2010-04-02 19:44:04 +00:00
|
|
|
DEBUG0("Loop iteration error, exiting");
|
2007-06-26 22:56:14 +00:00
|
|
|
break;
|
2009-01-20 19:25:15 +00:00
|
|
|
}
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&server->lock);
|
2008-12-04 22:16:40 +00:00
|
|
|
|
|
|
|
reprocess:
|
|
|
|
for (i = 0 ; i < server->nclients ; i++) {
|
|
|
|
int inactive;
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&server->clients[i]->lock);
|
2008-12-04 22:16:40 +00:00
|
|
|
inactive = server->clients[i]->fd == -1
|
|
|
|
&& server->clients[i]->refs == 0;
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&server->clients[i]->lock);
|
2008-12-04 22:16:40 +00:00
|
|
|
if (inactive) {
|
2009-01-20 19:25:15 +00:00
|
|
|
qemudFreeClient(server->clients[i]);
|
2008-12-04 22:16:40 +00:00
|
|
|
server->nclients--;
|
2009-01-20 19:25:15 +00:00
|
|
|
if (i < server->nclients)
|
2008-12-04 22:16:40 +00:00
|
|
|
memmove(server->clients + i,
|
|
|
|
server->clients + i + 1,
|
2009-01-20 19:25:15 +00:00
|
|
|
sizeof (*server->clients) * (server->nclients - i));
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(server->clients,
|
|
|
|
server->nclients) < 0) {
|
|
|
|
; /* ignore */
|
2008-12-04 22:16:40 +00:00
|
|
|
}
|
2009-01-20 19:25:15 +00:00
|
|
|
goto reprocess;
|
2008-12-04 22:16:40 +00:00
|
|
|
}
|
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-01-20 19:27:11 +00:00
|
|
|
/* If number of active workers exceeds both the min_workers
|
|
|
|
* threshold and the number of clients, then kill some
|
|
|
|
* off */
|
|
|
|
for (i = 0 ; (i < server->nworkers &&
|
|
|
|
server->nactiveworkers > server->nclients &&
|
|
|
|
server->nactiveworkers > min_workers) ; i++) {
|
|
|
|
|
|
|
|
if (server->workers[i].hasThread &&
|
|
|
|
!server->workers[i].processingCall) {
|
|
|
|
server->workers[i].quitRequest = 1;
|
|
|
|
|
|
|
|
virCondBroadcast(&server->job);
|
|
|
|
virMutexUnlock(&server->lock);
|
|
|
|
pthread_join(server->workers[i].thread, NULL);
|
|
|
|
virMutexLock(&server->lock);
|
|
|
|
server->workers[i].hasThread = 0;
|
|
|
|
server->nactiveworkers--;
|
|
|
|
}
|
|
|
|
}
|
2007-06-26 22:56:14 +00:00
|
|
|
}
|
|
|
|
|
2009-01-20 19:27:11 +00:00
|
|
|
cleanup:
|
2008-12-04 22:16:40 +00:00
|
|
|
for (i = 0 ; i < server->nworkers ; i++) {
|
2009-01-20 19:27:11 +00:00
|
|
|
if (!server->workers[i].hasThread)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
server->workers[i].quitRequest = 1;
|
|
|
|
virCondBroadcast(&server->job);
|
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&server->lock);
|
2009-01-20 19:27:11 +00:00
|
|
|
pthread_join(server->workers[i].thread, NULL);
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&server->lock);
|
2009-01-20 19:27:11 +00:00
|
|
|
server->workers[i].hasThread = 0;
|
2008-12-04 22:16:40 +00:00
|
|
|
}
|
2009-01-20 19:25:15 +00:00
|
|
|
VIR_FREE(server->workers);
|
2008-12-04 22:16:40 +00:00
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&server->lock);
|
2009-10-16 15:34:37 +00:00
|
|
|
return NULL;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
2009-10-16 15:34:37 +00:00
|
|
|
|
|
|
|
static int qemudStartEventLoop(struct qemud_server *server) {
|
|
|
|
pthread_attr_t attr;
|
|
|
|
pthread_attr_init(&attr);
|
|
|
|
/* We want to join the eventloop, so don't detach it */
|
|
|
|
/*pthread_attr_setdetachstate(&attr, 1);*/
|
|
|
|
|
|
|
|
if (pthread_create(&server->eventThread,
|
|
|
|
&attr,
|
|
|
|
qemudRunLoop,
|
|
|
|
server) != 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
server->hasEventThread = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
static void qemudCleanup(struct qemud_server *server) {
|
2007-02-20 17:51:41 +00:00
|
|
|
struct qemud_socket *sock;
|
|
|
|
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(server->sigread);
|
|
|
|
VIR_FORCE_CLOSE(server->sigwrite);
|
2007-02-20 17:51:41 +00:00
|
|
|
|
|
|
|
sock = server->sockets;
|
2007-02-14 01:40:09 +00:00
|
|
|
while (sock) {
|
2007-02-20 17:51:41 +00:00
|
|
|
struct qemud_socket *next = sock->next;
|
2009-10-16 10:24:01 +00:00
|
|
|
if (sock->watch)
|
|
|
|
virEventRemoveHandleImpl(sock->watch);
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(sock->fd);
|
2010-06-03 13:36:34 +00:00
|
|
|
|
|
|
|
/* Unlink unix domain sockets which are not in
|
|
|
|
* the abstract namespace */
|
|
|
|
if (sock->path &&
|
|
|
|
sock->path[0] != '@')
|
|
|
|
unlink(sock->path);
|
|
|
|
VIR_FREE(sock->path);
|
2010-10-21 14:45:12 +00:00
|
|
|
VIR_FREE(sock->addrstr);
|
2010-06-03 13:36:34 +00:00
|
|
|
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(sock);
|
2007-02-20 17:51:41 +00:00
|
|
|
sock = next;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(server->logDir);
|
2007-02-20 17:51:41 +00:00
|
|
|
|
2007-12-05 19:25:44 +00:00
|
|
|
#ifdef HAVE_SASL
|
2007-12-05 15:34:05 +00:00
|
|
|
if (server->saslUsernameWhitelist) {
|
|
|
|
char **list = server->saslUsernameWhitelist;
|
|
|
|
while (*list) {
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(*list);
|
2007-12-05 15:34:05 +00:00
|
|
|
list++;
|
|
|
|
}
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(server->saslUsernameWhitelist);
|
2007-12-05 15:34:05 +00:00
|
|
|
}
|
2007-12-05 19:25:44 +00:00
|
|
|
#endif
|
2007-02-20 17:51:41 +00:00
|
|
|
|
2009-10-16 10:24:01 +00:00
|
|
|
#if HAVE_POLKIT0
|
|
|
|
if (server->sysbus)
|
|
|
|
dbus_connection_unref(server->sysbus);
|
|
|
|
#endif
|
|
|
|
|
2007-06-26 22:56:14 +00:00
|
|
|
virStateCleanup();
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
if (virCondDestroy(&server->job) < 0) {
|
|
|
|
;
|
|
|
|
}
|
|
|
|
virMutexDestroy(&server->lock);
|
|
|
|
|
|
|
|
VIR_FREE(server);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
/* Allocate an array of malloc'd strings from the config file, filename
|
|
|
|
* (used only in diagnostics), using handle "conf". Upon error, return -1
|
|
|
|
* and free any allocated memory. Otherwise, save the array in *list_arg
|
|
|
|
* and return 0.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
remoteConfigGetStringList(virConfPtr conf, const char *key, char ***list_arg,
|
|
|
|
const char *filename)
|
|
|
|
{
|
|
|
|
char **list;
|
|
|
|
virConfValuePtr p = virConfGetValue (conf, key);
|
|
|
|
if (!p)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (p->type) {
|
|
|
|
case VIR_CONF_STRING:
|
2008-06-06 10:52:01 +00:00
|
|
|
if (VIR_ALLOC_N(list, 2) < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("failed to allocate memory for %s config list"), key);
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
list[0] = strdup (p->str);
|
|
|
|
list[1] = NULL;
|
|
|
|
if (list[0] == NULL) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("failed to allocate memory for %s config list value"),
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
key);
|
2008-06-06 10:52:01 +00:00
|
|
|
VIR_FREE(list);
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_CONF_LIST: {
|
|
|
|
int i, len = 0;
|
|
|
|
virConfValuePtr pp;
|
|
|
|
for (pp = p->list; pp; pp = pp->next)
|
|
|
|
len++;
|
2008-06-06 10:52:01 +00:00
|
|
|
if (VIR_ALLOC_N(list, 1+len) < 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("failed to allocate memory for %s config list"), key);
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0, pp = p->list; pp; ++i, pp = pp->next) {
|
|
|
|
if (pp->type != VIR_CONF_STRING) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("remoteReadConfigFile: %s: %s:"
|
2010-04-02 19:44:04 +00:00
|
|
|
" must be a string or list of strings"),
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
filename, key);
|
2008-06-06 10:52:01 +00:00
|
|
|
VIR_FREE(list);
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
list[i] = strdup (pp->str);
|
|
|
|
if (list[i] == NULL) {
|
|
|
|
int j;
|
|
|
|
for (j = 0 ; j < i ; j++)
|
2008-06-06 10:52:01 +00:00
|
|
|
VIR_FREE(list[j]);
|
|
|
|
VIR_FREE(list);
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("failed to allocate memory for %s config list value"),
|
|
|
|
key);
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
list[i] = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("remoteReadConfigFile: %s: %s:"
|
2010-04-02 19:44:04 +00:00
|
|
|
" must be a string or list of strings"),
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
filename, key);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*list_arg = list;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* A helper function used by each of the following macros. */
|
|
|
|
static int
|
|
|
|
checkType (virConfValuePtr p, const char *filename,
|
|
|
|
const char *key, virConfType required_type)
|
|
|
|
{
|
|
|
|
if (p->type != required_type) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("remoteReadConfigFile: %s: %s: invalid type:"
|
2010-04-02 19:44:04 +00:00
|
|
|
" got %s; expected %s"), filename, key,
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
virConfTypeName (p->type),
|
|
|
|
virConfTypeName (required_type));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there is no config data for the key, #var_name, then do nothing.
|
|
|
|
If there is valid data of type VIR_CONF_STRING, and strdup succeeds,
|
|
|
|
store the result in var_name. Otherwise, (i.e. invalid type, or strdup
|
|
|
|
failure), give a diagnostic and "goto" the cleanup-and-fail label. */
|
|
|
|
#define GET_CONF_STR(conf, filename, var_name) \
|
|
|
|
do { \
|
|
|
|
virConfValuePtr p = virConfGetValue (conf, #var_name); \
|
|
|
|
if (p) { \
|
|
|
|
if (checkType (p, filename, #var_name, VIR_CONF_STRING) < 0) \
|
|
|
|
goto free_and_fail; \
|
|
|
|
(var_name) = strdup (p->str); \
|
|
|
|
if ((var_name) == NULL) { \
|
2009-02-05 16:28:30 +00:00
|
|
|
char ebuf[1024]; \
|
2010-01-19 13:17:20 +00:00
|
|
|
VIR_ERROR(_("remoteReadConfigFile: %s"), \
|
2009-02-05 16:28:30 +00:00
|
|
|
virStrerror(errno, ebuf, sizeof ebuf)); \
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
goto free_and_fail; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/* Like GET_CONF_STR, but for integral values. */
|
|
|
|
#define GET_CONF_INT(conf, filename, var_name) \
|
|
|
|
do { \
|
|
|
|
virConfValuePtr p = virConfGetValue (conf, #var_name); \
|
|
|
|
if (p) { \
|
|
|
|
if (checkType (p, filename, #var_name, VIR_CONF_LONG) < 0) \
|
|
|
|
goto free_and_fail; \
|
|
|
|
(var_name) = p->l; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2007-12-05 15:34:05 +00:00
|
|
|
|
|
|
|
static int remoteConfigGetAuth(virConfPtr conf, const char *key, int *auth, const char *filename) {
|
|
|
|
virConfValuePtr p;
|
|
|
|
|
|
|
|
p = virConfGetValue (conf, key);
|
|
|
|
if (!p)
|
|
|
|
return 0;
|
|
|
|
|
2007-12-11 21:20:13 +00:00
|
|
|
if (checkType (p, filename, key, VIR_CONF_STRING) < 0)
|
2007-12-05 15:34:05 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!p->str)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (STREQ(p->str, "none")) {
|
|
|
|
*auth = REMOTE_AUTH_NONE;
|
|
|
|
#if HAVE_SASL
|
|
|
|
} else if (STREQ(p->str, "sasl")) {
|
|
|
|
*auth = REMOTE_AUTH_SASL;
|
2007-12-05 18:21:27 +00:00
|
|
|
#endif
|
|
|
|
#if HAVE_POLKIT
|
|
|
|
} else if (STREQ(p->str, "polkit")) {
|
|
|
|
*auth = REMOTE_AUTH_POLKIT;
|
2007-12-05 15:34:05 +00:00
|
|
|
#endif
|
|
|
|
} else {
|
2010-01-19 13:17:20 +00:00
|
|
|
VIR_ERROR(_("remoteReadConfigFile: %s: %s: unsupported auth %s"),
|
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 16:50:17 +00:00
|
|
|
filename, key, p->str);
|
2007-12-05 15:34:05 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-12-05 19:25:44 +00:00
|
|
|
#ifdef HAVE_SASL
|
|
|
|
static inline int
|
|
|
|
remoteReadSaslAllowedUsernameList (virConfPtr conf,
|
|
|
|
struct qemud_server *server,
|
|
|
|
const char *filename)
|
|
|
|
{
|
|
|
|
return
|
|
|
|
remoteConfigGetStringList (conf, "sasl_allowed_username_list",
|
|
|
|
&server->saslUsernameWhitelist, filename);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static inline int
|
|
|
|
remoteReadSaslAllowedUsernameList (virConfPtr conf ATTRIBUTE_UNUSED,
|
|
|
|
struct qemud_server *server ATTRIBUTE_UNUSED,
|
|
|
|
const char *filename ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-12-22 12:53:26 +00:00
|
|
|
/*
|
|
|
|
* Set up the logging environment
|
|
|
|
* By default if daemonized all errors go to syslog and the logging
|
|
|
|
* is also saved onto the logfile libvird.log, but if verbose or error
|
|
|
|
* debugging is asked for then output informations or debug.
|
|
|
|
*/
|
2008-12-22 16:16:10 +00:00
|
|
|
static int
|
2009-10-23 06:56:21 +00:00
|
|
|
qemudSetLogging(virConfPtr conf, const char *filename)
|
|
|
|
{
|
|
|
|
int log_level = 0;
|
2009-08-06 13:45:50 +00:00
|
|
|
char *log_filters = NULL;
|
|
|
|
char *log_outputs = NULL;
|
2008-12-22 16:16:10 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2008-12-22 12:53:26 +00:00
|
|
|
virLogReset();
|
|
|
|
|
2008-12-22 16:16:10 +00:00
|
|
|
/*
|
2009-08-06 13:55:07 +00:00
|
|
|
* Libvirtd's order of precedence is:
|
|
|
|
* cmdline > environment > config
|
|
|
|
*
|
|
|
|
* In order to achieve this, we must process configuration in
|
|
|
|
* different order for the log level versus the filters and
|
|
|
|
* outputs. Because filters and outputs append, we have to look at
|
|
|
|
* the environment first and then only check the config file if
|
|
|
|
* there was no result from the environment. The default output is
|
|
|
|
* then applied only if there was no setting from either of the
|
|
|
|
* first two. Because we don't have a way to determine if the log
|
|
|
|
* level has been set, we must process variables in the opposite
|
|
|
|
* order, each one overriding the previous.
|
2008-12-22 16:16:10 +00:00
|
|
|
*/
|
2008-12-22 12:53:26 +00:00
|
|
|
GET_CONF_INT (conf, filename, log_level);
|
2009-08-06 13:45:50 +00:00
|
|
|
if (log_level != 0)
|
|
|
|
virLogSetDefaultPriority(log_level);
|
|
|
|
|
2009-08-06 13:55:07 +00:00
|
|
|
virLogSetFromEnv();
|
2009-08-06 13:45:50 +00:00
|
|
|
|
|
|
|
if (virLogGetNbFilters() == 0) {
|
|
|
|
GET_CONF_STR (conf, filename, log_filters);
|
|
|
|
virLogParseFilters(log_filters);
|
2008-12-22 16:16:10 +00:00
|
|
|
}
|
2008-12-22 12:53:26 +00:00
|
|
|
|
2009-08-06 13:45:50 +00:00
|
|
|
if (virLogGetNbOutputs() == 0) {
|
|
|
|
GET_CONF_STR (conf, filename, log_outputs);
|
|
|
|
virLogParseOutputs(log_outputs);
|
2009-06-03 10:36:17 +00:00
|
|
|
}
|
2008-12-22 12:53:26 +00:00
|
|
|
|
|
|
|
/*
|
2009-08-06 13:45:50 +00:00
|
|
|
* If no defined outputs, then direct to syslog when running
|
|
|
|
* as daemon. Otherwise the default output is stderr.
|
2008-12-22 12:53:26 +00:00
|
|
|
*/
|
2009-08-06 13:45:50 +00:00
|
|
|
if (virLogGetNbOutputs() == 0) {
|
2009-07-01 11:21:15 +00:00
|
|
|
char *tmp = NULL;
|
2009-01-20 21:50:31 +00:00
|
|
|
if (godaemon) {
|
2009-08-06 13:45:50 +00:00
|
|
|
if (virAsprintf (&tmp, "%d:syslog:libvirtd",
|
|
|
|
virLogGetDefaultPriority()) < 0)
|
2009-01-20 21:50:31 +00:00
|
|
|
goto free_and_fail;
|
|
|
|
} else {
|
2009-08-06 13:45:50 +00:00
|
|
|
if (virAsprintf (&tmp, "%d:stderr",
|
|
|
|
virLogGetDefaultPriority()) < 0)
|
2009-07-01 11:21:15 +00:00
|
|
|
goto free_and_fail;
|
2009-01-20 21:50:31 +00:00
|
|
|
}
|
2009-07-01 11:21:15 +00:00
|
|
|
virLogParseOutputs(tmp);
|
|
|
|
VIR_FREE(tmp);
|
2009-06-03 10:36:17 +00:00
|
|
|
}
|
2009-08-06 13:55:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Command line override for --verbose
|
|
|
|
*/
|
|
|
|
if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
|
|
|
|
virLogSetDefaultPriority(VIR_LOG_INFO);
|
|
|
|
|
2008-12-22 16:16:10 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2008-12-22 12:53:26 +00:00
|
|
|
free_and_fail:
|
|
|
|
VIR_FREE(log_filters);
|
|
|
|
VIR_FREE(log_outputs);
|
2008-12-22 16:16:10 +00:00
|
|
|
return(ret);
|
2008-12-22 12:53:26 +00:00
|
|
|
}
|
2007-12-05 19:25:44 +00:00
|
|
|
|
2007-06-11 12:04:54 +00:00
|
|
|
/* Read the config file if it exists.
|
|
|
|
* Only used in the remote case, hence the name.
|
|
|
|
*/
|
|
|
|
static int
|
2007-12-05 15:34:05 +00:00
|
|
|
remoteReadConfigFile (struct qemud_server *server, const char *filename)
|
2007-06-11 12:04:54 +00:00
|
|
|
{
|
|
|
|
virConfPtr conf;
|
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
/* The following variable names must match the corresponding
|
|
|
|
configuration strings. */
|
|
|
|
char *unix_sock_ro_perms = NULL;
|
|
|
|
char *unix_sock_rw_perms = NULL;
|
|
|
|
char *unix_sock_group = NULL;
|
2009-04-16 14:53:19 +00:00
|
|
|
char *buf = NULL;
|
2010-05-25 14:33:51 +00:00
|
|
|
char *host_uuid = NULL;
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
|
2008-07-30 08:47:10 +00:00
|
|
|
#if HAVE_POLKIT
|
|
|
|
/* Change the default back to no auth for non-root */
|
2009-06-12 13:20:13 +00:00
|
|
|
if (!server->privileged && auth_unix_rw == REMOTE_AUTH_POLKIT)
|
2008-07-30 08:47:10 +00:00
|
|
|
auth_unix_rw = REMOTE_AUTH_NONE;
|
2009-06-12 13:20:13 +00:00
|
|
|
if (!server->privileged && auth_unix_ro == REMOTE_AUTH_POLKIT)
|
2008-07-30 08:47:10 +00:00
|
|
|
auth_unix_ro = REMOTE_AUTH_NONE;
|
|
|
|
#endif
|
|
|
|
|
2009-06-19 12:34:30 +00:00
|
|
|
conf = virConfReadFile (filename, 0);
|
2009-01-12 18:22:32 +00:00
|
|
|
if (!conf) return -1;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2008-12-22 12:53:26 +00:00
|
|
|
/*
|
|
|
|
* First get all the logging settings and activate them
|
|
|
|
*/
|
2008-12-22 16:16:10 +00:00
|
|
|
if (qemudSetLogging(conf, filename) < 0)
|
|
|
|
goto free_and_fail;
|
2008-12-22 12:53:26 +00:00
|
|
|
|
2007-12-05 18:56:27 +00:00
|
|
|
GET_CONF_INT (conf, filename, listen_tcp);
|
|
|
|
GET_CONF_INT (conf, filename, listen_tls);
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
GET_CONF_STR (conf, filename, tls_port);
|
|
|
|
GET_CONF_STR (conf, filename, tcp_port);
|
2008-05-14 20:57:20 +00:00
|
|
|
GET_CONF_STR (conf, filename, listen_addr);
|
2008-05-14 21:22:04 +00:00
|
|
|
|
2007-12-05 15:34:05 +00:00
|
|
|
if (remoteConfigGetAuth(conf, "auth_unix_rw", &auth_unix_rw, filename) < 0)
|
2008-03-03 13:15:57 +00:00
|
|
|
goto free_and_fail;
|
2007-12-05 18:21:27 +00:00
|
|
|
#if HAVE_POLKIT
|
|
|
|
/* Change default perms to be wide-open if PolicyKit is enabled.
|
|
|
|
* Admin can always override in config file
|
|
|
|
*/
|
|
|
|
if (auth_unix_rw == REMOTE_AUTH_POLKIT)
|
|
|
|
unix_sock_rw_mask = 0777;
|
|
|
|
#endif
|
2007-12-05 15:34:05 +00:00
|
|
|
if (remoteConfigGetAuth(conf, "auth_unix_ro", &auth_unix_ro, filename) < 0)
|
2008-03-03 13:15:57 +00:00
|
|
|
goto free_and_fail;
|
2007-12-05 15:34:05 +00:00
|
|
|
if (remoteConfigGetAuth(conf, "auth_tcp", &auth_tcp, filename) < 0)
|
2008-03-03 13:15:57 +00:00
|
|
|
goto free_and_fail;
|
2007-12-05 15:34:05 +00:00
|
|
|
if (remoteConfigGetAuth(conf, "auth_tls", &auth_tls, filename) < 0)
|
2008-03-03 13:15:57 +00:00
|
|
|
goto free_and_fail;
|
2007-12-05 15:34:05 +00:00
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
GET_CONF_STR (conf, filename, unix_sock_group);
|
|
|
|
if (unix_sock_group) {
|
2009-06-12 13:20:13 +00:00
|
|
|
if (!server->privileged) {
|
2010-05-19 10:00:18 +00:00
|
|
|
VIR_WARN0("Cannot set group when not running as root");
|
2007-09-19 02:28:01 +00:00
|
|
|
} else {
|
2009-04-16 14:53:19 +00:00
|
|
|
int ret;
|
2009-01-22 19:41:48 +00:00
|
|
|
struct group grpdata, *grp;
|
2009-04-16 14:53:19 +00:00
|
|
|
size_t maxbuf = sysconf(_SC_GETGR_R_SIZE_MAX);
|
|
|
|
|
|
|
|
if (maxbuf == -1)
|
|
|
|
maxbuf = 1024;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(buf, maxbuf) < 0) {
|
2010-05-20 06:10:38 +00:00
|
|
|
VIR_ERROR0(_("Failed to allocate memory for buffer"));
|
2009-04-16 14:53:19 +00:00
|
|
|
goto free_and_fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((ret = getgrnam_r(unix_sock_group, &grpdata,
|
|
|
|
buf, maxbuf,
|
|
|
|
&grp)) == ERANGE) {
|
|
|
|
maxbuf *= 2;
|
|
|
|
if (maxbuf > 65536 || VIR_REALLOC_N(buf, maxbuf) < 0) {
|
2010-05-20 06:10:38 +00:00
|
|
|
VIR_ERROR0(_("Failed to reallocate enough memory for buffer"));
|
2009-04-16 14:53:19 +00:00
|
|
|
goto free_and_fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret != 0 || !grp) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Failed to lookup group '%s'"), unix_sock_group);
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
goto free_and_fail;
|
2007-09-19 02:28:01 +00:00
|
|
|
}
|
|
|
|
unix_sock_gid = grp->gr_gid;
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(buf);
|
2007-09-19 02:28:01 +00:00
|
|
|
}
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(unix_sock_group);
|
2007-09-19 02:28:01 +00:00
|
|
|
}
|
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
GET_CONF_STR (conf, filename, unix_sock_ro_perms);
|
|
|
|
if (unix_sock_ro_perms) {
|
2008-02-08 09:15:16 +00:00
|
|
|
if (virStrToLong_i (unix_sock_ro_perms, NULL, 8, &unix_sock_ro_mask) != 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Failed to parse mode '%s'"), unix_sock_ro_perms);
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
goto free_and_fail;
|
2007-09-19 02:28:01 +00:00
|
|
|
}
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(unix_sock_ro_perms);
|
2007-09-19 02:28:01 +00:00
|
|
|
}
|
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
GET_CONF_STR (conf, filename, unix_sock_rw_perms);
|
|
|
|
if (unix_sock_rw_perms) {
|
2008-02-08 09:15:16 +00:00
|
|
|
if (virStrToLong_i (unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) {
|
2009-01-06 18:32:03 +00:00
|
|
|
VIR_ERROR(_("Failed to parse mode '%s'"), unix_sock_rw_perms);
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
goto free_and_fail;
|
2007-09-19 02:28:01 +00:00
|
|
|
}
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(unix_sock_rw_perms);
|
2007-09-19 02:28:01 +00:00
|
|
|
}
|
|
|
|
|
2009-02-09 17:52:38 +00:00
|
|
|
GET_CONF_STR (conf, filename, unix_sock_dir);
|
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
GET_CONF_INT (conf, filename, mdns_adv);
|
|
|
|
GET_CONF_STR (conf, filename, mdns_name);
|
2007-09-19 01:56:55 +00:00
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
GET_CONF_INT (conf, filename, tls_no_verify_certificate);
|
2007-06-11 12:04:54 +00:00
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
GET_CONF_STR (conf, filename, key_file);
|
|
|
|
GET_CONF_STR (conf, filename, cert_file);
|
|
|
|
GET_CONF_STR (conf, filename, ca_file);
|
|
|
|
GET_CONF_STR (conf, filename, crl_file);
|
2007-06-11 12:04:54 +00:00
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
if (remoteConfigGetStringList (conf, "tls_allowed_dn_list",
|
|
|
|
&tls_allowed_dn_list, filename) < 0)
|
|
|
|
goto free_and_fail;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2007-12-05 19:25:44 +00:00
|
|
|
if (remoteReadSaslAllowedUsernameList (conf, server, filename) < 0)
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
goto free_and_fail;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
2008-12-04 22:18:44 +00:00
|
|
|
|
|
|
|
GET_CONF_INT (conf, filename, min_workers);
|
|
|
|
GET_CONF_INT (conf, filename, max_workers);
|
|
|
|
GET_CONF_INT (conf, filename, max_clients);
|
|
|
|
|
2009-01-20 19:25:15 +00:00
|
|
|
GET_CONF_INT (conf, filename, max_requests);
|
|
|
|
GET_CONF_INT (conf, filename, max_client_requests);
|
|
|
|
|
2010-09-15 13:44:11 +00:00
|
|
|
GET_CONF_INT (conf, filename, audit_level);
|
|
|
|
GET_CONF_INT (conf, filename, audit_logging);
|
|
|
|
|
2010-05-25 14:33:51 +00:00
|
|
|
GET_CONF_STR (conf, filename, host_uuid);
|
2010-05-25 19:12:01 +00:00
|
|
|
if (virSetHostUUIDStr(host_uuid)) {
|
|
|
|
VIR_ERROR(_("invalid host UUID: %s"), host_uuid);
|
2010-05-25 14:33:51 +00:00
|
|
|
goto free_and_fail;
|
2010-05-25 19:12:01 +00:00
|
|
|
}
|
2010-05-25 14:33:51 +00:00
|
|
|
|
|
|
|
VIR_FREE(host_uuid);
|
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
virConfFree (conf);
|
|
|
|
return 0;
|
2007-06-11 12:04:54 +00:00
|
|
|
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
free_and_fail:
|
|
|
|
virConfFree (conf);
|
2010-05-25 14:33:51 +00:00
|
|
|
VIR_FREE(host_uuid);
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(mdns_name);
|
|
|
|
VIR_FREE(unix_sock_ro_perms);
|
|
|
|
VIR_FREE(unix_sock_rw_perms);
|
|
|
|
VIR_FREE(unix_sock_group);
|
|
|
|
VIR_FREE(buf);
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
|
2008-05-14 20:57:20 +00:00
|
|
|
/* Don't bother trying to free listen_addr, tcp_port, tls_port, key_file,
|
|
|
|
cert_file, ca_file, or crl_file, since they are initialized to
|
|
|
|
non-malloc'd strings. Besides, these are static variables, and callers
|
|
|
|
are unlikely to call this function more than once, so there wouldn't
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
even be a real leak. */
|
|
|
|
|
|
|
|
if (tls_allowed_dn_list) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; tls_allowed_dn_list[i]; i++)
|
2009-12-09 23:00:50 +00:00
|
|
|
VIR_FREE(tls_allowed_dn_list[i]);
|
|
|
|
VIR_FREE(tls_allowed_dn_list);
|
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 15:43:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2007-06-11 12:04:54 +00:00
|
|
|
}
|
|
|
|
|
2008-12-12 07:56:50 +00:00
|
|
|
/* Display version information. */
|
|
|
|
static void
|
2010-05-20 19:40:54 +00:00
|
|
|
version (void)
|
2008-12-12 07:56:50 +00:00
|
|
|
{
|
|
|
|
printf ("%s (%s) %s\n", argv0, PACKAGE_NAME, PACKAGE_VERSION);
|
|
|
|
}
|
|
|
|
|
2009-01-22 17:49:41 +00:00
|
|
|
#ifdef __sun
|
|
|
|
static int
|
|
|
|
qemudSetupPrivs (void)
|
|
|
|
{
|
|
|
|
chown ("/var/run/libvirt", SYSTEM_UID, SYSTEM_UID);
|
|
|
|
|
|
|
|
if (__init_daemon_priv (PU_RESETGROUPS | PU_CLEARLIMITSET,
|
|
|
|
SYSTEM_UID, SYSTEM_UID, PRIV_XVM_CONTROL, NULL)) {
|
2010-01-19 13:17:20 +00:00
|
|
|
VIR_ERROR0(_("additional privileges are required"));
|
2009-01-22 17:49:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv_set (PRIV_OFF, PRIV_ALLSETS, PRIV_FILE_LINK_ANY, PRIV_PROC_INFO,
|
|
|
|
PRIV_PROC_SESSION, PRIV_PROC_EXEC, PRIV_PROC_FORK, NULL)) {
|
2010-01-19 13:17:20 +00:00
|
|
|
VIR_ERROR0(_("failed to set reduced privileges"));
|
2009-01-22 17:49:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else
|
2010-03-09 18:22:22 +00:00
|
|
|
# define qemudSetupPrivs() 0
|
2009-01-22 17:49:41 +00:00
|
|
|
#endif
|
|
|
|
|
2009-10-16 10:48:50 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Doing anything non-trivial in signal handlers is pretty dangerous,
|
|
|
|
* since there are very few async-signal safe POSIX funtions. To
|
|
|
|
* deal with this we setup a very simple signal handler. It simply
|
|
|
|
* writes the signal number to a pipe. The main event loop then sees
|
|
|
|
* the signal on the pipe and can safely do the processing from
|
|
|
|
* event loop context
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
daemonSetupSignals(struct qemud_server *server)
|
|
|
|
{
|
|
|
|
struct sigaction sig_action;
|
|
|
|
int sigpipe[2];
|
|
|
|
|
|
|
|
if (pipe(sigpipe) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virSetNonBlock(sigpipe[0]) < 0 ||
|
|
|
|
virSetNonBlock(sigpipe[1]) < 0 ||
|
|
|
|
virSetCloseExec(sigpipe[0]) < 0 ||
|
|
|
|
virSetCloseExec(sigpipe[1]) < 0) {
|
|
|
|
char ebuf[1024];
|
|
|
|
VIR_ERROR(_("Failed to create pipe: %s"),
|
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
sig_action.sa_sigaction = sig_handler;
|
|
|
|
sig_action.sa_flags = SA_SIGINFO;
|
|
|
|
sigemptyset(&sig_action.sa_mask);
|
|
|
|
|
|
|
|
sigaction(SIGHUP, &sig_action, NULL);
|
|
|
|
sigaction(SIGINT, &sig_action, NULL);
|
|
|
|
sigaction(SIGQUIT, &sig_action, NULL);
|
|
|
|
sigaction(SIGTERM, &sig_action, NULL);
|
|
|
|
sigaction(SIGCHLD, &sig_action, NULL);
|
|
|
|
|
|
|
|
sig_action.sa_handler = SIG_IGN;
|
|
|
|
sigaction(SIGPIPE, &sig_action, NULL);
|
|
|
|
|
|
|
|
if (virEventAddHandleImpl(sigpipe[0],
|
|
|
|
VIR_EVENT_HANDLE_READABLE,
|
|
|
|
qemudDispatchSignalEvent,
|
|
|
|
server, NULL) < 0) {
|
|
|
|
VIR_ERROR0(_("Failed to register callback for signal pipe"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
server->sigread = sigpipe[0];
|
|
|
|
server->sigwrite = sigpipe[1];
|
|
|
|
sigwrite = sigpipe[1];
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(sigpipe[0]);
|
|
|
|
VIR_FORCE_CLOSE(sigpipe[1]);
|
2009-10-16 10:48:50 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-04-04 09:32:00 +00:00
|
|
|
/* Print command-line usage. */
|
|
|
|
static void
|
2010-05-20 19:40:54 +00:00
|
|
|
usage (void)
|
2007-04-04 09:32:00 +00:00
|
|
|
{
|
|
|
|
fprintf (stderr,
|
2010-05-20 08:01:32 +00:00
|
|
|
_("\n\
|
2007-06-11 12:04:54 +00:00
|
|
|
Usage:\n\
|
|
|
|
%s [options]\n\
|
|
|
|
\n\
|
|
|
|
Options:\n\
|
|
|
|
-v | --verbose Verbose messages.\n\
|
|
|
|
-d | --daemon Run as a daemon & write PID file.\n\
|
2007-06-26 23:48:46 +00:00
|
|
|
-l | --listen Listen for TCP/IP connections.\n\
|
|
|
|
-t | --timeout <secs> Exit after timeout period.\n\
|
2007-08-07 13:24:22 +00:00
|
|
|
-f | --config <file> Configuration file.\n\
|
2008-12-12 07:56:50 +00:00
|
|
|
| --version Display version information.\n\
|
2007-06-11 12:04:54 +00:00
|
|
|
-p | --pid-file <file> Change name of PID file.\n\
|
|
|
|
\n\
|
2007-06-26 23:48:46 +00:00
|
|
|
libvirt management daemon:\n\
|
2007-06-11 12:04:54 +00:00
|
|
|
\n\
|
|
|
|
Default paths:\n\
|
|
|
|
\n\
|
2009-11-10 14:53:20 +00:00
|
|
|
Configuration file (unless overridden by -f):\n\
|
2010-05-20 08:01:32 +00:00
|
|
|
%s/libvirt/libvirtd.conf\n\
|
2007-06-11 12:04:54 +00:00
|
|
|
\n\
|
2007-06-26 23:48:46 +00:00
|
|
|
Sockets (as root):\n\
|
2010-05-20 08:01:32 +00:00
|
|
|
%s/run/libvirt/libvirt-sock\n\
|
|
|
|
%s/run/libvirt/libvirt-sock-ro\n\
|
2007-06-26 23:48:46 +00:00
|
|
|
\n\
|
|
|
|
Sockets (as non-root):\n\
|
|
|
|
$HOME/.libvirt/libvirt-sock (in UNIX abstract namespace)\n\
|
2007-06-11 12:04:54 +00:00
|
|
|
\n\
|
|
|
|
TLS:\n\
|
2010-05-20 08:01:32 +00:00
|
|
|
CA certificate: %s\n\
|
|
|
|
Server certificate: %s\n\
|
|
|
|
Server private key: %s\n\
|
2007-06-11 12:04:54 +00:00
|
|
|
\n\
|
|
|
|
PID file (unless overridden by --pid-file):\n\
|
|
|
|
%s\n\
|
2010-05-20 08:01:32 +00:00
|
|
|
\n"),
|
|
|
|
argv0,
|
|
|
|
SYSCONF_DIR,
|
|
|
|
LOCAL_STATE_DIR,
|
|
|
|
LOCAL_STATE_DIR,
|
|
|
|
LIBVIRT_CACERT,
|
|
|
|
LIBVIRT_SERVERCERT,
|
|
|
|
LIBVIRT_SERVERKEY,
|
|
|
|
(REMOTE_PID_FILE[0] != '\0'
|
|
|
|
? REMOTE_PID_FILE
|
|
|
|
: _("(disabled in ./configure)")));
|
2007-04-04 09:32:00 +00:00
|
|
|
}
|
|
|
|
|
2008-12-12 07:56:50 +00:00
|
|
|
enum {
|
|
|
|
OPT_VERSION = 129
|
|
|
|
};
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
#define MAX_LISTEN 5
|
|
|
|
int main(int argc, char **argv) {
|
2008-03-03 18:10:19 +00:00
|
|
|
struct qemud_server *server = NULL;
|
2007-06-11 12:04:54 +00:00
|
|
|
const char *pid_file = NULL;
|
2009-01-12 18:22:32 +00:00
|
|
|
const char *remote_config_file = NULL;
|
2009-10-16 11:14:54 +00:00
|
|
|
int statuswrite = -1;
|
2007-02-23 12:48:36 +00:00
|
|
|
int ret = 1;
|
2010-05-20 19:40:54 +00:00
|
|
|
argv0 = argv[0];
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
struct option opts[] = {
|
|
|
|
{ "verbose", no_argument, &verbose, 1},
|
|
|
|
{ "daemon", no_argument, &godaemon, 1},
|
2007-06-26 23:48:46 +00:00
|
|
|
{ "listen", no_argument, &ipsock, 1},
|
2007-08-07 13:24:22 +00:00
|
|
|
{ "config", required_argument, NULL, 'f'},
|
2007-04-04 09:32:00 +00:00
|
|
|
{ "timeout", required_argument, NULL, 't'},
|
|
|
|
{ "pid-file", required_argument, NULL, 'p'},
|
2008-12-12 07:56:50 +00:00
|
|
|
{ "version", no_argument, NULL, OPT_VERSION },
|
2007-04-04 09:32:00 +00:00
|
|
|
{ "help", no_argument, NULL, '?' },
|
2007-02-14 01:40:09 +00:00
|
|
|
{0, 0, 0, 0}
|
|
|
|
};
|
|
|
|
|
2010-05-20 07:52:20 +00:00
|
|
|
if (virInitialize() < 0) {
|
2010-05-20 19:40:54 +00:00
|
|
|
fprintf (stderr, _("%s: initialization failed\n"), argv0);
|
2010-05-20 07:52:20 +00:00
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
2009-10-16 10:29:01 +00:00
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
while (1) {
|
|
|
|
int optidx = 0;
|
|
|
|
int c;
|
|
|
|
char *tmp;
|
|
|
|
|
2007-08-07 13:24:22 +00:00
|
|
|
c = getopt_long(argc, argv, "ldf:p:t:v", opts, &optidx);
|
2007-02-14 01:40:09 +00:00
|
|
|
|
|
|
|
if (c == -1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case 0:
|
|
|
|
/* Got one of the flags */
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
verbose = 1;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
godaemon = 1;
|
|
|
|
break;
|
2007-06-26 23:48:46 +00:00
|
|
|
case 'l':
|
|
|
|
ipsock = 1;
|
2007-02-14 01:40:09 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 't':
|
2008-02-08 09:15:16 +00:00
|
|
|
if (virStrToLong_i(optarg, &tmp, 10, &timeout) != 0
|
2007-11-14 10:53:05 +00:00
|
|
|
|| timeout <= 0
|
|
|
|
/* Ensure that we can multiply by 1000 without overflowing. */
|
|
|
|
|| timeout > INT_MAX / 1000)
|
2007-02-14 01:40:09 +00:00
|
|
|
timeout = -1;
|
|
|
|
break;
|
2007-02-23 12:48:36 +00:00
|
|
|
|
|
|
|
case 'p':
|
2007-06-11 12:04:54 +00:00
|
|
|
pid_file = optarg;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'f':
|
|
|
|
remote_config_file = optarg;
|
2007-02-23 12:48:36 +00:00
|
|
|
break;
|
|
|
|
|
2008-12-12 07:56:50 +00:00
|
|
|
case OPT_VERSION:
|
2010-05-20 19:40:54 +00:00
|
|
|
version ();
|
2008-12-12 07:56:50 +00:00
|
|
|
return 0;
|
|
|
|
|
2007-02-14 01:40:09 +00:00
|
|
|
case '?':
|
2010-05-20 19:40:54 +00:00
|
|
|
usage ();
|
2007-02-14 01:40:09 +00:00
|
|
|
return 2;
|
|
|
|
|
|
|
|
default:
|
2010-05-20 19:40:54 +00:00
|
|
|
fprintf (stderr, _("%s: internal error: unknown flag: %c\n"),
|
|
|
|
argv0, c);
|
2009-12-15 08:43:29 +00:00
|
|
|
exit (EXIT_FAILURE);
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-12 18:22:32 +00:00
|
|
|
if (remote_config_file == NULL) {
|
|
|
|
static const char *default_config_file
|
|
|
|
= SYSCONF_DIR "/libvirt/libvirtd.conf";
|
|
|
|
remote_config_file =
|
2009-01-13 12:22:24 +00:00
|
|
|
(access(default_config_file, R_OK) == 0
|
2009-01-12 18:22:32 +00:00
|
|
|
? default_config_file
|
|
|
|
: "/dev/null");
|
|
|
|
}
|
|
|
|
|
2008-05-20 16:17:36 +00:00
|
|
|
if (godaemon) {
|
2009-02-05 16:28:03 +00:00
|
|
|
char ebuf[1024];
|
2009-10-16 11:14:54 +00:00
|
|
|
if ((statuswrite = daemonForkIntoBackground()) < 0) {
|
2009-02-05 16:28:03 +00:00
|
|
|
VIR_ERROR(_("Failed to fork as daemon: %s"),
|
|
|
|
virStrerror(errno, ebuf, sizeof ebuf));
|
2009-10-16 10:48:50 +00:00
|
|
|
goto error;
|
2008-05-20 16:17:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If running as root and no PID file is set, use the default */
|
|
|
|
if (pid_file == NULL &&
|
2009-06-12 13:20:13 +00:00
|
|
|
geteuid() == 0 &&
|
2008-05-20 16:17:36 +00:00
|
|
|
REMOTE_PID_FILE[0] != '\0')
|
|
|
|
pid_file = REMOTE_PID_FILE;
|
|
|
|
|
|
|
|
/* If we have a pidfile set, claim it now, exiting if already taken */
|
|
|
|
if (pid_file != NULL &&
|
2009-10-16 11:14:54 +00:00
|
|
|
qemudWritePidFile (pid_file) < 0) {
|
|
|
|
pid_file = NULL; /* Prevent unlinking of someone else's pid ! */
|
|
|
|
ret = VIR_DAEMON_ERR_PIDFILE;
|
2009-10-16 10:48:50 +00:00
|
|
|
goto error;
|
2009-10-16 11:14:54 +00:00
|
|
|
}
|
2008-05-20 16:17:36 +00:00
|
|
|
|
2009-01-22 17:49:41 +00:00
|
|
|
/* Ensure the rundir exists (on tmpfs on some systems) */
|
2009-06-12 13:20:13 +00:00
|
|
|
if (geteuid() == 0) {
|
2009-01-22 17:49:41 +00:00
|
|
|
const char *rundir = LOCAL_STATE_DIR "/run/libvirt";
|
|
|
|
|
|
|
|
if (mkdir (rundir, 0755)) {
|
|
|
|
if (errno != EEXIST) {
|
2009-09-23 10:38:21 +00:00
|
|
|
char ebuf[1024];
|
|
|
|
VIR_ERROR(_("unable to create rundir %s: %s"), rundir,
|
|
|
|
virStrerror(errno, ebuf, sizeof(ebuf)));
|
2009-10-16 11:14:54 +00:00
|
|
|
ret = VIR_DAEMON_ERR_RUNDIR;
|
|
|
|
goto error;
|
2009-01-22 17:49:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-12 13:20:13 +00:00
|
|
|
/* Beyond this point, nothing should rely on using
|
|
|
|
* getuid/geteuid() == 0, for privilege level checks.
|
|
|
|
* It must all use the flag 'server->privileged'
|
|
|
|
* which is also passed into all libvirt stateful
|
|
|
|
* drivers
|
|
|
|
*/
|
2009-10-16 11:14:54 +00:00
|
|
|
if (qemudSetupPrivs() < 0) {
|
|
|
|
ret = VIR_DAEMON_ERR_PRIVS;
|
2009-10-16 10:48:50 +00:00
|
|
|
goto error;
|
2009-10-16 11:14:54 +00:00
|
|
|
}
|
2009-01-22 17:49:41 +00:00
|
|
|
|
2009-10-16 10:48:50 +00:00
|
|
|
if (!(server = qemudInitialize())) {
|
2009-10-16 11:14:54 +00:00
|
|
|
ret = VIR_DAEMON_ERR_INIT;
|
2009-10-16 10:48:50 +00:00
|
|
|
goto error;
|
2007-12-05 15:34:05 +00:00
|
|
|
}
|
2007-02-16 18:28:17 +00:00
|
|
|
|
2009-10-16 11:14:54 +00:00
|
|
|
if ((daemonSetupSignals(server)) < 0) {
|
|
|
|
ret = VIR_DAEMON_ERR_SIGNAL;
|
2009-10-16 10:48:50 +00:00
|
|
|
goto error;
|
2009-10-16 11:14:54 +00:00
|
|
|
}
|
2009-10-16 10:48:50 +00:00
|
|
|
|
2007-12-05 15:34:05 +00:00
|
|
|
/* Read the config file (if it exists). */
|
2009-10-16 11:14:54 +00:00
|
|
|
if (remoteReadConfigFile (server, remote_config_file) < 0) {
|
|
|
|
ret = VIR_DAEMON_ERR_CONFIG;
|
2009-10-16 10:48:50 +00:00
|
|
|
goto error;
|
2009-10-16 11:14:54 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2010-09-15 13:44:11 +00:00
|
|
|
if (audit_level) {
|
|
|
|
if (virAuditOpen() < 0) {
|
|
|
|
if (audit_level > 1) {
|
|
|
|
ret = VIR_DAEMON_ERR_AUDIT;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
virAuditLog(audit_logging);
|
|
|
|
|
2010-03-26 14:53:32 +00:00
|
|
|
/* setup the hooks if any */
|
2010-03-30 13:06:13 +00:00
|
|
|
if (virHookInitialize() < 0) {
|
2010-03-26 14:53:32 +00:00
|
|
|
ret = VIR_DAEMON_ERR_HOOKS;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-10-19 17:28:28 +00:00
|
|
|
/* Disable error func, now logging is setup */
|
|
|
|
virSetErrorFunc(NULL, virshErrorHandler);
|
|
|
|
|
2010-03-26 14:53:32 +00:00
|
|
|
/*
|
|
|
|
* Call the daemon startup hook
|
|
|
|
* TODO: should we abort the daemon startup if the script returned
|
|
|
|
* an error ?
|
|
|
|
*/
|
|
|
|
virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_START,
|
|
|
|
0, "start", NULL);
|
|
|
|
|
2009-10-16 10:24:01 +00:00
|
|
|
if (qemudNetworkInit(server) < 0) {
|
2009-10-16 11:14:54 +00:00
|
|
|
ret = VIR_DAEMON_ERR_NETWORK;
|
2009-10-16 10:48:50 +00:00
|
|
|
goto error;
|
2007-12-05 15:34:05 +00:00
|
|
|
}
|
|
|
|
|
2009-10-16 11:14:54 +00:00
|
|
|
/* Tell parent of daemon that basic initialization is complete
|
|
|
|
* In particular we're ready to accept net connections & have
|
|
|
|
* written the pidfile
|
|
|
|
*/
|
|
|
|
if (statuswrite != -1) {
|
|
|
|
char status = 0;
|
|
|
|
while (write(statuswrite, &status, 1) == -1 &&
|
|
|
|
errno == EINTR)
|
|
|
|
;
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(statuswrite);
|
2009-10-16 11:14:54 +00:00
|
|
|
}
|
|
|
|
|
2009-10-16 15:34:37 +00:00
|
|
|
/* Start the event loop in a background thread, since
|
|
|
|
* state initialization needs events to be being processed */
|
|
|
|
if (qemudStartEventLoop(server) < 0) {
|
2010-05-20 06:14:50 +00:00
|
|
|
VIR_ERROR0(_("Event thread startup failed"));
|
2009-10-16 15:34:37 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-10-16 11:14:54 +00:00
|
|
|
/* Start the stateful HV drivers
|
|
|
|
* This is delibrately done after telling the parent process
|
|
|
|
* we're ready, since it can take a long time and this will
|
|
|
|
* seriously delay OS bootup process */
|
|
|
|
if (virStateInitialize(server->privileged) < 0) {
|
2010-05-20 06:14:50 +00:00
|
|
|
VIR_ERROR0(_("Driver state initialization failed"));
|
2009-11-13 10:34:47 +00:00
|
|
|
goto shutdown;
|
2009-10-16 11:14:54 +00:00
|
|
|
}
|
2007-02-14 01:40:09 +00:00
|
|
|
|
2009-10-16 15:34:37 +00:00
|
|
|
/* Start accepting new clients from network */
|
|
|
|
virMutexLock(&server->lock);
|
|
|
|
if (qemudNetworkEnable(server) < 0) {
|
2010-05-20 06:14:50 +00:00
|
|
|
VIR_ERROR0(_("Network event loop enablement failed"));
|
2009-10-16 15:34:37 +00:00
|
|
|
goto shutdown;
|
|
|
|
}
|
|
|
|
virMutexUnlock(&server->lock);
|
|
|
|
|
2007-02-23 12:48:36 +00:00
|
|
|
ret = 0;
|
|
|
|
|
2009-10-16 15:34:37 +00:00
|
|
|
shutdown:
|
|
|
|
/* In a non-0 shutdown scenario we need to tell event loop
|
|
|
|
* to quit immediately. Otherwise in normal case we just
|
|
|
|
* sit in the thread join forever. Sure this means the
|
|
|
|
* main thread doesn't do anything useful ever, but that's
|
|
|
|
* not too much of drain on resources
|
|
|
|
*/
|
|
|
|
if (ret != 0) {
|
|
|
|
virMutexLock(&server->lock);
|
|
|
|
if (server->hasEventThread)
|
|
|
|
/* This SIGQUIT triggers the shutdown process */
|
|
|
|
kill(getpid(), SIGQUIT);
|
|
|
|
virMutexUnlock(&server->lock);
|
|
|
|
}
|
|
|
|
pthread_join(server->eventThread, NULL);
|
|
|
|
|
2010-03-26 14:53:32 +00:00
|
|
|
virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_SHUTDOWN,
|
|
|
|
0, "shutdown", NULL);
|
|
|
|
|
2009-10-16 10:48:50 +00:00
|
|
|
error:
|
2009-10-16 11:14:54 +00:00
|
|
|
if (statuswrite != -1) {
|
|
|
|
if (ret != 0) {
|
|
|
|
/* Tell parent of daemon what failed */
|
|
|
|
char status = ret;
|
|
|
|
while (write(statuswrite, &status, 1) == -1 &&
|
|
|
|
errno == EINTR)
|
|
|
|
;
|
|
|
|
}
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(statuswrite);
|
2009-10-16 11:14:54 +00:00
|
|
|
}
|
2008-03-03 18:10:19 +00:00
|
|
|
if (server)
|
|
|
|
qemudCleanup(server);
|
2008-05-20 16:17:36 +00:00
|
|
|
if (pid_file)
|
|
|
|
unlink (pid_file);
|
2008-12-22 12:53:26 +00:00
|
|
|
virLogShutdown();
|
2007-02-23 12:48:36 +00:00
|
|
|
return ret;
|
2007-02-14 01:40:09 +00:00
|
|
|
}
|