Skip to main content

cerbero_lib/core/
stringifier.rs

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}