*** 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; pgsocket sock; --- 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; pgsocket sock; *************** *** 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) + 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); ! ! radius_add_attribute(packet, RADIUS_PASSWORD, encryptedpassword, encryptedpasswordlen); /* Length need to be in network order on the wire */ packetlength = packet->length;