]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/radius/radius_server.c
EAP-TEAP server: Allow a specific Identity-Type to be requested/required
[thirdparty/hostap.git] / src / radius / radius_server.c
CommitLineData
6fc6879b 1/*
362bd35f 2 * RADIUS authentication server
429ed54a 3 * Copyright (c) 2005-2009, 2011-2019, Jouni Malinen <j@w1.fi>
6fc6879b 4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
6fc6879b
JM
7 */
8
9#include "includes.h"
10#include <net/if.h>
8a57da7e
JM
11#ifdef CONFIG_SQLITE
12#include <sqlite3.h>
13#endif /* CONFIG_SQLITE */
6fc6879b
JM
14
15#include "common.h"
16#include "radius.h"
17#include "eloop.h"
6fc6879b 18#include "eap_server/eap.h"
d0ee16ed 19#include "ap/ap_config.h"
390b9291 20#include "crypto/tls.h"
6fc6879b
JM
21#include "radius_server.h"
22
362bd35f
JM
23/**
24 * RADIUS_SESSION_TIMEOUT - Session timeout in seconds
25 */
6fc6879b 26#define RADIUS_SESSION_TIMEOUT 60
362bd35f 27
35677305
JM
28/**
29 * RADIUS_SESSION_MAINTAIN - Completed session expiration timeout in seconds
30 */
31#define RADIUS_SESSION_MAINTAIN 5
32
362bd35f
JM
33/**
34 * RADIUS_MAX_SESSION - Maximum number of active sessions
35 */
35677305 36#define RADIUS_MAX_SESSION 1000
362bd35f
JM
37
38/**
39 * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages
40 */
6fc6879b
JM
41#define RADIUS_MAX_MSG_LEN 3000
42
8b423edb 43static const struct eapol_callbacks radius_server_eapol_cb;
6fc6879b
JM
44
45struct radius_client;
46struct radius_server_data;
47
362bd35f
JM
48/**
49 * struct radius_server_counters - RADIUS server statistics counters
50 */
6fc6879b
JM
51struct radius_server_counters {
52 u32 access_requests;
53 u32 invalid_requests;
54 u32 dup_access_requests;
55 u32 access_accepts;
56 u32 access_rejects;
57 u32 access_challenges;
58 u32 malformed_access_requests;
59 u32 bad_authenticators;
60 u32 packets_dropped;
61 u32 unknown_types;
a1dd890a
JM
62
63 u32 acct_requests;
64 u32 invalid_acct_requests;
65 u32 acct_responses;
66 u32 malformed_acct_requests;
67 u32 acct_bad_authenticators;
68 u32 unknown_acct_types;
6fc6879b
JM
69};
70
362bd35f
JM
71/**
72 * struct radius_session - Internal RADIUS server data for a session
73 */
6fc6879b
JM
74struct radius_session {
75 struct radius_session *next;
76 struct radius_client *client;
77 struct radius_server_data *server;
78 unsigned int sess_id;
79 struct eap_sm *eap;
80 struct eap_eapol_interface *eap_if;
8a57da7e
JM
81 char *username; /* from User-Name attribute */
82 char *nas_ip;
04ee197f 83 u8 mac_addr[ETH_ALEN]; /* from Calling-Station-Id attribute */
6fc6879b
JM
84
85 struct radius_msg *last_msg;
86 char *last_from_addr;
87 int last_from_port;
88 struct sockaddr_storage last_from;
89 socklen_t last_fromlen;
90 u8 last_identifier;
91 struct radius_msg *last_reply;
92 u8 last_authenticator[16];
8d2a9921
JM
93
94 unsigned int remediation:1;
8943cc99 95 unsigned int macacl:1;
45260380 96 unsigned int t_c_filtering:1;
d0ee16ed
JM
97
98 struct hostapd_radius_attr *accept_attr;
45260380
JM
99
100 u32 t_c_timestamp; /* Last read T&C timestamp from user DB */
6fc6879b
JM
101};
102
362bd35f
JM
103/**
104 * struct radius_client - Internal RADIUS server data for a client
105 */
6fc6879b
JM
106struct radius_client {
107 struct radius_client *next;
108 struct in_addr addr;
109 struct in_addr mask;
110#ifdef CONFIG_IPV6
111 struct in6_addr addr6;
112 struct in6_addr mask6;
113#endif /* CONFIG_IPV6 */
114 char *shared_secret;
115 int shared_secret_len;
116 struct radius_session *sessions;
117 struct radius_server_counters counters;
abed6136
JM
118
119 u8 next_dac_identifier;
120 struct radius_msg *pending_dac_coa_req;
121 u8 pending_dac_coa_id;
122 u8 pending_dac_coa_addr[ETH_ALEN];
123 struct radius_msg *pending_dac_disconnect_req;
124 u8 pending_dac_disconnect_id;
125 u8 pending_dac_disconnect_addr[ETH_ALEN];
6fc6879b
JM
126};
127
362bd35f
JM
128/**
129 * struct radius_server_data - Internal RADIUS server data
130 */
6fc6879b 131struct radius_server_data {
362bd35f
JM
132 /**
133 * auth_sock - Socket for RADIUS authentication messages
134 */
6fc6879b 135 int auth_sock;
362bd35f 136
a1dd890a
JM
137 /**
138 * acct_sock - Socket for RADIUS accounting messages
139 */
140 int acct_sock;
141
362bd35f
JM
142 /**
143 * clients - List of authorized RADIUS clients
144 */
6fc6879b 145 struct radius_client *clients;
362bd35f
JM
146
147 /**
148 * next_sess_id - Next session identifier
149 */
6fc6879b 150 unsigned int next_sess_id;
362bd35f
JM
151
152 /**
153 * conf_ctx - Context pointer for callbacks
154 *
155 * This is used as the ctx argument in get_eap_user() calls.
156 */
6fc6879b 157 void *conf_ctx;
362bd35f
JM
158
159 /**
160 * num_sess - Number of active sessions
161 */
6fc6879b 162 int num_sess;
362bd35f 163
d3bddd8b
JM
164 const char *erp_domain;
165
166 struct dl_list erp_keys; /* struct eap_server_erp_key */
167
362bd35f
JM
168 /**
169 * ipv6 - Whether to enable IPv6 support in the RADIUS server
170 */
6fc6879b 171 int ipv6;
362bd35f
JM
172
173 /**
174 * start_time - Timestamp of server start
175 */
58707176 176 struct os_reltime start_time;
362bd35f
JM
177
178 /**
179 * counters - Statistics counters for server operations
180 *
181 * These counters are the sum over all clients.
182 */
6fc6879b 183 struct radius_server_counters counters;
362bd35f
JM
184
185 /**
186 * get_eap_user - Callback for fetching EAP user information
187 * @ctx: Context data from conf_ctx
188 * @identity: User identity
189 * @identity_len: identity buffer length in octets
190 * @phase2: Whether this is for Phase 2 identity
191 * @user: Data structure for filling in the user information
192 * Returns: 0 on success, -1 on failure
193 *
194 * This is used to fetch information from user database. The callback
195 * will fill in information about allowed EAP methods and the user
196 * password. The password field will be an allocated copy of the
197 * password data and RADIUS server will free it after use.
198 */
6fc6879b
JM
199 int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
200 int phase2, struct eap_user *user);
362bd35f
JM
201
202 /**
203 * eap_req_id_text - Optional data for EAP-Request/Identity
204 *
205 * This can be used to configure an optional, displayable message that
206 * will be sent in EAP-Request/Identity. This string can contain an
207 * ASCII-0 character (nul) to separate network infromation per RFC
208 * 4284. The actual string length is explicit provided in
209 * eap_req_id_text_len since nul character will not be used as a string
210 * terminator.
211 */
65d50f0a 212 char *eap_req_id_text;
362bd35f
JM
213
214 /**
215 * eap_req_id_text_len - Length of eap_req_id_text buffer in octets
216 */
65d50f0a 217 size_t eap_req_id_text_len;
bb437f28 218
505a3694
JM
219#ifdef CONFIG_RADIUS_TEST
220 char *dump_msk_file;
221#endif /* CONFIG_RADIUS_TEST */
8d2a9921
JM
222
223 char *subscr_remediation_url;
224 u8 subscr_remediation_method;
7bd8c76a 225 char *hs20_sim_provisioning_url;
8a57da7e 226
d4e39c51
JM
227 char *t_c_server_url;
228
8a57da7e
JM
229#ifdef CONFIG_SQLITE
230 sqlite3 *db;
231#endif /* CONFIG_SQLITE */
822e7c66
JM
232
233 struct eap_config *eap_cfg;
6fc6879b
JM
234};
235
236
6fc6879b
JM
237#define RADIUS_DEBUG(args...) \
238wpa_printf(MSG_DEBUG, "RADIUS SRV: " args)
239#define RADIUS_ERROR(args...) \
240wpa_printf(MSG_ERROR, "RADIUS SRV: " args)
241#define RADIUS_DUMP(args...) \
242wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args)
243#define RADIUS_DUMP_ASCII(args...) \
244wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args)
245
246
247static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
f481459f
JM
248static void radius_server_session_remove_timeout(void *eloop_ctx,
249 void *timeout_ctx);
6fc6879b 250
7bd8c76a
JM
251#ifdef CONFIG_SQLITE
252#ifdef CONFIG_HS20
253
254static int db_table_exists(sqlite3 *db, const char *name)
255{
256 char cmd[128];
257
258 os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
259 return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
260}
261
262
263static int db_table_create_sim_provisioning(sqlite3 *db)
264{
265 char *err = NULL;
266 const char *sql =
267 "CREATE TABLE sim_provisioning("
268 " mobile_identifier_hash TEXT PRIMARY KEY,"
269 " imsi TEXT,"
270 " mac_addr TEXT,"
271 " eap_method TEXT,"
272 " timestamp TEXT"
273 ");";
274
275 RADIUS_DEBUG("Adding database table for SIM provisioning information");
276 if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
277 RADIUS_ERROR("SQLite error: %s", err);
278 sqlite3_free(err);
279 return -1;
280 }
281
282 return 0;
283}
284
285#endif /* CONFIG_HS20 */
286#endif /* CONFIG_SQLITE */
287
288
8a57da7e
JM
289void srv_log(struct radius_session *sess, const char *fmt, ...)
290PRINTF_FORMAT(2, 3);
291
292void srv_log(struct radius_session *sess, const char *fmt, ...)
293{
294 va_list ap;
295 char *buf;
296 int buflen;
297
298 va_start(ap, fmt);
299 buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
300 va_end(ap);
301
302 buf = os_malloc(buflen);
303 if (buf == NULL)
304 return;
305 va_start(ap, fmt);
306 vsnprintf(buf, buflen, fmt, ap);
307 va_end(ap);
308
309 RADIUS_DEBUG("[0x%x %s] %s", sess->sess_id, sess->nas_ip, buf);
310
311#ifdef CONFIG_SQLITE
312 if (sess->server->db) {
313 char *sql;
314 sql = sqlite3_mprintf("INSERT INTO authlog"
315 "(timestamp,session,nas_ip,username,note)"
316 " VALUES ("
317 "strftime('%%Y-%%m-%%d %%H:%%M:%%f',"
318 "'now'),%u,%Q,%Q,%Q)",
319 sess->sess_id, sess->nas_ip,
320 sess->username, buf);
321 if (sql) {
322 if (sqlite3_exec(sess->server->db, sql, NULL, NULL,
323 NULL) != SQLITE_OK) {
324 RADIUS_ERROR("Failed to add authlog entry into sqlite database: %s",
325 sqlite3_errmsg(sess->server->db));
326 }
327 sqlite3_free(sql);
328 }
329 }
330#endif /* CONFIG_SQLITE */
331
332 os_free(buf);
333}
334
6fc6879b
JM
335
336static struct radius_client *
337radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
338 int ipv6)
339{
340 struct radius_client *client = data->clients;
341
342 while (client) {
343#ifdef CONFIG_IPV6
344 if (ipv6) {
345 struct in6_addr *addr6;
346 int i;
347
348 addr6 = (struct in6_addr *) addr;
349 for (i = 0; i < 16; i++) {
350 if ((addr6->s6_addr[i] &
351 client->mask6.s6_addr[i]) !=
352 (client->addr6.s6_addr[i] &
353 client->mask6.s6_addr[i])) {
354 i = 17;
355 break;
356 }
357 }
358 if (i == 16) {
359 break;
360 }
361 }
362#endif /* CONFIG_IPV6 */
363 if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) ==
364 (addr->s_addr & client->mask.s_addr)) {
365 break;
366 }
367
368 client = client->next;
369 }
370
371 return client;
372}
373
374
375static struct radius_session *
376radius_server_get_session(struct radius_client *client, unsigned int sess_id)
377{
378 struct radius_session *sess = client->sessions;
379
380 while (sess) {
381 if (sess->sess_id == sess_id) {
382 break;
383 }
384 sess = sess->next;
385 }
386
387 return sess;
388}
389
390
391static void radius_server_session_free(struct radius_server_data *data,
392 struct radius_session *sess)
393{
394 eloop_cancel_timeout(radius_server_session_timeout, data, sess);
f481459f 395 eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
6fc6879b 396 eap_server_sm_deinit(sess->eap);
9e7245bd 397 radius_msg_free(sess->last_msg);
6fc6879b 398 os_free(sess->last_from_addr);
9e7245bd 399 radius_msg_free(sess->last_reply);
8a57da7e
JM
400 os_free(sess->username);
401 os_free(sess->nas_ip);
6fc6879b
JM
402 os_free(sess);
403 data->num_sess--;
404}
405
406
6fc6879b
JM
407static void radius_server_session_remove(struct radius_server_data *data,
408 struct radius_session *sess)
409{
410 struct radius_client *client = sess->client;
411 struct radius_session *session, *prev;
412
413 eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
414
415 prev = NULL;
416 session = client->sessions;
417 while (session) {
418 if (session == sess) {
419 if (prev == NULL) {
420 client->sessions = sess->next;
421 } else {
422 prev->next = sess->next;
423 }
424 radius_server_session_free(data, sess);
425 break;
426 }
427 prev = session;
428 session = session->next;
429 }
430}
431
432
433static void radius_server_session_remove_timeout(void *eloop_ctx,
434 void *timeout_ctx)
435{
436 struct radius_server_data *data = eloop_ctx;
437 struct radius_session *sess = timeout_ctx;
438 RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);
439 radius_server_session_remove(data, sess);
440}
441
442
443static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx)
444{
445 struct radius_server_data *data = eloop_ctx;
446 struct radius_session *sess = timeout_ctx;
447
448 RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id);
449 radius_server_session_remove(data, sess);
450}
451
452
453static struct radius_session *
454radius_server_new_session(struct radius_server_data *data,
455 struct radius_client *client)
456{
457 struct radius_session *sess;
458
459 if (data->num_sess >= RADIUS_MAX_SESSION) {
460 RADIUS_DEBUG("Maximum number of existing session - no room "
461 "for a new session");
462 return NULL;
463 }
464
465 sess = os_zalloc(sizeof(*sess));
466 if (sess == NULL)
467 return NULL;
468
469 sess->server = data;
470 sess->client = client;
471 sess->sess_id = data->next_sess_id++;
472 sess->next = client->sessions;
473 client->sessions = sess;
474 eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0,
475 radius_server_session_timeout, data, sess);
476 data->num_sess++;
477 return sess;
478}
479
480
390b9291
JM
481#ifdef CONFIG_TESTING_OPTIONS
482static void radius_server_testing_options_tls(struct radius_session *sess,
483 const char *tls,
822e7c66 484 struct eap_session_data *eap_conf)
390b9291
JM
485{
486 int test = atoi(tls);
487
488 switch (test) {
489 case 1:
490 srv_log(sess, "TLS test - break VerifyData");
491 eap_conf->tls_test_flags = TLS_BREAK_VERIFY_DATA;
492 break;
493 case 2:
494 srv_log(sess, "TLS test - break ServerKeyExchange ServerParams hash");
495 eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_HASH;
496 break;
497 case 3:
498 srv_log(sess, "TLS test - break ServerKeyExchange ServerParams Signature");
499 eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_SIGNATURE;
500 break;
47bd94a0
JM
501 case 4:
502 srv_log(sess, "TLS test - RSA-DHE using a short 511-bit prime");
503 eap_conf->tls_test_flags = TLS_DHE_PRIME_511B;
504 break;
505 case 5:
506 srv_log(sess, "TLS test - RSA-DHE using a short 767-bit prime");
507 eap_conf->tls_test_flags = TLS_DHE_PRIME_767B;
508 break;
509 case 6:
510 srv_log(sess, "TLS test - RSA-DHE using a bogus 15 \"prime\"");
511 eap_conf->tls_test_flags = TLS_DHE_PRIME_15;
512 break;
513 case 7:
514 srv_log(sess, "TLS test - RSA-DHE using a short 58-bit prime in long container");
515 eap_conf->tls_test_flags = TLS_DHE_PRIME_58B;
516 break;
517 case 8:
518 srv_log(sess, "TLS test - RSA-DHE using a non-prime");
519 eap_conf->tls_test_flags = TLS_DHE_NON_PRIME;
520 break;
390b9291
JM
521 default:
522 srv_log(sess, "Unrecognized TLS test");
523 break;
524 }
525}
526#endif /* CONFIG_TESTING_OPTIONS */
527
528static void radius_server_testing_options(struct radius_session *sess,
822e7c66 529 struct eap_session_data *eap_conf)
390b9291
JM
530{
531#ifdef CONFIG_TESTING_OPTIONS
532 const char *pos;
533
534 pos = os_strstr(sess->username, "@test-");
535 if (pos == NULL)
536 return;
537 pos += 6;
538 if (os_strncmp(pos, "tls-", 4) == 0)
539 radius_server_testing_options_tls(sess, pos + 4, eap_conf);
540 else
541 srv_log(sess, "Unrecognized test: %s", pos);
542#endif /* CONFIG_TESTING_OPTIONS */
543}
544
545
3580ed82
JM
546#ifdef CONFIG_ERP
547static struct eap_server_erp_key *
548radius_server_erp_find_key(struct radius_server_data *data, const char *keyname)
549{
550 struct eap_server_erp_key *erp;
551
552 dl_list_for_each(erp, &data->erp_keys, struct eap_server_erp_key,
553 list) {
554 if (os_strcmp(erp->keyname_nai, keyname) == 0)
555 return erp;
556 }
557
558 return NULL;
559}
560#endif /* CONFIG_ERP */
561
562
6fc6879b
JM
563static struct radius_session *
564radius_server_get_new_session(struct radius_server_data *data,
565 struct radius_client *client,
8a57da7e 566 struct radius_msg *msg, const char *from_addr)
6fc6879b 567{
04ee197f
JM
568 u8 *user, *id;
569 size_t user_len, id_len;
6fc6879b
JM
570 int res;
571 struct radius_session *sess;
822e7c66 572 struct eap_session_data eap_sess;
1e653daa 573 struct eap_user *tmp;
6fc6879b
JM
574
575 RADIUS_DEBUG("Creating a new session");
576
8a57da7e
JM
577 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &user,
578 &user_len, NULL) < 0) {
6fc6879b 579 RADIUS_DEBUG("Could not get User-Name");
6fc6879b
JM
580 return NULL;
581 }
6fc6879b
JM
582 RADIUS_DUMP_ASCII("User-Name", user, user_len);
583
1e653daa
MH
584 tmp = os_zalloc(sizeof(*tmp));
585 if (!tmp)
586 return NULL;
6fc6879b 587
1e653daa 588 res = data->get_eap_user(data->conf_ctx, user, user_len, 0, tmp);
3580ed82 589#ifdef CONFIG_ERP
822e7c66 590 if (res != 0 && data->eap_cfg->erp) {
3580ed82
JM
591 char *username;
592
593 username = os_zalloc(user_len + 1);
594 if (username) {
595 os_memcpy(username, user, user_len);
596 if (radius_server_erp_find_key(data, username))
597 res = 0;
598 os_free(username);
599 }
600 }
601#endif /* CONFIG_ERP */
8a57da7e 602 if (res != 0) {
6fc6879b 603 RADIUS_DEBUG("User-Name not found from user database");
1e653daa 604 eap_user_free(tmp);
6fc6879b
JM
605 return NULL;
606 }
607
8a57da7e
JM
608 RADIUS_DEBUG("Matching user entry found");
609 sess = radius_server_new_session(data, client);
610 if (sess == NULL) {
611 RADIUS_DEBUG("Failed to create a new session");
1e653daa 612 eap_user_free(tmp);
8a57da7e
JM
613 return NULL;
614 }
1e653daa
MH
615 sess->accept_attr = tmp->accept_attr;
616 sess->macacl = tmp->macacl;
617 eap_user_free(tmp);
8a57da7e 618
95f6f6a4 619 sess->username = os_malloc(user_len * 4 + 1);
8a57da7e 620 if (sess->username == NULL) {
de01f254 621 radius_server_session_remove(data, sess);
8a57da7e
JM
622 return NULL;
623 }
95f6f6a4 624 printf_encode(sess->username, user_len * 4 + 1, user, user_len);
8a57da7e
JM
625
626 sess->nas_ip = os_strdup(from_addr);
627 if (sess->nas_ip == NULL) {
de01f254 628 radius_server_session_remove(data, sess);
8a57da7e
JM
629 return NULL;
630 }
631
04ee197f
JM
632 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID, &id,
633 &id_len, NULL) == 0) {
634 char buf[3 * ETH_ALEN];
635
636 os_memset(buf, 0, sizeof(buf));
637 if (id_len >= sizeof(buf))
638 id_len = sizeof(buf) - 1;
639 os_memcpy(buf, id, id_len);
640 if (hwaddr_aton2(buf, sess->mac_addr) < 0)
641 os_memset(sess->mac_addr, 0, ETH_ALEN);
642 else
643 RADIUS_DEBUG("Calling-Station-Id: " MACSTR,
644 MAC2STR(sess->mac_addr));
645 }
646
8a57da7e
JM
647 srv_log(sess, "New session created");
648
822e7c66
JM
649 os_memset(&eap_sess, 0, sizeof(eap_sess));
650 radius_server_testing_options(sess, &eap_sess);
6fc6879b 651 sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
822e7c66 652 data->eap_cfg, &eap_sess);
6fc6879b
JM
653 if (sess->eap == NULL) {
654 RADIUS_DEBUG("Failed to initialize EAP state machine for the "
655 "new session");
de01f254 656 radius_server_session_remove(data, sess);
6fc6879b
JM
657 return NULL;
658 }
659 sess->eap_if = eap_get_interface(sess->eap);
660 sess->eap_if->eapRestart = TRUE;
661 sess->eap_if->portEnabled = TRUE;
662
663 RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);
664
665 return sess;
666}
667
668
04ee197f
JM
669#ifdef CONFIG_HS20
670static void radius_srv_hs20_t_c_pending(struct radius_session *sess)
671{
672#ifdef CONFIG_SQLITE
673 char *sql;
674 char addr[3 * ETH_ALEN], *id_str;
675 const u8 *id;
676 size_t id_len;
677
678 if (!sess->server->db || !sess->eap ||
679 is_zero_ether_addr(sess->mac_addr))
680 return;
681
682 os_snprintf(addr, sizeof(addr), MACSTR, MAC2STR(sess->mac_addr));
683
684 id = eap_get_identity(sess->eap, &id_len);
685 if (!id)
686 return;
687 id_str = os_malloc(id_len + 1);
688 if (!id_str)
689 return;
690 os_memcpy(id_str, id, id_len);
691 id_str[id_len] = '\0';
692
693 sql = sqlite3_mprintf("INSERT OR REPLACE INTO pending_tc (mac_addr,identity) VALUES (%Q,%Q)",
694 addr, id_str);
695 os_free(id_str);
696 if (!sql)
697 return;
698
699 if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
700 SQLITE_OK) {
701 RADIUS_ERROR("Failed to add pending_tc entry into sqlite database: %s",
702 sqlite3_errmsg(sess->server->db));
703 }
704 sqlite3_free(sql);
705#endif /* CONFIG_SQLITE */
706}
707#endif /* CONFIG_HS20 */
708
709
2122fc83
JM
710static void radius_server_add_session(struct radius_session *sess)
711{
712#ifdef CONFIG_SQLITE
713 char *sql;
714 char addr_txt[ETH_ALEN * 3];
715 struct os_time now;
716
717 if (!sess->server->db)
718 return;
719
720
721 os_snprintf(addr_txt, sizeof(addr_txt), MACSTR,
722 MAC2STR(sess->mac_addr));
723
724 os_get_time(&now);
725 sql = sqlite3_mprintf("INSERT OR REPLACE INTO current_sessions(mac_addr,identity,start_time,nas,hs20_t_c_filtering) VALUES (%Q,%Q,%d,%Q,%u)",
726 addr_txt, sess->username, now.sec,
727 sess->nas_ip, sess->t_c_filtering);
728 if (sql) {
729 if (sqlite3_exec(sess->server->db, sql, NULL, NULL,
730 NULL) != SQLITE_OK) {
731 RADIUS_ERROR("Failed to add current_sessions entry into sqlite database: %s",
732 sqlite3_errmsg(sess->server->db));
733 }
734 sqlite3_free(sql);
735 }
736#endif /* CONFIG_SQLITE */
737}
738
739
ad4e4f60
JM
740static void db_update_last_msk(struct radius_session *sess, const char *msk)
741{
742#ifdef CONFIG_RADIUS_TEST
743#ifdef CONFIG_SQLITE
744 char *sql = NULL;
745 char *id_str = NULL;
746 const u8 *id;
747 size_t id_len;
7770a9dd 748 const char *serial_num;
ad4e4f60
JM
749
750 if (!sess->server->db)
751 return;
752
7770a9dd
JM
753 serial_num = eap_get_serial_num(sess->eap);
754 if (serial_num) {
755 id_len = 5 + os_strlen(serial_num) + 1;
756 id_str = os_malloc(id_len);
757 if (!id_str)
758 return;
759 os_snprintf(id_str, id_len, "cert-%s", serial_num);
760 } else {
761 id = eap_get_identity(sess->eap, &id_len);
762 if (!id)
763 return;
764 id_str = os_malloc(id_len + 1);
765 if (!id_str)
766 return;
767 os_memcpy(id_str, id, id_len);
768 id_str[id_len] = '\0';
769 }
ad4e4f60
JM
770
771 sql = sqlite3_mprintf("UPDATE users SET last_msk=%Q WHERE identity=%Q",
772 msk, id_str);
773 os_free(id_str);
774 if (!sql)
775 return;
776
777 if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
778 SQLITE_OK) {
779 RADIUS_DEBUG("Failed to update last_msk: %s",
780 sqlite3_errmsg(sess->server->db));
781 }
782 sqlite3_free(sql);
783#endif /* CONFIG_SQLITE */
784#endif /* CONFIG_RADIUS_TEST */
785}
786
787
7bd8c76a
JM
788#ifdef CONFIG_HS20
789
790static int radius_server_is_sim_method(struct radius_session *sess)
791{
792 const char *name;
793
794 name = eap_get_method(sess->eap);
795 return name &&
796 (os_strcmp(name, "SIM") == 0 ||
797 os_strcmp(name, "AKA") == 0 ||
798 os_strcmp(name, "AKA'") == 0);
799}
800
801
802static int radius_server_hs20_missing_sim_pps(struct radius_msg *request)
803{
804 u8 *buf, *pos, *end, type, sublen;
805 size_t len;
806
807 buf = NULL;
808 for (;;) {
809 if (radius_msg_get_attr_ptr(request,
810 RADIUS_ATTR_VENDOR_SPECIFIC,
811 &buf, &len, buf) < 0)
812 return 0;
813 if (len < 6)
814 continue;
815 pos = buf;
816 end = buf + len;
817 if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
818 continue;
819 pos += 4;
820
821 type = *pos++;
822 sublen = *pos++;
823 if (sublen < 2)
824 continue; /* invalid length */
825 sublen -= 2; /* skip header */
826 if (pos + sublen > end)
827 continue; /* invalid WFA VSA */
828
829 if (type != RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION)
830 continue;
831
832 RADIUS_DUMP("HS2.0 mobile device version", pos, sublen);
833 if (sublen < 1 + 2)
834 continue;
835 if (pos[0] == 0)
836 continue; /* Release 1 STA does not support provisioning
837
838 */
839 /* UpdateIdentifier 0 indicates no PPS MO */
840 return WPA_GET_BE16(pos + 1) == 0;
841 }
842}
843
844
845#define HS20_MOBILE_ID_HASH_LEN 16
846
847static int radius_server_sim_provisioning_session(struct radius_session *sess,
848 const u8 *hash)
849{
850#ifdef CONFIG_SQLITE
851 char *sql;
852 char addr_txt[ETH_ALEN * 3];
853 char hash_txt[2 * HS20_MOBILE_ID_HASH_LEN + 1];
854 struct os_time now;
855 int res;
856 const char *imsi, *eap_method;
857
858 if (!sess->server->db ||
859 (!db_table_exists(sess->server->db, "sim_provisioning") &&
860 db_table_create_sim_provisioning(sess->server->db) < 0))
861 return -1;
862
863 imsi = eap_get_imsi(sess->eap);
864 if (!imsi)
865 return -1;
866
867 eap_method = eap_get_method(sess->eap);
868 if (!eap_method)
869 return -1;
870
871 os_snprintf(addr_txt, sizeof(addr_txt), MACSTR,
872 MAC2STR(sess->mac_addr));
873 wpa_snprintf_hex(hash_txt, sizeof(hash_txt), hash,
874 HS20_MOBILE_ID_HASH_LEN);
875
876 os_get_time(&now);
877 sql = sqlite3_mprintf("INSERT INTO sim_provisioning(mobile_identifier_hash,imsi,mac_addr,eap_method,timestamp) VALUES (%Q,%Q,%Q,%Q,%u)",
878 hash_txt, imsi, addr_txt, eap_method, now.sec);
879 if (!sql)
880 return -1;
881
882 if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
883 SQLITE_OK) {
884 RADIUS_ERROR("Failed to add SIM provisioning entry into sqlite database: %s",
885 sqlite3_errmsg(sess->server->db));
886 res = -1;
887 } else {
888 res = 0;
889 }
890 sqlite3_free(sql);
891 return res;
892#endif /* CONFIG_SQLITE */
893 return -1;
894}
895
896#endif /* CONFIG_HS20 */
897
898
6fc6879b
JM
899static struct radius_msg *
900radius_server_encapsulate_eap(struct radius_server_data *data,
901 struct radius_client *client,
902 struct radius_session *sess,
903 struct radius_msg *request)
904{
905 struct radius_msg *msg;
906 int code;
907 unsigned int sess_id;
1489e11a 908 struct radius_hdr *hdr = radius_msg_get_hdr(request);
f75ed556 909 u16 reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
6fc6879b
JM
910
911 if (sess->eap_if->eapFail) {
912 sess->eap_if->eapFail = FALSE;
913 code = RADIUS_CODE_ACCESS_REJECT;
914 } else if (sess->eap_if->eapSuccess) {
915 sess->eap_if->eapSuccess = FALSE;
916 code = RADIUS_CODE_ACCESS_ACCEPT;
917 } else {
918 sess->eap_if->eapReq = FALSE;
919 code = RADIUS_CODE_ACCESS_CHALLENGE;
920 }
921
1489e11a 922 msg = radius_msg_new(code, hdr->identifier);
6fc6879b
JM
923 if (msg == NULL) {
924 RADIUS_DEBUG("Failed to allocate reply message");
925 return NULL;
926 }
927
928 sess_id = htonl(sess->sess_id);
929 if (code == RADIUS_CODE_ACCESS_CHALLENGE &&
930 !radius_msg_add_attr(msg, RADIUS_ATTR_STATE,
931 (u8 *) &sess_id, sizeof(sess_id))) {
932 RADIUS_DEBUG("Failed to add State attribute");
933 }
934
935 if (sess->eap_if->eapReqData &&
936 !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData),
937 wpabuf_len(sess->eap_if->eapReqData))) {
938 RADIUS_DEBUG("Failed to add EAP-Message attribute");
939 }
940
941 if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
942 int len;
505a3694 943#ifdef CONFIG_RADIUS_TEST
ad4e4f60
JM
944 char buf[2 * 64 + 1];
945
946 len = sess->eap_if->eapKeyDataLen;
947 if (len > 64)
948 len = 64;
949 len = wpa_snprintf_hex(buf, sizeof(buf),
950 sess->eap_if->eapKeyData, len);
951 buf[len] = '\0';
952
505a3694
JM
953 if (data->dump_msk_file) {
954 FILE *f;
ad4e4f60 955
505a3694
JM
956 f = fopen(data->dump_msk_file, "a");
957 if (f) {
958 len = sess->eap_if->eapKeyDataLen;
959 if (len > 64)
960 len = 64;
961 len = wpa_snprintf_hex(
962 buf, sizeof(buf),
963 sess->eap_if->eapKeyData, len);
964 buf[len] = '\0';
965 fprintf(f, "%s\n", buf);
966 fclose(f);
967 }
968 }
ad4e4f60
JM
969
970 db_update_last_msk(sess, buf);
505a3694 971#endif /* CONFIG_RADIUS_TEST */
6fc6879b
JM
972 if (sess->eap_if->eapKeyDataLen > 64) {
973 len = 32;
974 } else {
975 len = sess->eap_if->eapKeyDataLen / 2;
976 }
1489e11a 977 if (!radius_msg_add_mppe_keys(msg, hdr->authenticator,
6fc6879b
JM
978 (u8 *) client->shared_secret,
979 client->shared_secret_len,
980 sess->eap_if->eapKeyData + len,
981 len, sess->eap_if->eapKeyData,
982 len)) {
983 RADIUS_DEBUG("Failed to add MPPE key attributes");
984 }
59fcb3f0
JM
985
986 if (sess->eap_if->eapSessionId &&
987 !radius_msg_add_attr(msg, RADIUS_ATTR_EAP_KEY_NAME,
988 sess->eap_if->eapSessionId,
989 sess->eap_if->eapSessionIdLen)) {
990 RADIUS_DEBUG("Failed to add EAP-Key-Name attribute");
991 }
6fc6879b
JM
992 }
993
8d2a9921
JM
994#ifdef CONFIG_HS20
995 if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation &&
996 data->subscr_remediation_url) {
997 u8 *buf;
998 size_t url_len = os_strlen(data->subscr_remediation_url);
999 buf = os_malloc(1 + url_len);
1000 if (buf == NULL) {
1001 radius_msg_free(msg);
1002 return NULL;
1003 }
1004 buf[0] = data->subscr_remediation_method;
1005 os_memcpy(&buf[1], data->subscr_remediation_url, url_len);
1006 if (!radius_msg_add_wfa(
1007 msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
1008 buf, 1 + url_len)) {
1009 RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
1010 }
1011 os_free(buf);
1012 } else if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation) {
1013 u8 buf[1];
1014 if (!radius_msg_add_wfa(
1015 msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
1016 buf, 0)) {
1017 RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
1018 }
7bd8c76a
JM
1019 } else if (code == RADIUS_CODE_ACCESS_ACCEPT &&
1020 data->hs20_sim_provisioning_url &&
1021 radius_server_is_sim_method(sess) &&
1022 radius_server_hs20_missing_sim_pps(request)) {
1023 u8 *buf, *pos, hash[HS20_MOBILE_ID_HASH_LEN];
1024 size_t prefix_len, url_len;
1025
1026 RADIUS_DEBUG("Device needs HS 2.0 SIM provisioning");
1027
1028 if (os_get_random(hash, HS20_MOBILE_ID_HASH_LEN) < 0) {
1029 radius_msg_free(msg);
1030 return NULL;
1031 }
1032 RADIUS_DUMP("hotspot2dot0-mobile-identifier-hash",
1033 hash, HS20_MOBILE_ID_HASH_LEN);
1034
1035 if (radius_server_sim_provisioning_session(sess, hash) < 0) {
1036 radius_msg_free(msg);
1037 return NULL;
1038 }
1039
1040 prefix_len = os_strlen(data->hs20_sim_provisioning_url);
1041 url_len = prefix_len + 2 * HS20_MOBILE_ID_HASH_LEN;
1042 buf = os_malloc(1 + url_len + 1);
1043 if (!buf) {
1044 radius_msg_free(msg);
1045 return NULL;
1046 }
1047 pos = buf;
1048 *pos++ = data->subscr_remediation_method;
1049 os_memcpy(pos, data->hs20_sim_provisioning_url, prefix_len);
1050 pos += prefix_len;
1051 wpa_snprintf_hex((char *) pos, 2 * HS20_MOBILE_ID_HASH_LEN + 1,
1052 hash, HS20_MOBILE_ID_HASH_LEN);
1053 RADIUS_DEBUG("HS 2.0 subscription remediation URL: %s",
1054 (char *) &buf[1]);
1055 if (!radius_msg_add_wfa(
1056 msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
1057 buf, 1 + url_len)) {
1058 RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
1059 }
1060 os_free(buf);
8d2a9921 1061 }
45260380
JM
1062
1063 if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->t_c_filtering) {
1064 u8 buf[4] = { 0x01, 0x00, 0x00, 0x00 }; /* E=1 */
d4e39c51
JM
1065 const char *url = data->t_c_server_url, *pos;
1066 char *url2, *end2, *pos2;
1067 size_t url_len;
45260380
JM
1068
1069 if (!radius_msg_add_wfa(
1070 msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING,
1071 buf, sizeof(buf))) {
1072 RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering");
d4e39c51
JM
1073 radius_msg_free(msg);
1074 return NULL;
1075 }
1076
1077 if (!url) {
1078 RADIUS_DEBUG("No t_c_server_url configured");
1079 radius_msg_free(msg);
1080 return NULL;
1081 }
1082
1083 pos = os_strstr(url, "@1@");
1084 if (!pos) {
1085 RADIUS_DEBUG("No @1@ macro in t_c_server_url");
1086 radius_msg_free(msg);
1087 return NULL;
1088 }
1089
1090 url_len = os_strlen(url) + ETH_ALEN * 3 - 1 - 3;
5ca11965 1091 url2 = os_malloc(url_len + 1);
d4e39c51
JM
1092 if (!url2) {
1093 RADIUS_DEBUG("Failed to allocate room for T&C Server URL");
1094 os_free(url2);
1095 radius_msg_free(msg);
1096 return NULL;
45260380 1097 }
d4e39c51 1098 pos2 = url2;
5ca11965 1099 end2 = url2 + url_len + 1;
d4e39c51
JM
1100 os_memcpy(pos2, url, pos - url);
1101 pos2 += pos - url;
1102 os_snprintf(pos2, end2 - pos2, MACSTR, MAC2STR(sess->mac_addr));
1103 pos2 += ETH_ALEN * 3 - 1;
1104 os_memcpy(pos2, pos + 3, os_strlen(pos + 3));
1105 if (!radius_msg_add_wfa(msg,
1106 RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL,
1107 (const u8 *) url2, url_len)) {
1108 RADIUS_DEBUG("Failed to add WFA-HS20-T-C-URL");
1109 os_free(url2);
1110 radius_msg_free(msg);
1111 return NULL;
1112 }
1113 os_free(url2);
1114
04ee197f 1115 radius_srv_hs20_t_c_pending(sess);
45260380 1116 }
8d2a9921
JM
1117#endif /* CONFIG_HS20 */
1118
6fc6879b
JM
1119 if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
1120 RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
1121 radius_msg_free(msg);
6fc6879b
JM
1122 return NULL;
1123 }
1124
d0ee16ed
JM
1125 if (code == RADIUS_CODE_ACCESS_ACCEPT) {
1126 struct hostapd_radius_attr *attr;
1127 for (attr = sess->accept_attr; attr; attr = attr->next) {
1128 if (!radius_msg_add_attr(msg, attr->type,
1129 wpabuf_head(attr->val),
1130 wpabuf_len(attr->val))) {
1131 wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
1132 radius_msg_free(msg);
1133 return NULL;
1134 }
1135 }
1136 }
1137
f75ed556
JM
1138 if (code == RADIUS_CODE_ACCESS_REJECT) {
1139 if (radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
1140 reason) < 0) {
1141 RADIUS_DEBUG("Failed to add WLAN-Reason-Code attribute");
1142 radius_msg_free(msg);
1143 return NULL;
1144 }
1145 }
1146
6fc6879b
JM
1147 if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
1148 client->shared_secret_len,
1489e11a 1149 hdr->authenticator) < 0) {
6fc6879b
JM
1150 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
1151 }
1152
2122fc83
JM
1153 if (code == RADIUS_CODE_ACCESS_ACCEPT)
1154 radius_server_add_session(sess);
1155
6fc6879b
JM
1156 return msg;
1157}
1158
1159
8943cc99
JM
1160static struct radius_msg *
1161radius_server_macacl(struct radius_server_data *data,
1162 struct radius_client *client,
1163 struct radius_session *sess,
1164 struct radius_msg *request)
1165{
1166 struct radius_msg *msg;
1167 int code;
1168 struct radius_hdr *hdr = radius_msg_get_hdr(request);
1169 u8 *pw;
1170 size_t pw_len;
1171
1172 code = RADIUS_CODE_ACCESS_ACCEPT;
1173
1174 if (radius_msg_get_attr_ptr(request, RADIUS_ATTR_USER_PASSWORD, &pw,
1175 &pw_len, NULL) < 0) {
1176 RADIUS_DEBUG("Could not get User-Password");
1177 code = RADIUS_CODE_ACCESS_REJECT;
1178 } else {
1179 int res;
1180 struct eap_user tmp;
1181
1182 os_memset(&tmp, 0, sizeof(tmp));
1183 res = data->get_eap_user(data->conf_ctx, (u8 *) sess->username,
1184 os_strlen(sess->username), 0, &tmp);
1185 if (res || !tmp.macacl || tmp.password == NULL) {
1186 RADIUS_DEBUG("No MAC ACL user entry");
b7175b4d 1187 bin_clear_free(tmp.password, tmp.password_len);
8943cc99
JM
1188 code = RADIUS_CODE_ACCESS_REJECT;
1189 } else {
1190 u8 buf[128];
1191 res = radius_user_password_hide(
1192 request, tmp.password, tmp.password_len,
1193 (u8 *) client->shared_secret,
1194 client->shared_secret_len,
1195 buf, sizeof(buf));
b7175b4d 1196 bin_clear_free(tmp.password, tmp.password_len);
8943cc99
JM
1197
1198 if (res < 0 || pw_len != (size_t) res ||
c2371953 1199 os_memcmp_const(pw, buf, res) != 0) {
8943cc99
JM
1200 RADIUS_DEBUG("Incorrect User-Password");
1201 code = RADIUS_CODE_ACCESS_REJECT;
1202 }
1203 }
1204 }
1205
1206 msg = radius_msg_new(code, hdr->identifier);
1207 if (msg == NULL) {
1208 RADIUS_DEBUG("Failed to allocate reply message");
1209 return NULL;
1210 }
1211
1212 if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
1213 RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
1214 radius_msg_free(msg);
1215 return NULL;
1216 }
1217
1218 if (code == RADIUS_CODE_ACCESS_ACCEPT) {
1219 struct hostapd_radius_attr *attr;
1220 for (attr = sess->accept_attr; attr; attr = attr->next) {
1221 if (!radius_msg_add_attr(msg, attr->type,
1222 wpabuf_head(attr->val),
1223 wpabuf_len(attr->val))) {
1224 wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
1225 radius_msg_free(msg);
1226 return NULL;
1227 }
1228 }
1229 }
1230
1231 if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
1232 client->shared_secret_len,
1233 hdr->authenticator) < 0) {
1234 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
1235 }
1236
1237 return msg;
1238}
1239
1240
6fc6879b
JM
1241static int radius_server_reject(struct radius_server_data *data,
1242 struct radius_client *client,
1243 struct radius_msg *request,
1244 struct sockaddr *from, socklen_t fromlen,
1245 const char *from_addr, int from_port)
1246{
1247 struct radius_msg *msg;
1248 int ret = 0;
1249 struct eap_hdr eapfail;
1489e11a
JM
1250 struct wpabuf *buf;
1251 struct radius_hdr *hdr = radius_msg_get_hdr(request);
6fc6879b
JM
1252
1253 RADIUS_DEBUG("Reject invalid request from %s:%d",
1254 from_addr, from_port);
1255
1489e11a 1256 msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, hdr->identifier);
6fc6879b
JM
1257 if (msg == NULL) {
1258 return -1;
1259 }
1260
1261 os_memset(&eapfail, 0, sizeof(eapfail));
1262 eapfail.code = EAP_CODE_FAILURE;
1263 eapfail.identifier = 0;
1264 eapfail.length = host_to_be16(sizeof(eapfail));
1265
1266 if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) {
1267 RADIUS_DEBUG("Failed to add EAP-Message attribute");
1268 }
1269
1270 if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
1271 RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
1272 radius_msg_free(msg);
6fc6879b
JM
1273 return -1;
1274 }
1275
1276 if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
1277 client->shared_secret_len,
1489e11a
JM
1278 hdr->authenticator) <
1279 0) {
6fc6879b
JM
1280 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
1281 }
1282
1283 if (wpa_debug_level <= MSG_MSGDUMP) {
1284 radius_msg_dump(msg);
1285 }
1286
1287 data->counters.access_rejects++;
1288 client->counters.access_rejects++;
1489e11a
JM
1289 buf = radius_msg_get_buf(msg);
1290 if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
6fc6879b 1291 (struct sockaddr *) from, sizeof(*from)) < 0) {
61323e70 1292 wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno));
6fc6879b
JM
1293 ret = -1;
1294 }
1295
1296 radius_msg_free(msg);
6fc6879b
JM
1297
1298 return ret;
1299}
1300
1301
45260380
JM
1302static void radius_server_hs20_t_c_check(struct radius_session *sess,
1303 struct radius_msg *msg)
1304{
1305#ifdef CONFIG_HS20
1306 u8 *buf, *pos, *end, type, sublen, *timestamp = NULL;
1307 size_t len;
1308
1309 buf = NULL;
1310 for (;;) {
1311 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1312 &buf, &len, buf) < 0)
1313 break;
1314 if (len < 6)
1315 continue;
1316 pos = buf;
1317 end = buf + len;
1318 if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
1319 continue;
1320 pos += 4;
1321
1322 type = *pos++;
1323 sublen = *pos++;
1324 if (sublen < 2)
1325 continue; /* invalid length */
1326 sublen -= 2; /* skip header */
1327 if (pos + sublen > end)
1328 continue; /* invalid WFA VSA */
1329
1330 if (type == RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP && len >= 4) {
1331 timestamp = pos;
1332 break;
1333 }
1334 }
1335
1336 if (!timestamp)
1337 return;
1338 RADIUS_DEBUG("HS20-Timestamp: %u", WPA_GET_BE32(timestamp));
1339 if (sess->t_c_timestamp != WPA_GET_BE32(timestamp)) {
1340 RADIUS_DEBUG("Last read T&C timestamp does not match HS20-Timestamp --> require filtering");
1341 sess->t_c_filtering = 1;
1342 }
1343#endif /* CONFIG_HS20 */
1344}
1345
1346
6fc6879b
JM
1347static int radius_server_request(struct radius_server_data *data,
1348 struct radius_msg *msg,
1349 struct sockaddr *from, socklen_t fromlen,
1350 struct radius_client *client,
1351 const char *from_addr, int from_port,
1352 struct radius_session *force_sess)
1353{
e100828b 1354 struct wpabuf *eap = NULL;
6fc6879b
JM
1355 int res, state_included = 0;
1356 u8 statebuf[4];
1357 unsigned int state;
1358 struct radius_session *sess;
1359 struct radius_msg *reply;
7598210b 1360 int is_complete = 0;
6fc6879b
JM
1361
1362 if (force_sess)
1363 sess = force_sess;
1364 else {
1365 res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
1366 sizeof(statebuf));
1367 state_included = res >= 0;
1368 if (res == sizeof(statebuf)) {
1369 state = WPA_GET_BE32(statebuf);
1370 sess = radius_server_get_session(client, state);
1371 } else {
1372 sess = NULL;
1373 }
1374 }
1375
1376 if (sess) {
1377 RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);
1378 } else if (state_included) {
1379 RADIUS_DEBUG("State attribute included but no session found");
1380 radius_server_reject(data, client, msg, from, fromlen,
1381 from_addr, from_port);
1382 return -1;
1383 } else {
8a57da7e
JM
1384 sess = radius_server_get_new_session(data, client, msg,
1385 from_addr);
6fc6879b
JM
1386 if (sess == NULL) {
1387 RADIUS_DEBUG("Could not create a new session");
1388 radius_server_reject(data, client, msg, from, fromlen,
1389 from_addr, from_port);
1390 return -1;
1391 }
1392 }
1393
1394 if (sess->last_from_port == from_port &&
1489e11a
JM
1395 sess->last_identifier == radius_msg_get_hdr(msg)->identifier &&
1396 os_memcmp(sess->last_authenticator,
1397 radius_msg_get_hdr(msg)->authenticator, 16) == 0) {
6fc6879b
JM
1398 RADIUS_DEBUG("Duplicate message from %s", from_addr);
1399 data->counters.dup_access_requests++;
1400 client->counters.dup_access_requests++;
1401
1402 if (sess->last_reply) {
1489e11a
JM
1403 struct wpabuf *buf;
1404 buf = radius_msg_get_buf(sess->last_reply);
1405 res = sendto(data->auth_sock, wpabuf_head(buf),
1406 wpabuf_len(buf), 0,
6fc6879b
JM
1407 (struct sockaddr *) from, fromlen);
1408 if (res < 0) {
61323e70
JM
1409 wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
1410 strerror(errno));
6fc6879b
JM
1411 }
1412 return 0;
1413 }
1414
1415 RADIUS_DEBUG("No previous reply available for duplicate "
1416 "message");
1417 return -1;
1418 }
95de34a1 1419
e100828b 1420 eap = radius_msg_get_eap(msg);
8943cc99
JM
1421 if (eap == NULL && sess->macacl) {
1422 reply = radius_server_macacl(data, client, sess, msg);
1423 if (reply == NULL)
1424 return -1;
1425 goto send_reply;
1426 }
6fc6879b
JM
1427 if (eap == NULL) {
1428 RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
1429 from_addr);
1430 data->counters.packets_dropped++;
1431 client->counters.packets_dropped++;
1432 return -1;
1433 }
1434
e100828b 1435 RADIUS_DUMP("Received EAP data", wpabuf_head(eap), wpabuf_len(eap));
6fc6879b
JM
1436
1437 /* FIX: if Code is Request, Success, or Failure, send Access-Reject;
1438 * RFC3579 Sect. 2.6.2.
1439 * Include EAP-Response/Nak with no preferred method if
1440 * code == request.
1441 * If code is not 1-4, discard the packet silently.
1442 * Or is this already done by the EAP state machine? */
1443
1444 wpabuf_free(sess->eap_if->eapRespData);
e100828b 1445 sess->eap_if->eapRespData = eap;
6fc6879b
JM
1446 sess->eap_if->eapResp = TRUE;
1447 eap_server_sm_step(sess->eap);
1448
1449 if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess ||
1450 sess->eap_if->eapFail) && sess->eap_if->eapReqData) {
1451 RADIUS_DUMP("EAP data from the state machine",
1452 wpabuf_head(sess->eap_if->eapReqData),
1453 wpabuf_len(sess->eap_if->eapReqData));
1454 } else if (sess->eap_if->eapFail) {
1455 RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
1456 "set");
1457 } else if (eap_sm_method_pending(sess->eap)) {
9e7245bd 1458 radius_msg_free(sess->last_msg);
6fc6879b
JM
1459 sess->last_msg = msg;
1460 sess->last_from_port = from_port;
1461 os_free(sess->last_from_addr);
1462 sess->last_from_addr = os_strdup(from_addr);
1463 sess->last_fromlen = fromlen;
1464 os_memcpy(&sess->last_from, from, fromlen);
1465 return -2;
1466 } else {
1467 RADIUS_DEBUG("No EAP data from the state machine - ignore this"
1468 " Access-Request silently (assuming it was a "
1469 "duplicate)");
1470 data->counters.packets_dropped++;
1471 client->counters.packets_dropped++;
1472 return -1;
1473 }
1474
7598210b
AB
1475 if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
1476 is_complete = 1;
ad4e4f60 1477 if (sess->eap_if->eapFail) {
8a57da7e 1478 srv_log(sess, "EAP authentication failed");
ad4e4f60
JM
1479 db_update_last_msk(sess, "FAIL");
1480 } else if (sess->eap_if->eapSuccess) {
8a57da7e 1481 srv_log(sess, "EAP authentication succeeded");
ad4e4f60 1482 }
7598210b 1483
45260380
JM
1484 if (sess->eap_if->eapSuccess)
1485 radius_server_hs20_t_c_check(sess, msg);
1486
6fc6879b
JM
1487 reply = radius_server_encapsulate_eap(data, client, sess, msg);
1488
8943cc99 1489send_reply:
6fc6879b 1490 if (reply) {
1489e11a
JM
1491 struct wpabuf *buf;
1492 struct radius_hdr *hdr;
1493
6fc6879b
JM
1494 RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);
1495 if (wpa_debug_level <= MSG_MSGDUMP) {
1496 radius_msg_dump(reply);
1497 }
1498
1489e11a 1499 switch (radius_msg_get_hdr(reply)->code) {
6fc6879b 1500 case RADIUS_CODE_ACCESS_ACCEPT:
8a57da7e 1501 srv_log(sess, "Sending Access-Accept");
6fc6879b
JM
1502 data->counters.access_accepts++;
1503 client->counters.access_accepts++;
1504 break;
1505 case RADIUS_CODE_ACCESS_REJECT:
8a57da7e 1506 srv_log(sess, "Sending Access-Reject");
6fc6879b
JM
1507 data->counters.access_rejects++;
1508 client->counters.access_rejects++;
1509 break;
1510 case RADIUS_CODE_ACCESS_CHALLENGE:
1511 data->counters.access_challenges++;
1512 client->counters.access_challenges++;
1513 break;
1514 }
1489e11a
JM
1515 buf = radius_msg_get_buf(reply);
1516 res = sendto(data->auth_sock, wpabuf_head(buf),
1517 wpabuf_len(buf), 0,
6fc6879b
JM
1518 (struct sockaddr *) from, fromlen);
1519 if (res < 0) {
61323e70
JM
1520 wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
1521 strerror(errno));
6fc6879b 1522 }
9e7245bd 1523 radius_msg_free(sess->last_reply);
6fc6879b
JM
1524 sess->last_reply = reply;
1525 sess->last_from_port = from_port;
1489e11a
JM
1526 hdr = radius_msg_get_hdr(msg);
1527 sess->last_identifier = hdr->identifier;
1528 os_memcpy(sess->last_authenticator, hdr->authenticator, 16);
6fc6879b
JM
1529 } else {
1530 data->counters.packets_dropped++;
1531 client->counters.packets_dropped++;
1532 }
1533
7598210b 1534 if (is_complete) {
6fc6879b
JM
1535 RADIUS_DEBUG("Removing completed session 0x%x after timeout",
1536 sess->sess_id);
1537 eloop_cancel_timeout(radius_server_session_remove_timeout,
1538 data, sess);
35677305 1539 eloop_register_timeout(RADIUS_SESSION_MAINTAIN, 0,
6fc6879b
JM
1540 radius_server_session_remove_timeout,
1541 data, sess);
1542 }
1543
1544 return 0;
1545}
1546
1547
abed6136
JM
1548static void
1549radius_server_receive_disconnect_resp(struct radius_server_data *data,
1550 struct radius_client *client,
1551 struct radius_msg *msg, int ack)
1552{
1553 struct radius_hdr *hdr;
1554
1555 if (!client->pending_dac_disconnect_req) {
1556 RADIUS_DEBUG("Ignore unexpected Disconnect response");
1557 radius_msg_free(msg);
1558 return;
1559 }
1560
1561 hdr = radius_msg_get_hdr(msg);
1562 if (hdr->identifier != client->pending_dac_disconnect_id) {
1563 RADIUS_DEBUG("Ignore unexpected Disconnect response with unexpected identifier %u (expected %u)",
1564 hdr->identifier,
1565 client->pending_dac_disconnect_id);
1566 radius_msg_free(msg);
1567 return;
1568 }
1569
1570 if (radius_msg_verify(msg, (const u8 *) client->shared_secret,
1571 client->shared_secret_len,
1572 client->pending_dac_disconnect_req, 0)) {
1573 RADIUS_DEBUG("Ignore Disconnect response with invalid authenticator");
1574 radius_msg_free(msg);
1575 return;
1576 }
1577
1578 RADIUS_DEBUG("Disconnect-%s received for " MACSTR,
1579 ack ? "ACK" : "NAK",
1580 MAC2STR(client->pending_dac_disconnect_addr));
1581
1582 radius_msg_free(msg);
1583 radius_msg_free(client->pending_dac_disconnect_req);
1584 client->pending_dac_disconnect_req = NULL;
1585}
1586
1587
1588static void radius_server_receive_coa_resp(struct radius_server_data *data,
1589 struct radius_client *client,
1590 struct radius_msg *msg, int ack)
1591{
1592 struct radius_hdr *hdr;
1593#ifdef CONFIG_SQLITE
1594 char addrtxt[3 * ETH_ALEN];
1595 char *sql;
1596 int res;
1597#endif /* CONFIG_SQLITE */
1598
1599 if (!client->pending_dac_coa_req) {
1600 RADIUS_DEBUG("Ignore unexpected CoA response");
1601 radius_msg_free(msg);
1602 return;
1603 }
1604
1605 hdr = radius_msg_get_hdr(msg);
1606 if (hdr->identifier != client->pending_dac_coa_id) {
1607 RADIUS_DEBUG("Ignore unexpected CoA response with unexpected identifier %u (expected %u)",
1608 hdr->identifier,
1609 client->pending_dac_coa_id);
1610 radius_msg_free(msg);
1611 return;
1612 }
1613
1614 if (radius_msg_verify(msg, (const u8 *) client->shared_secret,
1615 client->shared_secret_len,
1616 client->pending_dac_coa_req, 0)) {
1617 RADIUS_DEBUG("Ignore CoA response with invalid authenticator");
1618 radius_msg_free(msg);
1619 return;
1620 }
1621
1622 RADIUS_DEBUG("CoA-%s received for " MACSTR,
1623 ack ? "ACK" : "NAK",
1624 MAC2STR(client->pending_dac_coa_addr));
1625
1626 radius_msg_free(msg);
1627 radius_msg_free(client->pending_dac_coa_req);
1628 client->pending_dac_coa_req = NULL;
1629
1630#ifdef CONFIG_SQLITE
1631 if (!data->db)
1632 return;
1633
1634 os_snprintf(addrtxt, sizeof(addrtxt), MACSTR,
1635 MAC2STR(client->pending_dac_coa_addr));
1636
1637 if (ack) {
1638 sql = sqlite3_mprintf("UPDATE current_sessions SET hs20_t_c_filtering=0, waiting_coa_ack=0, coa_ack_received=1 WHERE mac_addr=%Q",
1639 addrtxt);
1640 } else {
1641 sql = sqlite3_mprintf("UPDATE current_sessions SET waiting_coa_ack=0 WHERE mac_addr=%Q",
1642 addrtxt);
1643 }
1644 if (!sql)
1645 return;
1646
1647 res = sqlite3_exec(data->db, sql, NULL, NULL, NULL);
1648 sqlite3_free(sql);
1649 if (res != SQLITE_OK) {
1650 RADIUS_ERROR("Failed to update current_sessions entry: %s",
1651 sqlite3_errmsg(data->db));
1652 return;
1653 }
1654#endif /* CONFIG_SQLITE */
1655}
1656
1657
6fc6879b
JM
1658static void radius_server_receive_auth(int sock, void *eloop_ctx,
1659 void *sock_ctx)
1660{
1661 struct radius_server_data *data = eloop_ctx;
1662 u8 *buf = NULL;
5a641ae0
JM
1663 union {
1664 struct sockaddr_storage ss;
1665 struct sockaddr_in sin;
1666#ifdef CONFIG_IPV6
1667 struct sockaddr_in6 sin6;
1668#endif /* CONFIG_IPV6 */
1669 } from;
6fc6879b
JM
1670 socklen_t fromlen;
1671 int len;
1672 struct radius_client *client = NULL;
1673 struct radius_msg *msg = NULL;
1674 char abuf[50];
1675 int from_port = 0;
1676
1677 buf = os_malloc(RADIUS_MAX_MSG_LEN);
1678 if (buf == NULL) {
1679 goto fail;
1680 }
1681
1682 fromlen = sizeof(from);
1683 len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
5a641ae0 1684 (struct sockaddr *) &from.ss, &fromlen);
6fc6879b 1685 if (len < 0) {
61323e70
JM
1686 wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
1687 strerror(errno));
6fc6879b
JM
1688 goto fail;
1689 }
1690
1691#ifdef CONFIG_IPV6
1692 if (data->ipv6) {
5a641ae0
JM
1693 if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
1694 sizeof(abuf)) == NULL)
6fc6879b 1695 abuf[0] = '\0';
5a641ae0 1696 from_port = ntohs(from.sin6.sin6_port);
6fc6879b
JM
1697 RADIUS_DEBUG("Received %d bytes from %s:%d",
1698 len, abuf, from_port);
1699
1700 client = radius_server_get_client(data,
1701 (struct in_addr *)
5a641ae0 1702 &from.sin6.sin6_addr, 1);
6fc6879b
JM
1703 }
1704#endif /* CONFIG_IPV6 */
1705
1706 if (!data->ipv6) {
5a641ae0
JM
1707 os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
1708 from_port = ntohs(from.sin.sin_port);
6fc6879b
JM
1709 RADIUS_DEBUG("Received %d bytes from %s:%d",
1710 len, abuf, from_port);
1711
5a641ae0 1712 client = radius_server_get_client(data, &from.sin.sin_addr, 0);
6fc6879b
JM
1713 }
1714
1715 RADIUS_DUMP("Received data", buf, len);
1716
1717 if (client == NULL) {
1718 RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
1719 data->counters.invalid_requests++;
1720 goto fail;
1721 }
1722
1723 msg = radius_msg_parse(buf, len);
1724 if (msg == NULL) {
1725 RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
1726 data->counters.malformed_access_requests++;
1727 client->counters.malformed_access_requests++;
1728 goto fail;
1729 }
1730
1731 os_free(buf);
1732 buf = NULL;
1733
1734 if (wpa_debug_level <= MSG_MSGDUMP) {
1735 radius_msg_dump(msg);
1736 }
1737
abed6136
JM
1738 if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_ACK) {
1739 radius_server_receive_disconnect_resp(data, client, msg, 1);
1740 return;
1741 }
1742
1743 if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_NAK) {
1744 radius_server_receive_disconnect_resp(data, client, msg, 0);
1745 return;
1746 }
1747
1748 if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_ACK) {
1749 radius_server_receive_coa_resp(data, client, msg, 1);
1750 return;
1751 }
1752
1753 if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_NAK) {
1754 radius_server_receive_coa_resp(data, client, msg, 0);
1755 return;
1756 }
1757
1489e11a
JM
1758 if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) {
1759 RADIUS_DEBUG("Unexpected RADIUS code %d",
1760 radius_msg_get_hdr(msg)->code);
6fc6879b
JM
1761 data->counters.unknown_types++;
1762 client->counters.unknown_types++;
1763 goto fail;
1764 }
1765
1766 data->counters.access_requests++;
1767 client->counters.access_requests++;
1768
1769 if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret,
1770 client->shared_secret_len, NULL)) {
1771 RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf);
1772 data->counters.bad_authenticators++;
1773 client->counters.bad_authenticators++;
1774 goto fail;
1775 }
1776
1777 if (radius_server_request(data, msg, (struct sockaddr *) &from,
1778 fromlen, client, abuf, from_port, NULL) ==
1779 -2)
1780 return; /* msg was stored with the session */
1781
1782fail:
9e7245bd 1783 radius_msg_free(msg);
6fc6879b
JM
1784 os_free(buf);
1785}
1786
1787
a1dd890a
JM
1788static void radius_server_receive_acct(int sock, void *eloop_ctx,
1789 void *sock_ctx)
1790{
1791 struct radius_server_data *data = eloop_ctx;
1792 u8 *buf = NULL;
1793 union {
1794 struct sockaddr_storage ss;
1795 struct sockaddr_in sin;
1796#ifdef CONFIG_IPV6
1797 struct sockaddr_in6 sin6;
1798#endif /* CONFIG_IPV6 */
1799 } from;
1800 socklen_t fromlen;
1801 int len, res;
1802 struct radius_client *client = NULL;
1803 struct radius_msg *msg = NULL, *resp = NULL;
1804 char abuf[50];
1805 int from_port = 0;
1806 struct radius_hdr *hdr;
1807 struct wpabuf *rbuf;
1808
1809 buf = os_malloc(RADIUS_MAX_MSG_LEN);
1810 if (buf == NULL) {
1811 goto fail;
1812 }
1813
1814 fromlen = sizeof(from);
1815 len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
1816 (struct sockaddr *) &from.ss, &fromlen);
1817 if (len < 0) {
1818 wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
1819 strerror(errno));
1820 goto fail;
1821 }
1822
1823#ifdef CONFIG_IPV6
1824 if (data->ipv6) {
1825 if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
1826 sizeof(abuf)) == NULL)
1827 abuf[0] = '\0';
1828 from_port = ntohs(from.sin6.sin6_port);
1829 RADIUS_DEBUG("Received %d bytes from %s:%d",
1830 len, abuf, from_port);
1831
1832 client = radius_server_get_client(data,
1833 (struct in_addr *)
1834 &from.sin6.sin6_addr, 1);
1835 }
1836#endif /* CONFIG_IPV6 */
1837
1838 if (!data->ipv6) {
1839 os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
1840 from_port = ntohs(from.sin.sin_port);
1841 RADIUS_DEBUG("Received %d bytes from %s:%d",
1842 len, abuf, from_port);
1843
1844 client = radius_server_get_client(data, &from.sin.sin_addr, 0);
1845 }
1846
1847 RADIUS_DUMP("Received data", buf, len);
1848
1849 if (client == NULL) {
1850 RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
1851 data->counters.invalid_acct_requests++;
1852 goto fail;
1853 }
1854
1855 msg = radius_msg_parse(buf, len);
1856 if (msg == NULL) {
1857 RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
1858 data->counters.malformed_acct_requests++;
1859 client->counters.malformed_acct_requests++;
1860 goto fail;
1861 }
1862
1863 os_free(buf);
1864 buf = NULL;
1865
1866 if (wpa_debug_level <= MSG_MSGDUMP) {
1867 radius_msg_dump(msg);
1868 }
1869
1870 if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_REQUEST) {
1871 RADIUS_DEBUG("Unexpected RADIUS code %d",
1872 radius_msg_get_hdr(msg)->code);
1873 data->counters.unknown_acct_types++;
1874 client->counters.unknown_acct_types++;
1875 goto fail;
1876 }
1877
1878 data->counters.acct_requests++;
1879 client->counters.acct_requests++;
1880
1881 if (radius_msg_verify_acct_req(msg, (u8 *) client->shared_secret,
1882 client->shared_secret_len)) {
1883 RADIUS_DEBUG("Invalid Authenticator from %s", abuf);
1884 data->counters.acct_bad_authenticators++;
1885 client->counters.acct_bad_authenticators++;
1886 goto fail;
1887 }
1888
1889 /* TODO: Write accounting information to a file or database */
1890
1891 hdr = radius_msg_get_hdr(msg);
1892
1893 resp = radius_msg_new(RADIUS_CODE_ACCOUNTING_RESPONSE, hdr->identifier);
1894 if (resp == NULL)
1895 goto fail;
1896
1897 radius_msg_finish_acct_resp(resp, (u8 *) client->shared_secret,
1898 client->shared_secret_len,
1899 hdr->authenticator);
1900
1901 RADIUS_DEBUG("Reply to %s:%d", abuf, from_port);
1902 if (wpa_debug_level <= MSG_MSGDUMP) {
1903 radius_msg_dump(resp);
1904 }
1905 rbuf = radius_msg_get_buf(resp);
1906 data->counters.acct_responses++;
1907 client->counters.acct_responses++;
1908 res = sendto(data->acct_sock, wpabuf_head(rbuf), wpabuf_len(rbuf), 0,
1909 (struct sockaddr *) &from.ss, fromlen);
1910 if (res < 0) {
1911 wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
1912 strerror(errno));
1913 }
1914
1915fail:
1916 radius_msg_free(resp);
1917 radius_msg_free(msg);
1918 os_free(buf);
1919}
1920
1921
5cd89c26
JM
1922static int radius_server_disable_pmtu_discovery(int s)
1923{
1924 int r = -1;
1925#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1926 /* Turn off Path MTU discovery on IPv4/UDP sockets. */
1927 int action = IP_PMTUDISC_DONT;
1928 r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
1929 sizeof(action));
1930 if (r == -1)
1931 wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
1932 "%s", strerror(errno));
1933#endif
1934 return r;
1935}
1936
1937
6fc6879b
JM
1938static int radius_server_open_socket(int port)
1939{
1940 int s;
1941 struct sockaddr_in addr;
1942
1943 s = socket(PF_INET, SOCK_DGRAM, 0);
1944 if (s < 0) {
61323e70 1945 wpa_printf(MSG_INFO, "RADIUS: socket: %s", strerror(errno));
6fc6879b
JM
1946 return -1;
1947 }
1948
5cd89c26
JM
1949 radius_server_disable_pmtu_discovery(s);
1950
6fc6879b
JM
1951 os_memset(&addr, 0, sizeof(addr));
1952 addr.sin_family = AF_INET;
1953 addr.sin_port = htons(port);
1954 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
61323e70 1955 wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
6fc6879b
JM
1956 close(s);
1957 return -1;
1958 }
1959
1960 return s;
1961}
1962
1963
1964#ifdef CONFIG_IPV6
1965static int radius_server_open_socket6(int port)
1966{
1967 int s;
1968 struct sockaddr_in6 addr;
1969
1970 s = socket(PF_INET6, SOCK_DGRAM, 0);
1971 if (s < 0) {
61323e70
JM
1972 wpa_printf(MSG_INFO, "RADIUS: socket[IPv6]: %s",
1973 strerror(errno));
6fc6879b
JM
1974 return -1;
1975 }
1976
1977 os_memset(&addr, 0, sizeof(addr));
1978 addr.sin6_family = AF_INET6;
1979 os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
1980 addr.sin6_port = htons(port);
1981 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
61323e70 1982 wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
6fc6879b
JM
1983 close(s);
1984 return -1;
1985 }
1986
1987 return s;
1988}
1989#endif /* CONFIG_IPV6 */
1990
1991
1992static void radius_server_free_sessions(struct radius_server_data *data,
1993 struct radius_session *sessions)
1994{
1995 struct radius_session *session, *prev;
1996
1997 session = sessions;
1998 while (session) {
1999 prev = session;
2000 session = session->next;
2001 radius_server_session_free(data, prev);
2002 }
2003}
2004
2005
2006static void radius_server_free_clients(struct radius_server_data *data,
2007 struct radius_client *clients)
2008{
2009 struct radius_client *client, *prev;
2010
2011 client = clients;
2012 while (client) {
2013 prev = client;
2014 client = client->next;
2015
2016 radius_server_free_sessions(data, prev->sessions);
2017 os_free(prev->shared_secret);
abed6136
JM
2018 radius_msg_free(prev->pending_dac_coa_req);
2019 radius_msg_free(prev->pending_dac_disconnect_req);
6fc6879b
JM
2020 os_free(prev);
2021 }
2022}
2023
2024
2025static struct radius_client *
2026radius_server_read_clients(const char *client_file, int ipv6)
2027{
2028 FILE *f;
2029 const int buf_size = 1024;
2030 char *buf, *pos;
2031 struct radius_client *clients, *tail, *entry;
2032 int line = 0, mask, failed = 0, i;
2033 struct in_addr addr;
2034#ifdef CONFIG_IPV6
2035 struct in6_addr addr6;
2036#endif /* CONFIG_IPV6 */
2037 unsigned int val;
2038
2039 f = fopen(client_file, "r");
2040 if (f == NULL) {
2041 RADIUS_ERROR("Could not open client file '%s'", client_file);
2042 return NULL;
2043 }
2044
2045 buf = os_malloc(buf_size);
2046 if (buf == NULL) {
2047 fclose(f);
2048 return NULL;
2049 }
2050
2051 clients = tail = NULL;
2052 while (fgets(buf, buf_size, f)) {
2053 /* Configuration file format:
2054 * 192.168.1.0/24 secret
2055 * 192.168.1.2 secret
2056 * fe80::211:22ff:fe33:4455/64 secretipv6
2057 */
2058 line++;
2059 buf[buf_size - 1] = '\0';
2060 pos = buf;
2061 while (*pos != '\0' && *pos != '\n')
2062 pos++;
2063 if (*pos == '\n')
2064 *pos = '\0';
2065 if (*buf == '\0' || *buf == '#')
2066 continue;
2067
2068 pos = buf;
2069 while ((*pos >= '0' && *pos <= '9') || *pos == '.' ||
2070 (*pos >= 'a' && *pos <= 'f') || *pos == ':' ||
2071 (*pos >= 'A' && *pos <= 'F')) {
2072 pos++;
2073 }
2074
2075 if (*pos == '\0') {
2076 failed = 1;
2077 break;
2078 }
2079
2080 if (*pos == '/') {
2081 char *end;
2082 *pos++ = '\0';
2083 mask = strtol(pos, &end, 10);
2084 if ((pos == end) ||
2085 (mask < 0 || mask > (ipv6 ? 128 : 32))) {
2086 failed = 1;
2087 break;
2088 }
2089 pos = end;
2090 } else {
2091 mask = ipv6 ? 128 : 32;
2092 *pos++ = '\0';
2093 }
2094
2095 if (!ipv6 && inet_aton(buf, &addr) == 0) {
2096 failed = 1;
2097 break;
2098 }
2099#ifdef CONFIG_IPV6
2100 if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) {
2101 if (inet_pton(AF_INET, buf, &addr) <= 0) {
2102 failed = 1;
2103 break;
2104 }
2105 /* Convert IPv4 address to IPv6 */
2106 if (mask <= 32)
2107 mask += (128 - 32);
2108 os_memset(addr6.s6_addr, 0, 10);
2109 addr6.s6_addr[10] = 0xff;
2110 addr6.s6_addr[11] = 0xff;
2111 os_memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr,
2112 4);
2113 }
2114#endif /* CONFIG_IPV6 */
2115
2116 while (*pos == ' ' || *pos == '\t') {
2117 pos++;
2118 }
2119
2120 if (*pos == '\0') {
2121 failed = 1;
2122 break;
2123 }
2124
2125 entry = os_zalloc(sizeof(*entry));
2126 if (entry == NULL) {
2127 failed = 1;
2128 break;
2129 }
2130 entry->shared_secret = os_strdup(pos);
2131 if (entry->shared_secret == NULL) {
2132 failed = 1;
2133 os_free(entry);
2134 break;
2135 }
2136 entry->shared_secret_len = os_strlen(entry->shared_secret);
6fc6879b 2137 if (!ipv6) {
77381639 2138 entry->addr.s_addr = addr.s_addr;
6fc6879b
JM
2139 val = 0;
2140 for (i = 0; i < mask; i++)
429ed54a 2141 val |= 1U << (31 - i);
6fc6879b
JM
2142 entry->mask.s_addr = htonl(val);
2143 }
2144#ifdef CONFIG_IPV6
2145 if (ipv6) {
2146 int offset = mask / 8;
2147
2148 os_memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16);
2149 os_memset(entry->mask6.s6_addr, 0xff, offset);
2150 val = 0;
2151 for (i = 0; i < (mask % 8); i++)
2152 val |= 1 << (7 - i);
2153 if (offset < 16)
2154 entry->mask6.s6_addr[offset] = val;
2155 }
2156#endif /* CONFIG_IPV6 */
2157
2158 if (tail == NULL) {
2159 clients = tail = entry;
2160 } else {
2161 tail->next = entry;
2162 tail = entry;
2163 }
2164 }
2165
2166 if (failed) {
2167 RADIUS_ERROR("Invalid line %d in '%s'", line, client_file);
2168 radius_server_free_clients(NULL, clients);
2169 clients = NULL;
2170 }
2171
2172 os_free(buf);
2173 fclose(f);
2174
2175 return clients;
2176}
2177
2178
362bd35f
JM
2179/**
2180 * radius_server_init - Initialize RADIUS server
2181 * @conf: Configuration for the RADIUS server
2182 * Returns: Pointer to private RADIUS server context or %NULL on failure
2183 *
2184 * This initializes a RADIUS server instance and returns a context pointer that
2185 * will be used in other calls to the RADIUS server module. The server can be
2186 * deinitialize by calling radius_server_deinit().
2187 */
6fc6879b
JM
2188struct radius_server_data *
2189radius_server_init(struct radius_server_conf *conf)
2190{
2191 struct radius_server_data *data;
822e7c66 2192 struct eap_config *eap_cfg;
6fc6879b
JM
2193
2194#ifndef CONFIG_IPV6
2195 if (conf->ipv6) {
61323e70 2196 wpa_printf(MSG_ERROR, "RADIUS server compiled without IPv6 support");
6fc6879b
JM
2197 return NULL;
2198 }
2199#endif /* CONFIG_IPV6 */
2200
2201 data = os_zalloc(sizeof(*data));
2202 if (data == NULL)
2203 return NULL;
2204
822e7c66
JM
2205 eap_cfg = data->eap_cfg = os_zalloc(sizeof(*eap_cfg));
2206 if (!eap_cfg) {
2207 os_free(data);
2208 return NULL;
2209 }
baf8ab8c
JM
2210 data->auth_sock = -1;
2211 data->acct_sock = -1;
d3bddd8b 2212 dl_list_init(&data->erp_keys);
58707176 2213 os_get_reltime(&data->start_time);
6fc6879b 2214 data->conf_ctx = conf->conf_ctx;
822e7c66
JM
2215 eap_cfg->backend_auth = TRUE;
2216 eap_cfg->eap_server = 1;
2217 eap_cfg->eap_sim_db_priv = conf->eap_sim_db_priv;
2218 eap_cfg->ssl_ctx = conf->ssl_ctx;
2219 eap_cfg->msg_ctx = conf->msg_ctx;
6fc6879b
JM
2220 data->ipv6 = conf->ipv6;
2221 if (conf->pac_opaque_encr_key) {
822e7c66
JM
2222 eap_cfg->pac_opaque_encr_key = os_malloc(16);
2223 if (eap_cfg->pac_opaque_encr_key) {
2224 os_memcpy(eap_cfg->pac_opaque_encr_key,
4457f41b
MJ
2225 conf->pac_opaque_encr_key, 16);
2226 }
6fc6879b 2227 }
2d867244 2228 if (conf->eap_fast_a_id) {
822e7c66
JM
2229 eap_cfg->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
2230 if (eap_cfg->eap_fast_a_id) {
2231 os_memcpy(eap_cfg->eap_fast_a_id, conf->eap_fast_a_id,
2d867244 2232 conf->eap_fast_a_id_len);
822e7c66 2233 eap_cfg->eap_fast_a_id_len = conf->eap_fast_a_id_len;
2d867244
JM
2234 }
2235 }
2236 if (conf->eap_fast_a_id_info)
822e7c66
JM
2237 eap_cfg->eap_fast_a_id_info =
2238 os_strdup(conf->eap_fast_a_id_info);
2239 eap_cfg->eap_fast_prov = conf->eap_fast_prov;
2240 eap_cfg->pac_key_lifetime = conf->pac_key_lifetime;
2241 eap_cfg->pac_key_refresh_time = conf->pac_key_refresh_time;
2242 eap_cfg->eap_teap_auth = conf->eap_teap_auth;
2243 eap_cfg->eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
2244 eap_cfg->eap_teap_separate_result = conf->eap_teap_separate_result;
e54cfbb5 2245 eap_cfg->eap_teap_id = conf->eap_teap_id;
6fc6879b 2246 data->get_eap_user = conf->get_eap_user;
822e7c66
JM
2247 eap_cfg->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
2248 eap_cfg->eap_sim_id = conf->eap_sim_id;
2249 eap_cfg->tnc = conf->tnc;
2250 eap_cfg->wps = conf->wps;
2251 eap_cfg->pwd_group = conf->pwd_group;
2252 if (conf->server_id) {
2253 eap_cfg->server_id = (u8 *) os_strdup(conf->server_id);
2254 eap_cfg->server_id_len = os_strlen(conf->server_id);
2255 }
65d50f0a
JM
2256 if (conf->eap_req_id_text) {
2257 data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
2258 if (data->eap_req_id_text) {
2259 os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
2260 conf->eap_req_id_text_len);
2261 data->eap_req_id_text_len = conf->eap_req_id_text_len;
2262 }
2263 }
822e7c66 2264 eap_cfg->erp = conf->erp;
d3bddd8b 2265 data->erp_domain = conf->erp_domain;
822e7c66
JM
2266 eap_cfg->tls_session_lifetime = conf->tls_session_lifetime;
2267 eap_cfg->tls_flags = conf->tls_flags;
6fc6879b 2268
8d2a9921
JM
2269 if (conf->subscr_remediation_url) {
2270 data->subscr_remediation_url =
2271 os_strdup(conf->subscr_remediation_url);
2272 }
f6fb1926 2273 data->subscr_remediation_method = conf->subscr_remediation_method;
7bd8c76a
JM
2274 if (conf->hs20_sim_provisioning_url)
2275 data->hs20_sim_provisioning_url =
2276 os_strdup(conf->hs20_sim_provisioning_url);
8d2a9921 2277
d4e39c51
JM
2278 if (conf->t_c_server_url)
2279 data->t_c_server_url = os_strdup(conf->t_c_server_url);
2280
8a57da7e
JM
2281#ifdef CONFIG_SQLITE
2282 if (conf->sqlite_file) {
2283 if (sqlite3_open(conf->sqlite_file, &data->db)) {
2284 RADIUS_ERROR("Could not open SQLite file '%s'",
2285 conf->sqlite_file);
2286 radius_server_deinit(data);
2287 return NULL;
2288 }
2289 }
2290#endif /* CONFIG_SQLITE */
2291
505a3694
JM
2292#ifdef CONFIG_RADIUS_TEST
2293 if (conf->dump_msk_file)
2294 data->dump_msk_file = os_strdup(conf->dump_msk_file);
2295#endif /* CONFIG_RADIUS_TEST */
2296
6fc6879b
JM
2297 data->clients = radius_server_read_clients(conf->client_file,
2298 conf->ipv6);
2299 if (data->clients == NULL) {
61323e70 2300 wpa_printf(MSG_ERROR, "No RADIUS clients configured");
6fc6879b
JM
2301 radius_server_deinit(data);
2302 return NULL;
2303 }
2304
2305#ifdef CONFIG_IPV6
2306 if (conf->ipv6)
2307 data->auth_sock = radius_server_open_socket6(conf->auth_port);
2308 else
2309#endif /* CONFIG_IPV6 */
2310 data->auth_sock = radius_server_open_socket(conf->auth_port);
2311 if (data->auth_sock < 0) {
61323e70 2312 wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server");
6fc6879b
JM
2313 radius_server_deinit(data);
2314 return NULL;
2315 }
2316 if (eloop_register_read_sock(data->auth_sock,
2317 radius_server_receive_auth,
2318 data, NULL)) {
2319 radius_server_deinit(data);
2320 return NULL;
2321 }
2322
a1dd890a
JM
2323 if (conf->acct_port) {
2324#ifdef CONFIG_IPV6
2325 if (conf->ipv6)
2326 data->acct_sock = radius_server_open_socket6(
2327 conf->acct_port);
2328 else
2329#endif /* CONFIG_IPV6 */
2330 data->acct_sock = radius_server_open_socket(conf->acct_port);
2331 if (data->acct_sock < 0) {
2332 wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server");
2333 radius_server_deinit(data);
2334 return NULL;
2335 }
2336 if (eloop_register_read_sock(data->acct_sock,
2337 radius_server_receive_acct,
2338 data, NULL)) {
2339 radius_server_deinit(data);
2340 return NULL;
2341 }
2342 } else {
2343 data->acct_sock = -1;
2344 }
2345
6fc6879b
JM
2346 return data;
2347}
2348
2349
362bd35f 2350/**
2c6411ed 2351 * radius_server_erp_flush - Flush all ERP keys
362bd35f
JM
2352 * @data: RADIUS server context from radius_server_init()
2353 */
2c6411ed 2354void radius_server_erp_flush(struct radius_server_data *data)
6fc6879b 2355{
d3bddd8b
JM
2356 struct eap_server_erp_key *erp;
2357
2c6411ed
JM
2358 if (data == NULL)
2359 return;
2360 while ((erp = dl_list_first(&data->erp_keys, struct eap_server_erp_key,
2361 list)) != NULL) {
2362 dl_list_del(&erp->list);
2363 bin_clear_free(erp, sizeof(*erp));
2364 }
2365}
2366
2367
2368/**
2369 * radius_server_deinit - Deinitialize RADIUS server
2370 * @data: RADIUS server context from radius_server_init()
2371 */
2372void radius_server_deinit(struct radius_server_data *data)
2373{
6fc6879b
JM
2374 if (data == NULL)
2375 return;
2376
2377 if (data->auth_sock >= 0) {
2378 eloop_unregister_read_sock(data->auth_sock);
2379 close(data->auth_sock);
2380 }
2381
a1dd890a
JM
2382 if (data->acct_sock >= 0) {
2383 eloop_unregister_read_sock(data->acct_sock);
2384 close(data->acct_sock);
2385 }
2386
6fc6879b
JM
2387 radius_server_free_clients(data, data->clients);
2388
65d50f0a 2389 os_free(data->eap_req_id_text);
505a3694
JM
2390#ifdef CONFIG_RADIUS_TEST
2391 os_free(data->dump_msk_file);
2392#endif /* CONFIG_RADIUS_TEST */
8d2a9921 2393 os_free(data->subscr_remediation_url);
7bd8c76a 2394 os_free(data->hs20_sim_provisioning_url);
d4e39c51 2395 os_free(data->t_c_server_url);
8a57da7e
JM
2396
2397#ifdef CONFIG_SQLITE
2398 if (data->db)
2399 sqlite3_close(data->db);
2400#endif /* CONFIG_SQLITE */
2401
2c6411ed 2402 radius_server_erp_flush(data);
822e7c66 2403 eap_server_config_free(data->eap_cfg);
d3bddd8b 2404
6fc6879b
JM
2405 os_free(data);
2406}
2407
2408
362bd35f
JM
2409/**
2410 * radius_server_get_mib - Get RADIUS server MIB information
2411 * @data: RADIUS server context from radius_server_init()
2412 * @buf: Buffer for returning the MIB data in text format
2413 * @buflen: buf length in octets
2414 * Returns: Number of octets written into buf
2415 */
6fc6879b
JM
2416int radius_server_get_mib(struct radius_server_data *data, char *buf,
2417 size_t buflen)
2418{
2419 int ret, uptime;
2420 unsigned int idx;
2421 char *end, *pos;
58707176 2422 struct os_reltime now;
6fc6879b
JM
2423 struct radius_client *cli;
2424
2425 /* RFC 2619 - RADIUS Authentication Server MIB */
2426
2427 if (data == NULL || buflen == 0)
2428 return 0;
2429
2430 pos = buf;
2431 end = buf + buflen;
2432
58707176 2433 os_get_reltime(&now);
6fc6879b
JM
2434 uptime = (now.sec - data->start_time.sec) * 100 +
2435 ((now.usec - data->start_time.usec) / 10000) % 100;
2436 ret = os_snprintf(pos, end - pos,
2437 "RADIUS-AUTH-SERVER-MIB\n"
2438 "radiusAuthServIdent=hostapd\n"
2439 "radiusAuthServUpTime=%d\n"
2440 "radiusAuthServResetTime=0\n"
2441 "radiusAuthServConfigReset=4\n",
2442 uptime);
d85e1fc8 2443 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
2444 *pos = '\0';
2445 return pos - buf;
2446 }
2447 pos += ret;
2448
2449 ret = os_snprintf(pos, end - pos,
2450 "radiusAuthServTotalAccessRequests=%u\n"
2451 "radiusAuthServTotalInvalidRequests=%u\n"
2452 "radiusAuthServTotalDupAccessRequests=%u\n"
2453 "radiusAuthServTotalAccessAccepts=%u\n"
2454 "radiusAuthServTotalAccessRejects=%u\n"
2455 "radiusAuthServTotalAccessChallenges=%u\n"
2456 "radiusAuthServTotalMalformedAccessRequests=%u\n"
2457 "radiusAuthServTotalBadAuthenticators=%u\n"
2458 "radiusAuthServTotalPacketsDropped=%u\n"
a1dd890a
JM
2459 "radiusAuthServTotalUnknownTypes=%u\n"
2460 "radiusAccServTotalRequests=%u\n"
2461 "radiusAccServTotalInvalidRequests=%u\n"
2462 "radiusAccServTotalResponses=%u\n"
2463 "radiusAccServTotalMalformedRequests=%u\n"
2464 "radiusAccServTotalBadAuthenticators=%u\n"
2465 "radiusAccServTotalUnknownTypes=%u\n",
6fc6879b
JM
2466 data->counters.access_requests,
2467 data->counters.invalid_requests,
2468 data->counters.dup_access_requests,
2469 data->counters.access_accepts,
2470 data->counters.access_rejects,
2471 data->counters.access_challenges,
2472 data->counters.malformed_access_requests,
2473 data->counters.bad_authenticators,
2474 data->counters.packets_dropped,
a1dd890a
JM
2475 data->counters.unknown_types,
2476 data->counters.acct_requests,
2477 data->counters.invalid_acct_requests,
2478 data->counters.acct_responses,
2479 data->counters.malformed_acct_requests,
2480 data->counters.acct_bad_authenticators,
2481 data->counters.unknown_acct_types);
d85e1fc8 2482 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
2483 *pos = '\0';
2484 return pos - buf;
2485 }
2486 pos += ret;
2487
2488 for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) {
2489 char abuf[50], mbuf[50];
2490#ifdef CONFIG_IPV6
2491 if (data->ipv6) {
2492 if (inet_ntop(AF_INET6, &cli->addr6, abuf,
2493 sizeof(abuf)) == NULL)
2494 abuf[0] = '\0';
c9cd78e5 2495 if (inet_ntop(AF_INET6, &cli->mask6, mbuf,
6fc6879b
JM
2496 sizeof(mbuf)) == NULL)
2497 mbuf[0] = '\0';
2498 }
2499#endif /* CONFIG_IPV6 */
2500 if (!data->ipv6) {
2501 os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf));
2502 os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf));
2503 }
2504
2505 ret = os_snprintf(pos, end - pos,
2506 "radiusAuthClientIndex=%u\n"
2507 "radiusAuthClientAddress=%s/%s\n"
2508 "radiusAuthServAccessRequests=%u\n"
2509 "radiusAuthServDupAccessRequests=%u\n"
2510 "radiusAuthServAccessAccepts=%u\n"
2511 "radiusAuthServAccessRejects=%u\n"
2512 "radiusAuthServAccessChallenges=%u\n"
2513 "radiusAuthServMalformedAccessRequests=%u\n"
2514 "radiusAuthServBadAuthenticators=%u\n"
2515 "radiusAuthServPacketsDropped=%u\n"
a1dd890a
JM
2516 "radiusAuthServUnknownTypes=%u\n"
2517 "radiusAccServTotalRequests=%u\n"
2518 "radiusAccServTotalInvalidRequests=%u\n"
2519 "radiusAccServTotalResponses=%u\n"
2520 "radiusAccServTotalMalformedRequests=%u\n"
2521 "radiusAccServTotalBadAuthenticators=%u\n"
2522 "radiusAccServTotalUnknownTypes=%u\n",
6fc6879b
JM
2523 idx,
2524 abuf, mbuf,
2525 cli->counters.access_requests,
2526 cli->counters.dup_access_requests,
2527 cli->counters.access_accepts,
2528 cli->counters.access_rejects,
2529 cli->counters.access_challenges,
2530 cli->counters.malformed_access_requests,
2531 cli->counters.bad_authenticators,
2532 cli->counters.packets_dropped,
a1dd890a
JM
2533 cli->counters.unknown_types,
2534 cli->counters.acct_requests,
2535 cli->counters.invalid_acct_requests,
2536 cli->counters.acct_responses,
2537 cli->counters.malformed_acct_requests,
2538 cli->counters.acct_bad_authenticators,
2539 cli->counters.unknown_acct_types);
d85e1fc8 2540 if (os_snprintf_error(end - pos, ret)) {
6fc6879b
JM
2541 *pos = '\0';
2542 return pos - buf;
2543 }
2544 pos += ret;
2545 }
2546
2547 return pos - buf;
2548}
2549
2550
2551static int radius_server_get_eap_user(void *ctx, const u8 *identity,
2552 size_t identity_len, int phase2,
2553 struct eap_user *user)
2554{
2555 struct radius_session *sess = ctx;
2556 struct radius_server_data *data = sess->server;
8d2a9921 2557 int ret;
6fc6879b 2558
8d2a9921
JM
2559 ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
2560 phase2, user);
d0ee16ed
JM
2561 if (ret == 0 && user) {
2562 sess->accept_attr = user->accept_attr;
8d2a9921 2563 sess->remediation = user->remediation;
8943cc99 2564 sess->macacl = user->macacl;
45260380 2565 sess->t_c_timestamp = user->t_c_timestamp;
d0ee16ed 2566 }
fc48d33b
BG
2567
2568 if (ret) {
2569 RADIUS_DEBUG("%s: User-Name not found from user database",
2570 __func__);
2571 }
2572
8d2a9921 2573 return ret;
6fc6879b
JM
2574}
2575
2576
65d50f0a
JM
2577static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len)
2578{
2579 struct radius_session *sess = ctx;
2580 struct radius_server_data *data = sess->server;
2581 *len = data->eap_req_id_text_len;
2582 return data->eap_req_id_text;
2583}
2584
2585
01f7fe10
JM
2586static void radius_server_log_msg(void *ctx, const char *msg)
2587{
2588 struct radius_session *sess = ctx;
2589 srv_log(sess, "EAP: %s", msg);
2590}
2591
2592
d3bddd8b
JM
2593#ifdef CONFIG_ERP
2594
2595static const char * radius_server_get_erp_domain(void *ctx)
2596{
2597 struct radius_session *sess = ctx;
2598 struct radius_server_data *data = sess->server;
2599
2600 return data->erp_domain;
2601}
2602
2603
2604static struct eap_server_erp_key *
2605radius_server_erp_get_key(void *ctx, const char *keyname)
2606{
2607 struct radius_session *sess = ctx;
2608 struct radius_server_data *data = sess->server;
d3bddd8b 2609
3580ed82 2610 return radius_server_erp_find_key(data, keyname);
d3bddd8b
JM
2611}
2612
2613
2614static int radius_server_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
2615{
2616 struct radius_session *sess = ctx;
2617 struct radius_server_data *data = sess->server;
2618
2619 dl_list_add(&data->erp_keys, &erp->list);
2620 return 0;
2621}
2622
2623#endif /* CONFIG_ERP */
2624
2625
8b423edb 2626static const struct eapol_callbacks radius_server_eapol_cb =
6fc6879b
JM
2627{
2628 .get_eap_user = radius_server_get_eap_user,
65d50f0a 2629 .get_eap_req_id_text = radius_server_get_eap_req_id_text,
01f7fe10 2630 .log_msg = radius_server_log_msg,
d3bddd8b
JM
2631#ifdef CONFIG_ERP
2632 .get_erp_send_reauth_start = NULL,
2633 .get_erp_domain = radius_server_get_erp_domain,
2634 .erp_get_key = radius_server_erp_get_key,
2635 .erp_add_key = radius_server_erp_add_key,
2636#endif /* CONFIG_ERP */
6fc6879b
JM
2637};
2638
2639
362bd35f
JM
2640/**
2641 * radius_server_eap_pending_cb - Pending EAP data notification
2642 * @data: RADIUS server context from radius_server_init()
2643 * @ctx: Pending EAP context pointer
2644 *
2645 * This function is used to notify EAP server module that a pending operation
2646 * has been completed and processing of the EAP session can proceed.
2647 */
6fc6879b
JM
2648void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
2649{
2650 struct radius_client *cli;
2651 struct radius_session *s, *sess = NULL;
2652 struct radius_msg *msg;
2653
2654 if (data == NULL)
2655 return;
2656
2657 for (cli = data->clients; cli; cli = cli->next) {
2658 for (s = cli->sessions; s; s = s->next) {
2659 if (s->eap == ctx && s->last_msg) {
2660 sess = s;
2661 break;
2662 }
6fc6879b
JM
2663 }
2664 if (sess)
2665 break;
2666 }
2667
2668 if (sess == NULL) {
2669 RADIUS_DEBUG("No session matched callback ctx");
2670 return;
2671 }
2672
2673 msg = sess->last_msg;
2674 sess->last_msg = NULL;
2675 eap_sm_pending_cb(sess->eap);
2676 if (radius_server_request(data, msg,
2677 (struct sockaddr *) &sess->last_from,
2678 sess->last_fromlen, cli,
2679 sess->last_from_addr,
2680 sess->last_from_port, sess) == -2)
2681 return; /* msg was stored with the session */
2682
2683 radius_msg_free(msg);
6fc6879b 2684}
abed6136
JM
2685
2686
2687#ifdef CONFIG_SQLITE
2688
2689struct db_session_fields {
2690 char *identity;
2691 char *nas;
2692 int hs20_t_c_filtering;
2693 int waiting_coa_ack;
2694 int coa_ack_received;
2695};
2696
2697
2698static int get_db_session_fields(void *ctx, int argc, char *argv[], char *col[])
2699{
2700 struct db_session_fields *fields = ctx;
2701 int i;
2702
2703 for (i = 0; i < argc; i++) {
2704 if (!argv[i])
2705 continue;
2706
2707 RADIUS_DEBUG("Session DB: %s=%s", col[i], argv[i]);
2708
2709 if (os_strcmp(col[i], "identity") == 0) {
2710 os_free(fields->identity);
2711 fields->identity = os_strdup(argv[i]);
2712 } else if (os_strcmp(col[i], "nas") == 0) {
2713 os_free(fields->nas);
2714 fields->nas = os_strdup(argv[i]);
2715 } else if (os_strcmp(col[i], "hs20_t_c_filtering") == 0) {
2716 fields->hs20_t_c_filtering = atoi(argv[i]);
2717 } else if (os_strcmp(col[i], "waiting_coa_ack") == 0) {
2718 fields->waiting_coa_ack = atoi(argv[i]);
2719 } else if (os_strcmp(col[i], "coa_ack_received") == 0) {
2720 fields->coa_ack_received = atoi(argv[i]);
2721 }
2722 }
2723
2724 return 0;
2725}
2726
2727
2728static void free_db_session_fields(struct db_session_fields *fields)
2729{
2730 os_free(fields->identity);
2731 fields->identity = NULL;
2732 os_free(fields->nas);
2733 fields->nas = NULL;
2734}
2735
2736#endif /* CONFIG_SQLITE */
2737
2738
2739int radius_server_dac_request(struct radius_server_data *data, const char *req)
2740{
2741#ifdef CONFIG_SQLITE
2742 char *sql;
2743 int res;
2744 int disconnect;
2745 const char *pos = req;
2746 u8 addr[ETH_ALEN];
2747 char addrtxt[3 * ETH_ALEN];
2748 int t_c_clear = 0;
2749 struct db_session_fields fields;
2750 struct sockaddr_in das;
2751 struct radius_client *client;
2752 struct radius_msg *msg;
2753 struct wpabuf *buf;
2754 u8 identifier;
2755 struct os_time now;
2756
2757 if (!data)
2758 return -1;
2759
2760 /* req: <disconnect|coa> <MAC Address> [t_c_clear] */
2761
2762 if (os_strncmp(pos, "disconnect ", 11) == 0) {
2763 disconnect = 1;
2764 pos += 11;
2765 } else if (os_strncmp(req, "coa ", 4) == 0) {
2766 disconnect = 0;
2767 pos += 4;
2768 } else {
2769 return -1;
2770 }
2771
2772 if (hwaddr_aton(pos, addr))
2773 return -1;
2774 pos = os_strchr(pos, ' ');
2775 if (pos) {
2776 if (os_strstr(pos, "t_c_clear"))
2777 t_c_clear = 1;
2778 }
2779
2780 if (!disconnect && !t_c_clear) {
2781 RADIUS_ERROR("DAC request for CoA without any authorization change");
2782 return -1;
2783 }
2784
2785 if (!data->db) {
2786 RADIUS_ERROR("SQLite database not in use");
2787 return -1;
2788 }
2789
2790 os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(addr));
2791
2792 sql = sqlite3_mprintf("SELECT * FROM current_sessions WHERE mac_addr=%Q",
2793 addrtxt);
2794 if (!sql)
2795 return -1;
2796
2797 os_memset(&fields, 0, sizeof(fields));
2798 res = sqlite3_exec(data->db, sql, get_db_session_fields, &fields, NULL);
2799 sqlite3_free(sql);
2800 if (res != SQLITE_OK) {
2801 RADIUS_ERROR("Failed to find matching current_sessions entry from sqlite database: %s",
2802 sqlite3_errmsg(data->db));
2803 free_db_session_fields(&fields);
2804 return -1;
2805 }
2806
2807 if (!fields.nas) {
2808 RADIUS_ERROR("No NAS information found from current_sessions");
2809 free_db_session_fields(&fields);
2810 return -1;
2811 }
2812
2813 os_memset(&das, 0, sizeof(das));
2814 das.sin_family = AF_INET;
2815 das.sin_addr.s_addr = inet_addr(fields.nas);
2816 das.sin_port = htons(3799);
2817
2818 free_db_session_fields(&fields);
2819
2820 client = radius_server_get_client(data, &das.sin_addr, 0);
2821 if (!client) {
2822 RADIUS_ERROR("No NAS information available to protect the packet");
2823 return -1;
2824 }
2825
2826 identifier = client->next_dac_identifier++;
2827
2828 msg = radius_msg_new(disconnect ? RADIUS_CODE_DISCONNECT_REQUEST :
2829 RADIUS_CODE_COA_REQUEST, identifier);
2830 if (!msg)
2831 return -1;
2832
2833 os_snprintf(addrtxt, sizeof(addrtxt), RADIUS_802_1X_ADDR_FORMAT,
2834 MAC2STR(addr));
2835 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
2836 (u8 *) addrtxt, os_strlen(addrtxt))) {
2837 RADIUS_ERROR("Could not add Calling-Station-Id");
2838 radius_msg_free(msg);
2839 return -1;
2840 }
2841
2842 if (!disconnect && t_c_clear) {
2843 u8 val[4] = { 0x00, 0x00, 0x00, 0x00 }; /* E=0 */
2844
2845 if (!radius_msg_add_wfa(
2846 msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING,
2847 val, sizeof(val))) {
2848 RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering");
2849 radius_msg_free(msg);
2850 return -1;
2851 }
2852 }
2853
2854 os_get_time(&now);
2855 if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
2856 now.sec)) {
2857 RADIUS_ERROR("Failed to add Event-Timestamp attribute");
2858 radius_msg_free(msg);
2859 return -1;
2860 }
2861
2862 radius_msg_finish_acct(msg, (u8 *) client->shared_secret,
2863 client->shared_secret_len);
2864
2865 if (wpa_debug_level <= MSG_MSGDUMP)
2866 radius_msg_dump(msg);
2867
2868 buf = radius_msg_get_buf(msg);
2869 if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
2870 (struct sockaddr *) &das, sizeof(das)) < 0) {
2871 RADIUS_ERROR("Failed to send packet - sendto: %s",
2872 strerror(errno));
2873 radius_msg_free(msg);
2874 return -1;
2875 }
2876
2877 if (disconnect) {
2878 radius_msg_free(client->pending_dac_disconnect_req);
2879 client->pending_dac_disconnect_req = msg;
2880 client->pending_dac_disconnect_id = identifier;
2881 os_memcpy(client->pending_dac_disconnect_addr, addr, ETH_ALEN);
2882 } else {
2883 radius_msg_free(client->pending_dac_coa_req);
2884 client->pending_dac_coa_req = msg;
2885 client->pending_dac_coa_id = identifier;
2886 os_memcpy(client->pending_dac_coa_addr, addr, ETH_ALEN);
2887 }
2888
2889 return 0;
2890#else /* CONFIG_SQLITE */
2891 return -1;
2892#endif /* CONFIG_SQLITE */
2893}