Commit 7356381e authored by Magnus Hagander's avatar Magnus Hagander

* make pg_hba authoption be a set of 0 or more name=value pairs

* make LDAP use this instead of the hacky previous method to specify
  the DN to bind as
* make all auth options behave the same when they are not compiled
  into the server
* rename "ident maps" to "user name maps", and support them for all
  auth methods that provide an external username

This makes a backwards incompatible change in the format of pg_hba.conf
for the ident, PAM and LDAP authentication methods.
parent 2675d043
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.168 2008/09/15 12:32:56 mha Exp $ * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.169 2008/10/23 13:31:10 mha Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -126,9 +126,8 @@ char *pg_krb_realm = NULL; ...@@ -126,9 +126,8 @@ char *pg_krb_realm = NULL;
* MIT Kerberos authentication system - protocol version 5 * MIT Kerberos authentication system - protocol version 5
*---------------------------------------------------------------- *----------------------------------------------------------------
*/ */
static int pg_krb5_recvauth(Port *port);
#ifdef KRB5 #ifdef KRB5
static int pg_krb5_recvauth(Port *port);
#include <krb5.h> #include <krb5.h>
/* Some old versions of Kerberos do not include <com_err.h> in <krb5.h> */ /* Some old versions of Kerberos do not include <com_err.h> in <krb5.h> */
...@@ -150,14 +149,14 @@ static krb5_principal pg_krb5_server; ...@@ -150,14 +149,14 @@ static krb5_principal pg_krb5_server;
* GSSAPI Authentication * GSSAPI Authentication
*---------------------------------------------------------------- *----------------------------------------------------------------
*/ */
static int pg_GSS_recvauth(Port *port);
#ifdef ENABLE_GSS #ifdef ENABLE_GSS
#if defined(HAVE_GSSAPI_H) #if defined(HAVE_GSSAPI_H)
#include <gssapi.h> #include <gssapi.h>
#else #else
#include <gssapi/gssapi.h> #include <gssapi/gssapi.h>
#endif #endif
static int pg_GSS_recvauth(Port *port);
#endif /* ENABLE_GSS */ #endif /* ENABLE_GSS */
...@@ -165,12 +164,11 @@ static int pg_GSS_recvauth(Port *port); ...@@ -165,12 +164,11 @@ static int pg_GSS_recvauth(Port *port);
* SSPI Authentication * SSPI Authentication
*---------------------------------------------------------------- *----------------------------------------------------------------
*/ */
static int pg_SSPI_recvauth(Port *port);
#ifdef ENABLE_SSPI #ifdef ENABLE_SSPI
typedef SECURITY_STATUS typedef SECURITY_STATUS
(WINAPI * QUERY_SECURITY_CONTEXT_TOKEN_FN) ( (WINAPI * QUERY_SECURITY_CONTEXT_TOKEN_FN) (
PCtxtHandle, void **); PCtxtHandle, void **);
static int pg_SSPI_recvauth(Port *port);
#endif #endif
...@@ -236,16 +234,12 @@ auth_failed(Port *port, int status) ...@@ -236,16 +234,12 @@ auth_failed(Port *port, int status)
case uaPassword: case uaPassword:
errstr = gettext_noop("password authentication failed for user \"%s\""); errstr = gettext_noop("password authentication failed for user \"%s\"");
break; break;
#ifdef USE_PAM
case uaPAM: case uaPAM:
errstr = gettext_noop("PAM authentication failed for user \"%s\""); errstr = gettext_noop("PAM authentication failed for user \"%s\"");
break; break;
#endif /* USE_PAM */
#ifdef USE_LDAP
case uaLDAP: case uaLDAP:
errstr = gettext_noop("LDAP authentication failed for user \"%s\""); errstr = gettext_noop("LDAP authentication failed for user \"%s\"");
break; break;
#endif /* USE_LDAP */
default: default:
errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method"); errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
break; break;
...@@ -316,18 +310,30 @@ ClientAuthentication(Port *port) ...@@ -316,18 +310,30 @@ ClientAuthentication(Port *port)
} }
case uaKrb5: case uaKrb5:
#ifdef KRB5
sendAuthRequest(port, AUTH_REQ_KRB5); sendAuthRequest(port, AUTH_REQ_KRB5);
status = pg_krb5_recvauth(port); status = pg_krb5_recvauth(port);
#else
Assert(false);
#endif
break; break;
case uaGSS: case uaGSS:
#ifdef ENABLE_GSS
sendAuthRequest(port, AUTH_REQ_GSS); sendAuthRequest(port, AUTH_REQ_GSS);
status = pg_GSS_recvauth(port); status = pg_GSS_recvauth(port);
#else
Assert(false);
#endif
break; break;
case uaSSPI: case uaSSPI:
#ifdef ENABLE_SSPI
sendAuthRequest(port, AUTH_REQ_SSPI); sendAuthRequest(port, AUTH_REQ_SSPI);
status = pg_SSPI_recvauth(port); status = pg_SSPI_recvauth(port);
#else
Assert(false);
#endif
break; break;
case uaIdent: case uaIdent:
...@@ -377,18 +383,22 @@ ClientAuthentication(Port *port) ...@@ -377,18 +383,22 @@ ClientAuthentication(Port *port)
status = recv_and_check_password_packet(port); status = recv_and_check_password_packet(port);
break; break;
#ifdef USE_PAM
case uaPAM: case uaPAM:
#ifdef USE_PAM
pam_port_cludge = port; pam_port_cludge = port;
status = CheckPAMAuth(port, port->user_name, ""); status = CheckPAMAuth(port, port->user_name, "");
break; #else
Assert(false);
#endif /* USE_PAM */ #endif /* USE_PAM */
break;
#ifdef USE_LDAP
case uaLDAP: case uaLDAP:
#ifdef USE_LDAP
status = CheckLDAPAuth(port); status = CheckLDAPAuth(port);
break; #else
Assert(false);
#endif #endif
break;
case uaTrust: case uaTrust:
status = STATUS_OK; status = STATUS_OK;
...@@ -713,19 +723,8 @@ pg_krb5_recvauth(Port *port) ...@@ -713,19 +723,8 @@ pg_krb5_recvauth(Port *port)
return STATUS_ERROR; return STATUS_ERROR;
} }
if (pg_krb_caseins_users) ret = check_usermap(port->hba->usermap, port->user_name, kusername,
ret = pg_strncasecmp(port->user_name, kusername, SM_DATABASE_USER); pg_krb_caseins_users);
else
ret = strncmp(port->user_name, kusername, SM_DATABASE_USER);
if (ret)
{
ereport(LOG,
(errmsg("unexpected Kerberos user name received from client (received \"%s\", expected \"%s\")",
port->user_name, kusername)));
ret = STATUS_ERROR;
}
else
ret = STATUS_OK;
krb5_free_ticket(pg_krb5_context, ticket); krb5_free_ticket(pg_krb5_context, ticket);
krb5_auth_con_free(pg_krb5_context, auth_context); krb5_auth_con_free(pg_krb5_context, auth_context);
...@@ -733,16 +732,6 @@ pg_krb5_recvauth(Port *port) ...@@ -733,16 +732,6 @@ pg_krb5_recvauth(Port *port)
return ret; return ret;
} }
#else
static int
pg_krb5_recvauth(Port *port)
{
ereport(LOG,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Kerberos 5 not implemented on this server")));
return STATUS_ERROR;
}
#endif /* KRB5 */ #endif /* KRB5 */
...@@ -1020,38 +1009,13 @@ pg_GSS_recvauth(Port *port) ...@@ -1020,38 +1009,13 @@ pg_GSS_recvauth(Port *port)
return STATUS_ERROR; return STATUS_ERROR;
} }
if (pg_krb_caseins_users) ret = check_usermap(port->hba->usermap, port->user_name, gbuf.value,
ret = pg_strcasecmp(port->user_name, gbuf.value); pg_krb_caseins_users);
else
ret = strcmp(port->user_name, gbuf.value);
if (ret)
{
/* GSS name and PGUSER are not equivalent */
elog(DEBUG2,
"provided username (%s) and GSSAPI username (%s) don't match",
port->user_name, (char *) gbuf.value);
gss_release_buffer(&lmin_s, &gbuf);
return STATUS_ERROR;
}
gss_release_buffer(&lmin_s, &gbuf); gss_release_buffer(&lmin_s, &gbuf);
return STATUS_OK; return STATUS_OK;
} }
#else /* no ENABLE_GSS */
static int
pg_GSS_recvauth(Port *port)
{
ereport(LOG,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("GSSAPI not implemented on this server")));
return STATUS_ERROR;
}
#endif /* ENABLE_GSS */ #endif /* ENABLE_GSS */
...@@ -1328,30 +1292,8 @@ pg_SSPI_recvauth(Port *port) ...@@ -1328,30 +1292,8 @@ pg_SSPI_recvauth(Port *port)
* We have the username (without domain/realm) in accountname, compare to * We have the username (without domain/realm) in accountname, compare to
* the supplied value. In SSPI, always compare case insensitive. * the supplied value. In SSPI, always compare case insensitive.
*/ */
if (pg_strcasecmp(port->user_name, accountname)) return check_usermap(port->hba->usermap, port->user_name, accountname, true);
{
/* GSS name and PGUSER are not equivalent */
elog(DEBUG2,
"provided username (%s) and SSPI username (%s) don't match",
port->user_name, accountname);
return STATUS_ERROR;
}
return STATUS_OK;
} }
#else /* no ENABLE_SSPI */
static int
pg_SSPI_recvauth(Port *port)
{
ereport(LOG,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("SSPI not implemented on this server")));
return STATUS_ERROR;
}
#endif /* ENABLE_SSPI */ #endif /* ENABLE_SSPI */
...@@ -1795,14 +1737,7 @@ authident(hbaPort *port) ...@@ -1795,14 +1737,7 @@ authident(hbaPort *port)
return STATUS_ERROR; return STATUS_ERROR;
} }
ereport(DEBUG2, return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
(errmsg("Ident protocol identifies remote user as \"%s\"",
ident_user)));
if (check_ident_usermap(port->hba->usermap, port->user_name, ident_user))
return STATUS_OK;
else
return STATUS_ERROR;
} }
...@@ -1913,8 +1848,8 @@ CheckPAMAuth(Port *port, char *user, char *password) ...@@ -1913,8 +1848,8 @@ CheckPAMAuth(Port *port, char *user, char *password)
* not allocated */ * not allocated */
/* Optionally, one can set the service name in pg_hba.conf */ /* Optionally, one can set the service name in pg_hba.conf */
if (port->hba->auth_arg && port->hba->auth_arg[0] != '\0') if (port->hba->pamservice && port->hba->pamservice[0] != '\0')
retval = pam_start(port->hba->auth_arg, "pgsql@", retval = pam_start(port->hba->pamservice, "pgsql@",
&pam_passw_conv, &pamh); &pam_passw_conv, &pamh);
else else
retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@", retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@",
...@@ -2000,76 +1935,20 @@ static int ...@@ -2000,76 +1935,20 @@ static int
CheckLDAPAuth(Port *port) CheckLDAPAuth(Port *port)
{ {
char *passwd; char *passwd;
char server[128];
char basedn[128];
char prefix[128];
char suffix[128];
LDAP *ldap; LDAP *ldap;
bool ssl = false;
int r; int r;
int ldapversion = LDAP_VERSION3; int ldapversion = LDAP_VERSION3;
int ldapport = LDAP_PORT;
char fulluser[NAMEDATALEN + 256 + 1]; char fulluser[NAMEDATALEN + 256 + 1];
if (!port->hba->auth_arg || port->hba->auth_arg[0] == '\0') if (!port->hba->ldapserver|| port->hba->ldapserver[0] == '\0')
{ {
ereport(LOG, ereport(LOG,
(errmsg("LDAP configuration URL not specified"))); (errmsg("LDAP server not specified")));
return STATUS_ERROR; return STATUS_ERROR;
} }
/* if (port->hba->ldapport == 0)
* Crack the LDAP url. We do a very trivial parse: port->hba->ldapport = LDAP_PORT;
*
* ldap[s]://<server>[:<port>]/<basedn>[;prefix[;suffix]]
*
* This code originally used "%127s" for the suffix, but that doesn't
* work for embedded whitespace. We know that tokens formed by
* hba.c won't include newlines, so we can use a "not newline" scanset
* instead.
*/
server[0] = '\0';
basedn[0] = '\0';
prefix[0] = '\0';
suffix[0] = '\0';
/* ldap, including port number */
r = sscanf(port->hba->auth_arg,
"ldap://%127[^:]:%d/%127[^;];%127[^;];%127[^\n]",
server, &ldapport, basedn, prefix, suffix);
if (r < 3)
{
/* ldaps, including port number */
r = sscanf(port->hba->auth_arg,
"ldaps://%127[^:]:%d/%127[^;];%127[^;];%127[^\n]",
server, &ldapport, basedn, prefix, suffix);
if (r >= 3)
ssl = true;
}
if (r < 3)
{
/* ldap, no port number */
r = sscanf(port->hba->auth_arg,
"ldap://%127[^/]/%127[^;];%127[^;];%127[^\n]",
server, basedn, prefix, suffix);
}
if (r < 2)
{
/* ldaps, no port number */
r = sscanf(port->hba->auth_arg,
"ldaps://%127[^/]/%127[^;];%127[^;];%127[^\n]",
server, basedn, prefix, suffix);
if (r >= 2)
ssl = true;
}
if (r < 2)
{
ereport(LOG,
(errmsg("invalid LDAP URL: \"%s\"",
port->hba->auth_arg)));
return STATUS_ERROR;
}
sendAuthRequest(port, AUTH_REQ_PASSWORD); sendAuthRequest(port, AUTH_REQ_PASSWORD);
...@@ -2077,7 +1956,7 @@ CheckLDAPAuth(Port *port) ...@@ -2077,7 +1956,7 @@ CheckLDAPAuth(Port *port)
if (passwd == NULL) if (passwd == NULL)
return STATUS_EOF; /* client wouldn't send password */ return STATUS_EOF; /* client wouldn't send password */
ldap = ldap_init(server, ldapport); ldap = ldap_init(port->hba->ldapserver, port->hba->ldapport);
if (!ldap) if (!ldap)
{ {
#ifndef WIN32 #ifndef WIN32
...@@ -2100,7 +1979,7 @@ CheckLDAPAuth(Port *port) ...@@ -2100,7 +1979,7 @@ CheckLDAPAuth(Port *port)
return STATUS_ERROR; return STATUS_ERROR;
} }
if (ssl) if (port->hba->ldaptls)
{ {
#ifndef WIN32 #ifndef WIN32
if ((r = ldap_start_tls_s(ldap, NULL, NULL)) != LDAP_SUCCESS) if ((r = ldap_start_tls_s(ldap, NULL, NULL)) != LDAP_SUCCESS)
...@@ -2155,7 +2034,9 @@ CheckLDAPAuth(Port *port) ...@@ -2155,7 +2034,9 @@ CheckLDAPAuth(Port *port)
} }
snprintf(fulluser, sizeof(fulluser), "%s%s%s", snprintf(fulluser, sizeof(fulluser), "%s%s%s",
prefix, port->user_name, suffix); port->hba->ldapprefix ? port->hba->ldapprefix : "",
port->user_name,
port->hba->ldapsuffix ? port->hba->ldapsuffix : "");
fulluser[sizeof(fulluser) - 1] = '\0'; fulluser[sizeof(fulluser) - 1] = '\0';
r = ldap_simple_bind_s(ldap, fulluser, passwd); r = ldap_simple_bind_s(ldap, fulluser, passwd);
...@@ -2165,7 +2046,7 @@ CheckLDAPAuth(Port *port) ...@@ -2165,7 +2046,7 @@ CheckLDAPAuth(Port *port)
{ {
ereport(LOG, ereport(LOG,
(errmsg("LDAP login failed for user \"%s\" on server \"%s\": error code %d", (errmsg("LDAP login failed for user \"%s\" on server \"%s\": error code %d",
fulluser, server, r))); fulluser, port->hba->ldapserver, r)));
return STATUS_ERROR; return STATUS_ERROR;
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.168 2008/09/15 20:55:04 mha Exp $ * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.169 2008/10/23 13:31:10 mha Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -564,6 +564,44 @@ check_db(const char *dbname, const char *role, char *param_str) ...@@ -564,6 +564,44 @@ check_db(const char *dbname, const char *role, char *param_str)
} }
/*
* Macros used to check and report on invalid configuration options.
* INVALID_AUTH_OPTION = reports when an option is specified for a method where it's
* not supported.
* REQUIRE_AUTH_OPTION = same as INVALID_AUTH_OPTION, except it also checks if the
* method is actually the one specified. Used as a shortcut when
* the option is only valid for one authentication method.
* MANDATORY_AUTH_ARG = check if a required option is set for an authentication method,
* reporting error if it's not.
*/
#define INVALID_AUTH_OPTION(optname, validmethods) do {\
ereport(LOG, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
errmsg("authentication option '%s' is only valid for authentication methods '%s'", \
optname, validmethods), \
errcontext("line %d of configuration file \"%s\"", \
line_num, HbaFileName))); \
goto hba_other_error; \
} while (0);
#define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) do {\
if (parsedline->auth_method != methodval) \
INVALID_AUTH_OPTION("ldaptls", "ldap"); \
} while (0);
#define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
if (argvar == NULL) {\
ereport(LOG, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
errmsg("authentication method '%s' requires argument '%s' to be set", \
authname, argname), \
errcontext("line %d of configuration file \"%s\"", \
line_num, HbaFileName))); \
goto hba_other_error; \
} \
} while (0);
/* /*
* Parse one line in the hba config file and store the result in * Parse one line in the hba config file and store the result in
* a HbaLine structure. * a HbaLine structure.
...@@ -801,38 +839,102 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline) ...@@ -801,38 +839,102 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
goto hba_other_error; goto hba_other_error;
} }
/* Get the authentication argument token, if any */ /* Parse remaining arguments */
line_item = lnext(line_item); while ((line_item = lnext(line_item)) != NULL)
if (line_item)
{ {
char *c;
token = lfirst(line_item); token = lfirst(line_item);
parsedline->auth_arg= pstrdup(token);
}
/* c = strchr(token, '=');
* Backwards compatible format of ident authentication - support "naked" ident map if (c == NULL)
* name, as well as "sameuser"/"samerole"
*/
if (parsedline->auth_method == uaIdent)
{
if (parsedline->auth_arg && strlen(parsedline->auth_arg))
{ {
if (strcmp(parsedline->auth_arg, "sameuser\n") == 0 || /*
strcmp(parsedline->auth_arg, "samerole\n") == 0) * Got something that's not a name=value pair.
*
* XXX: attempt to do some backwards compatible parsing here?
*/
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication option not in name=value format: %s", token),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
goto hba_other_error;
}
else
{
*c++ = '\0'; /* token now holds "name", c holds "value" */
if (strcmp(token, "map") == 0)
{
if (parsedline->auth_method != uaIdent &&
parsedline->auth_method != uaKrb5 &&
parsedline->auth_method != uaGSS &&
parsedline->auth_method != uaSSPI)
INVALID_AUTH_OPTION("map", "ident, krb5, gssapi and sspi");
parsedline->usermap = pstrdup(c);
}
else if (strcmp(token, "pamservice") == 0)
{
REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
parsedline->pamservice = pstrdup(c);
}
else if (strcmp(token, "ldaptls") == 0)
{
REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
if (strcmp(c, "1") == 0)
parsedline->ldaptls = true;
else
parsedline->ldaptls = false;
}
else if (strcmp(token, "ldapserver") == 0)
{
REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
parsedline->ldapserver = pstrdup(c);
}
else if (strcmp(token, "ldapport") == 0)
{
REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
parsedline->ldapport = atoi(c);
if (parsedline->ldapport == 0)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid ldap port '%s'", c),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
goto hba_other_error;
}
}
else if (strcmp(token, "ldapprefix") == 0)
{ {
/* This is now the default */ REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
pfree(parsedline->auth_arg); parsedline->ldapprefix = pstrdup(c);
parsedline->auth_arg = NULL; }
parsedline->usermap = NULL; else if (strcmp(token, "ldapsuffix") == 0)
{
REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
parsedline->ldapsuffix = pstrdup(c);
} }
else else
{ {
/* Specific ident map specified */ ereport(LOG,
parsedline->usermap = parsedline->auth_arg; (errcode(ERRCODE_CONFIG_FILE_ERROR),
parsedline->auth_arg = NULL; errmsg("unknown authentication option name '%s'", token),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
goto hba_other_error;
} }
} }
} }
/*
* Check if the selected authentication method has any mandatory arguments that
* are not set.
*/
if (parsedline->auth_method == uaLDAP)
{
MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
}
return true; return true;
...@@ -1018,8 +1120,14 @@ free_hba_record(HbaLine *record) ...@@ -1018,8 +1120,14 @@ free_hba_record(HbaLine *record)
pfree(record->database); pfree(record->database);
if (record->role) if (record->role)
pfree(record->role); pfree(record->role);
if (record->auth_arg) if (record->pamservice)
pfree(record->auth_arg); pfree(record->pamservice);
if (record->ldapserver)
pfree(record->ldapserver);
if (record->ldapprefix)
pfree(record->ldapprefix);
if (record->ldapsuffix)
pfree(record->ldapsuffix);
} }
/* /*
...@@ -1150,7 +1258,7 @@ read_pg_database_line(FILE *fp, char *dbname, Oid *dboid, ...@@ -1150,7 +1258,7 @@ read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
static void static void
parse_ident_usermap(List *line, int line_number, const char *usermap_name, parse_ident_usermap(List *line, int line_number, const char *usermap_name,
const char *pg_role, const char *ident_user, const char *pg_role, const char *ident_user,
bool *found_p, bool *error_p) bool case_insensitive, bool *found_p, bool *error_p)
{ {
ListCell *line_item; ListCell *line_item;
char *token; char *token;
...@@ -1183,10 +1291,20 @@ parse_ident_usermap(List *line, int line_number, const char *usermap_name, ...@@ -1183,10 +1291,20 @@ parse_ident_usermap(List *line, int line_number, const char *usermap_name,
file_pgrole = token; file_pgrole = token;
/* Match? */ /* Match? */
if (strcmp(file_map, usermap_name) == 0 && if (case_insensitive)
strcmp(file_pgrole, pg_role) == 0 && {
strcmp(file_ident_user, ident_user) == 0) if (strcmp(file_map, usermap_name) == 0 &&
*found_p = true; pg_strcasecmp(file_pgrole, pg_role) == 0 &&
pg_strcasecmp(file_ident_user, ident_user) == 0)
*found_p = true;
}
else
{
if (strcmp(file_map, usermap_name) == 0 &&
strcmp(file_pgrole, pg_role) == 0 &&
strcmp(file_ident_user, ident_user) == 0)
*found_p = true;
}
return; return;
...@@ -1210,22 +1328,32 @@ ident_syntax: ...@@ -1210,22 +1328,32 @@ ident_syntax:
* file. That's an implied map where "pgrole" must be identical to * file. That's an implied map where "pgrole" must be identical to
* "ident_user" in order to be authorized. * "ident_user" in order to be authorized.
* *
* Iff authorized, return true. * Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
*/ */
bool int
check_ident_usermap(const char *usermap_name, check_usermap(const char *usermap_name,
const char *pg_role, const char *pg_role,
const char *ident_user) const char *auth_user,
bool case_insensitive)
{ {
bool found_entry = false, bool found_entry = false,
error = false; error = false;
if (usermap_name == NULL || usermap_name[0] == '\0') if (usermap_name == NULL || usermap_name[0] == '\0')
{ {
if (strcmp(pg_role, ident_user) == 0) if (case_insensitive)
found_entry = true; {
else if (pg_strcasecmp(pg_role, auth_user) == 0)
found_entry = false; return STATUS_OK;
}
else {
if (strcmp(pg_role, auth_user) == 0)
return STATUS_OK;
}
ereport(LOG,
(errmsg("provided username (%s) and authenticated username (%s) don't match",
auth_user, pg_role)));
return STATUS_ERROR;
} }
else else
{ {
...@@ -1235,13 +1363,20 @@ check_ident_usermap(const char *usermap_name, ...@@ -1235,13 +1363,20 @@ check_ident_usermap(const char *usermap_name,
forboth(line_cell, ident_lines, num_cell, ident_line_nums) forboth(line_cell, ident_lines, num_cell, ident_line_nums)
{ {
parse_ident_usermap(lfirst(line_cell), lfirst_int(num_cell), parse_ident_usermap(lfirst(line_cell), lfirst_int(num_cell),
usermap_name, pg_role, ident_user, usermap_name, pg_role, auth_user, case_insensitive,
&found_entry, &error); &found_entry, &error);
if (found_entry || error) if (found_entry || error)
break; break;
} }
} }
return found_entry; if (!found_entry && !error)
{
ereport(LOG,
(errmsg("no match in usermap for user '%s' authenticated as '%s'",
pg_role, auth_user),
errcontext("usermap '%s'", usermap_name)));
}
return found_entry?STATUS_OK:STATUS_ERROR;
} }
......
...@@ -9,10 +9,10 @@ ...@@ -9,10 +9,10 @@
# are authenticated, which PostgreSQL user names they can use, which # are authenticated, which PostgreSQL user names they can use, which
# databases they can access. Records take one of these forms: # databases they can access. Records take one of these forms:
# #
# local DATABASE USER METHOD [OPTION] # local DATABASE USER METHOD [OPTIONS]
# host DATABASE USER CIDR-ADDRESS METHOD [OPTION] # host DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
# hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTION] # hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
# hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTION] # hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
# #
# (The uppercase items must be replaced by actual values.) # (The uppercase items must be replaced by actual values.)
# #
...@@ -38,7 +38,10 @@ ...@@ -38,7 +38,10 @@
# "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords # "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords
# in clear text; "md5" is preferred since it sends encrypted passwords. # in clear text; "md5" is preferred since it sends encrypted passwords.
# #
# OPTION is the ident map or the name of the PAM service, depending on METHOD. # OPTIONS are a set of options for the authentication in the format
# NAME=VALUE. The available options depend on the different authentication
# methods - refer to the "Client Authentication" section in the documentation
# for a list of which options are available for which authentication methods.
# #
# Database and user names containing spaces, commas, quotes and other special # Database and user names containing spaces, commas, quotes and other special
# characters must be quoted. Quoting one of the keywords "all", "sameuser" or # characters must be quoted. Quoting one of the keywords "all", "sameuser" or
......
...@@ -5,18 +5,18 @@ ...@@ -5,18 +5,18 @@
# Authentication" for a complete description. A short synopsis # Authentication" for a complete description. A short synopsis
# follows. # follows.
# #
# This file controls PostgreSQL ident-based authentication. It maps # This file controls PostgreSQL username mapping. It maps
# ident user names (typically Unix user names) to their corresponding # external user names to their corresponding
# PostgreSQL user names. Records are of the form: # PostgreSQL user names. Records are of the form:
# #
# MAPNAME IDENT-USERNAME PG-USERNAME # MAPNAME SYSTEM-USERNAME PG-USERNAME
# #
# (The uppercase quantities must be replaced by actual values.) # (The uppercase quantities must be replaced by actual values.)
# #
# MAPNAME is the (otherwise freely chosen) map name that was used in # MAPNAME is the (otherwise freely chosen) map name that was used in
# pg_hba.conf. IDENT-USERNAME is the detected user name of the # pg_hba.conf. SYSTEM-USERNAME is the detected user name of the
# client. PG-USERNAME is the requested PostgreSQL user name. The # client. PG-USERNAME is the requested PostgreSQL user name. The
# existence of a record specifies that IDENT-USERNAME may connect as # existence of a record specifies that SYSTEM-USERNAME may connect as
# PG-USERNAME. Multiple maps may be specified in this file and used # PG-USERNAME. Multiple maps may be specified in this file and used
# by pg_hba.conf. # by pg_hba.conf.
# #
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
# Put your actual configuration here # Put your actual configuration here
# ---------------------------------- # ----------------------------------
# #
# No map names are defined in the default configuration. If all ident # No map names are defined in the default configuration. If all system
# user names and PostgreSQL user names are the same, you don't need # user names and PostgreSQL user names are the same, you don't need
# this file. # this file.
# MAPNAME IDENT-USERNAME PG-USERNAME # MAPNAME SYSTEM-USERNAME PG-USERNAME
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Interface to hba.c * Interface to hba.c
* *
* *
* $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.49 2008/09/15 12:32:57 mha Exp $ * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.50 2008/10/23 13:31:10 mha Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -25,13 +25,9 @@ typedef enum UserAuth ...@@ -25,13 +25,9 @@ typedef enum UserAuth
uaCrypt, uaCrypt,
uaMD5, uaMD5,
uaGSS, uaGSS,
uaSSPI uaSSPI,
#ifdef USE_PAM uaPAM,
,uaPAM uaLDAP
#endif /* USE_PAM */
#ifdef USE_LDAP
,uaLDAP
#endif
} UserAuth; } UserAuth;
typedef enum ConnType typedef enum ConnType
...@@ -51,8 +47,14 @@ typedef struct ...@@ -51,8 +47,14 @@ typedef struct
struct sockaddr_storage addr; struct sockaddr_storage addr;
struct sockaddr_storage mask; struct sockaddr_storage mask;
UserAuth auth_method; UserAuth auth_method;
char *usermap; char *usermap;
char *auth_arg; char *pamservice;
bool ldaptls;
char *ldapserver;
int ldapport;
char *ldapprefix;
char *ldapsuffix;
} HbaLine; } HbaLine;
typedef struct Port hbaPort; typedef struct Port hbaPort;
...@@ -64,8 +66,9 @@ extern void load_role(void); ...@@ -64,8 +66,9 @@ extern void load_role(void);
extern int hba_getauthmethod(hbaPort *port); extern int hba_getauthmethod(hbaPort *port);
extern bool read_pg_database_line(FILE *fp, char *dbname, Oid *dboid, extern bool read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
Oid *dbtablespace, TransactionId *dbfrozenxid); Oid *dbtablespace, TransactionId *dbfrozenxid);
extern bool check_ident_usermap(const char *usermap_name, extern int check_usermap(const char *usermap_name,
const char *pg_role, const char *ident_user); const char *pg_role, const char *auth_user,
bool case_sensitive);
extern bool pg_isblank(const char c); extern bool pg_isblank(const char c);
#endif /* HBA_H */ #endif /* HBA_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment