OLD | NEW |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """Parser for Linux utmp files.""" | 2 """Parser for Linux utmp files.""" |
3 | 3 |
4 from __future__ import unicode_literals | 4 from __future__ import unicode_literals |
5 | 5 |
6 from dfdatetime import posix_time as dfdatetime_posix_time | 6 from dfdatetime import posix_time as dfdatetime_posix_time |
7 | 7 |
8 from plaso.containers import events | 8 from plaso.containers import events |
9 from plaso.containers import time_events | 9 from plaso.containers import time_events |
10 from plaso.lib import errors | 10 from plaso.lib import errors |
11 from plaso.lib import definitions | 11 from plaso.lib import definitions |
12 from plaso.parsers import dtfabric_parser | 12 from plaso.parsers import dtfabric_parser |
13 from plaso.parsers import manager | 13 from plaso.parsers import manager |
14 | 14 |
15 | 15 |
16 class UtmpEventData(events.EventData): | 16 class UtmpEventData(events.EventData): |
17 """utmp event data. | 17 """utmp event data. |
18 | 18 |
19 Attributes: | 19 Attributes: |
20 computer_name (str): name of the computer. | |
21 exit_status (int): exit status. | 20 exit_status (int): exit status. |
| 21 hostname (str): hostname or IP address. |
22 ip_address (str): IP address from the connection. | 22 ip_address (str): IP address from the connection. |
23 pid (int): process identifier (PID). | 23 pid (int): process identifier (PID). |
| 24 terminal_identifier (int): inittab identifier. |
24 terminal (str): type of terminal. | 25 terminal (str): type of terminal. |
25 terminal_identifier (int): inittab identifier. | |
26 type (int): type of login. | 26 type (int): type of login. |
27 username (str): user name. | 27 username (str): user name. |
28 """ | 28 """ |
29 | 29 |
30 DATA_TYPE = 'linux:utmp:event' | 30 DATA_TYPE = 'linux:utmp:event' |
31 | 31 |
32 def __init__(self): | 32 def __init__(self): |
33 """Initializes event data.""" | 33 """Initializes event data.""" |
34 super(UtmpEventData, self).__init__(data_type=self.DATA_TYPE) | 34 super(UtmpEventData, self).__init__(data_type=self.DATA_TYPE) |
35 self.computer_name = None | |
36 self.exit_status = None | 35 self.exit_status = None |
| 36 self.hostname = None |
37 self.ip_address = None | 37 self.ip_address = None |
38 self.pid = None | 38 self.pid = None |
| 39 self.terminal_identifier = None |
39 self.terminal = None | 40 self.terminal = None |
40 self.terminal_identifier = None | |
41 self.type = None | 41 self.type = None |
42 self.username = None | 42 self.username = None |
43 | 43 |
44 | 44 |
45 class UtmpParser(dtfabric_parser.DtFabricBaseParser): | 45 class UtmpParser(dtfabric_parser.DtFabricBaseParser): |
46 """Parser for Linux/Unix utmp files.""" | 46 """Parser for Linux libc6 utmp files.""" |
47 | 47 |
48 NAME = 'utmp' | 48 NAME = 'utmp' |
49 DESCRIPTION = 'Parser for Linux/Unix utmp files.' | 49 DESCRIPTION = 'Parser for Linux libc6 utmp files.' |
50 | 50 |
51 _DEFINITION_FILE = 'utmp.yaml' | 51 _DEFINITION_FILE = 'utmp.yaml' |
52 | 52 |
53 _EMPTY_IP_ADDRESS = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | 53 _EMPTY_IP_ADDRESS = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
54 | 54 |
55 _SUPPORTED_TYPES = frozenset(range(0, 10)) | 55 _SUPPORTED_TYPES = frozenset(range(0, 10)) |
56 | 56 |
57 def _ReadEntry(self, parser_mediator, file_object, file_offset): | 57 def _ReadEntry(self, parser_mediator, file_object, file_offset): |
58 """Reads an utmp entry. | 58 """Reads an utmp entry. |
59 | 59 |
60 Args: | 60 Args: |
61 parser_mediator (ParserMediator): mediates interactions between parsers | 61 parser_mediator (ParserMediator): mediates interactions between parsers |
62 and other components, such as storage and dfvfs. | 62 and other components, such as storage and dfvfs. |
63 file_object (dfvfs.FileIO): a file-like object. | 63 file_object (dfvfs.FileIO): a file-like object. |
64 file_offset (int): offset of the data relative to the start of | 64 file_offset (int): offset of the data relative to the start of |
65 the file-like object. | 65 the file-like object. |
66 | 66 |
67 Returns: | 67 Returns: |
68 tuple: contains: | 68 tuple: contains: |
69 | 69 |
70 int: timestamp, which contains the number of microseconds | 70 int: timestamp, which contains the number of microseconds |
71 since January 1, 1970, 00:00:00 UTC. | 71 since January 1, 1970, 00:00:00 UTC. |
72 UtmpEventData: event data of the utmp entry read. | 72 UtmpEventData: event data of the utmp entry read. |
73 | 73 |
74 Raises: | 74 Raises: |
75 ParseError: if the entry cannot be parsed. | 75 ParseError: if the entry cannot be parsed. |
76 """ | 76 """ |
77 entry_map = self._GetDataTypeMap('utmp_entry') | 77 entry_map = self._GetDataTypeMap('linux_libc6_utmp_entry') |
78 | 78 |
79 try: | 79 try: |
80 entry, _ = self._ReadStructureFromFileObject( | 80 entry, _ = self._ReadStructureFromFileObject( |
81 file_object, file_offset, entry_map) | 81 file_object, file_offset, entry_map) |
82 except (ValueError, errors.ParseError) as exception: | 82 except (ValueError, errors.ParseError) as exception: |
83 raise errors.ParseError(( | 83 raise errors.ParseError(( |
84 'Unable to parse utmp entry at offset: 0x{0:08x} with error: ' | 84 'Unable to parse utmp entry at offset: 0x{0:08x} with error: ' |
85 '{1!s}.').format(file_offset, exception)) | 85 '{1!s}.').format(file_offset, exception)) |
86 | 86 |
87 if entry.type not in self._SUPPORTED_TYPES: | 87 if entry.type not in self._SUPPORTED_TYPES: |
88 raise errors.UnableToParseFile('Unsupported type: {0:d}'.format( | 88 raise errors.UnableToParseFile('Unsupported type: {0:d}'.format( |
89 entry.type)) | 89 entry.type)) |
90 | 90 |
91 encoding = parser_mediator.codepage or 'utf-8' | 91 encoding = parser_mediator.codepage or 'utf-8' |
92 | 92 |
93 try: | 93 try: |
94 username = entry.username.rstrip(b'\x00') | 94 username = entry.username.split(b'\x00')[0] |
95 username = username.decode(encoding) | 95 username = username.decode(encoding) |
96 except UnicodeDecodeError: | 96 except UnicodeDecodeError: |
97 parser_mediator.ProduceExtractionError('unable to decode username string') | 97 parser_mediator.ProduceExtractionError('unable to decode username string') |
98 username = None | 98 username = None |
99 | 99 |
100 try: | 100 try: |
101 terminal = entry.terminal.rstrip(b'\x00') | 101 terminal = entry.terminal.split(b'\x00')[0] |
102 terminal = terminal.decode(encoding) | 102 terminal = terminal.decode(encoding) |
103 except UnicodeDecodeError: | 103 except UnicodeDecodeError: |
104 parser_mediator.ProduceExtractionError('unable to decode terminal string') | 104 parser_mediator.ProduceExtractionError('unable to decode terminal string') |
105 terminal = None | 105 terminal = None |
106 | 106 |
107 if terminal == '~': | 107 if terminal == '~': |
108 terminal = 'system boot' | 108 terminal = 'system boot' |
109 | 109 |
110 try: | 110 try: |
111 hostname = entry.hostname.rstrip(b'\x00') | 111 hostname = entry.hostname.split(b'\x00')[0] |
112 hostname = hostname.decode(encoding) | 112 hostname = hostname.decode(encoding) |
113 except UnicodeDecodeError: | 113 except UnicodeDecodeError: |
114 parser_mediator.ProduceExtractionError('unable to decode hostname string') | 114 parser_mediator.ProduceExtractionError('unable to decode hostname string') |
115 hostname = None | 115 hostname = None |
116 | 116 |
117 if not hostname or hostname == ':0': | 117 if not hostname or hostname == ':0': |
118 hostname = 'localhost' | 118 hostname = 'localhost' |
119 | 119 |
120 if entry.ip_address[4:] == self._EMPTY_IP_ADDRESS[4:]: | 120 if entry.ip_address[4:] == self._EMPTY_IP_ADDRESS[4:]: |
121 ip_address = self._FormatPackedIPv4Address(entry.ip_address[:4]) | 121 ip_address = self._FormatPackedIPv4Address(entry.ip_address[:4]) |
122 else: | 122 else: |
123 ip_address = self._FormatPackedIPv6Address(entry.ip_address) | 123 ip_address = self._FormatPackedIPv6Address(entry.ip_address) |
124 | 124 |
125 # TODO: add termination status. | 125 # TODO: add termination status. |
126 # TODO: rename event data attributes to match data definition. | |
127 event_data = UtmpEventData() | 126 event_data = UtmpEventData() |
128 event_data.computer_name = hostname | 127 event_data.hostname = hostname |
129 event_data.exit_status = entry.exit_status | 128 event_data.exit_status = entry.exit_status |
130 event_data.ip_address = ip_address | 129 event_data.ip_address = ip_address |
| 130 event_data.offset = file_offset |
131 event_data.pid = entry.pid | 131 event_data.pid = entry.pid |
132 event_data.terminal = terminal | 132 event_data.terminal = terminal |
133 event_data.terminal_identifier = entry.terminal_identifier | 133 event_data.terminal_identifier = entry.terminal_identifier |
134 event_data.type = entry.type | 134 event_data.type = entry.type |
135 event_data.username = username | 135 event_data.username = username |
136 | 136 |
137 timestamp = entry.microseconds + ( | 137 timestamp = entry.microseconds + ( |
138 entry.timestamp * definitions.MICROSECONDS_PER_SECOND) | 138 entry.timestamp * definitions.MICROSECONDS_PER_SECOND) |
139 return timestamp, event_data | 139 return timestamp, event_data |
140 | 140 |
141 def ParseFileObject(self, parser_mediator, file_object, **kwargs): | 141 def ParseFileObject(self, parser_mediator, file_object, **kwargs): |
142 """Parses an utmp file-like object. | 142 """Parses an utmp file-like object. |
143 | 143 |
144 Args: | 144 Args: |
145 parser_mediator (ParserMediator): mediates interactions between parsers | 145 parser_mediator (ParserMediator): mediates interactions between parsers |
146 and other components, such as storage and dfvfs. | 146 and other components, such as storage and dfvfs. |
147 file_object (dfvfs.FileIO): a file-like object. | 147 file_object (dfvfs.FileIO): a file-like object. |
148 | 148 |
149 Raises: | 149 Raises: |
150 UnableToParseFile: when the file cannot be parsed. | 150 UnableToParseFile: when the file cannot be parsed. |
151 """ | 151 """ |
152 file_offset = 0 | 152 file_offset = 0 |
153 | 153 |
154 try: | 154 try: |
155 timestamp, event_data = self._ReadEntry( | 155 timestamp, event_data = self._ReadEntry( |
156 parser_mediator, file_object, file_offset) | 156 parser_mediator, file_object, file_offset) |
157 except errors.ParseError as exception: | 157 except errors.ParseError as exception: |
158 raise errors.UnableToParseFile( | 158 raise errors.UnableToParseFile( |
159 'Unable to parse utmp header with error: {0!s}'.format(exception)) | 159 'Unable to parse first utmp entry with error: {0!s}'.format( |
| 160 exception)) |
160 | 161 |
161 if not event_data.username: | 162 if not event_data.username: |
162 raise errors.UnableToParseFile( | 163 raise errors.UnableToParseFile( |
163 'Unable to parse utmp header with error: missing username') | 164 'Unable to parse first utmp entry with error: missing username') |
164 | 165 |
165 if not timestamp: | 166 if not timestamp: |
166 raise errors.UnableToParseFile( | 167 raise errors.UnableToParseFile( |
167 'Unable to parse utmp header with error: missing timestamp') | 168 'Unable to parse first utmp entry with error: missing timestamp') |
168 | 169 |
169 date_time = dfdatetime_posix_time.PosixTimeInMicroseconds( | 170 date_time = dfdatetime_posix_time.PosixTimeInMicroseconds( |
170 timestamp=timestamp) | 171 timestamp=timestamp) |
171 event = time_events.DateTimeValuesEvent( | 172 event = time_events.DateTimeValuesEvent( |
172 date_time, definitions.TIME_DESCRIPTION_START) | 173 date_time, definitions.TIME_DESCRIPTION_START) |
173 parser_mediator.ProduceEventWithEventData(event, event_data) | 174 parser_mediator.ProduceEventWithEventData(event, event_data) |
174 | 175 |
175 file_offset = file_object.tell() | 176 file_offset = file_object.tell() |
176 file_size = file_object.get_size() | 177 file_size = file_object.get_size() |
177 | 178 |
(...skipping 11 matching lines...) Expand all Loading... |
189 date_time = dfdatetime_posix_time.PosixTimeInMicroseconds( | 190 date_time = dfdatetime_posix_time.PosixTimeInMicroseconds( |
190 timestamp=timestamp) | 191 timestamp=timestamp) |
191 event = time_events.DateTimeValuesEvent( | 192 event = time_events.DateTimeValuesEvent( |
192 date_time, definitions.TIME_DESCRIPTION_START) | 193 date_time, definitions.TIME_DESCRIPTION_START) |
193 parser_mediator.ProduceEventWithEventData(event, event_data) | 194 parser_mediator.ProduceEventWithEventData(event, event_data) |
194 | 195 |
195 file_offset = file_object.tell() | 196 file_offset = file_object.tell() |
196 | 197 |
197 | 198 |
198 manager.ParsersManager.RegisterParser(UtmpParser) | 199 manager.ParsersManager.RegisterParser(UtmpParser) |
OLD | NEW |