From f9146d6ccbaed3cc6e25f5c7c8462cb8d1514c28 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 30 Oct 2014 13:34:12 +0000
Subject: [PATCH] v2v: Add --password-file parameter (RHBZ#1158526).
This allows you to send passwords to virt-v2v input modes without
being interactive.
(cherry picked from commit 65abc4420325c1226b002f2304709b2040160877)
---
v2v/cmdline.ml | 13 +++++++++-
v2v/domainxml-c.c | 52 ++++++++++++++++++++++++++++++++-----
v2v/domainxml.ml | 2 +-
v2v/domainxml.mli | 4 +--
v2v/input_libvirt.ml | 12 ++++-----
v2v/input_libvirt.mli | 4 +--
v2v/input_libvirt_other.ml | 8 +++---
v2v/input_libvirt_other.mli | 4 +--
v2v/input_libvirt_vcenter_https.ml | 29 +++++++++++++--------
v2v/input_libvirt_vcenter_https.mli | 2 +-
v2v/input_libvirt_xen_ssh.ml | 6 ++---
v2v/input_libvirt_xen_ssh.mli | 2 +-
v2v/virt-v2v.pod | 10 ++++++-
13 files changed, 106 insertions(+), 42 deletions(-)
diff --git a/v2v/cmdline.ml b/v2v/cmdline.ml
index 6f8a964..9c3253e 100644
--- a/v2v/cmdline.ml
+++ b/v2v/cmdline.ml
@@ -42,6 +42,7 @@ let parse_cmdline () =
let output_format = ref "" in
let output_name = ref "" in
let output_storage = ref "" in
+ let password_file = ref "" in
let print_source = ref false in
let qemu_boot = ref false in
let quiet = ref false in
@@ -165,6 +166,7 @@ let parse_cmdline () =
"-of", Arg.Set_string output_format, "raw|qcow2 " ^ s_"Set output format";
"-on", Arg.Set_string output_name, "name " ^ s_"Rename guest when converting";
"-os", Arg.Set_string output_storage, "storage " ^ s_"Set output storage location";
+ "--password-file", Arg.Set_string password_file, "file " ^ s_"Use password from file";
"--print-source", Arg.Set print_source, " " ^ s_"Print source and stop";
"--qemu-boot", Arg.Set qemu_boot, " " ^ s_"Boot in qemu (-o qemu only)";
"-q", Arg.Set quiet, " " ^ s_"Quiet output";
@@ -227,6 +229,7 @@ read the man page virt-v2v(1).
let output_mode = !output_mode in
let output_name = match !output_name with "" -> None | s -> Some s in
let output_storage = !output_storage in
+ let password_file = match !password_file with "" -> None | s -> Some s in
let print_source = !print_source in
let qemu_boot = !qemu_boot in
let quiet = !quiet in
@@ -256,6 +259,14 @@ read the man page virt-v2v(1).
exit 0
);
+ (* Parse out the password from the password file. *)
+ let password =
+ match password_file with
+ | None -> None
+ | Some filename ->
+ let password = read_whole_file filename in
+ Some password in
+
(* Parsing of the argument(s) depends on the input mode. *)
let input =
match input_mode with
@@ -278,7 +289,7 @@ read the man page virt-v2v(1).
| [guest] -> guest
| _ ->
error (f_"expecting a libvirt guest name on the command line") in
- Input_libvirt.input_libvirt verbose input_conn guest
+ Input_libvirt.input_libvirt verbose password input_conn guest
| `LibvirtXML ->
(* -i libvirtxml: Expecting a filename (XML file). *)
diff --git a/v2v/domainxml-c.c b/v2v/domainxml-c.c
index 8a55030..6fa8270 100644
--- a/v2v/domainxml-c.c
+++ b/v2v/domainxml-c.c
@@ -74,13 +74,47 @@ get_dom_state (virDomainPtr dom)
return -1;
}
+/* See src/libvirt-auth.c for why we need this. */
+static int
+libvirt_auth_default_wrapper (virConnectCredentialPtr cred,
+ unsigned int ncred,
+ void *passwordvp)
+{
+ const char *password = passwordvp;
+ unsigned int i;
+
+ if (password) {
+ /* If --password-file was specified on the command line, and the
+ * libvirt handler is asking for a password, return that.
+ */
+ for (i = 0; i < ncred; ++i) {
+ if (cred[i].type == VIR_CRED_PASSPHRASE) {
+ cred[i].result = strdup (password);
+ cred[i].resultlen = strlen (password);
+ }
+ else {
+ cred[i].result = NULL;
+ cred[i].resultlen = 0;
+ }
+ }
+ return 0;
+ }
+ else {
+ /* No --password-file so call the default handler. */
+ return virConnectAuthPtrDefault->cb (cred, ncred,
+ virConnectAuthPtrDefault->cbdata);
+ }
+}
+
value
-v2v_dumpxml (value connv, value domnamev)
+v2v_dumpxml (value passwordv, value connv, value domnamev)
{
- CAMLparam2 (connv, domnamev);
+ CAMLparam3 (passwordv, connv, domnamev);
CAMLlocal1 (retv);
+ const char *password = NULL;
const char *conn_uri = NULL;
const char *domname;
+ virConnectAuth authdata;
/* We have to assemble the error on the stack because a dynamic
* string couldn't be freed.
*/
@@ -91,16 +125,20 @@ v2v_dumpxml (value connv, value domnamev)
int is_test_uri = 0;
char *xml;
+ if (passwordv != Val_int (0))
+ password = String_val (Field (passwordv, 0)); /* Some password */
+
if (connv != Val_int (0)) {
conn_uri = String_val (Field (connv, 0)); /* Some conn */
is_test_uri = STRPREFIX (conn_uri, "test:");
}
- /* We have to call the default authentication handler, not least
- * since it handles all the PolicyKit crap. However it also makes
- * coding this simpler.
- */
- conn = virConnectOpenAuth (conn_uri, virConnectAuthPtrDefault, VIR_CONNECT_RO);
+ /* Set up authentication wrapper. */
+ authdata = *virConnectAuthPtrDefault;
+ authdata.cb = libvirt_auth_default_wrapper;
+ authdata.cbdata = (void *) password;
+
+ conn = virConnectOpenAuth (conn_uri, &authdata, VIR_CONNECT_RO);
if (conn == NULL) {
if (conn_uri)
snprintf (errmsg, sizeof errmsg,
diff --git a/v2v/domainxml.ml b/v2v/domainxml.ml
index d240918..61ed5e0 100644
--- a/v2v/domainxml.ml
+++ b/v2v/domainxml.ml
@@ -18,5 +18,5 @@
(* [virsh dumpxml] but with non-broken authentication handling. *)
-external dumpxml : ?conn:string -> string -> string = "v2v_dumpxml"
+external dumpxml : ?password:string -> ?conn:string -> string -> string = "v2v_dumpxml"
external pool_dumpxml : ?conn:string -> string -> string = "v2v_pool_dumpxml"
diff --git a/v2v/domainxml.mli b/v2v/domainxml.mli
index ced55ce..ffb1c46 100644
--- a/v2v/domainxml.mli
+++ b/v2v/domainxml.mli
@@ -23,8 +23,8 @@
password prompt to stdout, which is the same place we would be
reading the XML from. This file works around this brokenness. *)
-val dumpxml : ?conn:string -> string -> string
-(** [dumpxml ?conn dom] returns the libvirt XML of domain [dom].
+val dumpxml : ?password:string -> ?conn:string -> string -> string
+(** [dumpxml ?password ?conn dom] returns the libvirt XML of domain [dom].
The optional [?conn] parameter is the libvirt connection URI.
[dom] may be a guest name or UUID. *)
diff --git a/v2v/input_libvirt.ml b/v2v/input_libvirt.ml
index 60e88ac..aff97ac 100644
--- a/v2v/input_libvirt.ml
+++ b/v2v/input_libvirt.ml
@@ -27,10 +27,10 @@ open Types
open Utils
(* Choose the right subclass based on the URI. *)
-let input_libvirt verbose libvirt_uri guest =
+let input_libvirt verbose password libvirt_uri guest =
match libvirt_uri with
| None ->
- Input_libvirt_other.input_libvirt_other verbose libvirt_uri guest
+ Input_libvirt_other.input_libvirt_other verbose password libvirt_uri guest
| Some orig_uri ->
let { Xml.uri_server = server; uri_scheme = scheme } as parsed_uri =
@@ -45,15 +45,15 @@ let input_libvirt verbose libvirt_uri guest =
| Some _, None (* No scheme? *)
| Some _, Some "" ->
- Input_libvirt_other.input_libvirt_other verbose libvirt_uri guest
+ Input_libvirt_other.input_libvirt_other verbose password libvirt_uri guest
| Some server, Some ("esx"|"gsx"|"vpx" as scheme) -> (* vCenter over https *)
Input_libvirt_vcenter_https.input_libvirt_vcenter_https
- verbose libvirt_uri parsed_uri scheme server guest
+ verbose password libvirt_uri parsed_uri scheme server guest
| Some server, Some ("xen+ssh" as scheme) -> (* Xen over SSH *)
Input_libvirt_xen_ssh.input_libvirt_xen_ssh
- verbose libvirt_uri parsed_uri scheme server guest
+ verbose password libvirt_uri parsed_uri scheme server guest
(* Old virt-v2v also supported qemu+ssh://. However I am
* deliberately not supporting this in new virt-v2v. Don't
@@ -63,6 +63,6 @@ let input_libvirt verbose libvirt_uri guest =
| Some _, Some _ -> (* Unknown remote scheme. *)
warning ~prog (f_"no support for remote libvirt connections to '-ic %s'. The conversion may fail when it tries to read the source disks.")
orig_uri;
- Input_libvirt_other.input_libvirt_other verbose libvirt_uri guest
+ Input_libvirt_other.input_libvirt_other verbose password libvirt_uri guest
let () = Modules_list.register_input_module "libvirt"
diff --git a/v2v/input_libvirt.mli b/v2v/input_libvirt.mli
index 1ed704b..bdd40b6 100644
--- a/v2v/input_libvirt.mli
+++ b/v2v/input_libvirt.mli
@@ -18,7 +18,7 @@
(** [-i libvirt] source. *)
-val input_libvirt : bool -> string option -> string -> Types.input
-(** [input_libvirt verbose libvirt_uri guest] creates and returns a
+val input_libvirt : bool -> string option -> string option -> string -> Types.input
+(** [input_libvirt verbose password libvirt_uri guest] creates and returns a
new {!Types.input} object specialized for reading input from
libvirt sources. *)
diff --git a/v2v/input_libvirt_other.ml b/v2v/input_libvirt_other.ml
index 9f3eedb..c704af6 100644
--- a/v2v/input_libvirt_other.ml
+++ b/v2v/input_libvirt_other.ml
@@ -43,7 +43,7 @@ let error_if_no_ssh_agent () =
error (f_"ssh-agent authentication has not been set up ($SSH_AUTH_SOCK is not set). Please read \"INPUT FROM RHEL 5 XEN\" in the virt-v2v(1) man page.")
(* Superclass. *)
-class virtual input_libvirt verbose libvirt_uri guest =
+class virtual input_libvirt verbose password libvirt_uri guest =
object
inherit input verbose
@@ -58,9 +58,9 @@ end
(* Subclass specialized for handling anything that's *not* VMware vCenter
* or Xen.
*)
-class input_libvirt_other verbose libvirt_uri guest =
+class input_libvirt_other verbose password libvirt_uri guest =
object
- inherit input_libvirt verbose libvirt_uri guest
+ inherit input_libvirt verbose password libvirt_uri guest
method source () =
if verbose then printf "input_libvirt_other: source()\n%!";
@@ -68,7 +68,7 @@ object
(* Get the libvirt XML. This also checks (as a side-effect)
* that the domain is not running. (RHBZ#1138586)
*)
- let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in
+ let xml = Domainxml.dumpxml ?password ?conn:libvirt_uri guest in
let source, disks = Input_libvirtxml.parse_libvirt_xml ~verbose xml in
let disks =
diff --git a/v2v/input_libvirt_other.mli b/v2v/input_libvirt_other.mli
index 013d3bb..3eb82cb 100644
--- a/v2v/input_libvirt_other.mli
+++ b/v2v/input_libvirt_other.mli
@@ -21,10 +21,10 @@
val error_if_libvirt_backend : unit -> unit
val error_if_no_ssh_agent : unit -> unit
-class virtual input_libvirt : bool -> string option -> string -> object
+class virtual input_libvirt : bool -> string option -> string option -> string -> object
method as_options : string
method virtual source : unit -> Types.source
method adjust_overlay_parameters : Types.overlay -> unit
end
-val input_libvirt_other : bool -> string option -> string -> Types.input
+val input_libvirt_other : bool -> string option -> string option -> string -> Types.input
diff --git a/v2v/input_libvirt_vcenter_https.ml b/v2v/input_libvirt_vcenter_https.ml
index e514362..3d14a27 100644
--- a/v2v/input_libvirt_vcenter_https.ml
+++ b/v2v/input_libvirt_vcenter_https.ml
@@ -38,7 +38,7 @@ let readahead_for_copying = Some (64 * 1024 * 1024)
*)
let rec get_session_cookie =
let session_cookie = ref "" in
- fun verbose scheme uri sslverify url ->
+ fun verbose password scheme uri sslverify url ->
if !session_cookie <> "" then
Some !session_cookie
else (
@@ -48,9 +48,15 @@ let rec get_session_cookie =
"url", Some url;
] in
let curl_args =
- match uri.uri_user with
- | Some user -> ("user", Some user) :: curl_args
- | None -> curl_args in
+ match uri.uri_user, password with
+ | None, None -> curl_args
+ | None, Some _ ->
+ warning ~prog (f_"--password-file parameter ignored because 'user@' was not given in the URL");
+ curl_args
+ | Some user, None ->
+ ("user", Some user) :: curl_args
+ | Some user, Some password ->
+ ("user", Some (user ^ ":" ^ password)) :: curl_args in
let curl_args =
if not sslverify then ("insecure", None) :: curl_args else curl_args in
@@ -204,7 +210,7 @@ let get_datacenter uri scheme =
*)
let source_re = Str.regexp "^\\[\\(.*\\)\\] \\(.*\\)\\.vmdk$"
-let map_source_to_uri ?readahead verbose uri scheme server path =
+let map_source_to_uri ?readahead verbose password uri scheme server path =
if not (Str.string_match source_re path 0) then
path
else (
@@ -237,7 +243,8 @@ let map_source_to_uri ?readahead verbose uri scheme server path =
string_find query "no_verify=1" = -1 in
(* Now we have to query the server to get the session cookie. *)
- let session_cookie = get_session_cookie verbose scheme uri sslverify url in
+ let session_cookie =
+ get_session_cookie verbose password scheme uri sslverify url in
(* Construct the JSON parameters. *)
let json_params = [
@@ -274,9 +281,9 @@ let map_source_to_uri ?readahead verbose uri scheme server path =
(* Subclass specialized for handling VMware vCenter over https. *)
class input_libvirt_vcenter_https
- verbose libvirt_uri parsed_uri scheme server guest =
+ verbose password libvirt_uri parsed_uri scheme server guest =
object
- inherit input_libvirt verbose libvirt_uri guest
+ inherit input_libvirt verbose password libvirt_uri guest
val saved_source_paths = Hashtbl.create 13
@@ -290,7 +297,7 @@ object
(* Get the libvirt XML. This also checks (as a side-effect)
* that the domain is not running. (RHBZ#1138586)
*)
- let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in
+ let xml = Domainxml.dumpxml ?password ?conn:libvirt_uri guest in
let source, disks = parse_libvirt_xml ~verbose xml in
(* Save the original source paths, so that we can remap them again
@@ -314,7 +321,7 @@ object
| { p_source_disk = disk; p_source = P_dont_rewrite } -> disk
| { p_source_disk = disk; p_source = P_source_file path } ->
let qemu_uri = map_source_to_uri ?readahead
- verbose parsed_uri scheme server path in
+ verbose password parsed_uri scheme server path in
(* The libvirt ESX driver doesn't normally specify a format, but
* the format of the -flat file is *always* raw, so force it here.
@@ -335,7 +342,7 @@ object
let readahead = readahead_for_copying in
let backing_qemu_uri =
map_source_to_uri ?readahead
- verbose parsed_uri scheme server orig_path in
+ verbose password parsed_uri scheme server orig_path in
(* Rebase the qcow2 overlay to adjust the readahead parameter. *)
let cmd =
diff --git a/v2v/input_libvirt_vcenter_https.mli b/v2v/input_libvirt_vcenter_https.mli
index 82dce53..800c6ab 100644
--- a/v2v/input_libvirt_vcenter_https.mli
+++ b/v2v/input_libvirt_vcenter_https.mli
@@ -18,4 +18,4 @@
(** [-i libvirt] when the source is VMware vCenter *)
-val input_libvirt_vcenter_https : bool -> string option -> Xml.uri -> string -> string -> string -> Types.input
+val input_libvirt_vcenter_https : bool -> string option -> string option -> Xml.uri -> string -> string -> string -> Types.input
diff --git a/v2v/input_libvirt_xen_ssh.ml b/v2v/input_libvirt_xen_ssh.ml
index e1600a0..cf5f1ae 100644
--- a/v2v/input_libvirt_xen_ssh.ml
+++ b/v2v/input_libvirt_xen_ssh.ml
@@ -30,9 +30,9 @@ open Input_libvirt_other
open Printf
(* Subclass specialized for handling Xen over SSH. *)
-class input_libvirt_xen_ssh verbose libvirt_uri parsed_uri scheme server guest =
+class input_libvirt_xen_ssh verbose password libvirt_uri parsed_uri scheme server guest =
object
- inherit input_libvirt verbose libvirt_uri guest
+ inherit input_libvirt verbose password libvirt_uri guest
method source () =
if verbose then
@@ -45,7 +45,7 @@ object
(* Get the libvirt XML. This also checks (as a side-effect)
* that the domain is not running. (RHBZ#1138586)
*)
- let xml = Domainxml.dumpxml ?conn:libvirt_uri guest in
+ let xml = Domainxml.dumpxml ?password ?conn:libvirt_uri guest in
let source, disks = parse_libvirt_xml ~verbose xml in
(* Map the <source/> filename (which is relative to the remote
diff --git a/v2v/input_libvirt_xen_ssh.mli b/v2v/input_libvirt_xen_ssh.mli
index 85473ed..47eb62c 100644
--- a/v2v/input_libvirt_xen_ssh.mli
+++ b/v2v/input_libvirt_xen_ssh.mli
@@ -18,4 +18,4 @@
(** [-i libvirt] when the source is Xen *)
-val input_libvirt_xen_ssh : bool -> string option -> Xml.uri -> string -> string -> string -> Types.input
+val input_libvirt_xen_ssh : bool -> string option -> string option -> Xml.uri -> string -> string -> string -> Types.input
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
index 6e449cf..bebe105 100644
--- a/v2v/virt-v2v.pod
+++ b/v2v/virt-v2v.pod
@@ -423,6 +423,13 @@ C<root>.
You will get an error if virt-v2v is unable to mount/write to the
Export Storage Domain.
+=item B<--password-file> file
+
+Instead of asking for password(s) interactively, pass the password
+through a file. Note the file should contain the whole password,
+B<without any trailing newline>, and for security the file should have
+mode C<0600> so that others cannot read it.
+
=item B<--print-source>
Print information about the source guest and stop. This option is
@@ -789,7 +796,8 @@ down).
Note that you may be asked for the vCenter password I<twice>. This
happens once because libvirt needs it, and a second time because
-virt-v2v itself connects directly to the server.
+virt-v2v itself connects directly to the server. Use
+I<--password-file> to supply a password via a file.
In this case the output flags are set to write the converted guest to
a temporary directory as this is just an example, but you can also
--
1.8.3.1