- u_char *remmd, remmd_len;
- int secret_len, old_state;
- int code;
- char rhostname[256];
- MD5_CTX mdContext;
- char secret[MAXSECRETLEN];
- u_char hash[MD5_SIGNATURE_SIZE];
-
- if (cstate->serverstate == CHAPSS_CLOSED ||
- cstate->serverstate == CHAPSS_PENDING) {
- CHAPDEBUG(("ChapReceiveResponse: in state %d", cstate->serverstate));
- return;
- }
-
- if (id != cstate->chal_id)
- return; /* doesn't match ID of last challenge */
-
- /*
- * If we have received a duplicate or bogus Response,
- * we have to send the same answer (Success/Failure)
- * as we did for the first Response we saw.
- */
- if (cstate->serverstate == CHAPSS_OPEN) {
- ChapSendStatus(cstate, CHAP_SUCCESS);
- return;
- }
- if (cstate->serverstate == CHAPSS_BADAUTH) {
- ChapSendStatus(cstate, CHAP_FAILURE);
- return;
- }
-
- if (len < 2) {
- CHAPDEBUG(("ChapReceiveResponse: rcvd short packet."));
- return;
- }
- GETCHAR(remmd_len, inp); /* get length of MD */
- remmd = inp; /* get pointer to MD */
- INCPTR(remmd_len, inp);
-
- len -= sizeof (u_char) + remmd_len;
- if (len < 0) {
- CHAPDEBUG(("ChapReceiveResponse: rcvd short packet."));
- return;
- }
-
- UNTIMEOUT(ChapChallengeTimeout, cstate);
-
- if (len >= sizeof(rhostname))
- len = sizeof(rhostname) - 1;
- BCOPY(inp, rhostname, len);
- rhostname[len] = '\000';
-
- /*
- * Get secret for authenticating them with us,
- * do the hash ourselves, and compare the result.
- */
- code = CHAP_FAILURE;
- if (!get_secret(cstate->unit, (explicit_remote? remote_name: rhostname),
- cstate->chal_name, secret, &secret_len, 1)) {
- warn("No CHAP secret found for authenticating %q", rhostname);
- } else {
-
- /* generate MD based on negotiated type */
- switch (cstate->chal_type) {
-
- case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
- if (remmd_len != MD5_SIGNATURE_SIZE)
- break; /* it's not even the right length */
- MD5Init(&mdContext);
- MD5Update(&mdContext, &cstate->chal_id, 1);
- MD5Update(&mdContext, secret, secret_len);
- MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
- MD5Final(hash, &mdContext);
-
- /* compare local and remote MDs and send the appropriate status */
- if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
- code = CHAP_SUCCESS; /* they are the same! */
- break;
-
- default:
- CHAPDEBUG(("unknown digest type %d", cstate->chal_type));
- }
- }
-
- BZERO(secret, sizeof(secret));
- ChapSendStatus(cstate, code);
-
- if (code == CHAP_SUCCESS) {
- old_state = cstate->serverstate;
- cstate->serverstate = CHAPSS_OPEN;
- if (old_state == CHAPSS_INITIAL_CHAL) {
- auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
+ int response_len, ok, mlen;
+ unsigned char *response, *p;
+ char *name = NULL;
+ chap_verify_hook_fn *verifier;
+ char rname[MAXNAMELEN+1];
+
+ if ((ss->flags & LOWERUP) == 0)
+ return;
+ if (id != ss->challenge[PPP_HDRLEN+1] || len < 2)
+ return;
+ if (ss->flags & CHALLENGE_VALID) {
+ response = pkt;
+ GETCHAR(response_len, pkt);
+ len -= response_len + 1; /* length of name */
+ name = (char *)pkt + response_len;
+ if (len < 0)
+ return;
+
+ if (ss->flags & TIMEOUT_PENDING) {
+ ss->flags &= ~TIMEOUT_PENDING;
+ UNTIMEOUT(chap_server_timeout, ss);
+ }
+
+ if (explicit_remote) {
+ name = remote_name;
+ } else {
+ /* Null terminate and clean remote name. */
+ slprintf(rname, sizeof(rname), "%.*v", len, name);
+ name = rname;
+
+ /* strip the MS domain name */
+ if (chapms_strip_domain && strrchr(rname, '\\')) {
+ char tmp[MAXNAMELEN+1];
+
+ strcpy(tmp, strrchr(rname, '\\') + 1);
+ strcpy(rname, tmp);
+ }
+ }
+
+ if (chap_verify_hook)
+ verifier = chap_verify_hook;
+ else
+ verifier = chap_verify_response;
+ ok = (*verifier)(name, ss->name, id, ss->digest,
+ ss->challenge + PPP_HDRLEN + CHAP_HDRLEN,
+ response, ss->message, sizeof(ss->message));
+ if (!ok || !auth_number()) {
+ ss->flags |= AUTH_FAILED;
+ warn("Peer %q failed CHAP authentication", name);
+ }
+ } else if ((ss->flags & AUTH_DONE) == 0)
+ return;
+
+ /* send the response */
+ p = outpacket_buf;
+ MAKEHEADER(p, PPP_CHAP);
+ mlen = strlen(ss->message);
+ len = CHAP_HDRLEN + mlen;
+ p[0] = (ss->flags & AUTH_FAILED)? CHAP_FAILURE: CHAP_SUCCESS;
+ p[1] = id;
+ p[2] = len >> 8;
+ p[3] = len;
+ if (mlen > 0)
+ memcpy(p + CHAP_HDRLEN, ss->message, mlen);
+ output(0, outpacket_buf, PPP_HDRLEN + len);
+
+ if (ss->flags & CHALLENGE_VALID) {
+ ss->flags &= ~CHALLENGE_VALID;
+ if (!(ss->flags & AUTH_DONE) && !(ss->flags & AUTH_FAILED)) {
+ /*
+ * Auth is OK, so now we need to check session restrictions
+ * to ensure everything is OK, but only if we used a
+ * plugin, and only if we're configured to check. This
+ * allows us to do PAM checks on PPP servers that
+ * authenticate against ActiveDirectory, and use AD for
+ * account info (like when using Winbind integrated with
+ * PAM).
+ */
+ if (session_mgmt &&
+ session_check(name, NULL, devnam, NULL) == 0) {
+ ss->flags |= AUTH_FAILED;
+ warn("Peer %q failed CHAP Session verification", name);
+ }
+ }
+ if (ss->flags & AUTH_FAILED) {
+ auth_peer_fail(0, PPP_CHAP);
+ } else {
+ if ((ss->flags & AUTH_DONE) == 0)
+ auth_peer_success(0, PPP_CHAP,
+ ss->digest->code,
+ name, strlen(name));
+ if (chap_rechallenge_time) {
+ ss->flags |= TIMEOUT_PENDING;
+ TIMEOUT(chap_server_timeout, ss,
+ chap_rechallenge_time);
+ }
+ }
+ ss->flags |= AUTH_DONE;