@@ -2168,6 +2168,7 @@ CheckCertAuth(Port *port)
21682168
21692169#define RADIUS_VECTOR_LENGTH 16
21702170#define RADIUS_HEADER_LENGTH 20
2171+ #define RADIUS_MAX_PASSWORD_LENGTH 128
21712172
21722173typedef struct
21732174{
@@ -2241,7 +2242,9 @@ CheckRADIUSAuth(Port *port)
22412242 radius_packet * receivepacket = (radius_packet * ) receive_buffer ;
22422243 int32 service = htonl (RADIUS_AUTHENTICATE_ONLY );
22432244 uint8 * cryptvector ;
2244- uint8 encryptedpassword [RADIUS_VECTOR_LENGTH ];
2245+ int encryptedpasswordlen ;
2246+ uint8 encryptedpassword [RADIUS_MAX_PASSWORD_LENGTH ];
2247+ uint8 * md5trailer ;
22452248 int packetlength ;
22462249 pgsocket sock ;
22472250
@@ -2259,6 +2262,7 @@ CheckRADIUSAuth(Port *port)
22592262 fd_set fdset ;
22602263 struct timeval endtime ;
22612264 int i ,
2265+ j ,
22622266 r ;
22632267
22642268 /* Make sure struct alignment is correct */
@@ -2316,13 +2320,14 @@ CheckRADIUSAuth(Port *port)
23162320 return STATUS_ERROR ;
23172321 }
23182322
2319- if (strlen (passwd ) > RADIUS_VECTOR_LENGTH )
2323+ if (strlen (passwd ) > RADIUS_MAX_PASSWORD_LENGTH )
23202324 {
23212325 ereport (LOG ,
2322- (errmsg ("RADIUS authentication does not support passwords longer than 16 characters" )));
2326+ (errmsg ("RADIUS authentication does not support passwords longer than %d characters" , RADIUS_MAX_PASSWORD_LENGTH )));
23232327 return STATUS_ERROR ;
23242328 }
23252329
2330+
23262331 /* Construct RADIUS packet */
23272332 packet -> code = RADIUS_ACCESS_REQUEST ;
23282333 packet -> length = RADIUS_HEADER_LENGTH ;
@@ -2344,28 +2349,43 @@ CheckRADIUSAuth(Port *port)
23442349 radius_add_attribute (packet , RADIUS_NAS_IDENTIFIER , (unsigned char * ) identifier , strlen (identifier ));
23452350
23462351 /*
2347- * RADIUS password attributes are calculated as: e[0] = p[0] XOR
2348- * MD5(secret + vector)
2352+ * RADIUS password attributes are calculated as:
2353+ * e[0] = p[0] XOR MD5(secret + Request Authenticator)
2354+ * for the first group of 16 octets, and then:
2355+ * e[i] = p[i] XOR MD5(secret + e[i-1])
2356+ * for the following ones (if necessary)
23492357 */
2350- cryptvector = palloc (RADIUS_VECTOR_LENGTH + strlen (port -> hba -> radiussecret ));
2358+ encryptedpasswordlen = ((strlen (passwd ) + RADIUS_VECTOR_LENGTH - 1 ) / RADIUS_VECTOR_LENGTH ) * RADIUS_VECTOR_LENGTH ;
2359+ cryptvector = palloc (strlen (port -> hba -> radiussecret ) + RADIUS_VECTOR_LENGTH );
23512360 memcpy (cryptvector , port -> hba -> radiussecret , strlen (port -> hba -> radiussecret ));
2352- memcpy (cryptvector + strlen (port -> hba -> radiussecret ), packet -> vector , RADIUS_VECTOR_LENGTH );
2353- if (!pg_md5_binary (cryptvector , RADIUS_VECTOR_LENGTH + strlen (port -> hba -> radiussecret ), encryptedpassword ))
2361+
2362+ /* for the first iteration, we use the Request Authenticator vector */
2363+ md5trailer = packet -> vector ;
2364+ for (i = 0 ; i < encryptedpasswordlen ; i += RADIUS_VECTOR_LENGTH )
23542365 {
2355- ereport (LOG ,
2356- (errmsg ("could not perform MD5 encryption of password" )));
2357- pfree (cryptvector );
2358- return STATUS_ERROR ;
2366+ memcpy (cryptvector + strlen (port -> hba -> radiussecret ), md5trailer , RADIUS_VECTOR_LENGTH );
2367+ /* .. and for subsequent iterations the result of the previous XOR (calculated below) */
2368+ md5trailer = encryptedpassword + i ;
2369+
2370+ if (!pg_md5_binary (cryptvector , strlen (port -> hba -> radiussecret ) + RADIUS_VECTOR_LENGTH , encryptedpassword + i ))
2371+ {
2372+ ereport (LOG ,
2373+ (errmsg ("could not perform MD5 encryption of password" )));
2374+ pfree (cryptvector );
2375+ return STATUS_ERROR ;
2376+ }
2377+
2378+ for (j = i ; j < i + RADIUS_VECTOR_LENGTH ; j ++ )
2379+ {
2380+ if (j < strlen (passwd ))
2381+ encryptedpassword [j ] = passwd [j ] ^ encryptedpassword [j ];
2382+ else
2383+ encryptedpassword [j ] = '\0' ^ encryptedpassword [j ];
2384+ }
23592385 }
23602386 pfree (cryptvector );
2361- for (i = 0 ; i < RADIUS_VECTOR_LENGTH ; i ++ )
2362- {
2363- if (i < strlen (passwd ))
2364- encryptedpassword [i ] = passwd [i ] ^ encryptedpassword [i ];
2365- else
2366- encryptedpassword [i ] = '\0' ^ encryptedpassword [i ];
2367- }
2368- radius_add_attribute (packet , RADIUS_PASSWORD , encryptedpassword , RADIUS_VECTOR_LENGTH );
2387+
2388+ radius_add_attribute (packet , RADIUS_PASSWORD , encryptedpassword , encryptedpasswordlen );
23692389
23702390 /* Length need to be in network order on the wire */
23712391 packetlength = packet -> length ;
0 commit comments