1f05cddf9SRui Paulo /* 2f05cddf9SRui Paulo * WPA Supplicant - privilege separated driver interface 3f05cddf9SRui Paulo * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> 4f05cddf9SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7f05cddf9SRui Paulo */ 8f05cddf9SRui Paulo 9f05cddf9SRui Paulo #include "includes.h" 10f05cddf9SRui Paulo #include <sys/un.h> 11f05cddf9SRui Paulo 12f05cddf9SRui Paulo #include "common.h" 13f05cddf9SRui Paulo #include "driver.h" 14f05cddf9SRui Paulo #include "eloop.h" 15f05cddf9SRui Paulo #include "common/privsep_commands.h" 16f05cddf9SRui Paulo 17f05cddf9SRui Paulo 18f05cddf9SRui Paulo struct wpa_driver_privsep_data { 19f05cddf9SRui Paulo void *ctx; 20f05cddf9SRui Paulo u8 own_addr[ETH_ALEN]; 21f05cddf9SRui Paulo int priv_socket; 22f05cddf9SRui Paulo char *own_socket_path; 23f05cddf9SRui Paulo int cmd_socket; 24f05cddf9SRui Paulo char *own_cmd_path; 25f05cddf9SRui Paulo struct sockaddr_un priv_addr; 26f05cddf9SRui Paulo char ifname[16]; 27f05cddf9SRui Paulo }; 28f05cddf9SRui Paulo 29f05cddf9SRui Paulo 30f05cddf9SRui Paulo static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd) 31f05cddf9SRui Paulo { 32f05cddf9SRui Paulo int res; 33f05cddf9SRui Paulo 34f05cddf9SRui Paulo res = sendto(drv->priv_socket, &cmd, sizeof(cmd), 0, 35f05cddf9SRui Paulo (struct sockaddr *) &drv->priv_addr, 36f05cddf9SRui Paulo sizeof(drv->priv_addr)); 37f05cddf9SRui Paulo if (res < 0) 38*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "sendto: %s", strerror(errno)); 39f05cddf9SRui Paulo return res < 0 ? -1 : 0; 40f05cddf9SRui Paulo } 41f05cddf9SRui Paulo 42f05cddf9SRui Paulo 43f05cddf9SRui Paulo static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd, 44f05cddf9SRui Paulo const void *data, size_t data_len, 45f05cddf9SRui Paulo void *reply, size_t *reply_len) 46f05cddf9SRui Paulo { 47f05cddf9SRui Paulo struct msghdr msg; 48f05cddf9SRui Paulo struct iovec io[2]; 49f05cddf9SRui Paulo 50f05cddf9SRui Paulo io[0].iov_base = &cmd; 51f05cddf9SRui Paulo io[0].iov_len = sizeof(cmd); 52f05cddf9SRui Paulo io[1].iov_base = (u8 *) data; 53f05cddf9SRui Paulo io[1].iov_len = data_len; 54f05cddf9SRui Paulo 55f05cddf9SRui Paulo os_memset(&msg, 0, sizeof(msg)); 56f05cddf9SRui Paulo msg.msg_iov = io; 57f05cddf9SRui Paulo msg.msg_iovlen = data ? 2 : 1; 58f05cddf9SRui Paulo msg.msg_name = &drv->priv_addr; 59f05cddf9SRui Paulo msg.msg_namelen = sizeof(drv->priv_addr); 60f05cddf9SRui Paulo 61f05cddf9SRui Paulo if (sendmsg(drv->cmd_socket, &msg, 0) < 0) { 62*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "sendmsg(cmd_socket): %s", 63*5b9c547cSRui Paulo strerror(errno)); 64f05cddf9SRui Paulo return -1; 65f05cddf9SRui Paulo } 66f05cddf9SRui Paulo 67f05cddf9SRui Paulo if (reply) { 68f05cddf9SRui Paulo fd_set rfds; 69f05cddf9SRui Paulo struct timeval tv; 70f05cddf9SRui Paulo int res; 71f05cddf9SRui Paulo 72f05cddf9SRui Paulo FD_ZERO(&rfds); 73f05cddf9SRui Paulo FD_SET(drv->cmd_socket, &rfds); 74f05cddf9SRui Paulo tv.tv_sec = 5; 75f05cddf9SRui Paulo tv.tv_usec = 0; 76f05cddf9SRui Paulo res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv); 77f05cddf9SRui Paulo if (res < 0 && errno != EINTR) { 78*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "select: %s", strerror(errno)); 79f05cddf9SRui Paulo return -1; 80f05cddf9SRui Paulo } 81f05cddf9SRui Paulo 82f05cddf9SRui Paulo if (FD_ISSET(drv->cmd_socket, &rfds)) { 83f05cddf9SRui Paulo res = recv(drv->cmd_socket, reply, *reply_len, 0); 84f05cddf9SRui Paulo if (res < 0) { 85*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "recv: %s", 86*5b9c547cSRui Paulo strerror(errno)); 87f05cddf9SRui Paulo return -1; 88f05cddf9SRui Paulo } 89f05cddf9SRui Paulo *reply_len = res; 90f05cddf9SRui Paulo } else { 91f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "PRIVSEP: Timeout while waiting " 92f05cddf9SRui Paulo "for reply (cmd=%d)", cmd); 93f05cddf9SRui Paulo return -1; 94f05cddf9SRui Paulo } 95f05cddf9SRui Paulo } 96f05cddf9SRui Paulo 97f05cddf9SRui Paulo return 0; 98f05cddf9SRui Paulo } 99f05cddf9SRui Paulo 100f05cddf9SRui Paulo 101f05cddf9SRui Paulo static int wpa_driver_privsep_scan(void *priv, 102f05cddf9SRui Paulo struct wpa_driver_scan_params *params) 103f05cddf9SRui Paulo { 104f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = priv; 105f05cddf9SRui Paulo const u8 *ssid = params->ssids[0].ssid; 106f05cddf9SRui Paulo size_t ssid_len = params->ssids[0].ssid_len; 107f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv); 108f05cddf9SRui Paulo return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len, 109f05cddf9SRui Paulo NULL, NULL); 110f05cddf9SRui Paulo } 111f05cddf9SRui Paulo 112f05cddf9SRui Paulo 113f05cddf9SRui Paulo static struct wpa_scan_results * 114f05cddf9SRui Paulo wpa_driver_privsep_get_scan_results2(void *priv) 115f05cddf9SRui Paulo { 116f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = priv; 117f05cddf9SRui Paulo int res, num; 118f05cddf9SRui Paulo u8 *buf, *pos, *end; 119f05cddf9SRui Paulo size_t reply_len = 60000; 120f05cddf9SRui Paulo struct wpa_scan_results *results; 121f05cddf9SRui Paulo struct wpa_scan_res *r; 122f05cddf9SRui Paulo 123f05cddf9SRui Paulo buf = os_malloc(reply_len); 124f05cddf9SRui Paulo if (buf == NULL) 125f05cddf9SRui Paulo return NULL; 126f05cddf9SRui Paulo res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SCAN_RESULTS, 127f05cddf9SRui Paulo NULL, 0, buf, &reply_len); 128f05cddf9SRui Paulo if (res < 0) { 129f05cddf9SRui Paulo os_free(buf); 130f05cddf9SRui Paulo return NULL; 131f05cddf9SRui Paulo } 132f05cddf9SRui Paulo 133f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "privsep: Received %lu bytes of scan results", 134f05cddf9SRui Paulo (unsigned long) reply_len); 135f05cddf9SRui Paulo if (reply_len < sizeof(int)) { 136f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "privsep: Invalid scan result len %lu", 137f05cddf9SRui Paulo (unsigned long) reply_len); 138f05cddf9SRui Paulo os_free(buf); 139f05cddf9SRui Paulo return NULL; 140f05cddf9SRui Paulo } 141f05cddf9SRui Paulo 142f05cddf9SRui Paulo pos = buf; 143f05cddf9SRui Paulo end = buf + reply_len; 144f05cddf9SRui Paulo os_memcpy(&num, pos, sizeof(int)); 145f05cddf9SRui Paulo if (num < 0 || num > 1000) { 146f05cddf9SRui Paulo os_free(buf); 147f05cddf9SRui Paulo return NULL; 148f05cddf9SRui Paulo } 149f05cddf9SRui Paulo pos += sizeof(int); 150f05cddf9SRui Paulo 151f05cddf9SRui Paulo results = os_zalloc(sizeof(*results)); 152f05cddf9SRui Paulo if (results == NULL) { 153f05cddf9SRui Paulo os_free(buf); 154f05cddf9SRui Paulo return NULL; 155f05cddf9SRui Paulo } 156f05cddf9SRui Paulo 157f05cddf9SRui Paulo results->res = os_calloc(num, sizeof(struct wpa_scan_res *)); 158f05cddf9SRui Paulo if (results->res == NULL) { 159f05cddf9SRui Paulo os_free(results); 160f05cddf9SRui Paulo os_free(buf); 161f05cddf9SRui Paulo return NULL; 162f05cddf9SRui Paulo } 163f05cddf9SRui Paulo 164f05cddf9SRui Paulo while (results->num < (size_t) num && pos + sizeof(int) < end) { 165f05cddf9SRui Paulo int len; 166f05cddf9SRui Paulo os_memcpy(&len, pos, sizeof(int)); 167f05cddf9SRui Paulo pos += sizeof(int); 168f05cddf9SRui Paulo if (len < 0 || len > 10000 || pos + len > end) 169f05cddf9SRui Paulo break; 170f05cddf9SRui Paulo 171f05cddf9SRui Paulo r = os_malloc(len); 172f05cddf9SRui Paulo if (r == NULL) 173f05cddf9SRui Paulo break; 174f05cddf9SRui Paulo os_memcpy(r, pos, len); 175f05cddf9SRui Paulo pos += len; 176f05cddf9SRui Paulo if (sizeof(*r) + r->ie_len > (size_t) len) { 177f05cddf9SRui Paulo os_free(r); 178f05cddf9SRui Paulo break; 179f05cddf9SRui Paulo } 180f05cddf9SRui Paulo 181f05cddf9SRui Paulo results->res[results->num++] = r; 182f05cddf9SRui Paulo } 183f05cddf9SRui Paulo 184f05cddf9SRui Paulo os_free(buf); 185f05cddf9SRui Paulo return results; 186f05cddf9SRui Paulo } 187f05cddf9SRui Paulo 188f05cddf9SRui Paulo 189f05cddf9SRui Paulo static int wpa_driver_privsep_set_key(const char *ifname, void *priv, 190f05cddf9SRui Paulo enum wpa_alg alg, const u8 *addr, 191f05cddf9SRui Paulo int key_idx, int set_tx, 192f05cddf9SRui Paulo const u8 *seq, size_t seq_len, 193f05cddf9SRui Paulo const u8 *key, size_t key_len) 194f05cddf9SRui Paulo { 195f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = priv; 196f05cddf9SRui Paulo struct privsep_cmd_set_key cmd; 197f05cddf9SRui Paulo 198f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d", 199f05cddf9SRui Paulo __func__, priv, alg, key_idx, set_tx); 200f05cddf9SRui Paulo 201f05cddf9SRui Paulo os_memset(&cmd, 0, sizeof(cmd)); 202f05cddf9SRui Paulo cmd.alg = alg; 203f05cddf9SRui Paulo if (addr) 204f05cddf9SRui Paulo os_memcpy(cmd.addr, addr, ETH_ALEN); 205f05cddf9SRui Paulo else 206f05cddf9SRui Paulo os_memset(cmd.addr, 0xff, ETH_ALEN); 207f05cddf9SRui Paulo cmd.key_idx = key_idx; 208f05cddf9SRui Paulo cmd.set_tx = set_tx; 209f05cddf9SRui Paulo if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) { 210f05cddf9SRui Paulo os_memcpy(cmd.seq, seq, seq_len); 211f05cddf9SRui Paulo cmd.seq_len = seq_len; 212f05cddf9SRui Paulo } 213f05cddf9SRui Paulo if (key && key_len > 0 && key_len < sizeof(cmd.key)) { 214f05cddf9SRui Paulo os_memcpy(cmd.key, key, key_len); 215f05cddf9SRui Paulo cmd.key_len = key_len; 216f05cddf9SRui Paulo } 217f05cddf9SRui Paulo 218f05cddf9SRui Paulo return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_KEY, &cmd, sizeof(cmd), 219f05cddf9SRui Paulo NULL, NULL); 220f05cddf9SRui Paulo } 221f05cddf9SRui Paulo 222f05cddf9SRui Paulo 223f05cddf9SRui Paulo static int wpa_driver_privsep_associate( 224f05cddf9SRui Paulo void *priv, struct wpa_driver_associate_params *params) 225f05cddf9SRui Paulo { 226f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = priv; 227f05cddf9SRui Paulo struct privsep_cmd_associate *data; 228f05cddf9SRui Paulo int res; 229f05cddf9SRui Paulo size_t buflen; 230f05cddf9SRui Paulo 231f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d " 232f05cddf9SRui Paulo "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d", 233*5b9c547cSRui Paulo __func__, priv, params->freq.freq, params->pairwise_suite, 234f05cddf9SRui Paulo params->group_suite, params->key_mgmt_suite, 235f05cddf9SRui Paulo params->auth_alg, params->mode); 236f05cddf9SRui Paulo 237f05cddf9SRui Paulo buflen = sizeof(*data) + params->wpa_ie_len; 238f05cddf9SRui Paulo data = os_zalloc(buflen); 239f05cddf9SRui Paulo if (data == NULL) 240f05cddf9SRui Paulo return -1; 241f05cddf9SRui Paulo 242f05cddf9SRui Paulo if (params->bssid) 243f05cddf9SRui Paulo os_memcpy(data->bssid, params->bssid, ETH_ALEN); 244f05cddf9SRui Paulo os_memcpy(data->ssid, params->ssid, params->ssid_len); 245f05cddf9SRui Paulo data->ssid_len = params->ssid_len; 246*5b9c547cSRui Paulo data->hwmode = params->freq.mode; 247*5b9c547cSRui Paulo data->freq = params->freq.freq; 248*5b9c547cSRui Paulo data->channel = params->freq.channel; 249f05cddf9SRui Paulo data->pairwise_suite = params->pairwise_suite; 250f05cddf9SRui Paulo data->group_suite = params->group_suite; 251f05cddf9SRui Paulo data->key_mgmt_suite = params->key_mgmt_suite; 252f05cddf9SRui Paulo data->auth_alg = params->auth_alg; 253f05cddf9SRui Paulo data->mode = params->mode; 254f05cddf9SRui Paulo data->wpa_ie_len = params->wpa_ie_len; 255f05cddf9SRui Paulo if (params->wpa_ie) 256f05cddf9SRui Paulo os_memcpy(data + 1, params->wpa_ie, params->wpa_ie_len); 257f05cddf9SRui Paulo /* TODO: add support for other assoc parameters */ 258f05cddf9SRui Paulo 259f05cddf9SRui Paulo res = wpa_priv_cmd(drv, PRIVSEP_CMD_ASSOCIATE, data, buflen, 260f05cddf9SRui Paulo NULL, NULL); 261f05cddf9SRui Paulo os_free(data); 262f05cddf9SRui Paulo 263f05cddf9SRui Paulo return res; 264f05cddf9SRui Paulo } 265f05cddf9SRui Paulo 266f05cddf9SRui Paulo 267f05cddf9SRui Paulo static int wpa_driver_privsep_get_bssid(void *priv, u8 *bssid) 268f05cddf9SRui Paulo { 269f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = priv; 270f05cddf9SRui Paulo int res; 271f05cddf9SRui Paulo size_t len = ETH_ALEN; 272f05cddf9SRui Paulo 273f05cddf9SRui Paulo res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_BSSID, NULL, 0, bssid, &len); 274f05cddf9SRui Paulo if (res < 0 || len != ETH_ALEN) 275f05cddf9SRui Paulo return -1; 276f05cddf9SRui Paulo return 0; 277f05cddf9SRui Paulo } 278f05cddf9SRui Paulo 279f05cddf9SRui Paulo 280f05cddf9SRui Paulo static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid) 281f05cddf9SRui Paulo { 282f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = priv; 283f05cddf9SRui Paulo int res, ssid_len; 284f05cddf9SRui Paulo u8 reply[sizeof(int) + 32]; 285f05cddf9SRui Paulo size_t len = sizeof(reply); 286f05cddf9SRui Paulo 287f05cddf9SRui Paulo res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len); 288f05cddf9SRui Paulo if (res < 0 || len < sizeof(int)) 289f05cddf9SRui Paulo return -1; 290f05cddf9SRui Paulo os_memcpy(&ssid_len, reply, sizeof(int)); 291f05cddf9SRui Paulo if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) { 292f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply"); 293f05cddf9SRui Paulo return -1; 294f05cddf9SRui Paulo } 295f05cddf9SRui Paulo os_memcpy(ssid, &reply[sizeof(int)], ssid_len); 296f05cddf9SRui Paulo return ssid_len; 297f05cddf9SRui Paulo } 298f05cddf9SRui Paulo 299f05cddf9SRui Paulo 300f05cddf9SRui Paulo static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr, 301f05cddf9SRui Paulo int reason_code) 302f05cddf9SRui Paulo { 303f05cddf9SRui Paulo //struct wpa_driver_privsep_data *drv = priv; 304f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", 305f05cddf9SRui Paulo __func__, MAC2STR(addr), reason_code); 306f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s - TODO", __func__); 307f05cddf9SRui Paulo return 0; 308f05cddf9SRui Paulo } 309f05cddf9SRui Paulo 310f05cddf9SRui Paulo 311f05cddf9SRui Paulo static void wpa_driver_privsep_event_assoc(void *ctx, 312f05cddf9SRui Paulo enum wpa_event_type event, 313f05cddf9SRui Paulo u8 *buf, size_t len) 314f05cddf9SRui Paulo { 315f05cddf9SRui Paulo union wpa_event_data data; 316f05cddf9SRui Paulo int inc_data = 0; 317f05cddf9SRui Paulo u8 *pos, *end; 318f05cddf9SRui Paulo int ie_len; 319f05cddf9SRui Paulo 320f05cddf9SRui Paulo os_memset(&data, 0, sizeof(data)); 321f05cddf9SRui Paulo 322f05cddf9SRui Paulo pos = buf; 323f05cddf9SRui Paulo end = buf + len; 324f05cddf9SRui Paulo 325f05cddf9SRui Paulo if (end - pos < (int) sizeof(int)) 326f05cddf9SRui Paulo return; 327f05cddf9SRui Paulo os_memcpy(&ie_len, pos, sizeof(int)); 328f05cddf9SRui Paulo pos += sizeof(int); 329f05cddf9SRui Paulo if (ie_len < 0 || ie_len > end - pos) 330f05cddf9SRui Paulo return; 331f05cddf9SRui Paulo if (ie_len) { 332f05cddf9SRui Paulo data.assoc_info.req_ies = pos; 333f05cddf9SRui Paulo data.assoc_info.req_ies_len = ie_len; 334f05cddf9SRui Paulo pos += ie_len; 335f05cddf9SRui Paulo inc_data = 1; 336f05cddf9SRui Paulo } 337f05cddf9SRui Paulo 338f05cddf9SRui Paulo wpa_supplicant_event(ctx, event, inc_data ? &data : NULL); 339f05cddf9SRui Paulo } 340f05cddf9SRui Paulo 341f05cddf9SRui Paulo 342f05cddf9SRui Paulo static void wpa_driver_privsep_event_interface_status(void *ctx, u8 *buf, 343f05cddf9SRui Paulo size_t len) 344f05cddf9SRui Paulo { 345f05cddf9SRui Paulo union wpa_event_data data; 346f05cddf9SRui Paulo int ievent; 347f05cddf9SRui Paulo 348f05cddf9SRui Paulo if (len < sizeof(int) || 349f05cddf9SRui Paulo len - sizeof(int) > sizeof(data.interface_status.ifname)) 350f05cddf9SRui Paulo return; 351f05cddf9SRui Paulo 352f05cddf9SRui Paulo os_memcpy(&ievent, buf, sizeof(int)); 353f05cddf9SRui Paulo 354f05cddf9SRui Paulo os_memset(&data, 0, sizeof(data)); 355f05cddf9SRui Paulo data.interface_status.ievent = ievent; 356f05cddf9SRui Paulo os_memcpy(data.interface_status.ifname, buf + sizeof(int), 357f05cddf9SRui Paulo len - sizeof(int)); 358f05cddf9SRui Paulo wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &data); 359f05cddf9SRui Paulo } 360f05cddf9SRui Paulo 361f05cddf9SRui Paulo 362f05cddf9SRui Paulo static void wpa_driver_privsep_event_michael_mic_failure( 363f05cddf9SRui Paulo void *ctx, u8 *buf, size_t len) 364f05cddf9SRui Paulo { 365f05cddf9SRui Paulo union wpa_event_data data; 366f05cddf9SRui Paulo 367f05cddf9SRui Paulo if (len != sizeof(int)) 368f05cddf9SRui Paulo return; 369f05cddf9SRui Paulo 370f05cddf9SRui Paulo os_memset(&data, 0, sizeof(data)); 371f05cddf9SRui Paulo os_memcpy(&data.michael_mic_failure.unicast, buf, sizeof(int)); 372f05cddf9SRui Paulo wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); 373f05cddf9SRui Paulo } 374f05cddf9SRui Paulo 375f05cddf9SRui Paulo 376f05cddf9SRui Paulo static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf, 377f05cddf9SRui Paulo size_t len) 378f05cddf9SRui Paulo { 379f05cddf9SRui Paulo union wpa_event_data data; 380f05cddf9SRui Paulo 381f05cddf9SRui Paulo if (len != sizeof(struct pmkid_candidate)) 382f05cddf9SRui Paulo return; 383f05cddf9SRui Paulo 384f05cddf9SRui Paulo os_memset(&data, 0, sizeof(data)); 385f05cddf9SRui Paulo os_memcpy(&data.pmkid_candidate, buf, len); 386f05cddf9SRui Paulo wpa_supplicant_event(ctx, EVENT_PMKID_CANDIDATE, &data); 387f05cddf9SRui Paulo } 388f05cddf9SRui Paulo 389f05cddf9SRui Paulo 390f05cddf9SRui Paulo static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len) 391f05cddf9SRui Paulo { 392f05cddf9SRui Paulo union wpa_event_data data; 393f05cddf9SRui Paulo 394f05cddf9SRui Paulo if (len != ETH_ALEN) 395f05cddf9SRui Paulo return; 396f05cddf9SRui Paulo 397f05cddf9SRui Paulo os_memset(&data, 0, sizeof(data)); 398f05cddf9SRui Paulo os_memcpy(data.stkstart.peer, buf, ETH_ALEN); 399f05cddf9SRui Paulo wpa_supplicant_event(ctx, EVENT_STKSTART, &data); 400f05cddf9SRui Paulo } 401f05cddf9SRui Paulo 402f05cddf9SRui Paulo 403f05cddf9SRui Paulo static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf, 404f05cddf9SRui Paulo size_t len) 405f05cddf9SRui Paulo { 406f05cddf9SRui Paulo union wpa_event_data data; 407f05cddf9SRui Paulo 408f05cddf9SRui Paulo if (len < sizeof(int) + ETH_ALEN) 409f05cddf9SRui Paulo return; 410f05cddf9SRui Paulo 411f05cddf9SRui Paulo os_memset(&data, 0, sizeof(data)); 412f05cddf9SRui Paulo os_memcpy(&data.ft_ies.ft_action, buf, sizeof(int)); 413f05cddf9SRui Paulo os_memcpy(data.ft_ies.target_ap, buf + sizeof(int), ETH_ALEN); 414f05cddf9SRui Paulo data.ft_ies.ies = buf + sizeof(int) + ETH_ALEN; 415f05cddf9SRui Paulo data.ft_ies.ies_len = len - sizeof(int) - ETH_ALEN; 416f05cddf9SRui Paulo wpa_supplicant_event(ctx, EVENT_FT_RESPONSE, &data); 417f05cddf9SRui Paulo } 418f05cddf9SRui Paulo 419f05cddf9SRui Paulo 420f05cddf9SRui Paulo static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len) 421f05cddf9SRui Paulo { 422f05cddf9SRui Paulo if (len < ETH_ALEN) 423f05cddf9SRui Paulo return; 424f05cddf9SRui Paulo drv_event_eapol_rx(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN); 425f05cddf9SRui Paulo } 426f05cddf9SRui Paulo 427f05cddf9SRui Paulo 428f05cddf9SRui Paulo static void wpa_driver_privsep_receive(int sock, void *eloop_ctx, 429f05cddf9SRui Paulo void *sock_ctx) 430f05cddf9SRui Paulo { 431f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = eloop_ctx; 432f05cddf9SRui Paulo u8 *buf, *event_buf; 433f05cddf9SRui Paulo size_t event_len; 434f05cddf9SRui Paulo int res, event; 435f05cddf9SRui Paulo enum privsep_event e; 436f05cddf9SRui Paulo struct sockaddr_un from; 437f05cddf9SRui Paulo socklen_t fromlen = sizeof(from); 438f05cddf9SRui Paulo const size_t buflen = 2000; 439f05cddf9SRui Paulo 440f05cddf9SRui Paulo buf = os_malloc(buflen); 441f05cddf9SRui Paulo if (buf == NULL) 442f05cddf9SRui Paulo return; 443f05cddf9SRui Paulo res = recvfrom(sock, buf, buflen, 0, 444f05cddf9SRui Paulo (struct sockaddr *) &from, &fromlen); 445f05cddf9SRui Paulo if (res < 0) { 446*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "recvfrom(priv_socket): %s", 447*5b9c547cSRui Paulo strerror(errno)); 448f05cddf9SRui Paulo os_free(buf); 449f05cddf9SRui Paulo return; 450f05cddf9SRui Paulo } 451f05cddf9SRui Paulo 452f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "privsep_driver: received %u bytes", res); 453f05cddf9SRui Paulo 454f05cddf9SRui Paulo if (res < (int) sizeof(int)) { 455f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "Too short event message (len=%d)", res); 456f05cddf9SRui Paulo return; 457f05cddf9SRui Paulo } 458f05cddf9SRui Paulo 459f05cddf9SRui Paulo os_memcpy(&event, buf, sizeof(int)); 460f05cddf9SRui Paulo event_buf = &buf[sizeof(int)]; 461f05cddf9SRui Paulo event_len = res - sizeof(int); 462f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)", 463f05cddf9SRui Paulo event, (unsigned long) event_len); 464f05cddf9SRui Paulo 465f05cddf9SRui Paulo e = event; 466f05cddf9SRui Paulo switch (e) { 467f05cddf9SRui Paulo case PRIVSEP_EVENT_SCAN_RESULTS: 468f05cddf9SRui Paulo wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL); 469f05cddf9SRui Paulo break; 470f05cddf9SRui Paulo case PRIVSEP_EVENT_ASSOC: 471f05cddf9SRui Paulo wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC, 472f05cddf9SRui Paulo event_buf, event_len); 473f05cddf9SRui Paulo break; 474f05cddf9SRui Paulo case PRIVSEP_EVENT_DISASSOC: 475f05cddf9SRui Paulo wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); 476f05cddf9SRui Paulo break; 477f05cddf9SRui Paulo case PRIVSEP_EVENT_ASSOCINFO: 478f05cddf9SRui Paulo wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOCINFO, 479f05cddf9SRui Paulo event_buf, event_len); 480f05cddf9SRui Paulo break; 481f05cddf9SRui Paulo case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE: 482f05cddf9SRui Paulo wpa_driver_privsep_event_michael_mic_failure( 483f05cddf9SRui Paulo drv->ctx, event_buf, event_len); 484f05cddf9SRui Paulo break; 485f05cddf9SRui Paulo case PRIVSEP_EVENT_INTERFACE_STATUS: 486f05cddf9SRui Paulo wpa_driver_privsep_event_interface_status(drv->ctx, event_buf, 487f05cddf9SRui Paulo event_len); 488f05cddf9SRui Paulo break; 489f05cddf9SRui Paulo case PRIVSEP_EVENT_PMKID_CANDIDATE: 490f05cddf9SRui Paulo wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf, 491f05cddf9SRui Paulo event_len); 492f05cddf9SRui Paulo break; 493f05cddf9SRui Paulo case PRIVSEP_EVENT_STKSTART: 494f05cddf9SRui Paulo wpa_driver_privsep_event_stkstart(drv->ctx, event_buf, 495f05cddf9SRui Paulo event_len); 496f05cddf9SRui Paulo break; 497f05cddf9SRui Paulo case PRIVSEP_EVENT_FT_RESPONSE: 498f05cddf9SRui Paulo wpa_driver_privsep_event_ft_response(drv->ctx, event_buf, 499f05cddf9SRui Paulo event_len); 500f05cddf9SRui Paulo break; 501f05cddf9SRui Paulo case PRIVSEP_EVENT_RX_EAPOL: 502f05cddf9SRui Paulo wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf, 503f05cddf9SRui Paulo event_len); 504f05cddf9SRui Paulo break; 505f05cddf9SRui Paulo } 506f05cddf9SRui Paulo 507f05cddf9SRui Paulo os_free(buf); 508f05cddf9SRui Paulo } 509f05cddf9SRui Paulo 510f05cddf9SRui Paulo 511f05cddf9SRui Paulo static void * wpa_driver_privsep_init(void *ctx, const char *ifname) 512f05cddf9SRui Paulo { 513f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv; 514f05cddf9SRui Paulo 515f05cddf9SRui Paulo drv = os_zalloc(sizeof(*drv)); 516f05cddf9SRui Paulo if (drv == NULL) 517f05cddf9SRui Paulo return NULL; 518f05cddf9SRui Paulo drv->ctx = ctx; 519f05cddf9SRui Paulo drv->priv_socket = -1; 520f05cddf9SRui Paulo drv->cmd_socket = -1; 521f05cddf9SRui Paulo os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); 522f05cddf9SRui Paulo 523f05cddf9SRui Paulo return drv; 524f05cddf9SRui Paulo } 525f05cddf9SRui Paulo 526f05cddf9SRui Paulo 527f05cddf9SRui Paulo static void wpa_driver_privsep_deinit(void *priv) 528f05cddf9SRui Paulo { 529f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = priv; 530f05cddf9SRui Paulo 531f05cddf9SRui Paulo if (drv->priv_socket >= 0) { 532f05cddf9SRui Paulo wpa_priv_reg_cmd(drv, PRIVSEP_CMD_UNREGISTER); 533f05cddf9SRui Paulo eloop_unregister_read_sock(drv->priv_socket); 534f05cddf9SRui Paulo close(drv->priv_socket); 535f05cddf9SRui Paulo } 536f05cddf9SRui Paulo 537f05cddf9SRui Paulo if (drv->own_socket_path) { 538f05cddf9SRui Paulo unlink(drv->own_socket_path); 539f05cddf9SRui Paulo os_free(drv->own_socket_path); 540f05cddf9SRui Paulo } 541f05cddf9SRui Paulo 542f05cddf9SRui Paulo if (drv->cmd_socket >= 0) { 543f05cddf9SRui Paulo eloop_unregister_read_sock(drv->cmd_socket); 544f05cddf9SRui Paulo close(drv->cmd_socket); 545f05cddf9SRui Paulo } 546f05cddf9SRui Paulo 547f05cddf9SRui Paulo if (drv->own_cmd_path) { 548f05cddf9SRui Paulo unlink(drv->own_cmd_path); 549f05cddf9SRui Paulo os_free(drv->own_cmd_path); 550f05cddf9SRui Paulo } 551f05cddf9SRui Paulo 552f05cddf9SRui Paulo os_free(drv); 553f05cddf9SRui Paulo } 554f05cddf9SRui Paulo 555f05cddf9SRui Paulo 556f05cddf9SRui Paulo static int wpa_driver_privsep_set_param(void *priv, const char *param) 557f05cddf9SRui Paulo { 558f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = priv; 559f05cddf9SRui Paulo const char *pos; 560f05cddf9SRui Paulo char *own_dir, *priv_dir; 561f05cddf9SRui Paulo static unsigned int counter = 0; 562f05cddf9SRui Paulo size_t len; 563f05cddf9SRui Paulo struct sockaddr_un addr; 564f05cddf9SRui Paulo 565f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param); 566f05cddf9SRui Paulo if (param == NULL) 567f05cddf9SRui Paulo pos = NULL; 568f05cddf9SRui Paulo else 569f05cddf9SRui Paulo pos = os_strstr(param, "own_dir="); 570f05cddf9SRui Paulo if (pos) { 571f05cddf9SRui Paulo char *end; 572f05cddf9SRui Paulo own_dir = os_strdup(pos + 8); 573f05cddf9SRui Paulo if (own_dir == NULL) 574f05cddf9SRui Paulo return -1; 575f05cddf9SRui Paulo end = os_strchr(own_dir, ' '); 576f05cddf9SRui Paulo if (end) 577f05cddf9SRui Paulo *end = '\0'; 578f05cddf9SRui Paulo } else { 579f05cddf9SRui Paulo own_dir = os_strdup("/tmp"); 580f05cddf9SRui Paulo if (own_dir == NULL) 581f05cddf9SRui Paulo return -1; 582f05cddf9SRui Paulo } 583f05cddf9SRui Paulo 584f05cddf9SRui Paulo if (param == NULL) 585f05cddf9SRui Paulo pos = NULL; 586f05cddf9SRui Paulo else 587f05cddf9SRui Paulo pos = os_strstr(param, "priv_dir="); 588f05cddf9SRui Paulo if (pos) { 589f05cddf9SRui Paulo char *end; 590f05cddf9SRui Paulo priv_dir = os_strdup(pos + 9); 591f05cddf9SRui Paulo if (priv_dir == NULL) { 592f05cddf9SRui Paulo os_free(own_dir); 593f05cddf9SRui Paulo return -1; 594f05cddf9SRui Paulo } 595f05cddf9SRui Paulo end = os_strchr(priv_dir, ' '); 596f05cddf9SRui Paulo if (end) 597f05cddf9SRui Paulo *end = '\0'; 598f05cddf9SRui Paulo } else { 599f05cddf9SRui Paulo priv_dir = os_strdup("/var/run/wpa_priv"); 600f05cddf9SRui Paulo if (priv_dir == NULL) { 601f05cddf9SRui Paulo os_free(own_dir); 602f05cddf9SRui Paulo return -1; 603f05cddf9SRui Paulo } 604f05cddf9SRui Paulo } 605f05cddf9SRui Paulo 606f05cddf9SRui Paulo len = os_strlen(own_dir) + 50; 607f05cddf9SRui Paulo drv->own_socket_path = os_malloc(len); 608f05cddf9SRui Paulo if (drv->own_socket_path == NULL) { 609f05cddf9SRui Paulo os_free(priv_dir); 610f05cddf9SRui Paulo os_free(own_dir); 611f05cddf9SRui Paulo return -1; 612f05cddf9SRui Paulo } 613f05cddf9SRui Paulo os_snprintf(drv->own_socket_path, len, "%s/wpa_privsep-%d-%d", 614f05cddf9SRui Paulo own_dir, getpid(), counter++); 615f05cddf9SRui Paulo 616f05cddf9SRui Paulo len = os_strlen(own_dir) + 50; 617f05cddf9SRui Paulo drv->own_cmd_path = os_malloc(len); 618f05cddf9SRui Paulo if (drv->own_cmd_path == NULL) { 619f05cddf9SRui Paulo os_free(drv->own_socket_path); 620f05cddf9SRui Paulo drv->own_socket_path = NULL; 621f05cddf9SRui Paulo os_free(priv_dir); 622f05cddf9SRui Paulo os_free(own_dir); 623f05cddf9SRui Paulo return -1; 624f05cddf9SRui Paulo } 625f05cddf9SRui Paulo os_snprintf(drv->own_cmd_path, len, "%s/wpa_privsep-%d-%d", 626f05cddf9SRui Paulo own_dir, getpid(), counter++); 627f05cddf9SRui Paulo 628f05cddf9SRui Paulo os_free(own_dir); 629f05cddf9SRui Paulo 630f05cddf9SRui Paulo drv->priv_addr.sun_family = AF_UNIX; 631f05cddf9SRui Paulo os_snprintf(drv->priv_addr.sun_path, sizeof(drv->priv_addr.sun_path), 632f05cddf9SRui Paulo "%s/%s", priv_dir, drv->ifname); 633f05cddf9SRui Paulo os_free(priv_dir); 634f05cddf9SRui Paulo 635f05cddf9SRui Paulo drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0); 636f05cddf9SRui Paulo if (drv->priv_socket < 0) { 637*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); 638f05cddf9SRui Paulo os_free(drv->own_socket_path); 639f05cddf9SRui Paulo drv->own_socket_path = NULL; 640f05cddf9SRui Paulo return -1; 641f05cddf9SRui Paulo } 642f05cddf9SRui Paulo 643f05cddf9SRui Paulo os_memset(&addr, 0, sizeof(addr)); 644f05cddf9SRui Paulo addr.sun_family = AF_UNIX; 645f05cddf9SRui Paulo os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path)); 646f05cddf9SRui Paulo if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) < 647f05cddf9SRui Paulo 0) { 648*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, 649*5b9c547cSRui Paulo "privsep-set-params priv-sock: bind(PF_UNIX): %s", 650*5b9c547cSRui Paulo strerror(errno)); 651f05cddf9SRui Paulo close(drv->priv_socket); 652f05cddf9SRui Paulo drv->priv_socket = -1; 653f05cddf9SRui Paulo unlink(drv->own_socket_path); 654f05cddf9SRui Paulo os_free(drv->own_socket_path); 655f05cddf9SRui Paulo drv->own_socket_path = NULL; 656f05cddf9SRui Paulo return -1; 657f05cddf9SRui Paulo } 658f05cddf9SRui Paulo 659f05cddf9SRui Paulo eloop_register_read_sock(drv->priv_socket, wpa_driver_privsep_receive, 660f05cddf9SRui Paulo drv, NULL); 661f05cddf9SRui Paulo 662f05cddf9SRui Paulo drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0); 663f05cddf9SRui Paulo if (drv->cmd_socket < 0) { 664*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); 665f05cddf9SRui Paulo os_free(drv->own_cmd_path); 666f05cddf9SRui Paulo drv->own_cmd_path = NULL; 667f05cddf9SRui Paulo return -1; 668f05cddf9SRui Paulo } 669f05cddf9SRui Paulo 670f05cddf9SRui Paulo os_memset(&addr, 0, sizeof(addr)); 671f05cddf9SRui Paulo addr.sun_family = AF_UNIX; 672f05cddf9SRui Paulo os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path)); 673f05cddf9SRui Paulo if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0) 674f05cddf9SRui Paulo { 675*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, 676*5b9c547cSRui Paulo "privsep-set-params cmd-sock: bind(PF_UNIX): %s", 677*5b9c547cSRui Paulo strerror(errno)); 678f05cddf9SRui Paulo close(drv->cmd_socket); 679f05cddf9SRui Paulo drv->cmd_socket = -1; 680f05cddf9SRui Paulo unlink(drv->own_cmd_path); 681f05cddf9SRui Paulo os_free(drv->own_cmd_path); 682f05cddf9SRui Paulo drv->own_cmd_path = NULL; 683f05cddf9SRui Paulo return -1; 684f05cddf9SRui Paulo } 685f05cddf9SRui Paulo 686f05cddf9SRui Paulo if (wpa_priv_reg_cmd(drv, PRIVSEP_CMD_REGISTER) < 0) { 687f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Failed to register with wpa_priv"); 688f05cddf9SRui Paulo return -1; 689f05cddf9SRui Paulo } 690f05cddf9SRui Paulo 691f05cddf9SRui Paulo return 0; 692f05cddf9SRui Paulo } 693f05cddf9SRui Paulo 694f05cddf9SRui Paulo 695f05cddf9SRui Paulo static int wpa_driver_privsep_get_capa(void *priv, 696f05cddf9SRui Paulo struct wpa_driver_capa *capa) 697f05cddf9SRui Paulo { 698f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = priv; 699f05cddf9SRui Paulo int res; 700f05cddf9SRui Paulo size_t len = sizeof(*capa); 701f05cddf9SRui Paulo 702f05cddf9SRui Paulo res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len); 703f05cddf9SRui Paulo if (res < 0 || len != sizeof(*capa)) 704f05cddf9SRui Paulo return -1; 705f05cddf9SRui Paulo return 0; 706f05cddf9SRui Paulo } 707f05cddf9SRui Paulo 708f05cddf9SRui Paulo 709f05cddf9SRui Paulo static const u8 * wpa_driver_privsep_get_mac_addr(void *priv) 710f05cddf9SRui Paulo { 711f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = priv; 712f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s", __func__); 713f05cddf9SRui Paulo return drv->own_addr; 714f05cddf9SRui Paulo } 715f05cddf9SRui Paulo 716f05cddf9SRui Paulo 717f05cddf9SRui Paulo static int wpa_driver_privsep_set_country(void *priv, const char *alpha2) 718f05cddf9SRui Paulo { 719f05cddf9SRui Paulo struct wpa_driver_privsep_data *drv = priv; 720f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2); 721f05cddf9SRui Paulo return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2, 722f05cddf9SRui Paulo os_strlen(alpha2), NULL, NULL); 723f05cddf9SRui Paulo } 724f05cddf9SRui Paulo 725f05cddf9SRui Paulo 726f05cddf9SRui Paulo struct wpa_driver_ops wpa_driver_privsep_ops = { 727f05cddf9SRui Paulo "privsep", 728f05cddf9SRui Paulo "wpa_supplicant privilege separated driver", 729f05cddf9SRui Paulo .get_bssid = wpa_driver_privsep_get_bssid, 730f05cddf9SRui Paulo .get_ssid = wpa_driver_privsep_get_ssid, 731f05cddf9SRui Paulo .set_key = wpa_driver_privsep_set_key, 732f05cddf9SRui Paulo .init = wpa_driver_privsep_init, 733f05cddf9SRui Paulo .deinit = wpa_driver_privsep_deinit, 734f05cddf9SRui Paulo .set_param = wpa_driver_privsep_set_param, 735f05cddf9SRui Paulo .scan2 = wpa_driver_privsep_scan, 736f05cddf9SRui Paulo .deauthenticate = wpa_driver_privsep_deauthenticate, 737f05cddf9SRui Paulo .associate = wpa_driver_privsep_associate, 738f05cddf9SRui Paulo .get_capa = wpa_driver_privsep_get_capa, 739f05cddf9SRui Paulo .get_mac_addr = wpa_driver_privsep_get_mac_addr, 740f05cddf9SRui Paulo .get_scan_results2 = wpa_driver_privsep_get_scan_results2, 741f05cddf9SRui Paulo .set_country = wpa_driver_privsep_set_country, 742f05cddf9SRui Paulo }; 743f05cddf9SRui Paulo 744f05cddf9SRui Paulo 745f05cddf9SRui Paulo struct wpa_driver_ops *wpa_drivers[] = 746f05cddf9SRui Paulo { 747f05cddf9SRui Paulo &wpa_driver_privsep_ops, 748f05cddf9SRui Paulo NULL 749f05cddf9SRui Paulo }; 750