5 * Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 #include <sys/inotify.h>
34 #include <connman/log.h>
35 #include "../src/connman.h"
44 struct vpn_config_provider {
45 char *provider_identifier;
52 GHashTable *setting_strings;
54 char *config_ident; /* file prefix */
55 char *config_entry; /* entry name */
62 GHashTable *provider_table;
65 static GHashTable *config_table = NULL;
67 static bool cleanup = false;
69 /* Definition of possible strings in the .config files */
70 #define CONFIG_KEY_NAME "Name"
71 #define CONFIG_KEY_DESC "Description"
73 static const char *config_possible_keys[] = {
79 static void unregister_config(gpointer data)
81 struct vpn_config *config = data;
83 connman_info("Removing configuration %s", config->ident);
85 g_hash_table_destroy(config->provider_table);
87 g_free(config->description);
89 g_free(config->ident);
93 static void unregister_provider(gpointer data)
95 struct vpn_config_provider *config_provider = data;
96 struct vpn_provider *provider;
102 provider_id = config_provider->provider_identifier;
104 connman_info("Removing provider configuration %s provider %s",
105 config_provider->ident, provider_id);
107 provider = __vpn_provider_lookup(provider_id);
109 __vpn_provider_delete(provider);
111 if (!__connman_storage_remove_provider(provider_id))
112 DBG("Could not remove all files for provider %s",
117 g_free(config_provider->ident);
118 g_free(config_provider->type);
119 g_free(config_provider->name);
120 g_free(config_provider->host);
121 g_free(config_provider->domain);
122 g_free(config_provider->networks);
123 g_hash_table_destroy(config_provider->setting_strings);
124 g_free(config_provider->provider_identifier);
125 g_free(config_provider->config_ident);
126 g_free(config_provider->config_entry);
127 g_free(config_provider);
130 static int set_string(struct vpn_config_provider *config_provider,
131 const char *key, const char *value)
133 DBG("provider %p key %s value %s", config_provider, key, value);
135 if (g_str_equal(key, "Type")) {
136 g_free(config_provider->type);
137 config_provider->type = g_strdup(value);
138 } else if (g_str_equal(key, "Name")) {
139 g_free(config_provider->name);
140 config_provider->name = g_strdup(value);
141 } else if (g_str_equal(key, "Host")) {
142 g_free(config_provider->host);
143 config_provider->host = g_strdup(value);
144 } else if (g_str_equal(key, "Domain")) {
145 g_free(config_provider->domain);
146 config_provider->domain = g_strdup(value);
147 } else if (g_str_equal(key, "Networks")) {
148 g_free(config_provider->networks);
149 config_provider->networks = g_strdup(value);
152 g_hash_table_replace(config_provider->setting_strings,
153 g_strdup(key), g_strdup(value));
157 static const char *get_string(struct vpn_config_provider *config_provider,
160 DBG("provider %p key %s", config_provider, key);
162 if (g_str_equal(key, "Type"))
163 return config_provider->type;
164 else if (g_str_equal(key, "Name"))
165 return config_provider->name;
166 else if (g_str_equal(key, "Host"))
167 return config_provider->host;
168 else if (g_str_equal(key, "Domain"))
169 return config_provider->domain;
170 else if (g_str_equal(key, "Networks"))
171 return config_provider->networks;
173 return g_hash_table_lookup(config_provider->setting_strings, key);
176 static void add_keys(struct vpn_config_provider *config_provider,
177 GKeyFile *keyfile, const char *group)
180 gsize nb_avail_keys, i;
182 avail_keys = g_key_file_get_keys(keyfile, group, &nb_avail_keys, NULL);
186 for (i = 0 ; i < nb_avail_keys; i++) {
187 char *value = g_key_file_get_value(keyfile, group,
188 avail_keys[i], NULL);
190 connman_warn("Cannot find value for %s",
195 set_string(config_provider, avail_keys[i], value);
199 g_strfreev(avail_keys);
202 static int load_provider(GKeyFile *keyfile, const char *group,
203 struct vpn_config *config, enum what action)
205 struct vpn_config_provider *config_provider;
206 #if !defined TIZEN_EXT
207 const char *ident, *host, *domain;
209 const char *ident, *host, *domain, *name;
213 /* Strip off "provider_" prefix */
216 if (strlen(ident) < 1)
219 config_provider = g_hash_table_lookup(config->provider_table, ident);
223 config_provider = g_try_new0(struct vpn_config_provider, 1);
224 if (!config_provider)
227 config_provider->ident = g_strdup(ident);
229 config_provider->setting_strings = g_hash_table_new_full(g_str_hash,
230 g_str_equal, g_free, g_free);
232 add_keys(config_provider, keyfile, group);
234 host = get_string(config_provider, "Host");
235 domain = get_string(config_provider, "Domain");
236 #if !defined TIZEN_EXT
238 char *id = __vpn_provider_create_identifier(host, domain);
240 name = get_string(config_provider, "Name");
242 char *id = __vpn_provider_create_identifier(host, domain, name);
245 struct vpn_provider *provider;
246 provider = __vpn_provider_lookup(id);
248 if (action == REMOVE) {
249 __vpn_provider_delete(provider);
252 connman_warn("Provider configuration %s "
253 "already exist", id);
261 config_provider->provider_identifier = id;
263 DBG("provider identifier %s", id);
265 #if !defined TIZEN_EXT
266 DBG("invalid values host %s domain %s", host, domain);
268 DBG("invalid values host %s domain %s name %s", host, domain, name);
274 config_provider->config_ident = g_strdup(config->ident);
275 config_provider->config_entry = g_strdup_printf("provider_%s",
276 config_provider->ident);
278 err = __vpn_provider_create_from_config(
279 config_provider->setting_strings,
280 config_provider->config_ident,
281 config_provider->config_entry);
283 DBG("Cannot create provider from config file (%d/%s)",
284 -err, strerror(-err));
288 g_hash_table_insert(config->provider_table, config_provider->ident,
292 connman_info("Added provider configuration %s",
293 config_provider->ident);
297 g_free(config_provider->ident);
298 g_free(config_provider->type);
299 g_free(config_provider->name);
300 g_free(config_provider->host);
301 g_free(config_provider->domain);
302 g_free(config_provider->networks);
303 g_hash_table_destroy(config_provider->setting_strings);
304 g_free(config_provider);
309 static void check_keys(GKeyFile *keyfile, const char *group,
310 const char **possible_keys)
313 gsize nb_avail_keys, i, j;
315 avail_keys = g_key_file_get_keys(keyfile, group, &nb_avail_keys, NULL);
319 for (i = 0 ; i < nb_avail_keys; i++) {
320 for (j = 0; possible_keys[j] ; j++)
321 if (g_strcmp0(avail_keys[i], possible_keys[j]) == 0)
324 if (!possible_keys[j])
325 connman_warn("Unknown configuration key %s in [%s]",
326 avail_keys[i], group);
329 g_strfreev(avail_keys);
332 static int load_config(struct vpn_config *config, char *path, enum what action)
341 DBG("config %p", config);
343 keyfile = __connman_storage_load_provider_config(config->ident);
347 /* Verify keys validity of the global section */
348 check_keys(keyfile, "global", config_possible_keys);
350 str = __vpn_config_get_string(keyfile, "global", CONFIG_KEY_NAME, NULL);
352 g_free(config->name);
356 str = __vpn_config_get_string(keyfile, "global", CONFIG_KEY_DESC, NULL);
358 g_free(config->description);
359 config->description = str;
362 groups = g_key_file_get_groups(keyfile, &length);
364 for (i = 0; groups[i]; i++) {
365 if (g_str_has_prefix(groups[i], "provider_")) {
366 int ret = load_provider(keyfile, groups[i], config,
368 if (ret == 0 || ret == -EALREADY)
374 connman_warn("Config file %s/%s.config does not contain any "
375 "configuration that can be provisioned!",
376 path, config->ident);
380 g_key_file_free(keyfile);
385 static struct vpn_config *create_config(const char *ident)
387 struct vpn_config *config;
389 DBG("ident %s", ident);
391 if (g_hash_table_lookup(config_table, ident))
394 config = g_try_new0(struct vpn_config, 1);
398 config->ident = g_strdup(ident);
400 config->provider_table = g_hash_table_new_full(g_str_hash, g_str_equal,
401 NULL, unregister_provider);
403 g_hash_table_insert(config_table, config->ident, config);
405 connman_info("Adding configuration %s", config->ident);
410 static bool validate_ident(const char *ident)
417 for (i = 0; i < strlen(ident); i++)
418 if (!g_ascii_isprint(ident[i]))
424 static char *get_dir(void)
426 return g_strdup_printf("%s", VPN_STORAGEDIR);
429 static int read_configs(void)
432 char *path = get_dir();
434 DBG("path %s", path);
436 dir = g_dir_open(path, 0, NULL);
440 while ((file = g_dir_read_name(dir))) {
444 if (!g_str_has_suffix(file, ".config"))
447 ident = g_strrstr(file, ".config");
451 str = g_string_new_len(file, ident - file);
455 ident = g_string_free(str, FALSE);
457 if (validate_ident(ident)) {
458 struct vpn_config *config;
460 config = create_config(ident);
462 load_config(config, path, ADD);
464 connman_error("Invalid config ident %s", ident);
477 static void config_notify_handler(struct inotify_event *event,
485 if (!g_str_has_suffix(ident, ".config"))
488 ext = g_strrstr(ident, ".config");
494 if (!validate_ident(ident)) {
495 connman_error("Invalid config ident %s", ident);
499 if (event->mask & IN_CREATE)
502 if (event->mask & (IN_DELETE | IN_MOVED_FROM)) {
503 g_hash_table_remove(config_table, ident);
507 if (event->mask & (IN_MODIFY | IN_MOVED_TO)) {
508 struct vpn_config *config;
509 char *path = get_dir();
511 config = g_hash_table_lookup(config_table, ident);
513 g_hash_table_remove_all(config->provider_table);
514 load_config(config, path, REMOVE);
516 /* Re-scan the config file for any changes */
517 g_hash_table_remove_all(config->provider_table);
518 load_config(config, path, ADD);
521 * Inotify will send create event followed by modify
522 * event for any config file that is copied to
523 * monitored directory. So in practice we should just
524 * ignore the create event and trust only the modify
525 * one in order to avoid create/remove/create loop
527 config = create_config(ident);
529 load_config(config, path, ADD);
536 int __vpn_config_init(void)
538 char *dir = get_dir();
542 config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
543 NULL, unregister_config);
545 connman_inotify_register(dir, config_notify_handler);
549 return read_configs();
552 void __vpn_config_cleanup(void)
554 char *dir = get_dir();
560 connman_inotify_unregister(dir, config_notify_handler);
564 g_hash_table_destroy(config_table);
570 char *__vpn_config_get_string(GKeyFile *key_file,
571 const char *group_name, const char *key, GError **error)
573 char *str = g_key_file_get_string(key_file, group_name, key, error);
577 return g_strchomp(str);
580 char **__vpn_config_get_string_list(GKeyFile *key_file,
581 const char *group_name, const char *key, gsize *length, GError **error)
584 char **strlist = g_key_file_get_string_list(key_file, group_name, key,