1 /*
2  * Copyright (C) 2018 Rafael Ostertag
3  *
4  * This file is part of YAPET.
5  *
6  * YAPET is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * YAPET is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * YAPET.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Additional permission under GNU GPL version 3 section 7
20  *
21  * If you modify this program, or any covered work, by linking or combining it
22  * with the OpenSSL project's OpenSSL library (or a modified version of that
23  * library), containing parts covered by the terms of the OpenSSL or SSLeay
24  * licenses, Rafael Ostertag grants you additional permission to convey the
25  * resulting work.  Corresponding Source for a non-source form of such a
26  * combination shall include the source code for the parts of OpenSSL used as
27  * well as that of the covered work.
28  */
29 
30 #ifndef _CFG_H
31 #define _CFG_H 1
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include <algorithm>
38 #include <cassert>
39 #include <functional>
40 #include <limits>
41 #include <map>
42 #include <sstream>
43 #include <string>
44 
45 #include <sys/types.h>
46 
47 #include "cfgfile.h"
48 #include "consts.h"
49 #include "rng.hh"
50 
51 namespace YAPET {
52 namespace CONFIG {
53 extern std::string trim(const std::string& s);
54 extern std::string getHomeDir();
55 
56 namespace INTERNAL {
57 // Wrapper function object which returns bool so that it
58 // can be used by *_if algorithms
59 class IntIsTrue {
60     std::pointer_to_unary_function<int, int> __f;
61 
62    public:
IntIsTrue(std::pointer_to_unary_function<int,int> _f)63     IntIsTrue(std::pointer_to_unary_function<int, int> _f) : __f(_f) {}
operator()64     bool operator()(int i) { return std::not_equal_to<int>()(0, __f(i)); }
65 };
66 
67 // Wrapper function object which returns bool so that it
68 // can be used by *_if algorithms
69 class IntIsFalse {
70     std::pointer_to_unary_function<int, int> __f;
71 
72    public:
IntIsFalse(std::pointer_to_unary_function<int,int> _f)73     IntIsFalse(std::pointer_to_unary_function<int, int> _f) : __f(_f) {}
operator()74     bool operator()(int i) { return std::equal_to<int>()(0, __f(i)); }
75 };
76 }  // namespace INTERNAL
77 
78 class CfgValBase {
79    public:
80     virtual void set_str(const std::string&) = 0;
~CfgValBase()81     virtual ~CfgValBase() {}
82 };
83 
84 /**
85  * @brief template class used for configuration values
86  *
87  * This template class is mainly used for configuration
88  * values. It allows the values being locked, i.e. preventing
89  * the values being changed by set methods.
90  */
91 template <class T>
92 class CfgVal : public CfgValBase {
93    private:
94     //! Indicates whether or not the value can be changed.
95     bool locked;
96     T val;
97 
98    protected:
remove_space(const std::string & str)99     std::string remove_space(const std::string& str) {
100         std::string space_clean(str);
101 
102         INTERNAL::IntIsTrue space(std::ptr_fun<int, int>(std::isspace));
103 
104         std::string::iterator new_end =
105             std::remove_if(space_clean.begin(), space_clean.end(), space);
106 
107         if (new_end == space_clean.end()) return space_clean;
108 
109         space_clean.erase(new_end, space_clean.end());
110 
111         return space_clean;
112     }
113 
tolower(const std::string & str)114     std::string tolower(const std::string& str) {
115         std::string lower(str);
116         std::transform(lower.begin(), lower.end(), lower.begin(),
117                        std::ptr_fun<int, int>(std::tolower));
118 
119         return lower;
120     }
121 
122    public:
123     typedef T type;
124 
CfgVal()125     CfgVal() : locked(false) {}
126 
CfgVal(const T & v)127     CfgVal(const T& v) : locked(false), val(v) {}
128 
CfgVal(const CfgVal & c)129     CfgVal(const CfgVal& c) : locked(c.locked), val(c.val) {}
130 
131     CfgVal& operator=(const CfgVal& c) {
132         if (&c == this) return *this;
133 
134         locked = c.locked;
135         val = c.val;
136 
137         return *this;
138     }
139 
140     CfgVal& operator=(const T& c) {
141         if (!locked) val = c;
142 
143         return *this;
144     }
145 
set(const T & v)146     virtual void set(const T& v) {
147         if (!locked) val = v;
148     }
149 
get()150     virtual T get() const { return val; }
151 
lock()152     void lock() { locked = true; }
153 
unlock()154     void unlock() { locked = false; }
155 
is_locked()156     bool is_locked() const { return locked; }
157 
T()158     operator T() const { return val; }
159 };
160 
161 typedef CfgVal<std::string> CfgValStr;
162 
163 class CfgValPetFile : public CfgValStr {
164    private:
165     std::string cleanup_path(const std::string& p);
166     std::string add_suffix(const std::string& p);
167 
168    public:
169     CfgValPetFile(std::string v = std::string())
CfgValStr(add_suffix (cleanup_path (v)))170         : CfgValStr(add_suffix(cleanup_path(v))) {}
CfgValPetFile(const CfgValPetFile & cv)171     CfgValPetFile(const CfgValPetFile& cv) : CfgValStr(cv) {}
172     CfgValPetFile& operator=(const CfgValPetFile& cv) {
173         CfgValStr::operator=(cv);
174         return *this;
175     }
176     CfgValPetFile& operator=(const std::string b) {
177         CfgValStr::operator=(b);
178         return *this;
179     }
180 
181     void set(const std::string& s);
182     void set_str(const std::string& s);
183 };
184 
185 class CfgValBool : public CfgVal<bool> {
186    public:
187     CfgValBool(bool v = true) : CfgVal<bool>(v) {}
CfgValBool(const CfgValBool & cv)188     CfgValBool(const CfgValBool& cv) : CfgVal<bool>(cv) {}
189     CfgValBool& operator=(const CfgValBool& cv) {
190         CfgVal<bool>::operator=(cv);
191         return *this;
192     }
193     CfgValBool& operator=(const bool b) {
194         CfgVal<bool>::operator=(b);
195         return *this;
196     }
197 
198     void set_str(const std::string& s);
199 };
200 
201 class CfgValInt : public CfgVal<int> {
202    private:
203     int __min;
204     int __max;
205     int __def_out_of_bounds;
206 
207    public:
208     CfgValInt(int v = 0, int def_out_of_bounds = 0,
209               int min = std::numeric_limits<int>::min(),
210               int max = std::numeric_limits<int>::max())
211         : CfgVal<int>(v < min || v > max ? def_out_of_bounds : v),
212           __min(min),
213           __max(max),
214           __def_out_of_bounds(def_out_of_bounds) {
215         assert(__def_out_of_bounds >= __min);
216         assert(__def_out_of_bounds <= __max);
217     }
CfgValInt(const CfgValInt & cv)218     CfgValInt(const CfgValInt& cv) : CfgVal<int>(cv) {}
219     CfgValInt& operator=(const CfgValInt& cv) {
220         CfgVal<int>::operator=(cv);
221         return *this;
222     }
223     CfgValInt& operator=(const int b) {
224         CfgVal<int>::operator=(b);
225         return *this;
226     }
227 
set(const int & i)228     void set(const int& i) {
229         CfgVal<int>::set(i < __min || i > __max ? __def_out_of_bounds : i);
230     }
231 
232     void set_str(const std::string& s);
233 
string()234     operator std::string() const {
235         std::ostringstream conv;
236         conv << get();
237         return conv.str();
238     }
239 };
240 
241 class CfgValColor : public CfgValStr {
242    public:
set_str(const std::string & s)243     void set_str(const std::string& s) { set(s); }
244 };
245 
246 /**
247  * @brief Handle the command line and config file options.
248  *
249  * This class handles the command line and config file options.
250  */
251 class Config {
252    private:
253     // mainly used by ConfigFile;
254     std::map<std::string, CfgValBase*> _options;
255     //! Removes two or more consecutive slashes from the path
256     std::string cleanupPath(const std::string& s) const;
257 
258     void setup_map();
259 
260    public:
261     CfgValPetFile petfile;
262     /// @todo rename to locktimeout
263     CfgValInt timeout;
264     CfgValBool filesecurity;
265     CfgValInt pwgenpwlen;
266     CfgValBool pwgen_letters;
267     CfgValBool pwgen_digits;
268     CfgValBool pwgen_punct;
269     CfgValBool pwgen_special;
270     CfgValBool pwgen_other;
271     CfgValBool allow_lock_quit;
272     CfgValInt pw_input_timeout;
273     // in kibi
274     CfgValInt argon2_memory;
275     CfgValInt argon2_parallelism;
276     CfgValInt argon2_iterations;
277     CfgValBool ignorerc;
278     CfgValColor colors;
279 
280     Config();
281     Config(const Config& c);
282     Config(Config&& c) = delete;
283     ~Config();
284 
285     Config& operator=(Config&& c) = delete;
286     Config& operator=(const Config& c);
287 
288     /**
289      * Convenience method.
290      *
291      * @return @c int representing all selected character
292      * pools.
293      */
294     int character_pools() const;
295 
296     //! Lock all configuration values
297     void lock();
298 
299     //! Unlock all configuration values
300     void unlock();
301 
302     CfgValBase& operator[](const std::string& key);
303 };
304 }  // namespace CONFIG
305 }  // namespace YAPET
306 
307 #endif  // _CFG_H
308