blob: 78c264791546355edcfd157eb22378af0ccb58f0 [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
Richard Marian Thomaiyar06df8762018-12-08 17:38:25 +053019#include "channel_layer.hpp"
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053020#include "user_layer.hpp"
21
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053022#include <security/pam_appl.h>
23
Vernon Mauerye08fbff2019-04-03 09:19:34 -070024#include <ipmid/api.hpp>
George Liu82844ef2024-07-17 17:03:56 +080025#include <phosphor-logging/lg2.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050026
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053027#include <regex>
28
29namespace ipmi
30{
31
Saravanan Palanisamy77381f12019-05-15 22:33:17 +000032static constexpr uint8_t enableOperation = 0x00;
33static constexpr uint8_t disableOperation = 0x01;
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053034
George Liu36627e82025-07-08 13:53:25 +080035static constexpr uint8_t userIdEnabledViaSetPassword = 0x01;
36static constexpr uint8_t userIdDisabledViaSetPassword = 0x02;
37
38/** IPMI set password return codes (refer spec sec 22.30) */
39constexpr Cc ccPasswdFailMismatch = 0x80;
40
41static inline auto responsePasswdFailMismatch()
42{
43 return response(ccPasswdFailMismatch);
44}
45
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +053046/** @brief implements the set user access command
47 * @param ctx - IPMI context pointer (for channel)
48 * @param channel - channel number
49 * @param ipmiEnabled - indicates ipmi messaging state
50 * @param linkAuthEnabled - indicates link authentication state
51 * @param accessCallback - indicates callback state
52 * @param bitsUpdate - indicates update request
53 * @param userId - user id
54 * @param reserved1 - skip 2 bits
55 * @param privilege - user privilege
56 * @param reserved2 - skip 4 bits
57 * @param sessionLimit - optional - unused for now
58 *
59 * @returns ipmi completion code
60 */
Patrick Williams1318a5e2024-08-16 15:19:54 -040061ipmi::RspType<> ipmiSetUserAccess(
62 ipmi::Context::ptr ctx, uint4_t channel, uint1_t ipmiEnabled,
63 uint1_t linkAuthEnabled, uint1_t accessCallback, uint1_t bitsUpdate,
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053064
Patrick Williams1318a5e2024-08-16 15:19:54 -040065 uint6_t userId, uint2_t reserved1,
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +053066
Patrick Williams1318a5e2024-08-16 15:19:54 -040067 uint4_t privilege, uint4_t reserved2,
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +053068
Patrick Williams1318a5e2024-08-16 15:19:54 -040069 std::optional<uint8_t> sessionLimit)
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +053070{
71 uint8_t sessLimit = sessionLimit.value_or(0);
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +000072 if (reserved1 || reserved2 || sessLimit ||
73 !ipmiUserIsValidPrivilege(static_cast<uint8_t>(privilege)))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053074 {
George Liu82844ef2024-07-17 17:03:56 +080075 lg2::debug("Set user access - Invalid field in request");
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +053076 return ipmi::responseInvalidFieldRequest();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053077 }
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +000078
Patrick Williams1318a5e2024-08-16 15:19:54 -040079 uint8_t chNum =
80 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +000081 if (!isValidChannel(chNum))
82 {
George Liua0e545d2025-01-24 09:50:22 +080083 lg2::debug("Set user access - Invalid channel request: {CHANNEL}",
84 "CHANNEL", chNum);
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +000085 return ipmi::response(invalidChannel);
86 }
87 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
88 {
George Liu82844ef2024-07-17 17:03:56 +080089 lg2::debug("Set user access - No support on channel");
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +000090 return ipmi::response(ccActionNotSupportedForChannel);
91 }
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +053092 if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053093 {
George Liu82844ef2024-07-17 17:03:56 +080094 lg2::debug("Set user access - Parameter out of range");
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +053095 return ipmi::responseParmOutOfRange();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053096 }
Richard Marian Thomaiyar06df8762018-12-08 17:38:25 +053097
Willy Tu11d68892022-01-20 10:37:34 -080098 PrivAccess privAccess = {};
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +053099 if (bitsUpdate)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530100 {
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530101 privAccess.ipmiEnabled = static_cast<uint8_t>(ipmiEnabled);
102 privAccess.linkAuthEnabled = static_cast<uint8_t>(linkAuthEnabled);
103 privAccess.accessCallback = static_cast<uint8_t>(accessCallback);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530104 }
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530105 privAccess.privilege = static_cast<uint8_t>(privilege);
106 return ipmi::response(
107 ipmiUserSetPrivilegeAccess(static_cast<uint8_t>(userId), chNum,
108 privAccess, static_cast<bool>(bitsUpdate)));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530109}
110
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530111/** @brief implements the set user access command
112 * @param ctx - IPMI context pointer (for channel)
113 * @param channel - channel number
114 * @param reserved1 - skip 4 bits
115 * @param userId - user id
116 * @param reserved2 - skip 2 bits
117 *
118 * @returns ipmi completion code plus response data
119 * - maxChUsers - max channel users
120 * - reserved1 - skip 2 bits
121 * - enabledUsers - enabled users count
122 * - enabledStatus - enabled status
123 * - fixedUsers - fixed users count
124 * - reserved2 - skip 2 bits
125 * - privilege - user privilege
126 * - ipmiEnabled - ipmi messaging state
127 * - linkAuthEnabled - link authenticatin state
128 * - accessCallback - callback state
129 * - reserved - skip 1 bit
130 */
131ipmi::RspType<uint6_t, // max channel users
132 uint2_t, // reserved1
133
134 uint6_t, // enabled users count
135 uint2_t, // enabled status
136
137 uint6_t, // fixed users count
138 uint2_t, // reserved2
139
140 uint4_t, // privilege
141 uint1_t, // ipmi messaging state
142 uint1_t, // link authentication state
143 uint1_t, // access callback state
144 uint1_t // reserved3
145 >
146 ipmiGetUserAccess(ipmi::Context::ptr ctx, uint4_t channel,
147 uint4_t reserved1,
148
149 uint6_t userId, uint2_t reserved2)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530150{
Patrick Williams1318a5e2024-08-16 15:19:54 -0400151 uint8_t chNum =
152 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000153
154 if (reserved1 || reserved2 || !isValidChannel(chNum))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530155 {
George Liu82844ef2024-07-17 17:03:56 +0800156 lg2::debug("Get user access - Invalid field in request");
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530157 return ipmi::responseInvalidFieldRequest();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530158 }
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000159
160 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
161 {
George Liu82844ef2024-07-17 17:03:56 +0800162 lg2::debug("Get user access - No support on channel");
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000163 return ipmi::response(ccActionNotSupportedForChannel);
164 }
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530165 if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530166 {
George Liu82844ef2024-07-17 17:03:56 +0800167 lg2::debug("Get user access - Parameter out of range");
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530168 return ipmi::responseParmOutOfRange();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530169 }
170
171 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530172 ipmi::Cc retStatus;
Richard Marian Thomaiyarb6771e02019-01-29 14:42:44 +0530173 retStatus = ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000174 if (retStatus != ccSuccess)
Richard Marian Thomaiyarb6771e02019-01-29 14:42:44 +0530175 {
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530176 return ipmi::response(retStatus);
Richard Marian Thomaiyarb6771e02019-01-29 14:42:44 +0530177 }
178
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530179 bool enabledState = false;
Patrick Williams1318a5e2024-08-16 15:19:54 -0400180 retStatus =
181 ipmiUserCheckEnabled(static_cast<uint8_t>(userId), enabledState);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000182 if (retStatus != ccSuccess)
Richard Marian Thomaiyarb6771e02019-01-29 14:42:44 +0530183 {
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530184 return ipmi::response(retStatus);
Richard Marian Thomaiyarb6771e02019-01-29 14:42:44 +0530185 }
186
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530187 uint2_t enabledStatus = enabledState ? userIdEnabledViaSetPassword
188 : userIdDisabledViaSetPassword;
189 PrivAccess privAccess{};
190 retStatus = ipmiUserGetPrivilegeAccess(static_cast<uint8_t>(userId), chNum,
191 privAccess);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000192 if (retStatus != ccSuccess)
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530193 {
194 return ipmi::response(retStatus);
195 }
196 constexpr uint2_t res2Bits = 0;
197 return ipmi::responseSuccess(
198 static_cast<uint6_t>(maxChUsers), res2Bits,
199
200 static_cast<uint6_t>(enabledUsers), enabledStatus,
201
202 static_cast<uint6_t>(fixedUsers), res2Bits,
203
204 static_cast<uint4_t>(privAccess.privilege),
205 static_cast<uint1_t>(privAccess.ipmiEnabled),
206 static_cast<uint1_t>(privAccess.linkAuthEnabled),
207 static_cast<uint1_t>(privAccess.accessCallback),
208 static_cast<uint1_t>(privAccess.reserved));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530209}
210
Vernon Maueryac30b392021-08-05 11:08:23 -0700211/** @brief implementes the get user name command
212 * @param[in] ctx - ipmi command context
213 * @param[in] userId - 6-bit user ID
214 * @param[in] reserved - 2-bits reserved
215 * @param[in] name - 16-byte array for username
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530216
Vernon Maueryac30b392021-08-05 11:08:23 -0700217 * @returns ipmi response
218 */
Patrick Williams1318a5e2024-08-16 15:19:54 -0400219ipmi::RspType<> ipmiSetUserName(
220 [[maybe_unused]] ipmi::Context::ptr ctx, uint6_t id, uint2_t reserved,
221 const std::array<uint8_t, ipmi::ipmiMaxUserName>& name)
Vernon Maueryac30b392021-08-05 11:08:23 -0700222{
223 if (reserved)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530224 {
Vernon Maueryac30b392021-08-05 11:08:23 -0700225 return ipmi::responseInvalidFieldRequest();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530226 }
Vernon Maueryac30b392021-08-05 11:08:23 -0700227 uint8_t userId = static_cast<uint8_t>(id);
228 if (!ipmiUserIsValidUserId(userId))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530229 {
George Liu82844ef2024-07-17 17:03:56 +0800230 lg2::debug("Set user name - Invalid user id");
Vernon Maueryac30b392021-08-05 11:08:23 -0700231 return ipmi::responseParmOutOfRange();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530232 }
233
Vernon Maueryac30b392021-08-05 11:08:23 -0700234 size_t nameLen = strnlen(reinterpret_cast<const char*>(name.data()),
235 ipmi::ipmiMaxUserName);
236 const std::string strUserName(reinterpret_cast<const char*>(name.data()),
jayaprakash Mutyalacdcdf2b2020-03-28 00:12:05 +0000237 nameLen);
238
Vernon Maueryac30b392021-08-05 11:08:23 -0700239 ipmi::Cc res = ipmiUserSetUserName(userId, strUserName);
240 return ipmi::response(res);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530241}
242
243/** @brief implementes the get user name command
Vernon Mauery3c89de12021-08-05 11:08:23 -0700244 * @param[in] ctx - ipmi command context
245 * @param[in] userId - 6-bit user ID
246 * @param[in] reserved - 2-bits reserved
247
248 * @returns ipmi response with 16-byte username
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530249 */
Vernon Mauery3c89de12021-08-05 11:08:23 -0700250ipmi::RspType<std::array<uint8_t, ipmi::ipmiMaxUserName>> // user name
Willy Tu11d68892022-01-20 10:37:34 -0800251 ipmiGetUserName([[maybe_unused]] ipmi::Context::ptr ctx, uint6_t id,
252 uint2_t reserved)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530253{
Vernon Mauery3c89de12021-08-05 11:08:23 -0700254 if (reserved)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530255 {
Vernon Mauery3c89de12021-08-05 11:08:23 -0700256 return ipmi::responseInvalidFieldRequest();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530257 }
258
Vernon Mauery3c89de12021-08-05 11:08:23 -0700259 uint8_t userId = static_cast<uint8_t>(id);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530260 std::string userName;
Vernon Mauery3c89de12021-08-05 11:08:23 -0700261 if (ipmiUserGetUserName(userId, userName) != ccSuccess)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530262 { // Invalid User ID
George Liu82844ef2024-07-17 17:03:56 +0800263 lg2::debug("User Name not found, user Id: {USER_ID}", "USER_ID",
264 userId);
Vernon Mauery3c89de12021-08-05 11:08:23 -0700265 return ipmi::responseParmOutOfRange();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530266 }
Vernon Mauery3c89de12021-08-05 11:08:23 -0700267 // copy the std::string into a fixed array
268 if (userName.size() > ipmi::ipmiMaxUserName)
269 {
270 return ipmi::responseUnspecifiedError();
271 }
272 std::array<uint8_t, ipmi::ipmiMaxUserName> userNameFixed;
273 std::fill(userNameFixed.begin(), userNameFixed.end(), 0);
274 std::copy(userName.begin(), userName.end(), userNameFixed.begin());
275 return ipmi::responseSuccess(std::move(userNameFixed));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530276}
277
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700278/** @brief implementes the get user name command
279 * @param[in] ctx - ipmi command context
280 * @param[in] userId - 6-bit user ID
281 * @param[in] reserved - 2-bits reserved
282
283 * @returns ipmi response with 16-byte username
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530284 */
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700285ipmi::RspType<> // user name
Willy Tu11d68892022-01-20 10:37:34 -0800286 ipmiSetUserPassword([[maybe_unused]] ipmi::Context::ptr ctx, uint6_t id,
287 bool reserved1, bool pwLen20, uint2_t operation,
288 uint6_t reserved2, SecureBuffer& userPassword)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530289{
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700290 if (reserved1 || reserved2)
Snehalatha Venkatesh37b1d1a2021-06-28 10:13:37 +0000291 {
George Liu82844ef2024-07-17 17:03:56 +0800292 lg2::debug("Invalid data field in request");
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700293 return ipmi::responseInvalidFieldRequest();
Snehalatha Venkatesh37b1d1a2021-06-28 10:13:37 +0000294 }
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530295
Ayushi Smriti29b9f312021-09-24 12:29:23 +0530296 static constexpr uint2_t opDisableUser = 0x00;
297 static constexpr uint2_t opEnableUser = 0x01;
298 static constexpr uint2_t opSetPassword = 0x02;
299 static constexpr uint2_t opTestPassword = 0x03;
300
301 // If set / test password operation then password size has to be 16 or 20
302 // bytes based on the password size bit
303 if (((operation == opSetPassword) || (operation == opTestPassword)) &&
304 ((pwLen20 && (userPassword.size() != maxIpmi20PasswordSize)) ||
305 (!pwLen20 && (userPassword.size() != maxIpmi15PasswordSize))))
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530306 {
George Liu82844ef2024-07-17 17:03:56 +0800307 lg2::debug("Invalid Length");
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700308 return ipmi::responseReqDataLenInvalid();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530309 }
Ayushi Smriti29b9f312021-09-24 12:29:23 +0530310
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700311 size_t passwordLength = userPassword.size();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530312
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700313 uint8_t userId = static_cast<uint8_t>(id);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530314 std::string userName;
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700315 if (ipmiUserGetUserName(userId, userName) != ccSuccess)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530316 {
George Liu82844ef2024-07-17 17:03:56 +0800317 lg2::debug("User Name not found, user Id: {USER_ID}", "USER_ID",
318 userId);
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700319 return ipmi::responseParmOutOfRange();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530320 }
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700321
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700322 if (operation == opSetPassword)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530323 {
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700324 // turn the non-nul terminated SecureBuffer into a SecureString
325 SecureString password(
326 reinterpret_cast<const char*>(userPassword.data()), passwordLength);
327 ipmi::Cc res = ipmiUserSetUserPassword(userId, password.data());
328 return ipmi::response(res);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530329 }
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700330 else if (operation == opEnableUser || operation == opDisableUser)
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530331 {
Patrick Williams1318a5e2024-08-16 15:19:54 -0400332 ipmi::Cc res =
333 ipmiUserUpdateEnabledState(userId, static_cast<bool>(operation));
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700334 return ipmi::response(res);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530335 }
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700336 else if (operation == opTestPassword)
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530337 {
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700338 SecureString password = ipmiUserGetPassword(userName);
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700339 // extend with zeros, if needed
340 if (password.size() < passwordLength)
341 {
342 password.resize(passwordLength, '\0');
343 }
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700344 SecureString testPassword(
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700345 reinterpret_cast<const char*>(userPassword.data()), passwordLength);
Vernon Mauery1e22a0f2021-07-30 13:36:54 -0700346 // constant time string compare: always compare exactly as many bytes
347 // as the length of the input, resizing the actual password to match,
348 // maintaining a knowledge if the sizes differed originally
349 static const std::array<char, maxIpmi20PasswordSize> empty = {'\0'};
350 size_t cmpLen = testPassword.size();
351 bool pwLenDiffers = password.size() != cmpLen;
352 const char* cmpPassword = nullptr;
353 if (pwLenDiffers)
354 {
355 cmpPassword = empty.data();
356 }
357 else
358 {
359 cmpPassword = password.data();
360 }
361 bool pwBad = CRYPTO_memcmp(cmpPassword, testPassword.data(), cmpLen);
362 pwBad |= pwLenDiffers;
363 if (pwBad)
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530364 {
George Liu82844ef2024-07-17 17:03:56 +0800365 lg2::debug("Test password failed, user Id: {USER_ID}", "USER_ID",
366 userId);
George Liu36627e82025-07-08 13:53:25 +0800367 return ipmi::responsePasswdFailMismatch();
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530368 }
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700369 return ipmi::responseSuccess();
Richard Marian Thomaiyar282e79b2018-11-13 19:00:58 +0530370 }
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700371 return ipmi::responseInvalidFieldRequest();
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530372}
373
smritic46f6cd2019-03-20 14:09:41 +0530374/** @brief implements the get channel authentication command
375 * @param ctx - IPMI context pointer (for channel)
376 * @param extData - get IPMI 2.0 extended data
377 * @param reserved1 - skip 3 bits
378 * @param chNum - channel number to get info about
379 * @param reserved2 - skip 4 bits
380 * @param privLevel - requested privilege level
381
382 * @returns ipmi completion code plus response data
383 * - channel number
384 * - rmcpAuthTypes - RMCP auth types (IPMI 1.5)
385 * - reserved1
386 * - extDataSupport - true for IPMI 2.0 extensions
387 * - anonymousLogin - true for anonymous login enabled
388 * - nullUsers - true for null user names enabled
389 * - nonNullUsers - true for non-null usernames enabled
390 * - userAuth - false for user authentication enabled
391 * - perMessageAuth - false for per message authentication enabled
392 * - KGStatus - true for Kg required for authentication
393 * - reserved2
394 * - rmcp - RMCP (IPMI 1.5) connection support
395 * - rmcpp - RMCP+ (IPMI 2.0) connection support
396 * - reserved3
397 * - oemID - OEM IANA of any OEM auth support
398 * - oemAuxillary - OEM data for auth
399 */
400ipmi::RspType<uint8_t, // channel number
401 uint6_t, // rmcpAuthTypes
402 bool, // reserved1
403 bool, // extDataSupport
404 bool, // anonymousLogin
405 bool, // nullUsers
406 bool, // nonNullUsers
407 bool, // userAuth
408 bool, // perMessageAuth
409 bool, // KGStatus
410 uint2_t, // reserved2
411 bool, // rmcp
412 bool, // rmcpp
413 uint6_t, // reserved3
414 uint24_t, // oemID
415 uint8_t // oemAuxillary
416 >
Patrick Williams1318a5e2024-08-16 15:19:54 -0400417 ipmiGetChannelAuthenticationCapabilities(
418 ipmi::Context::ptr ctx, uint4_t chNum, uint3_t reserved1,
419 [[maybe_unused]] bool extData, uint4_t privLevel, uint4_t reserved2)
smritic46f6cd2019-03-20 14:09:41 +0530420{
Patrick Williams1318a5e2024-08-16 15:19:54 -0400421 uint8_t channel =
422 convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx->channel);
smritic46f6cd2019-03-20 14:09:41 +0530423
424 if (reserved1 || reserved2 || !isValidChannel(channel) ||
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000425 !isValidPrivLimit(static_cast<uint8_t>(privLevel)))
smritic46f6cd2019-03-20 14:09:41 +0530426 {
George Liu82844ef2024-07-17 17:03:56 +0800427 lg2::debug("Get channel auth capabilities - Invalid field in request");
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000428 return ipmi::responseInvalidFieldRequest();
429 }
430
431 if (getChannelSessionSupport(channel) == EChannelSessSupported::none)
432 {
George Liu82844ef2024-07-17 17:03:56 +0800433 lg2::debug("Get channel auth capabilities - No support on channel");
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000434 return ipmi::response(ccActionNotSupportedForChannel);
smritic46f6cd2019-03-20 14:09:41 +0530435 }
436
437 constexpr bool extDataSupport = true; // true for IPMI 2.0 extensions
438 constexpr bool reserved3 = false;
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500439 constexpr uint6_t rmcpAuthTypes = 0; // IPMI 1.5 auth types - not supported
smritic46f6cd2019-03-20 14:09:41 +0530440 constexpr uint2_t reserved4 = 0;
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500441 constexpr bool KGStatus = false; // Not supporting now.
smritic46f6cd2019-03-20 14:09:41 +0530442 constexpr bool perMessageAuth = false; // Per message auth - enabled
443 constexpr bool userAuth = false; // User authentication - enabled
444 constexpr bool nullUsers = false; // Null user names - not supported
445 constexpr bool anonymousLogin = false; // Anonymous login - not supported
446 constexpr uint6_t reserved5 = 0;
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500447 constexpr bool rmcpp = true; // IPMI 2.0 - supported
448 constexpr bool rmcp = false; // IPMI 1.5 - not supported
smritic46f6cd2019-03-20 14:09:41 +0530449 constexpr uint24_t oemID = 0;
450 constexpr uint8_t oemAuxillary = 0;
451
452 bool nonNullUsers = 0;
453 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
454 ipmi::ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers);
455 nonNullUsers = enabledUsers > 0;
456
457 return ipmi::responseSuccess(
458 channel, rmcpAuthTypes, reserved3, extDataSupport, anonymousLogin,
459 nullUsers, nonNullUsers, userAuth, perMessageAuth, KGStatus, reserved4,
460 rmcp, rmcpp, reserved5, oemID, oemAuxillary);
461}
462
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000463/** @brief implements the set user payload access command.
464 * @param ctx - IPMI context pointer (for channel)
465 * @param channel - channel number (4 bits)
466 * @param reserved1 - skip 4 bits
467 * @param userId - user id (6 bits)
468 * @param operation - access ENABLE /DISABLE. (2 bits)
469 * @param stdPayload0 - IPMI - reserved. (1 bit)
470 * @param stdPayload1 - SOL. (1 bit)
471 * @param stdPayload2 - (1 bit)
472 * @param stdPayload3 - (1 bit)
473 * @param stdPayload4 - (1 bit)
474 * @param stdPayload5 - (1 bit)
475 * @param stdPayload6 - (1 bit)
476 * @param stdPayload7 - (1 bit)
477 * @param stdPayloadEnables2Reserved - (8 bits)
478 * @param oemPayload0 - (1 bit)
479 * @param oemPayload1 - (1 bit)
480 * @param oemPayload2 - (1 bit)
481 * @param oemPayload3 - (1 bit)
482 * @param oemPayload4 - (1 bit)
483 * @param oemPayload5 - (1 bit)
484 * @param oemPayload6 - (1 bit)
485 * @param oemPayload7 - (1 bit)
486 * @param oemPayloadEnables2Reserved - (8 bits)
487 *
488 * @returns IPMI completion code
489 */
490ipmi::RspType<> ipmiSetUserPayloadAccess(
491 ipmi::Context::ptr ctx,
492
493 uint4_t channel, uint4_t reserved,
494
495 uint6_t userId, uint2_t operation,
496
497 bool stdPayload0ipmiReserved, bool stdPayload1SOL, bool stdPayload2,
498 bool stdPayload3, bool stdPayload4, bool stdPayload5, bool stdPayload6,
499 bool stdPayload7,
500
501 uint8_t stdPayloadEnables2Reserved,
502
503 bool oemPayload0, bool oemPayload1, bool oemPayload2, bool oemPayload3,
504 bool oemPayload4, bool oemPayload5, bool oemPayload6, bool oemPayload7,
505
506 uint8_t oemPayloadEnables2Reserved)
507{
Patrick Williams1318a5e2024-08-16 15:19:54 -0400508 auto chNum =
509 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000510 // Validate the reserved args. Only SOL payload is supported as on date.
511 if (reserved || stdPayload0ipmiReserved || stdPayload2 || stdPayload3 ||
512 stdPayload4 || stdPayload5 || stdPayload6 || stdPayload7 ||
513 oemPayload0 || oemPayload1 || oemPayload2 || oemPayload3 ||
514 oemPayload4 || oemPayload5 || oemPayload6 || oemPayload7 ||
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000515 stdPayloadEnables2Reserved || oemPayloadEnables2Reserved ||
516 !isValidChannel(chNum))
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000517 {
518 return ipmi::responseInvalidFieldRequest();
519 }
520
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000521 if ((operation != enableOperation && operation != disableOperation))
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000522 {
523 return ipmi::responseInvalidFieldRequest();
524 }
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000525 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
526 {
527 return ipmi::response(ccActionNotSupportedForChannel);
528 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000529 if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
530 {
531 return ipmi::responseParmOutOfRange();
532 }
533
Willy Tu11d68892022-01-20 10:37:34 -0800534 PayloadAccess payloadAccess = {};
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000535 payloadAccess.stdPayloadEnables1[1] = stdPayload1SOL;
536
537 return ipmi::response(ipmiUserSetUserPayloadAccess(
538 chNum, static_cast<uint8_t>(operation), static_cast<uint8_t>(userId),
539 payloadAccess));
540}
541
542/** @brief implements the get user payload access command
543 * This command returns information about user payload enable settings
544 * that were set using the 'Set User Payload Access' Command.
545 *
546 * @param ctx - IPMI context pointer (for channel)
547 * @param channel - channel number
548 * @param reserved1 - skip 4 bits
549 * @param userId - user id
550 * @param reserved2 - skip 2 bits
551 *
552 * @returns IPMI completion code plus response data
553 * - stdPayload0ipmiReserved - IPMI payload (reserved).
554 * - stdPayload1SOL - SOL payload
555 * - stdPayload2
556 * - stdPayload3
557 * - stdPayload4
558 * - stdPayload5
559 * - stdPayload6
560 * - stdPayload7
561
562 * - stdPayloadEnables2Reserved - Reserved.
563
564 * - oemPayload0
565 * - oemPayload1
566 * - oemPayload2
567 * - oemPayload3
568 * - oemPayload4
569 * - oemPayload5
570 * - oemPayload6
571 * - oemPayload7
572
573 * - oemPayloadEnables2Reserved - Reserved
574 */
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500575ipmi::RspType<bool, // stdPayload0ipmiReserved
576 bool, // stdPayload1SOL
577 bool, // stdPayload2
578 bool, // stdPayload3
579 bool, // stdPayload4
580 bool, // stdPayload5
581 bool, // stdPayload6
582 bool, // stdPayload7
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000583
584 uint8_t, // stdPayloadEnables2Reserved
585
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500586 bool, // oemPayload0
587 bool, // oemPayload1
588 bool, // oemPayload2
589 bool, // oemPayload3
590 bool, // oemPayload4
591 bool, // oemPayload5
592 bool, // oemPayload6
593 bool, // oemPayload7
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000594
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500595 uint8_t // oemPayloadEnables2Reserved
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000596 >
597 ipmiGetUserPayloadAccess(ipmi::Context::ptr ctx,
598
599 uint4_t channel, uint4_t reserved1,
600
601 uint6_t userId, uint2_t reserved2)
602{
Patrick Williams1318a5e2024-08-16 15:19:54 -0400603 uint8_t chNum =
604 convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000605
606 if (reserved1 || reserved2 || !isValidChannel(chNum))
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000607 {
608 return ipmi::responseInvalidFieldRequest();
609 }
jayaprakash Mutyala0e2dbee2019-12-26 13:03:04 +0000610 if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
611 {
612 return ipmi::response(ccActionNotSupportedForChannel);
613 }
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000614 if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
615 {
616 return ipmi::responseParmOutOfRange();
617 }
618
619 ipmi::Cc retStatus;
620 PayloadAccess payloadAccess = {};
621 retStatus = ipmiUserGetUserPayloadAccess(
622 chNum, static_cast<uint8_t>(userId), payloadAccess);
NITIN SHARMAb541a5a2019-07-18 12:46:59 +0000623 if (retStatus != ccSuccess)
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000624 {
625 return ipmi::response(retStatus);
626 }
627 constexpr uint8_t res8bits = 0;
Patrick Williams1318a5e2024-08-16 15:19:54 -0400628 return ipmi::responseSuccess(
629 payloadAccess.stdPayloadEnables1.test(0),
630 payloadAccess.stdPayloadEnables1.test(1),
631 payloadAccess.stdPayloadEnables1.test(2),
632 payloadAccess.stdPayloadEnables1.test(3),
633 payloadAccess.stdPayloadEnables1.test(4),
634 payloadAccess.stdPayloadEnables1.test(5),
635 payloadAccess.stdPayloadEnables1.test(6),
636 payloadAccess.stdPayloadEnables1.test(7),
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000637
Patrick Williams1318a5e2024-08-16 15:19:54 -0400638 res8bits,
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000639
Patrick Williams1318a5e2024-08-16 15:19:54 -0400640 payloadAccess.oemPayloadEnables1.test(0),
641 payloadAccess.oemPayloadEnables1.test(1),
642 payloadAccess.oemPayloadEnables1.test(2),
643 payloadAccess.oemPayloadEnables1.test(3),
644 payloadAccess.oemPayloadEnables1.test(4),
645 payloadAccess.oemPayloadEnables1.test(5),
646 payloadAccess.oemPayloadEnables1.test(6),
647 payloadAccess.oemPayloadEnables1.test(7),
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000648
Patrick Williams1318a5e2024-08-16 15:19:54 -0400649 res8bits);
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000650}
651
William A. Kennington III343d0612018-12-10 15:56:24 -0800652void registerUserIpmiFunctions() __attribute__((constructor));
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530653void registerUserIpmiFunctions()
654{
Richard Marian Thomaiyar0be80bd2020-01-10 12:20:16 +0530655 post_work([]() { ipmiUserInit(); });
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530656 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
657 ipmi::app::cmdSetUserAccessCommand,
658 ipmi::Privilege::Admin, ipmiSetUserAccess);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530659
Richard Marian Thomaiyar5b2535f2019-04-04 22:01:36 +0530660 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
661 ipmi::app::cmdGetUserAccessCommand,
ankita prasadbd604762023-01-18 10:56:43 +0000662 ipmi::Privilege::Admin, ipmiGetUserAccess);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530663
Vernon Mauery3c89de12021-08-05 11:08:23 -0700664 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
665 ipmi::app::cmdGetUserNameCommand,
ankita prasadbd604762023-01-18 10:56:43 +0000666 ipmi::Privilege::Admin, ipmiGetUserName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530667
Vernon Maueryac30b392021-08-05 11:08:23 -0700668 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
669 ipmi::app::cmdSetUserName, ipmi::Privilege::Admin,
670 ipmiSetUserName);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530671
Vernon Mauery7a3296d2021-08-05 11:08:23 -0700672 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
673 ipmi::app::cmdSetUserPasswordCommand,
674 ipmi::Privilege::Admin, ipmiSetUserPassword);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530675
smritic46f6cd2019-03-20 14:09:41 +0530676 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
677 ipmi::app::cmdGetChannelAuthCapabilities,
678 ipmi::Privilege::Callback,
679 ipmiGetChannelAuthenticationCapabilities);
Saravanan Palanisamy77381f12019-05-15 22:33:17 +0000680
681 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
682 ipmi::app::cmdSetUserPayloadAccess,
683 ipmi::Privilege::Admin, ipmiSetUserPayloadAccess);
684
685 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
686 ipmi::app::cmdGetUserPayloadAccess,
687 ipmi::Privilege::Operator, ipmiGetUserPayloadAccess);
688
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +0530689 return;
690}
691} // namespace ipmi