def import_middleware(): '''Check munki folder for a python file that starts with 'middleware'. If the file exists and has a callable 'process_request_options' attribute, the module is loaded under the 'middleware' name''' required_function_name = 'process_request_options' munki_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) for filename in os.listdir(munki_dir): if (filename.startswith('middleware') and os.path.splitext(filename)[1] == '.py'): name = os.path.splitext(filename)[0] filepath = os.path.join(munki_dir, filename) _tmp = imp.load_source(name, filepath) if hasattr(_tmp, required_function_name): if callable(getattr(_tmp, required_function_name)): munkicommon.display_debug1( 'Loading middleware module %s' % filename) globals()['middleware'] = _tmp return else: munkicommon.display_warning( '%s attribute in %s is not callable.' % (required_function_name, filepath)) munkicommon.display_warning('Ignoring %s' % filepath) else: munkicommon.display_warning( '%s does not have a %s function' % (filepath, required_function_name)) munkicommon.display_warning('Ignoring %s' % filepath) return
def remove_from_keychain_list(keychain_path): '''Remove keychain from the list of keychains''' # we use *foo to expand a list of keychain paths # pylint: disable=W0142 output = security('list-keychains', '-d', 'user') # Split the output and strip it of whitespace and leading/trailing # quotes, the result are absolute paths to keychains # Preserve the order in case we need to append to them search_keychains = [ x.strip().strip('"') for x in output.split('\n') if x.strip() ] if keychain_path in search_keychains: # Keychain is in the search path munkicommon.display_debug1('Removing %s from search path...', keychain_path) filtered_keychains = [ keychain for keychain in search_keychains if keychain != keychain_path ] try: output = security('list-keychains', '-d', 'user', '-s', *filtered_keychains) if output: munkicommon.display_debug2(output) except SecurityError, err: munkicommon.display_error('Could not set new keychain list: %s', err)
def import_middleware(): '''Check munki folder for a python file that starts with 'middleware'. If the file exists and has a callable 'process_request_options' attribute, the module is loaded under the 'middleware' name''' required_function_name = 'process_request_options' munki_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) for filename in os.listdir(munki_dir): if (filename.startswith('middleware') and os.path.splitext(filename)[1] == '.py'): name = os.path.splitext(filename)[0] filepath = os.path.join(munki_dir, filename) _tmp = imp.load_source(name, filepath) if hasattr(_tmp, required_function_name): if callable(getattr(_tmp, required_function_name)): munkicommon.display_debug1('Loading middleware module %s' % filename) globals()['middleware'] = _tmp return else: munkicommon.display_warning( '%s attribute in %s is not callable.' % (required_function_name, filepath)) munkicommon.display_warning('Ignoring %s' % filepath) else: munkicommon.display_warning('%s does not have a %s function' % (filepath, required_function_name)) munkicommon.display_warning('Ignoring %s' % filepath) return
def remove_from_keychain_list(keychain_path): '''Remove keychain from the list of keychains''' # we use *foo to expand a list of keychain paths # pylint: disable=W0142 output = security('list-keychains', '-d', 'user') # Split the output and strip it of whitespace and leading/trailing # quotes, the result are absolute paths to keychains # Preserve the order in case we need to append to them search_keychains = [x.strip().strip('"') for x in output.split('\n') if x.strip()] if keychain_path in search_keychains: # Keychain is in the search path munkicommon.display_debug1( 'Removing %s from search path...', keychain_path) filtered_keychains = [keychain for keychain in search_keychains if keychain != keychain_path] try: output = security( 'list-keychains', '-d', 'user', '-s', *filtered_keychains) if output: munkicommon.display_debug2(output) except SecurityError, err: munkicommon.display_error( 'Could not set new keychain list: %s', err)
def add_ca_certs_to_system_keychain(certdata=None): '''Adds any CA certs as trusted root certs to System.keychain''' if not certdata: certdata = get_munki_server_cert_data() ca_cert_path = certdata['ca_cert_path'] ca_dir_path = certdata['ca_dir_path'] SYSTEM_KEYCHAIN = "/Library/Keychains/System.keychain" if not os.path.exists(SYSTEM_KEYCHAIN): munkicommon.display_warning('%s not found.', SYSTEM_KEYCHAIN) return if not ca_cert_path and not ca_dir_path: # no CA certs, so nothing to do munkicommon.display_debug2( 'No CA cert info provided, so nothing to add to System keychain.') return else: munkicommon.display_debug2('CA cert path: %s', ca_cert_path) munkicommon.display_debug2('CA dir path: %s', ca_dir_path) # Add CA certs. security add-trusted-cert does the right thing even if # the cert is already added, so we just do it; checking to see if the # cert is already added is hard. certs_to_add = [] if ca_cert_path: certs_to_add.append(ca_cert_path) if ca_dir_path: # add any pem files in the ca_dir_path directory for item in os.listdir(ca_dir_path): if item.endswith('.pem'): certs_to_add.append(os.path.join(ca_dir_path, item)) for cert in certs_to_add: munkicommon.display_debug1('Adding CA cert %s...', cert) try: output = security('add-trusted-cert', '-d', '-k', SYSTEM_KEYCHAIN, cert) if output: munkicommon.display_debug2(output) except SecurityError, err: munkicommon.display_error( 'Could not add CA cert %s into System keychain: %s', cert, err)
def add_ca_certs_to_system_keychain(cert_info=None): '''Adds any CA certs as trusted root certs to System.keychain''' if not cert_info: cert_info = get_munki_server_cert_info() ca_cert_path = cert_info['ca_cert_path'] ca_dir_path = cert_info['ca_dir_path'] if not ca_cert_path and not ca_dir_path: # no CA certs, so nothing to do munkicommon.display_debug2( 'No CA cert info provided, so nothing to add to System keychain.') return else: munkicommon.display_debug2('CA cert path: %s', ca_cert_path) munkicommon.display_debug2('CA dir path: %s', ca_dir_path) SYSTEM_KEYCHAIN = "/Library/Keychains/System.keychain" if not os.path.exists(SYSTEM_KEYCHAIN): munkicommon.display_warning('%s not found.', SYSTEM_KEYCHAIN) return # Add CA certs. security add-trusted-cert does the right thing even if # the cert is already added, so we just do it; checking to see if the # cert is already added is hard. certs_to_add = [] if ca_cert_path: certs_to_add.append(ca_cert_path) if ca_dir_path: # add any pem files in the ca_dir_path directory for item in os.listdir(ca_dir_path): if item.endswith('.pem'): certs_to_add.append(os.path.join(ca_dir_path, item)) for cert in certs_to_add: munkicommon.display_debug1('Adding CA cert %s...', cert) try: output = security('add-trusted-cert', '-d', '-k', SYSTEM_KEYCHAIN, cert) if output: munkicommon.display_debug2(output) except SecurityError, err: munkicommon.display_error( 'Could not add CA cert %s into System keychain: %s', cert, err)
def make_client_keychain(cert_info=None): '''Builds a client cert keychain from existing client certs''' if not cert_info: # just grab data from Munki's preferences/defaults cert_info = get_munki_client_cert_info() client_cert_path = cert_info['client_cert_path'] client_key_path = cert_info['client_key_path'] site_urls = cert_info['site_urls'] if not client_cert_path: # no client, so nothing to do munkicommon.display_debug1( 'No client cert info provided, ' 'so no client keychain will be created.') return else: munkicommon.display_debug1('Client cert path: %s', client_cert_path) munkicommon.display_debug1('Client key path: %s', client_key_path) # to do some of the following options correctly, we need to be root # and have root's home. # check to see if we're root if os.geteuid() != 0: munkicommon.display_error( 'Can\'t make our client keychain unless we are root!') return # switch HOME if needed to root's home original_home = os.environ.get('HOME') if original_home: os.environ['HOME'] = os.path.expanduser('~root') keychain_pass = ( munkicommon.pref('KeychainPassword') or DEFAULT_KEYCHAIN_PASSWORD) abs_keychain_path = get_keychain_path() if os.path.exists(abs_keychain_path): os.unlink(abs_keychain_path) if not os.path.exists(os.path.dirname(abs_keychain_path)): os.makedirs(os.path.dirname(abs_keychain_path)) # create a new keychain munkicommon.display_debug1('Creating client keychain...') try: output = security('create-keychain', '-p', keychain_pass, abs_keychain_path) if output: munkicommon.display_debug2(output) except SecurityError, err: munkicommon.display_error( 'Could not create keychain %s: %s', abs_keychain_path, err) if original_home: # switch it back os.environ['HOME'] = original_home return
def getpkgkeys(pkgnames): """ Given a list of receipt names, bom file names, or package ids, gets a list of pkg_keys from the pkgs table in our database. """ # open connection and cursor to our database conn = sqlite3.connect(packagedb) curs = conn.cursor() # check package names to make sure they're all in the database, # build our list of pkg_keys pkgerror = False pkgkeyslist = [] for pkg in pkgnames: values_t = (pkg,) munkicommon.display_debug1("select pkg_key from pkgs where pkgid = %s", pkg) pkg_keys = curs.execute("select pkg_key from pkgs where pkgid = ?", values_t).fetchall() if not pkg_keys: # try pkgname munkicommon.display_debug1("select pkg_key from pkgs where pkgname = %s", pkg) pkg_keys = curs.execute("select pkg_key from pkgs where pkgname = ?", values_t).fetchall() if not pkg_keys: munkicommon.display_error("%s not found in database.", pkg) pkgerror = True else: for row in pkg_keys: # only want first column pkgkeyslist.append(row[0]) if pkgerror: pkgkeyslist = [] curs.close() conn.close() munkicommon.display_debug1("pkgkeys: %s", pkgkeyslist) return pkgkeyslist
def getpkgkeys(pkgnames): """ Given a list of receipt names, bom file names, or package ids, gets a list of pkg_keys from the pkgs table in our database. """ # open connection and cursor to our database conn = sqlite3.connect(packagedb) curs = conn.cursor() # check package names to make sure they're all in the database, # build our list of pkg_keys pkgerror = False pkgkeyslist = [] for pkg in pkgnames: values_t = (pkg, ) munkicommon.display_debug1("select pkg_key from pkgs where pkgid = %s", pkg) pkg_keys = curs.execute('select pkg_key from pkgs where pkgid = ?', values_t).fetchall() if not pkg_keys: # try pkgname munkicommon.display_debug1( "select pkg_key from pkgs where pkgname = %s", pkg) pkg_keys = curs.execute( 'select pkg_key from pkgs where pkgname = ?', values_t).fetchall() if not pkg_keys: munkicommon.display_error("%s not found in database.", pkg) pkgerror = True else: for row in pkg_keys: # only want first column pkgkeyslist.append(row[0]) if pkgerror: pkgkeyslist = [] curs.close() conn.close() munkicommon.display_debug1("pkgkeys: %s", pkgkeyslist) return pkgkeyslist
if combined_pem: # we created this; we should clean it up try: os.unlink(combined_pem) except (OSError, IOError): pass id_hash = pem_cert_sha1_digest(client_cert_path) if not id_hash: munkicommon.display_error( 'Cannot create keychain identity preference.') else: # set up identity preference(s) linking the identity (cert and key) # to the various urls munkicommon.display_debug1('Creating identity preferences...') try: output = security('default-keychain') if output: munkicommon.display_debug2(output) # One is defined, remember the path default_keychain = [ x.strip().strip('"') for x in output.split('\n') if x.strip()][0] except SecurityError, err: # error raised if there is no default default_keychain = None # Temporarily assign the default keychain to ours try: output = security( 'default-keychain', '-s', abs_keychain_path)
def debug_output(): '''Debugging output for keychain''' try: munkicommon.display_debug1('***Keychain list***') munkicommon.display_debug1(security('list-keychains', '-d', 'user')) munkicommon.display_debug1('***Default keychain info***') munkicommon.display_debug1(security('default-keychain', '-d', 'user')) keychainfile = get_keychain_path() if os.path.exists(keychainfile): munkicommon.display_debug1('***Info for %s***' % keychainfile) munkicommon.display_debug1( security('show-keychain-info', keychainfile)) except SecurityError, err: munkicommon.display_error(str(err))
# Gurl returned an error munkicommon.display_detail( 'Download error %s: %s', connection.error.code(), connection.error.localizedDescription()) if connection.SSLerror: munkicommon.display_detail( 'SSL error detail: %s', str(connection.SSLerror)) keychain.debug_output() munkicommon.display_detail('Headers: %s', connection.headers) if os.path.exists(tempdownloadpath) and not resume: os.remove(tempdownloadpath) raise GurlError(connection.error.code(), connection.error.localizedDescription()) if connection.response != None: munkicommon.display_debug1('Status: %s', connection.status) munkicommon.display_debug1('Headers: %s', connection.headers) if connection.redirection != []: munkicommon.display_debug1('Redirection: %s', connection.redirection) temp_download_exists = os.path.isfile(tempdownloadpath) connection.headers['http_result_code'] = str(connection.status) description = NSHTTPURLResponse.localizedStringForStatusCode_( connection.status) connection.headers['http_result_description'] = description if str(connection.status).startswith('2') and temp_download_exists: os.rename(tempdownloadpath, destinationpath) return connection.headers elif connection.status == 304: # unchanged on server
# Gurl returned an error munkicommon.display_detail('Download error %s: %s', connection.error.code(), connection.error.localizedDescription()) if connection.SSLerror: munkicommon.display_detail('SSL error detail: %s', str(connection.SSLerror)) keychain.debug_output() munkicommon.display_detail('Headers: %s', connection.headers) if os.path.exists(tempdownloadpath) and not resume: os.remove(tempdownloadpath) raise GurlError(connection.error.code(), connection.error.localizedDescription()) if connection.response != None: munkicommon.display_debug1('Status: %s', connection.status) munkicommon.display_debug1('Headers: %s', connection.headers) if connection.redirection != []: munkicommon.display_debug1('Redirection: %s', connection.redirection) temp_download_exists = os.path.isfile(tempdownloadpath) connection.headers['http_result_code'] = str(connection.status) description = NSHTTPURLResponse.localizedStringForStatusCode_( connection.status) connection.headers['http_result_description'] = description if str(connection.status).startswith('2') and temp_download_exists: os.rename(tempdownloadpath, destinationpath) return connection.headers elif connection.status == 304: # unchanged on server
onlyifnewer=getonlyifnewer, resume=resume, follow_redirects=follow_redirects) except CurlError, err: err = 'Error %s: %s' % tuple(err) raise CurlDownloadError(err) except HTTPError, err: err = 'HTTP result %s: %s' % tuple(err) raise CurlDownloadError(err) err = None if header['http_result_code'] == '304': # not modified, return existing file munkicommon.display_debug1('%s already exists and is up-to-date.' % destinationpath) # file is in cache and is unchanged, so we return False return False else: if header.get('last-modified'): # set the modtime of the downloaded file to the modtime of the # file on the server modtimestr = header['last-modified'] modtimetuple = time.strptime(modtimestr, '%a, %d %b %Y %H:%M:%S %Z') modtimeint = calendar.timegm(modtimetuple) os.utime(destinationpath, (time.time(), modtimeint)) if header.get('etag'): # store etag in extended attribute for future use xattr.setxattr(destinationpath, XATTR_ETAG, header['etag']) return True
os.environ['HOME'] = original_home return # Ensure the keychain is in the search path and unlocked added_keychain = add_to_keychain_list(abs_keychain_path) unlock_and_set_nonlocking(abs_keychain_path) # Add client cert (and optionally key) if client_key_path: # combine client cert and private key before we import cert_data = read_file(client_cert_path) key_data = read_file(client_key_path) # write the combined data combined_pem = os.path.join(munkicommon.tmpdir(), 'combined.pem') if write_file(cert_data + key_data, combined_pem): munkicommon.display_debug1('Importing client cert and key...') try: output = security('import', combined_pem, '-A', '-k', abs_keychain_path) if output: munkicommon.display_debug2(output) except SecurityError, err: munkicommon.display_error('Could not import %s: %s', combined_pem, err) os.unlink(combined_pem) else: munkicommon.display_error( 'Could not combine client cert and key for import!') else: munkicommon.display_debug2('Importing client cert and key...') try:
def debug_output(): '''Debugging output for keychain''' try: munkicommon.display_debug1('***Keychain list***') munkicommon.display_debug1(security('list-keychains', '-d', 'user')) munkicommon.display_debug1('***Default keychain info***') munkicommon.display_debug1(security('default-keychain', '-d', 'user')) keychainfile = get_keychain_path() if os.path.exists(keychainfile): munkicommon.display_debug1('***Info for %s***' % keychainfile) munkicommon.display_debug1( security('show-keychain-info', keychainfile)) except SecurityError, err: munkicommon.display_error(err)
os.environ['HOME'] = original_home return # Ensure the keychain is in the search path and unlocked added_keychain = add_to_keychain_list(abs_keychain_path) unlock_and_set_nonlocking(abs_keychain_path) # Add client cert (and optionally key) if client_key_path: # combine client cert and private key before we import cert_data = read_file(client_cert_path) key_data = read_file(client_key_path) # write the combined data combined_pem = os.path.join(munkicommon.tmpdir(), 'combined.pem') if write_file(cert_data + key_data, combined_pem): munkicommon.display_debug1('Importing client cert and key...') try: output = security( 'import', combined_pem, '-A', '-k', abs_keychain_path) if output: munkicommon.display_debug2(output) except SecurityError, err: munkicommon.display_error( 'Could not import %s: %s', combined_pem, err) os.unlink(combined_pem) else: munkicommon.display_error( 'Could not combine client cert and key for import!') else: munkicommon.display_debug2('Importing client cert and key...') try:
if connection.error != None: # Gurl returned an error munkicommon.display_detail( "Download error %s: %s", connection.error.code(), connection.error.localizedDescription() ) if connection.SSLerror: munkicommon.display_detail("SSL error detail: %s", str(connection.SSLerror)) keychain.debug_output() munkicommon.display_detail("Headers: %s", connection.headers) if os.path.exists(tempdownloadpath) and not resume: os.remove(tempdownloadpath) raise GurlError(connection.error.code(), connection.error.localizedDescription()) if connection.response != None: munkicommon.display_debug1("Status: %s", connection.status) munkicommon.display_debug1("Headers: %s", connection.headers) if connection.redirection != []: munkicommon.display_debug1("Redirection: %s", connection.redirection) temp_download_exists = os.path.isfile(tempdownloadpath) connection.headers["http_result_code"] = str(connection.status) description = NSHTTPURLResponse.localizedStringForStatusCode_(connection.status) connection.headers["http_result_description"] = description if str(connection.status).startswith("2") and temp_download_exists: os.rename(tempdownloadpath, destinationpath) return connection.headers elif connection.status == 304: # unchanged on server munkicommon.display_debug1("Item is unchanged on the server.")