diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml index 686684632a..75bcca8654 100644 --- a/doc/src/sgml/ref/alter_user.sgml +++ b/doc/src/sgml/ref/alter_user.sgml @@ -1,5 +1,5 @@ @@ -23,7 +23,10 @@ Postgres documentation 1999-07-20 -ALTER USER username [ WITH PASSWORD password ] +ALTER USER username + [ WITH + [ SYSID uid ] + [ PASSWORD password ] ] [ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ] [ IN GROUP groupname [, ...] ] [ VALID UNTIL 'abstime' ] @@ -62,6 +65,22 @@ ALTER USER username [ WITH PASSWORD + + uid + + + 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. + + + + groupname @@ -130,9 +149,7 @@ ERROR: alterUser: user "username" does not exist ALTER USER is used to change the attributes of a user's Postgres account. - Please note that it is not possible - to alter a user's "usesysid" via the alter user - statement. Also, it is only possible for the + Also, it is only possible for the Postgres user or any user with read and modify permissions on pg_shadow to alter user passwords. @@ -161,9 +178,7 @@ ERROR: alterUser: user "username" does not exist to create or remove a user account. - In the current release (v6.5), the IN GROUP clause is parsed - but has no affect. When it is fully implemented, it is - intended to modify the pg_group relation. + The IN GROUP clause is not yet implemented. diff --git a/doc/src/sgml/ref/create_user.sgml b/doc/src/sgml/ref/create_user.sgml index b7a55d05d4..9eccd3f713 100644 --- a/doc/src/sgml/ref/create_user.sgml +++ b/doc/src/sgml/ref/create_user.sgml @@ -1,5 +1,5 @@ @@ -23,8 +23,10 @@ Postgres documentation 1999-07-20 -CREATE USER username - [ WITH PASSWORD password ] +CREATE USER username + [ WITH + [ SYSID uid ] + [ PASSWORD password ] ] [ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ] [ IN GROUP groupname [, ...] ] [ VALID UNTIL 'abstime' ] @@ -49,11 +51,28 @@ CREATE USER username + + uid + + + The SYSID clause can be used to choose + the PostgreSQL user id of the user + that is being created. It is not at all necessary that those + match the UNIX user ids, but some people + choose to keep the numbers the same. + + + If this is not specified, the highest assigned user id plus one + will be used as default. + + + + password - The WITH PASSWORD clause sets the user's password within + 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 @@ -173,30 +192,9 @@ CREATE USER CREATE USER will add a new user to an instance of - Postgres. + PostgreSQL. - - The new user will be given a usesysid of: - - -SELECT MAX(usesysid) + 1 FROM pg_shadow; - - - This means that - Postgres users' usesysids will not - correspond to their operating - system(OS) user ids. The exception to this rule is - the postgres superuser, whose OS user id - is used as the - usesysid during the initdb process. - 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. - - 1998-09-21 @@ -216,19 +214,17 @@ SELECT MAX(usesysid) + 1 FROM pg_shadow; Refer to the pg_shadow table for further information. - Table = pg_shadow - +--------------------------+--------------------------+-------+ - | Field | Type | Length| - +--------------------------+--------------------------+-------+ - | usename | name | 32 | - | usesysid | int4 | 4 | - | usecreatedb | bool | 1 | - | usetrace | bool | 1 | - | usesuper | bool | 1 | - | usecatupd | bool | 1 | - | passwd | text | var | - | valuntil | abstime | 4 | - +--------------------------+--------------------------+-------+ + Table "pg_shadow" + Attribute | Type | Extra +-------------+---------+------- + usename | name | + usesysid | int4 | + usecreatedb | bool | + usetrace | bool | + usesuper | bool | + usecatupd | bool | + passwd | text | + valuntil | abstime | diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 27a11cbcaf..044779b7ee 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.38 1999/11/24 16:52:32 momjian Exp $ + * $Id: user.c,v 1.39 1999/11/30 03:57:23 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -105,14 +105,15 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest) TupleDesc pg_shadow_dsc; HeapScanDesc scan; HeapTuple tuple; - Datum datum; - bool exists = false, - n, + bool user_exists = false, + sysid_exists = false, inblock, + havesysid, havepassword, havevaluntil; int max_id = -1; + havesysid = stmt->sysid >= 0; havepassword = stmt->password && stmt->password[0]; havevaluntil = stmt->validUntil && stmt->validUntil[0]; @@ -129,13 +130,13 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest) 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\"", + elog(ERROR, "DefineUser: user \"%s\" does not have SELECT and INSERT privilege for \"%s\"", pg_shadow, ShadowRelationName); return; } /* - * Scan the pg_shadow relation to be certain the user doesn't already + * Scan the pg_shadow relation to be certain the user or id doesn't already * exist. Note we secure exclusive lock, because we also need to be * sure of what the next usesysid should be, and we need to protect * our update of the flat password file. @@ -144,25 +145,33 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest) pg_shadow_dsc = RelationGetDescr(pg_shadow_rel); scan = heap_beginscan(pg_shadow_rel, false, SnapshotNow, 0, NULL); - while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) + while (!user_exists && !sysid_exists && HeapTupleIsValid(tuple = heap_getnext(scan, 0))) { - datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_shadow_dsc, &n); + Datum datum; + bool null; - if (!exists && !strncmp((char *) datum, stmt->user, strlen(stmt->user))) - exists = true; + datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_shadow_dsc, &null); + user_exists = datum && !null && (strcmp((char *) datum, stmt->user) == 0); - datum = heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &n); - if ((int) datum > max_id) - max_id = (int) datum; + datum = heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &null); + if (havesysid) /* customized id wanted */ + sysid_exists = datum && !null && ((int)datum == stmt->sysid); + else /* pick 1 + max */ + { + if ((int) datum > max_id) + max_id = (int) datum; + } } heap_endscan(scan); - if (exists) + if (user_exists || sysid_exists) { heap_close(pg_shadow_rel, AccessExclusiveLock); UserAbortTransactionBlock(); - elog(ERROR, - "defineUser: user \"%s\" has already been created", stmt->user); + if (user_exists) + elog(ERROR, "DefineUser: user name \"%s\" already exists", stmt->user); + else + elog(ERROR, "DefineUser: sysid %d is already assigned", stmt->sysid); return; } @@ -184,7 +193,7 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest) "values('%s',%d,'%c','f','%c','%c',%s%s%s,%s%s%s)", ShadowRelationName, stmt->user, - max_id + 1, + havesysid ? stmt->sysid : max_id + 1, (stmt->createdb && *stmt->createdb) ? 't' : 'f', (stmt->createuser && *stmt->createuser) ? 't' : 'f', ((stmt->createdb && *stmt->createdb) || @@ -234,6 +243,7 @@ AlterUser(AlterUserStmt *stmt, CommandDest dest) TupleDesc pg_shadow_dsc; HeapTuple tuple; bool inblock; + bool comma = false; if (stmt->password) CheckPgUserAclNotNull(); @@ -248,7 +258,7 @@ AlterUser(AlterUserStmt *stmt, CommandDest dest) 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\"", + elog(ERROR, "AlterUser: user \"%s\" does not have SELECT and UPDATE privilege for \"%s\"", pg_shadow, ShadowRelationName); return; } @@ -268,43 +278,79 @@ AlterUser(AlterUserStmt *stmt, CommandDest dest) { heap_close(pg_shadow_rel, AccessExclusiveLock); UserAbortTransactionBlock(); - elog(ERROR, "alterUser: user \"%s\" does not exist", stmt->user); + elog(ERROR, "AlterUser: user \"%s\" does not exist", stmt->user); } + /* look for duplicate sysid */ + tuple = SearchSysCacheTuple(USESYSID, + Int32GetDatum(stmt->sysid), + 0, 0, 0); + if (HeapTupleIsValid(tuple)) + { + Datum datum; + bool null; + + 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); + } + } + + /* * 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); + snprintf(sql, SQL_LENGTH, "update %s set ", ShadowRelationName); if (stmt->password) + { snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), - " passwd = '%s'", stmt->password); + "passwd = '%s'", stmt->password); + comma = true; + } + + if (stmt->sysid>=0) + { + if (comma) + strcat(sql, ", "); + snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), + "usesysid = %d", stmt->sysid); + comma = true; + } if (stmt->createdb) - { + { + if (comma) + strcat(sql, ", "); snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), - "%s usecreatedb='%s'", - stmt->password ? "," : "", - *stmt->createdb ? "t" : "f"); - } + "usecreatedb='%c'", + *stmt->createdb ? 't' : 'f'); + comma = true; + } if (stmt->createuser) - { + { + if (comma) + strcat(sql, ", "); snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), - "%s usesuper='%s'", - (stmt->password || stmt->createdb) ? "," : "", - *stmt->createuser ? "t" : "f"); - } + "usesuper='%c'", + *stmt->createuser ? 't' : 'f'); + comma = true; + } if (stmt->validUntil) - { + { + if (comma) + strcat(sql, ", "); snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), - "%s valuntil='%s'", - (stmt->password || stmt->createdb || stmt->createuser) ? "," : "", + "valuntil='%s'", stmt->validUntil); - } + } snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), " where usename = '%s'", @@ -362,7 +408,7 @@ RemoveUser(char *user, CommandDest dest) 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\"", + elog(ERROR, "RemoveUser: user \"%s\" does not have SELECT and DELETE privilege for \"%s\"", pg_shadow, ShadowRelationName); } @@ -381,7 +427,7 @@ RemoveUser(char *user, CommandDest dest) { heap_close(pg_shadow_rel, AccessExclusiveLock); UserAbortTransactionBlock(); - elog(ERROR, "removeUser: user \"%s\" does not exist", user); + elog(ERROR, "RemoveUser: user \"%s\" does not exist", user); } usesysid = (int32) heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_dsc, &n); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 5a291dc867..c3d72896f6 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.115 1999/11/20 21:39:36 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.116 1999/11/30 03:57:24 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -137,6 +137,7 @@ static Node *doNegate(Node *n); %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 @@ -295,6 +296,7 @@ static Node *doNegate(Node *n); VALUES, VARCHAR, VARYING, VIEW, WHEN, WHERE, WITH, WORK, YEAR_P, ZONE + /* Keywords (in SQL3 reserved words) */ %token DEFERRABLE, DEFERRED, IMMEDIATE, INITIALLY, @@ -323,7 +325,7 @@ static Node *doNegate(Node *n); NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL, OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL, RENAME, RESET, RETURNS, ROW, RULE, - SEQUENCE, SERIAL, SETOF, SHARE, SHOW, START, STATEMENT, STDIN, STDOUT, + SEQUENCE, SERIAL, SETOF, SHARE, SHOW, START, STATEMENT, STDIN, STDOUT, SYSID, TRUNCATE, TRUSTED, UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION @@ -443,18 +445,34 @@ stmt : AddAttrStmt * *****************************************************************************/ -CreateUserStmt: CREATE USER UserId user_passwd_clause user_createdb_clause - user_createuser_clause user_group_clause user_valid_clause +CreateUserStmt: CREATE USER UserId + user_createdb_clause user_createuser_clause user_group_clause + user_valid_clause { CreateUserStmt *n = makeNode(CreateUserStmt); n->user = $3; - n->password = $4; - n->createdb = $5; - n->createuser = $6; - n->groupElts = $7; - n->validUntil = $8; + n->sysid = -1; + n->password = NULL; + n->createdb = $4; + n->createuser = $5; + n->groupElts = $6; + n->validUntil = $7; $$ = (Node *)n; } + | CREATE USER UserId WITH sysid_clause user_passwd_clause + user_createdb_clause user_createuser_clause user_group_clause + user_valid_clause + { + CreateUserStmt *n = makeNode(CreateUserStmt); + n->user = $3; + n->sysid = $5; + n->password = $6; + n->createdb = $7; + n->createuser = $8; + n->groupElts = $9; + n->validUntil = $10; + $$ = (Node *)n; + } ; /***************************************************************************** @@ -464,16 +482,31 @@ CreateUserStmt: CREATE USER UserId user_passwd_clause user_createdb_clause * *****************************************************************************/ -AlterUserStmt: ALTER USER UserId user_passwd_clause user_createdb_clause - user_createuser_clause user_group_clause user_valid_clause +AlterUserStmt: ALTER USER UserId user_createdb_clause + user_createuser_clause user_group_clause user_valid_clause { AlterUserStmt *n = makeNode(AlterUserStmt); n->user = $3; - n->password = $4; - n->createdb = $5; - n->createuser = $6; - n->groupElts = $7; - n->validUntil = $8; + n->sysid = -1; + n->password = NULL; + n->createdb = $4; + n->createuser = $5; + n->groupElts = $6; + n->validUntil = $7; + $$ = (Node *)n; + } + | ALTER USER UserId WITH sysid_clause user_passwd_clause + user_createdb_clause + user_createuser_clause user_group_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; $$ = (Node *)n; } ; @@ -493,10 +526,14 @@ DropUserStmt: DROP USER UserId } ; -user_passwd_clause: WITH PASSWORD UserId { $$ = $3; } - | /*EMPTY*/ { $$ = NULL; } +user_passwd_clause: PASSWORD UserId { $$ = $2; } + | /*EMPTY*/ { $$ = NULL; } ; +sysid_clause: SYSID Iconst { $$ = $2; } + | /*EMPTY*/ { $$ = -1; } + ; + user_createdb_clause: CREATEDB { bool* b; @@ -537,7 +574,13 @@ user_group_list: user_group_list ',' UserId } ; -user_group_clause: IN GROUP user_group_list { $$ = $3; } +user_group_clause: IN GROUP user_group_list + { + /* the backend doesn't actually process this, + * so an error message is probably fairer */ + yyerror("IN GROUP is not implemented"); + /* $$ = $3; */ + } | /*EMPTY*/ { $$ = NULL; } ; @@ -4764,6 +4807,7 @@ ColId: IDENT { $$ = $1; } | STATEMENT { $$ = "statement"; } | STDIN { $$ = "stdin"; } | STDOUT { $$ = "stdout"; } + | SYSID { $$ = "sysid"; } | TIME { $$ = "time"; } | TIMESTAMP { $$ = "timestamp"; } | TIMEZONE_HOUR { $$ = "timezone_hour"; } diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index 392e7509c8..3cb4e2787d 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.63 1999/10/15 01:49:41 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.64 1999/11/30 03:57:26 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -219,6 +219,7 @@ static ScanKeyword ScanKeywords[] = { {"stdin", STDIN}, {"stdout", STDOUT}, {"substring", SUBSTRING}, + {"sysid", SYSID}, {"table", TABLE}, {"temp", TEMP}, {"temporary", TEMPORARY}, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index aac3ef7de5..04c8c9b518 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.86 1999/10/26 03:12:39 momjian Exp $ + * $Id: parsenodes.h,v 1.87 1999/11/30 03:57:29 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -237,6 +237,7 @@ typedef struct CreateUserStmt NodeTag type; 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? */ List *groupElts; /* The groups the user is a member of */