RADIUS secret in file
Attached is the "last step" of the RADIUS authenticaiton as I promised
Stephen - which allows the reading of the RAIDUS secret from a file
instead of hardcoded in pg_hba.conf. One reason being you don't want
the secret in your config file that may be in a shared repository or
such. IIRC Stephen had some other reason, but I'll leave it to him to
fill that in :-)
--
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/
Attachments:
radius_file.patchapplication/octet-stream; name=radius_file.patchDownload
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index 53577d2..b16839e 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -1408,6 +1408,18 @@ ldapserver=ldap.example.net ldapprefix="cn=" ldapsuffix=", dc=example, dc=net"
</varlistentry>
<varlistentry>
+ <term><literal>radiussecretfile</literal></term>
+ <listitem>
+ <para>
+ Read the shared secret from the file specified. This file will be
+ read every time authentication is attempted, and should contain the
+ secret without any quotes. This parameter cannot be used together
+ with radiussecret.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><literal>radiusport</literal></term>
<listitem>
<para>
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 99d97b4..d32803c 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -37,6 +37,7 @@
#include "libpq/md5.h"
#include "miscadmin.h"
#include "storage/ipc.h"
+#include "storage/fd.h"
/*----------------------------------------------------------------
@@ -2511,6 +2512,8 @@ static int
CheckRADIUSAuth(Port *port)
{
char *passwd;
+ char *secret;
+ char local_secret[RADIUS_BUFFER_SIZE];
char *identifier = "postgresql";
char radius_buffer[RADIUS_BUFFER_SIZE];
char receive_buffer[RADIUS_BUFFER_SIZE];
@@ -2547,13 +2550,50 @@ CheckRADIUSAuth(Port *port)
return STATUS_ERROR;
}
- if (!port->hba->radiussecret || port->hba->radiussecret[0] == '\0')
+ if ((!port->hba->radiussecret || port->hba->radiussecret[0] == '\0') &&
+ (!port->hba->radiussecretfile || port->hba->radiussecretfile[0] == '\0'))
{
ereport(LOG,
(errmsg("RADIUS secret not specified")));
return STATUS_ERROR;
}
+ if (port->hba->radiussecretfile)
+ {
+ FILE *f;
+ /*
+ * RADIUS secret is in a file. Read it into a temporary buffer and use
+ * that.
+ */
+ f = AllocateFile(port->hba->radiussecretfile, "r");
+ if (!f)
+ {
+ ereport(LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("could not open RADIUS secret file \"%s\": %m",
+ port->hba->radiussecretfile)));
+ return STATUS_ERROR;
+ }
+ if (!fgets(local_secret, sizeof(local_secret), f))
+ {
+ ereport(LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("could not read from RADIUS secret file \"%s\": %m",
+ port->hba->radiussecretfile)));
+ FreeFile(f);
+ return STATUS_ERROR;
+ }
+ FreeFile(f);
+ while (strlen(local_secret) &&
+ (local_secret[strlen(local_secret)-1] == '\n' ||
+ local_secret[strlen(local_secret)-1] == '\r'))
+ local_secret[strlen(local_secret)-1] = '\0';
+
+ secret = local_secret;
+ }
+ else
+ secret = port->hba->radiussecret;
+
if (port->hba->radiusport == 0)
port->hba->radiusport = 1812;
@@ -2622,10 +2662,10 @@ CheckRADIUSAuth(Port *port)
* 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))
+ cryptvector = palloc(RADIUS_VECTOR_LENGTH + strlen(secret));
+ memcpy(cryptvector, secret, strlen(secret));
+ memcpy(cryptvector + strlen(secret), packet->vector, RADIUS_VECTOR_LENGTH);
+ if (!pg_md5_binary(cryptvector, RADIUS_VECTOR_LENGTH + strlen(secret), encryptedpassword))
{
ereport(LOG,
(errmsg("could not perform md5 encryption of password")));
@@ -2780,16 +2820,16 @@ CheckRADIUSAuth(Port *port)
* Verify the response authenticator, which is calculated as
* MD5(Code+ID+Length+RequestAuthenticator+Attributes+Secret)
*/
- cryptvector = palloc(packetlength + strlen(port->hba->radiussecret));
+ 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, receive_buffer + RADIUS_HEADER_LENGTH, packetlength-RADIUS_HEADER_LENGTH);
- memcpy(cryptvector+packetlength, port->hba->radiussecret, strlen(port->hba->radiussecret));
+ memcpy(cryptvector+packetlength, secret, strlen(secret));
if (!pg_md5_binary(cryptvector,
- packetlength + strlen(port->hba->radiussecret),
+ packetlength + strlen(secret),
encryptedpassword))
{
ereport(LOG,
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index de56683..352898d 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -1207,6 +1207,11 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecret", "radius");
parsedline->radiussecret = pstrdup(c);
}
+ else if (strcmp(token, "radiussecretfile") == 0)
+ {
+ REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecretfile", "radius");
+ parsedline->radiussecretfile = pstrdup(c);
+ }
else if (strcmp(token, "radiusidentifier") == 0)
{
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
@@ -1267,7 +1272,24 @@ 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");
+ if (!(parsedline->radiussecret || parsedline->radiussecretfile))
+ {
+ ereport(LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("authentication method \"radius\" requires argument \"radiussecret\" or \"radiussecretfile\" to be set"),
+ errcontext("line %d of configuration file \"%s\"",
+ line_num, HbaFileName)));
+ return false;
+ }
+ if (parsedline->radiussecret && parsedline->radiussecretfile)
+ {
+ ereport(LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("cannot use \"radiussecretfile\" together with \"radiussecret\""),
+ errcontext("line %d of configuration file \"%s\"",
+ line_num, HbaFileName)));
+ return false;
+ }
}
/*
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 76fefcb..4e5d3b1 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -74,6 +74,7 @@ typedef struct
bool include_realm;
char *radiusserver;
char *radiussecret;
+ char *radiussecretfile;
char *radiusidentifier;
int radiusport;
} HbaLine;
Magnus Hagander wrote:
Attached is the "last step" of the RADIUS authenticaiton as I promised
Stephen - which allows the reading of the RAIDUS secret from a file
instead of hardcoded in pg_hba.conf. One reason being you don't want
the secret in your config file that may be in a shared repository or
such. IIRC Stephen had some other reason, but I'll leave it to him to
fill that in :-)
Do we really need this in addition to the existing pg_hba.conf @-include
functionality?
Stefan
* Magnus Hagander (magnus@hagander.net) wrote:
IIRC Stephen had some other reason, but I'll leave it to him to
fill that in :-)
I was really looking for multi-server support as well, and support
for a config-file format that's commonly used for RADIUS. I'll
take a whack at doing that this evening.
Thanks,
Stephen