xref: /openbmc/phosphor-host-ipmid/user_channel/usercommands.cpp (revision d2afd054e3d8a3fb858c98b244bc22f2f296f9f4)
1 /*
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"
20 #include "channel_layer.hpp"
21 #include "user_layer.hpp"
22 
23 #include <security/pam_appl.h>
24 
25 #include <ipmid/api.hpp>
26 #include <phosphor-logging/log.hpp>
27 #include <regex>
28 
29 namespace ipmi
30 {
31 
32 using namespace phosphor::logging;
33 
34 static constexpr uint8_t disableUser = 0x00;
35 static constexpr uint8_t enableUser = 0x01;
36 static constexpr uint8_t setPassword = 0x02;
37 static constexpr uint8_t testPassword = 0x03;
38 static constexpr uint8_t passwordKeySize20 = 1;
39 static constexpr uint8_t passwordKeySize16 = 0;
40 static constexpr uint8_t enableOperation = 0x00;
41 static constexpr uint8_t disableOperation = 0x01;
42 
43 /** @struct SetUserNameReq
44  *
45  *  Structure for set user name request command (refer spec sec 22.28)
46  */
47 struct SetUserNameReq
48 {
49 #if BYTE_ORDER == LITTLE_ENDIAN
50     uint8_t userId : 6;
51     uint8_t reserved1 : 2;
52 #endif
53 #if BYTE_ORDER == BIG_ENDIAN
54     uint8_t reserved1 : 2;
55     uint8_t userId : 6;
56 #endif
57     uint8_t userName[16];
58 } __attribute__((packed));
59 
60 /** @struct GetUserNameReq
61  *
62  *  Structure for get user name request command (refer spec sec 22.29)
63  */
64 struct GetUserNameReq
65 {
66 #if BYTE_ORDER == LITTLE_ENDIAN
67     uint8_t userId : 6;
68     uint8_t reserved1 : 2;
69 #endif
70 #if BYTE_ORDER == BIG_ENDIAN
71     uint8_t reserved1 : 2;
72     uint8_t userId : 6;
73 #endif
74 } __attribute__((packed));
75 
76 /** @struct GetUserNameResp
77  *
78  *  Structure for get user name response command (refer spec sec 22.29)
79  */
80 struct GetUserNameResp
81 {
82     uint8_t userName[16];
83 } __attribute__((packed));
84 
85 /** @struct SetUserPasswordReq
86  *
87  *  Structure for set user password request command (refer spec sec 22.30)
88  */
89 struct SetUserPasswordReq
90 {
91 #if BYTE_ORDER == LITTLE_ENDIAN
92     uint8_t userId : 6;
93     uint8_t reserved1 : 1;
94     uint8_t ipmi20 : 1;
95     uint8_t operation : 2;
96     uint8_t reserved2 : 6;
97 #endif
98 #if BYTE_ORDER == BIG_ENDIAN
99     uint8_t ipmi20 : 1;
100     uint8_t reserved1 : 1;
101     uint8_t userId : 6;
102     uint8_t reserved2 : 6;
103     uint8_t operation : 2;
104 #endif
105     uint8_t userPassword[maxIpmi20PasswordSize];
106 } __attribute__((packed));
107 
108 /** @brief implements the set user access command
109  *  @param ctx - IPMI context pointer (for channel)
110  *  @param channel - channel number
111  *  @param ipmiEnabled - indicates ipmi messaging state
112  *  @param linkAuthEnabled - indicates link authentication state
113  *  @param accessCallback - indicates callback state
114  *  @param bitsUpdate - indicates update request
115  *  @param userId - user id
116  *  @param reserved1 - skip 2 bits
117  *  @param privilege - user privilege
118  *  @param reserved2 - skip 4 bits
119  *  @param sessionLimit - optional - unused for now
120  *
121  *  @returns ipmi completion code
122  */
123 ipmi::RspType<> ipmiSetUserAccess(ipmi::Context::ptr ctx, uint4_t channel,
124                                   uint1_t ipmiEnabled, uint1_t linkAuthEnabled,
125                                   uint1_t accessCallback, uint1_t bitsUpdate,
126 
127                                   uint6_t userId, uint2_t reserved1,
128 
129                                   uint4_t privilege, uint4_t reserved2,
130 
131                                   std::optional<uint8_t> sessionLimit)
132 {
133     uint8_t sessLimit = sessionLimit.value_or(0);
134     if (reserved1 || reserved2 || sessLimit ||
135         !ipmiUserIsValidPrivilege(static_cast<uint8_t>(privilege)))
136     {
137         log<level::DEBUG>("Set user access - Invalid field in request");
138         return ipmi::responseInvalidFieldRequest();
139     }
140 
141     uint8_t chNum =
142         convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
143     if (!isValidChannel(chNum))
144     {
145         log<level::DEBUG>("Set user access - Invalid channel request");
146         return ipmi::response(invalidChannel);
147     }
148     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
149     {
150         log<level::DEBUG>("Set user access - No support on channel");
151         return ipmi::response(ccActionNotSupportedForChannel);
152     }
153     if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
154     {
155         log<level::DEBUG>("Set user access - Parameter out of range");
156         return ipmi::responseParmOutOfRange();
157     }
158 
159     PrivAccess privAccess = {0};
160     if (bitsUpdate)
161     {
162         privAccess.ipmiEnabled = static_cast<uint8_t>(ipmiEnabled);
163         privAccess.linkAuthEnabled = static_cast<uint8_t>(linkAuthEnabled);
164         privAccess.accessCallback = static_cast<uint8_t>(accessCallback);
165     }
166     privAccess.privilege = static_cast<uint8_t>(privilege);
167     return ipmi::response(
168         ipmiUserSetPrivilegeAccess(static_cast<uint8_t>(userId), chNum,
169                                    privAccess, static_cast<bool>(bitsUpdate)));
170 }
171 
172 /** @brief implements the set user access command
173  *  @param ctx - IPMI context pointer (for channel)
174  *  @param channel - channel number
175  *  @param reserved1 - skip 4 bits
176  *  @param userId - user id
177  *  @param reserved2 - skip 2 bits
178  *
179  *  @returns ipmi completion code plus response data
180  *   - maxChUsers - max channel users
181  *   - reserved1 - skip 2 bits
182  *   - enabledUsers - enabled users count
183  *   - enabledStatus - enabled status
184  *   - fixedUsers - fixed users count
185  *   - reserved2 - skip 2 bits
186  *   - privilege - user privilege
187  *   - ipmiEnabled - ipmi messaging state
188  *   - linkAuthEnabled - link authenticatin state
189  *   - accessCallback - callback state
190  *   - reserved - skip 1 bit
191  */
192 ipmi::RspType<uint6_t, // max channel users
193               uint2_t, // reserved1
194 
195               uint6_t, // enabled users count
196               uint2_t, // enabled status
197 
198               uint6_t, // fixed users count
199               uint2_t, // reserved2
200 
201               uint4_t, // privilege
202               uint1_t, // ipmi messaging state
203               uint1_t, // link authentication state
204               uint1_t, // access callback state
205               uint1_t  // reserved3
206               >
207     ipmiGetUserAccess(ipmi::Context::ptr ctx, uint4_t channel,
208                       uint4_t reserved1,
209 
210                       uint6_t userId, uint2_t reserved2)
211 {
212     uint8_t chNum =
213         convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
214 
215     if (reserved1 || reserved2 || !isValidChannel(chNum))
216     {
217         log<level::DEBUG>("Get user access - Invalid field in request");
218         return ipmi::responseInvalidFieldRequest();
219     }
220 
221     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
222     {
223         log<level::DEBUG>("Get user access - No support on channel");
224         return ipmi::response(ccActionNotSupportedForChannel);
225     }
226     if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
227     {
228         log<level::DEBUG>("Get user access - Parameter out of range");
229         return ipmi::responseParmOutOfRange();
230     }
231 
232     uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
233     ipmi::Cc retStatus;
234     retStatus = ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers);
235     if (retStatus != ccSuccess)
236     {
237         return ipmi::response(retStatus);
238     }
239 
240     bool enabledState = false;
241     retStatus =
242         ipmiUserCheckEnabled(static_cast<uint8_t>(userId), enabledState);
243     if (retStatus != ccSuccess)
244     {
245         return ipmi::response(retStatus);
246     }
247 
248     uint2_t enabledStatus = enabledState ? userIdEnabledViaSetPassword
249                                          : userIdDisabledViaSetPassword;
250     PrivAccess privAccess{};
251     retStatus = ipmiUserGetPrivilegeAccess(static_cast<uint8_t>(userId), chNum,
252                                            privAccess);
253     if (retStatus != ccSuccess)
254     {
255         return ipmi::response(retStatus);
256     }
257     constexpr uint2_t res2Bits = 0;
258     return ipmi::responseSuccess(
259         static_cast<uint6_t>(maxChUsers), res2Bits,
260 
261         static_cast<uint6_t>(enabledUsers), enabledStatus,
262 
263         static_cast<uint6_t>(fixedUsers), res2Bits,
264 
265         static_cast<uint4_t>(privAccess.privilege),
266         static_cast<uint1_t>(privAccess.ipmiEnabled),
267         static_cast<uint1_t>(privAccess.linkAuthEnabled),
268         static_cast<uint1_t>(privAccess.accessCallback),
269         static_cast<uint1_t>(privAccess.reserved));
270 }
271 
272 Cc ipmiSetUserName(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
273                    ipmi_response_t response, ipmi_data_len_t dataLen,
274                    ipmi_context_t context)
275 {
276     const SetUserNameReq* req = static_cast<SetUserNameReq*>(request);
277     size_t reqLength = *dataLen;
278     *dataLen = 0;
279 
280     if (reqLength != sizeof(*req))
281     {
282         log<level::DEBUG>("Set user name - Invalid Length");
283         return ccReqDataLenInvalid;
284     }
285     if (req->reserved1)
286     {
287         return ccInvalidFieldRequest;
288     }
289     if (!ipmiUserIsValidUserId(req->userId))
290     {
291         log<level::DEBUG>("Set user name - Invalid user id");
292         return ccParmOutOfRange;
293     }
294 
295     size_t nameLen = strnlen(reinterpret_cast<const char*>(req->userName),
296                              sizeof(req->userName));
297     const std::string strUserName(reinterpret_cast<const char*>(req->userName),
298                                   nameLen);
299 
300     return ipmiUserSetUserName(req->userId, strUserName);
301 }
302 
303 /** @brief implementes the get user name command
304  *  @param[in] netfn - specifies netfn.
305  *  @param[in] cmd   - specifies cmd number.
306  *  @param[in] request - pointer to request data.
307  *  @param[in, out] dataLen - specifies request data length, and returns
308  * response data length.
309  *  @param[in] context - ipmi context.
310  *  @returns ipmi completion code.
311  */
312 Cc ipmiGetUserName(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
313                    ipmi_response_t response, ipmi_data_len_t dataLen,
314                    ipmi_context_t context)
315 {
316     const GetUserNameReq* req = static_cast<GetUserNameReq*>(request);
317     size_t reqLength = *dataLen;
318 
319     *dataLen = 0;
320 
321     if (reqLength != sizeof(*req))
322     {
323         log<level::DEBUG>("Get user name - Invalid Length");
324         return ccReqDataLenInvalid;
325     }
326 
327     std::string userName;
328     if (ipmiUserGetUserName(req->userId, userName) != ccSuccess)
329     { // Invalid User ID
330         log<level::DEBUG>("User Name not found",
331                           entry("USER-ID=%d", (uint8_t)req->userId));
332         return ccParmOutOfRange;
333     }
334     GetUserNameResp* resp = static_cast<GetUserNameResp*>(response);
335     std::fill(reinterpret_cast<uint8_t*>(resp),
336               reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
337     userName.copy(reinterpret_cast<char*>(resp->userName),
338                   sizeof(resp->userName), 0);
339     *dataLen = sizeof(*resp);
340 
341     return ccSuccess;
342 }
343 
344 /** @brief implementes the set user password command
345  *  @param[in] netfn - specifies netfn.
346  *  @param[in] cmd   - specifies cmd number.
347  *  @param[in] request - pointer to request data.
348  *  @param[in, out] dataLen - specifies request data length, and returns
349  * response data length.
350  *  @param[in] context - ipmi context.
351  *  @returns ipmi completion code.
352  */
353 Cc ipmiSetUserPassword(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
354                        ipmi_request_t request, ipmi_response_t response,
355                        ipmi_data_len_t dataLen, ipmi_context_t context)
356 {
357     const SetUserPasswordReq* req = static_cast<SetUserPasswordReq*>(request);
358     size_t reqLength = *dataLen;
359     // subtract 2 bytes header to know the password length - including NULL
360     uint8_t passwordLength = *dataLen - 2;
361     *dataLen = 0;
362     if (req->reserved1 || req->reserved2)
363     {
364         log<level::DEBUG>("Invalid data field in request");
365         return ccInvalidFieldRequest;
366     }
367 
368     // verify input length based on operation. Required password size is 20
369     // bytes as  we support only IPMI 2.0, but in order to be compatible with
370     // tools, accept 16 bytes of password size too.
371     if (reqLength < 2 ||
372         // If enable / disable user, reqLength has to be >=2 & <= 22
373         ((req->operation == disableUser || req->operation == enableUser) &&
374          ((reqLength < 2) || (reqLength > sizeof(SetUserPasswordReq)))))
375     {
376         log<level::DEBUG>("Invalid Length");
377         return ccReqDataLenInvalid;
378     }
379     // If set / test password then password length has to be 16 or 20 bytes
380     // based on the password size bit.
381     if (((req->operation == setPassword) || (req->operation == testPassword)) &&
382         (((req->ipmi20 == passwordKeySize20) &&
383           (passwordLength != maxIpmi20PasswordSize)) ||
384          ((req->ipmi20 == passwordKeySize16) &&
385           (passwordLength != maxIpmi15PasswordSize))))
386     {
387         log<level::DEBUG>("Invalid Length");
388         return ccReqDataLenInvalid;
389     }
390 
391     std::string userName;
392     if (ipmiUserGetUserName(req->userId, userName) != ccSuccess)
393     {
394         log<level::DEBUG>("User Name not found",
395                           entry("USER-ID=%d", (uint8_t)req->userId));
396         return ccParmOutOfRange;
397     }
398     if (req->operation == setPassword)
399     {
400         return ipmiUserSetUserPassword(
401             req->userId, reinterpret_cast<const char*>(req->userPassword));
402     }
403     else if (req->operation == enableUser || req->operation == disableUser)
404     {
405         return ipmiUserUpdateEnabledState(req->userId,
406                                           static_cast<bool>(req->operation));
407     }
408     else if (req->operation == testPassword)
409     {
410         auto password = ipmiUserGetPassword(userName);
411         std::string testPassword(
412             reinterpret_cast<const char*>(req->userPassword), 0,
413             passwordLength);
414         // Note: For security reasons password size won't be compared and
415         // wrong password size completion code will not be returned if size
416         // doesn't match as specified in IPMI specification.
417         if (password != testPassword)
418         {
419             log<level::DEBUG>("Test password failed",
420                               entry("USER-ID=%d", (uint8_t)req->userId));
421             // Clear sensitive data
422             OPENSSL_cleanse(&testPassword, testPassword.length());
423             OPENSSL_cleanse(&password, password.length());
424 
425             return static_cast<Cc>(
426                 IPMISetPasswordReturnCodes::ipmiCCPasswdFailMismatch);
427         }
428         // Clear sensitive data
429         OPENSSL_cleanse(&testPassword, testPassword.length());
430         OPENSSL_cleanse(&password, password.length());
431 
432         return ccSuccess;
433     }
434     return ccInvalidFieldRequest;
435 }
436 
437 /** @brief implements the get channel authentication command
438  *  @param ctx - IPMI context pointer (for channel)
439  *  @param extData - get IPMI 2.0 extended data
440  *  @param reserved1 - skip 3 bits
441  *  @param chNum - channel number to get info about
442  *  @param reserved2 - skip 4 bits
443  *  @param privLevel - requested privilege level
444 
445  *  @returns ipmi completion code plus response data
446  *   - channel number
447  *   - rmcpAuthTypes - RMCP auth types (IPMI 1.5)
448  *   - reserved1
449  *   - extDataSupport - true for IPMI 2.0 extensions
450  *   - anonymousLogin - true for anonymous login enabled
451  *   - nullUsers - true for null user names enabled
452  *   - nonNullUsers - true for non-null usernames enabled
453  *   - userAuth - false for user authentication enabled
454  *   - perMessageAuth - false for per message authentication enabled
455  *   - KGStatus - true for Kg required for authentication
456  *   - reserved2
457  *   - rmcp - RMCP (IPMI 1.5) connection support
458  *   - rmcpp - RMCP+ (IPMI 2.0) connection support
459  *   - reserved3
460  *   - oemID - OEM IANA of any OEM auth support
461  *   - oemAuxillary - OEM data for auth
462  */
463 ipmi::RspType<uint8_t,  // channel number
464               uint6_t,  // rmcpAuthTypes
465               bool,     // reserved1
466               bool,     // extDataSupport
467               bool,     // anonymousLogin
468               bool,     // nullUsers
469               bool,     // nonNullUsers
470               bool,     // userAuth
471               bool,     // perMessageAuth
472               bool,     // KGStatus
473               uint2_t,  // reserved2
474               bool,     // rmcp
475               bool,     // rmcpp
476               uint6_t,  // reserved3
477               uint24_t, // oemID
478               uint8_t   // oemAuxillary
479               >
480     ipmiGetChannelAuthenticationCapabilities(ipmi::Context::ptr ctx,
481                                              uint4_t chNum, uint3_t reserved1,
482                                              bool extData, uint4_t privLevel,
483                                              uint4_t reserved2)
484 {
485     uint8_t channel =
486         convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx->channel);
487 
488     if (reserved1 || reserved2 || !isValidChannel(channel) ||
489         !isValidPrivLimit(static_cast<uint8_t>(privLevel)))
490     {
491         log<level::DEBUG>(
492             "Get channel auth capabilities - Invalid field in request");
493         return ipmi::responseInvalidFieldRequest();
494     }
495 
496     if (getChannelSessionSupport(channel) == EChannelSessSupported::none)
497     {
498         log<level::DEBUG>(
499             "Get channel auth capabilities - No support on channel");
500         return ipmi::response(ccActionNotSupportedForChannel);
501     }
502 
503     constexpr bool extDataSupport = true; // true for IPMI 2.0 extensions
504     constexpr bool reserved3 = false;
505     constexpr uint6_t rmcpAuthTypes = 0; // IPMI 1.5 auth types - not supported
506     constexpr uint2_t reserved4 = 0;
507     constexpr bool KGStatus = false;       // Not supporting now.
508     constexpr bool perMessageAuth = false; // Per message auth - enabled
509     constexpr bool userAuth = false;       // User authentication - enabled
510     constexpr bool nullUsers = false;      // Null user names - not supported
511     constexpr bool anonymousLogin = false; // Anonymous login - not supported
512     constexpr uint6_t reserved5 = 0;
513     constexpr bool rmcpp = true; // IPMI 2.0 - supported
514     constexpr bool rmcp = false; // IPMI 1.5 - not supported
515     constexpr uint24_t oemID = 0;
516     constexpr uint8_t oemAuxillary = 0;
517 
518     bool nonNullUsers = 0;
519     uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
520     ipmi::ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers);
521     nonNullUsers = enabledUsers > 0;
522 
523     return ipmi::responseSuccess(
524         channel, rmcpAuthTypes, reserved3, extDataSupport, anonymousLogin,
525         nullUsers, nonNullUsers, userAuth, perMessageAuth, KGStatus, reserved4,
526         rmcp, rmcpp, reserved5, oemID, oemAuxillary);
527 }
528 
529 /** @brief implements the set user payload access command.
530  *  @param ctx - IPMI context pointer (for channel)
531  *  @param channel - channel number (4 bits)
532  *  @param reserved1 - skip 4 bits
533  *  @param userId - user id (6 bits)
534  *  @param operation - access ENABLE /DISABLE. (2 bits)
535  *  @param stdPayload0 - IPMI - reserved. (1 bit)
536  *  @param stdPayload1 - SOL.             (1 bit)
537  *  @param stdPayload2 -                  (1 bit)
538  *  @param stdPayload3 -                  (1 bit)
539  *  @param stdPayload4 -                  (1 bit)
540  *  @param stdPayload5 -                  (1 bit)
541  *  @param stdPayload6 -                  (1 bit)
542  *  @param stdPayload7 -                  (1 bit)
543  *  @param stdPayloadEnables2Reserved -   (8 bits)
544  *  @param oemPayload0 -                  (1 bit)
545  *  @param oemPayload1 -                  (1 bit)
546  *  @param oemPayload2 -                  (1 bit)
547  *  @param oemPayload3 -                  (1 bit)
548  *  @param oemPayload4 -                  (1 bit)
549  *  @param oemPayload5 -                  (1 bit)
550  *  @param oemPayload6 -                  (1 bit)
551  *  @param oemPayload7 -                  (1 bit)
552  *  @param oemPayloadEnables2Reserved -   (8 bits)
553  *
554  *  @returns IPMI completion code
555  */
556 ipmi::RspType<> ipmiSetUserPayloadAccess(
557     ipmi::Context::ptr ctx,
558 
559     uint4_t channel, uint4_t reserved,
560 
561     uint6_t userId, uint2_t operation,
562 
563     bool stdPayload0ipmiReserved, bool stdPayload1SOL, bool stdPayload2,
564     bool stdPayload3, bool stdPayload4, bool stdPayload5, bool stdPayload6,
565     bool stdPayload7,
566 
567     uint8_t stdPayloadEnables2Reserved,
568 
569     bool oemPayload0, bool oemPayload1, bool oemPayload2, bool oemPayload3,
570     bool oemPayload4, bool oemPayload5, bool oemPayload6, bool oemPayload7,
571 
572     uint8_t oemPayloadEnables2Reserved)
573 {
574     auto chNum =
575         convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
576     // Validate the reserved args. Only SOL payload is supported as on date.
577     if (reserved || stdPayload0ipmiReserved || stdPayload2 || stdPayload3 ||
578         stdPayload4 || stdPayload5 || stdPayload6 || stdPayload7 ||
579         oemPayload0 || oemPayload1 || oemPayload2 || oemPayload3 ||
580         oemPayload4 || oemPayload5 || oemPayload6 || oemPayload7 ||
581         stdPayloadEnables2Reserved || oemPayloadEnables2Reserved ||
582         !isValidChannel(chNum))
583     {
584         return ipmi::responseInvalidFieldRequest();
585     }
586 
587     if ((operation != enableOperation && operation != disableOperation))
588     {
589         return ipmi::responseInvalidFieldRequest();
590     }
591     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
592     {
593         return ipmi::response(ccActionNotSupportedForChannel);
594     }
595     if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
596     {
597         return ipmi::responseParmOutOfRange();
598     }
599 
600     PayloadAccess payloadAccess = {0};
601     payloadAccess.stdPayloadEnables1[1] = stdPayload1SOL;
602 
603     return ipmi::response(ipmiUserSetUserPayloadAccess(
604         chNum, static_cast<uint8_t>(operation), static_cast<uint8_t>(userId),
605         payloadAccess));
606 }
607 
608 /** @brief implements the get user payload access command
609  *  This command returns information about user payload enable settings
610  *  that were set using the 'Set User Payload Access' Command.
611  *
612  *  @param ctx - IPMI context pointer (for channel)
613  *  @param channel - channel number
614  *  @param reserved1 - skip 4 bits
615  *  @param userId - user id
616  *  @param reserved2 - skip 2 bits
617  *
618  *  @returns IPMI completion code plus response data
619  *   - stdPayload0ipmiReserved - IPMI payload (reserved).
620  *   - stdPayload1SOL - SOL payload
621  *   - stdPayload2
622  *   - stdPayload3
623  *   - stdPayload4
624  *   - stdPayload5
625  *   - stdPayload6
626  *   - stdPayload7
627 
628  *   - stdPayloadEnables2Reserved - Reserved.
629 
630  *   - oemPayload0
631  *   - oemPayload1
632  *   - oemPayload2
633  *   - oemPayload3
634  *   - oemPayload4
635  *   - oemPayload5
636  *   - oemPayload6
637  *   - oemPayload7
638 
639  *  - oemPayloadEnables2Reserved - Reserved
640  */
641 ipmi::RspType<bool, // stdPayload0ipmiReserved
642               bool, // stdPayload1SOL
643               bool, // stdPayload2
644               bool, // stdPayload3
645               bool, // stdPayload4
646               bool, // stdPayload5
647               bool, // stdPayload6
648               bool, // stdPayload7
649 
650               uint8_t, // stdPayloadEnables2Reserved
651 
652               bool, // oemPayload0
653               bool, // oemPayload1
654               bool, // oemPayload2
655               bool, // oemPayload3
656               bool, // oemPayload4
657               bool, // oemPayload5
658               bool, // oemPayload6
659               bool, // oemPayload7
660 
661               uint8_t // oemPayloadEnables2Reserved
662               >
663     ipmiGetUserPayloadAccess(ipmi::Context::ptr ctx,
664 
665                              uint4_t channel, uint4_t reserved1,
666 
667                              uint6_t userId, uint2_t reserved2)
668 {
669     uint8_t chNum =
670         convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
671 
672     if (reserved1 || reserved2 || !isValidChannel(chNum))
673     {
674         return ipmi::responseInvalidFieldRequest();
675     }
676     if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
677     {
678         return ipmi::response(ccActionNotSupportedForChannel);
679     }
680     if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
681     {
682         return ipmi::responseParmOutOfRange();
683     }
684 
685     ipmi::Cc retStatus;
686     PayloadAccess payloadAccess = {};
687     retStatus = ipmiUserGetUserPayloadAccess(
688         chNum, static_cast<uint8_t>(userId), payloadAccess);
689     if (retStatus != ccSuccess)
690     {
691         return ipmi::response(retStatus);
692     }
693     constexpr uint8_t res8bits = 0;
694     return ipmi::responseSuccess(payloadAccess.stdPayloadEnables1.test(0),
695                                  payloadAccess.stdPayloadEnables1.test(1),
696                                  payloadAccess.stdPayloadEnables1.test(2),
697                                  payloadAccess.stdPayloadEnables1.test(3),
698                                  payloadAccess.stdPayloadEnables1.test(4),
699                                  payloadAccess.stdPayloadEnables1.test(5),
700                                  payloadAccess.stdPayloadEnables1.test(6),
701                                  payloadAccess.stdPayloadEnables1.test(7),
702 
703                                  res8bits,
704 
705                                  payloadAccess.oemPayloadEnables1.test(0),
706                                  payloadAccess.oemPayloadEnables1.test(1),
707                                  payloadAccess.oemPayloadEnables1.test(2),
708                                  payloadAccess.oemPayloadEnables1.test(3),
709                                  payloadAccess.oemPayloadEnables1.test(4),
710                                  payloadAccess.oemPayloadEnables1.test(5),
711                                  payloadAccess.oemPayloadEnables1.test(6),
712                                  payloadAccess.oemPayloadEnables1.test(7),
713 
714                                  res8bits);
715 }
716 
717 void registerUserIpmiFunctions() __attribute__((constructor));
718 void registerUserIpmiFunctions()
719 {
720     post_work([]() { ipmiUserInit(); });
721     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
722                           ipmi::app::cmdSetUserAccessCommand,
723                           ipmi::Privilege::Admin, ipmiSetUserAccess);
724 
725     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
726                           ipmi::app::cmdGetUserAccessCommand,
727                           ipmi::Privilege::Operator, ipmiGetUserAccess);
728 
729     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_USER_NAME, NULL,
730                            ipmiGetUserName, PRIVILEGE_OPERATOR);
731 
732     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_USER_NAME, NULL,
733                            ipmiSetUserName, PRIVILEGE_ADMIN);
734 
735     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_USER_PASSWORD, NULL,
736                            ipmiSetUserPassword, PRIVILEGE_ADMIN);
737 
738     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
739                           ipmi::app::cmdGetChannelAuthCapabilities,
740                           ipmi::Privilege::Callback,
741                           ipmiGetChannelAuthenticationCapabilities);
742 
743     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
744                           ipmi::app::cmdSetUserPayloadAccess,
745                           ipmi::Privilege::Admin, ipmiSetUserPayloadAccess);
746 
747     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
748                           ipmi::app::cmdGetUserPayloadAccess,
749                           ipmi::Privilege::Operator, ipmiGetUserPayloadAccess);
750 
751     return;
752 }
753 } // namespace ipmi
754