@@ -2168,6 +2168,7 @@ CheckCertAuth(Port *port)
2168
2168
2169
2169
#define RADIUS_VECTOR_LENGTH 16
2170
2170
#define RADIUS_HEADER_LENGTH 20
2171
+ #define RADIUS_MAX_PASSWORD_LENGTH 128
2171
2172
2172
2173
typedef struct
2173
2174
{
@@ -2241,7 +2242,9 @@ CheckRADIUSAuth(Port *port)
2241
2242
radius_packet * receivepacket = (radius_packet * ) receive_buffer ;
2242
2243
int32 service = htonl (RADIUS_AUTHENTICATE_ONLY );
2243
2244
uint8 * cryptvector ;
2244
- uint8 encryptedpassword [RADIUS_VECTOR_LENGTH ];
2245
+ int encryptedpasswordlen ;
2246
+ uint8 encryptedpassword [RADIUS_MAX_PASSWORD_LENGTH ];
2247
+ uint8 * md5trailer ;
2245
2248
int packetlength ;
2246
2249
pgsocket sock ;
2247
2250
@@ -2259,6 +2262,7 @@ CheckRADIUSAuth(Port *port)
2259
2262
fd_set fdset ;
2260
2263
struct timeval endtime ;
2261
2264
int i ,
2265
+ j ,
2262
2266
r ;
2263
2267
2264
2268
/* Make sure struct alignment is correct */
@@ -2316,13 +2320,14 @@ CheckRADIUSAuth(Port *port)
2316
2320
return STATUS_ERROR ;
2317
2321
}
2318
2322
2319
- if (strlen (passwd ) > RADIUS_VECTOR_LENGTH )
2323
+ if (strlen (passwd ) > RADIUS_MAX_PASSWORD_LENGTH )
2320
2324
{
2321
2325
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 )));
2323
2327
return STATUS_ERROR ;
2324
2328
}
2325
2329
2330
+
2326
2331
/* Construct RADIUS packet */
2327
2332
packet -> code = RADIUS_ACCESS_REQUEST ;
2328
2333
packet -> length = RADIUS_HEADER_LENGTH ;
@@ -2344,28 +2349,43 @@ CheckRADIUSAuth(Port *port)
2344
2349
radius_add_attribute (packet , RADIUS_NAS_IDENTIFIER , (unsigned char * ) identifier , strlen (identifier ));
2345
2350
2346
2351
/*
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)
2349
2357
*/
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 );
2351
2360
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 )
2354
2365
{
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
+ }
2359
2385
}
2360
2386
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 );
2369
2389
2370
2390
/* Length need to be in network order on the wire */
2371
2391
packetlength = packet -> length ;
0 commit comments