def ParseMultiple(self, stats, kb): del kb # unused apps = {} for stat in stats: matches = re.search(r"/CurrentVersion/Uninstall/([^/]+)/([^$]+)", stat.pathspec.path) if not matches: continue app_name, key = matches.groups() apps.setdefault(app_name, {})[key] = stat.registry_data.GetValue() packages = [] for key, app in apps.items(): if "DisplayName" not in app: continue packages.append( rdf_client.SoftwarePackage.Installed( name=app.get("DisplayName"), description=app.get("Publisher", ""), version=app.get("DisplayVersion", ""))) if packages: return [rdf_client.SoftwarePackages(packages=packages)] return []
def Parse(self, cmd, args, stdout, stderr, return_val, time_taken, knowledge_base): _ = cmd, args, stdout, stderr, return_val, time_taken, knowledge_base packages = [] installed = rdf_client.SoftwarePackage.InstallState.INSTALLED packages.append( rdf_client.SoftwarePackage( name="Package1", description="Desc1", version="1", architecture="amd64", install_state=installed)) packages.append( rdf_client.SoftwarePackage( name="Package2", description="Desc2", version="1", architecture="i386", install_state=installed)) yield rdf_client.SoftwarePackages(packages=packages) # Also yield something random so we can test return type filtering. yield rdf_client_fs.StatEntry() # Also yield an anomaly to test that. yield rdf_anomaly.Anomaly( type="PARSER_ANOMALY", symptom="could not parse gremlins.")
def Parse(self, cmd, args, stdout, stderr, return_val, knowledge_base): """Parse the dpkg output.""" _ = stderr, args, knowledge_base # Unused. self.CheckReturn(cmd, return_val) lines = stdout.decode("utf-8").splitlines() num_columns = 0 i = 0 packages = [] for i, line in enumerate(lines): if line.startswith("+++-"): # This is a special header line that determines column size. columns = line.split("-") num_columns = len(columns) for col in columns[1:]: if not re.match("=*", col): raise parsers.ParseError( "Invalid header parsing for %s at line " "%s" % (cmd, i)) break if num_columns == 0: return elif num_columns not in [4, 5]: raise ValueError( "Bad number of columns ({}) in dpkg --list output:\n{}\n...". format(num_columns, "\n".join(lines[:10]))) for line in lines[i + 1:]: # Split the line at whitespace into at most `num_columns` columns. columns = line.split(None, num_columns - 1) # If the last column (description) is empty, pad it with None. if len(columns) == num_columns - 1: columns.append(None) if num_columns == 5: # Installed, Name, Version, Architecture, Description status, name, version, arch, desc = columns else: # num_columns is 4 # Older versions of dpkg don't print Architecture status, name, version, desc = columns arch = None # Status is potentially 3 columns, but always at least two, desired and # actual state. We only care about actual state. if status[1] == "i": status = rdf_client.SoftwarePackage.InstallState.INSTALLED else: status = rdf_client.SoftwarePackage.InstallState.UNKNOWN packages.append( rdf_client.SoftwarePackage(name=name, description=desc, version=version, architecture=arch, install_state=status)) if packages: yield rdf_client.SoftwarePackages(packages=packages)
def ParseFile( self, knowledge_base: rdf_client.KnowledgeBase, pathspec: rdf_paths.PathSpec, filedesc: IO[bytes], ) -> Iterator[rdf_client.SoftwarePackages]: del knowledge_base # Unused. del pathspec # Unused. try: plist = plistlib.load(filedesc) except plistlib.InvalidFileException as error: raise parsers.ParseError("Failed to parse a plist file", cause=error) if not isinstance(plist, list): raise parsers.ParseError( "InstallHistory plist is a '%s', expecting a list" % type(plist)) packages = [] for sw in plist: packages.append( rdf_client.SoftwarePackage.Installed( name=sw.get("displayName"), version=sw.get("displayVersion"), description=",".join(sw.get("packageIdentifiers", [])), # TODO(hanuszczak): make installed_on an RDFDatetime installed_on=_DateToEpoch(sw.get("date")))) if packages: yield rdf_client.SoftwarePackages(packages=packages)
def ParseFile( self, knowledge_base: rdf_client.KnowledgeBase, pathspec: rdf_paths.PathSpec, filedesc: IO[bytes], ) -> Iterator[rdf_client.SoftwarePackages]: del knowledge_base # Unused. del pathspec # Unused. packages = [] sw_data = utils.ReadFileBytesAsUnicode(filedesc) try: for pkg in self._deb822.Packages.iter_paragraphs( sw_data.splitlines()): if self.installed_re.match(pkg["Status"]): packages.append( rdf_client.SoftwarePackage( name=pkg["Package"], description=pkg["Description"], version=pkg["Version"], architecture=pkg["Architecture"], publisher=pkg["Maintainer"], install_state="INSTALLED")) except SystemError: yield rdf_anomaly.Anomaly(type="PARSER_ANOMALY", symptom="Invalid dpkg status file") finally: if packages: yield rdf_client.SoftwarePackages(packages=packages)
def testConvertsCorrectly(self): result = rdf_client.SoftwarePackages() for i in range(10): result.packages.append( rdf_client.SoftwarePackage.Pending( name="foo_%d" % i, version="ver_%d" % i, architecture="i386_%d" % i, publisher="somebody_%d" % i, description="desc_%d" % i, installed_on=42 + i, installed_by="user_%d" % i)) converter = software_package.SoftwarePackagesConverter() converted = list(converter.Convert(self.metadata, result)) self.assertLen(converted, 10) for i, r in enumerate(converted): self.assertEqual( r, software_package.ExportedSoftwarePackage( metadata=self.metadata, name="foo_%d" % i, version="ver_%d" % i, architecture="i386_%d" % i, publisher="somebody_%d" % i, install_state=software_package.ExportedSoftwarePackage .InstallState.PENDING, description="desc_%d" % i, installed_on=42 + i, installed_by="user_%d" % i))
def ParseFile(self, knowledge_base, pathspec, filedesc): del knowledge_base # Unused. del pathspec # Unused. plist = biplist.readPlist(filedesc) if not isinstance(plist, list): raise parser.ParseError( "InstallHistory plist is a '%s', expecting a list" % type(plist)) packages = [] for sw in plist: packages.append( rdf_client.SoftwarePackage( name=sw.get("displayName"), version=sw.get("displayVersion"), description=",".join(sw.get("packageIdentifiers")), # TODO(hanuszczak): make installed_on an RDFDatetime installed_on=_DateToEpoch(sw.get("date")), install_state=rdf_client.SoftwarePackage.InstallState. INSTALLED)) if packages: yield rdf_client.SoftwarePackages(packages=packages)
def Parse(self, cmd, args, stdout, stderr, return_val, knowledge_base): del cmd, args, stderr, return_val, knowledge_base # Unused yield rdf_client.SoftwarePackages(packages=[ rdf_client.SoftwarePackage.Installed(name="Package", description=stdout, version="1", architecture="amd64"), ])
def Parse(self, cmd, args, stdout, stderr, return_val, time_taken, knowledge_base): """Parse the dpkg output.""" _ = stderr, time_taken, args, knowledge_base # Unused. self.CheckReturn(cmd, return_val) column_lengths = [] i = 0 for i, line in enumerate(stdout.decode("utf-8").splitlines()): if line.startswith("+++-"): # This is a special header line that determines column size. for col in line.split("-")[1:]: if not re.match("=*", col): raise parser.ParseError( "Invalid header parsing for %s at line " "%s" % (cmd, i)) column_lengths.append(len(col)) break if not column_lengths: return packages = [] remaining_lines = stdout.splitlines()[i + 1:] for i, line in enumerate(remaining_lines): cols = line.split(None, len(column_lengths)) # The status column is ignored in column_lengths. if len(column_lengths) == 4: # Installed, Name, Version, Architecture, Description status, name, version, arch, desc = cols elif len(column_lengths) == 3: # Older versions of dpkg don't print Architecture status, name, version, desc = cols arch = None else: raise ValueError( "Bad number of columns in dpkg --list output: %s" % len(column_lengths)) # Status is potentially 3 columns, but always at least two, desired and # actual state. We only care about actual state. if status[1] == "i": status = rdf_client.SoftwarePackage.InstallState.INSTALLED else: status = rdf_client.SoftwarePackage.InstallState.UNKNOWN packages.append( rdf_client.SoftwarePackage(name=name, description=desc, version=version, architecture=arch, install_state=status)) if packages: yield rdf_client.SoftwarePackages(packages=packages)
def Parse(self, cmd, args, stdout, stderr, return_val, time_taken, knowledge_base): del cmd, args, stderr, return_val, time_taken, knowledge_base # Unused installed = rdf_client.SoftwarePackage.InstallState.INSTALLED yield rdf_client.SoftwarePackages(packages=[ rdf_client.SoftwarePackage(name="Package", description=stdout, version="1", architecture="amd64", install_state=installed) ])
def ParseMultiple(self, result_dicts): """Parse the WMI packages output.""" packages = [] for result_dict in result_dicts: packages.append( rdf_client.SoftwarePackage.Installed( name=result_dict["Name"], description=result_dict["Description"], version=result_dict["Version"])) if packages: yield rdf_client.SoftwarePackages(packages=packages)
def ParseMultiple(self, result_dicts): """Parse the WMI packages output.""" status = rdf_client.SoftwarePackage.InstallState.INSTALLED packages = [] for result_dict in result_dicts: packages.append( rdf_client.SoftwarePackage( name=result_dict["Name"], description=result_dict["Description"], version=result_dict["Version"], install_state=status)) if packages: yield rdf_client.SoftwarePackages(packages=packages)
def ParseMultiple(self, result_dicts): """Parse the WMI packages output.""" packages = [] for result_dict in result_dicts: result = result_dict.ToDict() # InstalledOn comes back in a godawful format such as '7/10/2013'. installed_on = self.AmericanDateToEpoch(result.get("InstalledOn", "")) packages.append( rdf_client.SoftwarePackage.Installed( name=result.get("HotFixID"), description=result.get("Caption"), installed_by=result.get("InstalledBy"), installed_on=installed_on)) if packages: yield rdf_client.SoftwarePackages(packages=packages)
def Parse(self, cmd, args, stdout, stderr, return_val, time_taken, knowledge_base): """Parse the yum output.""" _ = stderr, time_taken, args, knowledge_base # Unused. self.CheckReturn(cmd, return_val) packages = [] for line in stdout.decode("utf-8").splitlines()[1:]: # Ignore first line cols = line.split() name_arch, version, source = cols name, arch = name_arch.split(".") status = rdf_client.SoftwarePackage.InstallState.INSTALLED packages.append( rdf_client.SoftwarePackage( name=name, publisher=source, version=version, architecture=arch, install_state=status)) if packages: yield rdf_client.SoftwarePackages(packages=packages)
def Parse(self, stat, file_object, knowledge_base): """Parse the status file.""" _, _ = stat, knowledge_base packages = [] sw_data = utils.ReadFileBytesAsUnicode(file_object) try: for pkg in self._deb822.Packages.iter_paragraphs( sw_data.splitlines()): if self.installed_re.match(pkg["Status"]): packages.append( rdf_client.SoftwarePackage( name=pkg["Package"], description=pkg["Description"], version=pkg["Version"], architecture=pkg["Architecture"], publisher=pkg["Maintainer"], install_state="INSTALLED")) except SystemError: yield rdf_anomaly.Anomaly(type="PARSER_ANOMALY", symptom="Invalid dpkg status file") finally: if packages: yield rdf_client.SoftwarePackages(packages=packages)
def testWindowsRegistryInstalledSoftware(self): reg_str = rdf_client_fs.StatEntry.RegistryType.REG_SZ hklm = "HKEY_LOCAL_MACHINE" k = hklm + r"\Software\Microsoft\Windows\CurrentVersion\Uninstall" service_keys = [ # Valid. (k + r"\Google Chrome\DisplayName", "Google Chrome", reg_str), (k + r"\Google Chrome\DisplayVersion", "89.0.4389.82", reg_str), (k + r"\Google Chrome\Publisher", "Google LLC", reg_str), # Invalid - Contains no data. (k + r"\AddressBook\Default", "", reg_str), # Invalid - Missing DisplayName. (k + r"\Foo\DisplayVersion", "1.2.3.4", reg_str), (k + r"\Foo\Publisher", "Bar Inc", reg_str), # Valid. (k + r"\Baz\DisplayName", "Baz", reg_str), (k + r"\Baz\DisplayVersion", "2.3.4.5", reg_str), (k + r"\Baz\Publisher", "Baz LLC", reg_str), ] stats = [self._MakeRegStat(*x) for x in service_keys] parser = windows_registry_parser.WindowsRegistryInstalledSoftwareParser( ) results = parser.ParseMultiple(stats, None) want = [ rdf_client.SoftwarePackages(packages=[ rdf_client.SoftwarePackage.Installed(name="Google Chrome", description="Google LLC", version="89.0.4389.82"), rdf_client.SoftwarePackage.Installed( name="Baz", description="Baz LLC", version="2.3.4.5"), ]) ] got = list(results) self.assertEqual(want, got)