#include "netif/ppp/ppp_opts.h"
#if PPP_SUPPORT && PAP_SUPPORT
#if 0#endif
#include "netif/ppp/ppp_impl.h"
#include "netif/ppp/upap.h"
#if PPP_OPTIONS
static option_t pap_option_list[] = {
{ "hide-password", o_bool, &hide_password,
"Don't output passwords to log", OPT_PRIO | 1 },
{ "show-password", o_bool, &hide_password,
"Show password string in debug log messages", OPT_PRIOSUB | 0 },
{ "pap-restart", o_int, &upap[0].us_timeouttime,
"Set retransmit timeout for PAP", OPT_PRIO },
{ "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
"Set max number of transmissions for auth-reqs", OPT_PRIO },
{ "pap-timeout", o_int, &upap[0].us_reqtimeout,
"Set time limit for peer PAP authentication", OPT_PRIO },
{ NULL }
};
#endif
static void upap_init(ppp_pcb *pcb);
static void upap_lowerup(ppp_pcb *pcb);
static void upap_lowerdown(ppp_pcb *pcb);
static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l);
static void upap_protrej(ppp_pcb *pcb);
#if PRINTPKT_SUPPORT
static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg);
#endif
const struct protent pap_protent = {
PPP_PAP,
upap_init,
upap_input,
upap_protrej,
upap_lowerup,
upap_lowerdown,
NULL,
NULL,
#if PRINTPKT_SUPPORT
upap_printpkt,
#endif
#if PPP_DATAINPUT
NULL,
#endif
#if PRINTPKT_SUPPORT
"PAP",
NULL,
#endif
#if PPP_OPTIONS
pap_option_list,
NULL,
#endif
#if DEMAND_SUPPORT
NULL,
NULL
#endif
};
static void upap_timeout(void *arg);
#if PPP_SERVER
static void upap_reqtimeout(void *arg);
static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len);
#endif
static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len);
static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len);
static void upap_sauthreq(ppp_pcb *pcb);
#if PPP_SERVER
static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen);
#endif
static void upap_init(ppp_pcb *pcb) {
pcb->upap.us_user = NULL;
pcb->upap.us_userlen = 0;
pcb->upap.us_passwd = NULL;
pcb->upap.us_passwdlen = 0;
pcb->upap.us_clientstate = UPAPCS_INITIAL;
#if PPP_SERVER
pcb->upap.us_serverstate = UPAPSS_INITIAL;
#endif
pcb->upap.us_id = 0;
}
void upap_authwithpeer(ppp_pcb *pcb, const char *user, const char *password) {
if(!user || !password)
return;
pcb->upap.us_user = user;
pcb->upap.us_userlen = (u8_t)LWIP_MIN(strlen(user), 0xff);
pcb->upap.us_passwd = password;
pcb->upap.us_passwdlen = (u8_t)LWIP_MIN(strlen(password), 0xff);
pcb->upap.us_transmits = 0;
if (pcb->upap.us_clientstate == UPAPCS_INITIAL ||
pcb->upap.us_clientstate == UPAPCS_PENDING) {
pcb->upap.us_clientstate = UPAPCS_PENDING;
return;
}
upap_sauthreq(pcb);
}
#if PPP_SERVER
void upap_authpeer(ppp_pcb *pcb) {
if (pcb->upap.us_serverstate == UPAPSS_INITIAL ||
pcb->upap.us_serverstate == UPAPSS_PENDING) {
pcb->upap.us_serverstate = UPAPSS_PENDING;
return;
}
pcb->upap.us_serverstate = UPAPSS_LISTEN;
if (pcb->settings.pap_req_timeout > 0)
TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout);
}
#endif
static void upap_timeout(void *arg) {
ppp_pcb *pcb = (ppp_pcb*)arg;
if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ)
return;
if (pcb->upap.us_transmits >= pcb->settings.pap_max_transmits) {
ppp_error(("No response to PAP authenticate-requests"));
pcb->upap.us_clientstate = UPAPCS_BADAUTH;
auth_withpeer_fail(pcb, PPP_PAP);
return;
}
upap_sauthreq(pcb);
}
#if PPP_SERVER
static void upap_reqtimeout(void *arg) {
ppp_pcb *pcb = (ppp_pcb*)arg;
if (pcb->upap.us_serverstate != UPAPSS_LISTEN)
return;
auth_peer_fail(pcb, PPP_PAP);
pcb->upap.us_serverstate = UPAPSS_BADAUTH;
}
#endif
static void upap_lowerup(ppp_pcb *pcb) {
if (pcb->upap.us_clientstate == UPAPCS_INITIAL)
pcb->upap.us_clientstate = UPAPCS_CLOSED;
else if (pcb->upap.us_clientstate == UPAPCS_PENDING) {
upap_sauthreq(pcb);
}
#if PPP_SERVER
if (pcb->upap.us_serverstate == UPAPSS_INITIAL)
pcb->upap.us_serverstate = UPAPSS_CLOSED;
else if (pcb->upap.us_serverstate == UPAPSS_PENDING) {
pcb->upap.us_serverstate = UPAPSS_LISTEN;
if (pcb->settings.pap_req_timeout > 0)
TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout);
}
#endif
}
static void upap_lowerdown(ppp_pcb *pcb) {
if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ)
UNTIMEOUT(upap_timeout, pcb);
#if PPP_SERVER
if (pcb->upap.us_serverstate == UPAPSS_LISTEN && pcb->settings.pap_req_timeout > 0)
UNTIMEOUT(upap_reqtimeout, pcb);
#endif
pcb->upap.us_clientstate = UPAPCS_INITIAL;
#if PPP_SERVER
pcb->upap.us_serverstate = UPAPSS_INITIAL;
#endif
}
static void upap_protrej(ppp_pcb *pcb) {
if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) {
ppp_error(("PAP authentication failed due to protocol-reject"));
auth_withpeer_fail(pcb, PPP_PAP);
}
#if PPP_SERVER
if (pcb->upap.us_serverstate == UPAPSS_LISTEN) {
ppp_error(("PAP authentication of peer failed (protocol-reject)"));
auth_peer_fail(pcb, PPP_PAP);
}
#endif
upap_lowerdown(pcb);
}
static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l) {
u_char *inp;
u_char code, id;
int len;
inp = inpacket;
if (l < UPAP_HEADERLEN) {
UPAPDEBUG(("pap_input: rcvd short header."));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
GETSHORT(len, inp);
if (len < UPAP_HEADERLEN) {
UPAPDEBUG(("pap_input: rcvd illegal length."));
return;
}
if (len > l) {
UPAPDEBUG(("pap_input: rcvd short packet."));
return;
}
len -= UPAP_HEADERLEN;
switch (code) {
case UPAP_AUTHREQ:
#if PPP_SERVER
upap_rauthreq(pcb, inp, id, len);
#endif
break;
case UPAP_AUTHACK:
upap_rauthack(pcb, inp, id, len);
break;
case UPAP_AUTHNAK:
upap_rauthnak(pcb, inp, id, len);
break;
default:
break;
}
}
#if PPP_SERVER
static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len) {
u_char ruserlen, rpasswdlen;
char *ruser;
char *rpasswd;
char rhostname[256];
int retcode;
const char *msg;
int msglen;
if (pcb->upap.us_serverstate < UPAPSS_LISTEN)
return;
if (pcb->upap.us_serverstate == UPAPSS_OPEN) {
upap_sresp(pcb, UPAP_AUTHACK, id, "", 0);
return;
}
if (pcb->upap.us_serverstate == UPAPSS_BADAUTH) {
upap_sresp(pcb, UPAP_AUTHNAK, id, "", 0);
return;
}
if (len < 1) {
UPAPDEBUG(("pap_rauth: rcvd short packet."));
return;
}
GETCHAR(ruserlen, inp);
len -= sizeof (u_char) + ruserlen + sizeof (u_char);
if (len < 0) {
UPAPDEBUG(("pap_rauth: rcvd short packet."));
return;
}
ruser = (char *) inp;
INCPTR(ruserlen, inp);
GETCHAR(rpasswdlen, inp);
if (len < rpasswdlen) {
UPAPDEBUG(("pap_rauth: rcvd short packet."));
return;
}
rpasswd = (char *) inp;
retcode = UPAP_AUTHNAK;
if (auth_check_passwd(pcb, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen)) {
retcode = UPAP_AUTHACK;
}
BZERO(rpasswd, rpasswdlen);
#if 0#endif
upap_sresp(pcb, retcode, id, msg, msglen);
ppp_slprintf(rhostname, sizeof(rhostname), "%.*v", ruserlen, ruser);
if (retcode == UPAP_AUTHACK) {
pcb->upap.us_serverstate = UPAPSS_OPEN;
ppp_notice(("PAP peer authentication succeeded for %q", rhostname));
auth_peer_success(pcb, PPP_PAP, 0, ruser, ruserlen);
} else {
pcb->upap.us_serverstate = UPAPSS_BADAUTH;
ppp_warn(("PAP peer authentication failed for %q", rhostname));
auth_peer_fail(pcb, PPP_PAP);
}
if (pcb->settings.pap_req_timeout > 0)
UNTIMEOUT(upap_reqtimeout, pcb);
}
#endif
static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len) {
u_char msglen;
char *msg;
LWIP_UNUSED_ARG(id);
if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ)
return;
if (len < 1) {
UPAPDEBUG(("pap_rauthack: ignoring missing msg-length."));
} else {
GETCHAR(msglen, inp);
if (msglen > 0) {
len -= sizeof (u_char);
if (len < msglen) {
UPAPDEBUG(("pap_rauthack: rcvd short packet."));
return;
}
msg = (char *) inp;
PRINTMSG(msg, msglen);
}
}
UNTIMEOUT(upap_timeout, pcb);
pcb->upap.us_clientstate = UPAPCS_OPEN;
auth_withpeer_success(pcb, PPP_PAP, 0);
}
static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len) {
u_char msglen;
char *msg;
LWIP_UNUSED_ARG(id);
if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ)
return;
if (len < 1) {
UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length."));
} else {
GETCHAR(msglen, inp);
if (msglen > 0) {
len -= sizeof (u_char);
if (len < msglen) {
UPAPDEBUG(("pap_rauthnak: rcvd short packet."));
return;
}
msg = (char *) inp;
PRINTMSG(msg, msglen);
}
}
UNTIMEOUT(upap_timeout, pcb);
pcb->upap.us_clientstate = UPAPCS_BADAUTH;
ppp_error(("PAP authentication failed"));
auth_withpeer_fail(pcb, PPP_PAP);
}
static void upap_sauthreq(ppp_pcb *pcb) {
struct pbuf *p;
u_char *outp;
int outlen;
outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
pcb->upap.us_userlen + pcb->upap.us_passwdlen;
p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
pbuf_free(p);
return;
}
outp = (u_char*)p->payload;
MAKEHEADER(outp, PPP_PAP);
PUTCHAR(UPAP_AUTHREQ, outp);
PUTCHAR(++pcb->upap.us_id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(pcb->upap.us_userlen, outp);
MEMCPY(outp, pcb->upap.us_user, pcb->upap.us_userlen);
INCPTR(pcb->upap.us_userlen, outp);
PUTCHAR(pcb->upap.us_passwdlen, outp);
MEMCPY(outp, pcb->upap.us_passwd, pcb->upap.us_passwdlen);
ppp_write(pcb, p);
TIMEOUT(upap_timeout, pcb, pcb->settings.pap_timeout_time);
++pcb->upap.us_transmits;
pcb->upap.us_clientstate = UPAPCS_AUTHREQ;
}
#if PPP_SERVER
static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen) {
struct pbuf *p;
u_char *outp;
int outlen;
outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
pbuf_free(p);
return;
}
outp = (u_char*)p->payload;
MAKEHEADER(outp, PPP_PAP);
PUTCHAR(code, outp);
PUTCHAR(id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(msglen, outp);
MEMCPY(outp, msg, msglen);
ppp_write(pcb, p);
}
#endif
#if PRINTPKT_SUPPORT
static const char* const upap_codenames[] = {
"AuthReq", "AuthAck", "AuthNak"
};
static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg) {
int code, id, len;
int mlen, ulen, wlen;
const u_char *user, *pwd, *msg;
const u_char *pstart;
if (plen < UPAP_HEADERLEN)
return 0;
pstart = p;
GETCHAR(code, p);
GETCHAR(id, p);
GETSHORT(len, p);
if (len < UPAP_HEADERLEN || len > plen)
return 0;
if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(upap_codenames))
printer(arg, " %s", upap_codenames[code-1]);
else
printer(arg, " code=0x%x", code);
printer(arg, " id=0x%x", id);
len -= UPAP_HEADERLEN;
switch (code) {
case UPAP_AUTHREQ:
if (len < 1)
break;
ulen = p[0];
if (len < ulen + 2)
break;
wlen = p[ulen + 1];
if (len < ulen + wlen + 2)
break;
user = (const u_char *) (p + 1);
pwd = (const u_char *) (p + ulen + 2);
p += ulen + wlen + 2;
len -= ulen + wlen + 2;
printer(arg, " user=");
ppp_print_string(user, ulen, printer, arg);
printer(arg, " password=");
#if 0#endif
ppp_print_string(pwd, wlen, printer, arg);
#if 0#endif
break;
case UPAP_AUTHACK:
case UPAP_AUTHNAK:
if (len < 1)
break;
mlen = p[0];
if (len < mlen + 1)
break;
msg = (const u_char *) (p + 1);
p += mlen + 1;
len -= mlen + 1;
printer(arg, " ");
ppp_print_string(msg, mlen, printer, arg);
break;
default:
break;
}
for (; len > 0; --len) {
GETCHAR(code, p);
printer(arg, " %.2x", code);
}
return p - pstart;
}
#endif
#endif