Пример #1
0
/************************************************************************
 * Functions for MS-CHAP-V2(RFC 2759)
 ************************************************************************/
static void
mschapv2_send_error(chap *_this, int error, int can_retry)
{
	u_char *pkt, *challenge;
	int lpkt;

	challenge = _this->chall;

	pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
	lpkt = _this->ppp->mru - HEADERLEN;

	/*
	 * We don't use "M=<msg>"
	 *  - pppd on Mac OS 10.4 hungs up if it received a failure packet
	 *    with "M=<msg>".
	 *  - RRAS on windows server 2003 never uses "M=".
	 */
	snprintf(pkt, lpkt, "E=%d R=%d C=%02x%02x%02x%02x%02x%02x%02x%02x"
	    "%02x%02x%02x%02x%02x%02x%02x%02x V=3", error, can_retry,
	    challenge[0], challenge[1], challenge[2], challenge[3],
	    challenge[4], challenge[5], challenge[6], challenge[7],
	    challenge[8], challenge[9], challenge[10], challenge[11],
	    challenge[12], challenge[13], challenge[14], challenge[15]
	);
	lpkt = strlen(pkt);

	chap_response(_this, 0, pkt, lpkt);
}
Пример #2
0
/**
 * sending packet via MPPE.
 */
void
mppe_pkt_output(mppe *_this, uint16_t proto, u_char *pktp, int len)
{
	int encrypt, flushed;
	uint16_t coher_cnt;
	u_char *outp, *outp0;

	MPPE_ASSERT(proto == PPP_PROTO_IP);

	flushed = 0;
	encrypt = 1;

	outp = ppp_packetbuf(_this->ppp, PPP_PROTO_MPPE);
	outp0 = outp;

	if (_this->send.stateless != 0) {
		flushed = 1;
		mppe_key_change(_this, &_this->send);
	} else {
		if ((_this->send.coher_cnt % 0x100) == 0xff) {
			flushed = 1;
			mppe_key_change(_this, &_this->send);
		} else if (_this->send.resetreq != 0) {
			flushed = 1;
			_this->send.resetreq = 0;
		}
	}

	if (flushed) {
		mppe_rc4_setkey(_this, &_this->send);
	}

	MPPE_DBG((_this, DEBUG_LEVEL_2, "out coher_cnt=%03x %s%s",
	    _this->send.coher_cnt, (flushed)? "[flushed]" : "",
	    (encrypt)? "[encrypt]" : ""));

	coher_cnt = _this->send.coher_cnt & COHERENCY_CNT_MASK;
	if (flushed)
		coher_cnt |= 0x8000;
	if (encrypt)
		coher_cnt |= 0x1000;

	PUTSHORT(coher_cnt, outp);
	proto = htons(proto);
	mppe_rc4_encrypt(_this, &_this->send, 2, (u_char *)&proto, outp);
	mppe_rc4_encrypt(_this, &_this->send, len, pktp, outp + 2);

	ppp_output(_this->ppp, PPP_PROTO_MPPE, 0, 0, outp0, len + 4);
	_this->send.coher_cnt++;
	_this->send.coher_cnt &= COHERENCY_CNT_MASK;
}
Пример #3
0
static void
pap_response(pap *_this, int authok, const char *mes)
{
	int lpktp, lmes;
	u_char *pktp, *pktp1;
	const char *realm;

	pktp = ppp_packetbuf(_this->ppp, PPP_PROTO_PAP) + HEADERLEN;
	lpktp = _this->ppp->mru - HEADERLEN;
	realm = npppd_ppp_get_realm_name(_this->ppp->pppd, _this->ppp);

	pktp1 = pktp;
	if (mes == NULL)
		lmes = 0;
	else
		lmes = strlen(mes);
	lmes = MINIMUM(lmes, lpktp - 1);

	PUTCHAR(lmes, pktp1);
	if (lmes > 0)
		memcpy(pktp1, mes, lmes);
	lpktp = lmes + 1;

	if (authok)
		ppp_output(_this->ppp, PPP_PROTO_PAP, AUTHACK, _this->auth_id,
		    pktp, lpktp);
	else
		ppp_output(_this->ppp, PPP_PROTO_PAP, AUTHNAK, _this->auth_id,
		    pktp, lpktp);

	if (!authok) {
		pap_log(_this, LOG_ALERT,
		    "logtype=Failure username=\"%s\" realm=%s", _this->name,
		    realm);
		pap_stop(_this);
		ppp_set_disconnect_cause(_this->ppp, 
		    PPP_DISCON_AUTH_FAILED, PPP_PROTO_PAP, 1 /* peer */, NULL);
		ppp_stop(_this->ppp, "Authentication Required");
	} else {
		strlcpy(_this->ppp->username, _this->name,
		    sizeof(_this->ppp->username));
		pap_log(_this, LOG_INFO,
		    "logtype=Success username=\"%s\" realm=%s", _this->name,
		    realm);
		pap_stop(_this);
		ppp_auth_ok(_this->ppp);
		/* reset the state to response request of retransmision. */
		_this->state = PAP_STATE_SENT_RESPONSE;
	}
}
Пример #4
0
static void
chap_send_error(chap *_this, const char *msg)
{
	u_char *pkt, *challenge;
	int lpkt;

	challenge = _this->chall;

	pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
	lpkt = _this->ppp->mru - HEADERLEN;

	strlcpy(pkt, msg, lpkt);
	lpkt = strlen(msg);

	chap_response(_this, 0, pkt, lpkt);
}
Пример #5
0
/**
 * receiving packets via MPPE.
 * len must be 4 at least.
 */
void
mppe_input(mppe *_this, u_char *pktp, int len)
{
	int pktloss, encrypt, flushed, m, n;
	uint16_t coher_cnt;
	u_char *pktp0, *opktp, *opktp0;
	uint16_t proto;
	int delayed = 0;

	encrypt = 0;
	flushed = 0;

	MPPE_ASSERT(len >= 4);

	pktp0 = pktp;
	GETSHORT(coher_cnt, pktp);

	flushed = (coher_cnt & 0x8000)? 1 : 0;
	encrypt = (coher_cnt & 0x1000)? 1 : 0;
	coher_cnt &= COHERENCY_CNT_MASK;
	pktloss = 0;

	MPPE_DBG((_this, DEBUG_LEVEL_2, "in coher_cnt=%03x/%03x %s%s",
	    _this->recv.coher_cnt, coher_cnt, (flushed)? "[flushed]" : "",
	    (encrypt)? "[encrypt]" : ""));

	if (encrypt == 0) {
		mppe_log(_this, LOG_WARNING,
		    "Received unexpected MPPE packet.  (no encrypt)");
		return;
	}

	/*
	 * In L2TP/IPsec implementation, in case that the ppp frame sequence
	 * is not able to reconstruct and the ppp frame is out of sequence, it
	 * is unable to identify with many packets losing. If it does so, MPPE
	 * key is out of place.
	 * To avoid this problem, when it seems that more than 4096-256 packets
	 * drops, it assumes that the packet doesn't lose but the packet is out
	 * of sequence.
	 */
    {
	int coher_cnt0;

	coher_cnt0 = coher_cnt;
	if (coher_cnt < _this->recv.coher_cnt)
		coher_cnt0 += 0x1000;
	if (coher_cnt0 - _this->recv.coher_cnt > 0x0f00) {
		if (!_this->recv.stateless ||
		    coher_cnt0 - _this->recv.coher_cnt
		    <= 0x1000 - MPPE_NOLDKEY) {
			mppe_log(_this, LOG_INFO,
			    "Workaround the out-of-sequence PPP framing problem: "
			    "%d => %d", _this->recv.coher_cnt, coher_cnt);
			return;
		}
		delayed = 1;
	}
    }

	if (_this->recv.stateless != 0) {
		if (!delayed) {
			mppe_key_change(_this, &_this->recv);
			while (_this->recv.coher_cnt != coher_cnt) {
				_this->recv.coher_cnt++;
				_this->recv.coher_cnt &= COHERENCY_CNT_MASK;
				mppe_key_change(_this, &_this->recv);
				pktloss++;
			}
		}
		mppe_rc4_setoldkey(_this, &_this->recv, coher_cnt);
		flushed = 1;
	} else {
		if (flushed) {
			if (coher_cnt < _this->recv.coher_cnt) {
				/* in case of carrying up. */
				coher_cnt += 0x1000;
			}
			pktloss += coher_cnt - _this->recv.coher_cnt;
			m = _this->recv.coher_cnt / 256;
			n = coher_cnt / 256;
			while (m++ < n)
				mppe_key_change(_this, &_this->recv);

			coher_cnt &= COHERENCY_CNT_MASK;
			_this->recv.coher_cnt = coher_cnt;
		} else if (_this->recv.coher_cnt != coher_cnt) {
			_this->recv.resetreq = 1;

			opktp0 = ppp_packetbuf(_this->ppp,
			    PPP_PROTO_NCP | NCP_CCP);
			opktp = opktp0;

			PUTLONG(_this->ppp->ccp.mppe_p_bits, opktp);

			ppp_output(_this->ppp, PPP_PROTO_NCP | NCP_CCP,
			    RESETREQ, _this->recv.resetreq, opktp0,
				opktp - opktp0);
			return;
		}
		if ((coher_cnt & 0xff) == 0xff) {
			mppe_key_change(_this, &_this->recv);
			flushed = 1;
		}
		if (flushed) {
			mppe_rc4_setkey(_this, &_this->recv);
		}
	}

	if (pktloss > 1000) {
		/*
		 * In case of many packets losing or out of sequence.
		 * The latter is not able to communicate because the key is
		 * out of place soon.
		 *
		 */
		mppe_log(_this, LOG_WARNING, "%d packets loss", pktloss);
	}

	mppe_rc4_encrypt(_this, &_this->recv, len - 2, pktp, pktp);

	if (!delayed) {
		_this->recv.coher_cnt++;
		_this->recv.coher_cnt &= COHERENCY_CNT_MASK;
	}

	if (pktp[0] & 1)
		proto = pktp[0];
	else
		proto = pktp[0] << 8 | pktp[1];
	/*
	 * According to RFC3078 section 3,
	 * MPPE only accept protocol number 0021-00FA.
	 * If decrypted protocol number is out of range,
	 * it indicates loss of coherency.
	 */
	if (!(proto & 1) || proto < 0x21 || proto > 0xfa) {
		mppe_log(_this, LOG_INFO, "MPPE coherency is lost");
		return; /* drop frame */
	}

	_this->ppp->recv_packet(_this->ppp, pktp, len - 2,
	    PPP_IO_FLAGS_MPPE_ENCRYPTED);
}
Пример #6
0
static void
chap_radius_response(void *context, RADIUS_PACKET *pkt, int flags,
    RADIUS_REQUEST_CTX reqctx)
{
	int code, lrespkt;
	const char *secret, *reason = "";
	chap *_this;
	u_char *respkt, *respkt0;
	int errorCode;
	RADIUS_REQUEST_CTX radctx;

	CHAP_ASSERT(context != NULL);

	reason = "";
	errorCode = ERROR_AUTH_SERVER_TIMEOUT;
	_this = context;
	secret = radius_get_server_secret(_this->radctx);
	radctx = _this->radctx;
	_this->radctx = NULL;	/* IMPORTANT */

	respkt = respkt0 = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP)
	    + HEADERLEN;
	lrespkt = _this->ppp->mru - HEADERLEN;
	if (pkt == NULL) {
		if (flags & RADIUS_REQUEST_TIMEOUT)
			reason = "timeout";
		else if (flags & RADIUS_REQUEST_ERROR)
			reason = strerror(errno);
		else
			reason = "error";
		goto auth_failed;
	}

	code = radius_get_code(pkt);
	if (code == RADIUS_CODE_ACCESS_REJECT) {
		reason="reject";
		errorCode = ERROR_AUTHENTICATION_FAILURE;
		/* Windows peer will reset the password by this error code */
		goto auth_failed;
	} else if (code != RADIUS_CODE_ACCESS_ACCEPT) {
		reason="error";
		goto auth_failed;
	}
	if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK) == 0 &&
	    (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK) == 0) {
		reason="bad_authenticator";
		goto auth_failed;
	}
	/*
	 * Authetication OK
	 */
	switch (_this->type) {
	case PPP_AUTH_CHAP_MD5:
	    chap_response(_this, 1, "OK", 2);
	    break;
	case PPP_AUTH_CHAP_MS_V2:
	    {
		struct RADIUS_MS_CHAP2_SUCCESS success;
#ifdef USE_NPPPD_MPPE
		struct RADIUS_MPPE_KEY sendkey, recvkey;
#endif
		size_t len;

		len = sizeof(success);
		if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT,
		    RADIUS_VTYPE_MS_CHAP2_SUCCESS, &success, &len) != 0) {
			chap_log(_this, LOG_ERR, "no ms_chap2_success");
			goto auth_failed;
		}
#ifdef	USE_NPPPD_MPPE
		if (_this->ppp->mppe.enabled != 0) {
			len = sizeof(sendkey);
			if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT,
			    RADIUS_VTYPE_MPPE_SEND_KEY, &sendkey, &len) != 0) {
				chap_log(_this, LOG_ERR, "no mppe_send_key");
				goto auth_failed;
			}
			len = sizeof(recvkey);
			if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT,
			    RADIUS_VTYPE_MPPE_RECV_KEY, &recvkey, &len) != 0) {
				chap_log(_this, LOG_ERR, "no mppe_recv_key");
				goto auth_failed;
			}

			mschap_radiuskey(_this->ppp->mppe.send.master_key,
			    sendkey.salt, _this->authenticator, secret);

			mschap_radiuskey(_this->ppp->mppe.recv.master_key,
			    recvkey.salt, _this->authenticator, secret);
		}
#endif
		chap_response(_this, 1, success.str, sizeof(success.str));
		break;
	    }
	}
	ppp_process_radius_framed_ip(_this->ppp, pkt);

	return;
auth_failed:
	chap_log(_this, LOG_WARNING, "Radius authentication request failed: %s",
	    reason);
	/* No extra information */
	chap_failure(_this, "FAILED", errorCode);
}
Пример #7
0
/************************************************************************
 * Functions for RADIUS
 * RFC 2058: RADIUS
 * RFC 2548: Microsoft Vendor-specific RADIUS Attributes
 ************************************************************************/
static void
chap_radius_authenticate(chap *_this, int id, char *username,
    u_char *challenge, int lchallenge, u_char *response)
{
	void *radctx;
	RADIUS_PACKET *radpkt;
	radius_req_setting *rad_setting;
	int lpkt;
	u_char *pkt;
	char buf0[MAX_USERNAME_LENGTH];

	radpkt = NULL;
	radctx = NULL;

	if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd,
	    _this->ppp)) == NULL) {
		goto fail;	/* no radius server */
	}
	pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
	lpkt = _this->ppp->mru - HEADERLEN;

	if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST))
	    == NULL)
		goto fail;
	if (radius_prepare(rad_setting, _this, &radctx, chap_radius_response)
	    != 0) {
		radius_delete_packet(radpkt);
		goto fail;
	}

	if (ppp_set_radius_attrs_for_authreq(_this->ppp, rad_setting, radpkt)
	    != 0)
		goto fail;

	if (radius_put_string_attr(radpkt, RADIUS_TYPE_USER_NAME,
	    npppd_ppp_get_username_for_auth(_this->ppp->pppd, _this->ppp,
		username, buf0)) != 0)
		goto fail;

	switch (_this->type) {
	case PPP_AUTH_CHAP_MD5:
	    {
		u_char md5response[17];

		md5response[0] = _this->challid;
		memcpy(&md5response[1], response, 16);
		if (radius_put_raw_attr(radpkt,
		    RADIUS_TYPE_CHAP_PASSWORD, md5response, 17) != 0)
			goto fail;
		if (radius_put_raw_attr(radpkt,
		    RADIUS_TYPE_CHAP_CHALLENGE, challenge, lchallenge) != 0)
			goto fail;
		break;
	    }
	case PPP_AUTH_CHAP_MS_V2:
	    {
		struct RADIUS_MS_CHAP2_RESPONSE msresponse;

		/* Preparing RADIUS_MS_CHAP2_RESPONSE  */
		memset(&msresponse, 0, sizeof(msresponse));
		msresponse.ident = id;
		msresponse.flags = response[48];
		memcpy(&msresponse.peer_challenge, response, 16);
		memcpy(&msresponse.response, response + 24, 24);

		if (radius_put_vs_raw_attr(radpkt, RADIUS_VENDOR_MICROSOFT,
		    RADIUS_VTYPE_MS_CHAP_CHALLENGE, challenge, 16) != 0)
			goto fail;
		if (radius_put_vs_raw_attr(radpkt, RADIUS_VENDOR_MICROSOFT,
		    RADIUS_VTYPE_MS_CHAP2_RESPONSE, &msresponse,
		    sizeof(msresponse)) != 0)
			goto fail;
		break;
	    }

	}
	radius_get_authenticator(radpkt, _this->authenticator);

	/* Cancel previous request */
	if (_this->radctx != NULL)
		radius_cancel_request(_this->radctx);

	/* Send a request */
	_this->radctx = radctx;
	radius_request(radctx, radpkt);

	return;
fail:
	switch (_this->type) {
	case PPP_AUTH_CHAP_MD5:
		/* No extra information, just "FAILED" */
		chap_send_error(_this, "FAILED");
		break;
	case PPP_AUTH_CHAP_MS_V2:
		/* No extra information */
		mschapv2_send_error(_this, ERROR_AUTHENTICATION_FAILURE, 0);
		break;
	}
	if (radctx != NULL)
		radius_cancel_request(radctx);
}
Пример #8
0
static void
mschapv2_authenticate(chap *_this, int id, char *username, u_char *challenge,
    int lchallenge, u_char *response)
{
	int i, rval, passlen, lpkt;
	u_char *pkt;
	char password[MAX_PASSWORD_LENGTH * 2], ntresponse[24];
#ifdef	USE_NPPPD_MPPE
	char pwdhash[16], pwdhashhash[16];
#endif

	CHAP_DBG((_this, LOG_DEBUG, "%s()", __func__));
	pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
	lpkt = _this->ppp->mru - HEADERLEN;

	passlen = sizeof(password) / 2;
	rval = npppd_get_user_password(_this->ppp->pppd, _this->ppp, username,
	    password, &passlen);

	if (rval != 0) {
		switch (rval) {
		case 1:
			chap_log(_this, LOG_INFO,
			    "username=\"%s\" user unknown", username);
			break;
		default:
			chap_log(_this, LOG_ERR,
			    "username=\"%s\" generic error", username);
			break;
		}
		goto auth_failed;
	}

	/* Convert the string charset from ASCII to UTF16-LE */
	passlen = strlen(password);
	for (i = passlen - 1; i >= 0; i--) {
		password[i*2] = password[i];
		password[i*2+1] = 0;
	}

	mschap_nt_response(challenge, response, username, strlen(username),
		    password, passlen * 2, ntresponse);

	if (memcmp(ntresponse, response + 24, 24) != 0) {
		chap_log(_this, LOG_INFO,
		    "username=\"%s\" password mismatch.", username);
		goto auth_failed;
	}

    /*
     * Authentication succeed
     */
	CHAP_DBG((_this, LOG_DEBUG, "%s() OK", __func__));

	mschap_auth_response(password, passlen * 2, ntresponse,
	    challenge, response, username, strlen(username), pkt);
	lpkt = 42;
#ifdef	USE_NPPPD_MPPE
	if (_this->ppp->mppe.enabled != 0) {
		mschap_ntpassword_hash(password, passlen * 2, pwdhash);
		mschap_ntpassword_hash(pwdhash, sizeof(pwdhash), pwdhashhash);

		mschap_masterkey(pwdhashhash, ntresponse,
		    _this->ppp->mppe.master_key);
		mschap_asymetric_startkey(_this->ppp->mppe.master_key,
		    _this->ppp->mppe.recv.master_key, MPPE_KEYLEN, 0, 1);
		mschap_asymetric_startkey(_this->ppp->mppe.master_key,
		    _this->ppp->mppe.send.master_key, MPPE_KEYLEN, 1, 1);
	}
#endif
	chap_response(_this, 1, pkt, lpkt);

	return;
auth_failed:
	/* No extra information */
	mschapv2_send_error(_this, ERROR_AUTHENTICATION_FAILURE, 0);

	return;
}
Пример #9
0
/** Start CHAP as a authenticator.  Send a challenge */
void
chap_start(chap *_this)
{
	u_char *challp, *challp0;
	int lmyname;

	CHAP_ASSERT(_this != NULL);
	CHAP_ASSERT(_this->ppp != NULL);

	if (_this->state == CHAP_STATE_PROXY_AUTHENTICATION) {
		_this->type = PPP_AUTH_CHAP_MD5;
		_this->state = CHAP_STATE_AUTHENTICATING;
		chap_authenticate(_this, _this->ppp->proxy_authen_resp,
		    _this->ppp->lproxy_authen_resp);
		return;
	}

	if (_this->state == CHAP_STATE_INITIAL ||
	    _this->state == CHAP_STATE_SENT_CHALLENGE) {
		if (_this->ntry > 0) {
			_this->ntry--;
			_this->type = _this->ppp->peer_auth;

			/* The type is supported? */
			if (_this->type != PPP_AUTH_CHAP_MS_V2 &&
			    _this->type != PPP_AUTH_CHAP_MD5) {
				chap_log(_this, LOG_ALERT,
				    "Requested authentication type(0x%x) "
				    "is not supported.", _this->type);
				ppp_set_disconnect_cause(_this->ppp, 
				    PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE,
				    PPP_PROTO_CHAP, 2 /* local */, NULL);
				ppp_stop(_this->ppp, "Authentication Required");
				return;
			}


#ifdef USE_NPPPD_MPPE
			/* The peer must use MS-CHAP-V2 as the type */
			if (MPPE_IS_REQUIRED(_this->ppp) &&
			    _this->type != PPP_AUTH_CHAP_MS_V2) {
				chap_log(_this, LOG_ALERT,
				    "mppe is required but try to start chap "
				    "type=0x%02x", _this->type);
				ppp_set_disconnect_cause(_this->ppp,
				    PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE,
				    PPP_PROTO_CHAP, 2 /* local */, NULL);
				ppp_stop(_this->ppp, "Authentication Required");
				return;
			}
#endif
			/* Generate a challenge packet and send it */
			challp = ppp_packetbuf(_this->ppp, PPP_AUTH_CHAP);
			challp += HEADERLEN;
			challp0 = challp;

			chap_create_challenge(_this);

			PUTCHAR(_this->lchall, challp);
			memcpy(challp, &_this->chall, _this->lchall);
			challp += _this->lchall;

			lmyname = strlen(_this->myname);

			memcpy(challp, _this->myname, lmyname);
			challp += lmyname;

			_this->challid = ++_this->pktid;

			ppp_output(_this->ppp, PPP_PROTO_CHAP, CHAP_CHALLENGE,
			    _this->challid, challp0, challp - challp0);

			_this->state = CHAP_STATE_SENT_CHALLENGE;

			TIMEOUT((void (*)(void *))chap_start, _this,
			    CHAP_TIMEOUT);
		} else {
			chap_log(_this, LOG_INFO,
			    "Client did't respond our challenage.");
			ppp_set_disconnect_cause(_this->ppp, 
			    PPP_DISCON_AUTH_FSM_TIMEOUT,
			    PPP_PROTO_CHAP, 0, NULL);
			ppp_stop(_this->ppp, "Authentication Required");
		}
	}
}