• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 
16 #include "atm_command.h"
17 
18 #include <getopt.h>
19 #include <string>
20 
21 #include "access_token_error.h"
22 #include "accesstoken_kit.h"
23 #include "privacy_kit.h"
24 #include "to_string.h"
25 
26 namespace OHOS {
27 namespace Security {
28 namespace AccessToken {
29 namespace {
30 static constexpr int32_t MIN_ARGUMENT_NUMBER = 2;
31 static constexpr int32_t MAX_ARGUMENT_NUMBER = 4096;
32 static const std::string HELP_MSG_NO_OPTION = "error: you must specify an option at least.\n";
33 static const std::string SHORT_OPTIONS_DUMP = "ht::r::i:p:b:n:";
34 static const std::string TOOLS_NAME = "atm";
35 static const std::string HELP_MSG =
36     "usage: atm <command> <option>\n"
37     "These are common atm commands list:\n"
38     "  help    list available commands\n"
39     "  dump    dumpsys command\n"
40     "  perm    grant/cancel permission\n";
41 
42 static const std::string HELP_MSG_DUMP =
43     "usage: atm dump <option>.\n"
44     "options list:\n"
45     "  -h, --help                                               list available options\n"
46     "  -t, --token-info                                         list all token info in system\n"
47     "  -t, --token-info -i <token-id>                           list single token info by specific tokenId\n"
48     "  -t, --token-info -b <bundle-name>                        list all token info by specific bundleName\n"
49     "  -t, --token-info -n <process-name>                       list single token info by specific native processName\n"
50     "  -r, --record-info [-i <token-id>] [-p <permission-name>] list used records in system\n";
51 
52 static const std::string HELP_MSG_PERM =
53     "usage: atm perm <option>.\n"
54     "options list:\n"
55     "  -h, --help                                       list available options\n"
56     "  -g, --grant -i <token-id> -p <permission-name>   grant a permission by a specified token-id\n"
57     "  -c, --cancel -i <token-id> -p <permission-name>  cancel a permission by a specified token-id\n";
58 
59 static const struct option LONG_OPTIONS_DUMP[] = {
60     {"help", no_argument, nullptr, 'h'},
61     {"token-info", no_argument, nullptr, 't'},
62     {"record-info", no_argument, nullptr, 'r'},
63     {"token-id", required_argument, nullptr, 'i'},
64     {"permission-name", required_argument, nullptr, 'p'},
65     {"bundle-name", required_argument, nullptr, 'b'},
66     {"process-name", required_argument, nullptr, 'n'},
67     {nullptr, 0, nullptr, 0}
68 };
69 
70 static const std::string SHORT_OPTIONS_PERM = "hg::c::i:p:";
71 static const struct option LONG_OPTIONS_PERM[] = {
72     {"help", no_argument, nullptr, 'h'},
73     {"grant", no_argument, nullptr, 'g'},
74     {"cancel", no_argument, nullptr, 'c'},
75     {"token-id", required_argument, nullptr, 'i'},
76     {"permission-name", required_argument, nullptr, 'p'},
77     {nullptr, 0, nullptr, 0}
78 };
79 }
80 
AtmCommand(int32_t argc,char * argv[])81 AtmCommand::AtmCommand(int32_t argc, char *argv[]) : argc_(argc), argv_(argv), name_(TOOLS_NAME)
82 {
83     opterr = 0;
84 
85     commandMap_ = {
86         {"help", std::bind(&AtmCommand::RunAsHelpCommand, this)},
87         {"dump", std::bind(&AtmCommand::RunAsCommonCommand, this)},
88         {"perm", std::bind(&AtmCommand::RunAsCommonCommand, this)},
89     };
90 
91     if ((argc < MIN_ARGUMENT_NUMBER) || (argc > MAX_ARGUMENT_NUMBER)) {
92         cmd_ = "help";
93 
94         return;
95     }
96 
97     cmd_ = argv[1];
98 
99     for (int32_t i = 2; i < argc; i++) {
100         argList_.push_back(argv[i]);
101     }
102 }
103 
GetCommandErrorMsg() const104 std::string AtmCommand::GetCommandErrorMsg() const
105 {
106     std::string commandErrorMsg =
107         name_ + ": '" + cmd_ + "' is not a valid " + name_ + " command. See '" + name_ + " help'.\n";
108 
109     return commandErrorMsg;
110 }
111 
ExecCommand()112 std::string AtmCommand::ExecCommand()
113 {
114     auto respond = commandMap_[cmd_];
115     if (respond == nullptr) {
116         resultReceiver_.append(GetCommandErrorMsg());
117     } else {
118         respond();
119     }
120 
121     return resultReceiver_;
122 }
123 
RunAsHelpCommand()124 int32_t AtmCommand::RunAsHelpCommand()
125 {
126     resultReceiver_.append(HELP_MSG);
127 
128     return RET_SUCCESS;
129 }
130 
RunAsCommandError(void)131 int32_t AtmCommand::RunAsCommandError(void)
132 {
133     int32_t result = RET_SUCCESS;
134 
135     if ((optind < 0) || (optind >= argc_)) {
136         return ERR_INVALID_VALUE;
137     }
138 
139     // When scanning the first argument
140     if (strcmp(argv_[optind], cmd_.c_str()) == 0) {
141         // 'atm dump' with no option: atm dump
142         // 'atm dump' with a wrong argument: atm dump xxx
143 
144         resultReceiver_.append(HELP_MSG_NO_OPTION + "\n");
145         result = ERR_INVALID_VALUE;
146     }
147     return result;
148 }
149 
GetUnknownOptionMsg() const150 std::string AtmCommand::GetUnknownOptionMsg() const
151 {
152     std::string result;
153 
154     if ((optind < 0) || (optind > argc_)) {
155         return result;
156     }
157 
158     result.append("error: unknown option\n.");
159 
160     return result;
161 }
162 
RunAsCommandMissingOptionArgument(void)163 int32_t AtmCommand::RunAsCommandMissingOptionArgument(void)
164 {
165     int32_t result = RET_SUCCESS;
166     switch (optopt) {
167         case 'h':
168             // 'atm dump -h'
169             result = ERR_INVALID_VALUE;
170             break;
171         case 'i':
172         case 'p':
173         case 'g':
174         case 'c':
175             resultReceiver_.append("error: option ");
176             resultReceiver_.append("requires a value.\n");
177             result = ERR_INVALID_VALUE;
178             break;
179         default: {
180             std::string unknownOptionMsg = GetUnknownOptionMsg();
181 
182             resultReceiver_.append(unknownOptionMsg);
183             result = ERR_INVALID_VALUE;
184             break;
185         }
186     }
187     return result;
188 }
189 
RunAsCommandExistentOptionArgument(const int32_t & option,AtmToolsParamInfo & info)190 int32_t AtmCommand::RunAsCommandExistentOptionArgument(const int32_t& option, AtmToolsParamInfo& info)
191 {
192     int32_t result = RET_SUCCESS;
193     switch (option) {
194         case 'h':
195             // 'atm dump -h'
196             result = ERR_INVALID_VALUE;
197             break;
198         case 't':
199             info.type = DUMP_TOKEN;
200             break;
201         case 'r':
202             info.type = DUMP_RECORD;
203             break;
204         case 'g':
205             info.type = PERM_GRANT;
206             break;
207         case 'c':
208             info.type = PERM_REVOKE;
209             break;
210         case 'i':
211             if (optarg != nullptr) {
212                 info.tokenId = static_cast<AccessTokenID>(std::atoi(optarg));
213             }
214             break;
215         case 'p':
216             if (optarg != nullptr) {
217                 info.permissionName = optarg;
218             }
219             break;
220         case 'b':
221             if (optarg != nullptr) {
222                 info.bundleName = optarg;
223             }
224             break;
225         case 'n':
226             if (optarg != nullptr) {
227                 info.processName = optarg;
228             }
229             break;
230         default:
231             break;
232     }
233     return result;
234 }
235 
DumpRecordInfo(uint32_t tokenId,const std::string & permissionName)236 std::string AtmCommand::DumpRecordInfo(uint32_t tokenId, const std::string& permissionName)
237 {
238     PermissionUsedRequest request;
239     request.tokenId = tokenId;
240     request.flag = FLAG_PERMISSION_USAGE_DETAIL;
241     if (!permissionName.empty()) {
242         request.permissionList.emplace_back(permissionName);
243     }
244 
245     PermissionUsedResult result;
246     if (PrivacyKit::GetPermissionUsedRecords(request, result) != 0) {
247         return "";
248     }
249 
250     std::string dumpInfo;
251     ToString::PermissionUsedResultToString(result, dumpInfo);
252     return dumpInfo;
253 }
254 
ModifyPermission(const OptType & type,AccessTokenID tokenId,const std::string & permissionName)255 int32_t AtmCommand::ModifyPermission(const OptType& type, AccessTokenID tokenId, const std::string& permissionName)
256 {
257     if ((tokenId == 0) || (permissionName.empty())) {
258         return ERR_INVALID_VALUE;
259     }
260 
261     int32_t result = 0;
262     if (type == PERM_GRANT) {
263         result = AccessTokenKit::GrantPermission(tokenId, permissionName, PERMISSION_USER_FIXED);
264     } else if (type == PERM_REVOKE) {
265         result = AccessTokenKit::RevokePermission(tokenId, permissionName, PERMISSION_USER_FIXED);
266     } else {
267         return ERR_INVALID_VALUE;
268     }
269     return result;
270 }
271 
RunCommandByOperationType(const AtmToolsParamInfo & info)272 int32_t AtmCommand::RunCommandByOperationType(const AtmToolsParamInfo& info)
273 {
274     std::string dumpInfo;
275     int32_t ret = RET_SUCCESS;
276     switch (info.type) {
277         case DUMP_TOKEN:
278             AccessTokenKit::DumpTokenInfo(info, dumpInfo);
279             break;
280         case DUMP_RECORD:
281             dumpInfo = DumpRecordInfo(info.tokenId, info.permissionName);
282             break;
283         case PERM_GRANT:
284         case PERM_REVOKE:
285             ret = ModifyPermission(info.type, info.tokenId, info.permissionName);
286             if (ret == RET_SUCCESS) {
287                 dumpInfo = "Success";
288             } else {
289                 dumpInfo = "Failure";
290             }
291             break;
292         default:
293             resultReceiver_.append("error: miss option \n");
294             return ERR_INVALID_VALUE;
295     }
296     resultReceiver_.append(dumpInfo + "\n");
297     return ret;
298 }
299 
HandleComplexCommand(const std::string & shortOption,const struct option longOption[],const std::string & helpMsg)300 int32_t AtmCommand::HandleComplexCommand(const std::string& shortOption, const struct option longOption[],
301     const std::string& helpMsg)
302 {
303     int32_t result = RET_SUCCESS;
304     AtmToolsParamInfo info;
305     int32_t counter = 0;
306 
307     while (true) {
308         counter++;
309         int32_t option = getopt_long(argc_, argv_, shortOption.c_str(), longOption, nullptr);
310         if ((optind < 0) || (optind > argc_)) {
311             return ERR_INVALID_VALUE;
312         }
313 
314         if (option == -1) {
315             if (counter == 1) {
316                 result = RunAsCommandError();
317             }
318             break;
319         }
320 
321         if (option == '?') {
322             result = RunAsCommandMissingOptionArgument();
323             break;
324         }
325 
326         result = RunAsCommandExistentOptionArgument(option, info);
327     }
328 
329     if (result != RET_SUCCESS) {
330         resultReceiver_.append(helpMsg + "\n");
331     } else {
332         result = RunCommandByOperationType(info);
333     }
334     return result;
335 }
336 
RunAsCommonCommand()337 int32_t AtmCommand::RunAsCommonCommand()
338 {
339     if (cmd_ == "dump") {
340         return HandleComplexCommand(SHORT_OPTIONS_DUMP, LONG_OPTIONS_DUMP, HELP_MSG_DUMP);
341     } else if (cmd_ == "perm") {
342         return HandleComplexCommand(SHORT_OPTIONS_PERM, LONG_OPTIONS_PERM, HELP_MSG_PERM);
343     }
344 
345     return ERR_PARAM_INVALID;
346 }
347 } // namespace AccessToken
348 } // namespace Security
349 } // namespace OHOS
350