blob: f6190d71ff36beb6a2687448df2b0df21e09eaf5 [file] [log] [blame]
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include "usercommands.hpp"
18
19#include "apphandler.hpp"
Richard Marian Thomaiyar06df8762018-12-08 17:38:25 +053020#include "channel_layer.hpp"
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053021#include "user_layer.hpp"
22
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053023#include <security/pam_appl.h>
24
Vernon Mauerye08fbff2019-04-03 09:19:34 -070025#include <ipmid/api.hpp>
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053026#include <phosphor-logging/log.hpp>
27#include <regex>
28
29namespace ipmi
30{
31
32using namespace phosphor::logging;
33
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053034static constexpr uint8_t disableUser = 0x00;
35static constexpr uint8_t enableUser = 0x01;
36static constexpr uint8_t setPassword = 0x02;
37static constexpr uint8_t testPassword = 0x03;
Richard Marian Thomaiyar23df06f2019-01-04 16:42:22 +053038static constexpr uint8_t passwordKeySize20 = 1;
39static constexpr uint8_t passwordKeySize16 = 0;
Saravanan Palanisamy77381f12019-05-15 22:33:17 +000040static constexpr uint8_t enableOperation = 0x00;
41static constexpr uint8_t disableOperation = 0x01;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053042
Richard Marian Thomaiyar6e1ba9e2018-11-29 06:29:21 +053043/** @struct SetUserPasswordReq
44 *
45 * Structure for set user password request command (refer spec sec 22.30)
46 */
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053047struct SetUserPasswordReq
48{
49#if BYTE_ORDER == LITTLE_ENDIAN
50 uint8_t userId : 6;
51 uint8_t reserved1 : 1;
52 uint8_t ipmi20 : 1;
53 uint8_t operation : 2;
54 uint8_t reserved2 : 6;
55#endif
56#if BYTE_ORDER == BIG_ENDIAN
57 uint8_t ipmi20 : 1;
58 uint8_t reserved1 : 1;
59 uint8_t userId : 6;
60 uint8_t reserved2 : 6;
61 uint8_t operation : 2;
62#endif
63 uint8_t userPassword[maxIpmi20PasswordSize];
64} __attribute__((packed));
65
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +053066/** @brief implements the set user access command
67 * @param ctx - IPMI context pointer (for channel)
68 * @param channel - channel number
69 * @param ipmiEnabled - indicates ipmi messaging state
70 * @param linkAuthEnabled - indicates link authentication state
71 * @param accessCallback - indicates callback state
72 * @param bitsUpdate - indicates update request
73 * @param userId - user id
74 * @param reserved1 - skip 2 bits
75 * @param privilege - user privilege
76 * @param reserved2 - skip 4 bits
77 * @param sessionLimit - optional - unused for now
78 *
79 * @returns ipmi completion code
80 */
81ipmi::RspType<> ipmiSetUserAccess(ipmi::Context::ptr ctx, uint4_t channel,
82 uint1_t ipmiEnabled, uint1_t linkAuthEnabled,
83 uint1_t accessCallback, uint1_t bitsUpdate,
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053084
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +053085 uint6_t userId, uint2_t reserved1,
86
87 uint4_t privilege, uint4_t reserved2,
88
89 std::optional<uint8_t> sessionLimit)
90{
91 uint8_t sessLimit = sessionLimit.value_or(0);
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +000092 if (reserved1 || reserved2 || sessLimit ||
93 !ipmiUserIsValidPrivilege(static_cast<uint8_t>(privilege)))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053094 {
95 log<level::DEBUG>("Set user access - Invalid field in request");
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +053096 return ipmi::responseInvalidFieldRequest();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053097 }
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +000098
99 uint8_t chNum =
100 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
101 if (!isValidChannel(chNum))
102 {
103 log<level::DEBUG>("Set user access - Invalid channel request");
104 return ipmi::response(invalidChannel);
105 }
106 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
107 {
108 log<level::DEBUG>("Set user access - No support on channel");
109 return ipmi::response(ccActionNotSupportedForChannel);
110 }
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530111 if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530112 {
113 log<level::DEBUG>("Set user access - Parameter out of range");
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530114 return ipmi::responseParmOutOfRange();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530115 }
Richard Marian Thomaiyar06df8762018-12-08 17:38:25 +0530116
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530117 PrivAccess privAccess = {0};
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530118 if (bitsUpdate)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530119 {
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530120 privAccess.ipmiEnabled = static_cast<uint8_t>(ipmiEnabled);
121 privAccess.linkAuthEnabled = static_cast<uint8_t>(linkAuthEnabled);
122 privAccess.accessCallback = static_cast<uint8_t>(accessCallback);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530123 }
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530124 privAccess.privilege = static_cast<uint8_t>(privilege);
125 return ipmi::response(
126 ipmiUserSetPrivilegeAccess(static_cast<uint8_t>(userId), chNum,
127 privAccess, static_cast<bool>(bitsUpdate)));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530128}
129
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530130/** @brief implements the set user access command
131 * @param ctx - IPMI context pointer (for channel)
132 * @param channel - channel number
133 * @param reserved1 - skip 4 bits
134 * @param userId - user id
135 * @param reserved2 - skip 2 bits
136 *
137 * @returns ipmi completion code plus response data
138 * - maxChUsers - max channel users
139 * - reserved1 - skip 2 bits
140 * - enabledUsers - enabled users count
141 * - enabledStatus - enabled status
142 * - fixedUsers - fixed users count
143 * - reserved2 - skip 2 bits
144 * - privilege - user privilege
145 * - ipmiEnabled - ipmi messaging state
146 * - linkAuthEnabled - link authenticatin state
147 * - accessCallback - callback state
148 * - reserved - skip 1 bit
149 */
150ipmi::RspType<uint6_t, // max channel users
151 uint2_t, // reserved1
152
153 uint6_t, // enabled users count
154 uint2_t, // enabled status
155
156 uint6_t, // fixed users count
157 uint2_t, // reserved2
158
159 uint4_t, // privilege
160 uint1_t, // ipmi messaging state
161 uint1_t, // link authentication state
162 uint1_t, // access callback state
163 uint1_t // reserved3
164 >
165 ipmiGetUserAccess(ipmi::Context::ptr ctx, uint4_t channel,
166 uint4_t reserved1,
167
168 uint6_t userId, uint2_t reserved2)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530169{
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530170 uint8_t chNum =
Vernon Mauery5ed39592019-05-14 09:16:53 -0700171 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000172
173 if (reserved1 || reserved2 || !isValidChannel(chNum))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530174 {
175 log<level::DEBUG>("Get user access - Invalid field in request");
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530176 return ipmi::responseInvalidFieldRequest();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530177 }
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000178
179 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
180 {
181 log<level::DEBUG>("Get user access - No support on channel");
182 return ipmi::response(ccActionNotSupportedForChannel);
183 }
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530184 if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530185 {
186 log<level::DEBUG>("Get user access - Parameter out of range");
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530187 return ipmi::responseParmOutOfRange();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530188 }
189
190 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530191 ipmi::Cc retStatus;
Richard Marian Thomaiyarb6771e02019-01-29 14:42:44 +0530192 retStatus = ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000193 if (retStatus != ccSuccess)
Richard Marian Thomaiyarb6771e02019-01-29 14:42:44 +0530194 {
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530195 return ipmi::response(retStatus);
Richard Marian Thomaiyarb6771e02019-01-29 14:42:44 +0530196 }
197
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530198 bool enabledState = false;
199 retStatus =
200 ipmiUserCheckEnabled(static_cast<uint8_t>(userId), enabledState);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000201 if (retStatus != ccSuccess)
Richard Marian Thomaiyarb6771e02019-01-29 14:42:44 +0530202 {
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530203 return ipmi::response(retStatus);
Richard Marian Thomaiyarb6771e02019-01-29 14:42:44 +0530204 }
205
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530206 uint2_t enabledStatus = enabledState ? userIdEnabledViaSetPassword
207 : userIdDisabledViaSetPassword;
208 PrivAccess privAccess{};
209 retStatus = ipmiUserGetPrivilegeAccess(static_cast<uint8_t>(userId), chNum,
210 privAccess);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000211 if (retStatus != ccSuccess)
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530212 {
213 return ipmi::response(retStatus);
214 }
215 constexpr uint2_t res2Bits = 0;
216 return ipmi::responseSuccess(
217 static_cast<uint6_t>(maxChUsers), res2Bits,
218
219 static_cast<uint6_t>(enabledUsers), enabledStatus,
220
221 static_cast<uint6_t>(fixedUsers), res2Bits,
222
223 static_cast<uint4_t>(privAccess.privilege),
224 static_cast<uint1_t>(privAccess.ipmiEnabled),
225 static_cast<uint1_t>(privAccess.linkAuthEnabled),
226 static_cast<uint1_t>(privAccess.accessCallback),
227 static_cast<uint1_t>(privAccess.reserved));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530228}
229
Vernon Maueryac30b392021-08-05 11:08:23 -0700230/** @brief implementes the get user name command
231 * @param[in] ctx - ipmi command context
232 * @param[in] userId - 6-bit user ID
233 * @param[in] reserved - 2-bits reserved
234 * @param[in] name - 16-byte array for username
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530235
Vernon Maueryac30b392021-08-05 11:08:23 -0700236 * @returns ipmi response
237 */
238ipmi::RspType<>
239 ipmiSetUserName(ipmi::Context::ptr ctx, uint6_t id, uint2_t reserved,
240 const std::array<uint8_t, ipmi::ipmiMaxUserName>& name)
241{
242 if (reserved)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530243 {
Vernon Maueryac30b392021-08-05 11:08:23 -0700244 return ipmi::responseInvalidFieldRequest();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530245 }
Vernon Maueryac30b392021-08-05 11:08:23 -0700246 uint8_t userId = static_cast<uint8_t>(id);
247 if (!ipmiUserIsValidUserId(userId))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530248 {
249 log<level::DEBUG>("Set user name - Invalid user id");
Vernon Maueryac30b392021-08-05 11:08:23 -0700250 return ipmi::responseParmOutOfRange();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530251 }
252
Vernon Maueryac30b392021-08-05 11:08:23 -0700253 size_t nameLen = strnlen(reinterpret_cast<const char*>(name.data()),
254 ipmi::ipmiMaxUserName);
255 const std::string strUserName(reinterpret_cast<const char*>(name.data()),
jayaprakash Mutyalacdcdf2b2020-03-28 00:12:05 +0000256 nameLen);
257
Vernon Maueryac30b392021-08-05 11:08:23 -0700258 ipmi::Cc res = ipmiUserSetUserName(userId, strUserName);
259 return ipmi::response(res);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530260}
261
262/** @brief implementes the get user name command
Vernon Mauery3c89de12021-08-05 11:08:23 -0700263 * @param[in] ctx - ipmi command context
264 * @param[in] userId - 6-bit user ID
265 * @param[in] reserved - 2-bits reserved
266
267 * @returns ipmi response with 16-byte username
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530268 */
Vernon Mauery3c89de12021-08-05 11:08:23 -0700269ipmi::RspType<std::array<uint8_t, ipmi::ipmiMaxUserName>> // user name
270 ipmiGetUserName(ipmi::Context::ptr ctx, uint6_t id, uint2_t reserved)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530271{
Vernon Mauery3c89de12021-08-05 11:08:23 -0700272 if (reserved)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530273 {
Vernon Mauery3c89de12021-08-05 11:08:23 -0700274 return ipmi::responseInvalidFieldRequest();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530275 }
276
Vernon Mauery3c89de12021-08-05 11:08:23 -0700277 uint8_t userId = static_cast<uint8_t>(id);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530278 std::string userName;
Vernon Mauery3c89de12021-08-05 11:08:23 -0700279 if (ipmiUserGetUserName(userId, userName) != ccSuccess)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530280 { // Invalid User ID
Vernon Mauery3c89de12021-08-05 11:08:23 -0700281 log<level::DEBUG>("User Name not found", entry("USER-ID=%u", userId));
282 return ipmi::responseParmOutOfRange();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530283 }
Vernon Mauery3c89de12021-08-05 11:08:23 -0700284 // copy the std::string into a fixed array
285 if (userName.size() > ipmi::ipmiMaxUserName)
286 {
287 return ipmi::responseUnspecifiedError();
288 }
289 std::array<uint8_t, ipmi::ipmiMaxUserName> userNameFixed;
290 std::fill(userNameFixed.begin(), userNameFixed.end(), 0);
291 std::copy(userName.begin(), userName.end(), userNameFixed.begin());
292 return ipmi::responseSuccess(std::move(userNameFixed));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530293}
294
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530295/** @brief implementes the set user password command
296 * @param[in] netfn - specifies netfn.
297 * @param[in] cmd - specifies cmd number.
298 * @param[in] request - pointer to request data.
299 * @param[in, out] dataLen - specifies request data length, and returns
300 * response data length.
301 * @param[in] context - ipmi context.
302 * @returns ipmi completion code.
303 */
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000304Cc ipmiSetUserPassword(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
305 ipmi_request_t request, ipmi_response_t response,
306 ipmi_data_len_t dataLen, ipmi_context_t context)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530307{
308 const SetUserPasswordReq* req = static_cast<SetUserPasswordReq*>(request);
309 size_t reqLength = *dataLen;
310 // subtract 2 bytes header to know the password length - including NULL
311 uint8_t passwordLength = *dataLen - 2;
312 *dataLen = 0;
Snehalatha Venkatesh37b1d1a2021-06-28 10:13:37 +0000313 if (req->reserved1 || req->reserved2)
314 {
315 log<level::DEBUG>("Invalid data field in request");
316 return ccInvalidFieldRequest;
317 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530318
319 // verify input length based on operation. Required password size is 20
320 // bytes as we support only IPMI 2.0, but in order to be compatible with
321 // tools, accept 16 bytes of password size too.
322 if (reqLength < 2 ||
323 // If enable / disable user, reqLength has to be >=2 & <= 22
324 ((req->operation == disableUser || req->operation == enableUser) &&
325 ((reqLength < 2) || (reqLength > sizeof(SetUserPasswordReq)))))
326 {
327 log<level::DEBUG>("Invalid Length");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000328 return ccReqDataLenInvalid;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530329 }
330 // If set / test password then password length has to be 16 or 20 bytes
Richard Marian Thomaiyar23df06f2019-01-04 16:42:22 +0530331 // based on the password size bit.
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530332 if (((req->operation == setPassword) || (req->operation == testPassword)) &&
Richard Marian Thomaiyar23df06f2019-01-04 16:42:22 +0530333 (((req->ipmi20 == passwordKeySize20) &&
334 (passwordLength != maxIpmi20PasswordSize)) ||
335 ((req->ipmi20 == passwordKeySize16) &&
336 (passwordLength != maxIpmi15PasswordSize))))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530337 {
338 log<level::DEBUG>("Invalid Length");
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000339 return ccReqDataLenInvalid;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530340 }
341
342 std::string userName;
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000343 if (ipmiUserGetUserName(req->userId, userName) != ccSuccess)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530344 {
345 log<level::DEBUG>("User Name not found",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530346 entry("USER-ID=%d", (uint8_t)req->userId));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000347 return ccParmOutOfRange;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530348 }
349 if (req->operation == setPassword)
350 {
Suryakanth Sekar90b00c72019-01-16 10:37:57 +0530351 return ipmiUserSetUserPassword(
352 req->userId, reinterpret_cast<const char*>(req->userPassword));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530353 }
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530354 else if (req->operation == enableUser || req->operation == disableUser)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530355 {
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530356 return ipmiUserUpdateEnabledState(req->userId,
357 static_cast<bool>(req->operation));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530358 }
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530359 else if (req->operation == testPassword)
360 {
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700361 SecureString password = ipmiUserGetPassword(userName);
362 SecureString testPassword(
363 reinterpret_cast<const char*>(req->userPassword), passwordLength);
364 // constant time string compare: always compare exactly as many bytes
365 // as the length of the input, resizing the actual password to match,
366 // maintaining a knowledge if the sizes differed originally
367 static const std::array<char, maxIpmi20PasswordSize> empty = {'\0'};
368 size_t cmpLen = testPassword.size();
369 bool pwLenDiffers = password.size() != cmpLen;
370 const char* cmpPassword = nullptr;
371 if (pwLenDiffers)
372 {
373 cmpPassword = empty.data();
374 }
375 else
376 {
377 cmpPassword = password.data();
378 }
379 bool pwBad = CRYPTO_memcmp(cmpPassword, testPassword.data(), cmpLen);
380 pwBad |= pwLenDiffers;
381 if (pwBad)
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530382 {
383 log<level::DEBUG>("Test password failed",
Ayushi Smriti05ad3412019-10-16 16:10:18 +0530384 entry("USER-ID=%d", (uint8_t)req->userId));
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000385 return static_cast<Cc>(
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530386 IPMISetPasswordReturnCodes::ipmiCCPasswdFailMismatch);
387 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000388 return ccSuccess;
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530389 }
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000390 return ccInvalidFieldRequest;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530391}
392
smritic46f6cd2019-03-20 14:09:41 +0530393/** @brief implements the get channel authentication command
394 * @param ctx - IPMI context pointer (for channel)
395 * @param extData - get IPMI 2.0 extended data
396 * @param reserved1 - skip 3 bits
397 * @param chNum - channel number to get info about
398 * @param reserved2 - skip 4 bits
399 * @param privLevel - requested privilege level
400
401 * @returns ipmi completion code plus response data
402 * - channel number
403 * - rmcpAuthTypes - RMCP auth types (IPMI 1.5)
404 * - reserved1
405 * - extDataSupport - true for IPMI 2.0 extensions
406 * - anonymousLogin - true for anonymous login enabled
407 * - nullUsers - true for null user names enabled
408 * - nonNullUsers - true for non-null usernames enabled
409 * - userAuth - false for user authentication enabled
410 * - perMessageAuth - false for per message authentication enabled
411 * - KGStatus - true for Kg required for authentication
412 * - reserved2
413 * - rmcp - RMCP (IPMI 1.5) connection support
414 * - rmcpp - RMCP+ (IPMI 2.0) connection support
415 * - reserved3
416 * - oemID - OEM IANA of any OEM auth support
417 * - oemAuxillary - OEM data for auth
418 */
419ipmi::RspType<uint8_t, // channel number
420 uint6_t, // rmcpAuthTypes
421 bool, // reserved1
422 bool, // extDataSupport
423 bool, // anonymousLogin
424 bool, // nullUsers
425 bool, // nonNullUsers
426 bool, // userAuth
427 bool, // perMessageAuth
428 bool, // KGStatus
429 uint2_t, // reserved2
430 bool, // rmcp
431 bool, // rmcpp
432 uint6_t, // reserved3
433 uint24_t, // oemID
434 uint8_t // oemAuxillary
435 >
436 ipmiGetChannelAuthenticationCapabilities(ipmi::Context::ptr ctx,
437 uint4_t chNum, uint3_t reserved1,
438 bool extData, uint4_t privLevel,
439 uint4_t reserved2)
440{
smritic46f6cd2019-03-20 14:09:41 +0530441 uint8_t channel =
Vernon Mauery5ed39592019-05-14 09:16:53 -0700442 convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx->channel);
smritic46f6cd2019-03-20 14:09:41 +0530443
444 if (reserved1 || reserved2 || !isValidChannel(channel) ||
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000445 !isValidPrivLimit(static_cast<uint8_t>(privLevel)))
smritic46f6cd2019-03-20 14:09:41 +0530446 {
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000447 log<level::DEBUG>(
448 "Get channel auth capabilities - Invalid field in request");
449 return ipmi::responseInvalidFieldRequest();
450 }
451
452 if (getChannelSessionSupport(channel) == EChannelSessSupported::none)
453 {
454 log<level::DEBUG>(
455 "Get channel auth capabilities - No support on channel");
456 return ipmi::response(ccActionNotSupportedForChannel);
smritic46f6cd2019-03-20 14:09:41 +0530457 }
458
459 constexpr bool extDataSupport = true; // true for IPMI 2.0 extensions
460 constexpr bool reserved3 = false;
461 constexpr uint6_t rmcpAuthTypes = 0; // IPMI 1.5 auth types - not supported
462 constexpr uint2_t reserved4 = 0;
463 constexpr bool KGStatus = false; // Not supporting now.
464 constexpr bool perMessageAuth = false; // Per message auth - enabled
465 constexpr bool userAuth = false; // User authentication - enabled
466 constexpr bool nullUsers = false; // Null user names - not supported
467 constexpr bool anonymousLogin = false; // Anonymous login - not supported
468 constexpr uint6_t reserved5 = 0;
469 constexpr bool rmcpp = true; // IPMI 2.0 - supported
470 constexpr bool rmcp = false; // IPMI 1.5 - not supported
471 constexpr uint24_t oemID = 0;
472 constexpr uint8_t oemAuxillary = 0;
473
474 bool nonNullUsers = 0;
475 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
476 ipmi::ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers);
477 nonNullUsers = enabledUsers > 0;
478
479 return ipmi::responseSuccess(
480 channel, rmcpAuthTypes, reserved3, extDataSupport, anonymousLogin,
481 nullUsers, nonNullUsers, userAuth, perMessageAuth, KGStatus, reserved4,
482 rmcp, rmcpp, reserved5, oemID, oemAuxillary);
483}
484
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000485/** @brief implements the set user payload access command.
486 * @param ctx - IPMI context pointer (for channel)
487 * @param channel - channel number (4 bits)
488 * @param reserved1 - skip 4 bits
489 * @param userId - user id (6 bits)
490 * @param operation - access ENABLE /DISABLE. (2 bits)
491 * @param stdPayload0 - IPMI - reserved. (1 bit)
492 * @param stdPayload1 - SOL. (1 bit)
493 * @param stdPayload2 - (1 bit)
494 * @param stdPayload3 - (1 bit)
495 * @param stdPayload4 - (1 bit)
496 * @param stdPayload5 - (1 bit)
497 * @param stdPayload6 - (1 bit)
498 * @param stdPayload7 - (1 bit)
499 * @param stdPayloadEnables2Reserved - (8 bits)
500 * @param oemPayload0 - (1 bit)
501 * @param oemPayload1 - (1 bit)
502 * @param oemPayload2 - (1 bit)
503 * @param oemPayload3 - (1 bit)
504 * @param oemPayload4 - (1 bit)
505 * @param oemPayload5 - (1 bit)
506 * @param oemPayload6 - (1 bit)
507 * @param oemPayload7 - (1 bit)
508 * @param oemPayloadEnables2Reserved - (8 bits)
509 *
510 * @returns IPMI completion code
511 */
512ipmi::RspType<> ipmiSetUserPayloadAccess(
513 ipmi::Context::ptr ctx,
514
515 uint4_t channel, uint4_t reserved,
516
517 uint6_t userId, uint2_t operation,
518
519 bool stdPayload0ipmiReserved, bool stdPayload1SOL, bool stdPayload2,
520 bool stdPayload3, bool stdPayload4, bool stdPayload5, bool stdPayload6,
521 bool stdPayload7,
522
523 uint8_t stdPayloadEnables2Reserved,
524
525 bool oemPayload0, bool oemPayload1, bool oemPayload2, bool oemPayload3,
526 bool oemPayload4, bool oemPayload5, bool oemPayload6, bool oemPayload7,
527
528 uint8_t oemPayloadEnables2Reserved)
529{
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000530 auto chNum =
531 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000532 // Validate the reserved args. Only SOL payload is supported as on date.
533 if (reserved || stdPayload0ipmiReserved || stdPayload2 || stdPayload3 ||
534 stdPayload4 || stdPayload5 || stdPayload6 || stdPayload7 ||
535 oemPayload0 || oemPayload1 || oemPayload2 || oemPayload3 ||
536 oemPayload4 || oemPayload5 || oemPayload6 || oemPayload7 ||
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000537 stdPayloadEnables2Reserved || oemPayloadEnables2Reserved ||
538 !isValidChannel(chNum))
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000539 {
540 return ipmi::responseInvalidFieldRequest();
541 }
542
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000543 if ((operation != enableOperation && operation != disableOperation))
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000544 {
545 return ipmi::responseInvalidFieldRequest();
546 }
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000547 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
548 {
549 return ipmi::response(ccActionNotSupportedForChannel);
550 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000551 if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
552 {
553 return ipmi::responseParmOutOfRange();
554 }
555
556 PayloadAccess payloadAccess = {0};
557 payloadAccess.stdPayloadEnables1[1] = stdPayload1SOL;
558
559 return ipmi::response(ipmiUserSetUserPayloadAccess(
560 chNum, static_cast<uint8_t>(operation), static_cast<uint8_t>(userId),
561 payloadAccess));
562}
563
564/** @brief implements the get user payload access command
565 * This command returns information about user payload enable settings
566 * that were set using the 'Set User Payload Access' Command.
567 *
568 * @param ctx - IPMI context pointer (for channel)
569 * @param channel - channel number
570 * @param reserved1 - skip 4 bits
571 * @param userId - user id
572 * @param reserved2 - skip 2 bits
573 *
574 * @returns IPMI completion code plus response data
575 * - stdPayload0ipmiReserved - IPMI payload (reserved).
576 * - stdPayload1SOL - SOL payload
577 * - stdPayload2
578 * - stdPayload3
579 * - stdPayload4
580 * - stdPayload5
581 * - stdPayload6
582 * - stdPayload7
583
584 * - stdPayloadEnables2Reserved - Reserved.
585
586 * - oemPayload0
587 * - oemPayload1
588 * - oemPayload2
589 * - oemPayload3
590 * - oemPayload4
591 * - oemPayload5
592 * - oemPayload6
593 * - oemPayload7
594
595 * - oemPayloadEnables2Reserved - Reserved
596 */
597ipmi::RspType<bool, // stdPayload0ipmiReserved
598 bool, // stdPayload1SOL
599 bool, // stdPayload2
600 bool, // stdPayload3
601 bool, // stdPayload4
602 bool, // stdPayload5
603 bool, // stdPayload6
604 bool, // stdPayload7
605
606 uint8_t, // stdPayloadEnables2Reserved
607
608 bool, // oemPayload0
609 bool, // oemPayload1
610 bool, // oemPayload2
611 bool, // oemPayload3
612 bool, // oemPayload4
613 bool, // oemPayload5
614 bool, // oemPayload6
615 bool, // oemPayload7
616
617 uint8_t // oemPayloadEnables2Reserved
618 >
619 ipmiGetUserPayloadAccess(ipmi::Context::ptr ctx,
620
621 uint4_t channel, uint4_t reserved1,
622
623 uint6_t userId, uint2_t reserved2)
624{
625 uint8_t chNum =
626 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000627
628 if (reserved1 || reserved2 || !isValidChannel(chNum))
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000629 {
630 return ipmi::responseInvalidFieldRequest();
631 }
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000632 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
633 {
634 return ipmi::response(ccActionNotSupportedForChannel);
635 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000636 if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
637 {
638 return ipmi::responseParmOutOfRange();
639 }
640
641 ipmi::Cc retStatus;
642 PayloadAccess payloadAccess = {};
643 retStatus = ipmiUserGetUserPayloadAccess(
644 chNum, static_cast<uint8_t>(userId), payloadAccess);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000645 if (retStatus != ccSuccess)
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000646 {
647 return ipmi::response(retStatus);
648 }
649 constexpr uint8_t res8bits = 0;
650 return ipmi::responseSuccess(payloadAccess.stdPayloadEnables1.test(0),
651 payloadAccess.stdPayloadEnables1.test(1),
652 payloadAccess.stdPayloadEnables1.test(2),
653 payloadAccess.stdPayloadEnables1.test(3),
654 payloadAccess.stdPayloadEnables1.test(4),
655 payloadAccess.stdPayloadEnables1.test(5),
656 payloadAccess.stdPayloadEnables1.test(6),
657 payloadAccess.stdPayloadEnables1.test(7),
658
659 res8bits,
660
661 payloadAccess.oemPayloadEnables1.test(0),
662 payloadAccess.oemPayloadEnables1.test(1),
663 payloadAccess.oemPayloadEnables1.test(2),
664 payloadAccess.oemPayloadEnables1.test(3),
665 payloadAccess.oemPayloadEnables1.test(4),
666 payloadAccess.oemPayloadEnables1.test(5),
667 payloadAccess.oemPayloadEnables1.test(6),
668 payloadAccess.oemPayloadEnables1.test(7),
669
670 res8bits);
671}
672
William A. Kennington III343d0612018-12-10 15:56:24 -0800673void registerUserIpmiFunctions() __attribute__((constructor));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530674void registerUserIpmiFunctions()
675{
Richard Marian Thomaiyar0be80bd2020-01-10 12:20:16 +0530676 post_work([]() { ipmiUserInit(); });
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530677 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
678 ipmi::app::cmdSetUserAccessCommand,
679 ipmi::Privilege::Admin, ipmiSetUserAccess);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530680
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530681 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
682 ipmi::app::cmdGetUserAccessCommand,
683 ipmi::Privilege::Operator, ipmiGetUserAccess);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530684
Vernon Mauery3c89de12021-08-05 11:08:23 -0700685 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
686 ipmi::app::cmdGetUserNameCommand,
687 ipmi::Privilege::Operator, ipmiGetUserName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530688
Vernon Maueryac30b392021-08-05 11:08:23 -0700689 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
690 ipmi::app::cmdSetUserName, ipmi::Privilege::Admin,
691 ipmiSetUserName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530692
693 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_USER_PASSWORD, NULL,
694 ipmiSetUserPassword, PRIVILEGE_ADMIN);
695
smritic46f6cd2019-03-20 14:09:41 +0530696 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
697 ipmi::app::cmdGetChannelAuthCapabilities,
698 ipmi::Privilege::Callback,
699 ipmiGetChannelAuthenticationCapabilities);
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000700
701 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
702 ipmi::app::cmdSetUserPayloadAccess,
703 ipmi::Privilege::Admin, ipmiSetUserPayloadAccess);
704
705 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
706 ipmi::app::cmdGetUserPayloadAccess,
707 ipmi::Privilege::Operator, ipmiGetUserPayloadAccess);
708
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530709 return;
710}
711} // namespace ipmi