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