Support SMACK permissive mode in Buxton
[platform/upstream/buxton.git] / src / shared / configurator.c
1 /*
2  * This file is part of buxton.
3  *
4  * Copyright (C) 2013 Intel Corporation
5  *
6  * buxton is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1
9  * of the License, or (at your option) any later version.
10  */
11
12 #ifdef HAVE_CONFIG_H
13         #include "config.h"
14 #endif
15
16 #include <assert.h>
17 #include <iniparser.h>
18 #include <linux/limits.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "configurator.h"
25 #include "log.h"
26
27 /**
28  * Section name in ini file for our configuration
29  */
30 #define CONFIG_SECTION "Configuration"
31
32 #ifndef HAVE_SECURE_GETENV
33 #  ifdef HAVE___SECURE_GETENV
34 #    define secure_getenv __secure_getenv
35 #  else
36 #    error neither secure_getenv nor __secure_getenv is available
37 #  endif
38 #endif
39
40 /**
41  * @internal
42  * internal state of configurator
43  */
44 static struct _conf {
45         bool initialized;       /**< track if it's been init'd */
46         char* keys[CONFIG_MAX]; /**< bag of values */
47         dictionary* ini;        /**< ini parser dictionary */
48 } conf = {
49         .initialized = false,
50         .keys = {0},
51         .ini = NULL
52 };
53
54 /**
55  * @internal
56  * config keys as in environment
57  * @fixme name sucks
58  */
59 static const char *KS[CONFIG_MAX] = {
60         NULL,
61         "BUXTON_CONF_FILE",
62         "BUXTON_MODULE_DIR",
63         "BUXTON_DB_PATH",
64         "BUXTON_SMACK_LOAD_FILE",
65         "BUXTON_BUXTON_SOCKET",
66         "BUXTON_SMACK_PERMISSIVE"
67 };
68
69 /**
70  * @internal
71  * keys as they are used in config file
72  */
73 static const char *config_keys[CONFIG_MAX] = {
74         NULL,
75         NULL,                   /**< conf file entry in config file is meaningless */
76         "ModuleDirectory",
77         "DatabasePath",
78         "SmackLoadFile",
79         "SocketPath",
80         "SmackPermissive"
81 };
82
83 static const char *COMPILE_DEFAULT[CONFIG_MAX] = {
84         NULL,
85         _DEFAULT_CONFIGURATION_FILE,
86         _MODULE_DIRECTORY,
87         _DB_PATH,
88         _SMACK_LOAD_FILE,
89         _BUXTON_SOCKET,
90         _SMACK_PERMISSIVE
91 };
92
93 /**
94  * @internal
95  * wrap strdup and die if malloc fails
96  *
97  * @note This may seem lame and stupid at first glance. The former is
98  * right the latter is not. This function may abort()
99  *
100  * @return pointer to dup'd string
101  */
102 __attribute__ ((pure))
103 static inline char *_strdup(const char* string)
104 {
105         char* s;
106
107         s = strdup(string);
108         if (s == NULL) {
109                 abort();
110         }
111         return s;
112 }
113
114 /**
115  * @internal
116  * grab a string from the ini file
117  *
118  * @param section the section of the ini file
119  * @param name the name of the key
120  * @param required if key required or not
121  * @param def default value for nonrequired setting
122  *
123  * @note This function may abort()
124  *
125  * @return The value as a string. The the string is internal to
126  * libini, and if at this stage of the game it is null, just die.
127  * Something is really wrong and even if we could recover, the system
128  * is not working correctly.
129  */
130 static char *get_ini_string(char *section, char *name, bool required,
131         char *def)
132 {
133         char buf[PATH_MAX];
134         char *s;
135
136         assert(conf.ini);
137         snprintf(buf, sizeof(buf), "%s:%s", section, name);
138         s = iniparser_getstring(conf.ini, buf, def);
139         if (s == NULL && required) {
140                 abort();
141         }
142         return s;
143 }
144
145 /**
146  * analagous method to get_ini_string()
147  *
148  * @param section the section of the ini file
149  * @param name the name of the key
150  * @param required if key required or not
151  * @param def default value for nonrequired setting
152  *
153  * @note inlined b/c only used once and why not.
154  *
155  * @return the value
156  */
157 static inline int get_ini_int(char *section, char *name, bool required,
158         int def)
159 {
160         char buf[PATH_MAX];
161         int exists;
162
163         assert(conf.ini);
164         snprintf(buf, sizeof(buf), "%s:%s", section, name);
165         exists = iniparser_find_entry(conf.ini, buf);
166         if (!exists && required) {
167                 abort();
168         }
169         return iniparser_getint(conf.ini, buf, def);
170 }
171
172 /**
173  * @internal
174  * Initialize conf
175  *
176  */
177 static void initialize(void)
178 {
179         if (conf.initialized) {
180                 return;
181         }
182
183         for (int i= CONFIG_MIN+1; i < CONFIG_MAX; i++) {
184                 char *envkey;
185
186                 /* hasn't been set through command line */
187                 if (conf.keys[i] == NULL) {
188                         /* second priority is env */
189                         envkey = secure_getenv(KS[i]);
190                         if (envkey) {
191                                 conf.keys[i] = _strdup(envkey);
192                         }
193                 }
194
195                 /* third priority is conf file */
196                 if (conf.keys[i] == NULL && conf.ini) {
197                         /* for once config file is loaded */
198                         char key[PATH_MAX+strlen(CONFIG_SECTION)+1+1]; /* one for null and one for : */
199                         char *value;
200
201                         snprintf(key, sizeof(key), "%s:%s", CONFIG_SECTION, config_keys[i]);
202                         value = iniparser_getstring(conf.ini, key, NULL);
203                         if (value != NULL) {
204                                 conf.keys[i] = _strdup(value);
205                         }
206                 }
207
208                 if (conf.keys[i] == NULL) {
209                         /* last priority is compile time defaults */
210                         conf.keys[i] = _strdup(COMPILE_DEFAULT[i]);
211                 }
212
213                 /* if config file is not loaded, load */
214                 if (i == CONFIG_CONF_FILE) {
215                         char *path = conf.keys[CONFIG_CONF_FILE];
216
217                         conf.ini = iniparser_load(path);
218                         if (conf.ini == NULL) {
219                                 buxton_log("Failed to load buxton conf file: %s\n", path);
220                         }
221                 }
222         }
223         conf.initialized = true;
224 }
225
226 /**
227  * @internal
228  * use a destructor to free everything rather than yucky at_exit
229  * nonsense
230  *
231  * @return
232  */
233 __attribute__ ((destructor)) static void free_conf(void)
234 {
235         if (!conf.initialized) {
236                 return;
237         }
238         for (int i= CONFIG_MIN+1; i < CONFIG_MAX; i++) {
239                 free(conf.keys[i]);
240         }
241         iniparser_freedict(conf.ini);
242 }
243
244 void buxton_add_cmd_line(ConfigKey confkey, const char *data)
245 {
246         if (confkey >= CONFIG_MAX || confkey <= CONFIG_MIN) {
247                 buxton_log("invalid confkey");
248                 return;
249         }
250         if (!data) {
251                 buxton_log("invalid data");
252                 return;
253         }
254
255         conf.keys[confkey] = _strdup(data);
256 }
257
258 const char* buxton_module_dir(void)
259 {
260         initialize();
261         return (const char*)conf.keys[CONFIG_MODULE_DIR];
262 }
263
264 const char* buxton_conf_file(void)
265 {
266         initialize();
267         return (const char*)conf.keys[CONFIG_CONF_FILE];
268 }
269
270 const char* buxton_db_path(void)
271 {
272         initialize();
273         return (const char*)conf.keys[CONFIG_DB_PATH];
274 }
275
276 const char* buxton_smack_load_file(void)
277 {
278         initialize();
279         return (const char*)conf.keys[CONFIG_SMACK_LOAD_FILE];
280 }
281
282 const char* buxton_smack_permissive(void)
283 {
284         initialize();
285         return (const char*)conf.keys[CONFIG_SMACK_PERMISSIVE];
286 }
287
288 const char* buxton_socket(void)
289 {
290         initialize();
291         return (const char*)conf.keys[CONFIG_BUXTON_SOCKET];
292 }
293
294 int buxton_key_get_layers(ConfigLayer **layers)
295 {
296         ConfigLayer *_layers;
297         int n;
298         int j = 0;
299
300         assert(layers);
301         initialize();
302         if (conf.ini == NULL) {
303                 buxton_log("config file not loaded when calling buxton_key_get_layers()");
304                 abort();
305         }
306         n = iniparser_getnsec(conf.ini);
307         _layers = (ConfigLayer*)calloc((size_t)n, sizeof(ConfigLayer));
308         if (_layers == NULL) {
309                 abort();
310         }
311         for (int i= 0; i < n; i++) {
312                 char *section_name;
313
314                 section_name = iniparser_getsecname(conf.ini, i);
315                 if (!section_name) {
316                         abort();
317                 }
318                 if (!strcasecmp(section_name, CONFIG_SECTION)) {
319                         continue;
320                 }
321                 _layers[j].name = section_name;
322                 _layers[j].description = get_ini_string(section_name,
323                         "Description", true, NULL);
324                 _layers[j].backend = get_ini_string(section_name, "Backend",
325                         true, NULL);
326                 _layers[j].type = get_ini_string(section_name, "Type", true,
327                         NULL);
328                 _layers[j].priority = get_ini_int(section_name, "Priority",
329                         true, 0);
330                 _layers[j].access = get_ini_string(section_name, "Access",
331                         false, "read-write");
332                 j++;
333         }
334         *layers = _layers;
335         return j;
336 }
337
338 void include_configurator(void)
339 {
340         ;
341 }
342
343
344 /*
345  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
346  *
347  * Local variables:
348  * c-basic-offset: 8
349  * tab-width: 8
350  * indent-tabs-mode: t
351  * End:
352  *
353  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
354  * :indentSize=8:tabSize=8:noTabs=false:
355  */