diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml index 6e7a1d834d..a7c9c8616b 100644 --- a/doc/src/sgml/client-auth.sgml +++ b/doc/src/sgml/client-auth.sgml @@ -1,4 +1,4 @@ - + Client Authentication @@ -205,11 +205,10 @@ hostssl database IP-address Like the password method, but the password is sent over the wire encrypted using a simple - challenge-response protocol. This is still not - cryptographically secure but it protects against incidental + challenge-response protocol. This protects against incidental wire-sniffing. The name of a file may follow the - crypt keyword that contains a list of users - that this record pertains to. + crypt keyword. It contains a list of users + for this record. diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index ec35b9c96d..a6351dd8bd 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -1,4 +1,4 @@ - + Frontend/Backend Protocol @@ -1295,7 +1295,7 @@ EncryptedPasswordPacket (F) - The encrypted (using crypt()) password. + The encrypted (using MD5 or crypt()) password. diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml index 534d2a7eb2..3a502197ab 100644 --- a/doc/src/sgml/ref/alter_user.sgml +++ b/doc/src/sgml/ref/alter_user.sgml @@ -1,5 +1,5 @@ @@ -27,7 +27,7 @@ ALTER USER username [ [ WITH ] option can be: - PASSWORD 'password' + [ ENCRYPTED | UNENCRYPTED ] PASSWORD 'password' | CREATEDB | NOCREATEDB | CREATEUSER | NOCREATEUSER | VALID UNTIL 'abstime' @@ -53,10 +53,13 @@ where option can be: - password + [ encrypted | unencrypted ] password The new password to be used for this account. + Encrypted/ unencrypted + controls whether the password is stored encrypted in the + database. diff --git a/doc/src/sgml/ref/create_user.sgml b/doc/src/sgml/ref/create_user.sgml index 8c97dbcf86..f72b20f59d 100644 --- a/doc/src/sgml/ref/create_user.sgml +++ b/doc/src/sgml/ref/create_user.sgml @@ -1,5 +1,5 @@ @@ -28,7 +28,7 @@ CREATE USER username [ [ WITH ] option can be: SYSID uid - | PASSWORD 'password' + | [ ENCRYPTED | UNENCRYPTED ] PASSWORD 'password' | CREATEDB | NOCREATEDB | CREATEUSER | NOCREATEUSER | IN GROUP groupname [, ...] @@ -72,12 +72,19 @@ where option can be: - password + [ encrypted | unencrypted ] password Sets the user's password. If you do not plan to use password authentication you can omit this option, otherwise the user won't be able to connect to a password-authenticated server. + + + ENCRYPTED/UNENCRYPTED controls whether the + password is stored encrypted in the database. Older clients may + have trouble communicating using encrypted password storage. + + See the chapter on client authentication in the Administrator's Guide for details on how to set up authentication mechanisms. diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index d4d4dd8d53..6e80adf00e 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -1,5 +1,5 @@ @@ -967,6 +967,18 @@ env PGOPTIONS='-c geqo=off' psql + + AUSTRALIAN_TIMEZONES (bool) + + + If set to true, CST, EST, + and SAT are interpreted as Australian + timezones rather than as North American Central/Eastern + Timezones and Saturday. The default is false. + + + + deadlock @@ -1260,18 +1272,6 @@ dynamic_library_path = '/usr/local/lib:/home/my_project/lib:$libdir:$libdir/cont - - AUSTRALIAN_TIMEZONES (bool) - - - If set to true, CST, EST, - and SAT are interpreted as Australian - timezones rather than as North American Central/Eastern - Timezones and Saturday. The default is false. - - - - SSL diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 47c8dfa431..7f62b19928 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.79 2001/07/12 18:02:59 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.80 2001/08/15 18:42:14 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -25,6 +25,7 @@ #include "catalog/indexing.h" #include "commands/user.h" #include "libpq/crypt.h" +#include "libpq/md5.h" #include "miscadmin.h" #include "utils/array.h" #include "utils/builtins.h" @@ -34,7 +35,7 @@ static void CheckPgUserAclNotNull(void); - +extern bool Password_encryption; /*--------------------------------------------------------------------- * write_password_file / update_pg_pwd @@ -201,72 +202,80 @@ CreateUser(CreateUserStmt *stmt) int max_id = -1; List *item, *option; char *password = NULL; /* PostgreSQL user password */ + bool encrypt_password = Password_encryption; /* encrypt password? */ + char encrypted_password[MD5_PASSWD_LEN+1]; int sysid = 0; /* PgSQL system id (valid if havesysid) */ bool createdb = false; /* Can the user create databases? */ bool createuser = false; /* Can this user create users? */ List *groupElts = NIL; /* The groups the user is a member of */ char *validUntil = NULL; /* The time the login is valid until */ - DefElem *dpassword = NULL; - DefElem *dsysid = NULL; - DefElem *dcreatedb = NULL; - DefElem *dcreateuser = NULL; - DefElem *dgroupElts = NULL; - DefElem *dvalidUntil = NULL; + DefElem *dpassword = NULL; + DefElem *dsysid = NULL; + DefElem *dcreatedb = NULL; + DefElem *dcreateuser = NULL; + DefElem *dgroupElts = NULL; + DefElem *dvalidUntil = NULL; /* Extract options from the statement node tree */ foreach(option, stmt->options) { DefElem *defel = (DefElem *) lfirst(option); - if (strcasecmp(defel->defname, "password") == 0) { - if (dpassword) - elog(ERROR, "CREATE USER: conflicting options"); - dpassword = defel; - } - else if (strcasecmp(defel->defname, "sysid") == 0) { - if (dsysid) - elog(ERROR, "CREATE USER: conflicting options"); - dsysid = defel; - } - else if (strcasecmp(defel->defname, "createdb") == 0) { - if (dcreatedb) - elog(ERROR, "CREATE USER: conflicting options"); - dcreatedb = defel; - } - else if (strcasecmp(defel->defname, "createuser") == 0) { - if (dcreateuser) - elog(ERROR, "CREATE USER: conflicting options"); - dcreateuser = defel; - } - else if (strcasecmp(defel->defname, "groupElts") == 0) { - if (dgroupElts) - elog(ERROR, "CREATE USER: conflicting options"); - dgroupElts = defel; - } - else if (strcasecmp(defel->defname, "validUntil") == 0) { - if (dvalidUntil) - elog(ERROR, "CREATE USER: conflicting options"); - dvalidUntil = defel; - } - else - elog(ERROR,"CREATE USER: option \"%s\" not recognized", - defel->defname); - } + if (strcasecmp(defel->defname, "password") == 0 || + strcasecmp(defel->defname, "encryptedPassword") == 0 || + strcasecmp(defel->defname, "unencryptedPassword") == 0) { + if (dpassword) + elog(ERROR, "CREATE USER: conflicting options"); + dpassword = defel; + if (strcasecmp(defel->defname, "encryptedPassword") == 0) + encrypt_password = true; + else if (strcasecmp(defel->defname, "unencryptedPassword") == 0) + encrypt_password = false; + } + else if (strcasecmp(defel->defname, "sysid") == 0) { + if (dsysid) + elog(ERROR, "CREATE USER: conflicting options"); + dsysid = defel; + } + else if (strcasecmp(defel->defname, "createdb") == 0) { + if (dcreatedb) + elog(ERROR, "CREATE USER: conflicting options"); + dcreatedb = defel; + } + else if (strcasecmp(defel->defname, "createuser") == 0) { + if (dcreateuser) + elog(ERROR, "CREATE USER: conflicting options"); + dcreateuser = defel; + } + else if (strcasecmp(defel->defname, "groupElts") == 0) { + if (dgroupElts) + elog(ERROR, "CREATE USER: conflicting options"); + dgroupElts = defel; + } + else if (strcasecmp(defel->defname, "validUntil") == 0) { + if (dvalidUntil) + elog(ERROR, "CREATE USER: conflicting options"); + dvalidUntil = defel; + } + else + elog(ERROR,"CREATE USER: option \"%s\" not recognized", + defel->defname); + } - if (dcreatedb) + if (dcreatedb) createdb = intVal(dcreatedb->arg) != 0; - if (dcreateuser) + if (dcreateuser) createuser = intVal(dcreateuser->arg) != 0; - if (dsysid) + if (dsysid) { sysid = intVal(dsysid->arg); havesysid = true; } - if (dvalidUntil) + if (dvalidUntil) validUntil = strVal(dvalidUntil->arg); - if (dpassword) + if (dpassword) password = strVal(dpassword->arg); - if (dgroupElts) + if (dgroupElts) groupElts = (List *) dgroupElts->arg; /* Check some permissions first */ @@ -337,8 +346,18 @@ CreateUser(CreateUserStmt *stmt) new_record[Anum_pg_shadow_usecatupd - 1] = BoolGetDatum(createuser); if (password) - new_record[Anum_pg_shadow_passwd - 1] = - DirectFunctionCall1(textin, CStringGetDatum(password)); + { + if (!encrypt_password || isMD5(password)) + new_record[Anum_pg_shadow_passwd - 1] = + DirectFunctionCall1(textin, CStringGetDatum(password)); + else + { + if (!EncryptMD5(password, stmt->user, encrypted_password)) + elog(ERROR, "CREATE USER: password encryption failed"); + new_record[Anum_pg_shadow_passwd - 1] = + DirectFunctionCall1(textin, CStringGetDatum(encrypted_password)); + } + } if (validUntil) new_record[Anum_pg_shadow_valuntil - 1] = DirectFunctionCall1(nabstimein, CStringGetDatum(validUntil)); @@ -418,6 +437,8 @@ AlterUser(AlterUserStmt *stmt) bool null; List *option; char *password = NULL; /* PostgreSQL user password */ + bool encrypt_password = Password_encryption; /* encrypt password? */ + char encrypted_password[MD5_PASSWD_LEN+1]; int createdb = -1; /* Can the user create databases? */ int createuser = -1; /* Can this user create users? */ char *validUntil = NULL; /* The time the login is valid until */ @@ -431,10 +452,16 @@ AlterUser(AlterUserStmt *stmt) { DefElem *defel = (DefElem *) lfirst(option); - if (strcasecmp(defel->defname, "password") == 0) { + if (strcasecmp(defel->defname, "password") == 0 || + strcasecmp(defel->defname, "encryptedPassword") == 0 || + strcasecmp(defel->defname, "unencryptedPassword") == 0) { if (dpassword) elog(ERROR, "ALTER USER: conflicting options"); dpassword = defel; + if (strcasecmp(defel->defname, "encryptedPassword") == 0) + encrypt_password = true; + else if (strcasecmp(defel->defname, "unencryptedPassword") == 0) + encrypt_password = false; } else if (strcasecmp(defel->defname, "createdb") == 0) { if (dcreatedb) @@ -445,17 +472,17 @@ AlterUser(AlterUserStmt *stmt) if (dcreateuser) elog(ERROR, "ALTER USER: conflicting options"); dcreateuser = defel; - } + } else if (strcasecmp(defel->defname, "validUntil") == 0) { if (dvalidUntil) elog(ERROR, "ALTER USER: conflicting options"); dvalidUntil = defel; } - else + else elog(ERROR,"ALTER USER: option \"%s\" not recognized", defel->defname); } - + if (dcreatedb) createdb = intVal(dcreatedb->arg); if (dcreateuser) @@ -464,8 +491,8 @@ AlterUser(AlterUserStmt *stmt) validUntil = strVal(dvalidUntil->arg); if (dpassword) password = strVal(dpassword->arg); - - if (password) + + if (password) CheckPgUserAclNotNull(); /* must be superuser or just want to change your own password */ @@ -552,8 +579,16 @@ AlterUser(AlterUserStmt *stmt) /* password */ if (password) { - new_record[Anum_pg_shadow_passwd - 1] = - DirectFunctionCall1(textin, CStringGetDatum(password)); + if (!encrypt_password || isMD5(password)) + new_record[Anum_pg_shadow_passwd - 1] = + DirectFunctionCall1(textin, CStringGetDatum(password)); + else + { + if (!EncryptMD5(password, stmt->user, encrypted_password)) + elog(ERROR, "CREATE USER: password encryption failed"); + new_record[Anum_pg_shadow_passwd - 1] = + DirectFunctionCall1(textin, CStringGetDatum(encrypted_password)); + } new_record_nulls[Anum_pg_shadow_passwd - 1] = ' '; } else @@ -793,40 +828,40 @@ CreateGroup(CreateGroupStmt *stmt) Datum new_record[Natts_pg_group]; char new_record_nulls[Natts_pg_group]; List *item, - *option, + *option, *newlist = NIL; ArrayType *userarray; - int sysid = 0; - List *userElts = NIL; - DefElem *dsysid = NULL; - DefElem *duserElts = NULL; + int sysid = 0; + List *userElts = NIL; + DefElem *dsysid = NULL; + DefElem *duserElts = NULL; foreach(option, stmt->options) { DefElem *defel = (DefElem *) lfirst(option); - if (strcasecmp(defel->defname, "sysid") == 0) { - if (dsysid) - elog(ERROR, "CREATE GROUP: conflicting options"); - dsysid = defel; - } - else if (strcasecmp(defel->defname, "userElts") == 0) { - if (duserElts) - elog(ERROR, "CREATE GROUP: conflicting options"); - duserElts = defel; - } - else - elog(ERROR,"CREATE GROUP: option \"%s\" not recognized", - defel->defname); - } + if (strcasecmp(defel->defname, "sysid") == 0) { + if (dsysid) + elog(ERROR, "CREATE GROUP: conflicting options"); + dsysid = defel; + } + else if (strcasecmp(defel->defname, "userElts") == 0) { + if (duserElts) + elog(ERROR, "CREATE GROUP: conflicting options"); + duserElts = defel; + } + else + elog(ERROR,"CREATE GROUP: option \"%s\" not recognized", + defel->defname); + } - if (dsysid) + if (dsysid) { sysid = intVal(dsysid->arg); havesysid = true; } - if (duserElts) + if (duserElts) userElts = (List *) duserElts->arg; /* diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile index 619a0c8690..d71e5c9765 100644 --- a/src/backend/libpq/Makefile +++ b/src/backend/libpq/Makefile @@ -4,7 +4,7 @@ # Makefile for libpq subsystem (backend half of libpq interface) # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.24 2000/08/25 10:00:30 petere Exp $ +# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.25 2001/08/15 18:42:14 momjian Exp $ # #------------------------------------------------------------------------- @@ -15,7 +15,7 @@ include $(top_builddir)/src/Makefile.global # be-fsstubs is here for historical reasons, probably belongs elsewhere OBJS = be-fsstubs.o \ - auth.o crypt.o hba.o password.o \ + auth.o crypt.o hba.o md5.o password.o \ pqcomm.o pqformat.o pqpacket.o pqsignal.o util.o diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 81d4865ce6..fe7bc3c9d1 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.56 2001/08/07 10:44:13 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.57 2001/08/15 18:42:14 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -420,9 +420,8 @@ auth_failed(Port *port) authmethod = "IDENT"; break; case uaPassword: - authmethod = "Password"; - break; case uaCrypt: + case uaMD5: authmethod = "Password"; break; } @@ -507,6 +506,11 @@ ClientAuthentication(Port *port) status = recv_and_check_password_packet(port); break; + case uaMD5: + sendAuthRequest(port, AUTH_REQ_MD5); + status = recv_and_check_password_packet(port); + break; + case uaTrust: status = STATUS_OK; break; @@ -532,7 +536,7 @@ sendAuthRequest(Port *port, AuthRequest areq) pq_sendint(&buf, (int32) areq, sizeof(int32)); /* Add the salt for encrypted passwords. */ - if (areq == AUTH_REQ_CRYPT) + if (areq == AUTH_REQ_CRYPT || areq == AUTH_REQ_MD5) { pq_sendint(&buf, port->salt[0], 1); pq_sendint(&buf, port->salt[1], 1); @@ -557,7 +561,7 @@ recv_and_check_password_packet(Port *port) if (pq_eof() == EOF || pq_getint(&len, 4) == EOF) return STATUS_ERROR; /* client didn't want to send password */ initStringInfo(&buf); - pq_getstr(&buf); + pq_getstr(&buf); /* receive password */ if (DebugLvl) fprintf(stderr, "received password packet with len=%d, pw=%s\n", @@ -579,7 +583,7 @@ checkPassword(Port *port, char *user, char *password) if (port->auth_arg[0] != '\0') return verify_password(port, user, password); - return crypt_verify(port, user, password); + return md5_crypt_verify(port, user, password); } @@ -594,7 +598,6 @@ old_be_recvauth(Port *port) MsgType msgtype = (MsgType) port->proto; /* Handle the authentication that's offered. */ - switch (msgtype) { case STARTUP_KRB4_MSG: @@ -634,6 +637,7 @@ map_old_to_new(Port *port, UserAuth old, int status) switch (port->auth_method) { case uaCrypt: + case uaMD5: case uaReject: status = STATUS_ERROR; break; diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index e89963f9f6..62393d26e0 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -9,7 +9,7 @@ * Dec 17, 1997 - Todd A. Brandys * Orignal Version Completed. * - * $Id: crypt.c,v 1.32 2001/06/23 23:26:17 petere Exp $ + * $Id: crypt.c,v 1.33 2001/08/15 18:42:14 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,7 @@ #include "postgres.h" #include "libpq/crypt.h" +#include "libpq/md5.h" #include "miscadmin.h" #include "storage/fd.h" #include "utils/nabstime.h" @@ -254,7 +255,7 @@ crypt_getloginfo(const char *user, char **passwd, char **valuntil) /*-------------------------------------------------------------------------*/ int -crypt_verify(const Port *port, const char *user, const char *pgpass) +md5_crypt_verify(const Port *port, const char *user, const char *pgpass) { char *passwd, @@ -280,9 +281,47 @@ crypt_verify(const Port *port, const char *user, const char *pgpass) * Compare with the encrypted or plain password depending on the * authentication method being used for this connection. */ + switch (port->auth_method) + { + case uaCrypt: + crypt_pwd = crypt(passwd, port->salt); + break; + case uaMD5: + crypt_pwd = palloc(MD5_PASSWD_LEN+1); - crypt_pwd = - (port->auth_method == uaCrypt ? crypt(passwd, port->salt) : passwd); + if (isMD5(passwd)) + { + if (!EncryptMD5(passwd + strlen("md5"), + (char *)port->salt, crypt_pwd)) + { + pfree(crypt_pwd); + return STATUS_ERROR; + } + } + else + { + char *crypt_pwd2 = palloc(MD5_PASSWD_LEN+1); + + if (!EncryptMD5(passwd, port->user, crypt_pwd2)) + { + pfree(crypt_pwd); + pfree(crypt_pwd2); + return STATUS_ERROR; + } + if (!EncryptMD5(crypt_pwd2 + strlen("md5"), port->salt, + crypt_pwd)) + { + pfree(crypt_pwd); + pfree(crypt_pwd2); + return STATUS_ERROR; + } + pfree(crypt_pwd2); + } + break; + default: + crypt_pwd = passwd; + break; + } if (!strcmp(pgpass, crypt_pwd)) { @@ -302,9 +341,11 @@ crypt_verify(const Port *port, const char *user, const char *pgpass) retval = STATUS_OK; } - pfree((void *) passwd); + pfree(passwd); if (valuntil) - pfree((void *) valuntil); + pfree(valuntil); + if (port->auth_method == uaMD5) + pfree(crypt_pwd); return retval; } diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index b91427460d..d12225ab0e 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.61 2001/08/02 14:39:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.62 2001/08/15 18:42:15 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -203,8 +203,8 @@ free_lines(List **lines) * *error_p. line points to the next token of the line. */ static void -parse_hba_auth(List *line, UserAuth *userauth_p, char *auth_arg, - bool *error_p) +parse_hba_auth(List *line, ProtocolVersion proto, UserAuth *userauth_p, + char *auth_arg, bool *error_p) { char *token; @@ -227,7 +227,15 @@ parse_hba_auth(List *line, UserAuth *userauth_p, char *auth_arg, else if (strcmp(token, "reject") == 0) *userauth_p = uaReject; else if (strcmp(token, "crypt") == 0) - *userauth_p = uaCrypt; + { + /* if the client supports it, use MD5 */ + if (PG_PROTOCOL_MAJOR(proto) > 2 || + (PG_PROTOCOL_MAJOR(proto) == 2 && + PG_PROTOCOL_MINOR(proto) >= 1)) + *userauth_p = uaMD5; + else + *userauth_p = uaCrypt; + } else *error_p = true; line = lnext(line); @@ -285,7 +293,8 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) line = lnext(line); if (!line) goto hba_syntax; - parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p); + parse_hba_auth(line, port->proto, &port->auth_method, + port->auth_arg, error_p); if (*error_p) goto hba_syntax; @@ -354,7 +363,8 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) line = lnext(line); if (!line) goto hba_syntax; - parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p); + parse_hba_auth(line, port->proto, &port->auth_method, + port->auth_arg, error_p); if (*error_p) goto hba_syntax; diff --git a/src/backend/libpq/password.c b/src/backend/libpq/password.c index 2d4559a296..e98ab6bc0a 100644 --- a/src/backend/libpq/password.c +++ b/src/backend/libpq/password.c @@ -2,7 +2,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: password.c,v 1.37 2001/06/18 16:11:30 momjian Exp $ + * $Id: password.c,v 1.38 2001/08/15 18:42:15 momjian Exp $ * */ @@ -82,11 +82,14 @@ verify_password(const Port *port, const char *user, const char *password) * the current code needs non-encrypted passwords to * encrypt with a random salt. */ - if (port->auth_method == uaCrypt - || test_pw == NULL || test_pw[0] == '\0' - || strcmp(test_pw, "+") == 0) - return crypt_verify(port, user, password); + if (port->auth_method == uaCrypt || + port->auth_method == uaMD5 || + test_pw == NULL || + test_pw[0] == '\0' || + strcmp(test_pw, "+") == 0) + return md5_crypt_verify(port, user, password); + /* external password file is crypt-only */ if (strcmp(crypt(password, test_pw), test_pw) == 0) { /* it matched. */ diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample index 7dc39ee67b..a489b78a70 100644 --- a/src/backend/libpq/pg_hba.conf.sample +++ b/src/backend/libpq/pg_hba.conf.sample @@ -3,7 +3,6 @@ # # # This file controls: -# # o which hosts are allowed to connect # o how users are authenticated on each host # o databases accessible by each host @@ -24,7 +23,6 @@ # ============ # # There are three types of records: -# # o host # o hostssl # o local @@ -40,7 +38,6 @@ # host DBNAME IP_ADDRESS ADDRESS_MASK AUTH_TYPE [AUTH_ARGUMENT] # # DBNAME can be: -# # o the name of a PostgreSQL database # o "all" to indicate all databases # o "sameuser" to allow access only to databases with the same @@ -80,7 +77,6 @@ # allowed only if this record type appears. # # Format: -# # local DBNAME AUTH_TYPE [AUTH_ARGUMENT] # # This format is identical to the "host" record type except the IP_ADDRESS @@ -219,4 +215,3 @@ local all trust host all 127.0.0.1 255.255.255.255 trust - diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 391d821119..57242a5978 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.244 2001/08/13 21:34:51 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.245 2001/08/15 18:42:15 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -306,7 +306,7 @@ static void doNegateFloat(Value *v); CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, DAY_P, DEC, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP, - ELSE, END_TRANS, ESCAPE, EXCEPT, EXECUTE, EXISTS, EXTRACT, + ELSE, ENCRYPTED, END_TRANS, ESCAPE, EXCEPT, EXECUTE, EXISTS, EXTRACT, FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL, GLOBAL, GRANT, GROUP, HAVING, HOUR_P, IN, INNER_P, INSENSITIVE, INSERT, INTERSECT, INTERVAL, INTO, IS, @@ -319,7 +319,7 @@ static void doNegateFloat(Value *v); SCHEMA, SCROLL, SECOND_P, SELECT, SESSION, SESSION_USER, SET, SOME, SUBSTRING, TABLE, TEMPORARY, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE, TO, TRAILING, TRANSACTION, TRIM, TRUE_P, - UNION, UNIQUE, UNKNOWN, UPDATE, USER, USING, + UNENCRYPTED, UNION, UNIQUE, UNKNOWN, UPDATE, USER, USING, VALUES, VARCHAR, VARYING, VIEW, WHEN, WHERE, WITH, WORK, YEAR_P, ZONE @@ -558,6 +558,18 @@ OptUserElem: PASSWORD Sconst $$->defname = "password"; $$->arg = (Node *)makeString($2); } + | ENCRYPTED PASSWORD Sconst + { + $$ = makeNode(DefElem); + $$->defname = "encryptedPassword"; + $$->arg = (Node *)makeString($3); + } + | UNENCRYPTED PASSWORD Sconst + { + $$ = makeNode(DefElem); + $$->defname = "unencryptedPassword"; + $$->arg = (Node *)makeString($3); + } | SYSID Iconst { $$ = makeNode(DefElem); @@ -5765,6 +5777,7 @@ ColLabel: ColId { $$ = $1; } | DISTINCT { $$ = "distinct"; } | DO { $$ = "do"; } | ELSE { $$ = "else"; } + | ENCRYPTED { $$ = "encrypted"; } | END_TRANS { $$ = "end"; } | EXCEPT { $$ = "except"; } | EXISTS { $$ = "exists"; } @@ -5836,6 +5849,7 @@ ColLabel: ColId { $$ = $1; } | TRANSACTION { $$ = "transaction"; } | TRIM { $$ = "trim"; } | TRUE_P { $$ = "true"; } + | UNENCRYPTED { $$ = "unencrypted"; } | UNION { $$ = "union"; } | UNIQUE { $$ = "unique"; } | UNKNOWN { $$ = "unknown"; } diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index 014b119850..3fb39c0821 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.94 2001/07/16 05:06:58 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.95 2001/08/15 18:42:15 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -102,6 +102,7 @@ static ScanKeyword ScanKeywords[] = { {"each", EACH}, {"else", ELSE}, {"encoding", ENCODING}, + {"encrypted", ENCRYPTED}, {"end", END_TRANS}, {"escape", ESCAPE}, {"except", EXCEPT}, @@ -262,6 +263,7 @@ static ScanKeyword ScanKeywords[] = { {"truncate", TRUNCATE}, {"trusted", TRUSTED}, {"type", TYPE_P}, + {"unencrypted", UNENCRYPTED}, {"union", UNION}, {"unique", UNIQUE}, {"unknown", UNKNOWN}, diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index cc66604781..b0bb99817d 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -4,7 +4,7 @@ * Support for grand unified configuration scheme, including SET * command, configuration file, and command line options. * - * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.45 2001/07/05 15:19:40 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.46 2001/08/15 18:42:15 momjian Exp $ * * Copyright 2000 by PostgreSQL Global Development Group * Written by Peter Eisentraut . @@ -80,6 +80,8 @@ bool SQL_inheritance = true; bool Australian_timezones = false; +bool Password_encryption = false; + #ifndef PG_KRB_SRVTAB #define PG_KRB_SRVTAB "" #endif @@ -246,11 +248,12 @@ static struct config_bool {"sql_inheritance", PGC_USERSET, &SQL_inheritance, true, NULL}, - {"australian_timezones", PGC_USERSET, &Australian_timezones, - false, ClearDateCache}, + {"australian_timezones", PGC_USERSET, &Australian_timezones, false, ClearDateCache}, {"fixbtree", PGC_POSTMASTER, &FixBTree, true, NULL}, + {"password_encryption", PGC_USERSET, &Password_encryption, false, NULL}, + {NULL, 0, NULL, false, NULL} }; diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 6b25bbca6c..78abcd50c2 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -176,9 +176,10 @@ # # Misc # -#default_transaction_isolation = 'read committed' -#sql_inheritance = true #australian_timezones = false #deadlock_timeout = 1000 +#default_transaction_isolation = 'read committed' #max_expr_depth = 10000 # min 10 +#password_encryption = false +#sql_inheritance = true diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h index c3f58ee163..030921c254 100644 --- a/src/include/libpq/crypt.h +++ b/src/include/libpq/crypt.h @@ -22,10 +22,6 @@ extern int pwd_cache_count; extern char *crypt_getpwdfilename(void); extern char *crypt_getpwdreloadfilename(void); -#ifdef NOT_USED -extern MsgType crypt_salt(const char *user); - -#endif -extern int crypt_verify(const Port *port, const char *user, const char *pgpass); +extern int md5_crypt_verify(const Port *port, const char *user, const char *pgpass); #endif diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h index 0d792da3d3..11f052d363 100644 --- a/src/include/libpq/hba.h +++ b/src/include/libpq/hba.h @@ -4,7 +4,7 @@ * Interface to hba.c * * - * $Id: hba.h,v 1.22 2001/08/01 23:25:39 tgl Exp $ + * $Id: hba.h,v 1.23 2001/08/15 18:42:15 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -35,7 +35,9 @@ typedef enum UserAuth uaTrust, uaIdent, uaPassword, - uaCrypt + uaCrypt, + uaMD5 /* This starts as uaCrypt from pg_hba.conf, but gets + overridden if the client supports MD5 */ } UserAuth; typedef struct Port hbaPort; diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index 0f90ecdc67..c709553f69 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pqcomm.h,v 1.55 2001/03/22 04:00:48 momjian Exp $ + * $Id: pqcomm.h,v 1.56 2001/08/15 18:42:15 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -90,7 +90,7 @@ typedef union SockAddr /* The earliest and latest frontend/backend protocol version supported. */ #define PG_PROTOCOL_EARLIEST PG_PROTOCOL(0,0) -#define PG_PROTOCOL_LATEST PG_PROTOCOL(2,0) +#define PG_PROTOCOL_LATEST PG_PROTOCOL(2,1) /* * All packets sent to the postmaster start with the length. This is omitted @@ -127,11 +127,12 @@ typedef struct StartupPacket /* These are the authentication requests sent by the backend. */ -#define AUTH_REQ_OK 0 /* User is authenticated */ +#define AUTH_REQ_OK 0 /* User is authenticated */ #define AUTH_REQ_KRB4 1 /* Kerberos V4 */ #define AUTH_REQ_KRB5 2 /* Kerberos V5 */ #define AUTH_REQ_PASSWORD 3 /* Password */ -#define AUTH_REQ_CRYPT 4 /* Encrypted password */ +#define AUTH_REQ_CRYPT 4 /* crypt password */ +#define AUTH_REQ_MD5 5 /* md5 password */ typedef uint32 AuthRequest; diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index c3afaf89ec..89e0670911 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: miscadmin.h,v 1.88 2001/08/05 02:06:50 tgl Exp $ + * $Id: miscadmin.h,v 1.89 2001/08/15 18:42:15 momjian Exp $ * * NOTES * some of the information in this file should be moved to @@ -171,8 +171,10 @@ extern bool enableFsync; extern bool allowSystemTableMods; extern int SortMem; -/* a few postmaster startup options are exported here so the - configuration file processor has access to them */ +/* + * A few postmaster startup options are exported here so the + * configuration file processor can access them. + */ extern bool NetServer; extern bool EnableSSL; diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index 91759e9786..73507a15b3 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -4,7 +4,7 @@ # # Copyright (c) 1994, Regents of the University of California # -# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.53 2001/07/15 13:45:04 petere Exp $ +# $Header: /cvsroot/pgsql/src/interfaces/libpq/Makefile,v 1.54 2001/08/15 18:42:15 momjian Exp $ # #------------------------------------------------------------------------- @@ -20,7 +20,7 @@ SO_MINOR_VERSION= 2 override CPPFLAGS := -I$(srcdir) $(CPPFLAGS) -DFRONTEND -DSYSCONFDIR='"$(sysconfdir)"' OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \ - pqexpbuffer.o dllist.o pqsignal.o \ + pqexpbuffer.o dllist.o md5.o pqsignal.o \ $(INET_ATON) $(SNPRINTF) $(STRERROR) ifdef MULTIBYTE @@ -33,7 +33,7 @@ endif SHLIB_LINK += $(filter -L%, $(LDFLAGS)) $(filter -lcrypt -ldes -lkrb -lcom_err -lcrypto -lk5crypto -lkrb5 -lssl -lsocket -lnsl -lresolv -lintl, $(LIBS)) -all: all-lib +all: md5.c md5.h all-lib # Shared library stuff include $(top_srcdir)/src/Makefile.shlib @@ -49,6 +49,12 @@ backend_src = $(top_srcdir)/src/backend dllist.c: $(backend_src)/lib/dllist.c rm -f $@ && $(LN_S) $< . +md5.c: $(backend_src)/libpq/md5.c + rm -f $@ && $(LN_S) $< . + +md5.h: $(backend_src)/../include/libpq/md5.h + rm -f $@ && $(LN_S) $< . + # this only gets done if configure finds system doesn't have inet_aton() inet_aton.c: $(backend_src)/port/inet_aton.c rm -f $@ && $(LN_S) $< . @@ -82,7 +88,7 @@ uninstall: uninstall-lib rm -f $(addprefix $(DESTDIR)$(includedir)/, libpq-fe.h libpq-int.h pqexpbuffer.h) clean distclean maintainer-clean: clean-lib - rm -f $(OBJS) dllist.c wchar.c + rm -f $(OBJS) dllist.c md5.c md5.h wchar.c rm -f $(OBJS) inet_aton.c snprintf.c strerror.c depend dep: diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index d8b27c3772..6f874c485b 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -10,7 +10,7 @@ * exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes). * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.48 2001/07/15 13:45:04 petere Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.49 2001/08/15 18:42:15 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -33,6 +33,7 @@ #include "libpq-fe.h" #include "libpq-int.h" #include "fe-auth.h" +#include "md5.h" #ifdef WIN32 #include "win32.h" @@ -434,12 +435,52 @@ pg_krb5_sendauth(char *PQerrormsg, int sock, static int pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) { + int ret; + char *crypt_pwd; + /* Encrypt the password if needed. */ - if (areq == AUTH_REQ_CRYPT) - password = crypt(password, conn->salt); + switch (areq) + { + case AUTH_REQ_CRYPT: + crypt_pwd = crypt(password, conn->salt); + break; + case AUTH_REQ_MD5: + { + char *crypt_pwd2; - return pqPacketSend(conn, password, strlen(password) + 1); + if (!(crypt_pwd = malloc(MD5_PASSWD_LEN+1)) || + !(crypt_pwd2 = malloc(MD5_PASSWD_LEN+1))) + { + perror("malloc"); + return STATUS_ERROR; + } + if (!EncryptMD5(password, conn->pguser, crypt_pwd2)) + { + free(crypt_pwd); + free(crypt_pwd2); + return STATUS_ERROR; + } + if (!EncryptMD5(crypt_pwd2 + strlen("md5"), conn->salt, + crypt_pwd)) + { + free(crypt_pwd); + free(crypt_pwd2); + return STATUS_ERROR; + } + free(crypt_pwd2); + break; + } + default: + /* discard const so we can assign it */ + crypt_pwd = (char *)password; + break; + } + + ret = pqPacketSend(conn, crypt_pwd, strlen(crypt_pwd) + 1); + if (areq == AUTH_REQ_MD5) + free(crypt_pwd); + return ret; } /* @@ -494,6 +535,7 @@ fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname, case AUTH_REQ_PASSWORD: case AUTH_REQ_CRYPT: + case AUTH_REQ_MD5: if (password == NULL || *password == '\0') { (void) sprintf(PQerrormsg, @@ -506,9 +548,7 @@ fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname, "fe_sendauth: error sending password authentication\n"); return STATUS_ERROR; } - break; - default: snprintf(PQerrormsg, PQERRORMSG_LENGTH, libpq_gettext("authentication method %u not supported\n"), areq); diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 47f5d55c32..32983c53ad 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.172 2001/08/03 22:11:39 tgl Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.173 2001/08/15 18:42:15 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1341,7 +1341,7 @@ keep_going: /* We will come back to here until there } /* Get the password salt if there is one. */ - if (areq == AUTH_REQ_CRYPT) + if (areq == AUTH_REQ_CRYPT || areq == AUTH_REQ_MD5) { if (pqGetnchar(conn->salt, sizeof(conn->salt), conn)) { @@ -1960,7 +1960,7 @@ static void closePGconn(PGconn *conn) { /* Note that the protocol doesn't allow us to send Terminate - messages during the startup phase. */ + messages during the startup phase. */ if (conn->sock >= 0 && conn->status == CONNECTION_OK) { diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index c512f6928c..c5dfcd4210 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.105 2001/08/03 22:11:39 tgl Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.106 2001/08/15 18:42:15 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1269,7 +1269,6 @@ errout: static int getNotice(PGconn *conn) { - /* * Since the Notice might be pretty long, we create a temporary * PQExpBuffer rather than using conn->workBuffer. workBuffer is diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 5e90e492f1..a681e72bee 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-int.h,v 1.36 2001/07/15 13:45:04 petere Exp $ + * $Id: libpq-int.h,v 1.37 2001/08/15 18:42:16 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -45,7 +45,7 @@ * pqcomm.h describe what the backend knows, not what libpq knows. */ -#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(2,0) +#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(2,1) /* * POSTGRES backend dependent Constants. diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c index 90fc132b98..42196df9ee 100644 --- a/src/interfaces/odbc/connection.c +++ b/src/interfaces/odbc/connection.c @@ -677,7 +677,7 @@ CC_connect(ConnectionClass *self, char do_password) mylog("auth got 'R'\n"); areq = SOCK_get_int(sock, 4); - if (areq == AUTH_REQ_CRYPT) + if (areq == AUTH_REQ_CRYPT || areq == AUTH_REQ_MD5) SOCK_get_n_char(sock, salt, 2); mylog("areq = %d\n", areq); @@ -717,6 +717,7 @@ CC_connect(ConnectionClass *self, char do_password) break; case AUTH_REQ_CRYPT: + case AUTH_REQ_MD5: self->errormsg = "Password crypt authentication not supported"; self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED; return 0; @@ -1672,15 +1673,15 @@ CC_log_error(char *func, char *desc, ConnectionClass *self) int CC_get_max_query_len(const ConnectionClass *conn) { - int value; - /* Long Queries in 7.0+ */ - if (PG_VERSION_GE(conn, 7.0)) - value = 0 /* MAX_STATEMENT_LEN */; - /* Prior to 7.0 we used 2*BLCKSZ */ - else if (PG_VERSION_GE(conn, 6.5)) - value = (2 * BLCKSZ); - else - /* Prior to 6.5 we used BLCKSZ */ - value = BLCKSZ; - return value; + int value; + /* Long Queries in 7.0+ */ + if (PG_VERSION_GE(conn, 7.0)) + value = 0 /* MAX_STATEMENT_LEN */; + /* Prior to 7.0 we used 2*BLCKSZ */ + else if (PG_VERSION_GE(conn, 6.5)) + value = (2 * BLCKSZ); + else + /* Prior to 6.5 we used BLCKSZ */ + value = BLCKSZ; + return value; } diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h index d3eb8700b2..1038bf117b 100644 --- a/src/interfaces/odbc/connection.h +++ b/src/interfaces/odbc/connection.h @@ -93,6 +93,7 @@ typedef enum #define AUTH_REQ_KRB5 2 #define AUTH_REQ_PASSWORD 3 #define AUTH_REQ_CRYPT 4 +#define AUTH_REQ_MD5 5 /* Startup Packet sizes */ #define SM_DATABASE 64