1209139Srpaulo/* 2209139Srpaulo * WPA Supplicant / Windows Named Pipe -based control interface 3209139Srpaulo * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> 4209139Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7209139Srpaulo */ 8209139Srpaulo 9209139Srpaulo#include "includes.h" 10209139Srpaulo 11209139Srpaulo#include "common.h" 12209139Srpaulo#include "eloop.h" 13209139Srpaulo#include "config.h" 14209139Srpaulo#include "eapol_supp/eapol_supp_sm.h" 15209139Srpaulo#include "wpa_supplicant_i.h" 16209139Srpaulo#include "ctrl_iface.h" 17214734Srpaulo#include "common/wpa_ctrl.h" 18209139Srpaulo 19209139Srpaulo#ifdef __MINGW32_VERSION 20209139Srpaulo/* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here 21209139Srpaulo */ 22209139Srpaulo#define SDDL_REVISION_1 1 23209139SrpauloBOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA( 24209139Srpaulo LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); 25209139SrpauloBOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW( 26209139Srpaulo LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); 27209139Srpaulo#ifdef UNICODE 28209139Srpaulo#define ConvertStringSecurityDescriptorToSecurityDescriptor \ 29209139SrpauloConvertStringSecurityDescriptorToSecurityDescriptorW 30209139Srpaulo#else 31209139Srpaulo#define ConvertStringSecurityDescriptorToSecurityDescriptor \ 32209139SrpauloConvertStringSecurityDescriptorToSecurityDescriptorA 33209139Srpaulo#endif 34209139Srpaulo#else /* __MINGW32_VERSION */ 35209139Srpaulo#ifndef _WIN32_WINNT 36209139Srpaulo#define _WIN32_WINNT 0x0500 37209139Srpaulo#endif 38209139Srpaulo#include <sddl.h> 39209139Srpaulo#endif /* __MINGW32_VERSION */ 40209139Srpaulo 41209139Srpaulo#ifndef WPA_SUPPLICANT_NAMED_PIPE 42209139Srpaulo#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" 43209139Srpaulo#endif 44209139Srpaulo#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) 45209139Srpaulo 46209139Srpaulo/* Per-interface ctrl_iface */ 47209139Srpaulo 48209139Srpaulo#define REQUEST_BUFSIZE 256 49209139Srpaulo#define REPLY_BUFSIZE 4096 50209139Srpaulo 51209139Srpaulostruct ctrl_iface_priv; 52209139Srpaulo 53209139Srpaulo/** 54209139Srpaulo * struct wpa_ctrl_dst - Internal data structure of control interface clients 55209139Srpaulo * 56209139Srpaulo * This structure is used to store information about registered control 57209139Srpaulo * interface monitors into struct wpa_supplicant. This data is private to 58209139Srpaulo * ctrl_iface_named_pipe.c and should not be touched directly from other files. 59209139Srpaulo */ 60209139Srpaulostruct wpa_ctrl_dst { 61209139Srpaulo /* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */ 62209139Srpaulo OVERLAPPED overlap; 63209139Srpaulo struct wpa_ctrl_dst *next, *prev; 64209139Srpaulo struct ctrl_iface_priv *priv; 65209139Srpaulo HANDLE pipe; 66209139Srpaulo int attached; 67209139Srpaulo int debug_level; 68209139Srpaulo int errors; 69209139Srpaulo char req_buf[REQUEST_BUFSIZE]; 70209139Srpaulo char *rsp_buf; 71209139Srpaulo int used; 72209139Srpaulo}; 73209139Srpaulo 74209139Srpaulo 75209139Srpaulostruct ctrl_iface_priv { 76209139Srpaulo struct wpa_supplicant *wpa_s; 77209139Srpaulo struct wpa_ctrl_dst *ctrl_dst; 78209139Srpaulo SECURITY_ATTRIBUTES attr; 79209139Srpaulo int sec_attr_set; 80209139Srpaulo}; 81209139Srpaulo 82209139Srpaulo 83209139Srpaulostatic void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 84209139Srpaulo int level, const char *buf, 85209139Srpaulo size_t len); 86209139Srpaulo 87209139Srpaulostatic void ctrl_close_pipe(struct wpa_ctrl_dst *dst); 88209139Srpaulostatic void wpa_supplicant_ctrl_iface_receive(void *, void *); 89209139Srpaulostatic VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, 90209139Srpaulo LPOVERLAPPED overlap); 91209139Srpaulo 92209139Srpaulostruct wpa_global_dst; 93209139Srpaulostatic void global_close_pipe(struct wpa_global_dst *dst); 94209139Srpaulostatic void wpa_supplicant_global_iface_receive(void *eloop_data, 95209139Srpaulo void *user_ctx); 96209139Srpaulostatic VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, 97209139Srpaulo LPOVERLAPPED overlap); 98209139Srpaulo 99209139Srpaulo 100209139Srpaulostatic int ctrl_broken_pipe(HANDLE pipe, int used) 101209139Srpaulo{ 102209139Srpaulo DWORD err; 103209139Srpaulo 104209139Srpaulo if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL)) 105209139Srpaulo return 0; 106209139Srpaulo 107209139Srpaulo err = GetLastError(); 108209139Srpaulo if (err == ERROR_BROKEN_PIPE || (err == ERROR_BAD_PIPE && used)) 109209139Srpaulo return 1; 110209139Srpaulo return 0; 111209139Srpaulo} 112209139Srpaulo 113209139Srpaulo 114209139Srpaulostatic void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv) 115209139Srpaulo{ 116209139Srpaulo struct wpa_ctrl_dst *dst, *next; 117209139Srpaulo 118209139Srpaulo dst = priv->ctrl_dst; 119209139Srpaulo 120209139Srpaulo while (dst) { 121209139Srpaulo next = dst->next; 122209139Srpaulo if (ctrl_broken_pipe(dst->pipe, dst->used)) { 123209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", 124209139Srpaulo dst); 125209139Srpaulo ctrl_close_pipe(dst); 126209139Srpaulo } 127209139Srpaulo dst = next; 128209139Srpaulo } 129209139Srpaulo} 130209139Srpaulo 131209139Srpaulo 132209139Srpaulostatic int ctrl_open_pipe(struct ctrl_iface_priv *priv) 133209139Srpaulo{ 134209139Srpaulo struct wpa_ctrl_dst *dst; 135209139Srpaulo DWORD err; 136209139Srpaulo TCHAR name[256]; 137209139Srpaulo 138209139Srpaulo dst = os_zalloc(sizeof(*dst)); 139209139Srpaulo if (dst == NULL) 140209139Srpaulo return -1; 141209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); 142209139Srpaulo 143209139Srpaulo dst->priv = priv; 144209139Srpaulo dst->debug_level = MSG_INFO; 145209139Srpaulo dst->pipe = INVALID_HANDLE_VALUE; 146209139Srpaulo 147209139Srpaulo dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 148209139Srpaulo if (dst->overlap.hEvent == NULL) { 149209139Srpaulo wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", 150209139Srpaulo (int) GetLastError()); 151209139Srpaulo goto fail; 152209139Srpaulo } 153209139Srpaulo 154209139Srpaulo eloop_register_event(dst->overlap.hEvent, 155209139Srpaulo sizeof(dst->overlap.hEvent), 156209139Srpaulo wpa_supplicant_ctrl_iface_receive, dst, NULL); 157209139Srpaulo 158209139Srpaulo#ifdef UNICODE 159209139Srpaulo _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), 160209139Srpaulo priv->wpa_s->ifname); 161209139Srpaulo#else /* UNICODE */ 162209139Srpaulo os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", 163209139Srpaulo priv->wpa_s->ifname); 164209139Srpaulo#endif /* UNICODE */ 165209139Srpaulo 166209139Srpaulo /* TODO: add support for configuring access list for the pipe */ 167209139Srpaulo dst->pipe = CreateNamedPipe(name, 168209139Srpaulo PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 169209139Srpaulo PIPE_TYPE_MESSAGE | 170209139Srpaulo PIPE_READMODE_MESSAGE | 171209139Srpaulo PIPE_WAIT, 172209139Srpaulo 15, REPLY_BUFSIZE, REQUEST_BUFSIZE, 173209139Srpaulo 1000, 174209139Srpaulo priv->sec_attr_set ? &priv->attr : NULL); 175209139Srpaulo if (dst->pipe == INVALID_HANDLE_VALUE) { 176209139Srpaulo wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", 177209139Srpaulo (int) GetLastError()); 178209139Srpaulo goto fail; 179209139Srpaulo } 180209139Srpaulo 181209139Srpaulo if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { 182209139Srpaulo wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", 183209139Srpaulo (int) GetLastError()); 184209139Srpaulo CloseHandle(dst->pipe); 185209139Srpaulo os_free(dst); 186209139Srpaulo return -1; 187209139Srpaulo } 188209139Srpaulo 189209139Srpaulo err = GetLastError(); 190209139Srpaulo switch (err) { 191209139Srpaulo case ERROR_IO_PENDING: 192209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " 193209139Srpaulo "progress"); 194209139Srpaulo break; 195209139Srpaulo case ERROR_PIPE_CONNECTED: 196209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " 197209139Srpaulo "connected"); 198209139Srpaulo if (SetEvent(dst->overlap.hEvent)) 199209139Srpaulo break; 200209139Srpaulo /* fall through */ 201209139Srpaulo default: 202209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", 203209139Srpaulo (int) err); 204209139Srpaulo CloseHandle(dst->pipe); 205209139Srpaulo os_free(dst); 206209139Srpaulo return -1; 207209139Srpaulo } 208209139Srpaulo 209209139Srpaulo dst->next = priv->ctrl_dst; 210209139Srpaulo if (dst->next) 211209139Srpaulo dst->next->prev = dst; 212209139Srpaulo priv->ctrl_dst = dst; 213209139Srpaulo 214209139Srpaulo return 0; 215209139Srpaulo 216209139Srpaulofail: 217209139Srpaulo ctrl_close_pipe(dst); 218209139Srpaulo return -1; 219209139Srpaulo} 220209139Srpaulo 221209139Srpaulo 222209139Srpaulostatic void ctrl_close_pipe(struct wpa_ctrl_dst *dst) 223209139Srpaulo{ 224209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); 225209139Srpaulo 226209139Srpaulo if (dst->overlap.hEvent) { 227209139Srpaulo eloop_unregister_event(dst->overlap.hEvent, 228209139Srpaulo sizeof(dst->overlap.hEvent)); 229209139Srpaulo CloseHandle(dst->overlap.hEvent); 230209139Srpaulo } 231209139Srpaulo 232209139Srpaulo if (dst->pipe != INVALID_HANDLE_VALUE) { 233209139Srpaulo /* 234209139Srpaulo * Could use FlushFileBuffers() here to guarantee that all data 235209139Srpaulo * gets delivered to the client, but that can block, so let's 236209139Srpaulo * not do this for now. 237209139Srpaulo * FlushFileBuffers(dst->pipe); 238209139Srpaulo */ 239209139Srpaulo CloseHandle(dst->pipe); 240209139Srpaulo } 241209139Srpaulo 242209139Srpaulo if (dst->prev) 243209139Srpaulo dst->prev->next = dst->next; 244209139Srpaulo else 245209139Srpaulo dst->priv->ctrl_dst = dst->next; 246209139Srpaulo if (dst->next) 247209139Srpaulo dst->next->prev = dst->prev; 248209139Srpaulo 249209139Srpaulo os_free(dst->rsp_buf); 250209139Srpaulo os_free(dst); 251209139Srpaulo} 252209139Srpaulo 253209139Srpaulo 254209139Srpaulostatic VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes, 255209139Srpaulo LPOVERLAPPED overlap) 256209139Srpaulo{ 257209139Srpaulo struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; 258209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " 259209139Srpaulo "err=%d bytes=%d", dst, (int) err, (int) bytes); 260209139Srpaulo if (err) { 261209139Srpaulo ctrl_close_pipe(dst); 262209139Srpaulo return; 263209139Srpaulo } 264209139Srpaulo 265209139Srpaulo os_free(dst->rsp_buf); 266209139Srpaulo dst->rsp_buf = NULL; 267209139Srpaulo 268209139Srpaulo if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), 269209139Srpaulo &dst->overlap, ctrl_iface_read_completed)) { 270209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", 271209139Srpaulo (int) GetLastError()); 272209139Srpaulo ctrl_close_pipe(dst); 273209139Srpaulo return; 274209139Srpaulo } 275209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); 276209139Srpaulo} 277209139Srpaulo 278209139Srpaulo 279209139Srpaulostatic void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len) 280209139Srpaulo{ 281209139Srpaulo struct wpa_supplicant *wpa_s = dst->priv->wpa_s; 282209139Srpaulo char *reply = NULL, *send_buf; 283209139Srpaulo size_t reply_len = 0, send_len; 284209139Srpaulo int new_attached = 0; 285209139Srpaulo char *buf = dst->req_buf; 286209139Srpaulo 287209139Srpaulo dst->used = 1; 288209139Srpaulo if (len >= REQUEST_BUFSIZE) 289209139Srpaulo len = REQUEST_BUFSIZE - 1; 290209139Srpaulo buf[len] = '\0'; 291209139Srpaulo 292209139Srpaulo if (os_strcmp(buf, "ATTACH") == 0) { 293209139Srpaulo dst->attached = 1; 294209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached"); 295209139Srpaulo new_attached = 1; 296209139Srpaulo reply_len = 2; 297209139Srpaulo } else if (os_strcmp(buf, "DETACH") == 0) { 298209139Srpaulo dst->attached = 0; 299209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached"); 300209139Srpaulo reply_len = 2; 301209139Srpaulo } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 302209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6); 303209139Srpaulo dst->debug_level = atoi(buf + 6); 304209139Srpaulo reply_len = 2; 305209139Srpaulo } else { 306209139Srpaulo reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, 307209139Srpaulo &reply_len); 308209139Srpaulo } 309209139Srpaulo 310209139Srpaulo if (reply) { 311209139Srpaulo send_buf = reply; 312209139Srpaulo send_len = reply_len; 313209139Srpaulo } else if (reply_len == 2) { 314209139Srpaulo send_buf = "OK\n"; 315209139Srpaulo send_len = 3; 316209139Srpaulo } else { 317209139Srpaulo send_buf = "FAIL\n"; 318209139Srpaulo send_len = 5; 319209139Srpaulo } 320209139Srpaulo 321209139Srpaulo os_free(dst->rsp_buf); 322346981Scy dst->rsp_buf = os_memdup(send_buf, send_len); 323209139Srpaulo if (dst->rsp_buf == NULL) { 324209139Srpaulo ctrl_close_pipe(dst); 325209139Srpaulo os_free(reply); 326209139Srpaulo return; 327209139Srpaulo } 328209139Srpaulo os_free(reply); 329209139Srpaulo 330209139Srpaulo if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, 331209139Srpaulo ctrl_iface_write_completed)) { 332209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", 333209139Srpaulo (int) GetLastError()); 334209139Srpaulo ctrl_close_pipe(dst); 335209139Srpaulo } else { 336209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", 337209139Srpaulo dst); 338209139Srpaulo } 339209139Srpaulo 340209139Srpaulo if (new_attached) 341209139Srpaulo eapol_sm_notify_ctrl_attached(wpa_s->eapol); 342209139Srpaulo} 343209139Srpaulo 344209139Srpaulo 345209139Srpaulostatic VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, 346209139Srpaulo LPOVERLAPPED overlap) 347209139Srpaulo{ 348209139Srpaulo struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; 349209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " 350209139Srpaulo "bytes=%d", dst, (int) err, (int) bytes); 351209139Srpaulo if (err == 0 && bytes > 0) 352209139Srpaulo wpa_supplicant_ctrl_iface_rx(dst, bytes); 353209139Srpaulo} 354209139Srpaulo 355209139Srpaulo 356209139Srpaulostatic void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx) 357209139Srpaulo{ 358209139Srpaulo struct wpa_ctrl_dst *dst = eloop_data; 359209139Srpaulo struct ctrl_iface_priv *priv = dst->priv; 360209139Srpaulo DWORD bytes; 361209139Srpaulo 362209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive"); 363209139Srpaulo ResetEvent(dst->overlap.hEvent); 364209139Srpaulo 365209139Srpaulo if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { 366209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", 367209139Srpaulo (int) GetLastError()); 368209139Srpaulo return; 369209139Srpaulo } 370209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " 371209139Srpaulo "connected"); 372209139Srpaulo 373209139Srpaulo /* Open a new named pipe for the next client. */ 374209139Srpaulo ctrl_open_pipe(priv); 375209139Srpaulo 376209139Srpaulo /* Use write completion function to start reading a command */ 377209139Srpaulo ctrl_iface_write_completed(0, 0, &dst->overlap); 378209139Srpaulo 379209139Srpaulo ctrl_flush_broken_pipes(priv); 380209139Srpaulo} 381209139Srpaulo 382209139Srpaulo 383209139Srpaulostatic int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params) 384209139Srpaulo{ 385209139Srpaulo const char *sddl = NULL; 386209139Srpaulo TCHAR *t_sddl; 387209139Srpaulo 388209139Srpaulo if (os_strncmp(params, "SDDL=", 5) == 0) 389209139Srpaulo sddl = params + 5; 390209139Srpaulo if (!sddl) { 391209139Srpaulo sddl = os_strstr(params, " SDDL="); 392209139Srpaulo if (sddl) 393209139Srpaulo sddl += 6; 394209139Srpaulo } 395209139Srpaulo 396209139Srpaulo if (!sddl) 397209139Srpaulo return 0; 398209139Srpaulo 399209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl); 400209139Srpaulo os_memset(&priv->attr, 0, sizeof(priv->attr)); 401209139Srpaulo priv->attr.nLength = sizeof(priv->attr); 402209139Srpaulo priv->attr.bInheritHandle = FALSE; 403209139Srpaulo t_sddl = wpa_strdup_tchar(sddl); 404209139Srpaulo if (t_sddl == NULL) 405209139Srpaulo return -1; 406209139Srpaulo if (!ConvertStringSecurityDescriptorToSecurityDescriptor( 407209139Srpaulo t_sddl, SDDL_REVISION_1, 408209139Srpaulo (PSECURITY_DESCRIPTOR *) (void *) 409209139Srpaulo &priv->attr.lpSecurityDescriptor, 410209139Srpaulo NULL)) { 411209139Srpaulo os_free(t_sddl); 412209139Srpaulo wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to " 413209139Srpaulo "security descriptor: %d", 414209139Srpaulo sddl, (int) GetLastError()); 415209139Srpaulo return -1; 416209139Srpaulo } 417209139Srpaulo os_free(t_sddl); 418209139Srpaulo 419209139Srpaulo priv->sec_attr_set = 1; 420209139Srpaulo 421209139Srpaulo return 0; 422209139Srpaulo} 423209139Srpaulo 424209139Srpaulo 425289549Srpaulostatic void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, 426289549Srpaulo enum wpa_msg_type type, 427209139Srpaulo const char *txt, size_t len) 428209139Srpaulo{ 429209139Srpaulo struct wpa_supplicant *wpa_s = ctx; 430209139Srpaulo if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) 431209139Srpaulo return; 432209139Srpaulo wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); 433209139Srpaulo} 434209139Srpaulo 435209139Srpaulo 436209139Srpaulostruct ctrl_iface_priv * 437209139Srpaulowpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 438209139Srpaulo{ 439209139Srpaulo struct ctrl_iface_priv *priv; 440209139Srpaulo 441209139Srpaulo priv = os_zalloc(sizeof(*priv)); 442209139Srpaulo if (priv == NULL) 443209139Srpaulo return NULL; 444209139Srpaulo priv->wpa_s = wpa_s; 445209139Srpaulo 446209139Srpaulo if (wpa_s->conf->ctrl_interface == NULL) 447209139Srpaulo return priv; 448209139Srpaulo 449209139Srpaulo if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) { 450209139Srpaulo os_free(priv); 451209139Srpaulo return NULL; 452209139Srpaulo } 453209139Srpaulo 454209139Srpaulo if (ctrl_open_pipe(priv) < 0) { 455209139Srpaulo os_free(priv); 456209139Srpaulo return NULL; 457209139Srpaulo } 458209139Srpaulo 459209139Srpaulo wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 460209139Srpaulo 461209139Srpaulo return priv; 462209139Srpaulo} 463209139Srpaulo 464209139Srpaulo 465209139Srpaulovoid wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) 466209139Srpaulo{ 467209139Srpaulo while (priv->ctrl_dst) 468209139Srpaulo ctrl_close_pipe(priv->ctrl_dst); 469209139Srpaulo if (priv->sec_attr_set) 470209139Srpaulo LocalFree(priv->attr.lpSecurityDescriptor); 471209139Srpaulo os_free(priv); 472209139Srpaulo} 473209139Srpaulo 474209139Srpaulo 475209139Srpaulostatic void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 476209139Srpaulo int level, const char *buf, 477209139Srpaulo size_t len) 478209139Srpaulo{ 479209139Srpaulo struct wpa_ctrl_dst *dst, *next; 480209139Srpaulo char levelstr[10]; 481209139Srpaulo int idx; 482209139Srpaulo char *sbuf; 483209139Srpaulo int llen; 484209139Srpaulo DWORD written; 485209139Srpaulo 486209139Srpaulo dst = priv->ctrl_dst; 487209139Srpaulo if (dst == NULL) 488209139Srpaulo return; 489209139Srpaulo 490209139Srpaulo os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 491209139Srpaulo 492209139Srpaulo llen = os_strlen(levelstr); 493209139Srpaulo sbuf = os_malloc(llen + len); 494209139Srpaulo if (sbuf == NULL) 495209139Srpaulo return; 496209139Srpaulo 497209139Srpaulo os_memcpy(sbuf, levelstr, llen); 498209139Srpaulo os_memcpy(sbuf + llen, buf, len); 499209139Srpaulo 500209139Srpaulo idx = 0; 501209139Srpaulo while (dst) { 502209139Srpaulo next = dst->next; 503209139Srpaulo if (dst->attached && level >= dst->debug_level) { 504209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p", 505209139Srpaulo dst); 506209139Srpaulo if (!WriteFile(dst->pipe, sbuf, llen + len, &written, 507209139Srpaulo NULL)) { 508209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst " 509209139Srpaulo "%p failed: %d", 510209139Srpaulo dst, (int) GetLastError()); 511209139Srpaulo dst->errors++; 512209139Srpaulo if (dst->errors > 10) 513209139Srpaulo ctrl_close_pipe(dst); 514209139Srpaulo } else 515209139Srpaulo dst->errors = 0; 516209139Srpaulo } 517209139Srpaulo idx++; 518209139Srpaulo dst = next; 519209139Srpaulo } 520209139Srpaulo os_free(sbuf); 521209139Srpaulo} 522209139Srpaulo 523209139Srpaulo 524209139Srpaulovoid wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 525209139Srpaulo{ 526209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", 527209139Srpaulo priv->wpa_s->ifname); 528209139Srpaulo if (priv->ctrl_dst == NULL) 529209139Srpaulo return; 530209139Srpaulo WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE); 531209139Srpaulo} 532209139Srpaulo 533209139Srpaulo 534209139Srpaulo/* Global ctrl_iface */ 535209139Srpaulo 536209139Srpaulostruct ctrl_iface_global_priv; 537209139Srpaulo 538209139Srpaulostruct wpa_global_dst { 539209139Srpaulo /* Note: OVERLAPPED must be the first member of struct wpa_global_dst 540209139Srpaulo */ 541209139Srpaulo OVERLAPPED overlap; 542209139Srpaulo struct wpa_global_dst *next, *prev; 543209139Srpaulo struct ctrl_iface_global_priv *priv; 544209139Srpaulo HANDLE pipe; 545209139Srpaulo char req_buf[REQUEST_BUFSIZE]; 546209139Srpaulo char *rsp_buf; 547209139Srpaulo int used; 548209139Srpaulo}; 549209139Srpaulo 550209139Srpaulostruct ctrl_iface_global_priv { 551209139Srpaulo struct wpa_global *global; 552209139Srpaulo struct wpa_global_dst *ctrl_dst; 553209139Srpaulo}; 554209139Srpaulo 555209139Srpaulo 556209139Srpaulostatic void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv) 557209139Srpaulo{ 558209139Srpaulo struct wpa_global_dst *dst, *next; 559209139Srpaulo 560209139Srpaulo dst = priv->ctrl_dst; 561209139Srpaulo 562209139Srpaulo while (dst) { 563209139Srpaulo next = dst->next; 564209139Srpaulo if (ctrl_broken_pipe(dst->pipe, dst->used)) { 565209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", 566209139Srpaulo dst); 567209139Srpaulo global_close_pipe(dst); 568209139Srpaulo } 569209139Srpaulo dst = next; 570209139Srpaulo } 571209139Srpaulo} 572209139Srpaulo 573209139Srpaulo 574209139Srpaulostatic int global_open_pipe(struct ctrl_iface_global_priv *priv) 575209139Srpaulo{ 576209139Srpaulo struct wpa_global_dst *dst; 577209139Srpaulo DWORD err; 578209139Srpaulo 579209139Srpaulo dst = os_zalloc(sizeof(*dst)); 580209139Srpaulo if (dst == NULL) 581209139Srpaulo return -1; 582209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); 583209139Srpaulo 584209139Srpaulo dst->priv = priv; 585209139Srpaulo dst->pipe = INVALID_HANDLE_VALUE; 586209139Srpaulo 587209139Srpaulo dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 588209139Srpaulo if (dst->overlap.hEvent == NULL) { 589209139Srpaulo wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", 590209139Srpaulo (int) GetLastError()); 591209139Srpaulo goto fail; 592209139Srpaulo } 593209139Srpaulo 594209139Srpaulo eloop_register_event(dst->overlap.hEvent, 595209139Srpaulo sizeof(dst->overlap.hEvent), 596209139Srpaulo wpa_supplicant_global_iface_receive, dst, NULL); 597209139Srpaulo 598209139Srpaulo /* TODO: add support for configuring access list for the pipe */ 599209139Srpaulo dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX, 600209139Srpaulo PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 601209139Srpaulo PIPE_TYPE_MESSAGE | 602209139Srpaulo PIPE_READMODE_MESSAGE | 603209139Srpaulo PIPE_WAIT, 604209139Srpaulo 10, REPLY_BUFSIZE, REQUEST_BUFSIZE, 605209139Srpaulo 1000, NULL); 606209139Srpaulo if (dst->pipe == INVALID_HANDLE_VALUE) { 607209139Srpaulo wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", 608209139Srpaulo (int) GetLastError()); 609209139Srpaulo goto fail; 610209139Srpaulo } 611209139Srpaulo 612209139Srpaulo if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { 613209139Srpaulo wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", 614209139Srpaulo (int) GetLastError()); 615209139Srpaulo CloseHandle(dst->pipe); 616209139Srpaulo os_free(dst); 617209139Srpaulo return -1; 618209139Srpaulo } 619209139Srpaulo 620209139Srpaulo err = GetLastError(); 621209139Srpaulo switch (err) { 622209139Srpaulo case ERROR_IO_PENDING: 623209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " 624209139Srpaulo "progress"); 625209139Srpaulo break; 626209139Srpaulo case ERROR_PIPE_CONNECTED: 627209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " 628209139Srpaulo "connected"); 629209139Srpaulo if (SetEvent(dst->overlap.hEvent)) 630209139Srpaulo break; 631209139Srpaulo /* fall through */ 632209139Srpaulo default: 633209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", 634209139Srpaulo (int) err); 635209139Srpaulo CloseHandle(dst->pipe); 636209139Srpaulo os_free(dst); 637209139Srpaulo return -1; 638209139Srpaulo } 639209139Srpaulo 640209139Srpaulo dst->next = priv->ctrl_dst; 641209139Srpaulo if (dst->next) 642209139Srpaulo dst->next->prev = dst; 643209139Srpaulo priv->ctrl_dst = dst; 644209139Srpaulo 645209139Srpaulo return 0; 646209139Srpaulo 647209139Srpaulofail: 648209139Srpaulo global_close_pipe(dst); 649209139Srpaulo return -1; 650209139Srpaulo} 651209139Srpaulo 652209139Srpaulo 653209139Srpaulostatic void global_close_pipe(struct wpa_global_dst *dst) 654209139Srpaulo{ 655209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); 656209139Srpaulo 657209139Srpaulo if (dst->overlap.hEvent) { 658209139Srpaulo eloop_unregister_event(dst->overlap.hEvent, 659209139Srpaulo sizeof(dst->overlap.hEvent)); 660209139Srpaulo CloseHandle(dst->overlap.hEvent); 661209139Srpaulo } 662209139Srpaulo 663209139Srpaulo if (dst->pipe != INVALID_HANDLE_VALUE) { 664209139Srpaulo /* 665209139Srpaulo * Could use FlushFileBuffers() here to guarantee that all data 666209139Srpaulo * gets delivered to the client, but that can block, so let's 667209139Srpaulo * not do this for now. 668209139Srpaulo * FlushFileBuffers(dst->pipe); 669209139Srpaulo */ 670209139Srpaulo CloseHandle(dst->pipe); 671209139Srpaulo } 672209139Srpaulo 673209139Srpaulo if (dst->prev) 674209139Srpaulo dst->prev->next = dst->next; 675209139Srpaulo else 676209139Srpaulo dst->priv->ctrl_dst = dst->next; 677209139Srpaulo if (dst->next) 678209139Srpaulo dst->next->prev = dst->prev; 679209139Srpaulo 680209139Srpaulo os_free(dst->rsp_buf); 681209139Srpaulo os_free(dst); 682209139Srpaulo} 683209139Srpaulo 684209139Srpaulo 685209139Srpaulostatic VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes, 686209139Srpaulo LPOVERLAPPED overlap) 687209139Srpaulo{ 688209139Srpaulo struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 689209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " 690209139Srpaulo "err=%d bytes=%d", dst, (int) err, (int) bytes); 691209139Srpaulo if (err) { 692209139Srpaulo global_close_pipe(dst); 693209139Srpaulo return; 694209139Srpaulo } 695209139Srpaulo 696209139Srpaulo os_free(dst->rsp_buf); 697209139Srpaulo dst->rsp_buf = NULL; 698209139Srpaulo 699209139Srpaulo if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), 700209139Srpaulo &dst->overlap, global_iface_read_completed)) { 701209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", 702209139Srpaulo (int) GetLastError()); 703209139Srpaulo global_close_pipe(dst); 704209139Srpaulo /* FIX: if this was the pipe waiting for new global 705209139Srpaulo * connections, at this point there are no open global pipes.. 706209139Srpaulo * Should try to open a new pipe.. */ 707209139Srpaulo return; 708209139Srpaulo } 709209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); 710209139Srpaulo} 711209139Srpaulo 712209139Srpaulo 713209139Srpaulostatic void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst, 714209139Srpaulo size_t len) 715209139Srpaulo{ 716209139Srpaulo struct wpa_global *global = dst->priv->global; 717209139Srpaulo char *reply = NULL, *send_buf; 718209139Srpaulo size_t reply_len = 0, send_len; 719209139Srpaulo char *buf = dst->req_buf; 720209139Srpaulo 721209139Srpaulo dst->used = 1; 722209139Srpaulo if (len >= REQUEST_BUFSIZE) 723209139Srpaulo len = REQUEST_BUFSIZE - 1; 724209139Srpaulo buf[len] = '\0'; 725209139Srpaulo 726209139Srpaulo reply = wpa_supplicant_global_ctrl_iface_process(global, buf, 727209139Srpaulo &reply_len); 728209139Srpaulo if (reply) { 729209139Srpaulo send_buf = reply; 730209139Srpaulo send_len = reply_len; 731209139Srpaulo } else if (reply_len) { 732209139Srpaulo send_buf = "FAIL\n"; 733209139Srpaulo send_len = 5; 734209139Srpaulo } else { 735209139Srpaulo os_free(dst->rsp_buf); 736209139Srpaulo dst->rsp_buf = NULL; 737209139Srpaulo return; 738209139Srpaulo } 739209139Srpaulo 740209139Srpaulo os_free(dst->rsp_buf); 741346981Scy dst->rsp_buf = os_memdup(send_buf, send_len); 742209139Srpaulo if (dst->rsp_buf == NULL) { 743209139Srpaulo global_close_pipe(dst); 744209139Srpaulo os_free(reply); 745209139Srpaulo return; 746209139Srpaulo } 747209139Srpaulo os_free(reply); 748209139Srpaulo 749209139Srpaulo if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, 750209139Srpaulo global_iface_write_completed)) { 751209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", 752209139Srpaulo (int) GetLastError()); 753209139Srpaulo global_close_pipe(dst); 754209139Srpaulo } else { 755209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", 756209139Srpaulo dst); 757209139Srpaulo } 758209139Srpaulo} 759209139Srpaulo 760209139Srpaulo 761209139Srpaulostatic VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, 762209139Srpaulo LPOVERLAPPED overlap) 763209139Srpaulo{ 764209139Srpaulo struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 765209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " 766209139Srpaulo "bytes=%d", dst, (int) err, (int) bytes); 767209139Srpaulo if (err == 0 && bytes > 0) 768209139Srpaulo wpa_supplicant_global_iface_rx(dst, bytes); 769209139Srpaulo} 770209139Srpaulo 771209139Srpaulo 772209139Srpaulostatic void wpa_supplicant_global_iface_receive(void *eloop_data, 773209139Srpaulo void *user_ctx) 774209139Srpaulo{ 775209139Srpaulo struct wpa_global_dst *dst = eloop_data; 776209139Srpaulo struct ctrl_iface_global_priv *priv = dst->priv; 777209139Srpaulo DWORD bytes; 778209139Srpaulo 779209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive"); 780209139Srpaulo ResetEvent(dst->overlap.hEvent); 781209139Srpaulo 782209139Srpaulo if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { 783209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", 784209139Srpaulo (int) GetLastError()); 785209139Srpaulo return; 786209139Srpaulo } 787209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " 788209139Srpaulo "connected"); 789209139Srpaulo 790209139Srpaulo /* Open a new named pipe for the next client. */ 791209139Srpaulo if (global_open_pipe(priv) < 0) { 792209139Srpaulo wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed"); 793209139Srpaulo return; 794209139Srpaulo } 795209139Srpaulo 796209139Srpaulo /* Use write completion function to start reading a command */ 797209139Srpaulo global_iface_write_completed(0, 0, &dst->overlap); 798209139Srpaulo 799209139Srpaulo global_flush_broken_pipes(priv); 800209139Srpaulo} 801209139Srpaulo 802209139Srpaulo 803209139Srpaulostruct ctrl_iface_global_priv * 804209139Srpaulowpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 805209139Srpaulo{ 806209139Srpaulo struct ctrl_iface_global_priv *priv; 807209139Srpaulo 808209139Srpaulo priv = os_zalloc(sizeof(*priv)); 809209139Srpaulo if (priv == NULL) 810209139Srpaulo return NULL; 811209139Srpaulo priv->global = global; 812209139Srpaulo 813209139Srpaulo if (global_open_pipe(priv) < 0) { 814209139Srpaulo os_free(priv); 815209139Srpaulo return NULL; 816209139Srpaulo } 817209139Srpaulo 818209139Srpaulo return priv; 819209139Srpaulo} 820209139Srpaulo 821209139Srpaulo 822209139Srpaulovoid 823209139Srpaulowpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 824209139Srpaulo{ 825209139Srpaulo while (priv->ctrl_dst) 826209139Srpaulo global_close_pipe(priv->ctrl_dst); 827209139Srpaulo os_free(priv); 828209139Srpaulo} 829