Agent API RequestInput method for requesting passphrases
[platform/upstream/connman.git] / src / agent.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <gdbus.h>
31
32 #include "connman.h"
33
34 static DBusConnection *connection = NULL;
35 static guint agent_watch = 0;
36 static gchar *agent_path = NULL;
37 static gchar *agent_sender = NULL;
38
39 static void agent_free(void)
40 {
41         agent_watch = 0;
42
43         g_free(agent_sender);
44         agent_sender = NULL;
45
46         g_free(agent_path);
47         agent_path = NULL;
48 }
49
50 static void agent_disconnect(DBusConnection *connection, void *data)
51 {
52         DBG("data %p", data);
53
54         agent_free();
55 }
56
57 int __connman_agent_register(const char *sender, const char *path)
58 {
59         DBG("sender %s path %s", sender, path);
60
61         if (agent_path != NULL)
62                 return -EEXIST;
63
64         agent_sender = g_strdup(sender);
65         agent_path = g_strdup(path);
66
67         agent_watch = g_dbus_add_disconnect_watch(connection, sender,
68                                                 agent_disconnect, NULL, NULL);
69
70         return 0;
71 }
72
73 int __connman_agent_unregister(const char *sender, const char *path)
74 {
75         DBG("sender %s path %s", sender, path);
76
77         if (agent_path == NULL)
78                 return -ESRCH;
79
80         if (agent_watch > 0)
81                 g_dbus_remove_watch(connection, agent_watch);
82
83         agent_free();
84
85         return 0;
86 }
87
88 int __connman_agent_request_passphrase(struct connman_service *service,
89                                 passphrase_cb_t callback, void *user_data)
90 {
91         DBusMessage *message;
92         const char *path;
93
94         DBG("service %p", service);
95
96         if (agent_path == NULL)
97                 return -ESRCH;
98
99         message = dbus_message_new_method_call(agent_sender, agent_path,
100                                 CONNMAN_AGENT_INTERFACE, "RequestPassphrase");
101         if (message == NULL)
102                 return -ENOMEM;
103
104         dbus_message_set_no_reply(message, TRUE);
105
106         path = __connman_service_get_path(service);
107
108         dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &path,
109                                                         DBUS_TYPE_INVALID);
110
111         g_dbus_send_message(connection, message);
112
113         return -EIO;
114 }
115
116 struct request_input_reply {
117         struct connman_service *service;
118         passphrase_cb_t callback;
119         void *user_data;
120 };
121
122 static void request_input_passphrase_reply(DBusPendingCall *call, void *user_data)
123 {
124         struct request_input_reply *passphrase_reply = user_data;
125         char *passphrase = NULL;
126         char *key;
127         DBusMessageIter iter, dict;
128         DBusMessage *reply = dbus_pending_call_steal_reply(call);
129
130         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
131                 goto done;
132
133         dbus_message_iter_init(reply, &iter);
134         dbus_message_iter_recurse(&iter, &dict);
135         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
136                 DBusMessageIter entry, value;
137
138                 dbus_message_iter_recurse(&dict, &entry);
139                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
140                         break;
141
142                 dbus_message_iter_get_basic(&entry, &key);
143                 if (g_str_equal(key, "Passphrase")) {
144                         dbus_message_iter_next(&entry);
145                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
146                                 break;
147                         dbus_message_iter_recurse(&entry, &value);
148                         dbus_message_iter_get_basic(&value, &passphrase);
149                         break;
150                 }
151                 dbus_message_iter_next(&dict);
152         }
153
154 done:
155         passphrase_reply->callback(passphrase_reply->service,
156                                 passphrase, passphrase_reply->user_data);
157         connman_service_unref(passphrase_reply->service);
158         dbus_message_unref(reply);
159         g_free(passphrase_reply);
160 }
161
162 static void request_input_append_passphrase(DBusMessageIter *iter, void *user_data)
163 {
164         struct connman_service *service = user_data;
165         char *value;
166
167         switch (__connman_service_get_security(service)) {
168         case CONNMAN_SERVICE_SECURITY_WEP:
169                 value = "wep";
170                 break;
171         case CONNMAN_SERVICE_SECURITY_PSK:
172                 value = "psk";
173                 break;
174         default:
175                 value = "string";
176                 break;
177         }
178         connman_dbus_dict_append_basic(iter, "Type",
179                                 DBUS_TYPE_STRING, &value);
180         value = "Mandatory";
181         connman_dbus_dict_append_basic(iter, "Requirement",
182                                 DBUS_TYPE_STRING, &value);
183 }
184
185 int __connman_agent_request_input(struct connman_service *service,
186                                 passphrase_cb_t callback, void *user_data)
187 {
188         DBusMessage *message;
189         const char *path;
190         DBusMessageIter iter;
191         DBusMessageIter dict;
192         DBusPendingCall *call;
193         struct request_input_reply *passphrase_reply;
194
195         if (service == NULL || agent_path == NULL || callback == NULL)
196                 return -ESRCH;
197
198         message = dbus_message_new_method_call(agent_sender, agent_path,
199                                         CONNMAN_AGENT_INTERFACE,
200                                         "RequestInput");
201         if (message == NULL)
202                 return -ENOMEM;
203
204         dbus_message_iter_init_append(message, &iter);
205
206         path = __connman_service_get_path(service);
207         dbus_message_iter_append_basic(&iter,
208                                 DBUS_TYPE_OBJECT_PATH, &path);
209
210         connman_dbus_dict_open(&iter, &dict);
211         connman_dbus_dict_append_dict(&dict, "Passphrase",
212                                 request_input_append_passphrase, service);
213         connman_dbus_dict_close(&iter, &dict);
214
215         passphrase_reply = g_try_new0(struct request_input_reply, 1);
216         if (passphrase_reply == NULL) {
217                 dbus_message_unref(message);
218                 return -ENOMEM;
219         }
220
221         if (dbus_connection_send_with_reply(connection, message,
222                                                 &call, -1) == FALSE) {
223                 dbus_message_unref(message);
224                 g_free(passphrase_reply);
225                 return -ESRCH;
226         }
227
228         if (call == NULL) {
229                 dbus_message_unref(message);
230                 g_free(passphrase_reply);
231                 return -ESRCH;
232         }
233
234         passphrase_reply->service = connman_service_ref(service);
235         passphrase_reply->callback = callback;
236         passphrase_reply->user_data = user_data;
237
238         dbus_pending_call_set_notify(call, request_input_passphrase_reply,
239                                 passphrase_reply, NULL);
240
241         dbus_message_unref(message);
242
243         return -EIO;
244 }
245
246 int __connman_agent_init(void)
247 {
248         DBG("");
249
250         connection = connman_dbus_get_connection();
251         if (connection == NULL)
252                 return -1;
253
254         return 0;
255 }
256
257 void __connman_agent_cleanup(void)
258 {
259         DBusMessage *message;
260
261         DBG("");
262
263         if (connection == NULL)
264                 return;
265
266         if (agent_watch > 0)
267                 g_dbus_remove_watch(connection, agent_watch);
268
269         if (agent_path == NULL)
270                 return;
271
272         message = dbus_message_new_method_call(agent_sender, agent_path,
273                                         CONNMAN_AGENT_INTERFACE, "Release");
274         if (message == NULL)
275                 return;
276
277         dbus_message_set_no_reply(message, TRUE);
278
279         g_dbus_send_message(connection, message);
280
281         agent_free();
282
283         dbus_connection_unref(connection);
284 }