summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMagnus Hagander <magnus@hagander.net>2015-09-06 14:26:33 +0200
committerMagnus Hagander <magnus@hagander.net>2015-09-06 14:31:53 +0200
commit643beffe8f69327147513a0f0d750e8ca035a4f6 (patch)
treec5781fd1e0f34a4168b9881a87464ef9735530e2 /src
parentc314ead5be0c627a6f654a74f18099466c566c47 (diff)
Support RADIUS passwords up to 128 characters
Previous limit was 16 characters, due to lack of support for multiple passes of encryption. Marko Tiikkaja
Diffstat (limited to 'src')
-rw-r--r--src/backend/libpq/auth.c60
1 files changed, 40 insertions, 20 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 4699efacd05..aca4ffe4c7e 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -2168,6 +2168,7 @@ CheckCertAuth(Port *port)
#define RADIUS_VECTOR_LENGTH 16
#define RADIUS_HEADER_LENGTH 20
+#define RADIUS_MAX_PASSWORD_LENGTH 128
typedef struct
{
@@ -2241,7 +2242,9 @@ CheckRADIUSAuth(Port *port)
radius_packet *receivepacket = (radius_packet *) receive_buffer;
int32 service = htonl(RADIUS_AUTHENTICATE_ONLY);
uint8 *cryptvector;
- uint8 encryptedpassword[RADIUS_VECTOR_LENGTH];
+ int encryptedpasswordlen;
+ uint8 encryptedpassword[RADIUS_MAX_PASSWORD_LENGTH];
+ uint8 *md5trailer;
int packetlength;
pgsocket sock;
@@ -2259,6 +2262,7 @@ CheckRADIUSAuth(Port *port)
fd_set fdset;
struct timeval endtime;
int i,
+ j,
r;
/* Make sure struct alignment is correct */
@@ -2316,13 +2320,14 @@ CheckRADIUSAuth(Port *port)
return STATUS_ERROR;
}
- if (strlen(passwd) > RADIUS_VECTOR_LENGTH)
+ if (strlen(passwd) > RADIUS_MAX_PASSWORD_LENGTH)
{
ereport(LOG,
- (errmsg("RADIUS authentication does not support passwords longer than 16 characters")));
+ (errmsg("RADIUS authentication does not support passwords longer than %d characters", RADIUS_MAX_PASSWORD_LENGTH)));
return STATUS_ERROR;
}
+
/* Construct RADIUS packet */
packet->code = RADIUS_ACCESS_REQUEST;
packet->length = RADIUS_HEADER_LENGTH;
@@ -2344,28 +2349,43 @@ 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)
+ * 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)
*/
- cryptvector = palloc(RADIUS_VECTOR_LENGTH + strlen(port->hba->radiussecret));
+ 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));
- memcpy(cryptvector + strlen(port->hba->radiussecret), packet->vector, RADIUS_VECTOR_LENGTH);
- if (!pg_md5_binary(cryptvector, RADIUS_VECTOR_LENGTH + strlen(port->hba->radiussecret), encryptedpassword))
+
+ /* for the first iteration, we use the Request Authenticator vector */
+ md5trailer = packet->vector;
+ for (i = 0; i < encryptedpasswordlen; i += RADIUS_VECTOR_LENGTH)
{
- ereport(LOG,
- (errmsg("could not perform MD5 encryption of password")));
- pfree(cryptvector);
- return STATUS_ERROR;
+ 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) + RADIUS_VECTOR_LENGTH, encryptedpassword + i))
+ {
+ ereport(LOG,
+ (errmsg("could not perform MD5 encryption of password")));
+ pfree(cryptvector);
+ return STATUS_ERROR;
+ }
+
+ for (j = i; j < i+RADIUS_VECTOR_LENGTH; j++)
+ {
+ if (j < strlen(passwd))
+ encryptedpassword[j] = passwd[j] ^ encryptedpassword[j];
+ else
+ encryptedpassword[j] = '\0' ^ encryptedpassword[j];
+ }
}
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);
+
+ radius_add_attribute(packet, RADIUS_PASSWORD, encryptedpassword, encryptedpasswordlen);
/* Length need to be in network order on the wire */
packetlength = packet->length;