xref: /netbsd-src/external/bsd/wpa/dist/src/common/wpa_ctrl.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*
2  * wpa_supplicant/hostapd control interface library
3  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14 
15 #include "includes.h"
16 
17 #ifdef CONFIG_CTRL_IFACE
18 
19 #ifdef CONFIG_CTRL_IFACE_UNIX
20 #include <sys/un.h>
21 #endif /* CONFIG_CTRL_IFACE_UNIX */
22 
23 #ifdef ANDROID
24 #include <dirent.h>
25 #include <cutils/sockets.h>
26 #include "private/android_filesystem_config.h"
27 #endif /* ANDROID */
28 
29 #include "wpa_ctrl.h"
30 #include "common.h"
31 
32 
33 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
34 #define CTRL_IFACE_SOCKET
35 #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
36 
37 
38 /**
39  * struct wpa_ctrl - Internal structure for control interface library
40  *
41  * This structure is used by the wpa_supplicant/hostapd control interface
42  * library to store internal data. Programs using the library should not touch
43  * this data directly. They can only use the pointer to the data structure as
44  * an identifier for the control interface connection and use this as one of
45  * the arguments for most of the control interface library functions.
46  */
47 struct wpa_ctrl {
48 #ifdef CONFIG_CTRL_IFACE_UDP
49 	int s;
50 	struct sockaddr_in local;
51 	struct sockaddr_in dest;
52 	char *cookie;
53 #endif /* CONFIG_CTRL_IFACE_UDP */
54 #ifdef CONFIG_CTRL_IFACE_UNIX
55 	int s;
56 	struct sockaddr_un local;
57 	struct sockaddr_un dest;
58 #endif /* CONFIG_CTRL_IFACE_UNIX */
59 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
60 	HANDLE pipe;
61 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
62 };
63 
64 
65 #ifdef CONFIG_CTRL_IFACE_UNIX
66 
67 #ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
68 #define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
69 #endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
70 #ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
71 #define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
72 #endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
73 
74 
75 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
76 {
77 	struct wpa_ctrl *ctrl;
78 	static int counter = 0;
79 	int ret;
80 	size_t res;
81 	int tries = 0;
82 
83 	ctrl = os_malloc(sizeof(*ctrl));
84 	if (ctrl == NULL)
85 		return NULL;
86 	os_memset(ctrl, 0, sizeof(*ctrl));
87 
88 	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
89 	if (ctrl->s < 0) {
90 		os_free(ctrl);
91 		return NULL;
92 	}
93 
94 	ctrl->local.sun_family = AF_UNIX;
95 	counter++;
96 try_again:
97 	ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
98 			  CONFIG_CTRL_IFACE_CLIENT_DIR "/"
99 			  CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
100 			  (int) getpid(), counter);
101 	if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
102 		close(ctrl->s);
103 		os_free(ctrl);
104 		return NULL;
105 	}
106 	tries++;
107 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
108 		    sizeof(ctrl->local)) < 0) {
109 		if (errno == EADDRINUSE && tries < 2) {
110 			/*
111 			 * getpid() returns unique identifier for this instance
112 			 * of wpa_ctrl, so the existing socket file must have
113 			 * been left by unclean termination of an earlier run.
114 			 * Remove the file and try again.
115 			 */
116 			unlink(ctrl->local.sun_path);
117 			goto try_again;
118 		}
119 		close(ctrl->s);
120 		os_free(ctrl);
121 		return NULL;
122 	}
123 
124 #ifdef ANDROID
125 	chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
126 	chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
127 	/*
128 	 * If the ctrl_path isn't an absolute pathname, assume that
129 	 * it's the name of a socket in the Android reserved namespace.
130 	 * Otherwise, it's a normal UNIX domain socket appearing in the
131 	 * filesystem.
132 	 */
133 	if (ctrl_path != NULL && *ctrl_path != '/') {
134 		char buf[21];
135 		os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
136 		if (socket_local_client_connect(
137 			    ctrl->s, buf,
138 			    ANDROID_SOCKET_NAMESPACE_RESERVED,
139 			    SOCK_DGRAM) < 0) {
140 			close(ctrl->s);
141 			unlink(ctrl->local.sun_path);
142 			os_free(ctrl);
143 			return NULL;
144 		}
145 		return ctrl;
146 	}
147 #endif /* ANDROID */
148 
149 	ctrl->dest.sun_family = AF_UNIX;
150 	res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
151 			 sizeof(ctrl->dest.sun_path));
152 	if (res >= sizeof(ctrl->dest.sun_path)) {
153 		close(ctrl->s);
154 		os_free(ctrl);
155 		return NULL;
156 	}
157 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
158 		    sizeof(ctrl->dest)) < 0) {
159 		close(ctrl->s);
160 		unlink(ctrl->local.sun_path);
161 		os_free(ctrl);
162 		return NULL;
163 	}
164 
165 	return ctrl;
166 }
167 
168 
169 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
170 {
171 	if (ctrl == NULL)
172 		return;
173 	unlink(ctrl->local.sun_path);
174 	if (ctrl->s >= 0)
175 		close(ctrl->s);
176 	os_free(ctrl);
177 }
178 
179 
180 #ifdef ANDROID
181 /**
182  * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
183  * may be left over from clients that were previously connected to
184  * wpa_supplicant. This keeps these files from being orphaned in the
185  * event of crashes that prevented them from being removed as part
186  * of the normal orderly shutdown.
187  */
188 void wpa_ctrl_cleanup(void)
189 {
190 	DIR *dir;
191 	struct dirent entry;
192 	struct dirent *result;
193 	size_t dirnamelen;
194 	int prefixlen = os_strlen(CONFIG_CTRL_IFACE_CLIENT_PREFIX);
195 	size_t maxcopy;
196 	char pathname[PATH_MAX];
197 	char *namep;
198 
199 	if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
200 		return;
201 
202 	dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
203 					  CONFIG_CTRL_IFACE_CLIENT_DIR);
204 	if (dirnamelen >= sizeof(pathname)) {
205 		closedir(dir);
206 		return;
207 	}
208 	namep = pathname + dirnamelen;
209 	maxcopy = PATH_MAX - dirnamelen;
210 	while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
211 		if (os_strncmp(entry.d_name, CONFIG_CTRL_IFACE_CLIENT_PREFIX,
212 			       prefixlen) == 0) {
213 			if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
214 				unlink(pathname);
215 		}
216 	}
217 	closedir(dir);
218 }
219 #endif /* ANDROID */
220 
221 #else /* CONFIG_CTRL_IFACE_UNIX */
222 
223 #ifdef ANDROID
224 void wpa_ctrl_cleanup(void)
225 {
226 }
227 #endif /* ANDROID */
228 
229 #endif /* CONFIG_CTRL_IFACE_UNIX */
230 
231 
232 #ifdef CONFIG_CTRL_IFACE_UDP
233 
234 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
235 {
236 	struct wpa_ctrl *ctrl;
237 	char buf[128];
238 	size_t len;
239 
240 	ctrl = os_malloc(sizeof(*ctrl));
241 	if (ctrl == NULL)
242 		return NULL;
243 	os_memset(ctrl, 0, sizeof(*ctrl));
244 
245 	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
246 	if (ctrl->s < 0) {
247 		perror("socket");
248 		os_free(ctrl);
249 		return NULL;
250 	}
251 
252 	ctrl->local.sin_family = AF_INET;
253 	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
254 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
255 		 sizeof(ctrl->local)) < 0) {
256 		close(ctrl->s);
257 		os_free(ctrl);
258 		return NULL;
259 	}
260 
261 	ctrl->dest.sin_family = AF_INET;
262 	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
263 	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
264 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
265 		    sizeof(ctrl->dest)) < 0) {
266 		perror("connect");
267 		close(ctrl->s);
268 		os_free(ctrl);
269 		return NULL;
270 	}
271 
272 	len = sizeof(buf) - 1;
273 	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
274 		buf[len] = '\0';
275 		ctrl->cookie = os_strdup(buf);
276 	}
277 
278 	return ctrl;
279 }
280 
281 
282 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
283 {
284 	close(ctrl->s);
285 	os_free(ctrl->cookie);
286 	os_free(ctrl);
287 }
288 
289 #endif /* CONFIG_CTRL_IFACE_UDP */
290 
291 
292 #ifdef CTRL_IFACE_SOCKET
293 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
294 		     char *reply, size_t *reply_len,
295 		     void (*msg_cb)(char *msg, size_t len))
296 {
297 	struct timeval tv;
298 	int res;
299 	fd_set rfds;
300 	const char *_cmd;
301 	char *cmd_buf = NULL;
302 	size_t _cmd_len;
303 
304 #ifdef CONFIG_CTRL_IFACE_UDP
305 	if (ctrl->cookie) {
306 		char *pos;
307 		_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
308 		cmd_buf = os_malloc(_cmd_len);
309 		if (cmd_buf == NULL)
310 			return -1;
311 		_cmd = cmd_buf;
312 		pos = cmd_buf;
313 		os_strlcpy(pos, ctrl->cookie, _cmd_len);
314 		pos += os_strlen(ctrl->cookie);
315 		*pos++ = ' ';
316 		os_memcpy(pos, cmd, cmd_len);
317 	} else
318 #endif /* CONFIG_CTRL_IFACE_UDP */
319 	{
320 		_cmd = cmd;
321 		_cmd_len = cmd_len;
322 	}
323 
324 	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
325 		os_free(cmd_buf);
326 		return -1;
327 	}
328 	os_free(cmd_buf);
329 
330 	for (;;) {
331 		tv.tv_sec = 10;
332 		tv.tv_usec = 0;
333 		FD_ZERO(&rfds);
334 		FD_SET(ctrl->s, &rfds);
335 		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
336 		if (res < 0)
337 			return res;
338 		if (FD_ISSET(ctrl->s, &rfds)) {
339 			res = recv(ctrl->s, reply, *reply_len, 0);
340 			if (res < 0)
341 				return res;
342 			if (res > 0 && reply[0] == '<') {
343 				/* This is an unsolicited message from
344 				 * wpa_supplicant, not the reply to the
345 				 * request. Use msg_cb to report this to the
346 				 * caller. */
347 				if (msg_cb) {
348 					/* Make sure the message is nul
349 					 * terminated. */
350 					if ((size_t) res == *reply_len)
351 						res = (*reply_len) - 1;
352 					reply[res] = '\0';
353 					msg_cb(reply, res);
354 				}
355 				continue;
356 			}
357 			*reply_len = res;
358 			break;
359 		} else {
360 			return -2;
361 		}
362 	}
363 	return 0;
364 }
365 #endif /* CTRL_IFACE_SOCKET */
366 
367 
368 static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
369 {
370 	char buf[10];
371 	int ret;
372 	size_t len = 10;
373 
374 	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
375 			       buf, &len, NULL);
376 	if (ret < 0)
377 		return ret;
378 	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
379 		return 0;
380 	return -1;
381 }
382 
383 
384 int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
385 {
386 	return wpa_ctrl_attach_helper(ctrl, 1);
387 }
388 
389 
390 int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
391 {
392 	return wpa_ctrl_attach_helper(ctrl, 0);
393 }
394 
395 
396 #ifdef CTRL_IFACE_SOCKET
397 
398 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
399 {
400 	int res;
401 
402 	res = recv(ctrl->s, reply, *reply_len, 0);
403 	if (res < 0)
404 		return res;
405 	*reply_len = res;
406 	return 0;
407 }
408 
409 
410 int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
411 {
412 	struct timeval tv;
413 	fd_set rfds;
414 	tv.tv_sec = 0;
415 	tv.tv_usec = 0;
416 	FD_ZERO(&rfds);
417 	FD_SET(ctrl->s, &rfds);
418 	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
419 	return FD_ISSET(ctrl->s, &rfds);
420 }
421 
422 
423 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
424 {
425 	return ctrl->s;
426 }
427 
428 #endif /* CTRL_IFACE_SOCKET */
429 
430 
431 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
432 
433 #ifndef WPA_SUPPLICANT_NAMED_PIPE
434 #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
435 #endif
436 #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
437 
438 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
439 {
440 	struct wpa_ctrl *ctrl;
441 	DWORD mode;
442 	TCHAR name[256];
443 	int i, ret;
444 
445 	ctrl = os_malloc(sizeof(*ctrl));
446 	if (ctrl == NULL)
447 		return NULL;
448 	os_memset(ctrl, 0, sizeof(*ctrl));
449 
450 #ifdef UNICODE
451 	if (ctrl_path == NULL)
452 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
453 	else
454 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
455 				 ctrl_path);
456 #else /* UNICODE */
457 	if (ctrl_path == NULL)
458 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
459 	else
460 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
461 				  ctrl_path);
462 #endif /* UNICODE */
463 	if (ret < 0 || ret >= 256) {
464 		os_free(ctrl);
465 		return NULL;
466 	}
467 
468 	for (i = 0; i < 10; i++) {
469 		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
470 					NULL, OPEN_EXISTING, 0, NULL);
471 		/*
472 		 * Current named pipe server side in wpa_supplicant is
473 		 * re-opening the pipe for new clients only after the previous
474 		 * one is taken into use. This leaves a small window for race
475 		 * conditions when two connections are being opened at almost
476 		 * the same time. Retry if that was the case.
477 		 */
478 		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
479 		    GetLastError() != ERROR_PIPE_BUSY)
480 			break;
481 		WaitNamedPipe(name, 1000);
482 	}
483 	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
484 		os_free(ctrl);
485 		return NULL;
486 	}
487 
488 	mode = PIPE_READMODE_MESSAGE;
489 	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
490 		CloseHandle(ctrl->pipe);
491 		os_free(ctrl);
492 		return NULL;
493 	}
494 
495 	return ctrl;
496 }
497 
498 
499 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
500 {
501 	CloseHandle(ctrl->pipe);
502 	os_free(ctrl);
503 }
504 
505 
506 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
507 		     char *reply, size_t *reply_len,
508 		     void (*msg_cb)(char *msg, size_t len))
509 {
510 	DWORD written;
511 	DWORD readlen = *reply_len;
512 
513 	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
514 		return -1;
515 
516 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
517 		return -1;
518 	*reply_len = readlen;
519 
520 	return 0;
521 }
522 
523 
524 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
525 {
526 	DWORD len = *reply_len;
527 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
528 		return -1;
529 	*reply_len = len;
530 	return 0;
531 }
532 
533 
534 int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
535 {
536 	DWORD left;
537 
538 	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
539 		return -1;
540 	return left ? 1 : 0;
541 }
542 
543 
544 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
545 {
546 	return -1;
547 }
548 
549 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
550 
551 #endif /* CONFIG_CTRL_IFACE */
552