static int chapms2_check_success(ppp_pcb *pcb, unsigned char *msg, int len, unsigned char *private_) { LWIP_UNUSED_ARG(pcb); if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || strncmp((char *)msg, "S=", 2) != 0) { /* Packet does not start with "S=" */ ppp_error("MS-CHAPv2 Success packet is badly formed."); return 0; } msg += 2; len -= 2; if (len < MS_AUTH_RESPONSE_LENGTH || memcmp(msg, private_, MS_AUTH_RESPONSE_LENGTH)) { /* Authenticator Response did not match expected. */ ppp_error("MS-CHAPv2 mutual authentication failed."); return 0; } /* Authenticator Response matches. */ msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */ len -= MS_AUTH_RESPONSE_LENGTH; if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) { msg += 3; /* Eat the delimiter */ } else if (len) { /* Packet has extra text which does not begin " M=" */ ppp_error("MS-CHAPv2 Success packet is badly formed."); return 0; } return 1; }
/* * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. */ static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) { int ret; int treat_as_reject; if (id != f->reqid || f->seen_ack) /* Expected id? */ return; /* Nope, toss... */ if (code == CONFNAK) { ++f->rnakloops; treat_as_reject = (f->rnakloops >= f->maxnakloops); if (f->callbacks->nakci == NULL || !(ret = f->callbacks->nakci(f, inp, len, treat_as_reject))) { ppp_error("Received bad configure-nak: %P", inp, len); return; } } else { f->rnakloops = 0; if (f->callbacks->rejci == NULL || !(ret = f->callbacks->rejci(f, inp, len))) { ppp_error("Received bad configure-rej: %P", inp, len); return; } } f->seen_ack = 1; switch (f->state) { case PPP_FSM_CLOSED: case PPP_FSM_STOPPED: fsm_sdata(f, TERMACK, id, NULL, 0); break; case PPP_FSM_REQSENT: case PPP_FSM_ACKSENT: /* They didn't agree to what we wanted - try another request */ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ if (ret < 0) f->state = PPP_FSM_STOPPED; /* kludge for stopping CCP */ else fsm_sconfreq(f, 0); /* Send Configure-Request */ break; case PPP_FSM_ACKRCVD: /* Got a Nak/reject when we had already had an Ack?? oh well... */ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ fsm_sconfreq(f, 0); f->state = PPP_FSM_REQSENT; break; case PPP_FSM_OPENED: /* Go down and restart negotiation */ if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); /* Send initial Configure-Request */ f->state = PPP_FSM_REQSENT; break; default: break; } }
/* * upap_protrej - Peer doesn't speak this protocol. * * This shouldn't happen. In any case, pretend lower layer went down. */ 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 /* PPP_SERVER */ upap_lowerdown(pcb); }
/* * upap_rauthnak - Receive Authenticate-Nak. */ 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) /* XXX */ return; /* * Parse message. */ 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); } } pcb->upap.us_clientstate = UPAPCS_BADAUTH; ppp_error("PAP authentication failed"); auth_withpeer_fail(pcb, PPP_PAP); }
/* * fsm_rconfack - Receive Configure-Ack. */ static void fsm_rconfack(fsm *f, int id, u_char *inp, int len) { ppp_pcb *pcb = f->pcb; if (id != f->reqid || f->seen_ack) /* Expected id? */ return; /* Nope, toss... */ if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ){ /* Ack is bad - ignore it */ ppp_error("Received bad configure-ack: %P", inp, len); return; } f->seen_ack = 1; f->rnakloops = 0; switch (f->state) { case PPP_FSM_CLOSED: case PPP_FSM_STOPPED: fsm_sdata(f, TERMACK, id, NULL, 0); break; case PPP_FSM_REQSENT: f->state = PPP_FSM_ACKRCVD; f->retransmits = pcb->settings.fsm_max_conf_req_transmits; break; case PPP_FSM_ACKRCVD: /* Huh? an extra valid Ack? oh well... */ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ fsm_sconfreq(f, 0); f->state = PPP_FSM_REQSENT; break; case PPP_FSM_ACKSENT: UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ f->state = PPP_FSM_OPENED; f->retransmits = pcb->settings.fsm_max_conf_req_transmits; if (f->callbacks->up) (*f->callbacks->up)(f); /* Inform upper layers */ break; case PPP_FSM_OPENED: /* Go down and restart negotiation */ if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); /* Send initial Configure-Request */ f->state = PPP_FSM_REQSENT; break; default: break; } }
/* * upap_timeout - Retransmission timer for sending auth-reqs expired. */ 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) { /* give up in disgust */ ppp_error("No response to PAP authenticate-requests"); pcb->upap.us_clientstate = UPAPCS_BADAUTH; auth_withpeer_fail(pcb, PPP_PAP); return; } upap_sauthreq(pcb); /* Send Authenticate-Request */ }
static void chap_protrej(ppp_pcb *pcb) { #if PPP_SERVER if (pcb->chap_server.flags & TIMEOUT_PENDING) { pcb->chap_server.flags &= ~TIMEOUT_PENDING; UNTIMEOUT(chap_timeout, pcb); } if (pcb->chap_server.flags & AUTH_STARTED) { pcb->chap_server.flags = 0; auth_peer_fail(pcb, PPP_CHAP); } #endif /* PPP_SERVER */ if ((pcb->chap_client.flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) { pcb->chap_client.flags &= ~AUTH_STARTED; ppp_error("CHAP authentication failed due to protocol-reject"); auth_withpeer_fail(pcb, PPP_CHAP); } }
/* * chap_verify_response - check whether the peer's response matches * what we think it should be. Returns 1 if it does (authentication * succeeded), or 0 if it doesn't. */ static int chap_verify_response(ppp_pcb *pcb, const char *name, const char *ourname, int id, const struct chap_digest_type *digest, const unsigned char *challenge, const unsigned char *response, char *message, int message_space) { int ok; unsigned char secret[MAXSECRETLEN]; int secret_len; /* Get the secret that the peer is supposed to know */ if (!get_secret(pcb, name, ourname, (char *)secret, &secret_len, 1)) { ppp_error("No CHAP secret found for authenticating %q", name); return 0; } ok = digest->verify_response(pcb, id, name, secret, secret_len, challenge, response, message, message_space); memset(secret, 0, sizeof(secret)); return ok; }
/* * chap_auth_with_peer - Prepare to authenticate ourselves to the peer. * There isn't much to do until we receive a challenge. */ void chap_auth_with_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { const struct chap_digest_type *dp; int i; if(NULL == our_name) return; if (pcb->chap_client.flags & AUTH_STARTED) { ppp_error("CHAP: authentication with peer already started!"); return; } for (i = 0; (dp = chap_digests[i]) != NULL; ++i) if (dp->code == digest_code) break; if (dp == NULL) ppp_fatal("CHAP digest 0x%x requested but not available", digest_code); pcb->chap_client.digest = dp; pcb->chap_client.name = our_name; pcb->chap_client.flags |= AUTH_STARTED; }
/* * chap_auth_peer - Start authenticating the peer. * If the lower layer is already up, we start sending challenges, * otherwise we wait for the lower layer to come up. */ void chap_auth_peer(ppp_pcb *pcb, const char *our_name, int digest_code) { const struct chap_digest_type *dp; int i; if (pcb->chap_server.flags & AUTH_STARTED) { ppp_error("CHAP: peer authentication already started!"); return; } for (i = 0; (dp = chap_digests[i]) != NULL; ++i) if (dp->code == digest_code) break; if (dp == NULL) ppp_fatal("CHAP digest 0x%x requested but not available", digest_code); pcb->chap_server.digest = dp; pcb->chap_server.name = our_name; /* Start with a random ID value */ pcb->chap_server.id = magic(); pcb->chap_server.flags |= AUTH_STARTED; if (pcb->chap_server.flags & LOWERUP) chap_timeout(pcb); }
static void chap_handle_status(ppp_pcb *pcb, int code, int id, unsigned char *pkt, int len) { const char *msg = NULL; LWIP_UNUSED_ARG(id); if ((pcb->chap_client.flags & (AUTH_DONE|AUTH_STARTED|LOWERUP)) != (AUTH_STARTED|LOWERUP)) return; pcb->chap_client.flags |= AUTH_DONE; if (code == CHAP_SUCCESS) { /* used for MS-CHAP v2 mutual auth, yuck */ if (pcb->chap_client.digest->check_success != NULL) { if (!(*pcb->chap_client.digest->check_success)(pcb, pkt, len, pcb->chap_client.priv)) code = CHAP_FAILURE; } else msg = "CHAP authentication succeeded"; } else { if (pcb->chap_client.digest->handle_failure != NULL) (*pcb->chap_client.digest->handle_failure)(pcb, pkt, len); else msg = "CHAP authentication failed"; } if (msg) { if (len > 0) ppp_info("%s: %.*v", msg, len, pkt); else ppp_info("%s", msg); } if (code == CHAP_SUCCESS) auth_withpeer_success(pcb, PPP_CHAP, pcb->chap_client.digest->code); else { pcb->chap_client.flags |= AUTH_FAILED; ppp_error("CHAP authentication failed"); auth_withpeer_fail(pcb, PPP_CHAP); } }
static void chapms_handle_failure(ppp_pcb *pcb, unsigned char *inp, int len) { int err; const char *p; char msg[64]; LWIP_UNUSED_ARG(pcb); /* We want a null-terminated string for strxxx(). */ len = LWIP_MIN(len, 63); MEMCPY(msg, inp, len); msg[len] = 0; p = msg; /* * Deal with MS-CHAP formatted failure messages; just print the * M=<message> part (if any). For MS-CHAP we're not really supposed * to use M=<message>, but it shouldn't hurt. See * chapms[2]_verify_response. */ if (!strncmp(p, "E=", 2)) err = strtol(p+2, NULL, 10); /* Remember the error code. */ else goto print_msg; /* Message is badly formatted. */ if (len && ((p = strstr(p, " M=")) != NULL)) { /* M=<message> field found. */ p += 3; } else { /* No M=<message>; use the error code. */ switch (err) { case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS: p = "E=646 Restricted logon hours"; break; case MS_CHAP_ERROR_ACCT_DISABLED: p = "E=647 Account disabled"; break; case MS_CHAP_ERROR_PASSWD_EXPIRED: p = "E=648 Password expired"; break; case MS_CHAP_ERROR_NO_DIALIN_PERMISSION: p = "E=649 No dialin permission"; break; case MS_CHAP_ERROR_AUTHENTICATION_FAILURE: p = "E=691 Authentication failure"; break; case MS_CHAP_ERROR_CHANGING_PASSWORD: /* Should never see this, we don't support Change Password. */ p = "E=709 Error changing password"; break; default: ppp_error("Unknown MS-CHAP authentication failure: %.*v", len, inp); return; } } print_msg: if (p != NULL) ppp_error("MS-CHAP authentication failed: %v", p); }