Example #1
0
def getMCXData(ds_object):
    '''Returns a dictionary representation of dsAttrTypeStandard:MCXSettings
    from the given DirectoryServices object'''
    ds_object_parts = ds_object.split('/')
    ds_node = '/'.join(ds_object_parts[0:3])
    ds_object_path = '/' + '/'.join(ds_object_parts[3:])
    cmd = ['/usr/bin/dscl', '-plist', ds_node, 'read', ds_object_path,
           'dsAttrTypeStandard:MCXSettings']
    proc = subprocess.Popen(cmd, bufsize=1, stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
    (pliststr, err) = proc.communicate()
    if proc.returncode:
        errorAndExit("dscl error: %s" % err)
    # decode plist string returned by dscl
    try:
        mcx_dict = FoundationPlist.readPlistFromString(pliststr)
    except FoundationPlist.FoundationPlistException:
        errorAndExit(
            "Could not decode plist data from dscl:\n" % pliststr)
    # mcx_settings is a plist encoded inside the plist!
    try:
        mcx_data_plist = mcx_dict['dsAttrTypeStandard:MCXSettings'][0]
    except KeyError:
        errorAndExit("No mcx_settings in %s:\n%s" % (ds_object, pliststr))
    except IndexError:
        errorAndExit(
            "Unexpected mcx_settings format in %s:\n%s" % (ds_object, pliststr))
    # decode the embedded plist
    mcx_data = FoundationPlist.readPlistFromString(str(mcx_data_plist))
    return mcx_data['mcx_application_data']
    def createInstallsItems(self):
        """Calls makepkginfo to create an installs array."""
        faux_root = ""
        if self.env.get("faux_root"):
            faux_root = self.env["faux_root"].rstrip("/")
        
        args = ["/usr/local/munki/makepkginfo"]
        for item in self.env["installs_item_paths"]:
            args.extend(["-f", faux_root + item])
        
        # Call makepkginfo.
        try:
            proc = subprocess.Popen(
                args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            (out, err) = proc.communicate()
        except OSError as err:
            raise ProcessorError(
                "makepkginfo execution failed with error code %d: %s" 
                % (err.errno, err.strerror))
        if proc.returncode != 0:
            raise ProcessorError(
                "creating pkginfo failed: %s" % err)

        # Get pkginfo from output plist.
        pkginfo = FoundationPlist.readPlistFromString(out)
        installs_array = pkginfo.get("installs", [])
        
        if faux_root:
            for item in installs_array:
                if item["path"].startswith(faux_root):
                    item["path"] = item["path"][len(faux_root):]
                self.output("Created installs item for %s" % item["path"])
        if not "additional_pkginfo" in self.env:
            self.env["additional_pkginfo"] = {}
        self.env["additional_pkginfo"]["installs"] = installs_array
Example #3
0
    def loadData(self):

        pool = NSAutoreleasePool.alloc().init()
        self.volumes = macdisk.MountedVolumes()

        theURL = Utils.getServerURL()
        if theURL:
            plistData = Utils.downloadFile(theURL)
            if plistData:
                try:
                    converted_plist = FoundationPlist.readPlistFromString(plistData)
                except:
                    self.errorMessage = "Configuration plist couldn't be read."
                try:
                    self.passwordHash = converted_plist['password']
                except:
                    self.errorMessage = "Password wasn't set."

                try:
                    self.workflows = converted_plist['workflows']
                except:
                    self.errorMessage = "No workflows found in the configuration plist."
            else:
                self.errorMessage = "Couldn't get configuration plist from server."
        else:
            self.errorMessage = "Configuration URL wasn't set."

        self.performSelectorOnMainThread_withObject_waitUntilDone_(
            self.loadDataComplete, None, YES)
        del pool
Example #4
0
def read_signed_profile(profile_path):
    '''Attempts to read a (presumably) signed profile.'''

    # filed for future reference:
    # openssl smime -inform DER -verify -in Signed.mobileconfig
    #                           -noverify -out Unsigned.mobileconfig
    # will strip the signing from a signed profile
    # this might be a better approach
    # from: https://apple.stackexchange.com/questions/105981/
    #       how-do-i-view-or-verify-signed-mobileconfig-files-using-terminal

    # but... we're going to use an Apple-provided tool instead.

    cmd = ['/usr/bin/security', 'cms', '-D', '-i', profile_path]
    proc = subprocess.Popen(cmd,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
    stdout, stderr = proc.communicate()
    if proc.returncode:
        # security cms -D couldn't decode the file
        munkicommon.display_error('Error reading profile %s: %s' %
                                  (profile_path, stderr))
        return {}
    try:
        return FoundationPlist.readPlistFromString(stdout)
    except FoundationPlist.NSPropertyListSerializationException, err:
        # not a valid plist
        munkicommon.display_error('Error reading profile %s: %s' %
                                  (profile_path, err))
        return {}
Example #5
0
    def dmg_has_sla(self, dmgpath):
        '''Returns true if dmg has a Software License Agreement.
        These dmgs normally cannot be attached without user intervention'''
        has_sla = False
        proc = subprocess.Popen(
            ['/usr/bin/hdiutil', 'imageinfo', dmgpath, '-plist'],
            bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (stdout, stderr) = proc.communicate()
        if stderr:
            # some error with hdiutil.
            # Output but return False so we can attempt to continue
            self.output('hdiutil imageinfo error %s with image %s.'
                        % (stderr, dmgpath))
            return False

        (pliststr, stdout) = self.get_first_plist(stdout)
        if pliststr:
            try:
                plist = FoundationPlist.readPlistFromString(pliststr)
                properties = plist.get('Properties')
                if properties:
                    has_sla = properties.get(
                        'Software License Agreement', False)
            except FoundationPlist.NSPropertyListSerializationException:
                pass

        return has_sla
Example #6
0
    def dmg_has_sla(self, dmgpath):
        '''Returns true if dmg has a Software License Agreement.
        These dmgs normally cannot be attached without user intervention'''
        has_sla = False
        proc = subprocess.Popen(
            ['/usr/bin/hdiutil', 'imageinfo', dmgpath, '-plist'],
            bufsize=-1,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE)
        (stdout, stderr) = proc.communicate()
        if stderr:
            # some error with hdiutil.
            # Output but return False so we can attempt to continue
            self.output('hdiutil imageinfo error %s with image %s.' %
                        (stderr, dmgpath))
            return False

        (pliststr, stdout) = self.get_first_plist(stdout)
        if pliststr:
            try:
                plist = FoundationPlist.readPlistFromString(pliststr)
                properties = plist.get('Properties')
                if properties:
                    has_sla = properties.get('Software License Agreement',
                                             False)
            except FoundationPlist.NSPropertyListSerializationException:
                pass

        return has_sla
Example #7
0
    def DMGhasSLA(self, dmgpath):
        """Returns true if dmg has a Software License Agreement.
        These dmgs normally cannot be attached without user intervention"""
        hasSLA = False
        proc = subprocess.Popen(
            ["/usr/bin/hdiutil", "imageinfo", dmgpath, "-plist"],
            bufsize=-1,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )
        (out, err) = proc.communicate()
        if err:
            # some error with hdiutil.
            # Output but return False so we can attempt to continue
            self.output("hdiutil imageinfo error %s with image %s." % (err, dmgpath))
            return False

        (pliststr, out) = self.getFirstPlist(out)
        if pliststr:
            try:
                plist = FoundationPlist.readPlistFromString(pliststr)
                properties = plist.get("Properties")
                if properties:
                    hasSLA = properties.get("Software License Agreement", False)
            except FoundationPlist.NSPropertyListSerializationException:
                pass

        return hasSLA
    def create_installs_items(self):
        """Calls makepkginfo to create an installs array."""
        faux_root = ""
        if self.env.get("faux_root"):
            faux_root = self.env["faux_root"].rstrip("/")

        args = ["/usr/local/munki/makepkginfo"]
        for item in self.env["installs_item_paths"]:
            args.extend(["-f", faux_root + item])

        # Call makepkginfo.
        try:
            proc = subprocess.Popen(args,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
            (out, err) = proc.communicate()
        except OSError as err:
            raise ProcessorError(
                "makepkginfo execution failed with error code %d: %s" %
                (err.errno, err.strerror))
        if proc.returncode != 0:
            raise ProcessorError("creating pkginfo failed: %s" % err)

        # Get pkginfo from output plist.
        pkginfo = FoundationPlist.readPlistFromString(out)
        installs_array = pkginfo.get("installs", [])

        if faux_root:
            for item in installs_array:
                if item["path"].startswith(faux_root):
                    item["path"] = item["path"][len(faux_root):]
                self.output("Created installs item for %s" % item["path"])

        if "version_comparison_key" in self.env:
            for item in installs_array:
                cmp_key = None
                # If it's a string, set it for all installs items
                if isinstance(self.env["version_comparison_key"], basestring):
                    cmp_key = self.env["version_comparison_key"]
                # It it's a dict, find if there's a key that matches a path
                elif isinstance(self.env["version_comparison_key"],
                                NSDictionary):
                    for path, key in self.env["version_comparison_key"].items(
                    ):
                        if path == item["path"]:
                            cmp_key = key

                if cmp_key:
                    # Check that we really have this key available to compare
                    if cmp_key in item:
                        item["version_comparison_key"] = cmp_key
                    else:
                        raise ProcessorError(
                            "version_comparison_key '%s' could not be found in "
                            "the installs item for path '%s'" %
                            (cmp_key, item["path"]))

        if not "additional_pkginfo" in self.env:
            self.env["additional_pkginfo"] = {}
        self.env["additional_pkginfo"]["installs"] = installs_array
Example #9
0
def read_signed_profile(profile_path):
    '''Attempts to read a (presumably) signed profile.'''

    # filed for future reference:
    # openssl smime -inform DER -verify -in Signed.mobileconfig
    #                           -noverify -out Unsigned.mobileconfig
    # will strip the signing from a signed profile
    # this might be a better approach
    # from: http://apple.stackexchange.com/questions/105981/
    #       how-do-i-view-or-verify-signed-mobileconfig-files-using-terminal

    # but... we're going to use an Apple-provided tool instead.

    cmd = ['/usr/bin/security', 'cms', '-D', '-i', profile_path]
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = proc.communicate()
    if proc.returncode:
        # security cms -D couldn't decode the file
        munkicommon.display_error(
            'Error reading profile %s: %s' % (profile_path, stderr))
        return {}
    try:
        return FoundationPlist.readPlistFromString(stdout)
    except FoundationPlist.NSPropertyListSerializationException, err:
        # not a valid plist
        munkicommon.display_error(
            'Error reading profile %s: %s' % (profile_path, err))
        return {}
Example #10
0
 def main(self):
     # Wrap in a try/finally so the temp_path is always removed.
     temp_path = None
     try:
         # Check munki version.
         if os.path.exists("/usr/local/munki/munkilib/version.plist"):
             # Assume 0.7.0 or higher.
             munkiopts = ("displayname", "description", "catalog")
         else:
             # Assume 0.6.0
             munkiopts = ("catalog",)
         
         # Copy pkg to a temporary local directory, as installer -query
         # (which is called by makepkginfo) doesn't work on network drives.
         if self.env["pkg_path"].endswith("pkg"):
             # Create temporary directory.
             temp_path = tempfile.mkdtemp(prefix="autopkg", dir="/private/tmp")
             
             # Copy the pkg there
             pkg_for_makepkginfo = os.path.join(temp_path, os.path.basename(self.env["pkg_path"]))
             shutil.copyfile(self.env["pkg_path"], pkg_for_makepkginfo)
         else:
             pkg_for_makepkginfo = self.env["pkg_path"]
         
         # Generate arguments for makepkginfo.
         args = ["/usr/local/munki/makepkginfo"]
         for option in munkiopts:
             if option in self.env:
                 args.append("--%s=%s" % (option, self.env[option]))
         args.append(pkg_for_makepkginfo)
         
         # Call makepkginfo.
         try:
             p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
             (out, err) = p.communicate()
         except OSError as e:
             raise ProcessorError("makepkginfo execution failed with error code %d: %s" % (
                                   e.errno, e.strerror))
         if p.returncode != 0:
             raise ProcessorError("creating pkginfo for %s failed: %s" % (self.env['pkg_path'], err))
         
     # makepkginfo cleanup.
     finally:
         if temp_path is not None:
             shutil.rmtree(temp_path)
     
     # Read output plist.
     output = FoundationPlist.readPlistFromString(out)
     
     # Set version and name.
     if "version" in self.env:
         output["version"] = self.env["version"]
     if "name" in self.env:
         output["name"] = self.env["name"]
     
     # Save info.
     self.env["munki_info"] = output
     if "info_path" in self.env:
         FoundationPlist.writePlist(output, self.env["info_path"])
    def create_installs_items(self):
        """Calls makepkginfo to create an installs array."""
        faux_root = ""
        if self.env.get("faux_root"):
            faux_root = self.env["faux_root"].rstrip("/")

        args = ["/usr/local/munki/makepkginfo"]
        for item in self.env["installs_item_paths"]:
            args.extend(["-f", faux_root + item])

        # Call makepkginfo.
        try:
            proc = subprocess.Popen(
                args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
            )
            (out, err) = proc.communicate()
        except OSError as err:
            raise ProcessorError(
                "makepkginfo execution failed with error code %d: %s"
                % (err.errno, err.strerror)
            )
        if proc.returncode != 0:
            raise ProcessorError("creating pkginfo failed: %s" % err)

        # Get pkginfo from output plist.
        pkginfo = FoundationPlist.readPlistFromString(out)
        installs_array = pkginfo.get("installs", [])

        if faux_root:
            for item in installs_array:
                if item["path"].startswith(faux_root):
                    item["path"] = item["path"][len(faux_root) :]
                self.output("Created installs item for %s" % item["path"])

        if "version_comparison_key" in self.env:
            for item in installs_array:
                cmp_key = None
                # If it's a string, set it for all installs items
                if isinstance(self.env["version_comparison_key"], basestring):
                    cmp_key = self.env["version_comparison_key"]
                # It it's a dict, find if there's a key that matches a path
                elif isinstance(self.env["version_comparison_key"], NSDictionary):
                    for path, key in self.env["version_comparison_key"].items():
                        if path == item["path"]:
                            cmp_key = key

                if cmp_key:
                    # Check that we really have this key available to compare
                    if cmp_key in item:
                        item["version_comparison_key"] = cmp_key
                    else:
                        raise ProcessorError(
                            "version_comparison_key '%s' could not be found in "
                            "the installs item for path '%s'" % (cmp_key, item["path"])
                        )

        if "additional_pkginfo" not in self.env:
            self.env["additional_pkginfo"] = {}
        self.env["additional_pkginfo"]["installs"] = installs_array
	def create_munkipkginfo(self):
		# Set pkginfo plist path
		self.env["pkginfo_path"] = ("%s/%s.plist") % (self.env.get("RECIPE_CACHE_DIR"), self.env.get("NAME"))

		# Generate arguments for makepkginfo.
		args = ["/usr/local/munki/makepkginfo", self.env["pkg_path"]]
		if self.env.get("munkiimport_pkgname"):
			args.extend(["--pkgname", self.env["munkiimport_pkgname"]])
		if self.env.get("munkiimport_appname"):
			args.extend(["--appname", self.env["munkiimport_appname"]])
		if self.env.get("additional_makepkginfo_options"):
			args.extend(self.env["additional_makepkginfo_options"])
		if self.env.get("munkiimport_name"):
			args.extend(["--displayname", self.env["munkiimport_name"]])

		# Call makepkginfo.
		try:
			proc = subprocess.Popen(
				args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
			(out, err_out) = proc.communicate()
		except OSError as err:
			raise ProcessorError(
				"makepkginfo execution failed with error code %d: %s"
				% (err.errno, err.strerror))
		if proc.returncode != 0:
			raise ProcessorError(
				"creating pkginfo for %s failed: %s"
				% (self.env["pkg_path"], err_out))

		# Get pkginfo from output plist.
		pkginfo = FoundationPlist.readPlistFromString(out)

		# copy any keys from pkginfo in self.env
		if "pkginfo" in self.env:
			for key in self.env["pkginfo"]:
				pkginfo[key] = self.env["pkginfo"][key]

		# set an alternate version_comparison_key
		# if pkginfo has an installs item
		if "installs" in pkginfo and self.env.get("version_comparison_key"):
			for item in pkginfo["installs"]:
				if not self.env["version_comparison_key"] in item:
					raise ProcessorError(
						("version_comparison_key '%s' could not be found in "
						 "the installs item for path '%s'")
						% (self.env["version_comparison_key"], item["path"]))
				item["version_comparison_key"] = (
					self.env["version_comparison_key"])

		try:
			pkginfo_path = self.env["pkginfo_path"]
			FoundationPlist.writePlist(pkginfo, pkginfo_path)
		except OSError, err:
			raise ProcessorError("Could not write pkginfo %s: %s"
								 % (pkginfo_path, err.strerror))        
Example #13
0
    def mount(self, pathname):
        """Mount image with hdiutil."""
        # Make sure we don't try to mount something twice.
        if pathname in self.mounts:
            raise ProcessorError("%s is already mounted" % pathname)

        stdin = ""
        if self.dmg_has_sla(pathname):
            stdin = "Y\n"

        # Call hdiutil.
        try:
            proc = subprocess.Popen(
                (
                    "/usr/bin/hdiutil",
                    "attach",
                    "-plist",
                    "-mountrandom",
                    "/private/tmp",
                    "-nobrowse",
                    pathname,
                ),
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                stdin=subprocess.PIPE,
            )
            (stdout, stderr) = proc.communicate(stdin)
        except OSError as err:
            raise ProcessorError(
                "hdiutil execution failed with error code %d: %s"
                % (err.errno, err.strerror)
            )
        if proc.returncode != 0:
            raise ProcessorError("mounting %s failed: %s" % (pathname, stderr))

        # Read output plist.
        (pliststr, stdout) = self.get_first_plist(stdout)
        try:
            output = FoundationPlist.readPlistFromString(pliststr)
        except FoundationPlist.NSPropertyListSerializationException:
            raise ProcessorError(
                "mounting %s failed: unexpected output from hdiutil" % pathname
            )

        # Find mount point.
        for part in output.get("system-entities", []):
            if "mount-point" in part:
                # Add to mount list.
                self.mounts[pathname] = part["mount-point"]
                self.output("Mounted disk image %s" % pathname)
                return self.mounts[pathname]
        raise ProcessorError(
            "mounting %s failed: unexpected output from hdiutil" % pathname
        )
Example #14
0
    def read_input_plist(self):
        """Read environment from input plist."""

        try:
            indata = self.infile.read()
            if indata:
                self.env = FoundationPlist.readPlistFromString(indata)
            else:
                self.env = dict()
        except BaseException as err:
            raise ProcessorError(err)
Example #15
0
    def read_input_plist(self):
        """Read environment from input plist."""

        try:
            indata = self.infile.read()
            if indata:
                self.env = FoundationPlist.readPlistFromString(indata)
            else:
                self.env = dict()
        except BaseException as err:
            raise ProcessorError(err)
Example #16
0
    def mount(self, pathname):
        """Mount image with hdiutil."""
        # Make sure we don't try to mount something twice.
        if pathname in self.mounts:
            raise ProcessorError("%s is already mounted" % pathname)

        stdin = ""
        if self.dmg_has_sla(pathname):
            stdin = "Y\n"

        # Call hdiutil.
        try:
            proc = subprocess.Popen(
                (
                    "/usr/bin/hdiutil",
                    "attach",
                    "-plist",
                    "-mountrandom",
                    "/private/tmp",
                    "-nobrowse",
                    pathname,
                ),
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                stdin=subprocess.PIPE,
            )
            (stdout, stderr) = proc.communicate(stdin)
        except OSError as err:
            raise ProcessorError(
                "hdiutil execution failed with error code %d: %s" %
                (err.errno, err.strerror))
        if proc.returncode != 0:
            raise ProcessorError("mounting %s failed: %s" % (pathname, stderr))

        # Read output plist.
        (pliststr, stdout) = self.get_first_plist(stdout)
        try:
            output = FoundationPlist.readPlistFromString(pliststr)
        except FoundationPlist.NSPropertyListSerializationException:
            raise ProcessorError(
                "mounting %s failed: unexpected output from hdiutil" %
                pathname)

        # Find mount point.
        for part in output.get("system-entities", []):
            if "mount-point" in part:
                # Add to mount list.
                self.mounts[pathname] = part["mount-point"]
                self.output("Mounted disk image %s" % pathname)
                return self.mounts[pathname]
        raise ProcessorError(
            "mounting %s failed: unexpected output from hdiutil" % pathname)
 def verify_dmg(self, src_dmg):
     '''Check that dmg is good.'''
     try:
         p = subprocess.Popen(("/usr/bin/hdiutil",
                               "verify",
                               "-plist",
                               src_dmg),
                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         (out, err) = p.communicate()
         info = FoundationPlist.readPlistFromString(out)
     except (OSError, IOError), err:
         raise ProcessorError(
             "Couldn't verify dmg file")
Example #18
0
	def get_share_credentials(self):
		if 'credential_file' not in self.env:
			return ''
		else:
			try:
				cfile = open(self.env['credential_file'])
				data = cfile.read()
				cfile.close()
				plist = FoundationPlist.readPlistFromString(data)
				username = plist.get('Username')
				password = plist.get('Password')
			except BaseException as err:
				raise ProcessorError(err)
			return "%s:%s@" % (username, password)				
 def get_share_credentials(self):
     if 'credential_file' not in self.env:
         return ''
     else:
         try:
             cfile = open(self.env['credential_file'])
             data = cfile.read()
             cfile.close()
             plist = FoundationPlist.readPlistFromString(data)
             username = plist.get('Username')
             password = plist.get('Password')
         except Exception as err:
             raise ProcessorError(err)
         return "%s:%s@" % (username, password)
Example #20
0
def get_hardware_info():
    '''Uses system profiler to get hardware info for this machine'''
    cmd = ['/usr/sbin/system_profiler', 'SPHardwareDataType', '-xml']
    proc = subprocess.Popen(cmd, shell=False, bufsize=-1,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (output, unused_error) = proc.communicate()
    try:
        plist = FoundationPlist.readPlistFromString(output)
        # system_profiler xml is an array
        sp_dict = plist[0]
        items = sp_dict['_items']
        sp_hardware_dict = items[0]
        return sp_hardware_dict
    except Exception:
        return {}
Example #21
0
def get_hardware_info():
    '''Uses system profiler to get hardware info for this machine'''
    cmd = ['/usr/sbin/system_profiler', 'SPHardwareDataType', '-xml']
    proc = subprocess.Popen(cmd, shell=False, bufsize=-1,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (output, unused_error) = proc.communicate()
    try:
        plist = FoundationPlist.readPlistFromString(output)
        # system_profiler xml is an array
        sp_dict = plist[0]
        items = sp_dict['_items']
        sp_hardware_dict = items[0]
        return sp_hardware_dict
    except Exception:
        return {}
Example #22
0
    def loadData(self):

        pool = NSAutoreleasePool.alloc().init()
        self.volumes = macdisk.MountedVolumes()

        theURL = Utils.getServerURL()
        if theURL:
            plistData = Utils.downloadFile(theURL)
            converted_plist = FoundationPlist.readPlistFromString(plistData)
            self.passwordHash = converted_plist['password']
            self.workflows = converted_plist['workflows']
        else:
            self.passwordHash = False

        self.performSelectorOnMainThread_withObject_waitUntilDone_(
            self.loadDataComplete, None, YES)
        del pool
 def convert_to_dmg(self, src_cdr, out_dmg):
     '''Convert cdr to dmg'''
     try:
         p = subprocess.Popen(("/usr/bin/hdiutil",
                               "convert",
                               "-plist",
                               "-format",
                               "UDZO",
                               "-o",
                               out_dmg,
                               src_cdr),
                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         (out, err) = p.communicate()
         info = FoundationPlist.readPlistFromString(out)
         dmg_path = info[0]
     except (OSError, IOError), err:
         raise ProcessorError(
             "Couldn't convert cdr file")
Example #24
0
File: Utils.py Project: pilfs/imagr
def getPlistData(data):
    # Try the user's homedir
    try:
        # NSLog("Trying Home Location")
        homedir = os.path.expanduser("~")
        plist = FoundationPlist.readPlist(
            os.path.join(homedir, "Library", "Preferences",
                         "com.grahamgilbert.Imagr.plist"))
        return plist[data]
    except:
        pass
    # Try the main prefs
    try:
        # NSLog("Trying System Location")
        plist = FoundationPlist.readPlist(
            os.path.join("/Library", "Preferences",
                         "com.grahamgilbert.Imagr.plist"))
        return plist[data]
    except:
        pass

    # Hopefully we're in a netboot set, try in /System/Installation/Packages
    try:
        # NSLog("Trying NetBoot Location")
        plist = FoundationPlist.readPlist(
            os.path.join("/System", "Installation", "Packages",
                         "com.grahamgilbert.Imagr.plist"))
        return plist[data]
    except:
        pass

    # last chance; look for a file next to the app
    appPath = NSBundle.mainBundle().bundlePath()
    appDirPath = os.path.dirname(appPath)
    try:
        plistData = open(
            os.path.join(appDirPath, "com.grahamgilbert.Imagr.plist")).read()
        plistData = plistData.replace("{{current_volume_path}}",
                                      currentVolumePath()).encode("utf8")
        plist = FoundationPlist.readPlistFromString(plistData)
        return plist[data]
    except:
        pass
Example #25
0
def mountAdobeDmg(dmgpath):
    """
    Attempts to mount the dmg at dmgpath
    and returns a list of mountpoints
    """
    mountpoints = []
    dmgname = os.path.basename(dmgpath)
    proc = subprocess.Popen(['/usr/bin/hdiutil', 'attach', dmgpath,
                            '-nobrowse', '-noverify', '-plist'],
                            bufsize=1,
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (pliststr, err) = proc.communicate()
    if err:
        munkicommon.display_error("Error %s mounting %s." % (err, dmgname))
    if pliststr:
        plist = FoundationPlist.readPlistFromString(pliststr)
        for entity in plist['system-entities']:
            if 'mount-point' in entity:
                mountpoints.append(entity['mount-point'])

    return mountpoints
Example #26
0
    def DMGhasSLA(self, dmgpath):
        '''Returns true if dmg has a Software License Agreement.
        These dmgs normally cannot be attached without user intervention'''
        hasSLA = False
        proc = subprocess.Popen(
                    ['/usr/bin/hdiutil', 'imageinfo', dmgpath, '-plist'],
                    bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (out, err) = proc.communicate()
        if err:
            print >> sys.stderr, (
                'hdiutil error %s with image %s.' % (err, dmgpath))
        (pliststr, out) = self.getFirstPlist(out)
        if pliststr:
            try:
                plist = FoundationPlist.readPlistFromString(pliststr)
                properties = plist.get('Properties')
                if properties:
                    hasSLA = properties.get('Software License Agreement', False)
            except FoundationPlist.NSPropertyListSerializationException:
                pass

        return hasSLA
    def process_hd_installer(self):
        '''
        Process HD installer -
            app_json: Path to the Application JSON from within the PKG
        '''

        #pylint: disable=too-many-locals, too-many-statements
        self.output('Processing HD installer')
        with open(self.env['app_json']) as json_file:
            load_json = json.load(json_file)

            # AppLaunch is not always in the same format, but is splittable
            if 'AppLaunch' in load_json:  # Bridge CC is HD but does not have AppLaunch
                app_launch = load_json['AppLaunch']
                self.output('app_launch: %s' % app_launch)
                app_details = list(re.split('/', app_launch))
                if app_details[2].endswith('.app'):
                    app_bundle = app_details[2]
                    app_path = app_details[1]
                else:
                    app_bundle = app_details[1]
                    app_path = list(re.split('/', (load_json['InstallDir']['value'])))[1]
                self.output('app_bundle: %s' % app_bundle)
                self.output('app_path: %s' % app_path)

                installed_path = os.path.join('/Applications', app_path, app_bundle)
                self.output('installed_path: %s' % installed_path)

                if not app_path.endswith('CC') and not app_path.endswith('2020'):
                    self.env['display_name'] = app_path + ' 2020'
                elif app_path.endswith('CC') and not app_path.endswith('2020'):
                    self.env['display_name'] = app_path + ' 2020'
                else:
                    self.env['display_name'] = app_path
                self.output('display_name: %s' % self.env['display_name'])

                zip_file = load_json['Packages']['Package'][0]['PackageName']
                self.output('zip_file: %s' % zip_file)

                zip_path = os.path.join(self.env['PKG'], 'Contents/Resources/HD', \
                                    self.env['target_folder'], zip_file + '.zip')
                self.output('zip_path: %s' % zip_path)

                with zipfile.ZipFile(zip_path, mode='r') as myzip:
                    with myzip.open(zip_file + '.pimx') as mytxt:
                        txt = mytxt.read()
                        tree = ElementTree.fromstring(txt)
                        # Loop through .pmx's Assets, look for target=[INSTALLDIR],
                        # then grab Assets Source.
                        # Break when found .app/Contents/Info.plist
                        for elem in tree.findall('Assets'):
                            for i in  elem.getchildren():
                                # Below special tweak for the non-Classic Lightroom bundle
                                if i.attrib['target'].upper().startswith('[INSTALLDIR]') and not i.attrib['target'].endswith('Icons'):
                                    bundle_location = i.attrib['source']
                                    self.output('bundle_location: %s' % bundle_location)
                                else:
                                    continue
                                if not bundle_location.startswith('[StagingFolder]'):
                                    continue
                                elif bundle_location.endswith('Icons') or \
                                         bundle_location.endswith('AMT'):
                                    continue
                                else:
                                    bundle_location = bundle_location[16:]
                                    if bundle_location.endswith('.app'):
                                        zip_bundle = os.path.join('1', bundle_location, \
                                                                 'Contents/Info.plist')
                                    else:
                                        zip_bundle = os.path.join('1', bundle_location, \
                                                     app_bundle, 'Contents/Info.plist')
                                    try:
                                        with myzip.open(zip_bundle) as myplist:
                                            plist = myplist.read()
                                            data = FoundationPlist.readPlistFromString(plist)
                                            # If the App is Lightroom (Classic or non-Classic) we need to compare a different value in Info.plist
                                            if self.env['sap_code'] == 'LTRM' or self.env['sap_code'] == 'LRCC':
                                                self.env['vers_compare_key'] = 'CFBundleVersion'
                                            else:
                                                self.env['vers_compare_key'] = \
                                                  'CFBundleShortVersionString'
                                            self.output('vers_compare_key: %s' % \
                                                   self.env['vers_compare_key'])
                                            app_version = data[self.env['vers_compare_key']]
                                            self.output('staging_folder: %s' % bundle_location)
                                            self.output('staging_folder_path: %s' % zip_bundle)
                                            self.output('app_version: %s' % app_version)
                                            self.output('app_bundle: %s' % app_bundle)
                                            break
                                    except zipfile.BadZipfile:
                                        continue

                # Now we have the deets, let's use them
                self.create_pkginfo(app_bundle, app_version, installed_path)
Example #28
0
def getManifest(manifest):
    '''Returns a plist dictionary of manifest data'''
    req = urllib2.Request(MANIFESTS_URL + '/' + urllib2.quote(manifest))
    response = urllib2.urlopen(req)
    manifestData = response.read()
    return plistlib.readPlistFromString(manifestData)
Example #29
0
def ImportFromPkgutil(pkgname, curs):
    """
    Imports package data from pkgutil into our internal package database.
    """

    timestamp = 0
    owner = 0
    pkgid =  pkgname
    vers = "1.0"
    ppath = ""

    #get metadata from applepkgdb
    proc = subprocess.Popen(["/usr/sbin/pkgutil", "--pkg-info-plist", pkgid],
                            bufsize=1, stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
    (pliststr, unused_err) = proc.communicate()
    if pliststr:
        plist = FoundationPlist.readPlistFromString(pliststr)
        if "pkg-version" in plist:
            vers = plist["pkg-version"]
        if "install-time" in plist:
            timestamp = plist["install-time"]
        if "install-location" in plist:
            ppath = plist["install-location"]
            ppath = ppath.lstrip('./').rstrip('/')
        else:
            # there _should_ be an install-location. If there's not, let's
            # check the old /Library/Receipts.
            # (Workaround for QuarkXPress 8.1 packages)
            receiptpath = findBundleReceiptFromID(pkgid)
            if receiptpath:
                infopath = os.path.join(receiptpath, 'Contents/Info.plist')
                if os.path.exists(infopath):
                    infopl = FoundationPlist.readPlist(infopath)
                    if "IFPkgRelocatedPath" in infopl:
                        ppath = infopl["IFPkgRelocatedPath"]
                        ppath = ppath.lstrip('./').rstrip('/')

    values_t = (timestamp, owner, pkgid, vers, ppath, pkgname)
    curs.execute(
        '''INSERT INTO pkgs (timestamp, owner, pkgid, vers, ppath, pkgname)
           values (?, ?, ?, ?, ?, ?)''', values_t)
    pkgkey = curs.lastrowid

    cmd = ["/usr/sbin/pkgutil", "--files", pkgid]
    proc = subprocess.Popen(cmd, shell=False, bufsize=1,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    while True:
        line =  proc.stdout.readline().decode('UTF-8')
        if not line and (proc.poll() != None):
            break
        path = line.rstrip("\n")

        # pkgutil --files pkgid only gives us path info.  We don't
        # really need perms, uid and gid, so we'll just fake them.
        # if we needed them, we'd have to call
        # pkgutil --export-plist pkgid and iterate through the
        # plist.  That would be slower, so we'll do things this way...
        perms = "0000"
        uid = "0"
        gid = "0"
        if path != ".":
            # special case for MS Office 2008 installers
            # /tmp/com.microsoft.updater/office_location
            if ppath == "tmp/com.microsoft.updater/office_location":
                ppath = "Applications"

            #prepend the ppath so the paths match the actual install locations
            path = path.lstrip("./")
            if ppath:
                path = ppath + "/" + path

            values_t = (path, )
            row = curs.execute(
                'SELECT path_key from paths where path = ?',
                                                         values_t).fetchone()
            if not row:
                curs.execute(
                            'INSERT INTO paths (path) values (?)', values_t)
                pathkey = curs.lastrowid
            else:
                pathkey = row[0]

            values_t = (pkgkey, pathkey, uid, gid, perms)
            curs.execute(
                '''INSERT INTO pkgs_paths (pkg_key, path_key, uid, gid, perms)
                   values (?, ?, ?, ?, ?)''', values_t)
Example #30
0
def ImportBom(bompath, curs):
    """
    Imports package data into our internal package database
    using a combination of the bom file and data in Apple's
    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
    # a better indicator of what flat packages have actually been installed
    # on the current machine.
    # We still need to consult Apple's package database
    # because the bom files are missing metadata about the package.

    #applepkgdb = "/Library/Receipts/db/a.receiptdb"
    pkgname = os.path.basename(bompath)

    timestamp = os.stat(bompath).st_mtime
    owner = 0
    pkgid =  os.path.splitext(pkgname)[0]
    vers = "1.0"
    ppath = ""

    #try to get metadata from applepkgdb
    proc = subprocess.Popen(["/usr/sbin/pkgutil", "--pkg-info-plist", pkgid],
                            bufsize=1, stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
    (pliststr, unused_err) = proc.communicate()
    if pliststr:
        plist = FoundationPlist.readPlistFromString(pliststr)
        if "install-location" in plist:
            ppath = plist["install-location"]
            ppath = ppath.lstrip('./').rstrip('/')
        if "pkg-version" in plist:
            vers = plist["pkg-version"]
        if "install-time" in plist:
            timestamp = plist["install-time"]

    values_t = (timestamp, owner, pkgid, vers, ppath, pkgname)
    curs.execute(
        '''INSERT INTO pkgs (timestamp, owner, pkgid, vers, ppath, pkgname)
           values (?, ?, ?, ?, ?, ?)''', values_t)
    pkgkey = curs.lastrowid

    cmd = ["/usr/bin/lsbom", bompath]
    proc = subprocess.Popen(cmd, shell=False, bufsize=1,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    while True:
        line =  proc.stdout.readline().decode('UTF-8')
        if not line and (proc.poll() != None):
            break
        try:
            item = line.rstrip("\n").split("\t")
            path = item[0]
            perms = item[1]
            uidgid = item[2].split("/")
            uid = uidgid[0]
            gid = uidgid[1]
        except IndexError:
            # we really only care about the path
            perms = "0000"
            uid = "0"
            gid = "0"

        if path != ".":
            # special case for MS Office 2008 installers
            if ppath == "tmp/com.microsoft.updater/office_location":
                ppath = "Applications"

            #prepend the ppath so the paths match the actual install locations
            path = path.lstrip("./")
            if ppath:
                path = ppath + "/" + path

            values_t = (path, )
            row = curs.execute(
                'SELECT path_key from paths where path = ?',
                                                        values_t).fetchone()
            if not row:
                curs.execute(
                            'INSERT INTO paths (path) values (?)', values_t)
                pathkey = curs.lastrowid
            else:
                pathkey = row[0]

            values_t = (pkgkey, pathkey, uid, gid, perms)
            curs.execute(
                '''INSERT INTO pkgs_paths (pkg_key, path_key, uid, gid, perms)
                   values (?, ?, ?, ?, ?)''', values_t)
Example #31
0
def ImportBom(bompath, curs):
    """
    Imports package data into our internal package database
    using a combination of the bom file and data in Apple's
    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
    # a better indicator of what flat packages have actually been installed
    # on the current machine.
    # We still need to consult Apple's package database
    # because the bom files are missing metadata about the package.

    pkgname = os.path.basename(bompath)

    timestamp = os.stat(bompath).st_mtime
    owner = 0
    pkgid = os.path.splitext(pkgname)[0]
    vers = "1.0"
    ppath = ""

    # try to get metadata from applepkgdb
    proc = subprocess.Popen(["/usr/sbin/pkgutil", "--pkg-info-plist", pkgid],
                            bufsize=1,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
    (pliststr, dummy_err) = proc.communicate()
    if pliststr:
        plist = FoundationPlist.readPlistFromString(pliststr)
        if "install-location" in plist:
            ppath = plist["install-location"]
            ppath = ppath.lstrip('./').rstrip('/')
        if "pkg-version" in plist:
            vers = plist["pkg-version"]
        if "install-time" in plist:
            timestamp = plist["install-time"]

    values_t = (timestamp, owner, pkgid, vers, ppath, pkgname)
    curs.execute(
        '''INSERT INTO pkgs (timestamp, owner, pkgid, vers, ppath, pkgname)
           values (?, ?, ?, ?, ?, ?)''', values_t)
    pkgkey = curs.lastrowid

    cmd = ["/usr/bin/lsbom", bompath]
    proc = subprocess.Popen(cmd,
                            shell=False,
                            bufsize=1,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT)

    while True:
        line = proc.stdout.readline().decode('UTF-8')
        if not line and (proc.poll() != None):
            break
        try:
            item = line.rstrip("\n").split("\t")
            path = item[0]
            perms = item[1]
            uidgid = item[2].split("/")
            uid = uidgid[0]
            gid = uidgid[1]
        except IndexError:
            # we really only care about the path
            perms = "0000"
            uid = "0"
            gid = "0"

        if path != ".":
            # special case for MS Office 2008 installers
            if ppath == "tmp/com.microsoft.updater/office_location":
                ppath = "Applications"

            #prepend the ppath so the paths match the actual install locations
            path = path.lstrip("./")
            if ppath:
                path = ppath + "/" + path

            values_t = (path, )
            row = curs.execute('SELECT path_key from paths where path = ?',
                               values_t).fetchone()
            if not row:
                curs.execute('INSERT INTO paths (path) values (?)', values_t)
                pathkey = curs.lastrowid
            else:
                pathkey = row[0]

            values_t = (pkgkey, pathkey, uid, gid, perms)
            curs.execute(
                'INSERT INTO pkgs_paths (pkg_key, path_key, uid, gid, perms) '
                'values (?, ?, ?, ?, ?)', values_t)
    def process_hd_installer(self):
        """Process HD installer

        Inputs:
              app_json: Path to the Application JSON that was extracted from the feed.
        """
        self.output("Processing HD installer")
        with open(self.env["app_json"]) as json_file:
            load_json = json.load(json_file)

            # AppLaunch is not always in the same format, but is splittable
            if 'AppLaunch' in load_json:  # Bridge CC is HD but does not have AppLaunch
                app_launch = load_json["AppLaunch"]
                self.output("app_launch: %s" % app_launch)
                app_details = list(re.split("/", app_launch))
                if app_details[2].endswith(".app"):
                    app_bundle = app_details[2]
                    app_path = app_details[1]
                else:
                    app_bundle = app_details[1]
                    app_path = list(re.split("/", (load_json["InstallDir"]["value"])))[1]
                self.output("app_bundle: %s" % app_bundle)
                self.output("app_path: %s" % app_path)

                installed_path = os.path.join("/Applications", app_path, app_bundle)
                self.output("installed_path: %s" % installed_path)

                zip_file = load_json["Packages"]["Package"][0]["PackageName"]
                self.output("zip_file: %s" % zip_file)

                zip_path = os.path.join(self.env["pkg_path"], "Contents/Resources/HD", self.env["sapCode"] + self.env["ccpVersion"], zip_file + ".zip")
                self.output("zip_path: %s" % zip_path)
                with zipfile.ZipFile(zip_path, mode="r") as myzip:
                    with myzip.open(zip_file + ".pimx") as mytxt:
                        txt = mytxt.read()
                        tree = ElementTree.fromstring(txt)
                        # Loop through .pmx's Assets, look for target=[INSTALLDIR], then grab Assets Source.
                        # Break when found .app/Contents/Info.plist
                        for elem in tree.findall("Assets"):
                            for i in  elem.getchildren():
                                if i.attrib["target"].upper().startswith("[INSTALLDIR]"):
                                    bundle_location = i.attrib["source"]
                                else:
                                    continue
                                if not bundle_location.startswith("[StagingFolder]"):
                                    continue
                                else:
                                    bundle_location = bundle_location[16:]
                                    if bundle_location.endswith(".app"):
                                        zip_bundle = os.path.join("1", bundle_location, "Contents/Info.plist")
                                    else:
                                        zip_bundle = os.path.join("1", bundle_location, app_bundle, "Contents/Info.plist")
                                    try:
                                        with myzip.open(zip_bundle) as myplist:
                                            plist = myplist.read()
                                            data = FoundationPlist.readPlistFromString(plist)
                                            app_version = data["CFBundleShortVersionString"]
                                            #app_identifier = data["CFBundleIdentifier"]
                                            self.output("staging_folder: %s" % bundle_location)
                                            self.output("staging_folder_path: %s" % zip_bundle)
                                            self.output("app_version: %s" % app_version)
                                            self.output("app_bundle: %s" % app_bundle)
                                            #self.output("app_identifier: %s" % app_identifier)
                                            break
                                    except:
                                        continue

                # Now we have the deets, let's use them
                self.create_pkginfo(app_bundle, app_version, installed_path)
Example #33
0
    def main(self):
        # clear any pre-exising summary result
        if 'munki_importer_summary_result' in self.env:
            del self.env['munki_importer_summary_result']
        # Generate arguments for makepkginfo.
        args = ["/usr/local/munki/makepkginfo", self.env["pkg_path"]]
        if self.env.get("munkiimport_pkgname"):
            args.extend(["--pkgname", self.env["munkiimport_pkgname"]])
        if self.env.get("munkiimport_appname"):
            args.extend(["--appname", self.env["munkiimport_appname"]])
        # uninstaller pkg will be copied later, this is just to suppress
        # makepkginfo stderr warning output
        if self.env.get("uninstaller_pkg_path"):
            args.extend(["--uninstallpkg", self.env["uninstaller_pkg_path"]])
        if self.env.get("additional_makepkginfo_options"):
            args.extend(self.env["additional_makepkginfo_options"])

        # Call makepkginfo.
        try:
            proc = subprocess.Popen(args,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
            (out, err_out) = proc.communicate()
        except OSError as err:
            raise ProcessorError(
                "makepkginfo execution failed with error code %d: %s" %
                (err.errno, err.strerror))
        if err_out:
            for err_line in err_out.splitlines():
                self.output(err_line)
        if proc.returncode != 0:
            raise ProcessorError("creating pkginfo for %s failed: %s" %
                                 (self.env["pkg_path"], err_out))

        # Get pkginfo from output plist.
        pkginfo = FoundationPlist.readPlistFromString(out)

        # copy any keys from pkginfo in self.env
        if "pkginfo" in self.env:
            for key in self.env["pkginfo"]:
                pkginfo[key] = self.env["pkginfo"][key]

        # set an alternate version_comparison_key
        # if pkginfo has an installs item
        if "installs" in pkginfo and self.env.get("version_comparison_key"):
            for item in pkginfo["installs"]:
                if not self.env["version_comparison_key"] in item:
                    raise ProcessorError(
                        ("version_comparison_key '%s' could not be found in "
                         "the installs item for path '%s'") %
                        (self.env["version_comparison_key"], item["path"]))
                item["version_comparison_key"] = (
                    self.env["version_comparison_key"])

        # check to see if this item is already in the repo
        matchingitem = self.find_matching_item_in_repo(pkginfo)
        if matchingitem:
            self.env["pkginfo_repo_path"] = ""
            # set env["pkg_repo_path"] to the path of the matching item
            self.env["pkg_repo_path"] = os.path.join(
                self.env["MUNKI_REPO"], "pkgs",
                matchingitem['installer_item_location'])
            self.env["munki_info"] = {}
            if not "munki_repo_changed" in self.env:
                self.env["munki_repo_changed"] = False

            self.output("Item %s already exists in the munki repo as %s." %
                        (os.path.basename(self.env["pkg_path"]),
                         "pkgs/" + matchingitem['installer_item_location']))
            return

        # copy pkg/dmg to repo
        relative_path = self.copy_item_to_repo(pkginfo)
        # adjust the installer_item_location to match the actual location
        # and name
        pkginfo["installer_item_location"] = relative_path

        if self.env.get("uninstaller_pkg_path"):
            relative_uninstall_path = self.copy_item_to_repo(
                pkginfo, uninstaller_pkg=True)
            pkginfo["uninstaller_item_location"] = relative_uninstall_path
            pkginfo["uninstallable"] = True

        # set output variables
        self.env["pkginfo_repo_path"] = self.copy_pkginfo_to_repo(pkginfo)
        self.env["pkg_repo_path"] = os.path.join(self.env["MUNKI_REPO"],
                                                 "pkgs", relative_path)
        # update env["pkg_path"] to match env["pkg_repo_path"]
        # this allows subsequent recipe steps to reuse the uploaded
        # pkg/dmg instead of re-uploading
        # This won't affect most recipes, since most have a single
        # MunkiImporter step (and it's usually the last step)
        self.env["pkg_path"] = self.env["pkg_repo_path"]
        self.env["munki_info"] = pkginfo
        self.env["munki_repo_changed"] = True
        self.env["munki_importer_summary_result"] = {
            'summary_text':
            'The following new items were imported into Munki:',
            'report_fields':
            ['name', 'version', 'catalogs', 'pkginfo_path', 'pkg_repo_path'],
            'data': {
                'name':
                pkginfo['name'],
                'version':
                pkginfo['version'],
                'catalogs':
                ','.join(pkginfo['catalogs']),
                'pkginfo_path':
                self.env['pkginfo_repo_path'].partition('pkgsinfo/')[2],
                'pkg_repo_path':
                self.env['pkg_repo_path'].partition('pkgs/')[2]
            }
        }

        self.output("Copied pkginfo to %s" % self.env["pkginfo_repo_path"])
        self.output("Copied pkg to %s" % self.env["pkg_repo_path"])
Example #34
0
 def main(self):
     
     # Generate arguments for makepkginfo.
     args = ["/usr/local/munki/makepkginfo", self.env["pkg_path"]]
     if self.env.get("munkiimport_pkgname"):
         args.extend(["--pkgname", self.env["munkiimport_pkgname"]])
     if self.env.get("munkiimport_appname"):
         args.extend(["--appname", self.env["munkiimport_appname"]])
     if self.env.get("additional_makepkginfo_options"):
         args.extend(self.env["additional_makepkginfo_options"])
     
     # Call makepkginfo.
     try:
         proc = subprocess.Popen(
             args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         (out, err_out) = proc.communicate()
     except OSError as err:
         raise ProcessorError(
             "makepkginfo execution failed with error code %d: %s" 
             % (err.errno, err.strerror))
     if proc.returncode != 0:
         raise ProcessorError(
             "creating pkginfo for %s failed: %s" 
             % (self.env["pkg_path"], err_out))
     
     # Get pkginfo from output plist.
     pkginfo = FoundationPlist.readPlistFromString(out)
     
     # copy any keys from pkginfo in self.env
     if "pkginfo" in self.env:
         for key in self.env["pkginfo"]:
             pkginfo[key] = self.env["pkginfo"][key]
     
     # check to see if this item is already in the repo
     matchingitem = self.findMatchingItemInRepo(pkginfo)
     if matchingitem:
         self.env["pkginfo_repo_path"] = ""
         # set env["pkg_repo_path"] to the path of the matching item
         self.env["pkg_repo_path"] = os.path.join(
             self.env["MUNKI_REPO"], "pkgs",
             matchingitem['installer_item_location'])
         self.env["munki_info"] = {}
         if not "munki_repo_changed" in self.env:
             self.env["munki_repo_changed"] = False
         
         self.output("Item %s already exists in the munki repo as %s."
             % (os.path.basename(self.env["pkg_path"]),
                "pkgs/" + matchingitem['installer_item_location']))
         return
         
     # copy pkg/dmg to repo
     relative_path = self.copyItemToRepo(pkginfo)
     # adjust the installer_item_location to match the actual location
     # and name
     pkginfo["installer_item_location"] = relative_path
     
     # set output variables
     self.env["pkginfo_repo_path"] = self.copyPkginfoToRepo(pkginfo)
     self.env["pkg_repo_path"] = os.path.join(
         self.env["MUNKI_REPO"], "pkgs", relative_path)
     # update env["pkg_path"] to match env["pkg_repo_path"]
     # this allows subsequent recipe steps to reuse the uploaded
     # pkg/dmg instead of re-uploading
     # This won't affect most recipes, since most have a single
     # MunkiImporter step (and it's usually the last step)
     self.env["pkg_path"] = self.env["pkg_repo_path"]
     self.env["munki_info"] = pkginfo
     self.env["munki_repo_changed"] = True
     
     self.output("Copied pkginfo to %s" % self.env["pkginfo_repo_path"])
     self.output("Copied pkg to %s" % self.env["pkg_repo_path"])
    def process_hd_installer(self):
        """Process HD installer

        Inputs:
              app_json: Path to the Application JSON that was extracted from the feed.
        """
        self.output("Processing HD installer")
        with open(self.env["app_json"]) as json_file:
            load_json = json.load(json_file)

            # AppLaunch is not always in the same format, but is splittable
            if 'AppLaunch' in load_json:  # Bridge CC is HD but does not have AppLaunch
                app_launch = load_json["AppLaunch"]
                self.output("app_launch: %s" % app_launch)
                app_details = list(re.split("/", app_launch))
                if app_details[2].endswith(".app"):
                    app_bundle = app_details[2]
                    app_path = app_details[1]
                else:
                    app_bundle = app_details[1]
                    app_path = list(
                        re.split("/", (load_json["InstallDir"]["value"])))[1]
                self.output("app_bundle: %s" % app_bundle)
                self.output("app_path: %s" % app_path)

                installed_path = os.path.join("/Applications", app_path,
                                              app_bundle)
                self.output("installed_path: %s" % installed_path)

                zip_file = load_json["Packages"]["Package"][0]["PackageName"]
                self.output("zip_file: %s" % zip_file)

                zip_path = os.path.join(
                    self.env["pkg_path"], "Contents/Resources/HD",
                    self.env["sapCode"] + self.env["ccpVersion"],
                    zip_file + ".zip")
                self.output("zip_path: %s" % zip_path)
                with zipfile.ZipFile(zip_path, mode="r") as myzip:
                    with myzip.open(zip_file + ".pimx") as mytxt:
                        txt = mytxt.read()
                        tree = ElementTree.fromstring(txt)
                        # Loop through .pmx's Assets, look for target=[INSTALLDIR], then grab Assets Source.
                        # Break when found .app/Contents/Info.plist
                        for elem in tree.findall("Assets"):
                            for i in elem.getchildren():
                                if i.attrib["target"].upper().startswith(
                                        "[INSTALLDIR]"):
                                    bundle_location = i.attrib["source"]
                                else:
                                    continue
                                if not bundle_location.startswith(
                                        "[StagingFolder]"):
                                    continue
                                else:
                                    bundle_location = bundle_location[16:]
                                    if bundle_location.endswith(".app"):
                                        zip_bundle = os.path.join(
                                            "1", bundle_location,
                                            "Contents/Info.plist")
                                    else:
                                        zip_bundle = os.path.join(
                                            "1", bundle_location, app_bundle,
                                            "Contents/Info.plist")
                                    try:
                                        with myzip.open(zip_bundle) as myplist:
                                            plist = myplist.read()
                                            data = FoundationPlist.readPlistFromString(
                                                plist)
                                            app_version = data[
                                                "CFBundleShortVersionString"]
                                            #app_identifier = data["CFBundleIdentifier"]
                                            self.output("staging_folder: %s" %
                                                        bundle_location)
                                            self.output(
                                                "staging_folder_path: %s" %
                                                zip_bundle)
                                            self.output("app_version: %s" %
                                                        app_version)
                                            self.output("app_bundle: %s" %
                                                        app_bundle)
                                            #self.output("app_identifier: %s" % app_identifier)
                                            break
                                    except:
                                        continue

                # Now we have the deets, let's use them
                self.create_pkginfo(app_bundle, app_version, installed_path)
Example #36
0
def getCatalog(catalog):
    '''Takes a catalog name and returns the whole catalog'''
    req = urllib2.Request(CATALOG_URL + '/' + urllib2.quote(catalog))
    response = urllib2.urlopen(req)
    catalogData = response.read()
    return plistlib.readPlistFromString(catalogData)
Example #37
0
def ImportFromPkgutil(pkgname, curs):
    """
    Imports package data from pkgutil into our internal package database.
    """

    timestamp = 0
    owner = 0
    pkgid = pkgname
    vers = "1.0"
    ppath = ""

    #get metadata from applepkgdb
    proc = subprocess.Popen(["/usr/sbin/pkgutil", "--pkg-info-plist", pkgid],
                            bufsize=1,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
    (pliststr, dummy_err) = proc.communicate()
    if pliststr:
        plist = FoundationPlist.readPlistFromString(pliststr)
        if "pkg-version" in plist:
            vers = plist["pkg-version"]
        if "install-time" in plist:
            timestamp = plist["install-time"]
        if "install-location" in plist:
            ppath = plist["install-location"]
            ppath = ppath.lstrip('./').rstrip('/')
        else:
            # there _should_ be an install-location. If there's not, let's
            # check the old /Library/Receipts.
            # (Workaround for QuarkXPress 8.1 packages)
            receiptpath = findBundleReceiptFromID(pkgid)
            if receiptpath:
                infopath = os.path.join(receiptpath, 'Contents/Info.plist')
                if os.path.exists(infopath):
                    infopl = FoundationPlist.readPlist(infopath)
                    if "IFPkgRelocatedPath" in infopl:
                        ppath = infopl["IFPkgRelocatedPath"]
                        ppath = ppath.lstrip('./').rstrip('/')

    values_t = (timestamp, owner, pkgid, vers, ppath, pkgname)
    curs.execute(
        '''INSERT INTO pkgs (timestamp, owner, pkgid, vers, ppath, pkgname)
           values (?, ?, ?, ?, ?, ?)''', values_t)
    pkgkey = curs.lastrowid

    cmd = ["/usr/sbin/pkgutil", "--files", pkgid]
    proc = subprocess.Popen(cmd,
                            shell=False,
                            bufsize=1,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT)

    while True:
        line = proc.stdout.readline().decode('UTF-8')
        if not line and (proc.poll() != None):
            break
        path = line.rstrip("\n")

        # pkgutil --files pkgid only gives us path info.  We don't
        # really need perms, uid and gid, so we'll just fake them.
        # if we needed them, we'd have to call
        # pkgutil --export-plist pkgid and iterate through the
        # plist.  That would be slower, so we'll do things this way...
        perms = "0000"
        uid = "0"
        gid = "0"
        if path != ".":
            # special case for MS Office 2008 installers
            # /tmp/com.microsoft.updater/office_location
            if ppath == "tmp/com.microsoft.updater/office_location":
                ppath = "Applications"
            # another special case for Office 2011 updaters
            if ppath.startswith(
                    'tmp/com.microsoft.office.updater/com.microsoft.office.'):
                ppath = ""
            #prepend the ppath so the paths match the actual install locations
            path = path.lstrip("./")
            if ppath:
                path = ppath + "/" + path

            values_t = (path, )
            row = curs.execute('SELECT path_key from paths where path = ?',
                               values_t).fetchone()
            if not row:
                curs.execute('INSERT INTO paths (path) values (?)', values_t)
                pathkey = curs.lastrowid
            else:
                pathkey = row[0]

            values_t = (pkgkey, pathkey, uid, gid, perms)
            curs.execute(
                'INSERT INTO pkgs_paths (pkg_key, path_key, uid, gid, perms) '
                'values (?, ?, ?, ?, ?)', values_t)
Example #38
0
    def main(self):
        # clear any pre-exising summary result
        if 'munki_importer_summary_result' in self.env:
            del self.env['munki_importer_summary_result']
        # Generate arguments for makepkginfo.
        args = ["/usr/local/munki/makepkginfo", self.env["pkg_path"]]
        if self.env.get("munkiimport_pkgname"):
            args.extend(["--pkgname", self.env["munkiimport_pkgname"]])
        if self.env.get("munkiimport_appname"):
            args.extend(["--appname", self.env["munkiimport_appname"]])
        if self.env.get("additional_makepkginfo_options"):
            args.extend(self.env["additional_makepkginfo_options"])

        # Call makepkginfo.
        try:
            proc = subprocess.Popen(
                args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            (out, err_out) = proc.communicate()
        except OSError as err:
            raise ProcessorError(
                "makepkginfo execution failed with error code %d: %s"
                % (err.errno, err.strerror))
        if err_out:
            for err_line in err_out.splitlines():
                self.output(err_line)
        if proc.returncode != 0:
            raise ProcessorError(
                "creating pkginfo for %s failed: %s"
                % (self.env["pkg_path"], err_out))

        # Get pkginfo from output plist.
        pkginfo = FoundationPlist.readPlistFromString(out)

        # copy any keys from pkginfo in self.env
        if "pkginfo" in self.env:
            for key in self.env["pkginfo"]:
                pkginfo[key] = self.env["pkginfo"][key]

        # set an alternate version_comparison_key
        # if pkginfo has an installs item
        if "installs" in pkginfo and self.env.get("version_comparison_key"):
            for item in pkginfo["installs"]:
                if not self.env["version_comparison_key"] in item:
                    raise ProcessorError(
                        ("version_comparison_key '%s' could not be found in "
                         "the installs item for path '%s'")
                        % (self.env["version_comparison_key"], item["path"]))
                item["version_comparison_key"] = (
                    self.env["version_comparison_key"])

        # check to see if this item is already in the repo
        matchingitem = self.find_matching_item_in_repo(pkginfo)
        if matchingitem:
            self.env["pkginfo_repo_path"] = ""
            # set env["pkg_repo_path"] to the path of the matching item
            self.env["pkg_repo_path"] = os.path.join(
                self.env["MUNKI_REPO"], "pkgs",
                matchingitem['installer_item_location'])
            self.env["munki_info"] = {}
            if not "munki_repo_changed" in self.env:
                self.env["munki_repo_changed"] = False

            self.output("Item %s already exists in the munki repo as %s."
                        % (os.path.basename(self.env["pkg_path"]),
                           "pkgs/" + matchingitem['installer_item_location']))
            return

        # copy pkg/dmg to repo
        relative_path = self.copy_item_to_repo(pkginfo)
        # adjust the installer_item_location to match the actual location
        # and name
        pkginfo["installer_item_location"] = relative_path

        # set output variables
        self.env["pkginfo_repo_path"] = self.copy_pkginfo_to_repo(pkginfo)
        self.env["pkg_repo_path"] = os.path.join(
            self.env["MUNKI_REPO"], "pkgs", relative_path)
        # update env["pkg_path"] to match env["pkg_repo_path"]
        # this allows subsequent recipe steps to reuse the uploaded
        # pkg/dmg instead of re-uploading
        # This won't affect most recipes, since most have a single
        # MunkiImporter step (and it's usually the last step)
        self.env["pkg_path"] = self.env["pkg_repo_path"]
        self.env["munki_info"] = pkginfo
        self.env["munki_repo_changed"] = True
        self.env["munki_importer_summary_result"] = {
            'summary_text': 'The following new items were imported into Munki:',
            'report_fields': ['name', 'version', 'catalogs',
                              'pkginfo_path', 'pkg_repo_path'],
            'data': {
                'name': pkginfo['name'],
                'version': pkginfo['version'],
                'catalogs': ','. join(pkginfo['catalogs']),
                'pkginfo_path': 
                    self.env['pkginfo_repo_path'].partition('pkgsinfo/')[2],
                'pkg_repo_path': 
                    self.env['pkg_repo_path'].partition('pkgs/')[2]
            }
        }

        self.output("Copied pkginfo to %s" % self.env["pkginfo_repo_path"])
        self.output("Copied pkg to %s" % self.env["pkg_repo_path"])

        self.report["items"] = {
            "Name": self.env["munki_info"]["name"],
            "Version": self.env["munki_info"]["version"],
            "Catalogs" : ", ".join(self.env["munki_info"]["catalogs"]),
            "Pkginfo Path" : self.env["pkginfo_repo_path"]\
                            .partition("pkgsinfo/")[2],
            }
Example #39
0
 def main(self):
     
     # Generate arguments for makepkginfo.
     args = ["/usr/local/munki/makepkginfo", self.env["pkg_path"]]
     if self.env.get("munkiimport_pkgname"):
         args.extend(["--pkgname", self.env["munkiimport_pkgname"]])
     if self.env.get("munkiimport_appname"):
         args.extend(["--appname", self.env["munkiimport_appname"]])
     if self.env.get("additional_makepkginfo_options"):
         args.extend(self.env["additional_makepkginfo_options"])
     
     # Call makepkginfo.
     try:
         proc = subprocess.Popen(
             args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         (out, err_out) = proc.communicate()
     except OSError as err:
         raise ProcessorError(
             "makepkginfo execution failed with error code %d: %s" 
             % (err.errno, err.strerror))
     if proc.returncode != 0:
         raise ProcessorError(
             "creating pkginfo for %s failed: %s" 
             % (self.env["pkg_path"], err_out))
     
     # Get pkginfo from output plist.
     pkginfo = FoundationPlist.readPlistFromString(out)
     
     # copy any keys from pkginfo in self.env
     if "pkginfo" in self.env:
         for key in self.env["pkginfo"]:
             pkginfo[key] = self.env["pkginfo"][key]
     
     # check to see if this item is already in the repo
     matchingitem = self.findMatchingItemInRepo(pkginfo)
     if matchingitem:
         self.env["pkginfo_repo_path"] = ""
         # set env["pkg_repo_path"] to the path of the matching item
         self.env["pkg_repo_path"] = os.path.join(
             self.env["MUNKI_REPO"], "pkgs",
             matchingitem['installer_item_location'])
         self.env["munki_info"] = {}
         if not "munki_repo_changed" in self.env:
             self.env["munki_repo_changed"] = False
         
         self.output("Item %s already exists in the munki repo as %s."
             % (os.path.basename(self.env["pkg_path"]),
                "pkgs/" + matchingitem['installer_item_location']))
         return
         
     # copy pkg/dmg to repo
     relative_path = self.copyItemToRepo(pkginfo)
     # adjust the installer_item_location to match the actual location
     # and name
     pkginfo["installer_item_location"] = relative_path
     
     # set output variables
     self.env["pkginfo_repo_path"] = self.copyPkginfoToRepo(pkginfo)
     self.env["pkg_repo_path"] = os.path.join(
         self.env["MUNKI_REPO"], "pkgs", relative_path)
     # update env["pkg_path"] to match env["pkg_repo_path"]
     # this allows subsequent recipe steps to reuse the uploaded
     # pkg/dmg instead of re-uploading
     # This won't affect most recipes, since most have a single
     # MunkiImporter step (and it's usually the last step)
     self.env["pkg_path"] = self.env["pkg_repo_path"]
     self.env["munki_info"] = pkginfo
     self.env["munki_repo_changed"] = True
     
     self.output("Copied pkginfo to %s" % self.env["pkginfo_repo_path"])
     self.output("Copied pkg to %s" % self.env["pkg_repo_path"])
def main():
  dirpath = os.path.dirname(os.path.realpath(sys.argv[0]))
  opt = optparse.OptionParser()
  opts, args = opt.parse_args()

  # pprint.pprint(args[0])
  tree = ET.parse(args[0])

  output_location = tree.find(".//OutputLocation").text
  package_name = tree.find(".//PackageName").text

  root = tree.getroot()
  adobe_codes = {}
  target_names = {}
  product_names = {}

  media_list = tree.findall(".//Media")
  for media in media_list:
    if 'adobeCode' in media.find(".//DeploymentInstall//Payload").keys():
      product_name = media.find(".//prodName").text
      # Remove the () around the year in the product name: (2015) -> 2015
      # product_name = re.sub('[()]', '', product_name)
      # Remove the spaces and year from the name.
      # This should help match Munki item names
      product_name = re.sub('[()\s\d]', '', product_name)
      target_folder = media.find("TargetFolderName").text
      # adobe_code = media.find(".//mediaSignature").text
      adobe_code = media.find(".//DeploymentUninstall//Payload").attrib[
          'adobeCode']
      # print target_folder, adobe_code
      target_name = media.find(".//IncludedPayloads//Payload/[AdobeCode='{0}']"
                               .format(adobe_code)).findtext('TargetName')
      print "{0},{1},{2}".format(product_name, target_folder, adobe_code)
      adobe_codes[target_folder] = adobe_code
      target_names[target_folder] = target_name
      product_names[target_folder] = product_name

  for target_folder, adobe_code in adobe_codes.iteritems():
    media_db = "{0}/{1}/Build/{2}_Install.pkg/Contents/Resources/Setup/{3}"\
        "/payloads/{4}/Media_db.db".format(
            output_location,
            package_name,
            package_name,
            target_folder,
            target_names[target_folder])
    install_db = "{0}/{1}/Build/{2}_Install.pkg/Contents/Resources/Setup/{3}"\
        "/payloads/{4}/Install.db".format(
            output_location,
            package_name,
            package_name,
            target_folder,
            target_names[target_folder])
    zip_file = "{0}/{1}/Build/{2}_Install.pkg/Contents/Resources/Setup/{3}"\
        "/payloads/{4}/{4}.zip".format(
            output_location,
            package_name,
            package_name,
            target_folder,
            target_names[target_folder])

    payloadinfo = ET.fromstring(get_payloadinfo(media_db, adobe_code))
    applaunch_path = payloadinfo.find(".//AppLaunch").attrib['path']
    app_contents = "{0}Contents".format(
        applaunch_path.split('Contents')[0])
    app_info = "{0}/Info.plist".format(app_contents)
    source = get_source(install_db, app_info)

    if source is not None:
      head = source.split('/')[0].strip("[]").split('_')[1].title()
      tail = source.split('/', 1)[1]
      info_plist = "{0}/{1}".format(head, tail)
      with zipfile.ZipFile(zip_file) as zip:
        plist = FoundationPlist.readPlistFromString(zip.read(info_plist))
        icon_file = plist.get('CFBundleIconFile')

        icon_path = "{0}/Resources/{1}".format(app_contents, icon_file)
    if not icon_path.endswith('.icns'):
      icon_path = icon_path + '.icns'

    icon_source = get_source(install_db, icon_path)
    if icon_source is not None:
      head = icon_source.split('/')[0].strip("[]").split('_')[1].title()
      tail = icon_source.split('/', 1)[1]
      icon_path = "{0}/{1}".format(head, tail)
      icon_icns = "{0}.icns".format(product_names[target_folder])
      icon_png = "{0}.png".format(product_names[target_folder])
      icns_dest = os.path.join(dirpath, 'icons', icon_icns)
      png_dest = os.path.join(dirpath, 'icons', icon_png)
      with zipfile.ZipFile(zip_file) as zip:
        with open(icns_dest, 'wb') as f:
          f.write(zip.read(icon_path))

      convertIconToPNG(icns_dest, png_dest)