1use crate::util::Buf;
2use libgssapi_sys::{
3 gss_OID_desc, gss_display_status, OM_uint32, GSS_C_CALLING_ERROR_OFFSET,
4 GSS_C_GSS_CODE, GSS_C_MECH_CODE, GSS_C_ROUTINE_ERROR_OFFSET, GSS_S_COMPLETE,
5 _GSS_C_CALLING_ERROR_MASK, _GSS_C_ROUTINE_ERROR_MASK, _GSS_S_BAD_BINDINGS,
6 _GSS_S_BAD_MECH, _GSS_S_BAD_MECH_ATTR, _GSS_S_BAD_MIC, _GSS_S_BAD_NAME,
7 _GSS_S_BAD_NAMETYPE, _GSS_S_BAD_QOP, _GSS_S_BAD_SIG, _GSS_S_BAD_STATUS,
8 _GSS_S_CALL_BAD_STRUCTURE, _GSS_S_CALL_INACCESSIBLE_READ,
9 _GSS_S_CALL_INACCESSIBLE_WRITE, _GSS_S_CONTEXT_EXPIRED, _GSS_S_CONTINUE_NEEDED,
10 _GSS_S_CREDENTIALS_EXPIRED, _GSS_S_DEFECTIVE_CREDENTIAL, _GSS_S_DEFECTIVE_TOKEN,
11 _GSS_S_DUPLICATE_ELEMENT, _GSS_S_DUPLICATE_TOKEN, _GSS_S_FAILURE, _GSS_S_GAP_TOKEN,
12 _GSS_S_NAME_NOT_MN, _GSS_S_NO_CONTEXT, _GSS_S_NO_CRED, _GSS_S_OLD_TOKEN,
13 _GSS_S_UNAUTHORIZED, _GSS_S_UNAVAILABLE, _GSS_S_UNSEQ_TOKEN,
14};
15use std::{error, fmt, ptr, os::raw::c_int};
16
17bitflags! {
18 #[derive(Clone, Copy, Debug)]
19 pub struct MajorFlags: u32 {
20 const GSS_S_CALL_INACCESSIBLE_READ = _GSS_S_CALL_INACCESSIBLE_READ;
22 const GSS_S_CALL_INACCESSIBLE_WRITE = _GSS_S_CALL_INACCESSIBLE_WRITE;
23 const GSS_S_CALL_BAD_STRUCTURE = _GSS_S_CALL_BAD_STRUCTURE;
24
25 const GSS_S_BAD_MECH = _GSS_S_BAD_MECH;
27 const GSS_S_BAD_NAME = _GSS_S_BAD_NAME;
28 const GSS_S_BAD_NAMETYPE = _GSS_S_BAD_NAMETYPE;
29 const GSS_S_BAD_BINDINGS = _GSS_S_BAD_BINDINGS;
30 const GSS_S_BAD_STATUS = _GSS_S_BAD_STATUS;
31 const GSS_S_BAD_SIG = _GSS_S_BAD_SIG;
32 const GSS_S_BAD_MIC = _GSS_S_BAD_MIC;
33 const GSS_S_NO_CRED = _GSS_S_NO_CRED;
34 const GSS_S_NO_CONTEXT = _GSS_S_NO_CONTEXT;
35 const GSS_S_DEFECTIVE_TOKEN = _GSS_S_DEFECTIVE_TOKEN;
36 const GSS_S_DEFECTIVE_CREDENTIAL = _GSS_S_DEFECTIVE_CREDENTIAL;
37 const GSS_S_CREDENTIALS_EXPIRED = _GSS_S_CREDENTIALS_EXPIRED;
38 const GSS_S_CONTEXT_EXPIRED = _GSS_S_CONTEXT_EXPIRED;
39 const GSS_S_FAILURE = _GSS_S_FAILURE;
40 const GSS_S_BAD_QOP = _GSS_S_BAD_QOP;
41 const GSS_S_UNAUTHORIZED = _GSS_S_UNAUTHORIZED;
42 const GSS_S_UNAVAILABLE = _GSS_S_UNAVAILABLE;
43 const GSS_S_DUPLICATE_ELEMENT = _GSS_S_DUPLICATE_ELEMENT;
44 const GSS_S_NAME_NOT_MN = _GSS_S_NAME_NOT_MN;
45 const GSS_S_BAD_MECH_ATTR = _GSS_S_BAD_MECH_ATTR;
46
47 const GSS_S_CONTINUE_NEEDED = _GSS_S_CONTINUE_NEEDED;
49 const GSS_S_DUPLICATE_TOKEN = _GSS_S_DUPLICATE_TOKEN;
50 const GSS_S_OLD_TOKEN = _GSS_S_OLD_TOKEN;
51 const GSS_S_UNSEQ_TOKEN = _GSS_S_UNSEQ_TOKEN;
52 const GSS_S_GAP_TOKEN = _GSS_S_GAP_TOKEN;
53 }
54}
55
56pub(crate) fn gss_error(x: OM_uint32) -> OM_uint32 {
57 x & ((_GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET)
58 | (_GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
59}
60
61#[derive(Clone, Copy, Debug)]
62enum ErrorComponent {
63 Major = GSS_C_GSS_CODE as isize,
64 Minor = GSS_C_MECH_CODE as isize,
65}
66
67#[derive(Clone, Copy, Debug)]
68pub struct Error {
69 pub major: MajorFlags,
70 pub minor: u32,
71}
72
73impl Error {
74 fn fmt_code(f: &mut fmt::Formatter<'_>, code: u32, ctype: ErrorComponent) -> fmt::Result {
75 let mut message_context: OM_uint32 = 0;
76 loop {
77 let mut minor = GSS_S_COMPLETE as OM_uint32;
78 let mut buf = Buf::empty();
79 let major = unsafe {
80 gss_display_status(
81 &mut minor as *mut OM_uint32,
82 code,
83 ctype as c_int,
84 ptr::null_mut::<gss_OID_desc>(),
85 &mut message_context as *mut OM_uint32,
86 buf.to_c(),
87 )
88 };
89 if major == GSS_S_COMPLETE || major == _GSS_S_CONTINUE_NEEDED {
90 let s = String::from_utf8_lossy(&*buf);
91 let res = match ctype {
92 ErrorComponent::Major => write!(f, "{}", s),
93 ErrorComponent::Minor => write!(f, " ({})", s),
94 };
95 res?
96 } else {
97 write!(f, "unknown GSSAPI({:?}) error code({})\n", ctype, code)?;
98 break;
99 }
100 if message_context == 0 {
101 break;
102 }
103 }
104 Ok(())
105 }
106}
107
108impl fmt::Display for Error {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 Error::fmt_code(f, self.major.bits(), ErrorComponent::Major)?;
111 Ok(Error::fmt_code(f, self.minor, ErrorComponent::Minor)?)
112 }
113}
114
115impl error::Error for Error {}