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