0eca2bc80325355a5037ec857ec13683486efb1c
[platform/upstream/connman.git] / vpn / vpn-settings.c
1 /*
2  *  ConnMan VPN daemon settings
3  *
4  *  Copyright (C) 2012-2013  Intel Corporation. All rights reserved.
5  *  Copyright (C) 2018-2019 Jolla Ltd. All rights reserved.
6  *  Contact: jussi.laakkonen@jolla.com
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #include <connman/log.h>
28
29 #include "vpn.h"
30
31 #define DEFAULT_INPUT_REQUEST_TIMEOUT 300 * 1000
32 #define PLUGIN_CONFIGDIR CONFIGDIR "/vpn-plugin"
33 #define VPN_GROUP "DACPrivileges"
34
35 static struct {
36         unsigned int timeout_inputreq;
37         char *binary_user;
38         char *binary_group;
39         char **binary_supplementary_groups;
40 } connman_vpn_settings  = {
41         .timeout_inputreq               = DEFAULT_INPUT_REQUEST_TIMEOUT,
42         .binary_user                    = NULL,
43         .binary_group                   = NULL,
44         .binary_supplementary_groups    = NULL,
45 };
46
47 struct vpn_plugin_data {
48         char *binary_user;
49         char *binary_group;
50         char **binary_supplementary_groups;
51 };
52
53 GHashTable *plugin_hash = NULL;
54
55 const char *vpn_settings_get_binary_user(struct vpn_plugin_data *data)
56 {
57         if (data && data->binary_user)
58                 return data->binary_user;
59
60         return connman_vpn_settings.binary_user;
61 }
62
63 const char *vpn_settings_get_binary_group(struct vpn_plugin_data *data)
64 {
65         if (data && data->binary_group)
66                 return data->binary_group;
67
68         return connman_vpn_settings.binary_group;
69 }
70
71 char **vpn_settings_get_binary_supplementary_groups(struct vpn_plugin_data *data)
72 {
73         if (data && data->binary_supplementary_groups)
74                 return data->binary_supplementary_groups;
75
76         return connman_vpn_settings.binary_supplementary_groups;
77 }
78
79 unsigned int __vpn_settings_get_timeout_inputreq()
80 {
81         return connman_vpn_settings.timeout_inputreq;
82 }
83
84 static char *get_string(GKeyFile *config, const char *group, const char *key)
85 {
86         char *str = g_key_file_get_string(config, group, key, NULL);
87         return str ? g_strstrip(str) : NULL;
88 }
89
90 static char **get_string_list(GKeyFile *config, const char *group,
91                                 const char *key)
92 {
93         gsize len = 0;
94         char **str = g_key_file_get_string_list(config, group, key, &len, NULL);
95
96         if (str) {
97                 guint i = 0;
98
99                 for (i = 0; i < len ; i++) {
100                         str[i] = g_strstrip(str[i]);
101                 }
102         }
103
104         return str;
105 }
106
107 static void parse_config(GKeyFile *config, const char *file)
108 {
109         const char *group = "General";
110         GError *error = NULL;
111         int timeout;
112
113         if (!config)
114                 return;
115
116         DBG("parsing %s", file);
117
118         timeout = g_key_file_get_integer(config, group,
119                         "InputRequestTimeout", &error);
120         if (!error && timeout >= 0)
121                 connman_vpn_settings.timeout_inputreq = timeout * 1000;
122
123         g_clear_error(&error);
124
125         connman_vpn_settings.binary_user = get_string(config, VPN_GROUP,
126                                                 "User");
127         connman_vpn_settings.binary_group = get_string(config, VPN_GROUP,
128                                                 "Group");
129         connman_vpn_settings.binary_supplementary_groups = get_string_list(
130                                                 config, VPN_GROUP,
131                                                 "SupplementaryGroups");
132 }
133
134 struct vpn_plugin_data *vpn_settings_get_vpn_plugin_config(const char *name)
135 {
136         struct vpn_plugin_data *data = NULL;
137
138         if (plugin_hash)
139                 data = g_hash_table_lookup(plugin_hash, name);
140
141         return data;
142 }
143
144 static void vpn_plugin_data_free(gpointer data)
145 {
146         struct vpn_plugin_data *plugin_data = (struct vpn_plugin_data*)data;
147
148         g_free(plugin_data->binary_user);
149         g_free(plugin_data->binary_group);
150         g_strfreev(plugin_data->binary_supplementary_groups);
151
152         g_free(data);
153 }
154
155 int vpn_settings_parse_vpn_plugin_config(const char *name)
156 {
157         struct vpn_plugin_data *data;
158         gchar *file;
159         gchar *ext = ".conf";
160         GKeyFile *config;
161         gint err = 0;
162
163         if (!name || !*name)
164                 return -EINVAL;
165
166         if (vpn_settings_get_vpn_plugin_config(name))
167                 return -EALREADY;
168
169         file = g_strconcat(PLUGIN_CONFIGDIR, "/", name, ext, NULL);
170
171         config =  __vpn_settings_load_config(file);
172
173         if (!config) {
174                 err = -ENOENT;
175                 DBG("Cannot load config %s for %s", file, name);
176                 goto out;
177         }
178
179         data = g_try_new0(struct vpn_plugin_data, 1);
180
181         data->binary_user = get_string(config, VPN_GROUP, "User");
182         data->binary_group = get_string(config, VPN_GROUP, "Group");
183         data->binary_supplementary_groups = get_string_list(config, VPN_GROUP,
184                                                 "SupplementaryGroups");
185
186         DBG("Loaded settings for %s: %s - %s",
187                 name, data->binary_user, data->binary_group);
188
189         if (!plugin_hash)
190                 plugin_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
191                                                 g_free, vpn_plugin_data_free);
192
193         g_hash_table_replace(plugin_hash, g_strdup(name), data);
194
195         g_key_file_unref(config);
196
197 out:
198         g_free(file);
199         return err;
200 }
201
202 void vpn_settings_delete_vpn_plugin_config(const char *name)
203 {
204         if (plugin_hash && name)
205                 g_hash_table_remove(plugin_hash, name);
206 }
207
208 GKeyFile *__vpn_settings_load_config(const char *file)
209 {
210         GError *err = NULL;
211         GKeyFile *keyfile;
212
213         keyfile = g_key_file_new();
214
215         g_key_file_set_list_separator(keyfile, ',');
216
217         if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
218                 if (err->code != G_FILE_ERROR_NOENT) {
219                         connman_error("Parsing %s failed: %s", file,
220                                                                 err->message);
221                 }
222
223                 g_error_free(err);
224                 g_key_file_unref(keyfile);
225                 return NULL;
226         }
227
228         return keyfile;
229 }
230
231 int __vpn_settings_init(const char *file)
232 {
233         GKeyFile *config;
234
235         config = __vpn_settings_load_config(file);
236         parse_config(config, file);
237         if (config)
238                 g_key_file_unref(config);
239
240         return 0;
241 }
242
243 void __vpn_settings_cleanup()
244 {
245         g_free(connman_vpn_settings.binary_user);
246         g_free(connman_vpn_settings.binary_group);
247         g_strfreev(connman_vpn_settings.binary_supplementary_groups);
248
249         if (plugin_hash) {
250                 g_hash_table_destroy(plugin_hash);
251                 plugin_hash = NULL;
252         }
253 }