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 "account_command.h"
16 #include <getopt.h>
17 #include "account_log_wrapper.h"
18 #include "singleton.h"
19
20 using namespace OHOS::AAFwk;
21
22 namespace OHOS {
23 namespace AccountSA {
24 namespace {
25 const std::string SHORT_OPTIONS = "hn:t:i:c:ea";
26 const struct option LONG_OPTIONS[] = {
27 {"help", no_argument, nullptr, 'h'},
28 {"name", required_argument, nullptr, 'n'},
29 {"type", required_argument, nullptr, 't'},
30 {"id", required_argument, nullptr, 'i'},
31 {"constraint", required_argument, nullptr, 'c'},
32 {"enable", no_argument, nullptr, 'e'},
33 {"all", no_argument, nullptr, 'a'},
34 };
35
36 static const std::string STOP_COMMAND = "stop";
37 static const std::string DELETE_COMMAND = "delete";
38 static const std::string SWITCH_COMMAND = "switch";
39 static const std::string DUMP_COMMAND = "dump";
40 static const std::string SET_COMMAND = "set";
41 static const std::string CREATE_COMMAND = "create";
42
43 } // namespace
44
AccountCommand(int argc,char * argv[])45 AccountCommand::AccountCommand(int argc, char *argv[]) : ShellCommand(argc, argv, TOOL_NAME)
46 {
47 ACCOUNT_LOGD("enter");
48 for (int i = 0; i < argc_; i++) {
49 ACCOUNT_LOGD("argv_[%{public}d]: %{public}s", i, argv_[i]);
50 }
51 }
52
CreateCommandMap()53 ErrCode AccountCommand::CreateCommandMap()
54 {
55 ACCOUNT_LOGD("enter");
56
57 commandMap_ = {
58 {"help", std::bind(&AccountCommand::RunAsHelpCommand, this)},
59 {"create", std::bind(&AccountCommand::RunAsCreateCommand, this)},
60 {"delete", std::bind(&AccountCommand::RunAsDeleteCommand, this)},
61 {"dump", std::bind(&AccountCommand::RunAsDumpCommand, this)},
62 {"set", std::bind(&AccountCommand::RunAsSetCommand, this)},
63 {"switch", std::bind(&AccountCommand::RunAsSwitchCommand, this)},
64 #ifdef ENABLE_MULTIPLE_ACTIVE_ACCOUNTS
65 {"stop", std::bind(&AccountCommand::RunAsStopCommand, this)},
66 #endif // ENABLE_MULTIPLE_ACTIVE_ACCOUNTS
67 };
68
69 return ERR_OK;
70 }
71
CreateMessageMap()72 ErrCode AccountCommand::CreateMessageMap()
73 {
74 return ERR_OK;
75 }
76
init()77 ErrCode AccountCommand::init()
78 {
79 return ERR_OK;
80 }
81
RunAsHelpCommand(void)82 ErrCode AccountCommand::RunAsHelpCommand(void)
83 {
84 ACCOUNT_LOGD("enter");
85 resultReceiver_.append(HELP_MSG);
86 return ERR_OK;
87 }
88
RunAsCreateCommand(void)89 ErrCode AccountCommand::RunAsCreateCommand(void)
90 {
91 ACCOUNT_LOGD("enter");
92 ErrCode result = ERR_OK;
93 int counter = 0;
94 std::string name = "";
95 OsAccountType osAccountType = static_cast<OsAccountType>(-1);
96
97 while (true) {
98 counter++;
99
100 int option = getopt_long(argc_, argv_, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr);
101 ACCOUNT_LOGD("option: %{public}d, optopt: %{public}d, optind: %{public}d", option, optopt, optind);
102
103 if (option == -1) {
104 if (counter == 1) {
105 result = RunCommandError(CREATE_COMMAND);
106 }
107 break;
108 }
109
110 if (option == '?') {
111 result = RunAsCreateCommandMissingOptionArgument();
112 break;
113 }
114
115 result = RunAsCreateCommandExistentOptionArgument(option, name, osAccountType);
116 }
117
118 if (result == ERR_OK) {
119 if (name.size() == 0 || osAccountType == static_cast<OsAccountType>(-1)) {
120 ACCOUNT_LOGD("'acm create' without enough options");
121
122 if (name.size() == 0) {
123 resultReceiver_.append(HELP_MSG_NO_NAME_OPTION + "\n");
124 }
125
126 if (osAccountType == static_cast<OsAccountType>(-1)) {
127 resultReceiver_.append(HELP_MSG_NO_TYPE_OPTION + "\n");
128 }
129
130 result = ERR_INVALID_VALUE;
131 }
132 }
133
134 if (result != ERR_OK) {
135 resultReceiver_.append(HELP_MSG_CREATE);
136 } else {
137 /* create */
138
139 // make os account info
140 OsAccountInfo osAccountInfo;
141
142 // create an os account
143 result = OsAccount::GetInstance().CreateOsAccount(name, osAccountType, osAccountInfo);
144 if (result == ERR_OK) {
145 resultReceiver_ = STRING_CREATE_OS_ACCOUNT_OK + "\n";
146 } else {
147 resultReceiver_ = STRING_CREATE_OS_ACCOUNT_NG + "\n";
148 }
149 }
150
151 ACCOUNT_LOGD("result = %{public}d, name = %{public}s, type = %{public}d", result, name.c_str(), osAccountType);
152 return result;
153 }
154
RunAsDeleteCommand(void)155 ErrCode AccountCommand::RunAsDeleteCommand(void)
156 {
157 ErrCode result = ERR_OK;
158 int id = -1;
159
160 ParseCommandOpt(DELETE_COMMAND, result, id);
161
162 if (result != ERR_OK) {
163 resultReceiver_.append(HELP_MSG_DELETE);
164 } else {
165 /* delete */
166
167 // delete an os account
168 result = OsAccount::GetInstance().RemoveOsAccount(id);
169 if (result == ERR_OK) {
170 resultReceiver_ = STRING_DELETE_OS_ACCOUNT_OK + "\n";
171 } else {
172 resultReceiver_ = STRING_DELETE_OS_ACCOUNT_NG + "\n";
173 }
174 }
175
176 ACCOUNT_LOGD("result = %{public}d, id = %{public}d", result, id);
177 return result;
178 }
179
RunAsDumpCommand(void)180 ErrCode AccountCommand::RunAsDumpCommand(void)
181 {
182 ErrCode result = ERR_OK;
183 int id = -1;
184
185 ParseCommandOpt(DUMP_COMMAND, result, id);
186
187 if (result != ERR_OK) {
188 resultReceiver_.append(HELP_MSG_DUMP);
189 } else {
190 /* dump */
191
192 // dump state
193 std::vector<std::string> state;
194 result = OsAccount::GetInstance().DumpState(id, state);
195 if (result == ERR_OK) {
196 for (auto info : state) {
197 resultReceiver_ += info + "\n";
198 }
199 } else {
200 resultReceiver_ = STRING_DUMP_OS_ACCOUNT_NG + "\n";
201 }
202 }
203
204 ACCOUNT_LOGD("result = %{public}d, id = %{public}d", result, id);
205 return result;
206 }
207
RunCommand(int & counter,ErrCode & result,bool & enable,int & id,std::vector<std::string> & constraints)208 void AccountCommand::RunCommand(
209 int &counter, ErrCode &result, bool &enable, int &id, std::vector<std::string> &constraints)
210 {
211 while (true) {
212 counter++;
213
214 int option = getopt_long(argc_, argv_, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr);
215 ACCOUNT_LOGD("option: %{public}d, optopt: %{public}d, optind: %{public}d", option, optopt, optind);
216
217 if (option == -1) {
218 if (counter == 1) {
219 result = RunCommandError(SET_COMMAND);
220 }
221 break;
222 }
223
224 if (option == '?') {
225 result = RunAsSetCommandMissingOptionArgument();
226 break;
227 }
228
229 result = RunAsSetCommandExistentOptionArgument(option, id, constraints, enable);
230 }
231 }
232
RunAsSetCommand(void)233 ErrCode AccountCommand::RunAsSetCommand(void)
234 {
235 ErrCode result = ERR_OK;
236 int counter = 0;
237 int id = -1;
238 std::vector<std::string> constraints;
239 bool enable = false;
240
241 RunCommand(counter, result, enable, id, constraints);
242
243 if (result == ERR_OK) {
244 if (id == -1 || constraints.size() == 0) {
245 ACCOUNT_LOGD("'acm set' without enough options");
246
247 if (id == -1) {
248 resultReceiver_.append(HELP_MSG_NO_ID_OPTION + "\n");
249 }
250
251 if (constraints.size() == 0) {
252 resultReceiver_.append(HELP_MSG_NO_CONSTRAINTS_OPTION + "\n");
253 }
254
255 result = ERR_INVALID_VALUE;
256 }
257 }
258
259 if (result != ERR_OK) {
260 resultReceiver_.append(HELP_MSG_SET);
261 } else {
262 /* set */
263
264 // set os account constraints
265 result = OsAccount::GetInstance().SetOsAccountConstraints(id, constraints, enable);
266 if (result == ERR_OK) {
267 resultReceiver_ = STRING_SET_OS_ACCOUNT_CONSTRAINTS_OK + "\n";
268 } else {
269 resultReceiver_ = STRING_SET_OS_ACCOUNT_CONSTRAINTS_NG + "\n";
270 }
271 }
272
273 ACCOUNT_LOGD("result = %{public}d, id = %{public}d, enable = %{public}d", result, id, enable);
274 for (auto constraint : constraints) {
275 ACCOUNT_LOGD("constraint = %{public}s", constraint.c_str());
276 }
277
278 return result;
279 }
280
ParseCommandOpt(const std::string & command,ErrCode & result,int & id)281 void AccountCommand::ParseCommandOpt(const std::string &command, ErrCode &result, int &id)
282 {
283 int counter = 0;
284 while (true) {
285 counter++;
286
287 int option = getopt_long(argc_, argv_, SHORT_OPTIONS.c_str(), LONG_OPTIONS, nullptr);
288 ACCOUNT_LOGD("option: %{public}d, optopt: %{public}d, optind: %{public}d", option, optopt, optind);
289
290 if (option == -1) {
291 if (counter == 1) {
292 result = RunCommandError(command);
293 }
294 break;
295 }
296
297 if (option == '?') {
298 result = RunAsCommonCommandMissingOptionArgument(command);
299 break;
300 }
301
302 result = RunAsCommonCommandExistentOptionArgument(option, id);
303 }
304 }
305
RunAsSwitchCommand(void)306 ErrCode AccountCommand::RunAsSwitchCommand(void)
307 {
308 ErrCode result = ERR_OK;
309 int id = -1;
310 ParseCommandOpt(SWITCH_COMMAND, result, id);
311
312 if (result != ERR_OK) {
313 resultReceiver_.append(HELP_MSG_SWITCH);
314 } else {
315 /* switch */
316
317 // switch an os account
318 result = OsAccount::GetInstance().ActivateOsAccount(id);
319 if (result == ERR_OK) {
320 resultReceiver_ = STRING_SWITCH_OS_ACCOUNT_OK + "\n";
321 } else {
322 resultReceiver_ = STRING_SWITCH_OS_ACCOUNT_NG + "\n";
323 }
324 }
325
326 ACCOUNT_LOGD("result = %{public}d, id = %{public}d", result, id);
327 return result;
328 }
329
RunAsStopCommand(void)330 ErrCode AccountCommand::RunAsStopCommand(void)
331 {
332 ErrCode result = ERR_OK;
333 int id = -1;
334
335 ParseCommandOpt(STOP_COMMAND, result, id);
336
337 if (result != ERR_OK) {
338 resultReceiver_.append(HELP_MSG_STOP);
339 } else {
340 /* stop */
341
342 // stop an os account
343 result = OsAccount::GetInstance().StopOsAccount(id);
344 if (result == ERR_OK) {
345 resultReceiver_ = STRING_STOP_OS_ACCOUNT_OK + "\n";
346 } else {
347 resultReceiver_ = STRING_STOP_OS_ACCOUNT_NG + "\n";
348 }
349 }
350
351 ACCOUNT_LOGD("result = %{public}d, id = %{public}d", result, id);
352
353 return result;
354 }
355
RunAsCreateCommandMissingOptionArgument(void)356 ErrCode AccountCommand::RunAsCreateCommandMissingOptionArgument(void)
357 {
358 ErrCode result = ERR_OK;
359
360 switch (optopt) {
361 case 'n': {
362 // 'acm create -n <name>' with no argument: acm create -n
363 // 'acm create --name <name>' with no argument: acm create --name
364 ACCOUNT_LOGD("'acm create -n' with no argument.");
365
366 resultReceiver_.append(HELP_MSG_OPTION_REQUIRES_AN_ARGUMENT + "\n");
367 result = ERR_INVALID_VALUE;
368 break;
369 }
370 case 't': {
371 // 'acm create -t <type>' with no argument: acm create -t
372 // 'acm create --type <type>' with no argument: acm create --type
373 ACCOUNT_LOGD("'acm create -t' with no argument.");
374
375 resultReceiver_.append(HELP_MSG_OPTION_REQUIRES_AN_ARGUMENT + "\n");
376
377 result = ERR_INVALID_VALUE;
378 break;
379 }
380 default: {
381 // 'acm create' with an unknown option: acm create -x
382 // 'acm create' with an unknown option: acm create -xxx
383 std::string unknownOption = "";
384 std::string unknownOptionMsg = GetUnknownOptionMsg(unknownOption);
385
386 ACCOUNT_LOGD("'acm create' with an unknown option.");
387
388 resultReceiver_.append(unknownOptionMsg);
389 result = ERR_INVALID_VALUE;
390 break;
391 }
392 }
393
394 ACCOUNT_LOGD("end, result = %{public}d", result);
395 return result;
396 }
397
RunAsCreateCommandExistentOptionArgument(const int & option,std::string & name,OsAccountType & type)398 ErrCode AccountCommand::RunAsCreateCommandExistentOptionArgument(
399 const int &option, std::string &name, OsAccountType &type)
400 {
401 ErrCode result = ERR_OK;
402
403 switch (option) {
404 case 'h': {
405 // 'acm create -h'
406 // 'acm create --help'
407 result = ERR_INVALID_VALUE;
408 break;
409 }
410 case 'n': {
411 // 'acm create -n <name>'
412 // 'acm create --name <name>'
413 name = optarg;
414 break;
415 }
416 case 't': {
417 // 'acm create -t <type>'
418 // 'acm create --type <type>'
419 result = AnalyzeTypeArgument(type);
420 break;
421 }
422 default: {
423 break;
424 }
425 }
426
427 ACCOUNT_LOGD("end, result = %{public}d", result);
428 return result;
429 }
430
RunAsCommonCommandMissingOptionArgument(const std::string & command)431 ErrCode AccountCommand::RunAsCommonCommandMissingOptionArgument(const std::string &command)
432 {
433 ErrCode result = ERR_OK;
434
435 switch (optopt) {
436 case 'i': {
437 // 'acm command -i <id>' with no argument: acm command -i
438 // 'acm command --id <id>' with no argument: acm command --id
439 ACCOUNT_LOGD("'acm %{public}s -i' with no argument.", command.c_str());
440
441 resultReceiver_.append(HELP_MSG_OPTION_REQUIRES_AN_ARGUMENT + "\n");
442 result = ERR_INVALID_VALUE;
443 break;
444 }
445 default: {
446 // 'acm delete' with an unknown option: acm delete -x
447 // 'acm delete' with an unknown option: acm delete -xxx
448 std::string unknownOption = "";
449 std::string unknownOptionMsg = GetUnknownOptionMsg(unknownOption);
450
451 ACCOUNT_LOGD("'acm %{public}s' with an unknown option.", command.c_str());
452
453 resultReceiver_.append(unknownOptionMsg);
454 result = ERR_INVALID_VALUE;
455 break;
456 }
457 }
458 ACCOUNT_LOGD("end, result = %{public}d", result);
459 return result;
460 }
461
RunCommandError(const std::string & command)462 ErrCode AccountCommand::RunCommandError(const std::string &command)
463 {
464 ErrCode result = ERR_OK;
465
466 if (optind < 0 || optind >= argc_) {
467 ACCOUNT_LOGD("optind %{public}d invalid", optind);
468 return ERR_INVALID_VALUE;
469 }
470
471 // When scanning the first argument
472 if (strcmp(argv_[optind], cmd_.c_str()) == 0) {
473 // 'acm command' with no option: acm command
474 // 'acm command' with a wrong argument: acm command xxx
475 ACCOUNT_LOGD("'acm %{public}s' with no option.", command.c_str());
476
477 resultReceiver_.append(HELP_MSG_NO_OPTION + "\n");
478 result = ERR_INVALID_VALUE;
479 }
480
481 ACCOUNT_LOGD("end, result = %{public}d", result);
482
483 return result;
484 }
485
RunAsSetCommandMissingOptionArgument(void)486 ErrCode AccountCommand::RunAsSetCommandMissingOptionArgument(void)
487 {
488 ErrCode result = ERR_OK;
489
490 switch (optopt) {
491 case 'i': {
492 // 'acm set -i <id>' with no argument: acm set -i
493 // 'acm set --id <id>' with no argument: acm set --id
494 ACCOUNT_LOGD("'acm set -i' with no argument.");
495
496 resultReceiver_.append(HELP_MSG_OPTION_REQUIRES_AN_ARGUMENT + "\n");
497 result = ERR_INVALID_VALUE;
498 break;
499 }
500 case 'c': {
501 // 'acm set -c <constraints>' with no argument: acm set -c
502 // 'acm set --constraint <constraints>' with no argument: acm set --constraint
503 ACCOUNT_LOGD("'acm set -c' with no argument.");
504
505 resultReceiver_.append(HELP_MSG_OPTION_REQUIRES_AN_ARGUMENT + "\n");
506 result = ERR_INVALID_VALUE;
507 break;
508 }
509 default: {
510 // 'acm set' with an unknown option: acm set -x
511 // 'acm set' with an unknown option: acm set -xxx
512 std::string unknownOption = "";
513 std::string unknownOptionMsg = GetUnknownOptionMsg(unknownOption);
514
515 ACCOUNT_LOGD("'set dump' with an unknown option.");
516
517 resultReceiver_.append(unknownOptionMsg);
518 result = ERR_INVALID_VALUE;
519 break;
520 }
521 }
522 ACCOUNT_LOGD("end, result = %{public}d", result);
523 return result;
524 }
525
RunAsSetCommandExistentOptionArgument(const int & option,int & id,std::vector<std::string> & constraints,bool & enable)526 ErrCode AccountCommand::RunAsSetCommandExistentOptionArgument(
527 const int &option, int &id, std::vector<std::string> &constraints, bool &enable)
528 {
529 ErrCode result = ERR_OK;
530
531 switch (option) {
532 case 'h': {
533 // 'acm set -h'
534 // 'acm set --help'
535 result = ERR_INVALID_VALUE;
536 break;
537 }
538 case 'i': {
539 // 'acm set -i <id>'
540 // 'acm set --id <id>'
541 result = AnalyzeLocalIdArgument(id);
542 break;
543 }
544 case 'c': {
545 // 'acm set -c <constraints>'
546 // 'acm set --constraint <constraints>'
547 result = AnalyzeConstraintArgument(constraints);
548 break;
549 }
550 case 'e': {
551 // 'acm set -e'
552 // 'acm set --enable'
553 enable = true;
554 break;
555 }
556 default: {
557 break;
558 }
559 }
560
561 ACCOUNT_LOGD("end, result = %{public}d, id = %{public}d", result, id);
562 return result;
563 }
564
RunAsCommonCommandExistentOptionArgument(const int & option,int & id)565 ErrCode AccountCommand::RunAsCommonCommandExistentOptionArgument(const int &option, int &id)
566 {
567 ErrCode result = ERR_OK;
568
569 switch (option) {
570 case 'h': {
571 // 'acm command -h'
572 // 'acm command --help'
573 // command includes stop, switch, dump, delete
574 result = ERR_INVALID_VALUE;
575 break;
576 }
577 case 'i': {
578 // 'acm command -i <id>'
579 // 'acm command --id <id>
580 // command includes stop, switch, dump, delete
581 result = AnalyzeLocalIdArgument(id);
582 break;
583 }
584 default: {
585 break;
586 }
587 }
588 ACCOUNT_LOGD("end, result = %{public}d, id = %{public}d", result, id);
589 return result;
590 }
591
AnalyzeTypeArgument(OsAccountType & type)592 ErrCode AccountCommand::AnalyzeTypeArgument(OsAccountType &type)
593 {
594 ErrCode result = ERR_OK;
595 std::string typeByUser = optarg;
596
597 if (typeByUser == "admin") {
598 type = OsAccountType::ADMIN;
599 } else if (typeByUser == "normal") {
600 type = OsAccountType::NORMAL;
601 } else if (typeByUser == "guest") {
602 type = OsAccountType::GUEST;
603 } else {
604 resultReceiver_.append(HELP_MSG_INVALID_TYPE_ARGUMENT + "\n");
605 result = ERR_INVALID_VALUE;
606 }
607
608 return result;
609 }
610
AnalyzeLocalIdArgument(int & id)611 ErrCode AccountCommand::AnalyzeLocalIdArgument(int &id)
612 {
613 std::string idByUser = optarg;
614 if (idByUser == "0") {
615 id = 0;
616 return ERR_OK;
617 }
618
619 if (atoi(optarg) == 0) {
620 resultReceiver_.append(HELP_MSG_INVALID_ID_ARGUMENT + "\n");
621 return ERR_INVALID_VALUE;
622 }
623
624 id = atoi(optarg);
625
626 return ERR_OK;
627 }
628
AnalyzeConstraintArgument(std::vector<std::string> & constraints)629 ErrCode AccountCommand::AnalyzeConstraintArgument(std::vector<std::string> &constraints)
630 {
631 std::string constraintsByUser = optarg;
632 ACCOUNT_LOGD("constraintsByUser = %{public}s", constraintsByUser.c_str());
633
634 constraints.clear();
635 std::string constraint = "";
636 std::string delimiter = ",";
637 size_t last = 0;
638 size_t next = 0;
639
640 while ((next = constraintsByUser.find(delimiter, last)) != std::string::npos) {
641 constraint = constraintsByUser.substr(last, next - last);
642 ACCOUNT_LOGD("constraint = %{public}s", constraint.c_str());
643
644 constraints.emplace_back(constraint);
645 last = next + 1;
646 }
647 constraint = constraintsByUser.substr(last);
648 ACCOUNT_LOGD("constraint = %{public}s", constraint.c_str());
649 constraints.emplace_back(constraint);
650
651 return ERR_OK;
652 }
653 } // namespace AccountSA
654 } // namespace OHOS