diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml index b8970f27ec146b1481e86af1eeacdc3909c1c8dd..500fc6ea3fab9310d4c045c8aa341960742b9eb7 100644 --- a/doc/src/sgml/client-auth.sgml +++ b/doc/src/sgml/client-auth.sgml @@ -1,4 +1,4 @@ -<!-- $Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.1 2000/06/18 21:24:51 petere Exp $ --> +<!-- $Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.2 2000/07/04 16:31:51 petere Exp $ --> <chapter id="client-authentication"> <title>Client Authentication</title> @@ -202,15 +202,15 @@ host all 192.168.2.0 255.255.255.0 ident othermap <term>password</term> <listitem> <para> - The client is required to supply a password for the connection + The client is required to supply a password with the connection attempt which is required to match the password that was set up - for the user. (These passwords are separate from any operating - sytem password.) + for the user. </para> <para> - An optional password file may be specified after the - <literal>password</literal> keyword to obtain the password from - that file rather than the pg_shadow system catalog. + An optional file name may be specified after the + <literal>password</literal> keyword. This file is expected to + contain a list of users that this record pertains to, and + optionally alternative passwords. </para> <para> The password is sent over the wire in clear text. For better @@ -225,11 +225,11 @@ host all 192.168.2.0 255.255.255.0 ident othermap <para> Like the <literal>password</literal> method, but the password is sent over the wire encrypted using a simple - challenge-response protocol. Note that this is still not + challenge-response protocol. This is still not cryptographically secure but it protects against incidental - wire-sniffing. Interestingly enough, the - <literal>crypt</literal> does not support secondary password - files. + wire-sniffing. The name of a file may follow the + <literal>crypt</literal> keyword that contains a list of users + that this record pertains to. </para> </listitem> </varlistentry> @@ -276,24 +276,36 @@ host all 192.168.2.0 255.255.255.0 ident othermap <sect2> <title>Password authentication</title> <para> - Ordinarily, the password for each database user is stored in the - pg_shadow system catalog table. Passwords can be managed with the - query language commands <command>CREATE USER</command> and - <command>ALTER USER</command>, e.g., <userinput>CREATE USER foo - WITH PASSWORD 'secret';</userinput>. By default, that is, if no - password has explicitly been set up, the stored password is - <quote>NULL</quote> and password authentication will always fail - for that user. + <productname>Postgres</> database passwords are separate from any + operating system user passwords. Ordinarily, the password for each + database user is stored in the pg_shadow system catalog table. + Passwords can be managed with the query language commands + <command>CREATE USER</command> and <command>ALTER USER</command>, + e.g., <userinput>CREATE USER foo WITH PASSWORD + 'secret';</userinput>. By default, that is, if no password has + explicitly been set up, the stored password is <quote>NULL</quote> + and password authentication will always fail for that user. </para> <para> - Secondary password files can be used if a given set of passwords - should only apply to a particular database or set thereof. - Secondary password files have a format similar to the standard - Unix password file <filename>/etc/passwd</filename>, that is, - <synopsis> + To restrict the set of users that are allowed to connect to + certain databases, list the set of users in a separate file (one + user name per line) in the same directory that + <filename>pg_hba.conf</> is in, and mention the (base) name of the + file after the <literal>password</> or <literal>crypt</> keyword, + respectively, in <filename>pg_hba.conf</>. If you do not use this + feature, then any user that is known to the database system can + connect (as long as he passes password authentication, of course). + </para> + + <para> + These files can also be used a apply a different set of passwords + to a particular database or set thereof. In that case, the files + have a format similar to the standard Unix password file + <filename>/etc/passwd</filename>, that is, +<synopsis> <replaceable>username</replaceable>:<replaceable>password</replaceable> - </synopsis> +</synopsis> Any extra colon separated fields following the password are ignored. The password is expected to be encrypted using the system's <function>crypt()</function> function. The utility @@ -303,20 +315,29 @@ host all 192.168.2.0 255.255.255.0 ident othermap </para> <para> - Secondary password files can also be used to restrict certain - users from connecting to certain databases at all. This is - currently not possible to achieve using the normal password - mechanism (because users and passwords are global across all - databases). If a user is not listed in the applicable password - file the connection will be refused. + Lines with and without passwords can be mixed in secondary + password files. Lines without password indicate use the main + password in <literal>pg_shadow</> that is managed by + <command>CREATE USER</> and <command>ALTER USER</>. Lines with + passwords will cause that password to be used. A password entry of + <quote>+</quote> also means using the pg_shadow password. </para> <para> - Note that using secondary password files means that one can no - longer use <command>ALTER USER</command> to change one's password. - It will still appear to work but the password one is actually - changing is not the password that the system will end up using. + Alternative passwords cannot be used when using the + <literal>crypt</> method. The file will still be evaluated as + usual but the password field will simply be ignored and the + <literal>pg_shadow</> password will be used. </para> + + <para> + Note that using alternative passwords like this means that one can + no longer use <command>ALTER USER</command> to change one's + password. It will still appear to work but the password one is + actually changing is not the password that the system will end up + using. + </para> + </sect2> <sect2> @@ -361,14 +382,15 @@ integrated here. --> The <quote>Identification Protocol</quote> is described in <citetitle>RFC 1413</citetitle>. Virtually every Unix-like operating systems ships with an ident server that listens on TCP - port 113 by default. The basic functionality of the ident server + port 113 by default. The basic functionality of an ident server is to answer questions like <quote>What user initiated the connection that goes out of your port <replaceable>X</replaceable> and connects to my port <replaceable>Y</replaceable>?</quote>. - Since both <replaceable>X</replaceable> and - <replaceable>Y</replaceable> are known, - <productname>Postgres</productname> could theoretically determine - the operating system user for any given connection this way. + Since <productname>Postgres</> knows both <replaceable>X</> and + <replaceable>Y</> when a physical connection is established, it + can interrogate the ident server on the host of the connecting + client and could theoretically determine the operating system user + for any given connection this way. </para> <para> diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 5cd049062cb6412597a657a31899142e40ce524a..4f0dc6a31a0a8550f81fc797b06fadc28756aaac 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.47 2000/05/27 04:13:05 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.48 2000/07/04 16:31:53 petere Exp $ * *------------------------------------------------------------------------- */ @@ -52,9 +52,6 @@ static void auth_failed(Port *port); #ifdef KRB4 -/* This has to be ifdef'd out because krb.h does exist. This needs - to be fixed. -*/ /*---------------------------------------------------------------- * MIT Kerberos authentication system - protocol version 4 *---------------------------------------------------------------- @@ -141,9 +138,6 @@ pg_krb4_recvauth(Port *port) #ifdef KRB5 -/* This needs to be ifdef'd out because krb5.h doesn't exist. This needs - to be fixed. -*/ /*---------------------------------------------------------------- * MIT Kerberos authentication system - protocol version 5 *---------------------------------------------------------------- @@ -692,16 +686,14 @@ readPasswordPacket(void *arg, PacketLen len, void *pkt) /* - * Use the local flat password file if clear passwords are used and the file is - * specified. Otherwise use the password in the pg_shadow table, encrypted or - * not. + * Handle `password' and `crypt' records. If an auth argument was + * specified, use the respective file. Else use pg_shadow passwords. */ - static int checkPassword(Port *port, char *user, char *password) { - if (port->auth_method == uaPassword && port->auth_arg[0] != '\0') - return verify_password(port->auth_arg, user, password); + if (port->auth_arg[0] != '\0') + return verify_password(port, user, password); return crypt_verify(port, user, password); } diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index 38b8e0ed383cf1122d5454e5ce9bbba5d5127242..8b9eace73ef9a264d1ef75e05f93a5b0d2f87e3a 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.26 2000/07/03 20:48:30 petere Exp $ + * $Id: crypt.c,v 1.27 2000/07/04 16:31:53 petere Exp $ * *------------------------------------------------------------------------- */ @@ -249,7 +249,7 @@ crypt_getloginfo(const char *user, char **passwd, char **valuntil) /*-------------------------------------------------------------------------*/ int -crypt_verify(Port *port, const char *user, const char *pgpass) +crypt_verify(const Port *port, const char *user, const char *pgpass) { char *passwd, diff --git a/src/backend/libpq/password.c b/src/backend/libpq/password.c index c7656f8b98fa078efb89f3ddbb04cefc0cfd1f57..6f47d5d4378021393985cbdeea6035c57194f4b6 100644 --- a/src/backend/libpq/password.c +++ b/src/backend/libpq/password.c @@ -2,7 +2,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: password.c,v 1.29 2000/06/02 15:57:21 momjian Exp $ + * $Id: password.c,v 1.30 2000/07/04 16:31:53 petere Exp $ * */ @@ -15,18 +15,19 @@ #include "libpq/libpq.h" #include "libpq/password.h" +#include "libpq/crypt.h" #include "miscadmin.h" int -verify_password(char *auth_arg, char *user, char *password) +verify_password(const Port *port, const char *user, const char *password) { char *pw_file_fullname; FILE *pw_file; - pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(auth_arg) + 2); + pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(port->auth_arg) + 2); strcpy(pw_file_fullname, DataDir); strcat(pw_file_fullname, "/"); - strcat(pw_file_fullname, auth_arg); + strcat(pw_file_fullname, port->auth_arg); pw_file = AllocateFile(pw_file_fullname, PG_BINARY_R); if (!pw_file) @@ -52,23 +53,32 @@ verify_password(char *auth_arg, char *user, char *password) *test_pw; fgets(pw_file_line, sizeof(pw_file_line), pw_file); + /* kill the newline */ + if (pw_file_line[strlen(pw_file_line) - 1] == '\n') + pw_file_line[strlen(pw_file_line) - 1] = '\0'; + p = pw_file_line; test_user = strtok(p, ":"); test_pw = strtok(NULL, ":"); - if (!test_user || !test_pw || - test_user[0] == '\0' || test_pw[0] == '\0') + if (!test_user || test_user[0] == '\0') continue; - /* kill the newline */ - if (test_pw[strlen(test_pw) - 1] == '\n') - test_pw[strlen(test_pw) - 1] = '\0'; - if (strcmp(user, test_user) == 0) { /* we're outta here one way or the other, so close file */ FreeFile(pw_file); + /* + * If the password is empty of "+" then we use the regular + * pg_shadow passwords. If we use crypt then we have to + * use pg_shadow passwords no matter what. + */ + if (port->auth_method == uaCrypt + || test_pw == NULL || test_pw[0] == '\0' + || strcmp(test_pw, "+")==0) + return crypt_verify(port, user, password); + if (strcmp(crypt(password, test_pw), test_pw) == 0) { /* it matched. */ diff --git a/src/bin/pg_passwd/pg_passwd.c b/src/bin/pg_passwd/pg_passwd.c index b8d1aae97ac55c61125789048aee4b88fd99bd32..50aa4011b5142b69ca072aa9f94bb7f96fa9b661 100644 --- a/src/bin/pg_passwd/pg_passwd.c +++ b/src/bin/pg_passwd/pg_passwd.c @@ -105,13 +105,9 @@ try_again: /* get user name */ p = line; - if ((q = strchr(p, ':')) == NULL) - { - fprintf(stderr, "%s: line %d: illegal format.\n", - filename, npwds + 1); - exit(1); - } - *(q++) = '\0'; + if ((q = strchr(p, ':')) != NULL) + *q = '\0'; + if (strlen(p) == 0) { fprintf(stderr, "%s: line %d: null user name.\n", @@ -131,23 +127,23 @@ try_again: } /* get password field */ - p = q; - q = strchr(p, ':'); - - /* - * --- don't care ----- if ((q = strchr(p, ':')) == NULL) { - * fprintf(stderr, "%s: line %d: illegal format.\n", filename, - * npwds + 1); exit(1); } - */ - - if (q != NULL) - *(q++) = '\0'; - if (strlen(p) != 13) + if (q) { - fprintf(stderr, "WARNING: %s: line %d: illegal password length.\n", - filename, npwds + 1); + p = q + 1; + q = strchr(p, ':'); + + if (q != NULL) + *(q++) = '\0'; + + if (strlen(p) != 13 && strcmp(p, "+")!=0) + { + fprintf(stderr, "WARNING: %s: line %d: invalid password length.\n", + filename, npwds + 1); + } + pwds[npwds].pwd = strdup(p); } - pwds[npwds].pwd = strdup(p); + else + pwds[npwds].pwd = NULL; /* rest of the line is treated as is */ if (q == NULL) @@ -193,9 +189,12 @@ link_again: /* write file */ for (i = 0; i < npwds; ++i) { - fprintf(fp, "%s:%s%s%s\n", pwds[i].uname, pwds[i].pwd, - pwds[i].rest ? ":" : "", - pwds[i].rest ? pwds[i].rest : ""); + fprintf(fp, "%s", pwds[i].uname); + if (pwds[i].pwd) + fprintf(fp, ":%s", pwds[i].pwd); + if (pwds[i].rest) + fprintf(fp, ":%s", pwds[i].rest); + fprintf(fp, "\n"); } fclose(fp); diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h index 7827b464081dd1b13c949d54ab4a5704dacebd0a..c3f58ee1639f07af38a03959e9eef1b1d0e705ba 100644 --- a/src/include/libpq/crypt.h +++ b/src/include/libpq/crypt.h @@ -26,6 +26,6 @@ extern char *crypt_getpwdreloadfilename(void); extern MsgType crypt_salt(const char *user); #endif -extern int crypt_verify(Port *port, const char *user, const char *pgpass); +extern int crypt_verify(const Port *port, const char *user, const char *pgpass); #endif diff --git a/src/include/libpq/password.h b/src/include/libpq/password.h index 9c7421d8935de54f0d4694a500c80782a0ca2019..c704edeb34539da2c3ffba0344448b02fbdb2ce5 100644 --- a/src/include/libpq/password.h +++ b/src/include/libpq/password.h @@ -1,6 +1,6 @@ #ifndef PASSWORD_H #define PASSWORD_H -int verify_password(char *auth_arg, char *user, char *password); +int verify_password(const Port *port, const char *user, const char *password); #endif