def main(argv): p = optparse.OptionParser() p.set_usage("""Usage: %prog [options] userdata.plist [password]""") p.add_option("-v", "--verbose", action="store_true", help="Verbose output.") options, argv = p.parse_args(argv) if len(argv) not in (2, 3): print >>sys.stderr, p.get_usage() return 1 # Read the userdata.plist. plist = argv[1] plist_data = NSData.dataWithContentsOfFile_(plist) if not plist_data: print >>sys.stderr, "Couldn't read %s" % plist return 1 user_plist, plist_format, error = \ NSPropertyListSerialization.propertyListFromData_mutabilityOption_format_errorDescription_( plist_data, NSPropertyListMutableContainers, None, None) if error: print >>sys.stderr, "Can't read %s: %s" % (plist, error) return 1 # Use password on commandline, or ask if one isn't provided. try: password = argv[2] except IndexError: while True: password = getpass.getpass() verify_password = getpass.getpass("Password again: ") if password == verify_password: break else: print "Passwords don't match!" # Hash password with all available methods. hashed_passwords = dict() for k, m in hash_methods.items(): hashed_pwd = m(password) pwd_data = NSData.alloc().initWithBytes_length_(hashed_pwd, len(hashed_pwd)) hashed_passwords[k] = pwd_data # Serialize hashed passwords to a binary plist. serialized_passwords = serialize_hash_dict(hashed_passwords) if not serialized_passwords: return 2 # Write back userdata.plist with ShadowHashData. user_plist["ShadowHashData"] = list() user_plist["ShadowHashData"].append(serialized_passwords) plist_data, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( user_plist, plist_format, None) plist_data.writeToFile_atomically_(argv[1], True) return 0
def writePlistToString(rootObject): '''Return 'rootObject' as a plist-formatted string.''' plistData, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( rootObject, NSPropertyListXMLFormat_v1_0, None) if error: raise NSPropertyListSerializationException(error) else: return str(plistData)
def serialize_hash_dict(hash_dict): plist_data, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( hash_dict, NSPropertyListBinaryFormat_v1_0, None) if error: # FIXME: Raise an exception instead. print >>sys.stderr, error return None return plist_data
def writePlistToString(rootObject): """Return 'rootObject' as a plist-formatted string.""" plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( rootObject, NSPropertyListXMLFormat_v1_0, None ) if error: error = error.encode("ascii", "ignore") raise NSPropertyListSerializationException(error) else: return str(plistData)
def _generate_plist_string(rootObject, format=NSPropertyListXMLFormat_v1_0): '''Return 'rootObject' as a plist-formatted string.''' plistData, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( rootObject, format, None) if error: error = error.encode('ascii', 'ignore') raise salt.exceptions.SaltInvocationError( 'Error encoding Property List: {}'.format(error) ) else: return str(plistData)
def _writePlistToString(rootObject): '''Return 'rootObject' as a plist-formatted string.''' plistData, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( rootObject, NSPropertyListXMLFormat_v1_0, None) if error: error = error.encode('ascii', 'ignore') log.debug('Error encoding to plist') log.debug(error) raise NSPropertyListSerializationException(error) else: return str(plistData)
def writePlist(dataObject, filepath): """ Write 'rootObject' as a plist to filepath. """ plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( dataObject, NSPropertyListXMLFormat_v1_0, None ) if error: raise NSPropertyListSerializationException(error) else: if plistData.writeToFile_atomically_(filepath, True): return else: raise Exception("Failed to write plist data to %s" % filepath)
def write_bundle_info(self, info, path): """Write Contents/Info.plist inside a bundle.""" plistpath = os.path.join(path, "Contents", "Info.plist") plist_data, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( info, NSPropertyListXMLFormat_v1_0, None ) if error: raise ProcessorError("Can't serialize %s: %s" % (plistpath, error)) if not plist_data.writeToFile_atomically_(plistpath, True): raise ProcessorError("Can't write %s" % (plistpath))
def _plistToData(plistObject): """low-level function that creates NSData from a plist object""" darwin_vers = int(os.uname()[2].split(".")[0]) if darwin_vers > 10: (data, error) = NSPropertyListSerialization.dataWithPropertyList_format_options_error_( plistObject, NSPropertyListXMLFormat_v1_0, 0, None ) else: # use the older NSPropertyListSerialization function on 10.6 and 10.5 (data, error) = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( plistObject, NSPropertyListXMLFormat_v1_0, None ) if error: raise NSPropertyListSerializationException(error) return data
def writePlist(dataObject, filepath): ''' Write 'rootObject' as a plist to filepath. ''' plistData, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( dataObject, NSPropertyListXMLFormat_v1_0, None) if error: error = error.encode('ascii', 'ignore') raise NSPropertyListSerializationException(error) else: if plistData.writeToFile_atomically_(filepath, True): return else: raise NSPropertyListWriteException( "Failed to write plist data to %s" % filepath)
def _plistToData(plistObject): '''low-level function that creates NSData from a plist object''' darwin_vers = int(os.uname()[2].split('.')[0]) if darwin_vers > 10: (data, error) = ( NSPropertyListSerialization.dataWithPropertyList_format_options_error_( plistObject, NSPropertyListXMLFormat_v1_0, 0, None)) else: # use the older NSPropertyListSerialization function on 10.6 and 10.5 (data, error) = ( NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( plistObject, NSPropertyListXMLFormat_v1_0, None)) if data is None: if error is None: error = "Property list invalid for format." raise NSPropertyListSerializationException(error) return data
def _write_plist(dataObject, filepath, format=NSPropertyListXMLFormat_v1_0): ''' Write 'rootObject' as a plist to filepath. ''' plistData, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( dataObject, format, None) if error: error = error.encode('ascii', 'ignore') raise salt.exceptions.SaltInvocationError( 'Error encoding Property List: {}'.format(error)) else: if plistData.writeToFile_atomically_(filepath, True): return else: raise salt.exceptions.SaltInvocationError( 'Failed to write Property List at path: {}'.format(filepath))
def _write_plist(dataObject, filepath, format=NSPropertyListXMLFormat_v1_0): ''' Write 'rootObject' as a plist to filepath. ''' plistData, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( dataObject, format, None) if error: error = error.encode('ascii', 'ignore') raise salt.exceptions.SaltInvocationError( 'Error encoding Property List: {}'.format(error) ) else: if plistData.writeToFile_atomically_(filepath, True): return else: raise salt.exceptions.SaltInvocationError( 'Failed to write Property List at path: {}'.format(filepath) )
def writePlist(dataObject, filepath): """Write 'rootObject' as a plist to filepath.""" ( plistData, error, ) = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( dataObject, NSPropertyListXMLFormat_v1_0, None) if plistData is None: if error: error = error.encode("ascii", "ignore") else: error = "Unknown error" raise NSPropertyListSerializationException(error) else: if plistData.writeToFile_atomically_(filepath, True): return else: raise NSPropertyListWriteException( "Failed to write plist data to %s" % filepath)
def gen_string(data, format='xml'): ''' Take a python struct (normally a dict) and generate a string representing a property list. data Python data structure (dict) format (default 'xml') Generate format, 'xml' or 'binary' ''' serialization = NSPropertyListXMLFormat_v1_0 if format == 'xml' else NSPropertyListBinaryFormat_v1_0 plistData, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( data, serialization, None) if error: error = error.encode('ascii', 'ignore') log.debug('Error writing plist') log.debug(error) raise NSPropertyListSerializationException(error) else: return plistData
def _writePlist(dataObject, filepath): ''' Write 'rootObject' as a plist to filepath. ''' plistData, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( dataObject, NSPropertyListXMLFormat_v1_0, None) if error: error = error.encode('ascii', 'ignore') log.debug('Error writing plist') log.debug(error) raise NSPropertyListSerializationException(error) else: if plistData.writeToFile_atomically_(filepath, True): return else: errmsg = "Failed to write plist data to %s" % filepath import traceback log.debug(errmsg) log.debug(traceback.format_exc()) raise NSPropertyListWriteException(errmsg)
def main(): parser = argparse.ArgumentParser(description='Sign or encrypt mobileconfig profiles, using either a cert + key file, or a keychain certificate.') parser.add_argument('sign', choices=('sign', 'encrypt', 'both'), help='Choose to sign, encrypt, or do both on a profile.') key_group = parser.add_argument_group('Keychain arguments', description='Use these if you wish to sign with a Keychain certificate.') key_group.add_argument('-k', '--keychain', help='Name of keychain to search for cert. Defaults to login.keychain', default='login.keychain') key_group.add_argument('-n', '--name', help='Common name of certificate to use from keychain.', required=True) parser.add_argument('infile', help='Path to input .mobileconfig file') parser.add_argument('outfile', help='Path to output .mobileconfig file. Defaults to outputting into the same directory.') args = parser.parse_args() print "f**k yeah" if args.sign == 'encrypt' or args.sign == 'both': # encrypt the profile only, do not sign # Encrypting a profile: # 1. Extract payload content into its own file # 2. Serial that file as its own plist # 3. CMS-envelope that content (using openssl for now) # 4. Remove "PayloadContent" key and replace with "EncryptedPayloadContent" key # 5. Replace the PayloadContent <array> with <data> tags instead # Step 1: Extract payload content into its own file myProfile = plistlib.readPlist(args.infile) payloadContent = myProfile['PayloadContent'] # Step 2: Serialize that file into its own plist (pContentFile, pContentPath) = tempfile.mkstemp() plistlib.writePlist(payloadContent, pContentPath) # Step 3: Use openssl to encrypt that content # First, we need to extract the certificate we want to use from the keychain security_cmd = ['/usr/bin/security', 'find-certificate', '-c', args.name, '-p' ] if args.keychain: security_cmd += [args.keychain] print security_cmd proc = subprocess.Popen(security_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (sout, serr) = proc.communicate() if serr: print >> sys.stderr, "Error: %s" % serr sys.exit(1) # Now write the certificate to a temp file (certfile, certpath) = tempfile.mkstemp('.pem') try: with open(certpath, 'wb') as f: f.write(sout) except IOError: print >> sys.stderr, "Could not write to file!" sys.exit(1) # Now use openssl to encrypt the payload content using that certificate (encPContentfile, encPContentPath) = tempfile.mkstemp('.plist') enc_cmd = ['/usr/bin/openssl', 'smime', '-encrypt', '-aes256', '-outform', 'pem', '-in', pContentPath, '-out', encPContentPath] enc_cmd += [certpath] proc = subprocess.Popen(enc_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (encout, encerr) = proc.communicate() if encerr: print >> sys.stderr, "Error: %s" % encerr sys.exit(1) # openssl smime -encrypt produces no output if successful # Step 4: Add the new encrypted payload content back into the plist with open(encPContentPath, 'rb') as f: content = f.readlines() content = content[1:-1] #this is to skip the ---BEGIN PKCS7--- and ----END PKCS7---- lines encPayload = "" for line in content: encPayload += ''.join(line.rstrip()) # to get rid of Python's \n everywhere del myProfile['PayloadContent'] binaryEncPayload = base64.b64decode(encPayload) wrapped_data = NSData.dataWithBytes_length_(binaryEncPayload, len(binaryEncPayload)) myProfile['EncryptedPayloadContent'] = wrapped_data plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(myProfile, NSPropertyListXMLFormat_v1_0, None) plistData.writeToFile_atomically_(args.outfile, True) # Step 5: Use plistlib.Data to properly encode the content # myProfile['EncryptedPayloadContent'] = plistlib.Data(encPayload) # now save the profile # plistlib.writePlist(myProfile, args.outfile) # Now clean up after ourselves if args.sign == 'sign' or args.sign == 'both': # sign the profile only # Keychain check: if not args.name: print >> sys.stderr, 'Error: A certificate common name is required to sign profiles with the Keychain.' sys.exit(22) cmd = ['/usr/bin/security', 'cms', '-S', '-N', args.name, '-i', args.infile, '-o', args.outfile ] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (sout, serr) = proc.communicate() if serr: print >> sys.stderr, 'Error: %s' % serr sys.exit(1)
def serializePlist(data): plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( data, NSPropertyListXMLFormat_v1_0, None) if error: raise NSPropertyListSerializationException(error) return plistData
def main(argv): p = optparse.OptionParser() p.set_usage("""Usage: %prog [options] userdata.plist [password]""") p.add_option("-v", "--verbose", action="store_true", help="Verbose output.") options, argv = p.parse_args(argv) if len(argv) not in (2, 3): print >> sys.stderr, p.get_usage() return 1 # Read the userdata.plist. plist = argv[1] plist_data = NSData.dataWithContentsOfFile_(plist) if not plist_data: print >> sys.stderr, "Couldn't read %s" % plist return 1 user_plist, plist_format, error = \ NSPropertyListSerialization.propertyListFromData_mutabilityOption_format_errorDescription_( plist_data, NSPropertyListMutableContainers, None, None) if error: print >> sys.stderr, "Can't read %s: %s" % (plist, error) return 1 # Use password on commandline, or ask if one isn't provided. try: password = argv[2] except IndexError: while True: password = getpass.getpass() verify_password = getpass.getpass("Password again: ") if password == verify_password: break else: print "Passwords don't match!" # Hash password with all available methods. hashed_passwords = dict() for k, m in hash_methods.items(): hashed_pwd = m(password) pwd_data = NSData.alloc().initWithBytes_length_( hashed_pwd, len(hashed_pwd)) hashed_passwords[k] = pwd_data # Serialize hashed passwords to a binary plist. serialized_passwords = serialize_hash_dict(hashed_passwords) if not serialized_passwords: return 2 # Write back userdata.plist with ShadowHashData. user_plist["ShadowHashData"] = list() user_plist["ShadowHashData"].append(serialized_passwords) plist_data, error = \ NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( user_plist, plist_format, None) plist_data.writeToFile_atomically_(argv[1], True) return 0
def main(): parser = argparse.ArgumentParser( description= 'Sign or encrypt mobileconfig profiles, using either a cert + key file, or a keychain certificate.' ) parser.add_argument( 'sign', choices=('sign', 'encrypt', 'both'), help='Choose to sign, encrypt, or do both on a profile.') key_group = parser.add_argument_group( 'Keychain arguments', description='Use these if you wish to sign with a Keychain certificate.' ) key_group.add_argument( '-k', '--keychain', help='Name of keychain to search for cert. Defaults to login.keychain', default='login.keychain') key_group.add_argument( '-n', '--name', help='Common name of certificate to use from keychain.', required=True) parser.add_argument('infile', help='Path to input .mobileconfig file') parser.add_argument( 'outfile', help= 'Path to output .mobileconfig file. Defaults to outputting into the same directory.' ) args = parser.parse_args() print "f**k yeah" if args.sign == 'encrypt' or args.sign == 'both': # encrypt the profile only, do not sign # Encrypting a profile: # 1. Extract payload content into its own file # 2. Serial that file as its own plist # 3. CMS-envelope that content (using openssl for now) # 4. Remove "PayloadContent" key and replace with "EncryptedPayloadContent" key # 5. Replace the PayloadContent <array> with <data> tags instead # Step 1: Extract payload content into its own file myProfile = plistlib.readPlist(args.infile) payloadContent = myProfile['PayloadContent'] # Step 2: Serialize that file into its own plist (pContentFile, pContentPath) = tempfile.mkstemp() plistlib.writePlist(payloadContent, pContentPath) # Step 3: Use openssl to encrypt that content # First, we need to extract the certificate we want to use from the keychain security_cmd = [ '/usr/bin/security', 'find-certificate', '-c', args.name, '-p' ] if args.keychain: security_cmd += [args.keychain] print security_cmd proc = subprocess.Popen(security_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (sout, serr) = proc.communicate() if serr: print >> sys.stderr, "Error: %s" % serr sys.exit(1) # Now write the certificate to a temp file (certfile, certpath) = tempfile.mkstemp('.pem') try: with open(certpath, 'wb') as f: f.write(sout) except IOError: print >> sys.stderr, "Could not write to file!" sys.exit(1) # Now use openssl to encrypt the payload content using that certificate (encPContentfile, encPContentPath) = tempfile.mkstemp('.plist') enc_cmd = [ '/usr/bin/openssl', 'smime', '-encrypt', '-aes256', '-outform', 'pem', '-in', pContentPath, '-out', encPContentPath ] enc_cmd += [certpath] proc = subprocess.Popen(enc_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (encout, encerr) = proc.communicate() if encerr: print >> sys.stderr, "Error: %s" % encerr sys.exit(1) # openssl smime -encrypt produces no output if successful # Step 4: Add the new encrypted payload content back into the plist with open(encPContentPath, 'rb') as f: content = f.readlines() content = content[ 1: -1] #this is to skip the ---BEGIN PKCS7--- and ----END PKCS7---- lines encPayload = "" for line in content: encPayload += ''.join( line.rstrip()) # to get rid of Python's \n everywhere del myProfile['PayloadContent'] binaryEncPayload = base64.b64decode(encPayload) wrapped_data = NSData.dataWithBytes_length_(binaryEncPayload, len(binaryEncPayload)) myProfile['EncryptedPayloadContent'] = wrapped_data plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_( myProfile, NSPropertyListXMLFormat_v1_0, None) plistData.writeToFile_atomically_(args.outfile, True) # Step 5: Use plistlib.Data to properly encode the content # myProfile['EncryptedPayloadContent'] = plistlib.Data(encPayload) # now save the profile # plistlib.writePlist(myProfile, args.outfile) # Now clean up after ourselves if args.sign == 'sign' or args.sign == 'both': # sign the profile only # Keychain check: if not args.name: print >> sys.stderr, 'Error: A certificate common name is required to sign profiles with the Keychain.' sys.exit(22) cmd = [ '/usr/bin/security', 'cms', '-S', '-N', args.name, '-i', args.infile, '-o', args.outfile ] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (sout, serr) = proc.communicate() if serr: print >> sys.stderr, 'Error: %s' % serr sys.exit(1)
def main(): parser = argparse.ArgumentParser(description='Sign or encrypt mobileconfig profiles, using either a cert + key file, or a keychain certificate.') parser.add_argument('sign', choices=('sign', 'encrypt', 'both'), help='Choose to sign, encrypt, or do both on a profile.') key_group = parser.add_argument_group('Keychain arguments', description='Use these if you wish to sign with a Keychain certificate.') key_group.add_argument('-k', '--keychain', help='Name of keychain to search for cert. Defaults to login.keychain', default='login.keychain') key_group.add_argument('-n', '--name', help='Common name of certificate to use from keychain.', required=True) parser.add_argument('infile', help='Path to input .mobileconfig file') parser.add_argument('outfile', help='Path to output .mobileconfig file. Defaults to outputting into the same directory.') args = parser.parse_args() if args.sign == 'encrypt' or args.sign == 'both': if args.sign == 'both': outputFile = args.outfile + '_unsigned' else: outputFile = args.outfile # encrypt the profile only, do not sign # Encrypting a profile: # 1. Extract payload content into its own file # 2. Serial that file as its own plist # 3. CMS-envelope that content (using openssl for now) # 4. Remove "PayloadContent" key and replace with "EncryptedPayloadContent" key # 5. Replace the PayloadContent <array> with <data> tags instead # Step 1: Extract payload content into its own file myProfile = readPlist(args.infile) payloadContent = myProfile['PayloadContent'] # Step 2: Serialize that file into its own plist (pContentFile, pContentPath) = tempfile.mkstemp() #print "pContentPath: %s" % pContentPath writePlist(payloadContent, pContentPath) # Step 3: Use openssl to encrypt that content # First, we need to extract the certificate we want to use from the keychain security_cmd = ['/usr/bin/security', 'find-certificate', '-c', args.name, '-p' ] if args.keychain: security_cmd += [args.keychain] proc = subprocess.Popen(security_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (sout, serr) = proc.communicate() if serr: print >> sys.stderr, "Error: %s" % serr sys.exit(1) # Now write the certificate to a temp file (certfile, certpath) = tempfile.mkstemp('.der') #print "Certpath: %s" % certpath try: with open(certpath, 'wb') as f: f.write(sout) except IOError: print >> sys.stderr, "Could not write to file!" sys.exit(1) # Now use openssl to encrypt the payload content using that certificate (encPContentfile, encPContentPath) = tempfile.mkstemp('.plist') #print "encPContentPath: %s" % encPContentPath enc_cmd = ['/usr/bin/openssl', 'smime', '-encrypt', '-aes256', '-outform', 'der', '-in', pContentPath, '-out', encPContentPath] enc_cmd += [certpath] proc = subprocess.Popen(enc_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (encout, encerr) = proc.communicate() if encerr: print >> sys.stderr, "Error: %s" % encerr sys.exit(1) # openssl smime -encrypt produces no output if successful # Step 4: Add the new encrypted payload content back into the plist with open(encPContentPath, 'rb') as f: binaryEncPayload = f.read() del myProfile['PayloadContent'] wrapped_data = NSData.dataWithBytes_length_(binaryEncPayload, len(binaryEncPayload)) myProfile['EncryptedPayloadContent'] = wrapped_data # Step 5: Replace the plist with the new content plistData, error = NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(myProfile, NSPropertyListXMLFormat_v1_0, None) plistData.writeToFile_atomically_(outputFile, True) # Now clean up after ourselves os.remove(pContentPath) os.remove(certpath) os.remove(encPContentPath) if args.sign == 'sign' or args.sign == 'both': # Keychain check: if not args.name: print >> sys.stderr, 'Error: A certificate common name is required to sign profiles with the Keychain.' sys.exit(22) if args.sign == 'both': # If we already encrypted it, then the correct file is already in outputFile inputFile = outputFile else: inputFile = args.infile cmd = ['/usr/bin/security', 'cms', '-S', '-N', args.name, '-i', inputFile, '-o', args.outfile ] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (sout, serr) = proc.communicate() if serr: print >> sys.stderr, 'Error: %s' % serr sys.exit(1) if args.sign == 'both': os.remove(outputFile)