1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <grp.h>
16 #include <pwd.h>
17 #include <sys/ioctl.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <sys/wait.h>
21 #include <termios.h>
22
23 #include "begetctl.h"
24 #include "param_manager.h"
25 #include "param_security.h"
26 #include "shell_utils.h"
27 #include "init_param.h"
28 #include "beget_ext.h"
29 #ifdef PARAM_SUPPORT_SELINUX
30 #include <policycoreutils.h>
31 #include <selinux/selinux.h>
32 #include "selinux_parameter.h"
33 #endif // PARAM_SUPPORT_SELINUX
34
35 #define MASK_LENGTH_MAX 4
36 pid_t g_shellPid = 0;
37 static struct termios g_terminalState;
38 char g_isSetTerminal = 0;
39
demoExit(void)40 void demoExit(void)
41 {
42 BShellEnvDestory(GetShellHandle());
43 if (g_shellPid != 0) {
44 #ifndef STARTUP_INIT_TEST
45 kill(g_shellPid, SIGKILL);
46 #endif
47 }
48 BEGET_CHECK(g_isSetTerminal == 0, tcsetattr(0, TCSAFLUSH, &g_terminalState));
49 }
50
51 #define CMD_PATH "/system/bin/paramshell"
52 #define SHELL_NAME "paramshell"
53 #ifndef TIOCSCTTY
54 #define TIOCSCTTY 0x540E
55 #endif
GetLocalBuffer(uint32_t * buffSize)56 static char *GetLocalBuffer(uint32_t *buffSize)
57 {
58 static char buffer[PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX] = {0};
59 BEGET_CHECK(buffSize == NULL, *buffSize = sizeof(buffer));
60 return buffer;
61 }
62
GetRealParameter(BShellHandle shell,const char * name,char * buffer,uint32_t buffSize)63 static char *GetRealParameter(BShellHandle shell, const char *name, char *buffer, uint32_t buffSize)
64 {
65 BSH_CHECK(buffer != NULL && name != NULL, return NULL, "Invalid parameter");
66 const BShellParam *param = BShellEnvGetParam(shell, PARAM_REVERESD_NAME_CURR_PARAMETER);
67 const char *current = (param == NULL) ? "" : param->value.string;
68 int32_t realLen = 0;
69 int ret = 0;
70 if (name[0] == '.') { // relatively
71 if (strcmp(name, "..") == 0) {
72 char *tmp = strrchr(current, '.');
73 if (tmp != NULL) {
74 realLen = tmp - current;
75 ret = memcpy_s(buffer, buffSize, current, realLen);
76 } else {
77 ret = memcpy_s(buffer, buffSize, "#", 1);
78 realLen = 1;
79 }
80 BSH_CHECK(ret == 0, return NULL, "Failed to memcpy");
81 } else if (strcmp(name, ".") == 0) {
82 realLen = sprintf_s(buffer, buffSize, "%s", current);
83 } else {
84 realLen = sprintf_s(buffer, buffSize, "%s%s", current, name);
85 }
86 } else if (strlen(name) == 0) {
87 realLen = sprintf_s(buffer, buffSize, "%s", current);
88 } else {
89 realLen = sprintf_s(buffer, buffSize, "%s", name);
90 }
91 BSH_CHECK(realLen >= 0, return NULL, "Failed to format buffer");
92 buffer[realLen] = '\0';
93 BSH_LOGV("GetRealParameter current %s input %s real %s", current, name, buffer);
94 return buffer;
95 }
96
SetParamShellPrompt(BShellHandle shell,const char * param)97 int SetParamShellPrompt(BShellHandle shell, const char *param)
98 {
99 uint32_t buffSize = 0;
100 char *buffer = GetLocalBuffer(&buffSize);
101 char *realParameter = GetRealParameter(shell, param, buffer, buffSize);
102 BSH_CHECK(realParameter != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
103 if (strlen(realParameter) == 0) {
104 BShellEnvOutputPrompt(shell, PARAM_SHELL_DEFAULT_PROMPT);
105 return -1;
106 }
107 // check parameter
108 int ret = SystemCheckParamExist(realParameter);
109 if (ret == PARAM_CODE_NOT_FOUND) {
110 BShellEnvOutput(shell, "Error: parameter \'%s\' not found\r\n", realParameter);
111 return -1;
112 } else if (ret != 0 && ret != PARAM_CODE_NODE_EXIST) {
113 BShellEnvOutput(shell, "Error: Forbid to enter parameters \'%s\'\r\n", realParameter);
114 return -1;
115 }
116 if (strcmp(realParameter, "#") == 0) {
117 ret = BShellEnvSetParam(shell, PARAM_REVERESD_NAME_CURR_PARAMETER,
118 "", PARAM_STRING, (void *)"");
119 BSH_CHECK(ret == 0, return BSH_SYSTEM_ERR, "Failed to set param value");
120 BShellEnvOutputPrompt(shell, PARAM_SHELL_DEFAULT_PROMPT);
121 return 0;
122 }
123 ret = BShellEnvSetParam(shell, PARAM_REVERESD_NAME_CURR_PARAMETER,
124 "", PARAM_STRING, (void *)realParameter);
125 BSH_CHECK(ret == 0, return BSH_SYSTEM_ERR, "Failed to set param value");
126 if (strcat_s(realParameter, buffSize, "#") != 0) {
127 BSH_CHECK(ret != 0, return BSH_SYSTEM_ERR, "Failed to cat prompt %s", realParameter);
128 }
129 BShellEnvOutputPrompt(shell, realParameter);
130 return 0;
131 }
132
GetPermissionString(uint32_t mode,int shift,char * str,int size)133 static char *GetPermissionString(uint32_t mode, int shift, char *str, int size)
134 {
135 BEGET_CHECK(!(size < MASK_LENGTH_MAX), return str);
136 str[0] = '-';
137 str[1] = '-';
138 str[2] = '-'; // 2 watcher
139 str[3] = '\0'; // 3 end
140 if (mode & (DAC_READ >> shift)) {
141 str[0] = 'r';
142 }
143 if (mode & (DAC_WRITE >> shift)) {
144 str[1] = 'w';
145 }
146 if (mode & (DAC_WATCH >> shift)) {
147 str[2] = 'w'; // 2 watcher
148 }
149 return str;
150 }
151
ShowParam(BShellHandle shell,const char * name,const char * value)152 static void ShowParam(BShellHandle shell, const char *name, const char *value)
153 {
154 ParamAuditData auditData = {};
155 int ret = GetParamSecurityAuditData(name, 0, &auditData);
156 BSH_CHECK(ret == 0, return, "Failed to get param security for %s", name);
157 BShellEnvOutput(shell, "Parameter information:\r\n");
158 #ifdef PARAM_SUPPORT_SELINUX
159 BShellEnvOutput(shell, "selinux : %s \r\n", auditData.label);
160 #endif
161 char permissionStr[3][MASK_LENGTH_MAX] = {}; // 3 permission
162 struct passwd *user = getpwuid(auditData.dacData.uid);
163 struct group *group = getgrgid(auditData.dacData.gid);
164 if (user != NULL && group != NULL) {
165 BShellEnvOutput(shell, " dac : %s(%s) %s(%s) (%s) \r\n",
166 user->pw_name,
167 GetPermissionString(auditData.dacData.mode, 0, permissionStr[0], MASK_LENGTH_MAX),
168 group->gr_name,
169 GetPermissionString(auditData.dacData.mode,DAC_GROUP_START, permissionStr[1], MASK_LENGTH_MAX),
170 // 2 other
171 GetPermissionString(auditData.dacData.mode, DAC_OTHER_START, permissionStr[2], MASK_LENGTH_MAX));
172 }
173 if (strcmp("#", name) != 0) {
174 BShellEnvOutput(shell, " name : %s\r\n", name);
175 }
176 if (value != NULL) {
177 BShellEnvOutput(shell, " value: %s\r\n", value);
178 }
179 }
180
ShowParamForCmdLs(ParamHandle handle,void * cookie)181 static void ShowParamForCmdLs(ParamHandle handle, void *cookie)
182 {
183 uint32_t buffSize = 0;
184 char *buffer = GetLocalBuffer(&buffSize);
185 if (buffSize < (PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX)) {
186 return;
187 }
188 char *value = buffer + PARAM_NAME_LEN_MAX;
189 (void)SystemGetParameterName(handle, buffer, PARAM_NAME_LEN_MAX);
190 uint32_t valueLen = buffSize - PARAM_NAME_LEN_MAX;
191 (void)SystemGetParameterValue(handle, value, &valueLen);
192 ShowParam((BShellHandle)cookie, buffer, value);
193 }
194
BShellParamCmdLs(BShellHandle shell,int32_t argc,char * argv[])195 static int32_t BShellParamCmdLs(BShellHandle shell, int32_t argc, char *argv[])
196 {
197 BSH_CHECK(shell != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
198 int all = 0;
199 char *input = NULL;
200 for (int32_t i = 1; i < argc; i++) {
201 if (strcmp(argv[i], "-r") == 0) {
202 all = 1;
203 } else if (input == NULL) {
204 input = argv[i];
205 }
206 }
207 uint32_t buffSize = 0;
208 char *buffer = GetLocalBuffer(&buffSize);
209 char *realParameter = GetRealParameter(shell, (input == NULL) ? "" : input, buffer, buffSize);
210 BSH_CHECK(realParameter != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
211 char *prefix = strdup((strlen(realParameter) == 0) ? "#" : realParameter);
212 BSH_LOGV("BShellParamCmdLs prefix %s", prefix);
213 int ret = 0;
214 if (all != 0) {
215 ret = SystemTraversalParameter(prefix, ShowParamForCmdLs, (void *)shell);
216 if (ret != 0) {
217 BShellEnvOutput(shell, "Error: Forbid to list parameters\r\n");
218 }
219 } else {
220 ret = SystemCheckParamExist(prefix);
221 if (ret == 0) {
222 ParamHandle handle;
223 ret = SystemFindParameter(prefix, &handle);
224 if (ret != 0) {
225 BShellEnvOutput(shell, "Error: Forbid to list parameters\r\n");
226 } else {
227 ShowParamForCmdLs(handle, (void *)shell);
228 }
229 } else if (ret == PARAM_CODE_NODE_EXIST) {
230 ShowParam(shell, prefix, NULL);
231 } else if (ret != PARAM_CODE_NOT_FOUND) {
232 BShellEnvOutput(shell, "Error: Forbid to list parameters\r\n");
233 } else {
234 BShellEnvOutput(shell, "Parameter %s not found\r\n", prefix);
235 }
236 }
237 free(prefix);
238 return 0;
239 }
240
BShellParamCmdCat(BShellHandle shell,int32_t argc,char * argv[])241 static int32_t BShellParamCmdCat(BShellHandle shell, int32_t argc, char *argv[])
242 {
243 BSH_CHECK(shell != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
244 BSH_CHECK(argc >= 1, return BSH_CMD_PARAM_INVALID, "Invalid shell env");
245 uint32_t buffSize = 0;
246 char *buffer = GetLocalBuffer(&buffSize);
247 char *realParameter = GetRealParameter(shell, argv[1], buffer, buffSize);
248 BSH_CHECK(realParameter != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
249 int ret = SystemGetParameter(realParameter, buffer, &buffSize);
250 BSH_CHECK(ret != 0, BShellEnvOutput(shell, " %s\r\n", buffer));
251 return 0;
252 }
253
BShellParamCmdCd(BShellHandle shell,int32_t argc,char * argv[])254 static int32_t BShellParamCmdCd(BShellHandle shell, int32_t argc, char *argv[])
255 {
256 BSH_CHECK(shell != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
257 BSH_CHECK(argc >= 1, return BSH_CMD_PARAM_INVALID, "Invalid shell env");
258 SetParamShellPrompt(shell, argv[1]);
259 return 0;
260 }
261
ShowParamForCmdGet(ParamHandle handle,void * cookie)262 static void ShowParamForCmdGet(ParamHandle handle, void *cookie)
263 {
264 uint32_t buffSize = 0;
265 char *buffer = GetLocalBuffer(&buffSize);
266 BSH_CHECK(!(buffSize < (PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX)), return);
267 char *value = buffer + PARAM_NAME_LEN_MAX;
268 (void)SystemGetParameterName(handle, buffer, PARAM_NAME_LEN_MAX);
269 uint32_t valueLen = buffSize - PARAM_NAME_LEN_MAX;
270 (void)SystemGetParameterValue(handle, value, &valueLen);
271 BShellEnvOutput((BShellHandle)cookie, " %s = %s\r\n", buffer, value);
272 }
273
BShellParamCmdGet(BShellHandle shell,int32_t argc,char * argv[])274 static int32_t BShellParamCmdGet(BShellHandle shell, int32_t argc, char *argv[])
275 {
276 BSH_CHECK(shell != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
277 BSH_CHECK(argc >= 1, return BSH_CMD_PARAM_INVALID, "Invalid shell env");
278 int ret = 0;
279 uint32_t buffSize = 0;
280 char *buffer = GetLocalBuffer(&buffSize);
281 char *realParameter = GetRealParameter(shell, (argc == 1) ? "" : argv[1], buffer, buffSize);
282 if ((argc == 1) || (realParameter == NULL) ||
283 (strlen(realParameter) == 0) || (strcmp(realParameter, "#") == 0)) {
284 ret = SystemTraversalParameter(realParameter, ShowParamForCmdGet, (void *)shell);
285 if (ret != 0) {
286 BShellEnvOutput(shell, "Error: Forbid to get all parameters\r\n");
287 }
288 return 0;
289 }
290 char *key = strdup(realParameter);
291 ret = SystemGetParameter(key, buffer, &buffSize);
292 if (ret == 0) {
293 BShellEnvOutput(shell, "%s \n", buffer);
294 } else {
295 BShellEnvOutput(shell, "Get parameter \"%s\" fail\n", key);
296 }
297 free(key);
298 return 0;
299 }
300
BShellParamCmdSet(BShellHandle shell,int32_t argc,char * argv[])301 static int32_t BShellParamCmdSet(BShellHandle shell, int32_t argc, char *argv[])
302 {
303 BSH_CHECK(shell != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
304 if (argc < 3) { // 3 min param
305 char *helpArgs[] = {"param", NULL};
306 BShellCmdHelp(shell, 1, helpArgs);
307 return 0;
308 }
309 uint32_t buffSize = 0;
310 char *buffer = GetLocalBuffer(&buffSize);
311 char *realParameter = GetRealParameter(shell, argv[1], buffer, buffSize);
312 if ((realParameter == NULL) || (strlen(realParameter) == 0) || (strcmp(realParameter, "#") == 0)) {
313 BShellEnvOutput(shell, "Set parameter %s %s fail\n", argv[1], argv[2]); // 2 value param
314 return 0;
315 }
316 int ret = SystemSetParameter(realParameter, argv[2]); // 2 value param
317 if (ret == 0) {
318 BShellEnvOutput(shell, "Set parameter %s %s success\n", realParameter, argv[2]); // 2 value param
319 } else {
320 BShellEnvOutput(shell, "Set parameter %s %s fail\n", realParameter, argv[2]); // 2 value param
321 }
322 return 0;
323 }
324
BShellParamCmdWait(BShellHandle shell,int32_t argc,char * argv[])325 static int32_t BShellParamCmdWait(BShellHandle shell, int32_t argc, char *argv[])
326 {
327 BSH_CHECK(shell != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
328 if (argc < 2) { // 2 min param
329 char *helpArgs[] = {"param", NULL};
330 BShellCmdHelp(shell, 1, helpArgs);
331 return 0;
332 }
333 int32_t timeout = 30; // 30s
334 char *value = "*";
335 if (argc > 2) { // 2 value param
336 value = argv[2]; // 2 value param
337 }
338 if (argc > 3) { // 3 timeout param
339 timeout = atoi(argv[3]); // 3 timeout param
340 }
341 uint32_t buffSize = 0;
342 char *buffer = GetLocalBuffer(&buffSize);
343 char *realParameter = GetRealParameter(shell, argv[1], buffer, buffSize);
344 if ((realParameter == NULL) || (strlen(realParameter) == 0) || (strcmp(realParameter, "#") == 0)) {
345 BShellEnvOutput(shell, "Wait parameter %s fail\n", argv[1]);
346 return 0;
347 }
348
349 int ret = SystemWaitParameter(realParameter, value, timeout);
350 if (ret == 0) {
351 BShellEnvOutput(shell, "Wait parameter %s success\n", argv[1]);
352 } else {
353 BShellEnvOutput(shell, "Wait parameter %s fail\n", argv[1]);
354 }
355 return 0;
356 }
357
BShellParamCmdDump(BShellHandle shell,int32_t argc,char * argv[])358 static int32_t BShellParamCmdDump(BShellHandle shell, int32_t argc, char *argv[])
359 {
360 BSH_CHECK(shell != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
361 if (argc >= 2 && strcmp(argv[1], "verbose") == 0) { // 2 min arg
362 SystemDumpParameters(1, printf);
363 } else {
364 SystemDumpParameters(0, printf);
365 }
366 return 0;
367 }
368
BShellParamCmdPwd(BShellHandle shell,int32_t argc,char * argv[])369 static int32_t BShellParamCmdPwd(BShellHandle shell, int32_t argc, char *argv[])
370 {
371 uint32_t buffSize = 0;
372 char *buffer = GetLocalBuffer(&buffSize);
373 char *realParameter = GetRealParameter(shell, "", buffer, buffSize);
374 BShellEnvOutput(shell, "%s\r\n", realParameter);
375 return 0;
376 }
377
BShellParamCmdShell(BShellHandle shell,int32_t argc,char * argv[])378 static int32_t BShellParamCmdShell(BShellHandle shell, int32_t argc, char *argv[])
379 {
380 #ifndef STARTUP_INIT_TEST
381 BSH_CHECK(shell != NULL, return BSH_INVALID_PARAM, "Invalid shell env");
382 BSH_LOGV("BShellParamCmdShell %d %s", argc, argv[1]);
383 int ret = 0;
384 if (argc > 1) {
385 ret = SystemCheckParamExist(argv[1]);
386 if (ret != 0) {
387 BShellEnvOutput(shell, "Error: parameter \'%s\' not found\r\n", argv[1]);
388 return -1;
389 }
390 }
391 if (tcgetattr(0, &g_terminalState)) {
392 return BSH_SYSTEM_ERR;
393 }
394 g_isSetTerminal = 1;
395 pid_t pid = fork();
396 if (pid == 0) {
397 setuid(2000); // 2000 shell group
398 setgid(2000); // 2000 shell group
399 #ifdef PARAM_SUPPORT_SELINUX
400 setcon("u:r:normal_hap_domain:s0");
401 #endif
402 if (argc >= 2) { // 2 min argc
403 char *args[] = {SHELL_NAME, argv[1], NULL};
404 ret = execv(CMD_PATH, args);
405 } else {
406 char *args[] = {SHELL_NAME, NULL};
407 ret = execv(CMD_PATH, args);
408 }
409 if (ret < 0) {
410 printf("error on exec %d \n", errno);
411 exit(0);
412 }
413 exit(0);
414 } else if (pid > 0) {
415 g_shellPid = pid;
416 int status = 0;
417 wait(&status);
418 tcsetattr(0, TCSAFLUSH, &g_terminalState);
419 g_isSetTerminal = 0;
420 }
421 #endif
422 return 0;
423 }
424
BShellParamCmdRegForShell(BShellHandle shell)425 static int32_t BShellParamCmdRegForShell(BShellHandle shell)
426 {
427 const CmdInfo infos[] = {
428 {"ls", BShellParamCmdLs, "display system parameter", "ls [-r] [name]", NULL},
429 {"get", BShellParamCmdGet, "get system parameter", "get [name]", NULL},
430 {"set", BShellParamCmdSet, "set system parameter", "set name value", NULL},
431 {"wait", BShellParamCmdWait, "wait system parameter", "wait name [value] [timeout]", NULL},
432 {"dump", BShellParamCmdDump, "dump system parameter", "dump [verbose]", ""},
433 {"cd", BShellParamCmdCd, "change path of parameter", "cd name", NULL},
434 {"cat", BShellParamCmdCat, "display value of parameter", "cat name", NULL},
435 {"pwd", BShellParamCmdPwd, "display current parameter", "pwd", NULL},
436 };
437 for (size_t i = sizeof(infos) / sizeof(infos[0]); i > 0; i--) {
438 BShellEnvRegisterCmd(shell, &infos[i - 1]);
439 }
440 return 0;
441 }
442
BShellParamCmdRegForIndepent(BShellHandle shell)443 static int32_t BShellParamCmdRegForIndepent(BShellHandle shell)
444 {
445 const CmdInfo infos[] = {
446 {"param", BShellParamCmdLs, "display system parameter", "param ls [-r] [name]", "param ls"},
447 {"param", BShellParamCmdGet, "get system parameter", "param get [name]", "param get"},
448 {"param", BShellParamCmdSet, "set system parameter", "param set name value", "param set"},
449 {"param", BShellParamCmdWait, "wait system parameter", "param wait name [value] [timeout]", "param wait"},
450 {"param", BShellParamCmdDump, "dump system parameter", "param dump [verbose]", "param dump"},
451 {"param", BShellParamCmdShell, "shell system parameter", "param shell [name]", "param shell"},
452 };
453 for (size_t i = sizeof(infos) / sizeof(infos[0]); i > 0; i--) {
454 BShellEnvRegisterCmd(shell, &infos[i - 1]);
455 }
456 return 0;
457 }
458
BShellParamCmdRegister(BShellHandle shell,int execMode)459 int32_t BShellParamCmdRegister(BShellHandle shell, int execMode)
460 {
461 if (execMode) {
462 BShellParamCmdRegForShell(shell);
463 } else {
464 BShellParamCmdRegForIndepent(shell);
465 }
466 return 0;
467 }
468