<sect3 id="md5-authentication-file-format">
<title>Authentication file format</title>
-
+ <para>
+ To use the <literal>md5</literal> authentication
+ <xref linkend="guc-pool-passwd"> authentication file
+ must contain the user password in either plain text
+ <literal>md5</literal> or <literal>AES</literal> encrypted format.
+ </para>
<para>
The <xref linkend="guc-pool-passwd"> file should contain lines in the following format:
+ <programlisting>
+ "username:plain_text_passwd"
+ </programlisting>
<programlisting>
"username:encrypted_passwd"
</programlisting>
</term>
<listitem>
<para>
- Specify the password file name for md5 authentication.
+ Specify the password file name for authentication.
Default value is <literal>"pool_passwd"</literal>.
Specifying <literal>''</literal> (empty) disables the use
- of password file. See <xref linkend="auth-md5"> for more
- details.
+ of password file.
</para>
+ <para>
+ Passwords can be stored in the pool_passwd file using three formats.
+ AES256 encrypted format, plain text format and md5 format.
+ <productname>Pgpool-II</productname> identifies the password format type
+ by it's prefix, so each password entry in the pool_passwd must be prefixed
+ as per the password format.
+ </para>
+ <para>
+ To store the password in the plain text format use <literal>TEXT</literal> prefix.
+ For example. to store clear text password string <literal>"mypassword"</literal>
+ in the pool_passwd, prepend the password string with <literal>TEXT</literal> prefix.
+ e.g. <literal>TEXTmypassword</literal>
+ </para>
+ <para>
+ similarly md5 hashed passwords must be prefixed with <literal>md5</literal> and
+ AES256 encrypted password types can be stored using <literal>AES</literal> prefix.
+ see <xref linkend="auth-aes-encrypted-password"> for more details on using
+ AES256 encrypted passwords.
+ </para>
+
+ <para>
+ In the absence of a valid prefix, <productname>Pgpool-II</productname> will
+ be considered the string as a plain text password
+ </para>
<para>
This parameter can only be set at server start.
</para>
<literal>AES</literal> after encrypting (using <literal>aes-256-cbc</literal> algorithm) and
encoding to <literal>base64</literal>.
</para>
+ <para>
+ To specify the unencrypted clear text password, prefix the password string with
+ <literal>TEXT</literal>. For example if you want to set <literal>mypass</literal> as
+ a password, you should specify <literal>TEXTmypass</literal> in the password field.
+ In the absence of a valid prefix, <productname>Pgpool-II</productname> will considered
+ the string as a plain text password.
+ </para>
<para>
You can also use <xref linkend="PG-ENC"> utility to create the correctly formatted
<literal>AES</literal> encrypted password strings.
<literal>AES</literal> after encrypting (using <literal>aes-256-cbc</literal> algorithm) and
encoding to <literal>base64</literal>.
</para>
+ <para>
+ To specify the unencrypted clear text password, prefix the password string with
+ <literal>TEXT</literal>. For example if you want to set <literal>mypass</literal> as
+ a password, you should specify <literal>TEXTmypass</literal> in the password field.
+ In the absence of a valid prefix, <productname>Pgpool-II</productname> will considered
+ the string as a plain text password.
+ </para>
<para>
You can also use <xref linkend="PG-ENC"> utility to create the correctly formatted
<literal>AES</literal> encrypted password strings.
<literal>AES</literal> after encrypting (using <literal>aes-256-cbc</literal> algorithm) and
encoding to <literal>base64</literal>.
</para>
+ <para>
+ To specify the unencrypted clear text password, prefix the password string with
+ <literal>TEXT</literal>. For example if you want to set <literal>mypass</literal> as
+ a password, you should specify <literal>TEXTmypass</literal> in the password field.
+ In the absence of a valid prefix, <productname>Pgpool-II</productname> will considered
+ the string as a plain text password.
+ </para>
<para>
You can also use <xref linkend="PG-ENC"> utility to create the correctly formatted
<literal>AES</literal> encrypted password strings.
<literal>AES</literal> after encrypting (using <literal>aes-256-cbc</literal> algorithm) and
encoding to <literal>base64</literal>.
</para>
+ <para>
+ To specify the unencrypted clear text password, prefix the password string with
+ <literal>TEXT</literal>. For example if you want to set <literal>mypass</literal> as
+ a password, you should specify <literal>TEXTmypass</literal> in the password field.
+ In the absence of a valid prefix, <productname>Pgpool-II</productname> will considered
+ the string as a plain text password.
+ </para>
<para>
You can also use <xref linkend="PG-ENC"> utility to create the correctly formatted
<literal>AES</literal> encrypted password strings.
uint8 stored_key[SCRAM_KEY_LEN];
uint8 server_key[SCRAM_KEY_LEN];
uint8 computed_key[SCRAM_KEY_LEN];
- char *prep_password = NULL;
if (!parse_scram_verifier(verifier, &iterations, &encoded_salt,
stored_key, server_key))
scram_SaltedPassword(password, salt, saltlen, iterations, salted_password);
scram_ServerKey(salted_password, computed_key);
- if (prep_password)
- pfree(prep_password);
-
/*
* Compare the verifier's Server Key with the one computed from the
* user-supplied password.
*/
+ pfree(encoded_salt);
return memcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0;
}
*/
decoded_salt_buf = palloc(pg_b64_dec_len(strlen(salt_str)));
decoded_len = pg_b64_decode(salt_str, strlen(salt_str), decoded_salt_buf);
+ pfree(decoded_salt_buf);
+
if (decoded_len < 0)
goto invalid_verifier;
*salt = pstrdup(salt_str);
char *server_signature_base64;
int siglen;
scram_HMAC_ctx ctx;
+ char *res;
/* calculate ServerSignature */
scram_HMAC_init(&ctx, state->ServerKey, SCRAM_KEY_LEN);
*
*------
*/
- return psprintf("v=%s", server_signature_base64);
+ res = psprintf("v=%s", server_signature_base64);
+ pfree(server_signature_base64);
+ return res;
}
}
ereport(DEBUG1,
(errmsg("SCRAM authentication successful for user:%s", cp->sp->user)));
-
}
else
{
/* md5 authentication? */
else if (authkind == AUTH_REQ_MD5)
{
- char *password;
- PasswordType passwordType;
+ char *password = NULL;
+ PasswordType passwordType = PASSWORD_TYPE_UNKNOWN;
/*
* check if we can use md5 authentication.
errdetail("unable to decrypt password from pool_passwd"),
errhint("verify the valid pool_key exists")));
}
+ else if (frontend->passwordMapping->pgpoolUser.passwordType == PASSWORD_TYPE_TEXT_PREFIXED)
+ {
+ storedPassword = frontend->passwordMapping->pgpoolUser.password + strlen(PASSWORD_TEXT_PREFIX);
+ }
else if (frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_PLAINTEXT)
{
ereport(ERROR,
static int size;
char *pwd = NULL;
int kind;
+ PasswordType passwordType = PASSWORD_TYPE_UNKNOWN;
if (reauth && frontend->frontend_authenticated)
{
/* frontend and backend are both authenticated already */
return 0;
}
-
- /* get the password */
- if (frontend->pwd_size > 0)
+ if (get_auth_password(backend, frontend, reauth, &pwd, &passwordType) == false)
{
- pwd = frontend->password;
- size = frontend->pwd_size;
+ ereport(FATAL,
+ (return_code(2),
+ errmsg("clear text password authentication failed"),
+ errdetail("unable to get the password for user: \"%s\"", frontend->username)));
}
- else if (frontend->passwordMapping)
+
+ if (passwordType == PASSWORD_TYPE_AES)
{
- if (frontend->passwordMapping->pgpoolUser.passwordType == PASSWORD_TYPE_PLAINTEXT)
- {
- pwd = frontend->passwordMapping->pgpoolUser.password;
- size = pwd ? strlen(pwd) : 0;
- }
- else if (frontend->passwordMapping->pgpoolUser.passwordType == PASSWORD_TYPE_AES)
- {
- /*
- * decrypt the stored AES password for comparing it
- */
- pwd = get_decrypted_password(frontend->passwordMapping->pgpoolUser.password);
- if (pwd == NULL)
- ereport(ERROR,
- (errmsg("clear text password authentication failed"),
- errdetail("unable to decrypt password from pool_passwd"),
- errhint("verify the valid pool_key exists")));
- size = strlen(pwd);
- }
+ /*
+ * decrypt the stored AES password for comparing it
+ */
+ pwd = get_decrypted_password(pwd);
+ if (pwd == NULL)
+ ereport(ERROR,
+ (errmsg("clear text password authentication failed"),
+ errdetail("unable to decrypt password from pool_passwd"),
+ errhint("verify the valid pool_key exists")));
+ /* we have converted the password to plain text */
+ passwordType = PASSWORD_TYPE_PLAINTEXT;
}
- if (pwd == NULL)
+
+ if (pwd == NULL || passwordType != PASSWORD_TYPE_PLAINTEXT)
{
/* If we still do not have a password. we can't proceed */
ereport(ERROR,
return 0;
}
+ size = pwd ? strlen(pwd) : 0;
+
/* connection reusing? */
if (reauth)
{
PasswordType storedPasswordType = PASSWORD_TYPE_UNKNOWN;
char *storedPassword = NULL;
- if (!frontend->passwordMapping)
- frontend->passwordMapping = pool_get_user_credentials(frontend->username);
-
- if (!frontend->passwordMapping)
- {
- /* see if we have a password stored in the backend for this */
- if (reauth && backend->pwd_size)
- {
- storedPasswordType = backend->passwordType;
- storedPassword = backend->password;
- }
- else
- {
- ereport(FATAL,
- (return_code(2),
- errmsg("SCRAM authentication failed"),
- errdetail("pool_passwd file does not contain an entry for \"%s\"", frontend->username)));
- }
- }
- else
+ if (get_auth_password(backend, frontend, reauth,&storedPassword, &storedPasswordType) == false)
{
- storedPasswordType = frontend->passwordMapping->pgpoolUser.passwordType;
- storedPassword = frontend->passwordMapping->pgpoolUser.password;
+ ereport(FATAL,
+ (return_code(2),
+ errmsg("SCRAM authentication failed"),
+ errdetail("pool_passwd file does not contain an entry for \"%s\"", frontend->username)));
}
if (storedPasswordType == PASSWORD_TYPE_AES)
do_md5_single_backend(backend, frontend, reauth, protoMajor);
return; /* This will be handled later */
}
- if (!frontend->passwordMapping)
- frontend->passwordMapping = pool_get_user_credentials(frontend->username);
- if (!frontend->passwordMapping)
+ if (get_auth_password(backend, frontend, reauth,&storedPassword, &storedPasswordType) == false)
{
- /* see if we have a password stored in the backend for this */
- if (reauth && backend->pwd_size)
- {
- storedPasswordType = backend->passwordType;
- storedPassword = backend->password;
- }
- else
- {
- ereport(FATAL,
- (return_code(2),
- errmsg("md5 authentication failed"),
- errdetail("pool_passwd file does not contain an entry for \"%s\"", frontend->username)));
- }
- }
- else
- {
- storedPasswordType = frontend->passwordMapping->pgpoolUser.passwordType;
- storedPassword = frontend->passwordMapping->pgpoolUser.password;
+ ereport(FATAL,
+ (return_code(2),
+ errmsg("md5 authentication failed"),
+ errdetail("pool_passwd file does not contain an entry for \"%s\"", frontend->username)));
}
pool_random_salt(salt);
}
else
{
- *password = frontend->passwordMapping->pgpoolUser.password;
- *passwordType = frontend->passwordMapping->pgpoolUser.passwordType;
+ if (frontend->passwordMapping->pgpoolUser.passwordType == PASSWORD_TYPE_TEXT_PREFIXED)
+ {
+ /* convert the TEXT prefixed password to plain text password */
+ *passwordType = PASSWORD_TYPE_PLAINTEXT;
+ *password = frontend->passwordMapping->pgpoolUser.password + strlen(PASSWORD_TEXT_PREFIX);
+ }
+ else
+ {
+ *password = frontend->passwordMapping->pgpoolUser.password;
+ *passwordType = frontend->passwordMapping->pgpoolUser.passwordType;
+ }
return true;
}
return false;
case AUTH_REQ_OK:
/* Save the auth info in backend */
backend->auth_kind = AUTH_REQ_SASL;
+ if (sasl_state)
+ pg_fe_scram_free(sasl_state);
return true;
break;
case AUTH_REQ_SASL:
str, gai_strerror(ret));
if (gai_result)
freeaddrinfo_all(hints.ai_family, gai_result);
+ pfree(str);
return NULL;
}
line_num, HbaFileName)));
*err_msg = psprintf("specifying both host name and CIDR mask is invalid: \"%s\"",
token->string);
+ pfree(str);
return NULL;
}
line_num, HbaFileName)));
*err_msg = psprintf("invalid CIDR mask in address \"%s\"",
token->string);
+ pfree(str);
return NULL;
}
pfree(str);
ClientAuthentication(POOL_CONNECTION * frontend)
{
POOL_STATUS status = POOL_END;
+ MemoryContext oldContext;
PG_TRY();
{
/*
* Get the password for the user if it is stored in the pool_password
* file
+ * authentication process is called in the temporary memory
+ * context, but password mappings has to live till the life time
+ * of frontend connection, so call the pool_get_user_credentials in
+ * ProcessLoopContext memory context
*/
+ oldContext = MemoryContextSwitchTo(ProcessLoopContext);
frontend->passwordMapping = pool_get_user_credentials(frontend->username);
+ MemoryContextSwitchTo(oldContext);
+
switch (frontend->pool_hba->auth_method)
{
case uaImplicitReject:
* We're merely helping out the less clueful good guys.
*/
char hostinfo[NI_MAXHOST];
- char *errmessage;
- int messagelen;
getnameinfo_all(&frontend->raddr.addr, frontend->raddr.salen,
hostinfo, sizeof(hostinfo),
NULL, 0,
NI_NUMERICHOST);
- messagelen = sizeof(hostinfo) +
- strlen(frontend->username) + strlen(frontend->database) + 80;
- errmessage = (char *) palloc(messagelen + 1);
#ifdef USE_SSL
- snprintf(errmessage, messagelen + 7, /* +7 is for "SSL off" */
- "no pool_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
- hostinfo, frontend->username, frontend->database,
- frontend->ssl ? "SSL on" : "SSL off");
+ ereport(FATAL,
+ (return_code(2),
+ errmsg("client authentication failed"),
+ errdetail("no pool_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
+ hostinfo, frontend->username, frontend->database,
+ frontend->ssl ? "SSL on" : "SSL off"),
+ errhint("see pgpool log for details")));
#else
- snprintf(errmessage, messagelen,
- "no pool_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
- hostinfo, frontend->username, frontend->database);
-#endif
ereport(FATAL,
(return_code(2),
errmsg("client authentication failed"),
- errdetail("%s", errmessage),
+ errdetail("no pool_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
+ hostinfo, frontend->username, frontend->database),
errhint("see pgpool log for details")));
+#endif
break;
}
errdetail("pool_passwd file does not contain an entry for \"%s\"", frontend->username)));
if (frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_PLAINTEXT &&
frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_MD5 &&
+ frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_TEXT_PREFIXED &&
frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_AES)
ereport(FATAL,
(return_code(2),
errmsg("SCRAM authentication failed"),
errdetail("pool_passwd file does not contain an entry for \"%s\"", frontend->username)));
if (frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_PLAINTEXT &&
+ frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_TEXT_PREFIXED &&
frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_SCRAM_SHA_256 &&
frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_AES)
ereport(FATAL,
}
}
- if (passwordType != PASSWORD_TYPE_PLAINTEXT)
+ if (passwordType == PASSWORD_TYPE_TEXT_PREFIXED)
+ {
+ /* convert the TEXT prefixed password to plain text password */
+ passwordType = PASSWORD_TYPE_PLAINTEXT;
+ if (password)
+ password = (char*)(password + strlen(PASSWORD_TEXT_PREFIX));
+ }
+
+ if (password && strlen(password) && passwordType != PASSWORD_TYPE_PLAINTEXT)
{
ereport(WARNING,
(errmsg("could not get the password for user:%s", username),
return PASSWORD_TYPE_AES;
if (strncmp(shadow_pass, PASSWORD_SCRAM_PREFIX, strlen(PASSWORD_SCRAM_PREFIX)) == 0)
return PASSWORD_TYPE_SCRAM_SHA_256;
+ if (strncmp(shadow_pass, PASSWORD_TEXT_PREFIX, strlen(PASSWORD_TEXT_PREFIX)) == 0)
+ return PASSWORD_TYPE_TEXT_PREFIXED;
return PASSWORD_TYPE_PLAINTEXT;
}
if (!S_ISREG(stat_buf.st_mode))
{
ereport(WARNING,
- (errmsg("pool key file \"%s\" is not a text file\n", key_file_path)));
+ (errmsg("pool key file \"%s\" is not a plain file\n", key_file_path)));
return NULL;
}
/* If password file is insecure, alert the user. */
if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
{
- ereport(WARNING,
- (errmsg("pool key file \"%s\" is not a text file\n", key_file_path)));
-
ereport(WARNING,
(errmsg("pool key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n",
key_file_path)));
PASSWORD_TYPE_PLAINTEXT,
PASSWORD_TYPE_MD5,
PASSWORD_TYPE_AES,
- PASSWORD_TYPE_SCRAM_SHA_256
+ PASSWORD_TYPE_SCRAM_SHA_256,
+ PASSWORD_TYPE_TEXT_PREFIXED
} PasswordType;
typedef struct UserPassword
int i,
freed = 0;
StartupPacket *topmem_sp = NULL;
+ MemoryContext oldContext;
+ MemoryContext frontend_auth_cxt;
/*
* Save startup packet info
{
if (!freed)
{
- MemoryContext oldContext = MemoryContextSwitchTo(TopMemoryContext);
+ oldContext = MemoryContextSwitchTo(TopMemoryContext);
topmem_sp = StartupPacketCopy(sp);
MemoryContextSwitchTo(oldContext);
}
/* Reuse existing connection to backend */
+ frontend_auth_cxt = AllocSetContextCreate(CurrentMemoryContext,
+ "frontend_auth",
+ ALLOCSET_DEFAULT_SIZES);
+ oldContext = MemoryContextSwitchTo(frontend_auth_cxt);
pool_do_reauth(frontend, backend);
+ MemoryContextSwitchTo(oldContext);
+ MemoryContextDelete(frontend_auth_cxt);
+
if (MAJOR(backend) == 3)
{
char command_buf[1024];
PG_TRY();
{
+ MemoryContext frontend_auth_cxt;
MemoryContext oldContext = MemoryContextSwitchTo(TopMemoryContext);
topmem_sp = StartupPacketCopy(sp);
/*
* do authentication stuff
*/
+ frontend_auth_cxt = AllocSetContextCreate(CurrentMemoryContext,
+ "frontend_auth",
+ ALLOCSET_DEFAULT_SIZES);
+ oldContext = MemoryContextSwitchTo(frontend_auth_cxt);
+
pool_do_auth(frontend, backend);
+
+ MemoryContextSwitchTo(oldContext);
+ MemoryContextDelete(frontend_auth_cxt);
+
}
PG_CATCH();
{
* do client authentication. Note that ClientAuthentication does not
* return if frontend was rejected; it simply terminates this process.
*/
+ MemoryContext frontend_auth_cxt = AllocSetContextCreate(CurrentMemoryContext,
+ "frontend_auth",
+ ALLOCSET_DEFAULT_SIZES);
+ MemoryContext oldContext = MemoryContextSwitchTo(frontend_auth_cxt);
ClientAuthentication(frontend);
+
+ MemoryContextSwitchTo(oldContext);
+ MemoryContextDelete(frontend_auth_cxt);
}
/*