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 
41 /** @struct SetUserNameReq
42  *
43  *  Structure for set user name request command (refer spec sec 22.28)
44  */
45 struct SetUserNameReq
46 {
47 #if BYTE_ORDER == LITTLE_ENDIAN
48     uint8_t userId : 6;
49     uint8_t reserved1 : 2;
50 #endif
51 #if BYTE_ORDER == BIG_ENDIAN
52     uint8_t reserved1 : 2;
53     uint8_t userId : 6;
54 #endif
55     uint8_t userName[16];
56 } __attribute__((packed));
57 
58 /** @struct GetUserNameReq
59  *
60  *  Structure for get user name request command (refer spec sec 22.29)
61  */
62 struct GetUserNameReq
63 {
64 #if BYTE_ORDER == LITTLE_ENDIAN
65     uint8_t userId : 6;
66     uint8_t reserved1 : 2;
67 #endif
68 #if BYTE_ORDER == BIG_ENDIAN
69     uint8_t reserved1 : 2;
70     uint8_t userId : 6;
71 #endif
72 } __attribute__((packed));
73 
74 /** @struct GetUserNameResp
75  *
76  *  Structure for get user name response command (refer spec sec 22.29)
77  */
78 struct GetUserNameResp
79 {
80     uint8_t userName[16];
81 } __attribute__((packed));
82 
83 /** @struct SetUserPasswordReq
84  *
85  *  Structure for set user password request command (refer spec sec 22.30)
86  */
87 struct SetUserPasswordReq
88 {
89 #if BYTE_ORDER == LITTLE_ENDIAN
90     uint8_t userId : 6;
91     uint8_t reserved1 : 1;
92     uint8_t ipmi20 : 1;
93     uint8_t operation : 2;
94     uint8_t reserved2 : 6;
95 #endif
96 #if BYTE_ORDER == BIG_ENDIAN
97     uint8_t ipmi20 : 1;
98     uint8_t reserved1 : 1;
99     uint8_t userId : 6;
100     uint8_t reserved2 : 6;
101     uint8_t operation : 2;
102 #endif
103     uint8_t userPassword[maxIpmi20PasswordSize];
104 } __attribute__((packed));
105 
106 /** @brief implements the set user access command
107  *  @param ctx - IPMI context pointer (for channel)
108  *  @param channel - channel number
109  *  @param ipmiEnabled - indicates ipmi messaging state
110  *  @param linkAuthEnabled - indicates link authentication state
111  *  @param accessCallback - indicates callback state
112  *  @param bitsUpdate - indicates update request
113  *  @param userId - user id
114  *  @param reserved1 - skip 2 bits
115  *  @param privilege - user privilege
116  *  @param reserved2 - skip 4 bits
117  *  @param sessionLimit - optional - unused for now
118  *
119  *  @returns ipmi completion code
120  */
121 ipmi::RspType<> ipmiSetUserAccess(ipmi::Context::ptr ctx, uint4_t channel,
122                                   uint1_t ipmiEnabled, uint1_t linkAuthEnabled,
123                                   uint1_t accessCallback, uint1_t bitsUpdate,
124 
125                                   uint6_t userId, uint2_t reserved1,
126 
127                                   uint4_t privilege, uint4_t reserved2,
128 
129                                   std::optional<uint8_t> sessionLimit)
130 {
131     uint8_t sessLimit = sessionLimit.value_or(0);
132     uint8_t chNum =
133         convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx);
134     if (reserved1 != 0 || reserved2 != 0 || sessLimit != 0 ||
135         (!isValidChannel(chNum)) ||
136         (!ipmiUserIsValidPrivilege(static_cast<uint8_t>(privilege))) ||
137         (EChannelSessSupported::none == getChannelSessionSupport(chNum)))
138     {
139         log<level::DEBUG>("Set user access - Invalid field in request");
140         return ipmi::responseInvalidFieldRequest();
141     }
142     if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
143     {
144         log<level::DEBUG>("Set user access - Parameter out of range");
145         return ipmi::responseParmOutOfRange();
146     }
147 
148     PrivAccess privAccess = {0};
149     if (bitsUpdate)
150     {
151         privAccess.ipmiEnabled = static_cast<uint8_t>(ipmiEnabled);
152         privAccess.linkAuthEnabled = static_cast<uint8_t>(linkAuthEnabled);
153         privAccess.accessCallback = static_cast<uint8_t>(accessCallback);
154     }
155     privAccess.privilege = static_cast<uint8_t>(privilege);
156     return ipmi::response(
157         ipmiUserSetPrivilegeAccess(static_cast<uint8_t>(userId), chNum,
158                                    privAccess, static_cast<bool>(bitsUpdate)));
159 }
160 
161 /** @brief implements the set user access command
162  *  @param ctx - IPMI context pointer (for channel)
163  *  @param channel - channel number
164  *  @param reserved1 - skip 4 bits
165  *  @param userId - user id
166  *  @param reserved2 - skip 2 bits
167  *
168  *  @returns ipmi completion code plus response data
169  *   - maxChUsers - max channel users
170  *   - reserved1 - skip 2 bits
171  *   - enabledUsers - enabled users count
172  *   - enabledStatus - enabled status
173  *   - fixedUsers - fixed users count
174  *   - reserved2 - skip 2 bits
175  *   - privilege - user privilege
176  *   - ipmiEnabled - ipmi messaging state
177  *   - linkAuthEnabled - link authenticatin state
178  *   - accessCallback - callback state
179  *   - reserved - skip 1 bit
180  */
181 ipmi::RspType<uint6_t, // max channel users
182               uint2_t, // reserved1
183 
184               uint6_t, // enabled users count
185               uint2_t, // enabled status
186 
187               uint6_t, // fixed users count
188               uint2_t, // reserved2
189 
190               uint4_t, // privilege
191               uint1_t, // ipmi messaging state
192               uint1_t, // link authentication state
193               uint1_t, // access callback state
194               uint1_t  // reserved3
195               >
196     ipmiGetUserAccess(ipmi::Context::ptr ctx, uint4_t channel,
197                       uint4_t reserved1,
198 
199                       uint6_t userId, uint2_t reserved2)
200 {
201     uint8_t chNum =
202         convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx);
203     if (reserved1 != 0 || reserved2 != 0 || (!isValidChannel(chNum)) ||
204         (EChannelSessSupported::none == getChannelSessionSupport(chNum)))
205     {
206         log<level::DEBUG>("Get user access - Invalid field in request");
207         return ipmi::responseInvalidFieldRequest();
208     }
209     if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
210     {
211         log<level::DEBUG>("Get user access - Parameter out of range");
212         return ipmi::responseParmOutOfRange();
213     }
214 
215     uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
216     ipmi::Cc retStatus;
217     retStatus = ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers);
218     if (retStatus != IPMI_CC_OK)
219     {
220         return ipmi::response(retStatus);
221     }
222 
223     bool enabledState = false;
224     retStatus =
225         ipmiUserCheckEnabled(static_cast<uint8_t>(userId), enabledState);
226     if (retStatus != IPMI_CC_OK)
227     {
228         return ipmi::response(retStatus);
229     }
230 
231     uint2_t enabledStatus = enabledState ? userIdEnabledViaSetPassword
232                                          : userIdDisabledViaSetPassword;
233     PrivAccess privAccess{};
234     retStatus = ipmiUserGetPrivilegeAccess(static_cast<uint8_t>(userId), chNum,
235                                            privAccess);
236     if (retStatus != IPMI_CC_OK)
237     {
238         return ipmi::response(retStatus);
239     }
240     constexpr uint2_t res2Bits = 0;
241     return ipmi::responseSuccess(
242         static_cast<uint6_t>(maxChUsers), res2Bits,
243 
244         static_cast<uint6_t>(enabledUsers), enabledStatus,
245 
246         static_cast<uint6_t>(fixedUsers), res2Bits,
247 
248         static_cast<uint4_t>(privAccess.privilege),
249         static_cast<uint1_t>(privAccess.ipmiEnabled),
250         static_cast<uint1_t>(privAccess.linkAuthEnabled),
251         static_cast<uint1_t>(privAccess.accessCallback),
252         static_cast<uint1_t>(privAccess.reserved));
253 }
254 
255 ipmi_ret_t ipmiSetUserName(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
256                            ipmi_request_t request, ipmi_response_t response,
257                            ipmi_data_len_t dataLen, ipmi_context_t context)
258 {
259     const SetUserNameReq* req = static_cast<SetUserNameReq*>(request);
260     size_t reqLength = *dataLen;
261     *dataLen = 0;
262 
263     if (reqLength != sizeof(*req))
264     {
265         log<level::DEBUG>("Set user name - Invalid Length");
266         return IPMI_CC_REQ_DATA_LEN_INVALID;
267     }
268     if (req->reserved1)
269     {
270         return IPMI_CC_INVALID_FIELD_REQUEST;
271     }
272     if (!ipmiUserIsValidUserId(req->userId))
273     {
274         log<level::DEBUG>("Set user name - Invalid user id");
275         return IPMI_CC_PARM_OUT_OF_RANGE;
276     }
277 
278     return ipmiUserSetUserName(req->userId,
279                                reinterpret_cast<const char*>(req->userName));
280 }
281 
282 /** @brief implementes the get user name command
283  *  @param[in] netfn - specifies netfn.
284  *  @param[in] cmd   - specifies cmd number.
285  *  @param[in] request - pointer to request data.
286  *  @param[in, out] dataLen - specifies request data length, and returns
287  * response data length.
288  *  @param[in] context - ipmi context.
289  *  @returns ipmi completion code.
290  */
291 ipmi_ret_t ipmiGetUserName(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
292                            ipmi_request_t request, ipmi_response_t response,
293                            ipmi_data_len_t dataLen, ipmi_context_t context)
294 {
295     const GetUserNameReq* req = static_cast<GetUserNameReq*>(request);
296     size_t reqLength = *dataLen;
297 
298     *dataLen = 0;
299 
300     if (reqLength != sizeof(*req))
301     {
302         log<level::DEBUG>("Get user name - Invalid Length");
303         return IPMI_CC_REQ_DATA_LEN_INVALID;
304     }
305 
306     std::string userName;
307     if (ipmiUserGetUserName(req->userId, userName) != IPMI_CC_OK)
308     { // Invalid User ID
309         log<level::DEBUG>("User Name not found",
310                           entry("USER-ID:%d", (uint8_t)req->userId));
311         return IPMI_CC_PARM_OUT_OF_RANGE;
312     }
313     GetUserNameResp* resp = static_cast<GetUserNameResp*>(response);
314     std::fill(reinterpret_cast<uint8_t*>(resp),
315               reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
316     userName.copy(reinterpret_cast<char*>(resp->userName),
317                   sizeof(resp->userName), 0);
318     *dataLen = sizeof(*resp);
319 
320     return IPMI_CC_OK;
321 }
322 
323 /** @brief implementes the set user password command
324  *  @param[in] netfn - specifies netfn.
325  *  @param[in] cmd   - specifies cmd number.
326  *  @param[in] request - pointer to request data.
327  *  @param[in, out] dataLen - specifies request data length, and returns
328  * response data length.
329  *  @param[in] context - ipmi context.
330  *  @returns ipmi completion code.
331  */
332 ipmi_ret_t ipmiSetUserPassword(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
333                                ipmi_request_t request, ipmi_response_t response,
334                                ipmi_data_len_t dataLen, ipmi_context_t context)
335 {
336     const SetUserPasswordReq* req = static_cast<SetUserPasswordReq*>(request);
337     size_t reqLength = *dataLen;
338     // subtract 2 bytes header to know the password length - including NULL
339     uint8_t passwordLength = *dataLen - 2;
340     *dataLen = 0;
341 
342     // verify input length based on operation. Required password size is 20
343     // bytes as  we support only IPMI 2.0, but in order to be compatible with
344     // tools, accept 16 bytes of password size too.
345     if (reqLength < 2 ||
346         // If enable / disable user, reqLength has to be >=2 & <= 22
347         ((req->operation == disableUser || req->operation == enableUser) &&
348          ((reqLength < 2) || (reqLength > sizeof(SetUserPasswordReq)))))
349     {
350         log<level::DEBUG>("Invalid Length");
351         return IPMI_CC_REQ_DATA_LEN_INVALID;
352     }
353     // If set / test password then password length has to be 16 or 20 bytes
354     // based on the password size bit.
355     if (((req->operation == setPassword) || (req->operation == testPassword)) &&
356         (((req->ipmi20 == passwordKeySize20) &&
357           (passwordLength != maxIpmi20PasswordSize)) ||
358          ((req->ipmi20 == passwordKeySize16) &&
359           (passwordLength != maxIpmi15PasswordSize))))
360     {
361         log<level::DEBUG>("Invalid Length");
362         return IPMI_CC_REQ_DATA_LEN_INVALID;
363     }
364 
365     std::string userName;
366     if (ipmiUserGetUserName(req->userId, userName) != IPMI_CC_OK)
367     {
368         log<level::DEBUG>("User Name not found",
369                           entry("USER-ID:%d", (uint8_t)req->userId));
370         return IPMI_CC_PARM_OUT_OF_RANGE;
371     }
372     if (req->operation == setPassword)
373     {
374         return ipmiUserSetUserPassword(
375             req->userId, reinterpret_cast<const char*>(req->userPassword));
376     }
377     else if (req->operation == enableUser || req->operation == disableUser)
378     {
379         return ipmiUserUpdateEnabledState(req->userId,
380                                           static_cast<bool>(req->operation));
381     }
382     else if (req->operation == testPassword)
383     {
384         auto password = ipmiUserGetPassword(userName);
385         std::string testPassword(
386             reinterpret_cast<const char*>(req->userPassword), 0,
387             passwordLength);
388         // Note: For security reasons password size won't be compared and
389         // wrong password size completion code will not be returned if size
390         // doesn't match as specified in IPMI specification.
391         if (password != testPassword)
392         {
393             log<level::DEBUG>("Test password failed",
394                               entry("USER-ID:%d", (uint8_t)req->userId));
395             return static_cast<ipmi_ret_t>(
396                 IPMISetPasswordReturnCodes::ipmiCCPasswdFailMismatch);
397         }
398         return IPMI_CC_OK;
399     }
400     return IPMI_CC_INVALID_FIELD_REQUEST;
401 }
402 
403 /** @brief implements the get channel authentication command
404  *  @param ctx - IPMI context pointer (for channel)
405  *  @param extData - get IPMI 2.0 extended data
406  *  @param reserved1 - skip 3 bits
407  *  @param chNum - channel number to get info about
408  *  @param reserved2 - skip 4 bits
409  *  @param privLevel - requested privilege level
410 
411  *  @returns ipmi completion code plus response data
412  *   - channel number
413  *   - rmcpAuthTypes - RMCP auth types (IPMI 1.5)
414  *   - reserved1
415  *   - extDataSupport - true for IPMI 2.0 extensions
416  *   - anonymousLogin - true for anonymous login enabled
417  *   - nullUsers - true for null user names enabled
418  *   - nonNullUsers - true for non-null usernames enabled
419  *   - userAuth - false for user authentication enabled
420  *   - perMessageAuth - false for per message authentication enabled
421  *   - KGStatus - true for Kg required for authentication
422  *   - reserved2
423  *   - rmcp - RMCP (IPMI 1.5) connection support
424  *   - rmcpp - RMCP+ (IPMI 2.0) connection support
425  *   - reserved3
426  *   - oemID - OEM IANA of any OEM auth support
427  *   - oemAuxillary - OEM data for auth
428  */
429 ipmi::RspType<uint8_t,  // channel number
430               uint6_t,  // rmcpAuthTypes
431               bool,     // reserved1
432               bool,     // extDataSupport
433               bool,     // anonymousLogin
434               bool,     // nullUsers
435               bool,     // nonNullUsers
436               bool,     // userAuth
437               bool,     // perMessageAuth
438               bool,     // KGStatus
439               uint2_t,  // reserved2
440               bool,     // rmcp
441               bool,     // rmcpp
442               uint6_t,  // reserved3
443               uint24_t, // oemID
444               uint8_t   // oemAuxillary
445               >
446     ipmiGetChannelAuthenticationCapabilities(ipmi::Context::ptr ctx,
447                                              uint4_t chNum, uint3_t reserved1,
448                                              bool extData, uint4_t privLevel,
449                                              uint4_t reserved2)
450 {
451 
452     uint8_t channel =
453         convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx);
454 
455     if (reserved1 || reserved2 || !isValidChannel(channel) ||
456         !isValidPrivLimit(static_cast<uint8_t>(privLevel)) ||
457         (EChannelSessSupported::none == getChannelSessionSupport(channel)))
458     {
459         return ipmi::response(ccInvalidFieldRequest);
460     }
461 
462     constexpr bool extDataSupport = true; // true for IPMI 2.0 extensions
463     constexpr bool reserved3 = false;
464     constexpr uint6_t rmcpAuthTypes = 0; // IPMI 1.5 auth types - not supported
465     constexpr uint2_t reserved4 = 0;
466     constexpr bool KGStatus = false;       // Not supporting now.
467     constexpr bool perMessageAuth = false; // Per message auth - enabled
468     constexpr bool userAuth = false;       // User authentication - enabled
469     constexpr bool nullUsers = false;      // Null user names - not supported
470     constexpr bool anonymousLogin = false; // Anonymous login - not supported
471     constexpr uint6_t reserved5 = 0;
472     constexpr bool rmcpp = true; // IPMI 2.0 - supported
473     constexpr bool rmcp = false; // IPMI 1.5 - not supported
474     constexpr uint24_t oemID = 0;
475     constexpr uint8_t oemAuxillary = 0;
476 
477     bool nonNullUsers = 0;
478     uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
479     ipmi::ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers);
480     nonNullUsers = enabledUsers > 0;
481 
482     return ipmi::responseSuccess(
483         channel, rmcpAuthTypes, reserved3, extDataSupport, anonymousLogin,
484         nullUsers, nonNullUsers, userAuth, perMessageAuth, KGStatus, reserved4,
485         rmcp, rmcpp, reserved5, oemID, oemAuxillary);
486 }
487 
488 void registerUserIpmiFunctions() __attribute__((constructor));
489 void registerUserIpmiFunctions()
490 {
491     ipmiUserInit();
492     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
493                           ipmi::app::cmdSetUserAccessCommand,
494                           ipmi::Privilege::Admin, ipmiSetUserAccess);
495 
496     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
497                           ipmi::app::cmdGetUserAccessCommand,
498                           ipmi::Privilege::Operator, ipmiGetUserAccess);
499 
500     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_USER_NAME, NULL,
501                            ipmiGetUserName, PRIVILEGE_OPERATOR);
502 
503     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_USER_NAME, NULL,
504                            ipmiSetUserName, PRIVILEGE_ADMIN);
505 
506     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_USER_PASSWORD, NULL,
507                            ipmiSetUserPassword, PRIVILEGE_ADMIN);
508 
509     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
510                           ipmi::app::cmdGetChannelAuthCapabilities,
511                           ipmi::Privilege::Callback,
512                           ipmiGetChannelAuthenticationCapabilities);
513     return;
514 }
515 } // namespace ipmi
516