summaryrefslogtreecommitdiffstats
path: root/src/account
diff options
context:
space:
mode:
authorAlois Mahdal <amahdal@redhat.com>2014-03-17 21:02:38 +0100
committerAlois Mahdal <amahdal@redhat.com>2014-03-25 10:22:15 +0100
commit4982dd72dbb5c0441c2fe0e3e213cd25c0424ea7 (patch)
treee9d6abce6b3b9efcd94df21f448c954d287c2e3d /src/account
parent1dcddcb94f89be4f06c762ee982c1a4e477abad4 (diff)
downloadopenlmi-providers-4982dd72dbb5c0441c2fe0e3e213cd25c0424ea7.tar.gz
openlmi-providers-4982dd72dbb5c0441c2fe0e3e213cd25c0424ea7.tar.xz
openlmi-providers-4982dd72dbb5c0441c2fe0e3e213cd25c0424ea7.zip
account: Add tests for invalid system files
Each test creates an instance it LMI_Account, then intentionally cripples one of system files related to users/groups, and performs a simple sanity test that checks if instance properties are readable.
Diffstat (limited to 'src/account')
-rw-r--r--src/account/test/TestAccountInvalidEtc.py452
-rw-r--r--src/account/test/common.py119
2 files changed, 570 insertions, 1 deletions
diff --git a/src/account/test/TestAccountInvalidEtc.py b/src/account/test/TestAccountInvalidEtc.py
new file mode 100644
index 0000000..7ed77c3
--- /dev/null
+++ b/src/account/test/TestAccountInvalidEtc.py
@@ -0,0 +1,452 @@
+# -*- encoding: utf-8 -*-
+# Copyright(C) 2012-2013 Red Hat, Inc. All rights reserved.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or(at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Authors: Alois Mahdal <amahdal@redhat.com>
+
+import sys
+
+from common import AccountBase, BackupStorage, BaseCrippler
+from lmi.shell import LMIInstance
+
+
+## ......................................................................... ##
+## Helper functions
+## ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ##
+
+def gen_cripple(*args):
+ """
+ Generator of test methods. Each call to this function adds
+ one test method to TestAccountInvalidEtc.
+
+ All arguments are passed to PasswdCrippler.cripple.
+ """
+
+ def _new_cripple_test(self):
+ self.crippler.cripple(*args)
+ self.assertSane()
+
+ meth_name = "test%s_%s_%s" % (path.replace("/", "_"), op, case)
+ _new_cripple_test.__name__ = meth_name
+ setattr(TestAccountInvalidEtc, meth_name, _new_cripple_test)
+
+
+## ......................................................................... ##
+## Test data (later "converted" to test methods)
+## ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ##
+
+class PasswdCrippler(BaseCrippler):
+ """
+ Cripple files related to user management
+ """
+
+ def _define_cases(self):
+
+ data = {
+ 'ep': '$6$S2M8XGNtfRj/7mnX$Sn8XPyzOFYKSqSYLRlII4wYQc2A'
+ '.R6gQxh19Oz9e6KHLcCsvLK7ePJWLbZInWktI8/ZaiT/fFA'
+ 'Tjx6c3Q1A.Y1',
+ 'o15': 32769, # over 15-bit uint
+ 'o32': 4294967297, # over 32-bit uint
+ 'mi': sys.maxint,
+ 'omi': sys.maxint + 1,
+ }
+
+ cases = {}
+ cases['/etc/passwd'] = {
+
+ # syntax traps
+ 'empty_fields': "::::::",
+ 'one_field': "user1\n",
+ 'less_fields': "user1:x:2000:2000:U1:/home/user1",
+ 'more_fields': "user1:x:2000:2000:U1:/home/user1:/bin/bash:hm",
+
+ # funny
+ 'pegasus': "pegasus:x:66:65"
+ ":tog-pegasus OpenPegasus WBEM/CIM services"
+ ":/var/lib/Pegasus:/sbin/nologin",
+ 'root': "root:x:0:0:root:/root:/bin/bash",
+
+ # field: name
+ 'name_empty': ":x:2000:2000:U1:/home/user1:/bin/bash",
+ 'name_null': "\x00:x:2000:2000:U1:/home/user1:/bin/bash",
+ 'name_tab': "\x09:x:2000:2000:U1:/home/user1:/bin/bash",
+ 'name_space': " :x:2000:2000:U1:/home/user1:/bin/bash",
+ 'name_semicol': ";:x:2000:2000:U1:/home/user1:/bin/bash",
+ 'name_comma': ",:x:2000:2000:U1:/home/user1:/bin/bash",
+ 'name_duplicate': "user1:x:2000:2000:U1:/home/user1:/bin/bash\n"
+ "user1:x:2001:2001:User 2:/home/user2:/bin/bash",
+
+ # field: password
+ 'password_empty': "user1::2000:2000:U1:/home/user1:/bin/bash",
+ 'password_null': "user1:\x00:2000:2000:U1:/home/user1:/bin/bash",
+ 'password_tab': "user1:\x09:2000:2000:U1:/home/user1:/bin/bash",
+ 'password_space': "user1: :2000:2000:U1:/home/user1:/bin/bash",
+ 'password_semicol': "user1:;:2000:2000:U1:/home/user1:/bin/bash",
+ 'password_comma': "user1:,:2000:2000:U1:/home/user1:/bin/bash",
+ 'password_2aster': "user1:**:2000:2000:U1:/home/user1:/bin/bash",
+ 'password_2x': "user1:xx:2000:2000:U1:/home/user1:/bin/bash",
+ 'password_asterx': "user1:*x:2000:2000:U1:/home/user1:/bin/bash",
+ 'password_xaster': "user1:x*:2000:2000:U1:/home/user1:/bin/bash",
+
+ # field: uid
+ 'uid_empty': "user1:x::2000:U1:/home/user1:/bin/bash",
+ 'uid_null': "user1:x:\x00:2000:U1:/home/user1:/bin/bash",
+ 'uid_tab': "user1:x:\x09:2000:U1:/home/user1:/bin/bash",
+ 'uid_space': "user1:x: :2000:U1:/home/user1:/bin/bash",
+ 'uid_semicol': "user1:x:;:2000:U1:/home/user1:/bin/bash",
+ 'uid_comma': "user1:x:,:2000:U1:/home/user1:/bin/bash",
+ 'uid_string': "user1:x:hey:2000:U1:/home/user1:/bin/bash",
+ 'uid_negative': "user1:x:-2000:2000:U1:/home/user1:/bin/bash",
+ 'uid_over15': "user1:x:%(o15)d:2000:U1:/home/user1:/bin/bash",
+ 'uid_over32': "user1:x:%(o32)d:2000:U1:/home/user1:/bin/bash",
+ 'uid_over_maxint': "user1:x:%(omi)d:2000:U1:/home/user1:/bin/sh",
+ 'uid_maxint': "user1:x:%(mi)d:2000:U1:/home/user1:/bin/bash",
+ 'uid_duplicate': "user1:x:2000:2000:U1:/home/user1:/bin/bash\n"
+ "user2:x:2000:2001:User 2:/home/user2:/bin/bash",
+
+ # field: gid
+ 'gid_empty': "user1:x:2000::U1:/home/user1:/bin/bash",
+ 'gid_null': "user1:x:2000:\x00:U1:/home/user1:/bin/bash",
+ 'gid_tab': "user1:x:2000:\x09:U1:/home/user1:/bin/bash",
+ 'gid_space': "user1:x:2000: :U1:/home/user1:/bin/bash",
+ 'gid_semicol': "user1:x:2000:;:U1:/home/user1:/bin/bash",
+ 'gid_comma': "user1:x:2000:,:U1:/home/user1:/bin/bash",
+ 'gid_string': "user1:x:2000:hey:U1:/home/user1:/bin/bash",
+ 'gid_negative': "user1:x:2000:-2000:U1:/home/user1:/bin/bash",
+ 'gid_over15': "user1:x:2000:%(o15)d:U1:/home/user1:/bin/bash",
+ 'gid_over32': "user1:x:2000:%(o32)d:U1:/home/user1:/bin/bash",
+ 'gid_over_maxint': "user1:x:2000:%(omi)d:U1:/home/user1:/bin/sh",
+ 'gid_maxint': "user1:x:2000:%(mi)d:U1:/home/user1:/bin/bash",
+ 'gid_duplicate': "user1:x:2000:2000:U1:/home/user1:/bin/bash\n"
+ "user2:x:2001:2000:User 2:/home/user2:/bin/bash",
+
+ # field: directory
+ 'directory_empty': "user1:x:2000:2000:U1::/bin/bash",
+ 'directory_null': "user1:x:2000:2000:U1:\x00:/bin/bash",
+ 'directory_tab': "user1:x:2000:2000:U1:\x09:/bin/bash",
+
+ }
+
+ cases['/etc/group'] = {
+
+ # a valid line as a template
+ 'valid': "group1:x:2000:user1,user2,user3",
+
+ # syntax traps
+ 'empty_fields': ":::",
+ 'one_field': "group1\n",
+ 'less_fields': "group1:x:user1,user2,user3",
+ 'more_fields': "group1:x:2000:user1,user2,user3:hey",
+
+ # funny
+ 'pegasus': "pegasus:x:65:",
+ 'root': "root:x:0:",
+
+ # field: name
+ 'name_empty': ":x:2000:user1,user2,user3",
+ 'name_null': "\x00:x:2000:user1,user2,user3",
+ 'name_tab': "\x09:x:2000:user1,user2,user3",
+ 'name_space': " :x:2000:user1,user2,user3",
+ 'name_semicol': ";:x:2000:user1,user2,user3",
+ 'name_comma': ",:x:2000:user1,user2,user3",
+ 'name_duplicate': "group1:x:2000:user1,user2,user3\n"
+ "group1:x:2001:user1,user2,user3",
+
+ # field: password
+ 'password_empty': "group1::2000:user1,user2,user3",
+ 'password_null': "group1:\x00:2000:user1,user2,user3",
+ 'password_tab': "group1:\x09:2000:user1,user2,user3",
+ 'password_space': "group1: :2000:user1,user2,user3",
+ 'password_semicol': "group1:;:2000:user1,user2,user3",
+ 'password_comma': "group1:,:2000:user1,user2,user3",
+ 'password_2aster': "group1:**:2000:user1,user2,user3",
+ 'password_2x': "group1:xx:2000:user1,user2,user3",
+ 'password_asterx': "group1:*x:2000:user1,user2,user3",
+ 'password_xaster': "group1:x*:2000:user1,user2,user3",
+
+ # field: gid
+ 'gid_empty': "group1:x::user1,user2,user3",
+ 'gid_null': "group1:x:\x00:user1,user2,user3",
+ 'gid_tab': "group1:x:\x09:user1,user2,user3",
+ 'gid_space': "group1:x: :user1,user2,user3",
+ 'gid_semicol': "group1:x:;:user1,user2,user3",
+ 'gid_comma': "group1:x:,:user1,user2,user3",
+ 'gid_string': "group1:x:hey:user1,user2,user3",
+ 'gid_negative': "group1:x:-2000:user1,user2,user3",
+ 'gid_over15': "group1:x:%(o15)d:user1,user2,user3",
+ 'gid_over32': "group1:x:%(o32)d:user1,user2,user3",
+ 'gid_over_maxint': "group1:x:%(omi)d:user1.user2,user3",
+ 'gid_maxint': "group1:x:%(mi)d:user1,user2,user3",
+ 'gid_duplicate': "group1:x:2000:user1,user2,user3"
+ "user2:x:2000:user1,user2,user3",
+
+ # field: ulist
+ 'ulist_null': "group1:x:2000:\x00",
+ 'ulist_tab': "group1:x:2000:\x09",
+ 'ulist_space': "group1:x:2000: ",
+ 'ulist_semicol': "group1:x:2000:;",
+ 'ulist_nulls': "group1:x:2000:\x00,\x00",
+ 'ulist_tabs': "group1:x:2000:\x09,\x09",
+ 'ulist_spaces': "group1:x:2000: , ",
+ 'ulist_semicols': "group1:x:2000:;,;",
+ 'ulist_comma': "group1:x:2000:,",
+
+ }
+
+ cases['/etc/shadow'] = {
+
+ # a valid line as a template
+ 'valid': "user1:%(ep)s:16118:0:99999:7:::",
+
+ # syntax traps
+ 'empty_fields': "::::::::",
+ 'one_field': "user1\n",
+ 'less_fields': "user1:%(ep)s:16118:0:99999:7::",
+ 'more_fields': "user1:%(ep)s:16118:0:99999:7::::hey",
+
+ # funny
+ 'pegasus': "pegasus:$6$1.d1PKQWTeS.8eXI$qM5NXh0a9RRv7ajn"
+ "Sigd1wBqZp9l2.cVlJfPtybJUxbilM7HScfv.kW6EWcU"
+ "YKd3mU2bszTiQab0tKgmehzz5.:16146::::::",
+ 'root': "root:$6$s//AqmEc2gzQyFuL$9rUPnSPE6uYpDTBCiel"
+ "tHK5.5I0iJiiJva4bPnD5QH6/6iFKzJ32Lcrxxszz9In"
+ "BuorKT3ypIHeHeGvPkaPfO/:16118:0:99999:7:::",
+
+ # field: name
+ 'name_empty': ":%(ep)s:16118:0:99999:7:::",
+ 'name_null': "\x00:%(ep)s:16118:0:99999:7:::",
+ 'name_tab': "\x09:%(ep)s:16118:0:99999:7:::",
+ 'name_space': " :%(ep)s:16118:0:99999:7:::",
+ 'name_semicol': ";:%(ep)s:16118:0:99999:7:::",
+ 'name_comma': ",:%(ep)s:16118:0:99999:7:::",
+ 'name_duplicate': "user1:%(ep)s:16118:0:99999:7:::\n"
+ "user1:%(ep)s:16118:0:99999:7:::",
+
+ # field: password
+ 'password_empty': "user1:%(ep)s:16118:0:99999:7:::",
+ 'password_null': "user1:%(ep)s:16118:0:99999:7:::",
+ 'password_tab': "user1:%(ep)s:16118:0:99999:7:::",
+ 'password_space': "user1:%(ep)s:16118:0:99999:7:::",
+ 'password_semicol': "user1:%(ep)s:16118:0:99999:7:::",
+ 'password_comma': "user1:%(ep)s:16118:0:99999:7:::",
+ 'password_2aster': "user1:%(ep)s:16118:0:99999:7:::",
+ 'password_2x': "user1:%(ep)s:16118:0:99999:7:::",
+ 'password_asterx': "user1:%(ep)s:16118:0:99999:7:::",
+ 'password_xaster': "user1:%(ep)s:16118:0:99999:7:::",
+
+ # field: last change
+ 'lastch_empty': "user1:%(ep)s::0:99999:7:::",
+ 'lastch_null': "user1:%(ep)s:\x00:0:99999:7:::",
+ 'lastch_tab': "user1:%(ep)s:\x09:0:99999:7:::",
+ 'lastch_space': "user1:%(ep)s: :0:99999:7:::",
+ 'lastch_semicol': "user1:%(ep)s:;:0:99999:7:::",
+ 'lastch_comma': "user1:%(ep)s:,:0:99999:7:::",
+ 'lastch_string': "user1:%(ep)s:hey:0:99999:7:::",
+ 'lastch_negative': "user1:%(ep)s:-42:0:99999:7:::",
+ 'lastch_over15': "user1:%(ep)s:%(o15)d:0:99999:7:::",
+ 'lastch_over32': "user1:%(ep)s:%(o32)d:0:99999:7:::",
+ 'lastch_over_maxint': "user1:%(ep)s:%(omi)d:0:99999:7:::",
+ 'lastch_maxint': "user1:%(ep)s:%(mi)d:0:99999:7:::",
+
+ # field: minimum age
+ 'minage_empty': "user1:%(ep)s:16118::99999:7:::",
+ 'minage_null': "user1:%(ep)s:16118:\x00:99999:7:::",
+ 'minage_tab': "user1:%(ep)s:16118:\x09:99999:7:::",
+ 'minage_space': "user1:%(ep)s:16118: :99999:7:::",
+ 'minage_semicol': "user1:%(ep)s:16118:;:99999:7:::",
+ 'minage_comma': "user1:%(ep)s:16118:,:99999:7:::",
+ 'minage_string': "user1:%(ep)s:16118:hey:99999:7:::",
+ 'minage_negative': "user1:%(ep)s:16118:-42:99999:7:::",
+ 'minage_over15': "user1:%(ep)s:16118:%(o15)d:99999:7:::",
+ 'minage_over32': "user1:%(ep)s:16118:%(o32)d:99999:7:::",
+ 'minage_over_maxint': "user1:%(ep)s:16118:%(omi)d:99999:7:::",
+ 'minage_maxint': "user1:%(ep)s:16118:%(mi)d:99999:7:::",
+
+ # field: maximum age
+ 'maxage_empty': "user1:%(ep)s:16118:0::7:::",
+ 'maxage_null': "user1:%(ep)s:16118:0:\x00:7:::",
+ 'maxage_tab': "user1:%(ep)s:16118:0:\x09:7:::",
+ 'maxage_space': "user1:%(ep)s:16118:0: :7:::",
+ 'maxage_semicol': "user1:%(ep)s:16118:0:;:7:::",
+ 'maxage_comma': "user1:%(ep)s:16118:0:,:7:::",
+ 'maxage_string': "user1:%(ep)s:16118:0:hey:7:::",
+ 'maxage_negative': "user1:%(ep)s:16118:0:-42:7:::",
+ 'maxage_over15': "user1:%(ep)s:16118:0:%(o15)d:7:::",
+ 'maxage_over32': "user1:%(ep)s:16118:0:%(o32)d:7:::",
+ 'maxage_over_maxint': "user1:%(ep)s:16118:0:%(omi)d:7:::",
+ 'maxage_maxint': "user1:%(ep)s:16118:0:%(mi)d:7:::",
+
+ # field: warning period
+ 'wperiod_empty': "user1:%(ep)s:16118:0:99999::::",
+ 'wperiod_null': "user1:%(ep)s:16118:0:99999:\x00:::",
+ 'wperiod_tab': "user1:%(ep)s:16118:0:99999:\x09:::",
+ 'wperiod_space': "user1:%(ep)s:16118:0:99999: :::",
+ 'wperiod_semicol': "user1:%(ep)s:16118:0:99999:;:::",
+ 'wperiod_comma': "user1:%(ep)s:16118:0:99999:,:::",
+ 'wperiod_string': "user1:%(ep)s:16118:0:99999:hey:::",
+ 'wperiod_negative': "user1:%(ep)s:16118:0:99999:-42:::",
+ 'wperiod_over15': "user1:%(ep)s:16118:0:99999:%(o15)d:::",
+ 'wperiod_over32': "user1:%(ep)s:16118:0:99999:%(o32)d:::",
+ 'wperiod_over_maxint': "user1:%(ep)s:16118:0:99999:%(omi)d:::",
+ 'wperiod_maxint': "user1:%(ep)s:16118:0:99999:%(mi)d:::",
+
+ # field: inactivity period
+ 'iperiod_empty': "user1:%(ep)s:16118:0:99999:7:::",
+ 'iperiod_null': "user1:%(ep)s:16118:0:99999:7:\x00::",
+ 'iperiod_tab': "user1:%(ep)s:16118:0:99999:7:\x09::",
+ 'iperiod_space': "user1:%(ep)s:16118:0:99999:7: ::",
+ 'iperiod_semicol': "user1:%(ep)s:16118:0:99999:7:;::",
+ 'iperiod_comma': "user1:%(ep)s:16118:0:99999:7:,::",
+ 'iperiod_string': "user1:%(ep)s:16118:0:99999:7:hey::",
+ 'iperiod_negative': "user1:%(ep)s:16118:0:99999:7:-42::",
+ 'iperiod_over15': "user1:%(ep)s:16118:0:99999:7:%(o15)d::",
+ 'iperiod_over32': "user1:%(ep)s:16118:0:99999:7:%(o32)d::",
+ 'iperiod_over_maxint': "user1:%(ep)s:16118:0:99999:7:%(omi)d::",
+ 'iperiod_maxint': "user1:%(ep)s:16118:0:99999:7:%(mi)d::",
+
+ # field: account expiration date
+ 'expdate_empty': "user1:%(ep)s:16118:0:99999:7:::",
+ 'expdate_null': "user1:%(ep)s:16118:0:99999:7::\x00:",
+ 'expdate_tab': "user1:%(ep)s:16118:0:99999:7::\x09:",
+ 'expdate_space': "user1:%(ep)s:16118:0:99999:7:: :",
+ 'expdate_semicol': "user1:%(ep)s:16118:0:99999:7::;:",
+ 'expdate_comma': "user1:%(ep)s:16118:0:99999:7::,:",
+ 'expdate_string': "user1:%(ep)s:16118:0:99999:7::hey:",
+ 'expdate_negative': "user1:%(ep)s:16118:0:99999:7::-42:",
+ 'expdate_over15': "user1:%(ep)s:16118:0:99999:7::%(o15)d:",
+ 'expdate_over32': "user1:%(ep)s:16118:0:99999:7::%(o32)d:",
+ 'expdate_over_maxint': "user1:%(ep)s:16118:0:99999:7::%(omi)d:",
+ 'expdate_maxint': "user1:%(ep)s:16118:0:99999:7::%(mi)d:",
+
+ }
+
+ cases['/etc/gshadow'] = {
+
+ # a valid line as a template
+ 'valid': "group1:%(ep)s:user1,user2:user3,user4",
+
+ # syntax traps
+ 'empty_fields': ":::",
+ 'one_field': "user1\n",
+ 'less_fields': "group1:%(ep)s:user1,user2",
+ 'more_fields': "group1:%(ep)s:user1,user2:user3,user4:hey",
+
+ # funny
+ 'pegasus': "pegasus:!::",
+ 'root': "root:::",
+
+ # field: name
+ 'name_empty': ":%(ep)s:user1,user2:user3,user4",
+ 'name_null': "\x00:%(ep)s:user1,user2:user3,user4",
+ 'name_tab': "group1:%(ep)s:user1,user2:user3,user4",
+ 'name_space': "group1:%(ep)s:user1,user2:user3,user4",
+ 'name_semicol': "group1:%(ep)s:user1,user2:user3,user4",
+ 'name_comma': "group1:%(ep)s:user1,user2:user3,user4",
+ 'name_duplicate': "group1:%(ep)s:user1,user2:user3,user4\n"
+ "group1:%(ep)s:user1,user2:user3,user4",
+
+ # field: password
+ 'password_empty': "group1::user1,user2:user3,user4",
+ 'password_null': "group1:\x00:user1,user2:user3,user4",
+ 'password_tab': "group1:\x09:user1,user2:user3,user4",
+ 'password_space': "group1: :user1,user2:user3,user4",
+ 'password_semicol': "group1:;:user1,user2:user3,user4",
+ 'password_comma': "group1:,:user1,user2:user3,user4",
+ 'password_2aster': "group1:**:user1,user2:user3,user4",
+ 'password_2x': "group1:xx:user1,user2:user3,user4",
+ 'password_asterx': "group1:*x:user1,user2:user3,user4",
+ 'password_xaster': "group1:x*:user1,user2:user3,user4",
+
+ # field: alist
+ 'alist_null': "group1:%(ep)s:\x00:user3,user4",
+ 'alist_tab': "group1:%(ep)s:\x00:user3,user4",
+ 'alist_space': "group1:%(ep)s: :user3,user4",
+ 'alist_semicol': "group1:%(ep)s:;:user3,user4",
+ 'alist_nulls': "group1:%(ep)s:\x00,\x00:user3,user4",
+ 'alist_tabs': "group1:%(ep)s:\x09,\x09:user3,user4",
+ 'alist_spaces': "group1:%(ep)s: , :user3,user4",
+ 'alist_semicols': "group1:%(ep)s:;,;:user3,user4",
+ 'alist_comma': "group1:%(ep)s:,:user3,user4",
+
+ # field: ulist
+ 'ulist_null': "group1:%(ep)s:user1,user2:\x00",
+ 'ulist_tab': "group1:%(ep)s:user1,user2:\x00",
+ 'ulist_space': "group1:%(ep)s:user1,user2: ",
+ 'ulist_semicol': "group1:%(ep)s:user1,user2:;",
+ 'ulist_nulls': "group1:%(ep)s:user1,user2:\x00,\x00",
+ 'ulist_tabs': "group1:%(ep)s:user1,user2:\x09,\x09",
+ 'ulist_spaces': "group1:%(ep)s:user1,user2: , ",
+ 'ulist_semicols': "group1:%(ep)s:user1,user2:;,;",
+ 'ulist_comma': "group1:%(ep)s:user1,user2:,",
+
+ }
+
+ # add common cases
+ #
+ for key in cases:
+ cases[key]['many_fields'] = ":".join(["field"] * 5000)
+
+ # expand data
+ for path in cases:
+ for case in cases[path]:
+ cases[path][case] = cases[path][case] % data
+
+ return cases
+
+
+## ......................................................................... ##
+## Actual test
+## ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ##
+
+class TestAccountInvalidEtc(AccountBase):
+
+ CLASS_NAME = "LMI_Account"
+
+ def setUp(self):
+ self.bs = BackupStorage()
+ self.bs.add_file("/etc/passwd")
+ self.bs.add_file("/etc/shadow")
+ self.bs.add_file("/etc/group")
+ self.bs.add_file("/etc/gshadow")
+ self.inst = self.cim_class.first_instance()
+ self.addCleanup(self.bs.restore_all)
+ self.crippler = PasswdCrippler()
+
+ def assertSane(self):
+ """
+ Assert that main properties can be read
+ """
+ self.assertIsInstance(self.inst, LMIInstance)
+ # check if it provides key properties
+ for attr in ['CreationClassName', 'Name', 'SystemCreationClassName',
+ 'SystemName']:
+ self.assertIsNotNone(self.inst.properties_dict()[attr])
+
+ # check if it provides other properties, which should be set
+ for attr in ['host', 'UserID', 'UserPassword', 'UserPasswordEncoding']:
+ self.assertIsNotNone(self.inst.properties_dict()[attr])
+
+##
+## Here test methods are generated from data in PasswdCrippler instance,
+#
+
+crippler = PasswdCrippler()
+
+for path in crippler.all_paths():
+ for case in crippler.all_cases_for(path):
+ for op in ['append', 'replace']:
+ gen_cripple(path, case, op)
diff --git a/src/account/test/common.py b/src/account/test/common.py
index 2b3b423..862d1d4 100644
--- a/src/account/test/common.py
+++ b/src/account/test/common.py
@@ -13,7 +13,7 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Authors: Roman Rakus <rrakus@redhat.com>
#
@@ -24,6 +24,7 @@ Base class and utilities for all OpenLMI Account tests.
import hashlib
import os
import tempfile
+import string
import subprocess
from collections import Counter
from collections import OrderedDict
@@ -202,3 +203,119 @@ class BackupStorage():
Destroy the temporary backup
"""
subprocess.call(["rm", "-rf", self.root])
+
+
+class BaseCrippler:
+ """
+ Helper class for crippling system files.
+
+ To use the class, you need to sub-class it and implement
+ _define_cases method.
+ """
+
+ LINE_LENGTH = 500
+ LINE_COUNT = 50
+ BINARY_LENGTH = 10 * 1024 * 1024
+
+ ## virtual
+ #
+
+ def _define_cases(self):
+ """
+ Define cases per file supported
+
+ This function must return a dict with one set of cases per
+ file: key is path and value is another dict defining cases
+ as pairs of name ([a-zA-Z_]) and content.
+
+ Quick example:
+
+ {
+ '/etc/file1': {
+ 'case1': "some triggering content",
+ 'case2': "some other triggering content",
+ 'case3': "some funny triggering content",
+ },
+ '/etc/file2': {
+ 'case1': "some triggering content",
+ 'case2': "some other triggering content",
+ 'case3': "some funny triggering content",
+ },
+ }
+
+ Note that trailing newline is added automatically to each content
+ string. Also, whether content will be appended or replaced is decided
+ by caller of the BaseCrippler.cripple method.
+ """
+ pass
+
+ ## internal
+ #
+
+ def __init__(self):
+ self.autocases = {
+ 'empty': lambda: '',
+ 'random_line': self._random_line,
+ 'random_lines': self._random_lines,
+ 'random_binary': self._random_binary,
+ }
+ self.cases = self._define_cases()
+
+ def _append_to(self, path, content):
+ with open(path, 'a+') as fh:
+ fh.write(content)
+
+ def _clobber(self, path, content):
+ with open(path, 'w+') as fh:
+ fh.write(content)
+
+ def _random_binary(self, size=BINARY_LENGTH):
+ chars = ''.join([chr(i) for i in xrange(256)])
+ return methods.random_string(size, chars)
+
+ def _random_line(self, size=LINE_LENGTH):
+ chars = string.letters + string.punctuation + " \t"
+ return methods.random_string(size, chars) + "\n"
+
+ def _random_lines(self, size=LINE_LENGTH, count=LINE_COUNT):
+ return "".join([self._random_line(size) for i in xrange(count)])
+
+ def _get_content(self, path, case):
+
+ try:
+ content = self.autocases[case]()
+ except KeyError:
+ try:
+ content = self.cases[path][case] + "\n"
+ except KeyError:
+ raise ValueError("unknown case: %s for: %s" % (case, path))
+ return content
+
+ ## public
+ #
+
+ def all_cases_for(self, path):
+ """
+ Return list of cases available for path
+ """
+ return self.cases[path].keys() + self.autocases.keys()
+
+ def all_paths(self):
+ """
+ Return list of paths served by this implementation
+ """
+ return self.cases.keys()
+
+ def cripple(self, path, case, op="replace"):
+ """
+ Cripple file according to selected case.
+
+ op is either "append" or "replace" and means that the content will
+ be appended to the file, otherwise it will replace it.
+ """
+ if op == 'replace':
+ self._clobber(path, self._get_content(path, case))
+ elif op == 'append':
+ self._append_to(path, self._get_content(path, case))
+ else:
+ raise ValueError("unknown op: %s" % op)