Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for targetrc file to execute commands when a target shell is spawned #859

Merged
merged 8 commits into from
Oct 7, 2024

Conversation

twiggler
Copy link
Contributor

@twiggler twiggler commented Sep 19, 2024

Support execution of a ~/.targetrc file when a target shell is opened, and ~/.targetrc.registry in case of the registry shell.

We have decided on separate run command files because the registry and target shell are not compatible.

Additionally:

  • The run commands files to be executed can be configured per-target by setting the TARGETRCFILE (and TARGETRCFILE_REGISTRY) variables inside the target configuration file.

Closes #592

Copy link

codecov bot commented Sep 19, 2024

Codecov Report

Attention: Patch coverage is 87.50000% with 3 lines in your changes missing coverage. Please review.

Project coverage is 76.34%. Comparing base (3ac5b79) to head (5b96b70).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
dissect/target/tools/shell.py 87.50% 3 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #859   +/-   ##
=======================================
  Coverage   76.33%   76.34%           
=======================================
  Files         313      313           
  Lines       26859    26883   +24     
=======================================
+ Hits        20503    20524   +21     
- Misses       6356     6359    +3     
Flag Coverage Δ
unittests 76.34% <87.50%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Comment on lines 474 to 477
runcommands_file = pathlib.Path(
getattr(target._config, "TARGETRCFILE", self.DEFAULT_RUNCOMMANDSFILE)
).expanduser()
self.load_runcommands(runcommands_file)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not in TargetCmd?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The registry shell inherits from TargetCmd. Further, the "ordinary" shell and the registry shell are not fully compatible. Therefore, I don't think it makes sense to execute the same rc file in both shells.

We could support the registry shell with a different rc file. (I asked the team this on Thursday, and they indicated to restrict the rc file to the "ordinary" shell.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JSCU-CNI would you mind giving your thoughts on this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We agree it may be better to have different rc files for different shells.
Perhaps the logic of loading the targetrc file and executing commands can be stored in a superclass and inheriting classes can override where the commands are loaded from.

For example, the _load_targetrc function and calling said function from __init__ can be moved to the ExtendedCmd class, which has a DEFAULT_RUNCOMMANDSFILE property of None. Then, inheriting classes could override that property. This also leaves a good boilerplate for usages of ExtendedCmd that are not inheriting from TargetCmd.

dissect/target/tools/shell.py Outdated Show resolved Hide resolved
dissect/target/tools/shell.py Outdated Show resolved Hide resolved
@twiggler twiggler force-pushed the 529-targetrc branch 3 times, most recently from 0fac854 to 72ee60f Compare September 30, 2024 14:41
@twiggler twiggler requested review from JSCU-CNI and pyrco and removed request for JSCU-CNI September 30, 2024 14:47
pyrco
pyrco previously requested changes Oct 3, 2024
def _get_targetrc_path(self) -> pathlib.Path:
"""Get the path to the run commands file."""

return pathlib.Path(self.DEFAULT_RUNCOMMANDSFILE).expanduser()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does expanduser() work for ~ in paths on windows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it does.

(Verified on virtual machine, and see https://docs.python.org/3/library/os.path.html#os.path.expanduser)

@@ -95,6 +95,7 @@ class ExtendedCmd(cmd.Cmd):
"""

CMD_PREFIX = "cmd_"
DEFAULT_RUNCOMMANDSFILE = "~/.targetrc"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move this to TargetCmd and have this value be None?

@@ -96,6 +96,7 @@ class ExtendedCmd(cmd.Cmd):

CMD_PREFIX = "cmd_"
_runtime_aliases = {}
DEFAULT_RUNCOMMANDSFILE = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
DEFAULT_RUNCOMMANDSFILE = None
DEFAULT_RUNCOMMANDS_FILE = None

Comment on lines 139 to 140
"""Get the path to the run commands file. Can return None if DEFAULT_RUNCOMMANDSFILE is not set."""
return pathlib.Path(self.DEFAULT_RUNCOMMANDSFILE).expanduser() if self.DEFAULT_RUNCOMMANDSFILE else None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Get the path to the run commands file. Can return None if DEFAULT_RUNCOMMANDSFILE is not set."""
return pathlib.Path(self.DEFAULT_RUNCOMMANDSFILE).expanduser() if self.DEFAULT_RUNCOMMANDSFILE else None
"""Get the path to the run commands file. Can return ``None`` if ``DEFAULT_RUNCOMMANDS_FILE`` is not set."""
return pathlib.Path(self.DEFAULT_RUNCOMMANDS_FILE).expanduser() if self.DEFAULT_RUNCOMMANDS_FILE else None

Comment on lines 144 to 145
targetrc_path = self._get_targetrc_path()
if targetrc_path is not None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
targetrc_path = self._get_targetrc_path()
if targetrc_path is not None:
if targetrc_path := self._get_targetrc_path() is not None:

Comment on lines 336 to 337
DEFAULT_RUNCOMMANDSFILE = "~/.targetrc"
CONFIG_KEY_RUNCOMMANDSFILE = "TARGETRCFILE"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
DEFAULT_RUNCOMMANDSFILE = "~/.targetrc"
CONFIG_KEY_RUNCOMMANDSFILE = "TARGETRCFILE"
DEFAULT_RUNCOMMANDS_FILE = "~/.targetrc"
CONFIG_KEY_RUNCOMMANDS_FILE = "TARGETRCFILE"

"""Get the path to the run commands file."""

return pathlib.Path(
getattr(self.target._config, self.CONFIG_KEY_RUNCOMMANDSFILE, self.DEFAULT_RUNCOMMANDSFILE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
getattr(self.target._config, self.CONFIG_KEY_RUNCOMMANDSFILE, self.DEFAULT_RUNCOMMANDSFILE)
getattr(self.target._config, self.CONFIG_KEY_RUNCOMMANDS_FILE, self.DEFAULT_RUNCOMMANDS_FILE)

Comment on lines 1181 to 1182
DEFAULT_RUNCOMMANDSFILE = "~/.targetrc.registry"
CONFIG_KEY_RUNCOMMANDSFILE = "TARGETRCFILE_REGISTRY"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
DEFAULT_RUNCOMMANDSFILE = "~/.targetrc.registry"
CONFIG_KEY_RUNCOMMANDSFILE = "TARGETRCFILE_REGISTRY"
DEFAULT_RUNCOMMANDS_FILE = "~/.targetrc.registry"
CONFIG_KEY_RUNCOMMANDS_FILE = "TARGETRCFILE_REGISTRY"

except Exception as e:
log.debug("Error processing .targetrc file: %s", e)

def _get_targetrc_path(self) -> Optional[pathlib.Path]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def _get_targetrc_path(self) -> Optional[pathlib.Path]:
def _get_targetrc_path(self) -> pathlib.Path | None:

@@ -19,7 +19,7 @@
import sys
from contextlib import contextmanager
from datetime import datetime, timedelta, timezone
from typing import Any, BinaryIO, Callable, Iterator, TextIO
from typing import Any, BinaryIO, Callable, Iterator, Optional, TextIO
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from typing import Any, BinaryIO, Callable, Iterator, Optional, TextIO
from typing import Any, BinaryIO, Callable, Iterator, TextIO

Copy link
Member

@Schamper Schamper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meant to be a request changes.

@twiggler twiggler requested a review from Schamper October 7, 2024 11:04
@twiggler twiggler dismissed pyrco’s stale review October 7, 2024 11:36

Schamper reviewed

@twiggler twiggler merged commit b96029a into main Oct 7, 2024
18 checks passed
@twiggler twiggler deleted the 529-targetrc branch October 7, 2024 11:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add .targetrc file to execute commands at startup of target-shell
4 participants