[PATCH 1/2] mllib: hostname: replace the hostname on Debian also in /etc/hosts (RHBZ#953907).
In Debian/Ubuntu systems, read the previous hostname from /etc/hostname before replacing it, and try to carefully replace it in /etc/hosts with the new hostname. Since Perl_edit to edit /etc/hosts, it is added/changed as dependency for Hostname. --- builder/Makefile.am | 2 +- mllib/Makefile.am | 2 +- mllib/hostname.ml | 22 ++++++++++++++++++++++ sysprep/Makefile.am | 1 + 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/builder/Makefile.am b/builder/Makefile.am index 9d2dbc5..0880e03 100644 --- a/builder/Makefile.am +++ b/builder/Makefile.am @@ -69,10 +69,10 @@ OBJECTS = \ $(top_builddir)/mllib/common_utils.cmx \ $(top_builddir)/mllib/urandom.cmx \ $(top_builddir)/mllib/random_seed.cmx \ + $(top_builddir)/mllib/perl_edit.cmx \ $(top_builddir)/mllib/hostname.cmx \ $(top_builddir)/mllib/timezone.cmx \ $(top_builddir)/mllib/firstboot.cmx \ - $(top_builddir)/mllib/perl_edit.cmx \ $(top_builddir)/mllib/crypt-c.o \ $(top_builddir)/mllib/crypt.cmx \ $(top_builddir)/mllib/fsync-c.o \ diff --git a/mllib/Makefile.am b/mllib/Makefile.am index 67f0a0a..fc328d6 100644 --- a/mllib/Makefile.am +++ b/mllib/Makefile.am @@ -80,10 +80,10 @@ OBJECTS = \ common_utils.cmx \ urandom.cmx \ random_seed.cmx \ + perl_edit.cmx \ hostname.cmx \ timezone.cmx \ firstboot.cmx \ - perl_edit.cmx \ tTY.cmx \ fsync.cmx \ progress.cmx \ diff --git a/mllib/hostname.ml b/mllib/hostname.ml index 6702f29..e1c5d4b 100644 --- a/mllib/hostname.ml +++ b/mllib/hostname.ml @@ -42,7 +42,12 @@ let rec set_hostname (g : Guestfs.guestfs) root hostname = true | "linux", ("debian"|"ubuntu"), _ -> + let old_hostname = read_etc_hostname g in update_etc_hostname g hostname; + (match old_hostname with + | Some old_hostname -> replace_host_in_etc_hosts g old_hostname hostname + | None -> () + ); true | "linux", ("fedora"|"rhel"|"centos"|"scientificlinux"|"redhat-based"), _ -> @@ -78,3 +83,20 @@ and update_etc_hostname g hostname = and update_etc_machine_info g hostname = replace_line_in_file g "/etc/machine-info" "PRETTY_HOSTNAME" hostname + +and read_etc_hostname g = + let filename = "/etc/hostname" in + if g#is_file filename then ( + let lines = Array.to_list (g#read_lines filename) in + match lines with + | hd :: _ -> Some hd + | [] -> None + ) else + None + +and replace_host_in_etc_hosts g oldhost newhost = + let filename = "/etc/hosts" in + if g#is_file filename then ( + Perl_edit.edit_file ~debug:false g filename + ("s,(\\s)" ^ (Str.quote oldhost) ^ "(\\s|\\$),\\1" ^ (Str.quote newhost) ^ "\\2, if ($_ !~ /^#/)") + ) diff --git a/sysprep/Makefile.am b/sysprep/Makefile.am index 4c03c7f..25cdaa5 100644 --- a/sysprep/Makefile.am +++ b/sysprep/Makefile.am @@ -95,6 +95,7 @@ OBJECTS = \ $(top_builddir)/mllib/urandom.cmx \ $(top_builddir)/mllib/password.cmx \ $(top_builddir)/mllib/random_seed.cmx \ + $(top_builddir)/mllib/perl_edit.cmx \ $(top_builddir)/mllib/hostname.cmx \ $(top_builddir)/mllib/timezone.cmx \ $(top_builddir)/mllib/firstboot.cmx \ -- 1.8.3.1
On Wed, Feb 12, 2014 at 03:30:52PM +0100, Pino Toscano wrote:
+and replace_host_in_etc_hosts g oldhost newhost = + let filename = "/etc/hosts" in + if g#is_file filename then ( + Perl_edit.edit_file ~debug:false g filename + ("s,(\\s)" ^ (Str.quote oldhost) ^ "(\\s|\\$),\\1" ^ (Str.quote newhost) ^ "\\2, if ($_ !~ /^#/)")
I'd be surprised if Str.quote can properly quote this, since Perl regexps > the crappy regexps implemented in the Str module. In any case I'm not convinced this is the right way to do this. You should use Augeas instead. It is already used in one virt-sysprep module (sysprep/sysprep_operation_user_account.ml). So, NACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://people.redhat.com/~rjones/virt-top
In Debian/Ubuntu systems, read the previous hostname from /etc/hostname before replacing it, and replace it in /etc/hosts with the new hostname. --- mllib/hostname.ml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/mllib/hostname.ml b/mllib/hostname.ml index fce16ff..0d5b5d4 100644 --- a/mllib/hostname.ml +++ b/mllib/hostname.ml @@ -42,7 +42,12 @@ let rec set_hostname (g : Guestfs.guestfs) root hostname = true | "linux", ("debian"|"ubuntu"), _ -> + let old_hostname = read_etc_hostname g in update_etc_hostname g hostname; + (match old_hostname with + | Some old_hostname -> replace_host_in_etc_hosts g old_hostname hostname + | None -> () + ); true | "linux", ("fedora"|"rhel"|"centos"|"scientificlinux"|"redhat-based"), _ -> @@ -78,3 +83,25 @@ and update_etc_hostname g hostname = and update_etc_machine_info g hostname = replace_line_in_file g "/etc/machine-info" "PRETTY_HOSTNAME" hostname + +and read_etc_hostname g = + let filename = "/etc/hostname" in + if g#is_file filename then ( + let lines = Array.to_list (g#read_lines filename) in + match lines with + | hd :: _ -> Some hd + | [] -> None + ) else + None + +and replace_host_in_etc_hosts g oldhost newhost = + if g#is_file "/etc/hosts" then ( + let expr = "/files/etc/hosts/*[label() != '#comment']/*[label() != 'ipaddr'][. = '" ^ oldhost ^ "']" in + g#aug_init "/" 0; + let matches = Array.to_list (g#aug_match expr) in + List.iter ( + fun m -> + g#aug_set m newhost + ) matches; + g#aug_save () + ) -- 1.8.3.1
On Thu, Feb 13, 2014 at 02:15:31PM +0100, Pino Toscano wrote:
+ let expr = "/files/etc/hosts/*[label() != '#comment']/*[label() != 'ipaddr'][. = '" ^ oldhost ^ "']" in
Quoting? If oldhost contains a ' character + some Augeas code, this might be exploitable. I thought it might be possible to iterate over the Augeas tree. I'm fairly sure I used to have some code that did this, but I can't find it at the moment. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#)
On Thursday 13 February 2014 13:33:16 Richard W.M. Jones wrote:
On Thu, Feb 13, 2014 at 02:15:31PM +0100, Pino Toscano wrote:
+ let expr = "/files/etc/hosts/*[label() != '#comment']/*[label() != 'ipaddr'][. = '" ^ oldhost ^ "']" in Quoting? If oldhost contains a ' character + some Augeas code, this might be exploitable.
Hm right. Gone back in manually checking the values.
I thought it might be possible to iterate over the Augeas tree. I'm fairly sure I used to have some code that did this, but I can't find it at the moment.
At least in libguestfs, the two files which do augeas match+iteration are sysprep/sysprep_operation_user_account.ml (which you mentioned earlier) and src/inspect-fs-unix.c. -- Pino Toscano
In Debian/Ubuntu systems, read the previous hostname from /etc/hostname before replacing it, and replace it in /etc/hosts with the new hostname. --- mllib/hostname.ml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/mllib/hostname.ml b/mllib/hostname.ml index fce16ff..70ca934 100644 --- a/mllib/hostname.ml +++ b/mllib/hostname.ml @@ -42,7 +42,12 @@ let rec set_hostname (g : Guestfs.guestfs) root hostname = true | "linux", ("debian"|"ubuntu"), _ -> + let old_hostname = read_etc_hostname g in update_etc_hostname g hostname; + (match old_hostname with + | Some old_hostname -> replace_host_in_etc_hosts g old_hostname hostname + | None -> () + ); true | "linux", ("fedora"|"rhel"|"centos"|"scientificlinux"|"redhat-based"), _ -> @@ -78,3 +83,28 @@ and update_etc_hostname g hostname = and update_etc_machine_info g hostname = replace_line_in_file g "/etc/machine-info" "PRETTY_HOSTNAME" hostname + +and read_etc_hostname g = + let filename = "/etc/hostname" in + if g#is_file filename then ( + let lines = Array.to_list (g#read_lines filename) in + match lines with + | hd :: _ -> Some hd + | [] -> None + ) else + None + +and replace_host_in_etc_hosts g oldhost newhost = + if g#is_file "/etc/hosts" then ( + let expr = "/files/etc/hosts/*[label() != '#comment']/*[label() != 'ipaddr']" in + g#aug_init "/" 0; + let matches = Array.to_list (g#aug_match expr) in + List.iter ( + fun m -> + let value = g#aug_get m in + if value = oldhost then ( + g#aug_set m newhost + ) + ) matches; + g#aug_save () + ) -- 1.8.3.1
On Thu, Feb 13, 2014 at 03:10:41PM +0100, Pino Toscano wrote:
In Debian/Ubuntu systems, read the previous hostname from /etc/hostname before replacing it, and replace it in /etc/hosts with the new hostname. --- mllib/hostname.ml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/mllib/hostname.ml b/mllib/hostname.ml index fce16ff..70ca934 100644 --- a/mllib/hostname.ml +++ b/mllib/hostname.ml @@ -42,7 +42,12 @@ let rec set_hostname (g : Guestfs.guestfs) root hostname = true
| "linux", ("debian"|"ubuntu"), _ -> + let old_hostname = read_etc_hostname g in update_etc_hostname g hostname; + (match old_hostname with + | Some old_hostname -> replace_host_in_etc_hosts g old_hostname hostname + | None -> () + ); true
| "linux", ("fedora"|"rhel"|"centos"|"scientificlinux"|"redhat-based"), _ -> @@ -78,3 +83,28 @@ and update_etc_hostname g hostname =
and update_etc_machine_info g hostname = replace_line_in_file g "/etc/machine-info" "PRETTY_HOSTNAME" hostname + +and read_etc_hostname g = + let filename = "/etc/hostname" in + if g#is_file filename then ( + let lines = Array.to_list (g#read_lines filename) in + match lines with + | hd :: _ -> Some hd + | [] -> None + ) else + None + +and replace_host_in_etc_hosts g oldhost newhost = + if g#is_file "/etc/hosts" then ( + let expr = "/files/etc/hosts/*[label() != '#comment']/*[label() != 'ipaddr']" in + g#aug_init "/" 0; + let matches = Array.to_list (g#aug_match expr) in + List.iter ( + fun m -> + let value = g#aug_get m in + if value = oldhost then ( + g#aug_set m newhost + ) + ) matches; + g#aug_save () + )
Yup, third time lucky :-) ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://people.redhat.com/~rjones/virt-top
participants (2)
-
Pino Toscano -
Richard W.M. Jones