On Sat, May 05, 2007 at 12:17:44PM +0100, Richard W.M. Jones wrote:
Richard W.M. Jones wrote:
>3 Client-side
>-------------
>
>A src/remote_internal.c
>A src/remote_internal.h
>M src/driver.h
>M src/libvirt.c
This is the code which serialises requests on the client side. First up
is a small patch against driver.h and libvirt.c which just declares and
registers the new driver.
Secondly, the driver itself (remote_internal.h / remote_internal.c)
which I will describe in more detail.
The header file is small and I think non-controversial. It just
declares the remoteRegister function and a handful of constants like
paths and port numbers.
What sort of info is currently stored in the $sysconfdir/libvirtd.conf
file ? It seems to be referred to by both the client & server. Although
there will be options common to both the client & server I think it may
be worth having them refer to separate files (cf ssh_config, sshd_config).
ACAICT there's no compelling need to have them refer to same file since the
client & server will be on different machines anyway. The separation
could be useful if there turns out to be a reasonble to make libvirtd.conf
mode 0600.
On the subject of
/* GnuTLS functions used by remoteOpen. */
#define CAFILE "demoCA/cacert.pem" /* XXX */
#define KEY_FILE "127001key.pem" /* XXX */
#define CERT_FILE "127001cert.pem" /* XXX */
We've got to think about best way to provide TLS parameters. Bearing in mind
that people may want to port to Mozilla NSS in the future I think it is
probably best to not provide formal APIs for these options at this time, and
instead pick them up from the client's config file. As previously discussed
there's no clear standard for location of TLS certs, so I reckon we just
default to something like
tls_ca_cert = "/etc/pks/tls/ca-cert.pem"
tls_secret = "/etc/pks/tls/libvirt-key.pem"
tls_cert = "/etc/pks/tls/libvirt-cert.pem"
This actually does suggest we need separate libvirt.conf & libvirtd.conf
because obviously the server needs to point to its own key/cert & also
keep a whitelist of client keys.
The client might actually need a more flexible config - allowing it to
present different keys, per host. We could do something based on a
placeholder, with a default fallback
tls_ca_cert = "/etc/pks/tls/ca-cert.pem"
tls_default_secret = "/etc/pks/tls/libvirt-key.pem"
tls_default_cert = "/etc/pks/tls/libvirt-cert.pem"
tls_host_cert = "/etc/pks/tls/libvirt-%h-key.pem"
tls_host_cert = "/etc/pks/tls/libvirt-%h-cert.pem"
Since we're using client certs for authentication to start with, we ought
to actually make it possible to keep the certs in per-user home dirs rather
than globally readable. eg $HOME/.pki/tls/libvirt-key.pem and mode 0600
The driver itself (remote_internal.c) consists of the following
parts,
arranged here in the same order that they appear in the file:
(1) remoteOpen and associated, GnuTLS initialisation
This function and associated functions deals with parsing the remote
URI, deciding which transport to use, deciding the URI to forward to the
remote end, creating the transport (including initialising GnuTLS,
forking ssh, ...), and verifying the server's certificate.
Wrt to this snippet in negotiate_gnutls_on_connection()
const int cert_type_priority[3] = {
GNUTLS_CRT_X509,
GNUTLS_CRT_OPENPGP,
0
};
Do we have support in the client/server for doing whatever checks are needed
for the OpenPGP style 'certs'. If not we should probably comment out the
OpenGPG option for now.
(2) The driver functions, remoteClose, remoteType, etc. etc.
(3) The network driver functions, remoteNetworkOpen, etc. etc.
For each function we serialise the parameters as an XDR remote_foo_args
object, use the generic "call" function to dispatch the call, then
deserialise the XDR remote_foo_ret return value. Most of the heavy
lifting for the RPC is done in the "call" function itself ...
This all loooks good to me. Only thought I had was perhaps that
GET_PRIVATE (conn, -1);
is slightly more readable as
struct private_data *priv = GET_PRIVATE (conn, -1);
ie, to make it clear to the readable what local variable is being
provided, while still hiding away all the tedious error checking /
assertion logic.
(4) The RPC implementation (function "call"), error
handling,
serialisation of virDomainPtr and virNetworkPtr.
In the 'call' method:
/* Get a unique serial number for this message. */
/* XXX This is supposed to be atomic over threads, but I don't know
* if it is.
*/
static sig_atomic_t counter = 1;
sig_atomic_t serial = counter++;
Serial numbers only need to be unique within the scope of a single
client <-> server socket connection. So could we just store the
counter in the virConectPtr private data struct to avoid the threading
question here
... which also deals with making error handling transparent.
static void
error (virConnectPtr conn, virErrorNumber code, const char *info)
{
const char *errmsg;
/* XXX I don't think this is correct use of virErrorMsg. */
errmsg = __virErrorMsg (code, info);
This looks consistent with the way other drivers are using __virErrorMsg
at least. Anything in particular you thought was wrong ?
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 -=|