Package: bpalogin
Version: 2.0.2-10.1
Severity: important
Tags: patch

Bpalogin started dieing for me in May.  It behaved the same
way on two systems - one was Debian Sarge, and the other a
RedHat 7.2 system (2001 vintage).  Symptoms were the same in
both cases: bpalogin was running but Telstra had kicked me
off.  This happens approx every 2 hours or so.  There is one
other report of this here:

   
http://sourceforge.net/tracker/index.php?func=detail&aid=1726804&group_id=19555&atid=219555

The underlying cause of this turned out to be that bpalogin
was waiting for a response from Telstra to a login request.
The request was sent over a TCP connection.  The response
never comes, the TCP connection doesn't die, Bigpond closes
the modems session and the TCP connection still survives,
and bpalogin continues to wait indefinitely.  This didn't
happen before so I presume Telstra changed something.

The attached patch, which is working on my production machines,
fixes the problem by timeing out after 30 seconds if no
response is received.  The login attempt is then re-tried.
It always works the second time around.

I have sent the patch upstream, but is uses what I suspect
are 'nix specific functions (eg alarm()) and so probably
won't work on Win32, and that means it probably won't be
accepted.

A version of bpalogin with the patch applied can be found
here:

  https://www.stuart.id.au/russell/files/debian/sarge/bpalogin

One other request.  Would you mind changing recommends to:

  Recommends: dhcp-client | dhcp3-client


-- System Information:
Debian Release: 3.1
Architecture: i386 (i686)
Kernel: Linux 2.6.8-16sarge4-lube-686-smp
Locale: LANG=en_AU, LC_CTYPE=en_AU (charmap=ISO-8859-1)

Versions of packages bpalogin depends on:
ii  libc6                 2.3.2.ds1-22sarge6 GNU C Library: Shared libraries an
ii  lsb-base              3.0-11             Linux Standard Base 3.0 init scrip
ii  sysv-rc               2.86.ds1-1         Standard boot mechanism using syml

-- no debconf information
diff -Nur bpalogin-2.0.2/bpalogin.h.in bpalogin-2.0.2-new/bpalogin.h.in
--- bpalogin-2.0.2/bpalogin.h.in	2007-06-06 20:02:31.000000000 +1000
+++ bpalogin-2.0.2-new/bpalogin.h.in	2007-06-07 11:48:29.626417828 +1000
@@ -131,6 +131,8 @@
 #define T_MSG_RESTART_RESP 14
 #define T_MSG_MAX 14
 
+#define T_MSG_TIMEOUT 9999
+
 /*
 ** message parameter codes
 */
diff -Nur bpalogin-2.0.2/protocol.c bpalogin-2.0.2-new/protocol.c
--- bpalogin-2.0.2/protocol.c	2007-06-06 20:02:31.000000000 +1000
+++ bpalogin-2.0.2-new/protocol.c	2007-06-07 11:48:29.627417673 +1000
@@ -64,12 +64,16 @@
 	int err;
 	char credentials[16];
 	time_t logintime;
+	int returnvalue = 0;
 
 	int authsocket;
 	struct transaction t;
 	INT2 transactiontype;
 	int addrsize;
 
+	if (alarm(15) == -1)
+	  	s->debug(0, "alarm failed!");
+
 	s->localaddr.sin_port = htons(0);
 
 	authsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
@@ -77,8 +81,7 @@
 	if(err)
 	{
 		socketerror(s,"Error binding auth socket");
-		closesocket(authsocket);
-		return 0;
+		goto exit;
 	}
 		
 	err = connect(authsocket,(struct sockaddr *)&s->authhost,sizeof(struct sockaddr_in));
@@ -86,8 +89,7 @@
 	if(err)
 	{
 		socketerror(s,"Cant connect to auth server");
-		closesocket(authsocket);
-		return 0;
+		goto exit;
 	}
 	addrsize = sizeof(struct sockaddr_in);
 	err = getsockname(authsocket,(struct sockaddr *)&s->localipaddress,&addrsize);
@@ -104,10 +106,15 @@
 	send_transaction(s,authsocket,&t);
 
 	transactiontype = receive_transaction(s,authsocket,&t);
+	if(transactiontype == T_MSG_TIMEOUT)
+	{
+		socketerror(s,"TIMEOUT wating for login negotiate response");
+		goto exit;
+	}
 	if(transactiontype != T_MSG_PROTOCOL_NEG_RESP)
 	{
 		s->debug(0,"T_MSG_PROTOCOL_NEG_RESP - error transaction type (%d)",transactiontype);
-		return 0;
+		goto exit;
 	}
 
 	extract_valueINT2(s,&t,T_PARAM_STATUS_CODE,&s->retcode);
@@ -117,7 +124,7 @@
 	if(s->protocol != T_PROTOCOL_CHAL)
 	{
 		s->debug(0,"T_MSG_PROTOCOL_NEG_RESP - Unsupported protocol (%d)",s->protocol);
-		return 0;
+		goto exit;
 	}
 
 	switch(s->retcode)
@@ -128,17 +135,17 @@
 	case T_STATUS_LOGIN_FAIL_SWVER:
 		{
 		s->debug(0,"T_MSG_PROTOCOL_NEG_RESP - Login failure: software version");
-		return 0;
+		goto exit;
 		}
 	case T_STATUS_LOGIN_FAIL_INV_PROT:
 		{
 		s->debug(0,"T_MSG_PROTOCOL_NEG_RESP - Login failure: invalid protocol");
-		return 0;
+		goto exit;
 		}
 	case T_STATUS_LOGIN_UNKNOWN:
 		{
 		s->debug(0,"T_MSG_PROTOCOL_NEG_RESP - Login failure: unknown");
-		return 0;
+		goto exit;
 		}
 	}
 
@@ -149,15 +156,13 @@
 	if(err)
 	{
 		socketerror(s,"Error binding auth socket 2");
-		closesocket(authsocket);
-		return 0;
+		goto exit;
 	}
 	err = connect(authsocket,(struct sockaddr *)&s->authhost,sizeof(struct sockaddr_in));
 	if(err)
 	{
 		socketerror(s,"Error connecting auth socket 2");
-		closesocket(authsocket);
-		return 0;
+		goto exit;
 	}
 
 	start_transaction(&t,T_MSG_LOGIN_REQ,s->sessionid);
@@ -171,24 +176,29 @@
 	send_transaction(s,authsocket,&t);
 
 	transactiontype = receive_transaction(s,authsocket,&t);
+	if(transactiontype == T_MSG_TIMEOUT)
+	{
+		socketerror(s,"TIMEOUT wating for login request response");
+		goto exit;
+	}
 	if(transactiontype == T_MSG_LOGIN_RESP)
 		goto skippo;
 
 	if(transactiontype != T_MSG_AUTH_RESP)
 	{
 		s->debug(0,"T_MSG_AUTH_RESP - error transaction type (%d)",transactiontype);
-		return 0;
+		goto exit;
 	}
 
 	if(!extract_valueINT2(s,&t,T_PARAM_HASH_METHOD,&s->hashmethod))
 	{
 		s->debug(0,"T_MSG_AUTH_RESP - no hashmethod provided");
-		return 0;
+		goto exit;
 	}
 	if(!extract_valuestring(s,&t,T_PARAM_NONCE,s->nonce))
 	{
 		s->debug(0,"T_MSG_AUTH_RESP - no nonce supplied");
-		return 0;
+		goto exit;
 	}
 
 	if(s->hashmethod == T_AUTH_MD5_HASH)
@@ -207,11 +217,16 @@
 	send_transaction(s,authsocket,&t);
 
 	transactiontype = receive_transaction(s,authsocket,&t);
+	if(transactiontype == T_MSG_TIMEOUT)
+	{
+		socketerror(s,"TIMEOUT wating for login credentials response");
+		goto exit;
+	}
 skippo:
 	if(transactiontype != T_MSG_LOGIN_RESP)
 	{
 		s->debug(0,"T_MSG_LOGIN_RESP - error transaction type (%d)",transactiontype);
-		return 0;
+		goto exit;
 	}
 
 	extract_valueINT2(s,&t,T_PARAM_STATUS_CODE,&s->retcode);
@@ -224,17 +239,17 @@
 	case T_STATUS_USERNAME_NOT_FOUND:
 		{
 		s->debug(0,"T_MSG_LOGIN_RESP - Login failure: username not known");
-		return 0;
+		goto exit;
 		}
 	case T_STATUS_INCORRECT_PASSWORD:
 		{
 		s->debug(0,"T_MSG_LOGIN_RESP - Login failure: incorrect password");
-		return 0;
+		goto exit;
 		}
 	case T_STATUS_ACCOUNT_DISABLED:
 		{
 		s->debug(0,"T_MSG_LOGIN_RESP - Login failure: Account disabled");
-		return 0;
+		goto exit;
 		}
 	case T_STATUS_LOGIN_RETRY_LIMIT:
 	case T_STATUS_USER_DISABLED:
@@ -243,7 +258,7 @@
 	case T_STATUS_LOGIN_UNKNOWN:
 		{
 		s->debug(0,"T_MSG_LOGIN_RESP - Login failure: other error");
-		return 0;
+		goto exit;
 		}
 	}
 
@@ -288,8 +303,12 @@
 	s->lastheartbeat = time(NULL);
 	s->recenthb = 0;
 
+	returnvalue = 1;
+exit:
+
 	closesocket(authsocket);
-	return 1;
+	alarm(0);
+	return returnvalue;
 }
 
 /*
@@ -375,26 +394,28 @@
 	int err;
 	char credentials[16];
 	time_t logintime;
+	int returnvalue = 0;
 
 	int authsocket;
 	struct transaction t;
 	INT2 transactiontype;
 
+	if (alarm(15) == -1)
+	  	s->debug(0, "alarm failed!");
+
 	s->localaddr.sin_port = htons(0);
 	authsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 	err = bind(authsocket,(struct sockaddr *)&s->localaddr,sizeof(struct sockaddr_in));
 	if(err)
 	{
 		socketerror(s,"Error binding logout auth socket");
-		closesocket(authsocket);
-		return 0;
+		goto exit;
 	}
 	err = connect(authsocket,(struct sockaddr *)&s->authhost,sizeof(struct sockaddr_in));
 	if(err)
 	{
 		socketerror(s,"Error connecting logout auth socket");
-		closesocket(authsocket);
-		return 0;
+		goto exit;
 	}
 
 	/*
@@ -410,6 +431,11 @@
 	send_transaction(s,authsocket,&t);
 
 	transactiontype = receive_transaction(s,authsocket,&t);
+	if(transactiontype == T_MSG_TIMEOUT)
+	{
+		socketerror(s,"TIMEOUT wating for logout response");
+		goto exit;
+	}
 	if(transactiontype != T_MSG_AUTH_RESP)
 	{
 		s->critical("logic error");
@@ -440,6 +466,11 @@
 	send_transaction(s,authsocket,&t);
 
 	transactiontype = receive_transaction(s,authsocket,&t);
+	if(transactiontype == T_MSG_TIMEOUT)
+	{
+		socketerror(s,"TIMEOUT wating for logout credentials response");
+		goto exit;
+	}
 	if(transactiontype != T_MSG_LOGOUT_RESP)
 	{
 		s->critical("logic error");
@@ -473,8 +504,11 @@
 	logintime = time(NULL);
 
 	s->debug(0,"Logged out successful at %s",asctime(localtime(&logintime)));
-	
+
+	returnvalue = 1;
+
+exit:
 	closesocket(authsocket);
-	
-	return 1;
+	alarm(0);
+	return returnvalue;
 }
diff -Nur bpalogin-2.0.2/transaction.c bpalogin-2.0.2-new/transaction.c
--- bpalogin-2.0.2/transaction.c	2007-06-06 20:02:31.000000000 +1000
+++ bpalogin-2.0.2-new/transaction.c	2007-06-07 11:48:29.634416588 +1000
@@ -149,7 +149,13 @@
 {
 	INT2 * v;
 	int r = recv(socket,(char *)t,1500,0);
+	extern int errno;
 
+	if (r == -1 && errno == 4)		/* EINTR */
+	{
+	  	t->length = 0;
+		return T_MSG_TIMEOUT;
+	}
 	t->length = r;
 	dump_recv_transaction(s,t);
 
diff -Nur bpalogin-2.0.2/unixmain.c bpalogin-2.0.2-new/unixmain.c
--- bpalogin-2.0.2/unixmain.c	2007-06-06 20:02:31.000000000 +1000
+++ bpalogin-2.0.2-new/unixmain.c	2007-06-07 11:51:19.982005285 +1000
@@ -129,15 +129,25 @@
     exit(1);
 }
 
+void alarmsignal(int i)
+{
+    debug(1,"Alarm Signal\n");
+}
+
 int main(int argc,char* argv[])
 {
     int makedaemon = 1;
     char conffile[256];
-
+    struct sigaction act;
     int c;
 
     signal(SIGINT,onsignal);
     signal(SIGHUP,onsignal);
+    sigaction(SIGALRM,0,&act);
+    act.sa_handler = alarmsignal;
+    act.sa_flags = 0;
+    sigemptyset(&act.sa_mask);
+    sigaction(SIGALRM,&act,0);
     signal(SIGTERM,onsignal);
 
     strcpy(s.authserver,DEFAULT_AUTHSERVER);

Reply via email to