ieee802_11_auth.c 14 KB

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