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}