Re: crypt auth - Mailing list pgsql-hackers
From | Magnus Hagander |
---|---|
Subject | Re: crypt auth |
Date | |
Msg-id | 4905A1DE.5030102@hagander.net Whole thread Raw |
In response to | crypt auth (Magnus Hagander <magnus@hagander.net>) |
List | pgsql-hackers |
Magnus Hagander wrote: > I notice our docs have: > > If you are at all concerned about password > <quote>sniffing</> attacks then <literal>md5</> is preferred, with > <literal>crypt</> to be used only if you must support pre-7.2 > clients. Plain <literal>password</> should be avoided especially for > > > At what point do we just remove the support and say that people need to > upgrade their clients? Sure, it's up to ppl not to configure it that > way, but security-wise it's a foot-gun that I think is completely > unnecessary. Here's a patch that does this. Will apply unless there are objections. //Magnus *** a/doc/src/sgml/client-auth.sgml --- b/doc/src/sgml/client-auth.sgml *************** *** 316,339 **** hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable> </varlistentry> <varlistentry> - <term><literal>crypt</></term> - <listitem> - <note> - <para> - This option is recommended only for communicating with pre-7.2 - clients. - </para> - </note> - <para> - Require the client to supply a <function>crypt()</>-encrypted - password for authentication. - <literal>md5</literal> is now recommended over <literal>crypt</>. - See <xref linkend="auth-password"> for details. - </para> - </listitem> - </varlistentry> - - <varlistentry> <term><literal>password</></term> <listitem> <para> --- 316,321 ---- *************** *** 705,734 **** omicron bryanh guest1 <primary>MD5</> </indexterm> <indexterm> - <primary>crypt</> - </indexterm> - <indexterm> <primary>password</primary> <secondary>authentication</secondary> </indexterm> <para> The password-based authentication methods are <literal>md5</>, ! <literal>crypt</>, and <literal>password</>. These methods operate similarly except for the way that the password is sent across the ! connection: respectively, MD5-hashed, crypt-encrypted, and clear-text. ! A limitation is that the <literal>crypt</> method does not work with ! passwords that have been encrypted in <structname>pg_authid</structname>. </para> <para> If you are at all concerned about password ! <quote>sniffing</> attacks then <literal>md5</> is preferred, with ! <literal>crypt</> to be used only if you must support pre-7.2 ! clients. Plain <literal>password</> should be avoided especially for ! connections over the open Internet (unless you use <acronym>SSL</acronym>, ! <acronym>SSH</>, or another ! communications security wrapper around the connection). </para> <para> --- 687,707 ---- <primary>MD5</> </indexterm> <indexterm> <primary>password</primary> <secondary>authentication</secondary> </indexterm> <para> The password-based authentication methods are <literal>md5</>, ! and <literal>password</>. These methods operate similarly except for the way that the password is sent across the ! connection: respectively, MD5-hashed and clear-text. </para> <para> If you are at all concerned about password ! <quote>sniffing</> attacks then <literal>md5</> is preferred. ! Plain <literal>password</> should always be avoided if possible. </para> <para> *** a/doc/src/sgml/protocol.sgml --- b/doc/src/sgml/protocol.sgml *************** *** 296,314 **** </varlistentry> <varlistentry> - <term>AuthenticationCryptPassword</term> - <listitem> - <para> - The frontend must now send a PasswordMessage containing the - password encrypted via crypt(3), using the 2-character salt - specified in the AuthenticationCryptPassword message. If - this is the correct password, the server responds with an - AuthenticationOk, otherwise it responds with an ErrorResponse. - </para> - </listitem> - </varlistentry> - - <varlistentry> <term>AuthenticationMD5Password</term> <listitem> <para> --- 296,301 ---- *************** *** 1533,1593 **** AuthenticationCleartextPassword (B) <varlistentry> <term> - AuthenticationCryptPassword (B) - </term> - <listitem> - <para> - - <variablelist> - <varlistentry> - <term> - Byte1('R') - </term> - <listitem> - <para> - Identifies the message as an authentication request. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - Int32(10) - </term> - <listitem> - <para> - Length of message contents in bytes, including self. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - Int32(4) - </term> - <listitem> - <para> - Specifies that a crypt()-encrypted password is required. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - Byte2 - </term> - <listitem> - <para> - The salt to use when encrypting the password. - </para> - </listitem> - </varlistentry> - </variablelist> - - </para> - </listitem> - </varlistentry> - - - <varlistentry> - <term> AuthenticationMD5Password (B) </term> <listitem> --- 1520,1525 ---- *** a/doc/src/sgml/user-manag.sgml --- b/doc/src/sgml/user-manag.sgml *************** *** 215,222 **** CREATE USER <replaceable>name</replaceable>; <para> A password is only significant if the client authentication method requires the user to supply a password when connecting ! to the database. The <option>password</>, ! <option>md5</>, and <option>crypt</> authentication methods make use of passwords. Database passwords are separate from operating system passwords. Specify a password upon role creation with <literal>CREATE ROLE --- 215,222 ---- <para> A password is only significant if the client authentication method requires the user to supply a password when connecting ! to the database. The <option>password</> and ! <option>md5</> authentication methods make use of passwords. Database passwords are separate from operating system passwords. Specify a password upon role creation with <literal>CREATE ROLE *** a/src/backend/libpq/auth.c --- b/src/backend/libpq/auth.c *************** *** 230,236 **** auth_failed(Port *port, int status) errstr = gettext_noop("Ident authentication failed for user \"%s\""); break; case uaMD5: - case uaCrypt: case uaPassword: errstr = gettext_noop("password authentication failed for user \"%s\""); break; --- 230,235 ---- *************** *** 373,383 **** ClientAuthentication(Port *port) status = recv_and_check_password_packet(port); break; - case uaCrypt: - sendAuthRequest(port, AUTH_REQ_CRYPT); - status = recv_and_check_password_packet(port); - break; - case uaPassword: sendAuthRequest(port, AUTH_REQ_PASSWORD); status = recv_and_check_password_packet(port); --- 372,377 ---- *************** *** 426,433 **** sendAuthRequest(Port *port, AuthRequest areq) /* Add the salt for encrypted passwords. */ if (areq == AUTH_REQ_MD5) pq_sendbytes(&buf, port->md5Salt, 4); - else if (areq == AUTH_REQ_CRYPT) - pq_sendbytes(&buf, port->cryptSalt, 2); #if defined(ENABLE_GSS) || defined(ENABLE_SSPI) --- 420,425 ---- *** a/src/backend/libpq/crypt.c --- b/src/backend/libpq/crypt.c *************** *** 53,66 **** md5_crypt_verify(const Port *port, const char *role, char *client_pass) if (shadow_pass == NULL || *shadow_pass == '\0') return STATUS_ERROR; - /* We can't do crypt with MD5 passwords */ - if (isMD5(shadow_pass) && port->hba->auth_method == uaCrypt) - { - ereport(LOG, - (errmsg("cannot use authentication method \"crypt\" because password is MD5-encrypted"))); - return STATUS_ERROR; - } - /* * Compare with the encrypted or plain password depending on the * authentication method being used for this connection. --- 53,58 ---- *************** *** 106,119 **** md5_crypt_verify(const Port *port, const char *role, char *client_pass) pfree(crypt_pwd2); } break; - case uaCrypt: - { - char salt[3]; - - strlcpy(salt, port->cryptSalt, sizeof(salt)); - crypt_pwd = crypt(shadow_pass, salt); - break; - } default: if (isMD5(shadow_pass)) { --- 98,103 ---- *** a/src/backend/libpq/hba.c --- b/src/backend/libpq/hba.c *************** *** 791,798 **** parse_hba_line(List *line, int line_num, HbaLine *parsedline) parsedline->auth_method = uaReject; else if (strcmp(token, "md5") == 0) parsedline->auth_method = uaMD5; - else if (strcmp(token, "crypt") == 0) - parsedline->auth_method = uaCrypt; else if (strcmp(token, "pam") == 0) #ifdef USE_PAM parsedline->auth_method = uaPAM; --- 791,796 ---- *** a/src/backend/postmaster/postmaster.c --- b/src/backend/postmaster/postmaster.c *************** *** 323,329 **** static int initMasks(fd_set *rmask); static void report_fork_failure_to_client(Port *port, int errnum); static enum CAC_state canAcceptConnections(void); static long PostmasterRandom(void); ! static void RandomSalt(char *cryptSalt, char *md5Salt); static void signal_child(pid_t pid, int signal); static void SignalSomeChildren(int signal, bool only_autovac); --- 323,329 ---- static void report_fork_failure_to_client(Port *port, int errnum); static enum CAC_state canAcceptConnections(void); static long PostmasterRandom(void); ! static void RandomSalt(char *md5Salt); static void signal_child(pid_t pid, int signal); static void SignalSomeChildren(int signal, bool only_autovac); *************** *** 1808,1814 **** ConnCreate(int serverFd) * fork, not after. Else the postmaster's random sequence won't get * advanced, and all backends would end up using the same salt... */ ! RandomSalt(port->cryptSalt, port->md5Salt); } /* --- 1808,1814 ---- * fork, not after. Else the postmaster's random sequence won't get * advanced, and all backends would end up using the same salt... */ ! RandomSalt(port->md5Salt); } /* *************** *** 3910,3958 **** dummy_handler(SIGNAL_ARGS) { } - - /* - * CharRemap: given an int in range 0..61, produce textual encoding of it - * per crypt(3) conventions. - */ - static char - CharRemap(long ch) - { - if (ch < 0) - ch = -ch; - ch = ch % 62; - - if (ch < 26) - return 'A' + ch; - - ch -= 26; - if (ch < 26) - return 'a' + ch; - - ch -= 26; - return '0' + ch; - } - /* * RandomSalt */ static void ! RandomSalt(char *cryptSalt, char *md5Salt) { ! long rand = PostmasterRandom(); ! ! cryptSalt[0] = CharRemap(rand % 62); ! cryptSalt[1] = CharRemap(rand / 62); /* - * It's okay to reuse the first random value for one of the MD5 salt - * bytes, since only one of the two salts will be sent to the client. - * After that we need to compute more random bits. - * * We use % 255, sacrificing one possible byte value, so as to ensure that * all bits of the random() value participate in the result. While at it, * add one to avoid generating any null bytes. */ md5Salt[0] = (rand % 255) + 1; rand = PostmasterRandom(); md5Salt[1] = (rand % 255) + 1; --- 3910,3929 ---- { } /* * RandomSalt */ static void ! RandomSalt(char *md5Salt) { ! long rand; /* * We use % 255, sacrificing one possible byte value, so as to ensure that * all bits of the random() value participate in the result. While at it, * add one to avoid generating any null bytes. */ + rand = PostmasterRandom(); md5Salt[0] = (rand % 255) + 1; rand = PostmasterRandom(); md5Salt[1] = (rand % 255) + 1; *** a/src/include/libpq/hba.h --- b/src/include/libpq/hba.h *************** *** 22,28 **** typedef enum UserAuth uaTrust, uaIdent, uaPassword, - uaCrypt, uaMD5, uaGSS, uaSSPI, --- 22,27 ---- *** a/src/include/libpq/libpq-be.h --- b/src/include/libpq/libpq-be.h *************** *** 123,129 **** typedef struct Port */ HbaLine *hba; char md5Salt[4]; /* Password salt */ - char cryptSalt[2]; /* Password salt */ /* * Information that really has no business at all being in struct Port, --- 123,128 ---- *** a/src/include/libpq/pqcomm.h --- b/src/include/libpq/pqcomm.h *************** *** 153,159 **** extern bool Db_user_namespace; #define AUTH_REQ_KRB4 1 /* Kerberos V4. Not supported any more. */ #define AUTH_REQ_KRB5 2 /* Kerberos V5 */ #define AUTH_REQ_PASSWORD 3 /* Password */ ! #define AUTH_REQ_CRYPT 4 /* crypt password */ #define AUTH_REQ_MD5 5 /* md5 password */ #define AUTH_REQ_SCM_CREDS 6 /* transfer SCM credentials */ #define AUTH_REQ_GSS 7 /* GSSAPI without wrap() */ --- 153,159 ---- #define AUTH_REQ_KRB4 1 /* Kerberos V4. Not supported any more. */ #define AUTH_REQ_KRB5 2 /* Kerberos V5 */ #define AUTH_REQ_PASSWORD 3 /* Password */ ! #define AUTH_REQ_CRYPT 4 /* crypt password. Not supported any more. */ #define AUTH_REQ_MD5 5 /* md5 password */ #define AUTH_REQ_SCM_CREDS 6 /* transfer SCM credentials */ #define AUTH_REQ_GSS 7 /* GSSAPI without wrap() */ *** a/src/interfaces/libpq/fe-auth.c --- b/src/interfaces/libpq/fe-auth.c *************** *** 40,49 **** #include <pwd.h> #endif - #ifdef HAVE_CRYPT_H - #include <crypt.h> - #endif - #include "libpq-fe.h" #include "fe-auth.h" #include "libpq/md5.h" --- 40,45 ---- *************** *** 787,800 **** pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) } break; } - case AUTH_REQ_CRYPT: - { - char salt[3]; - - strlcpy(salt, conn->cryptSalt, sizeof(salt)); - crypt_pwd = crypt(password, salt); - break; - } case AUTH_REQ_PASSWORD: /* discard const so we can assign it */ crypt_pwd = (char *) password; --- 783,788 ---- *************** *** 938,945 **** pg_fe_sendauth(AuthRequest areq, PGconn *conn) #endif - case AUTH_REQ_MD5: case AUTH_REQ_CRYPT: case AUTH_REQ_PASSWORD: conn->password_needed = true; if (conn->pgpass == NULL || conn->pgpass[0] == '\0') --- 926,937 ---- #endif case AUTH_REQ_CRYPT: + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("Crypt authentication not supported\n")); + return STATUS_ERROR; + + case AUTH_REQ_MD5: case AUTH_REQ_PASSWORD: conn->password_needed = true; if (conn->pgpass == NULL || conn->pgpass[0] == '\0') *** a/src/interfaces/libpq/fe-connect.c --- b/src/interfaces/libpq/fe-connect.c *************** *** 1674,1688 **** keep_going: /* We will come back to here until there is return PGRES_POLLING_READING; } } - if (areq == AUTH_REQ_CRYPT) - { - if (pqGetnchar(conn->cryptSalt, - sizeof(conn->cryptSalt), conn)) - { - /* We'll come back when there are more data */ - return PGRES_POLLING_READING; - } - } #if defined(ENABLE_GSS) || defined(ENABLE_SSPI) /* --- 1674,1679 ---- *** a/src/interfaces/libpq/libpq-int.h --- b/src/interfaces/libpq/libpq-int.h *************** *** 340,346 **** struct pg_conn int be_pid; /* PID of backend --- needed for cancels */ int be_key; /* key of backend --- needed for cancels */ char md5Salt[4]; /* password salt received from backend */ - char cryptSalt[2]; /* password salt received from backend */ pgParameterStatus *pstatus; /* ParameterStatus data */ int client_encoding; /* encoding id */ bool std_strings; /* standard_conforming_strings */ --- 340,345 ----
pgsql-hackers by date: