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