l2_packet_privsep.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. * WPA Supplicant - Layer2 packet handling with privilege separation
  3. * Copyright (c) 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. #include "includes.h"
  15. #include <sys/un.h>
  16. #include "common.h"
  17. #include "eloop.h"
  18. #include "l2_packet.h"
  19. #include "common/privsep_commands.h"
  20. struct l2_packet_data {
  21. int fd; /* UNIX domain socket for privsep access */
  22. void (*rx_callback)(void *ctx, const u8 *src_addr,
  23. const u8 *buf, size_t len);
  24. void *rx_callback_ctx;
  25. u8 own_addr[ETH_ALEN];
  26. char *own_socket_path;
  27. struct sockaddr_un priv_addr;
  28. };
  29. static int wpa_priv_cmd(struct l2_packet_data *l2, int cmd,
  30. const void *data, size_t data_len)
  31. {
  32. struct msghdr msg;
  33. struct iovec io[2];
  34. io[0].iov_base = &cmd;
  35. io[0].iov_len = sizeof(cmd);
  36. io[1].iov_base = (u8 *) data;
  37. io[1].iov_len = data_len;
  38. os_memset(&msg, 0, sizeof(msg));
  39. msg.msg_iov = io;
  40. msg.msg_iovlen = data ? 2 : 1;
  41. msg.msg_name = &l2->priv_addr;
  42. msg.msg_namelen = sizeof(l2->priv_addr);
  43. if (sendmsg(l2->fd, &msg, 0) < 0) {
  44. perror("L2: sendmsg(cmd)");
  45. return -1;
  46. }
  47. return 0;
  48. }
  49. int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
  50. {
  51. os_memcpy(addr, l2->own_addr, ETH_ALEN);
  52. return 0;
  53. }
  54. int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
  55. const u8 *buf, size_t len)
  56. {
  57. struct msghdr msg;
  58. struct iovec io[4];
  59. int cmd = PRIVSEP_CMD_L2_SEND;
  60. io[0].iov_base = &cmd;
  61. io[0].iov_len = sizeof(cmd);
  62. io[1].iov_base = &dst_addr;
  63. io[1].iov_len = ETH_ALEN;
  64. io[2].iov_base = &proto;
  65. io[2].iov_len = 2;
  66. io[3].iov_base = (u8 *) buf;
  67. io[3].iov_len = len;
  68. os_memset(&msg, 0, sizeof(msg));
  69. msg.msg_iov = io;
  70. msg.msg_iovlen = 4;
  71. msg.msg_name = &l2->priv_addr;
  72. msg.msg_namelen = sizeof(l2->priv_addr);
  73. if (sendmsg(l2->fd, &msg, 0) < 0) {
  74. perror("L2: sendmsg(packet_send)");
  75. return -1;
  76. }
  77. return 0;
  78. }
  79. static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
  80. {
  81. struct l2_packet_data *l2 = eloop_ctx;
  82. u8 buf[2300];
  83. int res;
  84. struct sockaddr_un from;
  85. socklen_t fromlen = sizeof(from);
  86. os_memset(&from, 0, sizeof(from));
  87. res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
  88. &fromlen);
  89. if (res < 0) {
  90. perror("l2_packet_receive - recvfrom");
  91. return;
  92. }
  93. if (res < ETH_ALEN) {
  94. wpa_printf(MSG_DEBUG, "L2: Too show packet received");
  95. return;
  96. }
  97. if (from.sun_family != AF_UNIX ||
  98. os_strncmp(from.sun_path, l2->priv_addr.sun_path,
  99. sizeof(from.sun_path)) != 0) {
  100. wpa_printf(MSG_DEBUG, "L2: Received message from unexpected "
  101. "source");
  102. return;
  103. }
  104. l2->rx_callback(l2->rx_callback_ctx, buf, buf + ETH_ALEN,
  105. res - ETH_ALEN);
  106. }
  107. struct l2_packet_data * l2_packet_init(
  108. const char *ifname, const u8 *own_addr, unsigned short protocol,
  109. void (*rx_callback)(void *ctx, const u8 *src_addr,
  110. const u8 *buf, size_t len),
  111. void *rx_callback_ctx, int l2_hdr)
  112. {
  113. struct l2_packet_data *l2;
  114. char *own_dir = "/tmp";
  115. char *priv_dir = "/var/run/wpa_priv";
  116. size_t len;
  117. static unsigned int counter = 0;
  118. struct sockaddr_un addr;
  119. fd_set rfds;
  120. struct timeval tv;
  121. int res;
  122. u8 reply[ETH_ALEN + 1];
  123. int reg_cmd[2];
  124. l2 = os_zalloc(sizeof(struct l2_packet_data));
  125. if (l2 == NULL)
  126. return NULL;
  127. l2->rx_callback = rx_callback;
  128. l2->rx_callback_ctx = rx_callback_ctx;
  129. len = os_strlen(own_dir) + 50;
  130. l2->own_socket_path = os_malloc(len);
  131. if (l2->own_socket_path == NULL) {
  132. os_free(l2);
  133. return NULL;
  134. }
  135. os_snprintf(l2->own_socket_path, len, "%s/wpa_privsep-l2-%d-%d",
  136. own_dir, getpid(), counter++);
  137. l2->priv_addr.sun_family = AF_UNIX;
  138. os_snprintf(l2->priv_addr.sun_path, sizeof(l2->priv_addr.sun_path),
  139. "%s/%s", priv_dir, ifname);
  140. l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
  141. if (l2->fd < 0) {
  142. perror("socket(PF_UNIX)");
  143. os_free(l2->own_socket_path);
  144. l2->own_socket_path = NULL;
  145. os_free(l2);
  146. return NULL;
  147. }
  148. os_memset(&addr, 0, sizeof(addr));
  149. addr.sun_family = AF_UNIX;
  150. os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
  151. if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
  152. perror("bind(PF_UNIX)");
  153. goto fail;
  154. }
  155. reg_cmd[0] = protocol;
  156. reg_cmd[1] = l2_hdr;
  157. if (wpa_priv_cmd(l2, PRIVSEP_CMD_L2_REGISTER, reg_cmd, sizeof(reg_cmd))
  158. < 0) {
  159. wpa_printf(MSG_ERROR, "L2: Failed to register with wpa_priv");
  160. goto fail;
  161. }
  162. FD_ZERO(&rfds);
  163. FD_SET(l2->fd, &rfds);
  164. tv.tv_sec = 5;
  165. tv.tv_usec = 0;
  166. res = select(l2->fd + 1, &rfds, NULL, NULL, &tv);
  167. if (res < 0 && errno != EINTR) {
  168. perror("select");
  169. goto fail;
  170. }
  171. if (FD_ISSET(l2->fd, &rfds)) {
  172. res = recv(l2->fd, reply, sizeof(reply), 0);
  173. if (res < 0) {
  174. perror("recv");
  175. goto fail;
  176. }
  177. } else {
  178. wpa_printf(MSG_DEBUG, "L2: Timeout while waiting for "
  179. "registration reply");
  180. goto fail;
  181. }
  182. if (res != ETH_ALEN) {
  183. wpa_printf(MSG_DEBUG, "L2: Unexpected registration reply "
  184. "(len=%d)", res);
  185. }
  186. os_memcpy(l2->own_addr, reply, ETH_ALEN);
  187. eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
  188. return l2;
  189. fail:
  190. close(l2->fd);
  191. l2->fd = -1;
  192. unlink(l2->own_socket_path);
  193. os_free(l2->own_socket_path);
  194. l2->own_socket_path = NULL;
  195. os_free(l2);
  196. return NULL;
  197. }
  198. void l2_packet_deinit(struct l2_packet_data *l2)
  199. {
  200. if (l2 == NULL)
  201. return;
  202. if (l2->fd >= 0) {
  203. wpa_priv_cmd(l2, PRIVSEP_CMD_L2_UNREGISTER, NULL, 0);
  204. eloop_unregister_read_sock(l2->fd);
  205. close(l2->fd);
  206. }
  207. if (l2->own_socket_path) {
  208. unlink(l2->own_socket_path);
  209. os_free(l2->own_socket_path);
  210. }
  211. os_free(l2);
  212. }
  213. int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
  214. {
  215. /* TODO */
  216. return -1;
  217. }
  218. void l2_packet_notify_auth_start(struct l2_packet_data *l2)
  219. {
  220. wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0);
  221. }