]> git.ozlabs.org Git - ppp.git/commitdiff
pppd: Add client CHAP authentication timeout
authorSimon Arlott <git@sa.me.uk>
Sat, 4 Jul 2015 16:32:18 +0000 (17:32 +0100)
committerSimon Arlott <git@sa.me.uk>
Thu, 6 Aug 2020 11:25:08 +0000 (12:25 +0100)
If CHAP authentication is required with the peer but this is never
completed (either because the server never sends the challenge or
because the client doesn't receive the outcome) then the client
will wait forever, relying on the server to terminate the connection.

There are options for server side retries but a client side timeout
option is required to prevent the client from getting stuck if the
server won't terminate the connection. This is defaulted to 60 seconds.

Signed-off-by: Simon Arlott <git@sa.me.uk>
pppd/chap-new.c
pppd/pppd.8

index 2714bff6478589412aeed098f77262e89a91349c..2e74fb86151ce99460c1ce7ca12b9b6e44075e87 100644 (file)
@@ -55,20 +55,23 @@ int (*chap_verify_hook)(char *name, char *ourname, int id,
 /*
  * Option variables.
  */
-int chap_timeout_time = 3;
+int chap_server_timeout_time = 3;
 int chap_max_transmits = 10;
 int chap_rechallenge_time = 0;
+int chap_client_timeout_time = 60;
 
 /*
  * Command-line options.
  */
 static option_t chap_option_list[] = {
-       { "chap-restart", o_int, &chap_timeout_time,
-         "Set timeout for CHAP", OPT_PRIO },
+       { "chap-restart", o_int, &chap_server_timeout_time,
+         "Set timeout for CHAP (as server)", OPT_PRIO },
        { "chap-max-challenge", o_int, &chap_max_transmits,
          "Set max #xmits for challenge", OPT_PRIO },
        { "chap-interval", o_int, &chap_rechallenge_time,
          "Set interval for rechallenge", OPT_PRIO },
+       { "chap-timeout", o_int, &chap_client_timeout_time,
+         "Set timeout for CHAP (as client)", OPT_PRIO },
        { NULL }
 };
 
@@ -114,7 +117,8 @@ static struct chap_server_state {
 static void chap_init(int unit);
 static void chap_lowerup(int unit);
 static void chap_lowerdown(int unit);
-static void chap_timeout(void *arg);
+static void chap_server_timeout(void *arg);
+static void chap_client_timeout(void *arg);
 static void chap_generate_challenge(struct chap_server_state *ss);
 static void chap_handle_response(struct chap_server_state *ss, int code,
                unsigned char *pkt, int len);
@@ -171,7 +175,7 @@ chap_lowerup(int unit)
        cs->flags |= LOWERUP;
        ss->flags |= LOWERUP;
        if (ss->flags & AUTH_STARTED)
-               chap_timeout(ss);
+               chap_server_timeout(ss);
 }
 
 static void
@@ -180,9 +184,11 @@ chap_lowerdown(int unit)
        struct chap_client_state *cs = &client;
        struct chap_server_state *ss = &server;
 
+       if (cs->flags & TIMEOUT_PENDING)
+               UNTIMEOUT(chap_client_timeout, cs);
        cs->flags = 0;
        if (ss->flags & TIMEOUT_PENDING)
-               UNTIMEOUT(chap_timeout, ss);
+               UNTIMEOUT(chap_server_timeout, ss);
        ss->flags = 0;
 }
 
@@ -214,7 +220,7 @@ chap_auth_peer(int unit, char *our_name, int digest_code)
        ss->id = (unsigned char)(drand48() * 256);
        ss->flags |= AUTH_STARTED;
        if (ss->flags & LOWERUP)
-               chap_timeout(ss);
+               chap_server_timeout(ss);
 }
 
 /*
@@ -240,16 +246,17 @@ chap_auth_with_peer(int unit, char *our_name, int digest_code)
 
        cs->digest = dp;
        cs->name = our_name;
-       cs->flags |= AUTH_STARTED;
+       cs->flags |= AUTH_STARTED | TIMEOUT_PENDING;
+       TIMEOUT(chap_client_timeout, cs, chap_client_timeout_time);
 }
 
 /*
- * chap_timeout - It's time to send another challenge to the peer.
+ * chap_server_timeout - It's time to send another challenge to the peer.
  * This could be either a retransmission of a previous challenge,
  * or a new challenge to start re-authentication.
  */
 static void
-chap_timeout(void *arg)
+chap_server_timeout(void *arg)
 {
        struct chap_server_state *ss = arg;
 
@@ -268,7 +275,19 @@ chap_timeout(void *arg)
        output(0, ss->challenge, ss->challenge_pktlen);
        ++ss->challenge_xmits;
        ss->flags |= TIMEOUT_PENDING;
-       TIMEOUT(chap_timeout, arg, chap_timeout_time);
+       TIMEOUT(chap_server_timeout, arg, chap_server_timeout_time);
+}
+
+/* chap_client_timeout - Authentication with peer timed out. */
+static void
+chap_client_timeout(void *arg)
+{
+       struct chap_client_state *cs = arg;
+
+       cs->flags &= ~TIMEOUT_PENDING;
+       cs->flags |= AUTH_DONE | AUTH_FAILED;
+       error("CHAP authentication timed out");
+       auth_withpeer_fail(0, PPP_CHAP);
 }
 
 /*
@@ -327,7 +346,7 @@ chap_handle_response(struct chap_server_state *ss, int id,
 
                if (ss->flags & TIMEOUT_PENDING) {
                        ss->flags &= ~TIMEOUT_PENDING;
-                       UNTIMEOUT(chap_timeout, ss);
+                       UNTIMEOUT(chap_server_timeout, ss);
                }
 
                if (explicit_remote) {
@@ -392,7 +411,7 @@ chap_handle_response(struct chap_server_state *ss, int id,
                                                  name, strlen(name));
                        if (chap_rechallenge_time) {
                                ss->flags |= TIMEOUT_PENDING;
-                               TIMEOUT(chap_timeout, ss,
+                               TIMEOUT(chap_server_timeout, ss,
                                        chap_rechallenge_time);
                        }
                }
@@ -495,6 +514,9 @@ chap_handle_status(struct chap_client_state *cs, int code, int id,
                return;
        cs->flags |= AUTH_DONE;
 
+       UNTIMEOUT(chap_client_timeout, cs);
+       cs->flags &= ~TIMEOUT_PENDING;
+
        if (code == CHAP_SUCCESS) {
                /* used for MS-CHAP v2 mutual auth, yuck */
                if (cs->digest->check_success != NULL) {
@@ -562,7 +584,7 @@ chap_protrej(int unit)
 
        if (ss->flags & TIMEOUT_PENDING) {
                ss->flags &= ~TIMEOUT_PENDING;
-               UNTIMEOUT(chap_timeout, ss);
+               UNTIMEOUT(chap_server_timeout, ss);
        }
        if (ss->flags & AUTH_STARTED) {
                ss->flags = 0;
index c508d277df3aa5539dd3c0d94787d97f71709956..a97941d42b1f31d6e6ec152fcb59667cb1a1cc50 100644 (file)
@@ -277,6 +277,9 @@ Set the maximum number of CHAP challenge transmissions to \fIn\fR
 Set the CHAP restart interval (retransmission timeout for challenges)
 to \fIn\fR seconds (default 3).
 .TP
+.B chap-timeout \fIn
+Set timeout for CHAP authentication by peer to \fIn\fR seconds (default 60).
+.TP
 .B child\-timeout \fIn
 When exiting, wait for up to \fIn\fR seconds for any child processes
 (such as the command specified with the \fBpty\fR command) to exit