⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 radius_server.c

📁 IEEE802.11 a/b/g 客户端应用程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * hostapd / RADIUS authentication server * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include <net/if.h>#include "common.h"#include "radius.h"#include "eloop.h"#include "defs.h"#include "eap_server/eap.h"#include "radius_server.h"#define RADIUS_SESSION_TIMEOUT 60#define RADIUS_MAX_SESSION 100#define RADIUS_MAX_MSG_LEN 3000static struct eapol_callbacks radius_server_eapol_cb;struct radius_client;struct radius_server_data;struct radius_server_counters {	u32 access_requests;	u32 invalid_requests;	u32 dup_access_requests;	u32 access_accepts;	u32 access_rejects;	u32 access_challenges;	u32 malformed_access_requests;	u32 bad_authenticators;	u32 packets_dropped;	u32 unknown_types;};struct radius_session {	struct radius_session *next;	struct radius_client *client;	struct radius_server_data *server;	unsigned int sess_id;	struct eap_sm *eap;	struct eap_eapol_interface *eap_if;	struct radius_msg *last_msg;	char *last_from_addr;	int last_from_port;	struct sockaddr_storage last_from;	socklen_t last_fromlen;	u8 last_identifier;	struct radius_msg *last_reply;	u8 last_authenticator[16];};struct radius_client {	struct radius_client *next;	struct in_addr addr;	struct in_addr mask;#ifdef CONFIG_IPV6	struct in6_addr addr6;	struct in6_addr mask6;#endif /* CONFIG_IPV6 */	char *shared_secret;	int shared_secret_len;	struct radius_session *sessions;	struct radius_server_counters counters;};struct radius_server_data {	int auth_sock;	struct radius_client *clients;	unsigned int next_sess_id;	void *conf_ctx;	int num_sess;	void *eap_sim_db_priv;	void *ssl_ctx;	u8 *pac_opaque_encr_key;	char *eap_fast_a_id;	int eap_sim_aka_result_ind;	int tnc;	int ipv6;	struct os_time start_time;	struct radius_server_counters counters;	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,			    int phase2, struct eap_user *user);};extern int wpa_debug_level;#define RADIUS_DEBUG(args...) \wpa_printf(MSG_DEBUG, "RADIUS SRV: " args)#define RADIUS_ERROR(args...) \wpa_printf(MSG_ERROR, "RADIUS SRV: " args)#define RADIUS_DUMP(args...) \wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args)#define RADIUS_DUMP_ASCII(args...) \wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args)static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);static struct radius_client *radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,			 int ipv6){	struct radius_client *client = data->clients;	while (client) {#ifdef CONFIG_IPV6		if (ipv6) {			struct in6_addr *addr6;			int i;			addr6 = (struct in6_addr *) addr;			for (i = 0; i < 16; i++) {				if ((addr6->s6_addr[i] &				     client->mask6.s6_addr[i]) !=				    (client->addr6.s6_addr[i] &				     client->mask6.s6_addr[i])) {					i = 17;					break;				}			}			if (i == 16) {				break;			}		}#endif /* CONFIG_IPV6 */		if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) ==		    (addr->s_addr & client->mask.s_addr)) {			break;		}		client = client->next;	}	return client;}static struct radius_session *radius_server_get_session(struct radius_client *client, unsigned int sess_id){	struct radius_session *sess = client->sessions;	while (sess) {		if (sess->sess_id == sess_id) {			break;		}		sess = sess->next;	}	return sess;}static void radius_server_session_free(struct radius_server_data *data,				       struct radius_session *sess){	eloop_cancel_timeout(radius_server_session_timeout, data, sess);	eap_server_sm_deinit(sess->eap);	if (sess->last_msg) {		radius_msg_free(sess->last_msg);		os_free(sess->last_msg);	}	os_free(sess->last_from_addr);	if (sess->last_reply) {		radius_msg_free(sess->last_reply);		os_free(sess->last_reply);	}	os_free(sess);	data->num_sess--;}static void radius_server_session_remove_timeout(void *eloop_ctx,						 void *timeout_ctx);static void radius_server_session_remove(struct radius_server_data *data,					 struct radius_session *sess){	struct radius_client *client = sess->client;	struct radius_session *session, *prev;	eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);	prev = NULL;	session = client->sessions;	while (session) {		if (session == sess) {			if (prev == NULL) {				client->sessions = sess->next;			} else {				prev->next = sess->next;			}			radius_server_session_free(data, sess);			break;		}		prev = session;		session = session->next;	}}static void radius_server_session_remove_timeout(void *eloop_ctx,						 void *timeout_ctx){	struct radius_server_data *data = eloop_ctx;	struct radius_session *sess = timeout_ctx;	RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);	radius_server_session_remove(data, sess);}static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx){	struct radius_server_data *data = eloop_ctx;	struct radius_session *sess = timeout_ctx;	RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id);	radius_server_session_remove(data, sess);}static struct radius_session *radius_server_new_session(struct radius_server_data *data,			  struct radius_client *client){	struct radius_session *sess;	if (data->num_sess >= RADIUS_MAX_SESSION) {		RADIUS_DEBUG("Maximum number of existing session - no room "			     "for a new session");		return NULL;	}	sess = os_zalloc(sizeof(*sess));	if (sess == NULL)		return NULL;	sess->server = data;	sess->client = client;	sess->sess_id = data->next_sess_id++;	sess->next = client->sessions;	client->sessions = sess;	eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0,			       radius_server_session_timeout, data, sess);	data->num_sess++;	return sess;}static struct radius_session *radius_server_get_new_session(struct radius_server_data *data,			      struct radius_client *client,			      struct radius_msg *msg){	u8 *user;	size_t user_len;	int res;	struct radius_session *sess;	struct eap_config eap_conf;	RADIUS_DEBUG("Creating a new session");	user = os_malloc(256);	if (user == NULL) {		return NULL;	}	res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256);	if (res < 0 || res > 256) {		RADIUS_DEBUG("Could not get User-Name");		os_free(user);		return NULL;	}	user_len = res;	RADIUS_DUMP_ASCII("User-Name", user, user_len);	res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL);	os_free(user);	if (res == 0) {		RADIUS_DEBUG("Matching user entry found");		sess = radius_server_new_session(data, client);		if (sess == NULL) {			RADIUS_DEBUG("Failed to create a new session");			return NULL;		}	} else {		RADIUS_DEBUG("User-Name not found from user database");		return NULL;	}	os_memset(&eap_conf, 0, sizeof(eap_conf));	eap_conf.ssl_ctx = data->ssl_ctx;	eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;	eap_conf.backend_auth = TRUE;	eap_conf.eap_server = 1;	eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;	eap_conf.eap_fast_a_id = data->eap_fast_a_id;	eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;	eap_conf.tnc = data->tnc;	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,				       &eap_conf);	if (sess->eap == NULL) {		RADIUS_DEBUG("Failed to initialize EAP state machine for the "			     "new session");		radius_server_session_free(data, sess);		return NULL;	}	sess->eap_if = eap_get_interface(sess->eap);	sess->eap_if->eapRestart = TRUE;	sess->eap_if->portEnabled = TRUE;	RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);	return sess;}static struct radius_msg *radius_server_encapsulate_eap(struct radius_server_data *data,			      struct radius_client *client,			      struct radius_session *sess,			      struct radius_msg *request){	struct radius_msg *msg;	int code;	unsigned int sess_id;	if (sess->eap_if->eapFail) {		sess->eap_if->eapFail = FALSE;		code = RADIUS_CODE_ACCESS_REJECT;	} else if (sess->eap_if->eapSuccess) {		sess->eap_if->eapSuccess = FALSE;		code = RADIUS_CODE_ACCESS_ACCEPT;	} else {		sess->eap_if->eapReq = FALSE;		code = RADIUS_CODE_ACCESS_CHALLENGE;	}	msg = radius_msg_new(code, request->hdr->identifier);	if (msg == NULL) {		RADIUS_DEBUG("Failed to allocate reply message");		return NULL;	}	sess_id = htonl(sess->sess_id);	if (code == RADIUS_CODE_ACCESS_CHALLENGE &&	    !radius_msg_add_attr(msg, RADIUS_ATTR_STATE,				 (u8 *) &sess_id, sizeof(sess_id))) {		RADIUS_DEBUG("Failed to add State attribute");	}	if (sess->eap_if->eapReqData &&	    !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData),				wpabuf_len(sess->eap_if->eapReqData))) {		RADIUS_DEBUG("Failed to add EAP-Message attribute");	}	if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {		int len;		if (sess->eap_if->eapKeyDataLen > 64) {			len = 32;		} else {			len = sess->eap_if->eapKeyDataLen / 2;		}		if (!radius_msg_add_mppe_keys(msg, request->hdr->authenticator,					      (u8 *) client->shared_secret,					      client->shared_secret_len,					      sess->eap_if->eapKeyData + len,					      len, sess->eap_if->eapKeyData,					      len)) {			RADIUS_DEBUG("Failed to add MPPE key attributes");		}	}	if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {		RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");		radius_msg_free(msg);		os_free(msg);		return NULL;	}	if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,				  client->shared_secret_len,				  request->hdr->authenticator) < 0) {		RADIUS_DEBUG("Failed to add Message-Authenticator attribute");	}	return msg;}static int radius_server_reject(struct radius_server_data *data,				struct radius_client *client,				struct radius_msg *request,				struct sockaddr *from, socklen_t fromlen,				const char *from_addr, int from_port){	struct radius_msg *msg;	int ret = 0;	struct eap_hdr eapfail;	RADIUS_DEBUG("Reject invalid request from %s:%d",		     from_addr, from_port);	msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT,			     request->hdr->identifier);	if (msg == NULL) {		return -1;	}	os_memset(&eapfail, 0, sizeof(eapfail));	eapfail.code = EAP_CODE_FAILURE;	eapfail.identifier = 0;	eapfail.length = host_to_be16(sizeof(eapfail));	if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) {		RADIUS_DEBUG("Failed to add EAP-Message attribute");	}	if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {		RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");		radius_msg_free(msg);		os_free(msg);		return -1;	}	if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,				  client->shared_secret_len,				  request->hdr->authenticator) < 0) {		RADIUS_DEBUG("Failed to add Message-Authenticator attribute");	}	if (wpa_debug_level <= MSG_MSGDUMP) {		radius_msg_dump(msg);	}	data->counters.access_rejects++;	client->counters.access_rejects++;	if (sendto(data->auth_sock, msg->buf, msg->buf_used, 0,		   (struct sockaddr *) from, sizeof(*from)) < 0) {		perror("sendto[RADIUS SRV]");		ret = -1;	}	radius_msg_free(msg);	os_free(msg);	return ret;}static int radius_server_request(struct radius_server_data *data,				 struct radius_msg *msg,				 struct sockaddr *from, socklen_t fromlen,				 struct radius_client *client,				 const char *from_addr, int from_port,				 struct radius_session *force_sess){	u8 *eap = NULL;	size_t eap_len;	int res, state_included = 0;	u8 statebuf[4];	unsigned int state;	struct radius_session *sess;	struct radius_msg *reply;	if (force_sess)		sess = force_sess;	else {		res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,					  sizeof(statebuf));		state_included = res >= 0;		if (res == sizeof(statebuf)) {			state = WPA_GET_BE32(statebuf);			sess = radius_server_get_session(client, state);		} else {			sess = NULL;		}	}	if (sess) {		RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);	} else if (state_included) {		RADIUS_DEBUG("State attribute included but no session found");		radius_server_reject(data, client, msg, from, fromlen,				     from_addr, from_port);		return -1;	} else {		sess = radius_server_get_new_session(data, client, msg);		if (sess == NULL) {			RADIUS_DEBUG("Could not create a new session");			radius_server_reject(data, client, msg, from, fromlen,					     from_addr, from_port);			return -1;		}	}	if (sess->last_from_port == from_port &&	    sess->last_identifier == msg->hdr->identifier &&	    os_memcmp(sess->last_authenticator, msg->hdr->authenticator, 16) ==	    0) {		RADIUS_DEBUG("Duplicate message from %s", from_addr);		data->counters.dup_access_requests++;		client->counters.dup_access_requests++;		if (sess->last_reply) {			res = sendto(data->auth_sock, sess->last_reply->buf,				     sess->last_reply->buf_used, 0,				     (struct sockaddr *) from, fromlen);			if (res < 0) {				perror("sendto[RADIUS SRV]");			}			return 0;		}		RADIUS_DEBUG("No previous reply available for duplicate "			     "message");		return -1;	}		      	eap = radius_msg_get_eap(msg, &eap_len);	if (eap == NULL) {		RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",			     from_addr);		data->counters.packets_dropped++;		client->counters.packets_dropped++;		return -1;	}	RADIUS_DUMP("Received EAP data", eap, eap_len);	/* FIX: if Code is Request, Success, or Failure, send Access-Reject;	 * RFC3579 Sect. 2.6.2.	 * Include EAP-Response/Nak with no preferred method if	 * code == request.	 * If code is not 1-4, discard the packet silently.	 * Or is this already done by the EAP state machine? */	wpabuf_free(sess->eap_if->eapRespData);	sess->eap_if->eapRespData = wpabuf_alloc_ext_data(eap, eap_len);	if (sess->eap_if->eapRespData == NULL)		os_free(eap);	eap = NULL;	sess->eap_if->eapResp = TRUE;	eap_server_sm_step(sess->eap);	if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess ||	     sess->eap_if->eapFail) && sess->eap_if->eapReqData) {		RADIUS_DUMP("EAP data from the state machine",			    wpabuf_head(sess->eap_if->eapReqData),			    wpabuf_len(sess->eap_if->eapReqData));	} else if (sess->eap_if->eapFail) {		RADIUS_DEBUG("No EAP data from the state machine, but eapFail "			     "set");	} else if (eap_sm_method_pending(sess->eap)) {		if (sess->last_msg) {			radius_msg_free(sess->last_msg);			os_free(sess->last_msg);		}		sess->last_msg = msg;		sess->last_from_port = from_port;		os_free(sess->last_from_addr);		sess->last_from_addr = os_strdup(from_addr);		sess->last_fromlen = fromlen;		os_memcpy(&sess->last_from, from, fromlen);		return -2;	} else {		RADIUS_DEBUG("No EAP data from the state machine - ignore this"			     " Access-Request silently (assuming it was a "			     "duplicate)");		data->counters.packets_dropped++;		client->counters.packets_dropped++;		return -1;	}	reply = radius_server_encapsulate_eap(data, client, sess, msg);	if (reply) {		RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);		if (wpa_debug_level <= MSG_MSGDUMP) {			radius_msg_dump(reply);		}		switch (reply->hdr->code) {		case RADIUS_CODE_ACCESS_ACCEPT:			data->counters.access_accepts++;			client->counters.access_accepts++;			break;		case RADIUS_CODE_ACCESS_REJECT:			data->counters.access_rejects++;			client->counters.access_rejects++;			break;		case RADIUS_CODE_ACCESS_CHALLENGE:			data->counters.access_challenges++;			client->counters.access_challenges++;			break;		}		res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0,			     (struct sockaddr *) from, fromlen);		if (res < 0) {			perror("sendto[RADIUS SRV]");		}		if (sess->last_reply) {			radius_msg_free(sess->last_reply);			os_free(sess->last_reply);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -