Beispiel #1
0
static void
radius_ip_up(void)
{
	struct radius_attrib *attriblist, *recvattriblist;
	int ret;

	if (prev_ip_up_hook) {
		prev_ip_up_hook();
	}

	if (use_account) {
		if (radius_server == -1)
			return;

		attriblist = NULL;
		recvattriblist = NULL;
	
		if (!radius_add_attrib(
				&attriblist, PW_VENDOR_NONE, PW_ACCT_STATUS_TYPE,
				PW_STATUS_START, NULL, 0)) {
			radius_free_attrib(attriblist);
			return;
		}

		sprintf(sessionid, "%x", radius_sessionid());
		if (!radius_add_attrib(
				&attriblist, PW_VENDOR_NONE, PW_ACCT_SESSION_ID,
				0, sessionid, strlen(sessionid))) {
			radius_free_attrib(attriblist);
			return;
		}

		if (!radius_common_account_attrib(&attriblist)) {
			radius_free_attrib(attriblist);
			return;
		}

		ret = radius_send_account_request(
				radius_server, radius_auth_port+1, radius_secret,
				attriblist, &recvattriblist);

		radius_free_attrib(attriblist);
		radius_free_attrib(recvattriblist);

		if (ret >= 0) {
			accountstart = 1;
		}
	}
}
Beispiel #2
0
/* Authenticate/authorize */
static int
radius_pap_auth(char *t_user, char *t_passwd, char **t_msgp,
		struct wordlist **t_paddrs, struct wordlist **t_popts)
{
	int ret;
	struct radius_attrib *attriblist;
    
	if (!use_radius) {
		if (prev_pap_auth_hook)
			return prev_pap_auth_hook(t_user, t_passwd, t_msgp,
					t_paddrs, t_popts);
		else
			return -1;
	}

	*t_msgp = "Login failed";
	if (radius_server == -1) {
		error("RADIUS: server not found");
		return 0;
	}

	attriblist = NULL;

	if (!radius_add_attrib(
			&attriblist, PW_VENDOR_NONE, PW_USER_NAME,
			0, t_user, strlen(t_user))) {
		radius_free_attrib(attriblist);
		return 0;
	}

	if (!radius_add_attrib(
			&attriblist, PW_VENDOR_NONE, PW_PASSWORD,
			0, t_passwd, strlen(t_passwd))) {
		radius_free_attrib(attriblist);
		return 0;
	}

	ret = radius_auth(&attriblist, NULL);
	if (ret > 0)
		*t_msgp = "Login ok";

	radius_free_attrib(attriblist);

	return ret;
}
Beispiel #3
0
/* Return: success: 0, error: -1 */
static int
radius_get_attrib(struct radius_attrib **list, u_char *buf, int len,
		char *secret, u_char *vector)
{
	struct radius_attrib **next;

	next = list;
	*next = NULL;
	if (radius_get_attrib_vendor(&next, PW_VENDOR_NONE, buf, len,
			secret, vector) < 0) {
		radius_free_attrib(*list);
		*list = NULL;
		return -1;
	}

	return 0;
}
Beispiel #4
0
static void
radius_ip_down(void)
{
	struct radius_attrib *attriblist, *recvattriblist;

	if (prev_ip_down_hook) {
		prev_ip_down_hook();
	}

	/* Put in the accountstart check here since this hook
	 * also gets called if an IP address could not be
	 * negotiated. */
	if (use_account && accountstart) {
		accountstart = 0;

		if (radius_server == -1)
			return;

		attriblist = NULL;
		recvattriblist = NULL;
	
		if (!radius_add_attrib(
				&attriblist, PW_VENDOR_NONE, PW_ACCT_STATUS_TYPE,
				PW_STATUS_STOP, NULL, 0)) {
			radius_free_attrib(attriblist);
			return;
		}

		if (!radius_add_attrib(
				&attriblist, PW_VENDOR_NONE, PW_ACCT_SESSION_ID,
				0, sessionid, strlen(sessionid))) {
			radius_free_attrib(attriblist);
			return;
		}

		if (!radius_common_account_attrib(&attriblist)) {
			radius_free_attrib(attriblist);
			return;
		}

		if (link_stats_valid) {
			if (!radius_add_attrib(
					&attriblist, PW_VENDOR_NONE, PW_ACCT_INPUT_OCTETS,
					link_stats.bytes_in, NULL, 0)) {
				radius_free_attrib(attriblist);
				return;
			}

			if (!radius_add_attrib(
					&attriblist, PW_VENDOR_NONE, PW_ACCT_OUTPUT_OCTETS,
					link_stats.bytes_out, NULL, 0)) {
				radius_free_attrib(attriblist);
				return;
			}

			if (!radius_add_attrib(
					&attriblist, PW_VENDOR_NONE, PW_ACCT_SESSION_TIME,
					link_connect_time, NULL, 0)) {
				radius_free_attrib(attriblist);
				return;
			}

		}

		radius_send_account_request(
				radius_server, radius_auth_port+1, radius_secret,
				attriblist, &recvattriblist);

		radius_free_attrib(attriblist);
		radius_free_attrib(recvattriblist);
	}
}
Beispiel #5
0
static int
radius_chap_auth(char *user, u_char *remmd, int remmd_len, chap_state *cstate)
{
	struct radius_attrib *attriblist;
	u_char chap_password[MAX_RESPONSE_LENGTH+1], *p;
	int code = CHAP_SUCCESS;
    
	if (!use_radius) {
		if (prev_chap_auth_hook)
			return prev_chap_auth_hook(user, remmd, remmd_len, cstate);
		else
			return -1;
	}

	if (radius_server == -1) {
		error("RADIUS: server not found");
		return CHAP_FAILURE;
	}

	attriblist = NULL;

	if (!radius_add_attrib(
			&attriblist, PW_VENDOR_NONE, PW_USER_NAME,
			0, user, strlen(user)))
		goto error;

	switch (cstate->chal_type) {
	case CHAP_DIGEST_MD5:
		if (remmd_len != MD5_SIGNATURE_SIZE) {
			error("RADIUS: invalid CHAP response length '%d'",
					remmd_len);
			goto error;
		}

		if (!radius_add_attrib(
				&attriblist, PW_VENDOR_NONE, PW_CHAP_CHALLENGE,
				0, cstate->challenge, cstate->chal_len))
			goto error;

		p = chap_password;
		*p++ = cstate->chal_id;
		memcpy(p, remmd, remmd_len);
		if (!radius_add_attrib(
				&attriblist, PW_VENDOR_NONE, PW_CHAP_PASSWORD,
				0, chap_password, remmd_len+1))
			goto error;
		break;

#ifdef CHAPMS
	case CHAP_MICROSOFT: {
		MS_ChapResponse *response = (MS_ChapResponse *)remmd;

		if (remmd_len != MS_CHAP_RESPONSE_LEN) {
			error("RADIUS: invalid MSCHAP response length '%d'",
					remmd_len);
			goto error;
		}

		if (!radius_add_attrib(
				&attriblist, PW_VENDOR_MICROSOFT, PW_MS_CHAP_CHALLENGE,
				0, cstate->challenge, cstate->chal_len))
			goto error;

		p = chap_password;
		*p++ = cstate->chal_id;
		*p++ = response->UseNT;
		memcpy(p, response->LANManResp, sizeof(response->LANManResp));
		p += sizeof(response->LANManResp);
		memcpy(p, response->NTResp, sizeof(response->NTResp));
		p += sizeof(response->NTResp);

		if (!radius_add_attrib(
				&attriblist, PW_VENDOR_MICROSOFT, PW_MS_CHAP_RESPONSE,
				0, chap_password, p-chap_password))
			goto error;
		break;
	}

	case CHAP_MICROSOFT_V2: {
		MS_ChapResponse_v2 *response = (MS_ChapResponse_v2 *)remmd;

		if (remmd_len != MS_CHAP_RESPONSE_LEN) {
			error("RADIUS: invalid MSCHAPv2 response length '%d'",
					remmd_len);
			goto error;
		}

		if (!radius_add_attrib(
				&attriblist, PW_VENDOR_MICROSOFT, PW_MS_CHAP_CHALLENGE,
				0, cstate->challenge, cstate->chal_len))
			goto error;

		p = chap_password;
		*p++ = cstate->chal_id;
		*p++ = 0;
		memcpy(p, response->PeerChallenge, sizeof(response->PeerChallenge));
		p += sizeof(response->PeerChallenge);
		memset(p, 0, sizeof(response->Reserved));
		p += sizeof(response->Reserved);
		memcpy(p, response->NTResp, sizeof(response->NTResp));
		p += sizeof(response->NTResp);

		if (!radius_add_attrib(
				&attriblist, PW_VENDOR_MICROSOFT, PW_MS_CHAP2_RESPONSE,
				0, chap_password, p-chap_password)) {
			goto error;
		}
		code = CHAP_SUCCESS_R;
		break;
	}
#endif

	default:
		error("RADIUS: unsupported challenge type '%d'",
				cstate->chal_type);
		goto error;
	}

	if (radius_auth(&attriblist, cstate) == 1) {
		radius_free_attrib(attriblist);
		return code;
	}

 error:
	radius_free_attrib(attriblist);
	return CHAP_FAILURE;
}
Beispiel #6
0
static int
radius_auth(struct radius_attrib **attriblist, chap_state *cstate)
{
	int ret;
	struct radius_attrib *recvattriblist;
	struct radius_attrib *attrib;
#ifdef CHAPMS
	int ms_chap2_success = 0;
#endif
#ifdef MPPE
	int mppe_send_key = 0, mppe_recv_key = 0, mppe_policy = 0, mppe_types = 0;
#endif

	if (nas_ip_address != -1) {
		if (!radius_add_attrib(
				attriblist, PW_VENDOR_NONE, PW_NAS_IP_ADDRESS,
				nas_ip_address, NULL, 0)) {
			return 0;
		}
	}
	else if (nas_identifier[0]) {
		if (!radius_add_attrib(
				attriblist, PW_VENDOR_NONE, PW_NAS_IDENTIFIER,
				0, nas_identifier, strlen(nas_identifier))) {
			return 0;
		}
	}

	if (nas_real_port_number != -1) {
		if (!radius_add_attrib(
				attriblist, PW_VENDOR_NONE, PW_NAS_PORT_ID,
				nas_real_port_number, NULL, 0)) {
			return 0;
		}
	}

	if (nas_port_type != -1) {
		if (!radius_add_attrib(
				attriblist, PW_VENDOR_NONE, PW_NAS_PORT_TYPE,
				nas_port_type, NULL, 0)) {
			return 0;
		}
	}

	if (!radius_add_attrib(
			attriblist, PW_VENDOR_NONE, PW_SERVICE_TYPE,
			PW_FRAMED_USER, NULL, 0)) {
		return 0;
	}

	if (!radius_add_attrib(
			attriblist, PW_VENDOR_NONE, PW_FRAMED_PROTOCOL,
			PW_PPP, NULL, 0)) {
		return 0;
	}

	if (ipcp_wantoptions[0].hisaddr) {
		if (!radius_add_attrib(
				attriblist, PW_VENDOR_NONE,
				PW_FRAMED_IP_ADDRESS,
				ntohl(ipcp_wantoptions[0].hisaddr), NULL, 0)) {
			return 0;
		}
	}

	recvattriblist = NULL;
	ret = radius_send_access_request(
			radius_server, radius_auth_port, radius_secret,
			*attriblist, &recvattriblist);
	if (ret < 0) {
		error("RADIUS: server failed");
		ret = 0;
	}
	else if (ret == PW_AUTHENTICATION_ACK) {
		ret = 1; /* Default to success unless an attribute makes us fail */
		for (attrib=recvattriblist; ret && attrib!=NULL; attrib=attrib->next) {
			if (attrib->vendor == PW_VENDOR_NONE) {
				switch (attrib->type) {
				case PW_SERVICE_TYPE:
					if (ntohl(attrib->u.value) != PW_FRAMED_USER) {
						error("RADIUS: service type '%d' is not framed", ntohl(attrib->u.value));
						ret = 0;
					}
					break;

				case PW_FRAMED_PROTOCOL:
					if (ntohl(attrib->u.value) != PW_PPP) {
						error("RADIUS: framed protocol '%d' is not ppp", ntohl(attrib->u.value));
						ret = 0;
					}
					break;

				case PW_FRAMED_IP_ADDRESS:
					if (attrib->u.value == htonl(0xffffffff)) {
						radius_allow_any_ip = 1;
					}
					else if (attrib->u.value == htonl(0xfffffffe)) {
						radius_allow_server_ip = 1;
					}
					else {
						radius_remote_ip_addr = attrib->u.value;
					}
					break;

				case PW_FRAMED_IP_NETMASK:
					if (attrib->u.value && attrib->u.value != 0xffffffff) {
						netmask = attrib->u.value;
					}
					break;

				case PW_FRAMED_COMPRESSION:
					if (ntohl(attrib->u.value) == PW_NONE) {
						ipcp_wantoptions[0].neg_vj = 0;
						ipcp_allowoptions[0].neg_vj = 0;
					}
					else if (ntohl(attrib->u.value) == PW_VAN_JACOBSEN_TCP_IP) {
						ipcp_wantoptions[0].neg_vj = 1;
						ipcp_allowoptions[0].neg_vj = 1;
					}
					break;

				case PW_REPLY_MESSAGE:
					strncpy(radius_reply_message,attrib->u.string,AUTH_STRING_LEN);
					radius_reply_message[AUTH_STRING_LEN] = 0;
					notice(radius_reply_message);
					break;

#if 0
				case PW_FRAMED_ROUTE:
					/* XXX: store route for adding/removing in ip-up/ip-down */
					break;

				case PW_FRAMED_MTU:
					/* XXX: set the MTU? */
					break;
#endif

				case PW_IDLE_TIMEOUT:
					if (attrib->u.value != 0) {
						idle_time_limit = ntohl(attrib->u.value);
					}
					break;

				case PW_SESSION_TIMEOUT:
					if (attrib->u.value != 0) {
						maxconnect = ntohl(attrib->u.value);
					}
					break;

				case PW_CLASS:
					radius_class_length = attrib->length;
					if (radius_class_length > sizeof(radius_class))
						radius_class_length = sizeof(radius_class);
					memcpy(radius_class, attrib->u.string, radius_class_length);
					break;

				default:
					notice("RADIUS: ignoring unsupported attribute %d",
							attrib->type);
					break;
				}
			}
#ifdef CHAPMS
			else if (attrib->vendor == PW_VENDOR_MICROSOFT) {
				switch (attrib->type) {
				case PW_MS_CHAP2_SUCCESS:
					if (ms_chap2_success) {
						error("RADIUS: duplicate MS_CHAP2_SUCCESS");
						ret = 0;
						break;
					}
					ms_chap2_success = 1;

					if (!cstate || (cstate->chal_type != CHAP_MICROSOFT_V2)) {
						error("RADIUS: unexpected MS_CHAP2_SUCCESS");
						ret = 0;
						break;
					}

					if (attrib->length != 43) {
						error("RADIUS: invalid MS_CHAP2_SUCCESS length '%d'", attrib->length);
						ret = 0;
						break;
					}
					if (strncmp(attrib->u.string+1, "S=", 2)) {
						error("RADIUS: invalid MS_CHAP2_SUCCESS");
						ret = 0;
						break;
					}
					memcpy(cstate->response, attrib->u.string+1, attrib->length-1);
					cstate->response[attrib->length-1] = '\0';
					break;

#ifdef MPPE
				case PW_MS_CHAP_MPPE_KEYS: {
					unsigned char Digest[SHA_DIGEST_LENGTH];
					SHA_CTX Context;
    
					if (!cstate || (cstate->chal_type != CHAP_MICROSOFT)) {
						error("RADIUS: unexpected MS_CHAP_MPPE_KEYS");
						ret = 0;
						break;
					}

					if (attrib->length != 32) {
						error("RADIUS: invalid MS_CHAP_MPPE_KEYS length '%d'", attrib->length);
						ret = 0;
						break;
					}

					memcpy(mppe_master_send_key_40, attrib->u.string, 8);
					memcpy(mppe_master_recv_key_40, attrib->u.string, 8);

					SHA1_Init(&Context);
					SHA1_Update(&Context, attrib->u.string + 8, 16);
					SHA1_Update(&Context, attrib->u.string + 8, 16);
					SHA1_Update(&Context, cstate->challenge, 8);
					SHA1_Final(Digest, &Context);

					memcpy(mppe_master_send_key_128, Digest, 16);
					memcpy(mppe_master_recv_key_128, Digest, 16);
					mppe_send_key = mppe_recv_key = 1;
					break;
				}

				case PW_MS_MPPE_SEND_KEY:
					if (!cstate || (cstate->chal_type != CHAP_MICROSOFT_V2)) {
						error("RADIUS: unexpected MS_MPPE_SEND_KEY");
						ret = 0;
						break;
					}
					if (attrib->length != 34) {
						error("RADIUS: invalid MS_MPPE_SEND_KEY length '%d'", attrib->length);
						ret = 0;
						break;
					}
					if ((attrib->u.string[0] & 0x80) == 0) {
						error("RADIUS: invalid MS_MPPE_SEND_KEY salt '%02x%02x'", (unsigned char)attrib->u.string[0], (unsigned char)attrib->u.string[1]);
						ret = 0;
						break;
					}
					if (attrib->u.string[2] != 16) {
						error("RADIUS: invalid MS_MPPE_SEND_KEY keylength '%d'", attrib->u.string[2]);
						ret = 0;
						break;
					}
					memcpy(mppe_master_send_key_128, attrib->u.string+3, 16);
					memcpy(mppe_master_send_key_40, attrib->u.string+3, 8);
					mppe_send_key = 1;
					break;

				case PW_MS_MPPE_RECV_KEY:
					if (!cstate || (cstate->chal_type != CHAP_MICROSOFT_V2)) {
						error("RADIUS: unexpected MS_MPPE_RECV_KEY");
						ret = 0;
						break;
					}
					if (attrib->length != 34) {
						error("RADIUS: invalid MS_MPPE_RECV_KEY length '%d'", attrib->length);
						ret = 0;
						break;
					}
					if ((attrib->u.string[0] & 0x80) == 0) {
						error("RADIUS: invalid MS_MPPE_RECV_KEY salt '%02x%02x'", (unsigned char)attrib->u.string[0], (unsigned char)attrib->u.string[1]);
						ret = 0;
						break;
					}
					if (attrib->u.string[2] != 16) {
						error("RADIUS: invalid MS_MPPE_RECV_KEY keylength '%d'", attrib->u.string[2]);
						ret = 0;
						break;
					}
					memcpy(mppe_master_recv_key_128, attrib->u.string+3, 16);
					memcpy(mppe_master_recv_key_40, attrib->u.string+3, 8);
					mppe_recv_key = 1;
					break;

				case PW_MS_MPPE_ENCRYPTION_POLICY:
					if (!radius_check_integer_length(attrib)) {
						ret = 0;
						break;
					}

					if (attrib->u.value == htonl(1)) {
						/* Encryption allowed */
						ccp_allowoptions[0].mppe = 1;
						ccp_wantoptions[0].mppe = 0;
						mppe_policy = 1;
					}
					else if (attrib->u.value == htonl(2)) {
						/* Encryption required */
						/* XXX: current version of ppd doesn't support
						 * requiring encryption. */
						ccp_allowoptions[0].mppe = ccp_wantoptions[0].mppe = 1;
						mppe_policy = 1;
					}
					break;

				case PW_MS_MPPE_ENCRYPTION_TYPES:
					if (!radius_check_integer_length(attrib)) {
						ret = 0;
						break;
					}

					ccp_allowoptions[0].mppe_40
						= ccp_wantoptions[0].mppe_40
						= (attrib->u.value & htonl(2)) ? 1 : 0;
					ccp_allowoptions[0].mppe_128
						= ccp_wantoptions[0].mppe_128
						= (attrib->u.value & htonl(4)) ? 1 : 0;
					mppe_types = 1;
					break;
#endif /* MPPE */

#if 0
				case PW_MS_PRIMARY_DNS_SERVER:
				case PW_MS_SECONDARY_DNS_SERVER:
				case PW_MS_PRIMARY_NBNS_SERVER:
				case PW_MS_SECONDARY_NBNS_SERVER:
					break;
#endif

				default:
					notice("RADIUS: ignoring Microsoft attribute %d",
							attrib->type);
					break;
				}
			}
#endif /* CHAPMS */
			else {
				notice("RADIUS: ignoring vendor %d attribute %d",
						attrib->vendor, attrib->type);
			}
		}
#ifdef CHAPMS
		if (ret && cstate && (cstate->chal_type == CHAP_MICROSOFT_V2)
				&& !ms_chap2_success) {
			error("RADIUS: MSCHAPv2 success attribute not found");
			ret = 0;
		}
#endif
#ifdef MPPE
		if (mppe_send_key && mppe_recv_key) {
			if (mppe_policy && mppe_types) {
				mppe_allowed = 1;
			} else if (!mppe_policy) {
				mppe_allowed = 1;
			}
		}
#endif
	}
	else if (ret == PW_AUTHENTICATION_REJECT) {
		for (attrib=recvattriblist; attrib!=NULL; attrib=attrib->next) {
			if (attrib->vendor == PW_VENDOR_NONE
					&& attrib->type == PW_REPLY_MESSAGE) {
				strncpy(radius_reply_message,attrib->u.string,AUTH_STRING_LEN);
				radius_reply_message[AUTH_STRING_LEN] = 0;
				error("%s", radius_reply_message);
			}
		}
		ret = 0;
	}
	else if (ret == PW_ACCESS_CHALLENGE) {
		error("RADIUS: server sent unexpected CHAP challenge");
		ret = 0;
	}
	else {
		error("RADIUS: server sent unexpected response '%d'", ret);
		ret = 0;
	}

	radius_free_attrib(recvattriblist);

	return ret;
}