dissect.target 3.20.dev47__py3-none-any.whl → 3.20.dev48__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dissect/target/plugins/os/unix/log/utmp.py +47 -68
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev48.dist-info}/METADATA +1 -1
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev48.dist-info}/RECORD +8 -8
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev48.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev48.dist-info}/LICENSE +0 -0
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev48.dist-info}/WHEEL +0 -0
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev48.dist-info}/entry_points.txt +0 -0
- {dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev48.dist-info}/top_level.txt +0 -0
@@ -1,17 +1,17 @@
|
|
1
|
-
import
|
1
|
+
from __future__ import annotations
|
2
|
+
|
2
3
|
import ipaddress
|
3
4
|
import struct
|
4
5
|
from collections import namedtuple
|
5
6
|
from typing import Iterator
|
6
7
|
|
7
8
|
from dissect.cstruct import cstruct
|
8
|
-
from dissect.util.stream import BufferedStream
|
9
9
|
from dissect.util.ts import from_unix
|
10
10
|
|
11
11
|
from dissect.target.exceptions import UnsupportedPluginError
|
12
|
-
from dissect.target.helpers.fsutil import TargetPath
|
12
|
+
from dissect.target.helpers.fsutil import TargetPath, open_decompress
|
13
13
|
from dissect.target.helpers.record import TargetRecordDescriptor
|
14
|
-
from dissect.target.plugin import
|
14
|
+
from dissect.target.plugin import Plugin, alias, export
|
15
15
|
from dissect.target.target import Target
|
16
16
|
|
17
17
|
UTMP_FIELDS = [
|
@@ -27,16 +27,12 @@ UTMP_FIELDS = [
|
|
27
27
|
|
28
28
|
BtmpRecord = TargetRecordDescriptor(
|
29
29
|
"linux/log/btmp",
|
30
|
-
|
31
|
-
*UTMP_FIELDS,
|
32
|
-
],
|
30
|
+
UTMP_FIELDS,
|
33
31
|
)
|
34
32
|
|
35
33
|
WtmpRecord = TargetRecordDescriptor(
|
36
34
|
"linux/log/wtmp",
|
37
|
-
|
38
|
-
*UTMP_FIELDS,
|
39
|
-
],
|
35
|
+
UTMP_FIELDS,
|
40
36
|
)
|
41
37
|
|
42
38
|
utmp_def = """
|
@@ -104,24 +100,13 @@ UTMP_ENTRY = namedtuple(
|
|
104
100
|
class UtmpFile:
|
105
101
|
"""utmp maintains a full accounting of the current status of the system"""
|
106
102
|
|
107
|
-
def __init__(self,
|
108
|
-
self.fh =
|
109
|
-
|
110
|
-
if "gz" in path:
|
111
|
-
self.compressed = True
|
112
|
-
else:
|
113
|
-
self.compressed = False
|
103
|
+
def __init__(self, path: TargetPath):
|
104
|
+
self.fh = open_decompress(path, "rb")
|
114
105
|
|
115
106
|
def __iter__(self):
|
116
|
-
if self.compressed:
|
117
|
-
gzip_entry = BufferedStream(gzip.open(self.fh, mode="rb"))
|
118
|
-
byte_stream = gzip_entry
|
119
|
-
else:
|
120
|
-
byte_stream = self.fh
|
121
|
-
|
122
107
|
while True:
|
123
108
|
try:
|
124
|
-
entry = c_utmp.entry(
|
109
|
+
entry = c_utmp.entry(self.fh)
|
125
110
|
|
126
111
|
r_type = ""
|
127
112
|
if entry.ut_type in c_utmp.Type:
|
@@ -151,7 +136,7 @@ class UtmpFile:
|
|
151
136
|
# ut_addr_v6 is parsed as IPv4 address. This could not lead to incorrect results.
|
152
137
|
ut_addr = ipaddress.ip_address(struct.pack("<i", entry.ut_addr_v6[0]))
|
153
138
|
|
154
|
-
|
139
|
+
yield UTMP_ENTRY(
|
155
140
|
ts=from_unix(entry.ut_tv.tv_sec),
|
156
141
|
ut_type=r_type,
|
157
142
|
ut_pid=entry.ut_pid,
|
@@ -162,7 +147,6 @@ class UtmpFile:
|
|
162
147
|
ut_addr=ut_addr,
|
163
148
|
)
|
164
149
|
|
165
|
-
yield utmp_entry
|
166
150
|
except EOFError:
|
167
151
|
break
|
168
152
|
|
@@ -170,17 +154,28 @@ class UtmpFile:
|
|
170
154
|
class UtmpPlugin(Plugin):
|
171
155
|
"""Unix utmp log plugin."""
|
172
156
|
|
173
|
-
|
174
|
-
|
157
|
+
def __init__(self, target: Target):
|
158
|
+
super().__init__(target)
|
159
|
+
self.btmp_paths = list(self.target.fs.path("/").glob("var/log/btmp*"))
|
160
|
+
self.wtmp_paths = list(self.target.fs.path("/").glob("var/log/wtmp*"))
|
161
|
+
self.utmp_paths = list(self.target.fs.path("/").glob("var/run/utmp*"))
|
175
162
|
|
176
163
|
def check_compatible(self) -> None:
|
177
|
-
if not self.
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
164
|
+
if not any(self.btmp_paths + self.wtmp_paths + self.utmp_paths):
|
165
|
+
raise UnsupportedPluginError("No wtmp and/or btmp log files found")
|
166
|
+
|
167
|
+
def _build_record(self, record: TargetRecordDescriptor, entry: UTMP_ENTRY) -> Iterator[BtmpRecord | WtmpRecord]:
|
168
|
+
return record(
|
169
|
+
ts=entry.ts,
|
170
|
+
ut_type=entry.ut_type,
|
171
|
+
ut_pid=entry.ut_pid,
|
172
|
+
ut_user=entry.ut_user,
|
173
|
+
ut_line=entry.ut_line,
|
174
|
+
ut_id=entry.ut_id,
|
175
|
+
ut_host=entry.ut_host,
|
176
|
+
ut_addr=entry.ut_addr,
|
177
|
+
_target=self.target,
|
178
|
+
)
|
184
179
|
|
185
180
|
@export(record=BtmpRecord)
|
186
181
|
def btmp(self) -> Iterator[BtmpRecord]:
|
@@ -192,26 +187,18 @@ class UtmpPlugin(Plugin):
|
|
192
187
|
- https://en.wikipedia.org/wiki/Utmp
|
193
188
|
- https://www.thegeekdiary.com/what-is-the-purpose-of-utmp-wtmp-and-btmp-files-in-linux/
|
194
189
|
"""
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
for entry in btmp:
|
200
|
-
yield BtmpRecord(
|
201
|
-
ts=entry.ts,
|
202
|
-
ut_type=entry.ut_type,
|
203
|
-
ut_pid=entry.ut_pid,
|
204
|
-
ut_user=entry.ut_user,
|
205
|
-
ut_line=entry.ut_line,
|
206
|
-
ut_id=entry.ut_id,
|
207
|
-
ut_host=entry.ut_host,
|
208
|
-
ut_addr=entry.ut_addr,
|
209
|
-
_target=self.target,
|
210
|
-
)
|
190
|
+
for path in self.btmp_paths:
|
191
|
+
if not path.is_file():
|
192
|
+
self.target.log.warning("Unable to parse btmp file: %s is not a file", path)
|
193
|
+
continue
|
211
194
|
|
195
|
+
for entry in UtmpFile(path):
|
196
|
+
yield self._build_record(BtmpRecord, entry)
|
197
|
+
|
198
|
+
@alias("utmp")
|
212
199
|
@export(record=WtmpRecord)
|
213
200
|
def wtmp(self) -> Iterator[WtmpRecord]:
|
214
|
-
"""
|
201
|
+
"""Yield contents of wtmp log files.
|
215
202
|
|
216
203
|
The wtmp file contains the historical data of the utmp file. The utmp file contains information about users
|
217
204
|
logins at which terminals, logouts, system events and current status of the system, system boot time
|
@@ -220,19 +207,11 @@ class UtmpPlugin(Plugin):
|
|
220
207
|
References:
|
221
208
|
- https://www.thegeekdiary.com/what-is-the-purpose-of-utmp-wtmp-and-btmp-files-in-linux/
|
222
209
|
"""
|
223
|
-
|
224
|
-
for
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
ut_pid=entry.ut_pid,
|
232
|
-
ut_user=entry.ut_user,
|
233
|
-
ut_line=entry.ut_line,
|
234
|
-
ut_id=entry.ut_id,
|
235
|
-
ut_host=entry.ut_host,
|
236
|
-
ut_addr=entry.ut_addr,
|
237
|
-
_target=self.target,
|
238
|
-
)
|
210
|
+
|
211
|
+
for path in self.wtmp_paths + self.utmp_paths:
|
212
|
+
if not path.is_file():
|
213
|
+
self.target.log.warning("Unable to parse wtmp file: %s is not a file", path)
|
214
|
+
continue
|
215
|
+
|
216
|
+
for entry in UtmpFile(path):
|
217
|
+
yield self._build_record(WtmpRecord, entry)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dissect.target
|
3
|
-
Version: 3.20.
|
3
|
+
Version: 3.20.dev48
|
4
4
|
Summary: This module ties all other Dissect modules together, it provides a programming API and command line tools which allow easy access to various data sources inside disk images or file collections (a.k.a. targets)
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
6
6
|
License: Affero General Public License v3
|
@@ -272,7 +272,7 @@ dissect/target/plugins/os/unix/log/auth.py,sha256=9NJvlo7Vbsp_ENJFpKd04PH_sUuOy6
|
|
272
272
|
dissect/target/plugins/os/unix/log/journal.py,sha256=xe8p8MM_95uYjFNzNSP5IsoIthJtxwFEDicYR42RYAI,17681
|
273
273
|
dissect/target/plugins/os/unix/log/lastlog.py,sha256=Wr3-2n1-GwckN9mSx-yM55N6_L0PQyx6TGHoEvuc6c0,2515
|
274
274
|
dissect/target/plugins/os/unix/log/messages.py,sha256=XtjZ0a2budgQm_K5JT3fMf7JcjuD0AelcD3zOFN2xpI,5732
|
275
|
-
dissect/target/plugins/os/unix/log/utmp.py,sha256=
|
275
|
+
dissect/target/plugins/os/unix/log/utmp.py,sha256=k2A69s2qUT2JunJrH8GO6nQ0zMDotXMTaj8OzQ7ljj8,7336
|
276
276
|
dissect/target/plugins/os/windows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
277
277
|
dissect/target/plugins/os/windows/_os.py,sha256=-Bsp9696JqU7luh_AbqojzG9BxVdYIFl5Ma-LiFBQBo,12505
|
278
278
|
dissect/target/plugins/os/windows/activitiescache.py,sha256=BbGD-vETHm1IRMoazVer_vqSJIoQxxhWcJ_xlBeOMds,6899
|
@@ -378,10 +378,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
|
|
378
378
|
dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
|
379
379
|
dissect/target/volumes/md.py,sha256=7ShPtusuLGaIv27SvEETtgsuoQyAa4iAAeOR1NEaajI,1689
|
380
380
|
dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
|
381
|
-
dissect.target-3.20.
|
382
|
-
dissect.target-3.20.
|
383
|
-
dissect.target-3.20.
|
384
|
-
dissect.target-3.20.
|
385
|
-
dissect.target-3.20.
|
386
|
-
dissect.target-3.20.
|
387
|
-
dissect.target-3.20.
|
381
|
+
dissect.target-3.20.dev48.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
|
382
|
+
dissect.target-3.20.dev48.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
383
|
+
dissect.target-3.20.dev48.dist-info/METADATA,sha256=coXjiskalhbUYyedrn0Fe49ZmJvIbeAaMYawTB3Q9QQ,12897
|
384
|
+
dissect.target-3.20.dev48.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
385
|
+
dissect.target-3.20.dev48.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
|
386
|
+
dissect.target-3.20.dev48.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
387
|
+
dissect.target-3.20.dev48.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
{dissect.target-3.20.dev47.dist-info → dissect.target-3.20.dev48.dist-info}/entry_points.txt
RENAMED
File without changes
|
File without changes
|