ieee802_11_auth.c 15 KB

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