diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml index 2e700fb533bf4cd25dbbab5278d70c6c831f7265..841e78dd534416c6c23e293a83c01465f61941dd 100644 --- a/doc/src/sgml/client-auth.sgml +++ b/doc/src/sgml/client-auth.sgml @@ -1,4 +1,4 @@ - + Client Authentication @@ -1375,8 +1375,8 @@ ldapserver=ldap.example.net ldapprefix="cn=" ldapsuffix=", dc=example, dc=net" radiusserver - The IP address of the RADIUS server to connect to. This must - be an IPV4 address and not a hostname. This parameter is required. + The name or IP address of the RADIUS server to connect to. + This parameter is required. diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 63ce8aca625561d022de3f3cfd6171d310e4603d..01b6851e3585bf0f7cbbd226e81f65a84181ad84 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -8,7 +8,7 @@ * * * 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]; int packetlength; pgsocket sock; +#ifdef HAVE_IPV6 + struct sockaddr_in6 localaddr; + struct sockaddr_in6 remoteaddr; +#else struct sockaddr_in localaddr; struct sockaddr_in remoteaddr; +#endif + struct addrinfo hint; + struct addrinfo *serveraddrs; + char portstr[128]; ACCEPT_TYPE_ARG3 addrsize; fd_set fdset; struct timeval timeout; @@ -2549,17 +2557,22 @@ CheckRADIUSAuth(Port *port) if (port->hba->radiusport == 0) port->hba->radiusport = 1812; - memset(&remoteaddr, 0, sizeof(remoteaddr)); - remoteaddr.sin_family = AF_INET; - remoteaddr.sin_addr.s_addr = inet_addr(port->hba->radiusserver); - if (remoteaddr.sin_addr.s_addr == INADDR_NONE) + MemSet(&hint, 0, sizeof(hint)); + hint.ai_socktype = SOCK_DGRAM; + hint.ai_family = AF_UNSPEC; + snprintf(portstr, sizeof(portstr), "%d", port->hba->radiusport); + + r = pg_getaddrinfo_all(port->hba->radiusserver, portstr, &hint, &serveraddrs); + if (r || !serveraddrs) { ereport(LOG, - (errmsg("RADIUS server '%s' is not a valid IP address", - port->hba->radiusserver))); + (errmsg("could not translate RADIUS server name \"%s\" to address: %s", + port->hba->radiusserver, gai_strerror(r)))); + if (serveraddrs) + pg_freeaddrinfo_all(hint.ai_family, serveraddrs); 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]) identifier = port->hba->radiusidentifier; @@ -2633,34 +2646,51 @@ CheckRADIUSAuth(Port *port) packetlength = 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) { ereport(LOG, (errmsg("could not create RADIUS socket: %m"))); + pg_freeaddrinfo_all(hint.ai_family, serveraddrs); return STATUS_ERROR; } 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; - if (bind(sock, (struct sockaddr *) &localaddr, sizeof(localaddr))) + addrsize = sizeof(struct sockaddr_in); +#endif + if (bind(sock, (struct sockaddr *) &localaddr, addrsize)) { ereport(LOG, (errmsg("could not bind local RADIUS socket: %m"))); closesocket(sock); + pg_freeaddrinfo_all(hint.ai_family, serveraddrs); return STATUS_ERROR; } if (sendto(sock, radius_buffer, packetlength, 0, - (struct sockaddr *) &remoteaddr, sizeof(remoteaddr)) < 0) + serveraddrs[0].ai_addr, serveraddrs[0].ai_addrlen) < 0) { ereport(LOG, (errmsg("could not send RADIUS packet: %m"))); closesocket(sock); + pg_freeaddrinfo_all(hint.ai_family, serveraddrs); 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_usec = 0; FD_ZERO(&fdset); @@ -2705,11 +2735,21 @@ CheckRADIUSAuth(Port *port) closesocket(sock); +#ifdef HAVE_IPV6 + if (remoteaddr.sin6_port != htons(port->hba->radiusport)) +#else 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, (errmsg("RADIUS response was sent from incorrect port: %i", ntohs(remoteaddr.sin_port)))); +#endif return STATUS_ERROR; } diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 588ce643afcd1e641b3916873f634367cf783d8e..94cff7cfd5762c4c1005df3e38bc95f6cd67154b 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -10,7 +10,7 @@ * * * 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) { 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, (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\"", line_num, HbaFileName))); + if (gai_result) + pg_freeaddrinfo_all(hints.ai_family, gai_result); return false; - } + pg_freeaddrinfo_all(hints.ai_family, gai_result); parsedline->radiusserver = pstrdup(c); } else if (strcmp(token, "radiusport") == 0) diff --git a/src/include/port/solaris.h b/src/include/port/solaris.h index 5dc6894b795a4a2a1fde94861a04c64488f06b2e..6e7fe601a65ca6f1864c7ea21b071960365bf664 100644 --- a/src/include/port/solaris.h +++ b/src/include/port/solaris.h @@ -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 @@ -36,11 +36,3 @@ * still use our own fix for the buggy version. */ #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 -