diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/commands/user.c | 369 | ||||
-rw-r--r-- | src/backend/libpq/Makefile | 6 | ||||
-rw-r--r-- | src/backend/libpq/auth.c | 24 | ||||
-rw-r--r-- | src/backend/libpq/crypt.c | 232 | ||||
-rw-r--r-- | src/backend/libpq/hba.c | 808 | ||||
-rw-r--r-- | src/backend/libpq/password.c | 109 | ||||
-rw-r--r-- | src/backend/libpq/pg_hba.conf.sample | 179 | ||||
-rw-r--r-- | src/backend/postmaster/postmaster.c | 16 | ||||
-rw-r--r-- | src/backend/utils/adt/quote.c | 6 | ||||
-rw-r--r-- | src/backend/utils/init/miscinit.c | 317 | ||||
-rw-r--r-- | src/bin/Makefile | 4 | ||||
-rw-r--r-- | src/bin/initdb/initdb.sh | 13 | ||||
-rw-r--r-- | src/bin/pg_passwd/Makefile | 37 | ||||
-rw-r--r-- | src/bin/pg_passwd/pg_passwd.c | 412 | ||||
-rw-r--r-- | src/include/catalog/pg_proc.h | 6 | ||||
-rw-r--r-- | src/include/commands/user.h | 12 | ||||
-rw-r--r-- | src/include/libpq/crypt.h | 7 | ||||
-rw-r--r-- | src/include/libpq/hba.h | 16 | ||||
-rw-r--r-- | src/include/miscadmin.h | 3 | ||||
-rw-r--r-- | src/test/regress/expected/opr_sanity.out | 2 | ||||
-rw-r--r-- | src/test/regress/sql/opr_sanity.sql | 2 |
21 files changed, 1138 insertions, 1442 deletions
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 98ee4308975..9ebd6fa3a2d 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.94 2002/03/26 19:15:48 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.95 2002/04/04 04:25:45 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -15,6 +15,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <errno.h> #include <unistd.h> #include "access/heapam.h" @@ -27,6 +28,7 @@ #include "libpq/crypt.h" #include "miscadmin.h" #include "storage/pmsignal.h" +#include "utils/acl.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/fmgroids.h" @@ -39,8 +41,205 @@ extern bool Password_encryption; static void CheckPgUserAclNotNull(void); -/*--------------------------------------------------------------------- - * write_password_file / update_pg_pwd + + +/* + * fputs_quote + * + * Outputs string in quotes, with double-quotes duplicated. + * We could use quote_ident(), but that expects varlena. + */ +static void fputs_quote(char *str, FILE *fp) +{ + fputc('"', fp); + while (*str) + { + fputc(*str, fp); + if (*str == '"') + fputc('"', fp); + str++; + } + fputc('"', fp); +} + + + +/* + * group_getfilename --- get full pathname of group file + * + * Note that result string is palloc'd, and should be freed by the caller. + */ +char * +group_getfilename(void) +{ + int bufsize; + char *pfnam; + + bufsize = strlen(DataDir) + strlen("/global/") + + strlen(USER_GROUP_FILE) + 1; + pfnam = (char *) palloc(bufsize); + snprintf(pfnam, bufsize, "%s/global/%s", DataDir, USER_GROUP_FILE); + + return pfnam; +} + + + +/* + * Get full pathname of password file. + * Note that result string is palloc'd, and should be freed by the caller. + */ +char * +user_getfilename(void) +{ + int bufsize; + char *pfnam; + + bufsize = strlen(DataDir) + strlen("/global/") + + strlen(PWD_FILE) + 1; + pfnam = (char *) palloc(bufsize); + snprintf(pfnam, bufsize, "%s/global/%s", DataDir, PWD_FILE); + + return pfnam; +} + + + +/* + * write_group_file for trigger update_pg_pwd_and_pg_group + */ +static void +write_group_file(Relation urel, Relation grel) +{ + char *filename, + *tempname; + int bufsize; + FILE *fp; + mode_t oumask; + HeapScanDesc scan; + HeapTuple tuple; + TupleDesc dsc = RelationGetDescr(grel); + + /* + * Create a temporary filename to be renamed later. This prevents the + * backend from clobbering the pg_group file while the postmaster might + * be reading from it. + */ + filename = group_getfilename(); + bufsize = strlen(filename) + 12; + tempname = (char *) palloc(bufsize); + + snprintf(tempname, bufsize, "%s.%d", filename, MyProcPid); + oumask = umask((mode_t) 077); + fp = AllocateFile(tempname, "w"); + umask(oumask); + if (fp == NULL) + elog(ERROR, "write_group_file: unable to write %s: %m", tempname); + + /* read table */ + scan = heap_beginscan(grel, false, SnapshotSelf, 0, NULL); + while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) + { + Datum datum, grolist_datum; + bool isnull; + char *groname; + IdList *grolist_p; + AclId *aidp; + int i, j, + num; + char *usename; + bool first_user = true; + + datum = heap_getattr(tuple, Anum_pg_group_groname, dsc, &isnull); + if (isnull) + continue; /* ignore NULL groupnames */ + groname = (char *) DatumGetName(datum); + + grolist_datum = heap_getattr(tuple, Anum_pg_group_grolist, dsc, &isnull); + /* Ignore NULL group lists */ + if (isnull) + continue; + + grolist_p = DatumGetIdListP(grolist_datum); + /* + * Check for illegal characters in the group name. + */ + i = strcspn(groname, "\n"); + if (groname[i] != '\0') + { + elog(LOG, "Invalid group name '%s'", groname); + continue; + } + + /* be sure the IdList is not toasted */ + /* scan it */ + num = IDLIST_NUM(grolist_p); + aidp = IDLIST_DAT(grolist_p); + for (i = 0; i < num; ++i) + { + tuple = SearchSysCache(SHADOWSYSID, + PointerGetDatum(aidp[i]), + 0, 0, 0); + if (HeapTupleIsValid(tuple)) + { + usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename); + + /* + * Check for illegal characters in the user name. + */ + j = strcspn(usename, "\n"); + if (usename[j] != '\0') + { + elog(LOG, "Invalid user name '%s'", usename); + continue; + } + + /* File format is: + * "dbname" "user1","user2","user3" + * This matches pg_hba.conf. + */ + if (first_user) + { + fputs_quote(groname, fp); + fputs("\t", fp); + } + else + fputs(" ", fp); + + first_user = false; + fputs_quote(usename, fp); + + ReleaseSysCache(tuple); + } + } + if (!first_user) + fputs("\n", fp); + /* if IdList was toasted, free detoasted copy */ + if ((Pointer) grolist_p != DatumGetPointer(grolist_datum)) + pfree(grolist_p); + } + heap_endscan(scan); + + fflush(fp); + if (ferror(fp)) + elog(ERROR, "%s: %m", tempname); + FreeFile(fp); + + /* + * Rename the temp file to its final name, deleting the old pg_pwd. We + * expect that rename(2) is an atomic action. + */ + if (rename(tempname, filename)) + elog(ERROR, "rename %s to %s: %m", tempname, filename); + + pfree((void *) tempname); + pfree((void *) filename); +} + + + +/* + * write_password_file for trigger update_pg_pwd_and_pg_group * * copy the modified contents of pg_shadow to a file used by the postmaster * for user authentication. The file is stored as $PGDATA/global/pg_pwd. @@ -51,10 +250,9 @@ static void CheckPgUserAclNotNull(void); * We raise an error to force transaction rollback if we detect an illegal * username or password --- illegal being defined as values that would * mess up the pg_pwd parser. - *--------------------------------------------------------------------- */ static void -write_password_file(Relation rel) +write_user_file(Relation urel) { char *filename, *tempname; @@ -63,14 +261,14 @@ write_password_file(Relation rel) mode_t oumask; HeapScanDesc scan; HeapTuple tuple; - TupleDesc dsc = RelationGetDescr(rel); + TupleDesc dsc = RelationGetDescr(urel); /* * Create a temporary filename to be renamed later. This prevents the * backend from clobbering the pg_pwd file while the postmaster might * be reading from it. */ - filename = crypt_getpwdfilename(); + filename = user_getfilename(); bufsize = strlen(filename) + 12; tempname = (char *) palloc(bufsize); @@ -82,26 +280,22 @@ write_password_file(Relation rel) elog(ERROR, "write_password_file: unable to write %s: %m", tempname); /* read table */ - scan = heap_beginscan(rel, false, SnapshotSelf, 0, NULL); + scan = heap_beginscan(urel, false, SnapshotSelf, 0, NULL); while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) { - Datum datum_n, - datum_p, - datum_v; - bool null_n, - null_p, - null_v; - char *str_n, - *str_p, - *str_v; + Datum datum; + bool isnull; + char *usename, + *passwd, + *valuntil; int i; - datum_n = heap_getattr(tuple, Anum_pg_shadow_usename, dsc, &null_n); - if (null_n) + datum = heap_getattr(tuple, Anum_pg_shadow_usename, dsc, &isnull); + if (isnull) continue; /* ignore NULL usernames */ - str_n = DatumGetCString(DirectFunctionCall1(nameout, datum_n)); + usename = (char *) DatumGetName(datum); - datum_p = heap_getattr(tuple, Anum_pg_shadow_passwd, dsc, &null_p); + datum = heap_getattr(tuple, Anum_pg_shadow_passwd, dsc, &isnull); /* * It can be argued that people having a null password shouldn't @@ -110,57 +304,40 @@ write_password_file(Relation rel) * assuming an empty password in that case is better, change this * logic to look something like the code for valuntil. */ - if (null_p) - { - pfree(str_n); + if (isnull) continue; - } - str_p = DatumGetCString(DirectFunctionCall1(textout, datum_p)); - datum_v = heap_getattr(tuple, Anum_pg_shadow_valuntil, dsc, &null_v); - if (null_v) - str_v = pstrdup("\\N"); + passwd = DatumGetCString(DirectFunctionCall1(textout, datum)); + + datum = heap_getattr(tuple, Anum_pg_shadow_valuntil, dsc, &isnull); + if (isnull) + valuntil = pstrdup(""); else - str_v = DatumGetCString(DirectFunctionCall1(nabstimeout, datum_v)); + valuntil = DatumGetCString(DirectFunctionCall1(nabstimeout, datum)); /* * Check for illegal characters in the username and password. */ - i = strcspn(str_n, CRYPT_PWD_FILE_SEPSTR "\n"); - if (str_n[i] != '\0') - elog(ERROR, "Invalid user name '%s'", str_n); - i = strcspn(str_p, CRYPT_PWD_FILE_SEPSTR "\n"); - if (str_p[i] != '\0') - elog(ERROR, "Invalid user password '%s'", str_p); + i = strcspn(usename, "\n"); + if (usename[i] != '\0') + elog(ERROR, "Invalid user name '%s'", usename); + i = strcspn(passwd, "\n"); + if (passwd[i] != '\0') + elog(ERROR, "Invalid user password '%s'", passwd); /* * The extra columns we emit here are not really necessary. To * remove them, the parser in backend/libpq/crypt.c would need to * be adjusted. */ - fprintf(fp, - "%s" - CRYPT_PWD_FILE_SEPSTR - "0" - CRYPT_PWD_FILE_SEPSTR - "x" - CRYPT_PWD_FILE_SEPSTR - "x" - CRYPT_PWD_FILE_SEPSTR - "x" - CRYPT_PWD_FILE_SEPSTR - "x" - CRYPT_PWD_FILE_SEPSTR - "%s" - CRYPT_PWD_FILE_SEPSTR - "%s\n", - str_n, - str_p, - str_v); - - pfree(str_n); - pfree(str_p); - pfree(str_v); + fputs_quote(usename, fp); + fputs(" ", fp); + fputs_quote(passwd, fp); + fputs(" ", fp); + fputs_quote(valuntil, fp); + + pfree(passwd); + pfree(valuntil); } heap_endscan(scan); @@ -178,29 +355,33 @@ write_password_file(Relation rel) pfree((void *) tempname); pfree((void *) filename); - - /* - * Signal the postmaster to reload its password-file cache. - */ - SendPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE); } /* This is the wrapper for triggers. */ Datum -update_pg_pwd(PG_FUNCTION_ARGS) +update_pg_pwd_and_pg_group(PG_FUNCTION_ARGS) { /* * ExclusiveLock ensures no one modifies pg_shadow while we read it, * and that only one backend rewrites the flat file at a time. It's * OK to allow normal reads of pg_shadow in parallel, however. */ - Relation rel = heap_openr(ShadowRelationName, ExclusiveLock); + Relation urel = heap_openr(ShadowRelationName, ExclusiveLock); + Relation grel = heap_openr(GroupRelationName, ExclusiveLock); - write_password_file(rel); + write_user_file(urel); + write_group_file(urel, grel); /* OK to release lock, since we did not modify the relation */ - heap_close(rel, ExclusiveLock); + heap_close(grel, ExclusiveLock); + heap_close(urel, ExclusiveLock); + + /* + * Signal the postmaster to reload its password & group-file cache. + */ + SendPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE); + return PointerGetDatum(NULL); } @@ -446,14 +627,14 @@ CreateUser(CreateUserStmt *stmt) } /* - * Write the updated pg_shadow data to the flat password file. + * Now we can clean up; but keep lock until commit. */ - write_password_file(pg_shadow_rel); + heap_close(pg_shadow_rel, NoLock); /* - * Now we can clean up; but keep lock until commit. + * Write the updated pg_shadow and pg_group data to the flat file. */ - heap_close(pg_shadow_rel, NoLock); + update_pg_pwd_and_pg_group(NULL); } @@ -680,14 +861,14 @@ AlterUser(AlterUserStmt *stmt) heap_freetuple(new_tuple); /* - * Write the updated pg_shadow data to the flat password file. + * Now we can clean up. */ - write_password_file(pg_shadow_rel); + heap_close(pg_shadow_rel, NoLock); /* - * Now we can clean up. + * Write the updated pg_shadow and pg_group data to the flat file. */ - heap_close(pg_shadow_rel, NoLock); + update_pg_pwd_and_pg_group(NULL); } @@ -733,7 +914,7 @@ AlterUserSet(AlterUserSetStmt *stmt) { Datum datum; bool isnull; - ArrayType *a; + ArrayType *array; repl_null[Anum_pg_shadow_useconfig-1] = ' '; @@ -741,17 +922,17 @@ AlterUserSet(AlterUserSetStmt *stmt) Anum_pg_shadow_useconfig, &isnull); if (valuestr) - a = GUCArrayAdd(isnull + array = GUCArrayAdd(isnull ? NULL : (ArrayType *) pg_detoast_datum((struct varlena *)datum), stmt->variable, valuestr); else - a = GUCArrayDelete(isnull + array = GUCArrayDelete(isnull ? NULL : (ArrayType *) pg_detoast_datum((struct varlena *)datum), stmt->variable); - repl_val[Anum_pg_shadow_useconfig-1] = PointerGetDatum(a); + repl_val[Anum_pg_shadow_useconfig-1] = PointerGetDatum(array); } newtuple = heap_modifytuple(oldtuple, rel, repl_val, repl_null, repl_repl); @@ -846,7 +1027,7 @@ DropUser(DropUserStmt *stmt) datum = heap_getattr(tmp_tuple, Anum_pg_database_datname, pg_dsc, &null); Assert(!null); - dbname = DatumGetCString(DirectFunctionCall1(nameout, datum)); + dbname = (char *) DatumGetName(datum); elog(ERROR, "DROP USER: user \"%s\" owns database \"%s\", cannot be removed%s", user, dbname, (length(stmt->users) > 1) ? " (no users removed)" : ""); @@ -901,14 +1082,14 @@ DropUser(DropUserStmt *stmt) } /* - * Write the updated pg_shadow data to the flat password file. + * Now we can clean up. */ - write_password_file(pg_shadow_rel); + heap_close(pg_shadow_rel, NoLock); /* - * Now we can clean up. + * Write the updated pg_shadow and pg_group data to the flat file. */ - heap_close(pg_shadow_rel, NoLock); + update_pg_pwd_and_pg_group(NULL); } @@ -1111,6 +1292,11 @@ CreateGroup(CreateGroupStmt *stmt) } heap_close(pg_group_rel, NoLock); + + /* + * Write the updated pg_shadow and pg_group data to the flat file. + */ + update_pg_pwd_and_pg_group(NULL); } @@ -1366,7 +1552,15 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag) ReleaseSysCache(group_tuple); + /* + * Write the updated pg_shadow and pg_group data to the flat files. + */ heap_close(pg_group_rel, NoLock); + + /* + * Write the updated pg_shadow and pg_group data to the flat file. + */ + update_pg_pwd_and_pg_group(NULL); } @@ -1419,4 +1613,9 @@ DropGroup(DropGroupStmt *stmt) elog(ERROR, "DROP GROUP: group \"%s\" does not exist", stmt->name); heap_close(pg_group_rel, NoLock); + + /* + * Write the updated pg_shadow and pg_group data to the flat file. + */ + update_pg_pwd_and_pg_group(NULL); } diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile index f5c2339f1c3..d0f05e802d9 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.29 2002/03/04 01:46:02 tgl Exp $ +# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.30 2002/04/04 04:25:46 momjian Exp $ # #------------------------------------------------------------------------- @@ -14,9 +14,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 md5.o password.o \ - pqcomm.o pqformat.o pqsignal.o +OBJS = be-fsstubs.o auth.o crypt.o hba.o md5.o pqcomm.o pqformat.o pqsignal.o all: SUBSYS.o diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 637e2a623eb..81a494905ea 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.79 2002/03/05 07:57:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.80 2002/04/04 04:25:47 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -34,7 +34,6 @@ #include "miscadmin.h" static void sendAuthRequest(Port *port, AuthRequest areq); -static int checkPassword(Port *port, char *user, char *password); static int old_be_recvauth(Port *port); static int map_old_to_new(Port *port, UserAuth old, int status); static void auth_failed(Port *port, int status); @@ -381,7 +380,7 @@ recv_and_check_passwordv0(Port *port) saved = port->auth_method; port->auth_method = uaPassword; - status = checkPassword(port, user, password); + status = md5_crypt_verify(port, user, password); port->auth_method = saved; @@ -663,7 +662,7 @@ pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_re initStringInfo(&buf); pq_getstr(&buf); - + /* Do not echo failed password to logs, for security. */ elog(DEBUG5, "received PAM packet"); @@ -810,27 +809,14 @@ recv_and_check_password_packet(Port *port) /* Do not echo failed password to logs, for security. */ elog(DEBUG5, "received password packet"); - result = checkPassword(port, port->user, buf.data); + result = md5_crypt_verify(port, port->user, buf.data); + pfree(buf.data); return result; } /* - * 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_arg[0] != '\0') - return verify_password(port, user, password); - - return md5_crypt_verify(port, user, password); -} - - -/* * Server demux routine for incoming authentication information for protocol * version 0. */ diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index 6ab63ddffe0..7c665300c85 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -9,13 +9,12 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.44 2002/03/04 01:46:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.45 2002/04/04 04:25:47 momjian Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include <errno.h> #include <unistd.h> #ifdef HAVE_CRYPT_H #include <crypt.h> @@ -25,231 +24,10 @@ #include "libpq/libpq.h" #include "miscadmin.h" #include "storage/fd.h" +#include "nodes/pg_list.h" #include "utils/nabstime.h" -#define CRYPT_PWD_FILE "pg_pwd" - - -static char **pwd_cache = NULL; -static int pwd_cache_count = 0; - -/* - * crypt_getpwdfilename --- get full pathname of password file - * - * Note that result string is palloc'd, and should be freed by the caller. - */ -char * -crypt_getpwdfilename(void) -{ - int bufsize; - char *pfnam; - - bufsize = strlen(DataDir) + 8 + strlen(CRYPT_PWD_FILE) + 1; - pfnam = (char *) palloc(bufsize); - snprintf(pfnam, bufsize, "%s/global/%s", DataDir, CRYPT_PWD_FILE); - - return pfnam; -} - -/* - * Open the password file if possible (return NULL if not) - */ -static FILE * -crypt_openpwdfile(void) -{ - char *filename; - FILE *pwdfile; - - filename = crypt_getpwdfilename(); - pwdfile = AllocateFile(filename, "r"); - - if (pwdfile == NULL && errno != ENOENT) - elog(LOG, "could not open %s: %m", filename); - - pfree(filename); - - return pwdfile; -} - -/* - * Compare two password-file lines on the basis of their usernames. - * - * Can also be used to compare just a username against a password-file - * line (for bsearch). - */ -static int -compar_user(const void *user_a, const void *user_b) -{ - char *login_a; - char *login_b; - int len_a, - len_b, - result; - - login_a = *((char **) user_a); - login_b = *((char **) user_b); - - /* - * We only really want to compare the user logins which are first and - * are terminated by CRYPT_PWD_FILE_SEPSTR. (NB: this code - * effectively assumes that CRYPT_PWD_FILE_SEPSTR is just one char.) - */ - len_a = strcspn(login_a, CRYPT_PWD_FILE_SEPSTR); - len_b = strcspn(login_b, CRYPT_PWD_FILE_SEPSTR); - - result = strncmp(login_a, login_b, Min(len_a, len_b)); - - if (result == 0) /* one could be a prefix of the other */ - result = (len_a - len_b); - - return result; -} - -/* - * Load or reload the password-file cache - */ -void -load_password_cache(void) -{ - FILE *pwd_file; - char buffer[1024]; - - /* - * If for some reason we fail to open the password file, preserve the - * old cache contents; this seems better than dropping the cache if, - * say, we are temporarily out of filetable slots. - */ - if (!(pwd_file = crypt_openpwdfile())) - return; - - /* free any old data */ - if (pwd_cache) - { - while (--pwd_cache_count >= 0) - pfree(pwd_cache[pwd_cache_count]); - pfree(pwd_cache); - pwd_cache = NULL; - pwd_cache_count = 0; - } - - /* - * Read the file and store its lines in current memory context, which - * we expect will be PostmasterContext. That context will live as - * long as we need the cache to live, ie, until just after each - * postmaster child has completed client authentication. - */ - while (fgets(buffer, sizeof(buffer), pwd_file) != NULL) - { - int blen; - - /* - * We must remove the return char at the end of the string, as - * this will affect the correct parsing of the password entry. - */ - if (buffer[(blen = strlen(buffer) - 1)] == '\n') - buffer[blen] = '\0'; - - if (pwd_cache == NULL) - pwd_cache = (char **) - palloc(sizeof(char *) * (pwd_cache_count + 1)); - else - pwd_cache = (char **) - repalloc((void *) pwd_cache, - sizeof(char *) * (pwd_cache_count + 1)); - pwd_cache[pwd_cache_count++] = pstrdup(buffer); - } - - FreeFile(pwd_file); - - /* - * Now sort the entries in the cache for faster searching later. - */ - qsort((void *) pwd_cache, pwd_cache_count, sizeof(char *), compar_user); -} - -/* - * Parse a line of the password file to extract password and valid-until date. - */ -static bool -crypt_parsepwdentry(char *buffer, char **pwd, char **valdate) -{ - char *parse = buffer; - int count, - i; - - *pwd = NULL; - *valdate = NULL; - - /* - * skip to the password field - */ - for (i = 0; i < 6; i++) - { - parse += strcspn(parse, CRYPT_PWD_FILE_SEPSTR); - if (*parse == '\0') - return false; - parse++; - } - - /* - * store a copy of user password to return - */ - count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR); - *pwd = (char *) palloc(count + 1); - memcpy(*pwd, parse, count); - (*pwd)[count] = '\0'; - parse += count; - if (*parse == '\0') - { - pfree(*pwd); - *pwd = NULL; - return false; - } - parse++; - - /* - * store a copy of the date login becomes invalid - */ - count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR); - *valdate = (char *) palloc(count + 1); - memcpy(*valdate, parse, count); - (*valdate)[count] = '\0'; - - return true; -} - -/* - * Lookup a username in the password-file cache, - * return his password and valid-until date. - */ -static bool -crypt_getloginfo(const char *user, char **passwd, char **valuntil) -{ - *passwd = NULL; - *valuntil = NULL; - - if (pwd_cache) - { - char **pwd_entry; - - pwd_entry = (char **) bsearch((void *) &user, - (void *) pwd_cache, - pwd_cache_count, - sizeof(char *), - compar_user); - if (pwd_entry) - { - if (crypt_parsepwdentry(*pwd_entry, passwd, valuntil)) - return true; - } - } - - return false; -} - -/*-------------------------------------------------------------------------*/ - int md5_crypt_verify(const Port *port, const char *user, const char *pgpass) { @@ -257,10 +35,14 @@ md5_crypt_verify(const Port *port, const char *user, const char *pgpass) *valuntil, *crypt_pwd; int retval = STATUS_ERROR; + List **line; - if (!crypt_getloginfo(user, &passwd, &valuntil)) + if ((line = get_user_line(user)) == NULL) return STATUS_ERROR; + passwd = lfirst(lnext(lnext(*line))); + valuntil = lfirst(lnext(lnext(lnext(*line)))); + if (passwd == NULL || *passwd == '\0') { if (passwd) diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index b86cb817302..fce63ab2436 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.80 2002/03/04 01:46:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.81 2002/04/04 04:25:47 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -30,18 +30,20 @@ #include <arpa/inet.h> #include <unistd.h> +#include "commands/user.h" +#include "libpq/crypt.h" #include "libpq/libpq.h" #include "miscadmin.h" #include "nodes/pg_list.h" #include "storage/fd.h" -#define MAX_TOKEN 80 -/* Maximum size of one token in the configuration file */ - #define IDENT_USERNAME_MAX 512 /* Max size of username ident server can return */ +/* This is used to separate values in multi-valued column strings */ +#define MULTI_VALUE_SEP "\001" + /* * These variables hold the pre-parsed contents of the hba and ident * configuration files. Each is a list of sublists, one sublist for @@ -53,7 +55,17 @@ */ static List *hba_lines = NIL; /* pre-parsed contents of hba file */ static List *ident_lines = NIL; /* pre-parsed contents of ident file */ +static List *group_lines = NIL; /* pre-parsed contents of group file */ +static List *user_lines = NIL; /* pre-parsed contents of user password file */ + +/* sorted entries so we can do binary search lookups */ +static List **user_sorted = NULL; /* sorted user list, for bsearch() */ +static List **group_sorted = NULL; /* sorted group list, for bsearch() */ +static int user_length; +static int group_length; +static List *tokenize_file(FILE *file); +static char *tokenize_inc_file(const char *inc_filename); /* * Some standard C libraries, including GNU, have an isblank() function. @@ -67,41 +79,76 @@ isblank(const char c) /* - * Grab one token out of fp. Tokens are strings of non-blank - * characters bounded by blank characters, beginning of line, and end - * of line. Blank means space or tab. Return the token as *buf. - * Leave file positioned to character immediately after the token or - * EOF, whichever comes first. If no more tokens on line, return null - * string as *buf and position file to beginning of next line or EOF, - * whichever comes first. + * Grab one token out of fp. Tokens are strings of non-blank + * characters bounded by blank characters, beginning of line, and + * end of line. Blank means space or tab. Return the token as + * *buf. Leave file positioned to character immediately after the + * token or EOF, whichever comes first. If no more tokens on line, + * return null string as *buf and position file to beginning of + * next line or EOF, whichever comes first. Allow spaces in quoted + * strings. Terminate on unquoted commas. Handle comments. */ -static void +void next_token(FILE *fp, char *buf, const int bufsz) { int c; - char *eb = buf + (bufsz - 1); + char *end_buf = buf + (bufsz - 1); + bool in_quote = false; + bool was_quote = false; - /* Move over initial token-delimiting blanks */ - while ((c = getc(fp)) != EOF && isblank(c)) + /* Move over initial whitespace and commas */ + while ((c = getc(fp)) != EOF && (isblank(c) || c == ',')) ; if (c != EOF && c != '\n') { /* - * build a token in buf of next characters up to EOF, eol, or - * blank. If the token gets too long, we still parse it - * correctly, but the excess characters are not stored into *buf. + * Build a token in buf of next characters up to EOF, EOL, unquoted + * comma, or unquoted whitespace. */ - while (c != EOF && c != '\n' && !isblank(c)) + while (c != EOF && c != '\n' && + (!isblank(c) || in_quote == true)) { - if (buf < eb) + if (c == '"') + in_quote = !in_quote; + + /* skip comments to EOL */ + if (c == '#' && !in_quote) + { + while ((c = getc(fp)) != EOF && c != '\n') + ; + continue; + } + + if (buf >= end_buf) + { + elog(LOG, "Token too long in authentication file, skipping, %s", buf); + /* Discard remainder of line */ + while ((c = getc(fp)) != EOF && c != '\n') + ; + buf[0] = '\0'; + break; + } + + if (c != '"' || (c == '"' && was_quote)) *buf++ = c; + + /* We pass back the comma so the caller knows there is more */ + if ((isblank(c) || c == ',') && !in_quote) + break; + + /* Literal double-quote is two double-quotes */ + if (c == '"') + was_quote = !was_quote; + else + was_quote = false; + c = getc(fp); } /* * Put back the char right after the token (critical in case it is - * eol, since we need to detect end-of-line at next call). + * EOL, since we need to detect end-of-line at next call). */ if (c != EOF) ungetc(c, fp); @@ -109,17 +156,142 @@ next_token(FILE *fp, char *buf, const int bufsz) *buf = '\0'; } +/* + * Tokenize file and handle file inclusion and comma lists. We have + * to break apart the commas to expand any file names then + * reconstruct with commas. + */ +static char * +next_token_expand(FILE *file) +{ + char buf[MAX_TOKEN]; + char *comma_str = pstrdup(""); + bool trailing_comma; + char *incbuf; + + do + { + next_token(file, buf, sizeof(buf)); + if (!*buf) + break; + + if (buf[strlen(buf)-1] == ',') + { + trailing_comma = true; + buf[strlen(buf)-1] = '\0'; + } + else + trailing_comma = false; + + /* Is this referencing a file? */ + if (buf[0] == '@') + incbuf = tokenize_inc_file(buf+1); + else + incbuf = pstrdup(buf); + + comma_str = repalloc(comma_str, + strlen(comma_str) + strlen(incbuf) + 1); + strcat(comma_str, incbuf); + pfree(incbuf); + + if (trailing_comma) + { + comma_str = repalloc(comma_str, strlen(comma_str) + 1 + 1); + strcat(comma_str, MULTI_VALUE_SEP); + } + } while (trailing_comma); + + return comma_str; +} + +/* + * Free memory used by lines/tokens (i.e., structure built by tokenize_file) + */ static void -read_through_eol(FILE *file) +free_lines(List **lines) { - int c; + if (*lines) + { + List *line, + *token; - while ((c = getc(file)) != EOF && c != '\n') - ; + foreach(line, *lines) + { + List *ln = lfirst(line); + + /* free the pstrdup'd tokens (don't try it on the line number) */ + foreach(token, lnext(ln)) + pfree(lfirst(token)); + /* free the sublist structure itself */ + freeList(ln); + } + /* free the list structure itself */ + freeList(*lines); + /* clear the static variable */ + *lines = NIL; + } +} + + +static char * +tokenize_inc_file(const char *inc_filename) +{ + char *inc_fullname; + FILE *inc_file; + List *inc_lines; + List *line; + char *comma_str = pstrdup(""); + + inc_fullname = (char *) palloc(strlen(DataDir) + 1 + + strlen(inc_filename) + 1); + strcpy(inc_fullname, DataDir); + strcat(inc_fullname, "/"); + strcat(inc_fullname, inc_filename); + + inc_file = AllocateFile(inc_fullname, "r"); + if (!inc_file) + { + elog(LOG, "tokenize_inc_file: Unable to open secondary authentication file \"@%s\" as \"%s\": %m", + inc_filename, inc_fullname); + pfree(inc_fullname); + + /* return empty string, it matches nothing */ + return pstrdup(""); + } + pfree(inc_fullname); + + /* There is possible recursion here if the file contains @ */ + inc_lines = tokenize_file(inc_file); + FreeFile(inc_file); + + /* Create comma-separate string from List */ + foreach(line, inc_lines) + { + List *ln = lfirst(line); + List *token; + + /* First entry is line number */ + foreach(token, lnext(ln)) + { + if (strlen(comma_str)) + { + comma_str = repalloc(comma_str, strlen(comma_str) + 1); + strcat(comma_str, MULTI_VALUE_SEP); + } + comma_str = repalloc(comma_str, + strlen(comma_str) + strlen(lfirst(token)) + 1); + strcat(comma_str, lfirst(token)); + } + } + + free_lines(&inc_lines); + + return comma_str; } + /* * Read the given file and create a list of line sublists. */ @@ -129,19 +301,13 @@ tokenize_file(FILE *file) List *lines = NIL; List *next_line = NIL; int line_number = 1; - char buf[MAX_TOKEN]; - char *comment_ptr; + char *buf; while (!feof(file)) { - next_token(file, buf, sizeof(buf)); - - /* trim off comment, even if inside a token */ - comment_ptr = strchr(buf, '#'); - if (comment_ptr != NULL) - *comment_ptr = '\0'; + buf = next_token_expand(file); - /* add token to list, unless we are at eol or comment start */ + /* add token to list, unless we are at EOL or comment start */ if (buf[0] != '\0') { if (next_line == NIL) @@ -151,22 +317,15 @@ tokenize_file(FILE *file) lines = lappend(lines, next_line); } /* append token to current line's list */ - next_line = lappend(next_line, pstrdup(buf)); + next_line = lappend(next_line, buf); } else { - /* we are at real or logical eol, so force a new line List */ + /* we are at real or logical EOL, so force a new line List */ next_line = NIL; } - if (comment_ptr != NULL) - { - /* Found a comment, so skip the rest of the line */ - read_through_eol(file); - next_line = NIL; - } - - /* Advance line number whenever we reach eol */ + /* Advance line number whenever we reach EOL */ if (next_line == NIL) line_number++; } @@ -176,31 +335,116 @@ tokenize_file(FILE *file) /* - * Free memory used by lines/tokens (ie, structure built by tokenize_file) + * Compare two password-file lines on the basis of their user names. + * + * Used for qsort() sorting and bsearch() lookup. */ -static void -free_lines(List **lines) +static int +user_group_cmp(const void *user, const void *list) { - if (*lines) + /* first node is line number */ + char *user1 = (char *)user; + char *user2 = lfirst(lnext(*(List **)list)); + + return strcmp(user1, user2); +} + + +/* + * Lookup a group name in the pg_group file + */ +static List ** +get_group_line(const char *group) +{ + return (List **) bsearch((void *) group, + (void *) group_sorted, + group_length, + sizeof(List *), + user_group_cmp); +} + + +/* + * Lookup a user name in the pg_shadow file + */ +List ** +get_user_line(const char *user) +{ + return (List **) bsearch((void *) user, + (void *) user_sorted, + user_length, + sizeof(List *), + user_group_cmp); +} + + +/* + * Check group for a specific user. + */ +static int +check_group(char *group, char *user) +{ + List **line, *l; + + if ((line = get_group_line(group)) != NULL) { - List *line, - *token; + foreach(l, lnext(lnext(*line))) + if (strcmp(lfirst(l), user) == 0) + return 1; + } - foreach(line, *lines) + return 0; +} + +/* + * Check comma user list for a specific user, handle group names. + */ +static int +check_user(char *user, char *param_str) +{ + char *tok; + + for (tok = strtok(param_str, MULTI_VALUE_SEP); tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP)) + { + if (tok[0] == '+') { - List *ln = lfirst(line); + if (check_group(tok+1, user)) + return 1; + } + else if (strcmp(tok, user) == 0 || + strcmp(tok, "all") == 0) + return 1; + } - /* free the pstrdup'd tokens (don't try it on the line number) */ - foreach(token, lnext(ln)) - pfree(lfirst(token)); - /* free the sublist structure itself */ - freeList(ln); + return 0; +} + +/* + * Check to see if db/user combination matches param string. + */ +static int +check_db(char *dbname, char *user, char *param_str) +{ + char *tok; + + for (tok = strtok(param_str, MULTI_VALUE_SEP); tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP)) + { + if (strcmp(tok, "all") == 0) + return 1; + else if (strcmp(tok, "sameuser") == 0) + { + if (strcmp(dbname, user) == 0) + return 1; } - /* free the list structure itself */ - freeList(*lines); - /* clear the static variable */ - *lines = NIL; + else if (strcmp(tok, "samegroup") == 0) + { + if (check_group(dbname, user)) + return 1; + } + else if (strcmp(tok, dbname) == 0) + return 1; } + return 0; } @@ -278,6 +522,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) int line_number; char *token; char *db; + char *user; Assert(line != NIL); line_number = lfirsti(line); @@ -293,10 +538,17 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) goto hba_syntax; db = lfirst(line); - /* Read the rest of the line. */ + /* Get the user. */ + line = lnext(line); + if (!line) + goto hba_syntax; + user = lfirst(line); + line = lnext(line); if (!line) goto hba_syntax; + + /* Read the rest of the line. */ parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p); if (*error_p) goto hba_syntax; @@ -308,15 +560,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) port->auth_method == uaKrb5) goto hba_syntax; - /* - * If this record doesn't match the parameters of the connection - * attempt, ignore it. - */ - if ((strcmp(db, port->database) != 0 && - strcmp(db, "all") != 0 && - (strcmp(db, "sameuser") != 0 || - strcmp(port->database, port->user) != 0)) || - port->raddr.sa.sa_family != AF_UNIX) + if (port->raddr.sa.sa_family != AF_UNIX) return; } else if (strcmp(token, "host") == 0 || strcmp(token, "hostssl") == 0) @@ -347,6 +591,12 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) goto hba_syntax; db = lfirst(line); + /* Get the user. */ + line = lnext(line); + if (!line) + goto hba_syntax; + user = lfirst(line); + /* Read the IP address field. */ line = lnext(line); if (!line) @@ -371,21 +621,19 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) if (*error_p) goto hba_syntax; - /* - * If this record doesn't match the parameters of the connection - * attempt, ignore it. - */ - if ((strcmp(db, port->database) != 0 && - strcmp(db, "all") != 0 && - (strcmp(db, "sameuser") != 0 || - strcmp(port->database, port->user) != 0)) || - port->raddr.sa.sa_family != AF_INET || + /* Must meet network restrictions */ + if (port->raddr.sa.sa_family != AF_INET || ((file_ip_addr.s_addr ^ port->raddr.in.sin_addr.s_addr) & mask.s_addr) != 0) return; } else goto hba_syntax; + if (!check_db(port->database, port->user, db)) + return; + if (!check_user(port->user, user)) + return; + /* Success */ *found_p = true; return; @@ -430,6 +678,127 @@ check_hba(hbaPort *port) } + +/* + * Open the group file if possible (return NULL if not) + */ +static FILE * +group_openfile(void) +{ + char *filename; + FILE *groupfile; + + filename = group_getfilename(); + groupfile = AllocateFile(filename, "r"); + + if (groupfile == NULL && errno != ENOENT) + elog(LOG, "could not open %s: %m", filename); + + pfree(filename); + + return groupfile; +} + + + +/* + * Open the password file if possible (return NULL if not) + */ +static FILE * +user_openfile(void) +{ + char *filename; + FILE *pwdfile; + + filename = user_getfilename(); + pwdfile = AllocateFile(filename, "r"); + + if (pwdfile == NULL && errno != ENOENT) + elog(LOG, "could not open %s: %m", filename); + + pfree(filename); + + return pwdfile; +} + + + +/* + * Load group/user name mapping file + */ +void +load_group() +{ + FILE *group_file; + List *line; + + if (group_lines) + free_lines(&group_lines); + + group_file = group_openfile(); + if (!group_file) + return; + group_lines = tokenize_file(group_file); + FreeFile(group_file); + + /* create sorted lines for binary searching */ + if (group_sorted) + pfree(group_sorted); + group_length = length(group_lines); + if (group_length) + { + int i = 0; + + group_sorted = palloc(group_length * sizeof(List *)); + + foreach(line, group_lines) + group_sorted[i++] = lfirst(line); + + qsort((void *) group_sorted, group_length, sizeof(List *), user_group_cmp); + } + else + group_sorted = NULL; +} + + +/* + * Load user/password mapping file + */ +void +load_user() +{ + FILE *user_file; + List *line; + + if (user_lines) + free_lines(&user_lines); + + user_file = user_openfile(); + if (!user_file) + return; + user_lines = tokenize_file(user_file); + FreeFile(user_file); + + /* create sorted lines for binary searching */ + if (user_sorted) + pfree(user_sorted); + user_length = length(user_lines); + if (user_length) + { + int i = 0; + + user_sorted = palloc(user_length * sizeof(List *)); + + foreach(line, user_lines) + user_sorted[i++] = lfirst(line); + + qsort((void *) user_sorted, user_length, sizeof(List *), user_group_cmp); + } + else + user_sorted = NULL; +} + + /* * Read the config file and create a List of Lists of tokens in the file. * If we find a file by the old name of the config file (pg_hba), we issue @@ -437,60 +806,35 @@ check_hba(hbaPort *port) * follow directions and just installed his old hba file in the new database * system. */ -static void +void load_hba(void) { - int fd, - bufsize; + int bufsize; FILE *file; /* The config file we have to read */ - char *old_conf_file; + char *conf_file; /* The name of the config file */ if (hba_lines) free_lines(&hba_lines); - /* - * The name of old config file that better not exist. Fail if config - * file by old name exists. Put together the full pathname to the old - * config file. - */ - bufsize = (strlen(DataDir) + strlen(OLD_CONF_FILE) + 2) * sizeof(char); - old_conf_file = (char *) palloc(bufsize); - snprintf(old_conf_file, bufsize, "%s/%s", DataDir, OLD_CONF_FILE); + /* Put together the full pathname to the config file. */ + bufsize = (strlen(DataDir) + strlen(CONF_FILE) + 2) * sizeof(char); + conf_file = (char *) palloc(bufsize); + snprintf(conf_file, bufsize, "%s/%s", DataDir, CONF_FILE); - if ((fd = open(old_conf_file, O_RDONLY | PG_BINARY, 0)) != -1) + file = AllocateFile(conf_file, "r"); + if (file == NULL) { - /* Old config file exists. Tell this guy he needs to upgrade. */ - close(fd); - elog(LOG, "A file exists by the name used for host-based authentication " - "in prior releases of Postgres (%s). The name and format of " - "the configuration file have changed, so this file should be " - "converted.", old_conf_file); + /* The open of the config file failed. */ + elog(LOG, "load_hba: Unable to open authentication config file \"%s\": %m", + conf_file); + pfree(conf_file); } else { - char *conf_file; /* The name of the config file we have to - * read */ - - /* put together the full pathname to the config file */ - bufsize = (strlen(DataDir) + strlen(CONF_FILE) + 2) * sizeof(char); - conf_file = (char *) palloc(bufsize); - snprintf(conf_file, bufsize, "%s/%s", DataDir, CONF_FILE); - - file = AllocateFile(conf_file, "r"); - if (file == NULL) - { - /* The open of the config file failed. */ - elog(LOG, "load_hba: Unable to open authentication config file \"%s\": %m", - conf_file); - } - else - { - hba_lines = tokenize_file(file); - FreeFile(file); - } - pfree(conf_file); + hba_lines = tokenize_file(file); + FreeFile(file); } - pfree(old_conf_file); + pfree(conf_file); } @@ -606,7 +950,7 @@ check_ident_usermap(const char *usermap_name, /* * Read the ident config file and create a List of Lists of tokens in the file. */ -static void +void load_ident(void) { FILE *file; /* The map file we have to read */ @@ -622,7 +966,7 @@ load_ident(void) map_file = (char *) palloc(bufsize); snprintf(map_file, bufsize, "%s/%s", DataDir, USERMAP_FILE); - file = AllocateFile(map_file, PG_BINARY_R); + file = AllocateFile(map_file, "r"); if (file == NULL) { /* The open of the map file failed. */ @@ -640,8 +984,8 @@ load_ident(void) /* * Parse the string "*ident_response" as a response from a query to an Ident - * server. If it's a normal response indicating a username, return true - * and store the username at *ident_user. If it's anything else, + * server. If it's a normal response indicating a user name, return true + * and store the user name at *ident_user. If it's anything else, * return false. */ static bool @@ -708,7 +1052,7 @@ interpret_ident_response(char *ident_response, cursor++; /* Go over colon */ while (isblank(*cursor)) cursor++; /* skip blanks */ - /* Rest of line is username. Copy it over. */ + /* Rest of line is user name. Copy it over. */ i = 0; while (*cursor != '\r' && i < IDENT_USERNAME_MAX) ident_user[i++] = *cursor++; @@ -725,7 +1069,7 @@ interpret_ident_response(char *ident_response, /* * Talk to the ident server on host "remote_ip_addr" and find out who * owns the tcp connection from his port "remote_port" to port - * "local_port_addr" on host "local_ip_addr". Return the username the + * "local_port_addr" on host "local_ip_addr". Return the user name the * ident server gives as "*ident_user". * * IP addresses and port numbers are in network byte order. @@ -955,6 +1299,8 @@ ident_unix(int sock, char *ident_user) #endif } + + /* * Determine the username of the initiator of the connection described * by "port". Then look in the usermap file under the usermap @@ -1010,211 +1356,3 @@ hba_getauthmethod(hbaPort *port) return STATUS_ERROR; } -/* - * Clear and reload tokenized file contents. - */ -void -load_hba_and_ident(void) -{ - load_hba(); - load_ident(); -} - - -/* Character set stuff. Not sure it really belongs in this file. */ - -#ifdef CYR_RECODE - -#define CHARSET_FILE "charset.conf" -#define MAX_CHARSETS 10 -#define KEY_HOST 1 -#define KEY_BASE 2 -#define KEY_TABLE 3 - -struct CharsetItem -{ - char Orig[MAX_TOKEN]; - char Dest[MAX_TOKEN]; - char Table[MAX_TOKEN]; -}; - - -static bool -CharSetInRange(char *buf, int host) -{ - int valid, - i, - FromAddr, - ToAddr, - tmp; - struct in_addr file_ip_addr; - char *p; - unsigned int one = 0x80000000, - NetMask = 0; - unsigned char mask; - - p = strchr(buf, '/'); - if (p) - { - *p++ = '\0'; - valid = inet_aton(buf, &file_ip_addr); - if (valid) - { - mask = strtoul(p, 0, 0); - FromAddr = ntohl(file_ip_addr.s_addr); - ToAddr = ntohl(file_ip_addr.s_addr); - for (i = 0; i < mask; i++) - { - NetMask |= one; - one >>= 1; - } - FromAddr &= NetMask; - ToAddr = ToAddr | ~NetMask; - tmp = ntohl(host); - return ((unsigned) tmp >= (unsigned) FromAddr && - (unsigned) tmp <= (unsigned) ToAddr); - } - } - else - { - p = strchr(buf, '-'); - if (p) - { - *p++ = '\0'; - valid = inet_aton(buf, &file_ip_addr); - if (valid) - { - FromAddr = ntohl(file_ip_addr.s_addr); - valid = inet_aton(p, &file_ip_addr); - if (valid) - { - ToAddr = ntohl(file_ip_addr.s_addr); - tmp = ntohl(host); - return ((unsigned) tmp >= (unsigned) FromAddr && - (unsigned) tmp <= (unsigned) ToAddr); - } - } - } - else - { - valid = inet_aton(buf, &file_ip_addr); - if (valid) - { - FromAddr = file_ip_addr.s_addr; - return (unsigned) FromAddr == (unsigned) host; - } - } - } - return false; -} - -void -GetCharSetByHost(char *TableName, int host, const char *DataDir) -{ - FILE *file; - char buf[MAX_TOKEN], - BaseCharset[MAX_TOKEN], - OrigCharset[MAX_TOKEN], - DestCharset[MAX_TOKEN], - HostCharset[MAX_TOKEN], - *map_file; - int key, - ChIndex = 0, - c, - i, - bufsize; - struct CharsetItem *ChArray[MAX_CHARSETS]; - - *TableName = '\0'; - bufsize = (strlen(DataDir) + strlen(CHARSET_FILE) + 2) * sizeof(char); - map_file = (char *) palloc(bufsize); - snprintf(map_file, bufsize, "%s/%s", DataDir, CHARSET_FILE); - file = AllocateFile(map_file, PG_BINARY_R); - pfree(map_file); - if (file == NULL) - { - /* XXX should we log a complaint? */ - return; - } - while ((c = getc(file)) != EOF) - { - if (c == '#') - read_through_eol(file); - else - { - /* Read the key */ - ungetc(c, file); - next_token(file, buf, sizeof(buf)); - if (buf[0] != '\0') - { - key = 0; - if (strcasecmp(buf, "HostCharset") == 0) - key = KEY_HOST; - if (strcasecmp(buf, "BaseCharset") == 0) - key = KEY_BASE; - if (strcasecmp(buf, "RecodeTable") == 0) - key = KEY_TABLE; - switch (key) - { - case KEY_HOST: - /* Read the host */ - next_token(file, buf, sizeof(buf)); - if (buf[0] != '\0') - { - if (CharSetInRange(buf, host)) - { - /* Read the charset */ - next_token(file, buf, sizeof(buf)); - if (buf[0] != '\0') - strcpy(HostCharset, buf); - } - } - break; - case KEY_BASE: - /* Read the base charset */ - next_token(file, buf, sizeof(buf)); - if (buf[0] != '\0') - strcpy(BaseCharset, buf); - break; - case KEY_TABLE: - /* Read the original charset */ - next_token(file, buf, sizeof(buf)); - if (buf[0] != '\0') - { - strcpy(OrigCharset, buf); - /* Read the destination charset */ - next_token(file, buf, sizeof(buf)); - if (buf[0] != '\0') - { - strcpy(DestCharset, buf); - /* Read the table filename */ - next_token(file, buf, sizeof(buf)); - if (buf[0] != '\0') - { - ChArray[ChIndex] = - (struct CharsetItem *) palloc(sizeof(struct CharsetItem)); - strcpy(ChArray[ChIndex]->Orig, OrigCharset); - strcpy(ChArray[ChIndex]->Dest, DestCharset); - strcpy(ChArray[ChIndex]->Table, buf); - ChIndex++; - } - } - } - break; - } - read_through_eol(file); - } - } - } - FreeFile(file); - - for (i = 0; i < ChIndex; i++) - { - if (strcasecmp(BaseCharset, ChArray[i]->Orig) == 0 && - strcasecmp(HostCharset, ChArray[i]->Dest) == 0) - strncpy(TableName, ChArray[i]->Table, 79); - pfree(ChArray[i]); - } -} - -#endif /* CYR_RECODE */ diff --git a/src/backend/libpq/password.c b/src/backend/libpq/password.c deleted file mode 100644 index f8490f8bd57..00000000000 --- a/src/backend/libpq/password.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * $Id: password.c,v 1.41 2002/03/04 01:46:03 tgl Exp $ - * - */ - -#include <errno.h> -#include <unistd.h> - -#include "postgres.h" - -#ifdef HAVE_CRYPT_H -#include <crypt.h> -#endif - -#include "libpq/libpq.h" -#include "libpq/password.h" -#include "libpq/crypt.h" -#include "miscadmin.h" -#include "storage/fd.h" - - -int -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(port->auth_arg) + 2); - strcpy(pw_file_fullname, DataDir); - strcat(pw_file_fullname, "/"); - strcat(pw_file_fullname, port->auth_arg); - - pw_file = AllocateFile(pw_file_fullname, PG_BINARY_R); - if (!pw_file) - { - elog(LOG, "verify_password: Unable to open password file \"%s\": %m", - pw_file_fullname); - - pfree(pw_file_fullname); - - return STATUS_ERROR; - } - - pfree(pw_file_fullname); - - while (!feof(pw_file)) - { - char pw_file_line[255], - *p, - *test_user, - *test_pw; - - if (fgets(pw_file_line, sizeof(pw_file_line), pw_file) == NULL) - pw_file_line[0] = '\0'; - /* kill the newline */ - if (strlen(pw_file_line) > 0 && - 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, ":"); - if (!test_user || test_user[0] == '\0') - continue; - test_pw = strtok(NULL, ":"); - - 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 or "+" then we use the regular - * pg_shadow passwords. If we use crypt then we have to use - * pg_shadow passwords no matter what. This is because the - * current code needs non-encrypted passwords to encrypt with - * a random salt. - */ - if (port->auth_method == uaMD5 || - port->auth_method == uaCrypt || - 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. */ - return STATUS_OK; - } - - elog(LOG, "verify_password: password mismatch for '%s'", - user); - - return STATUS_ERROR; - } - } - - FreeFile(pw_file); - - elog(LOG, "verify_password: user '%s' not found in password file", - user); - - return STATUS_ERROR; -} diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample index 669588e517c..05e6959b4de 100644 --- a/src/backend/libpq/pg_hba.conf.sample +++ b/src/backend/libpq/pg_hba.conf.sample @@ -42,22 +42,36 @@ # # Format: # -# host DBNAME IP_ADDRESS ADDRESS_MASK AUTH_TYPE [AUTH_ARGUMENT] -# -# DBNAME can be: -# o a database name -# o "all", which means the record matches all databases -# o "sameuser", which means users can only access databases whose name -# is the same as their username +# host DATABASE USER IP_ADDRESS MASK AUTH_TYPE +# +# DATABASE can be: +# o a database name +# o "sameuser", which means a user can only access a database with the +# same name as their user name +# o "samegroup", which means a user can only access databases when they +# are members of a group with the same name as the database name +# o "all", which matches all databases +# o a list of database names, separated by commas +# o a file name containing database names, starting with '@' +# +# USER can be: +# o a user name +# o "all", which matches all users +# o a list of user names, separated by commas +# o a group name, starting with '+' +# o a file name containing user names, starting with '@' +# +# Files read using '@' can contain comma-separated database/user names, +# or one name per line. The files can also contain comments using '#'. # -# IP_ADDRESS and ADDRESS_MASK are standard dotted decimal IP address and +# IP_ADDRESS and MASK are standard dotted decimal IP address and # mask values. IP addresses can only be specified numerically, not as # domain or host names. # # Do not prevent the superuser from accessing the template1 database. # Various utility commands need access to template1. # -# AUTH_TYPE and AUTH_ARGUMENT are described below. +# AUTH_TYPE is described below. # # # hostssl @@ -65,10 +79,8 @@ # # The format of this record is identical to "host". # -# -# -# It specifies hosts that required connection via secure SSL. "host" -# records allow SSL connections too, but "hostssl" only allows SSL-secured +# It specifies hosts that require connection via secure SSL. "host" +# allows SSL connections too, but "hostssl" requires SSL-secured # connections. # # This keyword is only available if the server was compiled with SSL @@ -82,10 +94,10 @@ # connections. Without this record, UNIX-socket connections are disallowed # # Format: -# local DBNAME AUTH_TYPE [AUTH_ARGUMENT] +# local DATABASE USER AUTH_TYPE # # This format is identical to the "host" record type except there are no -# IP_ADDRESS and ADDRESS_MASK fields. +# IP_ADDRESS and MASK fields. # # # @@ -96,57 +108,38 @@ # has an AUTH_TYPE. # # trust: -# No authentication is done. Any valid username is accepted, +# No authentication is done. Any valid user name is accepted, # including the PostgreSQL superuser. This option should # be used only for hosts where all users are trusted. # -# password: -# Authentication is done by matching a password supplied -# in clear by the host. If no AUTH_ARGUMENT is used, the -# password is compared with the user's entry in the -# pg_shadow table. -# -# If AUTH_ARGUMENT is specified, the username is looked up -# in that file in the $PGDATA directory. If the username -# is found but there is no password, the password is looked -# up in pg_shadow. If a password exists in the file, it is -# used instead. These secondary files allow fine-grained -# control over who can access which databases and whether -# a non-default password is required. The same file can be -# used in multiple records for easier administration. -# Password files can be maintained with the pg_passwd(1) -# utility. Remember, these passwords override pg_shadow -# passwords. Also, such passwords are passed over the network -# in cleartext, meaning this should not be used on untrusted -# networks. -# # md5: -# Same as "password", except the password is encrypted over the -# network. This method is preferable to "password" and "crypt" -# except for pre-7.2 clients that don't support it. NOTE: md5 can -# use usernames stored in secondary password files but ignores -# passwords stored there. The pg_shadow password will always be -# used. +# Requires the client to supply an MD5 encrypted password for +# authentication. This is the only method that allows encrypted +# passwords to be stored in pg_shadow. # # crypt: -# Same as "md5", but uses crypt for pre-7.2 clients. You can -# not store encrypted passwords in pg_shadow if you use this -# method. +# Same as "md5", but uses crypt for pre-7.2 clients. # +# password: +# Same as "md5", but the password is sent in cleartext over +# the network. This should not be used on untrusted +# networks. +# # ident: # For TCP/IP connections, authentication is done by contacting the # ident server on the client host. This is only as secure as the -# client machine. On machines that support unix-domain socket -# credentials (currently Linux, FreeBSD, NetBSD, and BSD/OS), this -# method also works for "local" connections. +# client machine. You must specify the map name after the 'ident' +# keyword. It determines how to map remote user names to +# PostgreSQL user names. If you use "sameuser", the user names are +# assumed to be identical. If not, the map name is looked up +# in the $PGDATA/pg_ident.conf file. The connection is accepted if +# that file contains an entry for this map name with the +# ident-supplied username and the requested PostgreSQL username. # -# AUTH_ARGUMENT is required. It determines how to map remote user -# names to PostgreSQL user names. If you use "sameuser", the user -# names are assumed to be the identical. If not, AUTH_ARGUMENT is -# assumed to be a map name found in the $PGDATA/pg_ident.conf -# file. The connection is accepted if that file contains an entry -# for this map name with the ident-supplied username and the -# requested PostgreSQL username. +# On machines that support unix-domain socket credentials +# (currently Linux, FreeBSD, NetBSD, and BSD/OS), ident allows +# reliable authentication of 'local' connections without ident +# running on the local machine. # # krb4: # Kerberos V4 authentication is used. Allowed only for @@ -157,10 +150,10 @@ # TCP/IP connections, not for local UNIX-domain sockets. # # pam: -# Authentication is passed off to PAM (PostgreSQL must be -# configured --with-pam), using the default service name -# "postgresql" - you can specify your own service name by -# setting AUTH_ARGUMENT to the desired service name. +# Authentication is done by PAM using the default service name +# "postgresql". You can specify your own service name by adding +# the service name after the 'pam' keyword. To use this option, +# PostgreSQL must be configured --with-pam. # # reject: # Reject the connection. This is used to reject certain hosts @@ -177,60 +170,70 @@ # Allow any user on the local system to connect to any database under any # username using Unix-domain sockets (the default for local connections): # -# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT -# local all trust +# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE +# local all all trust # # The same using local loopback TCP/IP connections: # -# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT -# host all 127.0.0.1 255.255.255.255 trust +# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE +# host all all 127.0.0.1 255.255.255.255 trust # # Allow any user from any host with IP address 192.168.93.x to # connect to database "template1" as the same username that ident reports # for the connection (typically his Unix username): # -# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT -# host template1 192.168.93.0 255.255.255.0 ident sameuser +# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE +# host template1 all 192.168.93.0 255.255.255.0 ident sameuser # # Allow a user from host 192.168.12.10 to connect to database "template1" -# if the user's password in pg_shadow is correctly supplied: +# if the user's password is correctly supplied: # -# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT -# host template1 192.168.12.10 255.255.255.255 md5 +# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE +# host template1 all 192.168.12.10 255.255.255.255 md5 # # In the absence of preceding "host" lines, these two lines will reject # all connection from 192.168.54.1 (since that entry will be matched # first), but allow Kerberos V5 connections from anywhere else on the # Internet. The zero mask means that no bits of the host IP address are -# considered, so it matches any host: +# considered so it matches any host: # # -# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT -# host all 192.168.54.1 255.255.255.255 reject -# host all 0.0.0.0 0.0.0.0 krb5 +# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE +# host all all 192.168.54.1 255.255.255.255 reject +# host all all 0.0.0.0 0.0.0.0 krb5 # # Allow users from 192.168.x.x hosts to connect to any database if they # pass the ident check. For example, if ident says the user is "james" and # he requests to connect as PostgreSQL user "guest", the connection is # allowed if there is an entry in $PGDATA/pg_ident.conf with map name # "phoenix" that says "james" is allowed to connect as "guest": +# See $PGDATA/pg_ident.conf for more information on Ident maps. # -# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT -# host all 192.168.0.0 255.255.0.0 ident phoenix +# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE +# host all all 192.168.0.0 255.255.0.0 ident phoenix +# +# If these are the only three lines for local connections, they will +# allow local users to connect only to their own databases (databases +# with the same name as their user name) except for administrators and +# members of group 'support' who may connect to all databases . The file +# $PGDATA/admins contains a list of user names. Passwords are required in +# all cases. +# +# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE +# local sameuser all md5 +# local all @admins md5 +# local all +support md5 +# +# The last two lines above can be combined into a single line: +# +# local all @admins,+support md5 +# +# The database column can also use lists and file names, but not groups: +# +# local db1,db2,@demodbs all md5 # -# If these are the only two lines for local connections, they will allow -# local users to connect only to their own databases (databases with the -# same name as their user name) except for administrators who may connect -# to all databases. The file $PGDATA/admins lists the user names who are -# permitted to connect to all databases. Passwords are required in all -# cases. (If you prefer to use ident authorization, an ident map can -# serve a parallel purpose to the password list file used here.) # -# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT -# local sameuser md5 -# local all md5 admins # -# See $PGDATA/pg_ident.conf for more information on Ident maps. # # # @@ -250,7 +253,7 @@ # configuration is probably too liberal for you. Change it to use # something other than "trust" authentication. # -# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT +# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE -local all trust -host all 127.0.0.1 255.255.255.255 trust +local all all trust +host all all 127.0.0.1 255.255.255.255 trust diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index a6d6097a54c..0ce817b5b39 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.271 2002/03/15 19:20:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.272 2002/04/04 04:25:48 momjian Exp $ * * NOTES * @@ -748,8 +748,10 @@ PostmasterMain(int argc, char *argv[]) /* * Load cached files for client authentication. */ - load_hba_and_ident(); - load_password_cache(); + load_hba(); + load_ident(); + load_user(); + load_group(); /* * We're ready to rock and roll... @@ -1389,7 +1391,8 @@ SIGHUP_handler(SIGNAL_ARGS) elog(LOG, "Received SIGHUP, reloading configuration files"); SignalChildren(SIGHUP); ProcessConfigFile(PGC_SIGHUP); - load_hba_and_ident(); + load_hba(); + load_ident(); } PG_SETMASK(&UnBlockSig); @@ -2288,9 +2291,10 @@ sigusr1_handler(SIGNAL_ARGS) if (CheckPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE)) { /* - * Password file has changed. + * Password or group file has changed. */ - load_password_cache(); + load_user(); + load_group(); } if (CheckPostmasterSignal(PMSIGNAL_WAKEN_CHILDREN)) diff --git a/src/backend/utils/adt/quote.c b/src/backend/utils/adt/quote.c index 39a1ec4df16..537e97a50ee 100644 --- a/src/backend/utils/adt/quote.c +++ b/src/backend/utils/adt/quote.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/quote.c,v 1.6 2001/10/28 06:25:53 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/quote.c,v 1.7 2002/04/04 04:25:49 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -124,8 +124,6 @@ do_quote_ident(text *iptr) { if (*cp1 == '"') *cp2++ = '"'; - if (*cp1 == '\\') - *cp2++ = '\\'; *cp2++ = *cp1++; } *cp2++ = '"'; @@ -234,8 +232,6 @@ do_quote_ident(text *iptr) if (*cp1 == '"') *cp2++ = '"'; - if (*cp1 == '\\') - *cp2++ = '\\'; *cp2++ = *cp1++; len--; diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index dceb8b9cd6f..9ef8b1c87c5 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.85 2002/03/04 04:45:27 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.86 2002/04/04 04:25:49 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -236,85 +236,17 @@ pg_convert2(PG_FUNCTION_ARGS) #ifdef CYR_RECODE -#define MAX_TOKEN 80 - -/* - * Some standard C libraries, including GNU, have an isblank() function. - * Others, including Solaris, do not. So we have our own. - */ -static bool -isblank(const char c) -{ - return c == ' ' || c == '\t'; -} - - -/* - * Grab one token out of fp. Tokens are strings of non-blank - * characters bounded by blank characters, beginning of line, and end - * of line. Blank means space or tab. Return the token as *buf. - * Leave file positioned to character immediately after the token or - * EOF, whichever comes first. If no more tokens on line, return null - * string as *buf and position file to beginning of next line or EOF, - * whichever comes first. - */ -static void -next_token(FILE *fp, char *buf, const int bufsz) -{ - int c; - char *eb = buf + (bufsz - 1); - - /* Move over initial token-delimiting blanks */ - while ((c = getc(fp)) != EOF && isblank(c)) - ; - - if (c != EOF && c != '\n') - { - /* - * build a token in buf of next characters up to EOF, eol, or - * blank. If the token gets too long, we still parse it - * correctly, but the excess characters are not stored into *buf. - */ - while (c != EOF && c != '\n' && !isblank(c)) - { - if (buf < eb) - *buf++ = c; - c = getc(fp); - } - - /* - * Put back the char right after the token (critical in case it is - * eol, since we need to detect end-of-line at next call). - */ - if (c != EOF) - ungetc(c, fp); - } - *buf = '\0'; -} - - -static void -read_through_eol(FILE *file) -{ - int c; - - while ((c = getc(file)) != EOF && c != '\n') - ; -} - - -void SetCharSet(void) { FILE *file; - char *p; + char *filename; char *map_file; char buf[MAX_TOKEN]; int i, c; unsigned char FromChar, ToChar; - char ChTable[80]; + char ChTable[MAX_TOKEN]; for (i = 0; i < 128; i++) { @@ -325,39 +257,40 @@ SetCharSet(void) if (IsUnderPostmaster) { GetCharSetByHost(ChTable, MyProcPort->raddr.in.sin_addr.s_addr, DataDir); - p = ChTable; + filename = ChTable; } else - p = getenv("PG_RECODETABLE"); + filename = getenv("PG_RECODETABLE"); - if (p && *p != '\0') + if (filename && *filename != '\0') { - map_file = palloc(strlen(DataDir) + strlen(p) + 2); - sprintf(map_file, "%s/%s", DataDir, p); - file = AllocateFile(map_file, PG_BINARY_R); + map_file = palloc(strlen(DataDir) + strlen(filename) + 2); + sprintf(map_file, "%s/%s", DataDir, filename); + file = AllocateFile(map_file, "r"); pfree(map_file); if (file == NULL) return; - while ((c = getc(file)) != EOF) + + while (!feof(file)) { - if (c == '#') - read_through_eol(file); - else + next_token(file, buf, sizeof(buf)); + if (buf[0] != '\0') { - /* Read the FromChar */ - ungetc(c, file); + FromChar = strtoul(buf, 0, 0); + /* Read the ToChar */ next_token(file, buf, sizeof(buf)); if (buf[0] != '\0') { - FromChar = strtoul(buf, 0, 0); - /* Read the ToChar */ - next_token(file, buf, sizeof(buf)); - if (buf[0] != '\0') + ToChar = strtoul(buf, 0, 0); + RecodeForwTable[FromChar - 128] = ToChar; + RecodeBackTable[ToChar - 128] = FromChar; + + /* read to EOL */ + while (!feof(file) && buf[0]) { - ToChar = strtoul(buf, 0, 0); - RecodeForwTable[FromChar - 128] = ToChar; - RecodeBackTable[ToChar - 128] = FromChar; - read_through_eol(file); + next_token(file, buf, sizeof(buf)); + elog(LOG, "SetCharSet: unknown tag %s in file %s" + buf, filename); } } } @@ -366,6 +299,7 @@ SetCharSet(void) } } + char * convertstr(unsigned char *buff, int len, int dest) { @@ -384,7 +318,206 @@ convertstr(unsigned char *buff, int len, int dest) } return ch; } -#endif + +#define CHARSET_FILE "charset.conf" +#define MAX_CHARSETS 10 +#define KEY_HOST 1 +#define KEY_BASE 2 +#define KEY_TABLE 3 + +struct CharsetItem +{ + char Orig[MAX_TOKEN]; + char Dest[MAX_TOKEN]; + char Table[MAX_TOKEN]; +}; + + +static bool +CharSetInRange(char *buf, int host) +{ + int valid, + i, + FromAddr, + ToAddr, + tmp; + struct in_addr file_ip_addr; + char *p; + unsigned int one = 0x80000000, + NetMask = 0; + unsigned char mask; + + p = strchr(buf, '/'); + if (p) + { + *p++ = '\0'; + valid = inet_aton(buf, &file_ip_addr); + if (valid) + { + mask = strtoul(p, 0, 0); + FromAddr = ntohl(file_ip_addr.s_addr); + ToAddr = ntohl(file_ip_addr.s_addr); + for (i = 0; i < mask; i++) + { + NetMask |= one; + one >>= 1; + } + FromAddr &= NetMask; + ToAddr = ToAddr | ~NetMask; + tmp = ntohl(host); + return ((unsigned) tmp >= (unsigned) FromAddr && + (unsigned) tmp <= (unsigned) ToAddr); + } + } + else + { + p = strchr(buf, '-'); + if (p) + { + *p++ = '\0'; + valid = inet_aton(buf, &file_ip_addr); + if (valid) + { + FromAddr = ntohl(file_ip_addr.s_addr); + valid = inet_aton(p, &file_ip_addr); + if (valid) + { + ToAddr = ntohl(file_ip_addr.s_addr); + tmp = ntohl(host); + return ((unsigned) tmp >= (unsigned) FromAddr && + (unsigned) tmp <= (unsigned) ToAddr); + } + } + } + else + { + valid = inet_aton(buf, &file_ip_addr); + if (valid) + { + FromAddr = file_ip_addr.s_addr; + return (unsigned) FromAddr == (unsigned) host; + } + } + } + return false; +} + + +static void +GetCharSetByHost(char *TableName, int host, const char *DataDir) +{ + FILE *file; + char buf[MAX_TOKEN], + BaseCharset[MAX_TOKEN], + OrigCharset[MAX_TOKEN], + DestCharset[MAX_TOKEN], + HostCharset[MAX_TOKEN], + *map_file; + int key, + ChIndex = 0, + c, + i, + bufsize; + struct CharsetItem *ChArray[MAX_CHARSETS]; + + *TableName = '\0'; + bufsize = (strlen(DataDir) + strlen(CHARSET_FILE) + 2) * sizeof(char); + map_file = (char *) palloc(bufsize); + snprintf(map_file, bufsize, "%s/%s", DataDir, CHARSET_FILE); + file = AllocateFile(map_file, "r"); + pfree(map_file); + if (file == NULL) + { + /* XXX should we log a complaint? */ + return; + } + + while (!feof(file)) + { + next_token(file, buf, sizeof(buf)); + if (buf[0] != '\0') + { + key = 0; + if (strcasecmp(buf, "HostCharset") == 0) + key = KEY_HOST; + else if (strcasecmp(buf, "BaseCharset") == 0) + key = KEY_BASE; + else if (strcasecmp(buf, "RecodeTable") == 0) + key = KEY_TABLE; + else + elog(LOG, "GetCharSetByHost: unknown tag %s in file %s" + buf, CHARSET_FILE); + + switch (key) + { + case KEY_HOST: + /* Read the host */ + next_token(file, buf, sizeof(buf)); + if (buf[0] != '\0') + { + if (CharSetInRange(buf, host)) + { + /* Read the charset */ + next_token(file, buf, sizeof(buf)); + if (buf[0] != '\0') + strcpy(HostCharset, buf); + } + } + break; + case KEY_BASE: + /* Read the base charset */ + next_token(file, buf, sizeof(buf)); + if (buf[0] != '\0') + strcpy(BaseCharset, buf); + break; + case KEY_TABLE: + /* Read the original charset */ + next_token(file, buf, sizeof(buf)); + if (buf[0] != '\0') + { + strcpy(OrigCharset, buf); + /* Read the destination charset */ + next_token(file, buf, sizeof(buf)); + if (buf[0] != '\0') + { + strcpy(DestCharset, buf); + /* Read the table filename */ + next_token(file, buf, sizeof(buf)); + if (buf[0] != '\0') + { + ChArray[ChIndex] = + (struct CharsetItem *) palloc(sizeof(struct CharsetItem)); + strcpy(ChArray[ChIndex]->Orig, OrigCharset); + strcpy(ChArray[ChIndex]->Dest, DestCharset); + strcpy(ChArray[ChIndex]->Table, buf); + ChIndex++; + } + } + } + break; + } + + /* read to EOL */ + while (!feof(file) && buf[0]) + { + next_token(file, buf, sizeof(buf)); + elog(LOG, "GetCharSetByHost: unknown tag %s in file %s" + buf, CHARSET_FILE); + } + } + } + FreeFile(file); + + for (i = 0; i < ChIndex; i++) + { + if (strcasecmp(BaseCharset, ChArray[i]->Orig) == 0 && + strcasecmp(HostCharset, ChArray[i]->Dest) == 0) + strncpy(TableName, ChArray[i]->Table, 79); + pfree(ChArray[i]); + } +} + +#endif /* CYR_RECODE */ diff --git a/src/bin/Makefile b/src/bin/Makefile index a1d4b1e8fc0..7a293c35a26 100644 --- a/src/bin/Makefile +++ b/src/bin/Makefile @@ -5,7 +5,7 @@ # Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # -# $Header: /cvsroot/pgsql/src/bin/Makefile,v 1.34 2001/02/18 18:33:59 momjian Exp $ +# $Header: /cvsroot/pgsql/src/bin/Makefile,v 1.35 2002/04/04 04:25:50 momjian Exp $ # #------------------------------------------------------------------------- @@ -14,7 +14,7 @@ top_builddir = ../.. include $(top_builddir)/src/Makefile.global DIRS := initdb initlocation ipcclean pg_ctl pg_dump pg_id \ - pg_passwd psql scripts pg_config + psql scripts pg_config ifdef MULTIBYTE DIRS += pg_encoding diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh index e028ac1b10e..30f7de1f201 100644 --- a/src/bin/initdb/initdb.sh +++ b/src/bin/initdb/initdb.sh @@ -27,7 +27,7 @@ # Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # -# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.146 2002/04/03 05:39:32 petere Exp $ +# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.147 2002/04/04 04:25:50 momjian Exp $ # #------------------------------------------------------------------------- @@ -603,9 +603,11 @@ $ECHO_N "initializing pg_shadow... "$ECHO_C "$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF -- Create a trigger so that direct updates to pg_shadow will be written --- to the flat password file pg_pwd +-- to the flat password/group files pg_pwd and pg_group CREATE TRIGGER pg_sync_pg_pwd AFTER INSERT OR UPDATE OR DELETE ON pg_shadow \ -FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd(); +FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group(); +CREATE TRIGGER pg_sync_pg_group AFTER INSERT OR UPDATE OR DELETE ON pg_group \ +FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group(); -- needs to be done before alter user, because alter user checks that -- pg_shadow is secure ... REVOKE ALL on pg_shadow FROM public; @@ -643,6 +645,11 @@ EOF echo "The password file wasn't generated. Please report this problem." 1>&2 exit_nicely fi + if [ ! -f "$PGDATA"/global/pg_group ]; then + echo + echo "The group file wasn't generated. Please report this problem." 1>&2 + exit_nicely + fi echo "ok" fi diff --git a/src/bin/pg_passwd/Makefile b/src/bin/pg_passwd/Makefile deleted file mode 100644 index f6f4acd0118..00000000000 --- a/src/bin/pg_passwd/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# $Header: /cvsroot/pgsql/src/bin/pg_passwd/Attic/Makefile,v 1.14 2001/05/12 19:49:47 petere Exp $ - -subdir = src/bin/pg_passwd -top_builddir = ../../.. -include $(top_builddir)/src/Makefile.global - -OBJS = pg_passwd.o -ifdef STRDUP -OBJS += $(top_builddir)/src/utils/strdup.o -endif - -all: pg_passwd - -pg_passwd: $(OBJS) - $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@ - -$(top_builddir)/src/utils/strdup.o: - $(MAKE) -C $(top_builddir)/src/utils strdup.o - -install: all installdirs - $(INSTALL_PROGRAM) pg_passwd$(X) $(DESTDIR)$(bindir)/pg_passwd$(X) - -installdirs: - $(mkinstalldirs) $(DESTDIR)$(bindir) - -uninstall: - rm -f $(DESTDIR)$(bindir)/pg_passwd$(X) - -depend dep: - $(CC) -MM $(CFLAGS) *.c >depend - -clean distclean maintainer-clean: - rm -f pg_passwd$(X) pg_passwd.o - -ifeq (depend,$(wildcard depend)) -include depend -endif diff --git a/src/bin/pg_passwd/pg_passwd.c b/src/bin/pg_passwd/pg_passwd.c deleted file mode 100644 index 831c3823708..00000000000 --- a/src/bin/pg_passwd/pg_passwd.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * @(#) pg_passwd.c 1.8 09:13:16 97/07/02 Y. Ichikawa - */ -#include "postgres_fe.h" - -#include <unistd.h> -#include <errno.h> -#include <time.h> -#include <ctype.h> -#define issaltchar(c) (isalnum((unsigned char) (c)) || (c) == '.' || (c) == '/') - -#ifdef HAVE_TERMIOS_H -#include <termios.h> -#endif -#ifdef HAVE_CRYPT_H -#include <crypt.h> -#else -extern char *crypt(const char *, const char *); -#endif - -/* - * We assume that the output of crypt(3) is always 13 characters, - * and that at most 8 characters can usefully be sent to it. - * - * Postgres usernames are assumed to be less than NAMEDATALEN chars long. - */ -#define CLEAR_PASSWD_LEN 8 /* not including null */ -#define CRYPTED_PASSWD_LEN 13 /* not including null */ - -const char *progname; - -static void usage(void); -static void read_pwd_file(char *filename); -static void write_pwd_file(char *filename, char *bkname); -static void encrypt_pwd(char key[CLEAR_PASSWD_LEN + 1], - char salt[3], - char passwd[CRYPTED_PASSWD_LEN + 1]); -static void prompt_for_username(char *username); -static void prompt_for_password(char *prompt, char *password); - -static void -usage(void) -{ - printf("%s manipulates flat text password files for PostgreSQL.\n\n", progname); - printf("Usage:\n %s PASSWORD-FILE\n\n", progname); - printf("Report bugs to <pgsql-bugs@postgresql.org>.\n"); -} - -typedef struct -{ - char *uname; - char *pwd; - char *rest; -} pg_pwd; - -#define MAXPWDS 1024 - -pg_pwd pwds[MAXPWDS]; -int npwds = 0; - - -static void -read_pwd_file(char *filename) -{ - FILE *fp; - static char line[512]; - static char ans[128]; - int i; - -try_again: - fp = fopen(filename, PG_BINARY_R); - if (fp == NULL) - { - if (errno == ENOENT) - { - printf("File \"%s\" does not exist. Create? (y/n): ", filename); - fflush(stdout); - if (fgets(ans, sizeof(ans), stdin) == NULL) - exit(1); - switch (ans[0]) - { - case 'y': - case 'Y': - fp = fopen(filename, PG_BINARY_W); - if (fp == NULL) - { - perror(filename); - exit(1); - } - fclose(fp); - goto try_again; - default: - /* cannot continue */ - exit(1); - } - } - else - { - perror(filename); - exit(1); - } - } - - /* read all the entries */ - for (npwds = 0; - npwds < MAXPWDS && fgets(line, sizeof(line), fp) != NULL; - ++npwds) - { - int l; - char *p, - *q; - - l = strlen(line); - if (line[l - 1] == '\n') - line[l - 1] = '\0'; - else - { - fprintf(stderr, "%s:%d: line too long\n", - filename, npwds + 1); - exit(1); - } - - /* get user name */ - p = line; - if ((q = strchr(p, ':')) != NULL) - *q = '\0'; - - if (strlen(p) == 0) - { - fprintf(stderr, "%s:%d: null user name\n", - filename, npwds + 1); - exit(1); - } - pwds[npwds].uname = strdup(p); - - /* check for duplicate user name */ - for (i = 0; i < npwds; ++i) - { - if (strcmp(pwds[i].uname, pwds[npwds].uname) == 0) - { - fprintf(stderr, "Duplicate username %s in entry %d\n", - pwds[npwds].uname, npwds + 1); - exit(1); - } - } - - /* get password field */ - if (q) - { - p = q + 1; - q = strchr(p, ':'); - - if (q != NULL) - *(q++) = '\0'; - - if (strlen(p) != CRYPTED_PASSWD_LEN && strcmp(p, "+") != 0) - { - fprintf(stderr, "%s:%d: warning: invalid password length\n", - filename, npwds + 1); - } - pwds[npwds].pwd = strdup(p); - } - else - pwds[npwds].pwd = NULL; - - /* rest of the line is treated as is */ - if (q == NULL) - pwds[npwds].rest = NULL; - else - pwds[npwds].rest = strdup(q); - } - - fclose(fp); -} - -static void -write_pwd_file(char *filename, char *bkname) -{ - FILE *fp; - int i; - - /* make the backup file */ -link_again: - if (link(filename, bkname)) - { - if (errno == EEXIST) - { - unlink(bkname); - goto link_again; - } - perror(bkname); - exit(1); - } - if (unlink(filename)) - { - perror(filename); - exit(1); - } - - /* open file */ - if ((fp = fopen(filename, PG_BINARY_W)) == NULL) - { - perror(filename); - exit(1); - } - - /* write file */ - for (i = 0; i < npwds; ++i) - { - 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); -} - -static void -encrypt_pwd(char key[CLEAR_PASSWD_LEN + 1], - char salt[3], - char passwd[CRYPTED_PASSWD_LEN + 1]) -{ - int n; - - /* select a salt, if not already given */ - if (salt[0] == '\0') - { - srand(time(NULL)); - do - { - n = rand() % 256; - } while (!issaltchar(n)); - salt[0] = n; - do - { - n = rand() % 256; - } while (!issaltchar(n)); - salt[1] = n; - salt[2] = '\0'; - } - - /* get encrypted password */ - strcpy(passwd, crypt(key, salt)); - -#ifdef PG_PASSWD_DEBUG - /* show it */ - fprintf(stderr, "key = %s, salt = %s, password = %s\n", - key, salt, passwd); -#endif -} - -static void -prompt_for_username(char *username) -{ - int length; - - printf("Username: "); - fflush(stdout); - if (fgets(username, NAMEDATALEN, stdin) == NULL) - username[0] = '\0'; - - length = strlen(username); - if (length > 0 && username[length - 1] != '\n') - { - /* eat rest of the line */ - char buf[128]; - int buflen; - - do - { - if (fgets(buf, sizeof(buf), stdin) == NULL) - break; - buflen = strlen(buf); - } while (buflen > 0 && buf[buflen - 1] != '\n'); - } - if (length > 0 && username[length - 1] == '\n') - username[length - 1] = '\0'; -} - -static void -prompt_for_password(char *prompt, char *password) -{ - int length; - -#ifdef HAVE_TERMIOS_H - struct termios t_orig, - t; -#endif - -#ifdef HAVE_TERMIOS_H - tcgetattr(0, &t); - t_orig = t; - t.c_lflag &= ~ECHO; - tcsetattr(0, TCSADRAIN, &t); -#endif - - printf(prompt); - fflush(stdout); - - if (fgets(password, CLEAR_PASSWD_LEN + 1, stdin) == NULL) - password[0] = '\0'; - -#ifdef HAVE_TERMIOS_H - tcsetattr(0, TCSADRAIN, &t_orig); -#endif - - length = strlen(password); - if (length > 0 && password[length - 1] != '\n') - { - /* eat rest of the line */ - char buf[128]; - int buflen; - - do - { - if (fgets(buf, sizeof(buf), stdin) == NULL) - break; - buflen = strlen(buf); - } while (buflen > 0 && buf[buflen - 1] != '\n'); - } - if (length > 0 && password[length - 1] == '\n') - password[length - 1] = '\0'; - printf("\n"); -} - - -int -main(int argc, char *argv[]) -{ - char *filename; - char bkname[MAXPGPATH]; - char username[NAMEDATALEN]; - char salt[3]; - char key[CLEAR_PASSWD_LEN + 1], - key2[CLEAR_PASSWD_LEN + 1]; - char e_passwd[CRYPTED_PASSWD_LEN + 1]; - int i; - - progname = argv[0]; - - if (argc != 2) - { - fprintf(stderr, "%s: too %s arguments\nTry '%s --help' for more information.\n", - progname, argc > 2 ? "many" : "few", progname); - exit(1); - } - - if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) - { - usage(); - exit(0); - } - if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) - { - puts("pg_passwd (PostgreSQL) " PG_VERSION); - exit(0); - } - if (argv[1][0] == '-') - { - fprintf(stderr, "%s: invalid option: %s\nTry '%s --help' for more information.\n", - progname, argv[1], progname); - exit(1); - } - - filename = argv[1]; - - /* open file */ - read_pwd_file(filename); - - /* ask for the user name and the password */ - prompt_for_username(username); - prompt_for_password("New password: ", key); - prompt_for_password("Re-enter new password: ", key2); - if (strcmp(key, key2) != 0) - { - fprintf(stderr, "Password mismatch\n"); - exit(1); - } - salt[0] = '\0'; - encrypt_pwd(key, salt, e_passwd); - - /* check password entry */ - for (i = 0; i < npwds; ++i) - { - if (strcmp(pwds[i].uname, username) == 0) - { /* found */ - pwds[i].pwd = strdup(e_passwd); - break; - } - } - if (i == npwds) - { /* did not exist */ - if (npwds == MAXPWDS) - { - fprintf(stderr, "Cannot handle so many entries\n"); - exit(1); - } - pwds[npwds].uname = strdup(username); - pwds[npwds].pwd = strdup(e_passwd); - pwds[npwds].rest = NULL; - ++npwds; - } - - /* write back the file */ - sprintf(bkname, "%s.bk", filename); - write_pwd_file(filename, bkname); - - return 0; -} diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index ac32bd69aa0..cd939a9c10a 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.224 2002/03/29 19:06:19 tgl Exp $ + * $Id: pg_proc.h,v 1.225 2002/04/04 04:25:52 momjian Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2101,8 +2101,8 @@ DESCR("does not match LIKE expression, case-insensitive"); DATA(insert OID = 1637 ( like_escape PGUID 12 f t t t 2 f 25 "25 25" 100 0 0 100 like_escape - _null_ )); DESCR("convert match pattern to use backslash escapes"); -DATA(insert OID = 1689 ( update_pg_pwd PGUID 12 f t f t 0 f 0 "" 100 0 0 100 update_pg_pwd - _null_ )); -DESCR("update pg_pwd file"); +DATA(insert OID = 1689 ( update_pg_pwd_and_pg_group PGUID 12 f t f t 0 f 0 "" 100 0 0 100 update_pg_pwd_and_pg_group - _null_ )); +DESCR("update pg_pwd and pg_group files"); /* Oracle Compatibility Related Functions - By Edmund Mergl <E.Mergl@bawue.de> */ DATA(insert OID = 868 ( strpos PGUID 12 f t t t 2 f 23 "25 25" 100 0 0 100 textpos - _null_ )); diff --git a/src/include/commands/user.h b/src/include/commands/user.h index 351c2d6ef6d..046e022ae8f 100644 --- a/src/include/commands/user.h +++ b/src/include/commands/user.h @@ -3,15 +3,23 @@ * user.h * * - * $Id: user.h,v 1.17 2002/03/01 22:45:17 petere Exp $ + * $Id: user.h,v 1.18 2002/04/04 04:25:53 momjian Exp $ * *------------------------------------------------------------------------- */ #ifndef USER_H #define USER_H +#include "fmgr.h" #include "nodes/parsenodes.h" +#define PWD_FILE "pg_pwd" + +#define USER_GROUP_FILE "pg_group" + + +extern char *group_getfilename(void); +extern char *user_getfilename(void); extern void CreateUser(CreateUserStmt *stmt); extern void AlterUser(AlterUserStmt *stmt); extern void AlterUserSet(AlterUserSetStmt *stmt); @@ -21,6 +29,6 @@ extern void CreateGroup(CreateGroupStmt *stmt); extern void AlterGroup(AlterGroupStmt *stmt, const char *tag); extern void DropGroup(DropGroupStmt *stmt); -extern Datum update_pg_pwd(PG_FUNCTION_ARGS); +extern Datum update_pg_pwd_and_pg_group(PG_FUNCTION_ARGS); #endif /* USER_H */ diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h index 458be1fd2cf..a521a0e2cee 100644 --- a/src/include/libpq/crypt.h +++ b/src/include/libpq/crypt.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: crypt.h,v 1.19 2001/11/12 01:52:46 momjian Exp $ + * $Id: crypt.h,v 1.20 2002/04/04 04:25:53 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -15,8 +15,6 @@ #include "libpq/libpq-be.h" -#define CRYPT_PWD_FILE_SEPSTR "\t" - /* Also defined in interfaces/odbc/md5.h */ #define MD5_PASSWD_LEN 35 @@ -24,9 +22,6 @@ strlen(passwd) == MD5_PASSWD_LEN) -extern char *crypt_getpwdfilename(void); -extern void load_password_cache(void); - extern int md5_crypt_verify(const Port *port, const char *user, const char *pgpass); extern bool md5_hash(const void *buff, size_t len, char *hexsum); diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h index 0d5ddbaf702..b9daf985f5c 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.31 2001/11/05 17:46:33 momjian Exp $ + * $Id: hba.h,v 1.32 2002/04/04 04:25:54 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -15,15 +15,14 @@ #include <netinet/in.h> #endif +#include "nodes/pg_list.h" + #define CONF_FILE "pg_hba.conf" /* Name of the config file */ #define USERMAP_FILE "pg_ident.conf" /* Name of the usermap file */ -#define OLD_CONF_FILE "pg_hba" - /* Name of the config file in prior releases of Postgres. */ - #define IDENT_PORT 113 /* Standard TCP port number for Ident service. Assigned by IANA */ @@ -46,8 +45,15 @@ typedef enum UserAuth typedef struct Port hbaPort; +#define MAX_TOKEN 256 + +extern void next_token(FILE *fp, char *buf, const int bufsz); +extern List **get_user_line(const char *user); +extern void load_hba(void); +extern void load_ident(void); +extern void load_user(void); +extern void load_group(void); extern int hba_getauthmethod(hbaPort *port); extern int authident(hbaPort *port); -extern void load_hba_and_ident(void); #endif diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 4fb64473924..99f7fae88bf 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.101 2002/03/04 01:46:04 tgl Exp $ + * $Id: miscadmin.h,v 1.102 2002/04/04 04:25:51 momjian Exp $ * * NOTES * some of the information in this file should be moved to @@ -219,7 +219,6 @@ extern int FindExec(char *full_path, const char *argv0, extern int CheckPathAccess(char *path, char *name, int open_mode); #ifdef CYR_RECODE -extern void GetCharSetByHost(char *TableName, int host, const char *DataDir); extern void SetCharSet(void); extern char *convertstr(unsigned char *buff, int len, int dest); #endif diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index be08da82371..39130f2a5e3 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -30,7 +30,7 @@ WHERE (p1.prolang = 0 OR p1.prorettype = 0 OR AND p1.proname !~ '^pl[^_]+_call_handler$' AND p1.proname !~ '^RI_FKey_' AND p1.proname !~ 'costestimate$' - AND p1.proname != 'update_pg_pwd'; + AND p1.proname != 'update_pg_pwd_and_pg_group'; oid | proname -----+--------- (0 rows) diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 7a5991a74a1..6a95c4cd1be 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -33,7 +33,7 @@ WHERE (p1.prolang = 0 OR p1.prorettype = 0 OR AND p1.proname !~ '^pl[^_]+_call_handler$' AND p1.proname !~ '^RI_FKey_' AND p1.proname !~ 'costestimate$' - AND p1.proname != 'update_pg_pwd'; + AND p1.proname != 'update_pg_pwd_and_pg_group'; -- Look for conflicting proc definitions (same names and input datatypes). -- (This test should be dead code now that we have the unique index |