aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/libpq/auth.c36
-rw-r--r--src/backend/libpq/crypt.c35
2 files changed, 48 insertions, 23 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index fbcc596f15b..bf94e941e42 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -676,6 +676,20 @@ recv_password_packet(Port *port)
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid password packet size")));
+ /*
+ * Don't allow an empty password. Libpq treats an empty password the same
+ * as no password at all, and won't even try to authenticate. But other
+ * clients might, so allowing it would be confusing.
+ *
+ * Note that this only catches an empty password sent by the client in
+ * plaintext. There's another check in md5_crypt_verify to prevent an
+ * empty password from being used with MD5 authentication.
+ */
+ if (buf.data[0] == '\0')
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PASSWORD),
+ errmsg("empty password returned by client")));
+
/* Do not echo password to logs, for security. */
ereport(DEBUG5,
(errmsg("received password packet")));
@@ -1683,12 +1697,6 @@ pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg,
*/
goto fail;
}
- if (strlen(passwd) == 0)
- {
- ereport(LOG,
- (errmsg("empty password returned by client")));
- goto fail;
- }
}
if ((reply[i].resp = strdup(passwd)) == NULL)
goto fail;
@@ -1954,16 +1962,11 @@ CheckLDAPAuth(Port *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 (InitializeLDAPConnection(port, &ldap) == STATUS_ERROR)
+ {
/* Error message already sent */
return STATUS_ERROR;
+ }
if (port->hba->ldapbasedn)
{
@@ -2314,13 +2317,6 @@ CheckRADIUSAuth(Port *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,
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
index 5451db6d974..3d587b12dac 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -77,15 +77,44 @@ md5_crypt_verify(const Port *port, const char *role, char *client_pass,
ReleaseSysCache(roleTup);
- if (*shadow_pass == '\0')
- return STATUS_ERROR; /* empty password */
-
/* Re-enable immediate response to SIGTERM/SIGINT/timeout interrupts */
ImmediateInterruptOK = true;
/* And don't forget to detect one that already arrived */
CHECK_FOR_INTERRUPTS();
/*
+ * Don't allow an empty password. Libpq treats an empty password the same
+ * as no password at all, and won't even try to authenticate. But other
+ * clients might, so allowing it would be confusing.
+ *
+ * For a plaintext password, we can simply check that it's not an empty
+ * string. For an encrypted password, check that it does not match the MD5
+ * hash of an empty string.
+ */
+ if (*shadow_pass == '\0')
+ {
+ *logdetail = psprintf(_("User \"%s\" has an empty password."),
+ role);
+ return STATUS_ERROR; /* empty password */
+ }
+ if (isMD5(shadow_pass))
+ {
+ char crypt_empty[MD5_PASSWD_LEN + 1];
+
+ if (!pg_md5_encrypt("",
+ port->user_name,
+ strlen(port->user_name),
+ crypt_empty))
+ return STATUS_ERROR;
+ if (strcmp(shadow_pass, crypt_empty) == 0)
+ {
+ *logdetail = psprintf(_("User \"%s\" has an empty password."),
+ role);
+ return STATUS_ERROR; /* empty password */
+ }
+ }
+
+ /*
* Compare with the encrypted or plain password depending on the
* authentication method being used for this connection.
*/