*** a/src/backend/libpq/auth.c
--- b/src/backend/libpq/auth.c
***************
*** 2619,2625 **** CheckRADIUSAuth(Port *port)
  	char		portstr[128];
  	ACCEPT_TYPE_ARG3 addrsize;
  	fd_set		fdset;
! 	struct timeval timeout;
  	int			i,
  				r;
  
--- 2619,2625 ----
  	char		portstr[128];
  	ACCEPT_TYPE_ARG3 addrsize;
  	fd_set		fdset;
! 	struct timeval endtime;
  	int			i,
  				r;
  
***************
*** 2777,2790 **** CheckRADIUSAuth(Port *port)
  	/* Don't need the server address anymore */
  	pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
  
! 	/* Wait for a response */
! 	timeout.tv_sec = RADIUS_TIMEOUT;
! 	timeout.tv_usec = 0;
! 	FD_ZERO(&fdset);
! 	FD_SET(sock, &fdset);
  
  	while (true)
  	{
  		r = select(sock + 1, &fdset, NULL, NULL, &timeout);
  		if (r < 0)
  		{
--- 2777,2812 ----
  	/* Don't need the server address anymore */
  	pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
  
! 	/*
! 	 * Figure out at what time we should time out. We can't just use
! 	 * a single call to select() with a timeout, since somebody can
! 	 * be sending invalid packets to our port thus causing us to
! 	 * retry in a loop and never time out.
! 	 */
! 	gettimeofday(&endtime, NULL);
! 	endtime.tv_sec += RADIUS_TIMEOUT;
  
  	while (true)
  	{
+ 		struct timeval timeout;
+ 		struct timeval now;
+ 		int64 timeoutval;
+ 
+ 		gettimeofday(&now, NULL);
+ 		timeoutval = (endtime.tv_sec * 1000000 + endtime.tv_usec) - (now.tv_sec * 1000000 + now.tv_usec);
+ 		if (timeoutval <= 0)
+ 		{
+ 			ereport(LOG,
+ 					(errmsg("timeout waiting for RADIUS response")));
+ 			closesocket(sock);
+ 			return STATUS_ERROR;
+ 		}
+ 		timeout.tv_sec = timeoutval / 1000000;
+ 		timeout.tv_usec = timeoutval % 1000000;
+ 
+ 		FD_ZERO(&fdset);
+ 		FD_SET(sock, &fdset);
+ 
  		r = select(sock + 1, &fdset, NULL, NULL, &timeout);
  		if (r < 0)
  		{
***************
*** 2805,2815 **** CheckRADIUSAuth(Port *port)
  			return STATUS_ERROR;
  		}
  
! 		/* else we actually have a packet ready to read */
! 		break;
! 	}
  
- 	/* Read the response packet */
  	addrsize = sizeof(remoteaddr);
  	packetlength = recvfrom(sock, receive_buffer, RADIUS_BUFFER_SIZE, 0,
  							(struct sockaddr *) & remoteaddr, &addrsize);
--- 2827,2843 ----
  			return STATUS_ERROR;
  		}
  
! 		/*
! 		 * Attempt to read the response packet, and verify the contents.
! 		 *
! 		 * Any packet that's not actually a RADIUS packet, or otherwise
! 		 * does not validate as an explicit reject, is just ignored and
! 		 * we retry for another packet (until we reach the timeout). This
! 		 * is to avoid the possibility to denial-of-service the login by
! 		 * flooding the server with invalid packets on the port that
! 		 * we're expecting the RADIUS response on.
! 		 */
  
  	addrsize = sizeof(remoteaddr);
  	packetlength = recvfrom(sock, receive_buffer, RADIUS_BUFFER_SIZE, 0,
  							(struct sockaddr *) & remoteaddr, &addrsize);
***************
*** 2817,2828 **** CheckRADIUSAuth(Port *port)
  	{
  		ereport(LOG,
  				(errmsg("could not read RADIUS response: %m")));
- 		closesocket(sock);
  		return STATUS_ERROR;
  	}
  
- 	closesocket(sock);
- 
  #ifdef HAVE_IPV6
  	if (remoteaddr.sin6_port != htons(port->hba->radiusport))
  #else
--- 2845,2853 ----
***************
*** 2838,2851 **** CheckRADIUSAuth(Port *port)
  				(errmsg("RADIUS response was sent from incorrect port: %i",
  						ntohs(remoteaddr.sin_port))));
  #endif
! 		return STATUS_ERROR;
  	}
  
  	if (packetlength < RADIUS_HEADER_LENGTH)
  	{
  		ereport(LOG,
  				(errmsg("RADIUS response too short: %i", packetlength)));
! 		return STATUS_ERROR;
  	}
  
  	if (packetlength != ntohs(receivepacket->length))
--- 2863,2876 ----
  				(errmsg("RADIUS response was sent from incorrect port: %i",
  						ntohs(remoteaddr.sin_port))));
  #endif
! 			continue;
  	}
  
  	if (packetlength < RADIUS_HEADER_LENGTH)
  	{
  		ereport(LOG,
  				(errmsg("RADIUS response too short: %i", packetlength)));
! 			continue;
  	}
  
  	if (packetlength != ntohs(receivepacket->length))
***************
*** 2853,2859 **** CheckRADIUSAuth(Port *port)
  		ereport(LOG,
  		 (errmsg("RADIUS response has corrupt length: %i (actual length %i)",
  				 ntohs(receivepacket->length), packetlength)));
! 		return STATUS_ERROR;
  	}
  
  	if (packet->id != receivepacket->id)
--- 2878,2884 ----
  		ereport(LOG,
  		 (errmsg("RADIUS response has corrupt length: %i (actual length %i)",
  				 ntohs(receivepacket->length), packetlength)));
! 			continue;
  	}
  
  	if (packet->id != receivepacket->id)
***************
*** 2861,2867 **** CheckRADIUSAuth(Port *port)
  		ereport(LOG,
  				(errmsg("RADIUS response is to a different request: %i (should be %i)",
  						receivepacket->id, packet->id)));
! 		return STATUS_ERROR;
  	}
  
  	/*
--- 2886,2892 ----
  		ereport(LOG,
  				(errmsg("RADIUS response is to a different request: %i (should be %i)",
  						receivepacket->id, packet->id)));
! 			continue;
  	}
  
  	/*
***************
*** 2886,2892 **** CheckRADIUSAuth(Port *port)
  		ereport(LOG,
  			(errmsg("could not perform MD5 encryption of received packet")));
  		pfree(cryptvector);
! 		return STATUS_ERROR;
  	}
  	pfree(cryptvector);
  
--- 2911,2917 ----
  		ereport(LOG,
  			(errmsg("could not perform MD5 encryption of received packet")));
  		pfree(cryptvector);
! 			continue;
  	}
  	pfree(cryptvector);
  
***************
*** 2894,2911 **** CheckRADIUSAuth(Port *port)
  	{
  		ereport(LOG,
  				(errmsg("RADIUS response has incorrect MD5 signature")));
! 		return STATUS_ERROR;
  	}
  
  	if (receivepacket->code == RADIUS_ACCESS_ACCEPT)
  		return STATUS_OK;
  	else if (receivepacket->code == RADIUS_ACCESS_REJECT)
  		return STATUS_ERROR;
  	else
  	{
  		ereport(LOG,
  			 (errmsg("RADIUS response has invalid code (%i) for user \"%s\"",
  					 receivepacket->code, port->user_name)));
! 		return STATUS_ERROR;
  	}
  }
--- 2919,2943 ----
  	{
  		ereport(LOG,
  				(errmsg("RADIUS response has incorrect MD5 signature")));
! 			continue;
  	}
  
  	if (receivepacket->code == RADIUS_ACCESS_ACCEPT)
+ 		{
+ 			closesocket(sock);
  		return STATUS_OK;
+ 		}
  	else if (receivepacket->code == RADIUS_ACCESS_REJECT)
+ 		{
+ 			closesocket(sock);
  		return STATUS_ERROR;
+ 		}
  	else
  	{
  		ereport(LOG,
  			 (errmsg("RADIUS response has invalid code (%i) for user \"%s\"",
  					 receivepacket->code, port->user_name)));
! 			continue;
  	}
+ 	} /* while (true) */
  }
