@@ -2619,7 +2619,7 @@ CheckRADIUSAuth(Port *port)
2619
2619
char portstr [128 ];
2620
2620
ACCEPT_TYPE_ARG3 addrsize ;
2621
2621
fd_set fdset ;
2622
- struct timeval timeout ;
2622
+ struct timeval endtime ;
2623
2623
int i ,
2624
2624
r ;
2625
2625
@@ -2777,14 +2777,36 @@ CheckRADIUSAuth(Port *port)
2777
2777
/* Don't need the server address anymore */
2778
2778
pg_freeaddrinfo_all (hint .ai_family , serveraddrs );
2779
2779
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 ;
2785
2788
2786
2789
while (true)
2787
2790
{
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
+
2788
2810
r = select (sock + 1 , & fdset , NULL , NULL , & timeout );
2789
2811
if (r < 0 )
2790
2812
{
@@ -2805,107 +2827,117 @@ CheckRADIUSAuth(Port *port)
2805
2827
return STATUS_ERROR ;
2806
2828
}
2807
2829
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
+ */
2823
2840
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
+ }
2825
2850
2826
2851
#ifdef HAVE_IPV6
2827
- if (remoteaddr .sin6_port != htons (port -> hba -> radiusport ))
2852
+ if (remoteaddr .sin6_port != htons (port -> hba -> radiusport ))
2828
2853
#else
2829
- if (remoteaddr .sin_port != htons (port -> hba -> radiusport ))
2854
+ if (remoteaddr .sin_port != htons (port -> hba -> radiusport ))
2830
2855
#endif
2831
- {
2856
+ {
2832
2857
#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 ))));
2836
2861
#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 ))));
2840
2865
#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
+ }
2858
2868
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
+ }
2866
2875
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
+ }
2872
2883
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
+ }
2881
2891
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
+ }
2888
2916
pfree (cryptvector );
2889
- return STATUS_ERROR ;
2890
- }
2891
- pfree (cryptvector );
2892
2917
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
+ }
2899
2924
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) */
2911
2943
}
0 commit comments