Pino Toscano
2014-Apr-30 16:22 UTC
[Libguestfs] [PATCH 2/2] Fix handling of passwords in URLs
So far, passwords in URLs (eg http://user:password@host..) have been handled as part of the username, and thus passing add-drive path username:username:password ... instead of add-drive path username:username secret:password ... Fix the parsing of URLs to handle passwords as separate elements, properly passing it as "secret" parameter for add-drive, and properly readd it when building URLs in the direct backend. Furthmore, to keep curl- and ssh-based qemu drivers working with authenticated resources, make sure they can accept secrets. Reported in comment #1 of RHBZ#1092583. --- customize/customize_main.ml | 5 +++-- fish/options.c | 6 ++++++ fish/options.h | 1 + fish/uri.c | 26 ++++++++++++++++++++++---- fish/uri.h | 1 + mllib/uRI.ml | 1 + mllib/uRI.mli | 1 + mllib/uri-c.c | 13 ++++++++++++- resize/resize.ml | 5 +++-- src/drives.c | 10 ---------- src/launch-direct.c | 34 +++++++++++++++++++++++----------- sysprep/main.ml | 5 +++-- 12 files changed, 76 insertions(+), 32 deletions(-) diff --git a/customize/customize_main.ml b/customize/customize_main.ml index fb38336..00d5bae 100644 --- a/customize/customize_main.ml +++ b/customize/customize_main.ml @@ -157,11 +157,12 @@ read the man page virt-customize(1). List.iter ( fun (uri, format) -> let { URI.path = path; protocol = protocol; - server = server; username = username } = uri in + server = server; username = username; + password = password } = uri in let discard = if readonly then None else Some "besteffort" in g#add_drive ~readonly ?discard - ?format ~protocol ?server ?username + ?format ~protocol ?server ?username ?secret:password path ) files in diff --git a/fish/options.c b/fish/options.c index 80b71ec..5e6eb73 100644 --- a/fish/options.c +++ b/fish/options.c @@ -67,6 +67,7 @@ option_a (const char *arg, const char *format, struct drv **drvsp) drv->uri.protocol = uri.protocol; drv->uri.server = uri.server; drv->uri.username = uri.username; + drv->uri.password = uri.password; drv->uri.format = format; drv->uri.orig_uri = arg; } @@ -167,6 +168,10 @@ add_drives_handle (guestfs_h *g, struct drv *drv, char next_drive) ad_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_USERNAME_BITMASK; ad_optargs.username = drv->uri.username; } + if (drv->uri.password) { + ad_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_SECRET_BITMASK; + ad_optargs.secret = drv->uri.password; + } r = guestfs_add_drive_opts_argv (g, drv->uri.path, &ad_optargs); if (r == -1) @@ -290,6 +295,7 @@ free_drives (struct drv *drv) free (drv->uri.protocol); guestfs___free_string_list (drv->uri.server); free (drv->uri.username); + free (drv->uri.password); break; case drv_d: /* d.filename is optarg, don't free it */ diff --git a/fish/options.h b/fish/options.h index dbf9163..639b1fe 100644 --- a/fish/options.h +++ b/fish/options.h @@ -68,6 +68,7 @@ struct drv { char *protocol; /* protocol (eg. "nbd") */ char **server; /* server(s) - can be NULL */ char *username; /* username - can be NULL */ + char *password; /* password - can be NULL */ const char *format; /* format (NULL == autodetect) */ const char *orig_uri; /* original URI (for error messages etc.) */ } uri; diff --git a/fish/uri.c b/fish/uri.c index 95f8cf8..f45c907 100644 --- a/fish/uri.c +++ b/fish/uri.c @@ -34,7 +34,7 @@ #include "uri.h" static int is_uri (const char *arg); -static int parse (const char *arg, char **path_ret, char **protocol_ret, char ***server_ret, char **username_ret); +static int parse (const char *arg, char **path_ret, char **protocol_ret, char ***server_ret, char **username_ret, char **password_ret); static char *query_get (xmlURIPtr uri, const char *search_name); static int make_server (xmlURIPtr uri, const char *socket, char ***ret); @@ -45,10 +45,11 @@ parse_uri (const char *arg, struct uri *uri_ret) char *protocol = NULL; char **server = NULL; char *username = NULL; + char *password = NULL; /* Does it look like a URI? */ if (is_uri (arg)) { - if (parse (arg, &path, &protocol, &server, &username) == -1) + if (parse (arg, &path, &protocol, &server, &username, &password) == -1) return -1; } else { @@ -70,6 +71,7 @@ parse_uri (const char *arg, struct uri *uri_ret) uri_ret->protocol = protocol; uri_ret->server = server; uri_ret->username = username; + uri_ret->password = password; return 0; } @@ -99,7 +101,7 @@ is_uri (const char *arg) static int parse (const char *arg, char **path_ret, char **protocol_ret, - char ***server_ret, char **username_ret) + char ***server_ret, char **username_ret, char **password_ret) { CLEANUP_XMLFREEURI xmlURIPtr uri = NULL; CLEANUP_FREE char *socket = NULL; @@ -150,16 +152,31 @@ parse (const char *arg, char **path_ret, char **protocol_ret, return -1; } + *password_ret = NULL; + *username_ret = NULL; if (uri->user && STRNEQ (uri->user, "")) { + char *p = strchr (uri->user, ':'); + if (p != NULL) { + if (STRNEQ (p+1, "")) { + *password_ret = strdup (p+1); + if (*password_ret == NULL) { + perror ("strdup: password"); + free (*protocol_ret); + guestfs___free_string_list (*server_ret); + return -1; + } + } + *p = '\0'; + } *username_ret = strdup (uri->user); if (*username_ret == NULL) { perror ("strdup: username"); + free (*password_ret); free (*protocol_ret); guestfs___free_string_list (*server_ret); return -1; } } - else *username_ret = NULL; /* We may have to adjust the path depending on the protocol. For * example ceph/rbd URIs look like rbd:///pool/disk, but the @@ -180,6 +197,7 @@ parse (const char *arg, char **path_ret, char **protocol_ret, free (*protocol_ret); guestfs___free_string_list (*server_ret); free (*username_ret); + free (*password_ret); return -1; } diff --git a/fish/uri.h b/fish/uri.h index 420d20c..9202a70 100644 --- a/fish/uri.h +++ b/fish/uri.h @@ -26,6 +26,7 @@ struct uri { char *protocol; /* protocol (eg. "file", "nbd") */ char **server; /* server(s) - can be NULL */ char *username; /* username - can be NULL */ + char *password; /* password - can be NULL */ }; /* Parse the '-a' option parameter 'arg', and place the result in diff --git a/mllib/uRI.ml b/mllib/uRI.ml index 272f339..d4f7522 100644 --- a/mllib/uRI.ml +++ b/mllib/uRI.ml @@ -21,6 +21,7 @@ type uri = { protocol : string; server : string array option; username : string option; + password : string option; } external parse_uri : string -> uri = "virt_resize_parse_uri" diff --git a/mllib/uRI.mli b/mllib/uRI.mli index efd39dd..0692f95 100644 --- a/mllib/uRI.mli +++ b/mllib/uRI.mli @@ -23,6 +23,7 @@ type uri = { protocol : string; (** protocol, eg. [file], [nbd] *) server : string array option; (** list of servers *) username : string option; (** username *) + password : string option; (** password *) } val parse_uri : string -> uri diff --git a/mllib/uri-c.c b/mllib/uri-c.c index 1ae7350..2ce4021 100644 --- a/mllib/uri-c.c +++ b/mllib/uri-c.c @@ -47,7 +47,7 @@ virt_resize_parse_uri (value argv /* arg value, not an array! */) caml_invalid_argument ("URI.parse_uri"); /* Convert the struct into an OCaml tuple. */ - rv = caml_alloc_tuple (4); + rv = caml_alloc_tuple (5); /* path : string */ sv = caml_copy_string (uri.path); @@ -81,5 +81,16 @@ virt_resize_parse_uri (value argv /* arg value, not an array! */) ov = Val_int (0); Store_field (rv, 3, ov); + /* password : string option */ + if (uri.password) { + sv = caml_copy_string (uri.password); + free (uri.password); + ov = caml_alloc (1, 0); + Store_field (ov, 0, sv); + } + else + ov = Val_int (0); + Store_field (rv, 4, ov); + CAMLreturn (rv); } diff --git a/resize/resize.ml b/resize/resize.ml index c1794ed..c6b6c9e 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -322,8 +322,9 @@ read the man page virt-resize(1). let g = new G.guestfs () in if debug then g#set_trace true; let _, { URI.path = path; protocol = protocol; - server = server; username = username } = infile in - g#add_drive ?format ~readonly:true ~protocol ?server ?username path; + server = server; username = username; + password = password } = infile in + g#add_drive ?format ~readonly:true ~protocol ?server ?username ?secret:password path; (* The output disk is being created, so use cache=unsafe here. *) g#add_drive ?format:output_format ~readonly:false ~cachemode:"unsafe" outfile; diff --git a/src/drives.c b/src/drives.c index 57c2471..4bd8328 100644 --- a/src/drives.c +++ b/src/drives.c @@ -200,11 +200,6 @@ static struct drive * create_drive_curl (guestfs_h *g, const struct drive_create_data *data) { - if (data->secret != NULL) { - error (g, _("curl: you cannot specify a secret with this protocol")); - return NULL; - } - if (data->nr_servers != 1) { error (g, _("curl: you must specify exactly one server")); return NULL; @@ -371,11 +366,6 @@ static struct drive * create_drive_ssh (guestfs_h *g, const struct drive_create_data *data) { - if (data->secret != NULL) { - error (g, _("ssh: you cannot specify a secret with this protocol")); - return NULL; - } - if (data->nr_servers != 1) { error (g, _("ssh: you must specify exactly one server")); return NULL; diff --git a/src/launch-direct.c b/src/launch-direct.c index bb06c9e..96ae180 100644 --- a/src/launch-direct.c +++ b/src/launch-direct.c @@ -1207,12 +1207,14 @@ qemu_escape_param (guestfs_h *g, const char *param) static char * make_uri (guestfs_h *g, const char *scheme, const char *user, + const char *password, struct drive_server *server, const char *path) { xmlURI uri = { .scheme = (char *) scheme, .user = (char *) user }; CLEANUP_FREE char *query = NULL; CLEANUP_FREE char *pathslash = NULL; + CLEANUP_FREE char *userauth = NULL; /* Need to add a leading '/' to URI paths since xmlSaveUri doesn't. */ if (path[0] != '/') { @@ -1222,6 +1224,13 @@ make_uri (guestfs_h *g, const char *scheme, const char *user, else uri.path = (char *) path; + /* Rebuild user:password. */ + if (user != NULL && password != NULL) { + /* Keep the string in an own variable so it can be freed automatically. */ + userauth = safe_asprintf (g, "%s:%s", user, password); + uri.user = userauth; + } + switch (server->transport) { case drive_transport_none: case drive_transport_tcp: @@ -1267,34 +1276,37 @@ guestfs___drive_source_qemu_param (guestfs_h *g, const struct drive_source *src) return path; case drive_protocol_ftp: - return make_uri (g, "ftp", src->username, + return make_uri (g, "ftp", src->username, src->secret, &src->servers[0], src->u.exportname); case drive_protocol_ftps: - return make_uri (g, "ftps", src->username, + return make_uri (g, "ftps", src->username, src->secret, &src->servers[0], src->u.exportname); case drive_protocol_gluster: switch (src->servers[0].transport) { case drive_transport_none: - return make_uri (g, "gluster", NULL, &src->servers[0], src->u.exportname); + return make_uri (g, "gluster", NULL, NULL, + &src->servers[0], src->u.exportname); case drive_transport_tcp: - return make_uri (g, "gluster+tcp", - NULL, &src->servers[0], src->u.exportname); + return make_uri (g, "gluster+tcp", NULL, NULL, + &src->servers[0], src->u.exportname); case drive_transport_unix: - return make_uri (g, "gluster+unix", NULL, &src->servers[0], NULL); + return make_uri (g, "gluster+unix", NULL, NULL, + &src->servers[0], NULL); } case drive_protocol_http: - return make_uri (g, "http", src->username, + return make_uri (g, "http", src->username, src->secret, &src->servers[0], src->u.exportname); case drive_protocol_https: - return make_uri (g, "https", src->username, + return make_uri (g, "https", src->username, src->secret, &src->servers[0], src->u.exportname); case drive_protocol_iscsi: - return make_uri (g, "iscsi", NULL, &src->servers[0], src->u.exportname); + return make_uri (g, "iscsi", NULL, NULL, + &src->servers[0], src->u.exportname); case drive_protocol_nbd: { CLEANUP_FREE char *p = NULL; @@ -1380,11 +1392,11 @@ guestfs___drive_source_qemu_param (guestfs_h *g, const struct drive_source *src) src->u.exportname); case drive_protocol_ssh: - return make_uri (g, "ssh", src->username, + return make_uri (g, "ssh", src->username, src->secret, &src->servers[0], src->u.exportname); case drive_protocol_tftp: - return make_uri (g, "tftp", src->username, + return make_uri (g, "tftp", src->username, src->secret, &src->servers[0], src->u.exportname); } diff --git a/sysprep/main.ml b/sysprep/main.ml index 71abfa7..37e4dc8 100644 --- a/sysprep/main.ml +++ b/sysprep/main.ml @@ -203,11 +203,12 @@ read the man page virt-sysprep(1). List.iter ( fun (uri, format) -> let { URI.path = path; protocol = protocol; - server = server; username = username } = uri in + server = server; username = username; + password = password } = uri in let discard = if readonly then None else Some "besteffort" in g#add_drive ~readonly ?discard - ?format ~protocol ?server ?username + ?format ~protocol ?server ?username ?secret:password path ) files in -- 1.9.0
Pino Toscano
2014-Apr-30 16:26 UTC
Re: [Libguestfs] [PATCH 2/2] Fix handling of passwords in URLs
Small note: $subject is slightly wrong, as it is just one patch (so there is no 1/2). -- Pino Toscano
Richard W.M. Jones
2014-Apr-30 16:56 UTC
Re: [Libguestfs] [PATCH 2/2] Fix handling of passwords in URLs
On Wed, Apr 30, 2014 at 06:22:41PM +0200, Pino Toscano wrote:> So far, passwords in URLs (eg http://user:password@host..) have been > handled as part of the username, and thus passing > add-drive path username:username:password ... > instead of > add-drive path username:username secret:password ... > > Fix the parsing of URLs to handle passwords as separate elements, > properly passing it as "secret" parameter for add-drive, and properly > readd it when building URLs in the direct backend. > > Furthmore, to keep curl- and ssh-based qemu drivers working with > authenticated resources, make sure they can accept secrets. > > Reported in comment #1 of RHBZ#1092583.The patch looks good, at an initial read. I'd be happier if it had a test (see: fish/test-add-uri.sh), and if the test passes valgrind :-) Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-builder quickly builds VMs from scratch http://libguestfs.org/virt-builder.1.html
So far, passwords in URLs (eg http://user:password@host..) have been handled as part of the username, and thus passing add-drive path username:username:password ... instead of add-drive path username:username secret:password ... Fix the parsing of URLs to handle passwords as separate elements, properly passing it as "secret" parameter for add-drive, and properly readd it when building URLs in the direct backend. Furthmore, to keep curl- and ssh-based qemu drivers working with authenticated resources, make sure they can accept secrets. Reported in comment #1 of RHBZ#1092583. --- customize/customize_main.ml | 5 +++-- fish/options.c | 6 ++++++ fish/options.h | 1 + fish/test-add-uri.sh | 6 ++++++ fish/uri.c | 26 ++++++++++++++++++++++---- fish/uri.h | 1 + mllib/uRI.ml | 1 + mllib/uRI.mli | 1 + mllib/uri-c.c | 13 ++++++++++++- resize/resize.ml | 5 +++-- src/drives.c | 10 ---------- src/launch-direct.c | 34 +++++++++++++++++++++++----------- sysprep/main.ml | 5 +++-- 13 files changed, 82 insertions(+), 32 deletions(-) diff --git a/customize/customize_main.ml b/customize/customize_main.ml index fb38336..00d5bae 100644 --- a/customize/customize_main.ml +++ b/customize/customize_main.ml @@ -157,11 +157,12 @@ read the man page virt-customize(1). List.iter ( fun (uri, format) -> let { URI.path = path; protocol = protocol; - server = server; username = username } = uri in + server = server; username = username; + password = password } = uri in let discard = if readonly then None else Some "besteffort" in g#add_drive ~readonly ?discard - ?format ~protocol ?server ?username + ?format ~protocol ?server ?username ?secret:password path ) files in diff --git a/fish/options.c b/fish/options.c index 80b71ec..5e6eb73 100644 --- a/fish/options.c +++ b/fish/options.c @@ -67,6 +67,7 @@ option_a (const char *arg, const char *format, struct drv **drvsp) drv->uri.protocol = uri.protocol; drv->uri.server = uri.server; drv->uri.username = uri.username; + drv->uri.password = uri.password; drv->uri.format = format; drv->uri.orig_uri = arg; } @@ -167,6 +168,10 @@ add_drives_handle (guestfs_h *g, struct drv *drv, char next_drive) ad_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_USERNAME_BITMASK; ad_optargs.username = drv->uri.username; } + if (drv->uri.password) { + ad_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_SECRET_BITMASK; + ad_optargs.secret = drv->uri.password; + } r = guestfs_add_drive_opts_argv (g, drv->uri.path, &ad_optargs); if (r == -1) @@ -290,6 +295,7 @@ free_drives (struct drv *drv) free (drv->uri.protocol); guestfs___free_string_list (drv->uri.server); free (drv->uri.username); + free (drv->uri.password); break; case drv_d: /* d.filename is optarg, don't free it */ diff --git a/fish/options.h b/fish/options.h index dbf9163..639b1fe 100644 --- a/fish/options.h +++ b/fish/options.h @@ -68,6 +68,7 @@ struct drv { char *protocol; /* protocol (eg. "nbd") */ char **server; /* server(s) - can be NULL */ char *username; /* username - can be NULL */ + char *password; /* password - can be NULL */ const char *format; /* format (NULL == autodetect) */ const char *orig_uri; /* original URI (for error messages etc.) */ } uri; diff --git a/fish/test-add-uri.sh b/fish/test-add-uri.sh index 1a5b067..2b7a142 100755 --- a/fish/test-add-uri.sh +++ b/fish/test-add-uri.sh @@ -41,6 +41,9 @@ grep -sq 'add_drive ".*/test-add-uri.img"' test-add-uri.out || fail $VG ./guestfish -x -a ftp://user@example.com/disk.img </dev/null >test-add-uri.out 2>&1 grep -sq 'add_drive "/disk.img" "protocol:ftp" "server:tcp:example.com" "username:user"' test-add-uri.out || fail +$VG ./guestfish -x -a ftp://user:password@example.com/disk.img </dev/null >test-add-uri.out 2>&1 +grep -sq 'add_drive "/disk.img" "protocol:ftp" "server:tcp:example.com" "username:user" "secret:password"' test-add-uri.out || fail + # gluster $VG ./guestfish -x -a gluster://example.com/disk </dev/null >test-add-uri.out 2>&1 grep -sq 'add_drive "disk" "protocol:gluster" "server:tcp:example.com"' test-add-uri.out || fail @@ -78,6 +81,9 @@ grep -sq 'add_drive "/disk.img" "protocol:ssh" "server:tcp:example.com"' test-ad $VG ./guestfish -x -a ssh://user@example.com/disk.img </dev/null >test-add-uri.out 2>&1 grep -sq 'add_drive "/disk.img" "protocol:ssh" "server:tcp:example.com" "username:user"' test-add-uri.out || fail +$VG ./guestfish -x -a ssh://user:password@example.com/disk.img </dev/null >test-add-uri.out 2>&1 +grep -sq 'add_drive "/disk.img" "protocol:ssh" "server:tcp:example.com" "username:user" "secret:password"' test-add-uri.out || fail + $VG ./guestfish -x -a ssh://user@example.com:2000/disk.img </dev/null >test-add-uri.out 2>&1 grep -sq 'add_drive "/disk.img" "protocol:ssh" "server:tcp:example.com:2000" "username:user"' test-add-uri.out || fail diff --git a/fish/uri.c b/fish/uri.c index 95f8cf8..f45c907 100644 --- a/fish/uri.c +++ b/fish/uri.c @@ -34,7 +34,7 @@ #include "uri.h" static int is_uri (const char *arg); -static int parse (const char *arg, char **path_ret, char **protocol_ret, char ***server_ret, char **username_ret); +static int parse (const char *arg, char **path_ret, char **protocol_ret, char ***server_ret, char **username_ret, char **password_ret); static char *query_get (xmlURIPtr uri, const char *search_name); static int make_server (xmlURIPtr uri, const char *socket, char ***ret); @@ -45,10 +45,11 @@ parse_uri (const char *arg, struct uri *uri_ret) char *protocol = NULL; char **server = NULL; char *username = NULL; + char *password = NULL; /* Does it look like a URI? */ if (is_uri (arg)) { - if (parse (arg, &path, &protocol, &server, &username) == -1) + if (parse (arg, &path, &protocol, &server, &username, &password) == -1) return -1; } else { @@ -70,6 +71,7 @@ parse_uri (const char *arg, struct uri *uri_ret) uri_ret->protocol = protocol; uri_ret->server = server; uri_ret->username = username; + uri_ret->password = password; return 0; } @@ -99,7 +101,7 @@ is_uri (const char *arg) static int parse (const char *arg, char **path_ret, char **protocol_ret, - char ***server_ret, char **username_ret) + char ***server_ret, char **username_ret, char **password_ret) { CLEANUP_XMLFREEURI xmlURIPtr uri = NULL; CLEANUP_FREE char *socket = NULL; @@ -150,16 +152,31 @@ parse (const char *arg, char **path_ret, char **protocol_ret, return -1; } + *password_ret = NULL; + *username_ret = NULL; if (uri->user && STRNEQ (uri->user, "")) { + char *p = strchr (uri->user, ':'); + if (p != NULL) { + if (STRNEQ (p+1, "")) { + *password_ret = strdup (p+1); + if (*password_ret == NULL) { + perror ("strdup: password"); + free (*protocol_ret); + guestfs___free_string_list (*server_ret); + return -1; + } + } + *p = '\0'; + } *username_ret = strdup (uri->user); if (*username_ret == NULL) { perror ("strdup: username"); + free (*password_ret); free (*protocol_ret); guestfs___free_string_list (*server_ret); return -1; } } - else *username_ret = NULL; /* We may have to adjust the path depending on the protocol. For * example ceph/rbd URIs look like rbd:///pool/disk, but the @@ -180,6 +197,7 @@ parse (const char *arg, char **path_ret, char **protocol_ret, free (*protocol_ret); guestfs___free_string_list (*server_ret); free (*username_ret); + free (*password_ret); return -1; } diff --git a/fish/uri.h b/fish/uri.h index 420d20c..9202a70 100644 --- a/fish/uri.h +++ b/fish/uri.h @@ -26,6 +26,7 @@ struct uri { char *protocol; /* protocol (eg. "file", "nbd") */ char **server; /* server(s) - can be NULL */ char *username; /* username - can be NULL */ + char *password; /* password - can be NULL */ }; /* Parse the '-a' option parameter 'arg', and place the result in diff --git a/mllib/uRI.ml b/mllib/uRI.ml index 272f339..d4f7522 100644 --- a/mllib/uRI.ml +++ b/mllib/uRI.ml @@ -21,6 +21,7 @@ type uri = { protocol : string; server : string array option; username : string option; + password : string option; } external parse_uri : string -> uri = "virt_resize_parse_uri" diff --git a/mllib/uRI.mli b/mllib/uRI.mli index efd39dd..0692f95 100644 --- a/mllib/uRI.mli +++ b/mllib/uRI.mli @@ -23,6 +23,7 @@ type uri = { protocol : string; (** protocol, eg. [file], [nbd] *) server : string array option; (** list of servers *) username : string option; (** username *) + password : string option; (** password *) } val parse_uri : string -> uri diff --git a/mllib/uri-c.c b/mllib/uri-c.c index 1ae7350..2ce4021 100644 --- a/mllib/uri-c.c +++ b/mllib/uri-c.c @@ -47,7 +47,7 @@ virt_resize_parse_uri (value argv /* arg value, not an array! */) caml_invalid_argument ("URI.parse_uri"); /* Convert the struct into an OCaml tuple. */ - rv = caml_alloc_tuple (4); + rv = caml_alloc_tuple (5); /* path : string */ sv = caml_copy_string (uri.path); @@ -81,5 +81,16 @@ virt_resize_parse_uri (value argv /* arg value, not an array! */) ov = Val_int (0); Store_field (rv, 3, ov); + /* password : string option */ + if (uri.password) { + sv = caml_copy_string (uri.password); + free (uri.password); + ov = caml_alloc (1, 0); + Store_field (ov, 0, sv); + } + else + ov = Val_int (0); + Store_field (rv, 4, ov); + CAMLreturn (rv); } diff --git a/resize/resize.ml b/resize/resize.ml index c1794ed..c6b6c9e 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -322,8 +322,9 @@ read the man page virt-resize(1). let g = new G.guestfs () in if debug then g#set_trace true; let _, { URI.path = path; protocol = protocol; - server = server; username = username } = infile in - g#add_drive ?format ~readonly:true ~protocol ?server ?username path; + server = server; username = username; + password = password } = infile in + g#add_drive ?format ~readonly:true ~protocol ?server ?username ?secret:password path; (* The output disk is being created, so use cache=unsafe here. *) g#add_drive ?format:output_format ~readonly:false ~cachemode:"unsafe" outfile; diff --git a/src/drives.c b/src/drives.c index 57c2471..4bd8328 100644 --- a/src/drives.c +++ b/src/drives.c @@ -200,11 +200,6 @@ static struct drive * create_drive_curl (guestfs_h *g, const struct drive_create_data *data) { - if (data->secret != NULL) { - error (g, _("curl: you cannot specify a secret with this protocol")); - return NULL; - } - if (data->nr_servers != 1) { error (g, _("curl: you must specify exactly one server")); return NULL; @@ -371,11 +366,6 @@ static struct drive * create_drive_ssh (guestfs_h *g, const struct drive_create_data *data) { - if (data->secret != NULL) { - error (g, _("ssh: you cannot specify a secret with this protocol")); - return NULL; - } - if (data->nr_servers != 1) { error (g, _("ssh: you must specify exactly one server")); return NULL; diff --git a/src/launch-direct.c b/src/launch-direct.c index bb06c9e..96ae180 100644 --- a/src/launch-direct.c +++ b/src/launch-direct.c @@ -1207,12 +1207,14 @@ qemu_escape_param (guestfs_h *g, const char *param) static char * make_uri (guestfs_h *g, const char *scheme, const char *user, + const char *password, struct drive_server *server, const char *path) { xmlURI uri = { .scheme = (char *) scheme, .user = (char *) user }; CLEANUP_FREE char *query = NULL; CLEANUP_FREE char *pathslash = NULL; + CLEANUP_FREE char *userauth = NULL; /* Need to add a leading '/' to URI paths since xmlSaveUri doesn't. */ if (path[0] != '/') { @@ -1222,6 +1224,13 @@ make_uri (guestfs_h *g, const char *scheme, const char *user, else uri.path = (char *) path; + /* Rebuild user:password. */ + if (user != NULL && password != NULL) { + /* Keep the string in an own variable so it can be freed automatically. */ + userauth = safe_asprintf (g, "%s:%s", user, password); + uri.user = userauth; + } + switch (server->transport) { case drive_transport_none: case drive_transport_tcp: @@ -1267,34 +1276,37 @@ guestfs___drive_source_qemu_param (guestfs_h *g, const struct drive_source *src) return path; case drive_protocol_ftp: - return make_uri (g, "ftp", src->username, + return make_uri (g, "ftp", src->username, src->secret, &src->servers[0], src->u.exportname); case drive_protocol_ftps: - return make_uri (g, "ftps", src->username, + return make_uri (g, "ftps", src->username, src->secret, &src->servers[0], src->u.exportname); case drive_protocol_gluster: switch (src->servers[0].transport) { case drive_transport_none: - return make_uri (g, "gluster", NULL, &src->servers[0], src->u.exportname); + return make_uri (g, "gluster", NULL, NULL, + &src->servers[0], src->u.exportname); case drive_transport_tcp: - return make_uri (g, "gluster+tcp", - NULL, &src->servers[0], src->u.exportname); + return make_uri (g, "gluster+tcp", NULL, NULL, + &src->servers[0], src->u.exportname); case drive_transport_unix: - return make_uri (g, "gluster+unix", NULL, &src->servers[0], NULL); + return make_uri (g, "gluster+unix", NULL, NULL, + &src->servers[0], NULL); } case drive_protocol_http: - return make_uri (g, "http", src->username, + return make_uri (g, "http", src->username, src->secret, &src->servers[0], src->u.exportname); case drive_protocol_https: - return make_uri (g, "https", src->username, + return make_uri (g, "https", src->username, src->secret, &src->servers[0], src->u.exportname); case drive_protocol_iscsi: - return make_uri (g, "iscsi", NULL, &src->servers[0], src->u.exportname); + return make_uri (g, "iscsi", NULL, NULL, + &src->servers[0], src->u.exportname); case drive_protocol_nbd: { CLEANUP_FREE char *p = NULL; @@ -1380,11 +1392,11 @@ guestfs___drive_source_qemu_param (guestfs_h *g, const struct drive_source *src) src->u.exportname); case drive_protocol_ssh: - return make_uri (g, "ssh", src->username, + return make_uri (g, "ssh", src->username, src->secret, &src->servers[0], src->u.exportname); case drive_protocol_tftp: - return make_uri (g, "tftp", src->username, + return make_uri (g, "tftp", src->username, src->secret, &src->servers[0], src->u.exportname); } diff --git a/sysprep/main.ml b/sysprep/main.ml index 71abfa7..37e4dc8 100644 --- a/sysprep/main.ml +++ b/sysprep/main.ml @@ -203,11 +203,12 @@ read the man page virt-sysprep(1). List.iter ( fun (uri, format) -> let { URI.path = path; protocol = protocol; - server = server; username = username } = uri in + server = server; username = username; + password = password } = uri in let discard = if readonly then None else Some "besteffort" in g#add_drive ~readonly ?discard - ?format ~protocol ?server ?username + ?format ~protocol ?server ?username ?secret:password path ) files in -- 1.9.0