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