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