Re: [HACKERS] Add support for RADIUS passwords longer than 16 octets

2015-09-06 Thread Magnus Hagander
On Tue, Aug 18, 2015 at 11:36 PM, Marko Tiikkaja  wrote:

> On 2015-08-15 17:55, I wrote:
>
>> The attached patch adds support for RADIUS passwords longer than 16
>> octets.
>>
>
> Improved the coding and comments a bit, new version attached.



Looks good to me. Applied, thanks!


As a note - psql truncates passwords at 100 characters when it reads it
from the problem (in the connstr it's fine). Not sure we care enough to
change that, though - I doubt it's a very common usecase for psql...

-- 
 Magnus Hagander
 Me: http://www.hagander.net/
 Work: http://www.redpill-linpro.com/


Re: [HACKERS] Add support for RADIUS passwords longer than 16 octets

2015-08-18 Thread Marko Tiikkaja

On 2015-08-15 17:55, I wrote:

The attached patch adds support for RADIUS passwords longer than 16 octets.


Improved the coding and comments a bit, new version attached.


.m
*** a/src/backend/libpq/auth.c
--- b/src/backend/libpq/auth.c
***
*** 2168,2173  CheckCertAuth(Port *port)
--- 2168,2174 
  
  #define RADIUS_VECTOR_LENGTH 16
  #define RADIUS_HEADER_LENGTH 20
+ #define RADIUS_MAX_PASSWORD_LENGTH 128
  
  typedef struct
  {
***
*** 2241,2247  CheckRADIUSAuth(Port *port)
radius_packet *receivepacket = (radius_packet *) receive_buffer;
int32   service = htonl(RADIUS_AUTHENTICATE_ONLY);
uint8  *cryptvector;
!   uint8   encryptedpassword[RADIUS_VECTOR_LENGTH];
int packetlength;
pgsocketsock;
  
--- 2242,2250 
radius_packet *receivepacket = (radius_packet *) receive_buffer;
int32   service = htonl(RADIUS_AUTHENTICATE_ONLY);
uint8  *cryptvector;
!   int encryptedpasswordlen;
!   uint8   encryptedpassword[RADIUS_MAX_PASSWORD_LENGTH];
!   uint8  *md5trailer;
int packetlength;
pgsocketsock;
  
***
*** 2259,2264  CheckRADIUSAuth(Port *port)
--- 2262,2268 
fd_set  fdset;
struct timeval endtime;
int i,
+   j,
r;
  
/* Make sure struct alignment is correct */
***
*** 2316,2325  CheckRADIUSAuth(Port *port)
return STATUS_ERROR;
}
  
!   if (strlen(passwd)  RADIUS_VECTOR_LENGTH)
{
ereport(LOG,
!   (errmsg(RADIUS authentication does not support 
passwords longer than 16 characters)));
return STATUS_ERROR;
}
  
--- 2320,2329 
return STATUS_ERROR;
}
  
!   if (strlen(passwd)  RADIUS_MAX_PASSWORD_LENGTH)
{
ereport(LOG,
!   (errmsg(RADIUS authentication does not support 
passwords longer than %d characters, RADIUS_MAX_PASSWORD_LENGTH)));
return STATUS_ERROR;
}
  
***
*** 2344,2371  CheckRADIUSAuth(Port *port)
radius_add_attribute(packet, RADIUS_NAS_IDENTIFIER, (unsigned char *) 
identifier, strlen(identifier));
  
/*
!* RADIUS password attributes are calculated as: e[0] = p[0] XOR
!* MD5(secret + vector)
 */
!   cryptvector = palloc(RADIUS_VECTOR_LENGTH + 
strlen(port-hba-radiussecret));
memcpy(cryptvector, port-hba-radiussecret, 
strlen(port-hba-radiussecret));
!   memcpy(cryptvector + strlen(port-hba-radiussecret), packet-vector, 
RADIUS_VECTOR_LENGTH);
!   if (!pg_md5_binary(cryptvector, RADIUS_VECTOR_LENGTH + 
strlen(port-hba-radiussecret), encryptedpassword))
{
!   ereport(LOG,
!   (errmsg(could not perform MD5 encryption of 
password)));
!   pfree(cryptvector);
!   return STATUS_ERROR;
}
pfree(cryptvector);
!   for (i = 0; i  RADIUS_VECTOR_LENGTH; i++)
!   {
!   if (i  strlen(passwd))
!   encryptedpassword[i] = passwd[i] ^ encryptedpassword[i];
!   else
!   encryptedpassword[i] = '\0' ^ encryptedpassword[i];
!   }
!   radius_add_attribute(packet, RADIUS_PASSWORD, encryptedpassword, 
RADIUS_VECTOR_LENGTH);
  
/* Length need to be in network order on the wire */
packetlength = packet-length;
--- 2348,2390 
radius_add_attribute(packet, RADIUS_NAS_IDENTIFIER, (unsigned char *) 
identifier, strlen(identifier));
  
/*
!* RADIUS password attributes are calculated as:
!*   e[0] = p[0] XOR MD5(secret + Request Authenticator)
!* for the first group of 16 octets, and then:
!*   e[i] = p[i] XOR MD5(secret + e[i-1])
!* for the following ones (if necessary)
 */
!   encryptedpasswordlen = ((strlen(passwd) + RADIUS_VECTOR_LENGTH - 1) / 
RADIUS_VECTOR_LENGTH) * RADIUS_VECTOR_LENGTH;
!   cryptvector = palloc(strlen(port-hba-radiussecret) + 
RADIUS_VECTOR_LENGTH);
memcpy(cryptvector, port-hba-radiussecret, 
strlen(port-hba-radiussecret));
! 
!   /* for the first iteration, we use the Request Authenticator vector */
!   md5trailer = packet-vector;
!   for (i = 0; i  encryptedpasswordlen; i += RADIUS_VECTOR_LENGTH)
{
!   memcpy(cryptvector + strlen(port-hba-radiussecret), 
md5trailer, RADIUS_VECTOR_LENGTH);
!   /* .. and for subsequent iterations the result of the previous 
XOR (calculated below) */
!   md5trailer = encryptedpassword + i;
! 
!   if (!pg_md5_binary(cryptvector, strlen(port-hba-radiussecret) 
+