Skip to content

Commit ca301d5

Browse files
committed
Multiple changes.
* Sandboxing: enable in open source. * Bundled fleetspeak: add commands `fleetspeak_client` and `fleetspeak_server`. * Make grr_response_{server,client} depend on fleetspeak-{client,server}-bin packages. * `grr_config_updater`: stop using config option `Datastore.implementation`. * Implement API layer for recollecting VFS files. * Fix client search background color and alignment. * Fix CollectMultipleFiles result rendering.
1 parent 29a6ec7 commit ca301d5

File tree

21 files changed

+395
-75
lines changed

21 files changed

+395
-75
lines changed

api_client/python/grr_api_client/connectors/http.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ def SendStreamingRequest(
453453
self._CheckResponseStatus(response)
454454

455455
def GenerateChunks() -> Iterator[bytes]:
456-
with contextlib.closing(session):
456+
with contextlib.closing(session): # pytype: disable=wrong-arg-types
457457
with contextlib.closing(response):
458458
for chunk in response.iter_content(self.DEFAULT_BINARY_CHUNK_SIZE):
459459
yield chunk

debian/rules

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ override_dh_auto_test:
2424
override_dh_installinit:
2525
dh_installinit
2626
bash grr/core/scripts/install_server_from_src.sh -i debian/grr-server
27-
cp -v -r fleetspeak-server-bin/* debian/grr-server
27+
cp -v -r debian/grr-server/usr/share/grr-server/fleetspeak-server-bin/etc/fleetspeak-server debian/grr-server/etc
28+
rm -r debian/grr-server/usr/share/grr-server/fleetspeak-server-bin/etc/fleetspeak-server
2829

2930
override_dh_installdocs:
3031

@@ -49,6 +50,10 @@ override_dh_installwm:
4950
override_dh_installxfonts:
5051

5152
override_dh_link:
53+
dh_link etc/fleetspeak-server usr/share/grr-server/fleetspeak-server-bin/etc/fleetspeak-server
54+
dh_link usr/share/grr-server/fleetspeak-server-bin/usr/bin/fleetspeak-server usr/bin/fleetspeak-server
55+
dh_link usr/share/grr-server/fleetspeak-server-bin/usr/bin/fleetspeak-config usr/bin/fleetspeak-config
56+
dh_link usr/share/grr-server/fleetspeak-server-bin/lib/systemd/system/fleetspeak-server.service lib/systemd/system/fleetspeak-server.service
5257

5358
override_dh_gconf:
5459

grr/client/grr_response_client/distro_entry.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,8 @@ def FleetspeakClient():
1919
def PoolClient():
2020
from grr_response_client import poolclient
2121
app.run(poolclient.main)
22+
23+
24+
def FleetspeakClientWrapper():
25+
from grr_response_client import fleetspeak_client_wrapper
26+
app.run(fleetspeak_client_wrapper.main)
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#!/usr/bin/env python
2+
"""Wrapper for running a fleetspeak client in a virtualenv setup.
3+
4+
This script is meant to be used for development.
5+
6+
Requirements for running this script:
7+
8+
* Running from a virtualenv.
9+
* PIP package `fleetspeak-client-bin` is installed.
10+
* `grr_config_updater initialize` has been run.
11+
* Fleetspeak has been enabled.
12+
"""
13+
14+
import os
15+
import platform
16+
import subprocess
17+
18+
from absl import app
19+
20+
from google.protobuf import text_format
21+
from grr_response_core import config
22+
from grr_response_core.lib import config_lib
23+
from grr_response_core.lib import package
24+
from grr_response_core.lib import utils
25+
from grr_response_core.lib.util import temp
26+
from fleetspeak.src.client.daemonservice.proto.fleetspeak_daemonservice import config_pb2 as fs_daemon_config_pb2
27+
from fleetspeak.src.client.generic.proto.fleetspeak_client_generic import config_pb2 as fs_cli_config_pb2
28+
from fleetspeak.src.common.proto.fleetspeak import system_pb2 as fs_system_pb2
29+
30+
31+
class Error(Exception):
32+
pass
33+
34+
35+
def _CreateClientConfig(tmp_dir: str) -> str:
36+
"""Creates and returns the path to a fleetspeak client config."""
37+
38+
def TmpPath(*args):
39+
return os.path.join(tmp_dir, *args)
40+
41+
server_config_dir = package.ResourcePath(
42+
"fleetspeak-server-bin", "fleetspeak-server-bin/etc/fleetspeak-server")
43+
if not os.path.exists(server_config_dir):
44+
raise Error(
45+
f"Fleetspeak server config dir not found: {server_config_dir}. "
46+
"Please make sure `grr_config_updater initialize` has been run.")
47+
client_config_name = {
48+
"Linux": "linux_client.config",
49+
"Windows": "windows_client.config",
50+
"Darwin": "darwin_client.config",
51+
}
52+
client_config_path = os.path.join(server_config_dir,
53+
client_config_name[platform.system()])
54+
with open(client_config_path, "r") as f:
55+
client_config = text_format.Parse(f.read(), fs_cli_config_pb2.Config())
56+
if client_config.HasField("filesystem_handler"):
57+
client_config.filesystem_handler.configuration_directory = TmpPath()
58+
# We store the client state file in `Logging.path`.
59+
# 1) We need a writable path, where writing a file doesn't surprise the
60+
# user (as opposed to other paths in the source tree).
61+
# 2) We need the state file to be somewhat persistent, i.e. kept after
62+
# re-runs of this command. Otherwise the client ID of the client would
63+
# change at each re-run.
64+
client_config.filesystem_handler.state_file = os.path.join(
65+
config.CONFIG["Logging.path"], "fleetspeak-client.state")
66+
with open(TmpPath("config"), "w") as f:
67+
f.write(text_format.MessageToString(client_config))
68+
return TmpPath("config")
69+
70+
71+
def _CreateServiceConfig(config_dir: str) -> None:
72+
"""Creates a fleetspeak service config in the config directory."""
73+
service_config_path = config.CONFIG["ClientBuilder.fleetspeak_config_path"]
74+
with open(service_config_path, "r") as f:
75+
data = config.CONFIG.InterpolateValue(f.read())
76+
service_config = text_format.Parse(data,
77+
fs_system_pb2.ClientServiceConfig())
78+
daemon_config = fs_daemon_config_pb2.Config()
79+
service_config.config.Unpack(daemon_config)
80+
del daemon_config.argv[:]
81+
daemon_config.argv.extend([
82+
"grr_client",
83+
])
84+
service_config.config.Pack(daemon_config)
85+
utils.EnsureDirExists(os.path.join(config_dir, "textservices"))
86+
with open(os.path.join(config_dir, "textservices", "GRR.textproto"),
87+
"w") as f:
88+
f.write(text_format.MessageToString(service_config))
89+
90+
91+
def _RunClient(tmp_dir: str) -> None:
92+
"""Runs the fleetspeak client."""
93+
config_path = _CreateClientConfig(tmp_dir)
94+
_CreateServiceConfig(tmp_dir)
95+
fleetspeak_client = package.ResourcePath(
96+
"fleetspeak-client-bin",
97+
"fleetspeak-client-bin/usr/bin/fleetspeak-client")
98+
if not fleetspeak_client or not os.path.exists(fleetspeak_client):
99+
raise Error(
100+
f"Fleetspeak client binary not found: {fleetspeak_client}."
101+
"Please make sure that the package `fleetspeak-client-bin` has been "
102+
"installed.")
103+
command = [
104+
fleetspeak_client,
105+
"--logtostderr",
106+
"-config",
107+
config_path,
108+
]
109+
subprocess.check_call(command)
110+
111+
112+
def main(argv):
113+
del argv # unused
114+
config_lib.ParseConfigCommandLine()
115+
with temp.AutoTempDirPath(remove_non_empty=True) as tmp_dir:
116+
_RunClient(tmp_dir)
117+
118+
119+
if __name__ == "__main__":
120+
app.run(main)

grr/client/setup.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ def run(self):
119119
"grr_client = grr_response_client.distro_entry:Client",
120120
("grr_fleetspeak_client = "
121121
"grr_response_client.distro_entry:FleetspeakClient"),
122-
"grr_pool_client = grr_response_client.distro_entry:PoolClient"
122+
"grr_pool_client = grr_response_client.distro_entry:PoolClient",
123+
("fleetspeak_client = "
124+
"grr_response_client.distro_entry:FleetspeakClientWrapper"),
123125
]
124126
},
125127
cmdclass={
@@ -136,6 +138,7 @@ def run(self):
136138
PYTSK3,
137139
"retry==0.9.2",
138140
"libfsntfs-python==20210503",
141+
"fleetspeak-client-bin==0.1.9",
139142
],
140143
extras_require={
141144
# The following requirements are needed in Windows.

grr/core/grr_response_core/lib/util/sqlite.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def Query(self, query: Text) -> Iterator[Tuple]: # pylint: disable=g-bare-gener
3737
Yields:
3838
Database rows that are results of the query.
3939
"""
40-
with contextlib.closing(self._conn.cursor()) as cursor:
40+
with contextlib.closing(self._conn.cursor()) as cursor: # pytype: disable=wrong-arg-types
4141
cursor.execute(query)
4242

4343
while True:
@@ -65,7 +65,7 @@ def IOConnection(db_filedesc: IO[bytes]) -> Iterator[ConnectionContext]:
6565
with io.open(temp_db_filepath, mode="wb") as temp_db_filedesc:
6666
_CopyIO(input=db_filedesc, output=temp_db_filedesc)
6767

68-
with contextlib.closing(sqlite3.connect(temp_db_filepath)) as conn:
68+
with contextlib.closing(sqlite3.connect(temp_db_filepath)) as conn: # pytype: disable=wrong-arg-types
6969
yield ConnectionContext(conn)
7070

7171

grr/core/install_data/etc/grr-server.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ Platform:Darwin:
196196

197197
Client.platform: darwin
198198

199+
Global Install Context:
200+
Client.unprivileged_user: nobody
201+
Client.unprivileged_group: nobody
202+
Client.use_filesystem_sandboxing: True
203+
199204
Client Context:
200205
Logging.engines: stderr,file,syslog
201206

@@ -206,6 +211,12 @@ Platform:Linux:
206211

207212
Client.platform: linux
208213

214+
Global Install Context:
215+
Client.unprivileged_user: _%(Client.name)
216+
Client.unprivileged_group: _%(Client.name)
217+
Client.use_filesystem_sandboxing: True
218+
Client.use_memory_sandboxing: True
219+
209220
Client Context:
210221

211222
Logging.engines: stderr,file,syslog
@@ -233,6 +244,10 @@ Platform:Windows:
233244
- "%(install_path)"
234245
Client.grr_tempdir: "Temp"
235246

247+
Global Install Context:
248+
Client.use_filesystem_sandboxing: True
249+
Client.use_memory_sandboxing: True
250+
236251
Arch:amd64:
237252
ClientBuilder.vs_arch: x64
238253

grr/server/grr_response_server/bin/config_updater_util.py

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import getpass
66
import os
77
import re
8-
import shutil
98
import socket
109
import subprocess
1110
import sys
@@ -27,6 +26,7 @@
2726
from grr_api_client import root as api_root
2827
from grr_response_client_builder import repacking
2928
from grr_response_core import config as grr_config
29+
from grr_response_core.lib import package
3030
from grr_response_core.lib.util import compatibility
3131
from grr_response_server import maintenance_utils
3232
from grr_response_server import server_startup
@@ -331,7 +331,11 @@ def __init__(self):
331331
self.mysql_port = 3306
332332
self.mysql_database: str = None
333333
self.mysql_unix_socket: str = None
334-
self.config_dir = "/etc/fleetspeak-server"
334+
self.config_dir = package.ResourcePath(
335+
"fleetspeak-server-bin", "fleetspeak-server-bin/etc/fleetspeak-server")
336+
self._fleetspeak_config_command_path = package.ResourcePath(
337+
"fleetspeak-server-bin",
338+
"fleetspeak-server-bin/usr/bin/fleetspeak-config")
335339

336340
def Prompt(self, config):
337341
"""Sets up the in-memory configuration interactively."""
@@ -372,9 +376,10 @@ def _ConfigPath(self, *path_components: str) -> str:
372376
return os.path.join(self.config_dir, *path_components)
373377

374378
def _IsFleetspeakPresent(self) -> bool:
379+
"""Returns True, if a fleetspeak server is available on this system."""
375380
if not os.path.exists(self._ConfigPath()):
376381
return False
377-
if not shutil.which("fleetspeak-config"):
382+
if not os.path.exists(self._fleetspeak_config_command_path):
378383
return False
379384
return True
380385

@@ -477,8 +482,9 @@ def _WriteEnabled(self, config):
477482
cp.darwin_client_configuration_file = self._ConfigPath(
478483
"darwin_client.config")
479484

480-
p = subprocess.Popen(["fleetspeak-config", "-config", "/dev/stdin"],
481-
stdin=subprocess.PIPE)
485+
p = subprocess.Popen(
486+
[self._fleetspeak_config_command_path, "-config", "/dev/stdin"],
487+
stdin=subprocess.PIPE)
482488
p.communicate(input=text_format.MessageToString(cp).encode())
483489
if p.wait() != 0:
484490
raise RuntimeError("fleetspeak-config command failed.")
@@ -490,10 +496,10 @@ def _WriteEnabled(self, config):
490496
# pylint: enable=g-import-not-at-top
491497

492498
if (os.geteuid() == 0 and pwd.getpwnam("fleetspeak") and
493-
grp.getgrnam("fleetspeak")):
499+
grp.getgrnam("fleetspeak") and
500+
os.path.exists("/etc/fleetspeak-server")):
494501
subprocess.check_call(
495-
["chown", "-R", "fleetspeak:fleetspeak",
496-
self._ConfigPath()])
502+
["chown", "-R", "fleetspeak:fleetspeak", "/etc/fleetspeak-server"])
497503

498504
try:
499505
os.unlink(self._ConfigPath("disabled"))
@@ -577,35 +583,7 @@ def ConfigureDatastore(config):
577583
"For GRR to work each GRR server has to be able to communicate with\n"
578584
"the datastore. To do this we need to configure a datastore.\n")
579585

580-
existing_datastore = grr_config.CONFIG.Get("Datastore.implementation")
581-
582-
if not existing_datastore or existing_datastore == "FakeDataStore":
583-
ConfigureMySQLDatastore(config)
584-
return
585-
586-
print("Found existing settings:\n REL_DB MySQL database")
587-
if existing_datastore == "SqliteDataStore":
588-
set_up_mysql = RetryBoolQuestion(
589-
"The SQLite datastore is no longer supported. Would you like to\n"
590-
"set up a MySQL datastore? Answering 'no' will abort config "
591-
"initialization.", True)
592-
if set_up_mysql:
593-
print("\nPlease note that no data will be migrated from SQLite to "
594-
"MySQL.\n")
595-
ConfigureMySQLDatastore(config)
596-
else:
597-
raise ConfigInitError()
598-
elif existing_datastore == "MySQLAdvancedDataStore":
599-
set_up_mysql = RetryBoolQuestion(
600-
"The MySQLAdvancedDataStore is no longer supported. Would you like to\n"
601-
"set up a new MySQL datastore? Answering 'no' will abort config "
602-
"initialization.", True)
603-
if set_up_mysql:
604-
print("\nPlease note that no data will be migrated from the old data "
605-
"store.\n")
606-
ConfigureMySQLDatastore(config)
607-
else:
608-
raise ConfigInitError()
586+
ConfigureMySQLDatastore(config)
609587

610588

611589
def ConfigureUrls(config, external_hostname: Optional[Text] = None):
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env python
2+
"""Wrapper for running a fleetspeak server in a virtualenv setup.
3+
4+
This script is meant to be used for development.
5+
6+
Requirements for running this script:
7+
8+
* Running from a virtualenv.
9+
* PIP package `fletspeak-server-bin` is installed.
10+
* `grr_config_updater initialize` has been run.
11+
* Fleetspeak has been enabled.
12+
"""
13+
import os
14+
import subprocess
15+
16+
from absl import app
17+
18+
from grr_response_core.lib import config_lib
19+
from grr_response_core.lib import package
20+
21+
22+
class Error(Exception):
23+
pass
24+
25+
26+
def main(argv):
27+
config_lib.ParseConfigCommandLine()
28+
config_dir = package.ResourcePath(
29+
"fleetspeak-server-bin", "fleetspeak-server-bin/etc/fleetspeak-server")
30+
if not os.path.exists(config_dir):
31+
raise Error(
32+
f"Configuration directory not found: {config_dir}. "
33+
"Please make sure `grr_config_updater initialize` has been run.")
34+
fleetspeak_server = package.ResourcePath(
35+
"fleetspeak-server-bin",
36+
"fleetspeak-server-bin/usr/bin/fleetspeak-server")
37+
if not os.path.exists(fleetspeak_server):
38+
raise Error(
39+
f"Fleetspeak server binary not found: {fleetspeak_server}. "
40+
"Please make sure that the package `fleetspeak-server-bin` has been "
41+
"installed.")
42+
command = [
43+
fleetspeak_server,
44+
"--logtostderr",
45+
"--services_config",
46+
os.path.join(config_dir, "server.services.config"),
47+
"--components_config",
48+
os.path.join(config_dir, "server.components.config"),
49+
]
50+
subprocess.check_call(command)
51+
52+
53+
if __name__ == "__main__":
54+
app.run(main)

0 commit comments

Comments
 (0)