diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/user.c | 34 | ||||
-rw-r--r-- | src/backend/libpq/auth-scram.c | 20 | ||||
-rw-r--r-- | src/backend/libpq/auth.c | 26 | ||||
-rw-r--r-- | src/backend/libpq/crypt.c | 126 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 14 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 10 |
6 files changed, 68 insertions, 162 deletions
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index c719682274d..36d5f40f062 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -80,7 +80,6 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) ListCell *item; ListCell *option; char *password = NULL; /* user password */ - int password_type = Password_encryption; bool issuper = false; /* Make the user a superuser? */ bool inherit = true; /* Auto inherit privileges? */ bool createrole = false; /* Can this user create roles? */ @@ -128,9 +127,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) { DefElem *defel = (DefElem *) lfirst(option); - if (strcmp(defel->defname, "password") == 0 || - strcmp(defel->defname, "encryptedPassword") == 0 || - strcmp(defel->defname, "unencryptedPassword") == 0) + if (strcmp(defel->defname, "password") == 0) { if (dpassword) ereport(ERROR, @@ -138,15 +135,6 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) errmsg("conflicting or redundant options"), parser_errposition(pstate, defel->location))); dpassword = defel; - if (strcmp(defel->defname, "encryptedPassword") == 0) - { - if (Password_encryption == PASSWORD_TYPE_SCRAM_SHA_256) - password_type = PASSWORD_TYPE_SCRAM_SHA_256; - else - password_type = PASSWORD_TYPE_MD5; - } - else if (strcmp(defel->defname, "unencryptedPassword") == 0) - password_type = PASSWORD_TYPE_PLAINTEXT; } else if (strcmp(defel->defname, "sysid") == 0) { @@ -400,7 +388,8 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) /* Encrypt the password to the requested format. */ char *shadow_pass; - shadow_pass = encrypt_password(password_type, stmt->role, password); + shadow_pass = encrypt_password(Password_encryption, stmt->role, + password); new_record[Anum_pg_authid_rolpassword - 1] = CStringGetTextDatum(shadow_pass); } @@ -503,7 +492,6 @@ AlterRole(AlterRoleStmt *stmt) ListCell *option; char *rolename = NULL; char *password = NULL; /* user password */ - int password_type = Password_encryption; int issuper = -1; /* Make the user a superuser? */ int inherit = -1; /* Auto inherit privileges? */ int createrole = -1; /* Can this user create roles? */ @@ -537,24 +525,13 @@ AlterRole(AlterRoleStmt *stmt) { DefElem *defel = (DefElem *) lfirst(option); - if (strcmp(defel->defname, "password") == 0 || - strcmp(defel->defname, "encryptedPassword") == 0 || - strcmp(defel->defname, "unencryptedPassword") == 0) + if (strcmp(defel->defname, "password") == 0) { if (dpassword) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); dpassword = defel; - if (strcmp(defel->defname, "encryptedPassword") == 0) - { - if (Password_encryption == PASSWORD_TYPE_SCRAM_SHA_256) - password_type = PASSWORD_TYPE_SCRAM_SHA_256; - else - password_type = PASSWORD_TYPE_MD5; - } - else if (strcmp(defel->defname, "unencryptedPassword") == 0) - password_type = PASSWORD_TYPE_PLAINTEXT; } else if (strcmp(defel->defname, "superuser") == 0) { @@ -809,7 +786,8 @@ AlterRole(AlterRoleStmt *stmt) /* Encrypt the password to the requested format. */ char *shadow_pass; - shadow_pass = encrypt_password(password_type, rolename, password); + shadow_pass = encrypt_password(Password_encryption, rolename, + password); new_record[Anum_pg_authid_rolpassword - 1] = CStringGetTextDatum(shadow_pass); new_record_repl[Anum_pg_authid_rolpassword - 1] = true; diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c index 3acc2acfe41..99feb0ce947 100644 --- a/src/backend/libpq/auth-scram.c +++ b/src/backend/libpq/auth-scram.c @@ -199,27 +199,11 @@ pg_be_scram_init(const char *username, const char *shadow_pass) got_verifier = false; } } - else if (password_type == PASSWORD_TYPE_PLAINTEXT) - { - /* - * The stored password is in plain format. Generate a fresh SCRAM - * verifier from it, and proceed with that. - */ - char *verifier; - - verifier = pg_be_scram_build_verifier(shadow_pass); - - (void) parse_scram_verifier(verifier, &state->iterations, &state->salt, - state->StoredKey, state->ServerKey); - pfree(verifier); - - got_verifier = true; - } else { /* - * The user doesn't have SCRAM verifier, nor could we generate - * one. (You cannot do SCRAM authentication with an MD5 hash.) + * The user doesn't have SCRAM verifier. (You cannot do SCRAM + * authentication with an MD5 hash.) */ state->logdetail = psprintf(_("User \"%s\" does not have a valid SCRAM verifier."), state->username); diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index ab4be219431..6d3ff68607d 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -754,17 +754,13 @@ CheckPWChallengeAuth(Port *port, char **logdetail) shadow_pass = get_role_password(port->user_name, logdetail); /* - * If the user does not exist, or has no password, we still go through the - * motions of authentication, to avoid revealing to the client that the - * user didn't exist. If 'md5' is allowed, we choose whether to use 'md5' - * or 'scram-sha-256' authentication based on current password_encryption - * setting. The idea is that most genuine users probably have a password - * of that type, if we pretend that this user had a password of that type, - * too, it "blends in" best. - * - * If the user had a password, but it was expired, we'll use the details - * of the expired password for the authentication, but report it as - * failure to the client even if correct password was given. + * If the user does not exist, or has no password or it's expired, we + * still go through the motions of authentication, to avoid revealing to + * the client that the user didn't exist. If 'md5' is allowed, we choose + * whether to use 'md5' or 'scram-sha-256' authentication based on + * current password_encryption setting. The idea is that most genuine + * users probably have a password of that type, and if we pretend that + * this user had a password of that type, too, it "blends in" best. */ if (!shadow_pass) pwtype = Password_encryption; @@ -775,21 +771,15 @@ CheckPWChallengeAuth(Port *port, char **logdetail) * If 'md5' authentication is allowed, decide whether to perform 'md5' or * 'scram-sha-256' authentication based on the type of password the user * has. If it's an MD5 hash, we must do MD5 authentication, and if it's - * a SCRAM verifier, we must do SCRAM authentication. If it's stored in - * plaintext, we could do either one, so we opt for the more secure - * mechanism, SCRAM. + * a SCRAM verifier, we must do SCRAM authentication. * * If MD5 authentication is not allowed, always use SCRAM. If the user * had an MD5 password, CheckSCRAMAuth() will fail. */ if (port->hba->auth_method == uaMD5 && pwtype == PASSWORD_TYPE_MD5) - { auth_result = CheckMD5Auth(port, shadow_pass, logdetail); - } else - { auth_result = CheckSCRAMAuth(port, shadow_pass, logdetail); - } if (shadow_pass) pfree(shadow_pass); diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index 9fe79b48946..e7a6b04fb5a 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -109,9 +109,8 @@ get_password_type(const char *shadow_pass) * Given a user-supplied password, convert it into a verifier of * 'target_type' kind. * - * If the password looks like a valid MD5 hash, it is stored as it is. - * We cannot reverse the hash, so even if the caller requested a plaintext - * plaintext password, the MD5 hash is returned. + * If the password is already in encrypted form, we cannot reverse the + * hash, so it is stored as it is regardless of the requested type. */ char * encrypt_password(PasswordType target_type, const char *role, @@ -120,54 +119,30 @@ encrypt_password(PasswordType target_type, const char *role, PasswordType guessed_type = get_password_type(password); char *encrypted_password; - switch (target_type) + if (guessed_type != PASSWORD_TYPE_PLAINTEXT) { - case PASSWORD_TYPE_PLAINTEXT: - - /* - * We cannot convert a hashed password back to plaintext, so just - * store the password as it was, whether it was hashed or not. - */ - return pstrdup(password); + /* + * Cannot convert an already-encrypted password from one + * format to another, so return it as it is. + */ + return pstrdup(password); + } + switch (target_type) + { case PASSWORD_TYPE_MD5: - switch (guessed_type) - { - case PASSWORD_TYPE_PLAINTEXT: - encrypted_password = palloc(MD5_PASSWD_LEN + 1); - - if (!pg_md5_encrypt(password, role, strlen(role), - encrypted_password)) - elog(ERROR, "password encryption failed"); - return encrypted_password; + encrypted_password = palloc(MD5_PASSWD_LEN + 1); - case PASSWORD_TYPE_SCRAM_SHA_256: - - /* - * cannot convert a SCRAM verifier to an MD5 hash, so fall - * through to save the SCRAM verifier instead. - */ - case PASSWORD_TYPE_MD5: - return pstrdup(password); - } - break; + if (!pg_md5_encrypt(password, role, strlen(role), + encrypted_password)) + elog(ERROR, "password encryption failed"); + return encrypted_password; case PASSWORD_TYPE_SCRAM_SHA_256: - switch (guessed_type) - { - case PASSWORD_TYPE_PLAINTEXT: - return pg_be_scram_build_verifier(password); - - case PASSWORD_TYPE_MD5: + return pg_be_scram_build_verifier(password); - /* - * cannot convert an MD5 hash to a SCRAM verifier, so fall - * through to save the MD5 hash instead. - */ - case PASSWORD_TYPE_SCRAM_SHA_256: - return pstrdup(password); - } - break; + case PASSWORD_TYPE_PLAINTEXT: + elog(ERROR, "cannot encrypt password with 'plaintext'"); } /* @@ -197,10 +172,17 @@ md5_crypt_verify(const char *role, const char *shadow_pass, { int retval; char crypt_pwd[MD5_PASSWD_LEN + 1]; - char crypt_pwd2[MD5_PASSWD_LEN + 1]; Assert(md5_salt_len > 0); + if (get_password_type(shadow_pass) != PASSWORD_TYPE_MD5) + { + /* incompatible password hash format. */ + *logdetail = psprintf(_("User \"%s\" has a password that cannot be used with MD5 authentication."), + role); + return STATUS_ERROR; + } + /* * Compute the correct answer for the MD5 challenge. * @@ -208,40 +190,12 @@ md5_crypt_verify(const char *role, const char *shadow_pass, * below: the only possible error is out-of-memory, which is unlikely, and * if it did happen adding a psprintf call would only make things worse. */ - switch (get_password_type(shadow_pass)) + /* stored password already encrypted, only do salt */ + if (!pg_md5_encrypt(shadow_pass + strlen("md5"), + md5_salt, md5_salt_len, + crypt_pwd)) { - case PASSWORD_TYPE_MD5: - /* stored password already encrypted, only do salt */ - if (!pg_md5_encrypt(shadow_pass + strlen("md5"), - md5_salt, md5_salt_len, - crypt_pwd)) - { - return STATUS_ERROR; - } - break; - - case PASSWORD_TYPE_PLAINTEXT: - /* stored password is plain, double-encrypt */ - if (!pg_md5_encrypt(shadow_pass, - role, - strlen(role), - crypt_pwd2)) - { - return STATUS_ERROR; - } - if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), - md5_salt, md5_salt_len, - crypt_pwd)) - { - return STATUS_ERROR; - } - break; - - default: - /* unknown password hash format. */ - *logdetail = psprintf(_("User \"%s\" has a password that cannot be used with MD5 authentication."), - role); - return STATUS_ERROR; + return STATUS_ERROR; } if (strcmp(client_pass, crypt_pwd) == 0) @@ -259,8 +213,8 @@ md5_crypt_verify(const char *role, const char *shadow_pass, /* * Check given password for given user, and return STATUS_OK or STATUS_ERROR. * - * 'shadow_pass' is the user's correct password or password hash, as stored - * in pg_authid.rolpassword. + * 'shadow_pass' is the user's correct password hash, as stored in + * pg_authid.rolpassword. * 'client_pass' is the password given by the remote user. * * In the error case, optionally store a palloc'd string at *logdetail @@ -320,14 +274,10 @@ plain_crypt_verify(const char *role, const char *shadow_pass, break; case PASSWORD_TYPE_PLAINTEXT: - if (strcmp(client_pass, shadow_pass) == 0) - return STATUS_OK; - else - { - *logdetail = psprintf(_("Password does not match for user \"%s\"."), - role); - return STATUS_ERROR; - } + /* + * We never store passwords in plaintext, so this shouldn't + * happen. + */ break; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 818d2c29d49..2cad8b25b8a 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -994,13 +994,21 @@ AlterOptRoleElem: } | ENCRYPTED PASSWORD Sconst { - $$ = makeDefElem("encryptedPassword", + /* + * These days, passwords are always stored in encrypted + * form, so there is no difference between PASSWORD and + * ENCRYPTED PASSWORD. + */ + $$ = makeDefElem("password", (Node *)makeString($3), @1); } | UNENCRYPTED PASSWORD Sconst { - $$ = makeDefElem("unencryptedPassword", - (Node *)makeString($3), @1); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("UNENCRYPTED PASSWORD is no longer supported"), + errhint("Remove UNENCRYPTED to store the password in encrypted form instead."), + parser_errposition(@1))); } | INHERIT { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 587fbce147f..cb4e621c848 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -405,20 +405,16 @@ static const struct config_enum_entry force_parallel_mode_options[] = { /* * password_encryption used to be a boolean, so accept all the likely - * variants of "on" and "off", too. + * variants of "on", too. "off" used to store passwords in plaintext, + * but we don't support that anymore. */ static const struct config_enum_entry password_encryption_options[] = { - {"plain", PASSWORD_TYPE_PLAINTEXT, false}, {"md5", PASSWORD_TYPE_MD5, false}, {"scram-sha-256", PASSWORD_TYPE_SCRAM_SHA_256, false}, - {"off", PASSWORD_TYPE_PLAINTEXT, false}, - {"on", PASSWORD_TYPE_MD5, false}, + {"on", PASSWORD_TYPE_MD5, true}, {"true", PASSWORD_TYPE_MD5, true}, - {"false", PASSWORD_TYPE_PLAINTEXT, true}, {"yes", PASSWORD_TYPE_MD5, true}, - {"no", PASSWORD_TYPE_PLAINTEXT, true}, {"1", PASSWORD_TYPE_MD5, true}, - {"0", PASSWORD_TYPE_PLAINTEXT, true}, {NULL, 0, false} }; |