mirror of
https://github.com/munki/munki.git
synced 2026-04-24 05:49:42 -05:00
Merge: Verify permissions of preflight and postflight scripts are secure before; skip execution of insecure skips but continue Munki run.
git-svn-id: http://munki.googlecode.com/svn/trunk@738 a4e17f2e-e282-11dd-95e1-755cbddbdd66
This commit is contained in:
@@ -278,13 +278,20 @@ def runPreOrPostFlightScript(script, runtype='custom'):
|
||||
Args:
|
||||
script: string path to the pre/postflight script to execute.
|
||||
runtype: string mode managedsoftwareupdate was executed with.
|
||||
For more info see
|
||||
For more info see
|
||||
http://code.google.com/p/munki/wiki/PreflightAndPostflightScripts
|
||||
|
||||
Returns:
|
||||
Integer exit status from preflight or postflight script.
|
||||
"""
|
||||
if os.path.exists(script):
|
||||
try:
|
||||
munkicommon.verifyFileOnlyWritableByMunkiAndRoot(script)
|
||||
except munkicommon.VerifyFilePermissionsError, e:
|
||||
msg = ("Skipping execution due to failed file permissions "
|
||||
"verification: %s\n%s" % (script, str(e)))
|
||||
munkicommon.display_warning(msg)
|
||||
return 0 # preflight/postflight does not get run
|
||||
if os.access(script, os.X_OK):
|
||||
munkicommon.log('Running %s with runtype: %s...' %
|
||||
(script, runtype))
|
||||
|
||||
@@ -25,6 +25,7 @@ Common functions used by the munki tools.
|
||||
import hashlib
|
||||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -37,6 +38,18 @@ import munkistatus
|
||||
import FoundationPlist
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
"""Class for domain specific exceptions."""
|
||||
|
||||
|
||||
class VerifyFilePermissionsError(Error):
|
||||
"""There was an error verifying file permissions."""
|
||||
|
||||
|
||||
class InsecureFilePermissionsError(VerifyFilePermissionsError):
|
||||
"""The permissions of the specified file are insecure."""
|
||||
|
||||
|
||||
def get_version():
|
||||
'''Returns version of munkitools'''
|
||||
return "0.6.0 Build 709"
|
||||
@@ -973,7 +986,7 @@ def getInstalledPackageVersion(pkgid):
|
||||
try:
|
||||
plist = FoundationPlist.readPlistFromString(out)
|
||||
except FoundationPlist.NSPropertyListSerializationException:
|
||||
pass
|
||||
pass
|
||||
else:
|
||||
foundbundleid = plist.get("pkgid")
|
||||
foundvers = plist.get("pkg-version","0.0.0.0.0")
|
||||
@@ -1128,6 +1141,44 @@ def getPackageMetaData(pkgitem):
|
||||
|
||||
# some utility functions
|
||||
|
||||
|
||||
def verifyFileOnlyWritableByMunkiAndRoot(file_path):
|
||||
"""
|
||||
Check the permissions on a given file path; fail if owner or group
|
||||
does not match the munki process (default: root/admin) or the group is not
|
||||
"wheel", or if other users are able to write to the file. This prevents
|
||||
escalated execution of arbitrary code.
|
||||
|
||||
Args:
|
||||
file_path: str path of file to verify permissions on.
|
||||
Raises:
|
||||
VerifyFilePermissionsError: there was an error verifying file permissions.
|
||||
InsecureFilePermissionsError: file permissions were found to be insecure.
|
||||
"""
|
||||
try:
|
||||
file_stat = os.stat(file_path)
|
||||
except OSError, e:
|
||||
raise VerifyFilePermissionsError(
|
||||
'%s does not exist. \n %s' % (file_path, str(e)))
|
||||
|
||||
try:
|
||||
# verify the munki process uid matches the file owner uid.
|
||||
if os.geteuid() != file_stat.st_uid:
|
||||
raise InsecureFilePermissionsError(
|
||||
'owner does not match munki process!')
|
||||
# verify the munki process gid matches the file owner gid, or the file
|
||||
# owner gid is 80 (which is the admin group root is a member of).
|
||||
elif os.getegid() != file_stat.st_gid and file_stat.st_gid != 80:
|
||||
raise InsecureFilePermissionsError(
|
||||
'group does not match munki process!')
|
||||
# verify other users cannot write to the file.
|
||||
elif file_stat.st_mode & stat.S_IWOTH!= 0:
|
||||
raise InsecureFilePermissionsError('world writable!')
|
||||
except InsecureFilePermissionsError, e:
|
||||
raise InsecureFilePermissionsError(
|
||||
'%s is not secure! %s' % (file_path, e.args[0]))
|
||||
|
||||
|
||||
def getAvailableDiskSpace(volumepath="/"):
|
||||
'''Returns available diskspace in KBytes.'''
|
||||
cmd = ["/usr/sbin/diskutil", "info", "-plist", volumepath]
|
||||
|
||||
Reference in New Issue
Block a user