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

📄 radius_server.c

📁 hostapd源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * hostapd / RADIUS authentication server * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.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 "config.h"#include "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_session {	struct radius_session *next;	struct radius_client *client;	struct radius_server_data *server;	unsigned int sess_id;	struct eap_sm *eap;	u8 *eapKeyData, *eapReqData;	size_t eapKeyDataLen, eapReqDataLen;	Boolean eapSuccess, eapRestart, eapFail, eapResp, eapReq, eapNoReq;	Boolean portEnabled, eapTimeout;	struct radius_msg *last_msg;	char *last_from_addr;	int last_from_port;	struct sockaddr_storage last_from;	socklen_t last_fromlen;};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_data {	int auth_sock;	struct radius_client *clients;	unsigned int next_sess_id;	void *hostapd_conf;	int num_sess;	void *eap_sim_db_priv;	void *ssl_ctx;	int ipv6;};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);	free(sess->eapKeyData);	free(sess->eapReqData);	eap_sm_deinit(sess->eap);	if (sess->last_msg) {		radius_msg_free(sess->last_msg);		free(sess->last_msg);	}	free(sess->last_from_addr);	free(sess);	data->num_sess--;}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;	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_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 = wpa_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;	const struct hostapd_eap_user *eap_user;	int res;	struct radius_session *sess;	struct eap_config eap_conf;	RADIUS_DEBUG("Creating a new session");	user = 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");		free(user);		return NULL;	}	user_len = res;	RADIUS_DUMP_ASCII("User-Name", user, user_len);	eap_user = hostapd_get_eap_user(data->hostapd_conf, user, user_len, 0);	free(user);	if (eap_user) {		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;	}	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;	sess->eap = eap_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->eapRestart = TRUE;	sess->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->eapFail) {		code = RADIUS_CODE_ACCESS_REJECT;	} else if (sess->eapSuccess) {		code = RADIUS_CODE_ACCESS_ACCEPT;	} else {		code = RADIUS_CODE_ACCESS_CHALLENGE;	}	msg = radius_msg_new(code, request->hdr->identifier);	if (msg == NULL) {		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->eapReqData &&	    !radius_msg_add_eap(msg, sess->eapReqData, sess->eapReqDataLen)) {		RADIUS_DEBUG("Failed to add EAP-Message attribute");	}	if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eapKeyData) {		int len;		if (sess->eapKeyDataLen > 64) {			len = 32;		} else {			len = sess->eapKeyDataLen / 2;		}		if (!radius_msg_add_mppe_keys(msg, request->hdr->authenticator,					      (u8 *) client->shared_secret,					      client->shared_secret_len,					      sess->eapKeyData + len, len,					      sess->eapKeyData, len)) {			RADIUS_DEBUG("Failed to add MPPE key attributes");		}	}	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;	}	memset(&eapfail, 0, sizeof(eapfail));	eapfail.code = EAP_CODE_FAILURE;	eapfail.identifier = 0;	eapfail.length = htons(sizeof(eapfail));	if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) {		RADIUS_DEBUG("Failed to add EAP-Message attribute");	}	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);	}	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);	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], resp_id;	unsigned int state;	struct radius_session *sess;	struct radius_msg *reply;	struct eap_hdr *hdr;	/* TODO: Implement duplicate packet processing */	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 = (statebuf[0] << 24) | (statebuf[1] << 16) |				(statebuf[2] << 8) | statebuf[3];			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;		}	}	eap = radius_msg_get_eap(msg, &eap_len);	if (eap == NULL) {		RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",			     from_addr);		return -1;	}	RADIUS_DUMP("Received EAP data", eap, eap_len);	if (eap_len >= sizeof(*hdr)) {		hdr = (struct eap_hdr *) eap;		resp_id = hdr->identifier;	} else {		resp_id = 0;	}	/* 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? */	eap_set_eapRespData(sess->eap, eap, eap_len);	free(eap);	eap = NULL;	sess->eapResp = TRUE;	eap_sm_step(sess->eap);	if (sess->eapReqData) {		RADIUS_DUMP("EAP data from the state machine",			    sess->eapReqData, sess->eapReqDataLen);	} else if (sess->eapFail) {		RADIUS_DEBUG("No EAP data from the state machine, but eapFail "			     "set - generate EAP-Failure");		hdr = wpa_zalloc(sizeof(*hdr));		if (hdr) {			hdr->identifier = resp_id;			hdr->length = htons(sizeof(*hdr));			sess->eapReqData = (u8 *) hdr;			sess->eapReqDataLen = sizeof(*hdr);		}	} else if (eap_sm_method_pending(sess->eap)) {		if (sess->last_msg) {			radius_msg_free(sess->last_msg);			free(sess->last_msg);		}		sess->last_msg = msg;		sess->last_from_port = from_port;		free(sess->last_from_addr);		sess->last_from_addr = strdup(from_addr);		sess->last_fromlen = fromlen;		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)");		return -1;	}	reply = radius_server_encapsulate_eap(data, client, sess, msg);	free(sess->eapReqData);	sess->eapReqData = NULL;	sess->eapReqDataLen = 0;	if (reply) {		RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);		if (wpa_debug_level <= MSG_MSGDUMP) {			radius_msg_dump(reply);		}		res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0,			     (struct sockaddr *) from, fromlen);		if (res < 0) {			perror("sendto[RADIUS SRV]");		}		radius_msg_free(reply);		free(reply);	}	if (sess->eapSuccess || sess->eapFail) {		RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);		radius_server_session_remove(data, sess);	}	return 0;}static void radius_server_receive_auth(int sock, void *eloop_ctx,				       void *sock_ctx){	struct radius_server_data *data = eloop_ctx;	u8 *buf = NULL;	struct sockaddr_storage from;	socklen_t fromlen;	int len;	struct radius_client *client = NULL;	struct radius_msg *msg = NULL;	char abuf[50];	int from_port = 0;	buf = malloc(RADIUS_MAX_MSG_LEN);	if (buf == NULL) {		goto fail;	}	fromlen = sizeof(from);	len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,		       (struct sockaddr *) &from, &fromlen);	if (len < 0) {		perror("recvfrom[radius_server]");		goto fail;	}#ifdef CONFIG_IPV6	if (data->ipv6) {		struct sockaddr_in6 *from6 = (struct sockaddr_in6 *) &from;		if (inet_ntop(AF_INET6, &from6->sin6_addr, abuf, sizeof(abuf))

⌨️ 快捷键说明

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