From c0d4d5473a09cb7f6682a84abaee29e087c5886c Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 8 Sep 2001 15:24:00 +0000 Subject: Make the world somewhat safe for (not from) DELETE FROM pg_shadow; Assign the fixed user id 1 to the user created by initdb. A stand-alone backend will always set the user id to 1. (Consequently, the name of that user is no longer important.) In stand-alone mode, the user id 1 will have implicit superuser status, to allow repairs even if there are no users defined. Print a warning message when starting in stand-alone mode when no users are defined. Disallow dropping the current user and session user. Granting/revoking superuser status also grants/revokes usecatupd. (Previously, it would never grant it back. This could lead to "deadlocks".) CREATE USER and CREATE GROUP will start allocating user ids at 100 (unless explicitly specified), to prevent accidental creation of a superuser (plus some room for future extensions). --- src/backend/catalog/genbki.sh | 3 ++- src/backend/commands/user.c | 41 +++++++++++++++++++++------------ src/backend/utils/init/miscinit.c | 16 ++++++++++++- src/backend/utils/init/postinit.c | 47 ++++++++++++++++++++++++++++++++++---- src/backend/utils/misc/superuser.c | 6 ++++- src/bin/initdb/initdb.sh | 27 ++++++++++------------ src/include/catalog/catversion.h | 4 ++-- src/include/catalog/pg_shadow.h | 4 +++- src/include/miscadmin.h | 3 ++- 9 files changed, 110 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/backend/catalog/genbki.sh b/src/backend/catalog/genbki.sh index 25c8d7d2d4d..850c3295799 100644 --- a/src/backend/catalog/genbki.sh +++ b/src/backend/catalog/genbki.sh @@ -10,7 +10,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/catalog/Attic/genbki.sh,v 1.23 2001/08/26 16:55:59 tgl Exp $ +# $Header: /cvsroot/pgsql/src/backend/catalog/Attic/genbki.sh,v 1.24 2001/09/08 15:24:00 petere Exp $ # # NOTES # non-essential whitespace is removed from the generated file. @@ -183,6 +183,7 @@ sed -e "s/;[ ]*$//g" \ -e "s/[ ]TransactionId/ xid/g" \ -e "s/^TransactionId/xid/g" \ -e "s/(TransactionId/(xid/g" \ + -e "s/PGUID/1/g" \ -e "s/NAMEDATALEN/$NAMEDATALEN/g" \ -e "s/DEFAULT_ATTSTATTARGET/$DEFAULTATTSTATTARGET/g" \ -e "s/INDEX_MAX_KEYS\*2/$INDEXMAXKEYS2/g" \ diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index d830dfdfc90..122a4903615 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.82 2001/08/17 02:59:19 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.83 2001/09/08 15:24:00 petere Exp $ * *------------------------------------------------------------------------- */ @@ -198,7 +198,7 @@ CreateUser(CreateUserStmt *stmt) bool user_exists = false, sysid_exists = false, havesysid = false; - int max_id = -1; + int max_id; List *item, *option; char *password = NULL; /* PostgreSQL user password */ bool encrypt_password = Password_encryption; /* encrypt password? */ @@ -268,6 +268,8 @@ CreateUser(CreateUserStmt *stmt) if (dsysid) { sysid = intVal(dsysid->arg); + if (sysid <= 0) + elog(ERROR, "user id must be positive"); havesysid = true; } if (dvalidUntil) @@ -294,6 +296,7 @@ CreateUser(CreateUserStmt *stmt) pg_shadow_dsc = RelationGetDescr(pg_shadow_rel); scan = heap_beginscan(pg_shadow_rel, false, SnapshotNow, 0, NULL); + max_id = 99; /* start auto-assigned ids at 100 */ while (!user_exists && !sysid_exists && HeapTupleIsValid(tuple = heap_getnext(scan, 0))) { @@ -550,31 +553,31 @@ AlterUser(AlterUserStmt *stmt) new_record[Anum_pg_shadow_usetrace - 1] = heap_getattr(tuple, Anum_pg_shadow_usetrace, pg_shadow_dsc, &null); new_record_nulls[Anum_pg_shadow_usetrace - 1] = null ? 'n' : ' '; - /* createuser (superuser) */ + /* + * createuser (superuser) and catupd + * + * XXX It's rather unclear how to handle catupd. It's probably + * best to keep it equal to the superuser status, otherwise you + * could end up with a situation where no existing superuser can + * alter the catalogs, including pg_shadow! + */ if (createuser < 0) { /* don't change */ new_record[Anum_pg_shadow_usesuper - 1] = heap_getattr(tuple, Anum_pg_shadow_usesuper, pg_shadow_dsc, &null); new_record_nulls[Anum_pg_shadow_usesuper - 1] = null ? 'n' : ' '; + + new_record[Anum_pg_shadow_usecatupd - 1] = heap_getattr(tuple, Anum_pg_shadow_usecatupd, pg_shadow_dsc, &null); + new_record_nulls[Anum_pg_shadow_usecatupd - 1] = null ? 'n' : ' '; } else { new_record[Anum_pg_shadow_usesuper - 1] = BoolGetDatum(createuser > 0); new_record_nulls[Anum_pg_shadow_usesuper - 1] = ' '; - } - /* catupd - set to false if someone's superuser priv is being yanked */ - if (createuser == 0) - { - new_record[Anum_pg_shadow_usecatupd - 1] = BoolGetDatum(false); + new_record[Anum_pg_shadow_usecatupd - 1] = BoolGetDatum(createuser > 0); new_record_nulls[Anum_pg_shadow_usecatupd - 1] = ' '; } - else - { - /* leave alone */ - new_record[Anum_pg_shadow_usecatupd - 1] = heap_getattr(tuple, Anum_pg_shadow_usecatupd, pg_shadow_dsc, &null); - new_record_nulls[Anum_pg_shadow_usecatupd - 1] = null ? 'n' : ' '; - } /* password */ if (password) @@ -692,6 +695,11 @@ DropUser(DropUserStmt *stmt) usesysid = DatumGetInt32(heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &null)); + if (usesysid == GetUserId()) + elog(ERROR, "current user cannot be dropped"); + if (usesysid == GetSessionUserId()) + elog(ERROR, "session user cannot be dropped"); + /* * Check if user still owns a database. If so, error out. * @@ -825,7 +833,7 @@ CreateGroup(CreateGroupStmt *stmt) bool group_exists = false, sysid_exists = false, havesysid = false; - int max_id = 0; + int max_id; Datum new_record[Natts_pg_group]; char new_record_nulls[Natts_pg_group]; List *item, @@ -859,6 +867,8 @@ CreateGroup(CreateGroupStmt *stmt) if (dsysid) { sysid = intVal(dsysid->arg); + if (sysid <= 0) + elog(ERROR, "group id must be positive"); havesysid = true; } @@ -875,6 +885,7 @@ CreateGroup(CreateGroupStmt *stmt) pg_group_dsc = RelationGetDescr(pg_group_rel); scan = heap_beginscan(pg_group_rel, false, SnapshotNow, 0, NULL); + max_id = 99; /* start auto-assigned ids at 100 */ while (!group_exists && !sysid_exists && HeapTupleIsValid(tuple = heap_getnext(scan, false))) { diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index a57f3d2624a..e6da787bc4e 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.76 2001/08/15 07:07:40 ishii Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.77 2001/09/08 15:24:00 petere Exp $ * *------------------------------------------------------------------------- */ @@ -476,6 +476,20 @@ InitializeSessionUserId(const char *username) } +void +InitializeSessionUserIdStandalone(void) +{ + /* This function should only be called in a single-user backend. */ + AssertState(!IsUnderPostmaster); + + /* call only once */ + AssertState(!OidIsValid(SessionUserId)); + + SetSessionUserId(BOOTSTRAP_USESYSID); + AuthenticatedUserIsSuperuser = true; +} + + /* * Change session auth ID while running */ diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 51c95fb1415..60338397dbc 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.90 2001/09/07 00:27:29 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.91 2001/09/08 15:24:00 petere Exp $ * * *------------------------------------------------------------------------- @@ -25,6 +25,7 @@ #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/pg_database.h" +#include "catalog/pg_shadow.h" #include "commands/trigger.h" #include "commands/variable.h" /* for set_default_client_encoding() */ #include "mb/pg_wchar.h" @@ -43,6 +44,7 @@ static void ReverifyMyDatabase(const char *name); static void InitCommunication(void); static void ShutdownPostgres(void); +static bool ThereIsAtLeastOneUser(void); int lockingOff = 0; /* backend -L switch */ @@ -329,12 +331,24 @@ InitPostgres(const char *dbname, const char *username) LockDisable(true); /* - * Figure out our postgres user id. If bootstrapping, we can't - * assume that pg_shadow exists yet, so fake it. + * Figure out our postgres user id. In standalone mode we use a + * fixed id, otherwise we figure it out from the authenticated + * user name. */ if (bootstrap) - SetSessionUserId(geteuid()); + InitializeSessionUserIdStandalone(); + else if (!IsUnderPostmaster) + { + InitializeSessionUserIdStandalone(); + if (!ThereIsAtLeastOneUser()) + { + elog(NOTICE, "There are currently no users defined in this database system."); + elog(NOTICE, "You should immediately run 'CREATE USER \"%s\" WITH SYSID %d CREATEUSER;'.", + username, BOOTSTRAP_USESYSID); + } + } else + /* normal multiuser case */ InitializeSessionUserId(username); /* @@ -406,3 +420,28 @@ ShutdownPostgres(void) */ smgrDoPendingDeletes(false);/* delete as though aborting xact */ } + + + +/* + * Returns true if at least one user is defined in this database cluster. + */ +static bool +ThereIsAtLeastOneUser(void) +{ + Relation pg_shadow_rel; + TupleDesc pg_shadow_dsc; + HeapScanDesc scan; + bool result; + + pg_shadow_rel = heap_openr(ShadowRelationName, AccessExclusiveLock); + pg_shadow_dsc = RelationGetDescr(pg_shadow_rel); + + scan = heap_beginscan(pg_shadow_rel, false, SnapshotNow, 0, 0); + result = HeapTupleIsValid(heap_getnext(scan, 0)); + + heap_endscan(scan); + heap_close(pg_shadow_rel, AccessExclusiveLock); + + return result; +} diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c index 73cfe8cb979..2f092028480 100644 --- a/src/backend/utils/misc/superuser.c +++ b/src/backend/utils/misc/superuser.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.18 2001/06/13 21:44:41 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.19 2001/09/08 15:24:00 petere Exp $ * *------------------------------------------------------------------------- */ @@ -34,6 +34,10 @@ superuser(void) bool result = false; HeapTuple utup; + /* Special escape path in case you deleted all your users. */ + if (!IsUnderPostmaster && GetUserId() == BOOTSTRAP_USESYSID) + return true; + utup = SearchSysCache(SHADOWSYSID, ObjectIdGetDatum(GetUserId()), 0, 0, 0); diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh index 16f7cb95d3c..ae16fe1c0ec 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.136 2001/09/06 04:57:29 ishii Exp $ +# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.137 2001/09/08 15:24:00 petere Exp $ # #------------------------------------------------------------------------- @@ -183,7 +183,6 @@ show_setting= # user with the same name as the Unix user running it. That's # a security measure. POSTGRES_SUPERUSERNAME="$EffectiveUser" -POSTGRES_SUPERUSERID=`$PGPATH/pg_id -u` while [ "$#" -gt 0 ] do @@ -207,15 +206,15 @@ do noclean=yes echo "Running with noclean mode on. Mistakes will not be cleaned up." ;; -# The sysid of the database superuser. Can be freely changed. - --sysid|-i) - POSTGRES_SUPERUSERID="$2" +# The name of the database superuser. Can be freely changed. + --username|-U) + POSTGRES_SUPERUSERNAME="$2" shift;; - --sysid=*) - POSTGRES_SUPERUSERID=`echo $1 | sed 's/^--sysid=//'` + --username=*) + POSTGRES_SUPERUSERNAME=`echo $1 | sed 's/^--username=//'` ;; - -i*) - POSTGRES_SUPERUSERID=`echo $1 | sed 's/^-i//'` + -U*) + POSTGRES_SUPERUSERNAME=`echo $1 | sed 's/^-U//'` ;; # The default password of the database superuser. # Make initdb prompt for the default password of the database superuser. @@ -276,7 +275,7 @@ if [ "$usage" ]; then if [ -n "$MULTIBYTE" ] ; then echo " -E, --encoding ENCODING Set the default multibyte encoding for new databases" fi - echo " -i, --sysid SYSID Database sysid for the superuser" + echo " -U, --username NAME Database superuser name" echo "Less commonly used options: " echo " -L DIRECTORY Where to find the input files" echo " -d, --debug Generate lots of debugging output" @@ -343,7 +342,7 @@ then echo echo "initdb variables:" for var in PGDATA datadir PGPATH MULTIBYTE MULTIBYTEID \ - POSTGRES_SUPERUSERNAME POSTGRES_SUPERUSERID POSTGRES_BKI \ + POSTGRES_SUPERUSERNAME POSTGRES_BKI \ POSTGRES_DESCR POSTGRESQL_CONF_SAMPLE \ PG_HBA_SAMPLE PG_IDENT_SAMPLE ; do eval "echo ' '$var=\$$var" @@ -384,11 +383,10 @@ done trap 'echo "Caught signal." ; exit_nicely' 1 2 3 15 # Let's go -echo "This database system will be initialized with user name \"$POSTGRES_SUPERUSERNAME\"." -echo "This user will own all the data files and must also own the server process." +echo "The files belonging to this database system will be owned by user \"$EffectiveUser\"." +echo "This user must also own the server process." echo - ########################################################################## # # CREATE DATABASE DIRECTORY @@ -467,7 +465,6 @@ mkdir "$PGDATA"/base/1 || exit_nicely cat "$POSTGRES_BKI" \ | sed -e "s/POSTGRES/$POSTGRES_SUPERUSERNAME/g" \ - -e "s/PGUID/$POSTGRES_SUPERUSERID/g" \ -e "s/ENCODING/$MULTIBYTEID/g" \ | "$PGPATH"/postgres -boot -x1 $PGSQL_OPT $BACKEND_TALK_ARG template1 \ || exit_nicely diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 0b67a37ad22..d583d886288 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: catversion.h,v 1.93 2001/08/26 16:56:00 tgl Exp $ + * $Id: catversion.h,v 1.94 2001/09/08 15:24:00 petere Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200108251 +#define CATALOG_VERSION_NO 200109081 #endif diff --git a/src/include/catalog/pg_shadow.h b/src/include/catalog/pg_shadow.h index 49320b4e7d9..7a88e868b74 100644 --- a/src/include/catalog/pg_shadow.h +++ b/src/include/catalog/pg_shadow.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_shadow.h,v 1.13 2001/08/10 18:57:41 tgl Exp $ + * $Id: pg_shadow.h,v 1.14 2001/09/08 15:24:00 petere Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -71,4 +71,6 @@ typedef FormData_pg_shadow *Form_pg_shadow; */ DATA(insert ( "POSTGRES" PGUID t t t t _null_ _null_ )); +#define BOOTSTRAP_USESYSID 1 + #endif /* PG_SHADOW_H */ diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 89e0670911b..be1fbdd4efc 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.89 2001/08/15 18:42:15 momjian Exp $ + * $Id: miscadmin.h,v 1.90 2001/09/08 15:24:00 petere Exp $ * * NOTES * some of the information in this file should be moved to @@ -211,6 +211,7 @@ extern void SetUserId(Oid userid); extern Oid GetSessionUserId(void); extern void SetSessionUserId(Oid userid); extern void InitializeSessionUserId(const char *username); +extern void InitializeSessionUserIdStandalone(void); extern void SetSessionAuthorization(const char *username); extern void SetDataDir(const char *dir); -- cgit v1.2.3