1use crate::core::TicketCred;
2use chrono::Local;
3use kerberos_asn1::{
4 ApReq, AsRep, AsReq, Asn1Object, Checksum, EncryptedData, EncryptionKey, EtypeInfo2, EtypeInfo2Entry, KdcReqBody,
5 KerbPaPacRequest, KerberosTime, KrbCredInfo, KrbError, PaData, PaForUser, PaPacOptions, PrincipalName, TgsRep,
6 TgsReq, Ticket,
7};
8use kerberos_constants::{
9 ap_options, checksum_types, error_codes, etypes, kdc_options, message_types, pa_data_types, pa_pac_options,
10 principal_names, ticket_flags,
11};
12
13const NONE: &str = "-";
14const UNKNOWN: &str = "???";
15const INDENT_STEP: usize = 4;
16
17pub fn ticket_cred_to_string(tc: &TicketCred, indent_level: usize) -> String
18{
19 let indentation = indent(indent_level);
20 format!(
21 "{}[Ticket]\n\
22 {}\n\
23 {}[KrbCredInfo]\n\
24 {}",
25 indentation,
26 ticket_to_string(&tc.ticket, indent_level),
27 indentation,
28 krb_cred_info_to_string(&tc.cred_info, indent_level)
29 )
30}
31
32pub fn krb_error_to_string(ke: &KrbError, indent_level: usize) -> String
33{
34 let indentation = indent(indent_level);
35 format!(
36 "{}pvno: {}\n\
37 {}msg-type: {}\n\
38 {}ctime: {}\n\
39 {}cusec: {}\n\
40 {}stime: {}\n\
41 {}susec: {}\n\
42 {}error-code: {}\n\
43 {}crealm: {}\n\
44 {}cname:{}\n\
45 {}realm: {}\n\
46 {}sname:\n{}\n\
47 {}e-text: {}\n\
48 {}e-data: {}",
49 indentation,
50 ke.pvno,
51 indentation,
52 msg_type_to_string(ke.msg_type),
53 indentation,
54 ke.ctime.as_ref().map(kerberos_time_to_string).unwrap_or(NONE.into()),
55 indentation,
56 ke.cusec.map(|v| format!("{}", v)).unwrap_or(NONE.into()),
57 indentation,
58 kerberos_time_to_string(&ke.stime),
59 indentation,
60 ke.susec,
61 indentation,
62 error_code_to_string(ke.error_code),
63 indentation,
64 ke.crealm.as_ref().unwrap_or(&NONE.into()),
65 indentation,
66 ke.cname
67 .as_ref()
68 .map(|v| format!("\n{}", principal_name_to_string(v, indent_level + INDENT_STEP)))
69 .unwrap_or(NONE.into()),
70 indentation,
71 ke.realm,
72 indentation,
73 principal_name_to_string(&ke.sname, indent_level + INDENT_STEP),
74 indentation,
75 ke.e_text.as_ref().unwrap_or(&NONE.into()),
76 indentation,
77 ke.e_data.as_ref().map(|v| octet_string_to_string(v)).unwrap_or(NONE.into()),
78 )
79}
80
81pub fn error_code_to_string(ec: i32) -> String
82{
83 format!("{} -> {}", ec, error_code_name(ec))
84}
85
86pub fn error_code_name(ec: i32) -> &'static str
87{
88 match ec
89 {
90 error_codes::KDC_ERR_NONE => "kdc-err-none",
91 error_codes::KDC_ERR_NAME_EXP => "kdc-err-name-exp",
92 error_codes::KDC_ERR_SERVICE_EXP => "kdc-err-service-exp",
93 error_codes::KDC_ERR_BAD_PVNO => "kdc-err-bad-pvno",
94 error_codes::KDC_ERR_C_OLD_MAST_KVNO => "kdc-err-c-old-mast-kvno",
95 error_codes::KDC_ERR_S_OLD_MAST_KVNO => "kdc-err-s-old-mast-kvno",
96 error_codes::KDC_ERR_C_PRINCIPAL_UNKNOWN => "kdc-err-c-principal-unknown",
97 error_codes::KDC_ERR_S_PRINCIPAL_UNKNOWN => "kdc-err-s-principal-unknown",
98 error_codes::KDC_ERR_PRINCIPAL_NOT_UNIQUE => "kdc-err-principal-not-unique",
99 error_codes::KDC_ERR_NULL_KEY => "kdc-err-null-key",
100 error_codes::KDC_ERR_CANNOT_POSTDATE => "kdc-err-cannot-postdate",
101 error_codes::KDC_ERR_NEVER_VALID => "kdc-err-never-valid",
102 error_codes::KDC_ERR_POLICY => "kdc-err-policy",
103 error_codes::KDC_ERR_BADOPTION => "kdc-err-badoption",
104 error_codes::KDC_ERR_ETYPE_NOSUPP => "kdc-err-etype-nosupp",
105 error_codes::KDC_ERR_SUMTYPE_NOSUPP => "kdc-err-sumtype-nosupp",
106 error_codes::KDC_ERR_PADATA_TYPE_NOSUPP => "kdc-err-padata-type-nosupp",
107 error_codes::KDC_ERR_TRTYPE_NOSUPP => "kdc-err-trtype-nosupp",
108 error_codes::KDC_ERR_CLIENT_REVOKED => "kdc-err-client-revoked",
109 error_codes::KDC_ERR_SERVICE_REVOKED => "kdc-err-service-revoked",
110 error_codes::KDC_ERR_TGT_REVOKED => "kdc-err-tgt-revoked",
111 error_codes::KDC_ERR_CLIENT_NOTYET => "kdc-err-client-notyet",
112 error_codes::KDC_ERR_SERVICE_NOTYET => "kdc-err-service-notyet",
113 error_codes::KDC_ERR_KEY_EXPIRED => "kdc-err-key-expired",
114 error_codes::KDC_ERR_PREAUTH_FAILED => "kdc-err-preauth-failed",
115 error_codes::KDC_ERR_PREAUTH_REQUIRED => "kdc-err-preauth-required",
116 error_codes::KDC_ERR_SERVER_NOMATCH => "kdc-err-server-nomatch",
117 error_codes::KDC_ERR_MUST_USE_USER2USER => "kdc-err-must-use-user2user",
118 error_codes::KDC_ERR_PATH_NOT_ACCEPTED => "kdc-err-path-not-accepted",
119 error_codes::KDC_ERR_SVC_UNAVAILABLE => "kdc-err-svc-unavailable",
120 error_codes::KRB_AP_ERR_BAD_INTEGRITY => "krb-ap-err-bad-integrity",
121 error_codes::KRB_AP_ERR_TKT_EXPIRED => "krb-ap-tkt-expired",
122 error_codes::KRB_AP_ERR_TKT_NYV => "krb-ap-err-tkt-nyv",
123 error_codes::KRB_AP_ERR_REPEAT => "krb-ap-err-repeat",
124 error_codes::KRB_AP_ERR_NOT_US => "krb-ap-err-not-us",
125 error_codes::KRB_AP_ERR_BADMATCH => "krb-ap-err-badmatch",
126 error_codes::KRB_AP_ERR_SKEW => "krb-ap-err-skew",
127 error_codes::KRB_AP_ERR_BADADDR => "krb-ap-err-badaddr",
128 error_codes::KRB_AP_ERR_BADVERSION => "krb-ap-err-badversion",
129 error_codes::KRB_AP_ERR_MSG_TYPE => "krb-ap-err-msg-type",
130 error_codes::KRB_AP_ERR_MODIFIED => "krb-ap-err-modified",
131 error_codes::KRB_AP_ERR_BADORDER => "krb-ap-err-badorder",
132 error_codes::KRB_AP_ERR_BADKEYVER => "krb-ap-err-badkeyver",
133 error_codes::KRB_AP_ERR_NOKEY => "krb-ap-err-nokey",
134 error_codes::KRB_AP_ERR_MUT_FAIL => "krb-ap-err-mut-fail",
135 error_codes::KRB_AP_ERR_BADDIRECTION => "krb-ap-err-baddirection",
136 error_codes::KRB_AP_ERR_METHOD => "krb-ap-err-method",
137 error_codes::KRB_AP_ERR_BADSEQ => "krb-ap-err-badseq",
138 error_codes::KRB_AP_ERR_INAPP_CKSUM => "krb-ap-err-inapp-cksum",
139 error_codes::KRB_AP_PATH_NOT_ACCEPTED => "krb-ap-path-not-accepted",
140 error_codes::KRB_ERR_RESPONSE_TOO_BIG => "krb-err-response-too-big",
141 error_codes::KRB_ERR_GENERIC => "krb-err-generic",
142 error_codes::KRB_ERR_FIELD_TOOLONG => "krb-err-field-toolong",
143 error_codes::KDC_ERROR_CLIENT_NOT_TRUSTED => "kdc-error-client-not-trusted",
144 error_codes::KDC_ERROR_KDC_NOT_TRUSTED => "kdc-error-kdc-not-trusted",
145 error_codes::KDC_ERROR_INVALID_SIG => "kdc-error-invalid-sig",
146 error_codes::KDC_ERR_KEY_TOO_WEAK => "kdc-err-key-too-weak",
147 error_codes::KDC_ERR_CERTIFICATE_MISMATCH => "kdc-err-certificate-mismatch",
148 error_codes::KRB_AP_ERR_NO_TGT => "krb-ap-err-no-tgt",
149 error_codes::KDC_ERR_WRONG_REALM => "kdc-err-wrong-realm",
150 error_codes::KRB_AP_ERR_USER_TO_USER_REQUIRED => "krb-ap-err-user-to-user-required",
151 error_codes::KDC_ERR_CANT_VERIFY_CERTIFICATE => "kdc-err-cant-verify-certificate",
152 error_codes::KDC_ERR_INVALID_CERTIFICATE => "kdc-err-invalid-certificate",
153 error_codes::KDC_ERR_REVOKED_CERTIFICATE => "kdc-err-revoked-certificate",
154 error_codes::KDC_ERR_REVOCATION_STATUS_UNKNOWN => "kdc-err-revocation-status-unknown",
155 error_codes::KDC_ERR_REVOCATION_STATUS_UNAVAILABLE => "kdc-err-revocation-status-unavailable",
156 error_codes::KDC_ERR_CLIENT_NAME_MISMATCH => "kdc-err-client-name-mismatch",
157 error_codes::KDC_ERR_KDC_NAME_MISMATCH => "kdc-err-kdc-name-mismatch",
158 _ => UNKNOWN,
159 }
160}
161
162pub fn as_req_to_string(ar: &AsReq, indent_level: usize) -> String
163{
164 let indentation = indent(indent_level);
165 format!(
166 "{}pvno: {}\n\
167 {}msg-type: {}\n\
168 {}padata: {}\n\
169 {}req-body:\n{}",
170 indentation,
171 ar.pvno,
172 indentation,
173 msg_type_to_string(ar.msg_type),
174 indentation,
175 &ar.padata
176 .as_ref()
177 .map(|pds| format!("\n{}", padatas_to_string(pds, indent_level + INDENT_STEP)))
178 .unwrap_or(NONE.into()),
179 indentation,
180 kdc_req_body_to_string(&ar.req_body, indent_level + INDENT_STEP)
181 )
182}
183
184pub fn tgs_req_to_string(tr: &TgsReq, indent_level: usize) -> String
185{
186 let indentation = indent(indent_level);
187 format!(
188 "{}pvno: {}\n\
189 {}msg-type: {}\n\
190 {}padata: {}\n\
191 {}req-body:\n{}",
192 indentation,
193 tr.pvno,
194 indentation,
195 msg_type_to_string(tr.msg_type),
196 indentation,
197 &tr.padata
198 .as_ref()
199 .map(|pds| format!("\n{}", padatas_to_string(pds, indent_level + INDENT_STEP)))
200 .unwrap_or(NONE.into()),
201 indentation,
202 kdc_req_body_to_string(&tr.req_body, indent_level + INDENT_STEP)
203 )
204}
205
206pub fn kdc_req_body_to_string(krb: &KdcReqBody, indent_level: usize) -> String
207{
208 let indentation = indent(indent_level);
209 format!(
210 "{}kdc-options: {}\n\
211 {}cname:{}\n\
212 {}realm: {}\n\
213 {}sname:\n{}\n\
214 {}from: {}\n\
215 {}till: {}\n\
216 {}rtime: {}\n\
217 {}nonce: {}\n\
218 {}etypes:\n{}\n\
219 {}addresses: <Not Implemented>\n\
220 {}enc-authorization-data:{}\n\
221 {}additional-tickets:{}",
222 indentation,
223 kdc_options_to_string(krb.kdc_options.flags),
224 indentation,
225 krb.cname
226 .as_ref()
227 .map(|v| format!("\n{}", principal_name_to_string(v, indent_level + INDENT_STEP)))
228 .unwrap_or(format!(" {}", NONE)),
229 indentation,
230 krb.realm,
231 indentation,
232 krb.sname.as_ref().map(|v| principal_name_to_string(v, indent_level + INDENT_STEP)).unwrap_or(NONE.into()),
233 indentation,
234 krb.from.as_ref().map(kerberos_time_to_string).unwrap_or(NONE.into()),
235 indentation,
236 kerberos_time_to_string(&krb.till),
237 indentation,
238 krb.rtime.as_ref().map(kerberos_time_to_string).unwrap_or(NONE.into()),
239 indentation,
240 krb.nonce,
241 indentation,
242 etypes_to_string(&krb.etypes, indent_level + INDENT_STEP),
243 indentation,
244 indentation,
245 krb.enc_authorization_data
246 .as_ref()
247 .map(|v| format!("\n{}", encrypted_data_to_string(v, indent_level + INDENT_STEP)))
248 .unwrap_or(format!(" {}", NONE)),
249 indentation,
250 krb.additional_tickets
251 .as_ref()
252 .map(|v| format!("\n{}", tickets_to_string(v, indent_level + INDENT_STEP)))
253 .unwrap_or(format!(" {}", NONE))
254 )
255}
256
257pub fn kdc_options_to_string(ko: u32) -> String
258{
259 let options_names = [
260 (kdc_options::FORWARDABLE, "forwardable"),
261 (kdc_options::FORWARDED, "forwarded"),
262 (kdc_options::PROXIABLE, "proxiable"),
263 (kdc_options::PROXY, "proxy"),
264 (kdc_options::ALLOW_POSTDATE, "allow-postdate"),
265 (kdc_options::POSTDATED, "postdated"),
266 (kdc_options::RENEWABLE, "renewable"),
267 (kdc_options::OPT_HARDWARE_AUTH, "opt-hardware-auth"),
268 (kdc_options::CONSTRAINED_DELEGATION, "constrained-delegation"),
269 (kdc_options::CANONICALIZE, "canonicalize"),
270 (kdc_options::REQUEST_ANONYMOUS, "request-anonymous"),
271 (kdc_options::DISABLE_TRANSITED_CHECK, "disable-transited-check"),
272 (kdc_options::RENEWABLE_OK, "renewable-ok"),
273 (kdc_options::ENC_TKT_IN_SKEY, "enc-tkt-in-skey"),
274 (kdc_options::RENEW, "renew"),
275 (kdc_options::VALIDATE, "validate"),
276 ];
277
278 let mut names = Vec::new();
279
280 for option in options_names.iter()
281 {
282 if (ko & option.0) != 0
283 {
284 names.push(option.1)
285 }
286 }
287
288 format!("{:#06x} -> {}", ko, names.join(" "))
289}
290
291pub fn ap_req_to_string(ar: &ApReq, indent_level: usize) -> String
292{
293 let indentation = indent(indent_level);
294 format!(
295 "{}pvno: {}\n\
296 {}msg-type: {}\n\
297 {}ap-options: {}\n\
298 {}ticket:\n{}\n\
299 {}authenticator:\n{}",
300 indentation,
301 ar.pvno,
302 indentation,
303 ar.msg_type,
304 indentation,
305 ap_options_to_string(*ar.ap_options),
306 indentation,
307 ticket_to_string(&ar.ticket, indent_level + INDENT_STEP),
308 indentation,
309 encrypted_data_to_string(&ar.authenticator, indent_level + INDENT_STEP),
310 )
311}
312
313pub fn ap_options_to_string(ao: u32) -> String
314{
315 let ap_options_names = [
316 (ap_options::RESERVED, "reserved"),
317 (ap_options::USE_SESSION_KEY, "use-session-key"),
318 (ap_options::MUTUAL_REQUIRED, "mutual-required"),
319 ];
320
321 let mut names = Vec::new();
322
323 for option in ap_options_names.iter()
324 {
325 if (ao & option.0) != 0
326 {
327 names.push(option.1)
328 }
329 }
330
331 format!("{:#06x} -> {}", ao, names.join(" "))
332}
333
334pub fn as_rep_to_string(ar: &AsRep, indent_level: usize) -> String
335{
336 let indentation = indent(indent_level);
337 format!(
338 "{}pvno: {}\n\
339 {}msg-type: {}\n\
340 {}padata: {}\n\
341 {}crealm: {}\n\
342 {}cname:\n{}\n\
343 {}ticket:\n{}\n\
344 {}enc-part:\n{}",
345 indentation,
346 ar.pvno,
347 indentation,
348 msg_type_to_string(ar.msg_type),
349 indentation,
350 &ar.padata
351 .as_ref()
352 .map(|pds| format!("\n{}", padatas_to_string(pds, indent_level + INDENT_STEP)))
353 .unwrap_or(NONE.into()),
354 indentation,
355 ar.crealm,
356 indentation,
357 principal_name_to_string(&ar.cname, indent_level + INDENT_STEP),
358 indentation,
359 ticket_to_string(&ar.ticket, indent_level + INDENT_STEP),
360 indentation,
361 encrypted_data_to_string(&ar.enc_part, indent_level + INDENT_STEP)
362 )
363}
364
365pub fn tgs_rep_to_string(tr: &TgsRep, indent_level: usize) -> String
366{
367 let indentation = indent(indent_level);
368 format!(
369 "{}pvno: {}\n\
370 {}msg-type: {}\n\
371 {}padata: {}\n\
372 {}crealm: {}\n\
373 {}cname:\n{}\n\
374 {}ticket:\n{}\n\
375 {}enc-part:\n{}",
376 indentation,
377 tr.pvno,
378 indentation,
379 msg_type_to_string(tr.msg_type),
380 indentation,
381 &tr.padata
382 .as_ref()
383 .map(|pds| format!("\n{}", padatas_to_string(pds, indent_level + INDENT_STEP)))
384 .unwrap_or(NONE.into()),
385 indentation,
386 tr.crealm,
387 indentation,
388 principal_name_to_string(&tr.cname, indent_level + INDENT_STEP),
389 indentation,
390 ticket_to_string(&tr.ticket, indent_level + INDENT_STEP),
391 indentation,
392 encrypted_data_to_string(&tr.enc_part, indent_level + INDENT_STEP)
393 )
394}
395
396pub fn padatas_to_string(padatas: &[PaData], indent_level: usize) -> String
397{
398 let indentation = indent(indent_level);
399 let mut vs = Vec::new();
400
401 for (i, pd) in padatas.iter().enumerate()
402 {
403 vs.push(format!(
404 "{}[{}]\n\
405 {}",
406 indentation,
407 i,
408 padata_to_string(pd, indent_level)
409 ))
410 }
411
412 vs.join("\n")
413}
414
415pub fn padata_to_string(padata: &PaData, indent_level: usize) -> String
416{
417 let indentation = indent(indent_level);
418
419 format!(
420 "{}padata-type: {}\n\
421 {}padata-value:{}",
422 indentation,
423 padata_type_to_string(padata.padata_type),
424 indentation,
425 padata_value_to_string(padata, indent_level + INDENT_STEP).map(|v| format!("\n{}", v)).unwrap_or(
426 format!(" {}", octet_string_to_string(&padata.padata_value)))
427 )
428}
429
430pub fn padata_value_to_string(padata: &PaData, indent_level: usize) -> Option<String>
431{
432 match padata.padata_type
433 {
434 pa_data_types::PA_ETYPE_INFO2 =>
435 {
436 if let Ok((_, etype_info2)) = EtypeInfo2::parse(&padata.padata_value)
437 {
438 return Some(etype_info2_to_string(&etype_info2, indent_level));
439 }
440 },
441 pa_data_types::PA_PAC_REQUEST =>
442 {
443 if let Ok((_, pac_request)) = KerbPaPacRequest::parse(&padata.padata_value)
444 {
445 return Some(pa_pac_request_to_string(&pac_request, indent_level));
446 }
447 },
448 pa_data_types::PA_ENC_TIMESTAMP =>
449 {
450 if let Ok((_, pa_enc_timestamp)) = EncryptedData::parse(&padata.padata_value)
451 {
452 return Some(encrypted_data_to_string(&pa_enc_timestamp, indent_level));
453 }
454 },
455 pa_data_types::PA_TGS_REQ =>
456 {
457 if let Ok((_, pa_tgs_req)) = ApReq::parse(&padata.padata_value)
458 {
459 return Some(ap_req_to_string(&pa_tgs_req, indent_level));
460 }
461 },
462 pa_data_types::PA_PAC_OPTIONS =>
463 {
464 if let Ok((_, pa_pac_options)) = PaPacOptions::parse(&padata.padata_value)
465 {
466 return Some(pa_pac_options_to_string(&pa_pac_options, indent_level));
467 }
468 },
469 pa_data_types::PA_FOR_USER =>
470 {
471 if let Ok((_, pa_for_user)) = PaForUser::parse(&padata.padata_value)
472 {
473 return Some(pa_for_user_to_string(&pa_for_user, indent_level));
474 }
475 },
476 _ =>
477 {},
478 };
479 None
480}
481
482fn pa_for_user_to_string(pu: &PaForUser, indent_level: usize) -> String
483{
484 let indentation = indent(indent_level);
485
486 format!(
487 "{}userName:\n{}\n\
488 {}userRealm: {}\n\
489 {}cksum:\n{}\n\
490 {}auth-package: {}",
491 indentation,
492 principal_name_to_string(&pu.username, indent_level + INDENT_STEP),
493 indentation,
494 pu.userrealm,
495 indentation,
496 checksum_to_string(&pu.cksum, indent_level + INDENT_STEP),
497 indentation,
498 pu.auth_package,
499 )
500}
501
502fn checksum_to_string(ck: &Checksum, indent_level: usize) -> String
503{
504 let indentation = indent(indent_level);
505
506 format!(
507 "{}cksumtype: {}\n\
508 {}checksum: {}",
509 indentation,
510 checksum_type_to_string(ck.cksumtype),
511 indentation,
512 octet_string_to_string(&ck.checksum),
513 )
514}
515
516fn checksum_type_to_string(ct: i32) -> String
517{
518 format!("{:#06x} -> {}", ct, checksum_type_name(ct))
519}
520
521fn checksum_type_name(ct: i32) -> &'static str
522{
523 match ct
524 {
525 checksum_types::HMAC_MD5 => "hmac-md5",
526 checksum_types::HMAC_SHA1_96_AES128 => "hmac-sha1-96-aes128",
527 checksum_types::HMAC_SHA1_96_AES256 => "hmac-sha1-96-aes256",
528 checksum_types::HMAC_SHA1_DES3_KD => "hmac-sha1-des3-kd",
529 checksum_types::RSA_MD4_DES => "rsa-md4-des",
530 checksum_types::RSA_MD5_DES => "rsa-md5-des",
531 _ => UNKNOWN,
532 }
533}
534
535fn pa_pac_options_to_string(po: &PaPacOptions, indent_level: usize) -> String
536{
537 let indentation = indent(indent_level);
538
539 let pa_pac_options_names =
540 [
541 (pa_pac_options::BRANCH_AWARE, "branch-aware"),
542 (pa_pac_options::CLAIMS, "claims"),
543 (pa_pac_options::FORWARD_TO_FULL_DC, "forward-to-full-dc"),
544 (pa_pac_options::RESOURCE_BASED_CONSTRAINED_DELEGATION, "resource-based-constrained-delegation"),
545 ];
546
547 let mut names = Vec::new();
548
549 for option in pa_pac_options_names.iter()
550 {
551 if (po.kerberos_flags.flags & option.0) != 0
552 {
553 names.push(option.1)
554 }
555 }
556
557 format!("{}kerberos-flags: {:#06x} -> {}", indentation, po.kerberos_flags.flags, names.join(" "))
558}
559
560pub fn pa_pac_request_to_string(pr: &KerbPaPacRequest, indent_level: usize) -> String
561{
562 let indentation = indent(indent_level);
563 format!("{}include-pac: {}", indentation, pr.include_pac)
564}
565
566pub fn padata_type_to_string(padata_type: i32) -> String
567{
568 format!("{} -> {}", padata_type, padata_type_name(padata_type))
569}
570
571pub fn padata_type_name(padata_type: i32) -> &'static str
572{
573 match padata_type
574 {
575 pa_data_types::PA_TGS_REQ => "pa-tgs-req",
576 pa_data_types::PA_ENC_TIMESTAMP => "pa-enc-timestamp",
577 pa_data_types::PA_PW_SALT => "pa-pw-salt",
578 pa_data_types::PA_ENC_UNIX_TIME => "pa-enc-unix-time",
579 pa_data_types::PA_SANDIA_SECUREID => "pa-sandia-secureid",
580 pa_data_types::PA_SESAME => "pa-sesame",
581 pa_data_types::PA_OSF_DCE => "pa-osf-dce",
582 pa_data_types::PA_CYBERSAFE_SECUREID => "pa-cybersafe-secureid",
583 pa_data_types::PA_AFS3_SALT => "pa-afs3-salt",
584 pa_data_types::PA_ETYPE_INFO => "pa-etype-info",
585 pa_data_types::PA_SAM_CHALLENGE => "pa-sam-challenge",
586 pa_data_types::PA_SAM_RESPONSE => "pa-sam-response",
587 pa_data_types::PA_PK_AS_REQ_OLD => "pa-pk-as-req-old",
588 pa_data_types::PA_PK_AS_REP_OLD => "pa-pk-as-rep-old",
589 pa_data_types::PA_PK_AS_REQ => "pa-pk-as-req",
590 pa_data_types::PA_PK_AS_REP => "pa-pk-as-rep",
591 pa_data_types::PA_ETYPE_INFO2 => "pa-etype-info2",
592 pa_data_types::PA_SVR_REFERRAL_INFO => "pa-srv-referral-info | pa-use-specified-kvno",
593 pa_data_types::PA_SAM_REDIRECT => "pa-sam-redirect",
594 pa_data_types::PA_GET_FROM_TYPED_DATA => "pa-get-from-typed-data | td-padata",
595 pa_data_types::PA_SAM_ETYPE_INFO => "pa-sam-etype-info",
596 pa_data_types::PA_ALT_PRINC => "pa-alt-princ",
597 pa_data_types::PA_SAM_CHALLENGE2 => "pa-sam-challenge2",
598 pa_data_types::PA_SAM_RESPONSE2 => "pa-sam-response2",
599 pa_data_types::PA_EXTRA_TGT => "pa-extra-tgt",
600 pa_data_types::TD_PKINIT_CMS_CERTIFICATES => "td-pkinit-cms-certificates",
601 pa_data_types::TD_KRB_PRINCIPAL => "td-krb-principal",
602 pa_data_types::TD_KRB_REALM => "td-krb-realm",
603 pa_data_types::TD_TRUSTED_CERTIFIERS => "td-trusted-certifiers",
604 pa_data_types::TD_CERTIFICATE_INDEX => "td-certificate-index",
605 pa_data_types::TD_APP_DEFINED_ERROR => "td-app-defined-error",
606 pa_data_types::TD_REQ_NONCE => "td-req-nonce",
607 pa_data_types::TD_REQ_SEQ => "td-req-seq",
608 pa_data_types::PA_PAC_REQUEST => "pa-pac-request",
609 pa_data_types::PA_FOR_USER => "pa-for-user",
610 pa_data_types::PA_FX_COOKIE => "pa-fx-cookien",
611 pa_data_types::PA_FX_FAST => "pa-fx-fast",
612 pa_data_types::PA_FX_ERROR => "pa-fx-error",
613 pa_data_types::PA_ENCRYPTED_CHALLENGE => "pa-encrypted-challenge",
614 pa_data_types::KERB_KEY_LIST_REQ => "kerb-key-list-req",
615 pa_data_types::KERB_KEY_LIST_REP => "kerb-key-list-rep",
616 pa_data_types::PA_SUPPORTED_ENCTYPES => "pa-supported-enctypes",
617 pa_data_types::PA_PAC_OPTIONS => "pa-pac-options",
618 _ => UNKNOWN,
619 }
620}
621
622pub fn msg_type_to_string(msg_type: i32) -> String
623{
624 format!("{} -> {}", msg_type, msg_type_name(msg_type))
625}
626
627pub fn msg_type_name(msg_type: i32) -> &'static str
628{
629 match msg_type
630 {
631 message_types::KRB_AS_REQ => "krb-as-req",
632 message_types::KRB_AS_REP => "krb-as-rep",
633 message_types::KRB_TGS_REQ => "krb-tgs-req",
634 message_types::KRB_TGS_REP => "krb-tgs-rep",
635 message_types::KRB_AP_REQ => "krb-ap-req",
636 message_types::KRB_AP_REP => "krb-ap-rep",
637 message_types::KRB_RESERVED16 => "krb-reserved16",
638 message_types::KRB_RESERVED17 => "krb-reserved17",
639 message_types::KRB_SAFE => "krb-safe",
640 message_types::KRB_PRIV => "krb-priv",
641 message_types::KRB_CRED => "krb-cred",
642 message_types::KRB_ERROR => "krb-error",
643 _ => UNKNOWN,
644 }
645}
646
647pub fn tickets_to_string(tickets: &[Ticket], indent_level: usize) -> String
648{
649 let indentation = indent(indent_level);
650 let mut vs = Vec::new();
651
652 for (i, ticket) in tickets.iter().enumerate()
653 {
654 vs.push(format!(
655 "{}[{}]\n\
656 {}",
657 indentation,
658 i,
659 ticket_to_string(ticket, indent_level)
660 ))
661 }
662
663 vs.join("\n")
664}
665
666pub fn ticket_to_string(tkt: &Ticket, indent_level: usize) -> String
667{
668 let indentation = indent(indent_level);
669 format!(
670 "{}tkt-vno: {}\n\
671 {}realm: {}\n\
672 {}sname:\n{}\n\
673 {}enc-part:\n{}",
674 indentation,
675 tkt.tkt_vno,
676 indentation,
677 tkt.realm,
678 indentation,
679 principal_name_to_string(&tkt.sname, indent_level + INDENT_STEP),
680 indentation,
681 encrypted_data_to_string(&tkt.enc_part, indent_level + INDENT_STEP)
682 )
683}
684
685pub fn encrypted_data_to_string(ed: &EncryptedData, indent_level: usize) -> String
686{
687 let indentation = indent(indent_level);
688 format!(
689 "{}etype: {}\n\
690 {}kvno: {}\n\
691 {}cipher: {} bytes",
692 indentation,
693 etype_to_string(ed.etype),
694 indentation,
695 ed.kvno.map(|v| format!("{}", v)).unwrap_or(NONE.into()),
696 indentation,
697 ed.cipher.len()
698 )
699}
700
701fn indent(level: usize) -> String
702{
703 let mut ind = "".to_string();
704 for _ in 0..level
705 {
706 ind = format!(" {}", ind);
707 }
708 ind
709}
710
711pub fn krb_cred_info_to_string(kci: &KrbCredInfo, indent_level: usize) -> String
712{
713 let indentation = indent(indent_level);
714 format!(
715 "{}key:\n{}\n\
716 {}prealm: {}\n\
717 {}pname:\n{}\n\
718 {}flags: {}\n\
719 {}authtime: {}\n\
720 {}starttime: {}\n\
721 {}endtime: {}\n\
722 {}renew-till: {}\n\
723 {}srealm: {}\n\
724 {}sname:\n{}\n\
725 {}caddr: <Not Implemented>",
726 indentation,
727 encryption_key_to_string(&kci.key, indent_level + INDENT_STEP),
728 indentation,
729 &kci.prealm.as_ref().unwrap_or(&NONE.to_string()),
730 indentation,
731 &kci.pname.as_ref().map(|v| principal_name_to_string(v, indent_level + INDENT_STEP)).unwrap_or(NONE.into()),
732 indentation,
733 &kci.flags.as_ref().map(|v| kerberos_flags_to_string(v.flags)).unwrap_or(NONE.into()),
734 indentation,
735 &kci.authtime.as_ref().map(kerberos_time_to_string).unwrap_or(NONE.into()),
736 indentation,
737 &kci.starttime.as_ref().map(kerberos_time_to_string).unwrap_or(NONE.into()),
738 indentation,
739 &kci.endtime.as_ref().map(kerberos_time_to_string).unwrap_or(NONE.into()),
740 indentation,
741 &kci.renew_till.as_ref().map(kerberos_time_to_string).unwrap_or(NONE.into()),
742 indentation,
743 &kci.srealm.as_ref().unwrap_or(&NONE.into()),
744 indentation,
745 &kci.sname.as_ref().map(|v| principal_name_to_string(v, indent_level + INDENT_STEP)).unwrap_or(NONE.into()),
746 indentation
747 )
748}
749
750pub fn encryption_key_to_string(ek: &EncryptionKey, indent_level: usize) -> String
751{
752 let indentation = indent(indent_level);
753 format!(
754 "{}keytype: {}\n\
755 {}keyvalue: {}",
756 indentation,
757 etype_to_string(ek.keytype),
758 indentation,
759 octet_string_to_string(&ek.keyvalue)
760 )
761}
762
763pub fn octet_string_to_string(os: &[u8]) -> String
764{
765 let mut vs = Vec::new();
766
767 for o in os.iter()
768 {
769 vs.push(format!("{:02x}", o));
770 }
771 vs.join("")
772}
773
774pub fn principal_name_to_string(pname: &PrincipalName, indent_level: usize) -> String
775{
776 let indentation = indent(indent_level);
777 format!(
778 "{}name-type: {}\n\
779 {}name-string: {}",
780 indentation,
781 principal_name_type_to_string(pname.name_type),
782 indentation,
783 pname.name_string.join("/")
784 )
785}
786
787pub fn principal_name_type_to_string(name_type: i32) -> String
788{
789 format!("{} -> {}", name_type, name_type_name(name_type))
790}
791
792pub fn kerberos_time_to_string(krb_time: &KerberosTime) -> String
793{
794 krb_time.with_timezone(&Local).format("%m/%d/%Y %H:%M:%S").to_string()
795}
796
797pub fn kerberos_flags_to_string(flags: u32) -> String
798{
799 let mut flags_strs = Vec::new();
800
801 if (flags & ticket_flags::FORWARDABLE) != 0
802 {
803 flags_strs.push("forwardable")
804 }
805 if (flags & ticket_flags::FORWARDED) != 0
806 {
807 flags_strs.push("forwarded")
808 }
809 if (flags & ticket_flags::PROXIABLE) != 0
810 {
811 flags_strs.push("proxiable")
812 }
813 if (flags & ticket_flags::PROXY) != 0
814 {
815 flags_strs.push("proxy")
816 }
817 if (flags & ticket_flags::MAY_POSTDATE) != 0
818 {
819 flags_strs.push("may_postdate")
820 }
821 if (flags & ticket_flags::POSTDATE) != 0
822 {
823 flags_strs.push("postdate")
824 }
825 if (flags & ticket_flags::RENEWABLE) != 0
826 {
827 flags_strs.push("renewable")
828 }
829 if (flags & ticket_flags::INITIAL) != 0
830 {
831 flags_strs.push("initial")
832 }
833 if (flags & ticket_flags::INVALID) != 0
834 {
835 flags_strs.push("invalid")
836 }
837 if (flags & ticket_flags::HW_AUTHENT) != 0
838 {
839 flags_strs.push("hw_authent")
840 }
841 if (flags & ticket_flags::PRE_AUTHENT) != 0
842 {
843 flags_strs.push("pre_authent")
844 }
845 if (flags & ticket_flags::TRANSITED_POLICY_CHECKED) != 0
846 {
847 flags_strs.push("transited_policy_checked")
848 }
849 if (flags & ticket_flags::OK_AS_DELEGATE) != 0
850 {
851 flags_strs.push("ok_as_delegate")
852 }
853 if (flags & ticket_flags::REQUEST_ANONYMOUS) != 0
854 {
855 flags_strs.push("anonymous")
856 }
857 if (flags & ticket_flags::NAME_CANONICALIZE) != 0
858 {
859 flags_strs.push("name_canonicalize")
860 }
861
862 format!("{:#06x} -> {}", flags, flags_strs.join(" "))
863}
864
865pub fn etypes_to_string(etypes: &[i32], indent_level: usize) -> String
866{
867 let indentation = indent(indent_level);
868 let mut vs = Vec::new();
869
870 for (i, et) in etypes.iter().enumerate()
871 {
872 vs.push(format!(
873 "{}[{}]\n\
874 {}{}",
875 indentation,
876 i,
877 indentation,
878 etype_to_string(*et)
879 ))
880 }
881
882 vs.join("\n")
883}
884
885pub fn etype_to_string(etype: i32) -> String
886{
887 format!("{} -> {}", etype, etype_name(etype))
888}
889
890pub fn etype_name(etype: i32) -> &'static str
891{
892 match etype
893 {
894 etypes::AES128_CTS_HMAC_SHA1_96 => "aes128-cts-hmac-sha1-96",
895 etypes::AES256_CTS_HMAC_SHA1_96 => "aes256-cts-hmac-sha1-96",
896 etypes::DES_CBC_CRC => "des-cbc-crc",
897 etypes::DES_CBC_MD5 => "des-cbc-md5",
898 etypes::NO_ENCRYPTION => "no encryption",
899 etypes::RC4_HMAC => "rc4-hmac",
900 etypes::RC4_HMAC_EXP => "rc4-hmac-exp",
901 etypes::RC4_HMAC_OLD_EXP => "rc4-hmac-old-exp",
902 _ => UNKNOWN,
903 }
904}
905
906pub fn name_type_name(name_type: i32) -> &'static str
907{
908 match name_type
909 {
910 principal_names::NT_UNKNOWN => "nt-unknown",
911 principal_names::NT_PRINCIPAL => "nt-principal",
912 principal_names::NT_SRV_INST => "nt-srv-inst",
913 principal_names::NT_SRV_HST => "nt-srv-hst",
914 principal_names::NT_SRV_XHST => "nt-srv-xhst",
915 principal_names::NT_UID => "nt-uid",
916 principal_names::NT_X500_PRINCIPAL => "nt-x500-principal",
917 principal_names::NT_SMTP_NAME => "nt-smtp-name",
918 principal_names::NT_ENTERPRISE => "nt-enterprise",
919 principal_names::NT_MS_PRINCIPAL => "nt-ms-principal",
920 principal_names::NT_MS_PRINCIPAL_AND_ID => "nt-ms-principal-and-id",
921 principal_names::NT_ENT_PRINCIPAL_AND_ID => "nt-ent-principal-and-id",
922 _ => UNKNOWN,
923 }
924}
925
926pub fn etype_info2_to_string(padatas: &EtypeInfo2, indent_level: usize) -> String
927{
928 let indentation = indent(indent_level);
929 let mut vs = Vec::new();
930
931 for (i, ei) in padatas.iter().enumerate()
932 {
933 vs.push(format!(
934 "{}[{}]\n\
935 {}",
936 indentation,
937 i,
938 etype_info2_entry_to_string(ei, indent_level)
939 ))
940 }
941
942 vs.join("\n")
943}
944
945pub fn etype_info2_entry_to_string(entry: &EtypeInfo2Entry, indent_level: usize) -> String
946{
947 let indentation = indent(indent_level);
948 format!(
949 "{}etype: {}\n\
950 {}salt: {}\n\
951 {}s2kparams: {}",
952 indentation,
953 etype_to_string(entry.etype),
954 indentation,
955 &entry.salt.as_ref().unwrap_or(&NONE.to_string()),
956 indentation,
957 &entry.s2kparams.as_ref().map(|v| octet_string_to_string(v)).unwrap_or(NONE.into())
958 )
959}