radius_addr.patch

application/octet-stream

Filename: radius_addr.patch
Type: application/octet-stream
Part: 0
Message: Re: [COMMITTERS] pgsql: Define INADDR_NONE on Solaris when it's missing.

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
doc/src/sgml/client-auth.sgml 2 2
src/backend/libpq/auth.c 45 10
src/backend/libpq/hba.c 12 3
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index 2a9625f..47ba2a8 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -1375,8 +1375,8 @@ ldapserver=ldap.example.net ldapprefix="cn=" ldapsuffix=", dc=example, dc=net"
        <term><literal>radiusserver</literal></term>
        <listitem>
         <para>
-         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.
         </para>
        </listitem>
       </varlistentry>
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 36be782..c8bf16b 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -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,46 @@ 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;
+#else
+	localaddr.sin_family = serveraddrs[0].ai_family;
 	localaddr.sin_addr.s_addr = INADDR_ANY;
+#endif
 	if (bind(sock, (struct sockaddr *) &localaddr, sizeof(localaddr)))
 	{
 		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 +2730,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 dd7ad5c..927b394 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -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)