... |
... |
@@ -30,6 +30,8 @@ DATE_TIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
|
30 |
30 |
KEYTAB_FIRST_BYTE = 0x05
|
31 |
31 |
# Default prefix for struct's format strings, defining big-endian byte order:
|
32 |
32 |
BIG_ENDIAN='>'
|
|
33 |
+LITTLE_ENDIAN='<'
|
|
34 |
+NATIVE_ENDIANNESS='='
|
33 |
35 |
DEFAULT_PREFIX=BIG_ENDIAN
|
34 |
36 |
DEFAULT_ENCODING='ascii'
|
35 |
37 |
VERBOSITY=1
|
... |
... |
@@ -102,7 +104,7 @@ def int_to_enc_type(lookup_value):
|
102 |
104 |
return lookup(lookup_value, ENC_TYPES, 'ENCTYPE_UNKNOWN')
|
103 |
105 |
|
104 |
106 |
def principal_to_spn(principal):
|
105 |
|
- if principal['name_type_raw'] != 1:
|
|
107 |
+ if principal.get('name_type_raw') != NAME_TYPES['KRB5_NT_PRINCIPAL']:
|
106 |
108 |
return None
|
107 |
109 |
components = principal['components']
|
108 |
110 |
count = len(components)
|
... |
... |
@@ -145,29 +147,34 @@ def parse_data(buf, prefix=DEFAULT_PREFIX):
|
145 |
147 |
def parse_str(buf, prefix=DEFAULT_PREFIX, encoding=DEFAULT_ENCODING):
|
146 |
148 |
return parse_data(buf, prefix).decode(encoding)
|
147 |
149 |
|
148 |
|
-def parse_principal(buf, prefix=DEFAULT_PREFIX):
|
|
150 |
+def parse_principal(buf, prefix=DEFAULT_PREFIX, version=2):
|
149 |
151 |
principal = {}
|
150 |
152 |
# [1] states "count of components (32 bits)" but [2] says int16:
|
151 |
153 |
component_count = unpack(buf, prefix, 'H')
|
|
154 |
+ # [1] states "[includes realm in version 1]"
|
|
155 |
+ if version == 1:
|
|
156 |
+ component_count -= 1
|
152 |
157 |
principal['realm'] = parse_str(buf, prefix)
|
153 |
158 |
components = []
|
154 |
159 |
for i in range(component_count):
|
155 |
160 |
components.append(parse_str(buf, prefix))
|
156 |
161 |
principal['components'] = components
|
157 |
|
- # [3] states int32:
|
158 |
|
- principal['name_type_raw'] = unpack(buf, prefix, 'i')
|
|
162 |
+ # [1] states "[omitted in version 1]"
|
|
163 |
+ if version != 1:
|
|
164 |
+ # [3] states int32:
|
|
165 |
+ principal['name_type_raw'] = unpack(buf, prefix, 'i')
|
159 |
166 |
return principal
|
160 |
167 |
|
161 |
|
-def parse_entry(buf, prefix=DEFAULT_PREFIX):
|
|
168 |
+def parse_entry(buf, prefix=DEFAULT_PREFIX, version=2):
|
162 |
169 |
entry = {}
|
163 |
|
- entry['principal'] = parse_principal(buf, prefix)
|
|
170 |
+ entry['principal'] = parse_principal(buf, prefix, version)
|
164 |
171 |
entry['timestamp'], entry['kvno'], entry['enctype_raw'], entry['key_length'] = unpack(buf, prefix, 'IBHH')
|
165 |
172 |
entry['key'] = buf.read(entry['key_length'])
|
166 |
173 |
return entry
|
167 |
174 |
|
168 |
|
-def parse_record(buf, prefix=DEFAULT_PREFIX):
|
|
175 |
+def parse_record(buf, prefix=DEFAULT_PREFIX, version=2):
|
169 |
176 |
record = {'type': 'record'}
|
170 |
|
- record['entry'] = parse_entry(buf, prefix)
|
|
177 |
+ record['entry'] = parse_entry(buf, prefix, version)
|
171 |
178 |
record['tail'] = buf.read()
|
172 |
179 |
return record
|
173 |
180 |
|
... |
... |
@@ -175,8 +182,12 @@ def parse_keytab(buf, args):
|
175 |
182 |
second_byte = buf.read(2)[1]
|
176 |
183 |
verbose(2, 'keytab v{}', second_byte)
|
177 |
184 |
if second_byte == 1:
|
178 |
|
- verbose(1, 'Keytab v1 not supported yet!')
|
179 |
|
- sys.exit(1)
|
|
185 |
+ # Version 1 uses native byte order:
|
|
186 |
+ prefix = NATIVE_ENDIANNESS
|
|
187 |
+ if args.v1_endianness == 'big':
|
|
188 |
+ prefix = BIG_ENDIAN
|
|
189 |
+ elif args.v1_endianness == 'little':
|
|
190 |
+ prefix = LITTLE_ENDIAN
|
180 |
191 |
elif second_byte == 2:
|
181 |
192 |
# Version 2 always uses big-endian byte order:
|
182 |
193 |
prefix = BIG_ENDIAN
|
... |
... |
@@ -200,7 +211,7 @@ def parse_keytab(buf, args):
|
200 |
211 |
verbose(3, 'Record #{} of length {}', len(keytab['records']) + 1, record_length)
|
201 |
212 |
record = buf.read(abs(record_length))
|
202 |
213 |
if record_length > 0:
|
203 |
|
- record = parse_record(BufferedReader(BytesIO(record)), prefix)
|
|
214 |
+ record = parse_record(BufferedReader(BytesIO(record)), prefix, second_byte)
|
204 |
215 |
else:
|
205 |
216 |
record = {'type': 'hole', 'data': record}
|
206 |
217 |
record['length'] = record_length
|
... |
... |
@@ -300,6 +311,7 @@ def parse_args():
|
300 |
311 |
parser.add_argument('--verbose', '-v', dest='verbose', action='count', help='increase verbosity level', default=VERBOSITY)
|
301 |
312 |
parser.add_argument('--data-layout', '-l', dest='data_layout', choices=DATA_LAYOUTS.keys(), default='simple', help='data layout (keytab to YAML/JSON only)')
|
302 |
313 |
parser.add_argument('--output-format', '-f', dest='output_format', choices=['json', 'yaml'], default='yaml', help='output format (keytab to YAML/JSON only)')
|
|
314 |
+ parser.add_argument('--v1-endianness', '-e', dest='v1_endianness', choices=['native', 'little', 'big'], default='native', help='Enforce endianness (keytab v1 to YAML/JSON only)')
|
303 |
315 |
parser.add_argument('input', nargs='?', type=argparse.FileType('rb'), default=sys.stdin.buffer, help='input file; defaults to standard input')
|
304 |
316 |
args = parser.parse_args()
|
305 |
317 |
return args
|