Skip to content

Commit

Permalink
Add artifact for installing and configuring deb packages (Velocidex#3626
Browse files Browse the repository at this point in the history
)

In Debian-based OSes software is preferably installed through the
package manager. This artifact provides a comfortable way to install
packages, as well as configuring them using debconf. The package can
either be a name or a deb file, which can be optionally uploaded.

The purpose is to provide a reusable component for installing and
configuring tools and other packages needed by other artifacts in a
single command. `apt-get update` is optionally run, and dependencies, if
any, is automatically installed. debconf may be pre-seeded with answers
if the package requires configuration.

Other artifacts can offload all installation and configuration logic to
this artifact by calling it like this: `SELECT * FROM
Artifact.Linux.Utils.InstallDeb(DebName='sl')` or `SELECT * FROM
Artifact.Linux.Utils.InstallDeb(DebName='/tmp/mypackage_0.1.0-1_amd64.deb')`.
A row with *Step* "Installing package" and *ReturnCode* 0 will indicate
that the installation was a success.
  • Loading branch information
misje authored Jul 18, 2024
1 parent d3d94f8 commit 7c32605
Showing 1 changed file with 178 additions and 0 deletions.
178 changes: 178 additions & 0 deletions artifacts/definitions/Linux/Utils/InstallDeb.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
name: Linux.Utils.InstallDeb
author: Andreas Misje – @misje
description: |
Install a deb package and configure it with debconf answers. The package
may either be specified by name or be an uploaded file. If the package
already exists, it may be optionally reconfigured with debconf answers.
type: CLIENT

required_permissions:
- EXECVE

reference:
- https://manpages.debian.org/bookworm/debconf-doc/debconf-devel.7.en.html#Type

parameters:
- name: DebName
description: |
Package to install (by name). Ignored if DebFile is set. An absolute path
to a deb file that already exists on the system is also accepted.
- name: DebFile
description: |
Package to install (by file). Remember to click "Upload"! When set,
DebName is ignored. Use DebName with an absolute file path if the
file already exists on the system and does not need to be uploaded.
type: upload

- name: UpdateSources
description: |
Run `apt-get update` before installing the package. This is not necessary
if the package has no dependencies, and it should be disabled if there
is no Internet.
type: bool
default: True

- name: ForceConfNew
type: bool
description: |
Use the configuration delivered by the package instead of keeping the
local changes.
- name: ReconfigureIfInstalled
type: bool
description: |
If the package is already installed, run pre-seed debconf and
`dpkg-reconfigure` instead.
- name: DebConfValues
type: csv
description: |
debconf is a system used by many packages for interactive configuration.
When using a non-interactive frontend (like this artifact), answers may
by provided as a "pre-seed" file. Example line:
"wireshark-common/install-setuid,boolean,false"
default: |
Key,Type,Value
column_types:
- name: Stdout
type: nobreak

- name: Stderr
type: nobreak

sources:
- precondition:
SELECT OS From info() where OS = 'linux'

query: |
LET Package <= if(
condition=DebFile,
then=tempfile(data=DebFile, extension='_amd64.deb'),
else=DebName)
/* The file name is lost from the uploaded file, so extract it from the
package instead: */
LET PackageInfo = SELECT Stdout
FROM execve(argv=['/usr/bin/dpkg-deb', '--field', Package, 'Package'])
LET PackageName = if(
condition=DebFile,
then=PackageInfo[0].Stdout[:-1], // remove "\n"
else=DebName)
/* The file format is "package_name question type answer": */
LET PreSeedLines = SELECT
join(
sep=' ',
array=(PackageName, Key, Type, Value, )) AS Line
FROM DebConfValues
LET PreSeedFile <= tempfile(data=join(sep='\n', array=PreSeedLines.Line))
LET AptOpts <= ('-f', '-y', '-o', 'Debug::pkgProblemResolver=yes', '--no-install-recommends', ) + if(
condition=ForceConfNew,
then=('-o', 'Dpkg::Options::="--force-confnew"', ),
else=[])
LET PreSeed = SELECT
'Pre-seed debconf' AS Step,
*
FROM if(
condition=DebConfValues,
then={
SELECT *
FROM execve(argv=['/usr/bin/debconf-set-selections', PreSeedFile, ])
WHERE log(
message=format(
format='Pre-seeding %v',
args=[PackageName, ]),
level='INFO')
})
LET Install = SELECT *
FROM chain(
a_update={
SELECT
'Update index' AS Step,
*
FROM if(
condition=UpdateSources,
then={
SELECT *
FROM execve(argv=['/usr/bin/apt-get', '-y', 'update'])
WHERE log(
message='Updating package index before installing',
level='INFO')
})
},
b_debconf=PreSeed,
c_install={
SELECT
'Installing package' AS Step,
*
FROM execve(argv=('/usr/bin/apt-get', 'install', ) + AptOpts + (Package, ))
WHERE log(
message=format(
format='Installing deb package %v',
args=[PackageName, ]),
level='INFO')
})
LET IsInstalled = SELECT *
FROM stat(
filename=path_join(
components=('/var/lib/dpkg/info', PackageName + '.list')))
WHERE log(
message=format(
format='Package %v is already installed',
args=[PackageName, ]),
level='INFO')
SELECT *
FROM if(
condition=IsInstalled,
then=if(
condition=ReconfigureIfInstalled,
then={
SELECT *
FROM chain(
a_debconf=PreSeed,
b_reconfigure={
SELECT
'Reconfiguring package' AS Step,
*
FROM execve(argv=['/usr/sbin/dpkg-reconfigure', PackageName, ],
env=dict(
DEBIAN_FRONTEND='noninteractive'))
WHERE log(
message=format(
format='Reconfiguring deb package %v',
args=[PackageName, ]),
level='INFO')
})
}),
else=Install)

0 comments on commit 7c32605

Please sign in to comment.