libgssapi/
error.rs

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        // calling errors
21        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        // routine errors
26        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        // Supplementary info
48        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 {}