[virt-tools-list] [virt-bootstrap] [PATCH v3 04/12] set_root_password: Replace chpasswd with script
Radostin Stoyanov
rstoyanov1 at gmail.com
Thu Jul 20 11:29:39 UTC 2017
These changes aim to avoid the requirement for root privileges when
setting the password of root user on root file system.
The "-R, --root" flag of chpasswd is using chroot to apply changes in
root file system and this requires root privileges. [1]
Instead compute hash of the root password using passlib [2] and insert
the value in the /etc/shadow file in the rootfs.
[1] https://en.wikipedia.org/wiki/Chroot#Limitations
[2] http://passlib.readthedocs.io/en/stable/lib/passlib.hosts.html
---
setup.py | 5 +++++
src/virtBootstrap/utils.py | 33 +++++++++++++++++++++++++++++++++
src/virtBootstrap/virt_bootstrap.py | 18 +++---------------
3 files changed, 41 insertions(+), 15 deletions(-)
diff --git a/setup.py b/setup.py
index 70e3e03..b2e17ac 100755
--- a/setup.py
+++ b/setup.py
@@ -112,6 +112,11 @@ setup(
cmdclass={
'pylint': CheckPylint
},
+
+ # virt-bootstrap uses passlib to compute the hash of
+ # root password for root file system.
+ install_requires=['passlib>=1.7.1'],
+
extras_require={
'dev': [
'pylint',
diff --git a/src/virtBootstrap/utils.py b/src/virtBootstrap/utils.py
index a65d3f5..e1e681c 100644
--- a/src/virtBootstrap/utils.py
+++ b/src/virtBootstrap/utils.py
@@ -32,6 +32,7 @@ import tempfile
import logging
from subprocess import CalledProcessError, PIPE, Popen
+import passlib.hosts
# pylint: disable=invalid-name
# Create logger
@@ -331,6 +332,38 @@ def str2float(element):
return None
+def set_root_password(rootfs, password):
+ """
+ Set password on the root user within root filesystem
+ """
+ shadow_file = os.path.join(rootfs, "etc/shadow")
+
+ shadow_file_permissions = os.stat(shadow_file)[0]
+ # Set read-write permissions to shadow file
+ # 438 = 0110110110 = -rw-rw-rw-
+ os.chmod(shadow_file, 438)
+ try:
+ with open(shadow_file) as orig_file:
+ shadow_content = orig_file.read().split('\n')
+
+ for index, line in enumerate(shadow_content):
+ if line.startswith('root'):
+ line_split = line.split(':')
+ line_split[1] = passlib.hosts.linux_context.hash(password)
+ shadow_content[index] = ':'.join(line_split)
+ break
+
+ with open(shadow_file, "w") as new_file:
+ new_file.write('\n'.join(shadow_content))
+
+ except Exception:
+ raise
+
+ finally:
+ # Restore original permissions
+ os.chmod(shadow_file, shadow_file_permissions)
+
+
def write_progress(prog):
"""
Write progress output to console
diff --git a/src/virtBootstrap/virt_bootstrap.py b/src/virtBootstrap/virt_bootstrap.py
index fe27398..98c629a 100755
--- a/src/virtBootstrap/virt_bootstrap.py
+++ b/src/virtBootstrap/virt_bootstrap.py
@@ -27,7 +27,6 @@ import logging
import sys
import os
from textwrap import dedent
-from subprocess import CalledProcessError, Popen, PIPE
try:
from urlparse import urlparse
except ImportError:
@@ -70,18 +69,6 @@ def get_source(source_type):
raise Exception("Invalid image URL scheme: '%s'" % source_type)
-def set_root_password(rootfs, password):
- """
- Set password on the root user in rootfs
- """
- users = 'root:%s' % password
- args = ['chpasswd', '-R', rootfs]
- chpasswd = Popen(args, stdin=PIPE)
- chpasswd.communicate(input=users.encode('utf-8'))
- if chpasswd.returncode != 0:
- raise CalledProcessError(chpasswd.returncode, cmd=args, output=None)
-
-
# pylint: disable=too-many-arguments
def bootstrap(uri, dest,
fmt='dir',
@@ -117,8 +104,9 @@ def bootstrap(uri, dest,
no_cache=no_cache,
progress=prog).unpack(dest)
- if root_password is not None:
- set_root_password(dest, root_password)
+ if fmt == "dir" and root_password is not None:
+ logger.info("Setting password of the root account")
+ utils.set_root_password(dest, root_password)
def set_logging_conf(loglevel=None):
--
2.9.4
More information about the virt-tools-list
mailing list