static void eap_figure_next_state()

in net/ip/lwip_base/src/netif/ppp/eap.c [425:632]


static void eap_figure_next_state(ppp_pcb *pcb, int status) {
#ifdef USE_SRP
	unsigned char secbuf[MAXSECRETLEN], clear[8], *sp, *dp;
	struct t_pw tpw;
	struct t_confent *tce, mytce;
	char *cp, *cp2;
	struct t_server *ts;
	int id, i, plen, toffs;
	u_char vals[2];
	struct b64state bs;
#endif /* USE_SRP */

	pcb->settings.eap_timeout_time = pcb->eap.es_savedtime;
	switch (pcb->eap.es_server.ea_state) {
	case eapBadAuth:
		return;

	case eapIdentify:
#ifdef USE_SRP
		/* Discard any previous session. */
		ts = (struct t_server *)pcb->eap.es_server.ea_session;
		if (ts != NULL) {
			t_serverclose(ts);
			pcb->eap.es_server.ea_session = NULL;
			pcb->eap.es_server.ea_skey = NULL;
		}
#endif /* USE_SRP */
		if (status != 0) {
			pcb->eap.es_server.ea_state = eapBadAuth;
			break;
		}
#ifdef USE_SRP
		/* If we've got a pseudonym, try to decode to real name. */
		if (pcb->eap.es_server.ea_peerlen > SRP_PSEUDO_LEN &&
		    strncmp(pcb->eap.es_server.ea_peer, SRP_PSEUDO_ID,
			SRP_PSEUDO_LEN) == 0 &&
		    (pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN) * 3 / 4 <
		    sizeof (secbuf)) {
			BZERO(&bs, sizeof (bs));
			plen = b64dec(&bs,
			    pcb->eap.es_server.ea_peer + SRP_PSEUDO_LEN,
			    pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN,
			    secbuf);
			toffs = 0;
			for (i = 0; i < 5; i++) {
				pncrypt_setkey(toffs);
				toffs -= 86400;
				/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
				if (!DesDecrypt(secbuf, clear)) {
					ppp_dbglog("no DES here; cannot decode "
					    "pseudonym");
					return;
				}
				id = *(unsigned char *)clear;
				if (id + 1 <= plen && id + 9 > plen)
					break;
			}
			if (plen % 8 == 0 && i < 5) {
				/*
				 * Note that this is always shorter than the
				 * original stored string, so there's no need
				 * to realloc.
				 */
				if ((i = plen = *(unsigned char *)clear) > 7)
					i = 7;
				pcb->eap.es_server.ea_peerlen = plen;
				dp = (unsigned char *)pcb->eap.es_server.ea_peer;
				MEMCPY(dp, clear + 1, i);
				plen -= i;
				dp += i;
				sp = secbuf + 8;
				while (plen > 0) {
					/* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */
					(void) DesDecrypt(sp, dp);
					sp += 8;
					dp += 8;
					plen -= 8;
				}
				pcb->eap.es_server.ea_peer[
					pcb->eap.es_server.ea_peerlen] = '\0';
				ppp_dbglog("decoded pseudonym to \"%.*q\"",
				    pcb->eap.es_server.ea_peerlen,
				    pcb->eap.es_server.ea_peer);
			} else {
				ppp_dbglog("failed to decode real name");
				/* Stay in eapIdentfy state; requery */
				break;
			}
		}
		/* Look up user in secrets database. */
		if (get_srp_secret(pcb->eap.es_unit, pcb->eap.es_server.ea_peer,
		    pcb->eap.es_server.ea_name, (char *)secbuf, 1) != 0) {
			/* Set up default in case SRP entry is bad */
			pcb->eap.es_server.ea_state = eapMD5Chall;
			/* Get t_confent based on index in srp-secrets */
			id = strtol((char *)secbuf, &cp, 10);
			if (*cp++ != ':' || id < 0)
				break;
			if (id == 0) {
				mytce.index = 0;
				mytce.modulus.data = (u_char *)wkmodulus;
				mytce.modulus.len = sizeof (wkmodulus);
				mytce.generator.data = (u_char *)"\002";
				mytce.generator.len = 1;
				tce = &mytce;
			} else if ((tce = gettcid(id)) != NULL) {
				/*
				 * Client will have to verify this modulus/
				 * generator combination, and that will take
				 * a while.  Lengthen the timeout here.
				 */
				if (pcb->settings.eap_timeout_time > 0 &&
				    pcb->settings.eap_timeout_time < 30)
					pcb->settings.eap_timeout_time = 30;
			} else {
				break;
			}
			if ((cp2 = strchr(cp, ':')) == NULL)
				break;
			*cp2++ = '\0';
			tpw.pebuf.name = pcb->eap.es_server.ea_peer;
			tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf,
			    cp);
			tpw.pebuf.password.data = tpw.pwbuf;
			tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf,
			    cp2);
			tpw.pebuf.salt.data = tpw.saltbuf;
			if ((ts = t_serveropenraw(&tpw.pebuf, tce)) == NULL)
				break;
			pcb->eap.es_server.ea_session = (void *)ts;
			pcb->eap.es_server.ea_state = eapSRP1;
			vals[0] = pcb->eap.es_server.ea_id + 1;
			vals[1] = EAPT_SRP;
			t_serveraddexdata(ts, vals, 2);
			/* Generate B; must call before t_servergetkey() */
			t_servergenexp(ts);
			break;
		}
#endif /* USE_SRP */
		pcb->eap.es_server.ea_state = eapMD5Chall;
		break;

	case eapSRP1:
#ifdef USE_SRP
		ts = (struct t_server *)pcb->eap.es_server.ea_session;
		if (ts != NULL && status != 0) {
			t_serverclose(ts);
			pcb->eap.es_server.ea_session = NULL;
			pcb->eap.es_server.ea_skey = NULL;
		}
#endif /* USE_SRP */
		if (status == 1) {
			pcb->eap.es_server.ea_state = eapMD5Chall;
		} else if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
			pcb->eap.es_server.ea_state = eapBadAuth;
		} else {
			pcb->eap.es_server.ea_state = eapSRP2;
		}
		break;

	case eapSRP2:
#ifdef USE_SRP
		ts = (struct t_server *)pcb->eap.es_server.ea_session;
		if (ts != NULL && status != 0) {
			t_serverclose(ts);
			pcb->eap.es_server.ea_session = NULL;
			pcb->eap.es_server.ea_skey = NULL;
		}
#endif /* USE_SRP */
		if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
			pcb->eap.es_server.ea_state = eapBadAuth;
		} else {
			pcb->eap.es_server.ea_state = eapSRP3;
		}
		break;

	case eapSRP3:
	case eapSRP4:
#ifdef USE_SRP
		ts = (struct t_server *)pcb->eap.es_server.ea_session;
		if (ts != NULL && status != 0) {
			t_serverclose(ts);
			pcb->eap.es_server.ea_session = NULL;
			pcb->eap.es_server.ea_skey = NULL;
		}
#endif /* USE_SRP */
		if (status != 0 || pcb->eap.es_server.ea_session == NULL) {
			pcb->eap.es_server.ea_state = eapBadAuth;
		} else {
			pcb->eap.es_server.ea_state = eapOpen;
		}
		break;

	case eapMD5Chall:
		if (status != 0) {
			pcb->eap.es_server.ea_state = eapBadAuth;
		} else {
			pcb->eap.es_server.ea_state = eapOpen;
		}
		break;

	default:
		pcb->eap.es_server.ea_state = eapBadAuth;
		break;
	}
	if (pcb->eap.es_server.ea_state == eapBadAuth)
		eap_send_failure(pcb);
}