Add support for RADIUS authentication.
authorMagnus Hagander <magnus@hagander.net>
Wed, 27 Jan 2010 12:12:00 +0000 (12:12 +0000)
committerMagnus Hagander <magnus@hagander.net>
Wed, 27 Jan 2010 12:12:00 +0000 (12:12 +0000)
doc/src/sgml/client-auth.sgml
src/backend/libpq/auth.c
src/backend/libpq/hba.c
src/backend/libpq/md5.c
src/backend/libpq/pg_hba.conf.sample
src/include/libpq/hba.h
src/include/libpq/md5.h

index 9ceae856448b4ab9803ea807e718a8dcc73251ef..a8360936b2e66ca2080080d63e9a16251f7dd319 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.127 2010/01/26 06:45:31 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.128 2010/01/27 12:11:59 mha Exp $ -->
 
 <chapter id="client-authentication">
  <title>Client Authentication</title>
@@ -394,6 +394,16 @@ hostnossl  <replaceable>database</replaceable>  <replaceable>user</replaceable>
         </listitem>
        </varlistentry>
 
+       <varlistentry>
+        <term><literal>radius</></term>
+        <listitem>
+         <para>
+          Authenticate using a RADIUS server. See <xref
+          linkend="auth-radius"> for detauls.
+         </para>
+        </listitem>
+       </varlistentry>
+
        <varlistentry>
         <term><literal>cert</></term>
         <listitem>
@@ -1331,6 +1341,95 @@ ldapserver=ldap.example.net ldapprefix="cn=" ldapsuffix=", dc=example, dc=net"
 
   </sect2>
 
+  <sect2 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>password</> (encrypted) and
+    <literal>NAS Identifier</>. The request will be encrypted using
+    a secret shared with the server. The RADIUS server will respond to
+    this server with either <literal>Access Accept</> or
+    <literal>Access Reject</>. There is no support for RADIUS accounting.
+   </para>
+
+   <para>
+    The following configuration options are supported for RADIUS:
+     <variablelist>
+      <varlistentry>
+       <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.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><literal>radiussecret</literal></term>
+       <listitem>
+        <para>
+         The shared secret used when talking securely to the RADIUS
+         server. This must have exactly the same value on the PostgreSQL
+         and RADIUS servers. It is recommended that this is 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</> is built with support for
+          <productname>OpenSSL</>. 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>radiusport</literal></term>
+       <listitem>
+        <para>
+         The port number on the RADIUS server to connect to. If no port
+         is specified, the default port <literal>1812</> will be used.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><literal>radiusidentifier</literal></term>
+       <listitem>
+        <para>
+         The string used as <literal>NAS Identifier</> in the RADIUS
+         requests. This parameter can be used as a second parameter
+         identifying for example which database the user is attempting
+         to authenticate as, which can be used for policy matching on
+         the RADIUS server. If no identifier is specified, the default
+         <literal>postgresql</> will be used.
+        </para>
+       </listitem>
+      </varlistentry>
+
+     </variablelist>
+   </para>
+  </sect2>
+
   <sect2 id="auth-cert">
    <title>Certificate authentication</title>
 
index e7d0dbb29854cf782ceb1a9c2cf626358f01be25..26d2080e6f975eae9abd42c99d8f9e96ebf492ee 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.191 2010/01/10 14:16:07 mha Exp $
+ *   $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.192 2010/01/27 12:11:59 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <unistd.h>
+#include <stddef.h>
 
 #include "libpq/auth.h"
 #include "libpq/crypt.h"
 #include "libpq/ip.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
+#include "libpq/md5.h"
 #include "miscadmin.h"
 #include "storage/ipc.h"
 
@@ -182,6 +184,15 @@ typedef SECURITY_STATUS
 static int pg_SSPI_recvauth(Port *port);
 #endif
 
+/*----------------------------------------------------------------
+ * RADIUS Authentication
+ *----------------------------------------------------------------
+ */
+#ifdef USE_SSL
+#include <openssl/rand.h>
+#endif
+static int CheckRADIUSAuth(Port *port);
+
 
 /*
  * Maximum accepted size of GSS and SSPI authentication tokens.
@@ -265,6 +276,9 @@ auth_failed(Port *port, int status)
        case uaLDAP:
            errstr = gettext_noop("LDAP authentication failed for user \"%s\"");
            break;
+       case uaRADIUS:
+           errstr = gettext_noop("RADIUS authentication failed for user \"%s\"");
+           break;
        default:
            errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
            break;
@@ -473,7 +487,9 @@ ClientAuthentication(Port *port)
            Assert(false);
 #endif
            break;
-
+       case uaRADIUS:
+           status = CheckRADIUSAuth(port);
+           break;
        case uaTrust:
            status = STATUS_OK;
            break;
@@ -2415,3 +2431,350 @@ CheckCertAuth(Port *port)
 }
 
 #endif
+
+
+/*----------------------------------------------------------------
+ * RADIUS authentication
+ *----------------------------------------------------------------
+ */
+
+/*
+ * RADIUS authentication is described in RFC2865 (and several
+ * others).
+ */
+
+#define RADIUS_VECTOR_LENGTH 16
+#define RADIUS_HEADER_LENGTH 20
+
+typedef struct
+{
+   uint8   attribute;
+   uint8   length;
+   uint8   data[1];
+} radius_attribute;
+
+typedef struct
+{
+   uint8   code;
+   uint8   id;
+   uint16  length;
+   uint8   vector[RADIUS_VECTOR_LENGTH];
+} radius_packet;
+
+/* RADIUS packet types */
+#define RADIUS_ACCESS_REQUEST  1
+#define RADIUS_ACCESS_ACCEPT   2
+#define RADIUS_ACCESS_REJECT   3
+
+/* RAIDUS 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
+
+/* Maximum size of a RADIUS packet we will create or accept */
+#define RADIUS_BUFFER_SIZE 1024
+
+/* 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 %i with length %i 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;
+   char               *identifier = "postgresql";
+   char                radius_buffer[RADIUS_BUFFER_SIZE];
+   char                receive_buffer[RADIUS_BUFFER_SIZE];
+   radius_packet      *packet = (radius_packet *)radius_buffer;
+   radius_packet      *receivepacket = (radius_packet *)receive_buffer;
+   int32               service = htonl(RADIUS_AUTHENTICATE_ONLY);
+   uint8              *cryptvector;
+   uint8               encryptedpassword[RADIUS_VECTOR_LENGTH];
+   int                 packetlength;
+   pgsocket            sock;
+   struct sockaddr_in  localaddr;
+   struct sockaddr_in  remoteaddr;
+   socklen_t           addrsize;
+   fd_set              fdset;
+   struct timeval      timeout;
+   int                 i,r;
+
+   /* Make sure struct alignment is correct */
+   Assert(offsetof(radius_packet, vector) == 4);
+
+   /* Verify parameters */
+   if (!port->hba->radiusserver || port->hba->radiusserver[0] == '\0')
+   {
+       ereport(LOG,
+               (errmsg("RADIUS server not specified")));
+       return STATUS_ERROR;
+   }
+
+   if (!port->hba->radiussecret || port->hba->radiussecret[0] == '\0')
+   {
+       ereport(LOG,
+               (errmsg("RADIUS secret not specified")));
+       return STATUS_ERROR;
+   }
+
+   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)
+   {
+       ereport(LOG,
+               (errmsg("RADIUS server '%s' is not a valid IP address",
+                       port->hba->radiusserver)));
+       return STATUS_ERROR;
+   }
+   remoteaddr.sin_port = htons(port->hba->radiusport);
+
+   if (port->hba->radiusidentifier && port->hba->radiusidentifier[0])
+       identifier = port->hba->radiusidentifier;
+
+   /* Send regular password request to client, and get the response */
+   sendAuthRequest(port, AUTH_REQ_PASSWORD);
+
+   passwd = recv_password_packet(port);
+   if (passwd == NULL)
+       return STATUS_EOF;      /* client wouldn't send password */
+
+   if (strlen(passwd) == 0)
+   {
+       ereport(LOG,
+               (errmsg("empty password returned by client")));
+       return STATUS_ERROR;
+   }
+
+   if (strlen(passwd) > RADIUS_VECTOR_LENGTH)
+   {
+       ereport(LOG,
+               (errmsg("RADIUS authentication does not support passwords longer than 16 characters")));
+       return STATUS_ERROR;
+   }
+
+   /* Construct RADIUS packet */
+   packet->code = RADIUS_ACCESS_REQUEST;
+   packet->length = RADIUS_HEADER_LENGTH;
+#ifdef USE_SSL
+   if (RAND_bytes(packet->vector, RADIUS_VECTOR_LENGTH) != 1)
+   {
+       ereport(LOG,
+               (errmsg("could not generate random encryption vector")));
+       return STATUS_ERROR;
+   }
+#else
+   for (i = 0; i < RADIUS_VECTOR_LENGTH; i++)
+       /* Use a lower strengh random number of OpenSSL is not available */
+       packet->vector[i] = random() % 255;
+#endif
+   packet->id = packet->vector[0];
+   radius_add_attribute(packet, RADIUS_SERVICE_TYPE, (unsigned char *) &service, sizeof(service));
+   radius_add_attribute(packet, RADIUS_USER_NAME, (unsigned char *) port->user_name, strlen(port->user_name));
+   radius_add_attribute(packet, RADIUS_NAS_IDENTIFIER, (unsigned char *) identifier, strlen(identifier));
+
+   /*
+    * RADIUS password attributes are calculated as:
+    * e[0] = p[0] XOR MD5(secret + vector)
+    */
+   cryptvector = palloc(RADIUS_VECTOR_LENGTH + strlen(port->hba->radiussecret));
+   memcpy(cryptvector, port->hba->radiussecret, strlen(port->hba->radiussecret));
+   memcpy(cryptvector + strlen(port->hba->radiussecret), packet->vector, RADIUS_VECTOR_LENGTH);
+   if (!pg_md5_binary(cryptvector, RADIUS_VECTOR_LENGTH + strlen(port->hba->radiussecret), encryptedpassword))
+   {
+       ereport(LOG,
+               (errmsg("could not perform md5 encryption of password")));
+       pfree(cryptvector);
+       return STATUS_ERROR;
+   }
+   pfree(cryptvector);
+   for (i = 0; i < RADIUS_VECTOR_LENGTH; i++)
+   {
+       if (i < strlen(passwd))
+           encryptedpassword[i] = passwd[i] ^ encryptedpassword[i];
+       else
+           encryptedpassword[i] = '\0' ^ encryptedpassword[i];
+   }
+   radius_add_attribute(packet, RADIUS_PASSWORD, encryptedpassword, RADIUS_VECTOR_LENGTH);
+
+   /* Length need to be in network order on the wire */
+   packetlength = packet->length;
+   packet->length = htons(packet->length);
+
+   sock = socket(AF_INET, SOCK_DGRAM, 0);
+   if (sock < 0)
+   {
+       ereport(LOG,
+               (errmsg("could not create RADIUS socket: %m")));
+       return STATUS_ERROR;
+   }
+
+   memset(&localaddr, 0, sizeof(localaddr));
+   localaddr.sin_family = AF_INET;
+   localaddr.sin_addr.s_addr = INADDR_ANY;
+   if (bind(sock, (struct sockaddr *) &localaddr, sizeof(localaddr)))
+   {
+       ereport(LOG,
+               (errmsg("could not bind local RADIUS socket: %m")));
+       closesocket(sock);
+       return STATUS_ERROR;
+   }
+
+   if (sendto(sock, radius_buffer, packetlength, 0,
+              (struct sockaddr *) &remoteaddr, sizeof(remoteaddr)) < 0)
+   {
+       ereport(LOG,
+               (errmsg("could not send RADIUS packet: %m")));
+       closesocket(sock);
+       return STATUS_ERROR;
+   }
+
+   timeout.tv_sec = RADIUS_TIMEOUT;
+   timeout.tv_usec = 0;
+   FD_ZERO(&fdset);
+   FD_SET(sock, &fdset);
+   while (true)
+   {
+       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")));
+           closesocket(sock);
+           return STATUS_ERROR;
+       }
+
+       /* else we actually have a packet ready to read */
+       break;
+   }
+
+   /* Read the response packet */
+   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;
+   }
+
+   closesocket(sock);
+
+   if (remoteaddr.sin_port != htons(port->hba->radiusport))
+   {
+       ereport(LOG,
+               (errmsg("RADIUS response was sent from incorrect port: %i",
+                       ntohs(remoteaddr.sin_port))));
+       return STATUS_ERROR;
+   }
+
+   if (packetlength < RADIUS_HEADER_LENGTH)
+   {
+       ereport(LOG,
+               (errmsg("RADIUS response too short: %i", packetlength)));
+       return STATUS_ERROR;
+   }
+
+   if (packetlength != ntohs(receivepacket->length))
+   {
+       ereport(LOG,
+               (errmsg("RADIUS response has corrupt length: %i (actual length %i)",
+                       ntohs(receivepacket->length), packetlength)));
+       return STATUS_ERROR;
+   }
+
+   if (packet->id != receivepacket->id)
+   {
+       ereport(LOG,
+               (errmsg("RADIUS response is to a different request: %i (should be %i)",
+                       receivepacket->id, packet->id)));
+       return STATUS_ERROR;
+   }
+
+   /*
+    * Verify the response authenticator, which is calculated as
+    * MD5(Code+ID+Length+RequestAuthenticator+Attributes+Secret)
+    */
+   cryptvector = palloc(packetlength + strlen(port->hba->radiussecret));
+
+   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, receive_buffer + RADIUS_HEADER_LENGTH, packetlength-RADIUS_HEADER_LENGTH);
+   memcpy(cryptvector+packetlength, port->hba->radiussecret, strlen(port->hba->radiussecret));
+
+   if (!pg_md5_binary(cryptvector,
+                      packetlength + strlen(port->hba->radiussecret),
+                      encryptedpassword))
+   {
+       ereport(LOG,
+               (errmsg("could not perform md5 encryption of received packet")));
+       pfree(cryptvector);
+       return STATUS_ERROR;
+   }
+   pfree(cryptvector);
+
+   if (memcmp(receivepacket->vector, encryptedpassword, RADIUS_VECTOR_LENGTH)  != 0)
+   {
+       ereport(LOG,
+               (errmsg("RADIUS response has incorrect MD5 signature")));
+       return STATUS_ERROR;
+   }
+
+   if (receivepacket->code == RADIUS_ACCESS_ACCEPT)
+       return STATUS_OK;
+   else if (receivepacket->code == RADIUS_ACCESS_REJECT)
+       return STATUS_ERROR;
+   else
+   {
+       ereport(LOG,
+               (errmsg("RADIUS response has invalid code (%i) for user '%s'",
+                       receivepacket->code, port->user_name)));
+       return STATUS_ERROR;
+   }
+}
index 98011c2822bab399ae921aa3b0d1707ab3b4bc0d..588ce643afcd1e641b3916873f634367cf783d8e 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.195 2010/01/15 09:19:02 heikki Exp $
+ *   $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.196 2010/01/27 12:11:59 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -952,6 +952,8 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
 #else
        unsupauth = "cert";
 #endif
+   else if (strcmp(token, "radius")== 0)
+       parsedline->auth_method = uaRADIUS;
    else
    {
        ereport(LOG,
@@ -1162,6 +1164,45 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
                else
                    parsedline->include_realm = false;
            }
+           else if (strcmp(token, "radiusserver") == 0)
+           {
+               REQUIRE_AUTH_OPTION(uaRADIUS, "radiusserver", "radius");
+               if (inet_addr(c) == INADDR_NONE)
+               {
+                   ereport(LOG,
+                           (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                            errmsg("invalid RADIUS server IP address: \"%s\"", c),
+                          errcontext("line %d of configuration file \"%s\"",
+                                     line_num, HbaFileName)));
+                   return false;
+
+               }
+               parsedline->radiusserver = pstrdup(c);
+           }
+           else if (strcmp(token, "radiusport") == 0)
+           {
+               REQUIRE_AUTH_OPTION(uaRADIUS, "radiusport", "radius");
+               parsedline->radiusport = atoi(c);
+               if (parsedline->radiusport == 0)
+               {
+                   ereport(LOG,
+                           (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                            errmsg("invalid RADIUS port number: \"%s\"", c),
+                          errcontext("line %d of configuration file \"%s\"",
+                                     line_num, HbaFileName)));
+                   return false;
+               }
+           }
+           else if (strcmp(token, "radiussecret") == 0)
+           {
+               REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecret", "radius");
+               parsedline->radiussecret = pstrdup(c);
+           }
+           else if (strcmp(token, "radiusidentifier") == 0)
+           {
+               REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
+               parsedline->radiusidentifier = pstrdup(c);
+           }
            else
            {
                ereport(LOG,
@@ -1214,6 +1255,12 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
        }
    }
 
+   if (parsedline->auth_method == uaRADIUS)
+   {
+       MANDATORY_AUTH_ARG(parsedline->radiusserver, "radiusserver", "radius");
+       MANDATORY_AUTH_ARG(parsedline->radiussecret, "radiussecret", "radius");
+   }
+
    /*
     * Enforce any parameters implied by other settings.
     */
index 002afcf0ff51639f95ed61d4dd4e0ddbf7791120..e875f51ed72cc7af493f0c17074472b0ac34bd52 100644 (file)
@@ -14,7 +14,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/libpq/md5.c,v 1.38 2010/01/02 16:57:45 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/libpq/md5.c,v 1.39 2010/01/27 12:11:59 mha Exp $
  */
 
 /* This is intended to be used in both frontend and backend, so use c.h */
@@ -298,6 +298,12 @@ pg_md5_hash(const void *buff, size_t len, char *hexsum)
    return true;
 }
 
+bool pg_md5_binary(const void *buff, size_t len, void *outbuf)
+{
+   if (!calculateDigestFromBuffer((uint8 *) buff, len, outbuf))
+       return false;
+   return true;
+}
 
 
 /*
index 22bb14730aa31c23e74ba24e5f330e8174ba580c..e1017cf28cd61d840f50a207631cd13b1b79b031 100644 (file)
@@ -39,9 +39,9 @@
 # any subnet that the server is directly connected to.
 #
 # METHOD can be "trust", "reject", "md5", "password", "gss", "sspi",
-# "krb5", "ident", "pam", "ldap" or "cert".  Note that "password"
-# sends passwords in clear text; "md5" is preferred since it sends
-# encrypted passwords.
+# "krb5", "ident", "pam", "ldap", "radius" or "cert".  Note that
+# "password" sends passwords in clear text; "md5" is preferred since
+# it sends encrypted passwords.
 #
 # OPTIONS are a set of options for the authentication in the format
 # NAME=VALUE.  The available options depend on the different
index 8ee71a7e093647b84047e71374edce20ef5c3510..54261bba61dbd3d9fdca6c50ff478b52f50e3203 100644 (file)
@@ -4,7 +4,7 @@
  *   Interface to hba.c
  *
  *
- * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.60 2009/12/12 21:35:21 mha Exp $
+ * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.61 2010/01/27 12:12:00 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,7 +27,8 @@ typedef enum UserAuth
    uaSSPI,
    uaPAM,
    uaLDAP,
-   uaCert
+   uaCert,
+   uaRADIUS
 } UserAuth;
 
 typedef enum IPCompareMethod
@@ -71,6 +72,10 @@ typedef struct
    char       *krb_server_hostname;
    char       *krb_realm;
    bool        include_realm;
+   char       *radiusserver;
+   char       *radiussecret;
+   char       *radiusidentifier;
+   int         radiusport;
 } HbaLine;
 
 /* kluge to avoid including libpq/libpq-be.h here */
index aa36ac6fa2388c129521c331c19addd86fff6227..decc6ddf120dc4754cb83133fd0bc01e84ccd123 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/libpq/md5.h,v 1.7 2010/01/02 16:58:04 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/libpq/md5.h,v 1.8 2010/01/27 12:12:00 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,6 +23,7 @@
 
 
 extern bool pg_md5_hash(const void *buff, size_t len, char *hexsum);
+extern bool pg_md5_binary(const void *buff, size_t len, void *outbuf);
 extern bool pg_md5_encrypt(const char *passwd, const char *salt,
               size_t salt_len, char *buf);