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

📄 ttls.c

📁 radius服务器
💻 C
📖 第 1 页 / 共 2 页
字号:
			pairfree(&vp);			/*			 *	If we've been told to use the attributes from			 *	the reply, then do so.			 *			 *	WARNING: This may leak information about the			 *	tunneled user!			 */			if (t->use_tunneled_reply) {				pairadd(&request->reply->vps, reply->vps);				reply->vps = NULL;			}		}		/*		 *	Handle the ACK, by tunneling any necessary reply		 *	VP's back to the client.		 */		if (vp) {			vp2diameter(tls_session, vp);			pairfree(&vp);		}		break;	case PW_AUTHENTICATION_REJECT:		DEBUG2("  TTLS: Got tunneled Access-Reject");		rcode = RLM_MODULE_REJECT;		break;		/*		 *	Handle Access-Challenge, but only if we		 *	send tunneled reply data.  This is because		 *	an Access-Challenge means that we MUST tunnel		 *	a Reply-Message to the client.		 */	case PW_ACCESS_CHALLENGE:		DEBUG2("  TTLS: Got tunneled Access-Challenge");		/*		 *	Keep the State attribute, if necessary.		 *		 *	Get rid of the old State, too.		 */		pairfree(&t->state);		pairmove2(&t->state, &reply->vps, PW_STATE);		/*		 *	We should really be a bit smarter about this,		 *	and move over only those attributes which		 *	are relevant to the authentication request,		 *	but that's a lot more work, and this "dumb"		 *	method works in 99.9% of the situations.		 */		vp = NULL;		pairmove2(&vp, &reply->vps, PW_EAP_MESSAGE);		/*		 *	There MUST be a Reply-Message in the challenge,		 *	which we tunnel back to the client.		 *		 *	If there isn't one in the reply VP's, then		 *	we MUST create one, with an empty string as		 *	it's value.		 */		pairmove2(&vp, &reply->vps, PW_REPLY_MESSAGE);		/*		 *	Handle the ACK, by tunneling any necessary reply		 *	VP's back to the client.		 */		if (vp) {			vp2diameter(tls_session, vp);			pairfree(&vp);		}		rcode = RLM_MODULE_HANDLED;		break;	default:		DEBUG2("  TTLS: Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);		rcode = RLM_MODULE_REJECT;		break;	}	return rcode;}/* *	Do post-proxy processing, */static int eapttls_postproxy(EAP_HANDLER *handler, void *data){	int rcode;	tls_session_t *tls_session = (tls_session_t *) data;	REQUEST *fake;	DEBUG2("  TTLS: Passing reply from proxy back into the tunnel.");	/*	 *	If there was a fake request associated with the proxied	 *	request, do more processing of it.	 */	fake = (REQUEST *) request_data_get(handler->request,					    handler->request->proxy,					    REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK);		/*	 *	Do the callback, if it exists, and if it was a success.	 */	if (fake && (handler->request->proxy_reply->code == PW_AUTHENTICATION_ACK)) {		VALUE_PAIR *vp;		REQUEST *request = handler->request;		/*		 *	Terrible hacks.		 */		rad_assert(fake->packet == NULL);		fake->packet = request->proxy;		request->proxy = NULL;		rad_assert(fake->reply == NULL);		fake->reply = request->proxy_reply;		request->proxy_reply = NULL;		/*		 *	Perform a post-auth stage for the tunneled		 *	session.		 */		fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;		rcode = rad_postauth(fake);		DEBUG2("  POST-AUTH %d", rcode);#ifndef NDEBUG		if (debug_flag > 0) {			printf("  TTLS: Final reply from tunneled session code %d\n",			       fake->reply->code);						for (vp = fake->reply->vps; vp != NULL; vp = vp->next) {				putchar('\t');vp_print(stdout, vp);putchar('\n');			}		}#endif		/*		 *	Terrible hacks.		 */		request->proxy = fake->packet;		fake->packet = NULL;		request->proxy_reply = fake->reply;		fake->reply = NULL;		/*		 *	And we're done with this request.		 */		switch (rcode) {                case RLM_MODULE_FAIL:			request_free(&fake);			eaptls_fail(handler->eap_ds, 0);			return 0;			break;			                default:  /* Don't Do Anything */			DEBUG2(" TTLS: Got reply %d",			       request->proxy_reply->code);			break;		}		}	request_free(&fake);	/* robust if fake == NULL */	/*	 *	Process the reply from the home server.	 */	rcode = process_reply(handler, tls_session, handler->request,			      handler->request->proxy_reply);	/*	 *	The proxy code uses the reply from the home server as	 *	the basis for the reply to the NAS.  We don't want that,	 *	so we toss it, after we've had our way with it.	 */	pairfree(&handler->request->proxy_reply->vps);	switch (rcode) {	case RLM_MODULE_REJECT:		DEBUG2("  TTLS: Reply was rejected");		return 0;	case RLM_MODULE_HANDLED:		DEBUG2("  TTLS: Reply was handled");		eaptls_request(handler->eap_ds, tls_session);		return 1;	case RLM_MODULE_OK:		DEBUG2("  TTLS: Reply was OK");		eaptls_success(handler->eap_ds, 0);		eaptls_gen_mppe_keys(&handler->request->reply->vps,				     tls_session->ssl,				     "ttls keying material");		return 1;	default:		DEBUG2("  TTLS: Reply was unknown.");		break;	}	eaptls_fail(handler->eap_ds, 0);	return 0;}/* *	Free a request. */static void my_request_free(void *data){	REQUEST *request = (REQUEST *)data;	request_free(&request);}/* *	Process the "diameter" contents of the tunneled data. */int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session){	int err;	int rcode = PW_AUTHENTICATION_REJECT;	REQUEST *fake;	VALUE_PAIR *vp;	ttls_tunnel_t *t;	const uint8_t *data;	unsigned int data_len;	char buffer[1024];	REQUEST *request = handler->request;	/*	 *	Grab the dirty data, and copy it to our buffer.	 *	 *	I *really* don't like these 'record_t' things...	 */	data_len = record_minus(&tls_session->dirty_in, buffer, sizeof(buffer));	data = buffer;	/*	 *	Write the data from the dirty buffer (i.e. packet	 *	data) into the buffer which we will give to SSL for	 *	decoding.	 *	 *	Some of this code COULD technically go into the TLS	 *	module, in eaptls_process(), where it returns EAPTLS_OK.	 *	 *	Similarly, the writing of data to the SSL context could	 *	go there, too...	 */	BIO_write(tls_session->into_ssl, buffer, data_len);	record_init(&tls_session->clean_out);	/*	 *	Read (and decrypt) the tunneled data from the SSL session,	 *	and put it into the decrypted data buffer.	 */	err = SSL_read(tls_session->ssl, tls_session->clean_out.data,		       sizeof(tls_session->clean_out.data));	if (err < 0) {		/*		 *	FIXME: Call SSL_get_error() to see what went		 *	wrong.		 */		radlog(L_INFO, "rlm_eap_ttls: SSL_read Error");		return PW_AUTHENTICATION_REJECT;	}	t = (ttls_tunnel_t *) tls_session->opaque;	/*	 *	If there's no data, maybe this is an ACK to an	 *	MS-CHAP2-Success.	 */	if (err == 0) {		if (t->authenticated) {			DEBUG2("  TTLS: Got ACK, and the user was already authenticated.");			return PW_AUTHENTICATION_ACK;		} /* else no session, no data, die. */		/*		 *	FIXME: Call SSL_get_error() to see what went		 *	wrong.		 */		radlog(L_INFO, "rlm_eap_ttls: SSL_read Error");		return PW_AUTHENTICATION_REJECT;	}	data_len = tls_session->clean_out.used = err;	data = tls_session->clean_out.data;#ifndef NDEBUG	if (debug_flag > 2) {		unsigned int i;		for (i = 0; i < data_len; i++) {			if ((i & 0x0f) == 0) printf("  TTLS tunnel data in %04x: ", i);			printf("%02x ", data[i]);			if ((i & 0x0f) == 0x0f) printf("\n");		}		if ((data_len & 0x0f) != 0) printf("\n");	}#endif	if (!diameter_verify(data, data_len)) {		return PW_AUTHENTICATION_REJECT;	}	/*	 *	Allocate a fake REQUEST structe.	 */	fake = request_alloc_fake(request);	rad_assert(fake->packet->vps == NULL);	/*	 *	Add the tunneled attributes to the fake request.	 */	fake->packet->vps = diameter2vp(tls_session->ssl, data, data_len);	if (!fake->packet->vps) {		return PW_AUTHENTICATION_REJECT;	}	/*	 *	Tell the request that it's a fake one.	 */	vp = pairmake("Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);	if (vp) {		pairadd(&fake->packet->vps, vp);	}#ifndef NDEBUG	if (debug_flag > 0) {		printf("  TTLS: Got tunneled request\n");				for (vp = fake->packet->vps; vp != NULL; vp = vp->next) {			putchar('\t');vp_print(stdout, vp);putchar('\n');		}	}#endif	/*	 *	Update other items in the REQUEST data structure.	 */	fake->username = pairfind(fake->packet->vps, PW_USER_NAME);	fake->password = pairfind(fake->packet->vps, PW_PASSWORD);	/*	 *	No User-Name, try to create one from stored data.	 */	if (!fake->username) {		/*		 *	No User-Name in the stored data, look for		 *	an EAP-Identity, and pull it out of there.		 */		if (!t->username) {			vp = pairfind(fake->packet->vps, PW_EAP_MESSAGE);			if (vp &&			    (vp->length >= EAP_HEADER_LEN + 2) &&			    (vp->strvalue[0] == PW_EAP_RESPONSE) &&			    (vp->strvalue[EAP_HEADER_LEN] == PW_EAP_IDENTITY) &&			    (vp->strvalue[EAP_HEADER_LEN + 1] != 0)) {				/*				 *	Create & remember a User-Name				 */				t->username = pairmake("User-Name", "", T_OP_EQ);				rad_assert(t->username != NULL);				memcpy(t->username->strvalue, vp->strvalue + 5,				       vp->length - 5);				t->username->length = vp->length - 5;				t->username->strvalue[t->username->length] = 0;				DEBUG2("  TTLS: Got tunneled identity of %s",				       t->username->strvalue);				/*				 *	If there's a default EAP type,				 *	set it here.				 */				if (t->default_eap_type != 0) {					DEBUG2("  TTLS: Setting default EAP type for tunneled EAP session.");					vp = paircreate(PW_EAP_TYPE,							PW_TYPE_INTEGER);					rad_assert(vp != NULL);					vp->lvalue = t->default_eap_type;					pairadd(&fake->config_items, vp);				}			} else {				/*				 *	Don't reject the request outright,				 *	as it's permitted to do EAP without				 *	user-name.				 */				DEBUG2("  rlm_eap_ttls: WARNING! No EAP-Identity found to start EAP conversation.");			}		} /* else there WAS a t->username */		if (t->username) {			vp = paircopy(t->username);			pairadd(&fake->packet->vps, vp);			fake->username = pairfind(fake->packet->vps, PW_USER_NAME);		}	} /* else the request ALREADY had a User-Name */	/*	 *	Add the State attribute, too, if it exists.	 */	if (t->state) {		DEBUG2("  TTLS: Adding old state with %02x %02x",		       t->state->strvalue[0], t->state->strvalue[1]);		vp = paircopy(t->state);		if (vp) pairadd(&fake->packet->vps, vp);	}	/*	 *	If this is set, we copy SOME of the request attributes	 *	from outside of the tunnel to inside of the tunnel.	 *	 *	We copy ONLY those attributes which do NOT already	 *	exist in the tunneled request.	 */	if (t->copy_request_to_tunnel) {		VALUE_PAIR *copy;		for (vp = request->packet->vps; vp != NULL; vp = vp->next) {			/*			 *	The attribute is a server-side thingy,			 *	don't copy it.			 */			if ((vp->attribute > 255) &&			    (((vp->attribute >> 16) & 0xffff) == 0)) {				continue;			}			/*			 *	The outside attribute is already in the			 *	tunnel, don't copy it.			 *			 *	This works for BOTH attributes which			 *	are originally in the tunneled request,			 *	AND attributes which are copied there			 *	from below.			 */			if (pairfind(fake->packet->vps, vp->attribute)) {				continue;			}			/*			 *	Some attributes are handled specially.			 */			switch (vp->attribute) {				/*				 *	NEVER copy Message-Authenticator,				 *	EAP-Message, or State.  They're				 *	only for outside of the tunnel.				 */			case PW_USER_NAME:			case PW_USER_PASSWORD:			case PW_CHAP_PASSWORD:			case PW_CHAP_CHALLENGE:			case PW_PROXY_STATE:			case PW_MESSAGE_AUTHENTICATOR:			case PW_EAP_MESSAGE:			case PW_STATE:				continue;				break;				/*				 *	By default, copy it over.				 */			default:				break;			}			/*			 *	Don't copy from the head, we've already			 *	checked it.			 */			copy = paircopy2(vp, vp->attribute);			pairadd(&fake->packet->vps, copy);		}	}#ifndef NDEBUG	if (debug_flag > 0) {	  printf("  TTLS: Sending tunneled request\n");	  for (vp = fake->packet->vps; vp != NULL; vp = vp->next) {	    putchar('\t');vp_print(stdout, vp);putchar('\n');	  }	}#endif	/*	 *	Call authentication recursively, which will	 *	do PAP, CHAP, MS-CHAP, etc.	 */	rad_authenticate(fake);	/*	 *	Note that we don't do *anything* with the reply	 *	attributes.	 */#ifndef NDEBUG	if (debug_flag > 0) {	  printf("  TTLS: Got tunneled reply RADIUS code %d\n",		 fake->reply->code);	  for (vp = fake->reply->vps; vp != NULL; vp = vp->next) {	    putchar('\t');vp_print(stdout, vp);putchar('\n');	  }	}#endif	/*	 *	Decide what to do with the reply.	 */	switch (fake->reply->code) {	case 0:			/* No reply code, must be proxied... */		vp = pairfind(fake->config_items, PW_PROXY_TO_REALM);		if (vp) {			eap_tunnel_data_t *tunnel;			DEBUG2("  TTLS: Tunneled authentication will be proxied to %s", vp->strvalue);			/*			 *	Tell the original request that it's going			 *	to be proxied.			 */			pairmove2(&(request->config_items),				  &(fake->config_items),				  PW_PROXY_TO_REALM);			/*			 *	Seed the proxy packet with the			 *	tunneled request.			 */			rad_assert(request->proxy == NULL);			request->proxy = fake->packet;			fake->packet = NULL;			rad_free(&fake->reply);			fake->reply = NULL;			/*			 *	Set up the callbacks for the tunnel			 */			tunnel = rad_malloc(sizeof(*tunnel));			memset(tunnel, 0, sizeof(*tunnel));			tunnel->tls_session = tls_session;			tunnel->callback = eapttls_postproxy;			/*			 *	Associate the callback with the request.			 */			rcode = request_data_add(request,						 request->proxy,						 REQUEST_DATA_EAP_TUNNEL_CALLBACK,						 tunnel, free);			rad_assert(rcode == 0);						/*			 *	rlm_eap.c has taken care of associating			 *	the handler with the fake request.			 *			 *	So we associate the fake request with			 *	this request.			 */			rcode = request_data_add(request,						 request->proxy,						 REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK,						 fake, my_request_free);			rad_assert(rcode == 0);			fake = NULL;			/*			 *	Didn't authenticate the packet, but			 *	we're proxying it.			 */			rcode = PW_STATUS_CLIENT;		} else {			DEBUG2("  TTLS: No tunneled reply was found for request %d , and the request was not proxied: rejecting the user.",			       request->number);			rcode = PW_AUTHENTICATION_REJECT;		}		break;	default:		/*		 *	Returns RLM_MODULE_FOO, and we want to return		 *	PW_FOO		 */		rcode = process_reply(handler, tls_session, request,				      fake->reply);		switch (rcode) {		case RLM_MODULE_REJECT:			rcode = PW_AUTHENTICATION_REJECT;			break;					case RLM_MODULE_HANDLED:			rcode = PW_ACCESS_CHALLENGE;			break;					case RLM_MODULE_OK:			rcode = PW_AUTHENTICATION_ACK;			break;					default:			rcode = PW_AUTHENTICATION_REJECT;			break;		}		break;	}	request_free(&fake);	return rcode;}

⌨️ 快捷键说明

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