xref: /dflybsd-src/contrib/wpa_supplicant/src/l2_packet/l2_packet_privsep.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer  * WPA Supplicant - Layer2 packet handling with privilege separation
36d49e1aeSJan Lentfer  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
76d49e1aeSJan Lentfer  */
86d49e1aeSJan Lentfer 
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer #include <sys/un.h>
116d49e1aeSJan Lentfer 
126d49e1aeSJan Lentfer #include "common.h"
136d49e1aeSJan Lentfer #include "eloop.h"
146d49e1aeSJan Lentfer #include "l2_packet.h"
153ff40c12SJohn Marino #include "common/privsep_commands.h"
166d49e1aeSJan Lentfer 
176d49e1aeSJan Lentfer 
186d49e1aeSJan Lentfer struct l2_packet_data {
196d49e1aeSJan Lentfer 	int fd; /* UNIX domain socket for privsep access */
206d49e1aeSJan Lentfer 	void (*rx_callback)(void *ctx, const u8 *src_addr,
216d49e1aeSJan Lentfer 			    const u8 *buf, size_t len);
226d49e1aeSJan Lentfer 	void *rx_callback_ctx;
236d49e1aeSJan Lentfer 	u8 own_addr[ETH_ALEN];
246d49e1aeSJan Lentfer 	char *own_socket_path;
256d49e1aeSJan Lentfer 	struct sockaddr_un priv_addr;
266d49e1aeSJan Lentfer };
276d49e1aeSJan Lentfer 
286d49e1aeSJan Lentfer 
wpa_priv_cmd(struct l2_packet_data * l2,int cmd,const void * data,size_t data_len)296d49e1aeSJan Lentfer static int wpa_priv_cmd(struct l2_packet_data *l2, int cmd,
306d49e1aeSJan Lentfer 			const void *data, size_t data_len)
316d49e1aeSJan Lentfer {
326d49e1aeSJan Lentfer 	struct msghdr msg;
336d49e1aeSJan Lentfer 	struct iovec io[2];
346d49e1aeSJan Lentfer 
356d49e1aeSJan Lentfer 	io[0].iov_base = &cmd;
366d49e1aeSJan Lentfer 	io[0].iov_len = sizeof(cmd);
376d49e1aeSJan Lentfer 	io[1].iov_base = (u8 *) data;
386d49e1aeSJan Lentfer 	io[1].iov_len = data_len;
396d49e1aeSJan Lentfer 
406d49e1aeSJan Lentfer 	os_memset(&msg, 0, sizeof(msg));
416d49e1aeSJan Lentfer 	msg.msg_iov = io;
426d49e1aeSJan Lentfer 	msg.msg_iovlen = data ? 2 : 1;
436d49e1aeSJan Lentfer 	msg.msg_name = &l2->priv_addr;
446d49e1aeSJan Lentfer 	msg.msg_namelen = sizeof(l2->priv_addr);
456d49e1aeSJan Lentfer 
466d49e1aeSJan Lentfer 	if (sendmsg(l2->fd, &msg, 0) < 0) {
47*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "L2: sendmsg(cmd): %s", strerror(errno));
486d49e1aeSJan Lentfer 		return -1;
496d49e1aeSJan Lentfer 	}
506d49e1aeSJan Lentfer 
516d49e1aeSJan Lentfer 	return 0;
526d49e1aeSJan Lentfer }
536d49e1aeSJan Lentfer 
546d49e1aeSJan Lentfer 
l2_packet_get_own_addr(struct l2_packet_data * l2,u8 * addr)556d49e1aeSJan Lentfer int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
566d49e1aeSJan Lentfer {
576d49e1aeSJan Lentfer 	os_memcpy(addr, l2->own_addr, ETH_ALEN);
586d49e1aeSJan Lentfer 	return 0;
596d49e1aeSJan Lentfer }
606d49e1aeSJan Lentfer 
616d49e1aeSJan Lentfer 
l2_packet_send(struct l2_packet_data * l2,const u8 * dst_addr,u16 proto,const u8 * buf,size_t len)626d49e1aeSJan Lentfer int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
636d49e1aeSJan Lentfer 		   const u8 *buf, size_t len)
646d49e1aeSJan Lentfer {
656d49e1aeSJan Lentfer 	struct msghdr msg;
666d49e1aeSJan Lentfer 	struct iovec io[4];
676d49e1aeSJan Lentfer 	int cmd = PRIVSEP_CMD_L2_SEND;
686d49e1aeSJan Lentfer 
696d49e1aeSJan Lentfer 	io[0].iov_base = &cmd;
706d49e1aeSJan Lentfer 	io[0].iov_len = sizeof(cmd);
716d49e1aeSJan Lentfer 	io[1].iov_base = &dst_addr;
726d49e1aeSJan Lentfer 	io[1].iov_len = ETH_ALEN;
736d49e1aeSJan Lentfer 	io[2].iov_base = &proto;
746d49e1aeSJan Lentfer 	io[2].iov_len = 2;
756d49e1aeSJan Lentfer 	io[3].iov_base = (u8 *) buf;
766d49e1aeSJan Lentfer 	io[3].iov_len = len;
776d49e1aeSJan Lentfer 
786d49e1aeSJan Lentfer 	os_memset(&msg, 0, sizeof(msg));
796d49e1aeSJan Lentfer 	msg.msg_iov = io;
806d49e1aeSJan Lentfer 	msg.msg_iovlen = 4;
816d49e1aeSJan Lentfer 	msg.msg_name = &l2->priv_addr;
826d49e1aeSJan Lentfer 	msg.msg_namelen = sizeof(l2->priv_addr);
836d49e1aeSJan Lentfer 
846d49e1aeSJan Lentfer 	if (sendmsg(l2->fd, &msg, 0) < 0) {
85*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "L2: sendmsg(packet_send): %s",
86*a1157835SDaniel Fojt 			   strerror(errno));
876d49e1aeSJan Lentfer 		return -1;
886d49e1aeSJan Lentfer 	}
896d49e1aeSJan Lentfer 
906d49e1aeSJan Lentfer 	return 0;
916d49e1aeSJan Lentfer }
926d49e1aeSJan Lentfer 
936d49e1aeSJan Lentfer 
l2_packet_receive(int sock,void * eloop_ctx,void * sock_ctx)946d49e1aeSJan Lentfer static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
956d49e1aeSJan Lentfer {
966d49e1aeSJan Lentfer 	struct l2_packet_data *l2 = eloop_ctx;
976d49e1aeSJan Lentfer 	u8 buf[2300];
986d49e1aeSJan Lentfer 	int res;
996d49e1aeSJan Lentfer 	struct sockaddr_un from;
1006d49e1aeSJan Lentfer 	socklen_t fromlen = sizeof(from);
1016d49e1aeSJan Lentfer 
1026d49e1aeSJan Lentfer 	os_memset(&from, 0, sizeof(from));
1036d49e1aeSJan Lentfer 	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
1046d49e1aeSJan Lentfer 		       &fromlen);
1056d49e1aeSJan Lentfer 	if (res < 0) {
106*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "l2_packet_receive - recvfrom: %s",
107*a1157835SDaniel Fojt 			   strerror(errno));
1086d49e1aeSJan Lentfer 		return;
1096d49e1aeSJan Lentfer 	}
1106d49e1aeSJan Lentfer 	if (res < ETH_ALEN) {
1116d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "L2: Too show packet received");
1126d49e1aeSJan Lentfer 		return;
1136d49e1aeSJan Lentfer 	}
1146d49e1aeSJan Lentfer 
1156d49e1aeSJan Lentfer 	if (from.sun_family != AF_UNIX ||
1166d49e1aeSJan Lentfer 	    os_strncmp(from.sun_path, l2->priv_addr.sun_path,
1176d49e1aeSJan Lentfer 		       sizeof(from.sun_path)) != 0) {
1186d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "L2: Received message from unexpected "
1196d49e1aeSJan Lentfer 			   "source");
1206d49e1aeSJan Lentfer 		return;
1216d49e1aeSJan Lentfer 	}
1226d49e1aeSJan Lentfer 
1236d49e1aeSJan Lentfer 	l2->rx_callback(l2->rx_callback_ctx, buf, buf + ETH_ALEN,
1246d49e1aeSJan Lentfer 			res - ETH_ALEN);
1256d49e1aeSJan Lentfer }
1266d49e1aeSJan Lentfer 
1276d49e1aeSJan Lentfer 
l2_packet_init(const char * ifname,const u8 * own_addr,unsigned short protocol,void (* rx_callback)(void * ctx,const u8 * src_addr,const u8 * buf,size_t len),void * rx_callback_ctx,int l2_hdr)1286d49e1aeSJan Lentfer struct l2_packet_data * l2_packet_init(
1296d49e1aeSJan Lentfer 	const char *ifname, const u8 *own_addr, unsigned short protocol,
1306d49e1aeSJan Lentfer 	void (*rx_callback)(void *ctx, const u8 *src_addr,
1316d49e1aeSJan Lentfer 			    const u8 *buf, size_t len),
1326d49e1aeSJan Lentfer 	void *rx_callback_ctx, int l2_hdr)
1336d49e1aeSJan Lentfer {
1346d49e1aeSJan Lentfer 	struct l2_packet_data *l2;
1356d49e1aeSJan Lentfer 	char *own_dir = "/tmp";
1366d49e1aeSJan Lentfer 	char *priv_dir = "/var/run/wpa_priv";
1376d49e1aeSJan Lentfer 	size_t len;
1386d49e1aeSJan Lentfer 	static unsigned int counter = 0;
1396d49e1aeSJan Lentfer 	struct sockaddr_un addr;
1406d49e1aeSJan Lentfer 	fd_set rfds;
1416d49e1aeSJan Lentfer 	struct timeval tv;
1426d49e1aeSJan Lentfer 	int res;
1436d49e1aeSJan Lentfer 	u8 reply[ETH_ALEN + 1];
1446d49e1aeSJan Lentfer 	int reg_cmd[2];
1456d49e1aeSJan Lentfer 
1466d49e1aeSJan Lentfer 	l2 = os_zalloc(sizeof(struct l2_packet_data));
1476d49e1aeSJan Lentfer 	if (l2 == NULL)
1486d49e1aeSJan Lentfer 		return NULL;
1496d49e1aeSJan Lentfer 	l2->rx_callback = rx_callback;
1506d49e1aeSJan Lentfer 	l2->rx_callback_ctx = rx_callback_ctx;
1516d49e1aeSJan Lentfer 
1526d49e1aeSJan Lentfer 	len = os_strlen(own_dir) + 50;
1536d49e1aeSJan Lentfer 	l2->own_socket_path = os_malloc(len);
1546d49e1aeSJan Lentfer 	if (l2->own_socket_path == NULL) {
1556d49e1aeSJan Lentfer 		os_free(l2);
1566d49e1aeSJan Lentfer 		return NULL;
1576d49e1aeSJan Lentfer 	}
1586d49e1aeSJan Lentfer 	os_snprintf(l2->own_socket_path, len, "%s/wpa_privsep-l2-%d-%d",
1596d49e1aeSJan Lentfer 		    own_dir, getpid(), counter++);
1606d49e1aeSJan Lentfer 
1616d49e1aeSJan Lentfer 	l2->priv_addr.sun_family = AF_UNIX;
1626d49e1aeSJan Lentfer 	os_snprintf(l2->priv_addr.sun_path, sizeof(l2->priv_addr.sun_path),
1636d49e1aeSJan Lentfer 		    "%s/%s", priv_dir, ifname);
1646d49e1aeSJan Lentfer 
1656d49e1aeSJan Lentfer 	l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
1666d49e1aeSJan Lentfer 	if (l2->fd < 0) {
167*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
1686d49e1aeSJan Lentfer 		os_free(l2->own_socket_path);
1696d49e1aeSJan Lentfer 		l2->own_socket_path = NULL;
1706d49e1aeSJan Lentfer 		os_free(l2);
1716d49e1aeSJan Lentfer 		return NULL;
1726d49e1aeSJan Lentfer 	}
1736d49e1aeSJan Lentfer 
1746d49e1aeSJan Lentfer 	os_memset(&addr, 0, sizeof(addr));
1756d49e1aeSJan Lentfer 	addr.sun_family = AF_UNIX;
1766d49e1aeSJan Lentfer 	os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
1776d49e1aeSJan Lentfer 	if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
178*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "l2-pkt-privsep: bind(PF_UNIX): %s",
179*a1157835SDaniel Fojt 			   strerror(errno));
1806d49e1aeSJan Lentfer 		goto fail;
1816d49e1aeSJan Lentfer 	}
1826d49e1aeSJan Lentfer 
1836d49e1aeSJan Lentfer 	reg_cmd[0] = protocol;
1846d49e1aeSJan Lentfer 	reg_cmd[1] = l2_hdr;
1856d49e1aeSJan Lentfer 	if (wpa_priv_cmd(l2, PRIVSEP_CMD_L2_REGISTER, reg_cmd, sizeof(reg_cmd))
1866d49e1aeSJan Lentfer 	    < 0) {
1876d49e1aeSJan Lentfer 		wpa_printf(MSG_ERROR, "L2: Failed to register with wpa_priv");
1886d49e1aeSJan Lentfer 		goto fail;
1896d49e1aeSJan Lentfer 	}
1906d49e1aeSJan Lentfer 
1916d49e1aeSJan Lentfer 	FD_ZERO(&rfds);
1926d49e1aeSJan Lentfer 	FD_SET(l2->fd, &rfds);
1936d49e1aeSJan Lentfer 	tv.tv_sec = 5;
1946d49e1aeSJan Lentfer 	tv.tv_usec = 0;
1956d49e1aeSJan Lentfer 	res = select(l2->fd + 1, &rfds, NULL, NULL, &tv);
1966d49e1aeSJan Lentfer 	if (res < 0 && errno != EINTR) {
197*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "select: %s", strerror(errno));
1986d49e1aeSJan Lentfer 		goto fail;
1996d49e1aeSJan Lentfer 	}
2006d49e1aeSJan Lentfer 
2016d49e1aeSJan Lentfer 	if (FD_ISSET(l2->fd, &rfds)) {
2026d49e1aeSJan Lentfer 		res = recv(l2->fd, reply, sizeof(reply), 0);
2036d49e1aeSJan Lentfer 		if (res < 0) {
204*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
2056d49e1aeSJan Lentfer 			goto fail;
2066d49e1aeSJan Lentfer 		}
2076d49e1aeSJan Lentfer 	} else {
2086d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "L2: Timeout while waiting for "
2096d49e1aeSJan Lentfer 			   "registration reply");
2106d49e1aeSJan Lentfer 		goto fail;
2116d49e1aeSJan Lentfer 	}
2126d49e1aeSJan Lentfer 
2136d49e1aeSJan Lentfer 	if (res != ETH_ALEN) {
2146d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "L2: Unexpected registration reply "
2156d49e1aeSJan Lentfer 			   "(len=%d)", res);
2166d49e1aeSJan Lentfer 	}
2176d49e1aeSJan Lentfer 	os_memcpy(l2->own_addr, reply, ETH_ALEN);
2186d49e1aeSJan Lentfer 
2196d49e1aeSJan Lentfer 	eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
2206d49e1aeSJan Lentfer 
2216d49e1aeSJan Lentfer 	return l2;
2226d49e1aeSJan Lentfer 
2236d49e1aeSJan Lentfer fail:
2246d49e1aeSJan Lentfer 	close(l2->fd);
2256d49e1aeSJan Lentfer 	l2->fd = -1;
2266d49e1aeSJan Lentfer 	unlink(l2->own_socket_path);
2276d49e1aeSJan Lentfer 	os_free(l2->own_socket_path);
2286d49e1aeSJan Lentfer 	l2->own_socket_path = NULL;
2296d49e1aeSJan Lentfer 	os_free(l2);
2306d49e1aeSJan Lentfer 	return NULL;
2316d49e1aeSJan Lentfer }
2326d49e1aeSJan Lentfer 
2336d49e1aeSJan Lentfer 
l2_packet_init_bridge(const char * br_ifname,const char * ifname,const u8 * own_addr,unsigned short protocol,void (* rx_callback)(void * ctx,const u8 * src_addr,const u8 * buf,size_t len),void * rx_callback_ctx,int l2_hdr)234*a1157835SDaniel Fojt struct l2_packet_data * l2_packet_init_bridge(
235*a1157835SDaniel Fojt 	const char *br_ifname, const char *ifname, const u8 *own_addr,
236*a1157835SDaniel Fojt 	unsigned short protocol,
237*a1157835SDaniel Fojt 	void (*rx_callback)(void *ctx, const u8 *src_addr,
238*a1157835SDaniel Fojt 			    const u8 *buf, size_t len),
239*a1157835SDaniel Fojt 	void *rx_callback_ctx, int l2_hdr)
240*a1157835SDaniel Fojt {
241*a1157835SDaniel Fojt 	return l2_packet_init(br_ifname, own_addr, protocol, rx_callback,
242*a1157835SDaniel Fojt 			      rx_callback_ctx, l2_hdr);
243*a1157835SDaniel Fojt }
244*a1157835SDaniel Fojt 
245*a1157835SDaniel Fojt 
l2_packet_deinit(struct l2_packet_data * l2)2466d49e1aeSJan Lentfer void l2_packet_deinit(struct l2_packet_data *l2)
2476d49e1aeSJan Lentfer {
2486d49e1aeSJan Lentfer 	if (l2 == NULL)
2496d49e1aeSJan Lentfer 		return;
2506d49e1aeSJan Lentfer 
2516d49e1aeSJan Lentfer 	if (l2->fd >= 0) {
2526d49e1aeSJan Lentfer 		wpa_priv_cmd(l2, PRIVSEP_CMD_L2_UNREGISTER, NULL, 0);
2536d49e1aeSJan Lentfer 		eloop_unregister_read_sock(l2->fd);
2546d49e1aeSJan Lentfer 		close(l2->fd);
2556d49e1aeSJan Lentfer 	}
2566d49e1aeSJan Lentfer 
2576d49e1aeSJan Lentfer 	if (l2->own_socket_path) {
2586d49e1aeSJan Lentfer 		unlink(l2->own_socket_path);
2596d49e1aeSJan Lentfer 		os_free(l2->own_socket_path);
2606d49e1aeSJan Lentfer 	}
2616d49e1aeSJan Lentfer 
2626d49e1aeSJan Lentfer 	os_free(l2);
2636d49e1aeSJan Lentfer }
2646d49e1aeSJan Lentfer 
2656d49e1aeSJan Lentfer 
l2_packet_get_ip_addr(struct l2_packet_data * l2,char * buf,size_t len)2666d49e1aeSJan Lentfer int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
2676d49e1aeSJan Lentfer {
2686d49e1aeSJan Lentfer 	/* TODO */
2696d49e1aeSJan Lentfer 	return -1;
2706d49e1aeSJan Lentfer }
2716d49e1aeSJan Lentfer 
2726d49e1aeSJan Lentfer 
l2_packet_notify_auth_start(struct l2_packet_data * l2)2736d49e1aeSJan Lentfer void l2_packet_notify_auth_start(struct l2_packet_data *l2)
2746d49e1aeSJan Lentfer {
2756d49e1aeSJan Lentfer 	wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0);
2766d49e1aeSJan Lentfer }
277*a1157835SDaniel Fojt 
278*a1157835SDaniel Fojt 
l2_packet_set_packet_filter(struct l2_packet_data * l2,enum l2_packet_filter_type type)279*a1157835SDaniel Fojt int l2_packet_set_packet_filter(struct l2_packet_data *l2,
280*a1157835SDaniel Fojt 				enum l2_packet_filter_type type)
281*a1157835SDaniel Fojt {
282*a1157835SDaniel Fojt 	return -1;
283*a1157835SDaniel Fojt }
284