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 <host-ipmid/ipmid-api.h>
24 #include <security/pam_appl.h>
25 
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 maxIpmi20PasswordSize = 20;
35 static constexpr uint8_t maxIpmi15PasswordSize = 16;
36 static constexpr uint8_t disableUser = 0x00;
37 static constexpr uint8_t enableUser = 0x01;
38 static constexpr uint8_t setPassword = 0x02;
39 static constexpr uint8_t testPassword = 0x03;
40 static constexpr uint8_t passwordKeySize20 = 1;
41 static constexpr uint8_t passwordKeySize16 = 0;
42 
43 /** @struct SetUserAccessReq
44  *
45  *  Structure for set user access request command (refer spec sec 22.26)
46  */
47 struct SetUserAccessReq
48 {
49 #if BYTE_ORDER == LITTLE_ENDIAN
50     uint8_t chNum : 4;
51     uint8_t ipmiEnabled : 1;
52     uint8_t linkAuthEnabled : 1;
53     uint8_t accessCallback : 1;
54     uint8_t bitsUpdate : 1;
55     uint8_t userId : 6;
56     uint8_t reserved1 : 2;
57     uint8_t privilege : 4;
58     uint8_t reserved2 : 4;
59     uint8_t sessLimit : 4; // optional byte 4
60     uint8_t reserved3 : 4;
61 #endif
62 #if BYTE_ORDER == BIG_ENDIAN
63     uint8_t bitsUpdate : 1;
64     uint8_t accessCallback : 1;
65     uint8_t linkAuthEnabled : 1;
66     uint8_t ipmiEnabled : 1;
67     uint8_t chNum : 4;
68     uint8_t reserved1 : 2;
69     uint8_t userId : 6;
70     uint8_t reserved2 : 4;
71     uint8_t privilege : 4;
72     uint8_t reserved3 : 4;
73     uint8_t sessLimit : 4; // optional byte 4
74 #endif
75 
76 } __attribute__((packed));
77 
78 /** @struct GetUserAccessReq
79  *
80  *  Structure for get user access request command (refer spec sec 22.27)
81  */
82 struct GetUserAccessReq
83 {
84 #if BYTE_ORDER == LITTLE_ENDIAN
85     uint8_t chNum : 4;
86     uint8_t reserved1 : 4;
87     uint8_t userId : 6;
88     uint8_t reserved2 : 2;
89 #endif
90 #if BYTE_ORDER == BIG_ENDIAN
91     uint8_t reserved1 : 4;
92     uint8_t chNum : 4;
93     uint8_t reserved2 : 2;
94     uint8_t userId : 6;
95 #endif
96 } __attribute__((packed));
97 
98 /** @struct GetUserAccessResp
99  *
100  *  Structure for get user access response command (refer spec sec 22.27)
101  */
102 struct GetUserAccessResp
103 {
104 #if BYTE_ORDER == LITTLE_ENDIAN
105     uint8_t maxChUsers : 6;
106     uint8_t reserved1 : 2;
107     uint8_t enabledUsers : 6;
108     uint8_t enabledStatus : 2;
109     uint8_t fixedUsers : 6;
110     uint8_t reserved2 : 2;
111 #endif
112 #if BYTE_ORDER == BIG_ENDIAN
113     uint8_t reserved1 : 2;
114     uint8_t maxChUsers : 6;
115     uint8_t enabledStatus : 2;
116     uint8_t enabledUsers : 6;
117     uint8_t reserved2 : 2;
118     uint8_t fixedUsers : 6;
119 #endif
120     PrivAccess privAccess;
121 } __attribute__((packed));
122 
123 /** @struct SetUserNameReq
124  *
125  *  Structure for set user name request command (refer spec sec 22.28)
126  */
127 struct SetUserNameReq
128 {
129 #if BYTE_ORDER == LITTLE_ENDIAN
130     uint8_t userId : 6;
131     uint8_t reserved1 : 2;
132 #endif
133 #if BYTE_ORDER == BIG_ENDIAN
134     uint8_t reserved1 : 2;
135     uint8_t userId : 6;
136 #endif
137     uint8_t userName[16];
138 } __attribute__((packed));
139 
140 /** @struct GetUserNameReq
141  *
142  *  Structure for get user name request command (refer spec sec 22.29)
143  */
144 struct GetUserNameReq
145 {
146 #if BYTE_ORDER == LITTLE_ENDIAN
147     uint8_t userId : 6;
148     uint8_t reserved1 : 2;
149 #endif
150 #if BYTE_ORDER == BIG_ENDIAN
151     uint8_t reserved1 : 2;
152     uint8_t userId : 6;
153 #endif
154 } __attribute__((packed));
155 
156 /** @struct GetUserNameResp
157  *
158  *  Structure for get user name response command (refer spec sec 22.29)
159  */
160 struct GetUserNameResp
161 {
162     uint8_t userName[16];
163 } __attribute__((packed));
164 
165 /** @struct SetUserPasswordReq
166  *
167  *  Structure for set user password request command (refer spec sec 22.30)
168  */
169 struct SetUserPasswordReq
170 {
171 #if BYTE_ORDER == LITTLE_ENDIAN
172     uint8_t userId : 6;
173     uint8_t reserved1 : 1;
174     uint8_t ipmi20 : 1;
175     uint8_t operation : 2;
176     uint8_t reserved2 : 6;
177 #endif
178 #if BYTE_ORDER == BIG_ENDIAN
179     uint8_t ipmi20 : 1;
180     uint8_t reserved1 : 1;
181     uint8_t userId : 6;
182     uint8_t reserved2 : 6;
183     uint8_t operation : 2;
184 #endif
185     uint8_t userPassword[maxIpmi20PasswordSize];
186 } __attribute__((packed));
187 
188 ipmi_ret_t ipmiSetUserAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
189                              ipmi_request_t request, ipmi_response_t response,
190                              ipmi_data_len_t dataLen, ipmi_context_t context)
191 {
192     const SetUserAccessReq* req = static_cast<SetUserAccessReq*>(request);
193     size_t reqLength = *dataLen;
194     *dataLen = 0;
195 
196     if (!(reqLength == sizeof(*req) ||
197           (reqLength == (sizeof(*req) - sizeof(uint8_t) /* skip optional*/))))
198     {
199         log<level::DEBUG>("Set user access - Invalid Length");
200         return IPMI_CC_REQ_DATA_LEN_INVALID;
201     }
202     uint8_t chNum = convertCurrentChannelNum(req->chNum);
203     if (req->reserved1 != 0 || req->reserved2 != 0 || req->reserved3 != 0 ||
204         req->sessLimit != 0 || (!isValidChannel(chNum)) ||
205         (!ipmiUserIsValidPrivilege(req->privilege)) ||
206         (EChannelSessSupported::none == getChannelSessionSupport(chNum)))
207     {
208         log<level::DEBUG>("Set user access - Invalid field in request");
209         return IPMI_CC_INVALID_FIELD_REQUEST;
210     }
211     if (!ipmiUserIsValidUserId(req->userId))
212     {
213         log<level::DEBUG>("Set user access - Parameter out of range");
214         return IPMI_CC_PARM_OUT_OF_RANGE;
215     }
216 
217     PrivAccess privAccess = {0};
218     if (req->bitsUpdate)
219     {
220         privAccess.ipmiEnabled = req->ipmiEnabled;
221         privAccess.linkAuthEnabled = req->linkAuthEnabled;
222         privAccess.accessCallback = req->accessCallback;
223     }
224     privAccess.privilege = req->privilege;
225     return ipmiUserSetPrivilegeAccess(req->userId, chNum, privAccess,
226                                       req->bitsUpdate);
227 }
228 
229 ipmi_ret_t ipmiGetUserAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
230                              ipmi_request_t request, ipmi_response_t response,
231                              ipmi_data_len_t dataLen, ipmi_context_t context)
232 {
233     const GetUserAccessReq* req = static_cast<GetUserAccessReq*>(request);
234     size_t reqLength = *dataLen;
235     ipmi_ret_t retStatus = IPMI_CC_OK;
236 
237     *dataLen = 0;
238 
239     if (reqLength != sizeof(*req))
240     {
241         log<level::DEBUG>("Get user access - Invalid Length");
242         return IPMI_CC_REQ_DATA_LEN_INVALID;
243     }
244     uint8_t chNum = convertCurrentChannelNum(req->chNum);
245     if (req->reserved1 != 0 || req->reserved2 != 0 ||
246         (!isValidChannel(chNum)) ||
247         (EChannelSessSupported::none == getChannelSessionSupport(chNum)))
248     {
249         log<level::DEBUG>("Get user access - Invalid field in request");
250         return IPMI_CC_INVALID_FIELD_REQUEST;
251     }
252     if (!ipmiUserIsValidUserId(req->userId))
253     {
254         log<level::DEBUG>("Get user access - Parameter out of range");
255         return IPMI_CC_PARM_OUT_OF_RANGE;
256     }
257 
258     uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
259     bool enabledState = false;
260     GetUserAccessResp* resp = static_cast<GetUserAccessResp*>(response);
261 
262     std::fill(reinterpret_cast<uint8_t*>(resp),
263               reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
264 
265     retStatus = ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers);
266     if (retStatus != IPMI_CC_OK)
267     {
268         return retStatus;
269     }
270 
271     resp->maxChUsers = maxChUsers;
272     resp->enabledUsers = enabledUsers;
273     resp->fixedUsers = fixedUsers;
274 
275     retStatus = ipmiUserCheckEnabled(req->userId, enabledState);
276     if (retStatus != IPMI_CC_OK)
277     {
278         return retStatus;
279     }
280 
281     resp->enabledStatus = enabledState ? userIdEnabledViaSetPassword
282                                        : userIdDisabledViaSetPassword;
283     *dataLen = sizeof(*resp);
284     return ipmiUserGetPrivilegeAccess(req->userId, chNum, resp->privAccess);
285 }
286 
287 ipmi_ret_t ipmiSetUserName(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
288                            ipmi_request_t request, ipmi_response_t response,
289                            ipmi_data_len_t dataLen, ipmi_context_t context)
290 {
291     const SetUserNameReq* req = static_cast<SetUserNameReq*>(request);
292     size_t reqLength = *dataLen;
293     *dataLen = 0;
294 
295     if (reqLength != sizeof(*req))
296     {
297         log<level::DEBUG>("Set user name - Invalid Length");
298         return IPMI_CC_REQ_DATA_LEN_INVALID;
299     }
300     if (req->reserved1)
301     {
302         return IPMI_CC_INVALID_FIELD_REQUEST;
303     }
304     if (!ipmiUserIsValidUserId(req->userId))
305     {
306         log<level::DEBUG>("Set user name - Invalid user id");
307         return IPMI_CC_PARM_OUT_OF_RANGE;
308     }
309 
310     return ipmiUserSetUserName(req->userId,
311                                reinterpret_cast<const char*>(req->userName));
312 }
313 
314 /** @brief implementes the get user name command
315  *  @param[in] netfn - specifies netfn.
316  *  @param[in] cmd   - specifies cmd number.
317  *  @param[in] request - pointer to request data.
318  *  @param[in, out] dataLen - specifies request data length, and returns
319  * response data length.
320  *  @param[in] context - ipmi context.
321  *  @returns ipmi completion code.
322  */
323 ipmi_ret_t ipmiGetUserName(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
324                            ipmi_request_t request, ipmi_response_t response,
325                            ipmi_data_len_t dataLen, ipmi_context_t context)
326 {
327     const GetUserNameReq* req = static_cast<GetUserNameReq*>(request);
328     size_t reqLength = *dataLen;
329 
330     *dataLen = 0;
331 
332     if (reqLength != sizeof(*req))
333     {
334         log<level::DEBUG>("Get user name - Invalid Length");
335         return IPMI_CC_REQ_DATA_LEN_INVALID;
336     }
337 
338     std::string userName;
339     if (ipmiUserGetUserName(req->userId, userName) != IPMI_CC_OK)
340     { // Invalid User ID
341         log<level::DEBUG>("User Name not found",
342                           entry("USER-ID:%d", (uint8_t)req->userId));
343         return IPMI_CC_PARM_OUT_OF_RANGE;
344     }
345     GetUserNameResp* resp = static_cast<GetUserNameResp*>(response);
346     std::fill(reinterpret_cast<uint8_t*>(resp),
347               reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
348     userName.copy(reinterpret_cast<char*>(resp->userName),
349                   sizeof(resp->userName), 0);
350     *dataLen = sizeof(*resp);
351 
352     return IPMI_CC_OK;
353 }
354 
355 int pamFunctionConversation(int numMsg, const struct pam_message** msg,
356                             struct pam_response** resp, void* appdataPtr)
357 {
358     if (appdataPtr == nullptr)
359     {
360         return PAM_AUTH_ERR;
361     }
362     size_t passSize = std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1;
363     char* pass = reinterpret_cast<char*>(malloc(passSize));
364     std::strncpy(pass, reinterpret_cast<char*>(appdataPtr), passSize);
365 
366     *resp = reinterpret_cast<pam_response*>(
367         calloc(numMsg, sizeof(struct pam_response)));
368 
369     for (int i = 0; i < numMsg; ++i)
370     {
371         if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
372         {
373             continue;
374         }
375         resp[i]->resp = pass;
376     }
377     return PAM_SUCCESS;
378 }
379 
380 bool pamUpdatePasswd(const char* username, const char* password)
381 {
382     const struct pam_conv localConversation = {pamFunctionConversation,
383                                                const_cast<char*>(password)};
384     pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
385 
386     if (pam_start("passwd", username, &localConversation, &localAuthHandle) !=
387         PAM_SUCCESS)
388     {
389         return false;
390     }
391     int retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
392 
393     if (retval != PAM_SUCCESS)
394     {
395         if (retval == PAM_AUTHTOK_ERR)
396         {
397             log<level::DEBUG>("Authentication Failure");
398         }
399         else
400         {
401             log<level::DEBUG>("pam_chauthtok returned failure",
402                               entry("ERROR=%d", retval));
403         }
404         pam_end(localAuthHandle, retval);
405         return false;
406     }
407     if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
408     {
409         return false;
410     }
411     return true;
412 }
413 
414 /** @brief implementes the set user password command
415  *  @param[in] netfn - specifies netfn.
416  *  @param[in] cmd   - specifies cmd number.
417  *  @param[in] request - pointer to request data.
418  *  @param[in, out] dataLen - specifies request data length, and returns
419  * response data length.
420  *  @param[in] context - ipmi context.
421  *  @returns ipmi completion code.
422  */
423 ipmi_ret_t ipmiSetUserPassword(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
424                                ipmi_request_t request, ipmi_response_t response,
425                                ipmi_data_len_t dataLen, ipmi_context_t context)
426 {
427     const SetUserPasswordReq* req = static_cast<SetUserPasswordReq*>(request);
428     size_t reqLength = *dataLen;
429     // subtract 2 bytes header to know the password length - including NULL
430     uint8_t passwordLength = *dataLen - 2;
431     *dataLen = 0;
432 
433     // verify input length based on operation. Required password size is 20
434     // bytes as  we support only IPMI 2.0, but in order to be compatible with
435     // tools, accept 16 bytes of password size too.
436     if (reqLength < 2 ||
437         // If enable / disable user, reqLength has to be >=2 & <= 22
438         ((req->operation == disableUser || req->operation == enableUser) &&
439          ((reqLength < 2) || (reqLength > sizeof(SetUserPasswordReq)))))
440     {
441         log<level::DEBUG>("Invalid Length");
442         return IPMI_CC_REQ_DATA_LEN_INVALID;
443     }
444     // If set / test password then password length has to be 16 or 20 bytes
445     // based on the password size bit.
446     if (((req->operation == setPassword) || (req->operation == testPassword)) &&
447         (((req->ipmi20 == passwordKeySize20) &&
448           (passwordLength != maxIpmi20PasswordSize)) ||
449          ((req->ipmi20 == passwordKeySize16) &&
450           (passwordLength != maxIpmi15PasswordSize))))
451     {
452         log<level::DEBUG>("Invalid Length");
453         return IPMI_CC_REQ_DATA_LEN_INVALID;
454     }
455 
456     std::string userName;
457     if (ipmiUserGetUserName(req->userId, userName) != IPMI_CC_OK)
458     {
459         log<level::DEBUG>("User Name not found",
460                           entry("USER-ID:%d", (uint8_t)req->userId));
461         return IPMI_CC_PARM_OUT_OF_RANGE;
462     }
463     if (req->operation == setPassword)
464     {
465         std::string passwd;
466         passwd.assign(reinterpret_cast<const char*>(req->userPassword), 0,
467                       maxIpmi20PasswordSize);
468         if (!std::regex_match(passwd.c_str(),
469                               std::regex("[a-zA-z_0-9][a-zA-Z_0-9,?:`!\"]*")))
470         {
471             log<level::ERR>("Invalid password fields",
472                             entry("USER-ID:%d", (uint8_t)req->userId));
473             return IPMI_CC_INVALID_FIELD_REQUEST;
474         }
475         if (!pamUpdatePasswd(userName.c_str(), passwd.c_str()))
476         {
477             log<level::ERR>("Failed to update password",
478                             entry("USER-ID:%d", (uint8_t)req->userId));
479             return IPMI_CC_INVALID_FIELD_REQUEST;
480         }
481         return IPMI_CC_OK;
482     }
483     else if (req->operation == enableUser || req->operation == disableUser)
484     {
485         return ipmiUserUpdateEnabledState(req->userId,
486                                           static_cast<bool>(req->operation));
487     }
488     else if (req->operation == testPassword)
489     {
490         auto password = ipmiUserGetPassword(userName);
491         std::string testPassword(
492             reinterpret_cast<const char*>(req->userPassword), 0,
493             passwordLength);
494         // Note: For security reasons password size won't be compared and
495         // wrong password size completion code will not be returned if size
496         // doesn't match as specified in IPMI specification.
497         if (password != testPassword)
498         {
499             log<level::DEBUG>("Test password failed",
500                               entry("USER-ID:%d", (uint8_t)req->userId));
501             return static_cast<ipmi_ret_t>(
502                 IPMISetPasswordReturnCodes::ipmiCCPasswdFailMismatch);
503         }
504         return IPMI_CC_OK;
505     }
506     return IPMI_CC_INVALID_FIELD_REQUEST;
507 }
508 
509 void registerUserIpmiFunctions() __attribute__((constructor));
510 void registerUserIpmiFunctions()
511 {
512     ipmiUserInit();
513     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_USER_ACCESS, NULL,
514                            ipmiSetUserAccess, PRIVILEGE_ADMIN);
515 
516     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_USER_ACCESS, NULL,
517                            ipmiGetUserAccess, PRIVILEGE_OPERATOR);
518 
519     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_USER_NAME, NULL,
520                            ipmiGetUserName, PRIVILEGE_OPERATOR);
521 
522     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_USER_NAME, NULL,
523                            ipmiSetUserName, PRIVILEGE_ADMIN);
524 
525     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_USER_PASSWORD, NULL,
526                            ipmiSetUserPassword, PRIVILEGE_ADMIN);
527 
528     return;
529 }
530 } // namespace ipmi
531