2 * WPA Supplicant - privilege separated driver interface
3 * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
15 #include "common/privsep_commands.h"
18 struct wpa_driver_privsep_data
{
20 u8 own_addr
[ETH_ALEN
];
22 char *own_socket_path
;
25 struct sockaddr_un priv_addr
;
30 static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data
*drv
, int cmd
)
34 res
= sendto(drv
->priv_socket
, &cmd
, sizeof(cmd
), 0,
35 (struct sockaddr
*) &drv
->priv_addr
,
36 sizeof(drv
->priv_addr
));
39 return res
< 0 ? -1 : 0;
43 static int wpa_priv_cmd(struct wpa_driver_privsep_data
*drv
, int cmd
,
44 const void *data
, size_t data_len
,
45 void *reply
, size_t *reply_len
)
50 io
[0].iov_base
= &cmd
;
51 io
[0].iov_len
= sizeof(cmd
);
52 io
[1].iov_base
= (u8
*) data
;
53 io
[1].iov_len
= data_len
;
55 os_memset(&msg
, 0, sizeof(msg
));
57 msg
.msg_iovlen
= data
? 2 : 1;
58 msg
.msg_name
= &drv
->priv_addr
;
59 msg
.msg_namelen
= sizeof(drv
->priv_addr
);
61 if (sendmsg(drv
->cmd_socket
, &msg
, 0) < 0) {
62 perror("sendmsg(cmd_socket)");
72 FD_SET(drv
->cmd_socket
, &rfds
);
75 res
= select(drv
->cmd_socket
+ 1, &rfds
, NULL
, NULL
, &tv
);
76 if (res
< 0 && errno
!= EINTR
) {
81 if (FD_ISSET(drv
->cmd_socket
, &rfds
)) {
82 res
= recv(drv
->cmd_socket
, reply
, *reply_len
, 0);
89 wpa_printf(MSG_DEBUG
, "PRIVSEP: Timeout while waiting "
90 "for reply (cmd=%d)", cmd
);
99 static int wpa_driver_privsep_scan(void *priv
,
100 struct wpa_driver_scan_params
*params
)
102 struct wpa_driver_privsep_data
*drv
= priv
;
103 const u8
*ssid
= params
->ssids
[0].ssid
;
104 size_t ssid_len
= params
->ssids
[0].ssid_len
;
105 wpa_printf(MSG_DEBUG
, "%s: priv=%p", __func__
, priv
);
106 return wpa_priv_cmd(drv
, PRIVSEP_CMD_SCAN
, ssid
, ssid_len
,
111 static struct wpa_scan_results
*
112 wpa_driver_privsep_get_scan_results2(void *priv
)
114 struct wpa_driver_privsep_data
*drv
= priv
;
117 size_t reply_len
= 60000;
118 struct wpa_scan_results
*results
;
119 struct wpa_scan_res
*r
;
121 buf
= os_malloc(reply_len
);
124 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_SCAN_RESULTS
,
125 NULL
, 0, buf
, &reply_len
);
131 wpa_printf(MSG_DEBUG
, "privsep: Received %lu bytes of scan results",
132 (unsigned long) reply_len
);
133 if (reply_len
< sizeof(int)) {
134 wpa_printf(MSG_DEBUG
, "privsep: Invalid scan result len %lu",
135 (unsigned long) reply_len
);
141 end
= buf
+ reply_len
;
142 os_memcpy(&num
, pos
, sizeof(int));
143 if (num
< 0 || num
> 1000) {
149 results
= os_zalloc(sizeof(*results
));
150 if (results
== NULL
) {
155 results
->res
= os_calloc(num
, sizeof(struct wpa_scan_res
*));
156 if (results
->res
== NULL
) {
162 while (results
->num
< (size_t) num
&& pos
+ sizeof(int) < end
) {
164 os_memcpy(&len
, pos
, sizeof(int));
166 if (len
< 0 || len
> 10000 || pos
+ len
> end
)
172 os_memcpy(r
, pos
, len
);
174 if (sizeof(*r
) + r
->ie_len
> (size_t) len
) {
179 results
->res
[results
->num
++] = r
;
187 static int wpa_driver_privsep_set_key(const char *ifname
, void *priv
,
188 enum wpa_alg alg
, const u8
*addr
,
189 int key_idx
, int set_tx
,
190 const u8
*seq
, size_t seq_len
,
191 const u8
*key
, size_t key_len
)
193 struct wpa_driver_privsep_data
*drv
= priv
;
194 struct privsep_cmd_set_key cmd
;
196 wpa_printf(MSG_DEBUG
, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
197 __func__
, priv
, alg
, key_idx
, set_tx
);
199 os_memset(&cmd
, 0, sizeof(cmd
));
202 os_memcpy(cmd
.addr
, addr
, ETH_ALEN
);
204 os_memset(cmd
.addr
, 0xff, ETH_ALEN
);
205 cmd
.key_idx
= key_idx
;
207 if (seq
&& seq_len
> 0 && seq_len
< sizeof(cmd
.seq
)) {
208 os_memcpy(cmd
.seq
, seq
, seq_len
);
209 cmd
.seq_len
= seq_len
;
211 if (key
&& key_len
> 0 && key_len
< sizeof(cmd
.key
)) {
212 os_memcpy(cmd
.key
, key
, key_len
);
213 cmd
.key_len
= key_len
;
216 return wpa_priv_cmd(drv
, PRIVSEP_CMD_SET_KEY
, &cmd
, sizeof(cmd
),
221 static int wpa_driver_privsep_associate(
222 void *priv
, struct wpa_driver_associate_params
*params
)
224 struct wpa_driver_privsep_data
*drv
= priv
;
225 struct privsep_cmd_associate
*data
;
229 wpa_printf(MSG_DEBUG
, "%s: priv=%p freq=%d pairwise_suite=%d "
230 "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
231 __func__
, priv
, params
->freq
.freq
, params
->pairwise_suite
,
232 params
->group_suite
, params
->key_mgmt_suite
,
233 params
->auth_alg
, params
->mode
);
235 buflen
= sizeof(*data
) + params
->wpa_ie_len
;
236 data
= os_zalloc(buflen
);
241 os_memcpy(data
->bssid
, params
->bssid
, ETH_ALEN
);
242 os_memcpy(data
->ssid
, params
->ssid
, params
->ssid_len
);
243 data
->ssid_len
= params
->ssid_len
;
244 data
->hwmode
= params
->freq
.mode
;
245 data
->freq
= params
->freq
.freq
;
246 data
->channel
= params
->freq
.channel
;
247 data
->pairwise_suite
= params
->pairwise_suite
;
248 data
->group_suite
= params
->group_suite
;
249 data
->key_mgmt_suite
= params
->key_mgmt_suite
;
250 data
->auth_alg
= params
->auth_alg
;
251 data
->mode
= params
->mode
;
252 data
->wpa_ie_len
= params
->wpa_ie_len
;
254 os_memcpy(data
+ 1, params
->wpa_ie
, params
->wpa_ie_len
);
255 /* TODO: add support for other assoc parameters */
257 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_ASSOCIATE
, data
, buflen
,
265 static int wpa_driver_privsep_get_bssid(void *priv
, u8
*bssid
)
267 struct wpa_driver_privsep_data
*drv
= priv
;
269 size_t len
= ETH_ALEN
;
271 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_BSSID
, NULL
, 0, bssid
, &len
);
272 if (res
< 0 || len
!= ETH_ALEN
)
278 static int wpa_driver_privsep_get_ssid(void *priv
, u8
*ssid
)
280 struct wpa_driver_privsep_data
*drv
= priv
;
282 u8 reply
[sizeof(int) + 32];
283 size_t len
= sizeof(reply
);
285 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_SSID
, NULL
, 0, reply
, &len
);
286 if (res
< 0 || len
< sizeof(int))
288 os_memcpy(&ssid_len
, reply
, sizeof(int));
289 if (ssid_len
< 0 || ssid_len
> 32 || sizeof(int) + ssid_len
> len
) {
290 wpa_printf(MSG_DEBUG
, "privsep: Invalid get SSID reply");
293 os_memcpy(ssid
, &reply
[sizeof(int)], ssid_len
);
298 static int wpa_driver_privsep_deauthenticate(void *priv
, const u8
*addr
,
301 //struct wpa_driver_privsep_data *drv = priv;
302 wpa_printf(MSG_DEBUG
, "%s addr=" MACSTR
" reason_code=%d",
303 __func__
, MAC2STR(addr
), reason_code
);
304 wpa_printf(MSG_DEBUG
, "%s - TODO", __func__
);
309 static void wpa_driver_privsep_event_assoc(void *ctx
,
310 enum wpa_event_type event
,
313 union wpa_event_data data
;
318 os_memset(&data
, 0, sizeof(data
));
323 if (end
- pos
< (int) sizeof(int))
325 os_memcpy(&ie_len
, pos
, sizeof(int));
327 if (ie_len
< 0 || ie_len
> end
- pos
)
330 data
.assoc_info
.req_ies
= pos
;
331 data
.assoc_info
.req_ies_len
= ie_len
;
336 wpa_supplicant_event(ctx
, event
, inc_data
? &data
: NULL
);
340 static void wpa_driver_privsep_event_interface_status(void *ctx
, u8
*buf
,
343 union wpa_event_data data
;
346 if (len
< sizeof(int) ||
347 len
- sizeof(int) > sizeof(data
.interface_status
.ifname
))
350 os_memcpy(&ievent
, buf
, sizeof(int));
352 os_memset(&data
, 0, sizeof(data
));
353 data
.interface_status
.ievent
= ievent
;
354 os_memcpy(data
.interface_status
.ifname
, buf
+ sizeof(int),
356 wpa_supplicant_event(ctx
, EVENT_INTERFACE_STATUS
, &data
);
360 static void wpa_driver_privsep_event_michael_mic_failure(
361 void *ctx
, u8
*buf
, size_t len
)
363 union wpa_event_data data
;
365 if (len
!= sizeof(int))
368 os_memset(&data
, 0, sizeof(data
));
369 os_memcpy(&data
.michael_mic_failure
.unicast
, buf
, sizeof(int));
370 wpa_supplicant_event(ctx
, EVENT_MICHAEL_MIC_FAILURE
, &data
);
374 static void wpa_driver_privsep_event_pmkid_candidate(void *ctx
, u8
*buf
,
377 union wpa_event_data data
;
379 if (len
!= sizeof(struct pmkid_candidate
))
382 os_memset(&data
, 0, sizeof(data
));
383 os_memcpy(&data
.pmkid_candidate
, buf
, len
);
384 wpa_supplicant_event(ctx
, EVENT_PMKID_CANDIDATE
, &data
);
388 static void wpa_driver_privsep_event_stkstart(void *ctx
, u8
*buf
, size_t len
)
390 union wpa_event_data data
;
395 os_memset(&data
, 0, sizeof(data
));
396 os_memcpy(data
.stkstart
.peer
, buf
, ETH_ALEN
);
397 wpa_supplicant_event(ctx
, EVENT_STKSTART
, &data
);
401 static void wpa_driver_privsep_event_ft_response(void *ctx
, u8
*buf
,
404 union wpa_event_data data
;
406 if (len
< sizeof(int) + ETH_ALEN
)
409 os_memset(&data
, 0, sizeof(data
));
410 os_memcpy(&data
.ft_ies
.ft_action
, buf
, sizeof(int));
411 os_memcpy(data
.ft_ies
.target_ap
, buf
+ sizeof(int), ETH_ALEN
);
412 data
.ft_ies
.ies
= buf
+ sizeof(int) + ETH_ALEN
;
413 data
.ft_ies
.ies_len
= len
- sizeof(int) - ETH_ALEN
;
414 wpa_supplicant_event(ctx
, EVENT_FT_RESPONSE
, &data
);
418 static void wpa_driver_privsep_event_rx_eapol(void *ctx
, u8
*buf
, size_t len
)
422 drv_event_eapol_rx(ctx
, buf
, buf
+ ETH_ALEN
, len
- ETH_ALEN
);
426 static void wpa_driver_privsep_receive(int sock
, void *eloop_ctx
,
429 struct wpa_driver_privsep_data
*drv
= eloop_ctx
;
433 enum privsep_event e
;
434 struct sockaddr_un from
;
435 socklen_t fromlen
= sizeof(from
);
436 const size_t buflen
= 2000;
438 buf
= os_malloc(buflen
);
441 res
= recvfrom(sock
, buf
, buflen
, 0,
442 (struct sockaddr
*) &from
, &fromlen
);
444 perror("recvfrom(priv_socket)");
449 wpa_printf(MSG_DEBUG
, "privsep_driver: received %u bytes", res
);
451 if (res
< (int) sizeof(int)) {
452 wpa_printf(MSG_DEBUG
, "Too short event message (len=%d)", res
);
456 os_memcpy(&event
, buf
, sizeof(int));
457 event_buf
= &buf
[sizeof(int)];
458 event_len
= res
- sizeof(int);
459 wpa_printf(MSG_DEBUG
, "privsep: Event %d received (len=%lu)",
460 event
, (unsigned long) event_len
);
464 case PRIVSEP_EVENT_SCAN_RESULTS
:
465 wpa_supplicant_event(drv
->ctx
, EVENT_SCAN_RESULTS
, NULL
);
467 case PRIVSEP_EVENT_ASSOC
:
468 wpa_driver_privsep_event_assoc(drv
->ctx
, EVENT_ASSOC
,
469 event_buf
, event_len
);
471 case PRIVSEP_EVENT_DISASSOC
:
472 wpa_supplicant_event(drv
->ctx
, EVENT_DISASSOC
, NULL
);
474 case PRIVSEP_EVENT_ASSOCINFO
:
475 wpa_driver_privsep_event_assoc(drv
->ctx
, EVENT_ASSOCINFO
,
476 event_buf
, event_len
);
478 case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE
:
479 wpa_driver_privsep_event_michael_mic_failure(
480 drv
->ctx
, event_buf
, event_len
);
482 case PRIVSEP_EVENT_INTERFACE_STATUS
:
483 wpa_driver_privsep_event_interface_status(drv
->ctx
, event_buf
,
486 case PRIVSEP_EVENT_PMKID_CANDIDATE
:
487 wpa_driver_privsep_event_pmkid_candidate(drv
->ctx
, event_buf
,
490 case PRIVSEP_EVENT_STKSTART
:
491 wpa_driver_privsep_event_stkstart(drv
->ctx
, event_buf
,
494 case PRIVSEP_EVENT_FT_RESPONSE
:
495 wpa_driver_privsep_event_ft_response(drv
->ctx
, event_buf
,
498 case PRIVSEP_EVENT_RX_EAPOL
:
499 wpa_driver_privsep_event_rx_eapol(drv
->ctx
, event_buf
,
508 static void * wpa_driver_privsep_init(void *ctx
, const char *ifname
)
510 struct wpa_driver_privsep_data
*drv
;
512 drv
= os_zalloc(sizeof(*drv
));
516 drv
->priv_socket
= -1;
517 drv
->cmd_socket
= -1;
518 os_strlcpy(drv
->ifname
, ifname
, sizeof(drv
->ifname
));
524 static void wpa_driver_privsep_deinit(void *priv
)
526 struct wpa_driver_privsep_data
*drv
= priv
;
528 if (drv
->priv_socket
>= 0) {
529 wpa_priv_reg_cmd(drv
, PRIVSEP_CMD_UNREGISTER
);
530 eloop_unregister_read_sock(drv
->priv_socket
);
531 close(drv
->priv_socket
);
534 if (drv
->own_socket_path
) {
535 unlink(drv
->own_socket_path
);
536 os_free(drv
->own_socket_path
);
539 if (drv
->cmd_socket
>= 0) {
540 eloop_unregister_read_sock(drv
->cmd_socket
);
541 close(drv
->cmd_socket
);
544 if (drv
->own_cmd_path
) {
545 unlink(drv
->own_cmd_path
);
546 os_free(drv
->own_cmd_path
);
553 static int wpa_driver_privsep_set_param(void *priv
, const char *param
)
555 struct wpa_driver_privsep_data
*drv
= priv
;
557 char *own_dir
, *priv_dir
;
558 static unsigned int counter
= 0;
560 struct sockaddr_un addr
;
562 wpa_printf(MSG_DEBUG
, "%s: param='%s'", __func__
, param
);
566 pos
= os_strstr(param
, "own_dir=");
569 own_dir
= os_strdup(pos
+ 8);
572 end
= os_strchr(own_dir
, ' ');
576 own_dir
= os_strdup("/tmp");
584 pos
= os_strstr(param
, "priv_dir=");
587 priv_dir
= os_strdup(pos
+ 9);
588 if (priv_dir
== NULL
) {
592 end
= os_strchr(priv_dir
, ' ');
596 priv_dir
= os_strdup("/var/run/wpa_priv");
597 if (priv_dir
== NULL
) {
603 len
= os_strlen(own_dir
) + 50;
604 drv
->own_socket_path
= os_malloc(len
);
605 if (drv
->own_socket_path
== NULL
) {
610 os_snprintf(drv
->own_socket_path
, len
, "%s/wpa_privsep-%d-%d",
611 own_dir
, getpid(), counter
++);
613 len
= os_strlen(own_dir
) + 50;
614 drv
->own_cmd_path
= os_malloc(len
);
615 if (drv
->own_cmd_path
== NULL
) {
616 os_free(drv
->own_socket_path
);
617 drv
->own_socket_path
= NULL
;
622 os_snprintf(drv
->own_cmd_path
, len
, "%s/wpa_privsep-%d-%d",
623 own_dir
, getpid(), counter
++);
627 drv
->priv_addr
.sun_family
= AF_UNIX
;
628 os_snprintf(drv
->priv_addr
.sun_path
, sizeof(drv
->priv_addr
.sun_path
),
629 "%s/%s", priv_dir
, drv
->ifname
);
632 drv
->priv_socket
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
633 if (drv
->priv_socket
< 0) {
634 perror("socket(PF_UNIX)");
635 os_free(drv
->own_socket_path
);
636 drv
->own_socket_path
= NULL
;
640 os_memset(&addr
, 0, sizeof(addr
));
641 addr
.sun_family
= AF_UNIX
;
642 os_strlcpy(addr
.sun_path
, drv
->own_socket_path
, sizeof(addr
.sun_path
));
643 if (bind(drv
->priv_socket
, (struct sockaddr
*) &addr
, sizeof(addr
)) <
645 perror("privsep-set-params priv-sock: bind(PF_UNIX)");
646 close(drv
->priv_socket
);
647 drv
->priv_socket
= -1;
648 unlink(drv
->own_socket_path
);
649 os_free(drv
->own_socket_path
);
650 drv
->own_socket_path
= NULL
;
654 eloop_register_read_sock(drv
->priv_socket
, wpa_driver_privsep_receive
,
657 drv
->cmd_socket
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
658 if (drv
->cmd_socket
< 0) {
659 perror("socket(PF_UNIX)");
660 os_free(drv
->own_cmd_path
);
661 drv
->own_cmd_path
= NULL
;
665 os_memset(&addr
, 0, sizeof(addr
));
666 addr
.sun_family
= AF_UNIX
;
667 os_strlcpy(addr
.sun_path
, drv
->own_cmd_path
, sizeof(addr
.sun_path
));
668 if (bind(drv
->cmd_socket
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0)
670 perror("privsep-set-params cmd-sock: bind(PF_UNIX)");
671 close(drv
->cmd_socket
);
672 drv
->cmd_socket
= -1;
673 unlink(drv
->own_cmd_path
);
674 os_free(drv
->own_cmd_path
);
675 drv
->own_cmd_path
= NULL
;
679 if (wpa_priv_reg_cmd(drv
, PRIVSEP_CMD_REGISTER
) < 0) {
680 wpa_printf(MSG_ERROR
, "Failed to register with wpa_priv");
688 static int wpa_driver_privsep_get_capa(void *priv
,
689 struct wpa_driver_capa
*capa
)
691 struct wpa_driver_privsep_data
*drv
= priv
;
693 size_t len
= sizeof(*capa
);
695 res
= wpa_priv_cmd(drv
, PRIVSEP_CMD_GET_CAPA
, NULL
, 0, capa
, &len
);
696 if (res
< 0 || len
!= sizeof(*capa
))
702 static const u8
* wpa_driver_privsep_get_mac_addr(void *priv
)
704 struct wpa_driver_privsep_data
*drv
= priv
;
705 wpa_printf(MSG_DEBUG
, "%s", __func__
);
706 return drv
->own_addr
;
710 static int wpa_driver_privsep_set_country(void *priv
, const char *alpha2
)
712 struct wpa_driver_privsep_data
*drv
= priv
;
713 wpa_printf(MSG_DEBUG
, "%s country='%s'", __func__
, alpha2
);
714 return wpa_priv_cmd(drv
, PRIVSEP_CMD_SET_COUNTRY
, alpha2
,
715 os_strlen(alpha2
), NULL
, NULL
);
719 struct wpa_driver_ops wpa_driver_privsep_ops
= {
721 "wpa_supplicant privilege separated driver",
722 .get_bssid
= wpa_driver_privsep_get_bssid
,
723 .get_ssid
= wpa_driver_privsep_get_ssid
,
724 .set_key
= wpa_driver_privsep_set_key
,
725 .init
= wpa_driver_privsep_init
,
726 .deinit
= wpa_driver_privsep_deinit
,
727 .set_param
= wpa_driver_privsep_set_param
,
728 .scan2
= wpa_driver_privsep_scan
,
729 .deauthenticate
= wpa_driver_privsep_deauthenticate
,
730 .associate
= wpa_driver_privsep_associate
,
731 .get_capa
= wpa_driver_privsep_get_capa
,
732 .get_mac_addr
= wpa_driver_privsep_get_mac_addr
,
733 .get_scan_results2
= wpa_driver_privsep_get_scan_results2
,
734 .set_country
= wpa_driver_privsep_set_country
,
738 struct wpa_driver_ops
*wpa_drivers
[] =
740 &wpa_driver_privsep_ops
,