@@ -2619,7 +2619,7 @@ CheckRADIUSAuth(Port *port)
26192619char portstr [128 ];
26202620ACCEPT_TYPE_ARG3 addrsize ;
26212621fd_set fdset ;
2622- struct timeval timeout ;
2622+ struct timeval endtime ;
26232623int i ,
26242624r ;
26252625
@@ -2777,14 +2777,36 @@ CheckRADIUSAuth(Port *port)
27772777/* Don't need the server address anymore */
27782778pg_freeaddrinfo_all (hint .ai_family ,serveraddrs );
27792779
2780- /* Wait for a response */
2781- timeout .tv_sec = RADIUS_TIMEOUT ;
2782- timeout .tv_usec = 0 ;
2783- FD_ZERO (& fdset );
2784- FD_SET (sock ,& fdset );
2780+ /*
2781+ * Figure out at what time we should time out. We can't just use
2782+ * a single call to select() with a timeout, since somebody can
2783+ * be sending invalid packets to our port thus causing us to
2784+ * retry in a loop and never time out.
2785+ */
2786+ gettimeofday (& endtime ,NULL );
2787+ endtime .tv_sec += RADIUS_TIMEOUT ;
27852788
27862789while (true)
27872790{
2791+ struct timeval timeout ;
2792+ struct timeval now ;
2793+ int64 timeoutval ;
2794+
2795+ gettimeofday (& now ,NULL );
2796+ timeoutval = (endtime .tv_sec * 1000000 + endtime .tv_usec )- (now .tv_sec * 1000000 + now .tv_usec );
2797+ if (timeoutval <=0 )
2798+ {
2799+ ereport (LOG ,
2800+ (errmsg ("timeout waiting for RADIUS response" )));
2801+ closesocket (sock );
2802+ return STATUS_ERROR ;
2803+ }
2804+ timeout .tv_sec = timeoutval /1000000 ;
2805+ timeout .tv_usec = timeoutval %1000000 ;
2806+
2807+ FD_ZERO (& fdset );
2808+ FD_SET (sock ,& fdset );
2809+
27882810r = select (sock + 1 ,& fdset ,NULL ,NULL ,& timeout );
27892811if (r < 0 )
27902812{
@@ -2805,107 +2827,117 @@ CheckRADIUSAuth(Port *port)
28052827return STATUS_ERROR ;
28062828}
28072829
2808- /* else we actually have a packet ready to read */
2809- break ;
2810- }
2811-
2812- /* Read the response packet */
2813- addrsize = sizeof (remoteaddr );
2814- packetlength = recvfrom (sock ,receive_buffer ,RADIUS_BUFFER_SIZE ,0 ,
2815- (struct sockaddr * )& remoteaddr ,& addrsize );
2816- if (packetlength < 0 )
2817- {
2818- ereport (LOG ,
2819- (errmsg ("could not read RADIUS response: %m" )));
2820- closesocket (sock );
2821- return STATUS_ERROR ;
2822- }
2830+ /*
2831+ * Attempt to read the response packet, and verify the contents.
2832+ *
2833+ * Any packet that's not actually a RADIUS packet, or otherwise
2834+ * does not validate as an explicit reject, is just ignored and
2835+ * we retry for another packet (until we reach the timeout). This
2836+ * is to avoid the possibility to denial-of-service the login by
2837+ * flooding the server with invalid packets on the port that
2838+ * we're expecting the RADIUS response on.
2839+ */
28232840
2824- closesocket (sock );
2841+ addrsize = sizeof (remoteaddr );
2842+ packetlength = recvfrom (sock ,receive_buffer ,RADIUS_BUFFER_SIZE ,0 ,
2843+ (struct sockaddr * )& remoteaddr ,& addrsize );
2844+ if (packetlength < 0 )
2845+ {
2846+ ereport (LOG ,
2847+ (errmsg ("could not read RADIUS response: %m" )));
2848+ return STATUS_ERROR ;
2849+ }
28252850
28262851#ifdef HAVE_IPV6
2827- if (remoteaddr .sin6_port != htons (port -> hba -> radiusport ))
2852+ if (remoteaddr .sin6_port != htons (port -> hba -> radiusport ))
28282853#else
2829- if (remoteaddr .sin_port != htons (port -> hba -> radiusport ))
2854+ if (remoteaddr .sin_port != htons (port -> hba -> radiusport ))
28302855#endif
2831- {
2856+ {
28322857#ifdef HAVE_IPV6
2833- ereport (LOG ,
2834- (errmsg ("RADIUS response was sent from incorrect port: %i" ,
2835- ntohs (remoteaddr .sin6_port ))));
2858+ ereport (LOG ,
2859+ (errmsg ("RADIUS response was sent from incorrect port: %i" ,
2860+ ntohs (remoteaddr .sin6_port ))));
28362861#else
2837- ereport (LOG ,
2838- (errmsg ("RADIUS response was sent from incorrect port: %i" ,
2839- ntohs (remoteaddr .sin_port ))));
2862+ ereport (LOG ,
2863+ (errmsg ("RADIUS response was sent from incorrect port: %i" ,
2864+ ntohs (remoteaddr .sin_port ))));
28402865#endif
2841- return STATUS_ERROR ;
2842- }
2843-
2844- if (packetlength < RADIUS_HEADER_LENGTH )
2845- {
2846- ereport (LOG ,
2847- (errmsg ("RADIUS response too short: %i" ,packetlength )));
2848- return STATUS_ERROR ;
2849- }
2850-
2851- if (packetlength != ntohs (receivepacket -> length ))
2852- {
2853- ereport (LOG ,
2854- (errmsg ("RADIUS response has corrupt length: %i (actual length %i)" ,
2855- ntohs (receivepacket -> length ),packetlength )));
2856- return STATUS_ERROR ;
2857- }
2866+ continue ;
2867+ }
28582868
2859- if (packet -> id != receivepacket -> id )
2860- {
2861- ereport (LOG ,
2862- (errmsg ("RADIUS response is to a different request: %i (should be %i)" ,
2863- receivepacket -> id ,packet -> id )));
2864- return STATUS_ERROR ;
2865- }
2869+ if (packetlength < RADIUS_HEADER_LENGTH )
2870+ {
2871+ ereport (LOG ,
2872+ (errmsg ("RADIUS response too short: %i" ,packetlength )));
2873+ continue ;
2874+ }
28662875
2867- /*
2868- * Verify the response authenticator, which is calculated as
2869- * MD5(Code+ID+Length+RequestAuthenticator+Attributes+Secret)
2870- */
2871- cryptvector = palloc (packetlength + strlen (port -> hba -> radiussecret ));
2876+ if (packetlength != ntohs (receivepacket -> length ))
2877+ {
2878+ ereport (LOG ,
2879+ (errmsg ("RADIUS response has corrupt length: %i (actual length %i)" ,
2880+ ntohs (receivepacket -> length ),packetlength )));
2881+ continue ;
2882+ }
28722883
2873- memcpy (cryptvector ,receivepacket ,4 );/* code+id+length */
2874- memcpy (cryptvector + 4 ,packet -> vector ,RADIUS_VECTOR_LENGTH );/* request
2875- * authenticator, from
2876- * original packet */
2877- if (packetlength > RADIUS_HEADER_LENGTH )/* there may be no attributes
2878- * at all */
2879- memcpy (cryptvector + RADIUS_HEADER_LENGTH ,receive_buffer + RADIUS_HEADER_LENGTH ,packetlength - RADIUS_HEADER_LENGTH );
2880- memcpy (cryptvector + packetlength ,port -> hba -> radiussecret ,strlen (port -> hba -> radiussecret ));
2884+ if (packet -> id != receivepacket -> id )
2885+ {
2886+ ereport (LOG ,
2887+ (errmsg ("RADIUS response is to a different request: %i (should be %i)" ,
2888+ receivepacket -> id ,packet -> id )));
2889+ continue ;
2890+ }
28812891
2882- if (!pg_md5_binary (cryptvector ,
2883- packetlength + strlen (port -> hba -> radiussecret ),
2884- encryptedpassword ))
2885- {
2886- ereport (LOG ,
2887- (errmsg ("could not perform MD5 encryption of received packet" )));
2892+ /*
2893+ * Verify the response authenticator, which is calculated as
2894+ * MD5(Code+ID+Length+RequestAuthenticator+Attributes+Secret)
2895+ */
2896+ cryptvector = palloc (packetlength + strlen (port -> hba -> radiussecret ));
2897+
2898+ memcpy (cryptvector ,receivepacket ,4 );/* code+id+length */
2899+ memcpy (cryptvector + 4 ,packet -> vector ,RADIUS_VECTOR_LENGTH );/* request
2900+ * authenticator, from
2901+ * original packet */
2902+ if (packetlength > RADIUS_HEADER_LENGTH )/* there may be no attributes
2903+ * at all */
2904+ memcpy (cryptvector + RADIUS_HEADER_LENGTH ,receive_buffer + RADIUS_HEADER_LENGTH ,packetlength - RADIUS_HEADER_LENGTH );
2905+ memcpy (cryptvector + packetlength ,port -> hba -> radiussecret ,strlen (port -> hba -> radiussecret ));
2906+
2907+ if (!pg_md5_binary (cryptvector ,
2908+ packetlength + strlen (port -> hba -> radiussecret ),
2909+ encryptedpassword ))
2910+ {
2911+ ereport (LOG ,
2912+ (errmsg ("could not perform MD5 encryption of received packet" )));
2913+ pfree (cryptvector );
2914+ continue ;
2915+ }
28882916pfree (cryptvector );
2889- return STATUS_ERROR ;
2890- }
2891- pfree (cryptvector );
28922917
2893- if (memcmp (receivepacket -> vector ,encryptedpassword ,RADIUS_VECTOR_LENGTH )!= 0 )
2894- {
2895- ereport (LOG ,
2896- (errmsg ("RADIUS response has incorrect MD5 signature" )));
2897- return STATUS_ERROR ;
2898- }
2918+ if (memcmp (receivepacket -> vector ,encryptedpassword ,RADIUS_VECTOR_LENGTH )!= 0 )
2919+ {
2920+ ereport (LOG ,
2921+ (errmsg ("RADIUS response has incorrect MD5 signature" )));
2922+ continue ;
2923+ }
28992924
2900- if (receivepacket -> code == RADIUS_ACCESS_ACCEPT )
2901- return STATUS_OK ;
2902- else if (receivepacket -> code == RADIUS_ACCESS_REJECT )
2903- return STATUS_ERROR ;
2904- else
2905- {
2906- ereport (LOG ,
2907- (errmsg ("RADIUS response has invalid code (%i) for user \"%s\"" ,
2908- receivepacket -> code ,port -> user_name )));
2909- return STATUS_ERROR ;
2910- }
2925+ if (receivepacket -> code == RADIUS_ACCESS_ACCEPT )
2926+ {
2927+ closesocket (sock );
2928+ return STATUS_OK ;
2929+ }
2930+ else if (receivepacket -> code == RADIUS_ACCESS_REJECT )
2931+ {
2932+ closesocket (sock );
2933+ return STATUS_ERROR ;
2934+ }
2935+ else
2936+ {
2937+ ereport (LOG ,
2938+ (errmsg ("RADIUS response has invalid code (%i) for user \"%s\"" ,
2939+ receivepacket -> code ,port -> user_name )));
2940+ continue ;
2941+ }
2942+ }/* while (true) */
29112943}