b2049a3d361416a143b21260dc2854ec01348f12
[platform/upstream/connman.git] / src / agent-connman.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2012-2013  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 #include <connman/agent.h>
32 #include <connman/setting.h>
33 #include <connman/service.h>
34
35 #include "connman.h"
36
37 static bool check_reply_has_dict(DBusMessage *reply)
38 {
39         const char *signature = DBUS_TYPE_ARRAY_AS_STRING
40                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
41                 DBUS_TYPE_STRING_AS_STRING
42                 DBUS_TYPE_VARIANT_AS_STRING
43                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
44
45         if (dbus_message_has_signature(reply, signature))
46                 return true;
47
48         connman_warn("Reply %s to %s from %s has wrong signature %s",
49                         signature,
50                         dbus_message_get_interface(reply),
51                         dbus_message_get_sender(reply),
52                         dbus_message_get_signature(reply));
53
54         return false;
55 }
56
57 struct request_input_reply {
58         struct connman_service *service;
59         struct connman_peer *peer;
60         union {
61                 authentication_cb_t service_callback;
62                 peer_wps_cb_t peer_callback;
63         };
64         bool wps_requested;
65         void *user_data;
66 };
67
68 static void request_input_passphrase_reply(DBusMessage *reply, void *user_data)
69 {
70         struct request_input_reply *passphrase_reply = user_data;
71         bool values_received = false;
72         bool wps = false;
73         const char *error = NULL;
74         char *identity = NULL;
75         char *passphrase = NULL;
76         char *wpspin = NULL;
77         char *key;
78         char *name = NULL;
79         int name_len = 0;
80         DBusMessageIter iter, dict;
81
82         if (!reply)
83                 goto out;
84
85         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
86                 error = dbus_message_get_error_name(reply);
87                 goto done;
88         }
89
90         if (!check_reply_has_dict(reply))
91                 goto done;
92
93         values_received = true;
94
95         dbus_message_iter_init(reply, &iter);
96         dbus_message_iter_recurse(&iter, &dict);
97         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
98                 DBusMessageIter entry, value;
99
100                 dbus_message_iter_recurse(&dict, &entry);
101                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
102                         break;
103
104                 dbus_message_iter_get_basic(&entry, &key);
105
106                 if (g_str_equal(key, "Identity")) {
107                         dbus_message_iter_next(&entry);
108                         if (dbus_message_iter_get_arg_type(&entry)
109                                                         != DBUS_TYPE_VARIANT)
110                                 break;
111                         dbus_message_iter_recurse(&entry, &value);
112                         dbus_message_iter_get_basic(&value, &identity);
113
114                 } else if (g_str_equal(key, "Passphrase")) {
115                         dbus_message_iter_next(&entry);
116                         if (dbus_message_iter_get_arg_type(&entry)
117                                                         != DBUS_TYPE_VARIANT)
118                                 break;
119                         dbus_message_iter_recurse(&entry, &value);
120                         dbus_message_iter_get_basic(&value, &passphrase);
121
122                 } else if (g_str_equal(key, "WPS")) {
123                         wps = true;
124
125                         dbus_message_iter_next(&entry);
126                         if (dbus_message_iter_get_arg_type(&entry)
127                                                         != DBUS_TYPE_VARIANT)
128                                 break;
129                         dbus_message_iter_recurse(&entry, &value);
130                         dbus_message_iter_get_basic(&value, &wpspin);
131                         break;
132                 } else if (g_str_equal(key, "Name")) {
133                         dbus_message_iter_next(&entry);
134                         if (dbus_message_iter_get_arg_type(&entry)
135                                                         != DBUS_TYPE_VARIANT)
136                                 break;
137                         dbus_message_iter_recurse(&entry, &value);
138                         dbus_message_iter_get_basic(&value, &name);
139                         name_len = strlen(name);
140                 } else if (g_str_equal(key, "SSID")) {
141                         dbus_message_iter_next(&entry);
142                         if (dbus_message_iter_get_arg_type(&entry)
143                                                         != DBUS_TYPE_VARIANT)
144                                 break;
145                         dbus_message_iter_recurse(&entry, &value);
146                         if (dbus_message_iter_get_arg_type(&value)
147                                                         != DBUS_TYPE_VARIANT)
148                                 break;
149                         if (dbus_message_iter_get_element_type(&value)
150                                                         != DBUS_TYPE_VARIANT)
151                                 break;
152                         dbus_message_iter_get_fixed_array(&value, &name,
153                                                         &name_len);
154                 }
155                 dbus_message_iter_next(&dict);
156         }
157
158 done:
159         passphrase_reply->service_callback(passphrase_reply->service,
160                                         values_received, name, name_len,
161                                         identity, passphrase, wps, wpspin,
162                                         error, passphrase_reply->user_data);
163 out:
164         g_free(passphrase_reply);
165 }
166
167 static void request_input_append_alternates(DBusMessageIter *iter,
168                                                         void *user_data)
169 {
170         const char *str = user_data;
171         char **alternates, **alternative;
172
173         if (!str)
174                 return;
175
176         alternates = g_strsplit(str, ",", 0);
177         if (!alternates)
178                 return;
179
180         for (alternative = alternates; *alternative; alternative++)
181                 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
182                                                                 alternative);
183
184         g_strfreev(alternates);
185 }
186
187 static void request_input_append_identity(DBusMessageIter *iter,
188                                                         void *user_data)
189 {
190         char *str = "string";
191
192         connman_dbus_dict_append_basic(iter, "Type",
193                                 DBUS_TYPE_STRING, &str);
194         str = "mandatory";
195         connman_dbus_dict_append_basic(iter, "Requirement",
196                                 DBUS_TYPE_STRING, &str);
197 }
198
199 static void request_input_append_passphrase(DBusMessageIter *iter,
200                                                         void *user_data)
201 {
202         struct connman_service *service = user_data;
203         char *value;
204         const char *phase2;
205
206         switch (__connman_service_get_security(service)) {
207         case CONNMAN_SERVICE_SECURITY_WEP:
208                 value = "wep";
209                 break;
210         case CONNMAN_SERVICE_SECURITY_PSK:
211                 value = "psk";
212                 break;
213         case CONNMAN_SERVICE_SECURITY_8021X:
214                 phase2 = __connman_service_get_phase2(service);
215
216                 if (phase2 && (
217                                 g_str_has_suffix(phase2, "GTC") ||
218                                 g_str_has_suffix(phase2, "OTP")))
219                         value = "response";
220                 else
221                         value = "passphrase";
222
223                 break;
224         default:
225                 value = "string";
226                 break;
227         }
228         connman_dbus_dict_append_basic(iter, "Type",
229                                 DBUS_TYPE_STRING, &value);
230         value = "mandatory";
231         connman_dbus_dict_append_basic(iter, "Requirement",
232                                 DBUS_TYPE_STRING, &value);
233
234         if (__connman_service_wps_enabled(service)) {
235                 connman_dbus_dict_append_array(iter, "Alternates",
236                                         DBUS_TYPE_STRING,
237                                         request_input_append_alternates,
238                                         "WPS");
239         }
240 }
241
242 struct request_wps_data {
243         bool peer;
244 };
245
246 static void request_input_append_wps(DBusMessageIter *iter, void *user_data)
247 {
248         struct request_wps_data *wps = user_data;
249         const char *str = "wpspin";
250
251         connman_dbus_dict_append_basic(iter, "Type",
252                                 DBUS_TYPE_STRING, &str);
253         if (wps && wps->peer)
254                 str = "mandatory";
255         else
256                 str = "alternate";
257         connman_dbus_dict_append_basic(iter, "Requirement",
258                                 DBUS_TYPE_STRING, &str);
259 }
260
261 static void request_input_append_name(DBusMessageIter *iter, void *user_data)
262 {
263         const char *str = "string";
264
265         connman_dbus_dict_append_basic(iter, "Type",
266                                 DBUS_TYPE_STRING, &str);
267         str = "mandatory";
268         connman_dbus_dict_append_basic(iter, "Requirement",
269                                 DBUS_TYPE_STRING, &str);
270         connman_dbus_dict_append_array(iter, "Alternates",
271                                 DBUS_TYPE_STRING,
272                                 request_input_append_alternates,
273                                 "SSID");
274 }
275
276 static void request_input_append_ssid(DBusMessageIter *iter, void *user_data)
277 {
278         const char *str = "ssid";
279
280         connman_dbus_dict_append_basic(iter, "Type",
281                                 DBUS_TYPE_STRING, &str);
282         str = "alternate";
283         connman_dbus_dict_append_basic(iter, "Requirement",
284                                 DBUS_TYPE_STRING, &str);
285 }
286
287 static void request_input_append_password(DBusMessageIter *iter,
288                                                         void *user_data)
289 {
290         char *str = "passphrase";
291
292         connman_dbus_dict_append_basic(iter, "Type",
293                                 DBUS_TYPE_STRING, &str);
294         str = "mandatory";
295         connman_dbus_dict_append_basic(iter, "Requirement",
296                                 DBUS_TYPE_STRING, &str);
297 }
298
299 struct previous_passphrase_data {
300         const char *passphrase;
301         const char *type;
302 };
303
304 static void request_input_append_previouspassphrase(DBusMessageIter *iter,
305                                                         void *user_data)
306 {
307         struct previous_passphrase_data *data = user_data;
308         const char *requirement = "informational";
309
310         connman_dbus_dict_append_basic(iter, "Type",
311                                 DBUS_TYPE_STRING, &data->type);
312
313         connman_dbus_dict_append_basic(iter, "Requirement",
314                                 DBUS_TYPE_STRING, &requirement);
315
316         connman_dbus_dict_append_basic(iter, "Value",
317                                 DBUS_TYPE_STRING, &data->passphrase);
318 }
319
320 static void previous_passphrase_handler(DBusMessageIter *iter,
321                                         struct connman_service *service)
322 {
323         enum connman_service_security security;
324         struct previous_passphrase_data data;
325         struct connman_network *network;
326
327         network = __connman_service_get_network(service);
328         data.passphrase = connman_network_get_string(network, "WiFi.PinWPS");
329
330         if (connman_network_get_bool(network, "WiFi.UseWPS") &&
331                                                 data.passphrase) {
332                 data.type = "wpspin";
333         } else {
334                 data.passphrase = __connman_service_get_passphrase(service);
335                 if (!data.passphrase)
336                         return;
337
338                 security = __connman_service_get_security(service);
339                 switch (security) {
340                 case CONNMAN_SERVICE_SECURITY_WEP:
341                         data.type = "wep";
342                         break;
343                 case CONNMAN_SERVICE_SECURITY_PSK:
344                         data.type  = "psk";
345                         break;
346                 /*
347                  * This should never happen: no passphrase is set if security
348                  * is not one of the above. */
349                 default:
350                         break;
351                 }
352         }
353
354         connman_dbus_dict_append_dict(iter, "PreviousPassphrase",
355                         request_input_append_previouspassphrase, &data);
356 }
357
358 static void request_input_login_reply(DBusMessage *reply, void *user_data)
359 {
360         struct request_input_reply *username_password_reply = user_data;
361         const char *error = NULL;
362         bool values_received = false;
363         char *username = NULL;
364         char *password = NULL;
365         char *key;
366         DBusMessageIter iter, dict;
367
368         if (!reply)
369                 goto out;
370
371         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
372                 error = dbus_message_get_error_name(reply);
373                 goto done;
374         }
375
376         if (!check_reply_has_dict(reply))
377                 goto done;
378
379         values_received = true;
380
381         dbus_message_iter_init(reply, &iter);
382         dbus_message_iter_recurse(&iter, &dict);
383         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
384                 DBusMessageIter entry, value;
385
386                 dbus_message_iter_recurse(&dict, &entry);
387                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
388                         break;
389
390                 dbus_message_iter_get_basic(&entry, &key);
391
392                 if (g_str_equal(key, "Username")) {
393                         dbus_message_iter_next(&entry);
394                         if (dbus_message_iter_get_arg_type(&entry)
395                                                         != DBUS_TYPE_VARIANT)
396                                 break;
397                         dbus_message_iter_recurse(&entry, &value);
398                         dbus_message_iter_get_basic(&value, &username);
399
400                 } else if (g_str_equal(key, "Password")) {
401                         dbus_message_iter_next(&entry);
402                         if (dbus_message_iter_get_arg_type(&entry) !=
403                                                         DBUS_TYPE_VARIANT)
404                                 break;
405                         dbus_message_iter_recurse(&entry, &value);
406                         dbus_message_iter_get_basic(&value, &password);
407                 }
408
409                 dbus_message_iter_next(&dict);
410         }
411
412 done:
413         username_password_reply->service_callback(
414                         username_password_reply->service, values_received,
415                         NULL, 0, username, password, FALSE, NULL, error,
416                         username_password_reply->user_data);
417 out:
418         g_free(username_password_reply);
419 }
420
421 int __connman_agent_request_passphrase_input(struct connman_service *service,
422                                 authentication_cb_t callback,
423                                 const char *dbus_sender, void *user_data)
424 {
425         DBusMessage *message;
426         const char *path, *agent_sender, *agent_path;
427         DBusMessageIter iter;
428         DBusMessageIter dict;
429         struct request_input_reply *passphrase_reply;
430         int err;
431         void *agent;
432
433         agent = connman_agent_get_info(dbus_sender, &agent_sender,
434                                                         &agent_path);
435
436         DBG("agent %p service %p path %s", agent, service, agent_path);
437
438         if (!service || !agent || !agent_path || !callback)
439                 return -ESRCH;
440
441         message = dbus_message_new_method_call(agent_sender, agent_path,
442                                         CONNMAN_AGENT_INTERFACE,
443                                         "RequestInput");
444         if (!message)
445                 return -ENOMEM;
446
447         dbus_message_iter_init_append(message, &iter);
448
449         path = __connman_service_get_path(service);
450         dbus_message_iter_append_basic(&iter,
451                                 DBUS_TYPE_OBJECT_PATH, &path);
452
453         connman_dbus_dict_open(&iter, &dict);
454
455         if (__connman_service_is_hidden(service)) {
456                 connman_dbus_dict_append_dict(&dict, "Name",
457                                         request_input_append_name, NULL);
458                 connman_dbus_dict_append_dict(&dict, "SSID",
459                                         request_input_append_ssid, NULL);
460         }
461
462         if (__connman_service_get_security(service) ==
463                         CONNMAN_SERVICE_SECURITY_8021X) {
464                 connman_dbus_dict_append_dict(&dict, "Identity",
465                                         request_input_append_identity, service);
466         }
467
468         if (__connman_service_get_security(service) !=
469                         CONNMAN_SERVICE_SECURITY_NONE) {
470                 connman_dbus_dict_append_dict(&dict, "Passphrase",
471                                 request_input_append_passphrase, service);
472
473                 previous_passphrase_handler(&dict, service);
474         }
475
476         if (__connman_service_wps_enabled(service))
477                 connman_dbus_dict_append_dict(&dict, "WPS",
478                                 request_input_append_wps, NULL);
479
480         connman_dbus_dict_close(&iter, &dict);
481
482         passphrase_reply = g_try_new0(struct request_input_reply, 1);
483         if (!passphrase_reply) {
484                 dbus_message_unref(message);
485                 return -ENOMEM;
486         }
487
488         passphrase_reply->service = service;
489         passphrase_reply->service_callback = callback;
490         passphrase_reply->user_data = user_data;
491
492         err = connman_agent_queue_message(service, message,
493                         connman_timeout_input_request(),
494                         request_input_passphrase_reply,
495                         passphrase_reply, agent);
496
497         if (err < 0 && err != -EBUSY) {
498                 DBG("error %d sending agent message", err);
499                 dbus_message_unref(message);
500                 g_free(passphrase_reply);
501                 return err;
502         }
503
504         dbus_message_unref(message);
505
506         return -EINPROGRESS;
507 }
508
509 int __connman_agent_request_login_input(struct connman_service *service,
510                                 authentication_cb_t callback, void *user_data)
511 {
512         DBusMessage *message;
513         const char *path, *agent_sender, *agent_path;
514         DBusMessageIter iter;
515         DBusMessageIter dict;
516         struct request_input_reply *username_password_reply;
517         int err;
518         void *agent;
519
520         agent = connman_agent_get_info(NULL, &agent_sender, &agent_path);
521
522         if (!service || !agent || !agent_path || !callback)
523                 return -ESRCH;
524
525         message = dbus_message_new_method_call(agent_sender, agent_path,
526                                         CONNMAN_AGENT_INTERFACE,
527                                         "RequestInput");
528         if (!message)
529                 return -ENOMEM;
530
531         dbus_message_iter_init_append(message, &iter);
532
533         path = __connman_service_get_path(service);
534         dbus_message_iter_append_basic(&iter,
535                                 DBUS_TYPE_OBJECT_PATH, &path);
536
537         connman_dbus_dict_open(&iter, &dict);
538
539         connman_dbus_dict_append_dict(&dict, "Username",
540                                 request_input_append_identity, service);
541
542         connman_dbus_dict_append_dict(&dict, "Password",
543                                 request_input_append_password, service);
544
545         connman_dbus_dict_close(&iter, &dict);
546
547         username_password_reply = g_try_new0(struct request_input_reply, 1);
548         if (!username_password_reply) {
549                 dbus_message_unref(message);
550                 return -ENOMEM;
551         }
552
553         username_password_reply->service = service;
554         username_password_reply->service_callback = callback;
555         username_password_reply->user_data = user_data;
556
557         err = connman_agent_queue_message(service, message,
558                         connman_timeout_input_request(),
559                         request_input_login_reply, username_password_reply,
560                         agent);
561         if (err < 0 && err != -EBUSY) {
562                 DBG("error %d sending agent request", err);
563                 dbus_message_unref(message);
564                 g_free(username_password_reply);
565                 return err;
566         }
567
568         dbus_message_unref(message);
569
570         return -EINPROGRESS;
571 }
572
573 struct request_browser_reply_data {
574         struct connman_service *service;
575         browser_authentication_cb_t callback;
576         void *user_data;
577 };
578
579 static void request_browser_reply(DBusMessage *reply, void *user_data)
580 {
581         struct request_browser_reply_data *browser_reply_data = user_data;
582         bool result = false;
583         const char *error = NULL;
584
585         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
586                 error = dbus_message_get_error_name(reply);
587                 goto done;
588         }
589
590         result = true;
591
592 done:
593         browser_reply_data->callback(browser_reply_data->service, result,
594                                         error, browser_reply_data->user_data);
595         g_free(browser_reply_data);
596 }
597
598 int __connman_agent_request_browser(struct connman_service *service,
599                                 browser_authentication_cb_t callback,
600                                 const char *url, void *user_data)
601 {
602         struct request_browser_reply_data *browser_reply_data;
603         DBusMessage *message;
604         DBusMessageIter iter;
605         const char *path, *agent_sender, *agent_path;
606         int err;
607         void *agent;
608
609         agent = connman_agent_get_info(NULL, &agent_sender, &agent_path);
610
611         if (!service || !agent || !agent_path || !callback)
612                 return -ESRCH;
613
614         if (!url)
615                 url = "";
616
617         message = dbus_message_new_method_call(agent_sender, agent_path,
618                                         CONNMAN_AGENT_INTERFACE,
619                                         "RequestBrowser");
620         if (!message)
621                 return -ENOMEM;
622
623         dbus_message_iter_init_append(message, &iter);
624
625         path = __connman_service_get_path(service);
626         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
627
628         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &url);
629
630         browser_reply_data = g_try_new0(struct request_browser_reply_data, 1);
631         if (!browser_reply_data) {
632                 dbus_message_unref(message);
633                 return -ENOMEM;
634         }
635
636         browser_reply_data->service = service;
637         browser_reply_data->callback = callback;
638         browser_reply_data->user_data = user_data;
639
640         err = connman_agent_queue_message(service, message,
641                                 connman_timeout_browser_launch(),
642                                 request_browser_reply, browser_reply_data,
643                                 agent);
644
645         if (err < 0 && err != -EBUSY) {
646                 DBG("error %d sending browser request", err);
647                 dbus_message_unref(message);
648                 g_free(browser_reply_data);
649                 return err;
650         }
651
652         dbus_message_unref(message);
653
654         return -EINPROGRESS;
655 }
656
657 int __connman_agent_report_peer_error(struct connman_peer *peer,
658                                         const char *path, const char *error,
659                                         report_error_cb_t callback,
660                                         const char *dbus_sender,
661                                         void *user_data)
662 {
663         return connman_agent_report_error_full(peer, path, "ReportPeerError",
664                                 error, callback, dbus_sender, user_data);
665 }
666
667 static void request_peer_authorization_reply(DBusMessage *reply,
668                                                         void *user_data)
669 {
670         struct request_input_reply *auth_reply = user_data;
671         DBusMessageIter iter, dict;
672         const char *error = NULL;
673         bool choice_done = false;
674         char *wpspin = NULL;
675         char *key;
676
677         if (!reply)
678                 goto out;
679
680         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
681                 error = dbus_message_get_error_name(reply);
682                 goto done;
683         }
684
685         if (!check_reply_has_dict(reply))
686                 goto done;
687
688         dbus_message_iter_init(reply, &iter);
689         dbus_message_iter_recurse(&iter, &dict);
690         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
691                 DBusMessageIter entry, value;
692
693                 dbus_message_iter_recurse(&dict, &entry);
694                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
695                         break;
696
697                 dbus_message_iter_get_basic(&entry, &key);
698
699                 if (g_str_equal(key, "WPS")) {
700                         choice_done = true;
701
702                         dbus_message_iter_next(&entry);
703                         if (dbus_message_iter_get_arg_type(&entry)
704                                                         != DBUS_TYPE_VARIANT)
705                                 break;
706                         dbus_message_iter_recurse(&entry, &value);
707                         dbus_message_iter_get_basic(&value, &wpspin);
708                         break;
709                 }
710                 dbus_message_iter_next(&dict);
711         }
712
713         if (!auth_reply->wps_requested)
714                 choice_done = true;
715
716 done:
717         auth_reply->peer_callback(auth_reply->peer, choice_done, wpspin,
718                                                 error, auth_reply->user_data);
719 out:
720         g_free(auth_reply);
721 }
722
723 int __connman_agent_request_peer_authorization(struct connman_peer *peer,
724                                                 peer_wps_cb_t callback,
725                                                 bool wps_requested,
726                                                 const char *dbus_sender,
727                                                 void *user_data)
728 {
729         struct request_wps_data wps = { .peer = true };
730         const char *path, *agent_sender, *agent_path;
731         struct request_input_reply *auth_reply;
732         DBusMessageIter dict, iter;
733         DBusMessage *message;
734         void *agent;
735         int err;
736
737         agent = connman_agent_get_info(dbus_sender, &agent_sender,
738                                                         &agent_path);
739         DBG("agent %p peer %p path %s", agent, peer, agent_path);
740
741         if (!peer || !agent || !agent_path || !callback)
742                 return -ESRCH;
743
744         message = dbus_message_new_method_call(agent_sender, agent_path,
745                         CONNMAN_AGENT_INTERFACE, "RequestPeerAuthorization");
746         if (!message)
747                 return -ENOMEM;
748
749         dbus_message_iter_init_append(message, &iter);
750
751         path = __connman_peer_get_path(peer);
752         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
753
754         connman_dbus_dict_open(&iter, &dict);
755
756         if (wps_requested)
757                 connman_dbus_dict_append_dict(&dict, "WPS",
758                                         request_input_append_wps, &wps);
759
760         connman_dbus_dict_close(&iter, &dict);
761
762         auth_reply = g_try_new0(struct request_input_reply, 1);
763         if (!auth_reply) {
764                 dbus_message_unref(message);
765                 return -ENOMEM;
766         }
767
768         auth_reply->peer = peer;
769         auth_reply->peer_callback = callback;
770         auth_reply->wps_requested = wps_requested;
771         auth_reply->user_data = user_data;
772
773         err = connman_agent_queue_message(peer, message,
774                                         connman_timeout_input_request(),
775                                         request_peer_authorization_reply,
776                                         auth_reply, agent);
777         if (err < 0 && err != -EBUSY) {
778                 DBG("error %d sending agent message", err);
779                 dbus_message_unref(message);
780                 g_free(auth_reply);
781                 return err;
782         }
783
784         dbus_message_unref(message);
785
786         return -EINPROGRESS;
787 }