tacacs_plus/
error.rs

1use futures::io;
2use thiserror::Error;
3
4use tacacs_plus_protocol as protocol;
5use tacacs_plus_protocol::{accounting, authentication, authorization};
6
7/// An error during a TACACS+ exchange.
8#[non_exhaustive]
9#[derive(Debug, Error)]
10pub enum ClientError {
11    /// An error occurred when reading/writing a packet.
12    #[error(transparent)]
13    IOError(#[from] io::Error),
14
15    /// TACACS+ protocol error, e.g. an authentication failure.
16    #[error("error in TACACS+ protocol exchange")]
17    ProtocolError {
18        /// The data received from the server.
19        data: Vec<u8>,
20
21        /// The message sent by the server.
22        message: String,
23    },
24
25    /// TACACS+ protocol error, as reported from a server during authentication.
26    #[error("error when performing TACACS+ authentication")]
27    AuthenticationError {
28        /// The status returned from the server, which will not be `Pass` or `Fail`.
29        status: authentication::Status,
30
31        /// The data received from the server.
32        data: Vec<u8>,
33
34        /// The message sent by the server.
35        user_message: String,
36    },
37
38    // TODO: more descriptive error message
39    /// Error when performing authorization.
40    #[error("error when performing TACACS+ authorization")]
41    AuthorizationError {
42        /// The status received from the server.
43        status: authorization::Status,
44
45        /// The message returned by the server, to be displayed to the user.
46        user_message: String,
47
48        /// The administrative log message returned from the server.
49        admin_message: String,
50    },
51
52    /// Error when performing accounting.
53    #[error("error when performing TACACS+ accounting")]
54    AccountingError {
55        /// The status returned by the server.
56        status: accounting::Status,
57
58        /// The message that can be displayed to the user connected to the client.
59        user_message: String,
60
61        /// An administrative log message from the server.
62        admin_message: String,
63    },
64
65    /// Error when serializing a packet to the wire.
66    #[error(transparent)]
67    SerializeError(#[from] protocol::SerializeError),
68
69    /// Invalid packet received from a server.
70    #[error("invalid packet received from server: {0}")]
71    InvalidPacketReceived(#[from] protocol::DeserializeError),
72
73    /// Supplied data could not be encoded into a packet.
74    #[error("packet could not be constructed from provided data")]
75    InvalidPacketData,
76
77    /// The provided authentication password's length exceeded the valid range (i.e., 0 to `u8::MAX`, less some other data stored in the same field).
78    #[error("authentication data field (including password) was longer than 255 bytes")]
79    PasswordTooLong,
80
81    /// Too many arguments were provided to fit in a packet.
82    #[error("only up to 255 (i.e., `u8::MAX`) arguments fit in a packet")]
83    TooManyArguments,
84
85    /// An invalid argument was provided.
86    #[error(transparent)]
87    InvalidArgument(#[from] protocol::InvalidArgument),
88
89    /// Context had an invalid field.
90    #[error("session context had invalid field(s)")]
91    InvalidContext,
92
93    /// Sequence number in reply did not match what was expected.
94    #[error("sequence number mismatch: expected {expected}, got {actual}")]
95    SequenceNumberMismatch {
96        /// The packet sequence number expected from the server.
97        expected: u8,
98        /// The actual packet sequence number received from the server.
99        actual: u8,
100    },
101
102    /// Sequence number overflowed in session.
103    ///
104    /// This termination is required per [section 4.1 of RFC8907].
105    ///
106    /// [section 4.1 of RFC8907]: https://www.rfc-editor.org/rfc/rfc8907.html#section-4.1-13.2.1
107    #[error("sequence numberflow overflowed maximum, so session was terminated")]
108    SequenceNumberOverflow,
109
110    /// The system time was set before the Unix epoch, which is problematic for generating
111    /// timestamps during accounting.
112    #[error("system time was set before Unix epoch")]
113    SystemTimeBeforeEpoch(#[from] std::time::SystemTimeError),
114}
115
116// authentication data being too long is a direct result of the password being too long
117// hidden since this is an implementation detail that isn't important to library consumers
118#[doc(hidden)]
119impl From<authentication::DataTooLong> for ClientError {
120    fn from(_value: authentication::DataTooLong) -> Self {
121        Self::PasswordTooLong
122    }
123}