7052679 AI Sparc client gets wanboot.conf error when booting due to restrictive umask S11U1Build8
authorTomas Dzik <Tomas.Dzik@oracle.com>
Fri, 13 Jan 2012 10:23:52 +0100
changeset 1573 35d9a7aee5a9
parent 1572 30f73c6cdf05
child 1574 5cb2d0e5c9cb
7052679 AI Sparc client gets wanboot.conf error when booting due to restrictive umask
usr/src/cmd/installadm/dhcp.py
usr/src/cmd/installadm/grub.py
usr/src/cmd/installadm/service_config.py
usr/src/cmd/installadm/setup-sparc.sh
usr/src/cmd/installadm/test/test_create_service.py
usr/src/cmd/installadm/test/test_service_config.py
--- a/usr/src/cmd/installadm/dhcp.py	Tue Jan 10 14:31:15 2012 -0800
+++ b/usr/src/cmd/installadm/dhcp.py	Fri Jan 13 10:23:52 2012 +0100
@@ -499,6 +499,9 @@
         in_class = False
         seek_bootfile = False
         edit_complete = False
+        # dhcpd server runs under dhcpserv user account and needs to be able
+        # to read its config file
+        orig_umask = os.umask(0022)
         with open(tmp_cfgfile, "w") as tmp_cfg:
             for line in current_lines:
                 if not edit_complete:
@@ -562,7 +565,7 @@
                                 seek_bootfile = True
                 # Write each line from the old file to the new as we traverse
                 tmp_cfg.write(line)
-
+        os.umask(orig_umask)
         # Ok, we're done writing lines from the old file to the new. Let's
         # ensure we've made our edit. If not, for whatever reason, we should
         # inform the enduser that manual DHCP configuration might be required.
@@ -726,7 +729,7 @@
             logging.debug("dhcp.control: unexpected service state: %s",
                           self._state)
             raise DHCPServerError(cw(_("DHCP server is in an unexpected "
-                                       "state: action [%s] state [%s]") % 
+                                       "state: action [%s] state [%s]") %
                                        (action, self._state)))
 
     def _add_stanza_to_config_file(self, new_stanza):
@@ -1278,7 +1281,7 @@
     cmd = [SVCPROP, "-p", prop, service]
     p = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE,
                          logger='', stderr_loglevel=logging.DEBUG)
-    
+
     return p.stdout.strip()
 
 
@@ -1356,7 +1359,7 @@
     # be able to simply use the IP address returned from get_valid_networks().
     valid_nets = list(com.get_valid_networks())
     if valid_nets:
-        ipaddr = valid_nets[0] 
+        ipaddr = valid_nets[0]
     else:
         if verbose:
             print >> sys.stderr, cw(_("\nNo networks are currently set to "
--- a/usr/src/cmd/installadm/grub.py	Tue Jan 10 14:31:15 2012 -0800
+++ b/usr/src/cmd/installadm/grub.py	Fri Jan 13 10:23:52 2012 +0100
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 '''
 functions supporting creating and modifying menu.lst
@@ -157,6 +157,8 @@
         os.remove(media_grub)
 
     # Create a new menu.lst for the AI client to use during boot
+    # menu.lst should be created with right permissions
+    orig_umask = os.umask(0022)
     with open(os.path.join(menu_path, MENULST), "w") as menu:
         # First setup the the global environment variables
         menu.write("default=0\n")
@@ -188,3 +190,4 @@
                     srv_address))
         menu.write("\tmodule$ /%s/platform/i86pc/$ISADIR/boot_archive\n" %
                    svc_name)
+    os.umask(orig_umask)
--- a/usr/src/cmd/installadm/service_config.py	Tue Jan 10 14:31:15 2012 -0800
+++ b/usr/src/cmd/installadm/service_config.py	Fri Jan 13 10:23:52 2012 +0100
@@ -19,7 +19,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 '''
 This file contains functions to manage the properties of installation
@@ -760,9 +760,15 @@
 
     cfgpath = os.path.join(svcdir, CFGFILE)
     logging.log(com.XDEBUG, 'writing config file:  %s', cfgpath)
+
+    # .config file should be created with right permissions
+    orig_umask = os.umask(0022)
+
     with open(cfgpath, 'w') as cfgfile:
         cfg.write(cfgfile)
 
+    os.umask(orig_umask)
+
 
 def _write_service_config(service_name, props):
     '''Writes out the service related info to the .config file
--- a/usr/src/cmd/installadm/setup-sparc.sh	Tue Jan 10 14:31:15 2012 -0800
+++ b/usr/src/cmd/installadm/setup-sparc.sh	Fri Jan 13 10:23:52 2012 +0100
@@ -19,7 +19,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
 
 # Description:
 #	This script sets up the wanboot.conf file which is used
@@ -35,6 +35,9 @@
 
 . /usr/lib/installadm/installadm-common
 
+# Ensure that we will create files with right permissions
+# umask is shell built-in
+umask 022
 
 WANBOOTCGI="/usr/lib/inet/wanboot/wanboot-cgi"
 CGIBIN_WANBOOTCGI="cgi-bin/wanboot-cgi"
--- a/usr/src/cmd/installadm/test/test_create_service.py	Tue Jan 10 14:31:15 2012 -0800
+++ b/usr/src/cmd/installadm/test/test_create_service.py	Fri Jan 13 10:23:52 2012 +0100
@@ -19,7 +19,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 '''
@@ -29,13 +29,18 @@
 
 '''
 
-import unittest
+import os
 import osol_install.auto_install.create_service as create_service
+import osol_install.auto_install.dhcp as dhcp
+import osol_install.auto_install.grub as grub
 import osol_install.auto_install.installadm_common as com
+import shutil
+import tempfile
+import unittest
 
 
 class ParseOptions(unittest.TestCase):
-    '''Tests for parse_options.''' 
+    '''Tests for parse_options.'''
 
     @classmethod
     def setUpClass(cls):
@@ -43,7 +48,7 @@
            We want to sub out the is_multihomed() function from
            installadm_common because it calls into the installadm-common.sh
            script which is part of the installadm pkg and that pkg may not
-           be installed on the system running the unit tests. 
+           be installed on the system running the unit tests.
         '''
         cls.com_ismultihomed = com.is_multihomed
         com.is_multihomed = lambda: False
@@ -119,5 +124,106 @@
                           "pkg:/install-image/solaris-auto-install")
 
 
+class CreateTestService(unittest.TestCase):
+    '''Tests for install service set up.'''
+
+    def setUp(self):
+        '''unit test set up'''
+        self.svc_name = 'my-test-service'
+        self.image_path = tempfile.mkdtemp(dir="/tmp")
+        self.image_info = {'image_version': '3.0', 'grub_min_mem64': '0',
+                           'service_name': 'solaris11u1-i386-05',
+                           'grub_do_safe_default': 'true',
+                           'grub_title': 'Oracle Solaris 11',
+                           'image_size': '744619',
+                           'no_install_grub_title': 'Oracle Solaris 11'}
+        self.srv_address = '$serverIP:5555'
+        self.menu_path = self.image_path
+        self.bootargs = ''
+
+    def tearDown(self):
+        '''teardown'''
+        if os.path.exists(self.image_path):
+            shutil.rmtree(self.image_path)
+
+    def test_menu_permissions(self):
+        '''Ensure that menu.lst is created with correct permissions'''
+
+        # save original umask
+        orig_umask = os.umask(0022)
+        # set too restrictive and too open umask
+        for mask in (0066, 0000):
+            os.umask(mask)
+            grub.setup_grub(self.svc_name, self.image_path, self.image_info,
+                self.srv_address, self.menu_path, self.bootargs)
+            mode = os.stat(self.menu_path + '/' + 'menu.lst').st_mode
+            self.assertEqual(mode, 0100644)
+        # return umask to the original value
+        os.umask(orig_umask)
+
+
+class DHCPServerTest(unittest.TestCase):
+    '''Tests for interaction with ISC DHCP server.'''
+
+    def setUp(self):
+        '''Create test instance of dhcp SMF service'''
+
+        # save the original svc name of dhcp SMF service instance
+        self.dhcp_srv_orig = dhcp.DHCP_SERVER_IPV4_SVC
+        self.dhcp_srv = "svc:/network/dhcp/server"
+        # name of our test instance
+        self.instance_name = "ai-unittest"
+        self.dhcp_srv_inst = self.dhcp_srv + ':' + self.instance_name
+        self.dhcp_dir = tempfile.mkdtemp(dir="/tmp")
+
+        # redefine DHCP_SERVER_IPV4_SVC to our test SMF service
+        dhcp.DHCP_SERVER_IPV4_SVC = self.dhcp_srv_inst
+        # construct list of svccfg commands
+        cmds = list()
+        # create new instance of dhcp service
+        cmds.append([dhcp.SVCCFG, "-s", self.dhcp_srv,
+            "add", self.instance_name])
+        svccmd = [dhcp.SVCCFG, "-s", self.dhcp_srv_inst]
+        # add config property group
+        cmds.append(svccmd + ["addpg config application"])
+        # set test config file
+        cmds.append(svccmd + ["setprop config/config_file = astring: " +
+            self.dhcp_dir + "/dhcpd4.conf"])
+        # set lease file
+        cmds.append(svccmd + ["setprop config/lease_file = astring: " +
+            self.dhcp_dir + "/dhcpd4.leases"])
+        # general/complete must be set-up
+        cmds.append(svccmd + ["addpg general framework"])
+        cmds.append(svccmd + ['setprop general/complete = astring: ""'])
+        # disable service
+        cmds.append([dhcp.SVCADM, "disable", self.dhcp_srv_inst])
+
+        for cmd in cmds:
+            Popen.check_call(cmd)
+
+    def tearDown(self):
+        '''Delete test instance of dhcp SMF service'''
+        cmd = [dhcp.SVCCFG, "delete", self.dhcp_srv_inst]
+        Popen.check_call(cmd)
+        dhcp.DHCP_SERVER_IPV4_SVC = self.dhcp_srv_orig
+        if os.path.exists(self.dhcp_dir):
+            shutil.rmtree(self.dhcp_dir)
+
+    def test_permissions(self):
+        '''Test correct permissions of dhcpd4.conf'''
+
+        dhcpsrv = dhcp.DHCPServer()
+        dhcpsrv.add_arch_class('i386', 'some-test-string')
+        # save original umask
+        orig_umask = os.umask(0022)
+        # set too restrictive and too open umask
+        for mask in (0066, 0000):
+            os.umask(mask)
+            dhcpsrv.update_bootfile_for_arch('i386', 'some-other-test-string')
+            mode = os.stat(self.dhcp_dir + '/' + 'dhcpd4.conf').st_mode
+            self.assertEqual(mode, 0100644)
+        # return umask to the original value
+        os.umask(orig_umask)
+
 if __name__ == '__main__':
     unittest.main()
--- a/usr/src/cmd/installadm/test/test_service_config.py	Tue Jan 10 14:31:15 2012 -0800
+++ b/usr/src/cmd/installadm/test/test_service_config.py	Fri Jan 13 10:23:52 2012 +0100
@@ -19,7 +19,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 #
 
 '''
@@ -37,7 +37,7 @@
 
 
 class ServiceConfig(unittest.TestCase):
-    '''Tests for service_config''' 
+    '''Tests for service_config'''
 
     @classmethod
     def setUpClass(cls):
@@ -118,8 +118,8 @@
         config._write_service_config('s5', props)
         services = config.get_all_service_names()
         self.assertEqual(len(services), 5)
-        self.assertTrue('s1' in services and 's2' in services and 
-                        's3' in services and 's4' in services and 
+        self.assertTrue('s1' in services and 's2' in services and
+                        's3' in services and 's4' in services and
                         's5' in services)
 
     def test_get_all_service_props(self):
@@ -134,7 +134,7 @@
         self.assertEqual(all_props['s1'], {'version': config.CURRENT_VERSION,
                          'hot': 'fudge'})
         self.assertEqual(all_props['s2'], {'version': config.CURRENT_VERSION,
-                         'ice': 'cream'}) 
+                         'ice': 'cream'})
         self.assertEqual(all_props['s3'], {'version': config.CURRENT_VERSION,
                          'apple': 'pie'})
 
@@ -177,7 +177,6 @@
         self.assertRaises(config.ServiceCfgError,
                           config.verify_key_properties, 's1', props)
 
-
         props = {config.PROP_SERVICE_NAME: 's1',
                  config.PROP_STATUS: config.STATUS_ON,
                  config.PROP_TXT_RECORD: 'aiwebserver=ais:5555'}
@@ -208,7 +207,7 @@
         self.assertTrue(aliased == ['alias1'])
         aliased = config.get_aliased_services('base1', recurse=True)
         self.assertTrue(aliased == ['alias1', 'alias2'])
-        
+
     def test_clients(self):
         '''test clients'''
 
@@ -230,12 +229,28 @@
         self.assertEqual(clientdict.keys(), ['01AABBCCDDAABB',
                                              '01AAAAAAAAAAAA'])
         self.assertEqual(clientdict['01AAAAAAAAAAAA'][config.FILES],
-                         ['/tmp/aaa', '/tmp/AAA'] )
+                         ['/tmp/aaa', '/tmp/AAA'])
 
         config.remove_client_from_config('s1', '01AABBCCDDAABB')
         clientdict = config.get_clients('s1')
         self.assertTrue('01AABBCCDDAABB' not in clientdict)
 
+    def test_configfile_permissions(self):
+        '''test permissions of .config file'''
+
+        svc = 'permtestsvc'
+        props = {'french': 'fries', 'banana': 'split'}
+        # save original umask
+        orig_umask = os.umask(0022)
+        # set too restrictive and too open umask
+        for mask in (0066, 0000):
+            os.umask(mask)
+            config._write_service_config(svc, props)
+            path = config._get_configfile_path(svc)
+            mode = os.stat(path).st_mode
+            self.assertEqual(mode, 0100644)
+        # return umask to the original value
+        os.umask(orig_umask)
 
 if __name__ == '__main__':
     unittest.main()