tacacs_plus/
response.rs

1use tacacs_plus_protocol::Argument;
2use tacacs_plus_protocol::{authentication, authorization};
3
4/// The final status returned by a server during a TACACS+ session.
5#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
6pub enum ResponseStatus {
7    /// The operation succeeded.
8    Success,
9    /// The operation failed.
10    Failure,
11}
12
13/// A server response from an authentication session.
14#[must_use = "Authentication failure is not reported as an error, so the status field must be checked."]
15#[derive(PartialEq, Eq, Debug, Clone, Hash)]
16pub struct AuthenticationResponse {
17    /// Whether the authentication attempt passed or failed.
18    pub status: ResponseStatus,
19
20    /// The message returned by the server, intended to be displayed to the user.
21    pub user_message: String,
22
23    /// Extra data returned by the server.
24    pub data: Vec<u8>,
25}
26
27/// A TACACS+ server response from an authorization session.
28#[must_use = "The status of the response should be checked, since a failure is not reported as an error."]
29#[derive(PartialEq, Eq, Debug, Clone, Hash)]
30pub struct AuthorizationResponse {
31    /// Whether the authorization attempt succeeded.
32    pub status: ResponseStatus,
33
34    /// The arguments returned from the server, if any.
35    pub arguments: Vec<Argument<'static>>,
36
37    /// A message that may be presented to a user connected to this client. (`server_msg` from RFC8907)
38    pub user_message: String,
39
40    /// Administrative console message from the server. (`data` from RFC8907)
41    pub admin_message: String,
42}
43
44/// The response from a successful TACACS+ accounting operation.
45#[derive(Debug, PartialEq, Eq, Clone, Hash)]
46pub struct AccountingResponse {
47    /// The message that can be displayed to the user, if any.
48    pub user_message: String,
49
50    /// An administrative log message.
51    pub admin_message: String,
52}
53
54#[doc(hidden)]
55pub struct BadAuthenticationStatus(pub(super) authentication::Status);
56
57#[doc(hidden)]
58impl TryFrom<authentication::Status> for ResponseStatus {
59    type Error = BadAuthenticationStatus;
60
61    fn try_from(value: authentication::Status) -> Result<Self, Self::Error> {
62        match value {
63            authentication::Status::Pass => Ok(ResponseStatus::Success),
64            authentication::Status::Fail => Ok(ResponseStatus::Failure),
65
66            // this is a lowercase "should" from RFC8907
67            // (see section 5.4.3: https://www.rfc-editor.org/rfc/rfc8907.html#section-5.4.3-3)
68            #[allow(deprecated)]
69            authentication::Status::Follow => Ok(ResponseStatus::Failure),
70
71            // we don't support restart status for now, so we treat it as a failure per RFC 8907
72            // (see section 5.4.3 of RFC 8907: https://www.rfc-editor.org/rfc/rfc8907.html#section-5.4.3-6)
73            authentication::Status::Restart => Ok(ResponseStatus::Failure),
74
75            bad_status => Err(BadAuthenticationStatus(bad_status)),
76        }
77    }
78}
79
80#[doc(hidden)]
81pub struct BadAuthorizationStatus(pub(super) authorization::Status);
82
83#[doc(hidden)]
84impl TryFrom<authorization::Status> for ResponseStatus {
85    type Error = BadAuthorizationStatus;
86
87    fn try_from(value: authorization::Status) -> Result<Self, Self::Error> {
88        match value {
89            authorization::Status::PassAdd | authorization::Status::PassReplace => {
90                Ok(ResponseStatus::Success)
91            }
92
93            authorization::Status::Fail => Ok(ResponseStatus::Failure),
94
95            // treat follow status as failure like in authentication
96            // this might not be required by the RFC but is done for consistency
97            #[allow(deprecated)]
98            authorization::Status::Follow => Ok(ResponseStatus::Failure),
99
100            bad_status => Err(BadAuthorizationStatus(bad_status)),
101        }
102    }
103}