+Wed Dec 5 10:20:00 EST 2007 Daniel P. Berrange <berrange@redhat.com>
+
+ * configure.in: Add checks for SASL library
+ * include/libvirt/virterror.h: Add VIR_ERR_AUTH_FAILED
+ * libvirt.spec.in: Add deps on cyrus-sasl & md5 plugin
+ and add SASL config file
+ * qemud/Makefile.am: Add SASL config file & build flags
+ * qemud/remote_protocol.x: new RPC calls for SASL
+ * qemud/internal.h, qemud/qemud.c, qemud/remote.c: Server
+ side of SASL authentication support
+ * qemud/libvirtd.init.in, qemud/libvirtd.sysconf: Set
+ KRB5_KTNAME to tell daemon where kerberos keytab lives
+ * qemud/libvirtd.sasl: example SASL config file
+ * src/Makefile.am, tests/Makefile.am: add SASL build flags
+ * src/remote_internal.c: Add support for SASL auth client
+ * src/virterror.c: Add VOIR_ERR_AUTH_FAILED string
+
Wed Dec 5 10:07:00 EST 2007 Daniel P. Berrange <berrange@redhat.com>
* src/qemu_conf.c: Strip out NIC interfaces named vnetXXX since
LDFLAGS="$old_ldflags"
+dnl Cyrus SASL
+AC_ARG_WITH(sasl,
+ [ --with-sasl use cyrus SASL for authentication],
+ [],
+ [with_sasl=yes])
+
+SASL_CFLAGS=
+SASL_LIBS=
+if test "$with_sasl" != "no"; then
+ if test "$with_sasl" != "yes"; then
+ SASL_CFLAGS="-I$with_sasl"
+ SASL_LIBS="-L$with_sasl"
+ fi
+ old_cflags="$CFLAGS"
+ old_libs="$LIBS"
+ CFLAGS="$CFLAGS $SASL_CFLAGS"
+ LIBS="$LIBS $SASL_LIBS"
+ AC_CHECK_HEADER([sasl/sasl.h],
+ [],
+ AC_MSG_ERROR([You must install the Cyrus SASL development package in order to compile libvirt]))
+ AC_CHECK_LIB(sasl2, sasl_client_init,
+ [],
+ [AC_MSG_ERROR([You must install the Cyrus SASL library in order to compile and run libvirt])])
+ CFLAGS="$old_cflags"
+ LIBS="$old_libs"
+ SASL_LIBS="$SASL_LIBS -lsasl2"
+ AC_DEFINE_UNQUOTED(HAVE_SASL, 1, [whether Cyrus SASL is available for authentication])
+fi
+AM_CONDITIONAL(HAVE_SASL, [test "$with_sasl" != "no"])
+AC_SUBST(SASL_CFLAGS)
+AC_SUBST(SASL_LIBS)
+
+
+
dnl Avahi library
AC_ARG_WITH(avahi,
[ --with-avahi use avahi to advertise remote daemon],
AC_MSG_NOTICE([])
AC_MSG_NOTICE([ libxml: $LIBXML_CFLAGS $LIBXML_LIBS])
AC_MSG_NOTICE([ gnutls: $GNUTLS_CFLAGS $GNUTLS_LIBS])
+if test "$with_sasl" != "no" ; then
+AC_MSG_NOTICE([ sasl: $SASL_CFLAGS $SASL_LIBS])
+else
+AC_MSG_NOTICE([ sasl: no])
+fi
if test "$with_avahi" = "yes" ; then
AC_MSG_NOTICE([ avahi: $AVAHI_CFLAGS $AVAHI_LIBS])
else
VIR_ERR_NO_DOMAIN, /* domain not found or unexpectedly disappeared */
VIR_ERR_NO_NETWORK, /* network not found */
VIR_ERR_INVALID_MAC, /* invalid MAC adress */
+ VIR_ERR_AUTH_FAILED, /* authentication failed */
} virErrorNumber;
/**
Requires: dnsmasq
Requires: bridge-utils
Requires: iptables
+Requires: cyrus-sasl
+# Not technically required, but makes 'out-of-box' config
+# work correctly & doesn't have onerous dependancies
+Requires: cyrus-sasl-md5
BuildRequires: xen-devel
BuildRequires: libxml2-devel
BuildRequires: readline-devel
BuildRequires: dnsmasq
BuildRequires: bridge-utils
BuildRequires: qemu
+BuildRequires: cyrus-sasl-devel
Obsoletes: libvir
ExclusiveArch: i386 x86_64 ia64
%config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
%config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
%config(noreplace) %{_sysconfdir}/libvirt/qemu.conf
+%config(noreplace) %{_sysconfdir}/sasl2/libvirt.conf
%dir %{_datadir}/libvirt/
%dir %{_datadir}/libvirt/networks/
%{_datadir}/libvirt/networks/default.xml
remote_dispatch_localvars.h \
remote_dispatch_proc_switch.h \
mdns.c mdns.h \
+ libvirtd.sasl \
$(conf_DATA)
libvirtd_SOURCES = \
#-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L
libvirtd_CFLAGS = \
-I$(top_srcdir)/include -I$(top_builddir)/include \
- $(LIBXML_CFLAGS) $(GNUTLS_CFLAGS) \
+ $(LIBXML_CFLAGS) $(GNUTLS_CFLAGS) $(SASL_CFLAGS) \
$(WARN_CFLAGS) -DLOCAL_STATE_DIR="\"$(localstatedir)\"" \
-DSYSCONF_DIR="\"$(sysconfdir)\"" \
-DQEMUD_PID_FILE="\"$(QEMUD_PID_FILE)\"" \
-DREMOTE_PID_FILE="\"$(REMOTE_PID_FILE)\"" \
-DGETTEXT_PACKAGE=\"$(PACKAGE)\"
-libvirtd_LDFLAGS = $(WARN_CFLAGS) $(LIBXML_LIBS) $(GNUTLS_LIBS)
+libvirtd_LDFLAGS = $(WARN_CFLAGS) $(LIBXML_LIBS) $(GNUTLS_LIBS) $(SASL_LIBS)
libvirtd_DEPENDENCIES = ../src/libvirt.la
libvirtd_LDADD = ../src/libvirt.la
endif
default_xml_dest = libvirt/qemu/networks/default.xml
-install-data-local: install-init
+install-data-local: install-init install-data-sasl
mkdir -p $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart
$(INSTALL_DATA) $(srcdir)/default-network.xml \
$(DESTDIR)$(sysconfdir)/$(default_xml_dest)
mkdir -p $(DESTDIR)$(localstatedir)/run/libvirt
mkdir -p $(DESTDIR)$(localstatedir)/lib/libvirt
-uninstall-local: uninstall-init
+uninstall-local:: uninstall-init uninstall-data-sasl
rm -f $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
rm -f $(DESTDIR)$(sysconfdir)/$(default_xml_dest)
rmdir $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart || :
rmdir $(DESTDIR)$(localstatedir)/run/libvirt || :
rmdir $(DESTDIR)$(localstatedir)/lib/libvirt || :
+if HAVE_SASL
+install-data-sasl:: install-init
+ mkdir -p $(DESTDIR)$(sysconfdir)/sasl2/
+ $(INSTALL_DATA) $(srcdir)/libvirtd.sasl $(DESTDIR)$(sysconfdir)/sasl2/libvirt.conf
+
+uninstall-data-sasl:: install-init
+ rm -f $(DESTDIR)$(sysconfdir)/sasl2/libvirt.conf
+ rmdir $(DESTDIR)$(sysconfdir)/sasl2/
+else
+install-data-sasl:
+uninstall-data-sasl:
+endif
if RPCGEN
.x.c:
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "../src/gnutls_1_0_compat.h"
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
#ifdef HAVE_SYS_SYSLIMITS_H
#include <sys/syslimits.h>
int tls;
gnutls_session_t session;
enum qemud_tls_direction direction;
+ int auth;
+#if HAVE_SASL
+ sasl_conn_t *saslconn;
+#endif
unsigned int incomingSerial;
unsigned int outgoingSerial;
int readonly;
/* If set, TLS is required on this socket. */
int tls;
+ int auth;
int port;
struct qemud_socket *next;
};
LIBVIRTD_CONFIG=
LIBVIRTD_ARGS=
+KRB5_KTNAME=/etc/libvirt/krb5.tab
test -f @sysconfdir@/sysconfig/libvirtd && . @sysconfdir@/sysconfig/libvirtd
start() {
echo -n $"Starting $SERVICE daemon: "
- daemon --check $SERVICE $PROCESS --daemon $LIBVIRTD_CONFIG_ARGS $LIBVIRTD_ARGS
+ KRB5_KTNAME=$KRB5_KTNAME daemon --check $SERVICE $PROCESS --daemon $LIBVIRTD_CONFIG_ARGS $LIBVIRTD_ARGS
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch @localstatedir@/lock/subsys/$SERVICE
# Listen for TCP/IP connections
# NB. must setup TLS/SSL keys prior to using this
#LIBVIRTD_ARGS="--listen"
+
+# Override Kerberos service keytab for SASL/GSSAPI
+#KRB5_KTNAME=/etc/libvirt/krb5.tab
static int
remoteListenTCP (struct qemud_server *server,
const char *port,
- int tls)
+ int tls,
+ int auth)
{
int fds[2];
int nfds = 0;
sock->fd = fds[i];
sock->tls = tls;
+ sock->auth = auth;
if (getsockname(sock->fd, (struct sockaddr *)(&sa), &salen) < 0)
return -1;
struct qemud_socket *sock;
char sockname[PATH_MAX];
char roSockname[PATH_MAX];
+#if HAVE_SASL
+ int err;
+#endif /* HAVE_SASL */
if (!(server = calloc(1, sizeof(struct qemud_server)))) {
qemudLog(QEMUD_ERR, "Failed to allocate struct qemud_server");
virStateInitialize();
+#if HAVE_SASL
+ if ((err = sasl_server_init(NULL, "libvirt")) != SASL_OK) {
+ qemudLog(QEMUD_ERR, "Failed to initialize SASL authentication %s",
+ sasl_errstring(err, NULL, NULL));
+ goto cleanup;
+ }
+#endif
+
if (ipsock) {
- if (listen_tcp && remoteListenTCP (server, tcp_port, 0) < 0)
+#if HAVE_SASL
+ if (listen_tcp && remoteListenTCP (server, tcp_port, 0, REMOTE_AUTH_SASL) < 0)
+ goto cleanup;
+#else
+ if (listen_tcp && remoteListenTCP (server, tcp_port, 0, REMOTE_AUTH_NONE) < 0)
goto cleanup;
+#endif
if (listen_tls) {
if (remoteInitializeGnuTLS () < 0)
goto cleanup;
- if (remoteListenTCP (server, tls_port, 1) < 0)
+ if (remoteListenTCP (server, tls_port, 1, REMOTE_AUTH_NONE) < 0)
goto cleanup;
}
}
client->fd = fd;
client->readonly = sock->readonly;
client->tls = sock->tls;
+ client->auth = sock->auth;
memcpy (&client->addr, &addr, sizeof addr);
client->addrlen = addrlen;
if (client->conn)
virConnectClose(client->conn);
+#if HAVE_SASL
+ if (client->saslconn) sasl_dispose(&client->saslconn);
+#endif
if (client->tls && client->session) gnutls_deinit (client->session);
close(client->fd);
free(client);
#define DEBUG 0
+#define REMOTE_DEBUG(fmt,...) qemudDebug("REMOTE: " fmt, __VA_ARGS__)
+
static void remoteDispatchError (struct qemud_client *client,
remote_message_header *req,
const char *fmt, ...)
return;
}
+ /* If client is marked as needing auth, don't allow any RPC ops,
+ * except for authentication ones
+ */
+ if (client->auth) {
+ if (req.proc != REMOTE_PROC_AUTH_LIST &&
+ req.proc != REMOTE_PROC_AUTH_SASL_INIT &&
+ req.proc != REMOTE_PROC_AUTH_SASL_START &&
+ req.proc != REMOTE_PROC_AUTH_SASL_STEP
+ ) {
+ remoteDispatchError (client, &req, "authentication required");
+ xdr_destroy (&xdr);
+ return;
+ }
+ }
+
/* Based on the procedure number, dispatch. In future we may base
* this on the version number as well.
*/
* reply.
*/
static void
-remoteDispatchError (struct qemud_client *client,
- remote_message_header *req,
- const char *fmt, ...)
+remoteDispatchSendError (struct qemud_client *client,
+ remote_message_header *req,
+ int code, const char *msg)
{
remote_message_header rep;
remote_error error;
- va_list args;
- char msgbuf[1024];
- char *msg = msgbuf;
XDR xdr;
int len;
- va_start (args, fmt);
- vsnprintf (msgbuf, sizeof msgbuf, fmt, args);
- va_end (args);
-
- qemudDebug ("%s", msgbuf);
-
/* Future versions of the protocol may use different vers or prog. Try
* our hardest to send back a message that such clients could see.
*/
}
/* Construct the error. */
- error.code = VIR_ERR_RPC;
+ error.code = code;
error.domain = VIR_FROM_REMOTE;
- error.message = &msg;
+ error.message = (char**)&msg;
error.level = VIR_ERR_ERROR;
error.dom = NULL;
- error.str1 = &msg;
+ error.str1 = (char**)&msg;
error.str2 = NULL;
error.str3 = NULL;
error.int1 = 0;
if (client->tls) client->direction = QEMUD_TLS_DIRECTION_WRITE;
}
+static void
+remoteDispatchFailAuth (struct qemud_client *client,
+ remote_message_header *req)
+{
+ remoteDispatchSendError (client, req, VIR_ERR_AUTH_FAILED, "authentication failed");
+}
+
+static void
+remoteDispatchError (struct qemud_client *client,
+ remote_message_header *req,
+ const char *fmt, ...)
+{
+ va_list args;
+ char msgbuf[1024];
+ char *msg = msgbuf;
+
+ va_start (args, fmt);
+ vsnprintf (msgbuf, sizeof msgbuf, fmt, args);
+ va_end (args);
+
+ remoteDispatchSendError (client, req, VIR_ERR_RPC, msg);
+}
+
+
+
/*----- Functions. -----*/
static int
return 0;
}
+
+static int
+remoteDispatchAuthList (struct qemud_client *client,
+ remote_message_header *req ATTRIBUTE_UNUSED,
+ void *args ATTRIBUTE_UNUSED,
+ remote_auth_list_ret *ret)
+{
+ ret->types.types_len = 1;
+ if ((ret->types.types_val = calloc (ret->types.types_len, sizeof (remote_auth_type))) == NULL) {
+ remoteDispatchSendError(client, req, VIR_ERR_NO_MEMORY, "auth types");
+ return -2;
+ }
+ ret->types.types_val[0] = client->auth;
+ return 0;
+}
+
+
+#if HAVE_SASL
+/*
+ * NB, keep in sync with similar method in src/remote_internal.c
+ */
+static char *addrToString(struct qemud_client *client,
+ remote_message_header *req,
+ struct sockaddr_storage *sa, socklen_t salen) {
+ char host[1024], port[20];
+ char *addr;
+ int err;
+
+ if ((err = getnameinfo((struct sockaddr *)sa, salen,
+ host, sizeof(host),
+ port, sizeof(port),
+ NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+ remoteDispatchError(client, req,
+ "Cannot resolve address %d: %s", err, gai_strerror(err));
+ return NULL;
+ }
+
+ addr = malloc(strlen(host) + 1 + strlen(port) + 1);
+ if (!addr) {
+ remoteDispatchError(client, req, "cannot allocate address");
+ return NULL;
+ }
+
+ strcpy(addr, host);
+ strcat(addr, ";");
+ strcat(addr, port);
+ return addr;
+}
+
+
+/*
+ * Initializes the SASL session in prepare for authentication
+ * and gives the client a list of allowed mechansims to choose
+ *
+ * XXX callbacks for stuff like password verification ?
+ */
+static int
+remoteDispatchAuthSaslInit (struct qemud_client *client,
+ remote_message_header *req,
+ void *args ATTRIBUTE_UNUSED,
+ remote_auth_sasl_init_ret *ret)
+{
+ const char *mechlist = NULL;
+ int err;
+ struct sockaddr_storage sa;
+ socklen_t salen;
+ char *localAddr, *remoteAddr;
+
+ REMOTE_DEBUG("Initialize SASL auth %d", client->fd);
+ if (client->auth != REMOTE_AUTH_SASL ||
+ client->saslconn != NULL) {
+ qemudLog(QEMUD_ERR, "client tried invalid SASL init request");
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+
+ /* Get local address in form IPADDR:PORT */
+ salen = sizeof(sa);
+ if (getsockname(client->fd, (struct sockaddr*)&sa, &salen) < 0) {
+ remoteDispatchError(client, req, "failed to get sock address %d (%s)",
+ errno, strerror(errno));
+ return -2;
+ }
+ if ((localAddr = addrToString(client, req, &sa, salen)) == NULL) {
+ return -2;
+ }
+
+ /* Get remote address in form IPADDR:PORT */
+ salen = sizeof(sa);
+ if (getpeername(client->fd, (struct sockaddr*)&sa, &salen) < 0) {
+ remoteDispatchError(client, req, "failed to get peer address %d (%s)",
+ errno, strerror(errno));
+ free(localAddr);
+ return -2;
+ }
+ if ((remoteAddr = addrToString(client, req, &sa, salen)) == NULL) {
+ free(localAddr);
+ return -2;
+ }
+
+ err = sasl_server_new("libvirt",
+ NULL, /* FQDN - just delegates to gethostname */
+ NULL, /* User realm */
+ localAddr,
+ remoteAddr,
+ NULL, /* XXX Callbacks */
+ SASL_SUCCESS_DATA,
+ &client->saslconn);
+ free(localAddr);
+ free(remoteAddr);
+ if (err != SASL_OK) {
+ qemudLog(QEMUD_ERR, "sasl context setup failed %d (%s)",
+ err, sasl_errstring(err, NULL, NULL));
+ remoteDispatchFailAuth(client, req);
+ client->saslconn = NULL;
+ return -2;
+ }
+
+ err = sasl_listmech(client->saslconn,
+ NULL, /* Don't need to set user */
+ "", /* Prefix */
+ ",", /* Separator */
+ "", /* Suffix */
+ &mechlist,
+ NULL,
+ NULL);
+ if (err != SASL_OK) {
+ qemudLog(QEMUD_ERR, "cannot list SASL mechanisms %d (%s)",
+ err, sasl_errdetail(client->saslconn));
+ remoteDispatchFailAuth(client, req);
+ sasl_dispose(&client->saslconn);
+ client->saslconn = NULL;
+ return -2;
+ }
+ REMOTE_DEBUG("Available mechanisms for client: '%s'", mechlist);
+ ret->mechlist = strdup(mechlist);
+ if (!ret->mechlist) {
+ qemudLog(QEMUD_ERR, "cannot allocate mechlist");
+ remoteDispatchFailAuth(client, req);
+ sasl_dispose(&client->saslconn);
+ client->saslconn = NULL;
+ return -2;
+ }
+
+ return 0;
+}
+
+
+/*
+ * This starts the SASL authentication negotiation.
+ */
+static int
+remoteDispatchAuthSaslStart (struct qemud_client *client,
+ remote_message_header *req,
+ remote_auth_sasl_start_args *args,
+ remote_auth_sasl_start_ret *ret)
+{
+ const char *serverout;
+ unsigned int serveroutlen;
+ int err;
+
+ REMOTE_DEBUG("Start SASL auth %d", client->fd);
+ if (client->auth != REMOTE_AUTH_SASL ||
+ client->saslconn == NULL) {
+ qemudLog(QEMUD_ERR, "client tried invalid SASL start request");
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+
+ REMOTE_DEBUG("Using SASL mechanism %s. Data %d bytes, nil: %d",
+ args->mech, args->data.data_len, args->nil);
+ err = sasl_server_start(client->saslconn,
+ args->mech,
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ args->nil ? NULL : args->data.data_val,
+ args->data.data_len,
+ &serverout,
+ &serveroutlen);
+ if (err != SASL_OK &&
+ err != SASL_CONTINUE) {
+ qemudLog(QEMUD_ERR, "sasl start failed %d (%s)",
+ err, sasl_errdetail(client->saslconn));
+ sasl_dispose(&client->saslconn);
+ client->saslconn = NULL;
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+ if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
+ qemudLog(QEMUD_ERR, "sasl start reply data too long %d", serveroutlen);
+ sasl_dispose(&client->saslconn);
+ client->saslconn = NULL;
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ if (serverout) {
+ ret->data.data_val = malloc(serveroutlen);
+ if (!ret->data.data_val) {
+ remoteDispatchError (client, req, "out of memory allocating array");
+ return -2;
+ }
+ memcpy(ret->data.data_val, serverout, serveroutlen);
+ } else {
+ ret->data.data_val = NULL;
+ }
+ ret->nil = serverout ? 0 : 1;
+ ret->data.data_len = serveroutlen;
+
+ REMOTE_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
+ if (err == SASL_CONTINUE) {
+ ret->complete = 0;
+ } else {
+ REMOTE_DEBUG("Authentication successful %d", client->fd);
+ ret->complete = 1;
+ client->auth = REMOTE_AUTH_NONE;
+ }
+
+ return 0;
+}
+
+
+static int
+remoteDispatchAuthSaslStep (struct qemud_client *client,
+ remote_message_header *req,
+ remote_auth_sasl_step_args *args,
+ remote_auth_sasl_step_ret *ret)
+{
+ const char *serverout;
+ unsigned int serveroutlen;
+ int err;
+
+ REMOTE_DEBUG("Step SASL auth %d", client->fd);
+ if (client->auth != REMOTE_AUTH_SASL ||
+ client->saslconn == NULL) {
+ qemudLog(QEMUD_ERR, "client tried invalid SASL start request");
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+
+ REMOTE_DEBUG("Using SASL Data %d bytes, nil: %d",
+ args->data.data_len, args->nil);
+ err = sasl_server_step(client->saslconn,
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ args->nil ? NULL : args->data.data_val,
+ args->data.data_len,
+ &serverout,
+ &serveroutlen);
+ if (err != SASL_OK &&
+ err != SASL_CONTINUE) {
+ qemudLog(QEMUD_ERR, "sasl step failed %d (%s)",
+ err, sasl_errdetail(client->saslconn));
+ sasl_dispose(&client->saslconn);
+ client->saslconn = NULL;
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+
+ if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
+ qemudLog(QEMUD_ERR, "sasl step reply data too long %d", serveroutlen);
+ sasl_dispose(&client->saslconn);
+ client->saslconn = NULL;
+ remoteDispatchFailAuth(client, req);
+ return -2;
+ }
+
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ if (serverout) {
+ ret->data.data_val = malloc(serveroutlen);
+ if (!ret->data.data_val) {
+ remoteDispatchError (client, req, "out of memory allocating array");
+ return -2;
+ }
+ memcpy(ret->data.data_val, serverout, serveroutlen);
+ } else {
+ ret->data.data_val = NULL;
+ }
+ ret->nil = serverout ? 0 : 1;
+ ret->data.data_len = serveroutlen;
+
+ REMOTE_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
+ if (err == SASL_CONTINUE) {
+ ret->complete = 0;
+ } else {
+ REMOTE_DEBUG("Authentication successful %d", client->fd);
+ ret->complete = 1;
+ client->auth = REMOTE_AUTH_NONE;
+ }
+
+ return 0;
+}
+
+
+#else /* HAVE_SASL */
+static int
+remoteDispatchAuthSaslInit (struct qemud_client *client,
+ remote_message_header *req,
+ void *args ATTRIBUTE_UNUSED,
+ remote_auth_sasl_init_ret *ret ATTRIBUTE_UNUSED)
+{
+ qemudLog(QEMUD_ERR, "client tried unsupported SASL init request");
+ remoteDispatchFailAuth(client, req);
+ return -1;
+}
+
+static int
+remoteDispatchAuthSaslStart (struct qemud_client *client,
+ remote_message_header *req,
+ remote_auth_sasl_start_args *args ATTRIBUTE_UNUSED,
+ remote_auth_sasl_start_ret *ret ATTRIBUTE_UNUSED)
+{
+ qemudLog(QEMUD_ERR, "client tried unsupported SASL start request");
+ remoteDispatchFailAuth(client, req);
+ return -1;
+}
+
+static int
+remoteDispatchAuthSaslStep (struct qemud_client *client,
+ remote_message_header *req,
+ remote_auth_sasl_step_args *args ATTRIBUTE_UNUSED,
+ remote_auth_sasl_step_ret *ret ATTRIBUTE_UNUSED)
+{
+ qemudLog(QEMUD_ERR, "client tried unsupported SASL step request");
+ remoteDispatchFailAuth(client, req);
+ return -1;
+}
+#endif /* HAVE_SASL */
+
+
/*----- Helpers. -----*/
/* get_nonnull_domain and get_nonnull_network turn an on-wire
remote_list_defined_domains_ret lv_remote_list_defined_domains_ret;
remote_get_capabilities_ret lv_remote_get_capabilities_ret;
remote_domain_set_max_memory_args lv_remote_domain_set_max_memory_args;
+remote_auth_sasl_init_ret lv_remote_auth_sasl_init_ret;
remote_domain_get_os_type_args lv_remote_domain_get_os_type_args;
remote_domain_get_os_type_ret lv_remote_domain_get_os_type_ret;
remote_domain_get_autostart_args lv_remote_domain_get_autostart_args;
remote_domain_create_linux_args lv_remote_domain_create_linux_args;
remote_domain_create_linux_ret lv_remote_domain_create_linux_ret;
remote_domain_set_scheduler_parameters_args lv_remote_domain_set_scheduler_parameters_args;
+remote_auth_sasl_start_args lv_remote_auth_sasl_start_args;
+remote_auth_sasl_start_ret lv_remote_auth_sasl_start_ret;
remote_domain_interface_stats_args lv_remote_domain_interface_stats_args;
remote_domain_interface_stats_ret lv_remote_domain_interface_stats_ret;
remote_domain_get_max_vcpus_args lv_remote_domain_get_max_vcpus_args;
remote_network_get_bridge_name_args lv_remote_network_get_bridge_name_args;
remote_network_get_bridge_name_ret lv_remote_network_get_bridge_name_ret;
remote_domain_destroy_args lv_remote_domain_destroy_args;
+remote_auth_sasl_step_args lv_remote_auth_sasl_step_args;
+remote_auth_sasl_step_ret lv_remote_auth_sasl_step_ret;
remote_domain_migrate_finish_args lv_remote_domain_migrate_finish_args;
remote_domain_migrate_finish_ret lv_remote_domain_migrate_finish_ret;
remote_domain_get_vcpus_args lv_remote_domain_get_vcpus_args;
remote_network_set_autostart_args lv_remote_network_set_autostart_args;
remote_network_get_autostart_args lv_remote_network_get_autostart_args;
remote_network_get_autostart_ret lv_remote_network_get_autostart_ret;
+remote_auth_list_ret lv_remote_auth_list_ret;
remote_domain_core_dump_args lv_remote_domain_core_dump_args;
remote_domain_get_max_memory_args lv_remote_domain_get_max_memory_args;
remote_domain_get_max_memory_ret lv_remote_domain_get_max_memory_ret;
* Do not edit this file. Any changes you make will be lost.
*/
+case REMOTE_PROC_AUTH_LIST:
+ fn = (dispatch_fn) remoteDispatchAuthList;
+ ret_filter = (xdrproc_t) xdr_remote_auth_list_ret;
+ ret = (char *) &lv_remote_auth_list_ret;
+ memset (&lv_remote_auth_list_ret, 0, sizeof lv_remote_auth_list_ret);
+ break;
+case REMOTE_PROC_AUTH_SASL_INIT:
+ fn = (dispatch_fn) remoteDispatchAuthSaslInit;
+ ret_filter = (xdrproc_t) xdr_remote_auth_sasl_init_ret;
+ ret = (char *) &lv_remote_auth_sasl_init_ret;
+ memset (&lv_remote_auth_sasl_init_ret, 0, sizeof lv_remote_auth_sasl_init_ret);
+ break;
+case REMOTE_PROC_AUTH_SASL_START:
+ fn = (dispatch_fn) remoteDispatchAuthSaslStart;
+ args_filter = (xdrproc_t) xdr_remote_auth_sasl_start_args;
+ args = (char *) &lv_remote_auth_sasl_start_args;
+ memset (&lv_remote_auth_sasl_start_args, 0, sizeof lv_remote_auth_sasl_start_args);
+ ret_filter = (xdrproc_t) xdr_remote_auth_sasl_start_ret;
+ ret = (char *) &lv_remote_auth_sasl_start_ret;
+ memset (&lv_remote_auth_sasl_start_ret, 0, sizeof lv_remote_auth_sasl_start_ret);
+ break;
+case REMOTE_PROC_AUTH_SASL_STEP:
+ fn = (dispatch_fn) remoteDispatchAuthSaslStep;
+ args_filter = (xdrproc_t) xdr_remote_auth_sasl_step_args;
+ args = (char *) &lv_remote_auth_sasl_step_args;
+ memset (&lv_remote_auth_sasl_step_args, 0, sizeof lv_remote_auth_sasl_step_args);
+ ret_filter = (xdrproc_t) xdr_remote_auth_sasl_step_ret;
+ ret = (char *) &lv_remote_auth_sasl_step_ret;
+ memset (&lv_remote_auth_sasl_step_ret, 0, sizeof lv_remote_auth_sasl_step_ret);
+ break;
case REMOTE_PROC_CLOSE:
fn = (dispatch_fn) remoteDispatchClose;
break;
* Do not edit this file. Any changes you make will be lost.
*/
+static int remoteDispatchAuthList (struct qemud_client *client, remote_message_header *req, void *args, remote_auth_list_ret *ret);
+static int remoteDispatchAuthSaslInit (struct qemud_client *client, remote_message_header *req, void *args, remote_auth_sasl_init_ret *ret);
+static int remoteDispatchAuthSaslStart (struct qemud_client *client, remote_message_header *req, remote_auth_sasl_start_args *args, remote_auth_sasl_start_ret *ret);
+static int remoteDispatchAuthSaslStep (struct qemud_client *client, remote_message_header *req, remote_auth_sasl_step_args *args, remote_auth_sasl_step_ret *ret);
static int remoteDispatchClose (struct qemud_client *client, remote_message_header *req, void *args, void *ret);
static int remoteDispatchDomainAttachDevice (struct qemud_client *client, remote_message_header *req, remote_domain_attach_device_args *args, void *ret);
static int remoteDispatchDomainBlockStats (struct qemud_client *client, remote_message_header *req, remote_domain_block_stats_args *args, remote_domain_block_stats_ret *ret);
return TRUE;
}
+bool_t
+xdr_remote_auth_type (XDR *xdrs, remote_auth_type *objp)
+{
+
+ if (!xdr_enum (xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
bool_t
xdr_remote_vcpu_info (XDR *xdrs, remote_vcpu_info *objp)
{
return TRUE;
}
+bool_t
+xdr_remote_auth_list_ret (XDR *xdrs, remote_auth_list_ret *objp)
+{
+ char **objp_cpp0 = (char **) (void *) &objp->types.types_val;
+
+ if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->types.types_len, REMOTE_AUTH_TYPE_LIST_MAX,
+ sizeof (remote_auth_type), (xdrproc_t) xdr_remote_auth_type))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_remote_auth_sasl_init_ret (XDR *xdrs, remote_auth_sasl_init_ret *objp)
+{
+
+ if (!xdr_remote_nonnull_string (xdrs, &objp->mechlist))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_remote_auth_sasl_start_args (XDR *xdrs, remote_auth_sasl_start_args *objp)
+{
+ char **objp_cpp0 = (char **) (void *) &objp->data.data_val;
+
+ if (!xdr_remote_nonnull_string (xdrs, &objp->mech))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->nil))
+ return FALSE;
+ if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->data.data_len, REMOTE_AUTH_SASL_DATA_MAX,
+ sizeof (char), (xdrproc_t) xdr_char))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_remote_auth_sasl_start_ret (XDR *xdrs, remote_auth_sasl_start_ret *objp)
+{
+ char **objp_cpp0 = (char **) (void *) &objp->data.data_val;
+
+ if (!xdr_int (xdrs, &objp->complete))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->nil))
+ return FALSE;
+ if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->data.data_len, REMOTE_AUTH_SASL_DATA_MAX,
+ sizeof (char), (xdrproc_t) xdr_char))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_remote_auth_sasl_step_args (XDR *xdrs, remote_auth_sasl_step_args *objp)
+{
+ char **objp_cpp0 = (char **) (void *) &objp->data.data_val;
+
+ if (!xdr_int (xdrs, &objp->nil))
+ return FALSE;
+ if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->data.data_len, REMOTE_AUTH_SASL_DATA_MAX,
+ sizeof (char), (xdrproc_t) xdr_char))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
+xdr_remote_auth_sasl_step_ret (XDR *xdrs, remote_auth_sasl_step_ret *objp)
+{
+ char **objp_cpp0 = (char **) (void *) &objp->data.data_val;
+
+ if (!xdr_int (xdrs, &objp->complete))
+ return FALSE;
+ if (!xdr_int (xdrs, &objp->nil))
+ return FALSE;
+ if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->data.data_len, REMOTE_AUTH_SASL_DATA_MAX,
+ sizeof (char), (xdrproc_t) xdr_char))
+ return FALSE;
+ return TRUE;
+}
+
bool_t
xdr_remote_procedure (XDR *xdrs, remote_procedure *objp)
{
#define REMOTE_MIGRATE_COOKIE_MAX 256
#define REMOTE_NETWORK_NAME_LIST_MAX 256
#define REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX 16
+#define REMOTE_AUTH_SASL_DATA_MAX 65536
+#define REMOTE_AUTH_TYPE_LIST_MAX 20
typedef char remote_uuid[VIR_UUID_BUFLEN];
};
typedef struct remote_error remote_error;
+enum remote_auth_type {
+ REMOTE_AUTH_NONE = 0,
+ REMOTE_AUTH_SASL = 1,
+};
+typedef enum remote_auth_type remote_auth_type;
+
struct remote_vcpu_info {
u_int number;
int state;
int autostart;
};
typedef struct remote_network_set_autostart_args remote_network_set_autostart_args;
+
+struct remote_auth_list_ret {
+ struct {
+ u_int types_len;
+ remote_auth_type *types_val;
+ } types;
+};
+typedef struct remote_auth_list_ret remote_auth_list_ret;
+
+struct remote_auth_sasl_init_ret {
+ remote_nonnull_string mechlist;
+};
+typedef struct remote_auth_sasl_init_ret remote_auth_sasl_init_ret;
+
+struct remote_auth_sasl_start_args {
+ remote_nonnull_string mech;
+ int nil;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct remote_auth_sasl_start_args remote_auth_sasl_start_args;
+
+struct remote_auth_sasl_start_ret {
+ int complete;
+ int nil;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct remote_auth_sasl_start_ret remote_auth_sasl_start_ret;
+
+struct remote_auth_sasl_step_args {
+ int nil;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct remote_auth_sasl_step_args remote_auth_sasl_step_args;
+
+struct remote_auth_sasl_step_ret {
+ int complete;
+ int nil;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct remote_auth_sasl_step_ret remote_auth_sasl_step_ret;
#define REMOTE_PROGRAM 0x20008086
#define REMOTE_PROTOCOL_VERSION 1
REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 63,
REMOTE_PROC_DOMAIN_BLOCK_STATS = 64,
REMOTE_PROC_DOMAIN_INTERFACE_STATS = 65,
+ REMOTE_PROC_AUTH_LIST = 66,
+ REMOTE_PROC_AUTH_SASL_INIT = 67,
+ REMOTE_PROC_AUTH_SASL_START = 68,
+ REMOTE_PROC_AUTH_SASL_STEP = 69,
};
typedef enum remote_procedure remote_procedure;
extern bool_t xdr_remote_domain (XDR *, remote_domain*);
extern bool_t xdr_remote_network (XDR *, remote_network*);
extern bool_t xdr_remote_error (XDR *, remote_error*);
+extern bool_t xdr_remote_auth_type (XDR *, remote_auth_type*);
extern bool_t xdr_remote_vcpu_info (XDR *, remote_vcpu_info*);
extern bool_t xdr_remote_sched_param_value (XDR *, remote_sched_param_value*);
extern bool_t xdr_remote_sched_param (XDR *, remote_sched_param*);
extern bool_t xdr_remote_network_get_autostart_args (XDR *, remote_network_get_autostart_args*);
extern bool_t xdr_remote_network_get_autostart_ret (XDR *, remote_network_get_autostart_ret*);
extern bool_t xdr_remote_network_set_autostart_args (XDR *, remote_network_set_autostart_args*);
+extern bool_t xdr_remote_auth_list_ret (XDR *, remote_auth_list_ret*);
+extern bool_t xdr_remote_auth_sasl_init_ret (XDR *, remote_auth_sasl_init_ret*);
+extern bool_t xdr_remote_auth_sasl_start_args (XDR *, remote_auth_sasl_start_args*);
+extern bool_t xdr_remote_auth_sasl_start_ret (XDR *, remote_auth_sasl_start_ret*);
+extern bool_t xdr_remote_auth_sasl_step_args (XDR *, remote_auth_sasl_step_args*);
+extern bool_t xdr_remote_auth_sasl_step_ret (XDR *, remote_auth_sasl_step_ret*);
extern bool_t xdr_remote_procedure (XDR *, remote_procedure*);
extern bool_t xdr_remote_message_direction (XDR *, remote_message_direction*);
extern bool_t xdr_remote_message_status (XDR *, remote_message_status*);
extern bool_t xdr_remote_domain ();
extern bool_t xdr_remote_network ();
extern bool_t xdr_remote_error ();
+extern bool_t xdr_remote_auth_type ();
extern bool_t xdr_remote_vcpu_info ();
extern bool_t xdr_remote_sched_param_value ();
extern bool_t xdr_remote_sched_param ();
extern bool_t xdr_remote_network_get_autostart_args ();
extern bool_t xdr_remote_network_get_autostart_ret ();
extern bool_t xdr_remote_network_set_autostart_args ();
+extern bool_t xdr_remote_auth_list_ret ();
+extern bool_t xdr_remote_auth_sasl_init_ret ();
+extern bool_t xdr_remote_auth_sasl_start_args ();
+extern bool_t xdr_remote_auth_sasl_start_ret ();
+extern bool_t xdr_remote_auth_sasl_step_args ();
+extern bool_t xdr_remote_auth_sasl_step_ret ();
extern bool_t xdr_remote_procedure ();
extern bool_t xdr_remote_message_direction ();
extern bool_t xdr_remote_message_status ();
/* Upper limit on list of scheduler parameters. */
const REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX = 16;
+/* Upper limit on SASL auth negotiation packet */
+const REMOTE_AUTH_SASL_DATA_MAX = 65536;
+
+/* Maximum number of auth types */
+const REMOTE_AUTH_TYPE_LIST_MAX = 20;
+
/* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */
typedef opaque remote_uuid[VIR_UUID_BUFLEN];
remote_network net;
};
+/* Authentication types available thus far.... */
+enum remote_auth_type {
+ REMOTE_AUTH_NONE = 0,
+ REMOTE_AUTH_SASL = 1
+};
+
+
/* Wire encoding of virVcpuInfo. */
struct remote_vcpu_info {
unsigned int number;
int autostart;
};
+struct remote_auth_list_ret {
+ remote_auth_type types<REMOTE_AUTH_TYPE_LIST_MAX>;
+};
+
+struct remote_auth_sasl_init_ret {
+ remote_nonnull_string mechlist;
+};
+
+struct remote_auth_sasl_start_args {
+ remote_nonnull_string mech;
+ int nil;
+ char data<REMOTE_AUTH_SASL_DATA_MAX>;
+};
+
+struct remote_auth_sasl_start_ret {
+ int complete;
+ int nil;
+ char data<REMOTE_AUTH_SASL_DATA_MAX>;
+};
+
+struct remote_auth_sasl_step_args {
+ int nil;
+ char data<REMOTE_AUTH_SASL_DATA_MAX>;
+};
+
+struct remote_auth_sasl_step_ret {
+ int complete;
+ int nil;
+ char data<REMOTE_AUTH_SASL_DATA_MAX>;
+};
+
/*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */
REMOTE_PROC_DOMAIN_MIGRATE_PERFORM = 62,
REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 63,
REMOTE_PROC_DOMAIN_BLOCK_STATS = 64,
- REMOTE_PROC_DOMAIN_INTERFACE_STATS = 65
+ REMOTE_PROC_DOMAIN_INTERFACE_STATS = 65,
+ REMOTE_PROC_AUTH_LIST = 66,
+ REMOTE_PROC_AUTH_SASL_INIT = 67,
+ REMOTE_PROC_AUTH_SASL_START = 68,
+ REMOTE_PROC_AUTH_SASL_STEP = 69
};
/* Custom RPC structure. */
-I@top_srcdir@/qemud \
$(LIBXML_CFLAGS) \
$(GNUTLS_CFLAGS) \
+ $(SASL_CFLAGS) \
-DBINDIR=\""$(libexecdir)"\" \
-DSBINDIR=\""$(sbindir)"\" \
-DSYSCONF_DIR="\"$(sysconfdir)\"" \
../qemud/remote_protocol.c ../qemud/remote_protocol.h
libvirt_la_SOURCES = $(CLIENT_SOURCES) $(SERVER_SOURCES)
-libvirt_la_LIBADD = $(LIBXML_LIBS) $(GNUTLS_LIBS) $(LTLIBOBJS) \
+libvirt_la_LIBADD = $(LIBXML_LIBS) $(GNUTLS_LIBS) $(SASL_LIBS) $(LTLIBOBJS) \
@CYGWIN_EXTRA_LIBADD@
libvirt_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libvirt_sym.version \
-version-info @LIBVIRT_VERSION_INFO@ \
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "gnutls_1_0_compat.h"
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
#include <libxml/uri.h>
#include "internal.h"
char *type; /* Cached return from remoteType. */
int counter; /* Generates serial numbers for RPC. */
int networkOnly; /* Only used for network API */
+ char *hostname; /* Original hostname */
+ FILE *debugLog; /* Debug remote protocol */
+#if HAVE_SASL
+ sasl_conn_t *saslconn; /* SASL context */
+#endif
};
#define GET_PRIVATE(conn,retcode) \
return (retcode); \
}
-static int call (virConnectPtr conn, struct private_data *priv, int in_open, int proc_nr, xdrproc_t args_filter, char *args, xdrproc_t ret_filter, char *ret);
+enum {
+ REMOTE_CALL_IN_OPEN = 1,
+ REMOTE_CALL_QUIET_MISSING_RPC = 2,
+};
+
+
+static int call (virConnectPtr conn, struct private_data *priv,
+ int flags, int proc_nr,
+ xdrproc_t args_filter, char *args,
+ xdrproc_t ret_filter, char *ret);
+static int remoteAuthenticate (virConnectPtr conn, struct private_data *priv, int in_open);
+#if HAVE_SASL
+static int remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open);
+#endif
static void error (virConnectPtr conn, virErrorNumber code, const char *info);
static void server_error (virConnectPtr conn, remote_error *err);
static virDomainPtr get_nonnull_domain (virConnectPtr conn, remote_nonnull_domain domain);
/* GnuTLS functions used by remoteOpen. */
static int initialise_gnutls (virConnectPtr conn);
-static gnutls_session_t negotiate_gnutls_on_connection (virConnectPtr conn, int sock, int no_verify, const char *hostname);
+static gnutls_session_t negotiate_gnutls_on_connection (virConnectPtr conn, struct private_data *priv, int no_verify);
static int
remoteStartup(void)
return 0;
}
+#if HAVE_SASL
+static void
+remoteDebug(struct private_data *priv, const char *msg,...)
+{
+ va_list args;
+ if (priv->debugLog == NULL)
+ return;
+
+ va_start(args, msg);
+ vfprintf(priv->debugLog, msg, args);
+ va_end(args);
+ fprintf(priv->debugLog, "\n");
+}
+#endif /* HAVE_SASL */
+
+
/**
* remoteFindServerPath:
*
* get freed in the failed: path.
*/
char *name = 0, *command = 0, *sockname = 0, *netcat = 0, *username = 0;
- char *server = 0, *port = 0;
+ char *port = 0;
int no_verify = 0, no_tty = 0;
char **cmd_argv = 0;
int retcode = VIR_DRV_OPEN_ERROR;
/* Remote server defaults to "localhost" if not specified. */
- server = strdup (uri->server ? uri->server : "localhost");
- if (!server) {
- out_of_memory:
- error (conn, VIR_ERR_NO_MEMORY, "duplicating server name");
- goto failed;
- }
if (uri->port != 0) {
if (asprintf (&port, "%d", uri->port) == -1) goto out_of_memory;
} else if (transport == trans_tls) {
} else
port = NULL; /* Port not used for unix, ext. */
+
+ priv->hostname = strdup (uri->server ? uri->server : "localhost");
+ if (!priv->hostname) {
+ error (NULL, VIR_ERR_NO_MEMORY, "allocating priv->hostname");
+ goto failed;
+ }
if (uri->user) {
username = strdup (uri->user);
if (!username) goto out_of_memory;
} else if (strcasecmp (var->name, "no_tty") == 0) {
no_tty = atoi (var->value);
var->ignore = 1;
+ } else if (strcasecmp (var->name, "debug") == 0) {
+ if (var->value &&
+ strcasecmp(var->value, "stdout") == 0)
+ priv->debugLog = stdout;
+ else
+ priv->debugLog = stderr;
}
#if DEBUG
else
memset (&hints, 0, sizeof hints);
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_ADDRCONFIG;
- int e = getaddrinfo (server, port, &hints, &res);
+ int e = getaddrinfo (priv->hostname, port, &hints, &res);
if (e != 0) {
error (conn, VIR_ERR_INVALID_ARG, gai_strerror (e));
goto failed;
if (priv->uses_tls) {
priv->session =
negotiate_gnutls_on_connection
- (conn, priv->sock, no_verify, server);
+ (conn, priv, no_verify);
if (!priv->session) {
close (priv->sock);
priv->sock = -1;
cmd_argv[j++] = strdup ("-e");
cmd_argv[j++] = strdup ("none");
}
- cmd_argv[j++] = strdup (server);
+ cmd_argv[j++] = strdup (priv->hostname);
cmd_argv[j++] = strdup (netcat ? netcat : "nc");
cmd_argv[j++] = strdup ("-U");
cmd_argv[j++] = strdup (sockname ? sockname : LIBVIRTD_PRIV_UNIX_SOCKET);
}
} /* switch (transport) */
+
+ /* Try and authenticate with server */
+ if (remoteAuthenticate(conn, priv, 1) == -1)
+ goto failed;
+
/* Finally we can call the remote side's open function. */
remote_open_args args = { &name, flags };
- if (call (conn, priv, 1, REMOTE_PROC_OPEN,
+ if (call (conn, priv, REMOTE_CALL_IN_OPEN, REMOTE_PROC_OPEN,
(xdrproc_t) xdr_remote_open_args, (char *) &args,
(xdrproc_t) xdr_void, (char *) NULL) == -1)
goto failed;
/* Successful. */
retcode = VIR_DRV_OPEN_SUCCESS;
- /*FALLTHROUGH*/
- failed:
- /* Close the socket if we failed. */
- if (retcode != VIR_DRV_OPEN_SUCCESS && priv->sock >= 0) {
- if (priv->uses_tls && priv->session)
- gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
- close (priv->sock);
- if (priv->pid > 0) {
- pid_t reap;
- do {
- reap = waitpid(priv->pid, NULL, 0);
- if (reap == -1 && errno == EINTR)
- continue;
- } while (reap != -1 && reap != priv->pid);
- }
- }
-
+ cleanup:
/* Free up the URL and strings. */
if (name) free (name);
if (command) free (command);
if (sockname) free (sockname);
if (netcat) free (netcat);
if (username) free (username);
- if (server) free (server);
if (port) free (port);
if (cmd_argv) {
char **cmd_argv_ptr = cmd_argv;
}
return retcode;
+
+ out_of_memory:
+ error (NULL, VIR_ERR_NO_MEMORY, "uri params");
+
+ failed:
+ /* Close the socket if we failed. */
+ if (priv->sock >= 0) {
+ if (priv->uses_tls && priv->session) {
+ gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
+ gnutls_deinit (priv->session);
+ }
+ close (priv->sock);
+ if (priv->pid > 0) {
+ pid_t reap;
+ do {
+ reap = waitpid(priv->pid, NULL, 0);
+ if (reap == -1 && errno == EINTR)
+ continue;
+ } while (reap != -1 && reap != priv->pid);
+ }
+ }
+
+ if (priv->hostname) {
+ free (priv->hostname);
+ priv->hostname = NULL;
+ }
+
+ goto cleanup;
}
static int
return 0;
}
-static int verify_certificate (virConnectPtr conn, gnutls_session_t session, const char *hostname);
+static int verify_certificate (virConnectPtr conn, struct private_data *priv, gnutls_session_t session);
static gnutls_session_t
negotiate_gnutls_on_connection (virConnectPtr conn,
- int sock, int no_verify, const char *hostname)
+ struct private_data *priv,
+ int no_verify)
{
const int cert_type_priority[3] = {
GNUTLS_CRT_X509,
}
gnutls_transport_set_ptr (session,
- (gnutls_transport_ptr_t) (long) sock);
+ (gnutls_transport_ptr_t) (long) priv->sock);
/* Perform the TLS handshake. */
again:
}
/* Verify certificate. */
- if (verify_certificate (conn, session, hostname) == -1) {
+ if (verify_certificate (conn, priv, session) == -1) {
fprintf (stderr,
"remote_internal: failed to verify peer's certificate\n");
if (!no_verify) return NULL;
static int
verify_certificate (virConnectPtr conn ATTRIBUTE_UNUSED,
- gnutls_session_t session,
- const char *hostname)
+ struct private_data *priv,
+ gnutls_session_t session)
{
int ret;
unsigned int status;
}
if (i == 0) {
- if (!gnutls_x509_crt_check_hostname (cert, hostname)) {
+ if (!gnutls_x509_crt_check_hostname (cert, priv->hostname)) {
__virRaiseError
(conn, NULL, NULL,
VIR_FROM_REMOTE, VIR_ERR_RPC,
- VIR_ERR_ERROR, hostname, NULL, NULL,
+ VIR_ERR_ERROR, priv->hostname, NULL, NULL,
0, 0,
"Certificate's owner does not match the hostname (%s)",
- hostname);
+ priv->hostname);
gnutls_x509_crt_deinit (cert);
return -1;
}
return -1;
/* Close socket. */
- if (priv->uses_tls && priv->session)
+ if (priv->uses_tls && priv->session) {
gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
+ gnutls_deinit (priv->session);
+ }
+#if HAVE_SASL
+ if (priv->saslconn)
+ sasl_dispose (&priv->saslconn);
+#endif
close (priv->sock);
if (priv->pid > 0) {
} while (reap != -1 && reap != priv->pid);
}
+ /* Free hostname copy */
+ if (priv->hostname) free (priv->hostname);
+
/* See comment for remoteType. */
if (priv->type) free (priv->type);
/*----------------------------------------------------------------------*/
+static int
+remoteAuthenticate (virConnectPtr conn, struct private_data *priv, int in_open)
+{
+ struct remote_auth_list_ret ret;
+ int err;
+
+ memset(&ret, 0, sizeof ret);
+ err = call (conn, priv,
+ REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC,
+ REMOTE_PROC_AUTH_LIST,
+ (xdrproc_t) xdr_void, (char *) NULL,
+ (xdrproc_t) xdr_remote_auth_list_ret, (char *) &ret);
+ if (err == -2) /* Missing RPC - old server - ignore */
+ return 0;
+
+ if (err < 0)
+ return -1;
+
+ if (ret.types.types_len == 0)
+ return 0;
+
+ switch (ret.types.types_val[0]) {
+#if HAVE_SASL
+ case REMOTE_AUTH_SASL:
+ if (remoteAuthSASL(conn, priv, in_open) < 0) {
+ free(ret.types.types_val);
+ return -1;
+ }
+ break;
+#endif
+
+ case REMOTE_AUTH_NONE:
+ /* Nothing todo, hurrah ! */
+ break;
+
+ default:
+ __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
+ "unsupported authentication type %d", ret.types.types_val[0]);
+ free(ret.types.types_val);
+ return -1;
+ }
+
+ free(ret.types.types_val);
+
+ return 0;
+}
+
+
+
+#if HAVE_SASL
+/*
+ * NB, keep in sync with similar method in qemud/remote.c
+ */
+static char *addrToString(struct sockaddr_storage *sa, socklen_t salen)
+{
+ char host[NI_MAXHOST], port[NI_MAXSERV];
+ char *addr;
+ int err;
+
+ if ((err = getnameinfo((struct sockaddr *)sa, salen,
+ host, sizeof(host),
+ port, sizeof(port),
+ NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+ __virRaiseError (NULL, NULL, NULL, VIR_FROM_REMOTE,
+ VIR_ERR_NO_MEMORY, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
+ "Cannot resolve address %d: %s", err, gai_strerror(err));
+ return NULL;
+ }
+
+ addr = malloc(strlen(host) + 1 + strlen(port) + 1);
+ if (!addr) {
+ __virRaiseError (NULL, NULL, NULL, VIR_FROM_REMOTE,
+ VIR_ERR_NO_MEMORY, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
+ "address");
+ return NULL;
+ }
+
+ strcpy(addr, host);
+ strcat(addr, ";");
+ strcat(addr, port);
+ return addr;
+}
+
+
+/* Perform the SASL authentication process
+ *
+ * XXX negotiate a session encryption layer for non-TLS sockets
+ * XXX fetch credentials from a libvirt client app callback
+ * XXX max packet size spec
+ * XXX better mechanism negotiation ? Ask client app ?
+ */
+static int
+remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open)
+{
+ sasl_conn_t *saslconn = NULL;
+ remote_auth_sasl_init_ret iret;
+ remote_auth_sasl_start_args sargs;
+ remote_auth_sasl_start_ret sret;
+ remote_auth_sasl_step_args pargs;
+ remote_auth_sasl_step_ret pret;
+ const char *clientout;
+ char *serverin;
+ unsigned int clientoutlen, serverinlen;
+ const char *mech;
+ int err, complete;
+ struct sockaddr_storage sa;
+ socklen_t salen;
+ char *localAddr, *remoteAddr;
+
+ remoteDebug(priv, "Client initialize SASL authentication");
+ /* Sets up the SASL library as a whole */
+ err = sasl_client_init(NULL);
+ if (err != SASL_OK) {
+ __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
+ "failed to initialize SASL library: %d (%s)",
+ err, sasl_errstring(err, NULL, NULL));
+ return -1;
+ }
+
+ /* Get local address in form IPADDR:PORT */
+ salen = sizeof(sa);
+ if (getsockname(priv->sock, (struct sockaddr*)&sa, &salen) < 0) {
+ __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
+ "failed to get sock address %d (%s)",
+ errno, strerror(errno));
+ return -1;
+ }
+ if ((localAddr = addrToString(&sa, salen)) == NULL) {
+ return -1;
+ }
+
+ /* Get remote address in form IPADDR:PORT */
+ salen = sizeof(sa);
+ if (getpeername(priv->sock, (struct sockaddr*)&sa, &salen) < 0) {
+ __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
+ "failed to get peer address %d (%s)",
+ errno, strerror(errno));
+ free(localAddr);
+ return -1;
+ }
+ if ((remoteAddr = addrToString(&sa, salen)) == NULL) {
+ free(localAddr);
+ return -1;
+ }
+
+ /* Setup a handle for being a client */
+ err = sasl_client_new("libvirt",
+ priv->hostname,
+ localAddr,
+ remoteAddr,
+ NULL, /* XXX callbacks */
+ SASL_SUCCESS_DATA,
+ &saslconn);
+ free(localAddr);
+ free(remoteAddr);
+ if (err != SASL_OK) {
+ __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
+ "Failed to create SASL client context: %d (%s)",
+ err, sasl_errstring(err, NULL, NULL));
+ return -1;
+ }
+
+ /* First call is to inquire about supported mechanisms in the server */
+ memset (&iret, 0, sizeof iret);
+ if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_INIT,
+ (xdrproc_t) xdr_void, (char *)NULL,
+ (xdrproc_t) xdr_remote_auth_sasl_init_ret, (char *) &iret) != 0) {
+ sasl_dispose(&saslconn);
+ return -1; /* virError already set by call */
+ }
+
+
+ /* Start the auth negotiation on the client end first */
+ remoteDebug(priv, "Client start negotiation mechlist '%s'", iret.mechlist);
+ err = sasl_client_start(saslconn,
+ iret.mechlist,
+ NULL, /* XXX interactions */
+ &clientout,
+ &clientoutlen,
+ &mech);
+ if (err != SASL_OK && err != SASL_CONTINUE) {
+ __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
+ "Failed to start SASL negotiation: %d (%s)",
+ err, sasl_errdetail(saslconn));
+ free(iret.mechlist);
+ sasl_dispose(&saslconn);
+ return -1;
+ }
+ free(iret.mechlist);
+
+ if (clientoutlen > REMOTE_AUTH_SASL_DATA_MAX) {
+ __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
+ "SASL negotiation data too long: %d bytes", clientoutlen);
+ sasl_dispose(&saslconn);
+ return -1;
+ }
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ memset(&sargs, 0, sizeof sargs);
+ sargs.nil = clientout ? 0 : 1;
+ sargs.data.data_val = (char*)clientout;
+ sargs.data.data_len = clientoutlen;
+ sargs.mech = (char*)mech;
+ remoteDebug(priv, "Server start negotiation with mech %s. Data %d bytes %p", mech, clientoutlen, clientout);
+
+ /* Now send the initial auth data to the server */
+ memset (&sret, 0, sizeof sret);
+ if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_START,
+ (xdrproc_t) xdr_remote_auth_sasl_start_args, (char *) &sargs,
+ (xdrproc_t) xdr_remote_auth_sasl_start_ret, (char *) &sret) != 0) {
+ sasl_dispose(&saslconn);
+ return -1; /* virError already set by call */
+ }
+
+ complete = sret.complete;
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ serverin = sret.nil ? NULL : sret.data.data_val;
+ serverinlen = sret.data.data_len;
+ remoteDebug(priv, "Client step result complete: %d. Data %d bytes %p",
+ complete, serverinlen, serverin);
+
+ /* Loop-the-loop...
+ * Even if the server has completed, the client must *always* do at least one step
+ * in this loop to verify the server isn't lieing about something. Mutual auth */
+ for (;;) {
+ err = sasl_client_step(saslconn,
+ serverin,
+ serverinlen,
+ NULL, /* XXX interactions */
+ &clientout,
+ &clientoutlen);
+ if (serverin) free(serverin);
+ if (err != SASL_OK && err != SASL_CONTINUE) {
+ __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
+ "Failed SASL step: %d (%s)",
+ err, sasl_errdetail(saslconn));
+ sasl_dispose(&saslconn);
+ return -1;
+ }
+ remoteDebug(priv, "Client step result %d. Data %d bytes %p", err, clientoutlen, clientout);
+
+ /* Previous server call showed completion & we're now locally complete too */
+ if (complete && err == SASL_OK)
+ break;
+
+ /* Not done, prepare to talk with the server for another iteration */
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ memset(&pargs, 0, sizeof pargs);
+ pargs.nil = clientout ? 0 : 1;
+ pargs.data.data_val = (char*)clientout;
+ pargs.data.data_len = clientoutlen;
+ remoteDebug(priv, "Server step with %d bytes %p", clientoutlen, clientout);
+
+ memset (&pret, 0, sizeof pret);
+ if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_STEP,
+ (xdrproc_t) xdr_remote_auth_sasl_step_args, (char *) &pargs,
+ (xdrproc_t) xdr_remote_auth_sasl_step_ret, (char *) &pret) != 0) {
+ sasl_dispose(&saslconn);
+ return -1; /* virError already set by call */
+ }
+
+ complete = pret.complete;
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ serverin = pret.nil ? NULL : pret.data.data_val;
+ serverinlen = pret.data.data_len;
+
+ remoteDebug(priv, "Client step result complete: %d. Data %d bytes %p",
+ complete, serverinlen, serverin);
+
+ /* This server call shows complete, and earlier client step was OK */
+ if (complete && err == SASL_OK) {
+ if (serverin) free(serverin);
+ break;
+ }
+ }
+
+ remoteDebug(priv, "SASL authentication complete");
+ /* XXX keep this around for wire encoding */
+ sasl_dispose(&saslconn);
+ return 0;
+}
+#endif /* HAVE_SASL */
+
+/*----------------------------------------------------------------------*/
+
static int really_write (virConnectPtr conn, struct private_data *priv,
int in_open, char *bytes, int len);
static int really_read (virConnectPtr conn, struct private_data *priv,
*/
static int
call (virConnectPtr conn, struct private_data *priv,
- int in_open /* if we are in virConnectOpen */,
+ int flags /* if we are in virConnectOpen */,
int proc_nr,
xdrproc_t args_filter, char *args,
xdrproc_t ret_filter, char *ret)
/* Serialise header followed by args. */
xdrmem_create (&xdr, buffer, sizeof buffer, XDR_ENCODE);
if (!xdr_remote_message_header (&xdr, &hdr)) {
- error (in_open ? NULL : conn,
+ error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, "xdr_remote_message_header");
return -1;
}
if (!(*args_filter) (&xdr, args)) {
- error (in_open ? NULL : conn, VIR_ERR_RPC, "marshalling args");
+ error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, VIR_ERR_RPC, "marshalling args");
return -1;
}
/* Encode the length word. */
xdrmem_create (&xdr, buffer2, sizeof buffer2, XDR_ENCODE);
if (!xdr_int (&xdr, &len)) {
- error (in_open ? NULL : conn, VIR_ERR_RPC, "xdr_int (length word)");
+ error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, VIR_ERR_RPC, "xdr_int (length word)");
return -1;
}
xdr_destroy (&xdr);
/* Send length word followed by header+args. */
- if (really_write (conn, priv, in_open, buffer2, sizeof buffer2) == -1 ||
- really_write (conn, priv, in_open, buffer, len-4) == -1)
+ if (really_write (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer2, sizeof buffer2) == -1 ||
+ really_write (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer, len-4) == -1)
return -1;
/* Read and deserialise length word. */
- if (really_read (conn, priv, in_open, buffer2, sizeof buffer2) == -1)
+ if (really_read (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer2, sizeof buffer2) == -1)
return -1;
xdrmem_create (&xdr, buffer2, sizeof buffer2, XDR_DECODE);
if (!xdr_int (&xdr, &len)) {
- error (in_open ? NULL : conn,
+ error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, "xdr_int (length word, reply)");
return -1;
}
len -= 4;
if (len < 0 || len > REMOTE_MESSAGE_MAX) {
- error (in_open ? NULL : conn,
+ error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, "packet received from server too large");
return -1;
}
/* Read reply header and what follows (either a ret or an error). */
- if (really_read (conn, priv, in_open, buffer, len) == -1)
+ if (really_read (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer, len) == -1)
return -1;
/* Deserialise reply header. */
xdrmem_create (&xdr, buffer, len, XDR_DECODE);
if (!xdr_remote_message_header (&xdr, &hdr)) {
- error (in_open ? NULL : conn,
+ error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, "xdr_remote_message_header (reply)");
return -1;
}
/* Check program, version, etc. are what we expect. */
if (hdr.prog != REMOTE_PROGRAM) {
- __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ __virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
"unknown program (received %x, expected %x)",
hdr.prog, REMOTE_PROGRAM);
return -1;
}
if (hdr.vers != REMOTE_PROTOCOL_VERSION) {
- __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ __virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
"unknown protocol version (received %x, expected %x)",
hdr.vers, REMOTE_PROTOCOL_VERSION);
* message being received at this point.
*/
if (hdr.proc != proc_nr) {
- __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ __virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
"unknown procedure (received %x, expected %x)",
hdr.proc, proc_nr);
return -1;
}
if (hdr.direction != REMOTE_REPLY) {
- __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ __virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
"unknown direction (received %x, expected %x)",
hdr.direction, REMOTE_REPLY);
return -1;
}
if (hdr.serial != serial) {
- __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ __virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
"unknown serial (received %x, expected %x)",
hdr.serial, serial);
switch (hdr.status) {
case REMOTE_OK:
if (!(*ret_filter) (&xdr, ret)) {
- error (in_open ? NULL : conn, VIR_ERR_RPC, "unmarshalling ret");
+ error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, VIR_ERR_RPC, "unmarshalling ret");
return -1;
}
xdr_destroy (&xdr);
case REMOTE_ERROR:
memset (&rerror, 0, sizeof rerror);
if (!xdr_remote_error (&xdr, &rerror)) {
- error (in_open ? NULL : conn,
+ error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, "unmarshalling remote_error");
return -1;
}
xdr_destroy (&xdr);
- server_error (in_open ? NULL : conn, &rerror);
+ /* See if caller asked us to keep quiet about missing RPCs
+ * eg for interop with older servers */
+ if (flags & REMOTE_CALL_QUIET_MISSING_RPC &&
+ rerror.domain == VIR_FROM_REMOTE &&
+ rerror.code == VIR_ERR_RPC &&
+ rerror.level == VIR_ERR_ERROR &&
+ STREQLEN(*rerror.message, "unknown procedure", 17)) {
+ return -2;
+ }
+ server_error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, &rerror);
xdr_free ((xdrproc_t) xdr_remote_error, (char *) &rerror);
return -1;
default:
- __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
+ __virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
"unknown status (received %x)",
hdr.status);
else
errmsg = _("invalid MAC adress: %s");
break;
+ case VIR_ERR_AUTH_FAILED:
+ if (info == NULL)
+ errmsg = _("authentication failed");
+ else
+ errmsg = _("authentication failed: %s");
+ break;
}
return (errmsg);
}
-I$(top_srcdir)/src \
$(LIBXML_CFLAGS) \
$(GNUTLS_CFLAGS) \
+ $(SASL_CFLAGS) \
-D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=199506L \
-DGETTEXT_PACKAGE=\"$(PACKAGE)\" \
$(COVERAGE_CFLAGS) \
@STATIC_BINARIES@ \
$(LIBXML_LIBS) \
$(GNUTLS_LIBS) \
+ $(SASL_LIBS) \
$(WARN_CFLAGS) \
$(LIBVIRT) \
$(COVERAGE_LDFLAGS)