ieee802_11_auth.c 15 KB

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