Index: src/backend/access/transam/xact.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/access/transam/xact.c,v retrieving revision 1.195 diff -u -r1.195 xact.c --- src/backend/access/transam/xact.c 31 Dec 2004 21:59:29 -0000 1.195 +++ src/backend/access/transam/xact.c 21 Jan 2005 05:43:46 -0000 @@ -1464,7 +1464,7 @@ /* NOTIFY commit must come before lower-level cleanup */ AtCommit_Notify(); - /* Update the flat password file if we changed pg_shadow or pg_group */ + /* Update the flat password file if we changed pg_shadow */ /* This should be the last step before commit */ AtEOXact_UpdatePasswordFile(true); Index: src/backend/catalog/Makefile =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/catalog/Makefile,v retrieving revision 1.53 diff -u -r1.53 Makefile --- src/backend/catalog/Makefile 21 Jul 2004 20:34:45 -0000 1.53 +++ src/backend/catalog/Makefile 21 Jan 2005 05:43:46 -0000 @@ -31,7 +31,7 @@ pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \ pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \ pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \ - pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \ + pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h \ pg_tablespace.h pg_depend.h indexing.h \ ) Index: src/backend/catalog/aclchk.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/catalog/aclchk.c,v retrieving revision 1.108 diff -u -r1.108 aclchk.c --- src/backend/catalog/aclchk.c 31 Dec 2004 21:59:38 -0000 1.108 +++ src/backend/catalog/aclchk.c 21 Jan 2005 05:43:46 -0000 @@ -24,7 +24,6 @@ #include "catalog/namespace.h" #include "catalog/pg_conversion.h" #include "catalog/pg_database.h" -#include "catalog/pg_group.h" #include "catalog/pg_language.h" #include "catalog/pg_namespace.h" #include "catalog/pg_opclass.h" @@ -1209,48 +1208,6 @@ } -AclId -get_grosysid(char *groname) -{ - HeapTuple tuple; - AclId id = 0; - - tuple = SearchSysCache(GRONAME, - PointerGetDatum(groname), - 0, 0, 0); - if (HeapTupleIsValid(tuple)) - { - id = ((Form_pg_group) GETSTRUCT(tuple))->grosysid; - ReleaseSysCache(tuple); - } - else - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("group \"%s\" does not exist", groname))); - return id; -} - -/* - * Convert group ID to name, or return NULL if group can't be found - */ -char * -get_groname(AclId grosysid) -{ - HeapTuple tuple; - char *name = NULL; - - tuple = SearchSysCache(GROSYSID, - ObjectIdGetDatum(grosysid), - 0, 0, 0); - if (HeapTupleIsValid(tuple)) - { - name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tuple))->groname)); - ReleaseSysCache(tuple); - } - return name; -} - - /* * Standardized reporting of aclcheck permissions failures. * @@ -1348,8 +1305,8 @@ AclMode mask, AclMaskHow how) { AclMode result; - bool usesuper, - usecatupd; + bool rolesuper, + rolecatupd; HeapTuple tuple; Form_pg_class classForm; Datum aclDatum; @@ -1358,7 +1315,7 @@ AclId ownerId; /* - * Validate userid, find out if he is superuser, also get usecatupd + * Validate userid, find out if he is superuser, also get rolecatupd */ tuple = SearchSysCache(SHADOWSYSID, ObjectIdGetDatum(userid), @@ -1368,11 +1325,11 @@ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("user with ID %u does not exist", userid))); - usecatupd = ((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd; + rolecatupd = ((Form_pg_shadow) GETSTRUCT(tuple))->rolecatupd; ReleaseSysCache(tuple); - usesuper = superuser_arg(userid); + rolesuper = superuser_arg(userid); /* * Now get the relation's tuple from pg_class @@ -1389,7 +1346,7 @@ /* * Deny anyone permission to update a system catalog unless - * pg_shadow.usecatupd is set. (This is to let superusers protect + * pg_shadow.rolecatupd is set. (This is to let superusers protect * themselves from themselves.) Also allow it if * allowSystemTableMods. * @@ -1400,7 +1357,7 @@ if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) && IsSystemClass(classForm) && classForm->relkind != RELKIND_VIEW && - !usecatupd && + !rolecatupd && !allowSystemTableMods) { #ifdef ACLDEBUG @@ -1412,7 +1369,7 @@ /* * Otherwise, superusers bypass all permission-checking. */ - if (usesuper) + if (rolesuper) { #ifdef ACLDEBUG elog(DEBUG2, "%u is superuser, home free", userid); Index: src/backend/catalog/heap.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/catalog/heap.c,v retrieving revision 1.279 diff -u -r1.279 heap.c --- src/backend/catalog/heap.c 10 Jan 2005 20:02:19 -0000 1.279 +++ src/backend/catalog/heap.c 21 Jan 2005 05:43:46 -0000 @@ -252,8 +252,6 @@ } else if (strcmp(ShadowRelationName, relname) == 0) relid = RelOid_pg_shadow; - else if (strcmp(GroupRelationName, relname) == 0) - relid = RelOid_pg_group; else if (strcmp(DatabaseRelationName, relname) == 0) relid = RelOid_pg_database; else if (strcmp(TableSpaceRelationName, relname) == 0) Index: src/backend/catalog/information_schema.sql =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/catalog/information_schema.sql,v retrieving revision 1.26 diff -u -r1.26 information_schema.sql --- src/backend/catalog/information_schema.sql 1 Jan 2005 20:44:14 -0000 1.26 +++ src/backend/catalog/information_schema.sql 21 Jan 2005 05:43:46 -0000 @@ -209,13 +209,13 @@ CREATE VIEW applicable_roles AS SELECT CAST(current_user AS sql_identifier) AS grantee, - CAST(g.groname AS sql_identifier) AS role_name, + CAST(g.rolename AS sql_identifier) AS role_name, CAST('NO' AS character_data) AS is_grantable - FROM pg_group g, pg_user u + FROM pg_shadow g, pg_user u - WHERE u.usesysid = ANY (g.grolist) - AND u.usename = current_user; + WHERE (g.isgroup IS TRUE AND u.rolesysid = ANY (g.grolist)) + AND u.rolename = current_user; GRANT SELECT ON applicable_roles TO PUBLIC; Index: src/backend/catalog/namespace.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/catalog/namespace.c,v retrieving revision 1.73 diff -u -r1.73 namespace.c --- src/backend/catalog/namespace.c 31 Dec 2004 21:59:38 -0000 1.73 +++ src/backend/catalog/namespace.c 21 Jan 2005 05:43:47 -0000 @@ -1550,7 +1550,7 @@ { char *uname; - uname = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename); + uname = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->rolename); namespaceId = GetSysCacheOid(NAMESPACENAME, CStringGetDatum(uname), 0, 0, 0); Index: src/backend/commands/dbcommands.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/dbcommands.c,v retrieving revision 1.148 diff -u -r1.148 dbcommands.c --- src/backend/commands/dbcommands.c 31 Dec 2004 21:59:41 -0000 1.148 +++ src/backend/commands/dbcommands.c 21 Jan 2005 05:43:47 -0000 @@ -1017,7 +1017,7 @@ if (!HeapTupleIsValid(utup)) retval = false; else - retval = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb; + retval = ((Form_pg_shadow) GETSTRUCT(utup))->rolecreatedb; ReleaseSysCache(utup); Index: src/backend/commands/user.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/user.c,v retrieving revision 1.147 diff -u -r1.147 user.c --- src/backend/commands/user.c 31 Dec 2004 21:59:42 -0000 1.147 +++ src/backend/commands/user.c 21 Jan 2005 05:43:47 -0000 @@ -21,7 +21,6 @@ #include "catalog/catname.h" #include "catalog/indexing.h" #include "catalog/pg_database.h" -#include "catalog/pg_group.h" #include "catalog/pg_shadow.h" #include "catalog/pg_type.h" #include "commands/user.h" @@ -39,7 +38,6 @@ #define PWD_FILE "pg_pwd" -#define USER_GROUP_FILE "pg_group" extern bool Password_encryption; @@ -57,7 +55,6 @@ * SubTransactionId is detected. */ static SubTransactionId user_file_update_subid = InvalidSubTransactionId; -static SubTransactionId group_file_update_subid = InvalidSubTransactionId; #define user_file_update_needed() \ do { \ @@ -65,13 +62,6 @@ user_file_update_subid = GetCurrentSubTransactionId(); \ } while (0) -#define group_file_update_needed() \ - do { \ - if (group_file_update_subid == InvalidSubTransactionId) \ - group_file_update_subid = GetCurrentSubTransactionId(); \ - } while (0) - - static void CheckPgUserAclNotNull(void); static void UpdateGroupMembership(Relation group_rel, HeapTuple group_tuple, List *members); @@ -101,26 +91,6 @@ /* - * 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. @@ -141,153 +111,6 @@ /* - * write_group_file: update the flat group file - */ -static void -write_group_file(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) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not write to temporary file \"%s\": %m", tempname))); - - /* - * Read pg_group and write the file. Note we use SnapshotSelf to - * ensure we see all effects of current transaction. (Perhaps could - * do a CommandCounterIncrement beforehand, instead?) - */ - scan = heap_beginscan(grel, SnapshotSelf, 0, NULL); - while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) - { - 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); - /* ignore NULL groupnames --- shouldn't happen */ - if (isnull) - continue; - groname = NameStr(*DatumGetName(datum)); - - /* - * Check for invalid characters in the group name. - */ - i = strcspn(groname, "\n"); - if (groname[i] != '\0') - { - ereport(LOG, - (errmsg("invalid group name \"%s\"", groname))); - continue; - } - - grolist_datum = heap_getattr(tuple, Anum_pg_group_grolist, dsc, &isnull); - /* Ignore NULL group lists */ - if (isnull) - continue; - - /* be sure the IdList is not toasted */ - grolist_p = DatumGetIdListP(grolist_datum); - - /* scan grolist */ - 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') - { - ereport(LOG, - (errmsg("invalid user name \"%s\"", usename))); - continue; - } - - /* - * File format is: "dbname" "user1" "user2" "user3" - */ - 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); - - if (FreeFile(fp)) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not write to temporary file \"%s\": %m", - tempname))); - - /* - * 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)) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not rename file \"%s\" to \"%s\": %m", - tempname, filename))); - - pfree(tempname); - pfree(filename); -} - - -/* * write_user_file: update the flat password file */ static void @@ -328,72 +151,145 @@ scan = heap_beginscan(urel, SnapshotSelf, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { - Datum datum; + Datum datum, + grolist_datum; bool isnull; - char *usename, - *passwd, - *valuntil; + bool isgroup; + char *rolename, + *usename, + *passwd, + *valuntil; + IdList *grolist_p; + AclId *aidp; int i; - datum = heap_getattr(tuple, Anum_pg_shadow_usename, dsc, &isnull); - /* ignore NULL usernames (shouldn't happen) */ - if (isnull) - continue; - usename = NameStr(*DatumGetName(datum)); - - datum = heap_getattr(tuple, Anum_pg_shadow_passwd, dsc, &isnull); - - /* - * It can be argued that people having a null password shouldn't - * be allowed to connect under password authentication, because - * they need to have a password set up first. If you think - * assuming an empty password in that case is better, change this - * logic to look something like the code for valuntil. - */ + datum = heap_getattr(tuple, Anum_pg_shadow_rolename, dsc, &isnull); + /* ignore NULL rolenames (shouldn't happen) */ if (isnull) continue; + rolename = NameStr(*DatumGetName(datum)); - passwd = DatumGetCString(DirectFunctionCall1(textout, datum)); + /* + * Check for illegal characters in the rolename. + */ + i = strcspn(rolename, "\n"); + if (rolename[i] != '\0') + { + ereport(LOG, + (errmsg("invalid role name \"%s\"", rolename))); + continue; + } - datum = heap_getattr(tuple, Anum_pg_shadow_valuntil, dsc, &isnull); + datum = heap_getattr(tuple, Anum_pg_shadow_isgroup, dsc, &isnull); + /* ignore NULL isgroup (shouldn't happen) */ if (isnull) - valuntil = pstrdup(""); - else - valuntil = DatumGetCString(DirectFunctionCall1(abstimeout, datum)); - - /* - * Check for illegal characters in the username and password. - */ - i = strcspn(usename, "\n"); - if (usename[i] != '\0') - { - ereport(LOG, - (errmsg("invalid user name \"%s\"", usename))); continue; - } - i = strcspn(passwd, "\n"); - if (passwd[i] != '\0') - { - ereport(LOG, - (errmsg("invalid user password \"%s\"", passwd))); - continue; - } + isgroup = DatumGetBool(datum); - /* - * 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. - */ - fputs_quote(usename, fp); - fputs(" ", fp); - fputs_quote(passwd, fp); - fputs(" ", fp); - fputs_quote(valuntil, fp); - fputs("\n", fp); + if (!isgroup) { + datum = heap_getattr(tuple, Anum_pg_shadow_passwd, dsc, &isnull); - pfree(passwd); - pfree(valuntil); - } + /* + * It can be argued that people having a null password shouldn't + * be allowed to connect under password authentication, because + * they need to have a password set up first. If you think + * assuming an empty password in that case is better, change this + * logic to look something like the code for valuntil. + */ + if (isnull) + continue; + + passwd = DatumGetCString(DirectFunctionCall1(textout, datum)); + + datum = heap_getattr(tuple, Anum_pg_shadow_valuntil, dsc, &isnull); + if (isnull) + valuntil = pstrdup(""); + else + valuntil = DatumGetCString(DirectFunctionCall1(abstimeout, datum)); + + /* + * Check for illegal characters in the password. + */ + i = strcspn(passwd, "\n"); + if (passwd[i] != '\0') + { + ereport(LOG, + (errmsg("invalid user password \"%s\"", passwd))); + continue; + } + + /* + * 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. + */ + fputs_quote(rolename, fp); + fputs(" ", fp); + fputs_quote(passwd, fp); + fputs(" ", fp); + fputs_quote(valuntil, fp); + fputs("\n", fp); + + pfree(passwd); + pfree(valuntil); + } else { + int num, j; + bool first_user = true; + + grolist_datum = heap_getattr(tuple, Anum_pg_shadow_grolist, dsc, &isnull); + /* Ignore NULL group lists */ + if (isnull) + continue; + + /* be sure the IdList is not toasted */ + grolist_p = DatumGetIdListP(grolist_datum); + + /* scan grolist */ + 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))->rolename); + /* + * Check for illegal characters in the user name. + */ + j = strcspn(usename, "\n"); + if (usename[j] != '\0') + { + ereport(LOG, + (errmsg("invalid user name \"%s\"", usename))); + continue; + } + + /* + * File format is: +"groname" "user1" "user2" "user3" + */ + if (first_user) + { + fputs("+", fp); + fputs_quote(rolename, 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); if (FreeFile(fp)) @@ -418,7 +314,7 @@ /* - * This trigger is fired whenever someone modifies pg_shadow or pg_group + * This trigger is fired whenever someone modifies pg_shadow * via general-purpose INSERT/UPDATE/DELETE commands. * * XXX should probably have two separate triggers. @@ -427,7 +323,6 @@ update_pg_pwd_and_pg_group(PG_FUNCTION_ARGS) { user_file_update_needed(); - group_file_update_needed(); return PointerGetDatum(NULL); } @@ -451,16 +346,13 @@ AtEOXact_UpdatePasswordFile(bool isCommit) { Relation urel = NULL; - Relation grel = NULL; - if (user_file_update_subid == InvalidSubTransactionId && - group_file_update_subid == InvalidSubTransactionId) + if (user_file_update_subid == InvalidSubTransactionId) return; if (!isCommit) { user_file_update_subid = InvalidSubTransactionId; - group_file_update_subid = InvalidSubTransactionId; return; } @@ -474,10 +366,8 @@ */ if (user_file_update_subid != InvalidSubTransactionId) urel = heap_openr(ShadowRelationName, ExclusiveLock); - if (group_file_update_subid != InvalidSubTransactionId) - grel = heap_openr(GroupRelationName, ExclusiveLock); - /* Okay to write the files */ + /* Okay to write the file */ if (user_file_update_subid != InvalidSubTransactionId) { user_file_update_subid = InvalidSubTransactionId; @@ -485,13 +375,6 @@ heap_close(urel, NoLock); } - if (group_file_update_subid != InvalidSubTransactionId) - { - group_file_update_subid = InvalidSubTransactionId; - write_group_file(grel); - heap_close(grel, NoLock); - } - /* * Signal the postmaster to reload its password & group-file cache. */ @@ -513,17 +396,11 @@ { if (user_file_update_subid == mySubid) user_file_update_subid = parentSubid; - - if (group_file_update_subid == mySubid) - group_file_update_subid = parentSubid; } else { if (user_file_update_subid == mySubid) user_file_update_subid = InvalidSubTransactionId; - - if (group_file_update_subid == mySubid) - group_file_update_subid = InvalidSubTransactionId; } } @@ -550,6 +427,7 @@ char encrypted_password[MD5_PASSWD_LEN + 1]; int sysid = 0; /* PgSQL system id (valid if havesysid) */ bool createdb = false; /* Can the user create databases? */ + bool isgroup = false; /* Can the user create databases? */ bool createuser = false; /* Can this user create users? */ List *groupElts = NIL; /* The groups the user is a member of */ char *validUntil = NULL; /* The time the login is valid @@ -677,9 +555,9 @@ Form_pg_shadow shadow_form = (Form_pg_shadow) GETSTRUCT(tuple); int32 this_sysid; - user_exists = (strcmp(NameStr(shadow_form->usename), stmt->user) == 0); + user_exists = (strcmp(NameStr(shadow_form->rolename), stmt->user) == 0); - this_sysid = shadow_form->usesysid; + this_sysid = shadow_form->rolesysid; if (havesysid) /* customized id wanted */ sysid_exists = (this_sysid == sysid); else @@ -694,12 +572,12 @@ if (user_exists) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("user \"%s\" already exists", + errmsg("role \"%s\" already exists", stmt->user))); if (sysid_exists) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("user ID %d is already assigned", sysid))); + errmsg("role ID %d is already assigned", sysid))); /* If no sysid given, use max existing id + 1 */ if (!havesysid) @@ -711,15 +589,17 @@ MemSet(new_record, 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); - new_record[Anum_pg_shadow_usename - 1] = + new_record[Anum_pg_shadow_rolename - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->user)); - new_record[Anum_pg_shadow_usesysid - 1] = Int32GetDatum(sysid); + new_record[Anum_pg_shadow_rolesysid - 1] = Int32GetDatum(sysid); AssertState(BoolIsValid(createdb)); - new_record[Anum_pg_shadow_usecreatedb - 1] = BoolGetDatum(createdb); + new_record[Anum_pg_shadow_rolecreatedb - 1] = BoolGetDatum(createdb); AssertState(BoolIsValid(createuser)); - new_record[Anum_pg_shadow_usesuper - 1] = BoolGetDatum(createuser); + new_record[Anum_pg_shadow_rolesuper - 1] = BoolGetDatum(createuser); /* superuser gets catupd right by default */ - new_record[Anum_pg_shadow_usecatupd - 1] = BoolGetDatum(createuser); + new_record[Anum_pg_shadow_rolecatupd - 1] = BoolGetDatum(createuser); + AssertState(BoolIsValid(isgroup)); + new_record[Anum_pg_shadow_isgroup - 1] = BoolGetDatum(isgroup); if (password) { @@ -745,6 +625,7 @@ new_record_nulls[Anum_pg_shadow_valuntil - 1] = 'n'; new_record_nulls[Anum_pg_shadow_useconfig - 1] = 'n'; + new_record_nulls[Anum_pg_shadow_grolist - 1] = 'n'; tuple = heap_formtuple(pg_shadow_dsc, new_record, new_record_nulls); @@ -898,6 +779,11 @@ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("user \"%s\" does not exist", stmt->user))); + if (((Form_pg_shadow) GETSTRUCT(tuple))->isgroup) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("\"%s\" is not a user", stmt->user))); + /* * Build an updated tuple, perusing the information just obtained */ @@ -905,15 +791,15 @@ MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); MemSet(new_record_repl, ' ', sizeof(new_record_repl)); - new_record[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein, + new_record[Anum_pg_shadow_rolename - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->user)); - new_record_repl[Anum_pg_shadow_usename - 1] = 'r'; + new_record_repl[Anum_pg_shadow_rolename - 1] = 'r'; /* createdb */ if (createdb >= 0) { - new_record[Anum_pg_shadow_usecreatedb - 1] = BoolGetDatum(createdb > 0); - new_record_repl[Anum_pg_shadow_usecreatedb - 1] = 'r'; + new_record[Anum_pg_shadow_rolecreatedb - 1] = BoolGetDatum(createdb > 0); + new_record_repl[Anum_pg_shadow_rolecreatedb - 1] = 'r'; } /* @@ -926,11 +812,11 @@ */ if (createuser >= 0) { - new_record[Anum_pg_shadow_usesuper - 1] = BoolGetDatum(createuser > 0); - new_record_repl[Anum_pg_shadow_usesuper - 1] = 'r'; + new_record[Anum_pg_shadow_rolesuper - 1] = BoolGetDatum(createuser > 0); + new_record_repl[Anum_pg_shadow_rolesuper - 1] = 'r'; - new_record[Anum_pg_shadow_usecatupd - 1] = BoolGetDatum(createuser > 0); - new_record_repl[Anum_pg_shadow_usecatupd - 1] = 'r'; + new_record[Anum_pg_shadow_rolecatupd - 1] = BoolGetDatum(createuser > 0); + new_record_repl[Anum_pg_shadow_rolecatupd - 1] = 'r'; } /* password */ @@ -1011,8 +897,13 @@ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("user \"%s\" does not exist", stmt->user))); + if (((Form_pg_shadow) GETSTRUCT(oldtuple))->isgroup) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("\"%s\" is not a user", stmt->user))); + if (!(superuser() || - ((Form_pg_shadow) GETSTRUCT(oldtuple))->usesysid == GetUserId())) + ((Form_pg_shadow) GETSTRUCT(oldtuple))->rolesysid == GetUserId())) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied"))); @@ -1103,7 +994,12 @@ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("user \"%s\" does not exist", user))); - usesysid = ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid; + if (((Form_pg_shadow) GETSTRUCT(tuple))->isgroup) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("\"%s\" is not a user", user))); + + usesysid = ((Form_pg_shadow) GETSTRUCT(tuple))->rolesysid; if (usesysid == GetUserId()) ereport(ERROR, @@ -1172,7 +1068,7 @@ AlterGroupStmt ags; /* the group name from which to try to drop the user: */ - ags.name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tmp_tuple))->groname)); + ags.name = pstrdup(NameStr(((Form_pg_shadow) GETSTRUCT(tmp_tuple))->rolename)); ags.action = -1; ags.listUsers = list_make1(makeInteger(usesysid)); AlterGroup(&ags, "DROP USER"); @@ -1232,13 +1128,18 @@ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("user \"%s\" does not exist", oldname))); + if (((Form_pg_shadow) GETSTRUCT(oldtuple))->isgroup) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("\"%s\" is not a user", oldname))); + /* * XXX Client applications probably store the session user somewhere, * so renaming it could cause confusion. On the other hand, there may * not be an actual problem besides a little confusion, so think about * this and decide. */ - if (((Form_pg_shadow) GETSTRUCT(oldtuple))->usesysid == GetSessionUserId()) + if (((Form_pg_shadow) GETSTRUCT(oldtuple))->rolesysid == GetSessionUserId()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("session user may not be renamed"))); @@ -1260,10 +1161,10 @@ for (i = 0; i < Natts_pg_shadow; i++) repl_repl[i] = ' '; - repl_repl[Anum_pg_shadow_usename - 1] = 'r'; - repl_val[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein, + repl_repl[Anum_pg_shadow_rolename - 1] = 'r'; + repl_val[Anum_pg_shadow_rolename - 1] = DirectFunctionCall1(namein, CStringGetDatum(newname)); - repl_null[Anum_pg_shadow_usename - 1] = ' '; + repl_null[Anum_pg_shadow_rolename - 1] = ' '; datum = heap_getattr(oldtuple, Anum_pg_shadow_passwd, dsc, &isnull); @@ -1325,16 +1226,17 @@ void CreateGroup(CreateGroupStmt *stmt) { - Relation pg_group_rel; + Relation pg_shadow_rel; HeapScanDesc scan; HeapTuple tuple; - TupleDesc pg_group_dsc; + TupleDesc pg_shadow_dsc; bool group_exists = false, sysid_exists = false, - havesysid = false; + havesysid = false, + isgroup = true; int max_id; - Datum new_record[Natts_pg_group]; - char new_record_nulls[Natts_pg_group]; + Datum new_record[Natts_pg_shadow]; + char new_record_nulls[Natts_pg_shadow]; ListCell *item; ListCell *option; List *newlist = NIL; @@ -1402,20 +1304,20 @@ * to be sure of what the next grosysid should be, and we need to * protect our eventual update of the flat group file. */ - pg_group_rel = heap_openr(GroupRelationName, ExclusiveLock); - pg_group_dsc = RelationGetDescr(pg_group_rel); + pg_shadow_rel = heap_openr(ShadowRelationName, ExclusiveLock); + pg_shadow_dsc = RelationGetDescr(pg_shadow_rel); - scan = heap_beginscan(pg_group_rel, SnapshotNow, 0, NULL); + scan = heap_beginscan(pg_shadow_rel, SnapshotNow, 0, NULL); max_id = 99; /* start auto-assigned ids at 100 */ while (!group_exists && !sysid_exists && (tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { - Form_pg_group group_form = (Form_pg_group) GETSTRUCT(tuple); + Form_pg_shadow shadow_form = (Form_pg_shadow) GETSTRUCT(tuple); int32 this_sysid; - group_exists = (strcmp(NameStr(group_form->groname), stmt->name) == 0); + group_exists = (strcmp(NameStr(shadow_form->rolename), stmt->name) == 0); - this_sysid = group_form->grosysid; + this_sysid = shadow_form->rolesysid; if (havesysid) /* customized id wanted */ sysid_exists = (this_sysid == sysid); else @@ -1430,12 +1332,12 @@ if (group_exists) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("group \"%s\" already exists", + errmsg("role \"%s\" already exists", stmt->name))); if (sysid_exists) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("group ID %d is already assigned", sysid))); + errmsg("role ID %d is already assigned", sysid))); /* If no sysid given, use max existing id + 1 */ if (!havesysid) @@ -1462,35 +1364,41 @@ /* * Form a tuple to insert */ - new_record[Anum_pg_group_groname - 1] = + new_record[Anum_pg_shadow_rolename - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->name)); - new_record[Anum_pg_group_grosysid - 1] = Int32GetDatum(sysid); - new_record[Anum_pg_group_grolist - 1] = PointerGetDatum(grolist); + new_record[Anum_pg_shadow_rolesysid - 1] = Int32GetDatum(sysid); - new_record_nulls[Anum_pg_group_groname - 1] = ' '; - new_record_nulls[Anum_pg_group_grosysid - 1] = ' '; - new_record_nulls[Anum_pg_group_grolist - 1] = grolist ? ' ' : 'n'; + AssertState(BoolIsValid(isgroup)); + new_record[Anum_pg_shadow_isgroup - 1] = BoolGetDatum(isgroup); + new_record[Anum_pg_shadow_grolist - 1] = PointerGetDatum(grolist); + + new_record_nulls[Anum_pg_shadow_rolename - 1] = ' '; + new_record_nulls[Anum_pg_shadow_rolesysid - 1] = ' '; + new_record_nulls[Anum_pg_shadow_rolecreatedb - 1] = 'n'; + new_record_nulls[Anum_pg_shadow_rolesuper - 1] = 'n'; + new_record_nulls[Anum_pg_shadow_rolecatupd - 1] = 'n'; + new_record_nulls[Anum_pg_shadow_grolist - 1] = grolist ? ' ' : 'n'; - tuple = heap_formtuple(pg_group_dsc, new_record, new_record_nulls); + tuple = heap_formtuple(pg_shadow_dsc, new_record, new_record_nulls); /* * Insert a new record in the pg_group table */ - simple_heap_insert(pg_group_rel, tuple); + simple_heap_insert(pg_shadow_rel, tuple); /* Update indexes */ - CatalogUpdateIndexes(pg_group_rel, tuple); + CatalogUpdateIndexes(pg_shadow_rel, tuple); /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ - heap_close(pg_group_rel, NoLock); + heap_close(pg_shadow_rel, NoLock); /* * Set flag to update flat group file at commit. */ - group_file_update_needed(); + user_file_update_needed(); } @@ -1500,8 +1408,8 @@ void AlterGroup(AlterGroupStmt *stmt, const char *tag) { - Relation pg_group_rel; - TupleDesc pg_group_dsc; + Relation pg_shadow_rel; + TupleDesc pg_shadow_dsc; HeapTuple group_tuple; IdList *oldarray; Datum datum; @@ -1520,13 +1428,13 @@ /* * Secure exclusive lock to protect our update of the flat group file. */ - pg_group_rel = heap_openr(GroupRelationName, ExclusiveLock); - pg_group_dsc = RelationGetDescr(pg_group_rel); + pg_shadow_rel = heap_openr(ShadowRelationName, ExclusiveLock); + pg_shadow_dsc = RelationGetDescr(pg_shadow_rel); /* * Fetch existing tuple for group. */ - group_tuple = SearchSysCache(GRONAME, + group_tuple = SearchSysCache(SHADOWNAME, PointerGetDatum(stmt->name), 0, 0, 0); if (!HeapTupleIsValid(group_tuple)) @@ -1534,9 +1442,14 @@ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("group \"%s\" does not exist", stmt->name))); + if (!(((Form_pg_shadow) GETSTRUCT(group_tuple))->isgroup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("\"%s\" is not a group", stmt->name))); + /* Fetch old group membership. */ - datum = heap_getattr(group_tuple, Anum_pg_group_grolist, - pg_group_dsc, &null); + datum = heap_getattr(group_tuple, Anum_pg_shadow_grolist, + pg_shadow_dsc, &null); oldarray = null ? NULL : DatumGetIdListP(datum); /* initialize list with old array contents */ @@ -1582,7 +1495,7 @@ } /* Do the update */ - UpdateGroupMembership(pg_group_rel, group_tuple, newlist); + UpdateGroupMembership(pg_shadow_rel, group_tuple, newlist); } /* endif alter group add user */ else if (stmt->action == -1) /* drop users from group */ @@ -1627,7 +1540,7 @@ } /* Do the update */ - UpdateGroupMembership(pg_group_rel, group_tuple, newlist); + UpdateGroupMembership(pg_shadow_rel, group_tuple, newlist); } /* endif group not null */ } /* endif alter group drop user */ @@ -1637,12 +1550,12 @@ * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ - heap_close(pg_group_rel, NoLock); + heap_close(pg_shadow_rel, NoLock); /* * Set flag to update flat group file at commit. */ - group_file_update_needed(); + user_file_update_needed(); } /* @@ -1655,9 +1568,9 @@ List *members) { IdList *newarray; - Datum new_record[Natts_pg_group]; - char new_record_nulls[Natts_pg_group]; - char new_record_repl[Natts_pg_group]; + Datum new_record[Natts_pg_shadow]; + char new_record_nulls[Natts_pg_shadow]; + char new_record_repl[Natts_pg_shadow]; HeapTuple tuple; newarray = IdListToArray(members); @@ -1669,8 +1582,8 @@ MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); MemSet(new_record_repl, ' ', sizeof(new_record_repl)); - new_record[Anum_pg_group_grolist - 1] = PointerGetDatum(newarray); - new_record_repl[Anum_pg_group_grolist - 1] = 'r'; + new_record[Anum_pg_shadow_grolist - 1] = PointerGetDatum(newarray); + new_record_repl[Anum_pg_shadow_grolist - 1] = 'r'; tuple = heap_modifytuple(group_tuple, group_rel, new_record, new_record_nulls, new_record_repl); @@ -1745,7 +1658,7 @@ void DropGroup(DropGroupStmt *stmt) { - Relation pg_group_rel; + Relation pg_shadow_rel; HeapTuple tuple; /* @@ -1759,7 +1672,7 @@ /* * Secure exclusive lock to protect our update of the flat group file. */ - pg_group_rel = heap_openr(GroupRelationName, ExclusiveLock); + pg_shadow_rel = heap_openr(ShadowRelationName, ExclusiveLock); /* Find and delete the group. */ @@ -1771,18 +1684,23 @@ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("group \"%s\" does not exist", stmt->name))); - simple_heap_delete(pg_group_rel, &tuple->t_self); + if (!(((Form_pg_shadow) GETSTRUCT(tuple))->isgroup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("\"%s\" is not a group", stmt->name))); + + simple_heap_delete(pg_shadow_rel, &tuple->t_self); /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ - heap_close(pg_group_rel, NoLock); + heap_close(pg_shadow_rel, NoLock); /* * Set flag to update flat group file at commit. */ - group_file_update_needed(); + user_file_update_needed(); } @@ -1796,9 +1714,9 @@ Relation rel; /* ExclusiveLock because we need to update the flat group file */ - rel = heap_openr(GroupRelationName, ExclusiveLock); + rel = heap_openr(ShadowRelationName, ExclusiveLock); - tup = SearchSysCacheCopy(GRONAME, + tup = SearchSysCacheCopy(SHADOWNAME, CStringGetDatum(oldname), 0, 0, 0); if (!HeapTupleIsValid(tup)) @@ -1806,13 +1724,18 @@ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("group \"%s\" does not exist", oldname))); + if (!(((Form_pg_shadow) GETSTRUCT(tup))->isgroup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("\"%s\" is not a group", oldname))); + /* make sure the new name doesn't exist */ - if (SearchSysCacheExists(GRONAME, + if (SearchSysCacheExists(SHADOWNAME, CStringGetDatum(newname), 0, 0, 0)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("group \"%s\" already exists", newname))); + errmsg("role \"%s\" already exists", newname))); /* must be superuser */ if (!superuser()) @@ -1821,12 +1744,12 @@ errmsg("must be superuser to rename groups"))); /* rename */ - namestrcpy(&(((Form_pg_group) GETSTRUCT(tup))->groname), newname); + namestrcpy(&(((Form_pg_shadow) GETSTRUCT(tup))->rolename), newname); simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); heap_close(rel, NoLock); heap_freetuple(tup); - group_file_update_needed(); + user_file_update_needed(); } Index: src/backend/commands/variable.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/variable.c,v retrieving revision 1.105 diff -u -r1.105 variable.c --- src/backend/commands/variable.c 31 Dec 2004 21:59:42 -0000 1.105 +++ src/backend/commands/variable.c 21 Jan 2005 05:43:47 -0000 @@ -665,8 +665,8 @@ return NULL; } - usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid; - is_superuser = ((Form_pg_shadow) GETSTRUCT(userTup))->usesuper; + usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->rolesysid; + is_superuser = ((Form_pg_shadow) GETSTRUCT(userTup))->rolesuper; actual_username = value; ReleaseSysCache(userTup); Index: src/backend/libpq/hba.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/libpq/hba.c,v retrieving revision 1.136 diff -u -r1.136 hba.c --- src/backend/libpq/hba.c 31 Dec 2004 21:59:50 -0000 1.136 +++ src/backend/libpq/hba.c 21 Jan 2005 05:43:47 -0000 @@ -67,10 +67,6 @@ static List *ident_lines = NIL; static List *ident_line_nums = NIL; -/* pre-parsed content of group file and corresponding line #s */ -static List *group_lines = NIL; -static List *group_line_nums = NIL; - /* pre-parsed content of user passwd file and corresponding line #s */ static List *user_lines = NIL; static List *user_line_nums = NIL; @@ -919,64 +915,7 @@ /* - * Load group/user name mapping file - */ -void -load_group(void) -{ - char *filename; - FILE *group_file; - - /* Discard any old data */ - if (group_lines || group_line_nums) - free_lines(&group_lines, &group_line_nums); - if (group_sorted) - pfree(group_sorted); - group_sorted = NULL; - group_length = 0; - - /* Read in the file contents */ - filename = group_getfilename(); - group_file = AllocateFile(filename, "r"); - - if (group_file == NULL) - { - /* no complaint if not there */ - if (errno != ENOENT) - ereport(LOG, - (errcode_for_file_access(), - errmsg("could not open file \"%s\": %m", filename))); - pfree(filename); - return; - } - - tokenize_file(filename, group_file, &group_lines, &group_line_nums); - - FreeFile(group_file); - pfree(filename); - - /* create sorted lines for binary searching */ - group_length = list_length(group_lines); - if (group_length) - { - int i = 0; - ListCell *line; - - 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_qsort_cmp); - } -} - - -/* - * Load user/password mapping file + * Load user/password/group mapping file */ void load_user(void) @@ -1014,20 +953,31 @@ /* create sorted lines for binary searching */ user_length = list_length(user_lines); + group_length = list_length(user_lines); if (user_length) { - int i = 0; + int i = 0, j = 0; ListCell *line; user_sorted = palloc(user_length * sizeof(List *)); + group_sorted = palloc(group_length * sizeof(List *)); + + foreach(line, user_lines) { + if (!memcmp(lfirst(line),"+",1)) group_sorted[j++] = lfirst(line); else user_sorted[i++] = lfirst(line); + } - foreach(line, user_lines) - user_sorted[i++] = lfirst(line); + user_length = i; + group_length = j; qsort((void *) user_sorted, user_length, sizeof(List *), user_group_qsort_cmp); + + qsort((void *) group_sorted, + group_length, + sizeof(List *), + user_group_qsort_cmp); } } Index: src/backend/postmaster/postmaster.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v retrieving revision 1.443 diff -u -r1.443 postmaster.c --- src/backend/postmaster/postmaster.c 12 Jan 2005 16:38:17 -0000 1.443 +++ src/backend/postmaster/postmaster.c 21 Jan 2005 05:43:48 -0000 @@ -908,7 +908,6 @@ load_hba(); load_ident(); load_user(); - load_group(); /* * We're ready to rock and roll... @@ -2681,7 +2680,6 @@ load_hba(); load_ident(); load_user(); - load_group(); #endif /* @@ -3309,7 +3307,6 @@ * Password or group file has changed. */ load_user(); - load_group(); } if (CheckPostmasterSignal(PMSIGNAL_WAKEN_CHILDREN)) Index: src/backend/utils/adt/acl.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/acl.c,v retrieving revision 1.113 diff -u -r1.113 acl.c --- src/backend/utils/adt/acl.c 31 Dec 2004 22:01:21 -0000 1.113 +++ src/backend/utils/adt/acl.c 21 Jan 2005 05:43:48 -0000 @@ -393,7 +393,7 @@ 0, 0, 0); if (HeapTupleIsValid(htup)) { - putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename)); + putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->rolename)); ReleaseSysCache(htup); } else @@ -442,7 +442,7 @@ 0, 0, 0); if (HeapTupleIsValid(htup)) { - putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename)); + putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->rolename)); ReleaseSysCache(htup); } else @@ -1088,40 +1088,48 @@ int i, num; - tuple = SearchSysCache(GROSYSID, + tuple = SearchSysCache(SHADOWSYSID, ObjectIdGetDatum(gid), 0, 0, 0); - if (HeapTupleIsValid(tuple)) - { - att = SysCacheGetAttr(GROSYSID, - tuple, - Anum_pg_group_grolist, - &isNull); - if (!isNull) + if (!HeapTupleIsValid(tuple)) { + ereport(WARNING, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("group with ID %u does not exist", gid))); + return result; + } + + if (!(((Form_pg_shadow) GETSTRUCT(tuple))->isgroup)) { + ereport(WARNING, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("ID %u is not a group", gid))); + return result; + } + + att = SysCacheGetAttr(SHADOWSYSID, + tuple, + Anum_pg_shadow_grolist, + &isNull); + if (!isNull) + { + /* be sure the IdList is not toasted */ + glist = DatumGetIdListP(att); + /* scan it */ + num = IDLIST_NUM(glist); + aidp = IDLIST_DAT(glist); + for (i = 0; i < num; ++i) { - /* be sure the IdList is not toasted */ - glist = DatumGetIdListP(att); - /* scan it */ - num = IDLIST_NUM(glist); - aidp = IDLIST_DAT(glist); - for (i = 0; i < num; ++i) + if (aidp[i] == uid) { - if (aidp[i] == uid) - { - result = true; - break; - } + result = true; + break; } - /* if IdList was toasted, free detoasted copy */ - if ((Pointer) glist != DatumGetPointer(att)) - pfree(glist); } - ReleaseSysCache(tuple); + /* if IdList was toasted, free detoasted copy */ + if ((Pointer) glist != DatumGetPointer(att)) + pfree(glist); } - else - ereport(WARNING, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("group with ID %u does not exist", gid))); + ReleaseSysCache(tuple); + return result; } Index: src/backend/utils/adt/ruleutils.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v retrieving revision 1.188 diff -u -r1.188 ruleutils.c --- src/backend/utils/adt/ruleutils.c 13 Jan 2005 17:19:10 -0000 1.188 +++ src/backend/utils/adt/ruleutils.c 21 Jan 2005 05:43:48 -0000 @@ -1211,7 +1211,7 @@ if (HeapTupleIsValid(usertup)) { user_rec = (Form_pg_shadow) GETSTRUCT(usertup); - StrNCpy(NameStr(*result), NameStr(user_rec->usename), NAMEDATALEN); + StrNCpy(NameStr(*result), NameStr(user_rec->rolename), NAMEDATALEN); ReleaseSysCache(usertup); } else Index: src/backend/utils/cache/lsyscache.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v retrieving revision 1.119 diff -u -r1.119 lsyscache.c --- src/backend/utils/cache/lsyscache.c 31 Dec 2004 22:01:25 -0000 1.119 +++ src/backend/utils/cache/lsyscache.c 21 Jan 2005 05:43:49 -0000 @@ -2023,16 +2023,16 @@ * * Given a user name, look up the user's sysid. * Raises an error if no such user (rather than returning zero, - * which might possibly be a valid usesysid). + * which might possibly be a valid rolesysid). * - * Note: the type of usesysid is currently int4, but may change to Oid + * Note: the type of rolesysid is currently int4, but may change to Oid * someday. It'd be reasonable to return zero on failure if we were * using Oid ... */ AclId get_usesysid(const char *username) { - int32 result; + AclId result; HeapTuple userTup; userTup = SearchSysCache(SHADOWNAME, @@ -2043,9 +2043,75 @@ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("user \"%s\" does not exist", username))); - result = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid; + if ((((Form_pg_shadow) GETSTRUCT(userTup))->isgroup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("\"%s\" is not a user", username))); + + result = ((Form_pg_shadow) GETSTRUCT(userTup))->rolesysid; ReleaseSysCache(userTup); return result; } + +/* + * get_grosysid + * + * Given a group name, look up the group's sysid. + * Raises an error if no such group (rather than returning zero, + * which might possibly be a valid grosysid). + * + * Note: the type of rolesysid is currently int4, but may change to Oid + * someday. It'd be reasonable to return zero on failure if we were + * using Oid ... + */ +AclId +get_grosysid(char *groname) +{ + AclId id = 0; + HeapTuple groupTup; + + groupTup = SearchSysCache(SHADOWNAME, + PointerGetDatum(groname), + 0, 0, 0); + if (!HeapTupleIsValid(groupTup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("group \"%s\" does not exist", groname))); + + if (!(((Form_pg_shadow) GETSTRUCT(groupTup))->isgroup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("\"%s\" is not a group", groname))); + + id = ((Form_pg_shadow) GETSTRUCT(groupTup))->rolesysid; + ReleaseSysCache(groupTup); + + return id; +} + +/* + * get_groname + * + * Convert group ID to name, or return NULL if group can't be found + */ +char * +get_groname(AclId grosysid) +{ + char *name = NULL; + HeapTuple groupTup; + + groupTup = SearchSysCache(SHADOWSYSID, + ObjectIdGetDatum(grosysid), + 0, 0, 0); + if (HeapTupleIsValid(groupTup)) + { + if ((((Form_pg_shadow) GETSTRUCT(groupTup))->isgroup)) + name = pstrdup(NameStr(((Form_pg_shadow) GETSTRUCT(groupTup))->rolename)); + + ReleaseSysCache(groupTup); + } + return name; +} + Index: src/backend/utils/cache/syscache.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/cache/syscache.c,v retrieving revision 1.96 diff -u -r1.96 syscache.c --- src/backend/utils/cache/syscache.c 31 Dec 2004 22:01:25 -0000 1.96 +++ src/backend/utils/cache/syscache.c 21 Jan 2005 05:43:49 -0000 @@ -389,7 +389,7 @@ 0, 1, { - Anum_pg_shadow_usename, + Anum_pg_shadow_rolename, 0, 0, 0 @@ -399,7 +399,7 @@ 0, 1, { - Anum_pg_shadow_usesysid, + Anum_pg_shadow_rolesysid, 0, 0, 0 Index: src/backend/utils/init/miscinit.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/init/miscinit.c,v retrieving revision 1.137 diff -u -r1.137 miscinit.c --- src/backend/utils/init/miscinit.c 31 Dec 2004 22:01:40 -0000 1.137 +++ src/backend/utils/init/miscinit.c 21 Jan 2005 05:43:49 -0000 @@ -315,7 +315,7 @@ HeapTuple userTup; Datum datum; bool isnull; - AclId usesysid; + AclId rolesysid; /* * Don't do scans if we're bootstrapping, none of the system catalogs @@ -334,12 +334,12 @@ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("user \"%s\" does not exist", username))); - usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid; + rolesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->rolesysid; - AuthenticatedUserId = usesysid; - AuthenticatedUserIsSuperuser = ((Form_pg_shadow) GETSTRUCT(userTup))->usesuper; + AuthenticatedUserId = rolesysid; + AuthenticatedUserIsSuperuser = ((Form_pg_shadow) GETSTRUCT(userTup))->rolesuper; - SetSessionUserId(usesysid); /* sets CurrentUserId too */ + SetSessionUserId(rolesysid); /* sets CurrentUserId too */ /* Record username and superuser status as GUC settings too */ SetConfigOption("session_authorization", username, @@ -428,7 +428,7 @@ (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("invalid user ID: %d", userid))); - result = pstrdup(NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename)); + result = pstrdup(NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->rolename)); ReleaseSysCache(tuple); return result; Index: src/backend/utils/misc/superuser.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/superuser.c,v retrieving revision 1.30 diff -u -r1.30 superuser.c --- src/backend/utils/misc/superuser.c 31 Dec 2004 22:02:45 -0000 1.30 +++ src/backend/utils/misc/superuser.c 21 Jan 2005 05:43:49 -0000 @@ -53,7 +53,7 @@ 0, 0, 0); if (HeapTupleIsValid(utup)) { - result = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper; + result = ((Form_pg_shadow) GETSTRUCT(utup))->rolesuper; ReleaseSysCache(utup); } return result; Index: src/include/catalog/pg_shadow.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_shadow.h,v retrieving revision 1.27 diff -u -r1.27 pg_shadow.h --- src/include/catalog/pg_shadow.h 31 Dec 2004 22:03:26 -0000 1.27 +++ src/include/catalog/pg_shadow.h 21 Jan 2005 05:43:49 -0000 @@ -31,16 +31,18 @@ */ CATALOG(pg_shadow) BOOTSTRAP BKI_SHARED_RELATION BKI_WITHOUT_OIDS { - NameData usename; - int4 usesysid; - bool usecreatedb; - bool usesuper; /* read this field via superuser() only */ - bool usecatupd; + NameData rolename; + int4 rolesysid; + bool rolecreatedb; + bool rolesuper; /* read this field via superuser() only */ + bool rolecatupd; + bool isgroup; /* remaining fields may be null; use heap_getattr to read them! */ text passwd; int4 valuntil; /* actually abstime */ text useconfig[1]; + int4 grolist[1]; } FormData_pg_shadow; /* ---------------- @@ -54,15 +56,17 @@ * compiler constants for pg_shadow * ---------------- */ -#define Natts_pg_shadow 8 -#define Anum_pg_shadow_usename 1 -#define Anum_pg_shadow_usesysid 2 -#define Anum_pg_shadow_usecreatedb 3 -#define Anum_pg_shadow_usesuper 4 -#define Anum_pg_shadow_usecatupd 5 -#define Anum_pg_shadow_passwd 6 -#define Anum_pg_shadow_valuntil 7 -#define Anum_pg_shadow_useconfig 8 +#define Natts_pg_shadow 10 +#define Anum_pg_shadow_rolename 1 +#define Anum_pg_shadow_rolesysid 2 +#define Anum_pg_shadow_rolecreatedb 3 +#define Anum_pg_shadow_rolesuper 4 +#define Anum_pg_shadow_rolecatupd 5 +#define Anum_pg_shadow_isgroup 6 +#define Anum_pg_shadow_passwd 7 +#define Anum_pg_shadow_valuntil 8 +#define Anum_pg_shadow_useconfig 9 +#define Anum_pg_shadow_grolist 10 /* ---------------- * initial contents of pg_shadow @@ -71,7 +75,7 @@ * user choices. * ---------------- */ -DATA(insert ( "POSTGRES" PGUID t t t _null_ _null_ _null_ )); +DATA(insert ( "POSTGRES" PGUID t t t f _null_ _null_ _null_ _null_ )); #define BOOTSTRAP_USESYSID 1 Index: src/include/libpq/hba.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/libpq/hba.h,v retrieving revision 1.35 diff -u -r1.35 hba.h --- src/include/libpq/hba.h 2 Feb 2004 16:58:30 -0000 1.35 +++ src/include/libpq/hba.h 21 Jan 2005 05:43:49 -0000 @@ -38,7 +38,6 @@ 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); Index: src/include/utils/acl.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/utils/acl.h,v retrieving revision 1.76 diff -u -r1.76 acl.h --- src/include/utils/acl.h 31 Dec 2004 22:03:45 -0000 1.76 +++ src/include/utils/acl.h 21 Jan 2005 05:43:49 -0000 @@ -41,8 +41,8 @@ * AclIdType tag that describes if the AclId is a user, group, etc. */ #define ACL_IDTYPE_WORLD 0x00 /* PUBLIC */ -#define ACL_IDTYPE_UID 0x01 /* user id - from pg_shadow */ -#define ACL_IDTYPE_GID 0x02 /* group id - from pg_group */ +#define ACL_IDTYPE_UID 0x01 /* user id - from pg_shadow, isgroup false */ +#define ACL_IDTYPE_GID 0x02 /* group id - from pg_shadow, isgroup true */ /* * AclItem Index: src/include/utils/lsyscache.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/utils/lsyscache.h,v retrieving revision 1.93 diff -u -r1.93 lsyscache.h --- src/include/utils/lsyscache.h 31 Dec 2004 22:03:46 -0000 1.93 +++ src/include/utils/lsyscache.h 21 Jan 2005 05:43:49 -0000 @@ -115,7 +115,10 @@ Datum *values, int nvalues, float4 *numbers, int nnumbers); extern char *get_namespace_name(Oid nspid); -extern int32 get_usesysid(const char *username); +extern AclId get_usesysid(const char *username); +extern AclId get_grosysid(char *groname); +extern char *get_groname(AclId grosysid); + #define is_array_type(typid) (get_element_type(typid) != InvalidOid)