예제 #1
0
    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 []
예제 #2
0
  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.")
예제 #3
0
    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)
예제 #4
0
    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)
예제 #5
0
    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)
예제 #6
0
  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))
예제 #7
0
    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)
예제 #8
0
 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"),
     ])
예제 #9
0
    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)
예제 #10
0
 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)
     ])
예제 #11
0
    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)
예제 #12
0
    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)
예제 #13
0
  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)
예제 #14
0
  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)
예제 #15
0
    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)
예제 #16
0
    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)