]> granicus.if.org Git - postgresql/commitdiff
Make RADIUS authentication use pg_getaddrinfo_all() to get address of
authorMagnus Hagander <magnus@hagander.net>
Tue, 2 Feb 2010 19:09:37 +0000 (19:09 +0000)
committerMagnus Hagander <magnus@hagander.net>
Tue, 2 Feb 2010 19:09:37 +0000 (19:09 +0000)
the server.

Gets rid of a fairly ugly hack for Solaris, and also provides hostname
and IPV6 support.

doc/src/sgml/client-auth.sgml
src/backend/libpq/auth.c
src/backend/libpq/hba.c
src/include/port/solaris.h

index 2e700fb533bf4cd25dbbab5278d70c6c831f7265..841e78dd534416c6c23e293a83c01465f61941dd 100644 (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">
  <title>Client Authentication</title>
@@ -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>
index 63ce8aca625561d022de3f3cfd6171d310e4603d..01b6851e3585bf0f7cbbd226e81f65a84181ad84 100644 (file)
@@ -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;
        }
 
index 588ce643afcd1e641b3916873f634367cf783d8e..94cff7cfd5762c4c1005df3e38bc95f6cd67154b 100644 (file)
@@ -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)
index 5dc6894b795a4a2a1fde94861a04c64488f06b2e..6e7fe601a65ca6f1864c7ea21b071960365bf664 100644 (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
  * 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
-