blob: 1b605c7f085d47a1025720d497e3ff42382b440f [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * RADIUS authentication server
Hai Shalom021b0b52019-04-10 11:17:58 -07003 * Copyright (c) 2005-2009, 2011-2019, 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
Hai Shalom81f62d82019-07-22 12:10:00 -0700241 int eap_teap_auth;
242 int eap_teap_pac_no_inner;
243
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700244 /**
245 * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication
246 *
247 * This controls whether the protected success/failure indication
248 * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA.
249 */
250 int eap_sim_aka_result_ind;
251
252 /**
253 * tnc - Trusted Network Connect (TNC)
254 *
255 * This controls whether TNC is enabled and will be required before the
256 * peer is allowed to connect. Note: This is only used with EAP-TTLS
257 * and EAP-FAST. If any other EAP method is enabled, the peer will be
258 * allowed to connect without TNC.
259 */
260 int tnc;
261
262 /**
263 * pwd_group - The D-H group assigned for EAP-pwd
264 *
265 * If EAP-pwd is not used it can be set to zero.
266 */
267 u16 pwd_group;
268
269 /**
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700270 * server_id - Server identity
271 */
272 const char *server_id;
273
274 /**
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800275 * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
276 *
277 * This controls whether the authentication server derives ERP key
278 * hierarchy (rRK and rIK) from full EAP authentication and allows
279 * these keys to be used to perform ERP to derive rMSK instead of full
280 * EAP authentication to derive MSK.
281 */
282 int erp;
283
284 const char *erp_domain;
285
286 struct dl_list erp_keys; /* struct eap_server_erp_key */
287
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800288 unsigned int tls_session_lifetime;
289
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700290 unsigned int tls_flags;
291
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800292 /**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700293 * wps - Wi-Fi Protected Setup context
294 *
295 * If WPS is used with an external RADIUS server (which is quite
296 * unlikely configuration), this is used to provide a pointer to WPS
297 * context data. Normally, this can be set to %NULL.
298 */
299 struct wps_context *wps;
300
301 /**
302 * ipv6 - Whether to enable IPv6 support in the RADIUS server
303 */
304 int ipv6;
305
306 /**
307 * start_time - Timestamp of server start
308 */
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800309 struct os_reltime start_time;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700310
311 /**
312 * counters - Statistics counters for server operations
313 *
314 * These counters are the sum over all clients.
315 */
316 struct radius_server_counters counters;
317
318 /**
319 * get_eap_user - Callback for fetching EAP user information
320 * @ctx: Context data from conf_ctx
321 * @identity: User identity
322 * @identity_len: identity buffer length in octets
323 * @phase2: Whether this is for Phase 2 identity
324 * @user: Data structure for filling in the user information
325 * Returns: 0 on success, -1 on failure
326 *
327 * This is used to fetch information from user database. The callback
328 * will fill in information about allowed EAP methods and the user
329 * password. The password field will be an allocated copy of the
330 * password data and RADIUS server will free it after use.
331 */
332 int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
333 int phase2, struct eap_user *user);
334
335 /**
336 * eap_req_id_text - Optional data for EAP-Request/Identity
337 *
338 * This can be used to configure an optional, displayable message that
339 * will be sent in EAP-Request/Identity. This string can contain an
340 * ASCII-0 character (nul) to separate network infromation per RFC
341 * 4284. The actual string length is explicit provided in
342 * eap_req_id_text_len since nul character will not be used as a string
343 * terminator.
344 */
345 char *eap_req_id_text;
346
347 /**
348 * eap_req_id_text_len - Length of eap_req_id_text buffer in octets
349 */
350 size_t eap_req_id_text_len;
351
352 /*
353 * msg_ctx - Context data for wpa_msg() calls
354 */
355 void *msg_ctx;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800356
357#ifdef CONFIG_RADIUS_TEST
358 char *dump_msk_file;
359#endif /* CONFIG_RADIUS_TEST */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800360
361 char *subscr_remediation_url;
362 u8 subscr_remediation_method;
Hai Shalom74f70d42019-02-11 14:42:39 -0800363 char *hs20_sim_provisioning_url;
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700364
Roshan Pius3a1667e2018-07-03 15:17:14 -0700365 char *t_c_server_url;
366
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700367#ifdef CONFIG_SQLITE
368 sqlite3 *db;
369#endif /* CONFIG_SQLITE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700370};
371
372
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700373#define RADIUS_DEBUG(args...) \
374wpa_printf(MSG_DEBUG, "RADIUS SRV: " args)
375#define RADIUS_ERROR(args...) \
376wpa_printf(MSG_ERROR, "RADIUS SRV: " args)
377#define RADIUS_DUMP(args...) \
378wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args)
379#define RADIUS_DUMP_ASCII(args...) \
380wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args)
381
382
383static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
384static void radius_server_session_remove_timeout(void *eloop_ctx,
385 void *timeout_ctx);
386
Hai Shalom74f70d42019-02-11 14:42:39 -0800387#ifdef CONFIG_SQLITE
388#ifdef CONFIG_HS20
389
390static int db_table_exists(sqlite3 *db, const char *name)
391{
392 char cmd[128];
393
394 os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
395 return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
396}
397
398
399static int db_table_create_sim_provisioning(sqlite3 *db)
400{
401 char *err = NULL;
402 const char *sql =
403 "CREATE TABLE sim_provisioning("
404 " mobile_identifier_hash TEXT PRIMARY KEY,"
405 " imsi TEXT,"
406 " mac_addr TEXT,"
407 " eap_method TEXT,"
408 " timestamp TEXT"
409 ");";
410
411 RADIUS_DEBUG("Adding database table for SIM provisioning information");
412 if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
413 RADIUS_ERROR("SQLite error: %s", err);
414 sqlite3_free(err);
415 return -1;
416 }
417
418 return 0;
419}
420
421#endif /* CONFIG_HS20 */
422#endif /* CONFIG_SQLITE */
423
424
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700425void srv_log(struct radius_session *sess, const char *fmt, ...)
426PRINTF_FORMAT(2, 3);
427
428void srv_log(struct radius_session *sess, const char *fmt, ...)
429{
430 va_list ap;
431 char *buf;
432 int buflen;
433
434 va_start(ap, fmt);
435 buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
436 va_end(ap);
437
438 buf = os_malloc(buflen);
439 if (buf == NULL)
440 return;
441 va_start(ap, fmt);
442 vsnprintf(buf, buflen, fmt, ap);
443 va_end(ap);
444
445 RADIUS_DEBUG("[0x%x %s] %s", sess->sess_id, sess->nas_ip, buf);
446
447#ifdef CONFIG_SQLITE
448 if (sess->server->db) {
449 char *sql;
450 sql = sqlite3_mprintf("INSERT INTO authlog"
451 "(timestamp,session,nas_ip,username,note)"
452 " VALUES ("
453 "strftime('%%Y-%%m-%%d %%H:%%M:%%f',"
454 "'now'),%u,%Q,%Q,%Q)",
455 sess->sess_id, sess->nas_ip,
456 sess->username, buf);
457 if (sql) {
458 if (sqlite3_exec(sess->server->db, sql, NULL, NULL,
459 NULL) != SQLITE_OK) {
460 RADIUS_ERROR("Failed to add authlog entry into sqlite database: %s",
461 sqlite3_errmsg(sess->server->db));
462 }
463 sqlite3_free(sql);
464 }
465 }
466#endif /* CONFIG_SQLITE */
467
468 os_free(buf);
469}
470
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700471
472static struct radius_client *
473radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
474 int ipv6)
475{
476 struct radius_client *client = data->clients;
477
478 while (client) {
479#ifdef CONFIG_IPV6
480 if (ipv6) {
481 struct in6_addr *addr6;
482 int i;
483
484 addr6 = (struct in6_addr *) addr;
485 for (i = 0; i < 16; i++) {
486 if ((addr6->s6_addr[i] &
487 client->mask6.s6_addr[i]) !=
488 (client->addr6.s6_addr[i] &
489 client->mask6.s6_addr[i])) {
490 i = 17;
491 break;
492 }
493 }
494 if (i == 16) {
495 break;
496 }
497 }
498#endif /* CONFIG_IPV6 */
499 if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) ==
500 (addr->s_addr & client->mask.s_addr)) {
501 break;
502 }
503
504 client = client->next;
505 }
506
507 return client;
508}
509
510
511static struct radius_session *
512radius_server_get_session(struct radius_client *client, unsigned int sess_id)
513{
514 struct radius_session *sess = client->sessions;
515
516 while (sess) {
517 if (sess->sess_id == sess_id) {
518 break;
519 }
520 sess = sess->next;
521 }
522
523 return sess;
524}
525
526
527static void radius_server_session_free(struct radius_server_data *data,
528 struct radius_session *sess)
529{
530 eloop_cancel_timeout(radius_server_session_timeout, data, sess);
531 eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
532 eap_server_sm_deinit(sess->eap);
533 radius_msg_free(sess->last_msg);
534 os_free(sess->last_from_addr);
535 radius_msg_free(sess->last_reply);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700536 os_free(sess->username);
537 os_free(sess->nas_ip);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700538 os_free(sess);
539 data->num_sess--;
540}
541
542
543static void radius_server_session_remove(struct radius_server_data *data,
544 struct radius_session *sess)
545{
546 struct radius_client *client = sess->client;
547 struct radius_session *session, *prev;
548
549 eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
550
551 prev = NULL;
552 session = client->sessions;
553 while (session) {
554 if (session == sess) {
555 if (prev == NULL) {
556 client->sessions = sess->next;
557 } else {
558 prev->next = sess->next;
559 }
560 radius_server_session_free(data, sess);
561 break;
562 }
563 prev = session;
564 session = session->next;
565 }
566}
567
568
569static void radius_server_session_remove_timeout(void *eloop_ctx,
570 void *timeout_ctx)
571{
572 struct radius_server_data *data = eloop_ctx;
573 struct radius_session *sess = timeout_ctx;
574 RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);
575 radius_server_session_remove(data, sess);
576}
577
578
579static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx)
580{
581 struct radius_server_data *data = eloop_ctx;
582 struct radius_session *sess = timeout_ctx;
583
584 RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id);
585 radius_server_session_remove(data, sess);
586}
587
588
589static struct radius_session *
590radius_server_new_session(struct radius_server_data *data,
591 struct radius_client *client)
592{
593 struct radius_session *sess;
594
595 if (data->num_sess >= RADIUS_MAX_SESSION) {
596 RADIUS_DEBUG("Maximum number of existing session - no room "
597 "for a new session");
598 return NULL;
599 }
600
601 sess = os_zalloc(sizeof(*sess));
602 if (sess == NULL)
603 return NULL;
604
605 sess->server = data;
606 sess->client = client;
607 sess->sess_id = data->next_sess_id++;
608 sess->next = client->sessions;
609 client->sessions = sess;
610 eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0,
611 radius_server_session_timeout, data, sess);
612 data->num_sess++;
613 return sess;
614}
615
616
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700617#ifdef CONFIG_TESTING_OPTIONS
618static void radius_server_testing_options_tls(struct radius_session *sess,
619 const char *tls,
620 struct eap_config *eap_conf)
621{
622 int test = atoi(tls);
623
624 switch (test) {
625 case 1:
626 srv_log(sess, "TLS test - break VerifyData");
627 eap_conf->tls_test_flags = TLS_BREAK_VERIFY_DATA;
628 break;
629 case 2:
630 srv_log(sess, "TLS test - break ServerKeyExchange ServerParams hash");
631 eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_HASH;
632 break;
633 case 3:
634 srv_log(sess, "TLS test - break ServerKeyExchange ServerParams Signature");
635 eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_SIGNATURE;
636 break;
Dmitry Shmidtb36ed7c2014-03-17 10:57:26 -0700637 case 4:
638 srv_log(sess, "TLS test - RSA-DHE using a short 511-bit prime");
639 eap_conf->tls_test_flags = TLS_DHE_PRIME_511B;
640 break;
641 case 5:
642 srv_log(sess, "TLS test - RSA-DHE using a short 767-bit prime");
643 eap_conf->tls_test_flags = TLS_DHE_PRIME_767B;
644 break;
645 case 6:
646 srv_log(sess, "TLS test - RSA-DHE using a bogus 15 \"prime\"");
647 eap_conf->tls_test_flags = TLS_DHE_PRIME_15;
648 break;
649 case 7:
650 srv_log(sess, "TLS test - RSA-DHE using a short 58-bit prime in long container");
651 eap_conf->tls_test_flags = TLS_DHE_PRIME_58B;
652 break;
653 case 8:
654 srv_log(sess, "TLS test - RSA-DHE using a non-prime");
655 eap_conf->tls_test_flags = TLS_DHE_NON_PRIME;
656 break;
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700657 default:
658 srv_log(sess, "Unrecognized TLS test");
659 break;
660 }
661}
662#endif /* CONFIG_TESTING_OPTIONS */
663
664static void radius_server_testing_options(struct radius_session *sess,
665 struct eap_config *eap_conf)
666{
667#ifdef CONFIG_TESTING_OPTIONS
668 const char *pos;
669
670 pos = os_strstr(sess->username, "@test-");
671 if (pos == NULL)
672 return;
673 pos += 6;
674 if (os_strncmp(pos, "tls-", 4) == 0)
675 radius_server_testing_options_tls(sess, pos + 4, eap_conf);
676 else
677 srv_log(sess, "Unrecognized test: %s", pos);
678#endif /* CONFIG_TESTING_OPTIONS */
679}
680
681
Hai Shalom021b0b52019-04-10 11:17:58 -0700682#ifdef CONFIG_ERP
683static struct eap_server_erp_key *
684radius_server_erp_find_key(struct radius_server_data *data, const char *keyname)
685{
686 struct eap_server_erp_key *erp;
687
688 dl_list_for_each(erp, &data->erp_keys, struct eap_server_erp_key,
689 list) {
690 if (os_strcmp(erp->keyname_nai, keyname) == 0)
691 return erp;
692 }
693
694 return NULL;
695}
696#endif /* CONFIG_ERP */
697
698
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700699static struct radius_session *
700radius_server_get_new_session(struct radius_server_data *data,
701 struct radius_client *client,
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700702 struct radius_msg *msg, const char *from_addr)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700703{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700704 u8 *user, *id;
705 size_t user_len, id_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700706 int res;
707 struct radius_session *sess;
708 struct eap_config eap_conf;
Hai Shalom021b0b52019-04-10 11:17:58 -0700709 struct eap_user *tmp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700710
711 RADIUS_DEBUG("Creating a new session");
712
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700713 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &user,
714 &user_len, NULL) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700715 RADIUS_DEBUG("Could not get User-Name");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700716 return NULL;
717 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700718 RADIUS_DUMP_ASCII("User-Name", user, user_len);
719
Hai Shalom021b0b52019-04-10 11:17:58 -0700720 tmp = os_zalloc(sizeof(*tmp));
721 if (!tmp)
722 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700723
Hai Shalom021b0b52019-04-10 11:17:58 -0700724 res = data->get_eap_user(data->conf_ctx, user, user_len, 0, tmp);
725#ifdef CONFIG_ERP
726 if (res != 0 && data->erp) {
727 char *username;
728
729 username = os_zalloc(user_len + 1);
730 if (username) {
731 os_memcpy(username, user, user_len);
732 if (radius_server_erp_find_key(data, username))
733 res = 0;
734 os_free(username);
735 }
736 }
737#endif /* CONFIG_ERP */
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700738 if (res != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700739 RADIUS_DEBUG("User-Name not found from user database");
Hai Shalom021b0b52019-04-10 11:17:58 -0700740 eap_user_free(tmp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700741 return NULL;
742 }
743
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700744 RADIUS_DEBUG("Matching user entry found");
745 sess = radius_server_new_session(data, client);
746 if (sess == NULL) {
747 RADIUS_DEBUG("Failed to create a new session");
Hai Shalom021b0b52019-04-10 11:17:58 -0700748 eap_user_free(tmp);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700749 return NULL;
750 }
Hai Shalom021b0b52019-04-10 11:17:58 -0700751 sess->accept_attr = tmp->accept_attr;
752 sess->macacl = tmp->macacl;
753 eap_user_free(tmp);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700754
Dmitry Shmidtb5d893b2014-06-04 15:28:27 -0700755 sess->username = os_malloc(user_len * 4 + 1);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700756 if (sess->username == NULL) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700757 radius_server_session_remove(data, sess);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700758 return NULL;
759 }
Dmitry Shmidtb5d893b2014-06-04 15:28:27 -0700760 printf_encode(sess->username, user_len * 4 + 1, user, user_len);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700761
762 sess->nas_ip = os_strdup(from_addr);
763 if (sess->nas_ip == NULL) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700764 radius_server_session_remove(data, sess);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700765 return NULL;
766 }
767
Roshan Pius3a1667e2018-07-03 15:17:14 -0700768 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID, &id,
769 &id_len, NULL) == 0) {
770 char buf[3 * ETH_ALEN];
771
772 os_memset(buf, 0, sizeof(buf));
773 if (id_len >= sizeof(buf))
774 id_len = sizeof(buf) - 1;
775 os_memcpy(buf, id, id_len);
776 if (hwaddr_aton2(buf, sess->mac_addr) < 0)
777 os_memset(sess->mac_addr, 0, ETH_ALEN);
778 else
779 RADIUS_DEBUG("Calling-Station-Id: " MACSTR,
780 MAC2STR(sess->mac_addr));
781 }
782
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700783 srv_log(sess, "New session created");
784
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700785 os_memset(&eap_conf, 0, sizeof(eap_conf));
786 eap_conf.ssl_ctx = data->ssl_ctx;
787 eap_conf.msg_ctx = data->msg_ctx;
788 eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
789 eap_conf.backend_auth = TRUE;
790 eap_conf.eap_server = 1;
791 eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
792 eap_conf.eap_fast_a_id = data->eap_fast_a_id;
793 eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len;
794 eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info;
795 eap_conf.eap_fast_prov = data->eap_fast_prov;
796 eap_conf.pac_key_lifetime = data->pac_key_lifetime;
797 eap_conf.pac_key_refresh_time = data->pac_key_refresh_time;
Hai Shalom81f62d82019-07-22 12:10:00 -0700798 eap_conf.eap_teap_auth = data->eap_teap_auth;
799 eap_conf.eap_teap_pac_no_inner = data->eap_teap_pac_no_inner;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700800 eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
801 eap_conf.tnc = data->tnc;
802 eap_conf.wps = data->wps;
803 eap_conf.pwd_group = data->pwd_group;
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700804 eap_conf.server_id = (const u8 *) data->server_id;
805 eap_conf.server_id_len = os_strlen(data->server_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800806 eap_conf.erp = data->erp;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800807 eap_conf.tls_session_lifetime = data->tls_session_lifetime;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700808 eap_conf.tls_flags = data->tls_flags;
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700809 radius_server_testing_options(sess, &eap_conf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700810 sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
811 &eap_conf);
812 if (sess->eap == NULL) {
813 RADIUS_DEBUG("Failed to initialize EAP state machine for the "
814 "new session");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700815 radius_server_session_remove(data, sess);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700816 return NULL;
817 }
818 sess->eap_if = eap_get_interface(sess->eap);
819 sess->eap_if->eapRestart = TRUE;
820 sess->eap_if->portEnabled = TRUE;
821
822 RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);
823
824 return sess;
825}
826
827
Roshan Pius3a1667e2018-07-03 15:17:14 -0700828#ifdef CONFIG_HS20
829static void radius_srv_hs20_t_c_pending(struct radius_session *sess)
830{
831#ifdef CONFIG_SQLITE
832 char *sql;
833 char addr[3 * ETH_ALEN], *id_str;
834 const u8 *id;
835 size_t id_len;
836
837 if (!sess->server->db || !sess->eap ||
838 is_zero_ether_addr(sess->mac_addr))
839 return;
840
841 os_snprintf(addr, sizeof(addr), MACSTR, MAC2STR(sess->mac_addr));
842
843 id = eap_get_identity(sess->eap, &id_len);
844 if (!id)
845 return;
846 id_str = os_malloc(id_len + 1);
847 if (!id_str)
848 return;
849 os_memcpy(id_str, id, id_len);
850 id_str[id_len] = '\0';
851
852 sql = sqlite3_mprintf("INSERT OR REPLACE INTO pending_tc (mac_addr,identity) VALUES (%Q,%Q)",
853 addr, id_str);
854 os_free(id_str);
855 if (!sql)
856 return;
857
858 if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
859 SQLITE_OK) {
860 RADIUS_ERROR("Failed to add pending_tc entry into sqlite database: %s",
861 sqlite3_errmsg(sess->server->db));
862 }
863 sqlite3_free(sql);
864#endif /* CONFIG_SQLITE */
865}
866#endif /* CONFIG_HS20 */
867
868
869static void radius_server_add_session(struct radius_session *sess)
870{
871#ifdef CONFIG_SQLITE
872 char *sql;
873 char addr_txt[ETH_ALEN * 3];
874 struct os_time now;
875
876 if (!sess->server->db)
877 return;
878
879
880 os_snprintf(addr_txt, sizeof(addr_txt), MACSTR,
881 MAC2STR(sess->mac_addr));
882
883 os_get_time(&now);
884 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)",
885 addr_txt, sess->username, now.sec,
886 sess->nas_ip, sess->t_c_filtering);
887 if (sql) {
888 if (sqlite3_exec(sess->server->db, sql, NULL, NULL,
889 NULL) != SQLITE_OK) {
890 RADIUS_ERROR("Failed to add current_sessions entry into sqlite database: %s",
891 sqlite3_errmsg(sess->server->db));
892 }
893 sqlite3_free(sql);
894 }
895#endif /* CONFIG_SQLITE */
896}
897
898
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800899static void db_update_last_msk(struct radius_session *sess, const char *msk)
900{
901#ifdef CONFIG_RADIUS_TEST
902#ifdef CONFIG_SQLITE
903 char *sql = NULL;
904 char *id_str = NULL;
905 const u8 *id;
906 size_t id_len;
907 const char *serial_num;
908
909 if (!sess->server->db)
910 return;
911
912 serial_num = eap_get_serial_num(sess->eap);
913 if (serial_num) {
914 id_len = 5 + os_strlen(serial_num) + 1;
915 id_str = os_malloc(id_len);
916 if (!id_str)
917 return;
918 os_snprintf(id_str, id_len, "cert-%s", serial_num);
919 } else {
920 id = eap_get_identity(sess->eap, &id_len);
921 if (!id)
922 return;
923 id_str = os_malloc(id_len + 1);
924 if (!id_str)
925 return;
926 os_memcpy(id_str, id, id_len);
927 id_str[id_len] = '\0';
928 }
929
930 sql = sqlite3_mprintf("UPDATE users SET last_msk=%Q WHERE identity=%Q",
931 msk, id_str);
932 os_free(id_str);
933 if (!sql)
934 return;
935
936 if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
937 SQLITE_OK) {
938 RADIUS_DEBUG("Failed to update last_msk: %s",
939 sqlite3_errmsg(sess->server->db));
940 }
941 sqlite3_free(sql);
942#endif /* CONFIG_SQLITE */
943#endif /* CONFIG_RADIUS_TEST */
944}
945
946
Hai Shalom74f70d42019-02-11 14:42:39 -0800947#ifdef CONFIG_HS20
948
949static int radius_server_is_sim_method(struct radius_session *sess)
950{
951 const char *name;
952
953 name = eap_get_method(sess->eap);
954 return name &&
955 (os_strcmp(name, "SIM") == 0 ||
956 os_strcmp(name, "AKA") == 0 ||
957 os_strcmp(name, "AKA'") == 0);
958}
959
960
961static int radius_server_hs20_missing_sim_pps(struct radius_msg *request)
962{
963 u8 *buf, *pos, *end, type, sublen;
964 size_t len;
965
966 buf = NULL;
967 for (;;) {
968 if (radius_msg_get_attr_ptr(request,
969 RADIUS_ATTR_VENDOR_SPECIFIC,
970 &buf, &len, buf) < 0)
971 return 0;
972 if (len < 6)
973 continue;
974 pos = buf;
975 end = buf + len;
976 if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
977 continue;
978 pos += 4;
979
980 type = *pos++;
981 sublen = *pos++;
982 if (sublen < 2)
983 continue; /* invalid length */
984 sublen -= 2; /* skip header */
985 if (pos + sublen > end)
986 continue; /* invalid WFA VSA */
987
988 if (type != RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION)
989 continue;
990
991 RADIUS_DUMP("HS2.0 mobile device version", pos, sublen);
992 if (sublen < 1 + 2)
993 continue;
994 if (pos[0] == 0)
995 continue; /* Release 1 STA does not support provisioning
996
997 */
998 /* UpdateIdentifier 0 indicates no PPS MO */
999 return WPA_GET_BE16(pos + 1) == 0;
1000 }
1001}
1002
1003
1004#define HS20_MOBILE_ID_HASH_LEN 16
1005
1006static int radius_server_sim_provisioning_session(struct radius_session *sess,
1007 const u8 *hash)
1008{
1009#ifdef CONFIG_SQLITE
1010 char *sql;
1011 char addr_txt[ETH_ALEN * 3];
1012 char hash_txt[2 * HS20_MOBILE_ID_HASH_LEN + 1];
1013 struct os_time now;
1014 int res;
1015 const char *imsi, *eap_method;
1016
1017 if (!sess->server->db ||
1018 (!db_table_exists(sess->server->db, "sim_provisioning") &&
1019 db_table_create_sim_provisioning(sess->server->db) < 0))
1020 return -1;
1021
1022 imsi = eap_get_imsi(sess->eap);
1023 if (!imsi)
1024 return -1;
1025
1026 eap_method = eap_get_method(sess->eap);
1027 if (!eap_method)
1028 return -1;
1029
1030 os_snprintf(addr_txt, sizeof(addr_txt), MACSTR,
1031 MAC2STR(sess->mac_addr));
1032 wpa_snprintf_hex(hash_txt, sizeof(hash_txt), hash,
1033 HS20_MOBILE_ID_HASH_LEN);
1034
1035 os_get_time(&now);
1036 sql = sqlite3_mprintf("INSERT INTO sim_provisioning(mobile_identifier_hash,imsi,mac_addr,eap_method,timestamp) VALUES (%Q,%Q,%Q,%Q,%u)",
1037 hash_txt, imsi, addr_txt, eap_method, now.sec);
1038 if (!sql)
1039 return -1;
1040
1041 if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
1042 SQLITE_OK) {
1043 RADIUS_ERROR("Failed to add SIM provisioning entry into sqlite database: %s",
1044 sqlite3_errmsg(sess->server->db));
1045 res = -1;
1046 } else {
1047 res = 0;
1048 }
1049 sqlite3_free(sql);
1050 return res;
1051#endif /* CONFIG_SQLITE */
1052 return -1;
1053}
1054
1055#endif /* CONFIG_HS20 */
1056
1057
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001058static struct radius_msg *
1059radius_server_encapsulate_eap(struct radius_server_data *data,
1060 struct radius_client *client,
1061 struct radius_session *sess,
1062 struct radius_msg *request)
1063{
1064 struct radius_msg *msg;
1065 int code;
1066 unsigned int sess_id;
1067 struct radius_hdr *hdr = radius_msg_get_hdr(request);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001068 u16 reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001069
1070 if (sess->eap_if->eapFail) {
1071 sess->eap_if->eapFail = FALSE;
1072 code = RADIUS_CODE_ACCESS_REJECT;
1073 } else if (sess->eap_if->eapSuccess) {
1074 sess->eap_if->eapSuccess = FALSE;
1075 code = RADIUS_CODE_ACCESS_ACCEPT;
1076 } else {
1077 sess->eap_if->eapReq = FALSE;
1078 code = RADIUS_CODE_ACCESS_CHALLENGE;
1079 }
1080
1081 msg = radius_msg_new(code, hdr->identifier);
1082 if (msg == NULL) {
1083 RADIUS_DEBUG("Failed to allocate reply message");
1084 return NULL;
1085 }
1086
1087 sess_id = htonl(sess->sess_id);
1088 if (code == RADIUS_CODE_ACCESS_CHALLENGE &&
1089 !radius_msg_add_attr(msg, RADIUS_ATTR_STATE,
1090 (u8 *) &sess_id, sizeof(sess_id))) {
1091 RADIUS_DEBUG("Failed to add State attribute");
1092 }
1093
1094 if (sess->eap_if->eapReqData &&
1095 !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData),
1096 wpabuf_len(sess->eap_if->eapReqData))) {
1097 RADIUS_DEBUG("Failed to add EAP-Message attribute");
1098 }
1099
1100 if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
1101 int len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001102#ifdef CONFIG_RADIUS_TEST
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001103 char buf[2 * 64 + 1];
1104
1105 len = sess->eap_if->eapKeyDataLen;
1106 if (len > 64)
1107 len = 64;
1108 len = wpa_snprintf_hex(buf, sizeof(buf),
1109 sess->eap_if->eapKeyData, len);
1110 buf[len] = '\0';
1111
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001112 if (data->dump_msk_file) {
1113 FILE *f;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001114
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001115 f = fopen(data->dump_msk_file, "a");
1116 if (f) {
1117 len = sess->eap_if->eapKeyDataLen;
1118 if (len > 64)
1119 len = 64;
1120 len = wpa_snprintf_hex(
1121 buf, sizeof(buf),
1122 sess->eap_if->eapKeyData, len);
1123 buf[len] = '\0';
1124 fprintf(f, "%s\n", buf);
1125 fclose(f);
1126 }
1127 }
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001128
1129 db_update_last_msk(sess, buf);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001130#endif /* CONFIG_RADIUS_TEST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001131 if (sess->eap_if->eapKeyDataLen > 64) {
1132 len = 32;
1133 } else {
1134 len = sess->eap_if->eapKeyDataLen / 2;
1135 }
1136 if (!radius_msg_add_mppe_keys(msg, hdr->authenticator,
1137 (u8 *) client->shared_secret,
1138 client->shared_secret_len,
1139 sess->eap_if->eapKeyData + len,
1140 len, sess->eap_if->eapKeyData,
1141 len)) {
1142 RADIUS_DEBUG("Failed to add MPPE key attributes");
1143 }
Hai Shalom81f62d82019-07-22 12:10:00 -07001144
1145 if (sess->eap_if->eapSessionId &&
1146 !radius_msg_add_attr(msg, RADIUS_ATTR_EAP_KEY_NAME,
1147 sess->eap_if->eapSessionId,
1148 sess->eap_if->eapSessionIdLen)) {
1149 RADIUS_DEBUG("Failed to add EAP-Key-Name attribute");
1150 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001151 }
1152
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001153#ifdef CONFIG_HS20
1154 if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation &&
1155 data->subscr_remediation_url) {
1156 u8 *buf;
1157 size_t url_len = os_strlen(data->subscr_remediation_url);
1158 buf = os_malloc(1 + url_len);
1159 if (buf == NULL) {
1160 radius_msg_free(msg);
1161 return NULL;
1162 }
1163 buf[0] = data->subscr_remediation_method;
1164 os_memcpy(&buf[1], data->subscr_remediation_url, url_len);
1165 if (!radius_msg_add_wfa(
1166 msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
1167 buf, 1 + url_len)) {
1168 RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
1169 }
1170 os_free(buf);
1171 } else if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation) {
1172 u8 buf[1];
1173 if (!radius_msg_add_wfa(
1174 msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
1175 buf, 0)) {
1176 RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
1177 }
Hai Shalom74f70d42019-02-11 14:42:39 -08001178 } else if (code == RADIUS_CODE_ACCESS_ACCEPT &&
1179 data->hs20_sim_provisioning_url &&
1180 radius_server_is_sim_method(sess) &&
1181 radius_server_hs20_missing_sim_pps(request)) {
1182 u8 *buf, *pos, hash[HS20_MOBILE_ID_HASH_LEN];
1183 size_t prefix_len, url_len;
1184
1185 RADIUS_DEBUG("Device needs HS 2.0 SIM provisioning");
1186
1187 if (os_get_random(hash, HS20_MOBILE_ID_HASH_LEN) < 0) {
1188 radius_msg_free(msg);
1189 return NULL;
1190 }
1191 RADIUS_DUMP("hotspot2dot0-mobile-identifier-hash",
1192 hash, HS20_MOBILE_ID_HASH_LEN);
1193
1194 if (radius_server_sim_provisioning_session(sess, hash) < 0) {
1195 radius_msg_free(msg);
1196 return NULL;
1197 }
1198
1199 prefix_len = os_strlen(data->hs20_sim_provisioning_url);
1200 url_len = prefix_len + 2 * HS20_MOBILE_ID_HASH_LEN;
1201 buf = os_malloc(1 + url_len + 1);
1202 if (!buf) {
1203 radius_msg_free(msg);
1204 return NULL;
1205 }
1206 pos = buf;
1207 *pos++ = data->subscr_remediation_method;
1208 os_memcpy(pos, data->hs20_sim_provisioning_url, prefix_len);
1209 pos += prefix_len;
1210 wpa_snprintf_hex((char *) pos, 2 * HS20_MOBILE_ID_HASH_LEN + 1,
1211 hash, HS20_MOBILE_ID_HASH_LEN);
1212 RADIUS_DEBUG("HS 2.0 subscription remediation URL: %s",
1213 (char *) &buf[1]);
1214 if (!radius_msg_add_wfa(
1215 msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
1216 buf, 1 + url_len)) {
1217 RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
1218 }
1219 os_free(buf);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001220 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001221
1222 if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->t_c_filtering) {
1223 u8 buf[4] = { 0x01, 0x00, 0x00, 0x00 }; /* E=1 */
1224 const char *url = data->t_c_server_url, *pos;
1225 char *url2, *end2, *pos2;
1226 size_t url_len;
1227
1228 if (!radius_msg_add_wfa(
1229 msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING,
1230 buf, sizeof(buf))) {
1231 RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering");
1232 radius_msg_free(msg);
1233 return NULL;
1234 }
1235
1236 if (!url) {
1237 RADIUS_DEBUG("No t_c_server_url configured");
1238 radius_msg_free(msg);
1239 return NULL;
1240 }
1241
1242 pos = os_strstr(url, "@1@");
1243 if (!pos) {
1244 RADIUS_DEBUG("No @1@ macro in t_c_server_url");
1245 radius_msg_free(msg);
1246 return NULL;
1247 }
1248
1249 url_len = os_strlen(url) + ETH_ALEN * 3 - 1 - 3;
Hai Shalomc9e41a12018-07-31 14:41:42 -07001250 url2 = os_malloc(url_len + 1);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001251 if (!url2) {
1252 RADIUS_DEBUG("Failed to allocate room for T&C Server URL");
1253 os_free(url2);
1254 radius_msg_free(msg);
1255 return NULL;
1256 }
1257 pos2 = url2;
Hai Shalomc9e41a12018-07-31 14:41:42 -07001258 end2 = url2 + url_len + 1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001259 os_memcpy(pos2, url, pos - url);
1260 pos2 += pos - url;
1261 os_snprintf(pos2, end2 - pos2, MACSTR, MAC2STR(sess->mac_addr));
1262 pos2 += ETH_ALEN * 3 - 1;
1263 os_memcpy(pos2, pos + 3, os_strlen(pos + 3));
1264 if (!radius_msg_add_wfa(msg,
1265 RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL,
1266 (const u8 *) url2, url_len)) {
1267 RADIUS_DEBUG("Failed to add WFA-HS20-T-C-URL");
1268 os_free(url2);
1269 radius_msg_free(msg);
1270 return NULL;
1271 }
1272 os_free(url2);
1273
1274 radius_srv_hs20_t_c_pending(sess);
1275 }
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08001276#endif /* CONFIG_HS20 */
1277
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001278 if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
1279 RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
1280 radius_msg_free(msg);
1281 return NULL;
1282 }
1283
Dmitry Shmidt818ea482014-03-10 13:15:21 -07001284 if (code == RADIUS_CODE_ACCESS_ACCEPT) {
1285 struct hostapd_radius_attr *attr;
1286 for (attr = sess->accept_attr; attr; attr = attr->next) {
1287 if (!radius_msg_add_attr(msg, attr->type,
1288 wpabuf_head(attr->val),
1289 wpabuf_len(attr->val))) {
1290 wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
1291 radius_msg_free(msg);
1292 return NULL;
1293 }
1294 }
1295 }
1296
Roshan Pius3a1667e2018-07-03 15:17:14 -07001297 if (code == RADIUS_CODE_ACCESS_REJECT) {
1298 if (radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE,
1299 reason) < 0) {
1300 RADIUS_DEBUG("Failed to add WLAN-Reason-Code attribute");
1301 radius_msg_free(msg);
1302 return NULL;
1303 }
1304 }
1305
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001306 if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
1307 client->shared_secret_len,
1308 hdr->authenticator) < 0) {
1309 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
1310 }
1311
Roshan Pius3a1667e2018-07-03 15:17:14 -07001312 if (code == RADIUS_CODE_ACCESS_ACCEPT)
1313 radius_server_add_session(sess);
1314
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001315 return msg;
1316}
1317
1318
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001319static struct radius_msg *
1320radius_server_macacl(struct radius_server_data *data,
1321 struct radius_client *client,
1322 struct radius_session *sess,
1323 struct radius_msg *request)
1324{
1325 struct radius_msg *msg;
1326 int code;
1327 struct radius_hdr *hdr = radius_msg_get_hdr(request);
1328 u8 *pw;
1329 size_t pw_len;
1330
1331 code = RADIUS_CODE_ACCESS_ACCEPT;
1332
1333 if (radius_msg_get_attr_ptr(request, RADIUS_ATTR_USER_PASSWORD, &pw,
1334 &pw_len, NULL) < 0) {
1335 RADIUS_DEBUG("Could not get User-Password");
1336 code = RADIUS_CODE_ACCESS_REJECT;
1337 } else {
1338 int res;
1339 struct eap_user tmp;
1340
1341 os_memset(&tmp, 0, sizeof(tmp));
1342 res = data->get_eap_user(data->conf_ctx, (u8 *) sess->username,
1343 os_strlen(sess->username), 0, &tmp);
1344 if (res || !tmp.macacl || tmp.password == NULL) {
1345 RADIUS_DEBUG("No MAC ACL user entry");
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001346 bin_clear_free(tmp.password, tmp.password_len);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001347 code = RADIUS_CODE_ACCESS_REJECT;
1348 } else {
1349 u8 buf[128];
1350 res = radius_user_password_hide(
1351 request, tmp.password, tmp.password_len,
1352 (u8 *) client->shared_secret,
1353 client->shared_secret_len,
1354 buf, sizeof(buf));
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001355 bin_clear_free(tmp.password, tmp.password_len);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001356
1357 if (res < 0 || pw_len != (size_t) res ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001358 os_memcmp_const(pw, buf, res) != 0) {
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001359 RADIUS_DEBUG("Incorrect User-Password");
1360 code = RADIUS_CODE_ACCESS_REJECT;
1361 }
1362 }
1363 }
1364
1365 msg = radius_msg_new(code, hdr->identifier);
1366 if (msg == NULL) {
1367 RADIUS_DEBUG("Failed to allocate reply message");
1368 return NULL;
1369 }
1370
1371 if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
1372 RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
1373 radius_msg_free(msg);
1374 return NULL;
1375 }
1376
1377 if (code == RADIUS_CODE_ACCESS_ACCEPT) {
1378 struct hostapd_radius_attr *attr;
1379 for (attr = sess->accept_attr; attr; attr = attr->next) {
1380 if (!radius_msg_add_attr(msg, attr->type,
1381 wpabuf_head(attr->val),
1382 wpabuf_len(attr->val))) {
1383 wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
1384 radius_msg_free(msg);
1385 return NULL;
1386 }
1387 }
1388 }
1389
1390 if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
1391 client->shared_secret_len,
1392 hdr->authenticator) < 0) {
1393 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
1394 }
1395
1396 return msg;
1397}
1398
1399
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001400static int radius_server_reject(struct radius_server_data *data,
1401 struct radius_client *client,
1402 struct radius_msg *request,
1403 struct sockaddr *from, socklen_t fromlen,
1404 const char *from_addr, int from_port)
1405{
1406 struct radius_msg *msg;
1407 int ret = 0;
1408 struct eap_hdr eapfail;
1409 struct wpabuf *buf;
1410 struct radius_hdr *hdr = radius_msg_get_hdr(request);
1411
1412 RADIUS_DEBUG("Reject invalid request from %s:%d",
1413 from_addr, from_port);
1414
1415 msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, hdr->identifier);
1416 if (msg == NULL) {
1417 return -1;
1418 }
1419
1420 os_memset(&eapfail, 0, sizeof(eapfail));
1421 eapfail.code = EAP_CODE_FAILURE;
1422 eapfail.identifier = 0;
1423 eapfail.length = host_to_be16(sizeof(eapfail));
1424
1425 if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) {
1426 RADIUS_DEBUG("Failed to add EAP-Message attribute");
1427 }
1428
1429 if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
1430 RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
1431 radius_msg_free(msg);
1432 return -1;
1433 }
1434
1435 if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
1436 client->shared_secret_len,
1437 hdr->authenticator) <
1438 0) {
1439 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
1440 }
1441
1442 if (wpa_debug_level <= MSG_MSGDUMP) {
1443 radius_msg_dump(msg);
1444 }
1445
1446 data->counters.access_rejects++;
1447 client->counters.access_rejects++;
1448 buf = radius_msg_get_buf(msg);
1449 if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
1450 (struct sockaddr *) from, sizeof(*from)) < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001451 wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001452 ret = -1;
1453 }
1454
1455 radius_msg_free(msg);
1456
1457 return ret;
1458}
1459
1460
Roshan Pius3a1667e2018-07-03 15:17:14 -07001461static void radius_server_hs20_t_c_check(struct radius_session *sess,
1462 struct radius_msg *msg)
1463{
1464#ifdef CONFIG_HS20
1465 u8 *buf, *pos, *end, type, sublen, *timestamp = NULL;
1466 size_t len;
1467
1468 buf = NULL;
1469 for (;;) {
1470 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1471 &buf, &len, buf) < 0)
1472 break;
1473 if (len < 6)
1474 continue;
1475 pos = buf;
1476 end = buf + len;
1477 if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
1478 continue;
1479 pos += 4;
1480
1481 type = *pos++;
1482 sublen = *pos++;
1483 if (sublen < 2)
1484 continue; /* invalid length */
1485 sublen -= 2; /* skip header */
1486 if (pos + sublen > end)
1487 continue; /* invalid WFA VSA */
1488
1489 if (type == RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP && len >= 4) {
1490 timestamp = pos;
1491 break;
1492 }
1493 }
1494
1495 if (!timestamp)
1496 return;
1497 RADIUS_DEBUG("HS20-Timestamp: %u", WPA_GET_BE32(timestamp));
1498 if (sess->t_c_timestamp != WPA_GET_BE32(timestamp)) {
1499 RADIUS_DEBUG("Last read T&C timestamp does not match HS20-Timestamp --> require filtering");
1500 sess->t_c_filtering = 1;
1501 }
1502#endif /* CONFIG_HS20 */
1503}
1504
1505
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001506static int radius_server_request(struct radius_server_data *data,
1507 struct radius_msg *msg,
1508 struct sockaddr *from, socklen_t fromlen,
1509 struct radius_client *client,
1510 const char *from_addr, int from_port,
1511 struct radius_session *force_sess)
1512{
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001513 struct wpabuf *eap = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001514 int res, state_included = 0;
1515 u8 statebuf[4];
1516 unsigned int state;
1517 struct radius_session *sess;
1518 struct radius_msg *reply;
1519 int is_complete = 0;
1520
1521 if (force_sess)
1522 sess = force_sess;
1523 else {
1524 res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
1525 sizeof(statebuf));
1526 state_included = res >= 0;
1527 if (res == sizeof(statebuf)) {
1528 state = WPA_GET_BE32(statebuf);
1529 sess = radius_server_get_session(client, state);
1530 } else {
1531 sess = NULL;
1532 }
1533 }
1534
1535 if (sess) {
1536 RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);
1537 } else if (state_included) {
1538 RADIUS_DEBUG("State attribute included but no session found");
1539 radius_server_reject(data, client, msg, from, fromlen,
1540 from_addr, from_port);
1541 return -1;
1542 } else {
Dmitry Shmidt818ea482014-03-10 13:15:21 -07001543 sess = radius_server_get_new_session(data, client, msg,
1544 from_addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001545 if (sess == NULL) {
1546 RADIUS_DEBUG("Could not create a new session");
1547 radius_server_reject(data, client, msg, from, fromlen,
1548 from_addr, from_port);
1549 return -1;
1550 }
1551 }
1552
1553 if (sess->last_from_port == from_port &&
1554 sess->last_identifier == radius_msg_get_hdr(msg)->identifier &&
1555 os_memcmp(sess->last_authenticator,
1556 radius_msg_get_hdr(msg)->authenticator, 16) == 0) {
1557 RADIUS_DEBUG("Duplicate message from %s", from_addr);
1558 data->counters.dup_access_requests++;
1559 client->counters.dup_access_requests++;
1560
1561 if (sess->last_reply) {
1562 struct wpabuf *buf;
1563 buf = radius_msg_get_buf(sess->last_reply);
1564 res = sendto(data->auth_sock, wpabuf_head(buf),
1565 wpabuf_len(buf), 0,
1566 (struct sockaddr *) from, fromlen);
1567 if (res < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001568 wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
1569 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001570 }
1571 return 0;
1572 }
1573
1574 RADIUS_DEBUG("No previous reply available for duplicate "
1575 "message");
1576 return -1;
1577 }
Dmitry Shmidt29333592017-01-09 12:27:11 -08001578
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001579 eap = radius_msg_get_eap(msg);
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001580 if (eap == NULL && sess->macacl) {
1581 reply = radius_server_macacl(data, client, sess, msg);
1582 if (reply == NULL)
1583 return -1;
1584 goto send_reply;
1585 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001586 if (eap == NULL) {
1587 RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
1588 from_addr);
1589 data->counters.packets_dropped++;
1590 client->counters.packets_dropped++;
1591 return -1;
1592 }
1593
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001594 RADIUS_DUMP("Received EAP data", wpabuf_head(eap), wpabuf_len(eap));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001595
1596 /* FIX: if Code is Request, Success, or Failure, send Access-Reject;
1597 * RFC3579 Sect. 2.6.2.
1598 * Include EAP-Response/Nak with no preferred method if
1599 * code == request.
1600 * If code is not 1-4, discard the packet silently.
1601 * Or is this already done by the EAP state machine? */
1602
1603 wpabuf_free(sess->eap_if->eapRespData);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001604 sess->eap_if->eapRespData = eap;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001605 sess->eap_if->eapResp = TRUE;
1606 eap_server_sm_step(sess->eap);
1607
1608 if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess ||
1609 sess->eap_if->eapFail) && sess->eap_if->eapReqData) {
1610 RADIUS_DUMP("EAP data from the state machine",
1611 wpabuf_head(sess->eap_if->eapReqData),
1612 wpabuf_len(sess->eap_if->eapReqData));
1613 } else if (sess->eap_if->eapFail) {
1614 RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
1615 "set");
1616 } else if (eap_sm_method_pending(sess->eap)) {
1617 radius_msg_free(sess->last_msg);
1618 sess->last_msg = msg;
1619 sess->last_from_port = from_port;
1620 os_free(sess->last_from_addr);
1621 sess->last_from_addr = os_strdup(from_addr);
1622 sess->last_fromlen = fromlen;
1623 os_memcpy(&sess->last_from, from, fromlen);
1624 return -2;
1625 } else {
1626 RADIUS_DEBUG("No EAP data from the state machine - ignore this"
1627 " Access-Request silently (assuming it was a "
1628 "duplicate)");
1629 data->counters.packets_dropped++;
1630 client->counters.packets_dropped++;
1631 return -1;
1632 }
1633
1634 if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
1635 is_complete = 1;
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001636 if (sess->eap_if->eapFail) {
Dmitry Shmidt818ea482014-03-10 13:15:21 -07001637 srv_log(sess, "EAP authentication failed");
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001638 db_update_last_msk(sess, "FAIL");
1639 } else if (sess->eap_if->eapSuccess) {
Dmitry Shmidt818ea482014-03-10 13:15:21 -07001640 srv_log(sess, "EAP authentication succeeded");
Hai Shalom39ba6fc2019-01-22 12:40:38 -08001641 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001642
Roshan Pius3a1667e2018-07-03 15:17:14 -07001643 if (sess->eap_if->eapSuccess)
1644 radius_server_hs20_t_c_check(sess, msg);
1645
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001646 reply = radius_server_encapsulate_eap(data, client, sess, msg);
1647
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07001648send_reply:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001649 if (reply) {
1650 struct wpabuf *buf;
1651 struct radius_hdr *hdr;
1652
1653 RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);
1654 if (wpa_debug_level <= MSG_MSGDUMP) {
1655 radius_msg_dump(reply);
1656 }
1657
1658 switch (radius_msg_get_hdr(reply)->code) {
1659 case RADIUS_CODE_ACCESS_ACCEPT:
Dmitry Shmidt818ea482014-03-10 13:15:21 -07001660 srv_log(sess, "Sending Access-Accept");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001661 data->counters.access_accepts++;
1662 client->counters.access_accepts++;
1663 break;
1664 case RADIUS_CODE_ACCESS_REJECT:
Dmitry Shmidt818ea482014-03-10 13:15:21 -07001665 srv_log(sess, "Sending Access-Reject");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001666 data->counters.access_rejects++;
1667 client->counters.access_rejects++;
1668 break;
1669 case RADIUS_CODE_ACCESS_CHALLENGE:
1670 data->counters.access_challenges++;
1671 client->counters.access_challenges++;
1672 break;
1673 }
1674 buf = radius_msg_get_buf(reply);
1675 res = sendto(data->auth_sock, wpabuf_head(buf),
1676 wpabuf_len(buf), 0,
1677 (struct sockaddr *) from, fromlen);
1678 if (res < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001679 wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
1680 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001681 }
1682 radius_msg_free(sess->last_reply);
1683 sess->last_reply = reply;
1684 sess->last_from_port = from_port;
1685 hdr = radius_msg_get_hdr(msg);
1686 sess->last_identifier = hdr->identifier;
1687 os_memcpy(sess->last_authenticator, hdr->authenticator, 16);
1688 } else {
1689 data->counters.packets_dropped++;
1690 client->counters.packets_dropped++;
1691 }
1692
1693 if (is_complete) {
1694 RADIUS_DEBUG("Removing completed session 0x%x after timeout",
1695 sess->sess_id);
1696 eloop_cancel_timeout(radius_server_session_remove_timeout,
1697 data, sess);
Dmitry Shmidt29333592017-01-09 12:27:11 -08001698 eloop_register_timeout(RADIUS_SESSION_MAINTAIN, 0,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001699 radius_server_session_remove_timeout,
1700 data, sess);
1701 }
1702
1703 return 0;
1704}
1705
1706
Roshan Pius3a1667e2018-07-03 15:17:14 -07001707static void
1708radius_server_receive_disconnect_resp(struct radius_server_data *data,
1709 struct radius_client *client,
1710 struct radius_msg *msg, int ack)
1711{
1712 struct radius_hdr *hdr;
1713
1714 if (!client->pending_dac_disconnect_req) {
1715 RADIUS_DEBUG("Ignore unexpected Disconnect response");
1716 radius_msg_free(msg);
1717 return;
1718 }
1719
1720 hdr = radius_msg_get_hdr(msg);
1721 if (hdr->identifier != client->pending_dac_disconnect_id) {
1722 RADIUS_DEBUG("Ignore unexpected Disconnect response with unexpected identifier %u (expected %u)",
1723 hdr->identifier,
1724 client->pending_dac_disconnect_id);
1725 radius_msg_free(msg);
1726 return;
1727 }
1728
1729 if (radius_msg_verify(msg, (const u8 *) client->shared_secret,
1730 client->shared_secret_len,
1731 client->pending_dac_disconnect_req, 0)) {
1732 RADIUS_DEBUG("Ignore Disconnect response with invalid authenticator");
1733 radius_msg_free(msg);
1734 return;
1735 }
1736
1737 RADIUS_DEBUG("Disconnect-%s received for " MACSTR,
1738 ack ? "ACK" : "NAK",
1739 MAC2STR(client->pending_dac_disconnect_addr));
1740
1741 radius_msg_free(msg);
1742 radius_msg_free(client->pending_dac_disconnect_req);
1743 client->pending_dac_disconnect_req = NULL;
1744}
1745
1746
1747static void radius_server_receive_coa_resp(struct radius_server_data *data,
1748 struct radius_client *client,
1749 struct radius_msg *msg, int ack)
1750{
1751 struct radius_hdr *hdr;
1752#ifdef CONFIG_SQLITE
1753 char addrtxt[3 * ETH_ALEN];
1754 char *sql;
1755 int res;
1756#endif /* CONFIG_SQLITE */
1757
1758 if (!client->pending_dac_coa_req) {
1759 RADIUS_DEBUG("Ignore unexpected CoA response");
1760 radius_msg_free(msg);
1761 return;
1762 }
1763
1764 hdr = radius_msg_get_hdr(msg);
1765 if (hdr->identifier != client->pending_dac_coa_id) {
1766 RADIUS_DEBUG("Ignore unexpected CoA response with unexpected identifier %u (expected %u)",
1767 hdr->identifier,
1768 client->pending_dac_coa_id);
1769 radius_msg_free(msg);
1770 return;
1771 }
1772
1773 if (radius_msg_verify(msg, (const u8 *) client->shared_secret,
1774 client->shared_secret_len,
1775 client->pending_dac_coa_req, 0)) {
1776 RADIUS_DEBUG("Ignore CoA response with invalid authenticator");
1777 radius_msg_free(msg);
1778 return;
1779 }
1780
1781 RADIUS_DEBUG("CoA-%s received for " MACSTR,
1782 ack ? "ACK" : "NAK",
1783 MAC2STR(client->pending_dac_coa_addr));
1784
1785 radius_msg_free(msg);
1786 radius_msg_free(client->pending_dac_coa_req);
1787 client->pending_dac_coa_req = NULL;
1788
1789#ifdef CONFIG_SQLITE
1790 if (!data->db)
1791 return;
1792
1793 os_snprintf(addrtxt, sizeof(addrtxt), MACSTR,
1794 MAC2STR(client->pending_dac_coa_addr));
1795
1796 if (ack) {
1797 sql = sqlite3_mprintf("UPDATE current_sessions SET hs20_t_c_filtering=0, waiting_coa_ack=0, coa_ack_received=1 WHERE mac_addr=%Q",
1798 addrtxt);
1799 } else {
1800 sql = sqlite3_mprintf("UPDATE current_sessions SET waiting_coa_ack=0 WHERE mac_addr=%Q",
1801 addrtxt);
1802 }
1803 if (!sql)
1804 return;
1805
1806 res = sqlite3_exec(data->db, sql, NULL, NULL, NULL);
1807 sqlite3_free(sql);
1808 if (res != SQLITE_OK) {
1809 RADIUS_ERROR("Failed to update current_sessions entry: %s",
1810 sqlite3_errmsg(data->db));
1811 return;
1812 }
1813#endif /* CONFIG_SQLITE */
1814}
1815
1816
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001817static void radius_server_receive_auth(int sock, void *eloop_ctx,
1818 void *sock_ctx)
1819{
1820 struct radius_server_data *data = eloop_ctx;
1821 u8 *buf = NULL;
1822 union {
1823 struct sockaddr_storage ss;
1824 struct sockaddr_in sin;
1825#ifdef CONFIG_IPV6
1826 struct sockaddr_in6 sin6;
1827#endif /* CONFIG_IPV6 */
1828 } from;
1829 socklen_t fromlen;
1830 int len;
1831 struct radius_client *client = NULL;
1832 struct radius_msg *msg = NULL;
1833 char abuf[50];
1834 int from_port = 0;
1835
1836 buf = os_malloc(RADIUS_MAX_MSG_LEN);
1837 if (buf == NULL) {
1838 goto fail;
1839 }
1840
1841 fromlen = sizeof(from);
1842 len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
1843 (struct sockaddr *) &from.ss, &fromlen);
1844 if (len < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08001845 wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
1846 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001847 goto fail;
1848 }
1849
1850#ifdef CONFIG_IPV6
1851 if (data->ipv6) {
1852 if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
1853 sizeof(abuf)) == NULL)
1854 abuf[0] = '\0';
1855 from_port = ntohs(from.sin6.sin6_port);
1856 RADIUS_DEBUG("Received %d bytes from %s:%d",
1857 len, abuf, from_port);
1858
1859 client = radius_server_get_client(data,
1860 (struct in_addr *)
1861 &from.sin6.sin6_addr, 1);
1862 }
1863#endif /* CONFIG_IPV6 */
1864
1865 if (!data->ipv6) {
1866 os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
1867 from_port = ntohs(from.sin.sin_port);
1868 RADIUS_DEBUG("Received %d bytes from %s:%d",
1869 len, abuf, from_port);
1870
1871 client = radius_server_get_client(data, &from.sin.sin_addr, 0);
1872 }
1873
1874 RADIUS_DUMP("Received data", buf, len);
1875
1876 if (client == NULL) {
1877 RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
1878 data->counters.invalid_requests++;
1879 goto fail;
1880 }
1881
1882 msg = radius_msg_parse(buf, len);
1883 if (msg == NULL) {
1884 RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
1885 data->counters.malformed_access_requests++;
1886 client->counters.malformed_access_requests++;
1887 goto fail;
1888 }
1889
1890 os_free(buf);
1891 buf = NULL;
1892
1893 if (wpa_debug_level <= MSG_MSGDUMP) {
1894 radius_msg_dump(msg);
1895 }
1896
Roshan Pius3a1667e2018-07-03 15:17:14 -07001897 if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_ACK) {
1898 radius_server_receive_disconnect_resp(data, client, msg, 1);
1899 return;
1900 }
1901
1902 if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_NAK) {
1903 radius_server_receive_disconnect_resp(data, client, msg, 0);
1904 return;
1905 }
1906
1907 if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_ACK) {
1908 radius_server_receive_coa_resp(data, client, msg, 1);
1909 return;
1910 }
1911
1912 if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_NAK) {
1913 radius_server_receive_coa_resp(data, client, msg, 0);
1914 return;
1915 }
1916
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001917 if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) {
1918 RADIUS_DEBUG("Unexpected RADIUS code %d",
1919 radius_msg_get_hdr(msg)->code);
1920 data->counters.unknown_types++;
1921 client->counters.unknown_types++;
1922 goto fail;
1923 }
1924
1925 data->counters.access_requests++;
1926 client->counters.access_requests++;
1927
1928 if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret,
1929 client->shared_secret_len, NULL)) {
1930 RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf);
1931 data->counters.bad_authenticators++;
1932 client->counters.bad_authenticators++;
1933 goto fail;
1934 }
1935
1936 if (radius_server_request(data, msg, (struct sockaddr *) &from,
1937 fromlen, client, abuf, from_port, NULL) ==
1938 -2)
1939 return; /* msg was stored with the session */
1940
1941fail:
1942 radius_msg_free(msg);
1943 os_free(buf);
1944}
1945
1946
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08001947static void radius_server_receive_acct(int sock, void *eloop_ctx,
1948 void *sock_ctx)
1949{
1950 struct radius_server_data *data = eloop_ctx;
1951 u8 *buf = NULL;
1952 union {
1953 struct sockaddr_storage ss;
1954 struct sockaddr_in sin;
1955#ifdef CONFIG_IPV6
1956 struct sockaddr_in6 sin6;
1957#endif /* CONFIG_IPV6 */
1958 } from;
1959 socklen_t fromlen;
1960 int len, res;
1961 struct radius_client *client = NULL;
1962 struct radius_msg *msg = NULL, *resp = NULL;
1963 char abuf[50];
1964 int from_port = 0;
1965 struct radius_hdr *hdr;
1966 struct wpabuf *rbuf;
1967
1968 buf = os_malloc(RADIUS_MAX_MSG_LEN);
1969 if (buf == NULL) {
1970 goto fail;
1971 }
1972
1973 fromlen = sizeof(from);
1974 len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
1975 (struct sockaddr *) &from.ss, &fromlen);
1976 if (len < 0) {
1977 wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
1978 strerror(errno));
1979 goto fail;
1980 }
1981
1982#ifdef CONFIG_IPV6
1983 if (data->ipv6) {
1984 if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
1985 sizeof(abuf)) == NULL)
1986 abuf[0] = '\0';
1987 from_port = ntohs(from.sin6.sin6_port);
1988 RADIUS_DEBUG("Received %d bytes from %s:%d",
1989 len, abuf, from_port);
1990
1991 client = radius_server_get_client(data,
1992 (struct in_addr *)
1993 &from.sin6.sin6_addr, 1);
1994 }
1995#endif /* CONFIG_IPV6 */
1996
1997 if (!data->ipv6) {
1998 os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
1999 from_port = ntohs(from.sin.sin_port);
2000 RADIUS_DEBUG("Received %d bytes from %s:%d",
2001 len, abuf, from_port);
2002
2003 client = radius_server_get_client(data, &from.sin.sin_addr, 0);
2004 }
2005
2006 RADIUS_DUMP("Received data", buf, len);
2007
2008 if (client == NULL) {
2009 RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
2010 data->counters.invalid_acct_requests++;
2011 goto fail;
2012 }
2013
2014 msg = radius_msg_parse(buf, len);
2015 if (msg == NULL) {
2016 RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
2017 data->counters.malformed_acct_requests++;
2018 client->counters.malformed_acct_requests++;
2019 goto fail;
2020 }
2021
2022 os_free(buf);
2023 buf = NULL;
2024
2025 if (wpa_debug_level <= MSG_MSGDUMP) {
2026 radius_msg_dump(msg);
2027 }
2028
2029 if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_REQUEST) {
2030 RADIUS_DEBUG("Unexpected RADIUS code %d",
2031 radius_msg_get_hdr(msg)->code);
2032 data->counters.unknown_acct_types++;
2033 client->counters.unknown_acct_types++;
2034 goto fail;
2035 }
2036
2037 data->counters.acct_requests++;
2038 client->counters.acct_requests++;
2039
2040 if (radius_msg_verify_acct_req(msg, (u8 *) client->shared_secret,
2041 client->shared_secret_len)) {
2042 RADIUS_DEBUG("Invalid Authenticator from %s", abuf);
2043 data->counters.acct_bad_authenticators++;
2044 client->counters.acct_bad_authenticators++;
2045 goto fail;
2046 }
2047
2048 /* TODO: Write accounting information to a file or database */
2049
2050 hdr = radius_msg_get_hdr(msg);
2051
2052 resp = radius_msg_new(RADIUS_CODE_ACCOUNTING_RESPONSE, hdr->identifier);
2053 if (resp == NULL)
2054 goto fail;
2055
2056 radius_msg_finish_acct_resp(resp, (u8 *) client->shared_secret,
2057 client->shared_secret_len,
2058 hdr->authenticator);
2059
2060 RADIUS_DEBUG("Reply to %s:%d", abuf, from_port);
2061 if (wpa_debug_level <= MSG_MSGDUMP) {
2062 radius_msg_dump(resp);
2063 }
2064 rbuf = radius_msg_get_buf(resp);
2065 data->counters.acct_responses++;
2066 client->counters.acct_responses++;
2067 res = sendto(data->acct_sock, wpabuf_head(rbuf), wpabuf_len(rbuf), 0,
2068 (struct sockaddr *) &from.ss, fromlen);
2069 if (res < 0) {
2070 wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
2071 strerror(errno));
2072 }
2073
2074fail:
2075 radius_msg_free(resp);
2076 radius_msg_free(msg);
2077 os_free(buf);
2078}
2079
2080
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002081static int radius_server_disable_pmtu_discovery(int s)
2082{
2083 int r = -1;
2084#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2085 /* Turn off Path MTU discovery on IPv4/UDP sockets. */
2086 int action = IP_PMTUDISC_DONT;
2087 r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
2088 sizeof(action));
2089 if (r == -1)
2090 wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
2091 "%s", strerror(errno));
2092#endif
2093 return r;
2094}
2095
2096
2097static int radius_server_open_socket(int port)
2098{
2099 int s;
2100 struct sockaddr_in addr;
2101
2102 s = socket(PF_INET, SOCK_DGRAM, 0);
2103 if (s < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002104 wpa_printf(MSG_INFO, "RADIUS: socket: %s", strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002105 return -1;
2106 }
2107
2108 radius_server_disable_pmtu_discovery(s);
2109
2110 os_memset(&addr, 0, sizeof(addr));
2111 addr.sin_family = AF_INET;
2112 addr.sin_port = htons(port);
2113 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002114 wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002115 close(s);
2116 return -1;
2117 }
2118
2119 return s;
2120}
2121
2122
2123#ifdef CONFIG_IPV6
2124static int radius_server_open_socket6(int port)
2125{
2126 int s;
2127 struct sockaddr_in6 addr;
2128
2129 s = socket(PF_INET6, SOCK_DGRAM, 0);
2130 if (s < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002131 wpa_printf(MSG_INFO, "RADIUS: socket[IPv6]: %s",
2132 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002133 return -1;
2134 }
2135
2136 os_memset(&addr, 0, sizeof(addr));
2137 addr.sin6_family = AF_INET6;
2138 os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
2139 addr.sin6_port = htons(port);
2140 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002141 wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002142 close(s);
2143 return -1;
2144 }
2145
2146 return s;
2147}
2148#endif /* CONFIG_IPV6 */
2149
2150
2151static void radius_server_free_sessions(struct radius_server_data *data,
2152 struct radius_session *sessions)
2153{
2154 struct radius_session *session, *prev;
2155
2156 session = sessions;
2157 while (session) {
2158 prev = session;
2159 session = session->next;
2160 radius_server_session_free(data, prev);
2161 }
2162}
2163
2164
2165static void radius_server_free_clients(struct radius_server_data *data,
2166 struct radius_client *clients)
2167{
2168 struct radius_client *client, *prev;
2169
2170 client = clients;
2171 while (client) {
2172 prev = client;
2173 client = client->next;
2174
2175 radius_server_free_sessions(data, prev->sessions);
2176 os_free(prev->shared_secret);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002177 radius_msg_free(prev->pending_dac_coa_req);
2178 radius_msg_free(prev->pending_dac_disconnect_req);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002179 os_free(prev);
2180 }
2181}
2182
2183
2184static struct radius_client *
2185radius_server_read_clients(const char *client_file, int ipv6)
2186{
2187 FILE *f;
2188 const int buf_size = 1024;
2189 char *buf, *pos;
2190 struct radius_client *clients, *tail, *entry;
2191 int line = 0, mask, failed = 0, i;
2192 struct in_addr addr;
2193#ifdef CONFIG_IPV6
2194 struct in6_addr addr6;
2195#endif /* CONFIG_IPV6 */
2196 unsigned int val;
2197
2198 f = fopen(client_file, "r");
2199 if (f == NULL) {
2200 RADIUS_ERROR("Could not open client file '%s'", client_file);
2201 return NULL;
2202 }
2203
2204 buf = os_malloc(buf_size);
2205 if (buf == NULL) {
2206 fclose(f);
2207 return NULL;
2208 }
2209
2210 clients = tail = NULL;
2211 while (fgets(buf, buf_size, f)) {
2212 /* Configuration file format:
2213 * 192.168.1.0/24 secret
2214 * 192.168.1.2 secret
2215 * fe80::211:22ff:fe33:4455/64 secretipv6
2216 */
2217 line++;
2218 buf[buf_size - 1] = '\0';
2219 pos = buf;
2220 while (*pos != '\0' && *pos != '\n')
2221 pos++;
2222 if (*pos == '\n')
2223 *pos = '\0';
2224 if (*buf == '\0' || *buf == '#')
2225 continue;
2226
2227 pos = buf;
2228 while ((*pos >= '0' && *pos <= '9') || *pos == '.' ||
2229 (*pos >= 'a' && *pos <= 'f') || *pos == ':' ||
2230 (*pos >= 'A' && *pos <= 'F')) {
2231 pos++;
2232 }
2233
2234 if (*pos == '\0') {
2235 failed = 1;
2236 break;
2237 }
2238
2239 if (*pos == '/') {
2240 char *end;
2241 *pos++ = '\0';
2242 mask = strtol(pos, &end, 10);
2243 if ((pos == end) ||
2244 (mask < 0 || mask > (ipv6 ? 128 : 32))) {
2245 failed = 1;
2246 break;
2247 }
2248 pos = end;
2249 } else {
2250 mask = ipv6 ? 128 : 32;
2251 *pos++ = '\0';
2252 }
2253
2254 if (!ipv6 && inet_aton(buf, &addr) == 0) {
2255 failed = 1;
2256 break;
2257 }
2258#ifdef CONFIG_IPV6
2259 if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) {
2260 if (inet_pton(AF_INET, buf, &addr) <= 0) {
2261 failed = 1;
2262 break;
2263 }
2264 /* Convert IPv4 address to IPv6 */
2265 if (mask <= 32)
2266 mask += (128 - 32);
2267 os_memset(addr6.s6_addr, 0, 10);
2268 addr6.s6_addr[10] = 0xff;
2269 addr6.s6_addr[11] = 0xff;
2270 os_memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr,
2271 4);
2272 }
2273#endif /* CONFIG_IPV6 */
2274
2275 while (*pos == ' ' || *pos == '\t') {
2276 pos++;
2277 }
2278
2279 if (*pos == '\0') {
2280 failed = 1;
2281 break;
2282 }
2283
2284 entry = os_zalloc(sizeof(*entry));
2285 if (entry == NULL) {
2286 failed = 1;
2287 break;
2288 }
2289 entry->shared_secret = os_strdup(pos);
2290 if (entry->shared_secret == NULL) {
2291 failed = 1;
2292 os_free(entry);
2293 break;
2294 }
2295 entry->shared_secret_len = os_strlen(entry->shared_secret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002296 if (!ipv6) {
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08002297 entry->addr.s_addr = addr.s_addr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002298 val = 0;
2299 for (i = 0; i < mask; i++)
Hai Shalom021b0b52019-04-10 11:17:58 -07002300 val |= 1U << (31 - i);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002301 entry->mask.s_addr = htonl(val);
2302 }
2303#ifdef CONFIG_IPV6
2304 if (ipv6) {
2305 int offset = mask / 8;
2306
2307 os_memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16);
2308 os_memset(entry->mask6.s6_addr, 0xff, offset);
2309 val = 0;
2310 for (i = 0; i < (mask % 8); i++)
2311 val |= 1 << (7 - i);
2312 if (offset < 16)
2313 entry->mask6.s6_addr[offset] = val;
2314 }
2315#endif /* CONFIG_IPV6 */
2316
2317 if (tail == NULL) {
2318 clients = tail = entry;
2319 } else {
2320 tail->next = entry;
2321 tail = entry;
2322 }
2323 }
2324
2325 if (failed) {
2326 RADIUS_ERROR("Invalid line %d in '%s'", line, client_file);
2327 radius_server_free_clients(NULL, clients);
2328 clients = NULL;
2329 }
2330
2331 os_free(buf);
2332 fclose(f);
2333
2334 return clients;
2335}
2336
2337
2338/**
2339 * radius_server_init - Initialize RADIUS server
2340 * @conf: Configuration for the RADIUS server
2341 * Returns: Pointer to private RADIUS server context or %NULL on failure
2342 *
2343 * This initializes a RADIUS server instance and returns a context pointer that
2344 * will be used in other calls to the RADIUS server module. The server can be
2345 * deinitialize by calling radius_server_deinit().
2346 */
2347struct radius_server_data *
2348radius_server_init(struct radius_server_conf *conf)
2349{
2350 struct radius_server_data *data;
2351
2352#ifndef CONFIG_IPV6
2353 if (conf->ipv6) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002354 wpa_printf(MSG_ERROR, "RADIUS server compiled without IPv6 support");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002355 return NULL;
2356 }
2357#endif /* CONFIG_IPV6 */
2358
2359 data = os_zalloc(sizeof(*data));
2360 if (data == NULL)
2361 return NULL;
2362
Hai Shalom81f62d82019-07-22 12:10:00 -07002363 data->auth_sock = -1;
2364 data->acct_sock = -1;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002365 dl_list_init(&data->erp_keys);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002366 os_get_reltime(&data->start_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002367 data->conf_ctx = conf->conf_ctx;
2368 data->eap_sim_db_priv = conf->eap_sim_db_priv;
2369 data->ssl_ctx = conf->ssl_ctx;
2370 data->msg_ctx = conf->msg_ctx;
2371 data->ipv6 = conf->ipv6;
2372 if (conf->pac_opaque_encr_key) {
2373 data->pac_opaque_encr_key = os_malloc(16);
Dmitry Shmidt41712582015-06-29 11:02:15 -07002374 if (data->pac_opaque_encr_key) {
2375 os_memcpy(data->pac_opaque_encr_key,
2376 conf->pac_opaque_encr_key, 16);
2377 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002378 }
2379 if (conf->eap_fast_a_id) {
2380 data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
2381 if (data->eap_fast_a_id) {
2382 os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id,
2383 conf->eap_fast_a_id_len);
2384 data->eap_fast_a_id_len = conf->eap_fast_a_id_len;
2385 }
2386 }
2387 if (conf->eap_fast_a_id_info)
2388 data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
2389 data->eap_fast_prov = conf->eap_fast_prov;
2390 data->pac_key_lifetime = conf->pac_key_lifetime;
2391 data->pac_key_refresh_time = conf->pac_key_refresh_time;
Hai Shalom81f62d82019-07-22 12:10:00 -07002392 data->eap_teap_auth = conf->eap_teap_auth;
2393 data->eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002394 data->get_eap_user = conf->get_eap_user;
2395 data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
2396 data->tnc = conf->tnc;
2397 data->wps = conf->wps;
2398 data->pwd_group = conf->pwd_group;
Dmitry Shmidt34af3062013-07-11 10:46:32 -07002399 data->server_id = conf->server_id;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002400 if (conf->eap_req_id_text) {
2401 data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
2402 if (data->eap_req_id_text) {
2403 os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
2404 conf->eap_req_id_text_len);
2405 data->eap_req_id_text_len = conf->eap_req_id_text_len;
2406 }
2407 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002408 data->erp = conf->erp;
2409 data->erp_domain = conf->erp_domain;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002410 data->tls_session_lifetime = conf->tls_session_lifetime;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002411 data->tls_flags = conf->tls_flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002412
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002413 if (conf->subscr_remediation_url) {
2414 data->subscr_remediation_url =
2415 os_strdup(conf->subscr_remediation_url);
2416 }
Dmitry Shmidt71757432014-06-02 13:50:35 -07002417 data->subscr_remediation_method = conf->subscr_remediation_method;
Hai Shalom74f70d42019-02-11 14:42:39 -08002418 if (conf->hs20_sim_provisioning_url)
2419 data->hs20_sim_provisioning_url =
2420 os_strdup(conf->hs20_sim_provisioning_url);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002421
Roshan Pius3a1667e2018-07-03 15:17:14 -07002422 if (conf->t_c_server_url)
2423 data->t_c_server_url = os_strdup(conf->t_c_server_url);
2424
Dmitry Shmidt818ea482014-03-10 13:15:21 -07002425#ifdef CONFIG_SQLITE
2426 if (conf->sqlite_file) {
2427 if (sqlite3_open(conf->sqlite_file, &data->db)) {
2428 RADIUS_ERROR("Could not open SQLite file '%s'",
2429 conf->sqlite_file);
2430 radius_server_deinit(data);
2431 return NULL;
2432 }
2433 }
2434#endif /* CONFIG_SQLITE */
2435
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002436#ifdef CONFIG_RADIUS_TEST
2437 if (conf->dump_msk_file)
2438 data->dump_msk_file = os_strdup(conf->dump_msk_file);
2439#endif /* CONFIG_RADIUS_TEST */
2440
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002441 data->clients = radius_server_read_clients(conf->client_file,
2442 conf->ipv6);
2443 if (data->clients == NULL) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002444 wpa_printf(MSG_ERROR, "No RADIUS clients configured");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002445 radius_server_deinit(data);
2446 return NULL;
2447 }
2448
2449#ifdef CONFIG_IPV6
2450 if (conf->ipv6)
2451 data->auth_sock = radius_server_open_socket6(conf->auth_port);
2452 else
2453#endif /* CONFIG_IPV6 */
2454 data->auth_sock = radius_server_open_socket(conf->auth_port);
2455 if (data->auth_sock < 0) {
Dmitry Shmidtcce06662013-11-04 18:44:24 -08002456 wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002457 radius_server_deinit(data);
2458 return NULL;
2459 }
2460 if (eloop_register_read_sock(data->auth_sock,
2461 radius_server_receive_auth,
2462 data, NULL)) {
2463 radius_server_deinit(data);
2464 return NULL;
2465 }
2466
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08002467 if (conf->acct_port) {
2468#ifdef CONFIG_IPV6
2469 if (conf->ipv6)
2470 data->acct_sock = radius_server_open_socket6(
2471 conf->acct_port);
2472 else
2473#endif /* CONFIG_IPV6 */
2474 data->acct_sock = radius_server_open_socket(conf->acct_port);
2475 if (data->acct_sock < 0) {
2476 wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server");
2477 radius_server_deinit(data);
2478 return NULL;
2479 }
2480 if (eloop_register_read_sock(data->acct_sock,
2481 radius_server_receive_acct,
2482 data, NULL)) {
2483 radius_server_deinit(data);
2484 return NULL;
2485 }
2486 } else {
2487 data->acct_sock = -1;
2488 }
2489
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002490 return data;
2491}
2492
2493
2494/**
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002495 * radius_server_erp_flush - Flush all ERP keys
2496 * @data: RADIUS server context from radius_server_init()
2497 */
2498void radius_server_erp_flush(struct radius_server_data *data)
2499{
2500 struct eap_server_erp_key *erp;
2501
2502 if (data == NULL)
2503 return;
2504 while ((erp = dl_list_first(&data->erp_keys, struct eap_server_erp_key,
2505 list)) != NULL) {
2506 dl_list_del(&erp->list);
2507 bin_clear_free(erp, sizeof(*erp));
2508 }
2509}
2510
2511
2512/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002513 * radius_server_deinit - Deinitialize RADIUS server
2514 * @data: RADIUS server context from radius_server_init()
2515 */
2516void radius_server_deinit(struct radius_server_data *data)
2517{
2518 if (data == NULL)
2519 return;
2520
2521 if (data->auth_sock >= 0) {
2522 eloop_unregister_read_sock(data->auth_sock);
2523 close(data->auth_sock);
2524 }
2525
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08002526 if (data->acct_sock >= 0) {
2527 eloop_unregister_read_sock(data->acct_sock);
2528 close(data->acct_sock);
2529 }
2530
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002531 radius_server_free_clients(data, data->clients);
2532
2533 os_free(data->pac_opaque_encr_key);
2534 os_free(data->eap_fast_a_id);
2535 os_free(data->eap_fast_a_id_info);
2536 os_free(data->eap_req_id_text);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002537#ifdef CONFIG_RADIUS_TEST
2538 os_free(data->dump_msk_file);
2539#endif /* CONFIG_RADIUS_TEST */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002540 os_free(data->subscr_remediation_url);
Hai Shalom74f70d42019-02-11 14:42:39 -08002541 os_free(data->hs20_sim_provisioning_url);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002542 os_free(data->t_c_server_url);
Dmitry Shmidt818ea482014-03-10 13:15:21 -07002543
2544#ifdef CONFIG_SQLITE
2545 if (data->db)
2546 sqlite3_close(data->db);
2547#endif /* CONFIG_SQLITE */
2548
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002549 radius_server_erp_flush(data);
2550
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002551 os_free(data);
2552}
2553
2554
2555/**
2556 * radius_server_get_mib - Get RADIUS server MIB information
2557 * @data: RADIUS server context from radius_server_init()
2558 * @buf: Buffer for returning the MIB data in text format
2559 * @buflen: buf length in octets
2560 * Returns: Number of octets written into buf
2561 */
2562int radius_server_get_mib(struct radius_server_data *data, char *buf,
2563 size_t buflen)
2564{
2565 int ret, uptime;
2566 unsigned int idx;
2567 char *end, *pos;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002568 struct os_reltime now;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002569 struct radius_client *cli;
2570
2571 /* RFC 2619 - RADIUS Authentication Server MIB */
2572
2573 if (data == NULL || buflen == 0)
2574 return 0;
2575
2576 pos = buf;
2577 end = buf + buflen;
2578
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08002579 os_get_reltime(&now);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002580 uptime = (now.sec - data->start_time.sec) * 100 +
2581 ((now.usec - data->start_time.usec) / 10000) % 100;
2582 ret = os_snprintf(pos, end - pos,
2583 "RADIUS-AUTH-SERVER-MIB\n"
2584 "radiusAuthServIdent=hostapd\n"
2585 "radiusAuthServUpTime=%d\n"
2586 "radiusAuthServResetTime=0\n"
2587 "radiusAuthServConfigReset=4\n",
2588 uptime);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002589 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002590 *pos = '\0';
2591 return pos - buf;
2592 }
2593 pos += ret;
2594
2595 ret = os_snprintf(pos, end - pos,
2596 "radiusAuthServTotalAccessRequests=%u\n"
2597 "radiusAuthServTotalInvalidRequests=%u\n"
2598 "radiusAuthServTotalDupAccessRequests=%u\n"
2599 "radiusAuthServTotalAccessAccepts=%u\n"
2600 "radiusAuthServTotalAccessRejects=%u\n"
2601 "radiusAuthServTotalAccessChallenges=%u\n"
2602 "radiusAuthServTotalMalformedAccessRequests=%u\n"
2603 "radiusAuthServTotalBadAuthenticators=%u\n"
2604 "radiusAuthServTotalPacketsDropped=%u\n"
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08002605 "radiusAuthServTotalUnknownTypes=%u\n"
2606 "radiusAccServTotalRequests=%u\n"
2607 "radiusAccServTotalInvalidRequests=%u\n"
2608 "radiusAccServTotalResponses=%u\n"
2609 "radiusAccServTotalMalformedRequests=%u\n"
2610 "radiusAccServTotalBadAuthenticators=%u\n"
2611 "radiusAccServTotalUnknownTypes=%u\n",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002612 data->counters.access_requests,
2613 data->counters.invalid_requests,
2614 data->counters.dup_access_requests,
2615 data->counters.access_accepts,
2616 data->counters.access_rejects,
2617 data->counters.access_challenges,
2618 data->counters.malformed_access_requests,
2619 data->counters.bad_authenticators,
2620 data->counters.packets_dropped,
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08002621 data->counters.unknown_types,
2622 data->counters.acct_requests,
2623 data->counters.invalid_acct_requests,
2624 data->counters.acct_responses,
2625 data->counters.malformed_acct_requests,
2626 data->counters.acct_bad_authenticators,
2627 data->counters.unknown_acct_types);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002628 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002629 *pos = '\0';
2630 return pos - buf;
2631 }
2632 pos += ret;
2633
2634 for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) {
2635 char abuf[50], mbuf[50];
2636#ifdef CONFIG_IPV6
2637 if (data->ipv6) {
2638 if (inet_ntop(AF_INET6, &cli->addr6, abuf,
2639 sizeof(abuf)) == NULL)
2640 abuf[0] = '\0';
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07002641 if (inet_ntop(AF_INET6, &cli->mask6, mbuf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002642 sizeof(mbuf)) == NULL)
2643 mbuf[0] = '\0';
2644 }
2645#endif /* CONFIG_IPV6 */
2646 if (!data->ipv6) {
2647 os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf));
2648 os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf));
2649 }
2650
2651 ret = os_snprintf(pos, end - pos,
2652 "radiusAuthClientIndex=%u\n"
2653 "radiusAuthClientAddress=%s/%s\n"
2654 "radiusAuthServAccessRequests=%u\n"
2655 "radiusAuthServDupAccessRequests=%u\n"
2656 "radiusAuthServAccessAccepts=%u\n"
2657 "radiusAuthServAccessRejects=%u\n"
2658 "radiusAuthServAccessChallenges=%u\n"
2659 "radiusAuthServMalformedAccessRequests=%u\n"
2660 "radiusAuthServBadAuthenticators=%u\n"
2661 "radiusAuthServPacketsDropped=%u\n"
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08002662 "radiusAuthServUnknownTypes=%u\n"
2663 "radiusAccServTotalRequests=%u\n"
2664 "radiusAccServTotalInvalidRequests=%u\n"
2665 "radiusAccServTotalResponses=%u\n"
2666 "radiusAccServTotalMalformedRequests=%u\n"
2667 "radiusAccServTotalBadAuthenticators=%u\n"
2668 "radiusAccServTotalUnknownTypes=%u\n",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002669 idx,
2670 abuf, mbuf,
2671 cli->counters.access_requests,
2672 cli->counters.dup_access_requests,
2673 cli->counters.access_accepts,
2674 cli->counters.access_rejects,
2675 cli->counters.access_challenges,
2676 cli->counters.malformed_access_requests,
2677 cli->counters.bad_authenticators,
2678 cli->counters.packets_dropped,
Dmitry Shmidtbd14a572014-02-18 10:33:49 -08002679 cli->counters.unknown_types,
2680 cli->counters.acct_requests,
2681 cli->counters.invalid_acct_requests,
2682 cli->counters.acct_responses,
2683 cli->counters.malformed_acct_requests,
2684 cli->counters.acct_bad_authenticators,
2685 cli->counters.unknown_acct_types);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002686 if (os_snprintf_error(end - pos, ret)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002687 *pos = '\0';
2688 return pos - buf;
2689 }
2690 pos += ret;
2691 }
2692
2693 return pos - buf;
2694}
2695
2696
2697static int radius_server_get_eap_user(void *ctx, const u8 *identity,
2698 size_t identity_len, int phase2,
2699 struct eap_user *user)
2700{
2701 struct radius_session *sess = ctx;
2702 struct radius_server_data *data = sess->server;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002703 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002704
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002705 ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
2706 phase2, user);
Dmitry Shmidt818ea482014-03-10 13:15:21 -07002707 if (ret == 0 && user) {
2708 sess->accept_attr = user->accept_attr;
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002709 sess->remediation = user->remediation;
Dmitry Shmidtdf5a7e42014-04-02 12:59:59 -07002710 sess->macacl = user->macacl;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002711 sess->t_c_timestamp = user->t_c_timestamp;
Dmitry Shmidt818ea482014-03-10 13:15:21 -07002712 }
Dmitry Shmidt912c6ec2015-03-30 13:16:51 -07002713
2714 if (ret) {
2715 RADIUS_DEBUG("%s: User-Name not found from user database",
2716 __func__);
2717 }
2718
Dmitry Shmidtf21452a2014-02-26 10:55:25 -08002719 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002720}
2721
2722
2723static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len)
2724{
2725 struct radius_session *sess = ctx;
2726 struct radius_server_data *data = sess->server;
2727 *len = data->eap_req_id_text_len;
2728 return data->eap_req_id_text;
2729}
2730
2731
Dmitry Shmidt818ea482014-03-10 13:15:21 -07002732static void radius_server_log_msg(void *ctx, const char *msg)
2733{
2734 struct radius_session *sess = ctx;
2735 srv_log(sess, "EAP: %s", msg);
2736}
2737
2738
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002739#ifdef CONFIG_ERP
2740
2741static const char * radius_server_get_erp_domain(void *ctx)
2742{
2743 struct radius_session *sess = ctx;
2744 struct radius_server_data *data = sess->server;
2745
2746 return data->erp_domain;
2747}
2748
2749
2750static struct eap_server_erp_key *
2751radius_server_erp_get_key(void *ctx, const char *keyname)
2752{
2753 struct radius_session *sess = ctx;
2754 struct radius_server_data *data = sess->server;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002755
Hai Shalom021b0b52019-04-10 11:17:58 -07002756 return radius_server_erp_find_key(data, keyname);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002757}
2758
2759
2760static int radius_server_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
2761{
2762 struct radius_session *sess = ctx;
2763 struct radius_server_data *data = sess->server;
2764
2765 dl_list_add(&data->erp_keys, &erp->list);
2766 return 0;
2767}
2768
2769#endif /* CONFIG_ERP */
2770
2771
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07002772static const struct eapol_callbacks radius_server_eapol_cb =
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002773{
2774 .get_eap_user = radius_server_get_eap_user,
2775 .get_eap_req_id_text = radius_server_get_eap_req_id_text,
Dmitry Shmidt818ea482014-03-10 13:15:21 -07002776 .log_msg = radius_server_log_msg,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002777#ifdef CONFIG_ERP
2778 .get_erp_send_reauth_start = NULL,
2779 .get_erp_domain = radius_server_get_erp_domain,
2780 .erp_get_key = radius_server_erp_get_key,
2781 .erp_add_key = radius_server_erp_add_key,
2782#endif /* CONFIG_ERP */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002783};
2784
2785
2786/**
2787 * radius_server_eap_pending_cb - Pending EAP data notification
2788 * @data: RADIUS server context from radius_server_init()
2789 * @ctx: Pending EAP context pointer
2790 *
2791 * This function is used to notify EAP server module that a pending operation
2792 * has been completed and processing of the EAP session can proceed.
2793 */
2794void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
2795{
2796 struct radius_client *cli;
2797 struct radius_session *s, *sess = NULL;
2798 struct radius_msg *msg;
2799
2800 if (data == NULL)
2801 return;
2802
2803 for (cli = data->clients; cli; cli = cli->next) {
2804 for (s = cli->sessions; s; s = s->next) {
2805 if (s->eap == ctx && s->last_msg) {
2806 sess = s;
2807 break;
2808 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002809 }
2810 if (sess)
2811 break;
2812 }
2813
2814 if (sess == NULL) {
2815 RADIUS_DEBUG("No session matched callback ctx");
2816 return;
2817 }
2818
2819 msg = sess->last_msg;
2820 sess->last_msg = NULL;
2821 eap_sm_pending_cb(sess->eap);
2822 if (radius_server_request(data, msg,
2823 (struct sockaddr *) &sess->last_from,
2824 sess->last_fromlen, cli,
2825 sess->last_from_addr,
2826 sess->last_from_port, sess) == -2)
2827 return; /* msg was stored with the session */
2828
2829 radius_msg_free(msg);
2830}
Roshan Pius3a1667e2018-07-03 15:17:14 -07002831
2832
2833#ifdef CONFIG_SQLITE
2834
2835struct db_session_fields {
2836 char *identity;
2837 char *nas;
2838 int hs20_t_c_filtering;
2839 int waiting_coa_ack;
2840 int coa_ack_received;
2841};
2842
2843
2844static int get_db_session_fields(void *ctx, int argc, char *argv[], char *col[])
2845{
2846 struct db_session_fields *fields = ctx;
2847 int i;
2848
2849 for (i = 0; i < argc; i++) {
2850 if (!argv[i])
2851 continue;
2852
2853 RADIUS_DEBUG("Session DB: %s=%s", col[i], argv[i]);
2854
2855 if (os_strcmp(col[i], "identity") == 0) {
2856 os_free(fields->identity);
2857 fields->identity = os_strdup(argv[i]);
2858 } else if (os_strcmp(col[i], "nas") == 0) {
2859 os_free(fields->nas);
2860 fields->nas = os_strdup(argv[i]);
2861 } else if (os_strcmp(col[i], "hs20_t_c_filtering") == 0) {
2862 fields->hs20_t_c_filtering = atoi(argv[i]);
2863 } else if (os_strcmp(col[i], "waiting_coa_ack") == 0) {
2864 fields->waiting_coa_ack = atoi(argv[i]);
2865 } else if (os_strcmp(col[i], "coa_ack_received") == 0) {
2866 fields->coa_ack_received = atoi(argv[i]);
2867 }
2868 }
2869
2870 return 0;
2871}
2872
2873
2874static void free_db_session_fields(struct db_session_fields *fields)
2875{
2876 os_free(fields->identity);
2877 fields->identity = NULL;
2878 os_free(fields->nas);
2879 fields->nas = NULL;
2880}
2881
2882#endif /* CONFIG_SQLITE */
2883
2884
2885int radius_server_dac_request(struct radius_server_data *data, const char *req)
2886{
2887#ifdef CONFIG_SQLITE
2888 char *sql;
2889 int res;
2890 int disconnect;
2891 const char *pos = req;
2892 u8 addr[ETH_ALEN];
2893 char addrtxt[3 * ETH_ALEN];
2894 int t_c_clear = 0;
2895 struct db_session_fields fields;
2896 struct sockaddr_in das;
2897 struct radius_client *client;
2898 struct radius_msg *msg;
2899 struct wpabuf *buf;
2900 u8 identifier;
2901 struct os_time now;
2902
2903 if (!data)
2904 return -1;
2905
2906 /* req: <disconnect|coa> <MAC Address> [t_c_clear] */
2907
2908 if (os_strncmp(pos, "disconnect ", 11) == 0) {
2909 disconnect = 1;
2910 pos += 11;
2911 } else if (os_strncmp(req, "coa ", 4) == 0) {
2912 disconnect = 0;
2913 pos += 4;
2914 } else {
2915 return -1;
2916 }
2917
2918 if (hwaddr_aton(pos, addr))
2919 return -1;
2920 pos = os_strchr(pos, ' ');
2921 if (pos) {
2922 if (os_strstr(pos, "t_c_clear"))
2923 t_c_clear = 1;
2924 }
2925
2926 if (!disconnect && !t_c_clear) {
2927 RADIUS_ERROR("DAC request for CoA without any authorization change");
2928 return -1;
2929 }
2930
2931 if (!data->db) {
2932 RADIUS_ERROR("SQLite database not in use");
2933 return -1;
2934 }
2935
2936 os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(addr));
2937
2938 sql = sqlite3_mprintf("SELECT * FROM current_sessions WHERE mac_addr=%Q",
2939 addrtxt);
2940 if (!sql)
2941 return -1;
2942
2943 os_memset(&fields, 0, sizeof(fields));
2944 res = sqlite3_exec(data->db, sql, get_db_session_fields, &fields, NULL);
2945 sqlite3_free(sql);
2946 if (res != SQLITE_OK) {
2947 RADIUS_ERROR("Failed to find matching current_sessions entry from sqlite database: %s",
2948 sqlite3_errmsg(data->db));
2949 free_db_session_fields(&fields);
2950 return -1;
2951 }
2952
2953 if (!fields.nas) {
2954 RADIUS_ERROR("No NAS information found from current_sessions");
2955 free_db_session_fields(&fields);
2956 return -1;
2957 }
2958
2959 os_memset(&das, 0, sizeof(das));
2960 das.sin_family = AF_INET;
2961 das.sin_addr.s_addr = inet_addr(fields.nas);
2962 das.sin_port = htons(3799);
2963
2964 free_db_session_fields(&fields);
2965
2966 client = radius_server_get_client(data, &das.sin_addr, 0);
2967 if (!client) {
2968 RADIUS_ERROR("No NAS information available to protect the packet");
2969 return -1;
2970 }
2971
2972 identifier = client->next_dac_identifier++;
2973
2974 msg = radius_msg_new(disconnect ? RADIUS_CODE_DISCONNECT_REQUEST :
2975 RADIUS_CODE_COA_REQUEST, identifier);
2976 if (!msg)
2977 return -1;
2978
2979 os_snprintf(addrtxt, sizeof(addrtxt), RADIUS_802_1X_ADDR_FORMAT,
2980 MAC2STR(addr));
2981 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
2982 (u8 *) addrtxt, os_strlen(addrtxt))) {
2983 RADIUS_ERROR("Could not add Calling-Station-Id");
2984 radius_msg_free(msg);
2985 return -1;
2986 }
2987
2988 if (!disconnect && t_c_clear) {
2989 u8 val[4] = { 0x00, 0x00, 0x00, 0x00 }; /* E=0 */
2990
2991 if (!radius_msg_add_wfa(
2992 msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING,
2993 val, sizeof(val))) {
2994 RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering");
2995 radius_msg_free(msg);
2996 return -1;
2997 }
2998 }
2999
3000 os_get_time(&now);
3001 if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
3002 now.sec)) {
3003 RADIUS_ERROR("Failed to add Event-Timestamp attribute");
3004 radius_msg_free(msg);
3005 return -1;
3006 }
3007
3008 radius_msg_finish_acct(msg, (u8 *) client->shared_secret,
3009 client->shared_secret_len);
3010
3011 if (wpa_debug_level <= MSG_MSGDUMP)
3012 radius_msg_dump(msg);
3013
3014 buf = radius_msg_get_buf(msg);
3015 if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0,
3016 (struct sockaddr *) &das, sizeof(das)) < 0) {
3017 RADIUS_ERROR("Failed to send packet - sendto: %s",
3018 strerror(errno));
3019 radius_msg_free(msg);
3020 return -1;
3021 }
3022
3023 if (disconnect) {
3024 radius_msg_free(client->pending_dac_disconnect_req);
3025 client->pending_dac_disconnect_req = msg;
3026 client->pending_dac_disconnect_id = identifier;
3027 os_memcpy(client->pending_dac_disconnect_addr, addr, ETH_ALEN);
3028 } else {
3029 radius_msg_free(client->pending_dac_coa_req);
3030 client->pending_dac_coa_req = msg;
3031 client->pending_dac_coa_id = identifier;
3032 os_memcpy(client->pending_dac_coa_addr, addr, ETH_ALEN);
3033 }
3034
3035 return 0;
3036#else /* CONFIG_SQLITE */
3037 return -1;
3038#endif /* CONFIG_SQLITE */
3039}