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.commands.ResponseData;
30  import org.metricshub.ipmi.core.coding.payload.CompletionCode;
31  import org.metricshub.ipmi.core.coding.payload.IpmiPayload;
32  import org.metricshub.ipmi.core.coding.payload.lan.IPMIException;
33  import org.metricshub.ipmi.core.coding.payload.lan.IpmiLanRequest;
34  import org.metricshub.ipmi.core.coding.payload.lan.IpmiLanResponse;
35  import org.metricshub.ipmi.core.coding.payload.lan.NetworkFunction;
36  import org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
37  import org.metricshub.ipmi.core.coding.protocol.IpmiMessage;
38  import org.metricshub.ipmi.core.coding.protocol.Ipmiv15Message;
39  import org.metricshub.ipmi.core.coding.security.CipherSuite;
40  import org.metricshub.ipmi.core.common.TypeConverter;
41  
42  import java.security.InvalidKeyException;
43  import java.security.NoSuchAlgorithmException;
44  import java.util.ArrayList;
45  
46  /**
47   * Wrapper for Get Channel Authentication Capabilities request
48   */
49  public class GetChannelAuthenticationCapabilities extends IpmiCommandCoder {
50  
51      private PrivilegeLevel requestedPrivilegeLevel;
52  
53      private byte channelNumber;
54  
55      private IpmiVersion requestVersion;
56  
57      public void setRequestedPrivilegeLevel(
58              PrivilegeLevel requestedPrivilegeLevel) {
59          this.requestedPrivilegeLevel = requestedPrivilegeLevel;
60      }
61  
62      public PrivilegeLevel getRequestedPrivilegeLevel() {
63          return requestedPrivilegeLevel;
64      }
65  
66      /**
67       * Sets the channel number that will be put into IPMI command.
68       *
69       * @param channelNumber
70       *            - must be 0h-Bh or Eh-Fh <br>
71       *            Eh = retrieve information for channel this request was issued
72       *            on
73       * @throws IllegalArgumentException
74       */
75      public void setChannelNumber(int channelNumber) {
76          if (channelNumber < 0 || channelNumber > 0xF || channelNumber == 0xC
77                  || channelNumber == 0xD) {
78              throw new IllegalArgumentException("Invalid channel number");
79          }
80          this.channelNumber = TypeConverter.intToByte(channelNumber);
81      }
82  
83      public int getChannelNumber() {
84          return TypeConverter.byteToInt(channelNumber);
85      }
86  
87      protected void setRequestVersion(IpmiVersion requestVersion) {
88          this.requestVersion = requestVersion;
89      }
90  
91      protected IpmiVersion getRequestVersion() {
92          return requestVersion;
93      }
94  
95      /**
96       * Initiates class for decoding in 1.5 version. Sets requested privilege
97       * level to user. Sets channel number to 14 indicating that response will
98       * contain information for channel this request was issued on. Sets session
99       * parameters to default.
100      *
101      * @see IpmiCommandCoder#setSessionParameters(IpmiVersion, CipherSuite,
102      *      AuthenticationType)
103      * @see IpmiVersion
104      */
105     public GetChannelAuthenticationCapabilities() {
106         super();
107         setRequestedPrivilegeLevel(PrivilegeLevel.User);
108         setChannelNumber(14);
109     }
110 
111     /**
112      * Initiates class. Sets IPMI version to version. Sets requested privilege
113      * level to user. Sets channel number to 14 indicating that response will
114      * contain information for channel this request was issued on.
115      *
116      * @param version
117      *            - Version of IPMI protocol used
118      * @param requestVersion
119      *            - If Get Channel Authentication Capabilities command is sent
120      *            to BMC with requestVersion = {@link IpmiVersion#V15} it will
121      *            respond, that it does not support IPMI v2.0 even if it does.
122      * @param cipherSuite
123      *            - {@link CipherSuite} containing authentication,
124      *            confidentiality and integrity algorithms for this session.
125      * @see IpmiVersion
126      */
127     public GetChannelAuthenticationCapabilities(IpmiVersion version,
128             IpmiVersion requestVersion, CipherSuite cipherSuite) {
129         super(version, cipherSuite, AuthenticationType.None);
130         this.setRequestVersion(requestVersion);
131         setRequestedPrivilegeLevel(PrivilegeLevel.User);
132         setChannelNumber(14);
133     }
134 
135     /**
136      * Initiates class. Sets IPMI version to version. Sets requested privilege
137      * level privilegeLevel. Sets channel number to channelNumber.
138      *
139      * @param version
140      *            - Version of IPMI protocol used
141      * @param requestVersion
142      *            - If Get Channel Authentication Capabilities command is sent
143      *            to BMC with requestVersion = {@link IpmiVersion#V15} it will
144      *            respond, that it does not support IPMI v2.0 even if it does.
145      * @param cipherSuite
146      *            - {@link CipherSuite} containing authentication,
147      *            confidentiality and integrity algorithms for this session.
148      * @param privilegeLevel
149      *            - Maximum requested privilege level. Can't be
150      *            {@link PrivilegeLevel#MaximumAvailable}.
151      * @param channelNumber
152      *            - must be 0h-Bh or Eh-Fh <br>
153      *            Eh = retrieve information for channel this request was issued
154      *            on.
155      * @see IpmiVersion
156      * @see PrivilegeLevel
157      */
158     public GetChannelAuthenticationCapabilities(IpmiVersion version,
159             IpmiVersion requestVersion, CipherSuite cipherSuite,
160             PrivilegeLevel privilegeLevel, byte channelNumber) {
161         super(version, cipherSuite, AuthenticationType.None);
162         this.setRequestVersion(requestVersion);
163         setRequestedPrivilegeLevel(privilegeLevel);
164         setChannelNumber(channelNumber);
165     }
166 
167     @Override
168     public IpmiMessage encodePayload(int messageSequenceNumber, int sessionSequenceNumber, int sessionId)
169             throws InvalidKeyException, NoSuchAlgorithmException {
170         if (getIpmiVersion() == IpmiVersion.V15) {
171             if (sessionId != 0) {
172                 throw new IllegalArgumentException("Session ID must be 0");
173             }
174 
175             Ipmiv15Message message = new Ipmiv15Message();
176 
177             message.setAuthenticationType(getAuthenticationType());
178 
179             message.setSessionSequenceNumber(0);
180 
181             message.setSessionID(0);
182 
183             message.setPayload(preparePayload(messageSequenceNumber));
184 
185             return message;
186         } else {
187             setAuthenticationType(AuthenticationType.RMCPPlus);
188 
189             return super.encodePayload(messageSequenceNumber, sessionSequenceNumber, sessionId);
190         }
191     }
192 
193     @Override
194     protected IpmiPayload preparePayload(int sequenceNumber) {
195         byte[] payload = new byte[2];
196 
197         payload[0] = 0;
198 
199         if (getRequestVersion() == IpmiVersion.V20) {
200             payload[0] |= TypeConverter.intToByte(0x80);
201         }
202 
203         payload[0] |= channelNumber;
204 
205         payload[1] = encodePrivilegeLevel(requestedPrivilegeLevel);
206         return new IpmiLanRequest(getNetworkFunction(), getCommandCode(), payload,
207                 TypeConverter.intToByte(sequenceNumber));
208     }
209 
210     @Override
211     public byte getCommandCode() {
212         return CommandCodes.GET_CHANNEL_AUTHENTICATION_CAPABILITIES;
213     }
214 
215     @Override
216     public NetworkFunction getNetworkFunction() {
217         return NetworkFunction.ApplicationRequest;
218     }
219 
220     @Override
221     public ResponseData getResponseData(IpmiMessage message) throws IPMIException {
222         if (!isCommandResponse(message)) {
223             throw new IllegalArgumentException(
224                     "This is not a response for Get Channel Authentication Capabilities command");
225         }
226         if (!(message.getPayload() instanceof IpmiLanResponse)) {
227             throw new IllegalArgumentException("Invalid response payload");
228         }
229         if (((IpmiLanResponse) message.getPayload()).getCompletionCode() != CompletionCode.Ok) {
230             throw new IPMIException(
231                     ((IpmiLanResponse) message.getPayload())
232                             .getCompletionCode());
233         }
234         GetChannelAuthenticationCapabilitiesResponseData responseData = new GetChannelAuthenticationCapabilitiesResponseData();
235 
236         byte[] raw = message.getPayload().getIpmiCommandData();
237 
238         if (raw.length != 8) {
239             throw new IllegalArgumentException("Data has invalid length");
240         }
241 
242         responseData.setChannelNumber(raw[0]);
243 
244         responseData.setIpmiv20Support((raw[1] & 0x80) != 0);
245 
246         responseData
247                 .setAuthenticationTypes(new ArrayList<AuthenticationType>());
248 
249         if ((raw[1] & 0x20) != 0) {
250             responseData.getAuthenticationTypes().add(AuthenticationType.Oem);
251         }
252 
253         if ((raw[1] & 0x10) != 0) {
254             responseData.getAuthenticationTypes()
255                     .add(AuthenticationType.Simple);
256         }
257 
258         if ((raw[1] & 0x04) != 0) {
259             responseData.getAuthenticationTypes().add(AuthenticationType.Md5);
260         }
261 
262         if ((raw[1] & 0x02) != 0) {
263             responseData.getAuthenticationTypes().add(AuthenticationType.Md2);
264         }
265 
266         if ((raw[1] & 0x01) != 0) {
267             responseData.getAuthenticationTypes().add(AuthenticationType.None);
268         }
269 
270         responseData.setKgEnabled((raw[2] & 0x20) != 0);
271 
272         responseData.setPerMessageAuthenticationEnabled((raw[2] & 0x10) == 0);
273 
274         responseData.setUserLevelAuthenticationEnabled((raw[2] & 0x08) == 0);
275 
276         responseData.setNonNullUsernamesEnabled((raw[2] & 0x04) != 0);
277 
278         responseData.setNullUsernamesEnabled((raw[2] & 0x02) != 0);
279 
280         responseData.setAnonymusLoginEnabled((raw[2] & 0x01) != 0);
281 
282         byte[] oemId = new byte[4];
283 
284         System.arraycopy(raw, 4, oemId, 0, 3);
285 
286         oemId[3] = 0;
287 
288         responseData.setOemId(TypeConverter.littleEndianByteArrayToInt(oemId));
289 
290         responseData.setOemData(raw[7]);
291 
292         return responseData;
293     }
294 
295     /**
296      * Sets session parameters.
297      *
298      * @param version
299      *            - IPMI version of the command.
300      * @param cipherSuite
301      *            - {@link CipherSuite} containing authentication,
302      *            confidentiality and integrity algorithms for this session.
303      * @param authenticationType
304      *            - Type of authentication used. Must be RMCPPlus for IPMI v2.0.
305      */
306     @Override
307     public void setSessionParameters(IpmiVersion version,
308             CipherSuite cipherSuite, AuthenticationType authenticationType) {
309 
310         if (version == IpmiVersion.V20
311                 && authenticationType != AuthenticationType.RMCPPlus
312                 && authenticationType != AuthenticationType.None) {
313             throw new IllegalArgumentException(
314                     "Authentication Type must be RMCPPlus for IPMI v2.0 messages");
315         }
316 
317         setIpmiVersion(version);
318         setAuthenticationType(authenticationType);
319         setCipherSuite(cipherSuite);
320     }
321 
322 }