Make RADIUS authentication use pg_getaddrinfo_all() to get address of

the server.

Gets rid of a fairly ugly hack for Solaris, and also provides hostname
and IPV6 support.
This commit is contained in:
Magnus Hagander 2010-02-02 19:09:37 +00:00
parent d8db6a6096
commit 0a27347141
4 changed files with 69 additions and 28 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.129 2010/01/27 13:03:17 mha Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.130 2010/02/02 19:09:36 mha Exp $ -->
<chapter id="client-authentication"> <chapter id="client-authentication">
<title>Client Authentication</title> <title>Client Authentication</title>
@ -1375,8 +1375,8 @@ ldapserver=ldap.example.net ldapprefix="cn=" ldapsuffix=", dc=example, dc=net"
<term><literal>radiusserver</literal></term> <term><literal>radiusserver</literal></term>
<listitem> <listitem>
<para> <para>
The IP address of the RADIUS server to connect to. This must The name or IP address of the RADIUS server to connect to.
be an IPV4 address and not a hostname. This parameter is required. This parameter is required.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.193 2010/01/31 17:27:22 tgl Exp $ * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.194 2010/02/02 19:09:36 mha Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -2521,8 +2521,16 @@ CheckRADIUSAuth(Port *port)
uint8 encryptedpassword[RADIUS_VECTOR_LENGTH]; uint8 encryptedpassword[RADIUS_VECTOR_LENGTH];
int packetlength; int packetlength;
pgsocket sock; pgsocket sock;
#ifdef HAVE_IPV6
struct sockaddr_in6 localaddr;
struct sockaddr_in6 remoteaddr;
#else
struct sockaddr_in localaddr; struct sockaddr_in localaddr;
struct sockaddr_in remoteaddr; struct sockaddr_in remoteaddr;
#endif
struct addrinfo hint;
struct addrinfo *serveraddrs;
char portstr[128];
ACCEPT_TYPE_ARG3 addrsize; ACCEPT_TYPE_ARG3 addrsize;
fd_set fdset; fd_set fdset;
struct timeval timeout; struct timeval timeout;
@ -2549,17 +2557,22 @@ CheckRADIUSAuth(Port *port)
if (port->hba->radiusport == 0) if (port->hba->radiusport == 0)
port->hba->radiusport = 1812; port->hba->radiusport = 1812;
memset(&remoteaddr, 0, sizeof(remoteaddr)); MemSet(&hint, 0, sizeof(hint));
remoteaddr.sin_family = AF_INET; hint.ai_socktype = SOCK_DGRAM;
remoteaddr.sin_addr.s_addr = inet_addr(port->hba->radiusserver); hint.ai_family = AF_UNSPEC;
if (remoteaddr.sin_addr.s_addr == INADDR_NONE) snprintf(portstr, sizeof(portstr), "%d", port->hba->radiusport);
r = pg_getaddrinfo_all(port->hba->radiusserver, portstr, &hint, &serveraddrs);
if (r || !serveraddrs)
{ {
ereport(LOG, ereport(LOG,
(errmsg("RADIUS server '%s' is not a valid IP address", (errmsg("could not translate RADIUS server name \"%s\" to address: %s",
port->hba->radiusserver))); port->hba->radiusserver, gai_strerror(r))));
if (serveraddrs)
pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
return STATUS_ERROR; return STATUS_ERROR;
} }
remoteaddr.sin_port = htons(port->hba->radiusport); /* XXX: add support for multiple returned addresses? */
if (port->hba->radiusidentifier && port->hba->radiusidentifier[0]) if (port->hba->radiusidentifier && port->hba->radiusidentifier[0])
identifier = port->hba->radiusidentifier; identifier = port->hba->radiusidentifier;
@ -2633,34 +2646,51 @@ CheckRADIUSAuth(Port *port)
packetlength = packet->length; packetlength = packet->length;
packet->length = htons(packet->length); packet->length = htons(packet->length);
sock = socket(AF_INET, SOCK_DGRAM, 0); sock = socket(serveraddrs[0].ai_family, SOCK_DGRAM, 0);
if (sock < 0) if (sock < 0)
{ {
ereport(LOG, ereport(LOG,
(errmsg("could not create RADIUS socket: %m"))); (errmsg("could not create RADIUS socket: %m")));
pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
return STATUS_ERROR; return STATUS_ERROR;
} }
memset(&localaddr, 0, sizeof(localaddr)); memset(&localaddr, 0, sizeof(localaddr));
localaddr.sin_family = AF_INET; #ifdef HAVE_IPV6
localaddr.sin6_family = serveraddrs[0].ai_family;
localaddr.sin6_addr = in6addr_any;
if (localaddr.sin6_family == AF_INET6)
addrsize = sizeof(struct sockaddr_in6);
else
addrsize = sizeof(struct sockaddr_in);
#else
localaddr.sin_family = serveraddrs[0].ai_family;
localaddr.sin_addr.s_addr = INADDR_ANY; localaddr.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *) &localaddr, sizeof(localaddr))) addrsize = sizeof(struct sockaddr_in);
#endif
if (bind(sock, (struct sockaddr *) &localaddr, addrsize))
{ {
ereport(LOG, ereport(LOG,
(errmsg("could not bind local RADIUS socket: %m"))); (errmsg("could not bind local RADIUS socket: %m")));
closesocket(sock); closesocket(sock);
pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
return STATUS_ERROR; return STATUS_ERROR;
} }
if (sendto(sock, radius_buffer, packetlength, 0, if (sendto(sock, radius_buffer, packetlength, 0,
(struct sockaddr *) &remoteaddr, sizeof(remoteaddr)) < 0) serveraddrs[0].ai_addr, serveraddrs[0].ai_addrlen) < 0)
{ {
ereport(LOG, ereport(LOG,
(errmsg("could not send RADIUS packet: %m"))); (errmsg("could not send RADIUS packet: %m")));
closesocket(sock); closesocket(sock);
pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
return STATUS_ERROR; return STATUS_ERROR;
} }
/* Don't need the server address anymore */
pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
/* Wait for a response */
timeout.tv_sec = RADIUS_TIMEOUT; timeout.tv_sec = RADIUS_TIMEOUT;
timeout.tv_usec = 0; timeout.tv_usec = 0;
FD_ZERO(&fdset); FD_ZERO(&fdset);
@ -2705,11 +2735,21 @@ CheckRADIUSAuth(Port *port)
closesocket(sock); closesocket(sock);
#ifdef HAVE_IPV6
if (remoteaddr.sin6_port != htons(port->hba->radiusport))
#else
if (remoteaddr.sin_port != htons(port->hba->radiusport)) if (remoteaddr.sin_port != htons(port->hba->radiusport))
#endif
{ {
#ifdef HAVE_IPV6
ereport(LOG,
(errmsg("RADIUS response was sent from incorrect port: %i",
ntohs(remoteaddr.sin6_port))));
#else
ereport(LOG, ereport(LOG,
(errmsg("RADIUS response was sent from incorrect port: %i", (errmsg("RADIUS response was sent from incorrect port: %i",
ntohs(remoteaddr.sin_port)))); ntohs(remoteaddr.sin_port))));
#endif
return STATUS_ERROR; return STATUS_ERROR;
} }

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.196 2010/01/27 12:11:59 mha Exp $ * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.197 2010/02/02 19:09:37 mha Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1167,16 +1167,25 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
else if (strcmp(token, "radiusserver") == 0) else if (strcmp(token, "radiusserver") == 0)
{ {
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusserver", "radius"); REQUIRE_AUTH_OPTION(uaRADIUS, "radiusserver", "radius");
if (inet_addr(c) == INADDR_NONE)
MemSet(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = AF_UNSPEC;
ret = pg_getaddrinfo_all(c, NULL, &hints, &gai_result);
if (ret || !gai_result)
{ {
ereport(LOG, ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid RADIUS server IP address: \"%s\"", c), errmsg("could not translate RADIUS server name \"%s\" to address: %s",
c, gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"", errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName))); line_num, HbaFileName)));
if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
return false; return false;
} }
pg_freeaddrinfo_all(hints.ai_family, gai_result);
parsedline->radiusserver = pstrdup(c); parsedline->radiusserver = pstrdup(c);
} }
else if (strcmp(token, "radiusport") == 0) else if (strcmp(token, "radiusport") == 0)

View File

@ -1,4 +1,4 @@
/* $PostgreSQL: pgsql/src/include/port/solaris.h,v 1.18 2010/01/28 11:36:14 mha Exp $ */ /* $PostgreSQL: pgsql/src/include/port/solaris.h,v 1.19 2010/02/02 19:09:37 mha Exp $ */
/* /*
* Sort this out for all operating systems some time. The __xxx * Sort this out for all operating systems some time. The __xxx
@ -36,11 +36,3 @@
* still use our own fix for the buggy version. * still use our own fix for the buggy version.
*/ */
#define HAVE_BUGGY_SOLARIS_STRTOD #define HAVE_BUGGY_SOLARIS_STRTOD
/*
* Many versions of Solaris are missing the definition of INADDR_NONE
*/
#ifndef INADDR_NONE
#define INADDR_NONE ((in_addr_t)(-1))
#endif