[Pkg-libvirt-commits] [libguestfs] 35/66: v2v: -o rhev: Write files and directories as user:group 36:36 (RHBZ#1143887).
Hilko Bengen
bengen at moszumanska.debian.org
Fri Oct 3 14:47:44 UTC 2014
This is an automated email from the git hooks/post-receive script.
bengen pushed a commit to annotated tag debian/1%1.27.54-1
in repository libguestfs.
commit 0dfa96c043cee4ce82c0a45c3ad09b0a61798b79
Author: Richard W.M. Jones <rjones at redhat.com>
Date: Mon Sep 22 21:57:57 2014 +0100
v2v: -o rhev: Write files and directories as user:group 36:36 (RHBZ#1143887).
We need to write files and directories as user:group 36:36, else
RHEV-M cannot import the VM. Doing this in the presence of NFS is
difficult. See v2v/kvmuid.mli for how it is done in this commit.
---
po/POTFILES | 1 +
po/POTFILES-ml | 1 +
v2v/Makefile.am | 7 +++--
v2v/kvmuid-c.c | 33 +++++++++++++++++++++
v2v/kvmuid.ml | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
v2v/kvmuid.mli | 69 +++++++++++++++++++++++++++++++++++++++++++
v2v/output_rhev.ml | 57 ++++++++++++++++++++++++++++++------
7 files changed, 243 insertions(+), 11 deletions(-)
diff --git a/po/POTFILES b/po/POTFILES
index aec8c62..be2de28 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -337,5 +337,6 @@ src/tmpdirs.c
src/utils.c
test-tool/test-tool.c
v2v/domainxml-c.c
+v2v/kvmuid-c.c
v2v/utils-c.c
v2v/xml-c.c
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 76fe681..de37bf7 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -92,6 +92,7 @@ v2v/input_disk.ml
v2v/input_libvirt.ml
v2v/input_libvirtxml.ml
v2v/input_ova.ml
+v2v/kvmuid.ml
v2v/lib_esx.ml
v2v/lib_linux.ml
v2v/lib_ovf.ml
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 03d7442..4b57aca 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -37,6 +37,7 @@ SOURCES_MLI = \
input_libvirtxml.mli \
input_ova.mli \
JSON.mli \
+ kvmuid.mli \
lib_esx.mli \
lib_linux.mli \
lib_ovf.mli \
@@ -60,6 +61,7 @@ SOURCES_ML = \
domainxml.ml \
DOM.ml \
JSON.ml \
+ kvmuid.ml \
lib_esx.ml \
lib_xen.ml \
lib_ovf.ml \
@@ -88,9 +90,10 @@ SOURCES_C = \
$(top_builddir)/mllib/mkdtemp-c.c \
$(top_builddir)/customize/crypt-c.c \
$(top_builddir)/customize/perl_edit-c.c \
+ domainxml-c.c \
+ kvmuid-c.c \
utils-c.c \
- xml-c.c \
- domainxml-c.c
+ xml-c.c
if HAVE_OCAML
diff --git a/v2v/kvmuid-c.c b/v2v/kvmuid-c.c
new file mode 100644
index 0000000..fb41711
--- /dev/null
+++ b/v2v/kvmuid-c.c
@@ -0,0 +1,33 @@
+/* virt-v2v
+ * Copyright (C) 2009-2014 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <caml/mlvalues.h>
+
+extern int v2v_exit (value rv) __attribute__((noreturn));
+
+int
+v2v_exit (value rv)
+{
+ _exit (Int_val (rv));
+}
diff --git a/v2v/kvmuid.ml b/v2v/kvmuid.ml
new file mode 100644
index 0000000..93908d9
--- /dev/null
+++ b/v2v/kvmuid.ml
@@ -0,0 +1,86 @@
+(* virt-v2v
+ * Copyright (C) 2009-2014 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(* Functions for making files and directories as another user. *)
+
+open Unix
+open Printf
+
+open Common_gettext.Gettext
+
+open Utils
+
+type t = {
+ uid : int option;
+ gid : int option;
+}
+
+let create ?uid ?gid () = { uid = uid; gid = gid }
+
+(* Call _exit directly, ie. do not run OCaml atexit handlers. *)
+external _exit : int -> unit = "v2v_exit" "noalloc"
+
+let with_fork { uid = uid; gid = gid } f =
+ let pid = fork () in
+ if pid = 0 then ( (* child *)
+ (match gid with None -> () | Some gid -> setgid gid);
+ (match uid with None -> () | Some uid -> setuid uid);
+ (try f ()
+ with exn ->
+ eprintf "%s: KVM uid wrapper: %s\n%!" prog (Printexc.to_string exn);
+ _exit 1
+ );
+ _exit 0
+ );
+ (* parent *)
+ let _, status = waitpid [] pid in
+ match status with
+ | WEXITED 0 -> ()
+ | WEXITED i ->
+ error (f_"subprocess exited with non-zero error code %d") i
+ | WSIGNALED i | WSTOPPED i ->
+ error (f_"subprocess signalled or stopped by signal %d") i
+
+let mkdir t path perm =
+ with_fork t (fun () -> mkdir path perm)
+
+let rmdir t path =
+ with_fork t (fun () -> rmdir path)
+
+let output t path f =
+ with_fork t (
+ fun () ->
+ let chan = open_out path in
+ f chan;
+ close_out chan
+ )
+
+let make_file t path content =
+ output t path (fun chan -> output_string chan content)
+
+let unlink t path =
+ with_fork t (fun () -> unlink path)
+
+let func t f = with_fork t f
+
+let command t cmd =
+ with_fork t (
+ fun () ->
+ let r = Sys.command cmd in
+ if r <> 0 then failwith "external command failed"
+ )
diff --git a/v2v/kvmuid.mli b/v2v/kvmuid.mli
new file mode 100644
index 0000000..dfd31c2
--- /dev/null
+++ b/v2v/kvmuid.mli
@@ -0,0 +1,69 @@
+(* virt-v2v
+ * Copyright (C) 2009-2014 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(** Functions for making files and directories as another user.
+
+ [-o rhev] output mode has to write files as UID:GID 36:36,
+ otherwise RHEV cannot read them. Because the files are located on
+ NFS (and hence might be root-squashed) we also cannot chown the
+ files. We cannot setuid the whole process to 36:36 because it
+ needs to do other root things like mounting and unmounting the NFS
+ volume.
+
+ The solution to this craziness is to fork a subprocess every time
+ we need to create a file, setuid in the subprocess, and write the
+ file. The subprocess then exits, leaving the main process still
+ running as root.
+
+ This mini-library encapsulates this tomfoolery into something that
+ is slightly more sane to use.
+
+ NB. We are {b not} dropping permissions for security reasons.
+ This file has nothing to do with security. *)
+
+type t
+(** Abstract handle. *)
+
+val create : ?uid:int -> ?gid:int -> unit -> t
+(** Create handle. The optional [?uid] and [?gid] parameters are the
+ user/group to run as. If omitted, then we don't change user
+ and/or group (but we still do the forking anyway). *)
+
+val mkdir : t -> string -> int -> unit
+(** [mkdir t path perm] creates the directory [path] with mode [perm]. *)
+
+val rmdir : t -> string -> unit
+(** [rmdir t path] removes the directory [path]. *)
+
+val make_file : t -> string -> string -> unit
+(** [make_file t path content] creates the file [path] with content
+ [content]. The current umask controls file permissions. *)
+
+val output : t -> string -> (out_channel -> unit) -> unit
+(** [output t path f] creates the file [path] with content from
+ function [f]. The current umask controls file permissions. *)
+
+val unlink : t -> string -> unit
+(** [unlink t path] deletes the file [path]. *)
+
+val func : t -> (unit -> unit) -> unit
+(** [func t f] runs the arbitrary function [f]. *)
+
+val command : t -> string -> unit
+(** [command t cmd] runs [cmd] as the alternate user/group after
+ forking. *)
diff --git a/v2v/output_rhev.ml b/v2v/output_rhev.ml
index 59991ba..bb77787 100644
--- a/v2v/output_rhev.ml
+++ b/v2v/output_rhev.ml
@@ -38,8 +38,13 @@ let rec mount_and_check_storage_domain verbose domain_class os =
| server, export ->
let export = "/" ^ export in
- (* Try mounting it. *)
+ (* Create a mountpoint. Default mode is too restrictive for us
+ * when we need to write into the directory as 36:36.
+ *)
let mp = Mkdtemp.temp_dir "v2v." "" in
+ chmod mp 0o755;
+
+ (* Try mounting it. *)
let cmd =
sprintf "mount %s:%s %s" (quote server) (quote export) (quote mp) in
if verbose then printf "%s\n%!" cmd;
@@ -111,7 +116,19 @@ and check_storage_domain verbose domain_class os mp =
(* Looks good, so return the SD mountpoint and UUID. *)
(mp, uuid)
+(* UID:GID required for files and directories when writing to ESD. *)
+let uid = 36 and gid = 36
+
class output_rhev verbose os vmtype output_alloc =
+ (* Create a UID-switching handle. If we're not root, create a dummy
+ * one because we cannot switch UIDs.
+ *)
+ let running_as_root = geteuid () = 0 in
+ let kvmuid_t =
+ if running_as_root then
+ Kvmuid.create ~uid ~gid ()
+ else
+ Kvmuid.create () in
object
inherit output verbose
@@ -171,6 +188,23 @@ object
eprintf "RHEV: ESD mountpoint: %s\nRHEV: ESD UUID: %s\n%!"
esd_mp esd_uuid;
+ (* See if we can write files as UID:GID 36:36. *)
+ let () =
+ let testfile = esd_mp // esd_uuid // "v2v-uid-test" in
+ Kvmuid.make_file kvmuid_t testfile "";
+ let stat = stat testfile in
+ Kvmuid.unlink kvmuid_t testfile;
+ let actual_uid = stat.st_uid and actual_gid = stat.st_gid in
+ if verbose then
+ eprintf "RHEV: actual UID:GID of new files is %d:%d\n"
+ actual_uid actual_gid;
+ if uid <> actual_uid || gid <> actual_gid then (
+ if running_as_root then
+ warning ~prog (f_"cannot write files to the NFS server as %d:%d, even though we appear to be running as root. This probably means the NFS client or idmapd is not configured properly.\n\nYou will have to chown the files that virt-v2v creates after the run, otherwise RHEV-M will not be able to import the VM.") uid gid
+ else
+ warning ~prog (f_"cannot write files to the NFS server as %d:%d. You might want to stop virt-v2v (^C) and rerun it as root.") uid gid
+ ) in
+
(* Create unique UUIDs for everything *)
image_uuid <- uuidgen ~prog ();
vm_uuid <- uuidgen ~prog ();
@@ -185,7 +219,7 @@ object
* conversion fails for any reason then we delete this directory.
*)
image_dir <- esd_mp // esd_uuid // "images" // image_uuid;
- mkdir image_dir 0o755;
+ Kvmuid.mkdir kvmuid_t image_dir 0o755;
at_exit (fun () ->
if delete_target_directory then (
let cmd = sprintf "rm -rf %s" (quote image_dir) in
@@ -227,14 +261,21 @@ object
List.iter (
fun ({ target_file = target_file }, meta) ->
let meta_filename = target_file ^ ".meta" in
- let chan = open_out meta_filename in
- output_string chan meta;
- close_out chan
+ Kvmuid.make_file kvmuid_t meta_filename meta
) (List.combine targets metas);
(* Return the list of targets. *)
targets
+ method disk_create ?backingfile ?backingformat ?preallocation ?compat
+ ?clustersize path format size =
+ Kvmuid.func kvmuid_t (
+ fun () ->
+ let g = new Guestfs.guestfs () in
+ g#disk_create ?backingfile ?backingformat ?preallocation ?compat
+ ?clustersize path format size
+ )
+
(* This is called after conversion to write the OVF metadata. *)
method create_metadata source targets guestcaps inspect =
(* Create the metadata. *)
@@ -243,11 +284,9 @@ object
(* Write it to the metadata file. *)
let dir = esd_mp // esd_uuid // "master" // "vms" // vm_uuid in
- mkdir dir 0o755;
+ Kvmuid.mkdir kvmuid_t dir 0o755;
let file = dir // vm_uuid ^ ".ovf" in
- let chan = open_out file in
- doc_to_chan chan ovf;
- close_out chan;
+ Kvmuid.output kvmuid_t file (fun chan -> doc_to_chan chan ovf);
(* Finished, so don't delete the target directory on exit. *)
delete_target_directory <- false
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-libvirt/libguestfs.git
More information about the Pkg-libvirt-commits
mailing list