View Javadoc
1   package org.metricshub.ipmi.core.coding.commands.session;
2   
3   /*-
4    * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5    * IPMI Java Client
6    * ჻჻჻჻჻჻
7    * Copyright 2023 Verax Systems, MetricsHub
8    * ჻჻჻჻჻჻
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   *
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   *
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23   */
24  
25  import org.metricshub.ipmi.core.coding.commands.CommandCodes;
26  import org.metricshub.ipmi.core.coding.commands.IpmiCommandCoder;
27  import org.metricshub.ipmi.core.coding.commands.IpmiVersion;
28  import org.metricshub.ipmi.core.coding.commands.PrivilegeLevel;
29  import org.metricshub.ipmi.core.coding.payload.IpmiPayload;
30  import org.metricshub.ipmi.core.coding.payload.lan.IPMIException;
31  import org.metricshub.ipmi.core.coding.payload.lan.IpmiLanRequest;
32  import org.metricshub.ipmi.core.coding.payload.lan.NetworkFunction;
33  import org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
34  import org.metricshub.ipmi.core.coding.protocol.IpmiMessage;
35  import org.metricshub.ipmi.core.coding.protocol.Ipmiv15Message;
36  import org.metricshub.ipmi.core.coding.security.CipherSuite;
37  import org.metricshub.ipmi.core.common.TypeConverter;
38  
39  import java.security.InvalidKeyException;
40  import java.security.NoSuchAlgorithmException;
41  import java.util.ArrayList;
42  
43  /**
44   * Wrapper for Get Channel Authentication Capabilities request
45   */
46  public class GetChannelAuthenticationCapabilities
47  		extends IpmiCommandCoder<GetChannelAuthenticationCapabilitiesResponseData> {
48  
49  	private PrivilegeLevel requestedPrivilegeLevel;
50  
51  	private byte channelNumber;
52  
53  	private IpmiVersion requestVersion;
54  
55  	public void setRequestedPrivilegeLevel(PrivilegeLevel requestedPrivilegeLevel) {
56  		this.requestedPrivilegeLevel = requestedPrivilegeLevel;
57  	}
58  
59  	public PrivilegeLevel getRequestedPrivilegeLevel() {
60  		return requestedPrivilegeLevel;
61  	}
62  
63  	/**
64  	 * Sets the channel number that will be put into IPMI command.
65  	 *
66  	 * @param channelNumber
67  	 *        - must be 0h-Bh or Eh-Fh <br>
68  	 *        Eh = retrieve information for channel this request was issued
69  	 *        on
70  	 * @throws IllegalArgumentException
71  	 */
72  	public void setChannelNumber(int channelNumber) {
73  		if (channelNumber < 0 || channelNumber > 0xF || channelNumber == 0xC || channelNumber == 0xD) {
74  			throw new IllegalArgumentException("Invalid channel number");
75  		}
76  		this.channelNumber = TypeConverter.intToByte(channelNumber);
77  	}
78  
79  	public int getChannelNumber() {
80  		return TypeConverter.byteToInt(channelNumber);
81  	}
82  
83  	protected void setRequestVersion(IpmiVersion requestVersion) {
84  		this.requestVersion = requestVersion;
85  	}
86  
87  	protected IpmiVersion getRequestVersion() {
88  		return requestVersion;
89  	}
90  
91  	/**
92  	 * Initiates class for decoding in 1.5 version. Sets requested privilege
93  	 * level to user. Sets channel number to 14 indicating that response will
94  	 * contain information for channel this request was issued on. Sets session
95  	 * parameters to default.
96  	 *
97  	 * @see IpmiCommandCoder#setSessionParameters(IpmiVersion, CipherSuite,
98  	 *      AuthenticationType)
99  	 * @see IpmiVersion
100 	 */
101 	public GetChannelAuthenticationCapabilities() {
102 		super();
103 		setRequestedPrivilegeLevel(PrivilegeLevel.User);
104 		setChannelNumber(14);
105 	}
106 
107 	/**
108 	 * Initiates class. Sets IPMI version to version. Sets requested privilege
109 	 * level to user. Sets channel number to 14 indicating that response will
110 	 * contain information for channel this request was issued on.
111 	 *
112 	 * @param version
113 	 *        - Version of IPMI protocol used
114 	 * @param requestVersion
115 	 *        - If Get Channel Authentication Capabilities command is sent
116 	 *        to BMC with requestVersion = {@link IpmiVersion#V15} it will
117 	 *        respond, that it does not support IPMI v2.0 even if it does.
118 	 * @param cipherSuite
119 	 *        - {@link CipherSuite} containing authentication,
120 	 *        confidentiality and integrity algorithms for this session.
121 	 * @see IpmiVersion
122 	 */
123 	public GetChannelAuthenticationCapabilities(IpmiVersion version, IpmiVersion requestVersion,
124 			CipherSuite cipherSuite) {
125 		setSessionParameters(version, cipherSuite, AuthenticationType.None);
126 		this.setRequestVersion(requestVersion);
127 		setRequestedPrivilegeLevel(PrivilegeLevel.User);
128 		setChannelNumber(14);
129 	}
130 
131 	/**
132 	 * Initiates class. Sets IPMI version to version. Sets requested privilege
133 	 * level privilegeLevel. Sets channel number to channelNumber.
134 	 *
135 	 * @param version
136 	 *        - Version of IPMI protocol used
137 	 * @param requestVersion
138 	 *        - If Get Channel Authentication Capabilities command is sent
139 	 *        to BMC with requestVersion = {@link IpmiVersion#V15} it will
140 	 *        respond, that it does not support IPMI v2.0 even if it does.
141 	 * @param cipherSuite
142 	 *        - {@link CipherSuite} containing authentication,
143 	 *        confidentiality and integrity algorithms for this session.
144 	 * @param privilegeLevel
145 	 *        - Maximum requested privilege level. Can't be
146 	 *        {@link PrivilegeLevel#MaximumAvailable}.
147 	 * @param channelNumber
148 	 *        - must be 0h-Bh or Eh-Fh <br>
149 	 *        Eh = retrieve information for channel this request was issued
150 	 *        on.
151 	 * @see IpmiVersion
152 	 * @see PrivilegeLevel
153 	 */
154 	public GetChannelAuthenticationCapabilities(IpmiVersion version, IpmiVersion requestVersion, CipherSuite cipherSuite,
155 			PrivilegeLevel privilegeLevel, byte channelNumber) {
156 		setSessionParameters(version, cipherSuite, AuthenticationType.None);
157 		this.setRequestVersion(requestVersion);
158 		setRequestedPrivilegeLevel(privilegeLevel);
159 		setChannelNumber(channelNumber);
160 	}
161 
162 	@Override
163 	public IpmiMessage encodePayload(int messageSequenceNumber, int sessionSequenceNumber, int sessionId)
164 			throws InvalidKeyException,
165 			NoSuchAlgorithmException {
166 		if (getIpmiVersion() == IpmiVersion.V15) {
167 			if (sessionId != 0) {
168 				throw new IllegalArgumentException("Session ID must be 0");
169 			}
170 
171 			Ipmiv15Message message = new Ipmiv15Message();
172 
173 			message.setAuthenticationType(getAuthenticationType());
174 
175 			message.setSessionSequenceNumber(0);
176 
177 			message.setSessionID(0);
178 
179 			message.setPayload(preparePayload(messageSequenceNumber));
180 
181 			return message;
182 		} else {
183 			setAuthenticationType(AuthenticationType.RMCPPlus);
184 
185 			return super.encodePayload(messageSequenceNumber, sessionSequenceNumber, sessionId);
186 		}
187 	}
188 
189 	@Override
190 	protected IpmiPayload preparePayload(int sequenceNumber) {
191 		byte[] payload = new byte[2];
192 
193 		payload[0] = 0;
194 
195 		if (getRequestVersion() == IpmiVersion.V20) {
196 			payload[0] |= TypeConverter.intToByte(0x80);
197 		}
198 
199 		payload[0] |= channelNumber;
200 
201 		payload[1] = encodePrivilegeLevel(requestedPrivilegeLevel);
202 		return new IpmiLanRequest(getNetworkFunction(), getCommandCode(), payload, TypeConverter.intToByte(sequenceNumber));
203 	}
204 
205 	@Override
206 	public byte getCommandCode() {
207 		return CommandCodes.GET_CHANNEL_AUTHENTICATION_CAPABILITIES;
208 	}
209 
210 	@Override
211 	public NetworkFunction getNetworkFunction() {
212 		return NetworkFunction.ApplicationRequest;
213 	}
214 
215 	@Override
216 	public GetChannelAuthenticationCapabilitiesResponseData getResponseData(IpmiMessage message) throws IPMIException {
217 		byte[] raw = validateResponse(message);
218 
219 		GetChannelAuthenticationCapabilitiesResponseData responseData = new GetChannelAuthenticationCapabilitiesResponseData();
220 
221 		if (raw.length != 8) {
222 			throw new IllegalArgumentException("Data has invalid length");
223 		}
224 
225 		responseData.setChannelNumber(raw[0]);
226 
227 		// Byte 3 bit 7 only says that byte 5 holds the extended capabilities, whose bit 1 is the IPMI v2.0 support
228 		// (IPMI 2.0 table 22-15; raw[0] is byte 2, the channel number)
229 		responseData.setIpmiv20Support((raw[1] & 0x80) != 0 && (raw[3] & 0x02) != 0);
230 
231 		responseData.setAuthenticationTypes(new ArrayList<AuthenticationType>());
232 
233 		if ((raw[1] & 0x20) != 0) {
234 			responseData.getAuthenticationTypes().add(AuthenticationType.Oem);
235 		}
236 
237 		if ((raw[1] & 0x10) != 0) {
238 			responseData.getAuthenticationTypes().add(AuthenticationType.Simple);
239 		}
240 
241 		if ((raw[1] & 0x04) != 0) {
242 			responseData.getAuthenticationTypes().add(AuthenticationType.Md5);
243 		}
244 
245 		if ((raw[1] & 0x02) != 0) {
246 			responseData.getAuthenticationTypes().add(AuthenticationType.Md2);
247 		}
248 
249 		if ((raw[1] & 0x01) != 0) {
250 			responseData.getAuthenticationTypes().add(AuthenticationType.None);
251 		}
252 
253 		responseData.setKgEnabled((raw[2] & 0x20) != 0);
254 
255 		responseData.setPerMessageAuthenticationEnabled((raw[2] & 0x10) == 0);
256 
257 		responseData.setUserLevelAuthenticationEnabled((raw[2] & 0x08) == 0);
258 
259 		responseData.setNonNullUsernamesEnabled((raw[2] & 0x04) != 0);
260 
261 		responseData.setNullUsernamesEnabled((raw[2] & 0x02) != 0);
262 
263 		responseData.setAnonymusLoginEnabled((raw[2] & 0x01) != 0);
264 
265 		byte[] oemId = new byte[4];
266 
267 		System.arraycopy(raw, 4, oemId, 0, 3);
268 
269 		oemId[3] = 0;
270 
271 		responseData.setOemId(TypeConverter.littleEndianByteArrayToInt(oemId));
272 
273 		responseData.setOemData(raw[7]);
274 
275 		return responseData;
276 	}
277 
278 	/**
279 	 * Sets session parameters.
280 	 *
281 	 * @param version
282 	 *        - IPMI version of the command.
283 	 * @param cipherSuite
284 	 *        - {@link CipherSuite} containing authentication,
285 	 *        confidentiality and integrity algorithms for this session.
286 	 * @param authenticationType
287 	 *        - Type of authentication used. Must be RMCPPlus for IPMI v2.0.
288 	 */
289 	@Override
290 	public void setSessionParameters(
291 			IpmiVersion version,
292 			CipherSuite cipherSuite,
293 			AuthenticationType authenticationType) {
294 
295 		if (version == IpmiVersion.V20
296 				&& authenticationType != AuthenticationType.RMCPPlus
297 				&& authenticationType != AuthenticationType.None) {
298 			throw new IllegalArgumentException("Authentication Type must be RMCPPlus for IPMI v2.0 messages");
299 		}
300 
301 		setIpmiVersion(version);
302 		setAuthenticationType(authenticationType);
303 		setCipherSuite(cipherSuite);
304 	}
305 
306 }