0f4b85f12b74bd19b1404c8b6d54a4d66755530e
[platform/core/security/security-manager.git] / src / cmd / security-manager-cmd.cpp
1 /*
2  *  Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Rafal Krypa <r.krypa@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18 /*
19  * @file        service-manager-cmd.cpp
20  * @author      Sebastian Grabowski (s.grabowski@samsung.com)
21  * @version     1.0
22  * @brief       Implementation of security-manager-cmd tool for offline mode
23  */
24 /* vim: set ts=4 et sw=4 tw=78 : */
25
26 #include <iostream>
27 #include <utility>
28 #include <vector>
29 #include <map>
30
31 #include <dpl/log/log.h>
32 #include <dpl/singleton.h>
33 #include <dpl/singleton_safe_impl.h>
34 #include <protocols.h>
35 #include <security-manager.h>
36
37 #include <boost/program_options.hpp>
38 namespace po = boost::program_options;
39
40 IMPLEMENT_SAFE_SINGLETON(SecurityManager::Log::LogSystem);
41
42 static std::map <std::string, enum app_install_path_type> app_install_path_type_map = {
43     {"private", SECURITY_MANAGER_PATH_PRIVATE},
44     {"public", SECURITY_MANAGER_PATH_PUBLIC},
45     {"public_ro", SECURITY_MANAGER_PATH_PUBLIC_RO}
46 };
47
48 static std::map <std::string, enum security_manager_user_type> user_type_map = {
49     {"system", SM_USER_TYPE_SYSTEM},
50     {"admin", SM_USER_TYPE_ADMIN},
51     {"guest", SM_USER_TYPE_GUEST},
52     {"normal", SM_USER_TYPE_NORMAL}
53 };
54
55 static po::options_description getGenericOptions()
56 {
57     po::options_description opts("Generic options");
58     opts.add_options()
59          ("help,h", "produce help message")
60          ("install,i", "install an application")
61          ("manage-users,m", po::value<std::string>(), "add or remove user, parameter is 'a' or 'add' (for add) and 'r' or 'remove' (for remove)")
62          ;
63     return opts;
64 }
65
66 static po::options_description getInstallOptions()
67 {
68     po::options_description opts("Install options");
69     opts.add_options()
70          ("app,a", po::value<std::string>()->required(),
71           "application name (required)")
72          ("pkg,g", po::value<std::string>()->required(),
73           "package name for the application (required)")
74          /*
75           * multitoken: Specifies that the value can span multiple tokens.
76           *             So it is possible to pass values to an option like
77           *             this:
78           *             --path=/home/user dirtype
79           *             --path /home/user dirtype
80           *             --path="/home/user" dirtype
81           */
82          ("path,p", po::value< std::vector<std::string> >()->multitoken(),
83           "path for setting smack labels (may occur more than once).\n"
84           "Format: --path <path> <path type>\n"
85           "  where <path type> is: \tprivate, public, public_ro\n"
86           "example:\n"
87           "        \t--path=/home/user/app private")
88          ("privilege,s", po::value< std::vector<std::string> >(),
89           "privilege for the application (may occur more than once)")
90          ("uid,u", po::value<uid_t>()->required(),
91           "user identifier number (required)")
92          ;
93     return opts;
94 }
95
96 static po::options_description getUserOptions()
97 {
98     po::options_description opts("User management options");
99     opts.add_options()
100         ("uid,u", po::value<uid_t>()->required(), "user identifier number (required)")
101         ("usertype,t", po::value<std::string>(), "user type:"
102                 "one of system, admin, guest, normal. Set to 'normal' by default,"
103                 "ignored on user removal")
104          ;
105     return opts;
106 }
107
108 static po::options_description getAllOptions()
109 {
110     po::options_description opts("Allowed options");
111     opts.add(getGenericOptions());
112     opts.add(getInstallOptions());
113     opts.add(getUserOptions());
114
115     return opts;
116 }
117
118 static void usage(std::string name)
119 {
120     using namespace std;
121
122     cout << endl << name << " usage:" << endl;
123     cout << endl << getAllOptions() << endl << endl;
124 }
125
126 void parseCommandOptions(int argc, char *argv[],
127                                 po::options_description opts,
128                                 po::variables_map &vm)
129 {
130     const po::positional_options_description p;
131     /* style options:
132      * unix_style: The more-or-less traditional unix style. It looks as
133      *     follows: unix_style = (allow_short | short_allow_adjacent |
134      *                            short_allow_next | allow_long |
135      *                            long_allow_adjacent | long_allow_next |
136      *                            allow_sticky | allow_guessing |
137      *                            allow_dash_for_short)
138      * allow_long_disguise: Allow long options with single option starting
139      *     character, e.g -foo=10
140      * allow_guessing: Allow abbreviated spellings for long options, if
141      *     they unambiguously identify long option. No long
142      *     option name should be prefix of other long option name if
143      *     guessing is in effect.
144      * allow_short: Alow "-<single character" style.
145      * short_allow_adjacent: Allow option parameter in the same token for
146      *     short options.
147      * short_allow_next: Allow option parameter in the next token for
148      *     short options.
149      * allow_long: Allow "--long_name" style.
150      * long_allow_adjacent: Allow option parameter in the same token for
151      *     long option, like in --foo=10
152      * long_allow_next: Allow option parameter in the next token for long
153      *     options.
154      * allow_sticky: Allow to merge several short options together, so
155      *     that "-s -k" become "-sk". All of the options but
156      *     last should accept no parameter. For example, if "-s" accept a
157      *     parameter, then "k" will be taken as
158      *     parameter, not another short option. Dos-style short options
159      *     cannot be sticky.
160      * allow_dash_for_short: Allow "-" in short options.
161      */
162     po::store(po::command_line_parser(argc, argv).
163                   options(getGenericOptions().add(opts)).positional(p).
164                   style((po::command_line_style::unix_style |
165                         po::command_line_style::allow_long_disguise) &
166                         ~po::command_line_style::allow_guessing).
167                   run(),
168               vm);
169     po::notify(vm);
170 }
171
172 static bool loadPaths(const std::vector<std::string> &paths,
173                       struct app_inst_req &req)
174 {
175     if (paths.size() & 1) {
176         std::cout << "Wrong number of tokens was given for path option." <<
177                      std::endl;
178         LogDebug("Wrong paths size: " << paths.size());
179         return false;
180     }
181     req.appPaths.clear();
182     for (std::vector<std::string>::size_type i = 1; i < paths.size(); i += 2) {
183         app_install_path_type pathType;
184         LogDebug("path: " << paths[i - 1]);
185         try {
186             pathType = app_install_path_type_map.at(paths[i]);
187         } catch (const std::out_of_range &e) {
188             std::cout << "Invalid path type found." << std::endl;
189             LogError("Invalid path type found.");
190             req.appPaths.clear();
191             return false;
192         }
193         LogDebug("path type: " << pathType << " (" << paths[i] << ")");
194         req.appPaths.push_back(std::make_pair(paths[i - 1], pathType));
195     }
196     return (!req.appPaths.empty());
197 }
198
199 static void parseInstallOptions(int argc, char *argv[],
200                                 struct app_inst_req &req,
201                                 po::variables_map &vm)
202 {
203
204     parseCommandOptions(argc, argv, getInstallOptions(), vm);
205
206     if (vm.count("app"))
207         req.appId = vm["app"].as<std::string>();
208     if (vm.count("pkg"))
209         req.pkgId = vm["pkg"].as<std::string>();
210     if (vm.count("path")) {
211         const std::vector<std::string> paths =
212             vm["path"].as<std::vector<std::string> >();
213         if (!loadPaths(paths, req)) {
214             po::error e("Error in parsing path arguments.");
215             throw e;
216         }
217     }
218     if (vm.count("privilege")) {
219         req.privileges = vm["privilege"].as<std::vector<std::string> >();
220         if (req.privileges.empty()) {
221             po::error e("Error in parsing privilege arguments.");
222             throw e;
223         }
224 #ifdef BUILD_TYPE_DEBUG
225         LogDebug("Passed privileges:");
226         for (const auto &p : req.privileges) {
227             LogDebug("    " << p);
228         }
229 #endif
230     }
231     if (vm.count("uid"))
232         req.uid = vm["uid"].as<uid_t>();
233
234 }
235
236 static void parseUserOptions(int argc, char *argv[],
237                              struct user_req &req,
238                              po::variables_map &vm)
239 {
240     parseCommandOptions(argc, argv, getUserOptions(), vm);
241     try {
242         if (vm.count("uid"))
243             req.uid = vm["uid"].as<uid_t>();
244         if (vm.count("usertype")){
245             req.utype = user_type_map.at(vm["usertype"].as<std::string>());
246         } else
247             req.utype = SM_USER_TYPE_NORMAL;
248     } catch (const std::out_of_range &e) {
249         po::error er("Invalid user type found.");
250         throw er;
251     }
252 }
253
254 static int installApp(const struct app_inst_req &req)
255 {
256     int ret = EXIT_FAILURE;
257
258     ret = security_manager_app_install(&req);
259     if (SECURITY_MANAGER_SUCCESS == ret) {
260         std::cout << "Application " << req.appId <<
261                   " installed successfully." << std::endl;
262         LogDebug("Application " << req.appId <<
263                  " installed successfully.");
264     } else {
265         std::cout << "Failed to install " << req.appId << " application: " <<
266                   security_manager_strerror(static_cast<lib_retcode>(ret)) <<
267                   " (" << ret << ")." << std::endl;
268         LogError("Failed to install " << req.appId << " application: " <<
269                  security_manager_strerror(static_cast<lib_retcode>(ret)) <<
270                  " (" << ret << ")." << std::endl);
271     }
272     return ret;
273 }
274
275 static int manageUserOperation(const struct user_req &req, std::string operation)
276 {
277     int ret = EXIT_FAILURE;
278     if (operation == "a" || operation == "add") {
279         ret = security_manager_user_add(&req);
280         operation = "add";
281     }
282     else if (operation == "r" || operation == "remove") {
283         ret = security_manager_user_delete(&req);
284         operation = "remove";
285     } else {
286         std::cout << "Manage user option requires argument:"
287                 "\n\t'a' or 'add' (for adding user)"
288                 "\n\t'r' or 'remove' (for removing user)" << std::endl;
289         LogError("Manage user option wrong argument");
290         return EXIT_FAILURE;
291     }
292
293     if (SECURITY_MANAGER_SUCCESS == ret) {
294         std::cout << "User " << operation << " operation successfully finished (uid: "
295                 << req.uid << ")" << std::endl;
296         LogDebug("User " << operation << " operation successfully finished (uid: "
297                 << req.uid << ")");
298     } else {
299         std::cout << "Failed to "<< operation << " user of uid " << req.uid << ". " <<
300                   security_manager_strerror(static_cast<lib_retcode>(ret)) <<
301                   " (" << ret << ")." << std::endl;
302         LogError("Failed to "<< operation << " user of uid " << req.uid << "." <<
303                  security_manager_strerror(static_cast<lib_retcode>(ret)) <<
304                  " (" << ret << ").");
305     }
306     return ret;
307 }
308
309 int main(int argc, char *argv[])
310 {
311     po::variables_map vm;
312
313     try
314     {
315         SecurityManager::Singleton<SecurityManager::Log::LogSystem>::Instance().SetTag("SECURITY_MANAGER_INSTALLER");
316
317         LogDebug("argc: " << argc);
318         for (int i = 0; i < argc; ++i)
319             LogDebug("argv [" << i << "]: " << argv[i]);
320         if (argc < 2) {
321             std::cout << "Missing arguments." << std::endl;
322             usage(std::string(argv[0]));
323             return EXIT_FAILURE;
324         }
325
326          po::store(po::command_line_parser(argc, argv).
327                    options(getGenericOptions()).allow_unregistered().run(),
328                    vm);
329         if (vm.count("help")) {
330             usage(std::string(argv[0]));
331             return EXIT_SUCCESS;
332         }
333         LogDebug("Generic arguments has been parsed.");
334
335         if (vm.count("install")) {
336             struct app_inst_req *req = nullptr;
337             LogDebug("Install command.");
338             if (security_manager_app_inst_req_new(&req) != SECURITY_MANAGER_SUCCESS)
339                 return EXIT_FAILURE;
340             parseInstallOptions(argc, argv, *req, vm);
341             return installApp(*req);
342         } else if (vm.count("manage-users")) {
343             std::string operation = vm["manage-users"].as<std::string>();
344             struct user_req *req = nullptr;
345             LogDebug("Manage users command.");
346             if (security_manager_user_req_new(&req) != SECURITY_MANAGER_SUCCESS)
347                 return EXIT_FAILURE;
348             parseUserOptions(argc, argv, *req, vm);
349             return manageUserOperation(*req, operation);
350         } else {
351             std::cout << "No command argument was given." << std::endl;
352             usage(std::string(argv[0]));
353             return EXIT_FAILURE;
354         }
355     }
356     catch (po::error &e) {
357         std::cout << e.what() << std::endl;
358         LogError("Program options error occured: " << e.what());
359         return EXIT_FAILURE;
360     }
361     catch (const std::exception &e) {
362         std::cout << "Error occured: " << e.what() << std::endl;
363         LogError("Error occured: " << e.what());
364     }
365
366
367     return EXIT_FAILURE;
368 }
369