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