From 293a6fbe1dea6a77b1394ced5399105a7e5181a8 Mon Sep 17 00:00:00 2001
From: Nikos Skalkotos <skalkoto@grnet.gr>
Date: Mon, 15 Dec 2014 19:04:47 +0200
Subject: [PATCH] Add initial support for OpenBSD

 * Split code from freebsd.py to bsd.py
 * Make {Open,Net,Free}bsd classes inherit from Bsd
---
 image_creator/os_type/bsd.py     | 142 +++++++++++++++++++++++++++++++
 image_creator/os_type/freebsd.py |  66 ++------------
 image_creator/os_type/netbsd.py  |   4 +-
 image_creator/os_type/openbsd.py |  27 ++++++
 4 files changed, 176 insertions(+), 63 deletions(-)
 create mode 100644 image_creator/os_type/bsd.py
 create mode 100644 image_creator/os_type/openbsd.py

diff --git a/image_creator/os_type/bsd.py b/image_creator/os_type/bsd.py
new file mode 100644
index 0000000..510818b
--- /dev/null
+++ b/image_creator/os_type/bsd.py
@@ -0,0 +1,142 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2011-2014 GRNET S.A.
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+
+"""This module hosts OS-specific code for *BSD."""
+
+from image_creator.os_type.unix import Unix, sysprep
+
+import re
+
+
+class Bsd(Unix):
+    """OS class for *BSD Unix-like operating system"""
+
+    @sysprep("Cleaning up passwords & locking all user accounts")
+    def _cleanup_password(self):
+        """Remove all passwords and lock all user accounts"""
+
+        master_passwd = []
+
+        for line in self.image.g.cat('/etc/master.passwd').splitlines():
+
+            # Check for empty or comment lines
+            if len(line.split('#')[0]) == 0:
+                master_passwd.append(line)
+                continue
+
+            fields = line.split(':')
+            if fields[1] not in ('*', '!'):
+                fields[1] = '!'
+
+            master_passwd.append(":".join(fields))
+
+        self.image.g.write(
+            '/etc/master.passwd', "\n".join(master_passwd) + '\n')
+
+        # Make sure no one can login on the system
+        self.image.g.rm_rf('/etc/spwd.db')
+
+    def _check_enabled_sshd(self):
+        """Check if the ssh daemon is enabled at boot"""
+        return False
+
+    def _do_collect_metadata(self):
+        """Collect metadata about the OS"""
+        super(Bsd, self)._do_collect_metadata()
+
+        users = self._get_passworded_users()
+
+        self.meta["USERS"] = " ".join(users)
+
+        # The original product name key is long and ugly
+        self.meta['DESCRIPTION'] = \
+            self.meta['DESCRIPTION'].split('#')[0].strip()
+
+        # Delete the USERS metadata if empty
+        if not len(self.meta['USERS']):
+            self.out.warn("No passworded users found!")
+            del self.meta['USERS']
+
+        # Check if ssh is enabled
+        sshd_enabled = self._check_enabled_sshd()
+
+        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 _get_passworded_users(self):
+        """Returns a list of non-locked user accounts"""
+        users = []
+        regexp = re.compile(
+            '^([^:]+):((?:![^:]+)|(?:[^!*][^:]+)|):(?:[^:]*:){7}(?:[^:]*)'
+        )
+
+        for line in self.image.g.cat('/etc/master.passwd').splitlines():
+            line = line.split('#')[0]
+            match = regexp.match(line)
+            if not match:
+                continue
+
+            user, passwd = match.groups()
+            if len(passwd) > 0 and passwd[0] == '!':
+                self.out.warn("Ignoring locked %s account." % user)
+            else:
+                # Put root in the beginning.
+                if user == 'root':
+                    users.insert(0, user)
+                else:
+                    users.append(user)
+
+        return users
+
+    def _do_mount(self, readonly):
+        """Mount partitions in the correct order"""
+
+        critical_mpoints = ('/', '/etc', '/root', '/home', '/var')
+
+        mopts1 = "ufstype=44bsd,%s" % ('ro' if readonly else 'rw')
+        mopts2 = "ufstype=ufs2,%s" % ('ro' if readonly else 'rw')
+        for mp, dev in self._mountpoints():
+            try:
+                try:
+                    self.image.g.mount_vfs(mopts2, 'ufs', dev, mp)
+                except RuntimeError:
+                    self.image.g.mount_vfs(mopts1, 'ufs', dev, mp)
+            except RuntimeError as msg:
+                if mp in critical_mpoints:
+                    self._mount_error = str(msg)
+                    return False
+                else:
+                    self._mount_warnings.append('%s (ignored)' % msg)
+
+        return True
+
+# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
diff --git a/image_creator/os_type/freebsd.py b/image_creator/os_type/freebsd.py
index bacd0aa..2ec89e8 100644
--- a/image_creator/os_type/freebsd.py
+++ b/image_creator/os_type/freebsd.py
@@ -17,12 +17,12 @@
 
 """This module hosts OS-specific code for FreeBSD."""
 
-from image_creator.os_type.unix import Unix, sysprep
+from image_creator.os_type.bsd import Bsd, sysprep
 
 import re
 
 
-class Freebsd(Unix):
+class Freebsd(Bsd):
     """OS class for FreeBSD Unix-like operating system"""
 
     @sysprep("Cleaning up passwords & locking all user accounts")
@@ -50,24 +50,9 @@ class Freebsd(Unix):
         # Make sure no one can login on the system
         self.image.g.rm_rf('/etc/spwd.db')
 
-    def _do_collect_metadata(self):
-        """Collect metadata about the OS"""
-        super(Freebsd, self)._do_collect_metadata()
+    def _check_enabled_sshd(self):
+        """Check if the sshd is enabled at boot"""
 
-        users = self._get_passworded_users()
-
-        self.meta["USERS"] = " ".join(users)
-
-        # The original product name key is long and ugly
-        self.meta['DESCRIPTION'] = \
-            self.meta['DESCRIPTION'].split('#')[0].strip()
-
-        # Delete the USERS metadata if empty
-        if not len(self.meta['USERS']):
-            self.out.warn("No passworded users found!")
-            del self.meta['USERS']
-
-        # Check if ssh is enabled
         sshd_enabled = False
         sshd_service = re.compile(r'^sshd_enable=.+$')
 
@@ -87,23 +72,7 @@ class Freebsd(Unix):
                 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")
+        return sshd_enabled
 
     def _do_inspect(self):
         """Run various diagnostics to check if media is supported"""
@@ -117,31 +86,6 @@ class Freebsd(Unix):
         else:
             self.out.success(ptype)
 
-    def _get_passworded_users(self):
-        """Returns a list of non-locked user accounts"""
-        users = []
-        regexp = re.compile(
-            '^([^:]+):((?:![^:]+)|(?:[^!*][^:]+)|):(?:[^:]*:){7}(?:[^:]*)'
-        )
-
-        for line in self.image.g.cat('/etc/master.passwd').splitlines():
-            line = line.split('#')[0]
-            match = regexp.match(line)
-            if not match:
-                continue
-
-            user, passwd = match.groups()
-            if len(passwd) > 0 and passwd[0] == '!':
-                self.out.warn("Ignoring locked %s account." % user)
-            else:
-                # Put root in the beginning.
-                if user == 'root':
-                    users.insert(0, user)
-                else:
-                    users.append(user)
-
-        return users
-
     def _do_mount(self, readonly):
         """Mount partitions in the correct order"""
 
diff --git a/image_creator/os_type/netbsd.py b/image_creator/os_type/netbsd.py
index 002c5c8..e52b65a 100644
--- a/image_creator/os_type/netbsd.py
+++ b/image_creator/os_type/netbsd.py
@@ -17,10 +17,10 @@
 
 """This module hosts OS-specific code for NetBSD."""
 
-from image_creator.os_type.unix import Unix
+from image_creator.os_type.bsd import Bsd
 
 
-class Netbsd(Unix):
+class Netbsd(Bsd):
     """OS class for NetBSD"""
     pass
 
diff --git a/image_creator/os_type/openbsd.py b/image_creator/os_type/openbsd.py
new file mode 100644
index 0000000..0a916f7
--- /dev/null
+++ b/image_creator/os_type/openbsd.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2011-2014 GRNET S.A.
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+
+"""This module hosts OS-specific code for OpenBSD."""
+
+from image_creator.os_type.bsd import Bsd
+
+
+class Openbsd(Bsd):
+    """OS class for OpenBSD"""
+    pass
+
+# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
-- 
GitLab