diff --git a/doc/src/sgml/Makefile b/doc/src/sgml/Makefile index 59e8431a66..864d4621c2 100644 --- a/doc/src/sgml/Makefile +++ b/doc/src/sgml/Makefile @@ -8,7 +8,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/doc/src/sgml/Makefile,v 1.12 1999/12/05 20:21:59 momjian Exp $ +# $Header: /cvsroot/pgsql/doc/src/sgml/Makefile,v 1.13 2000/01/14 22:11:31 petere Exp $ # #---------------------------------------------------------------------------- @@ -85,15 +85,17 @@ APPLICATIONS= createdb.sgml createuser.sgml \ psql-ref.sgml \ vacuumdb.sgml -COMMANDS= abort.sgml alter_table.sgml alter_user.sgml \ +COMMANDS= abort.sgml alter_group.sgml alter_table.sgml alter_user.sgml \ begin.sgml \ close.sgml cluster.sgml commit.sgml copy.sgml \ - create_aggregate.sgml create_database.sgml create_function.sgml create_index.sgml \ + create_aggregate.sgml create_database.sgml create_function.sgml create_group.sgml \ + create_index.sgml \ create_language.sgml create_operator.sgml create_rule.sgml create_sequence.sgml \ create_table.sgml create_table_as.sgml create_trigger.sgml create_type.sgml \ create_user.sgml create_view.sgml \ declare.sgml delete.sgml \ - drop_aggregate.sgml drop_database.sgml drop_function.sgml drop_index.sgml \ + drop_aggregate.sgml drop_database.sgml drop_function.sgml drop_group.sgml \ + drop_index.sgml \ drop_language.sgml drop_operator.sgml drop_rule.sgml drop_sequence.sgml \ drop_table.sgml drop_trigger.sgml drop_type.sgml drop_user.sgml drop_view.sgml \ explain.sgml fetch.sgml grant.sgml \ diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml index dc04300f2a..09516b166b 100644 --- a/doc/src/sgml/ref/allfiles.sgml +++ b/doc/src/sgml/ref/allfiles.sgml @@ -1,5 +1,5 @@ @@ -40,6 +40,7 @@ Complete list of usable sgml source files in this directory. + @@ -50,6 +51,7 @@ Complete list of usable sgml source files in this directory. + @@ -66,6 +68,7 @@ Complete list of usable sgml source files in this directory. + diff --git a/doc/src/sgml/ref/alter_group.sgml b/doc/src/sgml/ref/alter_group.sgml new file mode 100644 index 0000000000..debbe979e1 --- /dev/null +++ b/doc/src/sgml/ref/alter_group.sgml @@ -0,0 +1,162 @@ + + + + + + ALTER GROUP + + SQL - Language Statements + + + + ALTER GROUP + + + Add users to a group, remove users from a group + + + + + 2000-01-14 + + +ALTER GROUP name ADD USER username [, ... ] +ALTER GROUP name DROP USER username [, ... ] + + + + + 2000-01-14 + + + Inputs + + + + + + name + + + The name of the group to modify. + + + + + + username + + + Users which are to be added or removed from the group. The user + names must exist. + + + + + + + + + + + 2000-01-14 + + + Outputs + + + + + ALTER GROUP + + + Message returned if the alteration was successful. + + + + + + + + + + + + 2000-01-14 + + + Description + + + ALTER GROUP is used to change add users to a group or + remove them from a group. Only database superusers can use this command. + Adding a user to a group does not create the user. Similarly, removing + a user from a group does not drop the user itself. + + + Use + to create a new group and to remove a group. + + + + + + Usage + + + Add users to a group: + + +ALTER GROUP staff ADD USER karl, john + + + Remove a user from a group + + +ALTER GROUP workers DROP USER beth + + + + + + + + Compatibility + + + + + 2000-01-14 + + + SQL92 + + + There is no ALTER GROUP statement in + SQL92. The concept of roles is + similar. + + + + + + diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml index 75bcca8654..f3ce32bb16 100644 --- a/doc/src/sgml/ref/alter_user.sgml +++ b/doc/src/sgml/ref/alter_user.sgml @@ -1,5 +1,5 @@ @@ -24,11 +24,8 @@ Postgres documentation ALTER USER username - [ WITH - [ SYSID uid ] - [ PASSWORD password ] ] + [ WITH PASSWORD 'password' ] [ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ] - [ IN GROUP groupname [, ...] ] [ VALID UNTIL 'abstime' ] @@ -40,24 +37,19 @@ ALTER USER username Inputs - - Refer to CREATE USER for a detailed description of each - clause. - - - username + username - The Postgres account name of the user whose details are to be altered. + The name of the user whose details are to be altered. - password + password The new password to be used for this account. @@ -66,36 +58,36 @@ ALTER USER username - uid + CREATEDB + NOCREATEDB - - The new PostgreSQL user id of the user. - Since this number is used as a key into the - pg_shadow/pg_user table - throughout the system catalogs, it is not recommended that you change - it unless the user in question does not own anything at all and/or - you really know what you are doing. Note that it is not necessary that - database and UNIX user ids match, but some people - choose to keep the numbers the same. + + These clauses define a user's ability to create databases. + If CREATEDB is specified, the user being defined will + be allowed to create his own databases. Using NOCREATEDB + will deny a user the ability to create databases. - groupname + CREATEUSER + NOCREATEUSER - The name of an access group into which this account is to be put. + These clauses determine whether a user will be permitted to + create new users himself. This option will also make the user + a superuser who can override all access restrictions. - abstime + abstime The date (and, optionally, the time) - at which this user's access is to be terminated. + at which this user's password is to expire. @@ -113,9 +105,7 @@ ALTER USER username - -ALTER USER - + ALTER USER Message returned if the alteration was successful. @@ -125,7 +115,7 @@ ALTER USER -ERROR: alterUser: user "username" does not exist +ERROR: ALTER USER: user "username" does not exist @@ -148,39 +138,15 @@ ERROR: alterUser: user "username" does not exist ALTER USER is used to change the attributes of a user's - Postgres account. - Also, it is only possible for the - Postgres - user or any user with read and modify permissions on - pg_shadow to alter user passwords. + PostgreSQL account. Only a database superuser + can change privileges and password expiration with this command. Ordinary + users can only change their own password. - - If any of the clauses of the alter user statement are - omitted, the corresponding value in the pg_shadow table - is left unchanged. + Use + to create a new user and to remove a user. - - - - 1998-09-08 - - - Notes - - - ALTER USER - is a Postgres - language extension. - - - Refer to CREATE/DROP USER - to create or remove a user account. - - - The IN GROUP clause is not yet implemented. - - @@ -190,34 +156,29 @@ ERROR: alterUser: user "username" does not exist Change a user password: - -ALTER USER davide WITH PASSWORD hu8jmn3; - + +ALTER USER davide WITH PASSWORD 'hu8jmn3'; + Change a user's valid until date - + ALTER USER manuel VALID UNTIL 'Jan 31 2030'; - + Change a user's valid until date, specifying that his authorisation should expire at midday on 4th May 1998 using the time zone which is one hour ahead of UTC - + ALTER USER chris VALID UNTIL 'May 4 12:00:00 1998 +1'; - + Give a user the ability to create other users and new databases. - + ALTER USER miriam CREATEUSER CREATEDB; - + - Place a user in two groups - - -ALTER USER miriam IN GROUP sales, payroll; - diff --git a/doc/src/sgml/ref/commands.sgml b/doc/src/sgml/ref/commands.sgml index a8f3201739..8516904dbf 100644 --- a/doc/src/sgml/ref/commands.sgml +++ b/doc/src/sgml/ref/commands.sgml @@ -1,5 +1,5 @@ @@ -14,6 +14,7 @@ Postgres documentation &abort; + &alterGroup; &alterTable; &alterUser; &begin; @@ -24,6 +25,7 @@ Postgres documentation &createAggregate; &createDatabase; &createFunction; + &createGroup; &createIndex; &createLanguage; &createOperator; @@ -40,6 +42,7 @@ Postgres documentation &dropAggregate; &dropDatabase; &dropFunction; + &dropGroup; &dropIndex; &dropLanguage; &dropOperator; diff --git a/doc/src/sgml/ref/create_group.sgml b/doc/src/sgml/ref/create_group.sgml new file mode 100644 index 0000000000..5202372301 --- /dev/null +++ b/doc/src/sgml/ref/create_group.sgml @@ -0,0 +1,176 @@ + + + + + + CREATE GROUP + + SQL - Language Statements + + + + CREATE GROUP + + + Creates a new group + + + + + 2000-01-14 + + +CREATE GROUP name + [ WITH + [ SYSID gid ] + [ USER username [, ...] ] ] + + + + + 2000-01-14 + + + Inputs + + + + + + name + + + The name of the group. + + + + + + gid + + + The SYSID clause can be used to choose + the PostgreSQL group id of the new + group. It is not necessary to do so, however. + + + If this is not specified, the highest assigned group id plus one, + starting at 1, will be used as default. + + + + + + username + + + A list of users to include in the group. The users must already exist. + + + + + + + + + + + 2000-01-14 + + + Outputs + + + + + + CREATE GROUP + + + Message returned if the command completes successfully. + + + + + + + + + + + 2000-01-14 + + + Description + + + CREATE GROUP will create a new group in the database installation. + Refer to the adminstrator's guide for information about using groups + for authentication. + You must be a database superuser to use this command. + + + Use + to change a group's membership, and to remove a group. + + + + + Usage + + + Create an empty group: + +CREATE GROUP staff + + + + + Create a group with members: + +CREATE GROUP marketing WITH USER jonathan, david + + + + + + + Compatibility + + + + + 2000-01-14 + + + SQL92 + + + + There is no CREATE GROUP statement in SQL92. + Roles are similar in concept to groups. + + + + + + diff --git a/doc/src/sgml/ref/create_user.sgml b/doc/src/sgml/ref/create_user.sgml index 2f5d1d7fee..6994837751 100644 --- a/doc/src/sgml/ref/create_user.sgml +++ b/doc/src/sgml/ref/create_user.sgml @@ -1,5 +1,5 @@ @@ -15,7 +15,7 @@ Postgres documentation CREATE USER - Creates account information for a new user + Creates a new database user @@ -26,7 +26,7 @@ Postgres documentation CREATE USER username [ WITH [ SYSID uid ] - [ PASSWORD password ] ] + [ PASSWORD 'password' ] ] [ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ] [ IN GROUP groupname [, ...] ] [ VALID UNTIL 'abstime' ] @@ -61,13 +61,6 @@ CREATE USER username match the UNIX user ids, but some people choose to keep the numbers the same. - - If you still want the - OS user id and the usesysid to match - for any given user, - use the createuser script provided with - the Postgres distribution. - If this is not specified, the highest assigned user id plus one will be used as default. @@ -79,30 +72,11 @@ CREATE USER username password - The PASSWORD clause sets the user's password within - the "pg_shadow" table. For this reason, - "pg_shadow" is no - longer accessible to the instance of - Postgres that the - Postgres - user's password is initially set to NULL. - - - When a - user's password in the "pg_shadow" - table is NULL, user - authentication proceeds as it historically has (HBA, - PG_PASSWORD, etc). However, if a password is set for a - user, a new authentication system supplants any other - configured for the Postgres - instance, and the password - stored in the "pg_shadow" table is used - for authentication. - For more details on how this authentication system - functions see pg_crypt(3). If the WITH PASSWORD clause is - omitted, the user's password is set to the empty - string which equates to a NULL value in the authentication - system mentioned above. + Sets the user's password. If you do not plan to use password + authentication you can omit this option, otherwise the user + won't be able to connect to a password-authenticated server. + See pg_hba.conf(5) or the administrator's guide for details on + how to set up authentication mechanisms. @@ -127,8 +101,8 @@ CREATE USER username These clauses determine whether a user will be permitted to - create new - users in an instance of Postgres. + create new users himself. This option will also make the user + a superuser who can override all access restrictions. Omitting this clause will set the user's value of this attribute to be NOCREATEUSER. @@ -149,15 +123,8 @@ CREATE USER username The VALID UNTIL clause sets an absolute time after which the - user's Postgres - login is no longer valid. Please note that - if a user does not have a password defined in the - "pg_shadow" - table, the valid until date will not be checked - during user authentication. If this clause is omitted, - a NULL value is stored in "pg_shadow" - for this attribute, - and the login will be valid for all time. + user's password is no longer valid. + If this clause is omitted the login will be valid for all time. @@ -176,9 +143,7 @@ CREATE USER username - -CREATE USER - + CREATE USER Message returned if the command completes successfully. @@ -199,61 +164,38 @@ CREATE USER CREATE USER will add a new user to an instance of - PostgreSQL. + PostgreSQL. Refer to the adminstrator's + guide for information about managing users and authentication. + You must be a database superuser to use this command. - - - - 1998-09-21 - - - Notes - - - CREATE USER statement is a - Postgres language extension. - - - Use DROP USER or ALTER USER - statements to remove or modify a user account. - - - Refer to the pg_shadow table for further information. - - - Table "pg_shadow" - Attribute | Type | Extra --------------+---------+------- - usename | name | - usesysid | int4 | - usecreatedb | bool | - usetrace | bool | - usesuper | bool | - usecatupd | bool | - passwd | text | - valuntil | abstime | - - - - + + Use + to change a user's password and privileges, and to remove a user. + Use ALTER GROUP to add or remove the user from other groups. + PostgreSQL + comes with a script + which has the same functionality as this command (in fact, it calls this command) + but can be run from the command shell. + + Usage Create a user with no password: - - + CREATE USER jonathan - + Create a user with a password: - - -CREATE USER davide WITH PASSWORD "jw8s0F4" - + +CREATE USER davide WITH PASSWORD 'jw8s0F4' + @@ -261,17 +203,16 @@ CREATE USER davide WITH PASSWORD "jw8s0F4" Note that after one second has ticked in 2002, the account is not valid: - -CREATE USER miriam WITH PASSWORD "jw8s0F4" VALID UNTIL 'Jan 1 2002' - + +CREATE USER miriam WITH PASSWORD 'jw8s0F4' VALID UNTIL 'Jan 1 2002' + Create an account where the user can create databases: - - -CREATE USER manuel WITH PASSWORD "jw8s0F4" CREATEDB - + +CREATE USER manuel WITH PASSWORD 'jw8s0F4' CREATEDB + diff --git a/doc/src/sgml/ref/drop_group.sgml b/doc/src/sgml/ref/drop_group.sgml new file mode 100644 index 0000000000..0d7db1ef09 --- /dev/null +++ b/doc/src/sgml/ref/drop_group.sgml @@ -0,0 +1,138 @@ + + + + + + DROP GROUP + + SQL - Language Statements + + + + DROP GROUP + + + Removes a group + + + + + 2000-01-14 + + +DROP GROUP name + + + + + 2000-01-14 + + + Inputs + + + + + + name + + + The name of an existing group. + + + + + + + + + + 2000-01-14 + + + Outputs + + + + + DROP GROUP + + + The message returned if the group is successfully deleted. + + + + + + + + + + + + 2000-01-14 + + + Description + + + DROP GROUP removes the specified group from the database. + The users in the group are not deleted. + + + Use + to add new groups, and to change a group's membership. + + + + + + Usage + + + To drop a group: + +DROP GROUP staff; + + + + + + + Compatibility + + + + + 2000-01-14 + + + SQL92 + + + There is no DROP GROUP in SQL92. + + + + + + diff --git a/doc/src/sgml/ref/drop_user.sgml b/doc/src/sgml/ref/drop_user.sgml index 27f339f82d..b2a96e0090 100644 --- a/doc/src/sgml/ref/drop_user.sgml +++ b/doc/src/sgml/ref/drop_user.sgml @@ -1,5 +1,5 @@ @@ -15,7 +15,7 @@ Postgres documentation DROP USER - Removes an user account information + Removes a user @@ -58,18 +58,17 @@ DROP USER name - -DROP - + DROP USER The message returned if the user is successfully deleted. + -ERROR: removeUser: user "name" does not exist. +ERROR: DROP USER: user "name" does not exist @@ -77,6 +76,18 @@ ERROR: removeUser: user "name" does + + + +DROP USER: user "name" owns database "name", cannot be removed + + + + You must drop the database first or change its ownership. + + + + @@ -90,30 +101,20 @@ ERROR: removeUser: user "name" does Description - DROP USER removes the specified - user from the database, - along with any databases owned by the user. It - does not remove tables, views, or triggers owned by the - named user in databases not owned by the user. + DROP USER removes the specified user from the database. + It does not remove tables, views, or other objects owned by the user. If the + user owns any database you get an error. - - - - 1998-09-22 - - - Notes - - - DROP USER is a Postgres - language extension. - - - Refer to CREATE USER and - ALTER USER for information on - how to create or modify user accounts. - - + + Use + to add new users, and to change a user's properties. + PostgreSQL + comes with a script + which has the same functionality as this command (in fact, it calls this command) + but can be run from the command shell. + @@ -122,9 +123,9 @@ ERROR: removeUser: user "name" does To drop a user account: - -DROP USER Jonathan; - + +DROP USER jonathan; + diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index f42665a956..7a8dd88007 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -6,7 +6,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.94 1999/12/16 22:19:41 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.95 2000/01/14 22:11:33 petere Exp $ * *------------------------------------------------------------------------- */ @@ -97,7 +97,11 @@ CopySendData(void *databuf, int datasize, FILE *fp) fe_eof = true; } else + { fwrite(databuf, datasize, 1, fp); + if (ferror(fp)) + elog(ERROR, "CopySendData: %s", strerror(errno)); + } } static void @@ -219,7 +223,7 @@ CopyDonePeek(FILE *fp, int c, int pickup) void DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, - char *filename, char *delim, char *null_print, int fileumask) + char *filename, char *delim, char *null_print) { /*---------------------------------------------------------------------------- Either unload or reload contents of class , depending on . @@ -235,11 +239,6 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, If in the text format, delimit columns with delimiter and print NULL values as . - is the umask(2) setting to use while creating an output file. - This should usually be more liberal than the backend's normal 077 umask, - but not always (in particular, "pg_pwd" should be written with 077!). - Up through version 6.5, was always 000, which was foolhardy. - When loading in the text format from an input stream (as opposed to a file), recognize a "." on a line by itself as EOF. Also recognize a stream EOF. When unloading in the text format to an output stream, @@ -272,12 +271,11 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, result = pg_aclcheck(relname, UserName, required_access); if (result != ACLCHECK_OK) elog(ERROR, "%s: %s", relname, aclcheck_error_strings[result]); - else if (!pipe && !superuser()) + if (!pipe && !superuser()) elog(ERROR, "You must have Postgres superuser privilege to do a COPY " "directly to or from a file. Anyone can COPY to stdout or " "from stdin. Psql's \\copy command also works for anyone."); - else - { + if (from) { /* copy from file to database */ if (rel->rd_rel->relkind == RELKIND_SEQUENCE) @@ -324,7 +322,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, { mode_t oumask; /* Pre-existing umask value */ - oumask = umask((mode_t) fileumask); + oumask = umask((mode_t) 022); #ifndef __CYGWIN32__ fp = AllocateFile(filename, "w"); #else @@ -350,7 +348,6 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, if (IsUnderPostmaster) pq_endcopyout(false); } - } /* * Close the relation. If reading, we can release the AccessShareLock diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index bb18cad4af..f53d34cb0f 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -5,7 +5,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: user.c,v 1.47 1999/12/21 22:39:01 wieck Exp $ + * $Id: user.c,v 1.48 2000/01/14 22:11:33 petere Exp $ * *------------------------------------------------------------------------- */ @@ -31,6 +31,7 @@ #include "tcop/tcopprot.h" #include "utils/acl.h" #include "utils/array.h" +#include "utils/builtins.h" #include "utils/syscache.h" static void CheckPgUserAclNotNull(void); @@ -38,30 +39,26 @@ static void CheckPgUserAclNotNull(void); #define SQL_LENGTH 512 /*--------------------------------------------------------------------- - * update_pg_pwd + * write_password_file / update_pg_pwd * * copy the modified contents of pg_shadow to a file used by the postmaster * for user authentication. The file is stored as $PGDATA/pg_pwd. * - * NB: caller is responsible for ensuring that only one backend can - * execute this routine at a time. Acquiring AccessExclusiveLock on - * pg_shadow is the standard way to do that. + * This function set is both a trigger function for direct updates to pg_shadow + * as well as being called directly from create/alter/drop user. *--------------------------------------------------------------------- */ - -HeapTuple -update_pg_pwd(void) +static void +write_password_file(Relation rel) { char *filename, *tempname; int bufsize; - - - /* - * This is a trigger, so clean out the information provided by - * the trigger manager. - */ - CurrentTriggerData = NULL; + FILE *fp; + mode_t oumask; + HeapScanDesc scan; + HeapTuple tuple; + TupleDesc dsc = RelationGetDescr(rel); /* * Create a temporary filename to be renamed later. This prevents the @@ -71,86 +68,134 @@ update_pg_pwd(void) filename = crypt_getpwdfilename(); 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, "%s: %s", tempname, strerror(errno)); - /* - * Copy the contents of pg_shadow to the pg_pwd ASCII file using the - * SEPCHAR character as the delimiter between fields. Make sure the - * file is created with mode 600 (umask 077). - */ - DoCopy(ShadowRelationName, /* relname */ - false, /* binary */ - false, /* oids */ - false, /* from */ - false, /* pipe */ - tempname, /* filename */ - CRYPT_PWD_FILE_SEPSTR, /* delim */ - "", /* nulls */ - 0077); /* fileumask */ - /* - * And rename the temp file to its final name, deleting the old pg_pwd. - */ - rename(tempname, filename); + /* read table */ + scan = heap_beginscan(rel, 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; - /* + datum_n = heap_getattr(tuple, Anum_pg_shadow_usename, dsc, &null_n); + if (null_n) + continue; /* don't allow empty users */ + datum_p = heap_getattr(tuple, Anum_pg_shadow_passwd, dsc, &null_p); + /* It could be argued that people having a null password + shouldn't be allowed to connect, because they need + to have a password set up first. If you think assuming + an empty password in that case is better, erase the following line. */ + if (null_p) + continue; + datum_v = heap_getattr(tuple, Anum_pg_shadow_valuntil, dsc, &null_v); + + /* These fake entries are not really necessary. To remove them, the parser + in backend/libpq/crypt.c would need to be adjusted. Initdb might also + need adjustments. */ + 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", + nameout(DatumGetName(datum_n)), + null_p ? "" : textout((text*)datum_p), + null_v ? "\\N" : nabstimeout((AbsoluteTime)datum_v) /* this is how the parser wants it */ + ); + if (ferror(fp)) + elog(ERROR, "%s: %s", tempname, strerror(errno)); + fflush(fp); + } + heap_endscan(scan); + FreeFile(fp); + + /* + * And rename the temp file to its final name, deleting the old pg_pwd. + */ + rename(tempname, filename); + + /* * Create a flag file the postmaster will detect the next time it * tries to authenticate a user. The postmaster will know to reload * the pg_pwd file contents. */ filename = crypt_getpwdreloadfilename(); - creat(filename, S_IRUSR | S_IWUSR); + if (creat(filename, S_IRUSR | S_IWUSR) == -1) + elog(ERROR, "%s: %s", filename, strerror(errno)); pfree((void *) tempname); - - return NULL; } -/*--------------------------------------------------------------------- - * DefineUser - * - * Add the user to the pg_shadow relation, and if specified make sure the - * user is specified in the desired groups of defined in pg_group. - *--------------------------------------------------------------------- + + +/* This is the wrapper for triggers. */ +HeapTuple +update_pg_pwd(void) +{ + Relation rel = heap_openr(ShadowRelationName, AccessExclusiveLock); + write_password_file(rel); + heap_close(rel, AccessExclusiveLock); + + /* + * This is a trigger, so clean out the information provided by + * the trigger manager. + */ + CurrentTriggerData = NULL; + return NULL; +} + + + +/* + * CREATE USER */ void -DefineUser(CreateUserStmt *stmt, CommandDest dest) +CreateUser(CreateUserStmt *stmt) { - char *pg_shadow, - sql[SQL_LENGTH]; Relation pg_shadow_rel; TupleDesc pg_shadow_dsc; HeapScanDesc scan; HeapTuple tuple; + Datum new_record[Natts_pg_shadow]; + char new_record_nulls[Natts_pg_shadow]; bool user_exists = false, sysid_exists = false, - inblock, - havesysid, - havepassword, - havevaluntil; + havesysid; int max_id = -1; List *item; - havesysid = stmt->sysid >= 0; - havepassword = stmt->password && stmt->password[0]; - havevaluntil = stmt->validUntil && stmt->validUntil[0]; + havesysid = stmt->sysid > 0; - if (havepassword) + /* Check some permissions first */ + if (stmt->password) CheckPgUserAclNotNull(); - if (!(inblock = IsTransactionBlock())) - BeginTransactionBlock(); - /* - * Make sure the user attempting to create a user can insert into the - * pg_shadow relation. - */ - pg_shadow = GetPgUserName(); - if (pg_aclcheck(ShadowRelationName, pg_shadow, ACL_RD | ACL_WR | ACL_AP) != ACLCHECK_OK) - { - UserAbortTransactionBlock(); - elog(ERROR, "DefineUser: user \"%s\" does not have SELECT and INSERT privilege for \"%s\"", - pg_shadow, ShadowRelationName); - return; - } + if (!superuser()) + elog(ERROR, "CREATE USER: permission denied"); + + /* The reason for the following is this: + * If you start a transaction block, create a user, then roll back the + * transaction, the pg_pwd won't get rolled back due to a bug in the + * Unix file system ( :}). Hence this is in the interest of security. + */ + if (IsTransactionBlock()) + elog(ERROR, "CREATE USER: may not be called in a transaction block"); /* * Scan the pg_shadow relation to be certain the user or id doesn't already @@ -184,49 +229,64 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest) if (user_exists || sysid_exists) { heap_close(pg_shadow_rel, AccessExclusiveLock); - UserAbortTransactionBlock(); if (user_exists) - elog(ERROR, "DefineUser: user name \"%s\" already exists", stmt->user); + elog(ERROR, "CREATE USER: user name \"%s\" already exists", stmt->user); else - elog(ERROR, "DefineUser: sysid %d is already assigned", stmt->sysid); + elog(ERROR, "CREATE USER: sysid %d is already assigned", stmt->sysid); return; } - /* - * Build the insert statement to be executed. - * - * XXX Ugly as this code is, it still fails to cope with ' or \ in any of - * the provided strings. - * - * XXX This routine would be *lots* better if it inserted the new - * tuple with formtuple/heap_insert. For one thing, all of the - * transaction-block gamesmanship could be eliminated, because - * it's only there to make the world safe for a recursive call - * to pg_exec_query_dest(). - */ - snprintf(sql, SQL_LENGTH, - "insert into %s (usename,usesysid,usecreatedb,usetrace," - "usesuper,usecatupd,passwd,valuntil) " - "values('%s',%d,'%c','f','%c','%c',%s%s%s,%s%s%s)", - ShadowRelationName, - stmt->user, - havesysid ? stmt->sysid : max_id + 1, - (stmt->createdb && *stmt->createdb) ? 't' : 'f', - (stmt->createuser && *stmt->createuser) ? 't' : 'f', - ((stmt->createdb && *stmt->createdb) || - (stmt->createuser && *stmt->createuser)) ? 't' : 'f', - havepassword ? "'" : "", - havepassword ? stmt->password : "NULL", - havepassword ? "'" : "", - havevaluntil ? "'" : "", - havevaluntil ? stmt->validUntil : "NULL", - havevaluntil ? "'" : ""); + /* + * Build a tuple to insert + */ + new_record[Anum_pg_shadow_usename-1] = PointerGetDatum(namein(stmt->user)); /* this truncated properly */ + new_record[Anum_pg_shadow_usesysid-1] = Int32GetDatum(havesysid ? stmt->sysid : max_id + 1); - /* - * XXX If insert fails, say because a bogus valuntil date is given, - * need to catch the resulting error and undo our transaction. - */ - pg_exec_query_dest(sql, dest, false); + AssertState(BoolIsValid(stmt->createdb)); + new_record[Anum_pg_shadow_usecreatedb-1] = (Datum)(stmt->createdb); + new_record[Anum_pg_shadow_usetrace-1] = (Datum)(false); + AssertState(BoolIsValid(stmt->createuser)); + new_record[Anum_pg_shadow_usesuper-1] = (Datum)(stmt->createuser); + /* superuser gets catupd right by default */ + new_record[Anum_pg_shadow_usecatupd-1] = (Datum)(stmt->createuser); + + if (stmt->password) + new_record[Anum_pg_shadow_passwd-1] = PointerGetDatum(textin(stmt->password)); + if (stmt->validUntil) + new_record[Anum_pg_shadow_valuntil-1] = PointerGetDatum(nabstimein(stmt->validUntil)); + + new_record_nulls[Anum_pg_shadow_usename-1] = ' '; + new_record_nulls[Anum_pg_shadow_usesysid-1] = ' '; + + new_record_nulls[Anum_pg_shadow_usecreatedb-1] = ' '; + new_record_nulls[Anum_pg_shadow_usetrace-1] = ' '; + new_record_nulls[Anum_pg_shadow_usesuper-1] = ' '; + new_record_nulls[Anum_pg_shadow_usecatupd-1] = ' '; + + new_record_nulls[Anum_pg_shadow_passwd-1] = stmt->password ? ' ' : 'n'; + new_record_nulls[Anum_pg_shadow_valuntil-1] = stmt->validUntil ? ' ' : 'n'; + + tuple = heap_formtuple(pg_shadow_dsc, new_record, new_record_nulls); + Assert(tuple); + + /* + * Insert a new record in the pg_shadow table + */ + if (heap_insert(pg_shadow_rel, tuple) == InvalidOid) + elog(ERROR, "CREATE USER: heap_insert failed"); + + /* + * Update indexes + */ + if (RelationGetForm(pg_shadow_rel)->relhasindex) { + Relation idescs[Num_pg_shadow_indices]; + + CatalogOpenIndices(Num_pg_shadow_indices, + Name_pg_shadow_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_shadow_indices, pg_shadow_rel, + tuple); + CatalogCloseIndices(Num_pg_shadow_indices, idescs); + } /* * Add the user to the groups specified. We'll just call the below @@ -236,59 +296,49 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest) { AlterGroupStmt ags; - ags.name = strVal(lfirst(item)); + ags.name = strVal(lfirst(item)); /* the group name to add this in */ ags.action = +1; - ags.listUsers = lcons((void*)makeString(stmt->user), NIL); - AlterGroup(&ags, dest); + ags.listUsers = lcons((void*)makeInteger(havesysid ? stmt->sysid : max_id + 1), NIL); + AlterGroup(&ags, "CREATE USER"); } /* * Write the updated pg_shadow data to the flat password file. - * Because we are still holding AccessExclusiveLock on pg_shadow, - * we can be sure no other backend will try to write the flat - * file at the same time. */ - update_pg_pwd(); - + write_password_file(pg_shadow_rel); /* * Now we can clean up. */ heap_close(pg_shadow_rel, AccessExclusiveLock); - - if (IsTransactionBlock() && !inblock) - EndTransactionBlock(); } -extern void -AlterUser(AlterUserStmt *stmt, CommandDest dest) -{ - char *pg_shadow, - sql[SQL_LENGTH]; +/* + * ALTER USER + */ +extern void +AlterUser(AlterUserStmt *stmt) +{ + Datum new_record[Natts_pg_shadow]; + char new_record_nulls[Natts_pg_shadow]; Relation pg_shadow_rel; TupleDesc pg_shadow_dsc; - HeapTuple tuple; - bool inblock; - bool comma = false; + HeapTuple tuple, new_tuple; + bool null; if (stmt->password) CheckPgUserAclNotNull(); - if (!(inblock = IsTransactionBlock())) - BeginTransactionBlock(); - /* - * Make sure the user attempting to create a user can insert into the - * pg_shadow relation. - */ - pg_shadow = GetPgUserName(); - if (pg_aclcheck(ShadowRelationName, pg_shadow, ACL_RD | ACL_WR) != ACLCHECK_OK) - { - UserAbortTransactionBlock(); - elog(ERROR, "AlterUser: user \"%s\" does not have SELECT and UPDATE privilege for \"%s\"", - pg_shadow, ShadowRelationName); - return; - } + /* must be superuser or just want to change your own password */ + if (!superuser() && + !(stmt->createdb==0 && stmt->createuser==0 && !stmt->validUntil + && stmt->password && strcmp(GetPgUserName(), stmt->user)==0)) + elog(ERROR, "ALTER USER: permission denied"); + + /* see comments in create user */ + if (IsTransactionBlock()) + elog(ERROR, "ALTER USER: may not be called in a transaction block"); /* * Scan the pg_shadow relation to be certain the user exists. @@ -304,142 +354,135 @@ AlterUser(AlterUserStmt *stmt, CommandDest dest) if (!HeapTupleIsValid(tuple)) { heap_close(pg_shadow_rel, AccessExclusiveLock); - UserAbortTransactionBlock(); - elog(ERROR, "AlterUser: user \"%s\" does not exist", stmt->user); + elog(ERROR, "ALTER USER: user \"%s\" does not exist", stmt->user); } - /* look for duplicate sysid */ - tuple = SearchSysCacheTuple(SHADOWSYSID, - Int32GetDatum(stmt->sysid), - 0, 0, 0); - if (HeapTupleIsValid(tuple)) - { - Datum datum; - bool null; + /* + * Build a tuple to update, perusing the information just obtained + */ + new_record[Anum_pg_shadow_usename-1] = PointerGetDatum(namein(stmt->user)); + new_record_nulls[Anum_pg_shadow_usename-1] = ' '; - datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_shadow_dsc, &null); - if (datum && !null && strcmp((char *) datum, stmt->user) != 0) - { - heap_close(pg_shadow_rel, AccessExclusiveLock); - UserAbortTransactionBlock(); - elog(ERROR, "AlterUser: sysid %d is already assigned", stmt->sysid); - } + /* sysid - leave as is */ + new_record[Anum_pg_shadow_usesysid-1] = heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &null); + new_record_nulls[Anum_pg_shadow_usesysid-1] = null ? 'n' : ' '; + + /* createdb */ + if (stmt->createdb == 0) + { + /* don't change */ + new_record[Anum_pg_shadow_usecreatedb-1] = heap_getattr(tuple, Anum_pg_shadow_usecreatedb, pg_shadow_dsc, &null); + new_record_nulls[Anum_pg_shadow_usecreatedb-1] = null ? 'n' : ' '; + } + else + { + new_record[Anum_pg_shadow_usecreatedb-1] = (Datum)(stmt->createdb > 0 ? true : false); + new_record_nulls[Anum_pg_shadow_usecreatedb-1] = ' '; } + /* trace - leave as is */ + 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' : ' '; - /* - * Create the update statement to modify the user. - * - * XXX see diatribe in preceding routine. This code is just as bogus. - */ - snprintf(sql, SQL_LENGTH, "update %s set ", ShadowRelationName); - - if (stmt->password) + /* createuser (superuser) */ + if (stmt->createuser == 0) { - snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), - "passwd = '%s'", stmt->password); - comma = true; + /* 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' : ' '; + } + else + { + new_record[Anum_pg_shadow_usesuper-1] = (Datum)(stmt->createuser > 0 ? true : false); + new_record_nulls[Anum_pg_shadow_usesuper-1] = ' '; } - if (stmt->sysid>=0) + /* catupd - set to false if someone's superuser priv is being yanked */ + if (stmt->createuser < 0) { - if (comma) - strcat(sql, ", "); - snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), - "usesysid = %d", stmt->sysid); - comma = true; + new_record[Anum_pg_shadow_usecatupd-1] = (Datum)(false); + 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' : ' '; } - if (stmt->createdb) + /* password */ + if (stmt->password) { - if (comma) - strcat(sql, ", "); - snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), - "usecreatedb='%c'", - *stmt->createdb ? 't' : 'f'); - comma = true; + new_record[Anum_pg_shadow_passwd-1] = PointerGetDatum(textin(stmt->password)); + new_record_nulls[Anum_pg_shadow_passwd-1] = ' '; + } + else + { + /* leave as is */ + new_record[Anum_pg_shadow_passwd-1] = heap_getattr(tuple, Anum_pg_shadow_passwd, pg_shadow_dsc, &null); + new_record_nulls[Anum_pg_shadow_passwd-1] = null ? 'n' : ' '; } - if (stmt->createuser) + /* valid until */ + if (stmt->validUntil) + { + new_record[Anum_pg_shadow_valuntil-1] = PointerGetDatum(nabstimein(stmt->validUntil)); + new_record_nulls[Anum_pg_shadow_valuntil-1] = ' '; + } + else { - if (comma) - strcat(sql, ", "); - snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), - "usesuper='%c'", - *stmt->createuser ? 't' : 'f'); - comma = true; + /* leave as is */ + new_record[Anum_pg_shadow_valuntil-1] = heap_getattr(tuple, Anum_pg_shadow_valuntil, pg_shadow_dsc, &null); + new_record_nulls[Anum_pg_shadow_valuntil-1] = null ? 'n' : ' '; } - if (stmt->validUntil) + new_tuple = heap_formtuple(pg_shadow_dsc, new_record, new_record_nulls); + Assert(new_tuple); + /* XXX check return value of this? */ + heap_update(pg_shadow_rel, &tuple->t_self, new_tuple, NULL); + + + /* Update indexes */ + if (RelationGetForm(pg_shadow_rel)->relhasindex) { - if (comma) - strcat(sql, ", "); - snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), - "valuntil='%s'", - stmt->validUntil); + Relation idescs[Num_pg_shadow_indices]; + + CatalogOpenIndices(Num_pg_shadow_indices, + Name_pg_shadow_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_shadow_indices, pg_shadow_rel, + tuple); + CatalogCloseIndices(Num_pg_shadow_indices, idescs); } - snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), - " where usename = '%s'", - stmt->user); - - pg_exec_query_dest(sql, dest, false); - - /* - * Add stuff here for groups? - */ - if (stmt->groupElts) - elog(NOTICE, "IN GROUP is not implemented for ALTER USER."); - /* * Write the updated pg_shadow data to the flat password file. - * Because we are still holding AccessExclusiveLock on pg_shadow, - * we can be sure no other backend will try to write the flat - * file at the same time. */ - update_pg_pwd(); + write_password_file(pg_shadow_rel); /* * Now we can clean up. */ heap_close(pg_shadow_rel, AccessExclusiveLock); - if (IsTransactionBlock() && !inblock) - EndTransactionBlock(); } -extern void -RemoveUser(char *user, CommandDest dest) + +/* + * DROP USER + */ +void +DropUser(DropUserStmt *stmt) { - char *pg_shadow; - Relation pg_shadow_rel, - pg_rel; - TupleDesc pg_dsc; - HeapScanDesc scan; - HeapTuple tuple; - Datum datum; - char sql[SQL_LENGTH]; - bool n, - inblock; - int32 usesysid; - int ndbase = 0; - char **dbase = NULL; + Relation pg_shadow_rel; + TupleDesc pg_shadow_dsc; + List *item; - if (!(inblock = IsTransactionBlock())) - BeginTransactionBlock(); + if (!superuser()) + elog(ERROR, "DROP USER: permission denied"); - /* - * Make sure the user attempting to create a user can delete from the - * pg_shadow relation. - */ - pg_shadow = GetPgUserName(); - if (pg_aclcheck(ShadowRelationName, pg_shadow, ACL_RD | ACL_WR) != ACLCHECK_OK) - { - UserAbortTransactionBlock(); - elog(ERROR, "RemoveUser: user \"%s\" does not have SELECT and DELETE privilege for \"%s\"", - pg_shadow, ShadowRelationName); - } + if (IsTransactionBlock()) + elog(ERROR, "DROP USER: may not be called in a transaction block"); /* * Scan the pg_shadow relation to find the usesysid of the user to be @@ -447,100 +490,109 @@ RemoveUser(char *user, CommandDest dest) * our update of the flat password file. */ pg_shadow_rel = heap_openr(ShadowRelationName, AccessExclusiveLock); - pg_dsc = RelationGetDescr(pg_shadow_rel); + pg_shadow_dsc = RelationGetDescr(pg_shadow_rel); - tuple = SearchSysCacheTuple(SHADOWNAME, - PointerGetDatum(user), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - { - heap_close(pg_shadow_rel, AccessExclusiveLock); - UserAbortTransactionBlock(); - elog(ERROR, "RemoveUser: user \"%s\" does not exist", user); - } + foreach(item, stmt->users) + { + HeapTuple tuple, + tmp_tuple; + Relation pg_rel; + TupleDesc pg_dsc; + ScanKeyData scankey; + HeapScanDesc scan; + Datum datum; + bool null; + int32 usesysid; + const char *user = strVal(lfirst(item)); - usesysid = (int32) heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_dsc, &n); + tuple = SearchSysCacheTuple(SHADOWNAME, + PointerGetDatum(user), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + { + heap_close(pg_shadow_rel, AccessExclusiveLock); + elog(ERROR, "DROP USER: user \"%s\" does not exist%s", user, + (length(stmt->users) > 1) ? " (no users removed)" : ""); + } - /* - * Perform a scan of the pg_database relation to find the databases - * owned by usesysid. Then drop them. - */ - pg_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock); - pg_dsc = RelationGetDescr(pg_rel); + usesysid = DatumGetInt32(heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &null)); - scan = heap_beginscan(pg_rel, false, SnapshotNow, 0, NULL); - while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) - { - datum = heap_getattr(tuple, Anum_pg_database_datdba, pg_dsc, &n); + /*------------------- + * Check if user still owns a database. If so, error out. + * + * (It used to be that this function would drop the database automatically. + * This is not only very dangerous for people that don't read the manual, + * it doesn't seem to be the behaviour one would expect either.) + * -- petere 2000/01/14) + *-------------------*/ + pg_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock); + pg_dsc = RelationGetDescr(pg_rel); - if ((int) datum == usesysid) - { - datum = heap_getattr(tuple, Anum_pg_database_datname, pg_dsc, &n); - if (memcmp((void *) datum, "template1", 9) != 0) - { - dbase = - (char **) repalloc((void *) dbase, sizeof(char *) * (ndbase + 1)); - dbase[ndbase] = (char *) palloc(NAMEDATALEN + 1); - memcpy((void *) dbase[ndbase], (void *) datum, NAMEDATALEN); - dbase[ndbase++][NAMEDATALEN] = '\0'; - } - } - } - heap_endscan(scan); - heap_close(pg_rel, AccessExclusiveLock); + ScanKeyEntryInitialize(&scankey, 0x0, Anum_pg_database_datdba, F_INT4EQ, + Int32GetDatum(usesysid)); - while (ndbase--) - { - elog(NOTICE, "Dropping database %s", dbase[ndbase]); - snprintf(sql, SQL_LENGTH, "DROP DATABASE %s", dbase[ndbase]); - pfree((void *) dbase[ndbase]); - pg_exec_query_dest(sql, dest, false); - } - if (dbase) - pfree((void *) dbase); + scan = heap_beginscan(pg_rel, false, SnapshotNow, 1, &scankey); - /* - * Since pg_shadow is global over all databases, one of two things - * must be done to insure complete consistency. First, pg_shadow - * could be made non-global. This would elminate the code above for - * deleting database and would require the addition of code to delete - * tables, views, etc owned by the user. - * - * The second option would be to create a means of deleting tables, view, - * etc. owned by the user from other databases. pg_shadow is global - * and so this must be done at some point. - * - * Let us not forget that the user should be removed from the pg_groups - * also. - * - * Todd A. Brandys 11/18/1997 - * - */ + if (HeapTupleIsValid(tmp_tuple = heap_getnext(scan, 0))) + { + datum = heap_getattr(tmp_tuple, Anum_pg_database_datname, pg_dsc, &null); + heap_close(pg_shadow_rel, AccessExclusiveLock); + elog(ERROR, "DROP USER: user \"%s\" owns database \"%s\", cannot be removed%s", + user, nameout(DatumGetName(datum)), + (length(stmt->users) > 1) ? " (no users removed)" : "" + ); + } + + heap_endscan(scan); + heap_close(pg_rel, AccessExclusiveLock); - /* - * Remove the user from the pg_shadow table - */ - snprintf(sql, SQL_LENGTH, - "delete from %s where usename = '%s'", ShadowRelationName, user); - pg_exec_query_dest(sql, dest, false); + /* + * Somehow we'd have to check for tables, views, etc. owned by the user + * as well, but those could be spread out over all sorts of databases + * which we don't have access to (easily). + */ + + /* + * Remove the user from the pg_shadow table + */ + heap_delete(pg_shadow_rel, &tuple->t_self, NULL); + + /* + * Remove user from groups + * + * try calling alter group drop user for every group + */ + pg_rel = heap_openr(GroupRelationName, AccessExclusiveLock); + pg_dsc = RelationGetDescr(pg_rel); + scan = heap_beginscan(pg_rel, false, SnapshotNow, 0, NULL); + while (HeapTupleIsValid(tmp_tuple = heap_getnext(scan, 0))) + { + AlterGroupStmt ags; + + datum = heap_getattr(tmp_tuple, Anum_pg_group_groname, pg_dsc, &null); + + ags.name = nameout(DatumGetName(datum)); /* the group name from which to try to drop the user */ + ags.action = -1; + ags.listUsers = lcons((void*)makeInteger(usesysid), NIL); + AlterGroup(&ags, "DROP USER"); + } + heap_endscan(scan); + heap_close(pg_rel, AccessExclusiveLock); + } /* * Write the updated pg_shadow data to the flat password file. - * Because we are still holding AccessExclusiveLock on pg_shadow, - * we can be sure no other backend will try to write the flat - * file at the same time. */ - update_pg_pwd(); + write_password_file(pg_shadow_rel); - /* - * Now we can clean up. - */ - heap_close(pg_shadow_rel, AccessExclusiveLock); - - if (IsTransactionBlock() && !inblock) - EndTransactionBlock(); + /* + * Now we can clean up. + */ + heap_close(pg_shadow_rel, AccessExclusiveLock); } + + /* * CheckPgUserAclNotNull * @@ -556,51 +608,56 @@ CheckPgUserAclNotNull() 0, 0, 0); if (!HeapTupleIsValid(htup)) { - elog(ERROR, "IsPgUserAclNull: class \"%s\" not found", + /* BIG problem */ + elog(ERROR, "IsPgUserAclNull: \"%s\" not found", ShadowRelationName); } if (heap_attisnull(htup, Anum_pg_class_relacl)) { - elog(NOTICE, "To use passwords, you have to revoke permissions on pg_shadow"); - elog(NOTICE, "so normal users can not read the passwords."); - elog(ERROR, "Try 'REVOKE ALL ON pg_shadow FROM PUBLIC'"); + elog(ERROR, + "To use passwords, you have to revoke permissions on %s " + "so normal users cannot read the passwords. " + "Try 'REVOKE ALL ON \"%s\" FROM PUBLIC'.", + ShadowRelationName, ShadowRelationName); } return; } -/*** GROUP THINGS ***/ +/* + * CREATE GROUP + */ void -CreateGroup(CreateGroupStmt *stmt, CommandDest dest) +CreateGroup(CreateGroupStmt *stmt) { Relation pg_group_rel; HeapScanDesc scan; HeapTuple tuple; TupleDesc pg_group_dsc; - bool inblock; bool group_exists = false, sysid_exists = false; - int max_id = -1; + int max_id = 0; Datum new_record[Natts_pg_group]; char new_record_nulls[Natts_pg_group]; List *item, *newlist=NULL; ArrayType *userarray; - - if (!(inblock = IsTransactionBlock())) - BeginTransactionBlock(); - /* * Make sure the user can do this. */ - if (pg_aclcheck(GroupRelationName, GetPgUserName(), ACL_RD | ACL_AP) != ACLCHECK_OK) - { - UserAbortTransactionBlock(); - elog(ERROR, "CreateGroup: Permission denied."); - } + if (!superuser()) + elog(ERROR, "CREATE GROUP: permission denied"); + + /* + * There is not real reason for this, but it makes it consistent + * with create user, and it seems like a good idea anyway. + */ + if (IsTransactionBlock()) + elog(ERROR, "CREATE GROUP: may not be called in a transaction block"); + pg_group_rel = heap_openr(GroupRelationName, AccessExclusiveLock); pg_group_dsc = RelationGetDescr(pg_group_rel); @@ -628,11 +685,10 @@ CreateGroup(CreateGroupStmt *stmt, CommandDest dest) if (group_exists || sysid_exists) { heap_close(pg_group_rel, AccessExclusiveLock); - UserAbortTransactionBlock(); if (group_exists) - elog(ERROR, "CreateGroup: Group name \"%s\" already exists.", stmt->name); + elog(ERROR, "CREATE GROUP: group name \"%s\" already exists", stmt->name); else - elog(ERROR, "CreateGroup: Group sysid %d is already assigned.", stmt->sysid); + elog(ERROR, "CREATE GROUP: group sysid %d is already assigned", stmt->sysid); } /* @@ -650,8 +706,7 @@ CreateGroup(CreateGroupStmt *stmt, CommandDest dest) if (!HeapTupleIsValid(tuple)) { heap_close(pg_group_rel, AccessExclusiveLock); - UserAbortTransactionBlock(); - elog(ERROR, "CreateGroup: User \"%s\" does not exist.", groupuser); + elog(ERROR, "CREATE GROUP: user \"%s\" does not exist", groupuser); } v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid); @@ -716,33 +771,34 @@ CreateGroup(CreateGroupStmt *stmt, CommandDest dest) CatalogCloseIndices(Num_pg_group_indices, idescs); } - heap_close(pg_group_rel, NoLock); - - if (IsTransactionBlock() && !inblock) - EndTransactionBlock(); + heap_close(pg_group_rel, AccessExclusiveLock); } +/* + * ALTER GROUP + */ void -AlterGroup(AlterGroupStmt *stmt, CommandDest dest) +AlterGroup(AlterGroupStmt *stmt, const char * tag) { Relation pg_group_rel; TupleDesc pg_group_dsc; - bool inblock; HeapTuple group_tuple; - if (!(inblock = IsTransactionBlock())) - BeginTransactionBlock(); - - /* + /* * Make sure the user can do this. */ - if (pg_aclcheck(GroupRelationName, GetPgUserName(), ACL_RD | ACL_WR) != ACLCHECK_OK) - { - UserAbortTransactionBlock(); - elog(ERROR, "AlterGroup: Permission denied."); - } + if (!superuser()) + elog(ERROR, "%s: permission denied", tag); + + /* + * There is not real reason for this, but it makes it consistent + * with alter user, and it seems like a good idea anyway. + */ + if (IsTransactionBlock()) + elog(ERROR, "%s: may not be called in a transaction block", tag); + pg_group_rel = heap_openr(GroupRelationName, AccessExclusiveLock); pg_group_dsc = RelationGetDescr(pg_group_rel); @@ -755,69 +811,14 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) if (!HeapTupleIsValid(group_tuple = SearchSysCacheTupleCopy(GRONAME, PointerGetDatum(stmt->name), 0, 0, 0))) { heap_close(pg_group_rel, AccessExclusiveLock); - UserAbortTransactionBlock(); - elog(ERROR, "AlterGroup: Group \"%s\" does not exist.", stmt->name); + elog(ERROR, "%s: group \"%s\" does not exist", tag, stmt->name); } + AssertState(stmt->action == +1 || stmt->action == -1); /* * Now decide what to do. */ - if (stmt->action == 0) /* change sysid */ - { - ScanKeyData keys[2]; - HeapTuple tuple; - HeapScanDesc scan; - Datum new_record[Natts_pg_group]; - char new_record_nulls[Natts_pg_group]; - bool null; - - /* - * First check if the id is already assigned. - */ - ScanKeyEntryInitialize(&keys[0], 0x0, Anum_pg_group_grosysid, F_INT4EQ, - Int32GetDatum(stmt->sysid)); - ScanKeyEntryInitialize(&keys[1], 0x0, Anum_pg_group_groname, F_NAMENE, - PointerGetDatum(stmt->name)); - scan = heap_beginscan(pg_group_rel, false, SnapshotNow, 2, keys); - - if (HeapTupleIsValid(heap_getnext(scan, false))) - { - heap_endscan(scan); - heap_close(pg_group_rel, AccessExclusiveLock); - UserAbortTransactionBlock(); - elog(ERROR, "AlterGroup: Group sysid %d is already assigned.", stmt->sysid); - } - heap_endscan(scan); - - /* - * Insert the new tuple with the updated sysid - */ - new_record[Anum_pg_group_groname-1] = (Datum)(stmt->name); - new_record[Anum_pg_group_grosysid-1] = (Datum)(stmt->sysid); - new_record[Anum_pg_group_grolist-1] = heap_getattr(group_tuple, Anum_pg_group_grolist, pg_group_dsc, &null); - new_record_nulls[Anum_pg_group_groname-1] = ' '; - new_record_nulls[Anum_pg_group_grosysid-1] = ' '; - new_record_nulls[Anum_pg_group_grolist-1] = null ? 'n' : ' '; - - tuple = heap_formtuple(pg_group_dsc, new_record, new_record_nulls); - heap_update(pg_group_rel, &group_tuple->t_self, tuple, NULL); - - /* Update indexes */ - if (RelationGetForm(pg_group_rel)->relhasindex) { - Relation idescs[Num_pg_group_indices]; - - CatalogOpenIndices(Num_pg_group_indices, - Name_pg_group_indices, idescs); - CatalogIndexInsert(idescs, Num_pg_group_indices, pg_group_rel, - tuple); - CatalogCloseIndices(Num_pg_group_indices, idescs); - } - } - - /* - * add users to group - */ - else if (stmt->action > 0) + if (stmt->action == +1) /* add users, might also be invoked by create user */ { Datum new_record[Natts_pg_group]; char new_record_nulls[Natts_pg_group] = { ' ', ' ', ' '}; @@ -853,22 +854,34 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) foreach(item, stmt->listUsers) { Value *v; - /* Get the uid of the proposed user to add. */ - tuple = SearchSysCacheTuple(SHADOWNAME, - PointerGetDatum(strVal(lfirst(item))), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) + if (strcmp(tag, "ALTER GROUP")==0) { - heap_close(pg_group_rel, AccessExclusiveLock); - UserAbortTransactionBlock(); - elog(ERROR, "AlterGroup: User \"%s\" does not exist.", strVal(lfirst(item))); + /* Get the uid of the proposed user to add. */ + tuple = SearchSysCacheTuple(SHADOWNAME, + PointerGetDatum(strVal(lfirst(item))), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + { + heap_close(pg_group_rel, AccessExclusiveLock); + elog(ERROR, "%s: user \"%s\" does not exist", tag, strVal(lfirst(item))); + } + v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid); } - - v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid); + else if (strcmp(tag, "CREATE USER")==0) + { + /* in this case we already know the uid and it wouldn't + be in the cache anyway yet */ + v = lfirst(item); + } + else + elog(ERROR, "AlterGroup: unknown tag %s", tag); + if (!member(v, newlist)) newlist = lcons(v, newlist); else - elog(NOTICE, "AlterGroup: User \"%s\" is already in group \"%s\".", strVal(lfirst(item)), stmt->name); + /* we silently assume here that this error will only come up + in a ALTER GROUP statement */ + elog(NOTICE, "%s: user \"%s\" is already in group \"%s\"", tag, strVal(lfirst(item)), stmt->name); } newarray = palloc(ARR_OVERHEAD(1) + length(newlist) * sizeof(int32)); @@ -906,17 +919,18 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) } } /* endif alter group add user */ - /* - * drop users from group - */ - else if (stmt->action < 0) + else if (stmt->action == -1) /*drop users from group */ { Datum datum; bool null; + bool is_dropuser = strcmp(tag, "DROP USER")==0; datum = heap_getattr(group_tuple, Anum_pg_group_grolist, pg_group_dsc, &null); if (null) - elog(NOTICE, "AlterGroup: Group \"%s\"'s membership is NULL.", stmt->name); + { + if (!is_dropuser) + elog(NOTICE, "ALTER GROUP: group \"%s\" does not have any members", stmt->name); + } else { HeapTuple tuple; @@ -950,22 +964,28 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) foreach(item, stmt->listUsers) { Value *v; - /* Get the uid of the proposed user to drop. */ - tuple = SearchSysCacheTuple(SHADOWNAME, - PointerGetDatum(strVal(lfirst(item))), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) + if (!is_dropuser) { - heap_close(pg_group_rel, AccessExclusiveLock); - UserAbortTransactionBlock(); - elog(ERROR, "AlterGroup: User \"%s\" does not exist.", strVal(lfirst(item))); + /* Get the uid of the proposed user to drop. */ + tuple = SearchSysCacheTuple(SHADOWNAME, + PointerGetDatum(strVal(lfirst(item))), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + { + heap_close(pg_group_rel, AccessExclusiveLock); + elog(ERROR, "ALTER GROUP: user \"%s\" does not exist", strVal(lfirst(item))); + } + v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid); + } + else + { + /* for dropuser we already know the uid */ + v = lfirst(item); } - - v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid); if (member(v, newlist)) newlist = LispRemove(v, newlist); - else - elog(NOTICE, "AlterGroup: User \"%s\" is not in group \"%s\".", strVal(lfirst(item)), stmt->name); + else if (!is_dropuser) + elog(NOTICE, "ALTER GROUP: user \"%s\" is not in group \"%s\"", strVal(lfirst(item)), stmt->name); } newarray = palloc(ARR_OVERHEAD(1) + length(newlist) * sizeof(int32)); @@ -1005,40 +1025,40 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) } /* endif group not null */ } /* endif alter group drop user */ - heap_close(pg_group_rel, NoLock); + heap_close(pg_group_rel, AccessExclusiveLock); pfree(group_tuple); - - if (IsTransactionBlock() && !inblock) - EndTransactionBlock(); } +/* + * DROP GROUP + */ void -DropGroup(DropGroupStmt *stmt, CommandDest dest) +DropGroup(DropGroupStmt *stmt) { Relation pg_group_rel; HeapScanDesc scan; HeapTuple tuple; TupleDesc pg_group_dsc; - bool inblock; bool gro_exists = false; - if (!(inblock = IsTransactionBlock())) - BeginTransactionBlock(); - - /* + /* * Make sure the user can do this. */ - if (pg_aclcheck(GroupRelationName, GetPgUserName(), ACL_RD | ACL_WR) != ACLCHECK_OK) - { - UserAbortTransactionBlock(); - elog(ERROR, "DropGroup: Permission denied."); - } + if (!superuser()) + elog(ERROR, "DROP GROUP: permission denied"); /* - * Scan the pg_group table and delete all matching users. + * There is not real reason for this, but it makes it consistent + * with drop user, and it seems like a good idea anyway. + */ + if (IsTransactionBlock()) + elog(ERROR, "DROP GROUP: may not be called in a transaction block"); + + /* + * Scan the pg_group table and delete all matching groups. */ pg_group_rel = heap_openr(GroupRelationName, AccessExclusiveLock); pg_group_dsc = RelationGetDescr(pg_group_rel); @@ -1055,7 +1075,6 @@ DropGroup(DropGroupStmt *stmt, CommandDest dest) gro_exists = true; heap_delete(pg_group_rel, &tuple->t_self, NULL); } - } heap_endscan(scan); @@ -1067,12 +1086,8 @@ DropGroup(DropGroupStmt *stmt, CommandDest dest) { heap_close(pg_group_rel, AccessExclusiveLock); UserAbortTransactionBlock(); - elog(ERROR, "DropGroup: Group \"%s\" does not exist.", stmt->name); + elog(ERROR, "DROP GROUP: group \"%s\" does not exist", stmt->name); } - heap_close(pg_group_rel, NoLock); - - if (IsTransactionBlock() && !inblock) - EndTransactionBlock(); + heap_close(pg_group_rel, AccessExclusiveLock); } - diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index e21a26dcd6..069af39f05 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.124 2000/01/13 18:26:07 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.125 2000/01/14 22:11:34 petere Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -90,7 +90,6 @@ static Node *doNegate(Node *n); char chr; char *str; bool boolean; - bool* pboolean; /* for pg_shadow privileges */ List *list; Node *node; Value *value; @@ -137,11 +136,11 @@ static Node *doNegate(Node *n); %type opt_lock, lock_type %type opt_lmode -%type user_createdb_clause, user_createuser_clause +%type user_createdb_clause, user_createuser_clause %type user_passwd_clause %type sysid_clause %type user_valid_clause -%type user_group_list, user_group_clause, users_in_new_group_clause +%type user_list, user_group_clause, users_in_new_group_clause %type TriggerActionTime, TriggerForSpec, PLangTrusted @@ -459,8 +458,8 @@ CreateUserStmt: CREATE USER UserId n->user = $3; n->sysid = -1; n->password = NULL; - n->createdb = $4; - n->createuser = $5; + n->createdb = $4 == +1 ? true : false; + n->createuser = $5 == +1 ? true : false; n->groupElts = $6; n->validUntil = $7; $$ = (Node *)n; @@ -473,8 +472,8 @@ CreateUserStmt: CREATE USER UserId n->user = $3; n->sysid = $5; n->password = $6; - n->createdb = $7; - n->createuser = $8; + n->createdb = $7 == +1 ? true : false; + n->createuser = $8 == +1 ? true : false; n->groupElts = $9; n->validUntil = $10; $$ = (Node *)n; @@ -489,30 +488,26 @@ CreateUserStmt: CREATE USER UserId *****************************************************************************/ AlterUserStmt: ALTER USER UserId user_createdb_clause - user_createuser_clause user_group_clause user_valid_clause + user_createuser_clause user_valid_clause { AlterUserStmt *n = makeNode(AlterUserStmt); n->user = $3; - n->sysid = -1; n->password = NULL; n->createdb = $4; n->createuser = $5; - n->groupElts = $6; - n->validUntil = $7; + n->validUntil = $6; $$ = (Node *)n; } - | ALTER USER UserId WITH sysid_clause user_passwd_clause + | ALTER USER UserId WITH PASSWORD Sconst user_createdb_clause - user_createuser_clause user_group_clause user_valid_clause + user_createuser_clause user_valid_clause { AlterUserStmt *n = makeNode(AlterUserStmt); n->user = $3; - n->sysid = $5; n->password = $6; n->createdb = $7; n->createuser = $8; - n->groupElts = $9; - n->validUntil = $10; + n->validUntil = $9; $$ = (Node *)n; } ; @@ -524,53 +519,38 @@ AlterUserStmt: ALTER USER UserId user_createdb_clause * *****************************************************************************/ -DropUserStmt: DROP USER UserId +DropUserStmt: DROP USER user_list { DropUserStmt *n = makeNode(DropUserStmt); - n->user = $3; + n->users = $3; $$ = (Node *)n; } ; -user_passwd_clause: PASSWORD UserId { $$ = $2; } +user_passwd_clause: PASSWORD Sconst { $$ = $2; } | /*EMPTY*/ { $$ = NULL; } ; -sysid_clause: SYSID Iconst { $$ = $2; } +sysid_clause: SYSID Iconst + { + if ($2 <= 0) + elog(ERROR, "sysid must be positive"); + $$ = $2; + } | /*EMPTY*/ { $$ = -1; } ; -user_createdb_clause: CREATEDB - { - bool* b; - $$ = (b = (bool*)palloc(sizeof(bool))); - *b = true; - } - | NOCREATEDB - { - bool* b; - $$ = (b = (bool*)palloc(sizeof(bool))); - *b = false; - } - | /*EMPTY*/ { $$ = NULL; } +user_createdb_clause: CREATEDB { $$ = +1; } + | NOCREATEDB { $$ = -1; } + | /*EMPTY*/ { $$ = 0; } ; -user_createuser_clause: CREATEUSER - { - bool* b; - $$ = (b = (bool*)palloc(sizeof(bool))); - *b = true; - } - | NOCREATEUSER - { - bool* b; - $$ = (b = (bool*)palloc(sizeof(bool))); - *b = false; - } - | /*EMPTY*/ { $$ = NULL; } +user_createuser_clause: CREATEUSER { $$ = +1; } + | NOCREATEUSER { $$ = -1; } + | /*EMPTY*/ { $$ = 0; } ; -user_group_list: user_group_list ',' UserId +user_list: user_list ',' UserId { $$ = lcons((void*)makeString($3), $1); } @@ -580,7 +560,7 @@ user_group_list: user_group_list ',' UserId } ; -user_group_clause: IN GROUP user_group_list { $$ = $3; } +user_group_clause: IN GROUP user_list { $$ = $3; } | /*EMPTY*/ { $$ = NULL; } ; @@ -615,7 +595,7 @@ CreateGroupStmt: CREATE GROUP UserId } ; -users_in_new_group_clause: USER user_group_list { $$ = $2; } +users_in_new_group_clause: USER user_list { $$ = $2; } | /* EMPTY */ { $$ = NULL; } ; @@ -626,17 +606,7 @@ users_in_new_group_clause: USER user_group_list { $$ = $2; } * *****************************************************************************/ -AlterGroupStmt: ALTER GROUP UserId WITH SYSID Iconst - { - AlterGroupStmt *n = makeNode(AlterGroupStmt); - n->name = $3; - n->sysid = $6; - n->action = 0; - n->listUsers = NULL; - $$ = (Node *)n; - } - | - ALTER GROUP UserId ADD USER user_group_list +AlterGroupStmt: ALTER GROUP UserId ADD USER user_list { AlterGroupStmt *n = makeNode(AlterGroupStmt); n->name = $3; @@ -646,7 +616,7 @@ AlterGroupStmt: ALTER GROUP UserId WITH SYSID Iconst $$ = (Node *)n; } | - ALTER GROUP UserId DROP USER user_group_list + ALTER GROUP UserId DROP USER user_list { AlterGroupStmt *n = makeNode(AlterGroupStmt); n->name = $3; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 0a97e3acac..ed1cf862e7 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.77 2000/01/13 18:26:10 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.78 2000/01/14 22:11:35 petere Exp $ * *------------------------------------------------------------------------- */ @@ -266,11 +266,7 @@ ProcessUtility(Node *parsetree, */ stmt->filename, stmt->delimiter, - stmt->null_print, - /* - * specify 022 umask while writing files with COPY. - */ - 0022); + stmt->null_print); } break; @@ -775,21 +771,21 @@ ProcessUtility(Node *parsetree, PS_SET_STATUS(commandTag = "CREATE USER"); CHECK_IF_ABORTED(); - DefineUser((CreateUserStmt *) parsetree, dest); + CreateUser((CreateUserStmt *) parsetree); break; case T_AlterUserStmt: PS_SET_STATUS(commandTag = "ALTER USER"); CHECK_IF_ABORTED(); - AlterUser((AlterUserStmt *) parsetree, dest); + AlterUser((AlterUserStmt *) parsetree); break; case T_DropUserStmt: PS_SET_STATUS(commandTag = "DROP USER"); CHECK_IF_ABORTED(); - RemoveUser(((DropUserStmt *) parsetree)->user, dest); + DropUser((DropUserStmt *) parsetree); break; case T_LockStmt: @@ -810,21 +806,21 @@ ProcessUtility(Node *parsetree, PS_SET_STATUS(commandTag = "CREATE GROUP"); CHECK_IF_ABORTED(); - CreateGroup((CreateGroupStmt *) parsetree, dest); + CreateGroup((CreateGroupStmt *) parsetree); break; case T_AlterGroupStmt: PS_SET_STATUS(commandTag = "ALTER GROUP"); CHECK_IF_ABORTED(); - AlterGroup((AlterGroupStmt *) parsetree, dest); + AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP"); break; case T_DropGroupStmt: PS_SET_STATUS(commandTag = "DROP GROUP"); CHECK_IF_ABORTED(); - DropGroup((DropGroupStmt *) parsetree, dest); + DropGroup((DropGroupStmt *) parsetree); break; /* diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c index c1f0a3231d..51d0d29c7b 100644 --- a/src/backend/utils/misc/superuser.c +++ b/src/backend/utils/misc/superuser.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.12 1999/11/24 16:52:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.13 2000/01/14 22:11:36 petere Exp $ * * DESCRIPTION * See superuser(). @@ -18,6 +18,7 @@ #include "postgres.h" #include "catalog/pg_shadow.h" #include "utils/syscache.h" +#include "miscadmin.h" bool superuser(void) @@ -26,12 +27,10 @@ superuser(void) The Postgres user running this command has Postgres superuser privileges. --------------------------------------------------------------------------*/ - extern char *UserName; /* defined in global.c */ - HeapTuple utup; utup = SearchSysCacheTuple(SHADOWNAME, - PointerGetDatum(UserName), + PointerGetDatum(GetPgUserName()), 0, 0, 0); Assert(utup != NULL); return ((Form_pg_shadow) GETSTRUCT(utup))->usesuper; diff --git a/src/bin/scripts/createuser b/src/bin/scripts/createuser index dd184c9a4e..8849994b6e 100644 --- a/src/bin/scripts/createuser +++ b/src/bin/scripts/createuser @@ -8,7 +8,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createuser,v 1.5 2000/01/12 19:36:36 petere Exp $ +# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createuser,v 1.6 2000/01/14 22:11:36 petere Exp $ # # Note - this should NOT be setuid. # @@ -193,7 +193,7 @@ QUERY="CREATE USER \"$NewUser\"" SUBQUERY= [ "$SysID" ] && SUBQUERY="$SUBQUERY SYSID $SysID" -[ "$Password" ] && SUBQUERY="$SUBQUERY PASSWORD \"$Password\"" +[ "$Password" ] && SUBQUERY="$SUBQUERY PASSWORD '$Password'" [ "$SUBQUERY" ] && QUERY="$QUERY WITH $SUBQUERY" [ "$CanCreateDb" = t ] && QUERY="$QUERY CREATEDB" diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h index 1f2af72122..4560cd3672 100644 --- a/src/include/commands/copy.h +++ b/src/include/commands/copy.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: copy.h,v 1.7 1999/12/14 00:08:19 momjian Exp $ + * $Id: copy.h,v 1.8 2000/01/14 22:11:37 petere Exp $ * *------------------------------------------------------------------------- */ @@ -15,6 +15,6 @@ void DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, - char *filename, char *delim, char *null_print, int fileumask); + char *filename, char *delim, char *null_print); #endif /* COPY_H */ diff --git a/src/include/commands/user.h b/src/include/commands/user.h index 036f157682..6a52fe613d 100644 --- a/src/include/commands/user.h +++ b/src/include/commands/user.h @@ -11,15 +11,15 @@ #define USER_H #include "nodes/parsenodes.h" -#include "tcop/dest.h" +#include "access/htup.h" -extern void DefineUser(CreateUserStmt *stmt, CommandDest); -extern void AlterUser(AlterUserStmt *stmt, CommandDest); -extern void RemoveUser(char *user, CommandDest); +extern void CreateUser(CreateUserStmt *stmt); +extern void AlterUser(AlterUserStmt *stmt); +extern void DropUser(DropUserStmt *stmt); -extern void CreateGroup(CreateGroupStmt *stmt, CommandDest dest); -extern void AlterGroup(AlterGroupStmt *stmt, CommandDest dest); -extern void DropGroup(DropGroupStmt *stmt, CommandDest dest); +extern void CreateGroup(CreateGroupStmt *stmt); +extern void AlterGroup(AlterGroupStmt *stmt, const char * tag); +extern void DropGroup(DropGroupStmt *stmt); extern HeapTuple update_pg_pwd(void); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 714f06d5db..0b2a2a0e93 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: parsenodes.h,v 1.92 1999/12/16 17:24:19 momjian Exp $ + * $Id: parsenodes.h,v 1.93 2000/01/14 22:11:38 petere Exp $ * *------------------------------------------------------------------------- */ @@ -270,18 +270,26 @@ typedef struct CreateUserStmt char *user; /* PostgreSQL user login */ char *password; /* PostgreSQL user password */ int sysid; /* PgSQL system id (-1 if don't care) */ - bool *createdb; /* Can the user create databases? */ - bool *createuser; /* Can this user create users? */ + bool createdb; /* Can the user create databases? */ + bool createuser; /* Can this user create users? */ List *groupElts; /* The groups the user is a member of */ char *validUntil; /* The time the login is valid until */ } CreateUserStmt; -typedef CreateUserStmt AlterUserStmt; +typedef struct AlterUserStmt +{ + NodeTag type; + char *user; /* PostgreSQL user login */ + char *password; /* PostgreSQL user password */ + int createdb; /* Can the user create databases? */ + int createuser; /* Can this user create users? */ + char *validUntil; /* The time the login is valid until */ +} AlterUserStmt; typedef struct DropUserStmt { NodeTag type; - char *user; /* PostgreSQL user login */ + List *users; /* List of users to remove */ } DropUserStmt; @@ -301,7 +309,7 @@ typedef struct AlterGroupStmt { NodeTag type; char *name; /* name of group to alter */ - int action; /* +1 = add, -1 = drop, 0 = other (HACK!) */ + int action; /* +1 = add, -1 = drop user */ int sysid; /* sysid change */ List *listUsers; /* list of users to add/drop */ } AlterGroupStmt;