1214501Srpaulo/*
2214501Srpaulo * WPA Supplicant / dbus-based control interface (WPS)
3214501Srpaulo * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4214501Srpaulo * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
5214501Srpaulo *
6252190Srpaulo * This software may be distributed under the terms of the BSD license.
7252190Srpaulo * See README for more details.
8214501Srpaulo */
9214501Srpaulo
10214501Srpaulo#include "includes.h"
11214501Srpaulo
12214501Srpaulo#include "common.h"
13214501Srpaulo#include "../config.h"
14214501Srpaulo#include "../wpa_supplicant_i.h"
15214501Srpaulo#include "../wps_supplicant.h"
16252190Srpaulo#include "../driver_i.h"
17252190Srpaulo#include "../ap.h"
18214501Srpaulo#include "dbus_new_helpers.h"
19214501Srpaulo#include "dbus_new.h"
20214501Srpaulo#include "dbus_new_handlers.h"
21214501Srpaulo#include "dbus_dict_helpers.h"
22214501Srpaulo
23214501Srpaulo
24214501Srpaulostruct wps_start_params {
25214501Srpaulo	int role; /* 0 - not set, 1 - enrollee, 2 - registrar */
26214501Srpaulo	int type; /* 0 - not set, 1 - pin,      2 - pbc       */
27214501Srpaulo	u8 *bssid;
28214501Srpaulo	char *pin;
29252190Srpaulo	u8 *p2p_dev_addr;
30214501Srpaulo};
31214501Srpaulo
32214501Srpaulo
33214501Srpaulostatic int wpas_dbus_handler_wps_role(DBusMessage *message,
34214501Srpaulo				      DBusMessageIter *entry_iter,
35214501Srpaulo				      struct wps_start_params *params,
36214501Srpaulo				      DBusMessage **reply)
37214501Srpaulo{
38214501Srpaulo	DBusMessageIter variant_iter;
39214501Srpaulo	char *val;
40214501Srpaulo
41214501Srpaulo	dbus_message_iter_recurse(entry_iter, &variant_iter);
42214501Srpaulo	if (dbus_message_iter_get_arg_type(&variant_iter) !=
43214501Srpaulo	    DBUS_TYPE_STRING) {
44214501Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, "
45214501Srpaulo			   "string required");
46214501Srpaulo		*reply = wpas_dbus_error_invalid_args(message,
47214501Srpaulo						      "Role must be a string");
48214501Srpaulo		return -1;
49214501Srpaulo	}
50214501Srpaulo	dbus_message_iter_get_basic(&variant_iter, &val);
51214501Srpaulo	if (os_strcmp(val, "enrollee") == 0)
52214501Srpaulo		params->role = 1;
53214501Srpaulo	else if (os_strcmp(val, "registrar") == 0)
54214501Srpaulo		params->role = 2;
55214501Srpaulo	else {
56214501Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Uknown role %s", val);
57214501Srpaulo		*reply = wpas_dbus_error_invalid_args(message, val);
58214501Srpaulo		return -1;
59214501Srpaulo	}
60214501Srpaulo	return 0;
61214501Srpaulo}
62214501Srpaulo
63214501Srpaulo
64214501Srpaulostatic int wpas_dbus_handler_wps_type(DBusMessage *message,
65214501Srpaulo				      DBusMessageIter *entry_iter,
66214501Srpaulo				      struct wps_start_params *params,
67214501Srpaulo				      DBusMessage **reply)
68214501Srpaulo{
69214501Srpaulo	DBusMessageIter variant_iter;
70214501Srpaulo	char *val;
71214501Srpaulo
72214501Srpaulo	dbus_message_iter_recurse(entry_iter, &variant_iter);
73214501Srpaulo	if (dbus_message_iter_get_arg_type(&variant_iter) !=
74214501Srpaulo	    DBUS_TYPE_STRING) {
75214501Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, "
76214501Srpaulo			   "string required");
77214501Srpaulo		*reply = wpas_dbus_error_invalid_args(message,
78214501Srpaulo						      "Type must be a string");
79214501Srpaulo		return -1;
80214501Srpaulo	}
81214501Srpaulo	dbus_message_iter_get_basic(&variant_iter, &val);
82214501Srpaulo	if (os_strcmp(val, "pin") == 0)
83214501Srpaulo		params->type = 1;
84214501Srpaulo	else if (os_strcmp(val, "pbc") == 0)
85214501Srpaulo		params->type = 2;
86214501Srpaulo	else {
87214501Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Unknown type %s",
88214501Srpaulo			   val);
89214501Srpaulo		*reply = wpas_dbus_error_invalid_args(message, val);
90214501Srpaulo		return -1;
91214501Srpaulo	}
92214501Srpaulo	return 0;
93214501Srpaulo}
94214501Srpaulo
95214501Srpaulo
96214501Srpaulostatic int wpas_dbus_handler_wps_bssid(DBusMessage *message,
97214501Srpaulo				       DBusMessageIter *entry_iter,
98214501Srpaulo				       struct wps_start_params *params,
99214501Srpaulo				       DBusMessage **reply)
100214501Srpaulo{
101214501Srpaulo	DBusMessageIter variant_iter, array_iter;
102214501Srpaulo	int len;
103214501Srpaulo
104214501Srpaulo	dbus_message_iter_recurse(entry_iter, &variant_iter);
105214501Srpaulo	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
106214501Srpaulo	    dbus_message_iter_get_element_type(&variant_iter) !=
107252190Srpaulo	    DBUS_TYPE_BYTE) {
108214501Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, "
109214501Srpaulo			   "byte array required");
110214501Srpaulo		*reply = wpas_dbus_error_invalid_args(
111214501Srpaulo			message, "Bssid must be a byte array");
112214501Srpaulo		return -1;
113214501Srpaulo	}
114214501Srpaulo	dbus_message_iter_recurse(&variant_iter, &array_iter);
115214501Srpaulo	dbus_message_iter_get_fixed_array(&array_iter, &params->bssid, &len);
116214501Srpaulo	if (len != ETH_ALEN) {
117214501Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length "
118214501Srpaulo			   "%d", len);
119214501Srpaulo		*reply = wpas_dbus_error_invalid_args(message,
120214501Srpaulo						      "Bssid is wrong length");
121214501Srpaulo		return -1;
122214501Srpaulo	}
123214501Srpaulo	return 0;
124214501Srpaulo}
125214501Srpaulo
126214501Srpaulo
127214501Srpaulostatic int wpas_dbus_handler_wps_pin(DBusMessage *message,
128214501Srpaulo				     DBusMessageIter *entry_iter,
129214501Srpaulo				     struct wps_start_params *params,
130214501Srpaulo				     DBusMessage **reply)
131214501Srpaulo{
132214501Srpaulo	DBusMessageIter variant_iter;
133214501Srpaulo
134214501Srpaulo	dbus_message_iter_recurse(entry_iter, &variant_iter);
135214501Srpaulo	if (dbus_message_iter_get_arg_type(&variant_iter) !=
136214501Srpaulo	    DBUS_TYPE_STRING) {
137214501Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, "
138214501Srpaulo			   "string required");
139214501Srpaulo		*reply = wpas_dbus_error_invalid_args(message,
140214501Srpaulo						      "Pin must be a string");
141214501Srpaulo		return -1;
142214501Srpaulo	}
143214501Srpaulo	dbus_message_iter_get_basic(&variant_iter, &params->pin);
144214501Srpaulo	return 0;
145214501Srpaulo}
146214501Srpaulo
147214501Srpaulo
148252190Srpaulo#ifdef CONFIG_P2P
149252190Srpaulostatic int wpas_dbus_handler_wps_p2p_dev_addr(DBusMessage *message,
150252190Srpaulo					      DBusMessageIter *entry_iter,
151252190Srpaulo					      struct wps_start_params *params,
152252190Srpaulo					      DBusMessage **reply)
153252190Srpaulo{
154252190Srpaulo	DBusMessageIter variant_iter, array_iter;
155252190Srpaulo	int len;
156252190Srpaulo
157252190Srpaulo	dbus_message_iter_recurse(entry_iter, &variant_iter);
158252190Srpaulo	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
159252190Srpaulo	    dbus_message_iter_get_element_type(&variant_iter) !=
160252190Srpaulo	    DBUS_TYPE_BYTE) {
161252190Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
162252190Srpaulo			   "P2PDeviceAddress type, byte array required");
163252190Srpaulo		*reply = wpas_dbus_error_invalid_args(
164252190Srpaulo			message, "P2PDeviceAddress must be a byte array");
165252190Srpaulo		return -1;
166252190Srpaulo	}
167252190Srpaulo	dbus_message_iter_recurse(&variant_iter, &array_iter);
168252190Srpaulo	dbus_message_iter_get_fixed_array(&array_iter, &params->p2p_dev_addr,
169252190Srpaulo					  &len);
170252190Srpaulo	if (len != ETH_ALEN) {
171252190Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
172252190Srpaulo			   "P2PDeviceAddress length %d", len);
173252190Srpaulo		*reply = wpas_dbus_error_invalid_args(message,
174252190Srpaulo						      "P2PDeviceAddress "
175252190Srpaulo						      "has wrong length");
176252190Srpaulo		return -1;
177252190Srpaulo	}
178252190Srpaulo	return 0;
179252190Srpaulo}
180252190Srpaulo#endif /* CONFIG_P2P */
181252190Srpaulo
182252190Srpaulo
183214501Srpaulostatic int wpas_dbus_handler_wps_start_entry(DBusMessage *message, char *key,
184214501Srpaulo					     DBusMessageIter *entry_iter,
185214501Srpaulo					     struct wps_start_params *params,
186214501Srpaulo					     DBusMessage **reply)
187214501Srpaulo{
188214501Srpaulo	if (os_strcmp(key, "Role") == 0)
189214501Srpaulo		return wpas_dbus_handler_wps_role(message, entry_iter,
190214501Srpaulo						  params, reply);
191214501Srpaulo	else if (os_strcmp(key, "Type") == 0)
192214501Srpaulo		return wpas_dbus_handler_wps_type(message, entry_iter,
193214501Srpaulo						  params, reply);
194214501Srpaulo	else if (os_strcmp(key, "Bssid") == 0)
195214501Srpaulo		return wpas_dbus_handler_wps_bssid(message, entry_iter,
196214501Srpaulo						   params, reply);
197214501Srpaulo	else if (os_strcmp(key, "Pin") == 0)
198214501Srpaulo		return wpas_dbus_handler_wps_pin(message, entry_iter,
199214501Srpaulo						 params, reply);
200252190Srpaulo#ifdef CONFIG_P2P
201252190Srpaulo	else if (os_strcmp(key, "P2PDeviceAddress") == 0)
202252190Srpaulo		return wpas_dbus_handler_wps_p2p_dev_addr(message, entry_iter,
203252190Srpaulo							  params, reply);
204252190Srpaulo#endif /* CONFIG_P2P */
205214501Srpaulo
206214501Srpaulo	wpa_printf(MSG_DEBUG, "dbus: WPS.Start - unknown key %s", key);
207214501Srpaulo	*reply = wpas_dbus_error_invalid_args(message, key);
208214501Srpaulo	return -1;
209214501Srpaulo}
210214501Srpaulo
211214501Srpaulo
212214501Srpaulo/**
213214501Srpaulo * wpas_dbus_handler_wps_start - Start WPS configuration
214214501Srpaulo * @message: Pointer to incoming dbus message
215214501Srpaulo * @wpa_s: %wpa_supplicant data structure
216214501Srpaulo * Returns: DBus message dictionary on success or DBus error on failure
217214501Srpaulo *
218214501Srpaulo * Handler for "Start" method call. DBus dictionary argument contains
219214501Srpaulo * information about role (enrollee or registrar), authorization method
220214501Srpaulo * (pin or push button) and optionally pin and bssid. Returned message
221214501Srpaulo * has a dictionary argument which may contain newly generated pin (optional).
222214501Srpaulo */
223214501SrpauloDBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
224214501Srpaulo					  struct wpa_supplicant *wpa_s)
225214501Srpaulo{
226214501Srpaulo	DBusMessage *reply = NULL;
227214501Srpaulo	DBusMessageIter iter, dict_iter, entry_iter;
228214501Srpaulo	struct wps_start_params params;
229214501Srpaulo	char *key;
230214501Srpaulo	char npin[9] = { '\0' };
231214501Srpaulo	int ret;
232214501Srpaulo
233214501Srpaulo	os_memset(&params, 0, sizeof(params));
234214501Srpaulo	dbus_message_iter_init(message, &iter);
235214501Srpaulo
236214501Srpaulo	dbus_message_iter_recurse(&iter, &dict_iter);
237214501Srpaulo	while (dbus_message_iter_get_arg_type(&dict_iter) ==
238214501Srpaulo	       DBUS_TYPE_DICT_ENTRY) {
239214501Srpaulo		dbus_message_iter_recurse(&dict_iter, &entry_iter);
240214501Srpaulo
241214501Srpaulo		dbus_message_iter_get_basic(&entry_iter, &key);
242214501Srpaulo		dbus_message_iter_next(&entry_iter);
243214501Srpaulo
244214501Srpaulo		if (wpas_dbus_handler_wps_start_entry(message, key,
245214501Srpaulo						      &entry_iter,
246214501Srpaulo						      &params, &reply))
247214501Srpaulo			return reply;
248214501Srpaulo
249214501Srpaulo		dbus_message_iter_next(&dict_iter);
250214501Srpaulo	}
251214501Srpaulo
252214501Srpaulo	if (params.role == 0) {
253214501Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified");
254214501Srpaulo		return wpas_dbus_error_invalid_args(message,
255214501Srpaulo						    "Role not specified");
256214501Srpaulo	} else if (params.role == 1 && params.type == 0) {
257214501Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified");
258214501Srpaulo		return wpas_dbus_error_invalid_args(message,
259214501Srpaulo						    "Type not specified");
260214501Srpaulo	} else if (params.role == 2 && params.pin == NULL) {
261214501Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for "
262214501Srpaulo			   "registrar role");
263214501Srpaulo		return wpas_dbus_error_invalid_args(
264214501Srpaulo			message, "Pin required for registrar role.");
265214501Srpaulo	}
266214501Srpaulo
267214501Srpaulo	if (params.role == 2)
268214501Srpaulo		ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
269214501Srpaulo					 NULL);
270214501Srpaulo	else if (params.type == 1) {
271252190Srpaulo#ifdef CONFIG_AP
272252190Srpaulo		if (wpa_s->ap_iface)
273252190Srpaulo			ret = wpa_supplicant_ap_wps_pin(wpa_s,
274252190Srpaulo							params.bssid,
275252190Srpaulo							params.pin,
276252190Srpaulo							npin, sizeof(npin), 0);
277252190Srpaulo		else
278252190Srpaulo#endif /* CONFIG_AP */
279252190Srpaulo		{
280252190Srpaulo			ret = wpas_wps_start_pin(wpa_s, params.bssid,
281252190Srpaulo						 params.pin, 0,
282252190Srpaulo						 DEV_PW_DEFAULT);
283252190Srpaulo			if (ret > 0)
284252190Srpaulo				os_snprintf(npin, sizeof(npin), "%08d", ret);
285252190Srpaulo		}
286252190Srpaulo	} else {
287252190Srpaulo#ifdef CONFIG_AP
288252190Srpaulo		if (wpa_s->ap_iface)
289252190Srpaulo			ret = wpa_supplicant_ap_wps_pbc(wpa_s,
290252190Srpaulo							params.bssid,
291252190Srpaulo							params.p2p_dev_addr);
292252190Srpaulo		else
293252190Srpaulo#endif /* CONFIG_AP */
294252190Srpaulo		ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
295252190Srpaulo	}
296214501Srpaulo
297214501Srpaulo	if (ret < 0) {
298214501Srpaulo		wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in "
299214501Srpaulo			   "role %s and key %s",
300214501Srpaulo			   (params.role == 1 ? "enrollee" : "registrar"),
301214501Srpaulo			   (params.type == 0 ? "" :
302214501Srpaulo			    (params.type == 1 ? "pin" : "pbc")));
303214501Srpaulo		return wpas_dbus_error_unknown_error(message,
304214501Srpaulo						     "WPS start failed");
305214501Srpaulo	}
306214501Srpaulo
307214501Srpaulo	reply = dbus_message_new_method_return(message);
308214501Srpaulo	if (!reply) {
309214501Srpaulo		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
310214501Srpaulo					      NULL);
311214501Srpaulo	}
312214501Srpaulo
313214501Srpaulo	dbus_message_iter_init_append(reply, &iter);
314214501Srpaulo	if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
315214501Srpaulo		dbus_message_unref(reply);
316214501Srpaulo		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
317214501Srpaulo					      NULL);
318214501Srpaulo	}
319214501Srpaulo
320214501Srpaulo	if (os_strlen(npin) > 0) {
321214501Srpaulo		if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) {
322214501Srpaulo			dbus_message_unref(reply);
323214501Srpaulo			return dbus_message_new_error(message,
324214501Srpaulo						      DBUS_ERROR_NO_MEMORY,
325214501Srpaulo						      NULL);
326214501Srpaulo		}
327214501Srpaulo	}
328214501Srpaulo
329214501Srpaulo	if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
330214501Srpaulo		dbus_message_unref(reply);
331214501Srpaulo		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
332214501Srpaulo					      NULL);
333214501Srpaulo	}
334214501Srpaulo
335214501Srpaulo	return reply;
336214501Srpaulo}
337214501Srpaulo
338214501Srpaulo
339214501Srpaulo/**
340214501Srpaulo * wpas_dbus_getter_process_credentials - Check if credentials are processed
341214501Srpaulo * @message: Pointer to incoming dbus message
342214501Srpaulo * @wpa_s: %wpa_supplicant data structure
343252190Srpaulo * Returns: TRUE on success, FALSE on failure
344214501Srpaulo *
345214501Srpaulo * Getter for "ProcessCredentials" property. Returns returned boolean will be
346214501Srpaulo * true if wps_cred_processing configuration field is not equal to 1 or false
347214501Srpaulo * if otherwise.
348214501Srpaulo */
349252190Srpaulodbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
350252190Srpaulo						 DBusError *error,
351252190Srpaulo						 void *user_data)
352214501Srpaulo{
353252190Srpaulo	struct wpa_supplicant *wpa_s = user_data;
354214501Srpaulo	dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1);
355252190Srpaulo	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
356252190Srpaulo						&process, error);
357214501Srpaulo}
358214501Srpaulo
359214501Srpaulo
360214501Srpaulo/**
361214501Srpaulo * wpas_dbus_setter_process_credentials - Set credentials_processed conf param
362252190Srpaulo * @iter: Pointer to incoming dbus message iter
363252190Srpaulo * @error: Location to store error on failure
364252190Srpaulo * @user_data: Function specific data
365252190Srpaulo * Returns: TRUE on success, FALSE on failure
366214501Srpaulo *
367214501Srpaulo * Setter for "ProcessCredentials" property. Sets credentials_processed on 2
368214501Srpaulo * if boolean argument is true or on 1 if otherwise.
369214501Srpaulo */
370252190Srpaulodbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
371252190Srpaulo						 DBusError *error,
372252190Srpaulo						 void *user_data)
373214501Srpaulo{
374252190Srpaulo	struct wpa_supplicant *wpa_s = user_data;
375214501Srpaulo	dbus_bool_t process_credentials, old_pc;
376214501Srpaulo
377252190Srpaulo	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
378252190Srpaulo					      &process_credentials))
379252190Srpaulo		return FALSE;
380214501Srpaulo
381214501Srpaulo	old_pc = (wpa_s->conf->wps_cred_processing != 1);
382214501Srpaulo	wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1);
383214501Srpaulo
384214501Srpaulo	if ((wpa_s->conf->wps_cred_processing != 1) != old_pc)
385214501Srpaulo		wpa_dbus_mark_property_changed(wpa_s->global->dbus,
386214501Srpaulo					       wpa_s->dbus_new_path,
387214501Srpaulo					       WPAS_DBUS_NEW_IFACE_WPS,
388214501Srpaulo					       "ProcessCredentials");
389214501Srpaulo
390252190Srpaulo	return TRUE;
391214501Srpaulo}
392