ipmi_rs/app/auth/
get_channel_authentication_capabilities.rs1use crate::connection::{Channel, IpmiCommand, Message, NetFn};
2
3use super::{AuthType, PrivilegeLevel};
4
5#[derive(Debug, Clone)]
6pub struct ChannelAuthenticationCapabilities {
7 pub channel_number: u8,
8 pub oem_proprietary: bool,
9 pub key: bool,
10 pub md5: bool,
11 pub md2: bool,
12 pub none: bool,
13 pub kg_status: bool,
14 pub per_message_authentication_enabled: bool,
15 pub user_level_authentication_enabled: bool,
16 pub non_null_usernames_enabled: bool,
17 pub null_usernames_enabled: bool,
18 pub anonymous_login_enabled: bool,
19 pub ipmi2_connections_supported: bool,
20 pub ipmi15_connections_supported: bool,
21 pub oem_id: [u8; 3],
22 pub oem_auxiliary_data: u8,
23}
24
25impl ChannelAuthenticationCapabilities {
26 pub fn best_auth(&self) -> Option<AuthType> {
27 let auth_type = if self.md5 {
28 AuthType::MD5
29 } else if self.md2 {
30 AuthType::MD2
31 } else if self.key {
32 AuthType::Key
33 } else if self.none {
34 AuthType::None
35 } else {
36 return None;
37 };
38 Some(auth_type)
39 }
40}
41
42#[derive(Debug, Clone)]
43pub struct GetChannelAuthenticationCapabilities {
44 channel_number: Channel,
45 privilege_level: PrivilegeLevel,
46}
47
48impl GetChannelAuthenticationCapabilities {
49 pub fn new(channel_number: Channel, privilege_level: PrivilegeLevel) -> Self {
50 Self {
51 channel_number,
52 privilege_level,
53 }
54 }
55}
56
57impl From<GetChannelAuthenticationCapabilities> for Message {
58 fn from(value: GetChannelAuthenticationCapabilities) -> Message {
59 Message::new_request(
60 NetFn::App,
61 0x38,
62 vec![
63 0x80 | value.channel_number.value(),
64 value.privilege_level.into(),
65 ],
66 )
67 }
68}
69
70impl IpmiCommand for GetChannelAuthenticationCapabilities {
71 type Output = ChannelAuthenticationCapabilities;
72
73 type Error = ();
74
75 fn parse_response(
76 completion_code: crate::connection::CompletionCode,
77 data: &[u8],
78 ) -> Result<Self::Output, crate::connection::ParseResponseError<Self::Error>> {
79 Self::check_cc_success(completion_code)?;
80
81 if data.len() < 7 {
82 return Err(crate::connection::ParseResponseError::NotEnoughData);
83 }
84
85 let channel_number = data[0];
86 let ipmi2_ext_cap = (data[1] & 0x80) == 0x80;
87
88 let oem_proprietary = (data[1] & 0x20) == 0x20;
89 let key = (data[1] & 0x10) == 0x10;
90 let md5 = (data[1] & 0x04) == 0x04;
91 let md2 = (data[1] & 0x02) == 0x02;
92 let none = (data[1] & 0x01) == 0x01;
93
94 let pma = (data[2] & 0x10) == 0x10;
95 let ula = (data[2] & 0x08) == 0x08;
96 let nnue = (data[2] & 0x04) == 0x04;
97 let nue = (data[2] & 0x02) == 0x02;
98 let ale = (data[2] & 0x01) == 0x01;
99
100 let (kg, v2, v15, oem_id, oem_aux) = if ipmi2_ext_cap {
101 if data.len() < 8 {
102 return Err(crate::connection::ParseResponseError::NotEnoughData);
103 }
104
105 let kg = (data[2] & 0x20) == 0x20;
106
107 let v2 = (data[3] & 0x02) == 0x02;
108 let v15 = (data[3] & 0x01) == 0x01;
109
110 let oem_id = [data[4], data[5], data[6]];
111 let oem_aux = data[7];
112 (kg, v2, v15, oem_id, oem_aux)
113 } else {
114 let oem_id = [data[3], data[4], data[5]];
115 let oem_aux = data[6];
116 (false, false, false, oem_id, oem_aux)
117 };
118
119 Ok(ChannelAuthenticationCapabilities {
120 channel_number,
121 oem_proprietary,
122 key,
123 md5,
124 md2,
125 none,
126 kg_status: kg,
127 per_message_authentication_enabled: !pma,
128 user_level_authentication_enabled: !ula,
129 non_null_usernames_enabled: nnue,
130 null_usernames_enabled: nue,
131 anonymous_login_enabled: ale,
132 ipmi2_connections_supported: v2,
133 ipmi15_connections_supported: v15,
134 oem_id,
135 oem_auxiliary_data: oem_aux,
136 })
137 }
138}