[Libvir] PATCH: 0/4: Remote authentication support

This is the 2nd iteration of my remote authentication / SASL patches previously provided here: http://www.redhat.com/archives/libvir-list/2007-October/msg00131.html In this iteration I've changed the wire protocol to give better compatability with older libvirt clients. My previous version clients would get a cryptic "unknown status 3" if the server was mandating authentication. This is because I extended the reply codes for RPC to include a specific 'auth required' code which old clients are not expecting. The idea was that the new client would run the REMOTE_PROC_OPEN rpc call & it would return a special NEED_AUTH code, the client would then authenticate & redo the REMOTE_PROC_OPEN. In the new way of doing things, instead of calling REMOTE_PROC_OPEN as the first RPC, a new client will do REMOTE_PROC_AUTH_LIST to query auth types required by the server. It will choose an auth method (there may be several to choose from), then complete the auth sequence. Only then will it try to do the REMOTE_PROC_OPEN. For compatability with older servers which do not implement the REMOTE_PROC_AUTH_LIST rpc, it will catch & ignore the error this may generate. Old clients which don't know to call REMOTE_PROC_AUTH_LIST will get a proper virErrorPtr object returned from REMOTE_PROC_OPEN with a clear 'authentication required' message. The end result is that new client <-> new server has same level of functionality as my previous patches, and old client <-> new server gets friendly errors reported (if server mandates auth - if no auth is enabled old client works just fine). The main outstanding item to be finalized before these patches can be added to CVS is the question of callbacks. For some auth methods we need to be able to gather credentials from the user. There is no way for the caller to know ahead of time what credentials are needed, because this is deterined by the config of the server. Thus we need callbacks in some form. I've come up with a couple of ideas... 1. A global method to supply a list of callbacks per credential type: enum { VIR_CONN_AUTH_PASSWORD, VIR_CONN_AUTH_USERNAME, VIR_CONN_AUTH_LANG, VIR_CONN_AUTH_CHALLENGE, VIR_CONN_AUTH_REALM, } virConnectAuthToken; typedef int (virConnectAuthCBSimple)(const char **result, unsigned *len); typedef int (virConnectAuthCBPrompt)(const char *challenge, const char *prompt, const char *defresult, const char *result, unsigned *len); typedef int (virConnetAuthCBRealm)(const char **availrealms, const char *result); typedef struct { int token; union { virConnectAuthCBSimple simple; virConnectAuthCBPrompt prompt; virConnectAuthCBRealm realm; } cb; } virConnectAuthCallback; virConnectSetAuthCallbacks(virConnectAuthCallback *cbs, int ncbs) This is described a little more here: http://www.redhat.com/archives/libvir-list/2007-January/msg00024.html 2. A new variant of virConnectOpen which takes a callback. The callback gives invoked with a list of required credentials struct _virConnectInteract { int type; /* One of virConnectInteractType constants */ const char *prompt; const char *challenge; const char *defresult; char *result; unsigned int resultlen; }; typedef struct _virConnectInteract virConnectInteract; typedef virConnectInteract *virConnectInteractPtr; /** * When authentication requires one or more interactions, this callback * is invoked. For each interaction supplied, data must be gathered * from the user and filled in to the 'result' and 'resultlen' fields. * If an interaction can not be filled, fill in NULL and 0. * * Return 0 if all interactions were filled, or -1 upon error */ typedef int (*virConnectAuthCallbackPtr)(const char *uri, virConnectInteractPtr interact, unsigned int ninteract); virConnectPtr virConnectOpenAuth (const char *name, virConnectAuthCallbackPtr cb, int flags); Iternally the virConnectOpen & virConnectOpenReadOnly can both just be delegating to this new virConnectOpenAuth call. Existing users of libvirt won't know about this new call, but that doesn't matter because they're not loosing any functionality - merely not able to put up UI to prompt for auth credentials/ The compelling thing about the 2nd way of doing things is that the callback gets a complete list of all required data items at once. This makes it very easy to present a UI with form entry fields for all items. The first way where there is a separate callback per item makes UI very hard. There is one issue not addressed by those two options though - there may be a choice of authentication methods to use. eg SASL vs PolicyKit. The callback only provides a way to supply credentials, no way to choose between auth types if a server offers more than one. Again there's a couple of ways to address this. 1. A global method to set preferred auth type. Simply a sorted list of auth types. Internally, we pick the first auth type in this list that the server supports virConnectSetAuthPriority(int types[], int ntypes); 2. A 2nd callback providing the int types[] and letting the client app choose which one they want to use per connection. 3. Separate out the operation of creating a virConnectPtr object, from the act of connecting, eg /* Allocate a handle */ virConnectPtr virConnectNew(const char *uri); /* List available auth methods */ int virConnectListAuth(virConnectPtr conn, int **types, int *ntypes); /* Connect to HV, with a speciifc auth method */ int virConnectInit(virConnectPtr conn, int auth); Any of these three, can be combined with either of the 2 options for supplying auth credentials. So we've got a choice of 6 :-) My preference, is to go for option 2, of the credentials choice, and option 1 of the auth type priority choice. eg a static priority list for auth types, and a single callback passed into a new virConnectOpenAuth() call. The final tedious bit, is the question of how we deal with underlying HV which may need further authentication. eg, if connecting to XenAPI we may need to provide a username & password. If the XenAPI connection is being made through a local libvirt driver hooking up the callbacks as described is fairly easy. If the XenAPI connection is made indirectly via the remote driver, then we have two drivers requiring auth - the initial remote driver, and then the remotely run XenAPi driver. This would need us to figure out a way to hook up the callbacks to the REMOTE_PROC_OPEN api call. Not pleasant ! Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

This patch simply cleans up some legacy code which was choosing between the QEMU driver protocol, and the generic remote protocol. There is no ABI wire change there - just tidying up the structs we use internally. a/qemud/protocol.c | 17 -------------- a/qemud/protocol.h | 39 -------------------------------- a/qemud/protocol.x | 40 --------------------------------- qemud/Makefile.am | 5 ---- qemud/internal.h | 1 qemud/qemud.c | 57 +++++++++++++++--------------------------------- qemud/remote.c | 2 - qemud/remote_protocol.h | 1 qemud/remote_protocol.x | 3 ++ src/Makefile.am | 1 10 files changed, 24 insertions(+), 142 deletions(-) Dan. diff -r ee2425c4d587 qemud/Makefile.am --- a/qemud/Makefile.am Wed Oct 17 11:35:03 2007 -0400 +++ b/qemud/Makefile.am Wed Oct 17 15:02:48 2007 -0400 @@ -10,8 +10,7 @@ conf_DATA = libvirtd.conf # Distribute the generated files so that rpcgen isn't required on the # target machine (although almost any Unix machine will have it). EXTRA_DIST = libvirtd.init.in libvirtd.sysconf default-network.xml \ - protocol.x remote_protocol.x \ - protocol.c protocol.h \ + remote_protocol.x \ remote_protocol.c remote_protocol.h \ remote_generate_stubs.pl rpcgen_fix.pl \ remote_dispatch_prototypes.h \ @@ -22,7 +21,6 @@ EXTRA_DIST = libvirtd.init.in libvirtd.s libvirtd_SOURCES = \ qemud.c internal.h \ - protocol.h protocol.c \ remote_protocol.h remote_protocol.c \ remote.c \ event.c event.h @@ -76,7 +74,6 @@ uninstall-local: uninstall-init rm -f $@ rpcgen -h -o $@ $< -protocol.c: protocol.h remote_protocol.c: remote_protocol.h remote.c: remote_dispatch_prototypes.h \ diff -r ee2425c4d587 qemud/internal.h --- a/qemud/internal.h Wed Oct 17 11:35:03 2007 -0400 +++ b/qemud/internal.h Wed Oct 17 15:02:48 2007 -0400 @@ -29,7 +29,6 @@ #include <gnutls/x509.h> #include "../src/gnutls_1_0_compat.h" -#include "protocol.h" #include "remote_protocol.h" #include "../config.h" diff -r ee2425c4d587 qemud/protocol.c --- a/qemud/protocol.c Wed Oct 17 11:35:03 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -/* - * Please do not edit this file. - * It was generated using rpcgen. - */ - -#include "protocol.h" - -bool_t -xdr_qemud_packet_header (XDR *xdrs, qemud_packet_header *objp) -{ - - if (!xdr_uint32_t (xdrs, &objp->length)) - return FALSE; - if (!xdr_uint32_t (xdrs, &objp->prog)) - return FALSE; - return TRUE; -} diff -r ee2425c4d587 qemud/protocol.h --- a/qemud/protocol.h Wed Oct 17 11:35:03 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Please do not edit this file. - * It was generated using rpcgen. - */ - -#ifndef _PROTOCOL_H_RPCGEN -#define _PROTOCOL_H_RPCGEN - -#include <rpc/rpc.h> - - -#ifdef __cplusplus -extern "C" { -#endif - -#define QEMUD_PROGRAM 0x20001A64 -#define QEMUD_PKT_HEADER_XDR_LEN 8 - -struct qemud_packet_header { - uint32_t length; - uint32_t prog; -}; -typedef struct qemud_packet_header qemud_packet_header; - -/* the xdr functions */ - -#if defined(__STDC__) || defined(__cplusplus) -extern bool_t xdr_qemud_packet_header (XDR *, qemud_packet_header*); - -#else /* K&R C */ -extern bool_t xdr_qemud_packet_header (); - -#endif /* K&R C */ - -#ifdef __cplusplus -} -#endif - -#endif /* !_PROTOCOL_H_RPCGEN */ diff -r ee2425c4d587 qemud/protocol.x --- a/qemud/protocol.x Wed Oct 17 11:35:03 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* -*- c -*- - * protocol_xdr.x: wire protocol message format & data structures - * - * Copyright (C) 2006, 2007 Red Hat, Inc. - * 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> - */ - - -/* The first two words in the messages are length and program number - * (previously called "magic"). This makes the protocol compatible - * with the remote protocol, although beyond the first two words - * the protocols are completely different. - * - * Note the length is the total number of bytes in the message - * _including_ the length and program number. - */ - -const QEMUD_PROGRAM = 0x20001A64; -const QEMUD_PKT_HEADER_XDR_LEN = 8; - -struct qemud_packet_header { - uint32_t length; - uint32_t prog; -}; diff -r ee2425c4d587 qemud/qemud.c --- a/qemud/qemud.c Wed Oct 17 11:35:03 2007 -0400 +++ b/qemud/qemud.c Wed Oct 17 15:02:48 2007 -0400 @@ -1051,7 +1051,7 @@ static int qemudDispatchServer(struct qe if (!client->tls) { client->mode = QEMUD_MODE_RX_HEADER; - client->bufferLength = QEMUD_PKT_HEADER_XDR_LEN; + client->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN; if (qemudRegisterClientEvent (server, client, 0) < 0) goto cleanup; @@ -1180,7 +1180,7 @@ static void qemudDispatchClientRead(stru switch (client->mode) { case QEMUD_MODE_RX_HEADER: { XDR x; - qemud_packet_header h; + unsigned int len; if (qemudClientRead(server, client) < 0) return; /* Error, or blocking */ @@ -1190,33 +1190,32 @@ static void qemudDispatchClientRead(stru xdrmem_create(&x, client->buffer, client->bufferLength, XDR_DECODE); - if (!xdr_qemud_packet_header(&x, &h)) { - qemudDebug("Failed to decode packet header"); + if (!xdr_u_int(&x, &len)) { + xdr_destroy (&x); + qemudDebug("Failed to decode packet length"); qemudDispatchClientFailure(server, client); return; } - - if (h.prog != REMOTE_PROGRAM) { - qemudDebug("Header magic %x mismatch", h.prog); + xdr_destroy (&x); + + if (len > REMOTE_MESSAGE_MAX) { + qemudDebug("Packet length %u too large", len); qemudDispatchClientFailure(server, client); return; } - /* NB: h.length is unsigned. */ - if (h.length > REMOTE_MESSAGE_MAX) { - qemudDebug("Packet length %u too large", h.length); + /* Length include length of the length field itself, so + * check minimum size requirements */ + if (len <= REMOTE_MESSAGE_HEADER_XDR_LEN) { + qemudDebug("Packet length %u too small", len); qemudDispatchClientFailure(server, client); return; } client->mode = QEMUD_MODE_RX_PAYLOAD; - client->bufferLength = h.length; + client->bufferLength = len - REMOTE_MESSAGE_HEADER_XDR_LEN; + client->bufferOffset = 0; if (client->tls) client->direction = QEMUD_TLS_DIRECTION_READ; - /* Note that we don't reset bufferOffset here because we want - * to retain the whole message, including header. - */ - - xdr_destroy (&x); if (qemudRegisterClientEvent(server, client, 1) < 0) { qemudDispatchClientFailure(server, client); @@ -1227,35 +1226,15 @@ static void qemudDispatchClientRead(stru } case QEMUD_MODE_RX_PAYLOAD: { - XDR x; - qemud_packet_header h; - if (qemudClientRead(server, client) < 0) return; /* Error, or blocking */ if (client->bufferOffset < client->bufferLength) return; /* Not read enough */ - /* Reparse the header to decide if this is for qemud or remote. */ - xdrmem_create(&x, client->buffer, client->bufferLength, XDR_DECODE); - - if (!xdr_qemud_packet_header(&x, &h)) { - qemudDebug("Failed to decode packet header"); + remoteDispatchClientRequest (server, client); + if (qemudRegisterClientEvent(server, client, 1) < 0) qemudDispatchClientFailure(server, client); - return; - } - - if (h.prog == REMOTE_PROGRAM) { - remoteDispatchClientRequest (server, client); - if (qemudRegisterClientEvent(server, client, 1) < 0) - qemudDispatchClientFailure(server, client); - } else { - /* An internal error. */ - qemudDebug ("Not REMOTE_PROGRAM"); - qemudDispatchClientFailure(server, client); - } - - xdr_destroy (&x); break; } @@ -1336,7 +1315,7 @@ static void qemudDispatchClientWrite(str if (client->bufferOffset == client->bufferLength) { /* Done writing, switch back to receive */ client->mode = QEMUD_MODE_RX_HEADER; - client->bufferLength = QEMUD_PKT_HEADER_XDR_LEN; + client->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN; client->bufferOffset = 0; if (client->tls) client->direction = QEMUD_TLS_DIRECTION_READ; diff -r ee2425c4d587 qemud/remote.c --- a/qemud/remote.c Wed Oct 17 11:35:03 2007 -0400 +++ b/qemud/remote.c Wed Oct 17 15:03:02 2007 -0400 @@ -83,7 +83,7 @@ remoteDispatchClientRequest (struct qemu #include "remote_dispatch_localvars.h" /* Parse the header. */ - xdrmem_create (&xdr, client->buffer+4, client->bufferLength-4, XDR_DECODE); + xdrmem_create (&xdr, client->buffer, client->bufferLength, XDR_DECODE); if (!xdr_remote_message_header (&xdr, &req)) { remoteDispatchError (client, NULL, "xdr_remote_message_header"); diff -r ee2425c4d587 qemud/remote_protocol.h --- a/qemud/remote_protocol.h Wed Oct 17 11:35:03 2007 -0400 +++ b/qemud/remote_protocol.h Wed Oct 17 15:02:48 2007 -0400 @@ -743,6 +743,7 @@ enum remote_message_status { REMOTE_ERROR = 1, }; typedef enum remote_message_status remote_message_status; +#define REMOTE_MESSAGE_HEADER_XDR_LEN 4 struct remote_message_header { u_int prog; diff -r ee2425c4d587 qemud/remote_protocol.x --- a/qemud/remote_protocol.x Wed Oct 17 11:35:03 2007 -0400 +++ b/qemud/remote_protocol.x Wed Oct 17 15:02:48 2007 -0400 @@ -717,6 +717,9 @@ enum remote_message_status { REMOTE_ERROR = 1 }; +/* 4 byte length word per header */ +const REMOTE_MESSAGE_HEADER_XDR_LEN = 4; + struct remote_message_header { unsigned prog; /* REMOTE_PROGRAM */ unsigned vers; /* REMOTE_PROTOCOL_VERSION */ diff -r ee2425c4d587 src/Makefile.am --- a/src/Makefile.am Wed Oct 17 11:35:03 2007 -0400 +++ b/src/Makefile.am Wed Oct 17 15:02:48 2007 -0400 @@ -60,7 +60,6 @@ CLIENT_SOURCES = \ util.c util.h SERVER_SOURCES = \ - ../qemud/protocol.h ../qemud/protocol.c \ ../qemud/remote_protocol.c ../qemud/remote_protocol.h libvirt_la_SOURCES = $(CLIENT_SOURCES) $(SERVER_SOURCES) -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

"Daniel P. Berrange" <berrange@redhat.com> wrote:
This patch simply cleans up some legacy code which was choosing between the QEMU driver protocol, and the generic remote protocol. There is no ABI wire change there - just tidying up the structs we use internally.
a/qemud/protocol.c | 17 -------------- a/qemud/protocol.h | 39 -------------------------------- a/qemud/protocol.x | 40 --------------------------------- qemud/Makefile.am | 5 ---- qemud/internal.h | 1 qemud/qemud.c | 57 +++++++++++++++--------------------------------- qemud/remote.c | 2 - qemud/remote_protocol.h | 1 qemud/remote_protocol.x | 3 ++ src/Makefile.am | 1 10 files changed, 24 insertions(+), 142 deletions(-)
Hi Dan, This looks fine to me. In case it helps, here's a ChangeLog entry: Cleanup remote dispatch legacy code. * qemud/Makefile.am: Remove protocol.[chx] from EXTRA_DIST. Remove protocol.h and protocol.c from libvirtd_SOURCES. Remove protocol.c dependency. * qemud/protocol.c, qemud/protocol.h, qemud/protocol.x: Remove files. * qemud/internal.h: Don't include "protocol.h". * qemud/qemud.c: Clean up qemudDispatchClientRead. s/QEMUD_PKT_HEADER_XDR_LEN/REMOTE_MESSAGE_HEADER_XDR_LEN/ * qemud/remote.c: In remoteDispatchClientRequest, reflect that the client buffer no longer starts with the 4-byte XDR header length. * qemud/remote_protocol.h: Regenerate. * qemud/remote_protocol.x: Define REMOTE_MESSAGE_HEADER_XDR_LEN. * src/Makefile.am: Remove protocol.h, protocol.c from SERVER_SOURCES.

On Thu, Nov 15, 2007 at 10:34:33PM +0100, Jim Meyering wrote:
"Daniel P. Berrange" <berrange@redhat.com> wrote:
This patch simply cleans up some legacy code which was choosing between the QEMU driver protocol, and the generic remote protocol. There is no ABI wire change there - just tidying up the structs we use internally.
a/qemud/protocol.c | 17 -------------- a/qemud/protocol.h | 39 -------------------------------- a/qemud/protocol.x | 40 --------------------------------- qemud/Makefile.am | 5 ---- qemud/internal.h | 1 qemud/qemud.c | 57 +++++++++++++++--------------------------------- qemud/remote.c | 2 - qemud/remote_protocol.h | 1 qemud/remote_protocol.x | 3 ++ src/Makefile.am | 1 10 files changed, 24 insertions(+), 142 deletions(-)
Hi Dan,
This looks fine to me. In case it helps, here's a ChangeLog entry:
Thanks, Jim. I've commited this patch with the changelog since its independant of the rest of the SASL patches. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

This patch hooks up the basic authentication RPC calls, and the specific SASL implementation. The SASL impl can be enabled/disable via the configurre script with --without-sasl / --with-sasl - it'll auto-enable it if it finds the headers & libs OK. The sample /etc/sasl2/libvirt.conf file enables the GSSAPI mechanism. This requires a file /etc/libvirt/krb5.tab containing a service principle. On some distros you need to set KRB5_KTNAME to point to this file when starting the daemon, so our init script does that. Other distros, the 'keytab' config param in /etc/sasl2/libvirt.conf is actually honoured. With this patch you can successfully authentication client <-> server for any authentication mechansim which doesn't need to prompt the user for credentials. In effect this means it only works for GSSAPI/Kerberos. If suitabl callbacks were supplied the same code would work for any other auth mechanism, so we just need to agree on a callback API. The way auth is controlled, is that if the 'auth' parameter is set on the struct qemud_client object, *NO* rpc call will be processed except for the REMOTE_PROC_AUTH_LIST, SASL_AUTH_INIT, SASL_AUTH_START & SASL_AUTH_STEP calls. If SASL is not compiled in, the latter 3 will throw errors. Only once authentication is complete, are the other calls allowed. It currently hardcodes use of SASL on the TCP socket. The TLS & UNIX sockets are unchanged. The wire protocol for the SASL calls is changed so there is no longer a fixed maximum string size for the auth negotiation packets. We also now supply the info about the local & remote IP address & port to the SASL api so it can enable any auth mechanism which require that info. b/qemud/libvirtd.sasl | 11 configure.in | 39 +++ include/libvirt/virterror.h | 1 libvirt.spec.in | 4 qemud/Makefile.am | 21 + qemud/internal.h | 8 qemud/libvirtd.init.in | 3 qemud/libvirtd.sysconf | 3 qemud/qemud.c | 26 +- qemud/remote.c | 381 +++++++++++++++++++++++++++++-- qemud/remote_dispatch_localvars.h | 6 qemud/remote_dispatch_proc_switch.h | 30 ++ qemud/remote_dispatch_prototypes.h | 4 qemud/remote_protocol.c | 87 +++++++ qemud/remote_protocol.h | 78 ++++++ qemud/remote_protocol.x | 50 +++- src/Makefile.am | 3 src/remote_internal.c | 442 ++++++++++++++++++++++++++++++++---- src/virsh.c | 4 src/virterror.c | 6 tests/Makefile.am | 2 21 files changed, 1139 insertions(+), 70 deletions(-) Dan. diff -r b5fe91c98e78 configure.in --- a/configure.in Tue Oct 30 16:14:32 2007 -0400 +++ b/configure.in Thu Nov 01 15:03:01 2007 -0400 @@ -329,6 +329,40 @@ AC_CHECK_TYPE(gnutls_session, [#include <gnutls/gnutls.h>]) CFLAGS="$old_cflags" 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 @@ -537,6 +571,11 @@ AC_MSG_NOTICE([]) 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 diff -r b5fe91c98e78 include/libvirt/virterror.h --- a/include/libvirt/virterror.h Tue Oct 30 16:14:32 2007 -0400 +++ b/include/libvirt/virterror.h Thu Nov 01 15:03:01 2007 -0400 @@ -129,6 +129,7 @@ typedef enum { 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; /** diff -r b5fe91c98e78 libvirt.spec.in --- a/libvirt.spec.in Tue Oct 30 16:14:32 2007 -0400 +++ b/libvirt.spec.in Thu Nov 01 15:03:01 2007 -0400 @@ -16,6 +16,8 @@ Requires: dnsmasq Requires: dnsmasq Requires: bridge-utils Requires: iptables +Requires: cyrus-sasl +Requires: cyrus-sasl-gssapi BuildRequires: xen-devel BuildRequires: libxml2-devel BuildRequires: readline-devel @@ -26,6 +28,7 @@ BuildRequires: dnsmasq BuildRequires: dnsmasq BuildRequires: bridge-utils BuildRequires: qemu +BuildRequires: cyrus-sasl-devel Obsoletes: libvir ExclusiveArch: i386 x86_64 ia64 @@ -132,6 +135,7 @@ fi %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 diff -r b5fe91c98e78 qemud/Makefile.am --- a/qemud/Makefile.am Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/Makefile.am Thu Nov 01 15:03:01 2007 -0400 @@ -17,6 +17,7 @@ EXTRA_DIST = libvirtd.init.in libvirtd.s remote_dispatch_localvars.h \ remote_dispatch_proc_switch.h \ mdns.c mdns.h \ + libvirtd.sasl \ $(conf_DATA) libvirtd_SOURCES = \ @@ -28,14 +29,14 @@ 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 @@ -45,7 +46,7 @@ libvirtd_LDADD += $(AVAHI_LIBS) libvirtd_LDADD += $(AVAHI_LIBS) endif -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)/libvirt/qemu/networks/default.xml sed -i -e "s,</name>,</name>\n <uuid>$(UUID)</uuid>," $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml @@ -55,7 +56,7 @@ install-data-local: install-init 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)/libvirt/qemu/networks/default.xml rmdir $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart || : @@ -63,6 +64,18 @@ uninstall-local: uninstall-init 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 .x.c: rm -f $@ diff -r b5fe91c98e78 qemud/internal.h --- a/qemud/internal.h Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/internal.h Thu Nov 01 16:54:13 2007 -0400 @@ -28,6 +28,9 @@ #include <gnutls/gnutls.h> #include <gnutls/x509.h> #include "../src/gnutls_1_0_compat.h" +#if HAVE_SASL +#include <sasl/sasl.h> +#endif #include "remote_protocol.h" #include "../config.h" @@ -85,6 +88,10 @@ struct qemud_client { 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; @@ -110,6 +117,7 @@ struct qemud_socket { int readonly; /* If set, TLS is required on this socket. */ int tls; + int auth; int port; struct qemud_socket *next; }; diff -r b5fe91c98e78 qemud/libvirtd.init.in --- a/qemud/libvirtd.init.in Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/libvirtd.init.in Thu Nov 01 15:03:01 2007 -0400 @@ -37,6 +37,7 @@ PROCESS=libvirtd LIBVIRTD_CONFIG= LIBVIRTD_ARGS= +KRB5_KTNAME=/etc/libvirt/krb5.tab test -f @sysconfdir@/sysconfig/libvirtd && . @sysconfdir@/sysconfig/libvirtd @@ -50,7 +51,7 @@ RETVAL=0 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 diff -r b5fe91c98e78 qemud/libvirtd.sasl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qemud/libvirtd.sasl Thu Nov 01 15:03:01 2007 -0400 @@ -0,0 +1,11 @@ +# If you want to use the non-TLS socket, then you *must* include +# the GSSAPI mechanism, because its the only one that can offer +# session encryption as well as authentication. +# +# If you're only using TLS, then you can turn on any mechanisms +# you like for authentication, because TLS provides the encryption +mech_list: gssapi + +# MIT kerberos ignores this option & needs KRB5_KTNAME env var. +# May be useful for other non-Linux OS though.... +keytab: /etc/libvirt/krb5.tab diff -r b5fe91c98e78 qemud/libvirtd.sysconf --- a/qemud/libvirtd.sysconf Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/libvirtd.sysconf Thu Nov 01 15:03:01 2007 -0400 @@ -4,3 +4,6 @@ # 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 diff -r b5fe91c98e78 qemud/qemud.c --- a/qemud/qemud.c Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/qemud.c Thu Nov 01 16:54:13 2007 -0400 @@ -577,7 +577,8 @@ static int static int remoteListenTCP (struct qemud_server *server, const char *port, - int tls) + int tls, + int auth) { int fds[2]; int nfds = 0; @@ -606,6 +607,7 @@ remoteListenTCP (struct qemud_server *se sock->fd = fds[i]; sock->tls = tls; + sock->auth = auth; if (getsockname(sock->fd, (struct sockaddr *)(&sa), &salen) < 0) return -1; @@ -699,6 +701,7 @@ static struct qemud_server *qemudInitial struct qemud_socket *sock; char sockname[PATH_MAX]; char roSockname[PATH_MAX]; + int err; if (!(server = calloc(1, sizeof(struct qemud_server)))) { qemudLog(QEMUD_ERR, "Failed to allocate struct qemud_server"); @@ -728,15 +731,28 @@ static struct qemud_server *qemudInitial 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; } } @@ -1046,6 +1062,7 @@ static int qemudDispatchServer(struct qe client->fd = fd; client->readonly = sock->readonly; client->tls = sock->tls; + client->auth = sock->auth; memcpy (&client->addr, &addr, sizeof addr); client->addrlen = addrlen; @@ -1126,6 +1143,9 @@ static void qemudDispatchClientFailure(s 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); diff -r b5fe91c98e78 qemud/remote.c --- a/qemud/remote.c Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/remote.c Thu Nov 01 16:54:13 2007 -0400 @@ -52,6 +52,8 @@ #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, ...); @@ -115,6 +117,21 @@ remoteDispatchClientRequest (struct qemu (int) req.status); xdr_destroy (&xdr); 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 @@ -274,23 +291,14 @@ remoteDispatchClientRequest (struct qemu * 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. @@ -312,12 +320,12 @@ remoteDispatchError (struct qemud_client } /* 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; @@ -362,6 +370,31 @@ remoteDispatchError (struct qemud_client client->bufferOffset = 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. -----*/ @@ -1945,6 +1978,324 @@ remoteDispatchNumOfNetworks (struct qemu 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; + ret->types.types_val = calloc (ret->types.types_len, sizeof (remote_auth_type)); + ret->types.types_val[0] = client->auth; + return 0; +} + + +#if HAVE_SASL +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; + + if (getnameinfo((struct sockaddr *)sa, salen, + host, sizeof(host), + port, sizeof(port), + NI_NUMERICHOST | NI_NUMERICSERV) < 0) { + remoteDispatchError(client, req, + "Cannot resolve address %d: %s", errno, strerror(errno)); + 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 illegal 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) { + 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 illegal 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 illegal 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 +static int +remoteDispatchAuthSaslInit (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 init request"); + remoteDispatchFailAuth(client, req); + return -1; +} + +static int +remoteDispatchAuthSaslStart (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 start request"); + remoteDispatchFailAuth(client, req); + return -1; +} + +static int +remoteDispatchAuthSaslStep (struct qemud_client *client, + remote_message_header *req, + remote_auth_sasl_step_args *args, + remote_auth_sasl_step_ret *ret) + qemudLog(QEMUD_ERR, "client tried unsupported SASL step request"); + remoteDispatchFailAuth(client, req); + return -1; +} +#endif + + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff -r b5fe91c98e78 qemud/remote_dispatch_localvars.h --- a/qemud/remote_dispatch_localvars.h Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/remote_dispatch_localvars.h Thu Nov 01 16:36:53 2007 -0400 @@ -9,6 +9,7 @@ remote_list_defined_domains_ret lv_remot 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; @@ -36,6 +37,8 @@ remote_domain_create_linux_args lv_remot 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; @@ -50,6 +53,8 @@ remote_network_get_bridge_name_args lv_r 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; @@ -74,6 +79,7 @@ remote_network_set_autostart_args lv_rem 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; diff -r b5fe91c98e78 qemud/remote_dispatch_proc_switch.h --- a/qemud/remote_dispatch_proc_switch.h Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/remote_dispatch_proc_switch.h Thu Nov 01 16:36:53 2007 -0400 @@ -2,6 +2,36 @@ * 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; diff -r b5fe91c98e78 qemud/remote_dispatch_prototypes.h --- a/qemud/remote_dispatch_prototypes.h Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/remote_dispatch_prototypes.h Thu Nov 01 16:54:10 2007 -0400 @@ -2,6 +2,10 @@ * 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); diff -r b5fe91c98e78 qemud/remote_protocol.c --- a/qemud/remote_protocol.c Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/remote_protocol.c Thu Nov 01 16:36:53 2007 -0400 @@ -100,6 +100,15 @@ xdr_remote_error (XDR *xdrs, remote_erro if (!xdr_int (xdrs, &objp->int2)) return FALSE; if (!xdr_remote_network (xdrs, &objp->net)) + return FALSE; + 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; } @@ -1222,6 +1231,84 @@ xdr_remote_network_set_autostart_args (X } 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) { diff -r b5fe91c98e78 qemud/remote_protocol.h --- a/qemud/remote_protocol.h Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/remote_protocol.h Thu Nov 01 16:36:52 2007 -0400 @@ -28,6 +28,8 @@ typedef remote_nonnull_string *remote_st #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]; @@ -63,6 +65,12 @@ struct remote_error { }; 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; @@ -659,6 +667,58 @@ struct remote_network_set_autostart_args 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 @@ -728,6 +788,10 @@ enum remote_procedure { 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; @@ -766,6 +830,7 @@ extern bool_t xdr_remote_domain (XDR *, 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*); @@ -864,6 +929,12 @@ extern bool_t xdr_remote_network_get_au 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*); @@ -878,6 +949,7 @@ extern bool_t xdr_remote_domain (); 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 (); @@ -976,6 +1048,12 @@ extern bool_t xdr_remote_network_get_aut 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 (); diff -r b5fe91c98e78 qemud/remote_protocol.x --- a/qemud/remote_protocol.x Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/remote_protocol.x Thu Nov 01 16:36:51 2007 -0400 @@ -80,6 +80,12 @@ const REMOTE_NETWORK_NAME_LIST_MAX = 256 /* 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]; @@ -122,6 +128,13 @@ struct remote_error { int int2; 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 { @@ -610,6 +623,37 @@ struct remote_network_set_autostart_args struct remote_network_set_autostart_args { remote_nonnull_network net; 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. -----*/ @@ -683,7 +727,11 @@ enum remote_procedure { 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. */ diff -r b5fe91c98e78 src/Makefile.am --- a/src/Makefile.am Tue Oct 30 16:14:32 2007 -0400 +++ b/src/Makefile.am Thu Nov 01 15:03:01 2007 -0400 @@ -5,6 +5,7 @@ INCLUDES = -I$(top_builddir)/include \ -I@top_srcdir@/qemud \ $(LIBXML_CFLAGS) \ $(GNUTLS_CFLAGS) \ + $(SASL_CFLAGS) \ -DBINDIR=\""$(libexecdir)"\" \ -DSBINDIR=\""$(sbindir)"\" \ -DSYSCONF_DIR="\"$(sysconfdir)\"" \ @@ -24,7 +25,7 @@ EXTRA_DIST = libvirt_sym.version $(conf_ EXTRA_DIST = libvirt_sym.version $(conf_DATA) lib_LTLIBRARIES = libvirt.la -libvirt_la_LIBADD = $(LIBXML_LIBS) $(GNUTLS_LIBS) +libvirt_la_LIBADD = $(LIBXML_LIBS) $(GNUTLS_LIBS) $(SASL_LIBS) libvirt_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libvirt_sym.version \ -version-info @LIBVIRT_VERSION_INFO@ \ $(COVERAGE_CFLAGS:-f%=-Wc,-f%) diff -r b5fe91c98e78 src/remote_internal.c --- a/src/remote_internal.c Tue Oct 30 16:14:32 2007 -0400 +++ b/src/remote_internal.c Thu Nov 01 16:54:45 2007 -0400 @@ -46,6 +46,9 @@ #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" @@ -71,6 +74,11 @@ struct private_data { int counter; /* Generates serial numbers for RPC. */ char *uri; /* Original (remote) URI. */ 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) \ @@ -89,7 +97,12 @@ struct private_data { 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); +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); +static int remoteAuthenticate (virConnectPtr conn, struct private_data *priv, int in_open); +static int remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open); 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); @@ -120,7 +133,7 @@ static void query_free (struct query_fie /* 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) @@ -131,6 +144,20 @@ remoteStartup(void) inside_daemon = 1; return 0; } + +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"); +} + /** * remoteFindServerPath: @@ -302,7 +329,7 @@ doRemoteOpen (virConnectPtr conn, struct * 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; @@ -310,12 +337,6 @@ doRemoteOpen (virConnectPtr conn, struct 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 (NULL, 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) { @@ -330,6 +351,12 @@ doRemoteOpen (virConnectPtr conn, struct } 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; @@ -372,6 +399,12 @@ doRemoteOpen (virConnectPtr conn, struct } 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 @@ -441,7 +474,7 @@ doRemoteOpen (virConnectPtr conn, struct 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 (NULL, VIR_ERR_INVALID_ARG, gai_strerror (e)); goto failed; @@ -481,7 +514,7 @@ doRemoteOpen (virConnectPtr conn, struct 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; @@ -595,7 +628,7 @@ doRemoteOpen (virConnectPtr conn, struct 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); @@ -648,6 +681,11 @@ doRemoteOpen (virConnectPtr conn, struct } } /* 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 }; @@ -659,19 +697,46 @@ doRemoteOpen (virConnectPtr conn, struct /* Duplicate and save the uri_str. */ priv->uri = strdup (uri_str); if (!priv->uri) { + free(priv->hostname); + priv->hostname = NULL; error (NULL, VIR_ERR_NO_MEMORY, "allocating priv->uri"); goto failed; } /* Successful. */ retcode = VIR_DRV_OPEN_SUCCESS; + + cleanup: + /* Free up the URL and strings. */ + xmlFreeURI (uri); + if (name) free (name); + if (command) free (command); + if (sockname) free (sockname); + if (netcat) free (netcat); + if (username) free (username); + if (port) free (port); + if (cmd_argv) { + char **cmd_argv_ptr = cmd_argv; + while (*cmd_argv_ptr) { + free (*cmd_argv_ptr); + cmd_argv_ptr++; + } + free (cmd_argv); + } + + return retcode; + + out_of_memory: + error (NULL, VIR_ERR_NO_MEMORY, "uri params"); /*FALLTHROUGH*/ failed: /* Close the socket if we failed. */ - if (retcode != VIR_DRV_OPEN_SUCCESS && priv->sock >= 0) { - if (priv->uses_tls && priv->session) + 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; @@ -682,26 +747,12 @@ doRemoteOpen (virConnectPtr conn, struct } while (reap != -1 && reap != priv->pid); } } - - /* Free up the URL and strings. */ - xmlFreeURI (uri); - 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; - while (*cmd_argv_ptr) { - free (*cmd_argv_ptr); - cmd_argv_ptr++; - } - free (cmd_argv); - } - - return retcode; + if (priv->hostname) { + free (priv->hostname); + priv->hostname = NULL; + } + + goto cleanup; } static int @@ -1005,11 +1056,12 @@ initialise_gnutls (virConnectPtr conn AT 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, @@ -1050,7 +1102,7 @@ negotiate_gnutls_on_connection (virConne } gnutls_transport_set_ptr (session, - (gnutls_transport_ptr_t) (long) sock); + (gnutls_transport_ptr_t) (long) priv->sock); /* Perform the TLS handshake. */ again: @@ -1063,7 +1115,7 @@ negotiate_gnutls_on_connection (virConne } /* 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; @@ -1098,8 +1150,8 @@ negotiate_gnutls_on_connection (virConne 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; @@ -1177,14 +1229,14 @@ verify_certificate (virConnectPtr conn A } if (i == 0) { - if (!gnutls_x509_crt_check_hostname (cert, hostname)) { + if (!gnutls_x509_crt_check_hostname (cert, priv->hostname)) { __virRaiseError (NULL, 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; } @@ -1206,8 +1258,14 @@ doRemoteClose (virConnectPtr conn, struc 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) { @@ -1224,6 +1282,9 @@ doRemoteClose (virConnectPtr conn, struc /* Free URI copy. */ if (priv->uri) free (priv->uri); + + /* Free hostname copy */ + if (priv->hostname) free (priv->hostname); /* Free private data. */ priv->magic = DEAD; @@ -2756,6 +2817,299 @@ remoteNetworkSetAutostart (virNetworkPtr return 0; } + +/*----------------------------------------------------------------------*/ + +static int +remoteAuthenticate (virConnectPtr conn, struct private_data *priv, int in_open) +{ + struct remote_auth_list_ret ret; + + memset(&ret, 0, sizeof ret); + if (call (conn, priv, in_open, REMOTE_PROC_AUTH_LIST, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_remote_auth_list_ret, (char *) &ret) == -1) { + virErrorPtr err = virGetLastError(); + if (!err) + return -1; + if (err->domain == VIR_FROM_REMOTE && + err->code == VIR_ERR_RPC && + err->level == VIR_ERR_ERROR && + STREQLEN(err->message, "unknown procedure", 17) == 0) { + virResetLastError(); + /* Old server. Does not do authentication */ + return 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 +static char *addrToString(struct sockaddr_storage *sa, socklen_t salen) +{ + char host[1024], port[20]; + char *addr; + + if (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", errno, strerror(errno)); + 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; + 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; + } + printf("'%s' '%s' '%s'\n", priv->hostname, localAddr, remoteAddr); + /* 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 /*----------------------------------------------------------------------*/ diff -r b5fe91c98e78 src/virsh.c --- a/src/virsh.c Tue Oct 30 16:14:32 2007 -0400 +++ b/src/virsh.c Thu Nov 01 15:03:01 2007 -0400 @@ -4512,8 +4512,10 @@ vshInit(vshControl * ctl) * vshConnectionUsability, except ones which don't need a connection * such as "help". */ - if (!ctl->conn) + if (!ctl->conn) { vshError(ctl, FALSE, _("failed to connect to the hypervisor")); + return FALSE; + } return TRUE; } diff -r b5fe91c98e78 src/virterror.c --- a/src/virterror.c Tue Oct 30 16:14:32 2007 -0400 +++ b/src/virterror.c Thu Nov 01 15:03:01 2007 -0400 @@ -652,6 +652,12 @@ __virErrorMsg(virErrorNumber error, cons 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); } diff -r b5fe91c98e78 tests/Makefile.am --- a/tests/Makefile.am Tue Oct 30 16:14:32 2007 -0400 +++ b/tests/Makefile.am Thu Nov 01 15:03:01 2007 -0400 @@ -17,6 +17,7 @@ INCLUDES = \ -I$(top_srcdir)/src \ $(LIBXML_CFLAGS) \ $(GNUTLS_CFLAGS) \ + $(SASL_CFLAGS) \ -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=199506L \ -DGETTEXT_PACKAGE=\"$(PACKAGE)\" \ $(COVERAGE_CFLAGS) \ @@ -27,6 +28,7 @@ LDADDS = \ @STATIC_BINARIES@ \ $(LIBXML_LIBS) \ $(GNUTLS_LIBS) \ + $(SASL_LIBS) \ $(WARN_CFLAGS) \ $(LIBVIRT) \ $(COVERAGE_LDFLAGS) -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

"Daniel P. Berrange" <berrange@redhat.com> wrote:
This patch hooks up the basic authentication RPC calls, and the specific SASL implementation. The SASL impl can be enabled/disable via the configurre script with --without-sasl / --with-sasl - it'll auto-enable it if it finds the headers & libs OK.
Nice! I like the design. I found some implementation nits: ...
diff -r b5fe91c98e78 qemud/remote.c --- a/qemud/remote.c Tue Oct 30 16:14:32 2007 -0400 +++ b/qemud/remote.c Thu Nov 01 16:54:13 2007 -0400 ... +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; + ret->types.types_val = calloc (ret->types.types_len, sizeof (remote_auth_type));
Detect calloc failure: if (ret->types.types_val == NULL) { remoteDispatchError(client, req, "cannot allocate auth type list"); return -1; }
+ ret->types.types_val[0] = client->auth; + return 0; +} + + +#if HAVE_SASL +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; + + if (getnameinfo((struct sockaddr *)sa, salen, ... + remoteDispatchError(client, req, + "Cannot resolve address %d: %s", errno, strerror(errno));
There's enough shared code between this addrToString and the identically-named function in qemud/remote.c, that it'd be nice to add a warning/comment in each that they need to be kept in sync. It's probably not worth trying to merge them: with two uses of each, pulling the error- reporting bits out would just unfactor/pollute into the callers. Well, maybe it's worth factoring after all: Both use errno rather than gai_strerror(the return value). Also, it's better to test getnameinfo() != 0, since officially, that's all that matters. I.e., 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: %s", gai_strerror(err)); return NULL; }
+ remoteDispatchError(client, req, + "Cannot resolve address %d: %s", errno, strerror(errno)); + 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) +{ ... + 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) {
Maybe another qemudLog call here, for the sake of consistency? e.g., qemudLog(QEMUD_ERR, "mechlist allocation failure")
+ 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 illegal SASL start request");
s/illegal/invalid/ (and two more, below) "illegal" regards laws and the legal system
+ remoteDispatchFailAuth(client, req); + return -2; ... +static int +remoteDispatchAuthSaslStep (struct qemud_client *client, + remote_message_header *req, + remote_auth_sasl_step_args *args, + remote_auth_sasl_step_ret *ret) ...
The two preceding functions are so similar, that I took the time to compare and factor them into one, to avoid the duplication. In the process, I found one minor nit that might have caused confusion: remoteDispatchAuthSasl*Step* can log an invalid *start* request, when I think it means a "step" request:
+ qemudLog(QEMUD_ERR, "client tried illegal SASL start request");
Here's the factored version. Yeah, it's a 70-line macro, and that's ugly, but there's no other way. IMHO, eliminating that much duplication makes it worthwhile. ...
+static int +remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open) ... + if ((remoteAddr = addrToString(&sa, salen)) == NULL) { + free(localAddr); + return -1; + } + printf("'%s' '%s' '%s'\n", priv->hostname, localAddr, remoteAddr);
Is this printf for debugging?

With the TLS socket, all data is encrypted on the wire. The TCP socket though is still clear text. Fortunately some SASL authentication mechanism can also supply encryption capabilities. This is called SSF in SASL terminology. This patch mandates the use of an SSF capable SASL authentiction mechanism on the TCP socket. This in effect restricts you to a choise between GSSAPI and DIGEST-MD5 as your SASL auth methods (the latter is a user/password based scheme). We also disallow anonymous & plaintext auth methods. If you really want to run the TCP socket in clear text & with anonymous auth, simply turn off SASL altogether. Since TLS already provides encryptiuon, if you run SASL over the TLS socket, we don't place any restrictions on the choice of SASL auth mechanism. On the server side I have removed the 'direction' field of the client object. This was only used on the TLS socket & was intended to track whether the handshake process was waiting to receive or send. Rather than try to set this in various places throughout the daemon code, we simply query the neccessary direction at the one point where we register a FD event handle with poll(). This makes the code clearer to follow & reduces the chance of accidentally messing up the state. The send & receive functions previously would call read vs gnutls_record_recv and write vs gnutls_record_send depending on the type of socket. If there is a SASL SSF layer enabled, we have to first pass the outgoing data through the sasl_encode() API, and pass incoming data through sasl_decode(). So the send/recive APIs have changed a little, to deal with this codec need and thus there is also some more state being tracked per connection - we may have to cache the output for sasl_decode for future calls depending on how much data we need in short term. NB, the SSF layer lets you choose a strength factor from 0 -> a large number and the docs all talk about * 0 = no protection * 1 = integrity protection only * 40 = 40-bit DES or 40-bit RC2/RC4 * 56 = DES * 112 = triple-DES * 128 = 128-bit RC2/RC4/BLOWFISH * 256 = baseline AES This is incredibly misleading. The GSSAPI mechanism in SASL will never report a strength of anything other than 56. Even if it is using triple-DES. The true strength of the GSSAPI/Kerberos impl is impossible to figure out from the SASL apis - you have to trust that the underlying Kerberos impl was compiled with suitably strong ciphers - all modern OS use strong ciphers in Kebreros so I don't think this is a huge issue. If you are truely paranoid though, you always have the option of using TLS (which gives at least 128 bit ciphers, often 256 bit), and then just using Kerberos for auth and ignore the SASL SSF layer. This is an site admin config choice. qemud/internal.h | 17 ++- qemud/qemud.c | 207 +++++++++++++++++++++++++++++------- qemud/remote.c | 97 ++++++++++++++++- src/remote_internal.c | 283 ++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 503 insertions(+), 101 deletions(-) Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

Daniel P. Berrange wrote:
qemud/internal.h | 17 ++- qemud/qemud.c | 207 +++++++++++++++++++++++++++++------- qemud/remote.c | 97 ++++++++++++++++- src/remote_internal.c | 283 ++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 503 insertions(+), 101 deletions(-)
The diffstat is here, but I don't see the patch :). Chris Lalancette

On Fri, Nov 02, 2007 at 01:09:26AM +0000, Daniel P. Berrange wrote:
With the TLS socket, all data is encrypted on the wire. The TCP socket though is still clear text. Fortunately some SASL authentication mechanism can also supply encryption capabilities. This is called SSF in SASL terminology.
This patch mandates the use of an SSF capable SASL authentiction mechanism on the TCP socket. This in effect restricts you to a choise between GSSAPI and DIGEST-MD5 as your SASL auth methods (the latter is a user/password based scheme). We also disallow anonymous & plaintext auth methods. If you really want to run the TCP socket in clear text & with anonymous auth, simply turn off SASL altogether. Since TLS already provides encryptiuon, if you run SASL over the TLS socket, we don't place any restrictions on the choice of SASL auth mechanism.
On the server side I have removed the 'direction' field of the client object. This was only used on the TLS socket & was intended to track whether the handshake process was waiting to receive or send. Rather than try to set this in various places throughout the daemon code, we simply query the neccessary direction at the one point where we register a FD event handle with poll(). This makes the code clearer to follow & reduces the chance of accidentally messing up the state.
The send & receive functions previously would call read vs gnutls_record_recv and write vs gnutls_record_send depending on the type of socket. If there is a SASL SSF layer enabled, we have to first pass the outgoing data through the sasl_encode() API, and pass incoming data through sasl_decode(). So the send/recive APIs have changed a little, to deal with this codec need and thus there is also some more state being tracked per connection - we may have to cache the output for sasl_decode for future calls depending on how much data we need in short term.
NB, the SSF layer lets you choose a strength factor from 0 -> a large number and the docs all talk about
* 0 = no protection * 1 = integrity protection only * 40 = 40-bit DES or 40-bit RC2/RC4 * 56 = DES * 112 = triple-DES * 128 = 128-bit RC2/RC4/BLOWFISH * 256 = baseline AES
This is incredibly misleading. The GSSAPI mechanism in SASL will never report a strength of anything other than 56. Even if it is using triple-DES. The true strength of the GSSAPI/Kerberos impl is impossible to figure out from the SASL apis - you have to trust that the underlying Kerberos impl was compiled with suitably strong ciphers - all modern OS use strong ciphers in Kebreros so I don't think this is a huge issue. If you are truely paranoid though, you always have the option of using TLS (which gives at least 128 bit ciphers, often 256 bit), and then just using Kerberos for auth and ignore the SASL SSF layer. This is an site admin config choice.
qemud/internal.h | 17 ++- qemud/qemud.c | 207 +++++++++++++++++++++++++++++------- qemud/remote.c | 97 ++++++++++++++++- src/remote_internal.c | 283 ++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 503 insertions(+), 101 deletions(-)
diff -r 1052e0b6c97b qemud/internal.h --- a/qemud/internal.h Thu Nov 01 16:28:22 2007 -0400 +++ b/qemud/internal.h Thu Nov 01 16:28:26 2007 -0400 @@ -67,10 +67,11 @@ enum qemud_mode { QEMUD_MODE_TLS_HANDSHAKE, }; -/* These have to remain compatible with gnutls_record_get_direction. */ -enum qemud_tls_direction { - QEMUD_TLS_DIRECTION_READ = 0, - QEMUD_TLS_DIRECTION_WRITE = 1, +/* Whether we're passing reads & writes through a sasl SSF */ +enum qemud_sasl_ssf { + QEMUD_SASL_SSF_NONE = 0, + QEMUD_SASL_SSF_READ = 1, + QEMUD_SASL_SSF_WRITE = 2, }; /* Stores the per-client connection state */ @@ -87,10 +88,16 @@ struct qemud_client { /* If set, TLS is required on this socket. */ int tls; gnutls_session_t session; - enum qemud_tls_direction direction; int auth; #if HAVE_SASL sasl_conn_t *saslconn; + int saslSSF; + const char *saslDecoded; + unsigned int saslDecodedLength; + unsigned int saslDecodedOffset; + const char *saslEncoded; + unsigned int saslEncodedLength; + unsigned int saslEncodedOffset; #endif unsigned int incomingSerial; diff -r 1052e0b6c97b qemud/qemud.c --- a/qemud/qemud.c Thu Nov 01 16:28:22 2007 -0400 +++ b/qemud/qemud.c Thu Nov 01 16:28:26 2007 -0400 @@ -701,7 +701,9 @@ static struct qemud_server *qemudInitial struct qemud_socket *sock; char sockname[PATH_MAX]; char roSockname[PATH_MAX]; +#if HAVE_SASL int err; +#endif if (!(server = calloc(1, sizeof(struct qemud_server)))) { qemudLog(QEMUD_ERR, "Failed to allocate struct qemud_server"); @@ -1029,7 +1031,6 @@ remoteCheckAccess (struct qemud_client * client->bufferOffset = 0; client->buffer[0] = '\1'; client->mode = QEMUD_MODE_TX_PACKET; - client->direction = QEMUD_TLS_DIRECTION_WRITE; return 0; } @@ -1095,7 +1096,6 @@ static int qemudDispatchServer(struct qe /* Most likely. */ client->mode = QEMUD_MODE_TLS_HANDSHAKE; client->bufferLength = -1; - client->direction = gnutls_record_get_direction (client->session); if (qemudRegisterClientEvent (server, client, 0) < 0) goto cleanup; @@ -1153,13 +1153,10 @@ static void qemudDispatchClientFailure(s -static int qemudClientRead(struct qemud_server *server, - struct qemud_client *client) { - int ret, len; - char *data; - - data = client->buffer + client->bufferOffset; - len = client->bufferLength - client->bufferOffset; +static int qemudClientReadBuf(struct qemud_server *server, + struct qemud_client *client, + char *data, unsigned len) { + int ret; /*qemudDebug ("qemudClientRead: len = %d", len);*/ @@ -1174,7 +1171,6 @@ static int qemudClientRead(struct qemud_ } } else { ret = gnutls_record_recv (client->session, data, len); - client->direction = gnutls_record_get_direction (client->session); if (qemudRegisterClientEvent (server, client, 1) < 0) qemudDispatchClientFailure (server, client); else if (ret <= 0) { @@ -1189,9 +1185,79 @@ static int qemudClientRead(struct qemud_ } } + return ret; +} + +static int qemudClientReadPlain(struct qemud_server *server, + struct qemud_client *client) { + int ret; + ret = qemudClientReadBuf(server, client, + client->buffer + client->bufferOffset, + client->bufferLength - client->bufferOffset); + if (ret < 0) + return ret; client->bufferOffset += ret; return 0; } + +#if HAVE_SASL +static int qemudClientReadSASL(struct qemud_server *server, + struct qemud_client *client) { + int got, want; + + /* 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) { + char encoded[8192]; + int encodedLen = sizeof(encoded); + encodedLen = qemudClientReadBuf(server, client, encoded, encodedLen); + + if (encodedLen < 0) + return -1; + + sasl_decode(client->saslconn, encoded, encodedLen, + &client->saslDecoded, &client->saslDecodedLength); + + client->saslDecodedOffset = 0; + } + + /* Some buffered decoded data to return now */ + got = client->saslDecodedLength - client->saslDecodedOffset; + want = client->bufferLength - client->bufferOffset; + + if (want > got) + want = got; + + memcpy(client->buffer + client->bufferOffset, + client->saslDecoded + client->saslDecodedOffset, want); + client->saslDecodedOffset += want; + client->bufferOffset += want; + + if (client->saslDecodedOffset == client->saslDecodedLength) { + client->saslDecoded = NULL; + client->saslDecodedOffset = client->saslDecodedLength = 0; + } + + return 0; +} +#endif + +static int qemudClientRead(struct qemud_server *server, + struct qemud_client *client) { +#if HAVE_SASL + if (client->saslSSF & QEMUD_SASL_SSF_READ) + return qemudClientReadSASL(server, client); + else +#endif + return qemudClientReadPlain(server, client); +} + static void qemudDispatchClientRead(struct qemud_server *server, struct qemud_client *client) { @@ -1235,7 +1301,6 @@ static void qemudDispatchClientRead(stru client->mode = QEMUD_MODE_RX_PAYLOAD; client->bufferLength = len - REMOTE_MESSAGE_HEADER_XDR_LEN; client->bufferOffset = 0; - if (client->tls) client->direction = QEMUD_TLS_DIRECTION_READ; if (qemudRegisterClientEvent(server, client, 1) < 0) { qemudDispatchClientFailure(server, client); @@ -1275,7 +1340,6 @@ static void qemudDispatchClientRead(stru gnutls_strerror (ret)); qemudDispatchClientFailure (server, client); } else { - client->direction = gnutls_record_get_direction (client->session); if (qemudRegisterClientEvent (server ,client, 1) < 0) qemudDispatchClientFailure (server, client); } @@ -1290,14 +1354,10 @@ static void qemudDispatchClientRead(stru } -static int qemudClientWrite(struct qemud_server *server, - struct qemud_client *client) { - int ret, len; - char *data; - - data = client->buffer + client->bufferOffset; - len = client->bufferLength - client->bufferOffset; - +static int qemudClientWriteBuf(struct qemud_server *server, + struct qemud_client *client, + const char *data, int len) { + int ret; if (!client->tls) { if ((ret = write(client->fd, data, len)) == -1) { if (errno != EAGAIN) { @@ -1308,7 +1368,6 @@ static int qemudClientWrite(struct qemud } } else { ret = gnutls_record_send (client->session, data, len); - client->direction = gnutls_record_get_direction (client->session); if (qemudRegisterClientEvent (server, client, 1) < 0) qemudDispatchClientFailure (server, client); else if (ret < 0) { @@ -1320,9 +1379,69 @@ static int qemudClientWrite(struct qemud return -1; } } - + return ret; +} + + +static int qemudClientWritePlain(struct qemud_server *server, + struct qemud_client *client) { + int ret = qemudClientWriteBuf(server, client, + client->buffer + client->bufferOffset, + client->bufferLength - client->bufferOffset); + if (ret < 0) + return -1; client->bufferOffset += ret; return 0; +} + + +#if HAVE_SASL +static int qemudClientWriteSASL(struct qemud_server *server, + struct qemud_client *client) { + int ret; + + /* Not got any pending encoded data, so we need to encode raw stuff */ + if (client->saslEncoded == NULL) { + int err; + err = sasl_encode(client->saslconn, + client->buffer + client->bufferOffset, + client->bufferLength - client->bufferOffset, + &client->saslEncoded, + &client->saslEncodedLength); + + client->saslEncodedOffset = 0; + } + + /* Send some of the encoded stuff out on the wire */ + ret = qemudClientWriteBuf(server, client, + client->saslEncoded + client->saslEncodedOffset, + client->saslEncodedLength - client->saslEncodedOffset); + + if (ret < 0) + return -1; + + /* 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; + client->bufferOffset = client->bufferLength; + } + + return 0; +} +#endif + +static int qemudClientWrite(struct qemud_server *server, + struct qemud_client *client) { +#if HAVE_SASL + if (client->saslSSF & QEMUD_SASL_SSF_WRITE) + return qemudClientWriteSASL(server, client); + else +#endif + return qemudClientWritePlain(server, client); } @@ -1337,7 +1456,6 @@ static void qemudDispatchClientWrite(str client->mode = QEMUD_MODE_RX_HEADER; client->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN; client->bufferOffset = 0; - if (client->tls) client->direction = QEMUD_TLS_DIRECTION_READ; if (qemudRegisterClientEvent (server, client, 1) < 0) qemudDispatchClientFailure (server, client); @@ -1362,7 +1480,6 @@ static void qemudDispatchClientWrite(str gnutls_strerror (ret)); qemudDispatchClientFailure (server, client); } else { - client->direction = gnutls_record_get_direction (client->session); if (qemudRegisterClientEvent (server, client, 1)) qemudDispatchClientFailure (server, client); } @@ -1402,25 +1519,37 @@ static int qemudRegisterClientEvent(stru static int qemudRegisterClientEvent(struct qemud_server *server, struct qemud_client *client, int removeFirst) { + int mode; + switch (client->mode) { + case QEMUD_MODE_TLS_HANDSHAKE: + if (gnutls_record_get_direction (client->session) == 0) + mode = POLLIN; + else + mode = POLLOUT; + break; + + case QEMUD_MODE_RX_HEADER: + case QEMUD_MODE_RX_PAYLOAD: + mode = POLLIN; + break; + + case QEMUD_MODE_TX_PACKET: + mode = POLLOUT; + break; + + default: + return -1; + } + if (removeFirst) if (virEventRemoveHandleImpl(client->fd) < 0) return -1; - if (client->tls) { - if (virEventAddHandleImpl(client->fd, - (client->direction ? - POLLOUT : POLLIN) | POLLERR | POLLHUP, - qemudDispatchClientEvent, - server) < 0) - return -1; - } else { - if (virEventAddHandleImpl(client->fd, - (client->mode == QEMUD_MODE_TX_PACKET ? - POLLOUT : POLLIN) | POLLERR | POLLHUP, - qemudDispatchClientEvent, - server) < 0) - return -1; - } + if (virEventAddHandleImpl(client->fd, + mode | POLLERR | POLLHUP, + qemudDispatchClientEvent, + server) < 0) + return -1; return 0; } diff -r 1052e0b6c97b qemud/remote.c --- a/qemud/remote.c Thu Nov 01 16:28:22 2007 -0400 +++ b/qemud/remote.c Thu Nov 01 16:32:06 2007 -0400 @@ -283,7 +283,6 @@ remoteDispatchClientRequest (struct qemu client->mode = QEMUD_MODE_TX_PACKET; client->bufferLength = len; client->bufferOffset = 0; - if (client->tls) client->direction = QEMUD_TLS_DIRECTION_WRITE; } /* An error occurred during the dispatching process itself (ie. not @@ -368,7 +367,6 @@ remoteDispatchSendError (struct qemud_cl client->mode = QEMUD_MODE_TX_PACKET; client->bufferLength = len; client->bufferOffset = 0; - if (client->tls) client->direction = QEMUD_TLS_DIRECTION_WRITE; } static void @@ -2034,6 +2032,7 @@ remoteDispatchAuthSaslInit (struct qemud remote_auth_sasl_init_ret *ret) { const char *mechlist = NULL; + sasl_security_properties_t secprops; int err; struct sockaddr_storage sa; socklen_t salen; @@ -2089,6 +2088,51 @@ remoteDispatchAuthSaslInit (struct qemud return -2; } + /* Inform SASL that we've got an external SSF layer from TLS */ + if (client->tls) { + gnutls_cipher_algorithm_t cipher; + sasl_ssf_t ssf; + + cipher = gnutls_cipher_get(client->session); + if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) { + qemudLog(QEMUD_ERR, "cannot TLS get cipher size"); + remoteDispatchFailAuth(client, req); + sasl_dispose(&client->saslconn); + client->saslconn = NULL; + return -2; + } + ssf *= 8; /* tls key size is bytes, sasl wants bits */ + + err = sasl_setprop(client->saslconn, SASL_SSF_EXTERNAL, &ssf); + if (err != SASL_OK) { + qemudLog(QEMUD_ERR, "cannot set SASL external SSF %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + remoteDispatchFailAuth(client, req); + sasl_dispose(&client->saslconn); + client->saslconn = NULL; + return -2; + } + } + + memset (&secprops, 0, sizeof secprops); + /* If we've got TLS, we don't care about SSF */ + secprops.min_ssf = client->tls ? 0 : 56; /* Good enough to require kerberos */ + secprops.max_ssf = client->tls ? 0 : 100000; /* Arbitrary big number */ + secprops.maxbufsize = 8192; + /* If we're not TLS, then forbid any anonymous or trivially crackable auth */ + secprops.security_flags = client->tls ? 0 : + SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; + + err = sasl_setprop(client->saslconn, SASL_SEC_PROPS, &secprops); + if (err != SASL_OK) { + qemudLog(QEMUD_ERR, "cannot set SASL security props %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + remoteDispatchFailAuth(client, req); + sasl_dispose(&client->saslconn); + client->saslconn = NULL; + return -2; + } + err = sasl_listmech(client->saslconn, NULL, /* Don't need to set user */ "", /* Prefix */ @@ -2117,6 +2161,45 @@ remoteDispatchAuthSaslInit (struct qemud return 0; } + +/* We asked for an SSF layer, so sanity check that we actaully + * got what we asked for */ +static int +remoteSASLCheckSSF (struct qemud_client *client, + remote_message_header *req) { + const void *val; + int err, ssf; + + err = sasl_getprop(client->saslconn, SASL_SSF, &val); + if (err != SASL_OK) { + qemudLog(QEMUD_ERR, "cannot query SASL ssf on connection %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + remoteDispatchFailAuth(client, req); + sasl_dispose(&client->saslconn); + client->saslconn = NULL; + return -1; + } + ssf = *(const int *)val; + REMOTE_DEBUG("negotiated an SSF of %d", ssf); + if (ssf < 56) { /* 56 is good for Kerberos */ + qemudLog(QEMUD_ERR, "negotiated SSF %d was not strong enough", ssf); + remoteDispatchFailAuth(client, req); + sasl_dispose(&client->saslconn); + client->saslconn = NULL; + return -1; + } + + /* Only setup for read initially, because we're about to send an RPC + * reply which must be in plain text. When the next incoming RPC + * arrives, we'll switch on writes too + * + * cf qemudClientReadSASL in qemud.c + */ + client->saslSSF = QEMUD_SASL_SSF_READ; + + /* We have a SSF !*/ + return 0; +} /* * This starts the SASL authentication negotiation. @@ -2183,6 +2266,11 @@ remoteDispatchAuthSaslStart (struct qemu if (err == SASL_CONTINUE) { ret->complete = 0; } else { + /* If non-TLS, check a suitable SSF was negotiated */ + if (!client->tls && + remoteSASLCheckSSF(client, req) < 0) + return -2; + REMOTE_DEBUG("Authentication successful %d", client->fd); ret->complete = 1; client->auth = REMOTE_AUTH_NONE; @@ -2254,6 +2342,11 @@ remoteDispatchAuthSaslStep (struct qemud if (err == SASL_CONTINUE) { ret->complete = 0; } else { + /* If non-TLS, check a suitable SSF was negotiated */ + if (!client->tls && + remoteSASLCheckSSF(client, req) < 0) + return -2; + REMOTE_DEBUG("Authentication successful %d", client->fd); ret->complete = 1; client->auth = REMOTE_AUTH_NONE; diff -r 1052e0b6c97b src/remote_internal.c --- a/src/remote_internal.c Thu Nov 01 16:28:22 2007 -0400 +++ b/src/remote_internal.c Thu Nov 01 16:32:48 2007 -0400 @@ -78,6 +78,9 @@ struct private_data { FILE *debugLog; /* Debug remote protocol */ #if HAVE_SASL sasl_conn_t *saslconn; /* SASL context */ + const char *saslDecoded; + unsigned int saslDecodedLength; + unsigned int saslDecodedOffset; #endif }; @@ -145,6 +148,7 @@ remoteStartup(void) return 0; } +#if HAVE_SASL static void remoteDebug(struct private_data *priv, const char *msg,...) { @@ -157,6 +161,7 @@ remoteDebug(struct private_data *priv, c va_end(args); fprintf(priv->debugLog, "\n"); } +#endif /** @@ -2904,15 +2909,14 @@ static char *addrToString(struct sockadd /* 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; + sasl_security_properties_t secprops; remote_auth_sasl_init_ret iret; remote_auth_sasl_start_args sargs; remote_auth_sasl_start_ret sret; @@ -2926,6 +2930,8 @@ remoteAuthSASL (virConnectPtr conn, stru struct sockaddr_storage sa; socklen_t salen; char *localAddr, *remoteAddr; + const void *val; + sasl_ssf_t ssf; remoteDebug(priv, "Client initialize SASL authentication"); /* Sets up the SASL library as a whole */ @@ -2965,7 +2971,7 @@ remoteAuthSASL (virConnectPtr conn, stru free(localAddr); return -1; } - printf("'%s' '%s' '%s'\n", priv->hostname, localAddr, remoteAddr); + /* Setup a handle for being a client */ err = sasl_client_new("libvirt", priv->hostname, @@ -2981,6 +2987,51 @@ remoteAuthSASL (virConnectPtr conn, stru 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; + } + + /* Initialize some connection props we care about */ + if (priv->uses_tls) { + gnutls_cipher_algorithm_t cipher; + + cipher = gnutls_cipher_get(priv->session); + if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) { + __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE, + VIR_ERR_INTERNAL_ERROR, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "invalid cipher size for TLS session"); + sasl_dispose(&saslconn); + return -1; + } + ssf *= 8; /* key size is bytes, sasl wants bits */ + + remoteDebug(priv, "Setting external SSF %d", ssf); + err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf); + if (err != SASL_OK) { + __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE, + VIR_ERR_INTERNAL_ERROR, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "cannot set external SSF %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + sasl_dispose(&saslconn); + return -1; + } + } + + memset (&secprops, 0, sizeof secprops); + /* If we've got TLS, we don't care about SSF */ + secprops.min_ssf = priv->uses_tls ? 0 : 56; /* Equiv to DES supported by all Kerberos */ + secprops.max_ssf = priv->uses_tls ? 0 : 100000; /* Very strong ! AES == 256 */ + secprops.maxbufsize = 100000; + /* If we're not TLS, then forbid any anonymous or trivially crackable auth */ + secprops.security_flags = priv->uses_tls ? 0 : + SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; + + err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops); + if (err != SASL_OK) { + __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE, + VIR_ERR_INTERNAL_ERROR, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "cannot set security props %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + sasl_dispose(&saslconn); return -1; } @@ -3100,9 +3151,30 @@ remoteAuthSASL (virConnectPtr conn, stru } } + /* Check for suitable SSF if non-TLS */ + if (!priv->uses_tls) { + err = sasl_getprop(saslconn, SASL_SSF, &val); + 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, + "cannot query SASL ssf on connection %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + sasl_dispose(&saslconn); + return -1; + } + ssf = *(const int *)val; + remoteDebug(priv, "SASL SSF value %d", ssf); + if (ssf < 56) { /* 56 == DES level, good for Kerberos */ + __virRaiseError (in_open ? NULL : conn, NULL, NULL, VIR_FROM_REMOTE, + VIR_ERR_AUTH_FAILED, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0, + "negotiation SSF %d was not strong enough", ssf); + sasl_dispose(&saslconn); + return -1; + } + } + remoteDebug(priv, "SASL authentication complete"); - /* XXX keep this around for wire encoding */ - sasl_dispose(&saslconn); + priv->saslconn = saslconn; return 0; } #endif @@ -3294,11 +3366,11 @@ call (virConnectPtr conn, struct private } static int -really_write (virConnectPtr conn, struct private_data *priv, - int in_open /* if we are in virConnectOpen */, - char *bytes, int len) -{ - char *p; +really_write_buf (virConnectPtr conn, struct private_data *priv, + int in_open /* if we are in virConnectOpen */, + const char *bytes, int len) +{ + const char *p; int err; p = bytes; @@ -3336,55 +3408,156 @@ really_write (virConnectPtr conn, struct } static int +really_write_plain (virConnectPtr conn, struct private_data *priv, + int in_open /* if we are in virConnectOpen */, + char *bytes, int len) +{ + return really_write_buf(conn, priv, in_open, bytes, len); +} + +#if HAVE_SASL +static int +really_write_sasl (virConnectPtr conn, struct private_data *priv, + int in_open /* if we are in virConnectOpen */, + char *bytes, int len) +{ + const char *output; + unsigned int outputlen; + int err; + + err = sasl_encode(priv->saslconn, bytes, len, &output, &outputlen); + if (err != SASL_OK) { + return -1; + } + + return really_write_buf(conn, priv, in_open, output, outputlen); +} +#endif + +static int +really_write (virConnectPtr conn, struct private_data *priv, + int in_open /* if we are in virConnectOpen */, + char *bytes, int len) +{ +#if HAVE_SASL + if (priv->saslconn) + return really_write_sasl(conn, priv, in_open, bytes, len); + else +#endif + return really_write_plain(conn, priv, in_open, bytes, len); +} + +static int +really_read_buf (virConnectPtr conn, struct private_data *priv, + int in_open /* if we are in virConnectOpen */, + char *bytes, int len) +{ + int err; + + if (priv->uses_tls) { + tlsreread: + err = gnutls_record_recv (priv->session, bytes, len); + if (err < 0) { + if (err == GNUTLS_E_INTERRUPTED) + goto tlsreread; + error (in_open ? NULL : conn, + VIR_ERR_GNUTLS_ERROR, gnutls_strerror (err)); + return -1; + } + if (err == 0) { + error (in_open ? NULL : conn, + VIR_ERR_RPC, "socket closed unexpectedly"); + return -1; + } + return err; + } else { + reread: + err = read (priv->sock, bytes, len); + if (err == -1) { + if (errno == EINTR) + goto reread; + error (in_open ? NULL : conn, + VIR_ERR_SYSTEM_ERROR, strerror (errno)); + return -1; + } + if (err == 0) { + error (in_open ? NULL : conn, + VIR_ERR_RPC, "socket closed unexpectedly"); + return -1; + } + return err; + } + + return 0; +} + +static int +really_read_plain (virConnectPtr conn, struct private_data *priv, + int in_open /* if we are in virConnectOpen */, + char *bytes, int len) +{ + do { + int ret = really_read_buf (conn, priv, in_open, bytes, len); + if (ret < 0) + return -1; + + len -= ret; + bytes += ret; + } while (len > 0); + + return 0; +} + +#if HAVE_SASL +static int +really_read_sasl (virConnectPtr conn, struct private_data *priv, + int in_open /* if we are in virConnectOpen */, + char *bytes, int len) +{ + do { + int want, got; + if (priv->saslDecoded == NULL) { + char encoded[8192]; + int encodedLen = sizeof(encoded); + int err, ret; + ret = really_read_buf (conn, priv, in_open, encoded, encodedLen); + if (ret < 0) + return -1; + + err = sasl_decode(priv->saslconn, encoded, ret, + &priv->saslDecoded, &priv->saslDecodedLength); + } + + got = priv->saslDecodedLength - priv->saslDecodedOffset; + want = len; + if (want > got) + want = got; + + memcpy(bytes, priv->saslDecoded + priv->saslDecodedOffset, want); + priv->saslDecodedOffset += want; + if (priv->saslDecodedOffset == priv->saslDecodedLength) { + priv->saslDecoded = NULL; + priv->saslDecodedOffset = priv->saslDecodedLength = 0; + } + bytes += want; + len -= want; + } while (len > 0); + + return 0; +} +#endif + +static int really_read (virConnectPtr conn, struct private_data *priv, int in_open /* if we are in virConnectOpen */, char *bytes, int len) { - char *p; - int err; - - p = bytes; - if (priv->uses_tls) { - do { - err = gnutls_record_recv (priv->session, p, len); - if (err < 0) { - if (err == GNUTLS_E_INTERRUPTED || err == GNUTLS_E_AGAIN) - continue; - error (in_open ? NULL : conn, - VIR_ERR_GNUTLS_ERROR, gnutls_strerror (err)); - return -1; - } - if (err == 0) { - error (in_open ? NULL : conn, - VIR_ERR_RPC, "socket closed unexpectedly"); - return -1; - } - len -= err; - p += err; - } - while (len > 0); - } else { - do { - err = read (priv->sock, p, len); - if (err == -1) { - if (errno == EINTR || errno == EAGAIN) - continue; - error (in_open ? NULL : conn, - VIR_ERR_SYSTEM_ERROR, strerror (errno)); - return -1; - } - if (err == 0) { - error (in_open ? NULL : conn, - VIR_ERR_RPC, "socket closed unexpectedly"); - return -1; - } - len -= err; - p += err; - } - while (len > 0); - } - - return 0; +#if HAVE_SASL + if (priv->saslconn) + return really_read_sasl (conn, priv, in_open, bytes, len); + else +#endif + return really_read_plain (conn, priv, in_open, bytes, len); } /* For errors internal to this library. */ -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

"Daniel P. Berrange" <berrange@redhat.com> wrote:
On Fri, Nov 02, 2007 at 01:09:26AM +0000, Daniel P. Berrange wrote:
With the TLS socket, all data is encrypted on the wire. The TCP socket though is still clear text. Fortunately some SASL authentication mechanism can ... qemud/internal.h | 17 ++- qemud/qemud.c | 207 +++++++++++++++++++++++++++++------- qemud/remote.c | 97 ++++++++++++++++- src/remote_internal.c | 283 ++++++++++++++++++++++++++++++++++++++++----------
Hi Dan, I like the design and have started looking at the implementation. I have two small suggestions so far:
+#if HAVE_SASL +static int qemudClientReadSASL(struct qemud_server *server, + struct qemud_client *client) { + int got, want; ... + if (want > got) + want = got;
Barely worth mentioning, but... The first time I read that, I didn't recognize right away that it's essentially "want = MIN(want, got)". For such a test, I find it more readable to reverse the inequality: if (got < want) want = got; whatever. ...
+#if HAVE_SASL +static int qemudClientWriteSASL(struct qemud_server *server, + struct qemud_client *client) { + int ret; + + /* Not got any pending encoded data, so we need to encode raw stuff */ + if (client->saslEncoded == NULL) { + int err; + err = sasl_encode(client->saslconn, + client->buffer + client->bufferOffset, + client->bufferLength - client->bufferOffset, + &client->saslEncoded, + &client->saslEncodedLength); + + client->saslEncodedOffset = 0; + }
The documentation for sasl_encode suggests that it can fail in many ways. I guess it needs the same "if (err != SASL_OK) { ... }" test as used in the latter parts of this patch.

This patch provides the ability to configure what authentication mechanism is used on each socket - UNIX RW, UNIX RO, TCP, and TLS sockets - all can have independant settings. By default the UNIX & TLS sockets have no auth, and the TCP socket has SASL auth enabled. The /etc/libvirt/libvirtd.conf file lets you override these options. There is also a new sasl_allowed_username_list = ["admin"] config param to let you whitelist the users you want to allow. This supports use of wildcards. The username is dependnat on the SASL auth mechanism. For DIGEST-MD5 it will be plain usernames, for Kerberos it will be a username + realm, eg admin@EXAMPLE.COM After discussion with Rich, I also remove the tls_allowed_ip_list for whitelisting source IP addresses. This was a) not protecting us because it was only checked after the TLS handshake - thus allowing trivial DOS attack b) much easier to handle via tcp wrappers, or IPtables. c) only ever checked for the TLS socket d) IP addresses are easily spoofed. If summary, if you're using a real authentication mechanism, this is only useful for protecting against DOS attacks & that's better done by iptables. internal.h | 4 libvirtd.conf | 139 ++++++++++++---- qemud.c | 357 +++++++++++++++++++++---------------------- remote.c | 290 +++++++++++++++++++++++++--------- remote_dispatch_prototypes.h | 138 ++++++++-------- remote_generate_stubs.pl | 5 6 files changed, 572 insertions(+), 361 deletions(-) diff -r 54ffed012e46 qemud/internal.h --- a/qemud/internal.h Thu Nov 01 16:33:15 2007 -0400 +++ b/qemud/internal.h Thu Nov 01 16:33:19 2007 -0400 @@ -98,6 +98,7 @@ struct qemud_client { const char *saslEncoded; unsigned int saslEncodedLength; unsigned int saslEncodedOffset; + char *saslUsername; #endif unsigned int incomingSerial; @@ -141,6 +142,9 @@ struct qemud_server { #ifdef HAVE_AVAHI struct libvirtd_mdns *mdns; #endif +#if HAVE_SASL + char **saslUsernameWhitelist; +#endif }; void qemudLog(int priority, const char *fmt, ...) diff -r 54ffed012e46 qemud/libvirtd.conf --- a/qemud/libvirtd.conf Thu Nov 01 16:33:15 2007 -0400 +++ b/qemud/libvirtd.conf Thu Nov 01 16:33:19 2007 -0400 @@ -2,6 +2,11 @@ # # For further information consult http://libvirt.org/format.html + +################################################################# +# +# Network connectivitiy controls +# # Flag listening for secure TLS connections on the public TCP/IP port. # NB, must pass the --listen flag to the libvirtd process for this to @@ -17,7 +22,9 @@ # NB, must pass the --listen flag to the libvirtd process for this to # have any effect. # -# NB, this is insecure. Do not use except for development. +# Using the TCP socket requires SASL authentication by default. Only +# SASL mechanisms which support data encryption are allowed. This is +# DIGEST_MD5 and GSSAPI (Kerberos5) # # This is disabled by default, uncomment this to enable it. # listen_tcp = 1 @@ -53,6 +60,10 @@ # mdns_name "Virtualization Host Joe Demo" +################################################################# +# +# UNIX socket access controls +# # Set the UNIX domain socket group ownership. This can be used to # allow a 'trusted' set of users access to management capabilities @@ -77,6 +88,86 @@ +################################################################# +# +# Authentication. +# +# - none: do not perform auth checks. If you can connect to the +# socket you are allowed. This is suitable if there are +# restrictions on connecting to the socket (eg, UNIX +# socket permissions), or if there is a lower layer in +# the network providing auth (eg, TLS/x509 certificates) +# +# - sasl: use SASL infrastructure. The actual auth scheme is then +# controlled from /etc/sasl2/libvirt.conf. For the TCP +# socket only GSSAPI & DIGEST-MD5 mechanisms will be used. +# For non-TCP or TLS sockets, any scheme is allowed. +# + +# Set an authentication scheme for UNIX read-only sockets +# By default socket permissions allow anyone to connect +# +# To restrict monitoring of domains you may wish to enable +# an authentication mechnaism here +# auth_unix_ro = "none" + +# Set an authentication scheme for UNIX read-write sockets +# By default socket permissions only allow root. +# +# If the unix_sock_rw_perms are changed you may wish to enable +# an authentication mechnaism here +# auth_unix_rw = "none" + +# Change the authentication scheme for TCP sockets. +# +# If you don't enable SASL, then all TCP traffic is cleartext. +# Don't do this outside of a dev/test scenario. For real world +# use, always enable SASL and use the GSSAPI or DIGEST-MD5 +# mechanism in /etc/sasl2/libvirt.conf +# auth_tcp = "sasl" + +# Change the authentication scheme for TLS sockets. +# +# TLS sockets already have encryption provided by the TLS +# layer, and limited authentication is done by certificates +# +# It is possible to make use of any SASL authentication +# mechanism as well, by using 'sasl' for this option +# auth_tls = "none" + + + +################################################################# +# +# TLS x509 certificate configuration +# + + +# Override the default server key file path +# +# key_file "/etc/pki/libvirt/private/serverkey.pem" + +# Override the default server certificate file path +# +# cert_file "/etc/pki/libvirt/servercert.pem" + +# Override the default CA certificate path +# +# ca_file "/etc/pki/CA/cacert.pem" + +# Specify a certificate revocation list. +# +# Defaults to not using a CRL, uncomment to enable it +# crl_file "/etc/pki/CA/crl.pem" + + + +################################################################# +# +# Authorization controls +# + + # Flag to disable verification of client certificates # # Client certificate verification is the primary authentication mechanism. @@ -87,31 +178,6 @@ # verification - make sure an IP whitelist is set # tls_no_verify_certificate 1 -# Flag to disable verification of client IP address -# -# Client IP address will be verified against the CommonName field -# of the x509 certificate. This has minimal security benefit since -# it is easy to spoof source IP. -# -# Uncommenting this will disable verification -# tls_no_verify_address 1 - -# Override the default server key file path -# -# key_file "/etc/pki/libvirt/private/serverkey.pem" - -# Override the default server certificate file path -# -# cert_file "/etc/pki/libvirt/servercert.pem" - -# Override the default CA certificate path -# -# ca_file "/etc/pki/CA/cacert.pem" - -# Specify a certificate revocation list. -# -# Defaults to not using a CRL, uncomment to enable it -# crl_file "/etc/pki/CA/crl.pem" # A whitelist of allowed x509 Distinguished Names # This list may contain wildcards such as @@ -127,15 +193,20 @@ # tls_allowed_dn_list ["DN1", "DN2"] -# A whitelist of allowed client IP addresses -# -# This list may contain wildcards such as 192.168.* See the POSIX fnmatch -# function for the format of the wildcards. +# A whitelist of allowed SASL usernames. The format for usernames +# depends on the SASL authentication mechanism. Kerberos usernames +# look like username@REALM +# +# This list may contain wildcards such as +# +# "*@EXAMPLE.COM" +# +# See the POSIX fnmatch function for the format of the wildcards. # # NB If this is an empty list, no client can connect, so comment out # entirely rather than using empty list to disable these checks # -# By default, no IP's are checked. This can be IPv4 or IPv6 addresses -# tls_allowed_ip_list ["ip1", "ip2", "ip3"] - - +# By default, no Username's are checked +# sasl_allowed_username_list ["joe@EXAMPLE.COM", "fred@EXAMPLE.COM" ] + + diff -r 54ffed012e46 qemud/qemud.c --- a/qemud/qemud.c Thu Nov 01 16:33:15 2007 -0400 +++ b/qemud/qemud.c Thu Nov 01 16:35:57 2007 -0400 @@ -77,15 +77,23 @@ static int unix_sock_rw_perms = 0700; /* static int unix_sock_rw_perms = 0700; /* Allow user only */ static int unix_sock_ro_perms = 0777; /* Allow world */ + +static int auth_unix_rw = REMOTE_AUTH_NONE; +static int auth_unix_ro = REMOTE_AUTH_NONE; +#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; + #ifdef HAVE_AVAHI static int mdns_adv = 1; static const char *mdns_name = NULL; #endif static int tls_no_verify_certificate = 0; -static int tls_no_verify_address = 0; -static const char **tls_allowed_ip_list = 0; -static const char **tls_allowed_dn_list = 0; +static char **tls_allowed_dn_list = 0; static const char *key_file = LIBVIRT_SERVERKEY; static const char *cert_file = LIBVIRT_SERVERCERT; @@ -450,7 +458,7 @@ static int qemudWritePidFile(const char } static int qemudListenUnix(struct qemud_server *server, - const char *path, int readonly) { + const char *path, int readonly, int auth) { struct qemud_socket *sock = calloc(1, sizeof(struct qemud_socket)); struct sockaddr_un addr; mode_t oldmask; @@ -463,6 +471,7 @@ static int qemudListenUnix(struct qemud_ sock->readonly = readonly; sock->port = -1; + sock->auth = auth; if ((sock->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { qemudLog(QEMUD_ERR, "Failed to create socket: %s", @@ -698,6 +707,27 @@ static int qemudInitPaths(struct qemud_s static struct qemud_server *qemudInitialize(int sigread) { struct qemud_server *server; + + if (!(server = calloc(1, sizeof(struct qemud_server)))) { + qemudLog(QEMUD_ERR, "Failed to allocate struct qemud_server"); + return NULL; + } + + server->sigread = sigread; + + __virEventRegisterImpl(virEventAddHandleImpl, + virEventUpdateHandleImpl, + virEventRemoveHandleImpl, + virEventAddTimeoutImpl, + virEventUpdateTimeoutImpl, + virEventRemoveTimeoutImpl); + + virStateInitialize(); + + return server; +} + +static struct qemud_server *qemudNetworkInit(struct qemud_server *server) { struct qemud_socket *sock; char sockname[PATH_MAX]; char roSockname[PATH_MAX]; @@ -705,56 +735,39 @@ static struct qemud_server *qemudInitial int err; #endif - if (!(server = calloc(1, sizeof(struct qemud_server)))) { - qemudLog(QEMUD_ERR, "Failed to allocate struct qemud_server"); - return NULL; - } - - /* We don't have a dom-0, so start from 1 */ - server->sigread = sigread; - roSockname[0] = '\0'; if (qemudInitPaths(server, sockname, roSockname, PATH_MAX) < 0) goto cleanup; - if (qemudListenUnix(server, sockname, 0) < 0) + if (qemudListenUnix(server, sockname, 0, auth_unix_rw) < 0) goto cleanup; - if (roSockname[0] != '\0' && qemudListenUnix(server, roSockname, 1) < 0) + if (roSockname[0] != '\0' && qemudListenUnix(server, roSockname, 1, auth_unix_ro) < 0) goto cleanup; - __virEventRegisterImpl(virEventAddHandleImpl, - virEventUpdateHandleImpl, - virEventRemoveHandleImpl, - virEventAddTimeoutImpl, - virEventUpdateTimeoutImpl, - virEventRemoveTimeoutImpl); - - 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; + 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) { + qemudLog(QEMUD_ERR, "Failed to initialize SASL authentication %s", + sasl_errstring(err, NULL, NULL)); + goto cleanup; + } } #endif if (ipsock) { -#if HAVE_SASL - if (listen_tcp && remoteListenTCP (server, tcp_port, 0, REMOTE_AUTH_SASL) < 0) + if (listen_tcp && remoteListenTCP (server, tcp_port, 0, auth_tcp) < 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, REMOTE_AUTH_NONE) < 0) + if (remoteListenTCP (server, tls_port, 1, auth_tls) < 0) goto cleanup; } } @@ -856,7 +869,7 @@ remoteCheckDN (gnutls_x509_crt_t cert) { char name[256]; size_t namesize = sizeof name; - const char **wildcards; + char **wildcards; int err; err = gnutls_x509_crt_get_dn (cert, name, &namesize); @@ -974,53 +987,11 @@ static int static int remoteCheckAccess (struct qemud_client *client) { - char addr[NI_MAXHOST]; - const char **wildcards; - int found, err; - /* Verify client certificate. */ if (remoteCheckCertificate (client->session) == -1) { qemudLog (QEMUD_ERR, "remoteCheckCertificate: failed to verify client's certificate"); if (!tls_no_verify_certificate) return -1; else qemudLog (QEMUD_INFO, "remoteCheckCertificate: tls_no_verify_certificate is set so the bad certificate is ignored"); - } - - /*----- IP address check, similar to tcp wrappers -----*/ - - /* Convert IP address to printable string (eg. "127.0.0.1" or "::1"). */ - err = getnameinfo ((struct sockaddr *) &client->addr, client->addrlen, - addr, sizeof addr, NULL, 0, - NI_NUMERICHOST); - if (err != 0) { - qemudLog (QEMUD_ERR, "getnameinfo: %s", gai_strerror (err)); - return -1; - } - - /* Verify the client is on the list of allowed clients. - * - * NB: No tls_allowed_ip_list in config file means anyone can access. - * If tls_allowed_ip_list is in the config file but empty, means no - * one can access (not particularly useful, but it's what the sysadmin - * would expect). - */ - wildcards = tls_allowed_ip_list; - if (wildcards) { - found = 0; - - while (*wildcards) { - if (fnmatch (*wildcards, addr, 0) == 0) { - found = 1; - break; - } - wildcards++; - } - } else - found = 1; - - if (!found) { - qemudLog (QEMUD_ERR, "remoteCheckAccess: client's IP address (%s) is not on the list of allowed clients (tls_allowed_ip_list)", addr); - if (!tls_no_verify_address) return -1; - else qemudLog (QEMUD_INFO, "remoteCheckAccess: tls_no_verify_address is set so the client's IP address is ignored"); } /* Checks have succeeded. Write a '\1' byte back to the client to @@ -1646,17 +1617,93 @@ static void qemudCleanup(struct qemud_se sock = next; } - + if (server->saslUsernameWhitelist) { + char **list = server->saslUsernameWhitelist; + while (*list) { + if (*list) + free(*list); + list++; + } + } virStateCleanup(); free(server); +} + + +static int remoteConfigGetStringList(virConfPtr conf, const char *key, char ***list, const char *filename) { + virConfValuePtr p; + + p = virConfGetValue (conf, key); + if (p) { + switch (p->type) { + case VIR_CONF_STRING: + *list = malloc (2 * sizeof (char *)); + (*list)[0] = strdup (p->str); + (*list)[1] = 0; + break; + + case VIR_CONF_LIST: { + int i, len = 0; + virConfValuePtr pp; + for (pp = p->list; pp; pp = p->next) + len++; + *list = + malloc ((1+len) * sizeof (char *)); + for (i = 0, pp = p->list; pp; ++i, pp = p->next) { + if (pp->type != VIR_CONF_STRING) { + qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: %s: should be a string or list of strings\n", filename, key); + return -1; + } + (*list)[i] = strdup (pp->str); + } + (*list)[i] = 0; + break; + } + + default: + qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: %s: should be a string or list of strings\n", filename, key); + return -1; + } + } + + return 0; +} + +static int remoteConfigGetAuth(virConfPtr conf, const char *key, int *auth, const char *filename) { + virConfValuePtr p; + + p = virConfGetValue (conf, key); + if (!p) + return 0; + + if (p->type != VIR_CONF_STRING) { + qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: %s: should be a string\n", filename, key); + 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; +#endif + } else { + qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: %s: unsupported auth %s\n", filename, key, p->str); + return -1; + } + + return 0; } /* Read the config file if it exists. * Only used in the remote case, hence the name. */ static int -remoteReadConfigFile (const char *filename) +remoteReadConfigFile (struct qemud_server *server, const char *filename) { virConfPtr conf; @@ -1692,6 +1739,15 @@ remoteReadConfigFile (const char *filena p = virConfGetValue (conf, "tcp_port"); CHECK_TYPE ("tcp_port", VIR_CONF_STRING); tcp_port = p ? strdup (p->str) : tcp_port; + + if (remoteConfigGetAuth(conf, "auth_unix_rw", &auth_unix_rw, filename) < 0) + return -1; + if (remoteConfigGetAuth(conf, "auth_unix_ro", &auth_unix_ro, filename) < 0) + return -1; + if (remoteConfigGetAuth(conf, "auth_tcp", &auth_tcp, filename) < 0) + return -1; + if (remoteConfigGetAuth(conf, "auth_tls", &auth_tls, filename) < 0) + return -1; p = virConfGetValue (conf, "unix_sock_group"); CHECK_TYPE ("unix_sock_group", VIR_CONF_STRING); @@ -1744,10 +1800,6 @@ remoteReadConfigFile (const char *filena CHECK_TYPE ("tls_no_verify_certificate", VIR_CONF_LONG); tls_no_verify_certificate = p ? p->l : tls_no_verify_certificate; - p = virConfGetValue (conf, "tls_no_verify_address"); - CHECK_TYPE ("tls_no_verify_address", VIR_CONF_LONG); - tls_no_verify_address = p ? p->l : tls_no_verify_address; - p = virConfGetValue (conf, "key_file"); CHECK_TYPE ("key_file", VIR_CONF_STRING); key_file = p ? strdup (p->str) : key_file; @@ -1764,71 +1816,11 @@ remoteReadConfigFile (const char *filena CHECK_TYPE ("crl_file", VIR_CONF_STRING); crl_file = p ? strdup (p->str) : crl_file; - p = virConfGetValue (conf, "tls_allowed_dn_list"); - if (p) { - switch (p->type) { - case VIR_CONF_STRING: - tls_allowed_dn_list = malloc (2 * sizeof (char *)); - tls_allowed_dn_list[0] = strdup (p->str); - tls_allowed_dn_list[1] = 0; - break; - - case VIR_CONF_LIST: { - int i, len = 0; - virConfValuePtr pp; - for (pp = p->list; pp; pp = p->next) - len++; - tls_allowed_dn_list = - malloc ((1+len) * sizeof (char *)); - for (i = 0, pp = p->list; pp; ++i, pp = p->next) { - if (pp->type != VIR_CONF_STRING) { - qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: tls_allowed_dn_list: should be a string or list of strings\n", filename); - return -1; - } - tls_allowed_dn_list[i] = strdup (pp->str); - } - tls_allowed_dn_list[i] = 0; - break; - } - - default: - qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: tls_allowed_dn_list: should be a string or list of strings\n", filename); - return -1; - } - } - - p = virConfGetValue (conf, "tls_allowed_ip_list"); - if (p) { - switch (p->type) { - case VIR_CONF_STRING: - tls_allowed_ip_list = malloc (2 * sizeof (char *)); - tls_allowed_ip_list[0] = strdup (p->str); - tls_allowed_ip_list[1] = 0; - break; - - case VIR_CONF_LIST: { - int i, len = 0; - virConfValuePtr pp; - for (pp = p->list; pp; pp = p->next) - len++; - tls_allowed_ip_list = - malloc ((1+len) * sizeof (char *)); - for (i = 0, pp = p->list; pp; ++i, pp = p->next) { - if (pp->type != VIR_CONF_STRING) { - qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: tls_allowed_ip_list: should be a string or list of strings\n", filename); - return -1; - } - tls_allowed_ip_list[i] = strdup (pp->str); - } - tls_allowed_ip_list[i] = 0; - break; - } - - default: - qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: tls_allowed_ip_list: should be a string or list of strings\n", filename); - return -1; - } - } + if (remoteConfigGetStringList(conf, "tls_allowed_dn_list", &tls_allowed_dn_list, filename) < 0) + return -1; + + if (remoteConfigGetStringList(conf, "sasl_allowed_username_list", &server->saslUsernameWhitelist, filename) < 0) + return -1; virConfFree (conf); return 0; @@ -1951,13 +1943,6 @@ int main(int argc, char **argv) { } } - /* Read the config file (if it exists). */ - if (remoteReadConfigFile (remote_config_file) < 0) - goto error1; - - if (godaemon) - openlog("libvirtd", 0, 0); - if (pipe(sigpipe) < 0 || qemudSetNonBlock(sigpipe[0]) < 0 || qemudSetNonBlock(sigpipe[1]) < 0) { @@ -1965,8 +1950,38 @@ int main(int argc, char **argv) { strerror(errno)); goto error1; } - sigwrite = sigpipe[1]; + + if (!(server = qemudInitialize(sigpipe[0]))) { + ret = 2; + goto error1; + } + + /* Read the config file (if it exists). */ + if (remoteReadConfigFile (server, remote_config_file) < 0) + goto error1; + + if (godaemon) { + int pid; + openlog("libvirtd", 0, 0); + pid = qemudGoDaemon(); + if (pid < 0) { + qemudLog(QEMUD_ERR, "Failed to fork as daemon: %s", + strerror(errno)); + goto error1; + } + if (pid > 0) + goto out; + + /* Choose the name of the PID file. */ + if (!pid_file) { + if (REMOTE_PID_FILE[0] != '\0') + pid_file = REMOTE_PID_FILE; + } + + if (pid_file && qemudWritePidFile (pid_file) < 0) + goto error1; + } sig_action.sa_handler = sig_handler; sig_action.sa_flags = 0; @@ -1980,31 +1995,6 @@ int main(int argc, char **argv) { sig_action.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sig_action, NULL); - - if (godaemon) { - int pid = qemudGoDaemon(); - if (pid < 0) { - qemudLog(QEMUD_ERR, "Failed to fork as daemon: %s", - strerror(errno)); - goto error1; - } - if (pid > 0) - goto out; - - /* Choose the name of the PID file. */ - if (!pid_file) { - if (REMOTE_PID_FILE[0] != '\0') - pid_file = REMOTE_PID_FILE; - } - - if (pid_file && qemudWritePidFile (pid_file) < 0) - goto error1; - } - - if (!(server = qemudInitialize(sigpipe[0]))) { - ret = 2; - goto error2; - } if (virEventAddHandleImpl(sigpipe[0], POLLIN, @@ -2012,6 +2002,11 @@ int main(int argc, char **argv) { server) < 0) { qemudLog(QEMUD_ERR, "Failed to register callback for signal pipe"); ret = 3; + goto error2; + } + + if (!(server = qemudNetworkInit(server))) { + ret = 2; goto error2; } diff -r 54ffed012e46 qemud/remote.c --- a/qemud/remote.c Thu Nov 01 16:33:15 2007 -0400 +++ b/qemud/remote.c Thu Nov 01 16:37:12 2007 -0400 @@ -44,6 +44,7 @@ #include <getopt.h> #include <ctype.h> #include <assert.h> +#include <fnmatch.h> #include <libvirt/virterror.h> @@ -64,14 +65,18 @@ static void make_nonnull_network (remote #include "remote_dispatch_prototypes.h" -typedef int (*dispatch_fn) (struct qemud_client *client, remote_message_header *req, char *args, char *ret); +typedef int (*dispatch_fn) (struct qemud_server *server, + struct qemud_client *client, + remote_message_header *req, + char *args, + char *ret); /* This function gets called from qemud when it detects an incoming * remote protocol message. At this point, client->buffer contains * the full call message (including length word which we skip). */ void -remoteDispatchClientRequest (struct qemud_server *server ATTRIBUTE_UNUSED, +remoteDispatchClientRequest (struct qemud_server *server, struct qemud_client *client) { XDR xdr; @@ -157,7 +162,7 @@ remoteDispatchClientRequest (struct qemu xdr_destroy (&xdr); /* Call function. */ - rv = fn (client, &req, args, ret); + rv = fn (server, client, &req, args, ret); xdr_free (args_filter, args); /* Dispatch function must return -2, -1 or 0. Anything else is @@ -397,7 +402,8 @@ remoteDispatchError (struct qemud_client /*----- Functions. -----*/ static int -remoteDispatchOpen (struct qemud_client *client, remote_message_header *req, +remoteDispatchOpen (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, struct remote_open_args *args, void *ret ATTRIBUTE_UNUSED) { const char *name; @@ -436,7 +442,8 @@ remoteDispatchOpen (struct qemud_client } static int -remoteDispatchClose (struct qemud_client *client, remote_message_header *req, +remoteDispatchClose (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, void *args ATTRIBUTE_UNUSED, void *ret ATTRIBUTE_UNUSED) { int rv; @@ -449,7 +456,8 @@ remoteDispatchClose (struct qemud_client } static int -remoteDispatchSupportsFeature (struct qemud_client *client, remote_message_header *req, +remoteDispatchSupportsFeature (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_supports_feature_args *args, remote_supports_feature_ret *ret) { CHECK_CONN(client); @@ -461,7 +469,8 @@ remoteDispatchSupportsFeature (struct qe } static int -remoteDispatchGetType (struct qemud_client *client, remote_message_header *req, +remoteDispatchGetType (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, void *args ATTRIBUTE_UNUSED, remote_get_type_ret *ret) { const char *type; @@ -483,7 +492,8 @@ remoteDispatchGetType (struct qemud_clie } static int -remoteDispatchGetVersion (struct qemud_client *client, +remoteDispatchGetVersion (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, void *args ATTRIBUTE_UNUSED, remote_get_version_ret *ret) @@ -499,7 +509,8 @@ remoteDispatchGetVersion (struct qemud_c } static int -remoteDispatchGetHostname (struct qemud_client *client, +remoteDispatchGetHostname (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, void *args ATTRIBUTE_UNUSED, remote_get_hostname_ret *ret) @@ -515,7 +526,8 @@ remoteDispatchGetHostname (struct qemud_ } static int -remoteDispatchGetMaxVcpus (struct qemud_client *client, +remoteDispatchGetMaxVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_get_max_vcpus_args *args, remote_get_max_vcpus_ret *ret) @@ -531,7 +543,8 @@ remoteDispatchGetMaxVcpus (struct qemud_ } static int -remoteDispatchNodeGetInfo (struct qemud_client *client, +remoteDispatchNodeGetInfo (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, void *args ATTRIBUTE_UNUSED, remote_node_get_info_ret *ret) @@ -555,7 +568,8 @@ remoteDispatchNodeGetInfo (struct qemud_ } static int -remoteDispatchGetCapabilities (struct qemud_client *client, +remoteDispatchGetCapabilities (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, void *args ATTRIBUTE_UNUSED, remote_get_capabilities_ret *ret) @@ -571,7 +585,8 @@ remoteDispatchGetCapabilities (struct qe } static int -remoteDispatchDomainGetSchedulerType (struct qemud_client *client, +remoteDispatchDomainGetSchedulerType (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_get_scheduler_type_args *args, remote_domain_get_scheduler_type_ret *ret) @@ -600,7 +615,8 @@ remoteDispatchDomainGetSchedulerType (st } static int -remoteDispatchDomainGetSchedulerParameters (struct qemud_client *client, +remoteDispatchDomainGetSchedulerParameters (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_get_scheduler_parameters_args *args, remote_domain_get_scheduler_parameters_ret *ret) @@ -686,7 +702,8 @@ remoteDispatchDomainGetSchedulerParamete } static int -remoteDispatchDomainSetSchedulerParameters (struct qemud_client *client, +remoteDispatchDomainSetSchedulerParameters (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_set_scheduler_parameters_args *args, void *ret ATTRIBUTE_UNUSED) @@ -746,7 +763,8 @@ remoteDispatchDomainSetSchedulerParamete } static int -remoteDispatchDomainBlockStats (struct qemud_client *client, +remoteDispatchDomainBlockStats (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_block_stats_args *args, remote_domain_block_stats_ret *ret) @@ -776,7 +794,8 @@ remoteDispatchDomainBlockStats (struct q } static int -remoteDispatchDomainInterfaceStats (struct qemud_client *client, +remoteDispatchDomainInterfaceStats (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_interface_stats_args *args, remote_domain_interface_stats_ret *ret) @@ -809,7 +828,8 @@ remoteDispatchDomainInterfaceStats (stru } static int -remoteDispatchDomainAttachDevice (struct qemud_client *client, +remoteDispatchDomainAttachDevice (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_attach_device_args *args, void *ret ATTRIBUTE_UNUSED) @@ -832,7 +852,8 @@ remoteDispatchDomainAttachDevice (struct } static int -remoteDispatchDomainCreate (struct qemud_client *client, +remoteDispatchDomainCreate (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_create_args *args, void *ret ATTRIBUTE_UNUSED) @@ -855,7 +876,8 @@ remoteDispatchDomainCreate (struct qemud } static int -remoteDispatchDomainCreateLinux (struct qemud_client *client, +remoteDispatchDomainCreateLinux (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_create_linux_args *args, remote_domain_create_linux_ret *ret) @@ -873,7 +895,8 @@ remoteDispatchDomainCreateLinux (struct } static int -remoteDispatchDomainDefineXml (struct qemud_client *client, +remoteDispatchDomainDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_define_xml_args *args, remote_domain_define_xml_ret *ret) @@ -891,7 +914,8 @@ remoteDispatchDomainDefineXml (struct qe } static int -remoteDispatchDomainDestroy (struct qemud_client *client, +remoteDispatchDomainDestroy (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_destroy_args *args, void *ret ATTRIBUTE_UNUSED) @@ -912,7 +936,8 @@ remoteDispatchDomainDestroy (struct qemu } static int -remoteDispatchDomainDetachDevice (struct qemud_client *client, +remoteDispatchDomainDetachDevice (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_detach_device_args *args, void *ret ATTRIBUTE_UNUSED) @@ -936,7 +961,8 @@ remoteDispatchDomainDetachDevice (struct } static int -remoteDispatchDomainDumpXml (struct qemud_client *client, +remoteDispatchDomainDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_dump_xml_args *args, remote_domain_dump_xml_ret *ret) @@ -961,7 +987,8 @@ remoteDispatchDomainDumpXml (struct qemu } static int -remoteDispatchDomainGetAutostart (struct qemud_client *client, +remoteDispatchDomainGetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_get_autostart_args *args, remote_domain_get_autostart_ret *ret) @@ -984,7 +1011,8 @@ remoteDispatchDomainGetAutostart (struct } static int -remoteDispatchDomainGetInfo (struct qemud_client *client, +remoteDispatchDomainGetInfo (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_get_info_args *args, remote_domain_get_info_ret *ret) @@ -1016,7 +1044,8 @@ remoteDispatchDomainGetInfo (struct qemu } static int -remoteDispatchDomainGetMaxMemory (struct qemud_client *client, +remoteDispatchDomainGetMaxMemory (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_get_max_memory_args *args, remote_domain_get_max_memory_ret *ret) @@ -1040,7 +1069,8 @@ remoteDispatchDomainGetMaxMemory (struct } static int -remoteDispatchDomainGetMaxVcpus (struct qemud_client *client, +remoteDispatchDomainGetMaxVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_get_max_vcpus_args *args, remote_domain_get_max_vcpus_ret *ret) @@ -1064,7 +1094,8 @@ remoteDispatchDomainGetMaxVcpus (struct } static int -remoteDispatchDomainGetOsType (struct qemud_client *client, +remoteDispatchDomainGetOsType (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_get_os_type_args *args, remote_domain_get_os_type_ret *ret) @@ -1089,7 +1120,8 @@ remoteDispatchDomainGetOsType (struct qe } static int -remoteDispatchDomainGetVcpus (struct qemud_client *client, +remoteDispatchDomainGetVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_get_vcpus_args *args, remote_domain_get_vcpus_ret *ret) @@ -1153,7 +1185,8 @@ remoteDispatchDomainGetVcpus (struct qem } static int -remoteDispatchDomainMigratePrepare (struct qemud_client *client, +remoteDispatchDomainMigratePrepare (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_migrate_prepare_args *args, remote_domain_migrate_prepare_ret *ret) @@ -1188,7 +1221,8 @@ remoteDispatchDomainMigratePrepare (stru } static int -remoteDispatchDomainMigratePerform (struct qemud_client *client, +remoteDispatchDomainMigratePerform (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_migrate_perform_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1217,7 +1251,8 @@ remoteDispatchDomainMigratePerform (stru } static int -remoteDispatchDomainMigrateFinish (struct qemud_client *client, +remoteDispatchDomainMigrateFinish (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_migrate_finish_args *args, remote_domain_migrate_finish_ret *ret) @@ -1238,7 +1273,8 @@ remoteDispatchDomainMigrateFinish (struc } static int -remoteDispatchListDefinedDomains (struct qemud_client *client, +remoteDispatchListDefinedDomains (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_list_defined_domains_args *args, remote_list_defined_domains_ret *ret) @@ -1263,7 +1299,8 @@ remoteDispatchListDefinedDomains (struct } static int -remoteDispatchDomainLookupById (struct qemud_client *client, +remoteDispatchDomainLookupById (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_id_args *args, remote_domain_lookup_by_id_ret *ret) @@ -1280,7 +1317,8 @@ remoteDispatchDomainLookupById (struct q } static int -remoteDispatchDomainLookupByName (struct qemud_client *client, +remoteDispatchDomainLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_name_args *args, remote_domain_lookup_by_name_ret *ret) @@ -1297,7 +1335,8 @@ remoteDispatchDomainLookupByName (struct } static int -remoteDispatchDomainLookupByUuid (struct qemud_client *client, +remoteDispatchDomainLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_uuid_args *args, remote_domain_lookup_by_uuid_ret *ret) @@ -1314,7 +1353,8 @@ remoteDispatchDomainLookupByUuid (struct } static int -remoteDispatchNumOfDefinedDomains (struct qemud_client *client, +remoteDispatchNumOfDefinedDomains (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, void *args ATTRIBUTE_UNUSED, remote_num_of_defined_domains_ret *ret) @@ -1328,7 +1368,8 @@ remoteDispatchNumOfDefinedDomains (struc } static int -remoteDispatchDomainPinVcpu (struct qemud_client *client, +remoteDispatchDomainPinVcpu (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_pin_vcpu_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1361,7 +1402,8 @@ remoteDispatchDomainPinVcpu (struct qemu } static int -remoteDispatchDomainReboot (struct qemud_client *client, +remoteDispatchDomainReboot (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_reboot_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1384,7 +1426,8 @@ remoteDispatchDomainReboot (struct qemud } static int -remoteDispatchDomainRestore (struct qemud_client *client, +remoteDispatchDomainRestore (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_restore_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1398,7 +1441,8 @@ remoteDispatchDomainRestore (struct qemu } static int -remoteDispatchDomainResume (struct qemud_client *client, +remoteDispatchDomainResume (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_resume_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1421,7 +1465,8 @@ remoteDispatchDomainResume (struct qemud } static int -remoteDispatchDomainSave (struct qemud_client *client, +remoteDispatchDomainSave (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_save_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1444,7 +1489,8 @@ remoteDispatchDomainSave (struct qemud_c } static int -remoteDispatchDomainCoreDump (struct qemud_client *client, +remoteDispatchDomainCoreDump (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_core_dump_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1467,7 +1513,8 @@ remoteDispatchDomainCoreDump (struct qem } static int -remoteDispatchDomainSetAutostart (struct qemud_client *client, +remoteDispatchDomainSetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_set_autostart_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1490,7 +1537,8 @@ remoteDispatchDomainSetAutostart (struct } static int -remoteDispatchDomainSetMaxMemory (struct qemud_client *client, +remoteDispatchDomainSetMaxMemory (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_set_max_memory_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1513,7 +1561,8 @@ remoteDispatchDomainSetMaxMemory (struct } static int -remoteDispatchDomainSetMemory (struct qemud_client *client, +remoteDispatchDomainSetMemory (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_set_memory_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1536,7 +1585,8 @@ remoteDispatchDomainSetMemory (struct qe } static int -remoteDispatchDomainSetVcpus (struct qemud_client *client, +remoteDispatchDomainSetVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_set_vcpus_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1559,7 +1609,8 @@ remoteDispatchDomainSetVcpus (struct qem } static int -remoteDispatchDomainShutdown (struct qemud_client *client, +remoteDispatchDomainShutdown (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_shutdown_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1582,7 +1633,8 @@ remoteDispatchDomainShutdown (struct qem } static int -remoteDispatchDomainSuspend (struct qemud_client *client, +remoteDispatchDomainSuspend (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_suspend_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1605,7 +1657,8 @@ remoteDispatchDomainSuspend (struct qemu } static int -remoteDispatchDomainUndefine (struct qemud_client *client, +remoteDispatchDomainUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_domain_undefine_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1628,7 +1681,8 @@ remoteDispatchDomainUndefine (struct qem } static int -remoteDispatchListDefinedNetworks (struct qemud_client *client, +remoteDispatchListDefinedNetworks (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_list_defined_networks_args *args, remote_list_defined_networks_ret *ret) @@ -1653,7 +1707,8 @@ remoteDispatchListDefinedNetworks (struc } static int -remoteDispatchListDomains (struct qemud_client *client, +remoteDispatchListDomains (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_list_domains_args *args, remote_list_domains_ret *ret) @@ -1677,7 +1732,8 @@ remoteDispatchListDomains (struct qemud_ } static int -remoteDispatchListNetworks (struct qemud_client *client, +remoteDispatchListNetworks (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_list_networks_args *args, remote_list_networks_ret *ret) @@ -1702,7 +1758,8 @@ remoteDispatchListNetworks (struct qemud } static int -remoteDispatchNetworkCreate (struct qemud_client *client, +remoteDispatchNetworkCreate (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_network_create_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1725,7 +1782,8 @@ remoteDispatchNetworkCreate (struct qemu } static int -remoteDispatchNetworkCreateXml (struct qemud_client *client, +remoteDispatchNetworkCreateXml (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_network_create_xml_args *args, remote_network_create_xml_ret *ret) @@ -1742,7 +1800,8 @@ remoteDispatchNetworkCreateXml (struct q } static int -remoteDispatchNetworkDefineXml (struct qemud_client *client, +remoteDispatchNetworkDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_network_define_xml_args *args, remote_network_define_xml_ret *ret) @@ -1759,7 +1818,8 @@ remoteDispatchNetworkDefineXml (struct q } static int -remoteDispatchNetworkDestroy (struct qemud_client *client, +remoteDispatchNetworkDestroy (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_network_destroy_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1782,7 +1842,8 @@ remoteDispatchNetworkDestroy (struct qem } static int -remoteDispatchNetworkDumpXml (struct qemud_client *client, +remoteDispatchNetworkDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_network_dump_xml_args *args, remote_network_dump_xml_ret *ret) @@ -1807,7 +1868,8 @@ remoteDispatchNetworkDumpXml (struct qem } static int -remoteDispatchNetworkGetAutostart (struct qemud_client *client, +remoteDispatchNetworkGetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_network_get_autostart_args *args, remote_network_get_autostart_ret *ret) @@ -1830,7 +1892,8 @@ remoteDispatchNetworkGetAutostart (struc } static int -remoteDispatchNetworkGetBridgeName (struct qemud_client *client, +remoteDispatchNetworkGetBridgeName (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_network_get_bridge_name_args *args, remote_network_get_bridge_name_ret *ret) @@ -1855,7 +1918,8 @@ remoteDispatchNetworkGetBridgeName (stru } static int -remoteDispatchNetworkLookupByName (struct qemud_client *client, +remoteDispatchNetworkLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_network_lookup_by_name_args *args, remote_network_lookup_by_name_ret *ret) @@ -1872,7 +1936,8 @@ remoteDispatchNetworkLookupByName (struc } static int -remoteDispatchNetworkLookupByUuid (struct qemud_client *client, +remoteDispatchNetworkLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_network_lookup_by_uuid_args *args, remote_network_lookup_by_uuid_ret *ret) @@ -1889,7 +1954,8 @@ remoteDispatchNetworkLookupByUuid (struc } static int -remoteDispatchNetworkSetAutostart (struct qemud_client *client, +remoteDispatchNetworkSetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_network_set_autostart_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1912,7 +1978,8 @@ remoteDispatchNetworkSetAutostart (struc } static int -remoteDispatchNetworkUndefine (struct qemud_client *client, +remoteDispatchNetworkUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_network_undefine_args *args, void *ret ATTRIBUTE_UNUSED) @@ -1935,7 +2002,8 @@ remoteDispatchNetworkUndefine (struct qe } static int -remoteDispatchNumOfDefinedNetworks (struct qemud_client *client, +remoteDispatchNumOfDefinedNetworks (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, void *args ATTRIBUTE_UNUSED, remote_num_of_defined_networks_ret *ret) @@ -1949,7 +2017,8 @@ remoteDispatchNumOfDefinedNetworks (stru } static int -remoteDispatchNumOfDomains (struct qemud_client *client, +remoteDispatchNumOfDomains (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, void *args ATTRIBUTE_UNUSED, remote_num_of_domains_ret *ret) @@ -1963,7 +2032,8 @@ remoteDispatchNumOfDomains (struct qemud } static int -remoteDispatchNumOfNetworks (struct qemud_client *client, +remoteDispatchNumOfNetworks (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, void *args ATTRIBUTE_UNUSED, remote_num_of_networks_ret *ret) @@ -1978,7 +2048,8 @@ remoteDispatchNumOfNetworks (struct qemu static int -remoteDispatchAuthList (struct qemud_client *client, +remoteDispatchAuthList (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req ATTRIBUTE_UNUSED, void *args ATTRIBUTE_UNUSED, remote_auth_list_ret *ret) @@ -2026,7 +2097,8 @@ static char *addrToString(struct qemud_c * XXX callbacks for stuff like password verification ? */ static int -remoteDispatchAuthSaslInit (struct qemud_client *client, +remoteDispatchAuthSaslInit (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, void *args ATTRIBUTE_UNUSED, remote_auth_sasl_init_ret *ret) @@ -2201,11 +2273,67 @@ remoteSASLCheckSSF (struct qemud_client return 0; } +static int +remoteSASLCheckAccess (struct qemud_server *server, + struct qemud_client *client, + remote_message_header *req) { + const void *val; + int err; + char **wildcards; + + err = sasl_getprop(client->saslconn, SASL_USERNAME, &val); + if (err != SASL_OK) { + qemudLog(QEMUD_ERR, "cannot query SASL username on connection %d (%s)", + err, sasl_errstring(err, NULL, NULL)); + remoteDispatchFailAuth(client, req); + sasl_dispose(&client->saslconn); + client->saslconn = NULL; + return -1; + } + if (val == NULL) { + qemudLog(QEMUD_ERR, "no client username was found"); + remoteDispatchFailAuth(client, req); + sasl_dispose(&client->saslconn); + client->saslconn = NULL; + return -1; + } + REMOTE_DEBUG("SASL client username %s", (const char *)val); + + client->saslUsername = strdup((const char*)val); + if (client->saslUsername == NULL) { + qemudLog(QEMUD_ERR, "out of memory copying username"); + remoteDispatchFailAuth(client, req); + sasl_dispose(&client->saslconn); + client->saslconn = NULL; + return -1; + } + + /* If the list is not set, allow any DN. */ + wildcards = server->saslUsernameWhitelist; + if (!wildcards) + return 0; /* No ACL, allow all */ + + while (*wildcards) { + if (fnmatch (*wildcards, client->saslUsername, 0) == 0) + return 0; /* Allowed */ + wildcards++; + } + + /* Denied */ + qemudLog(QEMUD_ERR, "SASL client %s not allowed in whitelist", client->saslUsername); + remoteDispatchFailAuth(client, req); + sasl_dispose(&client->saslconn); + client->saslconn = NULL; + return -1; +} + + /* * This starts the SASL authentication negotiation. */ static int -remoteDispatchAuthSaslStart (struct qemud_client *client, +remoteDispatchAuthSaslStart (struct qemud_server *server, + struct qemud_client *client, remote_message_header *req, remote_auth_sasl_start_args *args, remote_auth_sasl_start_ret *ret) @@ -2271,6 +2399,10 @@ remoteDispatchAuthSaslStart (struct qemu remoteSASLCheckSSF(client, req) < 0) return -2; + /* Check username whitelist ACL */ + if (remoteSASLCheckAccess(server, client, req) < 0) + return -2; + REMOTE_DEBUG("Authentication successful %d", client->fd); ret->complete = 1; client->auth = REMOTE_AUTH_NONE; @@ -2281,7 +2413,8 @@ remoteDispatchAuthSaslStart (struct qemu static int -remoteDispatchAuthSaslStep (struct qemud_client *client, +remoteDispatchAuthSaslStep (struct qemud_server *server, + struct qemud_client *client, remote_message_header *req, remote_auth_sasl_step_args *args, remote_auth_sasl_step_ret *ret) @@ -2347,6 +2480,10 @@ remoteDispatchAuthSaslStep (struct qemud remoteSASLCheckSSF(client, req) < 0) return -2; + /* Check username whitelist ACL */ + if (remoteSASLCheckAccess(server, client, req) < 0) + return -2; + REMOTE_DEBUG("Authentication successful %d", client->fd); ret->complete = 1; client->auth = REMOTE_AUTH_NONE; @@ -2358,7 +2495,8 @@ remoteDispatchAuthSaslStep (struct qemud #else static int -remoteDispatchAuthSaslInit (struct qemud_client *client, +remoteDispatchAuthSaslInit (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_auth_sasl_step_args *args ATTRIBUTE_UNUSED, remote_auth_sasl_step_ret *ret ATTRIBUTE_UNUSED) @@ -2368,7 +2506,8 @@ remoteDispatchAuthSaslInit (struct qemud } static int -remoteDispatchAuthSaslStart (struct qemud_client *client, +remoteDispatchAuthSaslStart (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_auth_sasl_step_args *args ATTRIBUTE_UNUSED, remote_auth_sasl_step_ret *ret ATTRIBUTE_UNUSED) @@ -2378,7 +2517,8 @@ remoteDispatchAuthSaslStart (struct qemu } static int -remoteDispatchAuthSaslStep (struct qemud_client *client, +remoteDispatchAuthSaslStep (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, remote_message_header *req, remote_auth_sasl_step_args *args, remote_auth_sasl_step_ret *ret) diff -r 54ffed012e46 qemud/remote_dispatch_prototypes.h --- a/qemud/remote_dispatch_prototypes.h Thu Nov 01 16:33:15 2007 -0400 +++ b/qemud/remote_dispatch_prototypes.h Thu Nov 01 16:36:53 2007 -0400 @@ -2,72 +2,72 @@ * 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); -static int remoteDispatchDomainCoreDump (struct qemud_client *client, remote_message_header *req, remote_domain_core_dump_args *args, void *ret); -static int remoteDispatchDomainCreate (struct qemud_client *client, remote_message_header *req, remote_domain_create_args *args, void *ret); -static int remoteDispatchDomainCreateLinux (struct qemud_client *client, remote_message_header *req, remote_domain_create_linux_args *args, remote_domain_create_linux_ret *ret); -static int remoteDispatchDomainDefineXml (struct qemud_client *client, remote_message_header *req, remote_domain_define_xml_args *args, remote_domain_define_xml_ret *ret); -static int remoteDispatchDomainDestroy (struct qemud_client *client, remote_message_header *req, remote_domain_destroy_args *args, void *ret); -static int remoteDispatchDomainDetachDevice (struct qemud_client *client, remote_message_header *req, remote_domain_detach_device_args *args, void *ret); -static int remoteDispatchDomainDumpXml (struct qemud_client *client, remote_message_header *req, remote_domain_dump_xml_args *args, remote_domain_dump_xml_ret *ret); -static int remoteDispatchDomainGetAutostart (struct qemud_client *client, remote_message_header *req, remote_domain_get_autostart_args *args, remote_domain_get_autostart_ret *ret); -static int remoteDispatchDomainGetInfo (struct qemud_client *client, remote_message_header *req, remote_domain_get_info_args *args, remote_domain_get_info_ret *ret); -static int remoteDispatchDomainGetMaxMemory (struct qemud_client *client, remote_message_header *req, remote_domain_get_max_memory_args *args, remote_domain_get_max_memory_ret *ret); -static int remoteDispatchDomainGetMaxVcpus (struct qemud_client *client, remote_message_header *req, remote_domain_get_max_vcpus_args *args, remote_domain_get_max_vcpus_ret *ret); -static int remoteDispatchDomainGetOsType (struct qemud_client *client, remote_message_header *req, remote_domain_get_os_type_args *args, remote_domain_get_os_type_ret *ret); -static int remoteDispatchDomainGetSchedulerParameters (struct qemud_client *client, remote_message_header *req, remote_domain_get_scheduler_parameters_args *args, remote_domain_get_scheduler_parameters_ret *ret); -static int remoteDispatchDomainGetSchedulerType (struct qemud_client *client, remote_message_header *req, remote_domain_get_scheduler_type_args *args, remote_domain_get_scheduler_type_ret *ret); -static int remoteDispatchDomainGetVcpus (struct qemud_client *client, remote_message_header *req, remote_domain_get_vcpus_args *args, remote_domain_get_vcpus_ret *ret); -static int remoteDispatchDomainInterfaceStats (struct qemud_client *client, remote_message_header *req, remote_domain_interface_stats_args *args, remote_domain_interface_stats_ret *ret); -static int remoteDispatchDomainLookupById (struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_id_args *args, remote_domain_lookup_by_id_ret *ret); -static int remoteDispatchDomainLookupByName (struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_name_args *args, remote_domain_lookup_by_name_ret *ret); -static int remoteDispatchDomainLookupByUuid (struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_uuid_args *args, remote_domain_lookup_by_uuid_ret *ret); -static int remoteDispatchDomainMigrateFinish (struct qemud_client *client, remote_message_header *req, remote_domain_migrate_finish_args *args, remote_domain_migrate_finish_ret *ret); -static int remoteDispatchDomainMigratePerform (struct qemud_client *client, remote_message_header *req, remote_domain_migrate_perform_args *args, void *ret); -static int remoteDispatchDomainMigratePrepare (struct qemud_client *client, remote_message_header *req, remote_domain_migrate_prepare_args *args, remote_domain_migrate_prepare_ret *ret); -static int remoteDispatchDomainPinVcpu (struct qemud_client *client, remote_message_header *req, remote_domain_pin_vcpu_args *args, void *ret); -static int remoteDispatchDomainReboot (struct qemud_client *client, remote_message_header *req, remote_domain_reboot_args *args, void *ret); -static int remoteDispatchDomainRestore (struct qemud_client *client, remote_message_header *req, remote_domain_restore_args *args, void *ret); -static int remoteDispatchDomainResume (struct qemud_client *client, remote_message_header *req, remote_domain_resume_args *args, void *ret); -static int remoteDispatchDomainSave (struct qemud_client *client, remote_message_header *req, remote_domain_save_args *args, void *ret); -static int remoteDispatchDomainSetAutostart (struct qemud_client *client, remote_message_header *req, remote_domain_set_autostart_args *args, void *ret); -static int remoteDispatchDomainSetMaxMemory (struct qemud_client *client, remote_message_header *req, remote_domain_set_max_memory_args *args, void *ret); -static int remoteDispatchDomainSetMemory (struct qemud_client *client, remote_message_header *req, remote_domain_set_memory_args *args, void *ret); -static int remoteDispatchDomainSetSchedulerParameters (struct qemud_client *client, remote_message_header *req, remote_domain_set_scheduler_parameters_args *args, void *ret); -static int remoteDispatchDomainSetVcpus (struct qemud_client *client, remote_message_header *req, remote_domain_set_vcpus_args *args, void *ret); -static int remoteDispatchDomainShutdown (struct qemud_client *client, remote_message_header *req, remote_domain_shutdown_args *args, void *ret); -static int remoteDispatchDomainSuspend (struct qemud_client *client, remote_message_header *req, remote_domain_suspend_args *args, void *ret); -static int remoteDispatchDomainUndefine (struct qemud_client *client, remote_message_header *req, remote_domain_undefine_args *args, void *ret); -static int remoteDispatchGetCapabilities (struct qemud_client *client, remote_message_header *req, void *args, remote_get_capabilities_ret *ret); -static int remoteDispatchGetHostname (struct qemud_client *client, remote_message_header *req, void *args, remote_get_hostname_ret *ret); -static int remoteDispatchGetMaxVcpus (struct qemud_client *client, remote_message_header *req, remote_get_max_vcpus_args *args, remote_get_max_vcpus_ret *ret); -static int remoteDispatchGetType (struct qemud_client *client, remote_message_header *req, void *args, remote_get_type_ret *ret); -static int remoteDispatchGetVersion (struct qemud_client *client, remote_message_header *req, void *args, remote_get_version_ret *ret); -static int remoteDispatchListDefinedDomains (struct qemud_client *client, remote_message_header *req, remote_list_defined_domains_args *args, remote_list_defined_domains_ret *ret); -static int remoteDispatchListDefinedNetworks (struct qemud_client *client, remote_message_header *req, remote_list_defined_networks_args *args, remote_list_defined_networks_ret *ret); -static int remoteDispatchListDomains (struct qemud_client *client, remote_message_header *req, remote_list_domains_args *args, remote_list_domains_ret *ret); -static int remoteDispatchListNetworks (struct qemud_client *client, remote_message_header *req, remote_list_networks_args *args, remote_list_networks_ret *ret); -static int remoteDispatchNetworkCreate (struct qemud_client *client, remote_message_header *req, remote_network_create_args *args, void *ret); -static int remoteDispatchNetworkCreateXml (struct qemud_client *client, remote_message_header *req, remote_network_create_xml_args *args, remote_network_create_xml_ret *ret); -static int remoteDispatchNetworkDefineXml (struct qemud_client *client, remote_message_header *req, remote_network_define_xml_args *args, remote_network_define_xml_ret *ret); -static int remoteDispatchNetworkDestroy (struct qemud_client *client, remote_message_header *req, remote_network_destroy_args *args, void *ret); -static int remoteDispatchNetworkDumpXml (struct qemud_client *client, remote_message_header *req, remote_network_dump_xml_args *args, remote_network_dump_xml_ret *ret); -static int remoteDispatchNetworkGetAutostart (struct qemud_client *client, remote_message_header *req, remote_network_get_autostart_args *args, remote_network_get_autostart_ret *ret); -static int remoteDispatchNetworkGetBridgeName (struct qemud_client *client, remote_message_header *req, remote_network_get_bridge_name_args *args, remote_network_get_bridge_name_ret *ret); -static int remoteDispatchNetworkLookupByName (struct qemud_client *client, remote_message_header *req, remote_network_lookup_by_name_args *args, remote_network_lookup_by_name_ret *ret); -static int remoteDispatchNetworkLookupByUuid (struct qemud_client *client, remote_message_header *req, remote_network_lookup_by_uuid_args *args, remote_network_lookup_by_uuid_ret *ret); -static int remoteDispatchNetworkSetAutostart (struct qemud_client *client, remote_message_header *req, remote_network_set_autostart_args *args, void *ret); -static int remoteDispatchNetworkUndefine (struct qemud_client *client, remote_message_header *req, remote_network_undefine_args *args, void *ret); -static int remoteDispatchNodeGetInfo (struct qemud_client *client, remote_message_header *req, void *args, remote_node_get_info_ret *ret); -static int remoteDispatchNumOfDefinedDomains (struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_domains_ret *ret); -static int remoteDispatchNumOfDefinedNetworks (struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_networks_ret *ret); -static int remoteDispatchNumOfDomains (struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_domains_ret *ret); -static int remoteDispatchNumOfNetworks (struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_networks_ret *ret); -static int remoteDispatchOpen (struct qemud_client *client, remote_message_header *req, remote_open_args *args, void *ret); -static int remoteDispatchSupportsFeature (struct qemud_client *client, remote_message_header *req, remote_supports_feature_args *args, remote_supports_feature_ret *ret); +static int remoteDispatchAuthList (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_auth_list_ret *ret); +static int remoteDispatchAuthSaslInit (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_auth_sasl_init_ret *ret); +static int remoteDispatchAuthSaslStart (struct qemud_server *server, 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_server *server, 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_server *server, struct qemud_client *client, remote_message_header *req, void *args, void *ret); +static int remoteDispatchDomainAttachDevice (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_attach_device_args *args, void *ret); +static int remoteDispatchDomainBlockStats (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_block_stats_args *args, remote_domain_block_stats_ret *ret); +static int remoteDispatchDomainCoreDump (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_core_dump_args *args, void *ret); +static int remoteDispatchDomainCreate (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_create_args *args, void *ret); +static int remoteDispatchDomainCreateLinux (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_create_linux_args *args, remote_domain_create_linux_ret *ret); +static int remoteDispatchDomainDefineXml (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_define_xml_args *args, remote_domain_define_xml_ret *ret); +static int remoteDispatchDomainDestroy (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_destroy_args *args, void *ret); +static int remoteDispatchDomainDetachDevice (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_detach_device_args *args, void *ret); +static int remoteDispatchDomainDumpXml (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_dump_xml_args *args, remote_domain_dump_xml_ret *ret); +static int remoteDispatchDomainGetAutostart (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_autostart_args *args, remote_domain_get_autostart_ret *ret); +static int remoteDispatchDomainGetInfo (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_info_args *args, remote_domain_get_info_ret *ret); +static int remoteDispatchDomainGetMaxMemory (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_max_memory_args *args, remote_domain_get_max_memory_ret *ret); +static int remoteDispatchDomainGetMaxVcpus (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_max_vcpus_args *args, remote_domain_get_max_vcpus_ret *ret); +static int remoteDispatchDomainGetOsType (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_os_type_args *args, remote_domain_get_os_type_ret *ret); +static int remoteDispatchDomainGetSchedulerParameters (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_scheduler_parameters_args *args, remote_domain_get_scheduler_parameters_ret *ret); +static int remoteDispatchDomainGetSchedulerType (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_scheduler_type_args *args, remote_domain_get_scheduler_type_ret *ret); +static int remoteDispatchDomainGetVcpus (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_get_vcpus_args *args, remote_domain_get_vcpus_ret *ret); +static int remoteDispatchDomainInterfaceStats (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_interface_stats_args *args, remote_domain_interface_stats_ret *ret); +static int remoteDispatchDomainLookupById (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_id_args *args, remote_domain_lookup_by_id_ret *ret); +static int remoteDispatchDomainLookupByName (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_name_args *args, remote_domain_lookup_by_name_ret *ret); +static int remoteDispatchDomainLookupByUuid (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_uuid_args *args, remote_domain_lookup_by_uuid_ret *ret); +static int remoteDispatchDomainMigrateFinish (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_migrate_finish_args *args, remote_domain_migrate_finish_ret *ret); +static int remoteDispatchDomainMigratePerform (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_migrate_perform_args *args, void *ret); +static int remoteDispatchDomainMigratePrepare (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_migrate_prepare_args *args, remote_domain_migrate_prepare_ret *ret); +static int remoteDispatchDomainPinVcpu (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_pin_vcpu_args *args, void *ret); +static int remoteDispatchDomainReboot (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_reboot_args *args, void *ret); +static int remoteDispatchDomainRestore (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_restore_args *args, void *ret); +static int remoteDispatchDomainResume (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_resume_args *args, void *ret); +static int remoteDispatchDomainSave (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_save_args *args, void *ret); +static int remoteDispatchDomainSetAutostart (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_set_autostart_args *args, void *ret); +static int remoteDispatchDomainSetMaxMemory (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_set_max_memory_args *args, void *ret); +static int remoteDispatchDomainSetMemory (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_set_memory_args *args, void *ret); +static int remoteDispatchDomainSetSchedulerParameters (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_set_scheduler_parameters_args *args, void *ret); +static int remoteDispatchDomainSetVcpus (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_set_vcpus_args *args, void *ret); +static int remoteDispatchDomainShutdown (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_shutdown_args *args, void *ret); +static int remoteDispatchDomainSuspend (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_suspend_args *args, void *ret); +static int remoteDispatchDomainUndefine (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_undefine_args *args, void *ret); +static int remoteDispatchGetCapabilities (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_capabilities_ret *ret); +static int remoteDispatchGetHostname (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_hostname_ret *ret); +static int remoteDispatchGetMaxVcpus (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_get_max_vcpus_args *args, remote_get_max_vcpus_ret *ret); +static int remoteDispatchGetType (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_type_ret *ret); +static int remoteDispatchGetVersion (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_get_version_ret *ret); +static int remoteDispatchListDefinedDomains (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_list_defined_domains_args *args, remote_list_defined_domains_ret *ret); +static int remoteDispatchListDefinedNetworks (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_list_defined_networks_args *args, remote_list_defined_networks_ret *ret); +static int remoteDispatchListDomains (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_list_domains_args *args, remote_list_domains_ret *ret); +static int remoteDispatchListNetworks (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_list_networks_args *args, remote_list_networks_ret *ret); +static int remoteDispatchNetworkCreate (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_create_args *args, void *ret); +static int remoteDispatchNetworkCreateXml (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_create_xml_args *args, remote_network_create_xml_ret *ret); +static int remoteDispatchNetworkDefineXml (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_define_xml_args *args, remote_network_define_xml_ret *ret); +static int remoteDispatchNetworkDestroy (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_destroy_args *args, void *ret); +static int remoteDispatchNetworkDumpXml (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_dump_xml_args *args, remote_network_dump_xml_ret *ret); +static int remoteDispatchNetworkGetAutostart (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_get_autostart_args *args, remote_network_get_autostart_ret *ret); +static int remoteDispatchNetworkGetBridgeName (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_get_bridge_name_args *args, remote_network_get_bridge_name_ret *ret); +static int remoteDispatchNetworkLookupByName (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_lookup_by_name_args *args, remote_network_lookup_by_name_ret *ret); +static int remoteDispatchNetworkLookupByUuid (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_lookup_by_uuid_args *args, remote_network_lookup_by_uuid_ret *ret); +static int remoteDispatchNetworkSetAutostart (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_set_autostart_args *args, void *ret); +static int remoteDispatchNetworkUndefine (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_network_undefine_args *args, void *ret); +static int remoteDispatchNodeGetInfo (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_node_get_info_ret *ret); +static int remoteDispatchNumOfDefinedDomains (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_domains_ret *ret); +static int remoteDispatchNumOfDefinedNetworks (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_defined_networks_ret *ret); +static int remoteDispatchNumOfDomains (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_domains_ret *ret); +static int remoteDispatchNumOfNetworks (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, remote_num_of_networks_ret *ret); +static int remoteDispatchOpen (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_open_args *args, void *ret); +static int remoteDispatchSupportsFeature (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_supports_feature_args *args, remote_supports_feature_ret *ret); diff -r 54ffed012e46 qemud/remote_generate_stubs.pl --- a/qemud/remote_generate_stubs.pl Thu Nov 01 16:33:15 2007 -0400 +++ b/qemud/remote_generate_stubs.pl Thu Nov 01 16:33:19 2007 -0400 @@ -93,7 +93,7 @@ elsif ($opt_i) { elsif ($opt_i) { my @keys = sort (keys %calls); foreach (@keys) { - print "static int remoteDispatch$calls{$_}->{ProcName} (struct qemud_client *client, remote_message_header *req, $calls{$_}->{args} *args, $calls{$_}->{ret} *ret);\n"; + print "static int remoteDispatch$calls{$_}->{ProcName} (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, $calls{$_}->{args} *args, $calls{$_}->{ret} *ret);\n"; } } @@ -196,7 +196,8 @@ elsif ($opt_s) { my $retvoid = $ret eq "void"; print "static int\n"; - print "remoteDispatch$calls{$_}->{ProcName} (struct qemud_client *client,\n"; + print "remoteDispatch$calls{$_}->{ProcName} (struct qemud_server *server,\n"; + print " struct qemud_client *client,\n"; print " remote_message_header *req,\n"; print " remote_get_max_vcpus_args *args,\n"; print " remote_get_max_vcpus_ret *ret)\n"; Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

"Daniel P. Berrange" <berrange@redhat.com> wrote:
This patch provides the ability to configure what authentication mechanism is used on each socket - UNIX RW, UNIX RO, TCP, and TLS sockets - all can have independant settings. By default the UNIX & TLS sockets have no auth, ...
Hi Dan, I've gone through part 3/4 and had no further feedback beyond the two comments I already made there. As usual, it looks very good. I spotted a few minor problems below. ...
diff -r 54ffed012e46 qemud/qemud.c --- a/qemud/qemud.c Thu Nov 01 16:33:15 2007 -0400 +++ b/qemud/qemud.c Thu Nov 01 16:35:57 2007 -0400 ... +static int remoteConfigGetStringList(virConfPtr conf, const char *key, char ***list, const char *filename) { + virConfValuePtr p; + + p = virConfGetValue (conf, key); + if (p) { + switch (p->type) { + case VIR_CONF_STRING: + *list = malloc (2 * sizeof (char *)); + (*list)[0] = strdup (p->str);
check for malloc and strdup failure [I do see you're just moving this existing code.]
+ (*list)[1] = 0; + break; + + case VIR_CONF_LIST: { + int i, len = 0; + virConfValuePtr pp; + for (pp = p->list; pp; pp = p->next) + len++; + *list = + malloc ((1+len) * sizeof (char *));
here too
+ for (i = 0, pp = p->list; pp; ++i, pp = p->next) { + if (pp->type != VIR_CONF_STRING) { + qemudLog (QEMUD_ERR, "remoteReadConfigFile: %s: %s: should be a string or list of strings\n", filename, key); + return -1; + } + (*list)[i] = strdup (pp->str);
here too. While technically not necessary (there'd be no segfault), a failed strdup would mean ignoring part of the config file.
+ } + (*list)[i] = 0;
s/0/NULL/ makes it clearer that (*list)[i] is a pointer. ...
-remoteReadConfigFile (const char *filename) +remoteReadConfigFile (struct qemud_server *server, const char *filename) { virConfPtr conf;
@@ -1692,6 +1739,15 @@ remoteReadConfigFile (const char *filena p = virConfGetValue (conf, "tcp_port"); CHECK_TYPE ("tcp_port", VIR_CONF_STRING); tcp_port = p ? strdup (p->str) : tcp_port;
We need to check strdup here, too, since a couple levels down, tcp_port becomes "service" in a call to getaddrinfo(NULL, service, ... and in that case, service must not be NULL. There are a few more strdup calls in that area, but for all others, it looks like it's ok for the result to be NULL.

On Wed, Nov 21, 2007 at 08:34:17PM +0100, Jim Meyering wrote:
"Daniel P. Berrange" <berrange@redhat.com> wrote:
This patch provides the ability to configure what authentication mechanism is used on each socket - UNIX RW, UNIX RO, TCP, and TLS sockets - all can have independant settings. By default the UNIX & TLS sockets have no auth, ...
Hi Dan,
I've gone through part 3/4 and had no further feedback beyond the two comments I already made there.
As usual, it looks very good. I spotted a few minor problems below.
...
diff -r 54ffed012e46 qemud/qemud.c --- a/qemud/qemud.c Thu Nov 01 16:33:15 2007 -0400 +++ b/qemud/qemud.c Thu Nov 01 16:35:57 2007 -0400 ... +static int remoteConfigGetStringList(virConfPtr conf, const char *key, char ***list, const char *filename) { + virConfValuePtr p; + + p = virConfGetValue (conf, key); + if (p) { + switch (p->type) { + case VIR_CONF_STRING: + *list = malloc (2 * sizeof (char *)); + (*list)[0] = strdup (p->str);
check for malloc and strdup failure [I do see you're just moving this existing code.]
Looks like basically the entire remoteReadConfigFile() method needs to be fixed to check malloc() / strdup() return values actually, so might as well fix everything in one go. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
participants (3)
-
Chris Lalancette
-
Daniel P. Berrange
-
Jim Meyering