5 * Copyright (C) 2012 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 connman_bool_t protected;
63 GHashTable *provider_table;
66 static GHashTable *config_table = NULL;
67 static GSList *protected_providers = NULL;
69 static connman_bool_t cleanup = FALSE;
71 /* Definition of possible strings in the .config files */
72 #define CONFIG_KEY_NAME "Name"
73 #define CONFIG_KEY_DESC "Description"
74 #define CONFIG_KEY_PROT "Protected"
76 static const char *config_possible_keys[] = {
83 static void unregister_config(gpointer data)
85 struct vpn_config *config = data;
87 connman_info("Removing configuration %s", config->ident);
89 g_hash_table_destroy(config->provider_table);
91 g_free(config->description);
93 g_free(config->ident);
97 static void unregister_provider(gpointer data)
99 struct vpn_config_provider *config_provider = data;
100 struct vpn_provider *provider;
106 provider_id = config_provider->provider_identifier;
108 connman_info("Removing provider configuration %s provider %s",
109 config_provider->ident, provider_id);
111 protected_providers = g_slist_remove(protected_providers,
114 provider = __vpn_provider_lookup(provider_id);
115 if (provider != NULL)
116 __vpn_provider_delete(provider);
118 if (__connman_storage_remove_provider(provider_id) == FALSE)
119 DBG("Could not remove all files for provider %s",
124 g_free(config_provider->ident);
125 g_free(config_provider->type);
126 g_free(config_provider->name);
127 g_free(config_provider->host);
128 g_free(config_provider->domain);
129 g_free(config_provider->networks);
130 g_hash_table_destroy(config_provider->setting_strings);
131 g_free(config_provider->provider_identifier);
132 g_free(config_provider->config_ident);
133 g_free(config_provider->config_entry);
134 g_free(config_provider);
137 static connman_bool_t check_type(const char *type)
139 if (g_strcmp0(type, "OpenConnect") == 0)
141 if (g_strcmp0(type, "OpenVPN") == 0)
143 if (g_strcmp0(type, "VPNC") == 0)
145 if (g_strcmp0(type, "L2TP") == 0)
147 if (g_strcmp0(type, "PPTP") == 0)
153 static connman_bool_t
154 is_protected_provider(struct vpn_config_provider *config_provider)
158 DBG("ident %s", config_provider->ident);
160 for (list = protected_providers; list; list = list->next) {
161 struct vpn_config_provider *p = list->data;
163 if (g_strcmp0(p->type, config_provider->type) != 0)
166 if (check_type(config_provider->type) == TRUE)
173 static int set_string(struct vpn_config_provider *config_provider,
174 const char *key, const char *value)
176 DBG("provider %p key %s value %s", config_provider, key, value);
178 if (g_str_equal(key, "Type") == TRUE) {
179 g_free(config_provider->type);
180 config_provider->type = g_strdup(value);
181 } else if (g_str_equal(key, "Name") == TRUE) {
182 g_free(config_provider->name);
183 config_provider->name = g_strdup(value);
184 } else if (g_str_equal(key, "Host") == TRUE) {
185 g_free(config_provider->host);
186 config_provider->host = g_strdup(value);
187 } else if (g_str_equal(key, "Domain") == TRUE) {
188 g_free(config_provider->domain);
189 config_provider->domain = g_strdup(value);
190 } else if (g_str_equal(key, "Networks") == TRUE) {
191 g_free(config_provider->networks);
192 config_provider->networks = g_strdup(value);
195 g_hash_table_replace(config_provider->setting_strings,
196 g_strdup(key), g_strdup(value));
200 static const char *get_string(struct vpn_config_provider *config_provider,
203 DBG("provider %p key %s", config_provider, key);
205 if (g_str_equal(key, "Type") == TRUE)
206 return config_provider->type;
207 else if (g_str_equal(key, "Name") == TRUE)
208 return config_provider->name;
209 else if (g_str_equal(key, "Host") == TRUE)
210 return config_provider->host;
211 else if (g_str_equal(key, "Domain") == TRUE)
212 return config_provider->domain;
213 else if (g_str_equal(key, "Networks") == TRUE)
214 return config_provider->networks;
216 return g_hash_table_lookup(config_provider->setting_strings, key);
219 static void add_keys(struct vpn_config_provider *config_provider,
220 GKeyFile *keyfile, const char *group)
223 gsize nb_avail_keys, i;
225 avail_keys = g_key_file_get_keys(keyfile, group, &nb_avail_keys, NULL);
226 if (avail_keys == NULL)
229 for (i = 0 ; i < nb_avail_keys; i++) {
230 char *value = g_key_file_get_value(keyfile, group,
231 avail_keys[i], NULL);
233 connman_warn("Cannot find value for %s",
238 set_string(config_provider, avail_keys[i], value);
242 g_strfreev(avail_keys);
245 static int load_provider(GKeyFile *keyfile, const char *group,
246 struct vpn_config *config, enum what action)
248 struct vpn_config_provider *config_provider;
249 const char *ident, *host, *domain;
252 /* Strip off "provider_" prefix */
255 if (strlen(ident) < 1)
258 config_provider = g_hash_table_lookup(config->provider_table, ident);
259 if (config_provider != NULL)
262 config_provider = g_try_new0(struct vpn_config_provider, 1);
263 if (config_provider == NULL)
266 config_provider->ident = g_strdup(ident);
268 config_provider->setting_strings = g_hash_table_new_full(g_str_hash,
269 g_str_equal, g_free, g_free);
271 add_keys(config_provider, keyfile, group);
273 host = get_string(config_provider, "Host");
274 domain = get_string(config_provider, "Domain");
275 if (host != NULL && domain != NULL) {
276 char *id = __vpn_provider_create_identifier(host, domain);
278 struct vpn_provider *provider;
279 provider = __vpn_provider_lookup(id);
280 if (provider != NULL) {
281 if (action == REMOVE)
282 __vpn_provider_delete(provider);
289 config_provider->provider_identifier = id;
291 DBG("provider identifier %s", id);
293 DBG("invalid values host %s domain %s", host, domain);
298 if (is_protected_provider(config_provider) == TRUE) {
299 connman_error("Trying to provision a protected service");
304 config_provider->config_ident = g_strdup(config->ident);
305 config_provider->config_entry = g_strdup_printf("provider_%s",
306 config_provider->ident);
308 g_hash_table_insert(config->provider_table,
309 config_provider->ident, config_provider);
311 if (config->protected == TRUE)
312 protected_providers =
313 g_slist_prepend(protected_providers, config_provider);
315 err = __vpn_provider_create_from_config(
316 config_provider->setting_strings,
317 config_provider->config_ident,
318 config_provider->config_entry);
320 DBG("Cannot create provider from config file (%d/%s)",
321 -err, strerror(-err));
325 connman_info("Added provider configuration %s",
326 config_provider->ident);
330 g_free(config_provider->ident);
331 g_free(config_provider->type);
332 g_free(config_provider->name);
333 g_free(config_provider->host);
334 g_free(config_provider->domain);
335 g_free(config_provider->networks);
336 g_hash_table_destroy(config_provider->setting_strings);
337 g_free(config_provider);
342 static void check_keys(GKeyFile *keyfile, const char *group,
343 const char **possible_keys)
346 gsize nb_avail_keys, i, j;
348 avail_keys = g_key_file_get_keys(keyfile, group, &nb_avail_keys, NULL);
349 if (avail_keys == NULL)
352 for (i = 0 ; i < nb_avail_keys; i++) {
353 for (j = 0; possible_keys[j] ; j++)
354 if (g_strcmp0(avail_keys[i], possible_keys[j]) == 0)
357 if (possible_keys[j] == NULL)
358 connman_warn("Unknown configuration key %s in [%s]",
359 avail_keys[i], group);
362 g_strfreev(avail_keys);
365 static int load_config(struct vpn_config *config, char *path, enum what action)
368 GError *error = NULL;
372 gboolean protected, found = FALSE;
375 DBG("config %p", config);
377 keyfile = __connman_storage_load_provider_config(config->ident);
381 /* Verify keys validity of the global section */
382 check_keys(keyfile, "global", config_possible_keys);
384 str = g_key_file_get_string(keyfile, "global", CONFIG_KEY_NAME, NULL);
386 g_free(config->name);
390 str = g_key_file_get_string(keyfile, "global", CONFIG_KEY_DESC, NULL);
392 g_free(config->description);
393 config->description = str;
396 protected = g_key_file_get_boolean(keyfile, "global",
397 CONFIG_KEY_PROT, &error);
399 config->protected = protected;
401 config->protected = TRUE;
402 g_clear_error(&error);
404 groups = g_key_file_get_groups(keyfile, &length);
406 for (i = 0; groups[i] != NULL; i++) {
407 if (g_str_has_prefix(groups[i], "provider_") == TRUE) {
408 int ret = load_provider(keyfile, groups[i], config,
410 if (ret == 0 || ret == -EALREADY)
416 connman_warn("Config file %s/%s.config does not contain any "
417 "configuration that can be provisioned!",
418 path, config->ident);
422 g_key_file_free(keyfile);
427 static struct vpn_config *create_config(const char *ident)
429 struct vpn_config *config;
431 DBG("ident %s", ident);
433 if (g_hash_table_lookup(config_table, ident) != NULL)
436 config = g_try_new0(struct vpn_config, 1);
440 config->ident = g_strdup(ident);
442 config->provider_table = g_hash_table_new_full(g_str_hash, g_str_equal,
443 NULL, unregister_provider);
445 g_hash_table_insert(config_table, config->ident, config);
447 connman_info("Adding configuration %s", config->ident);
452 static connman_bool_t validate_ident(const char *ident)
459 for (i = 0; i < strlen(ident); i++)
460 if (g_ascii_isprint(ident[i]) == FALSE)
466 static char *get_dir()
468 return g_strdup_printf("%s", VPN_STORAGEDIR);
471 static int read_configs(void)
474 char *path = get_dir();
476 DBG("path %s", path);
478 dir = g_dir_open(path, 0, NULL);
482 while ((file = g_dir_read_name(dir)) != NULL) {
486 if (g_str_has_suffix(file, ".config") == FALSE)
489 ident = g_strrstr(file, ".config");
493 str = g_string_new_len(file, ident - file);
497 ident = g_string_free(str, FALSE);
499 if (validate_ident(ident) == TRUE) {
500 struct vpn_config *config;
502 config = create_config(ident);
504 load_config(config, path, ADD);
506 connman_error("Invalid config ident %s", ident);
519 static void config_notify_handler(struct inotify_event *event,
527 if (g_str_has_suffix(ident, ".config") == FALSE)
530 ext = g_strrstr(ident, ".config");
536 if (validate_ident(ident) == FALSE) {
537 connman_error("Invalid config ident %s", ident);
541 if (event->mask & IN_CREATE)
544 if (event->mask & IN_DELETE) {
545 g_hash_table_remove(config_table, ident);
549 if (event->mask & IN_MODIFY) {
550 struct vpn_config *config;
551 char *path = get_dir();
553 config = g_hash_table_lookup(config_table, ident);
554 if (config != NULL) {
555 g_hash_table_remove_all(config->provider_table);
556 load_config(config, path, REMOVE);
558 /* Re-scan the config file for any changes */
559 g_hash_table_remove_all(config->provider_table);
560 load_config(config, path, ADD);
563 * Inotify will send create event followed by modify
564 * event for any config file that is copied to
565 * monitored directory. So in practice we should just
566 * ignore the create event and trust only the modify
567 * one in order to avoid create/remove/create loop
569 config = create_config(ident);
571 load_config(config, path, ADD);
578 int __vpn_config_init(void)
580 char *dir = get_dir();
584 config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
585 NULL, unregister_config);
587 connman_inotify_register(dir, config_notify_handler);
591 return read_configs();
594 void __vpn_config_cleanup(void)
596 char *dir = get_dir();
602 connman_inotify_unregister(dir, config_notify_handler);
606 g_hash_table_destroy(config_table);