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