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