ieee802_11_auth.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /*
  2. * hostapd / IEEE 802.11 authentication (ACL)
  3. * Copyright (c) 2003-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. #ifndef CONFIG_NATIVE_WINDOWS
  16. #include "hostapd.h"
  17. #include "ieee802_11.h"
  18. #include "ieee802_11_auth.h"
  19. #include "radius/radius.h"
  20. #include "radius/radius_client.h"
  21. #include "eloop.h"
  22. #include "driver.h"
  23. #define RADIUS_ACL_TIMEOUT 30
  24. struct hostapd_cached_radius_acl {
  25. time_t timestamp;
  26. macaddr addr;
  27. int accepted; /* HOSTAPD_ACL_* */
  28. struct hostapd_cached_radius_acl *next;
  29. u32 session_timeout;
  30. u32 acct_interim_interval;
  31. int vlan_id;
  32. };
  33. struct hostapd_acl_query_data {
  34. time_t timestamp;
  35. u8 radius_id;
  36. macaddr addr;
  37. u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
  38. size_t auth_msg_len;
  39. struct hostapd_acl_query_data *next;
  40. };
  41. static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
  42. {
  43. struct hostapd_cached_radius_acl *prev;
  44. while (acl_cache) {
  45. prev = acl_cache;
  46. acl_cache = acl_cache->next;
  47. os_free(prev);
  48. }
  49. }
  50. static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
  51. u32 *session_timeout,
  52. u32 *acct_interim_interval, int *vlan_id)
  53. {
  54. struct hostapd_cached_radius_acl *entry;
  55. time_t now;
  56. time(&now);
  57. entry = hapd->acl_cache;
  58. while (entry) {
  59. if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
  60. if (now - entry->timestamp > RADIUS_ACL_TIMEOUT)
  61. return -1; /* entry has expired */
  62. if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
  63. if (session_timeout)
  64. *session_timeout =
  65. entry->session_timeout;
  66. if (acct_interim_interval)
  67. *acct_interim_interval =
  68. entry->acct_interim_interval;
  69. if (vlan_id)
  70. *vlan_id = entry->vlan_id;
  71. return entry->accepted;
  72. }
  73. entry = entry->next;
  74. }
  75. return -1;
  76. }
  77. static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
  78. {
  79. if (query == NULL)
  80. return;
  81. os_free(query->auth_msg);
  82. os_free(query);
  83. }
  84. static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
  85. struct hostapd_acl_query_data *query)
  86. {
  87. struct radius_msg *msg;
  88. char buf[128];
  89. query->radius_id = radius_client_get_id(hapd->radius);
  90. msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
  91. if (msg == NULL)
  92. return -1;
  93. radius_msg_make_authenticator(msg, addr, ETH_ALEN);
  94. os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
  95. if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
  96. os_strlen(buf))) {
  97. wpa_printf(MSG_DEBUG, "Could not add User-Name");
  98. goto fail;
  99. }
  100. if (!radius_msg_add_attr_user_password(
  101. msg, (u8 *) buf, os_strlen(buf),
  102. hapd->conf->radius->auth_server->shared_secret,
  103. hapd->conf->radius->auth_server->shared_secret_len)) {
  104. wpa_printf(MSG_DEBUG, "Could not add User-Password");
  105. goto fail;
  106. }
  107. if (hapd->conf->own_ip_addr.af == AF_INET &&
  108. !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
  109. (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
  110. wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address");
  111. goto fail;
  112. }
  113. #ifdef CONFIG_IPV6
  114. if (hapd->conf->own_ip_addr.af == AF_INET6 &&
  115. !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
  116. (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
  117. wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address");
  118. goto fail;
  119. }
  120. #endif /* CONFIG_IPV6 */
  121. if (hapd->conf->nas_identifier &&
  122. !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
  123. (u8 *) hapd->conf->nas_identifier,
  124. os_strlen(hapd->conf->nas_identifier))) {
  125. wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier");
  126. goto fail;
  127. }
  128. os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
  129. MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
  130. if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
  131. (u8 *) buf, os_strlen(buf))) {
  132. wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id");
  133. goto fail;
  134. }
  135. os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
  136. MAC2STR(addr));
  137. if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
  138. (u8 *) buf, os_strlen(buf))) {
  139. wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
  140. goto fail;
  141. }
  142. if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
  143. RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
  144. wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type");
  145. goto fail;
  146. }
  147. os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
  148. if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
  149. (u8 *) buf, os_strlen(buf))) {
  150. wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
  151. goto fail;
  152. }
  153. radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
  154. return 0;
  155. fail:
  156. radius_msg_free(msg);
  157. os_free(msg);
  158. return -1;
  159. }
  160. int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
  161. const u8 *msg, size_t len, u32 *session_timeout,
  162. u32 *acct_interim_interval, int *vlan_id)
  163. {
  164. if (session_timeout)
  165. *session_timeout = 0;
  166. if (acct_interim_interval)
  167. *acct_interim_interval = 0;
  168. if (vlan_id)
  169. *vlan_id = 0;
  170. if (hostapd_maclist_found(hapd->conf->accept_mac,
  171. hapd->conf->num_accept_mac, addr))
  172. return HOSTAPD_ACL_ACCEPT;
  173. if (hostapd_maclist_found(hapd->conf->deny_mac,
  174. hapd->conf->num_deny_mac, addr))
  175. return HOSTAPD_ACL_REJECT;
  176. if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
  177. return HOSTAPD_ACL_ACCEPT;
  178. if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
  179. return HOSTAPD_ACL_REJECT;
  180. if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
  181. struct hostapd_acl_query_data *query;
  182. /* Check whether ACL cache has an entry for this station */
  183. int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
  184. acct_interim_interval,
  185. vlan_id);
  186. if (res == HOSTAPD_ACL_ACCEPT ||
  187. res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
  188. return res;
  189. if (res == HOSTAPD_ACL_REJECT)
  190. return HOSTAPD_ACL_REJECT;
  191. query = hapd->acl_queries;
  192. while (query) {
  193. if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
  194. /* pending query in RADIUS retransmit queue;
  195. * do not generate a new one */
  196. return HOSTAPD_ACL_PENDING;
  197. }
  198. query = query->next;
  199. }
  200. if (!hapd->conf->radius->auth_server)
  201. return HOSTAPD_ACL_REJECT;
  202. /* No entry in the cache - query external RADIUS server */
  203. query = os_zalloc(sizeof(*query));
  204. if (query == NULL) {
  205. wpa_printf(MSG_ERROR, "malloc for query data failed");
  206. return HOSTAPD_ACL_REJECT;
  207. }
  208. time(&query->timestamp);
  209. os_memcpy(query->addr, addr, ETH_ALEN);
  210. if (hostapd_radius_acl_query(hapd, addr, query)) {
  211. wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
  212. "for ACL query.");
  213. hostapd_acl_query_free(query);
  214. return HOSTAPD_ACL_REJECT;
  215. }
  216. query->auth_msg = os_malloc(len);
  217. if (query->auth_msg == NULL) {
  218. wpa_printf(MSG_ERROR, "Failed to allocate memory for "
  219. "auth frame.");
  220. hostapd_acl_query_free(query);
  221. return HOSTAPD_ACL_REJECT;
  222. }
  223. os_memcpy(query->auth_msg, msg, len);
  224. query->auth_msg_len = len;
  225. query->next = hapd->acl_queries;
  226. hapd->acl_queries = query;
  227. /* Queued data will be processed in hostapd_acl_recv_radius()
  228. * when RADIUS server replies to the sent Access-Request. */
  229. return HOSTAPD_ACL_PENDING;
  230. }
  231. return HOSTAPD_ACL_REJECT;
  232. }
  233. static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
  234. {
  235. struct hostapd_cached_radius_acl *prev, *entry, *tmp;
  236. prev = NULL;
  237. entry = hapd->acl_cache;
  238. while (entry) {
  239. if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
  240. wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
  241. " has expired.", MAC2STR(entry->addr));
  242. if (prev)
  243. prev->next = entry->next;
  244. else
  245. hapd->acl_cache = entry->next;
  246. #ifdef CONFIG_DRIVER_RADIUS_ACL
  247. hostapd_set_radius_acl_expire(hapd, entry->addr);
  248. #endif /* CONFIG_DRIVER_RADIUS_ACL */
  249. tmp = entry;
  250. entry = entry->next;
  251. os_free(tmp);
  252. continue;
  253. }
  254. prev = entry;
  255. entry = entry->next;
  256. }
  257. }
  258. static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
  259. {
  260. struct hostapd_acl_query_data *prev, *entry, *tmp;
  261. prev = NULL;
  262. entry = hapd->acl_queries;
  263. while (entry) {
  264. if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
  265. wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
  266. " has expired.", MAC2STR(entry->addr));
  267. if (prev)
  268. prev->next = entry->next;
  269. else
  270. hapd->acl_queries = entry->next;
  271. tmp = entry;
  272. entry = entry->next;
  273. hostapd_acl_query_free(tmp);
  274. continue;
  275. }
  276. prev = entry;
  277. entry = entry->next;
  278. }
  279. }
  280. static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
  281. {
  282. struct hostapd_data *hapd = eloop_ctx;
  283. time_t now;
  284. time(&now);
  285. hostapd_acl_expire_cache(hapd, now);
  286. hostapd_acl_expire_queries(hapd, now);
  287. eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
  288. }
  289. /* Return 0 if RADIUS message was a reply to ACL query (and was processed here)
  290. * or -1 if not. */
  291. static RadiusRxResult
  292. hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
  293. u8 *shared_secret, size_t shared_secret_len,
  294. void *data)
  295. {
  296. struct hostapd_data *hapd = data;
  297. struct hostapd_acl_query_data *query, *prev;
  298. struct hostapd_cached_radius_acl *cache;
  299. query = hapd->acl_queries;
  300. prev = NULL;
  301. while (query) {
  302. if (query->radius_id == msg->hdr->identifier)
  303. break;
  304. prev = query;
  305. query = query->next;
  306. }
  307. if (query == NULL)
  308. return RADIUS_RX_UNKNOWN;
  309. wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
  310. "message (id=%d)", query->radius_id);
  311. if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
  312. wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
  313. "correct authenticator - dropped\n");
  314. return RADIUS_RX_INVALID_AUTHENTICATOR;
  315. }
  316. if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
  317. msg->hdr->code != RADIUS_CODE_ACCESS_REJECT) {
  318. wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
  319. "query", msg->hdr->code);
  320. return RADIUS_RX_UNKNOWN;
  321. }
  322. /* Insert Accept/Reject info into ACL cache */
  323. cache = os_zalloc(sizeof(*cache));
  324. if (cache == NULL) {
  325. wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
  326. goto done;
  327. }
  328. time(&cache->timestamp);
  329. os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
  330. if (msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
  331. if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
  332. &cache->session_timeout) == 0)
  333. cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
  334. else
  335. cache->accepted = HOSTAPD_ACL_ACCEPT;
  336. if (radius_msg_get_attr_int32(
  337. msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
  338. &cache->acct_interim_interval) == 0 &&
  339. cache->acct_interim_interval < 60) {
  340. wpa_printf(MSG_DEBUG, "Ignored too small "
  341. "Acct-Interim-Interval %d for STA " MACSTR,
  342. cache->acct_interim_interval,
  343. MAC2STR(query->addr));
  344. cache->acct_interim_interval = 0;
  345. }
  346. cache->vlan_id = radius_msg_get_vlanid(msg);
  347. } else
  348. cache->accepted = HOSTAPD_ACL_REJECT;
  349. cache->next = hapd->acl_cache;
  350. hapd->acl_cache = cache;
  351. #ifdef CONFIG_DRIVER_RADIUS_ACL
  352. hostapd_set_radius_acl_auth(hapd, query->addr, cache->accepted,
  353. cache->session_timeout);
  354. #else /* CONFIG_DRIVER_RADIUS_ACL */
  355. /* Re-send original authentication frame for 802.11 processing */
  356. wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
  357. "successful RADIUS ACL query");
  358. ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
  359. WLAN_FC_STYPE_AUTH, NULL);
  360. #endif /* CONFIG_DRIVER_RADIUS_ACL */
  361. done:
  362. if (prev == NULL)
  363. hapd->acl_queries = query->next;
  364. else
  365. prev->next = query->next;
  366. hostapd_acl_query_free(query);
  367. return RADIUS_RX_PROCESSED;
  368. }
  369. int hostapd_acl_init(struct hostapd_data *hapd)
  370. {
  371. if (radius_client_register(hapd->radius, RADIUS_AUTH,
  372. hostapd_acl_recv_radius, hapd))
  373. return -1;
  374. eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
  375. return 0;
  376. }
  377. void hostapd_acl_deinit(struct hostapd_data *hapd)
  378. {
  379. struct hostapd_acl_query_data *query, *prev;
  380. eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
  381. hostapd_acl_cache_free(hapd->acl_cache);
  382. query = hapd->acl_queries;
  383. while (query) {
  384. prev = query;
  385. query = query->next;
  386. hostapd_acl_query_free(prev);
  387. }
  388. }
  389. int hostapd_acl_reconfig(struct hostapd_data *hapd,
  390. struct hostapd_config *oldconf)
  391. {
  392. if (!hapd->radius_client_reconfigured)
  393. return 0;
  394. hostapd_acl_deinit(hapd);
  395. return hostapd_acl_init(hapd);
  396. }
  397. #endif /* CONFIG_NATIVE_WINDOWS */