]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Remove RADIUS support.
authorThomas Munro <tmunro@postgresql.org>
Wed, 8 Apr 2026 10:38:43 +0000 (22:38 +1200)
committerThomas Munro <tmunro@postgresql.org>
Wed, 8 Apr 2026 10:38:43 +0000 (22:38 +1200)
Our RADIUS implementation supported only the deprecated RADIUS/UDP
variant, without the recommended Message-Authenticator attribute to
mitigate against the Blast-RADIUS vulnerability.  By now, popular RADIUS
servers are expected to generate loud warnings or reject our
authentication attempts outright.

Since there have been no user reports about this, it seems unlikely that
there are users.

Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Reviewed-by: Aleksander Alekseev <aleksander@tigerdata.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Jacob Champion <jacob.champion@enterprisedb.com>
Reviewed-by: Michael Banck <mbanck@gmx.net>
Discussion: https://postgr.es/m/CA%2BhUKG%2BSH309V8KECU5%3DxuLP9Dks0v9f9UVS2W74fPAE5O21dg%40mail.gmail.com

doc/src/sgml/appendix-obsolete-auth-radius.sgml [new file with mode: 0644]
doc/src/sgml/appendix-obsolete.sgml
doc/src/sgml/client-auth.sgml
doc/src/sgml/filelist.sgml
src/backend/libpq/auth.c
src/backend/libpq/hba.c
src/backend/libpq/pg_hba.conf.sample
src/backend/utils/adt/hbafuncs.c
src/include/libpq/hba.h
src/tools/pgindent/typedefs.list

diff --git a/doc/src/sgml/appendix-obsolete-auth-radius.sgml b/doc/src/sgml/appendix-obsolete-auth-radius.sgml
new file mode 100644 (file)
index 0000000..68d49df
--- /dev/null
@@ -0,0 +1,20 @@
+<!-- doc/src/sgml/appendix-obsolete-auth-radius.sgml -->
+<!--
+  See doc/src/sgml/appendix-obsolete.sgml for why this file exists. Do not change the id attribute.
+-->
+
+<sect1 id="auth-radius">
+  <title>RADIUS authentication removed</title>
+
+   <indexterm zone="auth-radius">
+    <primary>RADIUS</primary>
+   </indexterm>
+
+   <para>
+    PostgreSQL 18 and below supported the RADIUS authentication protocol.
+    Information about an alternative way to configure RADIUS support
+    is available on the PostgreSQL
+    <ulink url="https://wiki.postgresql.org/wiki/RADIUS">wiki</ulink>.
+   </para>
+
+</sect1>
index b1a00c8ce67b5515d93d14e6ff82dd842471ead8..cc0026530525122086a868fc1ae28c77ea3c6e17 100644 (file)
@@ -38,5 +38,6 @@
  &obsolete-pgxlogdump;
  &obsolete-pgresetxlog;
  &obsolete-pgreceivexlog;
+ &obsolete-auth-radius;
 
 </appendix>
index bca09a80416fb62a2f163ea402a8f2f489b6a315..e4e65f8feb1d11f524ebc92431a1ab38f25b2f21 100644 (file)
@@ -616,16 +616,6 @@ include_dir         <replaceable>directory</replaceable>
         </listitem>
        </varlistentry>
 
-       <varlistentry>
-        <term><literal>radius</literal></term>
-        <listitem>
-         <para>
-          Authenticate using a RADIUS server. See <xref
-          linkend="auth-radius"/> for details.
-         </para>
-        </listitem>
-       </varlistentry>
-
        <varlistentry>
         <term><literal>cert</literal></term>
         <listitem>
@@ -1127,12 +1117,6 @@ omicron         bryanh                  guest1
       relies on an LDAP authentication server.
      </para>
     </listitem>
-    <listitem>
-     <para>
-      <link linkend="auth-radius">RADIUS authentication</link>, which
-      relies on a RADIUS authentication server.
-     </para>
-    </listitem>
     <listitem>
      <para>
       <link linkend="auth-cert">Certificate authentication</link>, which
@@ -2096,118 +2080,6 @@ host ... ldap ldapbasedn="dc=example,dc=net"
 
   </sect1>
 
-  <sect1 id="auth-radius">
-   <title>RADIUS Authentication</title>
-
-   <indexterm zone="auth-radius">
-    <primary>RADIUS</primary>
-   </indexterm>
-
-   <para>
-    This authentication method operates similarly to
-    <literal>password</literal> except that it uses RADIUS
-    as the password verification method. RADIUS is used only to validate
-    the user name/password pairs. Therefore the user must already
-    exist in the database before RADIUS can be used for
-    authentication.
-   </para>
-
-   <para>
-    When using RADIUS authentication, an Access Request message will be sent
-    to the configured RADIUS server. This request will be of type
-    <literal>Authenticate Only</literal>, and include parameters for
-    <literal>user name</literal>, <literal>password</literal> (encrypted) and
-    <literal>NAS Identifier</literal>. The request will be encrypted using
-    a secret shared with the server. The RADIUS server will respond to
-    this request with either <literal>Access Accept</literal> or
-    <literal>Access Reject</literal>. There is no support for RADIUS accounting.
-   </para>
-
-   <para>
-    Multiple RADIUS servers can be specified, in which case they will
-    be tried sequentially. If a negative response is received from
-    a server, the authentication will fail. If no response is received,
-    the next server in the list will be tried. To specify multiple
-    servers, separate the server names with commas and surround the list
-    with double quotes. If multiple servers are specified, the other
-    RADIUS options can also be given as comma-separated lists, to provide
-    individual values for each server. They can also be specified as
-    a single value, in which case that value will apply to all servers.
-   </para>
-
-   <para>
-    The following configuration options are supported for RADIUS:
-     <variablelist>
-      <varlistentry>
-       <term><literal>radiusservers</literal></term>
-       <listitem>
-        <para>
-         The DNS names or IP addresses of the RADIUS servers to connect to.
-         This parameter is required.
-        </para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term><literal>radiussecrets</literal></term>
-       <listitem>
-        <para>
-         The shared secrets used when talking securely to the RADIUS
-         servers. This must have exactly the same value on the PostgreSQL
-         and RADIUS servers. It is recommended that this be a string of
-         at least 16 characters. This parameter is required.
-         <note>
-         <para>
-          The encryption vector used will only be cryptographically
-          strong if <productname>PostgreSQL</productname> is built with support for
-          <productname>OpenSSL</productname>. In other cases, the transmission to the
-          RADIUS server should only be considered obfuscated, not secured, and
-          external security measures should be applied if necessary.
-         </para>
-         </note>
-        </para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term><literal>radiusports</literal></term>
-       <listitem>
-        <para>
-         The port numbers to connect to on the RADIUS servers. If no port
-         is specified, the default RADIUS port (<literal>1812</literal>)
-         will be used.
-        </para>
-       </listitem>
-      </varlistentry>
-
-      <varlistentry>
-       <term><literal>radiusidentifiers</literal></term>
-       <listitem>
-        <para>
-         The strings to be used as <literal>NAS Identifier</literal> in the
-         RADIUS requests. This parameter can be used, for example, to
-         identify which database cluster the user is attempting to connect
-         to, which can be useful for policy matching on
-         the RADIUS server. If no identifier is specified, the default
-         <literal>postgresql</literal> will be used.
-        </para>
-       </listitem>
-      </varlistentry>
-
-     </variablelist>
-   </para>
-
-   <para>
-    If it is necessary to have a comma or whitespace in a RADIUS parameter
-    value, that can be done by putting double quotes around the value, but
-    it is tedious because two layers of double-quoting are now required.
-    An example of putting whitespace into RADIUS secret strings is:
-<programlisting>
-host ... radius radiusservers="server1,server2" radiussecrets="""secret one"",""secret two"""
-</programlisting>
-   </para>
-  </sect1>
-
   <sect1 id="auth-cert">
    <title>Certificate Authentication</title>
 
index e8f758fc24b336cdf3bf878d87371cbe72bcac2f..25a85082759b435f4cda1e9d43490b9a0051859b 100644 (file)
 <!ENTITY obsolete-pgxlogdump SYSTEM "appendix-obsolete-pgxlogdump.sgml">
 <!ENTITY obsolete-pgresetxlog SYSTEM "appendix-obsolete-pgresetxlog.sgml">
 <!ENTITY obsolete-pgreceivexlog SYSTEM "appendix-obsolete-pgreceivexlog.sgml">
+<!ENTITY obsolete-auth-radius SYSTEM "appendix-obsolete-auth-radius.sgml">
index 47b5eeb8f2268422dafa57ea098f0da4fc7c777e..2af5615e54a45c3d271114981071b4bc021f9d3f 100644 (file)
@@ -203,13 +203,6 @@ static int pg_SSPI_make_upn(char *accountname,
                                                         bool update_accountname);
 #endif
 
-/*----------------------------------------------------------------
- * RADIUS Authentication
- *----------------------------------------------------------------
- */
-static int     CheckRADIUSAuth(Port *port);
-static int     PerformRadiusTransaction(const char *server, const char *secret, const char *portstr, const char *identifier, const char *user_name, const char *passwd);
-
 
 /*----------------------------------------------------------------
  * Global authentication functions
@@ -299,9 +292,6 @@ auth_failed(Port *port, int elevel, int status, const char *logdetail)
                case uaCert:
                        errstr = gettext_noop("certificate authentication failed for user \"%s\"");
                        break;
-               case uaRADIUS:
-                       errstr = gettext_noop("RADIUS authentication failed for user \"%s\"");
-                       break;
                case uaOAuth:
                        errstr = gettext_noop("OAuth bearer authentication failed for user \"%s\"");
                        break;
@@ -630,9 +620,6 @@ ClientAuthentication(Port *port)
                        Assert(false);
 #endif
                        break;
-               case uaRADIUS:
-                       status = CheckRADIUSAuth(port);
-                       break;
                case uaCert:
                        /* uaCert will be treated as if clientcert=verify-full (uaTrust) */
                case uaTrust:
@@ -775,7 +762,7 @@ recv_password_packet(Port *port)
         * We rely on that for MD5 and SCRAM authentication, but we still need
         * this check here, to prevent an empty password from being used with
         * authentication methods that check the password against an external
-        * system, like PAM, LDAP and RADIUS.
+        * system, like PAM and LDAP.
         */
        if (buf.len == 1)
                ereport(ERROR,
@@ -2790,499 +2777,3 @@ CheckCertAuth(Port *port)
        return status_check_usermap;
 }
 #endif
-
-
-/*----------------------------------------------------------------
- * RADIUS authentication
- *----------------------------------------------------------------
- */
-
-/*
- * RADIUS authentication is described in RFC2865 (and several others).
- */
-
-#define RADIUS_VECTOR_LENGTH 16
-#define RADIUS_HEADER_LENGTH 20
-#define RADIUS_MAX_PASSWORD_LENGTH 128
-
-/* Maximum size of a RADIUS packet we will create or accept */
-#define RADIUS_BUFFER_SIZE 1024
-
-typedef struct
-{
-       uint8           attribute;
-       uint8           length;
-       uint8           data[FLEXIBLE_ARRAY_MEMBER];
-} radius_attribute;
-
-typedef struct
-{
-       uint8           code;
-       uint8           id;
-       uint16          length;
-       uint8           vector[RADIUS_VECTOR_LENGTH];
-       /* this is a bit longer than strictly necessary: */
-       char            pad[RADIUS_BUFFER_SIZE - RADIUS_VECTOR_LENGTH];
-} radius_packet;
-
-/* RADIUS packet types */
-#define RADIUS_ACCESS_REQUEST  1
-#define RADIUS_ACCESS_ACCEPT   2
-#define RADIUS_ACCESS_REJECT   3
-
-/* RADIUS attributes */
-#define RADIUS_USER_NAME               1
-#define RADIUS_PASSWORD                        2
-#define RADIUS_SERVICE_TYPE            6
-#define RADIUS_NAS_IDENTIFIER  32
-
-/* RADIUS service types */
-#define RADIUS_AUTHENTICATE_ONLY       8
-
-/* Seconds to wait - XXX: should be in a config variable! */
-#define RADIUS_TIMEOUT 3
-
-static void
-radius_add_attribute(radius_packet *packet, uint8 type, const unsigned char *data, int len)
-{
-       radius_attribute *attr;
-
-       if (packet->length + len > RADIUS_BUFFER_SIZE)
-       {
-               /*
-                * With remotely realistic data, this can never happen. But catch it
-                * just to make sure we don't overrun a buffer. We'll just skip adding
-                * the broken attribute, which will in the end cause authentication to
-                * fail.
-                */
-               elog(WARNING,
-                        "adding attribute code %d with length %d to radius packet would create oversize packet, ignoring",
-                        type, len);
-               return;
-       }
-
-       attr = (radius_attribute *) ((unsigned char *) packet + packet->length);
-       attr->attribute = type;
-       attr->length = len + 2;         /* total size includes type and length */
-       memcpy(attr->data, data, len);
-       packet->length += attr->length;
-}
-
-static int
-CheckRADIUSAuth(Port *port)
-{
-       char       *passwd;
-       ListCell   *server,
-                          *secrets,
-                          *radiusports,
-                          *identifiers;
-
-       /* Make sure struct alignment is correct */
-       Assert(offsetof(radius_packet, vector) == 4);
-
-       /* Verify parameters */
-       if (port->hba->radiusservers == NIL)
-       {
-               ereport(LOG,
-                               (errmsg("RADIUS server not specified")));
-               return STATUS_ERROR;
-       }
-
-       if (port->hba->radiussecrets == NIL)
-       {
-               ereport(LOG,
-                               (errmsg("RADIUS secret not specified")));
-               return STATUS_ERROR;
-       }
-
-       /* Send regular password request to client, and get the response */
-       sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
-
-       passwd = recv_password_packet(port);
-       if (passwd == NULL)
-               return STATUS_EOF;              /* client wouldn't send password */
-
-       if (strlen(passwd) > RADIUS_MAX_PASSWORD_LENGTH)
-       {
-               ereport(LOG,
-                               (errmsg("RADIUS authentication does not support passwords longer than %d characters", RADIUS_MAX_PASSWORD_LENGTH)));
-               pfree(passwd);
-               return STATUS_ERROR;
-       }
-
-       /*
-        * Loop over and try each server in order.
-        */
-       secrets = list_head(port->hba->radiussecrets);
-       radiusports = list_head(port->hba->radiusports);
-       identifiers = list_head(port->hba->radiusidentifiers);
-       foreach(server, port->hba->radiusservers)
-       {
-               int                     ret = PerformRadiusTransaction(lfirst(server),
-                                                                                                  lfirst(secrets),
-                                                                                                  radiusports ? lfirst(radiusports) : NULL,
-                                                                                                  identifiers ? lfirst(identifiers) : NULL,
-                                                                                                  port->user_name,
-                                                                                                  passwd);
-
-               /*------
-                * STATUS_OK = Login OK
-                * STATUS_ERROR = Login not OK, but try next server
-                * STATUS_EOF = Login not OK, and don't try next server
-                *------
-                */
-               if (ret == STATUS_OK)
-               {
-                       set_authn_id(port, port->user_name);
-
-                       pfree(passwd);
-                       return STATUS_OK;
-               }
-               else if (ret == STATUS_EOF)
-               {
-                       pfree(passwd);
-                       return STATUS_ERROR;
-               }
-
-               /*
-                * secret, port and identifiers either have length 0 (use default),
-                * length 1 (use the same everywhere) or the same length as servers.
-                * So if the length is >1, we advance one step. In other cases, we
-                * don't and will then reuse the correct value.
-                */
-               if (list_length(port->hba->radiussecrets) > 1)
-                       secrets = lnext(port->hba->radiussecrets, secrets);
-               if (list_length(port->hba->radiusports) > 1)
-                       radiusports = lnext(port->hba->radiusports, radiusports);
-               if (list_length(port->hba->radiusidentifiers) > 1)
-                       identifiers = lnext(port->hba->radiusidentifiers, identifiers);
-       }
-
-       /* No servers left to try, so give up */
-       pfree(passwd);
-       return STATUS_ERROR;
-}
-
-static int
-PerformRadiusTransaction(const char *server, const char *secret, const char *portstr, const char *identifier, const char *user_name, const char *passwd)
-{
-       radius_packet radius_send_pack;
-       radius_packet radius_recv_pack;
-       radius_packet *packet = &radius_send_pack;
-       radius_packet *receivepacket = &radius_recv_pack;
-       void       *radius_buffer = &radius_send_pack;
-       void       *receive_buffer = &radius_recv_pack;
-       int32           service = pg_hton32(RADIUS_AUTHENTICATE_ONLY);
-       uint8      *cryptvector;
-       int                     encryptedpasswordlen;
-       uint8           encryptedpassword[RADIUS_MAX_PASSWORD_LENGTH];
-       uint8      *md5trailer;
-       int                     packetlength;
-       pgsocket        sock;
-
-       struct sockaddr_in6 localaddr;
-       struct sockaddr_in6 remoteaddr;
-       struct addrinfo hint;
-       struct addrinfo *serveraddrs;
-       int                     port;
-       socklen_t       addrsize;
-       fd_set          fdset;
-       struct timeval endtime;
-       int                     i,
-                               j,
-                               r;
-
-       /* Assign default values */
-       if (portstr == NULL)
-               portstr = "1812";
-       if (identifier == NULL)
-               identifier = "postgresql";
-
-       MemSet(&hint, 0, sizeof(hint));
-       hint.ai_socktype = SOCK_DGRAM;
-       hint.ai_family = AF_UNSPEC;
-       port = atoi(portstr);
-
-       r = pg_getaddrinfo_all(server, portstr, &hint, &serveraddrs);
-       if (r || !serveraddrs)
-       {
-               ereport(LOG,
-                               (errmsg("could not translate RADIUS server name \"%s\" to address: %s",
-                                               server, gai_strerror(r))));
-               if (serveraddrs)
-                       pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
-               return STATUS_ERROR;
-       }
-       /* XXX: add support for multiple returned addresses? */
-
-       /* Construct RADIUS packet */
-       packet->code = RADIUS_ACCESS_REQUEST;
-       packet->length = RADIUS_HEADER_LENGTH;
-       if (!pg_strong_random(packet->vector, RADIUS_VECTOR_LENGTH))
-       {
-               ereport(LOG,
-                               (errmsg("could not generate random encryption vector")));
-               pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
-               return STATUS_ERROR;
-       }
-       packet->id = packet->vector[0];
-       radius_add_attribute(packet, RADIUS_SERVICE_TYPE, (const unsigned char *) &service, sizeof(service));
-       radius_add_attribute(packet, RADIUS_USER_NAME, (const unsigned char *) user_name, strlen(user_name));
-       radius_add_attribute(packet, RADIUS_NAS_IDENTIFIER, (const 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(secret) + RADIUS_VECTOR_LENGTH);
-       memcpy(cryptvector, secret, strlen(secret));
-
-       /* for the first iteration, we use the Request Authenticator vector */
-       md5trailer = packet->vector;
-       for (i = 0; i < encryptedpasswordlen; i += RADIUS_VECTOR_LENGTH)
-       {
-               const char *errstr = NULL;
-
-               memcpy(cryptvector + strlen(secret), 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(secret) + RADIUS_VECTOR_LENGTH,
-                                                  encryptedpassword + i, &errstr))
-               {
-                       ereport(LOG,
-                                       (errmsg("could not perform MD5 encryption of password: %s",
-                                                       errstr)));
-                       pfree(cryptvector);
-                       pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
-                       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 needs to be in network order on the wire */
-       packetlength = packet->length;
-       packet->length = pg_hton16(packet->length);
-
-       sock = socket(serveraddrs[0].ai_family, SOCK_DGRAM, 0);
-       if (sock == PGINVALID_SOCKET)
-       {
-               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.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);
-
-       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,
-                          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);
-
-       /*
-        * Figure out at what time we should time out. We can't just use a single
-        * call to select() with a timeout, since somebody can be sending invalid
-        * packets to our port thus causing us to retry in a loop and never time
-        * out.
-        *
-        * XXX: Using WaitLatchOrSocket() and doing a CHECK_FOR_INTERRUPTS() if
-        * the latch was set would improve the responsiveness to
-        * timeouts/cancellations.
-        */
-       gettimeofday(&endtime, NULL);
-       endtime.tv_sec += RADIUS_TIMEOUT;
-
-       while (true)
-       {
-               struct timeval timeout;
-               struct timeval now;
-               int64           timeoutval;
-               const char *errstr = NULL;
-
-               gettimeofday(&now, NULL);
-               timeoutval = (endtime.tv_sec * 1000000 + endtime.tv_usec) - (now.tv_sec * 1000000 + now.tv_usec);
-               if (timeoutval <= 0)
-               {
-                       ereport(LOG,
-                                       (errmsg("timeout waiting for RADIUS response from %s",
-                                                       server)));
-                       closesocket(sock);
-                       return STATUS_ERROR;
-               }
-               timeout.tv_sec = timeoutval / 1000000;
-               timeout.tv_usec = timeoutval % 1000000;
-
-               FD_ZERO(&fdset);
-               FD_SET(sock, &fdset);
-
-               r = select(sock + 1, &fdset, NULL, NULL, &timeout);
-               if (r < 0)
-               {
-                       if (errno == EINTR)
-                               continue;
-
-                       /* Anything else is an actual error */
-                       ereport(LOG,
-                                       (errmsg("could not check status on RADIUS socket: %m")));
-                       closesocket(sock);
-                       return STATUS_ERROR;
-               }
-               if (r == 0)
-               {
-                       ereport(LOG,
-                                       (errmsg("timeout waiting for RADIUS response from %s",
-                                                       server)));
-                       closesocket(sock);
-                       return STATUS_ERROR;
-               }
-
-               /*
-                * Attempt to read the response packet, and verify the contents.
-                *
-                * Any packet that's not actually a RADIUS packet, or otherwise does
-                * not validate as an explicit reject, is just ignored and we retry
-                * for another packet (until we reach the timeout). This is to avoid
-                * the possibility to denial-of-service the login by flooding the
-                * server with invalid packets on the port that we're expecting the
-                * RADIUS response on.
-                */
-
-               addrsize = sizeof(remoteaddr);
-               packetlength = recvfrom(sock, receive_buffer, RADIUS_BUFFER_SIZE, 0,
-                                                               (struct sockaddr *) &remoteaddr, &addrsize);
-               if (packetlength < 0)
-               {
-                       ereport(LOG,
-                                       (errmsg("could not read RADIUS response: %m")));
-                       closesocket(sock);
-                       return STATUS_ERROR;
-               }
-
-               if (remoteaddr.sin6_port != pg_hton16(port))
-               {
-                       ereport(LOG,
-                                       (errmsg("RADIUS response from %s was sent from incorrect port: %d",
-                                                       server, pg_ntoh16(remoteaddr.sin6_port))));
-                       continue;
-               }
-
-               if (packetlength < RADIUS_HEADER_LENGTH)
-               {
-                       ereport(LOG,
-                                       (errmsg("RADIUS response from %s too short: %d", server, packetlength)));
-                       continue;
-               }
-
-               if (packetlength != pg_ntoh16(receivepacket->length))
-               {
-                       ereport(LOG,
-                                       (errmsg("RADIUS response from %s has corrupt length: %d (actual length %d)",
-                                                       server, pg_ntoh16(receivepacket->length), packetlength)));
-                       continue;
-               }
-
-               if (packet->id != receivepacket->id)
-               {
-                       ereport(LOG,
-                                       (errmsg("RADIUS response from %s is to a different request: %d (should be %d)",
-                                                       server, receivepacket->id, packet->id)));
-                       continue;
-               }
-
-               /*
-                * Verify the response authenticator, which is calculated as
-                * MD5(Code+ID+Length+RequestAuthenticator+Attributes+Secret)
-                */
-               cryptvector = palloc(packetlength + strlen(secret));
-
-               memcpy(cryptvector, receivepacket, 4);  /* code+id+length */
-               memcpy(cryptvector + 4, packet->vector, RADIUS_VECTOR_LENGTH);  /* request
-                                                                                                                                                * authenticator, from
-                                                                                                                                                * original packet */
-               if (packetlength > RADIUS_HEADER_LENGTH)        /* there may be no
-                                                                                                        * attributes at all */
-                       memcpy(cryptvector + RADIUS_HEADER_LENGTH,
-                                  (char *) receive_buffer + RADIUS_HEADER_LENGTH,
-                                  packetlength - RADIUS_HEADER_LENGTH);
-               memcpy(cryptvector + packetlength, secret, strlen(secret));
-
-               if (!pg_md5_binary(cryptvector,
-                                                  packetlength + strlen(secret),
-                                                  encryptedpassword, &errstr))
-               {
-                       ereport(LOG,
-                                       (errmsg("could not perform MD5 encryption of received packet: %s",
-                                                       errstr)));
-                       pfree(cryptvector);
-                       continue;
-               }
-               pfree(cryptvector);
-
-               if (memcmp(receivepacket->vector, encryptedpassword, RADIUS_VECTOR_LENGTH) != 0)
-               {
-                       ereport(LOG,
-                                       (errmsg("RADIUS response from %s has incorrect MD5 signature",
-                                                       server)));
-                       continue;
-               }
-
-               if (receivepacket->code == RADIUS_ACCESS_ACCEPT)
-               {
-                       closesocket(sock);
-                       return STATUS_OK;
-               }
-               else if (receivepacket->code == RADIUS_ACCESS_REJECT)
-               {
-                       closesocket(sock);
-                       return STATUS_EOF;
-               }
-               else
-               {
-                       ereport(LOG,
-                                       (errmsg("RADIUS response from %s has invalid code (%d) for user \"%s\"",
-                                                       server, receivepacket->code, user_name)));
-                       continue;
-               }
-       }                                                       /* while (true) */
-}
index 7694506aaf716f0cfa8947b56287757b01573a6d..d47eab2cba0c0636ff1186ec82e68fee47a30904 100644 (file)
@@ -114,7 +114,6 @@ static const char *const UserAuthName[] =
        "bsd",
        "ldap",
        "cert",
-       "radius",
        "peer",
        "oauth",
 };
@@ -1744,8 +1743,6 @@ parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
 #else
                unsupauth = "cert";
 #endif
-       else if (strcmp(token->string, "radius") == 0)
-               parsedline->auth_method = uaRADIUS;
        else if (strcmp(token->string, "oauth") == 0)
                parsedline->auth_method = uaOAuth;
        else
@@ -1947,87 +1944,6 @@ parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
                }
        }
 
-       if (parsedline->auth_method == uaRADIUS)
-       {
-               MANDATORY_AUTH_ARG(parsedline->radiusservers, "radiusservers", "radius");
-               MANDATORY_AUTH_ARG(parsedline->radiussecrets, "radiussecrets", "radius");
-
-               if (parsedline->radiusservers == NIL)
-               {
-                       ereport(elevel,
-                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                        errmsg("list of RADIUS servers cannot be empty"),
-                                        errcontext("line %d of configuration file \"%s\"",
-                                                               line_num, file_name)));
-                       *err_msg = "list of RADIUS servers cannot be empty";
-                       return NULL;
-               }
-
-               if (parsedline->radiussecrets == NIL)
-               {
-                       ereport(elevel,
-                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                        errmsg("list of RADIUS secrets cannot be empty"),
-                                        errcontext("line %d of configuration file \"%s\"",
-                                                               line_num, file_name)));
-                       *err_msg = "list of RADIUS secrets cannot be empty";
-                       return NULL;
-               }
-
-               /*
-                * Verify length of option lists - each can be 0 (except for secrets,
-                * but that's already checked above), 1 (use the same value
-                * everywhere) or the same as the number of servers.
-                */
-               if (!(list_length(parsedline->radiussecrets) == 1 ||
-                         list_length(parsedline->radiussecrets) == list_length(parsedline->radiusservers)))
-               {
-                       ereport(elevel,
-                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                        errmsg("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
-                                                       list_length(parsedline->radiussecrets),
-                                                       list_length(parsedline->radiusservers)),
-                                        errcontext("line %d of configuration file \"%s\"",
-                                                               line_num, file_name)));
-                       *err_msg = psprintf("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
-                                                               list_length(parsedline->radiussecrets),
-                                                               list_length(parsedline->radiusservers));
-                       return NULL;
-               }
-               if (!(list_length(parsedline->radiusports) == 0 ||
-                         list_length(parsedline->radiusports) == 1 ||
-                         list_length(parsedline->radiusports) == list_length(parsedline->radiusservers)))
-               {
-                       ereport(elevel,
-                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                        errmsg("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
-                                                       list_length(parsedline->radiusports),
-                                                       list_length(parsedline->radiusservers)),
-                                        errcontext("line %d of configuration file \"%s\"",
-                                                               line_num, file_name)));
-                       *err_msg = psprintf("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
-                                                               list_length(parsedline->radiusports),
-                                                               list_length(parsedline->radiusservers));
-                       return NULL;
-               }
-               if (!(list_length(parsedline->radiusidentifiers) == 0 ||
-                         list_length(parsedline->radiusidentifiers) == 1 ||
-                         list_length(parsedline->radiusidentifiers) == list_length(parsedline->radiusservers)))
-               {
-                       ereport(elevel,
-                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                        errmsg("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
-                                                       list_length(parsedline->radiusidentifiers),
-                                                       list_length(parsedline->radiusservers)),
-                                        errcontext("line %d of configuration file \"%s\"",
-                                                               line_num, file_name)));
-                       *err_msg = psprintf("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
-                                                               list_length(parsedline->radiusidentifiers),
-                                                               list_length(parsedline->radiusservers));
-                       return NULL;
-               }
-       }
-
        /*
         * Enforce any parameters implied by other settings.
         */
@@ -2350,138 +2266,6 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
                else
                        hbaline->upn_username = false;
        }
-       else if (strcmp(name, "radiusservers") == 0)
-       {
-               struct addrinfo *gai_result;
-               struct addrinfo hints;
-               int                     ret;
-               List       *parsed_servers;
-               ListCell   *l;
-               char       *dupval = pstrdup(val);
-
-               REQUIRE_AUTH_OPTION(uaRADIUS, "radiusservers", "radius");
-
-               if (!SplitGUCList(dupval, ',', &parsed_servers))
-               {
-                       /* syntax error in list */
-                       ereport(elevel,
-                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                        errmsg("could not parse RADIUS server list \"%s\"",
-                                                       val),
-                                        errcontext("line %d of configuration file \"%s\"",
-                                                               line_num, file_name)));
-                       return false;
-               }
-
-               /* For each entry in the list, translate it */
-               foreach(l, parsed_servers)
-               {
-                       MemSet(&hints, 0, sizeof(hints));
-                       hints.ai_socktype = SOCK_DGRAM;
-                       hints.ai_family = AF_UNSPEC;
-
-                       ret = pg_getaddrinfo_all((char *) lfirst(l), NULL, &hints, &gai_result);
-                       if (ret || !gai_result)
-                       {
-                               ereport(elevel,
-                                               (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                                errmsg("could not translate RADIUS server name \"%s\" to address: %s",
-                                                               (char *) lfirst(l), gai_strerror(ret)),
-                                                errcontext("line %d of configuration file \"%s\"",
-                                                                       line_num, file_name)));
-                               if (gai_result)
-                                       pg_freeaddrinfo_all(hints.ai_family, gai_result);
-
-                               list_free(parsed_servers);
-                               return false;
-                       }
-                       pg_freeaddrinfo_all(hints.ai_family, gai_result);
-               }
-
-               /* All entries are OK, so store them */
-               hbaline->radiusservers = parsed_servers;
-               hbaline->radiusservers_s = pstrdup(val);
-       }
-       else if (strcmp(name, "radiusports") == 0)
-       {
-               List       *parsed_ports;
-               ListCell   *l;
-               char       *dupval = pstrdup(val);
-
-               REQUIRE_AUTH_OPTION(uaRADIUS, "radiusports", "radius");
-
-               if (!SplitGUCList(dupval, ',', &parsed_ports))
-               {
-                       ereport(elevel,
-                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                        errmsg("could not parse RADIUS port list \"%s\"",
-                                                       val),
-                                        errcontext("line %d of configuration file \"%s\"",
-                                                               line_num, file_name)));
-                       *err_msg = psprintf("invalid RADIUS port number: \"%s\"", val);
-                       return false;
-               }
-
-               foreach(l, parsed_ports)
-               {
-                       if (atoi(lfirst(l)) == 0)
-                       {
-                               ereport(elevel,
-                                               (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                                errmsg("invalid RADIUS port number: \"%s\"", val),
-                                                errcontext("line %d of configuration file \"%s\"",
-                                                                       line_num, file_name)));
-
-                               return false;
-                       }
-               }
-               hbaline->radiusports = parsed_ports;
-               hbaline->radiusports_s = pstrdup(val);
-       }
-       else if (strcmp(name, "radiussecrets") == 0)
-       {
-               List       *parsed_secrets;
-               char       *dupval = pstrdup(val);
-
-               REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecrets", "radius");
-
-               if (!SplitGUCList(dupval, ',', &parsed_secrets))
-               {
-                       /* syntax error in list */
-                       ereport(elevel,
-                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                        errmsg("could not parse RADIUS secret list \"%s\"",
-                                                       val),
-                                        errcontext("line %d of configuration file \"%s\"",
-                                                               line_num, file_name)));
-                       return false;
-               }
-
-               hbaline->radiussecrets = parsed_secrets;
-               hbaline->radiussecrets_s = pstrdup(val);
-       }
-       else if (strcmp(name, "radiusidentifiers") == 0)
-       {
-               List       *parsed_identifiers;
-               char       *dupval = pstrdup(val);
-
-               REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifiers", "radius");
-
-               if (!SplitGUCList(dupval, ',', &parsed_identifiers))
-               {
-                       /* syntax error in list */
-                       ereport(elevel,
-                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                                        errmsg("could not parse RADIUS identifiers list \"%s\"",
-                                                       val),
-                                        errcontext("line %d of configuration file \"%s\"",
-                                                               line_num, file_name)));
-                       return false;
-               }
-
-               hbaline->radiusidentifiers = parsed_identifiers;
-               hbaline->radiusidentifiers_s = pstrdup(val);
-       }
        else if (strcmp(name, "issuer") == 0)
        {
                REQUIRE_AUTH_OPTION(uaOAuth, "issuer", "oauth");
index 475100f88653ba99a916595fc4ca4eda51f47406..2c8db777479666b915aacd3f44e898878659b090 100644 (file)
@@ -53,8 +53,8 @@
 # directly connected to.
 #
 # METHOD can be "trust", "reject", "md5", "password", "scram-sha-256",
-# "gss", "sspi", "ident", "peer", "pam", "oauth", "ldap", "radius" or
-# "cert".  Note that "password" sends passwords in clear text; "md5" or
+# "gss", "sspi", "ident", "peer", "pam", "oauth", "ldap" or "cert".
+# Note that "password" sends passwords in clear text; "md5" or
 # "scram-sha-256" are preferred since they send encrypted passwords.
 #
 # OPTIONS are a set of options for the authentication in the format
index fdce3ed79279e1c64e36a51983b63ebde301ca7e..bd23eda3f79324f1b6c8dcd0f2c43fa17fd09031 100644 (file)
@@ -135,25 +135,6 @@ get_hba_options(HbaLine *hba)
                                CStringGetTextDatum(psprintf("ldapscope=%d", hba->ldapscope));
        }
 
-       if (hba->auth_method == uaRADIUS)
-       {
-               if (hba->radiusservers_s)
-                       options[noptions++] =
-                               CStringGetTextDatum(psprintf("radiusservers=%s", hba->radiusservers_s));
-
-               if (hba->radiussecrets_s)
-                       options[noptions++] =
-                               CStringGetTextDatum(psprintf("radiussecrets=%s", hba->radiussecrets_s));
-
-               if (hba->radiusidentifiers_s)
-                       options[noptions++] =
-                               CStringGetTextDatum(psprintf("radiusidentifiers=%s", hba->radiusidentifiers_s));
-
-               if (hba->radiusports_s)
-                       options[noptions++] =
-                               CStringGetTextDatum(psprintf("radiusports=%s", hba->radiusports_s));
-       }
-
        if (hba->auth_method == uaOAuth)
        {
                if (hba->oauth_issuer)
index e8898561c8c0ce33eef8856da6441223d9676856..29e2a6c5b3db18e6c4523b1ef752c087dcf25b25 100644 (file)
@@ -37,7 +37,6 @@ typedef enum UserAuth
        uaBSD,
        uaLDAP,
        uaCert,
-       uaRADIUS,
        uaPeer,
        uaOAuth,
 #define USER_AUTH_LAST uaOAuth /* Must be last value of this enum */
@@ -128,14 +127,6 @@ typedef struct HbaLine
        bool            include_realm;
        bool            compat_realm;
        bool            upn_username;
-       List       *radiusservers;
-       char       *radiusservers_s;
-       List       *radiussecrets;
-       char       *radiussecrets_s;
-       List       *radiusidentifiers;
-       char       *radiusidentifiers_s;
-       List       *radiusports;
-       char       *radiusports_s;
        char       *oauth_issuer;
        char       *oauth_scope;
        char       *oauth_validator;
index 87832856dbafbed74491b5bc1c6325aa87a82c56..ea95e7984bcfbedd3fae5c7528b0361307397111 100644 (file)
@@ -4185,8 +4185,6 @@ qc_hash_func
 qsort_arg_comparator
 qsort_comparator
 query_pathkeys_callback
-radius_attribute
-radius_packet
 RadixSortInfo
 rangeTableEntry_used_context
 rank_context