Implement --set-bucket and --delete-bucket in Cyad
[platform/core/security/cynara.git] / src / cyad / CommandlineParser / CyadCommandlineParser.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  * @file        src/cyad/CommandlineParser/CyadCommandlineParser.cpp
18  * @author      Aleksander Zdyb <a.zdyb@samsung.com>
19  * @version     1.0
20  * @brief       Commandline parser for Cyad
21  */
22
23 #include <cstring>
24 #include <getopt.h>
25 #include <map>
26 #include <sstream>
27 #include <string>
28
29 #include <cyad/CommandlineParser/PolicyParsingException.h>
30
31 #include "CyadCommandlineParser.h"
32
33 namespace Cynara {
34
35 namespace CyadCmdlineArgs {
36     const char HELP = 'h';
37     const char * const HELP_LONG = "help";
38
39     const char SET_BUCKET = 'b';
40     const char * const SET_BUCKET_LONG = "set-bucket";
41
42     const char DELETE_BUCKET = 'd';
43     const char * const DELETE_BUCKET_LONG = "delete-bucket";
44
45     const char POLICY = 'p';
46     const char * const POLICY_LONG = "policy";
47
48     const char METADATA = 'm';
49     const char * const METADATA_LONG = "metadata";
50 }
51
52 namespace CyadCmdlineErrors {
53     const char * const UNKNOWN_ERROR = "Unknown error";
54     const char * const NO_OPTION = "No option specified";
55     const char * const UNKNOWN_OPTION = "Unknown option";
56     const char * const UNKNOWN_OPTION_SET_BUCKET = "Unknown option in --set-bucket";
57     const char * const UNKNOWN_OPTION_DELETE_BUCKET = "Unknown option in --delete-bucket";
58     const char * const NO_POLICY = "No --policy specified";
59     const char * const NO_BUCKET = "No bucket specified";
60     const char * const INVALID_POLICY = "Invalid --policy option";
61 }
62
63 CyadCommandlineParser::CyadCommandlineParser(int argc, char * const *argv)
64     : m_argc(argc), m_argv(argv) {}
65
66 CyadCommandlineParser::~CyadCommandlineParser() {}
67
68 std::shared_ptr<CyadCommand> CyadCommandlineParser::parseMain(void) {
69     namespace Args = CyadCmdlineArgs;
70
71     const struct option long_options[] = {
72         { Args::HELP_LONG,          no_argument,       nullptr, Args::HELP },
73         { Args::SET_BUCKET_LONG,    required_argument, nullptr, Args::SET_BUCKET },
74         { Args::DELETE_BUCKET_LONG, required_argument, nullptr, Args::DELETE_BUCKET },
75         { nullptr, 0, nullptr, 0 }
76     };
77
78     optind = 0; // On entry to `getopt', zero means this is the first call; initialize.
79     int opt;
80     std::stringstream optstr;
81     optstr << ":" << Args::HELP
82            << Args::SET_BUCKET << ":"
83            << Args::DELETE_BUCKET << ":";
84
85     while ((opt = getopt_long(m_argc, m_argv, optstr.str().c_str(), long_options, nullptr)) != -1) {
86         switch (opt) {
87             case Args::HELP:
88                 return std::make_shared<HelpCyadCommand>();
89
90             case Args::SET_BUCKET:
91                 return parseSetBucket(optarg);
92
93             case Args::DELETE_BUCKET:
94                 return parseDeleteBucket(optarg);
95
96             case '?': // Unknown option
97                 return std::make_shared<ErrorCyadCommand>(CyadCmdlineErrors::UNKNOWN_OPTION);
98
99             case ':': // Missing argument
100                 switch (optopt) {
101                     case Args::SET_BUCKET:
102                     case Args::DELETE_BUCKET:
103                         return std::make_shared<ErrorCyadCommand>(CyadCmdlineErrors::NO_BUCKET);
104                 }
105                 // Shall never happen, but let's just make compiler happy.
106                 return std::make_shared<ErrorCyadCommand>(CyadCmdlineErrors::UNKNOWN_ERROR);
107
108             default:
109                 return std::make_shared<ErrorCyadCommand>(CyadCmdlineErrors::UNKNOWN_OPTION);
110         }
111     }
112
113     return std::make_shared<ErrorCyadCommand>(CyadCmdlineErrors::NO_OPTION);
114 }
115
116 std::shared_ptr<CyadCommand> CyadCommandlineParser::parseSetBucket(const std::string &bucketId) {
117     namespace Args = CyadCmdlineArgs;
118     namespace Errors = CyadCmdlineErrors;
119
120     const struct option long_options[] = {
121         { Args::POLICY_LONG, required_argument, nullptr, Args::POLICY },
122         { Args::METADATA_LONG, required_argument, nullptr, Args::METADATA },
123         { nullptr, 0, nullptr, 0 }
124     };
125
126     std::string policy;
127     std::string metadata;
128
129     int opt;
130     std::stringstream optstr;
131     optstr << ":"
132            << Args::POLICY << ":"
133            << Args::METADATA << ":";
134
135     while ((opt = getopt_long(m_argc, m_argv, optstr.str().c_str(), long_options, nullptr)) != -1) {
136         switch(opt) {
137         case Args::POLICY:
138             policy = optarg;
139             break;
140         case Args::METADATA:
141             metadata = optarg;
142             break;
143         default:
144             return std::make_shared<ErrorCyadCommand>(Errors::UNKNOWN_OPTION_SET_BUCKET);
145         }
146     }
147
148     if (policy.empty())
149         return std::make_shared<ErrorCyadCommand>(Errors::NO_POLICY);
150
151     try {
152         auto policyType = parsePolicyType(policy);
153         return std::make_shared<SetBucketCyadCommand>(bucketId, PolicyResult(policyType, metadata));
154     } catch (const PolicyParsingException &) {
155         return std::make_shared<ErrorCyadCommand>(Errors::INVALID_POLICY);
156     }
157 }
158
159 std::shared_ptr<CyadCommand> CyadCommandlineParser::parseDeleteBucket(const std::string &bucketId) {
160     namespace Errors = CyadCmdlineErrors;
161
162     // Expect no additional options
163     const struct option long_options[] = {
164         { nullptr, 0, nullptr, 0 }
165     };
166
167     if (getopt_long(m_argc, m_argv, ":", long_options, nullptr) == -1) {
168         return std::make_shared<DeleteBucketCyadCommand>(bucketId);
169     } else {
170         return std::make_shared<ErrorCyadCommand>(Errors::UNKNOWN_OPTION_DELETE_BUCKET);
171     }
172 }
173
174 PolicyType CyadCommandlineParser::parsePolicyType(const std::string &rawPolicy) {
175     if (rawPolicy == "DENY")
176         return CYNARA_ADMIN_DENY;
177     if (rawPolicy == "NONE")
178         return CYNARA_ADMIN_NONE;
179     if (rawPolicy == "BUCKET")
180         return CYNARA_ADMIN_BUCKET;
181     if (rawPolicy == "ALLOW")
182         return CYNARA_ADMIN_ALLOW;
183
184     // If base for std::stoi is set to 0, it detects base by itself from the format of the sequence
185     try {
186         return std::stoi(rawPolicy, nullptr, 0);
187     } catch (const std::logic_error &) {
188         throw PolicyParsingException();
189     }
190 }
191
192 } /* namespace Cynara */