Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Pepijn Bruienne
2016-03-17 14:07:20 -04:00
80 changed files with 483 additions and 1642 deletions

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2010-2014 Greg Neagle.
# Copyright 2010-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2010-2014 Greg Neagle.
# Copyright 2010-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2011-2014 Greg Neagle.
# Copyright 2011-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# encoding: utf-8
#
# Copyright 2009-2014 Greg Neagle.
# Copyright 2009-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2008-2014 Greg Neagle.
# Copyright 2008-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2009-2014 Greg Neagle.
# Copyright 2009-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
@@ -634,7 +634,7 @@ def main():
munkicommon.log("### Starting managedsoftwareupdate run: %s ###" % runtype)
if options.verbose:
print 'Managed Software Update Tool'
print 'Copyright 2010-2014 The Munki Project'
print 'Copyright 2010-2016 The Munki Project'
print 'https://github.com/munki/munki\n'
munkicommon.display_status_major('Starting...')
@@ -710,6 +710,7 @@ def main():
if options.manualcheck:
# record our result
recordUpdateCheckResult(-1)
if options.munkistatusoutput:
# connect to socket and quit
munkistatus.activate()
munkistatus.quit()

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2011-2014 Greg Neagle.
# Copyright 2011-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2010-2014 Greg Neagle.
# Copyright 2010-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2009-2014 Greg Neagle.
# Copyright 2009-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -7,7 +7,7 @@ Utilities to enable munki to install/uninstall Adobe CS3/CS4/CS5 products
using the CS3/CS4/CS5 Deployment Toolkits.
"""
# Copyright 2009-2014 Greg Neagle.
# Copyright 2009-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -6,7 +6,7 @@ appleupdates.py
Utilities for dealing with Apple Software Update.
"""
# Copyright 2009-2015 Greg Neagle.
# Copyright 2009-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -1610,7 +1610,7 @@ class AppleUpdates(object):
if key in metadata_to_copy and metadata[key]:
if key == 'RestartAction':
# Ensure that a heavier weighted 'RestartAction' is not
# overriden by one supplied in metadata
# overridden by one supplied in metadata
if metadata[key] not in RestartActions.get(
item.get(key, 'None')):
munkicommon.display_debug2(

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2011-2014 Greg Neagle.
# Copyright 2011-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2009-2014 Greg Neagle.
# Copyright 2009-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
gurl.py
Created by Greg Neagle on 2013-11-21.
Modified in Feb 2016 to add support for NSURLSession.
curl replacement using NSURLConnection and friends
"""
@@ -32,22 +33,63 @@ from objc import super
# PyLint cannot properly find names inside Cocoa libraries, so issues bogus
# No name 'Foo' in module 'Bar' warnings. Disable them.
# pylint: disable=E0611
from Foundation import NSBundle
from Foundation import NSRunLoop, NSDate
from Foundation import NSObject, NSURL, NSURLConnection
from Foundation import NSMutableURLRequest
from Foundation import NSURLRequestReloadIgnoringLocalCacheData
from Foundation import NSURLResponseUnknownLength
from Foundation import NSLog
from Foundation import NSURLCredential, NSURLCredentialPersistenceNone
from Foundation import NSPropertyListSerialization
from Foundation import NSPropertyListMutableContainersAndLeaves
from Foundation import NSPropertyListXMLFormat_v1_0
# pylint: enable=E0611
from Foundation import NSBundle, \
NSRunLoop, NSDate, \
NSObject, NSURL, NSURLConnection, \
NSMutableURLRequest, \
NSURLRequestReloadIgnoringLocalCacheData, \
NSURLResponseUnknownLength, \
NSLog, \
NSURLCredential, NSURLCredentialPersistenceNone, \
NSPropertyListSerialization, \
NSPropertyListMutableContainersAndLeaves, \
NSPropertyListXMLFormat_v1_0
try:
from Foundation import NSURLSession, NSURLSessionConfiguration
NSURLSESSION_AVAILABLE = True
except ImportError:
NSURLSESSION_AVAILABLE = False
# Disable PyLint complaining about 'invalid' names
# pylint: disable=C0103
if NSURLSESSION_AVAILABLE:
# NSURLSessionAuthChallengeDisposition enum constants
NSURLSessionAuthChallengeUseCredential = 0
NSURLSessionAuthChallengePerformDefaultHandling = 1
NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2
NSURLSessionAuthChallengeRejectProtectionSpace = 3
# NSURLSessionResponseDisposition enum constants
NSURLSessionResponseCancel = 0
NSURLSessionResponseAllow = 1
NSURLSessionResponseBecomeDownload = 2
# TLS/SSLProtocol enum constants
kSSLProtocolUnknown = 0
kSSLProtocol3 = 2
kTLSProtocol1 = 4
kTLSProtocol11 = 7
kTLSProtocol12 = 8
kDTLSProtocol1 = 9
# define a helper function for block callbacks
import ctypes
import objc
_objc_so = ctypes.cdll.LoadLibrary(
os.path.join(objc.__path__[0], '_objc.so'))
PyObjCMethodSignature_WithMetaData = (
_objc_so.PyObjCMethodSignature_WithMetaData)
PyObjCMethodSignature_WithMetaData.restype = ctypes.py_object
def objc_method_signature(signature_str):
'''Return a PyObjCMethodSignature given a call signature in string
format'''
return PyObjCMethodSignature_WithMetaData(
ctypes.create_string_buffer(signature_str), None, False)
# pylint: enable=E0611
# disturbing hack warning!
# this works around an issue with App Transport Security on 10.11
@@ -56,6 +98,11 @@ info = bundle.localizedInfoDictionary() or bundle.infoDictionary()
info['NSAppTransportSecurity'] = {'NSAllowsArbitraryLoads': True}
def NSLogWrapper(message):
'''A wrapper function for NSLog to prevent format string errors'''
NSLog('%@', message)
ssl_error_codes = {
-9800: u'SSL protocol error',
-9801: u'Cipher Suite negotiation failure',
@@ -111,7 +158,7 @@ ssl_error_codes = {
class Gurl(NSObject):
'''A class for getting content from a URL
using NSURLConnection and friends'''
using NSURLConnection/NSURLSession and friends'''
# since we inherit from NSObject, PyLint issues a few bogus warnings
# pylint: disable=W0232,E1002
@@ -139,8 +186,11 @@ class Gurl(NSObject):
'download_only_if_changed', False)
self.cache_data = options.get('cache_data')
self.connection_timeout = options.get('connection_timeout', 60)
if NSURLSESSION_AVAILABLE:
self.minimum_tls_protocol = options.get(
'minimum_tls_protocol', kTLSProtocol1)
self.log = options.get('logging_function', NSLog)
self.log = options.get('logging_function', NSLogWrapper)
self.resume = False
self.response = None
@@ -155,6 +205,8 @@ class Gurl(NSObject):
self.expectedLength = -1
self.percentComplete = 0
self.connection = None
self.session = None
self.task = None
return self
def start(self):
@@ -189,18 +241,34 @@ class Gurl(NSObject):
if 'etag' in stored_data:
request.setValue_forHTTPHeaderField_(
stored_data['etag'], 'if-none-match')
self.connection = NSURLConnection.alloc().initWithRequest_delegate_(
request, self)
if NSURLSESSION_AVAILABLE:
configuration = \
NSURLSessionConfiguration.defaultSessionConfiguration()
# set minumum supported TLS protocol (defaults to TLS1)
configuration.setTLSMinimumSupportedProtocol_(
self.minimum_tls_protocol)
self.session = \
NSURLSession.sessionWithConfiguration_delegate_delegateQueue_(
configuration, self, None)
self.task = self.session.dataTaskWithRequest_(request)
self.task.resume()
else:
self.connection = NSURLConnection.alloc().initWithRequest_delegate_(
request, self)
def cancel(self):
'''Cancel the connection'''
if self.connection:
self.connection.cancel()
if NSURLSESSION_AVAILABLE:
self.session.invalidateAndCancel()
else:
self.connection.cancel()
self.done = True
def isDone(self):
'''Check if the connection request is complete. As a side effect,
allow the delegates to work my letting the run loop run for a bit'''
allow the delegates to work by letting the run loop run for a bit'''
if self.done:
return self.done
# let the delegates do their thing
@@ -255,13 +323,8 @@ class Gurl(NSObject):
new_dict[key.lower()] = value
return new_dict
def connection_didFailWithError_(self, connection, error):
'''NSURLConnection delegate method
Sent when a connection fails to load its request successfully.'''
# we don't actually use the connection argument, so
# pylint: disable=W0613
def recordError_(self, error):
'''Record any error info from completed connection/session'''
self.error = error
# If this was an SSL error, try to extract the SSL error code.
if 'NSUnderlyingError' in error.userInfo():
@@ -270,13 +333,40 @@ class Gurl(NSObject):
if ssl_code:
self.SSLerror = (ssl_code, ssl_error_codes.get(
ssl_code, 'Unknown SSL error'))
def removeExpectedSizeFromStoredHeaders(self):
'''If a successful transfer, clear the expected size so we
don\'t attempt to resume the download next time'''
if str(self.status).startswith('2'):
# remove the expected-size from the stored headers
headers = self.get_stored_headers()
if 'expected-length' in headers:
del headers['expected-length']
self.store_headers(headers)
def URLSession_task_didCompleteWithError_(self, session, task, error):
'''NSURLSessionTaskDelegate method.'''
# we don't actually use the session or task arguments, so
# pylint: disable=W0613
if self.destination and self.destination_path:
self.destination.close()
self.removeExpectedSizeFromStoredHeaders()
if error:
self.recordError_(error)
self.done = True
def connection_didFailWithError_(self, connection, error):
'''NSURLConnectionDelegate method
Sent when a connection fails to load its request successfully.'''
# we don't actually use the connection argument, so
# pylint: disable=W0613
self.recordError_(error)
self.done = True
if self.destination and self.destination_path:
self.destination.close()
# delete it? Might not want to...
def connectionDidFinishLoading_(self, connection):
'''NSURLConnectionDataDelegat delegate method
'''NSURLConnectionDataDelegate method
Sent when a connection has finished loading successfully.'''
# we don't actually use the connection argument, so
@@ -285,18 +375,11 @@ class Gurl(NSObject):
self.done = True
if self.destination and self.destination_path:
self.destination.close()
if str(self.status).startswith('2'):
# remove the expected-size from the stored headers
headers = self.get_stored_headers()
if 'expected-length' in headers:
del headers['expected-length']
self.store_headers(headers)
def connection_didReceiveResponse_(self, connection, response):
'''NSURLConnectionDataDelegate delegate method
Sent when the connection has received sufficient data to construct the
URL response for its request.'''
self.removeExpectedSizeFromStoredHeaders()
def handleResponse_withCompletionHandler_(
self, response, completionHandler):
'''Handle the response to the connection'''
self.response = response
self.bytesReceived = 0
self.percentComplete = -1
@@ -330,7 +413,12 @@ class Gurl(NSObject):
# we have a partial for
self.log(
'Can\'t resume download; file on server has changed.')
connection.cancel()
if completionHandler:
# tell the session task to cancel
completionHandler(NSURLSessionResponseCancel)
else:
# cancel the connection
self.connection.cancel()
self.log('Removing %s' % self.destination_path)
os.unlink(self.destination_path)
# restart and attempt to download the entire file
@@ -355,85 +443,107 @@ class Gurl(NSObject):
# the downloadand for future checking if the file on the server
# has changed
self.store_headers(download_data)
if completionHandler:
# tell the session task to continue
completionHandler(NSURLSessionResponseAllow)
def connection_willSendRequest_redirectResponse_(
self, connection, request, response):
def URLSession_dataTask_didReceiveResponse_completionHandler_(
self, session, task, response, completionHandler):
'''NSURLSessionDataDelegate method'''
# we don't actually use the session or task arguments, so
# pylint: disable=W0613
completionHandler.__block_signature__ = objc_method_signature('v@i')
self.handleResponse_withCompletionHandler_(response, completionHandler)
def connection_didReceiveResponse_(self, connection, response):
'''NSURLConnectionDataDelegate delegate method
Sent when the connection determines that it must change URLs in order to
continue loading a request.'''
Sent when the connection has received sufficient data to construct the
URL response for its request.'''
# we don't actually use the connection argument, so
# pylint: disable=W0613
self.handleResponse_withCompletionHandler_(response, None)
def handleRedirect_newRequest_withCompletionHandler_(
self, response, request, completionHandler):
'''Handle the redirect request'''
if response == None:
# This isn't a real redirect, this is without talking to a server.
# Pass it back as-is
return request
# But if we're here, it appears to be a real redirect attempt
# the request has changed the NSURLRequest in order to standardize
# its format, for example, changing a request for
# http://www.apple.com to http://www.apple.com/. This occurs because
# the standardized, or canonical, version of the request is used for
# cache management. Pass the request back as-is
# (it appears that at some point Apple also defined a redirect like
# http://developer.apple.com to https://developer.apple.com to be
# 'merely' a change in the canonical URL.)
# Further -- it appears that this delegate method isn't called at
# all in this scenario, unlike NSConnectionDelegate method
# connection:willSendRequest:redirectResponse:
# we'll leave this here anyway in case we're wrong about that
if completionHandler:
completionHandler(request)
return
else:
return request
# If we get here, it appears to be a real redirect attempt
# Annoyingly, we apparently can't get access to the headers from the
# site that told us to redirect. All we know is that we were told
# to redirect and where the new location is.
newURL = request.URL().absoluteString()
self.redirection.append([newURL, dict(response.allHeaderFields())])
newParsedURL = urlparse(newURL)
# This code was largely based on the work of Andreas Fuchs
# This code was largely based on the work of Andreas Fuchs
# (https://github.com/munki/munki/pull/465)
if self.follow_redirects == True or self.follow_redirects == 'all':
# Allow the redirect
self.log('Allowing redirect to: %s' % newURL)
return request
elif self.follow_redirects == 'https' and newParsedURL.scheme == 'https':
if completionHandler:
completionHandler(request)
return
else:
return request
elif (self.follow_redirects == 'https'
and newParsedURL.scheme == 'https'):
# Once again, allow the redirect
self.log('Allowing redirect to: %s' % newURL)
return request
if completionHandler:
completionHandler(request)
return
else:
return request
else:
# If we're down here either the preference was set to 'none',
# the url we're forwarding on to isn't https or follow_redirects
# was explicitly set to False
self.log('Denying redirect to: %s' % newURL)
return None
if completionHandler:
completionHandler(None)
return
else:
return None
def connection_willSendRequestForAuthenticationChallenge_(
self, connection, challenge):
'''NSURLConnection delegate method
Tells the delegate that the connection will send a request for an
authentication challenge.
New in 10.7.'''
def URLSession_task_willPerformHTTPRedirection_newRequest_completionHandler_(
self, session, task, response, request, completionHandler):
'''NSURLSessionTaskDelegate method'''
# we don't actually use the session or task arguments, so
# pylint: disable=W0613
self.log(
'URLSession_task_willPerformHTTPRedirection_newRequest_'
'completionHandler_')
completionHandler.__block_signature__ = objc_method_signature('v@@')
self.handleRedirect_newRequest_withCompletionHandler_(
response, request, completionHandler)
def connection_willSendRequest_redirectResponse_(
self, connection, request, response):
'''NSURLConnectionDataDelegate method
Sent when the connection determines that it must change URLs in order to
continue loading a request.'''
# we don't actually use the connection argument, so
# pylint: disable=W0613
self.log('connection_willSendRequestForAuthenticationChallenge_')
protectionSpace = challenge.protectionSpace()
host = protectionSpace.host()
realm = protectionSpace.realm()
authenticationMethod = protectionSpace.authenticationMethod()
self.log(
'Authentication challenge for Host: %s Realm: %s AuthMethod: %s'
% (host, realm, authenticationMethod))
if challenge.previousFailureCount() > 0:
# we have the wrong credentials. just fail
self.log('Previous authentication attempt failed.')
challenge.sender().cancelAuthenticationChallenge_(challenge)
if self.username and self.password and authenticationMethod in [
'NSURLAuthenticationMethodDefault',
'NSURLAuthenticationMethodHTTPBasic',
'NSURLAuthenticationMethodHTTPDigest']:
self.log('Will attempt to authenticate.')
self.log('Username: %s Password: %s'
% (self.username, ('*' * len(self.password or ''))))
credential = (
NSURLCredential.credentialWithUser_password_persistence_(
self.username, self.password,
NSURLCredentialPersistenceNone))
challenge.sender().useCredential_forAuthenticationChallenge_(
credential, challenge)
else:
# fall back to system-provided default behavior
self.log('Allowing OS to handle authentication request')
challenge.sender(
).performDefaultHandlingForAuthenticationChallenge_(
challenge)
self.log('connection_willSendRequest_redirectResponse_')
return self.handleRedirect_newRequest_withCompletionHandler_(
response, request, None)
def connection_canAuthenticateAgainstProtectionSpace_(
self, connection, protectionSpace):
@@ -464,17 +574,9 @@ class Gurl(NSObject):
self.log('Allowing OS to handle authentication request')
return False
def connection_didReceiveAuthenticationChallenge_(
self, connection, challenge):
'''NSURLConnection delegate method
Sent when a connection must authenticate a challenge in order to
download its request.
Deprecated in 10.10'''
# we don't actually use the connection argument, so
# pylint: disable=W0613
self.log('connection_didReceiveAuthenticationChallenge_')
def handleChallenge_withCompletionHandler_(
self, challenge, completionHandler):
'''Handle an authentication challenge'''
protectionSpace = challenge.protectionSpace()
host = protectionSpace.host()
realm = protectionSpace.realm()
@@ -485,7 +587,12 @@ class Gurl(NSObject):
if challenge.previousFailureCount() > 0:
# we have the wrong credentials. just fail
self.log('Previous authentication attempt failed.')
challenge.sender().cancelAuthenticationChallenge_(challenge)
if completionHandler:
completionHandler(
NSURLSessionAuthChallengeCancelAuthenticationChallenge,
None)
else:
challenge.sender().cancelAuthenticationChallenge_(challenge)
if self.username and self.password and authenticationMethod in [
'NSURLAuthenticationMethodDefault',
'NSURLAuthenticationMethodHTTPBasic',
@@ -497,22 +604,65 @@ class Gurl(NSObject):
NSURLCredential.credentialWithUser_password_persistence_(
self.username, self.password,
NSURLCredentialPersistenceNone))
challenge.sender().useCredential_forAuthenticationChallenge_(
credential, challenge)
if completionHandler:
completionHandler(
NSURLSessionAuthChallengeUseCredential, credential)
else:
challenge.sender().useCredential_forAuthenticationChallenge_(
credential, challenge)
else:
# fall back to system-provided default behavior
self.log('Continuing without credential.')
challenge.sender(
).continueWithoutCredentialForAuthenticationChallenge_(
challenge)
def connection_didReceiveData_(self, connection, data):
'''NSURLConnectionDataDelegate method
Sent as a connection loads data incrementally'''
self.log('Allowing OS to handle authentication request')
if completionHandler:
completionHandler(
NSURLSessionAuthChallengePerformDefaultHandling, None)
else:
if (challenge.sender().respondsToSelector_(
'performDefaultHandlingForAuthenticationChallenge:')):
self.log('Allowing OS to handle authentication request')
challenge.sender(
).performDefaultHandlingForAuthenticationChallenge_(
challenge)
else:
# Mac OS X 10.6 doesn't support
# performDefaultHandlingForAuthenticationChallenge:
self.log('Continuing without credential.')
challenge.sender(
).continueWithoutCredentialForAuthenticationChallenge_(
challenge)
def connection_willSendRequestForAuthenticationChallenge_(
self, connection, challenge):
'''NSURLConnection delegate method
Tells the delegate that the connection will send a request for an
authentication challenge. New in 10.7.'''
# we don't actually use the connection argument, so
# pylint: disable=W0613
self.log('connection_willSendRequestForAuthenticationChallenge_')
self.handleChallenge_withCompletionHandler_(challenge, None)
def URLSession_task_didReceiveChallenge_completionHandler_(
self, session, task, challenge, completionHandler):
'''NSURLSessionTaskDelegate method'''
# we don't actually use the session or task arguments, so
# pylint: disable=W0613
completionHandler.__block_signature__ = objc_method_signature('v@i@')
self.log('URLSession_task_didReceiveChallenge_completionHandler_')
self.handleChallenge_withCompletionHandler_(
challenge, completionHandler)
def connection_didReceiveAuthenticationChallenge_(
self, connection, challenge):
'''NSURLConnection delegate method
Sent when a connection must authenticate a challenge in order to
download its request. Deprecated in 10.10'''
# we don't actually use the connection argument, so
# pylint: disable=W0613
self.log('connection_didReceiveAuthenticationChallenge_')
self.handleChallenge_withCompletionHandler_(challenge, None)
def handleReceivedData_(self, data):
'''Handle received data'''
if self.destination:
self.destination.write(str(data))
else:
@@ -521,3 +671,16 @@ class Gurl(NSObject):
if self.expectedLength != NSURLResponseUnknownLength:
self.percentComplete = int(
float(self.bytesReceived)/float(self.expectedLength) * 100.0)
def URLSession_dataTask_didReceiveData_(self, session, task, data):
'''NSURLSessionDataDelegate method'''
# we don't actually use the session or task arguments, so
# pylint: disable=W0613
self.handleReceivedData_(data)
def connection_didReceiveData_(self, connection, data):
'''NSURLConnectionDataDelegate method
Sent as a connection loads data incrementally'''
# we don't actually use the connection argument, so
# pylint: disable=W0613
self.handleReceivedData_(data)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2010-2014 Greg Neagle.
# Copyright 2010-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2009-2014 Greg Neagle.
# Copyright 2009-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -467,7 +467,7 @@ def copyItemsFromMountpoint(mountpoint, itemlist):
# all tests passed, OK to copy
munkicommon.display_status_minor(
"Copying %s to %s" % (source_itemname, full_destpath))
retcode = subprocess.call(["/bin/cp", "-pR",
retcode = subprocess.call(["/usr/bin/ditto", "--noqtn",
source_itempath, full_destpath])
if retcode:
munkicommon.display_error(
@@ -506,20 +506,6 @@ def copyItemsFromMountpoint(mountpoint, itemlist):
"Error setting mode for %s" % (full_destpath))
return retcode
# remove com.apple.quarantine attribute from copied item
cmd = ["/usr/bin/xattr", full_destpath]
proc = subprocess.Popen(cmd, shell=False, bufsize=-1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(out, dummy_err) = proc.communicate()
if out:
xattrs = str(out).splitlines()
if "com.apple.quarantine" in xattrs:
dummy_result = subprocess.call(
["/usr/bin/xattr", "-d", "com.apple.quarantine",
full_destpath])
# all items copied successfully!
return 0

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2014 Greg Neagle.
# Copyright 2014-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2011-2014 Greg Neagle.
# Copyright 2011-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2009-2014 Greg Neagle.
# Copyright 2009-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2009-2014 Greg Neagle.
# Copyright 2009-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2014 Greg Neagle.
# Copyright 2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2009-2014 Greg Neagle.
# Copyright 2009-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -335,7 +335,7 @@ def ImportBom(bompath, curs):
package database into our internal package database.
"""
# If we completely trusted the accuracy of Apple's database, we wouldn't
# need the bom files, but in my enviroment at least, the bom files are
# need the bom files, but in my environment at least, the bom files are
# a better indicator of what flat packages have actually been installed
# on the current machine.
# We still need to consult Apple's package database

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2009-2014 Greg Neagle.
# Copyright 2009-2016 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
@@ -1467,7 +1467,7 @@ def lookForUpdates(itemname, cataloglist):
update_list = []
for catalogname in cataloglist:
if not catalogname in CATALOG.keys():
# in case the list refers to a non-existant catalog
# in case the list refers to a non-existent catalog
continue
updaters = CATALOG[catalogname]['updaters']
@@ -1925,7 +1925,7 @@ def processInstall(manifestitem, cataloglist, installinfo):
iteminfo[key] = item_pl[key]
if not 'apple_item' in iteminfo:
# admin did not explictly mark this item; let's determine if
# admin did not explicitly mark this item; let's determine if
# it's from Apple
if isAppleItem(item_pl):
munkicommon.log("Marking %s as apple_item - this may affect \
@@ -2370,7 +2370,7 @@ def processRemoval(manifestitem, cataloglist, installinfo):
iteminfo[key] = uninstall_item[key]
if not 'apple_item' in iteminfo:
# admin did not explictly mark this item; let's determine if
# admin did not explicitly mark this item; let's determine if
# it's from Apple
if isAppleItem(item_pl):
iteminfo['apple_item'] = True
@@ -2892,7 +2892,7 @@ def download_icons(item_list):
def download_client_resources():
"""Download client customization resources (if any)."""
# Munki's preferences can specify an explict name
# Munki's preferences can specify an explicit name
# under ClientResourcesFilename
# if that doesn't exist, use the primary manifest name as the
# filename. If that fails, try site_default.zip

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2010-2013 Google Inc. All Rights Reserved.
# Copyright 2010-2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@ Created by Justin McWilliams on 2010-10-26.
Common utility functions used throughout Munki.
Note: this module should be 100% free of ObjC-dependant Python imports.
Note: this module should be 100% free of ObjC-dependent Python imports.
"""

View File

@@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>CFBundleShortVersionString</key>
<string>2.5.1</string>
<string>2.6.0</string>
</dict>
</plist>

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2011-2013 Google Inc. All Rights Reserved.
# Copyright 2011-2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.