--- generator/actions.ml | 20 ++++++++--- src/drives.c | 86 +++++++++++++++++++++++++++++++++++++----------- src/guestfs-internal.h | 2 ++ src/guestfs.pod | 5 ++- src/launch-libvirt.c | 3 ++ 5 files changed, 90 insertions(+), 26 deletions(-) diff --git a/generator/actions.ml b/generator/actions.ml index daea6b6..b0b4be7 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -1247,7 +1247,7 @@ not all belong to a single logical operating system { defaults with name = "add_drive"; - style = RErr, [String "filename"], [OBool "readonly"; OString "format"; OString "iface"; OString "name"; OString "label"; OString "protocol"; OStringList "server"; OString "username"]; + style = RErr, [String "filename"], [OBool "readonly"; OString "format"; OString "iface"; OString "name"; OString "label"; OString "protocol"; OStringList "server"; OString "username"; OString "secret"]; once_had_no_optargs = true; blocking = false; fish_alias = ["add"]; @@ -1353,6 +1353,7 @@ See also: L<guestfs(3)/NETWORK BLOCK DEVICE>. Connect to the Ceph (librbd/RBD) server. The C<server> parameter must also be supplied - see below. The C<username> parameter may be supplied. See below. +The C<secret> parameter may be supplied. See below. See also: L<guestfs(3)/CEPH>. @@ -1404,12 +1405,21 @@ for the protocol is used (see C</etc/services>). For the C<ssh> and C<rbd> protocols only, this specifies the remote username. -If not given, then the local username is used for C<ssh>, and 'admin' is used -for C<rbd>. But note this sometimes may give unexpected results, for example -if using the libvirt backend and if the libvirt backend is configured to start -the qemu appliance as a special user such as C<qemu.qemu>. If in doubt, +If not given, then the local username is used for C<ssh>, and no authentication +is attempted for ceph. But note this sometimes may give unexpected results, for +example if using the libvirt backend and if the libvirt backend is configured to +start the qemu appliance as a special user such as C<qemu.qemu>. If in doubt, specify the remote username you want. +=item C<secret> + +For the C<rbd> protocol only, this specifies the 'secret' to use when +connecting to the remote device. + +If not given, then a secret matching the given username will be looked up in the +default keychain locations, or if no username is given, then no authentication +will be used. + =back" }; { defaults with diff --git a/src/drives.c b/src/drives.c index a510e1e..1429050 100644 --- a/src/drives.c +++ b/src/drives.c @@ -107,7 +107,8 @@ static struct drive * create_drive_non_file (guestfs_h *g, enum drive_protocol protocol, struct drive_server *servers, size_t nr_servers, - const char *exportname, const char *username, + const char *exportname, + const char *username, const char *secret, bool readonly, const char *format, const char *iface, const char *name, const char *disk_label, @@ -120,6 +121,7 @@ create_drive_non_file (guestfs_h *g, drv->src.nr_servers = nr_servers; drv->src.u.exportname = safe_strdup (g, exportname); drv->src.username = username ? safe_strdup (g, username) : NULL; + drv->src.secret = secret ? safe_strdup (g, secret) : NULL; drv->readonly = readonly; drv->format = format ? safe_strdup (g, format) : NULL; @@ -136,7 +138,8 @@ create_drive_non_file (guestfs_h *g, static struct drive * create_drive_gluster (guestfs_h *g, struct drive_server *servers, size_t nr_servers, - const char *exportname, const char *username, + const char *exportname, + const char *username, const char *secret, bool readonly, const char *format, const char *iface, const char *name, const char *disk_label, @@ -146,6 +149,11 @@ create_drive_gluster (guestfs_h *g, error (g, _("gluster: you cannot specify a username with this protocol")); return NULL; } + if (secret != NULL) { + error (g, _("gluster: you cannot specify a secret with this protocol")); + return NULL; + } + if (nr_servers != 1) { error (g, _("gluster: you must specify exactly one server")); @@ -165,7 +173,8 @@ create_drive_gluster (guestfs_h *g, } return create_drive_non_file (g, drive_protocol_gluster, - servers, nr_servers, exportname, username, + servers, nr_servers, exportname, + username, secret, readonly, format, iface, name, disk_label, use_cache_none); } @@ -185,7 +194,8 @@ nbd_port (void) static struct drive * create_drive_nbd (guestfs_h *g, struct drive_server *servers, size_t nr_servers, - const char *exportname, const char *username, + const char *exportname, + const char *username, const char *secret, bool readonly, const char *format, const char *iface, const char *name, const char *disk_label, @@ -195,6 +205,10 @@ create_drive_nbd (guestfs_h *g, error (g, _("nbd: you cannot specify a username with this protocol")); return NULL; } + if (secret != NULL) { + error (g, _("nbd: you cannot specify a secret with this protocol")); + return NULL; + } if (nr_servers != 1) { error (g, _("nbd: you must specify exactly one server")); @@ -205,7 +219,8 @@ create_drive_nbd (guestfs_h *g, servers[0].port = nbd_port (); return create_drive_non_file (g, drive_protocol_nbd, - servers, nr_servers, exportname, username, + servers, nr_servers, exportname, + username, secret, readonly, format, iface, name, disk_label, use_cache_none); } @@ -213,7 +228,8 @@ create_drive_nbd (guestfs_h *g, static struct drive * create_drive_rbd (guestfs_h *g, struct drive_server *servers, size_t nr_servers, - const char *exportname, const char *username, + const char *exportname, + const char *username, const char *secret, bool readonly, const char *format, const char *iface, const char *name, const char *disk_label, @@ -244,7 +260,8 @@ create_drive_rbd (guestfs_h *g, } return create_drive_non_file (g, drive_protocol_rbd, - servers, nr_servers, exportname, username, + servers, nr_servers, exportname, + username, secret, readonly, format, iface, name, disk_label, use_cache_none); } @@ -252,7 +269,8 @@ create_drive_rbd (guestfs_h *g, static struct drive * create_drive_sheepdog (guestfs_h *g, struct drive_server *servers, size_t nr_servers, - const char *exportname, const char *username, + const char *exportname, + const char *username, const char *secret, bool readonly, const char *format, const char *iface, const char *name, const char *disk_label, @@ -264,6 +282,10 @@ create_drive_sheepdog (guestfs_h *g, error (g, _("sheepdog: you cannot specify a username with this protocol")); return NULL; } + if (secret != NULL) { + error (g, _("sheepdog: you cannot specify a secret with this protocol")); + return NULL; + } for (i = 0; i < nr_servers; ++i) { if (servers[i].transport != drive_transport_none && @@ -283,7 +305,8 @@ create_drive_sheepdog (guestfs_h *g, } return create_drive_non_file (g, drive_protocol_sheepdog, - servers, nr_servers, exportname, username, + servers, nr_servers, exportname, + username, secret, readonly, format, iface, name, disk_label, use_cache_none); } @@ -291,12 +314,18 @@ create_drive_sheepdog (guestfs_h *g, static struct drive * create_drive_ssh (guestfs_h *g, struct drive_server *servers, size_t nr_servers, - const char *exportname, const char *username, + const char *exportname, + const char *username, const char *secret, bool readonly, const char *format, const char *iface, const char *name, const char *disk_label, bool use_cache_none) { + if (secret != NULL) { + error (g, _("ssh: you cannot specify a secret with this protocol")); + return NULL; + } + if (nr_servers != 1) { error (g, _("ssh: you must specify exactly one server")); return NULL; @@ -319,7 +348,8 @@ create_drive_ssh (guestfs_h *g, } return create_drive_non_file (g, drive_protocol_ssh, - servers, nr_servers, exportname, username, + servers, nr_servers, exportname, + username, secret, readonly, format, iface, name, disk_label, use_cache_none); } @@ -690,6 +720,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, size_t nr_servers = 0; struct drive_server *servers = NULL; const char *username; + const char *secret; int use_cache_none; struct drive *drv; size_t i, drv_index; @@ -720,6 +751,8 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, } username = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_USERNAME_BITMASK ? optargs->username : NULL; + secret = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_SECRET_BITMASK + ? optargs->secret : NULL; if (format && !valid_format_iface (format)) { error (g, _("%s parameter is empty or contains disallowed characters"), @@ -750,6 +783,11 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, free_drive_servers (servers, nr_servers); return -1; } + if (secret != NULL) { + error (g, _("you cannot specify a secret with file-backed disks")); + free_drive_servers (servers, nr_servers); + return -1; + } if (STREQ (filename, "/dev/null")) drv = create_drive_dev_null (g, readonly, format, iface, name, @@ -775,27 +813,32 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, } } else if (STREQ (protocol, "gluster")) { - drv = create_drive_gluster (g, servers, nr_servers, filename, username, + drv = create_drive_gluster (g, servers, nr_servers, filename, + username, secret, readonly, format, iface, name, disk_label, false); } else if (STREQ (protocol, "nbd")) { - drv = create_drive_nbd (g, servers, nr_servers, filename, username, + drv = create_drive_nbd (g, servers, nr_servers, filename, + username, secret, readonly, format, iface, name, disk_label, false); } else if (STREQ (protocol, "rbd")) { - drv = create_drive_rbd (g, servers, nr_servers, filename, username, + drv = create_drive_rbd (g, servers, nr_servers, filename, + username, secret, readonly, format, iface, name, disk_label, false); } else if (STREQ (protocol, "sheepdog")) { - drv = create_drive_sheepdog (g, servers, nr_servers, filename, username, + drv = create_drive_sheepdog (g, servers, nr_servers, filename, + username, secret, readonly, format, iface, name, disk_label, false); } else if (STREQ (protocol, "ssh")) { - drv = create_drive_ssh (g, servers, nr_servers, filename, username, + drv = create_drive_ssh (g, servers, nr_servers, filename, + username, secret, readonly, format, iface, name, disk_label, false); } @@ -1083,7 +1126,7 @@ guestfs___drive_source_qemu_param (guestfs_h *g, const struct drive_source *src) case drive_protocol_rbd: { /* build the list of all the mon hosts */ - CLEANUP_FREE char *mon_host = NULL, *username = NULL; + CLEANUP_FREE char *mon_host = NULL, *username = NULL, *secret = NULL; char *auth; size_t n = 0; for (int i = 0; i < src->nr_servers; i++) { @@ -1113,13 +1156,15 @@ guestfs___drive_source_qemu_param (guestfs_h *g, const struct drive_source *src) if (src->username) username = safe_asprintf (g, ":id=%s", src->username); - if (username) + if (src->secret) + secret = safe_asprintf (g, ":key=%s", src->secret); + if (username || secret) auth = ":auth_supported=cephx\\;none"; else auth = ":auth_supported=none"; - return safe_asprintf (g, "rbd:%s:mon_host=%s%s%s", src->u.exportname, mon_host, - username ? username : "", auth); + return safe_asprintf (g, "rbd:%s:mon_host=%s%s%s%s", src->u.exportname, mon_host, + username ? username : "", auth, secret ? secret : ""); } case drive_protocol_sheepdog: @@ -1155,6 +1200,7 @@ guestfs___free_drive_source (struct drive_source *src) if (src) { free (src->u.path); free (src->username); + free (src->secret); free_drive_servers (src->servers, src->nr_servers); } } diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index e13c498..6a58f2f 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -161,6 +161,8 @@ struct drive_source { /* Optional username (may be NULL if not specified). */ char *username; + /* Optional secret (may be NULL if not specified). */ + char *secret; }; struct drive { diff --git a/src/guestfs.pod b/src/guestfs.pod index ee9cc2a..99374c2 100644 --- a/src/guestfs.pod +++ b/src/guestfs.pod @@ -652,11 +652,14 @@ L</guestfs_add_drive_opts> like this: GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "rbd", GUESTFS_ADD_DRIVE_OPTS_SERVER, servers, + GUESTFS_ADD_DRIVE_OPTS_USERNAME, "rbduser", + GUESTFS_ADD_DRIVE_OPTS_SECRET, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", -1); C<servers> (the C<server> parameter) is a list of one or more Ceph servers. The server string is documented in -L</guestfs_add_drive_opts>. +L</guestfs_add_drive_opts>. The C<username> and C<secret> parameters are +also optional, and if not given, then no authentication will be used. =head3 GLUSTER diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c index c2bd81c..e33ddc6 100644 --- a/src/launch-libvirt.c +++ b/src/launch-libvirt.c @@ -1144,6 +1144,9 @@ construct_libvirt_xml_disk (guestfs_h *g, XMLERROR (-1, xmlTextWriterWriteAttribute (xo, BAD_CAST "username", BAD_CAST drv_priv->real_src.username)); + /* TODO: write the drive secret, after first storing it separately + * in libvirt + */ XMLERROR (-1, xmlTextWriterEndElement (xo)); } } -- 1.7.9.5