Skip to content
Snippets Groups Projects
Commit 3c1fe780 authored by Nikos Skalkotos's avatar Nikos Skalkotos
Browse files

Merge branch 'feature-remote-connection' into develop

parents f8d60861 7df370f2
No related branches found
No related tags found
No related merge requests found
...@@ -517,6 +517,8 @@ class OSBase(object): ...@@ -517,6 +517,8 @@ class OSBase(object):
http://libguestfs.org/guestfs.3.html#guestfs_readdir http://libguestfs.org/guestfs.3.html#guestfs_readdir
* exclude: Exclude all files that follow this pattern. * exclude: Exclude all files that follow this pattern.
* include: Only include files that follow this pattern.
""" """
if not self.image.g.is_dir(directory): if not self.image.g.is_dir(directory):
self.out.warn("Directory: `%s' does not exist!" % directory) self.out.warn("Directory: `%s' does not exist!" % directory)
...@@ -531,6 +533,7 @@ class OSBase(object): ...@@ -531,6 +533,7 @@ class OSBase(object):
kargs['maxdepth'] = maxdepth kargs['maxdepth'] = maxdepth
exclude = None if 'exclude' not in kargs else kargs['exclude'] exclude = None if 'exclude' not in kargs else kargs['exclude']
include = None if 'include' not in kargs else kargs['include']
ftype = None if 'ftype' not in kargs else kargs['ftype'] ftype = None if 'ftype' not in kargs else kargs['ftype']
has_ftype = lambda x, y: y is None and True or x['ftyp'] == y has_ftype = lambda x, y: y is None and True or x['ftyp'] == y
...@@ -543,6 +546,9 @@ class OSBase(object): ...@@ -543,6 +546,9 @@ class OSBase(object):
if exclude and re.match(exclude, full_path): if exclude and re.match(exclude, full_path):
continue continue
if include and not re.match(include, full_path):
continue
if has_ftype(f, 'd'): if has_ftype(f, 'd'):
self._foreach_file(full_path, action, **kargs) self._foreach_file(full_path, action, **kargs)
......
...@@ -53,7 +53,10 @@ class Freebsd(Unix): ...@@ -53,7 +53,10 @@ class Freebsd(Unix):
def _do_collect_metadata(self): def _do_collect_metadata(self):
"""Collect metadata about the OS""" """Collect metadata about the OS"""
super(Freebsd, self)._do_collect_metadata() super(Freebsd, self)._do_collect_metadata()
self.meta["USERS"] = " ".join(self._get_passworded_users())
users = self._get_passworded_users()
self.meta["USERS"] = " ".join(users)
# The original product name key is long and ugly # The original product name key is long and ugly
self.meta['DESCRIPTION'] = \ self.meta['DESCRIPTION'] = \
...@@ -64,6 +67,44 @@ class Freebsd(Unix): ...@@ -64,6 +67,44 @@ class Freebsd(Unix):
self.out.warn("No passworded users found!") self.out.warn("No passworded users found!")
del self.meta['USERS'] del self.meta['USERS']
# Check if ssh is enabled
sshd_enabled = False
sshd_service = re.compile(r'^sshd_enable=.+$')
# Freebsd has a checkyesno() functions that tests the service variable
# against all those different values in a case insensitive manner!!!
sshd_yes = re.compile(r"^sshd_enable=(['\"]?)(YES|TRUE|ON|1)\1$",
re.IGNORECASE)
for rc_conf in ('/etc/rc.conf', '/etc/rc.conf.local'):
if not self.image.g.is_file(rc_conf):
continue
for line in self.image.g.cat(rc_conf).splitlines():
line = line.split('#')[0].strip()
# Be paranoid. Don't stop examining lines after a match. This
# is a shell variable and can be overwritten many times. Only
# the last match counts.
if sshd_service.match(line):
sshd_enabled = sshd_yes.match(line) is not None
if sshd_enabled:
ssh = []
opts = self.ssh_connection_options(users)
for user in opts['users']:
ssh.append("ssh:port=%d,user=%s" % (opts['port'], user))
if 'REMOTE_CONNECTION' not in self.meta:
self.meta['REMOTE_CONNECTION'] = ""
else:
self.meta['REMOTE_CONNECTION'] += " "
if len(users):
self.meta['REMOTE_CONNECTION'] += " ".join(ssh)
else:
self.meta['REMOTE_CONNECTION'] += "ssh:port=%d" % opts['port']
else:
self.out.warn("OpenSSH Daemon is not configured to run on boot")
def _do_inspect(self): def _do_inspect(self):
"""Run various diagnostics to check if media is supported""" """Run various diagnostics to check if media is supported"""
...@@ -93,7 +134,11 @@ class Freebsd(Unix): ...@@ -93,7 +134,11 @@ class Freebsd(Unix):
if len(passwd) > 0 and passwd[0] == '!': if len(passwd) > 0 and passwd[0] == '!':
self.out.warn("Ignoring locked %s account." % user) self.out.warn("Ignoring locked %s account." % user)
else: else:
users.append(user) # Put root in the beginning.
if user == 'root':
users.insert(0, user)
else:
users.append(user)
return users return users
......
...@@ -22,6 +22,19 @@ from image_creator.os_type.unix import Unix, sysprep ...@@ -22,6 +22,19 @@ from image_creator.os_type.unix import Unix, sysprep
import re import re
import time import time
X2GO_DESKTOPSESSIONS = {
'CINNAMON': 'cinnamon',
'KDE': 'startkde',
'GNOME': 'gnome-session',
'MATE': 'mate-session',
'XFCE': 'xfce4-session',
'LXDE': 'startlxde',
'TRINITY': 'starttrinity',
'UNITY': 'unity',
}
X2GO_EXECUTABLE = "x2goruncommand"
class Linux(Unix): class Linux(Unix):
"""OS class for Linux""" """OS class for Linux"""
...@@ -300,13 +313,101 @@ class Linux(Unix): ...@@ -300,13 +313,101 @@ class Linux(Unix):
def _do_collect_metadata(self): def _do_collect_metadata(self):
"""Collect metadata about the OS""" """Collect metadata about the OS"""
super(Linux, self)._do_collect_metadata() super(Linux, self)._do_collect_metadata()
self.meta["USERS"] = " ".join(self._get_passworded_users()) users = self._get_passworded_users()
self.meta["USERS"] = " ".join(users)
# Delete the USERS metadata if empty # Delete the USERS metadata if empty
if not len(self.meta['USERS']): if not len(self.meta['USERS']):
self.out.warn("No passworded users found!") self.out.warn("No passworded users found!")
del self.meta['USERS'] del self.meta['USERS']
if self.is_enabled('sshd'):
ssh = []
opts = self.ssh_connection_options(users)
for user in opts['users']:
ssh.append("ssh:port=%d,user=%s" % (opts['port'], user))
if 'REMOTE_CONNECTION' not in self.meta:
self.meta['REMOTE_CONNECTION'] = ""
else:
self.meta['REMOTE_CONNECTION'] += " "
if len(ssh):
self.meta['REMOTE_CONNECTION'] += " ".join(ssh)
else:
self.meta['REMOTE_CONNECTION'] += "ssh:port=%d" % opts['port']
# Check if x2go is installed
x2go_installed = False
desktops = set()
for path in ('/bin', '/usr/bin', '/usr/local/bin'):
if self.image.g.is_file("%s/%s" % (path, X2GO_EXECUTABLE)):
x2go_installed = True
for name, exe in X2GO_DESKTOPSESSIONS.items():
if self.image.g.is_file("%s/%s" % (path, exe)):
desktops.add(name)
if x2go_installed:
self.meta['REMOTE_CONNECTION'] += " "
if len(desktops) == 0:
self.meta['REMOTE_CONNECTION'] += "x2go"
else:
self.meta['REMOTE_CONNECTION'] += \
" ".join(["x2go:session=%s" % d for d in desktops])
else:
self.out.warn("OpenSSH Daemon is not configured to run on boot")
def is_enabled(self, service):
"""Check if a service is enabled to run on boot"""
systemd_services = '/etc/systemd/system/multi-user.target.wants'
exec_start = re.compile(r'^\s*ExecStart=.+bin/%s\s?' % service)
if self.image.g.is_dir(systemd_services):
for entry in self.image.g.readdir(systemd_services):
if entry['ftyp'] not in ('l', 'f'):
continue
service_file = "%s/%s" % (systemd_services, entry['name'])
for line in self.image.g.cat(service_file).splitlines():
if exec_start.search(line):
return True
found = set()
def check_file(path):
regexp = re.compile(r"[/=\s'\"]%s('\")?\s" % service)
for line in self.image.g.cat(path).splitlines():
line = line.split('#', 1)[0].strip()
if len(line) == 0:
continue
if regexp.search(line):
found.add(path)
return
# Check upstart config files under /etc/init
# Only examine *.conf files
if self.image.g.is_dir('/etc/init'):
self._foreach_file('/etc/init', check_file, maxdepth=1,
include='.+\.conf$')
if len(found):
return True
# Check scripts under /etc/rc[1-5].d/ and /etc/rc.d/rc[1-5].d/
for conf in ["/etc/%src%d.d" % (d, i) for i in xrange(1, 6)
for d in ('', 'rc.d/')]:
try:
for entry in self.image.g.readdir(conf):
if entry['ftyp'] not in ('l', 'f'):
continue
check_file("%s/%s" % (conf, entry['name']))
if len(found):
return True
except RuntimeError:
continue
return False
def _get_passworded_users(self): def _get_passworded_users(self):
"""Returns a list of non-locked user accounts""" """Returns a list of non-locked user accounts"""
users = [] users = []
......
...@@ -32,4 +32,16 @@ class Slackware(Linux): ...@@ -32,4 +32,16 @@ class Slackware(Linux):
self._foreach_file('/var/log', self.image.g.truncate, ftype='r', self._foreach_file('/var/log', self.image.g.truncate, ftype='r',
exclude='/var/log/packages') exclude='/var/log/packages')
def is_enabled(self, service):
"""Check if a service is enabled to start on boot"""
name = '/etc/rc.d/%s' % service
# In slackware a service will be executed during boot if the
# execute bit is set for the root
if self.image.g.is_file(name):
return self.image.g.stat(name)['mode'] & 0400
self.out.warn('Service %s not found on the media' % service)
return False
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
...@@ -70,6 +70,37 @@ class Unix(OSBase): ...@@ -70,6 +70,37 @@ class Unix(OSBase):
return True return True
def ssh_connection_options(self, users):
"""Returns a list of valid ssh connection options"""
def sshd_config():
"""Read /etc/ssh/sshd_config and return it as a dictionary"""
config = {}
fname = '/etc/ssh/sshd_config'
if not self.image.g.is_file(fname):
return {}
for line in self.image.g.cat(fname).splitlines():
line = line.split('#')[0].strip()
if not len(line):
continue
line = line.split()
config[line[0]] = line[1:]
return config
config = sshd_config()
try:
port = int(config['Port'][0])
except:
port = 22
if 'PermitRootLogin' in config and config['PermitRootLogin'] == 'no':
if 'root' in users:
users.remove('root')
return {'port': port, 'users': users}
@sysprep('Removing files under /var/cache') @sysprep('Removing files under /var/cache')
def _cleanup_cache(self): def _cleanup_cache(self):
"""Remove all regular files under /var/cache""" """Remove all regular files under /var/cache"""
......
...@@ -697,8 +697,26 @@ class Windows(OSBase): ...@@ -697,8 +697,26 @@ class Windows(OSBase):
super(Windows, self)._do_collect_metadata() super(Windows, self)._do_collect_metadata()
# We only care for active users # We only care for active users
self.meta["USERS"] = \ active = [self.usernames[a] for a in self.active_users]
" ".join([self.usernames[a] for a in self.active_users]) self.meta["USERS"] = " ".join(active)
# Get RDP settings
settings = self.registry.get_rdp_settings()
if settings['disabled']:
self.out.warn("RDP is disabled on the image")
else:
if 'REMOTE_CONNECTION' not in self.meta:
self.meta['REMOTE_CONNECTION'] = ""
else:
self.meta['REMOTE_CONNECTION'] += " "
port = settings['port']
if len(active):
rdp = ["rdp:port=%d,user=%s" % (port, user) for user in active]
self.meta['REMOTE_CONNECTION'] += " ".join(rdp)
else:
self.meta['REMOTE_CONNECTION'] += "rdp:port=%d" % port
def _check_connectivity(self): def _check_connectivity(self):
"""Check if winexe works on the Windows VM""" """Check if winexe works on the Windows VM"""
......
...@@ -170,6 +170,29 @@ class Registry(object): ...@@ -170,6 +170,29 @@ class Registry(object):
raise FatalError("Unknown Windows Setup State: %s" % value) raise FatalError("Unknown Windows Setup State: %s" % value)
def get_rdp_settings(self):
"""Returns Remote Desktop Settings of the image"""
settings = {}
with self.open_hive('SYSTEM') as hive:
path = '%s/Control/Terminal Server' % self.current_control_set
term_server = traverse(hive, path)
disabled = hive.node_get_value(term_server, "fDenyTSConnections")
# expecting a little endian dword
assert hive.value_type(disabled)[1] == 4
settings['disabled'] = hive.value_dword(disabled) != 0
path += "/WinStations/RDP-Tcp"
rdp_tcp = traverse(hive, path)
port = hive.node_get_value(rdp_tcp, "PortNumber")
# expecting a little endian dword
assert hive.value_type(port)[1] == 4
settings['port'] = hive.value_dword(port)
return settings
def runonce(self, commands): def runonce(self, commands):
"""Add commands to the RunOnce registry key""" """Add commands to the RunOnce registry key"""
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment