Support multiple RADIUS servers

This changes all the RADIUS related parameters (radiusserver,
radiussecret, radiusport, radiusidentifier) to be plural and to accept a
comma separated list of servers, which will be tried in order.

Reviewed by Adam Brightwell
This commit is contained in:
Magnus Hagander 2017-03-22 17:55:16 +01:00
parent c137c68ea6
commit 6b76f1bb58
4 changed files with 343 additions and 127 deletions

View File

@ -1621,24 +1621,36 @@ host ... ldap ldapurl="ldap://ldap.example.net/dc=example,dc=net?uid?sub"
<literal>Access Reject</>. 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, put the names within quotes and separate the server names
with a comma. If multiple servers are specified, all other RADIUS
options can also be given as a comma separate list, to apply
individual values to each server. They can also be specified as
a single value, in which case this value will apply to all servers.
</para>
<para>
The following configuration options are supported for RADIUS:
<variablelist>
<varlistentry>
<term><literal>radiusserver</literal></term>
<term><literal>radiusservers</literal></term>
<listitem>
<para>
The name or IP address of the RADIUS server to connect to.
The name or IP addresses of the RADIUS servers to connect to.
This parameter is required.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>radiussecret</literal></term>
<term><literal>radiussecrets</literal></term>
<listitem>
<para>
The shared secret used when talking securely to the RADIUS
The shared secrets 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 be a string of
at least 16 characters. This parameter is required.
@ -1656,17 +1668,17 @@ host ... ldap ldapurl="ldap://ldap.example.net/dc=example,dc=net?uid?sub"
</varlistentry>
<varlistentry>
<term><literal>radiusport</literal></term>
<term><literal>radiusports</literal></term>
<listitem>
<para>
The port number on the RADIUS server to connect to. If no port
The port number on the RADIUS servers 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>
<term><literal>radiusidentifiers</literal></term>
<listitem>
<para>
The string used as <literal>NAS Identifier</> in the RADIUS

View File

@ -197,6 +197,7 @@ static int pg_SSPI_make_upn(char *accountname,
*----------------------------------------------------------------
*/
static int CheckRADIUSAuth(Port *port);
static int PerformRadiusTransaction(char *server, char *secret, char *portstr, char *identifier, char *user_name, char *passwd);
/*----------------------------------------------------------------
@ -2591,77 +2592,29 @@ 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;
int encryptedpasswordlen;
uint8 encryptedpassword[RADIUS_MAX_PASSWORD_LENGTH];
uint8 *md5trailer;
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 endtime;
int i,
j,
r;
ListCell *server,
*secrets,
*radiusports,
*identifiers;
/* Make sure struct alignment is correct */
Assert(offsetof(radius_packet, vector) == 4);
/* Verify parameters */
if (!port->hba->radiusserver || port->hba->radiusserver[0] == '\0')
if (list_length(port->hba->radiusservers) < 1)
{
ereport(LOG,
(errmsg("RADIUS server not specified")));
return STATUS_ERROR;
}
if (!port->hba->radiussecret || port->hba->radiussecret[0] == '\0')
if (list_length(port->hba->radiussecrets) < 1)
{
ereport(LOG,
(errmsg("RADIUS secret not specified")));
return STATUS_ERROR;
}
if (port->hba->radiusport == 0)
port->hba->radiusport = 1812;
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("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;
}
/* XXX: add support for multiple returned addresses? */
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, NULL, 0);
@ -2683,6 +2636,104 @@ CheckRADIUSAuth(Port *port)
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)
return STATUS_OK;
else if (ret == STATUS_EOF)
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(secrets);
if (list_length(port->hba->radiusports) > 1)
radiusports = lnext(radiusports);
if (list_length(port->hba->radiusidentifiers) > 1)
identifiers = lnext(identifiers);
}
/* No servers left to try, so give up */
return STATUS_ERROR;
}
static int
PerformRadiusTransaction(char *server, char *secret, char *portstr, char *identifier, char *user_name, char *passwd)
{
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;
int encryptedpasswordlen;
uint8 encryptedpassword[RADIUS_MAX_PASSWORD_LENGTH];
uint8 *md5trailer;
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;
int port;
ACCEPT_TYPE_ARG3 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;
@ -2695,7 +2746,7 @@ CheckRADIUSAuth(Port *port)
}
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_USER_NAME, (unsigned char *) user_name, strlen(user_name));
radius_add_attribute(packet, RADIUS_NAS_IDENTIFIER, (unsigned char *) identifier, strlen(identifier));
/*
@ -2705,14 +2756,14 @@ CheckRADIUSAuth(Port *port)
* (if necessary)
*/
encryptedpasswordlen = ((strlen(passwd) + RADIUS_VECTOR_LENGTH - 1) / RADIUS_VECTOR_LENGTH) * RADIUS_VECTOR_LENGTH;
cryptvector = palloc(strlen(port->hba->radiussecret) + RADIUS_VECTOR_LENGTH);
memcpy(cryptvector, port->hba->radiussecret, strlen(port->hba->radiussecret));
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)
{
memcpy(cryptvector + strlen(port->hba->radiussecret), md5trailer, RADIUS_VECTOR_LENGTH);
memcpy(cryptvector + strlen(secret), md5trailer, RADIUS_VECTOR_LENGTH);
/*
* .. and for subsequent iterations the result of the previous XOR
@ -2720,7 +2771,7 @@ CheckRADIUSAuth(Port *port)
*/
md5trailer = encryptedpassword + i;
if (!pg_md5_binary(cryptvector, strlen(port->hba->radiussecret) + RADIUS_VECTOR_LENGTH, encryptedpassword + i))
if (!pg_md5_binary(cryptvector, strlen(secret) + RADIUS_VECTOR_LENGTH, encryptedpassword + i))
{
ereport(LOG,
(errmsg("could not perform MD5 encryption of password")));
@ -2812,7 +2863,8 @@ CheckRADIUSAuth(Port *port)
if (timeoutval <= 0)
{
ereport(LOG,
(errmsg("timeout waiting for RADIUS response")));
(errmsg("timeout waiting for RADIUS response from %s",
server)));
closesocket(sock);
return STATUS_ERROR;
}
@ -2837,7 +2889,8 @@ CheckRADIUSAuth(Port *port)
if (r == 0)
{
ereport(LOG,
(errmsg("timeout waiting for RADIUS response")));
(errmsg("timeout waiting for RADIUS response from %s",
server)));
closesocket(sock);
return STATUS_ERROR;
}
@ -2864,19 +2917,19 @@ CheckRADIUSAuth(Port *port)
}
#ifdef HAVE_IPV6
if (remoteaddr.sin6_port != htons(port->hba->radiusport))
if (remoteaddr.sin6_port != htons(port))
#else
if (remoteaddr.sin_port != htons(port->hba->radiusport))
if (remoteaddr.sin_port != htons(port))
#endif
{
#ifdef HAVE_IPV6
ereport(LOG,
(errmsg("RADIUS response was sent from incorrect port: %d",
ntohs(remoteaddr.sin6_port))));
(errmsg("RADIUS response from %s was sent from incorrect port: %d",
server, ntohs(remoteaddr.sin6_port))));
#else
ereport(LOG,
(errmsg("RADIUS response was sent from incorrect port: %d",
ntohs(remoteaddr.sin_port))));
(errmsg("RADIUS response from %s was sent from incorrect port: %d",
server, ntohs(remoteaddr.sin_port))));
#endif
continue;
}
@ -2884,23 +2937,23 @@ CheckRADIUSAuth(Port *port)
if (packetlength < RADIUS_HEADER_LENGTH)
{
ereport(LOG,
(errmsg("RADIUS response too short: %d", packetlength)));
(errmsg("RADIUS response from %s too short: %d", server, packetlength)));
continue;
}
if (packetlength != ntohs(receivepacket->length))
{
ereport(LOG,
(errmsg("RADIUS response has corrupt length: %d (actual length %d)",
ntohs(receivepacket->length), packetlength)));
(errmsg("RADIUS response from %s has corrupt length: %d (actual length %d)",
server, ntohs(receivepacket->length), packetlength)));
continue;
}
if (packet->id != receivepacket->id)
{
ereport(LOG,
(errmsg("RADIUS response is to a different request: %d (should be %d)",
receivepacket->id, packet->id)));
(errmsg("RADIUS response from %s is to a different request: %d (should be %d)",
server, receivepacket->id, packet->id)));
continue;
}
@ -2908,7 +2961,7 @@ 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
@ -2917,10 +2970,10 @@ CheckRADIUSAuth(Port *port)
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,
@ -2933,7 +2986,8 @@ CheckRADIUSAuth(Port *port)
if (memcmp(receivepacket->vector, encryptedpassword, RADIUS_VECTOR_LENGTH) != 0)
{
ereport(LOG,
(errmsg("RADIUS response has incorrect MD5 signature")));
(errmsg("RADIUS response from %s has incorrect MD5 signature",
server)));
continue;
}
@ -2945,13 +2999,13 @@ CheckRADIUSAuth(Port *port)
else if (receivepacket->code == RADIUS_ACCESS_REJECT)
{
closesocket(sock);
return STATUS_ERROR;
return STATUS_EOF;
}
else
{
ereport(LOG,
(errmsg("RADIUS response has invalid code (%d) for user \"%s\"",
receivepacket->code, port->user_name)));
(errmsg("RADIUS response from %s has invalid code (%d) for user \"%s\"",
server, receivepacket->code, user_name)));
continue;
}
} /* while (true) */

View File

@ -39,6 +39,7 @@
#include "storage/fd.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/varlena.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
@ -143,6 +144,8 @@ static List *tokenize_inc_file(List *tokens, const char *outer_filename,
const char *inc_filename, int elevel, char **err_msg);
static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
int elevel, char **err_msg);
static bool verify_option_list_length(List *options, char *optionname,
List *masters, char *mastername, int line_num);
static ArrayType *gethba_options(HbaLine *hba);
static void fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
int lineno, HbaLine *hba, const char *err_msg);
@ -1532,8 +1535,52 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
if (parsedline->auth_method == uaRADIUS)
{
MANDATORY_AUTH_ARG(parsedline->radiusserver, "radiusserver", "radius");
MANDATORY_AUTH_ARG(parsedline->radiussecret, "radiussecret", "radius");
MANDATORY_AUTH_ARG(parsedline->radiusservers, "radiusservers", "radius");
MANDATORY_AUTH_ARG(parsedline->radiussecrets, "radiussecrets", "radius");
if (list_length(parsedline->radiusservers) < 1)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("list of RADIUS servers cannot be empty"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
if (list_length(parsedline->radiussecrets) < 1)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("list of RADIUS secrets cannot be empty"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
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 (!verify_option_list_length(parsedline->radiussecrets,
"RADIUS secrets",
parsedline->radiusservers,
"RADIUS servers",
line_num))
return NULL;
if (!verify_option_list_length(parsedline->radiusports,
"RADIUS ports",
parsedline->radiusservers,
"RADIUS servers",
line_num))
return NULL;
if (!verify_option_list_length(parsedline->radiusidentifiers,
"RADIUS identifiers",
parsedline->radiusservers,
"RADIUS servers",
line_num))
return NULL;
}
/*
@ -1547,6 +1594,28 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
return parsedline;
}
static bool
verify_option_list_length(List *options, char *optionname, List *masters, char *mastername, int line_num)
{
if (list_length(options) == 0 ||
list_length(options) == 1 ||
list_length(options) == list_length(masters))
return true;
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("the number of %s (%i) must be 1 or the same as the number of %s (%i)",
optionname,
list_length(options),
mastername,
list_length(masters)
),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
/*
* Parse one name-value pair as an authentication option into the given
* HbaLine. Return true if we successfully parse the option, false if we
@ -1766,60 +1835,137 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
else
hbaline->upn_username = false;
}
else if (strcmp(name, "radiusserver") == 0)
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, "radiusserver", "radius");
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusservers", "radius");
MemSet(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = AF_UNSPEC;
ret = pg_getaddrinfo_all(val, NULL, &hints, &gai_result);
if (ret || !gai_result)
if (!SplitIdentifierString(dupval, ',', &parsed_servers))
{
/* syntax error in list */
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not translate RADIUS server name \"%s\" to address: %s",
val, gai_strerror(ret)),
errmsg("could not parse RADIUS server list \"%s\"",
val),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
*err_msg = psprintf("could not translate RADIUS server name \"%s\" to address: %s",
val, gai_strerror(ret));
if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
return false;
}
pg_freeaddrinfo_all(hints.ai_family, gai_result);
hbaline->radiusserver = pstrdup(val);
/* 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, HbaFileName)));
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, "radiusport") == 0)
else if (strcmp(name, "radiusports") == 0)
{
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusport", "radius");
hbaline->radiusport = atoi(val);
if (hbaline->radiusport == 0)
List *parsed_ports;
ListCell *l;
char *dupval = pstrdup(val);
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusports", "radius");
if (!SplitIdentifierString(dupval, ',', &parsed_ports))
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid RADIUS port number: \"%s\"", val),
errmsg("could not parse RADIUS port list \"%s\"",
val),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
*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, HbaFileName)));
return false;
}
}
hbaline->radiusports = parsed_ports;
hbaline->radiusports_s = pstrdup(val);
}
else if (strcmp(name, "radiussecret") == 0)
else if (strcmp(name, "radiussecrets") == 0)
{
REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecret", "radius");
hbaline->radiussecret = pstrdup(val);
List *parsed_secrets;
char *dupval = pstrdup(val);
REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecrets", "radius");
if (!SplitIdentifierString(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, HbaFileName)));
return false;
}
hbaline->radiussecrets = parsed_secrets;
hbaline->radiussecrets_s = pstrdup(val);
}
else if (strcmp(name, "radiusidentifier") == 0)
else if (strcmp(name, "radiusidentifiers") == 0)
{
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
hbaline->radiusidentifier = pstrdup(val);
List *parsed_identifiers;
char *dupval = pstrdup(val);
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifiers", "radius");
if (!SplitIdentifierString(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, HbaFileName)));
return false;
}
hbaline->radiusidentifiers = parsed_identifiers;
hbaline->radiusidentifiers_s = pstrdup(val);
}
else
{
@ -2124,21 +2270,21 @@ gethba_options(HbaLine *hba)
if (hba->auth_method == uaRADIUS)
{
if (hba->radiusserver)
if (hba->radiusservers_s)
options[noptions++] =
CStringGetTextDatum(psprintf("radiusserver=%s", hba->radiusserver));
CStringGetTextDatum(psprintf("radiusservers=%s", hba->radiusservers_s));
if (hba->radiussecret)
if (hba->radiussecrets_s)
options[noptions++] =
CStringGetTextDatum(psprintf("radiussecret=%s", hba->radiussecret));
CStringGetTextDatum(psprintf("radiussecrets=%s", hba->radiussecrets_s));
if (hba->radiusidentifier)
if (hba->radiusidentifiers_s)
options[noptions++] =
CStringGetTextDatum(psprintf("radiusidentifier=%s", hba->radiusidentifier));
CStringGetTextDatum(psprintf("radiusidentifiers=%s", hba->radiusidentifiers_s));
if (hba->radiusport)
if (hba->radiusports_s)
options[noptions++] =
CStringGetTextDatum(psprintf("radiusport=%d", hba->radiusport));
CStringGetTextDatum(psprintf("radiusports=%s", hba->radiusports_s));
}
Assert(noptions <= MAX_HBA_OPTIONS);

View File

@ -89,10 +89,14 @@ typedef struct HbaLine
bool include_realm;
bool compat_realm;
bool upn_username;
char *radiusserver;
char *radiussecret;
char *radiusidentifier;
int radiusport;
List *radiusservers;
char *radiusservers_s;
List *radiussecrets;
char *radiussecrets_s;
List *radiusidentifiers;
char *radiusidentifiers_s;
List *radiusports;
char *radiusports_s;
} HbaLine;
typedef struct IdentLine