Imported Upstream connman version 1.38
[platform/upstream/connman.git] / vpn / vpn-agent.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2012  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2019  Jolla Ltd. All rights reserved.
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  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <gdbus.h>
32 #include <connman/log.h>
33 #include <connman/agent.h>
34 #include <connman/vpn-dbus.h>
35 #include <connman/task.h>
36 #include <vpn/vpn-provider.h>
37
38 #include "vpn-agent.h"
39 #include "vpn.h"
40
41 bool vpn_agent_check_reply_has_dict(DBusMessage *reply)
42 {
43         const char *signature = DBUS_TYPE_ARRAY_AS_STRING
44                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
45                 DBUS_TYPE_STRING_AS_STRING
46                 DBUS_TYPE_VARIANT_AS_STRING
47                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
48
49         if (dbus_message_has_signature(reply, signature))
50                 return true;
51
52         connman_warn("Reply %s to %s from %s has wrong signature %s",
53                         signature,
54                         dbus_message_get_interface(reply),
55                         dbus_message_get_sender(reply),
56                         dbus_message_get_signature(reply));
57
58         return false;
59 }
60
61 static void request_input_append_name(DBusMessageIter *iter, void *user_data)
62 {
63         struct vpn_provider *provider = user_data;
64         const char *str = "string";
65
66         connman_dbus_dict_append_basic(iter, "Type",
67                                 DBUS_TYPE_STRING, &str);
68         str = "informational";
69         connman_dbus_dict_append_basic(iter, "Requirement",
70                                 DBUS_TYPE_STRING, &str);
71
72         str = vpn_provider_get_name(provider);
73         connman_dbus_dict_append_basic(iter, "Value",
74                                 DBUS_TYPE_STRING, &str);
75 }
76
77 static void request_input_append_host(DBusMessageIter *iter, void *user_data)
78 {
79         struct vpn_provider *provider = user_data;
80         const char *str = "string";
81
82         connman_dbus_dict_append_basic(iter, "Type",
83                                 DBUS_TYPE_STRING, &str);
84         str = "informational";
85         connman_dbus_dict_append_basic(iter, "Requirement",
86                                 DBUS_TYPE_STRING, &str);
87
88         str = vpn_provider_get_host(provider);
89         connman_dbus_dict_append_basic(iter, "Value",
90                                 DBUS_TYPE_STRING, &str);
91 }
92
93 void vpn_agent_append_host_and_name(DBusMessageIter *iter,
94                                 struct vpn_provider *provider)
95 {
96         connman_dbus_dict_append_dict(iter, "Host",
97                                 request_input_append_host,
98                                 provider);
99
100         connman_dbus_dict_append_dict(iter, "Name",
101                                 request_input_append_name,
102                                 provider);
103 }
104
105 struct user_info_data {
106         struct vpn_provider *provider;
107         const char *username_str;
108         const char *type_str;
109 };
110
111 static void request_input_append_user_info(DBusMessageIter *iter,
112                                                 void *user_data)
113 {
114         struct user_info_data *data = user_data;
115         struct vpn_provider *provider = data->provider;
116         const char *str = NULL;
117
118         connman_dbus_dict_append_basic(iter, "Type",
119                                 DBUS_TYPE_STRING, &data->type_str);
120         str = "mandatory";
121         connman_dbus_dict_append_basic(iter, "Requirement",
122                                 DBUS_TYPE_STRING, &str);
123
124         if (data->username_str) {
125                 str = vpn_provider_get_string(provider, data->username_str);
126                 if (str)
127                         connman_dbus_dict_append_basic(iter, "Value",
128                                                 DBUS_TYPE_STRING, &str);
129         }
130 }
131
132 void vpn_agent_append_user_info(DBusMessageIter *iter,
133                                 struct vpn_provider *provider,
134                                 const char *username_str)
135 {
136         struct user_info_data data = {
137                 .provider = provider,
138                 .username_str = username_str
139         };
140
141         data.type_str = "string";
142         connman_dbus_dict_append_dict(iter, "Username",
143                                 request_input_append_user_info,
144                                 &data);
145
146         data.username_str = NULL;
147         data.type_str = "password";
148         connman_dbus_dict_append_dict(iter, "Password",
149                                 request_input_append_user_info,
150                                 &data);
151 }
152
153 static void request_input_append_flag(DBusMessageIter *iter,
154                                                 void *user_data)
155 {
156         dbus_bool_t data = (dbus_bool_t)GPOINTER_TO_INT(user_data);
157         const char *str = NULL;
158
159         str = "boolean";
160         connman_dbus_dict_append_basic(iter, "Type",
161                                 DBUS_TYPE_STRING, &str);
162
163         str = "control";
164         connman_dbus_dict_append_basic(iter, "Requirement",
165                                 DBUS_TYPE_STRING, &str);
166
167         connman_dbus_dict_append_basic(iter, "Value",
168                                 DBUS_TYPE_BOOLEAN, &data);
169 }
170
171 void vpn_agent_append_allow_credential_storage(DBusMessageIter *iter,
172                                 bool allow)
173 {
174         connman_dbus_dict_append_dict(iter, "AllowStoreCredentials",
175                                 request_input_append_flag,
176                                 GINT_TO_POINTER(allow));
177 }
178
179 void vpn_agent_append_allow_credential_retrieval(DBusMessageIter *iter,
180                                 bool allow)
181 {
182         connman_dbus_dict_append_dict(iter, "AllowRetrieveCredentials",
183                                 request_input_append_flag,
184                                 GINT_TO_POINTER(allow));
185 }
186
187 void vpn_agent_append_keep_credentials(DBusMessageIter *iter, bool allow)
188 {
189         connman_dbus_dict_append_dict(iter, "KeepCredentials",
190                                 request_input_append_flag,
191                                 GINT_TO_POINTER(allow));
192 }
193
194 struct failure_data {
195         struct vpn_provider *provider;
196         const char* type_str;
197         const char *key;
198         const char* str;
199 };
200
201 static void request_input_append_failure(DBusMessageIter *iter,
202                                                 void *user_data)
203 {
204         struct failure_data *data;
205         const char *str;
206
207         data = user_data;
208
209         connman_dbus_dict_append_basic(iter, "Type",
210                                 DBUS_TYPE_STRING, &data->type_str);
211         str = "informational";
212         connman_dbus_dict_append_basic(iter, "Requirement",
213                                 DBUS_TYPE_STRING, &str);
214
215         str = data->str;
216
217         /* Try to get information from provider about error */
218         if (!str)
219                 str = vpn_provider_get_string(data->provider, data->key);
220
221         if (str)
222                 connman_dbus_dict_append_basic(iter, "Value",
223                                                 DBUS_TYPE_STRING, &str);
224 }
225
226 void vpn_agent_append_auth_failure(DBusMessageIter *iter,
227                                 struct vpn_provider *provider,
228                                 const char* information)
229 {
230         struct failure_data data;
231         unsigned int value;
232
233         /* Skip if there are no auth errors */
234         value = vpn_provider_get_authentication_errors(provider);
235         if (!value)
236                 return;
237
238         data.provider = provider;
239         data.type_str = "string";
240         data.key = "VpnAgent.AuthFailure";
241         data.str = information;
242
243         connman_dbus_dict_append_dict(iter, data.key,
244                                 request_input_append_failure, &data);
245 }
246
247 int vpn_agent_check_and_process_reply_error(DBusMessage *reply,
248                                 struct vpn_provider *provider,
249                                 struct connman_task *task,
250                                 vpn_provider_connect_cb_t cb, void *user_data)
251 {
252         DBusError error;
253         int err;
254
255         if (!reply || !provider)
256                 return EINVAL;
257
258         dbus_error_init(&error);
259
260         if (!dbus_set_error_from_message(&error, reply))
261                 return 0;
262
263         if (!g_strcmp0(error.name, VPN_AGENT_INTERFACE ".Error.Canceled"))
264                 err = ECANCELED;
265         else if (!g_strcmp0(error.name, "org.freedesktop.DBus.Error.Timeout"))
266                 err = ETIMEDOUT;
267         else if (!g_strcmp0(error.name, "org.freedesktop.DBus.Error.NoReply"))
268                 err = ENOMSG;
269         else
270                 err = EACCES;
271
272         dbus_error_free(&error);
273
274         if (cb)
275                 cb(provider, user_data, err);
276
277         if (task)
278                 connman_task_stop(task);
279
280         /*
281          * VPN agent dialog cancel, timeout, broken connection should set the
282          * VPN back to idle state
283          */
284         vpn_provider_set_state(provider, VPN_PROVIDER_STATE_IDLE);
285
286         return err;
287 }