Commit 4ceb2d0c authored by Peter Eisentraut's avatar Peter Eisentraut

* User management commands no longer user pg_exec_query_dest -> more robust

* Let unprivileged users change their own passwords.

* The password is now an Sconst in the parser, which better reflects its text datatype and also
forces users to quote them.

* If your password is NULL you won't be written to the password file, meaning you can't connect
until you have a password set up (if you use password authentication).

* When you drop a user that owns a database you get an error. The database is not gone.
parent 2af360ed
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
# #
# #
# IDENTIFICATION # 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 \ ...@@ -85,15 +85,17 @@ APPLICATIONS= createdb.sgml createuser.sgml \
psql-ref.sgml \ psql-ref.sgml \
vacuumdb.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 \ begin.sgml \
close.sgml cluster.sgml commit.sgml copy.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_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_table.sgml create_table_as.sgml create_trigger.sgml create_type.sgml \
create_user.sgml create_view.sgml \ create_user.sgml create_view.sgml \
declare.sgml delete.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_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 \ drop_table.sgml drop_trigger.sgml drop_type.sgml drop_user.sgml drop_view.sgml \
explain.sgml fetch.sgml grant.sgml \ explain.sgml fetch.sgml grant.sgml \
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.14 1999/12/05 20:02:42 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.15 2000/01/14 22:11:32 petere Exp $
Postgres documentation Postgres documentation
Complete list of usable sgml source files in this directory. Complete list of usable sgml source files in this directory.
--> -->
...@@ -40,6 +40,7 @@ Complete list of usable sgml source files in this directory. ...@@ -40,6 +40,7 @@ Complete list of usable sgml source files in this directory.
<!-- these are in the "commands" reference chapter --> <!-- these are in the "commands" reference chapter -->
<!entity abort system "abort.sgml"> <!entity abort system "abort.sgml">
<!entity alterGroup system "alter_group.sgml">
<!entity alterTable system "alter_table.sgml"> <!entity alterTable system "alter_table.sgml">
<!entity alterUser system "alter_user.sgml"> <!entity alterUser system "alter_user.sgml">
<!entity begin system "begin.sgml"> <!entity begin system "begin.sgml">
...@@ -50,6 +51,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.
<!entity createAggregate system "create_aggregate.sgml"> <!entity createAggregate system "create_aggregate.sgml">
<!entity createDatabase system "create_database.sgml"> <!entity createDatabase system "create_database.sgml">
<!entity createFunction system "create_function.sgml"> <!entity createFunction system "create_function.sgml">
<!entity createGroup system "create_group.sgml">
<!entity createIndex system "create_index.sgml"> <!entity createIndex system "create_index.sgml">
<!entity createLanguage system "create_language.sgml"> <!entity createLanguage system "create_language.sgml">
<!entity createOperator system "create_operator.sgml"> <!entity createOperator system "create_operator.sgml">
...@@ -66,6 +68,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.
<!entity dropAggregate system "drop_aggregate.sgml"> <!entity dropAggregate system "drop_aggregate.sgml">
<!entity dropDatabase system "drop_database.sgml"> <!entity dropDatabase system "drop_database.sgml">
<!entity dropFunction system "drop_function.sgml"> <!entity dropFunction system "drop_function.sgml">
<!entity dropGroup system "drop_group.sgml">
<!entity dropIndex system "drop_index.sgml"> <!entity dropIndex system "drop_index.sgml">
<!entity dropLanguage system "drop_language.sgml"> <!entity dropLanguage system "drop_language.sgml">
<!entity dropOperator system "drop_operator.sgml"> <!entity dropOperator system "drop_operator.sgml">
......
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_group.sgml,v 1.1 2000/01/14 22:11:32 petere Exp $
Postgres documentation
-->
<refentry id="SQL-ALTERGROUP">
<refmeta>
<refentrytitle id="SQL-ALTERGROUP-title">
ALTER GROUP
</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>
ALTER GROUP
</refname>
<refpurpose>
Add users to a group, remove users from a group
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<refsynopsisdivinfo>
<date>2000-01-14</date>
</refsynopsisdivinfo>
<synopsis>
ALTER GROUP <replaceable class="PARAMETER">name</replaceable> ADD USER <replaceable class="PARAMETER">username</replaceable> [, ... ]
ALTER GROUP <replaceable class="PARAMETER">name</replaceable> DROP USER <replaceable class="PARAMETER">username</replaceable> [, ... ]
</synopsis>
<refsect2 id="R2-SQL-ALTERGROUP-1">
<refsect2info>
<date>2000-01-14</date>
</refsect2info>
<title>
Inputs
</title>
<para>
<variablelist>
<varlistentry>
<term><replaceable class="PARAMETER">name</replaceable></term>
<listitem>
<para>
The name of the group to modify.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">username</replaceable></term>
<listitem>
<para>
Users which are to be added or removed from the group. The user
names must exist.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
<refsect2 id="R2-SQL-ALTERGROUP-2">
<refsect2info>
<date>2000-01-14</date>
</refsect2info>
<title>
Outputs
</title>
<para>
<variablelist>
<varlistentry>
<term><computeroutput>ALTER GROUP</computeroutput></term>
<listitem>
<para>
Message returned if the alteration was successful.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
</refsynopsisdiv>
<refsect1 id="R1-SQL-ALTERGROUP-1">
<refsect1info>
<date>2000-01-14</date>
</refsect1info>
<title>
Description
</title>
<para>
<command>ALTER GROUP</command> 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.
</para>
<para>
Use <xref linkend="SQL-CREATEGROUP" endterm="SQL-CREATEGROUP-title">
to create a new group and <xref linkend="SQL-DROPGROUP"
endterm="SQL-DROPGROUP-title"> to remove a group.
</para>
</refsect1>
<refsect1 id="R1-SQL-ALTERGROUP-2">
<title>
Usage
</title>
<para>
Add users to a group:
<programlisting>
ALTER GROUP staff ADD USER karl, john
</programlisting>
Remove a user from a group
<programlisting>
ALTER GROUP workers DROP USER beth
</programlisting>
</para>
</refsect1>
<refsect1 id="R1-SQL-ALTERGROUP-3">
<title>
Compatibility
</title>
<refsect2 id="R2-SQL-ALTERGROUP-4">
<refsect2info>
<date>2000-01-14</date>
</refsect2info>
<title>
SQL92
</title>
<para>
There is no <command>ALTER GROUP</command> statement in
<acronym>SQL92</acronym>. The concept of roles is
similar.
</para>
</refsect2>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.9 1999/11/30 03:57:22 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.10 2000/01/14 22:11:32 petere Exp $
Postgres documentation Postgres documentation
--> -->
...@@ -24,11 +24,8 @@ Postgres documentation ...@@ -24,11 +24,8 @@ Postgres documentation
</refsynopsisdivinfo> </refsynopsisdivinfo>
<synopsis> <synopsis>
ALTER USER <replaceable class="PARAMETER">username</replaceable> ALTER USER <replaceable class="PARAMETER">username</replaceable>
[ WITH [ WITH PASSWORD '<replaceable class="PARAMETER">password</replaceable>' ]
[ SYSID <replaceable class="PARAMETER">uid</replaceable> ]
[ PASSWORD <replaceable class="PARAMETER">password</replaceable> ] ]
[ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ] [ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ]
[ IN GROUP <replaceable class="PARAMETER">groupname</replaceable> [, ...] ]
[ VALID UNTIL '<replaceable class="PARAMETER">abstime</replaceable>' ] [ VALID UNTIL '<replaceable class="PARAMETER">abstime</replaceable>' ]
</synopsis> </synopsis>
...@@ -40,24 +37,19 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable> ...@@ -40,24 +37,19 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable>
Inputs Inputs
</title> </title>
<para>
Refer to <command>CREATE USER</command> for a detailed description of each
clause.
</para>
<para> <para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term><replaceable class="PARAMETER"> username </replaceable></term> <term><replaceable class="PARAMETER">username</replaceable></term>
<listitem> <listitem>
<para> <para>
The Postgres account name of the user whose details are to be altered. The name of the user whose details are to be altered.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="PARAMETER"> password </replaceable></term> <term><replaceable class="PARAMETER">password</replaceable></term>
<listitem> <listitem>
<para> <para>
The new password to be used for this account. The new password to be used for this account.
...@@ -66,36 +58,36 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable> ...@@ -66,36 +58,36 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="parameter">uid</replaceable></term> <term>CREATEDB</term>
<term>NOCREATEDB</term>
<listitem> <listitem>
<para> <para>
The new <productname>PostgreSQL</productname> user id of the user. These clauses define a user's ability to create databases.
Since this number is used as a key into the If CREATEDB is specified, the user being defined will
<literal>pg_shadow</literal>/<literal>pg_user</literal> table be allowed to create his own databases. Using NOCREATEDB
throughout the system catalogs, it is not recommended that you change will deny a user the ability to create databases.
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 <acronym>UNIX</acronym> user ids match, but some people
choose to keep the numbers the same.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="PARAMETER"> groupname </replaceable></term> <term>CREATEUSER</term>
<term>NOCREATEUSER</term>
<listitem> <listitem>
<para> <para>
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.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="PARAMETER"> abstime </replaceable></term> <term><replaceable class="PARAMETER">abstime</replaceable></term>
<listitem> <listitem>
<para> <para>
The date (and, optionally, the time) 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.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -113,9 +105,7 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable> ...@@ -113,9 +105,7 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable>
<para> <para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term><computeroutput> <term><computeroutput>ALTER USER</computeroutput></term>
ALTER USER
</computeroutput></term>
<listitem> <listitem>
<para> <para>
Message returned if the alteration was successful. Message returned if the alteration was successful.
...@@ -125,7 +115,7 @@ ALTER USER ...@@ -125,7 +115,7 @@ ALTER USER
<varlistentry> <varlistentry>
<term><computeroutput> <term><computeroutput>
ERROR: alterUser: user "username" does not exist ERROR: ALTER USER: user "username" does not exist
</computeroutput></term> </computeroutput></term>
<listitem> <listitem>
<para> <para>
...@@ -148,39 +138,15 @@ ERROR: alterUser: user "username" does not exist ...@@ -148,39 +138,15 @@ ERROR: alterUser: user "username" does not exist
</title> </title>
<para> <para>
<command>ALTER USER</command> is used to change the attributes of a user's <command>ALTER USER</command> is used to change the attributes of a user's
<productname>Postgres</productname> account. <productname>PostgreSQL</productname> account. Only a database superuser
Also, it is only possible for the can change privileges and password expiration with this command. Ordinary
<productname>Postgres</productname> users can only change their own password.
user or any user with read and modify permissions on
<literal>pg_shadow</literal> to alter user passwords.
</para>
<para>
If any of the clauses of the alter user statement are
omitted, the corresponding value in the <literal>pg_shadow</literal> table
is left unchanged.
</para>
<refsect2 id="R2-SQL-ALTERUSER-3">
<refsect2info>
<date>1998-09-08</date>
</refsect2info>
<title>
Notes
</title>
<para>
<command>ALTER USER</command>
is a <productname>Postgres</productname>
language extension.
</para>
<para>
Refer to <command>CREATE/DROP USER</command>
to create or remove a user account.
</para> </para>
<para> <para>
The IN GROUP clause is not yet implemented. Use <xref linkend="SQL-CREATEUSER" endterm="SQL-CREATEUSER-title">
to create a new user and <xref linkend="SQL-DROPUSER"
endterm="SQL-DROPUSER-title"> to remove a user.
</para> </para>
</refsect2>
</refsect1> </refsect1>
<refsect1 id="R1-SQL-ALTERUSER-2"> <refsect1 id="R1-SQL-ALTERUSER-2">
...@@ -190,34 +156,29 @@ ERROR: alterUser: user "username" does not exist ...@@ -190,34 +156,29 @@ ERROR: alterUser: user "username" does not exist
<para> <para>
Change a user password: Change a user password:
<programlisting> <programlisting>
ALTER USER davide WITH PASSWORD hu8jmn3; ALTER USER davide WITH PASSWORD 'hu8jmn3';
</programlisting> </programlisting>
Change a user's valid until date Change a user's valid until date
<programlisting> <programlisting>
ALTER USER manuel VALID UNTIL 'Jan 31 2030'; ALTER USER manuel VALID UNTIL 'Jan 31 2030';
</programlisting> </programlisting>
Change a user's valid until date, specifying that his Change a user's valid until date, specifying that his
authorisation should expire at midday on 4th May 1998 using authorisation should expire at midday on 4th May 1998 using
the time zone which is one hour ahead of UTC the time zone which is one hour ahead of UTC
<programlisting> <programlisting>
ALTER USER chris VALID UNTIL 'May 4 12:00:00 1998 +1'; ALTER USER chris VALID UNTIL 'May 4 12:00:00 1998 +1';
</programlisting> </programlisting>
Give a user the ability to create other users and new databases. Give a user the ability to create other users and new databases.
<programlisting> <programlisting>
ALTER USER miriam CREATEUSER CREATEDB; ALTER USER miriam CREATEUSER CREATEDB;
</programlisting> </programlisting>
Place a user in two groups
<programlisting>
ALTER USER miriam IN GROUP sales, payroll;
</programlisting>
</para> </para>
</refsect1> </refsect1>
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/Attic/commands.sgml,v 1.21 1999/12/05 20:02:42 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/Attic/commands.sgml,v 1.22 2000/01/14 22:11:32 petere Exp $
Postgres documentation Postgres documentation
--> -->
...@@ -14,6 +14,7 @@ Postgres documentation ...@@ -14,6 +14,7 @@ Postgres documentation
</abstract> </abstract>
&abort; &abort;
&alterGroup;
&alterTable; &alterTable;
&alterUser; &alterUser;
&begin; &begin;
...@@ -24,6 +25,7 @@ Postgres documentation ...@@ -24,6 +25,7 @@ Postgres documentation
&createAggregate; &createAggregate;
&createDatabase; &createDatabase;
&createFunction; &createFunction;
&createGroup;
&createIndex; &createIndex;
&createLanguage; &createLanguage;
&createOperator; &createOperator;
...@@ -40,6 +42,7 @@ Postgres documentation ...@@ -40,6 +42,7 @@ Postgres documentation
&dropAggregate; &dropAggregate;
&dropDatabase; &dropDatabase;
&dropFunction; &dropFunction;
&dropGroup;
&dropIndex; &dropIndex;
&dropLanguage; &dropLanguage;
&dropOperator; &dropOperator;
......
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_group.sgml,v 1.1 2000/01/14 22:11:32 petere Exp $
Postgres documentation
-->
<refentry id="SQL-CREATEGROUP">
<refmeta>
<refentrytitle id="sql-creategroup-title">
CREATE GROUP
</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>
CREATE GROUP
</refname>
<refpurpose>
Creates a new group
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<refsynopsisdivinfo>
<date>2000-01-14</date>
</refsynopsisdivinfo>
<synopsis>
CREATE GROUP <replaceable class="PARAMETER">name</replaceable>
[ WITH
[ SYSID <replaceable class="PARAMETER">gid</replaceable> ]
[ USER <replaceable class="PARAMETER">username</replaceable> [, ...] ] ]
</synopsis>
<refsect2 id="R2-SQL-CREATEGROUP-1">
<refsect2info>
<date>2000-01-14</date>
</refsect2info>
<title>
Inputs
</title>
<para>
<variablelist>
<varlistentry>
<term><replaceable class="parameter">name</replaceable></term>
<listitem>
<para>
The name of the group.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">gid</replaceable></term>
<listitem>
<para>
The <literal>SYSID</literal> clause can be used to choose
the <productname>PostgreSQL</productname> group id of the new
group. It is not necessary to do so, however.
</para>
<para>
If this is not specified, the highest assigned group id plus one,
starting at 1, will be used as default.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">username</replaceable></term>
<listitem>
<para>
A list of users to include in the group. The users must already exist.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
<refsect2 id="R2-SQL-CREATEGROUP-2">
<refsect2info>
<date>2000-01-14</date>
</refsect2info>
<title>
Outputs
</title>
<para>
<variablelist>
<varlistentry>
<term><computeroutput>CREATE GROUP</computeroutput></term>
<listitem>
<para>
Message returned if the command completes successfully.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
</refsynopsisdiv>
<refsect1 id="R1-SQL-CREATEGROUP-1">
<refsect1info>
<date>2000-01-14</date>
</refsect1info>
<title>
Description
</title>
<para>
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.
</para>
<para>
Use <xref linkend="SQL-ALTERGROUP" endterm="SQL-ALTERGROUP-title">
to change a group's membership, and <xref linkend="SQL-DROPGROUP"
endterm="SQL-DROPGROUP-title"> to remove a group.
</para>
</refsect1>
<refsect1 id="R1-SQL-CREATEGROUP-2">
<title>
Usage
</title>
<para>
Create an empty group:
<programlisting>
CREATE GROUP staff
</programlisting>
</para>
<para>
Create a group with members:
<programlisting>
CREATE GROUP marketing WITH USER jonathan, david
</programlisting>
</para>
</refsect1>
<refsect1 id="R1-SQL-CREATEGROUP-3">
<title>
Compatibility
</title>
<refsect2 id="R2-SQL-CREATEGROUP-4">
<refsect2info>
<date>2000-01-14</date>
</refsect2info>
<title>
SQL92
</title>
<para>
There is no <command>CREATE GROUP</command> statement in SQL92.
Roles are similar in concept to groups.
</para>
</refsect2>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_user.sgml,v 1.12 1999/12/04 05:03:49 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_user.sgml,v 1.13 2000/01/14 22:11:32 petere Exp $
Postgres documentation Postgres documentation
--> -->
...@@ -15,7 +15,7 @@ Postgres documentation ...@@ -15,7 +15,7 @@ Postgres documentation
CREATE USER CREATE USER
</refname> </refname>
<refpurpose> <refpurpose>
Creates account information for a new user Creates a new database user
</refpurpose> </refpurpose>
</refnamediv> </refnamediv>
<refsynopsisdiv> <refsynopsisdiv>
...@@ -26,7 +26,7 @@ Postgres documentation ...@@ -26,7 +26,7 @@ Postgres documentation
CREATE USER <replaceable class="PARAMETER">username</replaceable> CREATE USER <replaceable class="PARAMETER">username</replaceable>
[ WITH [ WITH
[ SYSID <replaceable class="PARAMETER">uid</replaceable> ] [ SYSID <replaceable class="PARAMETER">uid</replaceable> ]
[ PASSWORD <replaceable class="PARAMETER">password</replaceable> ] ] [ PASSWORD '<replaceable class="PARAMETER">password</replaceable>' ] ]
[ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ] [ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ]
[ IN GROUP <replaceable class="PARAMETER">groupname</replaceable> [, ...] ] [ IN GROUP <replaceable class="PARAMETER">groupname</replaceable> [, ...] ]
[ VALID UNTIL '<replaceable class="PARAMETER">abstime</replaceable>' ] [ VALID UNTIL '<replaceable class="PARAMETER">abstime</replaceable>' ]
...@@ -61,13 +61,6 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable> ...@@ -61,13 +61,6 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable>
match the <acronym>UNIX</acronym> user ids, but some people match the <acronym>UNIX</acronym> user ids, but some people
choose to keep the numbers the same. choose to keep the numbers the same.
</para> </para>
<para>
If you still want the
OS user id and the <filename>usesysid</filename> to match
for any given user,
use the <application>createuser</application> script provided with
the <productname>Postgres</productname> distribution.
</para>
<para> <para>
If this is not specified, the highest assigned user id plus one If this is not specified, the highest assigned user id plus one
will be used as default. will be used as default.
...@@ -79,30 +72,11 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable> ...@@ -79,30 +72,11 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable>
<term><replaceable class="parameter">password</replaceable></term> <term><replaceable class="parameter">password</replaceable></term>
<listitem> <listitem>
<para> <para>
The PASSWORD clause sets the user's password within Sets the user's password. If you do not plan to use password
the "<filename>pg_shadow</filename>" table. For this reason, authentication you can omit this option, otherwise the user
<filename>"pg_shadow</filename>" is no won't be able to connect to a password-authenticated server.
longer accessible to the instance of See pg_hba.conf(5) or the administrator's guide for details on
<productname>Postgres</productname> that the how to set up authentication mechanisms.
<productname>Postgres</productname>
user's password is initially set to NULL.
</para>
<para>
When a
user's password in the "<filename>pg_shadow</filename>"
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 <productname>Postgres</productname>
instance, and the password
stored in the "<filename>pg_shadow</filename>" 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.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -127,8 +101,8 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable> ...@@ -127,8 +101,8 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable>
<listitem> <listitem>
<para> <para>
These clauses determine whether a user will be permitted to These clauses determine whether a user will be permitted to
create new create new users himself. This option will also make the user
users in an instance of <productname>Postgres</productname>. a superuser who can override all access restrictions.
Omitting this clause will set the user's value of this Omitting this clause will set the user's value of this
attribute to be NOCREATEUSER. attribute to be NOCREATEUSER.
</para> </para>
...@@ -149,15 +123,8 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable> ...@@ -149,15 +123,8 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable>
<listitem> <listitem>
<para> <para>
The VALID UNTIL clause sets an absolute time after which the The VALID UNTIL clause sets an absolute time after which the
user's <productname>Postgres</productname> user's password is no longer valid.
login is no longer valid. Please note that If this clause is omitted the login will be valid for all time.
if a user does not have a password defined in the
"<filename>pg_shadow</filename>"
table, the valid until date will not be checked
during user authentication. If this clause is omitted,
a NULL value is stored in "<filename>pg_shadow</filename>"
for this attribute,
and the login will be valid for all time.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -176,9 +143,7 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable> ...@@ -176,9 +143,7 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable>
<para> <para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term><computeroutput> <term><computeroutput>CREATE USER</computeroutput></term>
CREATE USER
</computeroutput></term>
<listitem> <listitem>
<para> <para>
Message returned if the command completes successfully. Message returned if the command completes successfully.
...@@ -199,61 +164,38 @@ CREATE USER ...@@ -199,61 +164,38 @@ CREATE USER
</title> </title>
<para> <para>
CREATE USER will add a new user to an instance of CREATE USER will add a new user to an instance of
<productname>PostgreSQL</productname>. <productname>PostgreSQL</productname>. Refer to the adminstrator's
guide for information about managing users and authentication.
You must be a database superuser to use this command.
</para> </para>
<refsect2 id="R2-SQL-CREATEUSER-3">
<refsect2info>
<date>1998-09-21</date>
</refsect2info>
<title>
Notes
</title>
<para> <para>
<command>CREATE USER</command> statement is a Use <xref linkend="SQL-ALTERUSER" endterm="SQL-ALTERUSER-title">
<productname>Postgres</productname> language extension. to change a user's password and privileges, and <xref linkend="SQL-DROPUSER"
endterm="SQL-DROPUSER-title"> to remove a user.
Use <command>ALTER GROUP</command> to add or remove the user from other groups.
<productname>PostgreSQL</productname>
comes with a script <xref linkend="APP-CREATEUSER"
endterm="APP-CREATEUSER-title">
which has the same functionality as this command (in fact, it calls this command)
but can be run from the command shell.
</para> </para>
<para>
Use <command>DROP USER</command> or <command>ALTER USER</command>
statements to remove or modify a user account.
</para>
<para>
Refer to the <filename>pg_shadow</filename> table for further information.
</para>
<programlisting>
Table "pg_shadow"
Attribute | Type | Extra
-------------+---------+-------
usename | name |
usesysid | int4 |
usecreatedb | bool |
usetrace | bool |
usesuper | bool |
usecatupd | bool |
passwd | text |
valuntil | abstime |
</programlisting>
</refsect2>
</refsect1> </refsect1>
<refsect1 id="R1-SQL-CREATEUSER-2"> <refsect1 id="R1-SQL-CREATEUSER-2">
<title> <title>
Usage Usage
</title> </title>
<para> <para>
Create a user with no password: Create a user with no password:
<programlisting>
<programlisting>
CREATE USER jonathan CREATE USER jonathan
</programlisting> </programlisting>
</para> </para>
<para> <para>
Create a user with a password: Create a user with a password:
<programlisting>
<programlisting> CREATE USER davide WITH PASSWORD 'jw8s0F4'
CREATE USER davide WITH PASSWORD "jw8s0F4" </programlisting>
</programlisting>
</para> </para>
<para> <para>
...@@ -261,17 +203,16 @@ 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 Note that after one second has ticked in 2002, the account is not
valid: valid:
<programlisting> <programlisting>
CREATE USER miriam WITH PASSWORD "jw8s0F4" VALID UNTIL 'Jan 1 2002' CREATE USER miriam WITH PASSWORD 'jw8s0F4' VALID UNTIL 'Jan 1 2002'
</programlisting> </programlisting>
</para> </para>
<para> <para>
Create an account where the user can create databases: Create an account where the user can create databases:
<programlisting>
<programlisting> CREATE USER manuel WITH PASSWORD 'jw8s0F4' CREATEDB
CREATE USER manuel WITH PASSWORD "jw8s0F4" CREATEDB </programlisting>
</programlisting>
</para> </para>
</refsect1> </refsect1>
......
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_group.sgml,v 1.1 2000/01/14 22:11:32 petere Exp $
Postgres documentation
-->
<refentry id="SQL-DROPGROUP">
<refmeta>
<refentrytitle id="SQL-DROPGROUP-TITLE">
DROP GROUP
</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>
DROP GROUP
</refname>
<refpurpose>
Removes a group
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<refsynopsisdivinfo>
<date>2000-01-14</date>
</refsynopsisdivinfo>
<synopsis>
DROP GROUP <replaceable class="PARAMETER">name</replaceable>
</synopsis>
<refsect2 id="R2-SQL-DROPGROUP-1">
<refsect2info>
<date>2000-01-14</date>
</refsect2info>
<title>
Inputs
</title>
<para>
<variablelist>
<varlistentry>
<term><replaceable class="PARAMETER">name</replaceable></term>
<listitem>
<para>
The name of an existing group.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
<refsect2 id="R2-SQL-DROPGROUP-2">
<refsect2info>
<date>2000-01-14</date>
</refsect2info>
<title>
Outputs
</title>
<para>
<variablelist>
<varlistentry>
<term><computeroutput>DROP GROUP</computeroutput></term>
<listitem>
<para>
The message returned if the group is successfully deleted.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
</refsynopsisdiv>
<refsect1 id="R1-SQL-DROPGROUP-1">
<refsect1info>
<date>2000-01-14</date>
</refsect1info>
<title>
Description
</title>
<para>
<command>DROP GROUP</command> removes the specified group from the database.
The users in the group are not deleted.
</para>
<para>
Use <xref linkend="SQL-CREATEGROUP" endterm="SQL-CREATEGROUP-title">
to add new groups, and <xref linkend="SQL-ALTERGROUP"
endterm="SQL-ALTERGROUP-title"> to change a group's membership.
</para>
</refsect1>
<refsect1 id="R1-SQL-DROPGROUP-2">
<title>
Usage
</title>
<para>
To drop a group:
<programlisting>
DROP GROUP staff;
</programlisting>
</para>
</refsect1>
<refsect1 id="R1-SQL-DROPGROUP-3">
<title>
Compatibility
</title>
<refsect2 id="R2-SQL-DROPGROUP-4">
<refsect2info>
<date>2000-01-14</date>
</refsect2info>
<title>
SQL92
</title>
<para>
There is no <command>DROP GROUP</command> in <acronym>SQL92</acronym>.
</para>
</refsect2>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_user.sgml,v 1.9 1999/12/07 22:41:41 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_user.sgml,v 1.10 2000/01/14 22:11:32 petere Exp $
Postgres documentation Postgres documentation
--> -->
...@@ -15,7 +15,7 @@ Postgres documentation ...@@ -15,7 +15,7 @@ Postgres documentation
DROP USER DROP USER
</refname> </refname>
<refpurpose> <refpurpose>
Removes an user account information Removes a user
</refpurpose> </refpurpose>
</refnamediv> </refnamediv>
<refsynopsisdiv> <refsynopsisdiv>
...@@ -58,18 +58,17 @@ DROP USER <replaceable class="PARAMETER">name</replaceable> ...@@ -58,18 +58,17 @@ DROP USER <replaceable class="PARAMETER">name</replaceable>
<para> <para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>
<term><computeroutput> <term><computeroutput>DROP USER</computeroutput></term>
DROP
</computeroutput></term>
<listitem> <listitem>
<para> <para>
The message returned if the user is successfully deleted. The message returned if the user is successfully deleted.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><computeroutput> <term><computeroutput>
ERROR: removeUser: user "<replaceable class="parameter">name</replaceable>" does not exist. ERROR: DROP USER: user "<replaceable class="parameter">name</replaceable>" does not exist
</computeroutput></term> </computeroutput></term>
<listitem> <listitem>
<para> <para>
...@@ -77,6 +76,18 @@ ERROR: removeUser: user "<replaceable class="parameter">name</replaceable>" does ...@@ -77,6 +76,18 @@ ERROR: removeUser: user "<replaceable class="parameter">name</replaceable>" does
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><computeroutput>
DROP USER: user "<replaceable class="parameter">name</replaceable>" owns database "<replaceable class="parameter">name</replaceable>", cannot be removed
</computeroutput></term>
<listitem>
<para>
You must drop the database first or change its ownership.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
</refsect2> </refsect2>
...@@ -90,30 +101,20 @@ ERROR: removeUser: user "<replaceable class="parameter">name</replaceable>" does ...@@ -90,30 +101,20 @@ ERROR: removeUser: user "<replaceable class="parameter">name</replaceable>" does
Description Description
</title> </title>
<para> <para>
<command>DROP USER</command> removes the specified <command>DROP USER</command> removes the specified user from the database.
user from the database, It does not remove tables, views, or other objects owned by the user. If the
along with any databases owned by the user. It user owns any database you get an error.
does not remove tables, views, or triggers owned by the
named user in databases not owned by the user.
</para> </para>
<refsect2 id="R2-SQL-DROPUSER-3">
<refsect2info>
<date>1998-09-22</date>
</refsect2info>
<title>
Notes
</title>
<para> <para>
<command>DROP USER</command> is a <productname>Postgres</productname> Use <xref linkend="SQL-CREATEUSER" endterm="SQL-CREATEUSER-title">
language extension. to add new users, and <xref linkend="SQL-ALTERUSER"
endterm="SQL-ALTERUSER-title"> to change a user's properties.
<productname>PostgreSQL</productname>
comes with a script <xref linkend="APP-DROPUSER"
endterm="APP-DROPUSER-title">
which has the same functionality as this command (in fact, it calls this command)
but can be run from the command shell.
</para> </para>
<para>
Refer to <command>CREATE USER</command> and
<command>ALTER USER</command> for information on
how to create or modify user accounts.
</para>
</refsect2>
</refsect1> </refsect1>
<refsect1 id="R1-SQL-DROPUSER-2"> <refsect1 id="R1-SQL-DROPUSER-2">
...@@ -122,9 +123,9 @@ ERROR: removeUser: user "<replaceable class="parameter">name</replaceable>" does ...@@ -122,9 +123,9 @@ ERROR: removeUser: user "<replaceable class="parameter">name</replaceable>" does
</title> </title>
<para> <para>
To drop a user account: To drop a user account:
<programlisting> <programlisting>
DROP USER Jonathan; DROP USER jonathan;
</programlisting> </programlisting>
</para> </para>
</refsect1> </refsect1>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -97,7 +97,11 @@ CopySendData(void *databuf, int datasize, FILE *fp)
fe_eof = true; fe_eof = true;
} }
else else
{
fwrite(databuf, datasize, 1, fp); fwrite(databuf, datasize, 1, fp);
if (ferror(fp))
elog(ERROR, "CopySendData: %s", strerror(errno));
}
} }
static void static void
...@@ -219,7 +223,7 @@ CopyDonePeek(FILE *fp, int c, int pickup) ...@@ -219,7 +223,7 @@ CopyDonePeek(FILE *fp, int c, int pickup)
void void
DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, 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 <relname>, depending on <from>. Either unload or reload contents of class <relname>, depending on <from>.
...@@ -235,11 +239,6 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, ...@@ -235,11 +239,6 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
If in the text format, delimit columns with delimiter <delim> and print If in the text format, delimit columns with delimiter <delim> and print
NULL values as <null_print>. NULL values as <null_print>.
<fileumask> 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, <fileumask> was always 000, which was foolhardy.
When loading in the text format from an input stream (as opposed to 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 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, 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, ...@@ -272,12 +271,11 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
result = pg_aclcheck(relname, UserName, required_access); result = pg_aclcheck(relname, UserName, required_access);
if (result != ACLCHECK_OK) if (result != ACLCHECK_OK)
elog(ERROR, "%s: %s", relname, aclcheck_error_strings[result]); 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 " elog(ERROR, "You must have Postgres superuser privilege to do a COPY "
"directly to or from a file. Anyone can COPY to stdout or " "directly to or from a file. Anyone can COPY to stdout or "
"from stdin. Psql's \\copy command also works for anyone."); "from stdin. Psql's \\copy command also works for anyone.");
else
{
if (from) if (from)
{ /* copy from file to database */ { /* copy from file to database */
if (rel->rd_rel->relkind == RELKIND_SEQUENCE) if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
...@@ -324,7 +322,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, ...@@ -324,7 +322,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
{ {
mode_t oumask; /* Pre-existing umask value */ mode_t oumask; /* Pre-existing umask value */
oumask = umask((mode_t) fileumask); oumask = umask((mode_t) 022);
#ifndef __CYGWIN32__ #ifndef __CYGWIN32__
fp = AllocateFile(filename, "w"); fp = AllocateFile(filename, "w");
#else #else
...@@ -350,7 +348,6 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, ...@@ -350,7 +348,6 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
if (IsUnderPostmaster) if (IsUnderPostmaster)
pq_endcopyout(false); pq_endcopyout(false);
} }
}
/* /*
* Close the relation. If reading, we can release the AccessShareLock * Close the relation. If reading, we can release the AccessShareLock
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -31,6 +31,7 @@
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/array.h" #include "utils/array.h"
#include "utils/builtins.h"
#include "utils/syscache.h" #include "utils/syscache.h"
static void CheckPgUserAclNotNull(void); static void CheckPgUserAclNotNull(void);
...@@ -38,30 +39,26 @@ static void CheckPgUserAclNotNull(void); ...@@ -38,30 +39,26 @@ static void CheckPgUserAclNotNull(void);
#define SQL_LENGTH 512 #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 * 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. * for user authentication. The file is stored as $PGDATA/pg_pwd.
* *
* NB: caller is responsible for ensuring that only one backend can * This function set is both a trigger function for direct updates to pg_shadow
* execute this routine at a time. Acquiring AccessExclusiveLock on * as well as being called directly from create/alter/drop user.
* pg_shadow is the standard way to do that.
*--------------------------------------------------------------------- *---------------------------------------------------------------------
*/ */
static void
HeapTuple write_password_file(Relation rel)
update_pg_pwd(void)
{ {
char *filename, char *filename,
*tempname; *tempname;
int bufsize; int bufsize;
FILE *fp;
mode_t oumask;
/* HeapScanDesc scan;
* This is a trigger, so clean out the information provided by HeapTuple tuple;
* the trigger manager. TupleDesc dsc = RelationGetDescr(rel);
*/
CurrentTriggerData = NULL;
/* /*
* Create a temporary filename to be renamed later. This prevents the * Create a temporary filename to be renamed later. This prevents the
...@@ -71,22 +68,63 @@ update_pg_pwd(void) ...@@ -71,22 +68,63 @@ update_pg_pwd(void)
filename = crypt_getpwdfilename(); filename = crypt_getpwdfilename();
bufsize = strlen(filename) + 12; bufsize = strlen(filename) + 12;
tempname = (char *) palloc(bufsize); tempname = (char *) palloc(bufsize);
snprintf(tempname, bufsize, "%s.%d", filename, MyProcPid); 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));
/* 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);
/*
* 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. * And rename the temp file to its final name, deleting the old pg_pwd.
*/ */
...@@ -98,59 +136,66 @@ update_pg_pwd(void) ...@@ -98,59 +136,66 @@ update_pg_pwd(void)
* the pg_pwd file contents. * the pg_pwd file contents.
*/ */
filename = crypt_getpwdreloadfilename(); 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); pfree((void *) tempname);
}
/* 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; return NULL;
} }
/*---------------------------------------------------------------------
* DefineUser
* /*
* Add the user to the pg_shadow relation, and if specified make sure the * CREATE USER
* user is specified in the desired groups of defined in pg_group.
*---------------------------------------------------------------------
*/ */
void void
DefineUser(CreateUserStmt *stmt, CommandDest dest) CreateUser(CreateUserStmt *stmt)
{ {
char *pg_shadow,
sql[SQL_LENGTH];
Relation pg_shadow_rel; Relation pg_shadow_rel;
TupleDesc pg_shadow_dsc; TupleDesc pg_shadow_dsc;
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple tuple; HeapTuple tuple;
Datum new_record[Natts_pg_shadow];
char new_record_nulls[Natts_pg_shadow];
bool user_exists = false, bool user_exists = false,
sysid_exists = false, sysid_exists = false,
inblock, havesysid;
havesysid,
havepassword,
havevaluntil;
int max_id = -1; int max_id = -1;
List *item; List *item;
havesysid = stmt->sysid >= 0; havesysid = stmt->sysid > 0;
havepassword = stmt->password && stmt->password[0];
havevaluntil = stmt->validUntil && stmt->validUntil[0];
if (havepassword) /* Check some permissions first */
if (stmt->password)
CheckPgUserAclNotNull(); CheckPgUserAclNotNull();
if (!(inblock = IsTransactionBlock()))
BeginTransactionBlock();
/* if (!superuser())
* Make sure the user attempting to create a user can insert into the elog(ERROR, "CREATE USER: permission denied");
* pg_shadow relation.
/* 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.
*/ */
pg_shadow = GetPgUserName(); if (IsTransactionBlock())
if (pg_aclcheck(ShadowRelationName, pg_shadow, ACL_RD | ACL_WR | ACL_AP) != ACLCHECK_OK) elog(ERROR, "CREATE USER: may not be called in a transaction block");
{
UserAbortTransactionBlock();
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 or id doesn't already * Scan the pg_shadow relation to be certain the user or id doesn't already
...@@ -184,49 +229,64 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest) ...@@ -184,49 +229,64 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest)
if (user_exists || sysid_exists) if (user_exists || sysid_exists)
{ {
heap_close(pg_shadow_rel, AccessExclusiveLock); heap_close(pg_shadow_rel, AccessExclusiveLock);
UserAbortTransactionBlock();
if (user_exists) 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 else
elog(ERROR, "DefineUser: sysid %d is already assigned", stmt->sysid); elog(ERROR, "CREATE USER: sysid %d is already assigned", stmt->sysid);
return; return;
} }
/* /*
* Build the insert statement to be executed. * Build a tuple to insert
*
* 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, new_record[Anum_pg_shadow_usename-1] = PointerGetDatum(namein(stmt->user)); /* this truncated properly */
"insert into %s (usename,usesysid,usecreatedb,usetrace," new_record[Anum_pg_shadow_usesysid-1] = Int32GetDatum(havesysid ? stmt->sysid : max_id + 1);
"usesuper,usecatupd,passwd,valuntil) "
"values('%s',%d,'%c','f','%c','%c',%s%s%s,%s%s%s)", AssertState(BoolIsValid(stmt->createdb));
ShadowRelationName, new_record[Anum_pg_shadow_usecreatedb-1] = (Datum)(stmt->createdb);
stmt->user, new_record[Anum_pg_shadow_usetrace-1] = (Datum)(false);
havesysid ? stmt->sysid : max_id + 1, AssertState(BoolIsValid(stmt->createuser));
(stmt->createdb && *stmt->createdb) ? 't' : 'f', new_record[Anum_pg_shadow_usesuper-1] = (Datum)(stmt->createuser);
(stmt->createuser && *stmt->createuser) ? 't' : 'f', /* superuser gets catupd right by default */
((stmt->createdb && *stmt->createdb) || new_record[Anum_pg_shadow_usecatupd-1] = (Datum)(stmt->createuser);
(stmt->createuser && *stmt->createuser)) ? 't' : 'f',
havepassword ? "'" : "", if (stmt->password)
havepassword ? stmt->password : "NULL", new_record[Anum_pg_shadow_passwd-1] = PointerGetDatum(textin(stmt->password));
havepassword ? "'" : "", if (stmt->validUntil)
havevaluntil ? "'" : "", new_record[Anum_pg_shadow_valuntil-1] = PointerGetDatum(nabstimein(stmt->validUntil));
havevaluntil ? stmt->validUntil : "NULL",
havevaluntil ? "'" : ""); 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);
/* /*
* XXX If insert fails, say because a bogus valuntil date is given, * Insert a new record in the pg_shadow table
* need to catch the resulting error and undo our transaction.
*/ */
pg_exec_query_dest(sql, dest, false); 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 * Add the user to the groups specified. We'll just call the below
...@@ -236,59 +296,49 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest) ...@@ -236,59 +296,49 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest)
{ {
AlterGroupStmt ags; AlterGroupStmt ags;
ags.name = strVal(lfirst(item)); ags.name = strVal(lfirst(item)); /* the group name to add this in */
ags.action = +1; ags.action = +1;
ags.listUsers = lcons((void*)makeString(stmt->user), NIL); ags.listUsers = lcons((void*)makeInteger(havesysid ? stmt->sysid : max_id + 1), NIL);
AlterGroup(&ags, dest); AlterGroup(&ags, "CREATE USER");
} }
/* /*
* Write the updated pg_shadow data to the flat password file. * 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. * Now we can clean up.
*/ */
heap_close(pg_shadow_rel, AccessExclusiveLock); heap_close(pg_shadow_rel, AccessExclusiveLock);
if (IsTransactionBlock() && !inblock)
EndTransactionBlock();
} }
/*
* ALTER USER
*/
extern void extern void
AlterUser(AlterUserStmt *stmt, CommandDest dest) AlterUser(AlterUserStmt *stmt)
{ {
Datum new_record[Natts_pg_shadow];
char *pg_shadow, char new_record_nulls[Natts_pg_shadow];
sql[SQL_LENGTH];
Relation pg_shadow_rel; Relation pg_shadow_rel;
TupleDesc pg_shadow_dsc; TupleDesc pg_shadow_dsc;
HeapTuple tuple; HeapTuple tuple, new_tuple;
bool inblock; bool null;
bool comma = false;
if (stmt->password) if (stmt->password)
CheckPgUserAclNotNull(); CheckPgUserAclNotNull();
if (!(inblock = IsTransactionBlock()))
BeginTransactionBlock();
/* /* must be superuser or just want to change your own password */
* Make sure the user attempting to create a user can insert into the if (!superuser() &&
* pg_shadow relation. !(stmt->createdb==0 && stmt->createuser==0 && !stmt->validUntil
*/ && stmt->password && strcmp(GetPgUserName(), stmt->user)==0))
pg_shadow = GetPgUserName(); elog(ERROR, "ALTER USER: permission denied");
if (pg_aclcheck(ShadowRelationName, pg_shadow, ACL_RD | ACL_WR) != ACLCHECK_OK)
{ /* see comments in create user */
UserAbortTransactionBlock(); if (IsTransactionBlock())
elog(ERROR, "AlterUser: user \"%s\" does not have SELECT and UPDATE privilege for \"%s\"", elog(ERROR, "ALTER USER: may not be called in a transaction block");
pg_shadow, ShadowRelationName);
return;
}
/* /*
* Scan the pg_shadow relation to be certain the user exists. * Scan the pg_shadow relation to be certain the user exists.
...@@ -304,142 +354,135 @@ AlterUser(AlterUserStmt *stmt, CommandDest dest) ...@@ -304,142 +354,135 @@ AlterUser(AlterUserStmt *stmt, CommandDest dest)
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{ {
heap_close(pg_shadow_rel, AccessExclusiveLock); heap_close(pg_shadow_rel, AccessExclusiveLock);
UserAbortTransactionBlock(); elog(ERROR, "ALTER USER: user \"%s\" does not exist", stmt->user);
elog(ERROR, "AlterUser: user \"%s\" does not exist", stmt->user);
} }
/* look for duplicate sysid */ /*
tuple = SearchSysCacheTuple(SHADOWSYSID, * Build a tuple to update, perusing the information just obtained
Int32GetDatum(stmt->sysid), */
0, 0, 0); new_record[Anum_pg_shadow_usename-1] = PointerGetDatum(namein(stmt->user));
if (HeapTupleIsValid(tuple)) new_record_nulls[Anum_pg_shadow_usename-1] = ' ';
{
Datum datum;
bool null;
datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_shadow_dsc, &null); /* sysid - leave as is */
if (datum && !null && strcmp((char *) datum, stmt->user) != 0) 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)
{ {
heap_close(pg_shadow_rel, AccessExclusiveLock); /* don't change */
UserAbortTransactionBlock(); new_record[Anum_pg_shadow_usecreatedb-1] = heap_getattr(tuple, Anum_pg_shadow_usecreatedb, pg_shadow_dsc, &null);
elog(ERROR, "AlterUser: sysid %d is already assigned", stmt->sysid); 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' : ' ';
/* /* createuser (superuser) */
* Create the update statement to modify the user. if (stmt->createuser == 0)
*
* XXX see diatribe in preceding routine. This code is just as bogus.
*/
snprintf(sql, SQL_LENGTH, "update %s set ", ShadowRelationName);
if (stmt->password)
{ {
snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), /* don't change */
"passwd = '%s'", stmt->password); new_record[Anum_pg_shadow_usesuper-1] = heap_getattr(tuple, Anum_pg_shadow_usesuper, pg_shadow_dsc, &null);
comma = true; new_record_nulls[Anum_pg_shadow_usesuper-1] = null ? 'n' : ' ';
} }
else
if (stmt->sysid>=0)
{ {
if (comma) new_record[Anum_pg_shadow_usesuper-1] = (Datum)(stmt->createuser > 0 ? true : false);
strcat(sql, ", "); new_record_nulls[Anum_pg_shadow_usesuper-1] = ' ';
snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
"usesysid = %d", stmt->sysid);
comma = true;
} }
if (stmt->createdb) /* catupd - set to false if someone's superuser priv is being yanked */
if (stmt->createuser < 0)
{
new_record[Anum_pg_shadow_usecatupd-1] = (Datum)(false);
new_record_nulls[Anum_pg_shadow_usecatupd-1] = ' ';
}
else
{ {
if (comma) /* leave alone */
strcat(sql, ", "); new_record[Anum_pg_shadow_usecatupd-1] = heap_getattr(tuple, Anum_pg_shadow_usecatupd, pg_shadow_dsc, &null);
snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), new_record_nulls[Anum_pg_shadow_usecatupd-1] = null ? 'n' : ' ';
"usecreatedb='%c'",
*stmt->createdb ? 't' : 'f');
comma = true;
} }
if (stmt->createuser) /* password */
if (stmt->password)
{
new_record[Anum_pg_shadow_passwd-1] = PointerGetDatum(textin(stmt->password));
new_record_nulls[Anum_pg_shadow_passwd-1] = ' ';
}
else
{ {
if (comma) /* leave as is */
strcat(sql, ", "); new_record[Anum_pg_shadow_passwd-1] = heap_getattr(tuple, Anum_pg_shadow_passwd, pg_shadow_dsc, &null);
snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), new_record_nulls[Anum_pg_shadow_passwd-1] = null ? 'n' : ' ';
"usesuper='%c'",
*stmt->createuser ? 't' : 'f');
comma = true;
} }
/* valid until */
if (stmt->validUntil) if (stmt->validUntil)
{ {
if (comma) new_record[Anum_pg_shadow_valuntil-1] = PointerGetDatum(nabstimein(stmt->validUntil));
strcat(sql, ", "); new_record_nulls[Anum_pg_shadow_valuntil-1] = ' ';
snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), }
"valuntil='%s'", else
stmt->validUntil); {
/* 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' : ' ';
} }
snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql), new_tuple = heap_formtuple(pg_shadow_dsc, new_record, new_record_nulls);
" where usename = '%s'", Assert(new_tuple);
stmt->user); /* XXX check return value of this? */
heap_update(pg_shadow_rel, &tuple->t_self, new_tuple, NULL);
pg_exec_query_dest(sql, dest, false);
/* /* Update indexes */
* Add stuff here for groups? if (RelationGetForm(pg_shadow_rel)->relhasindex)
*/ {
if (stmt->groupElts) Relation idescs[Num_pg_shadow_indices];
elog(NOTICE, "IN GROUP is not implemented for ALTER USER.");
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);
}
/* /*
* Write the updated pg_shadow data to the flat password file. * 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. * Now we can clean up.
*/ */
heap_close(pg_shadow_rel, AccessExclusiveLock); 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;
Relation pg_shadow_rel, TupleDesc pg_shadow_dsc;
pg_rel; List *item;
TupleDesc pg_dsc;
HeapScanDesc scan;
HeapTuple tuple;
Datum datum;
char sql[SQL_LENGTH];
bool n,
inblock;
int32 usesysid;
int ndbase = 0;
char **dbase = NULL;
if (!(inblock = IsTransactionBlock())) if (!superuser())
BeginTransactionBlock(); elog(ERROR, "DROP USER: permission denied");
/* if (IsTransactionBlock())
* Make sure the user attempting to create a user can delete from the elog(ERROR, "DROP USER: may not be called in a transaction block");
* 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);
}
/* /*
* Scan the pg_shadow relation to find the usesysid of the user to be * Scan the pg_shadow relation to find the usesysid of the user to be
...@@ -447,7 +490,20 @@ RemoveUser(char *user, CommandDest dest) ...@@ -447,7 +490,20 @@ RemoveUser(char *user, CommandDest dest)
* our update of the flat password file. * our update of the flat password file.
*/ */
pg_shadow_rel = heap_openr(ShadowRelationName, AccessExclusiveLock); pg_shadow_rel = heap_openr(ShadowRelationName, AccessExclusiveLock);
pg_dsc = RelationGetDescr(pg_shadow_rel); pg_shadow_dsc = RelationGetDescr(pg_shadow_rel);
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));
tuple = SearchSysCacheTuple(SHADOWNAME, tuple = SearchSysCacheTuple(SHADOWNAME,
PointerGetDatum(user), PointerGetDatum(user),
...@@ -455,92 +511,88 @@ RemoveUser(char *user, CommandDest dest) ...@@ -455,92 +511,88 @@ RemoveUser(char *user, CommandDest dest)
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{ {
heap_close(pg_shadow_rel, AccessExclusiveLock); heap_close(pg_shadow_rel, AccessExclusiveLock);
UserAbortTransactionBlock(); elog(ERROR, "DROP USER: user \"%s\" does not exist%s", user,
elog(ERROR, "RemoveUser: user \"%s\" does not exist", user); (length(stmt->users) > 1) ? " (no users removed)" : "");
} }
usesysid = (int32) heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_dsc, &n); usesysid = DatumGetInt32(heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &null));
/* /*-------------------
* Perform a scan of the pg_database relation to find the databases * Check if user still owns a database. If so, error out.
* owned by usesysid. Then drop them. *
*/ * (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_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
pg_dsc = RelationGetDescr(pg_rel); pg_dsc = RelationGetDescr(pg_rel);
scan = heap_beginscan(pg_rel, false, SnapshotNow, 0, NULL); ScanKeyEntryInitialize(&scankey, 0x0, Anum_pg_database_datdba, F_INT4EQ,
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) Int32GetDatum(usesysid));
{
datum = heap_getattr(tuple, Anum_pg_database_datdba, pg_dsc, &n);
if ((int) datum == usesysid) scan = heap_beginscan(pg_rel, false, SnapshotNow, 1, &scankey);
{
datum = heap_getattr(tuple, Anum_pg_database_datname, pg_dsc, &n); if (HeapTupleIsValid(tmp_tuple = heap_getnext(scan, 0)))
if (memcmp((void *) datum, "template1", 9) != 0)
{ {
dbase = datum = heap_getattr(tmp_tuple, Anum_pg_database_datname, pg_dsc, &null);
(char **) repalloc((void *) dbase, sizeof(char *) * (ndbase + 1)); heap_close(pg_shadow_rel, AccessExclusiveLock);
dbase[ndbase] = (char *) palloc(NAMEDATALEN + 1); elog(ERROR, "DROP USER: user \"%s\" owns database \"%s\", cannot be removed%s",
memcpy((void *) dbase[ndbase], (void *) datum, NAMEDATALEN); user, nameout(DatumGetName(datum)),
dbase[ndbase++][NAMEDATALEN] = '\0'; (length(stmt->users) > 1) ? " (no users removed)" : ""
} );
}
} }
heap_endscan(scan); heap_endscan(scan);
heap_close(pg_rel, AccessExclusiveLock); heap_close(pg_rel, AccessExclusiveLock);
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);
/* /*
* Since pg_shadow is global over all databases, one of two things * Somehow we'd have to check for tables, views, etc. owned by the user
* must be done to insure complete consistency. First, pg_shadow * as well, but those could be spread out over all sorts of databases
* could be made non-global. This would elminate the code above for * which we don't have access to (easily).
* 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
*
*/ */
/* /*
* Remove the user from the pg_shadow table * Remove the user from the pg_shadow table
*/ */
snprintf(sql, SQL_LENGTH, heap_delete(pg_shadow_rel, &tuple->t_self, NULL);
"delete from %s where usename = '%s'", ShadowRelationName, user);
pg_exec_query_dest(sql, dest, false); /*
* 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. * 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. * Now we can clean up.
*/ */
heap_close(pg_shadow_rel, AccessExclusiveLock); heap_close(pg_shadow_rel, AccessExclusiveLock);
if (IsTransactionBlock() && !inblock)
EndTransactionBlock();
} }
/* /*
* CheckPgUserAclNotNull * CheckPgUserAclNotNull
* *
...@@ -556,51 +608,56 @@ CheckPgUserAclNotNull() ...@@ -556,51 +608,56 @@ CheckPgUserAclNotNull()
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(htup)) if (!HeapTupleIsValid(htup))
{ {
elog(ERROR, "IsPgUserAclNull: class \"%s\" not found", /* BIG problem */
elog(ERROR, "IsPgUserAclNull: \"%s\" not found",
ShadowRelationName); ShadowRelationName);
} }
if (heap_attisnull(htup, Anum_pg_class_relacl)) if (heap_attisnull(htup, Anum_pg_class_relacl))
{ {
elog(NOTICE, "To use passwords, you have to revoke permissions on pg_shadow"); elog(ERROR,
elog(NOTICE, "so normal users can not read the passwords."); "To use passwords, you have to revoke permissions on %s "
elog(ERROR, "Try 'REVOKE ALL ON pg_shadow FROM PUBLIC'"); "so normal users cannot read the passwords. "
"Try 'REVOKE ALL ON \"%s\" FROM PUBLIC'.",
ShadowRelationName, ShadowRelationName);
} }
return; return;
} }
/*** GROUP THINGS ***/
/*
* CREATE GROUP
*/
void void
CreateGroup(CreateGroupStmt *stmt, CommandDest dest) CreateGroup(CreateGroupStmt *stmt)
{ {
Relation pg_group_rel; Relation pg_group_rel;
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple tuple; HeapTuple tuple;
TupleDesc pg_group_dsc; TupleDesc pg_group_dsc;
bool inblock;
bool group_exists = false, bool group_exists = false,
sysid_exists = false; sysid_exists = false;
int max_id = -1; int max_id = 0;
Datum new_record[Natts_pg_group]; Datum new_record[Natts_pg_group];
char new_record_nulls[Natts_pg_group]; char new_record_nulls[Natts_pg_group];
List *item, *newlist=NULL; List *item, *newlist=NULL;
ArrayType *userarray; ArrayType *userarray;
if (!(inblock = IsTransactionBlock()))
BeginTransactionBlock();
/* /*
* Make sure the user can do this. * Make sure the user can do this.
*/ */
if (pg_aclcheck(GroupRelationName, GetPgUserName(), ACL_RD | ACL_AP) != ACLCHECK_OK) if (!superuser())
{ elog(ERROR, "CREATE GROUP: permission denied");
UserAbortTransactionBlock();
elog(ERROR, "CreateGroup: 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_rel = heap_openr(GroupRelationName, AccessExclusiveLock);
pg_group_dsc = RelationGetDescr(pg_group_rel); pg_group_dsc = RelationGetDescr(pg_group_rel);
...@@ -628,11 +685,10 @@ CreateGroup(CreateGroupStmt *stmt, CommandDest dest) ...@@ -628,11 +685,10 @@ CreateGroup(CreateGroupStmt *stmt, CommandDest dest)
if (group_exists || sysid_exists) if (group_exists || sysid_exists)
{ {
heap_close(pg_group_rel, AccessExclusiveLock); heap_close(pg_group_rel, AccessExclusiveLock);
UserAbortTransactionBlock();
if (group_exists) 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 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) ...@@ -650,8 +706,7 @@ CreateGroup(CreateGroupStmt *stmt, CommandDest dest)
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{ {
heap_close(pg_group_rel, AccessExclusiveLock); heap_close(pg_group_rel, AccessExclusiveLock);
UserAbortTransactionBlock(); elog(ERROR, "CREATE GROUP: user \"%s\" does not exist", groupuser);
elog(ERROR, "CreateGroup: User \"%s\" does not exist.", groupuser);
} }
v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid); v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid);
...@@ -716,33 +771,34 @@ CreateGroup(CreateGroupStmt *stmt, CommandDest dest) ...@@ -716,33 +771,34 @@ CreateGroup(CreateGroupStmt *stmt, CommandDest dest)
CatalogCloseIndices(Num_pg_group_indices, idescs); CatalogCloseIndices(Num_pg_group_indices, idescs);
} }
heap_close(pg_group_rel, NoLock); heap_close(pg_group_rel, AccessExclusiveLock);
if (IsTransactionBlock() && !inblock)
EndTransactionBlock();
} }
/*
* ALTER GROUP
*/
void void
AlterGroup(AlterGroupStmt *stmt, CommandDest dest) AlterGroup(AlterGroupStmt *stmt, const char * tag)
{ {
Relation pg_group_rel; Relation pg_group_rel;
TupleDesc pg_group_dsc; TupleDesc pg_group_dsc;
bool inblock;
HeapTuple group_tuple; HeapTuple group_tuple;
if (!(inblock = IsTransactionBlock()))
BeginTransactionBlock();
/* /*
* Make sure the user can do this. * Make sure the user can do this.
*/ */
if (pg_aclcheck(GroupRelationName, GetPgUserName(), ACL_RD | ACL_WR) != ACLCHECK_OK) if (!superuser())
{ elog(ERROR, "%s: permission denied", tag);
UserAbortTransactionBlock();
elog(ERROR, "AlterGroup: Permission denied."); /*
} * 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_rel = heap_openr(GroupRelationName, AccessExclusiveLock);
pg_group_dsc = RelationGetDescr(pg_group_rel); pg_group_dsc = RelationGetDescr(pg_group_rel);
...@@ -755,69 +811,14 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) ...@@ -755,69 +811,14 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
if (!HeapTupleIsValid(group_tuple = SearchSysCacheTupleCopy(GRONAME, PointerGetDatum(stmt->name), 0, 0, 0))) if (!HeapTupleIsValid(group_tuple = SearchSysCacheTupleCopy(GRONAME, PointerGetDatum(stmt->name), 0, 0, 0)))
{ {
heap_close(pg_group_rel, AccessExclusiveLock); heap_close(pg_group_rel, AccessExclusiveLock);
UserAbortTransactionBlock(); elog(ERROR, "%s: group \"%s\" does not exist", tag, stmt->name);
elog(ERROR, "AlterGroup: Group \"%s\" does not exist.", stmt->name);
} }
AssertState(stmt->action == +1 || stmt->action == -1);
/* /*
* Now decide what to do. * Now decide what to do.
*/ */
if (stmt->action == 0) /* change sysid */ if (stmt->action == +1) /* add users, might also be invoked by create user */
{
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)
{ {
Datum new_record[Natts_pg_group]; Datum new_record[Natts_pg_group];
char new_record_nulls[Natts_pg_group] = { ' ', ' ', ' '}; char new_record_nulls[Natts_pg_group] = { ' ', ' ', ' '};
...@@ -853,6 +854,8 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) ...@@ -853,6 +854,8 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
foreach(item, stmt->listUsers) foreach(item, stmt->listUsers)
{ {
Value *v; Value *v;
if (strcmp(tag, "ALTER GROUP")==0)
{
/* Get the uid of the proposed user to add. */ /* Get the uid of the proposed user to add. */
tuple = SearchSysCacheTuple(SHADOWNAME, tuple = SearchSysCacheTuple(SHADOWNAME,
PointerGetDatum(strVal(lfirst(item))), PointerGetDatum(strVal(lfirst(item))),
...@@ -860,15 +863,25 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) ...@@ -860,15 +863,25 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{ {
heap_close(pg_group_rel, AccessExclusiveLock); heap_close(pg_group_rel, AccessExclusiveLock);
UserAbortTransactionBlock(); elog(ERROR, "%s: user \"%s\" does not exist", tag, strVal(lfirst(item)));
elog(ERROR, "AlterGroup: User \"%s\" does not exist.", 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)) if (!member(v, newlist))
newlist = lcons(v, newlist); newlist = lcons(v, newlist);
else 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)); newarray = palloc(ARR_OVERHEAD(1) + length(newlist) * sizeof(int32));
...@@ -906,17 +919,18 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) ...@@ -906,17 +919,18 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
} }
} /* endif alter group add user */ } /* endif alter group add user */
/* else if (stmt->action == -1) /*drop users from group */
* drop users from group
*/
else if (stmt->action < 0)
{ {
Datum datum; Datum datum;
bool null; bool null;
bool is_dropuser = strcmp(tag, "DROP USER")==0;
datum = heap_getattr(group_tuple, Anum_pg_group_grolist, pg_group_dsc, &null); datum = heap_getattr(group_tuple, Anum_pg_group_grolist, pg_group_dsc, &null);
if (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 else
{ {
HeapTuple tuple; HeapTuple tuple;
...@@ -950,6 +964,8 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) ...@@ -950,6 +964,8 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
foreach(item, stmt->listUsers) foreach(item, stmt->listUsers)
{ {
Value *v; Value *v;
if (!is_dropuser)
{
/* Get the uid of the proposed user to drop. */ /* Get the uid of the proposed user to drop. */
tuple = SearchSysCacheTuple(SHADOWNAME, tuple = SearchSysCacheTuple(SHADOWNAME,
PointerGetDatum(strVal(lfirst(item))), PointerGetDatum(strVal(lfirst(item))),
...@@ -957,15 +973,19 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) ...@@ -957,15 +973,19 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{ {
heap_close(pg_group_rel, AccessExclusiveLock); heap_close(pg_group_rel, AccessExclusiveLock);
UserAbortTransactionBlock(); elog(ERROR, "ALTER GROUP: user \"%s\" does not exist", strVal(lfirst(item)));
elog(ERROR, "AlterGroup: User \"%s\" does not exist.", strVal(lfirst(item)));
} }
v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid); v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid);
}
else
{
/* for dropuser we already know the uid */
v = lfirst(item);
}
if (member(v, newlist)) if (member(v, newlist))
newlist = LispRemove(v, newlist); newlist = LispRemove(v, newlist);
else else if (!is_dropuser)
elog(NOTICE, "AlterGroup: User \"%s\" is not in group \"%s\".", strVal(lfirst(item)), stmt->name); 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)); newarray = palloc(ARR_OVERHEAD(1) + length(newlist) * sizeof(int32));
...@@ -1005,40 +1025,40 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest) ...@@ -1005,40 +1025,40 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
} /* endif group not null */ } /* endif group not null */
} /* endif alter group drop user */ } /* endif alter group drop user */
heap_close(pg_group_rel, NoLock); heap_close(pg_group_rel, AccessExclusiveLock);
pfree(group_tuple); pfree(group_tuple);
if (IsTransactionBlock() && !inblock)
EndTransactionBlock();
} }
/*
* DROP GROUP
*/
void void
DropGroup(DropGroupStmt *stmt, CommandDest dest) DropGroup(DropGroupStmt *stmt)
{ {
Relation pg_group_rel; Relation pg_group_rel;
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple tuple; HeapTuple tuple;
TupleDesc pg_group_dsc; TupleDesc pg_group_dsc;
bool inblock;
bool gro_exists = false; bool gro_exists = false;
if (!(inblock = IsTransactionBlock()))
BeginTransactionBlock();
/* /*
* Make sure the user can do this. * Make sure the user can do this.
*/ */
if (pg_aclcheck(GroupRelationName, GetPgUserName(), ACL_RD | ACL_WR) != ACLCHECK_OK) if (!superuser())
{ elog(ERROR, "DROP GROUP: permission denied");
UserAbortTransactionBlock();
elog(ERROR, "DropGroup: Permission denied."); /*
} * 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 users. * Scan the pg_group table and delete all matching groups.
*/ */
pg_group_rel = heap_openr(GroupRelationName, AccessExclusiveLock); pg_group_rel = heap_openr(GroupRelationName, AccessExclusiveLock);
pg_group_dsc = RelationGetDescr(pg_group_rel); pg_group_dsc = RelationGetDescr(pg_group_rel);
...@@ -1055,7 +1075,6 @@ DropGroup(DropGroupStmt *stmt, CommandDest dest) ...@@ -1055,7 +1075,6 @@ DropGroup(DropGroupStmt *stmt, CommandDest dest)
gro_exists = true; gro_exists = true;
heap_delete(pg_group_rel, &tuple->t_self, NULL); heap_delete(pg_group_rel, &tuple->t_self, NULL);
} }
} }
heap_endscan(scan); heap_endscan(scan);
...@@ -1067,12 +1086,8 @@ DropGroup(DropGroupStmt *stmt, CommandDest dest) ...@@ -1067,12 +1086,8 @@ DropGroup(DropGroupStmt *stmt, CommandDest dest)
{ {
heap_close(pg_group_rel, AccessExclusiveLock); heap_close(pg_group_rel, AccessExclusiveLock);
UserAbortTransactionBlock(); 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); heap_close(pg_group_rel, AccessExclusiveLock);
if (IsTransactionBlock() && !inblock)
EndTransactionBlock();
} }
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -90,7 +90,6 @@ static Node *doNegate(Node *n); ...@@ -90,7 +90,6 @@ static Node *doNegate(Node *n);
char chr; char chr;
char *str; char *str;
bool boolean; bool boolean;
bool* pboolean; /* for pg_shadow privileges */
List *list; List *list;
Node *node; Node *node;
Value *value; Value *value;
...@@ -137,11 +136,11 @@ static Node *doNegate(Node *n); ...@@ -137,11 +136,11 @@ static Node *doNegate(Node *n);
%type <ival> opt_lock, lock_type %type <ival> opt_lock, lock_type
%type <boolean> opt_lmode %type <boolean> opt_lmode
%type <pboolean> user_createdb_clause, user_createuser_clause %type <ival> user_createdb_clause, user_createuser_clause
%type <str> user_passwd_clause %type <str> user_passwd_clause
%type <ival> sysid_clause %type <ival> sysid_clause
%type <str> user_valid_clause %type <str> user_valid_clause
%type <list> user_group_list, user_group_clause, users_in_new_group_clause %type <list> user_list, user_group_clause, users_in_new_group_clause
%type <boolean> TriggerActionTime, TriggerForSpec, PLangTrusted %type <boolean> TriggerActionTime, TriggerForSpec, PLangTrusted
...@@ -459,8 +458,8 @@ CreateUserStmt: CREATE USER UserId ...@@ -459,8 +458,8 @@ CreateUserStmt: CREATE USER UserId
n->user = $3; n->user = $3;
n->sysid = -1; n->sysid = -1;
n->password = NULL; n->password = NULL;
n->createdb = $4; n->createdb = $4 == +1 ? true : false;
n->createuser = $5; n->createuser = $5 == +1 ? true : false;
n->groupElts = $6; n->groupElts = $6;
n->validUntil = $7; n->validUntil = $7;
$$ = (Node *)n; $$ = (Node *)n;
...@@ -473,8 +472,8 @@ CreateUserStmt: CREATE USER UserId ...@@ -473,8 +472,8 @@ CreateUserStmt: CREATE USER UserId
n->user = $3; n->user = $3;
n->sysid = $5; n->sysid = $5;
n->password = $6; n->password = $6;
n->createdb = $7; n->createdb = $7 == +1 ? true : false;
n->createuser = $8; n->createuser = $8 == +1 ? true : false;
n->groupElts = $9; n->groupElts = $9;
n->validUntil = $10; n->validUntil = $10;
$$ = (Node *)n; $$ = (Node *)n;
...@@ -489,30 +488,26 @@ CreateUserStmt: CREATE USER UserId ...@@ -489,30 +488,26 @@ CreateUserStmt: CREATE USER UserId
*****************************************************************************/ *****************************************************************************/
AlterUserStmt: ALTER USER UserId user_createdb_clause 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); AlterUserStmt *n = makeNode(AlterUserStmt);
n->user = $3; n->user = $3;
n->sysid = -1;
n->password = NULL; n->password = NULL;
n->createdb = $4; n->createdb = $4;
n->createuser = $5; n->createuser = $5;
n->groupElts = $6; n->validUntil = $6;
n->validUntil = $7;
$$ = (Node *)n; $$ = (Node *)n;
} }
| ALTER USER UserId WITH sysid_clause user_passwd_clause | ALTER USER UserId WITH PASSWORD Sconst
user_createdb_clause user_createdb_clause
user_createuser_clause user_group_clause user_valid_clause user_createuser_clause user_valid_clause
{ {
AlterUserStmt *n = makeNode(AlterUserStmt); AlterUserStmt *n = makeNode(AlterUserStmt);
n->user = $3; n->user = $3;
n->sysid = $5;
n->password = $6; n->password = $6;
n->createdb = $7; n->createdb = $7;
n->createuser = $8; n->createuser = $8;
n->groupElts = $9; n->validUntil = $9;
n->validUntil = $10;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
...@@ -524,53 +519,38 @@ AlterUserStmt: ALTER USER UserId user_createdb_clause ...@@ -524,53 +519,38 @@ AlterUserStmt: ALTER USER UserId user_createdb_clause
* *
*****************************************************************************/ *****************************************************************************/
DropUserStmt: DROP USER UserId DropUserStmt: DROP USER user_list
{ {
DropUserStmt *n = makeNode(DropUserStmt); DropUserStmt *n = makeNode(DropUserStmt);
n->user = $3; n->users = $3;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
user_passwd_clause: PASSWORD UserId { $$ = $2; } user_passwd_clause: PASSWORD Sconst { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; } | /*EMPTY*/ { $$ = NULL; }
; ;
sysid_clause: SYSID Iconst { $$ = $2; } sysid_clause: SYSID Iconst
{
if ($2 <= 0)
elog(ERROR, "sysid must be positive");
$$ = $2;
}
| /*EMPTY*/ { $$ = -1; } | /*EMPTY*/ { $$ = -1; }
; ;
user_createdb_clause: CREATEDB user_createdb_clause: CREATEDB { $$ = +1; }
{ | NOCREATEDB { $$ = -1; }
bool* b; | /*EMPTY*/ { $$ = 0; }
$$ = (b = (bool*)palloc(sizeof(bool)));
*b = true;
}
| NOCREATEDB
{
bool* b;
$$ = (b = (bool*)palloc(sizeof(bool)));
*b = false;
}
| /*EMPTY*/ { $$ = NULL; }
; ;
user_createuser_clause: CREATEUSER user_createuser_clause: CREATEUSER { $$ = +1; }
{ | NOCREATEUSER { $$ = -1; }
bool* b; | /*EMPTY*/ { $$ = 0; }
$$ = (b = (bool*)palloc(sizeof(bool)));
*b = true;
}
| NOCREATEUSER
{
bool* b;
$$ = (b = (bool*)palloc(sizeof(bool)));
*b = false;
}
| /*EMPTY*/ { $$ = NULL; }
; ;
user_group_list: user_group_list ',' UserId user_list: user_list ',' UserId
{ {
$$ = lcons((void*)makeString($3), $1); $$ = lcons((void*)makeString($3), $1);
} }
...@@ -580,7 +560,7 @@ user_group_list: user_group_list ',' UserId ...@@ -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; } | /*EMPTY*/ { $$ = NULL; }
; ;
...@@ -615,7 +595,7 @@ CreateGroupStmt: CREATE GROUP UserId ...@@ -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; } | /* EMPTY */ { $$ = NULL; }
; ;
...@@ -626,17 +606,7 @@ users_in_new_group_clause: USER user_group_list { $$ = $2; } ...@@ -626,17 +606,7 @@ users_in_new_group_clause: USER user_group_list { $$ = $2; }
* *
*****************************************************************************/ *****************************************************************************/
AlterGroupStmt: ALTER GROUP UserId WITH SYSID Iconst AlterGroupStmt: ALTER GROUP UserId ADD USER user_list
{
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 *n = makeNode(AlterGroupStmt); AlterGroupStmt *n = makeNode(AlterGroupStmt);
n->name = $3; n->name = $3;
...@@ -646,7 +616,7 @@ AlterGroupStmt: ALTER GROUP UserId WITH SYSID Iconst ...@@ -646,7 +616,7 @@ AlterGroupStmt: ALTER GROUP UserId WITH SYSID Iconst
$$ = (Node *)n; $$ = (Node *)n;
} }
| |
ALTER GROUP UserId DROP USER user_group_list ALTER GROUP UserId DROP USER user_list
{ {
AlterGroupStmt *n = makeNode(AlterGroupStmt); AlterGroupStmt *n = makeNode(AlterGroupStmt);
n->name = $3; n->name = $3;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -266,11 +266,7 @@ ProcessUtility(Node *parsetree,
*/ */
stmt->filename, stmt->filename,
stmt->delimiter, stmt->delimiter,
stmt->null_print, stmt->null_print);
/*
* specify 022 umask while writing files with COPY.
*/
0022);
} }
break; break;
...@@ -775,21 +771,21 @@ ProcessUtility(Node *parsetree, ...@@ -775,21 +771,21 @@ ProcessUtility(Node *parsetree,
PS_SET_STATUS(commandTag = "CREATE USER"); PS_SET_STATUS(commandTag = "CREATE USER");
CHECK_IF_ABORTED(); CHECK_IF_ABORTED();
DefineUser((CreateUserStmt *) parsetree, dest); CreateUser((CreateUserStmt *) parsetree);
break; break;
case T_AlterUserStmt: case T_AlterUserStmt:
PS_SET_STATUS(commandTag = "ALTER USER"); PS_SET_STATUS(commandTag = "ALTER USER");
CHECK_IF_ABORTED(); CHECK_IF_ABORTED();
AlterUser((AlterUserStmt *) parsetree, dest); AlterUser((AlterUserStmt *) parsetree);
break; break;
case T_DropUserStmt: case T_DropUserStmt:
PS_SET_STATUS(commandTag = "DROP USER"); PS_SET_STATUS(commandTag = "DROP USER");
CHECK_IF_ABORTED(); CHECK_IF_ABORTED();
RemoveUser(((DropUserStmt *) parsetree)->user, dest); DropUser((DropUserStmt *) parsetree);
break; break;
case T_LockStmt: case T_LockStmt:
...@@ -810,21 +806,21 @@ ProcessUtility(Node *parsetree, ...@@ -810,21 +806,21 @@ ProcessUtility(Node *parsetree,
PS_SET_STATUS(commandTag = "CREATE GROUP"); PS_SET_STATUS(commandTag = "CREATE GROUP");
CHECK_IF_ABORTED(); CHECK_IF_ABORTED();
CreateGroup((CreateGroupStmt *) parsetree, dest); CreateGroup((CreateGroupStmt *) parsetree);
break; break;
case T_AlterGroupStmt: case T_AlterGroupStmt:
PS_SET_STATUS(commandTag = "ALTER GROUP"); PS_SET_STATUS(commandTag = "ALTER GROUP");
CHECK_IF_ABORTED(); CHECK_IF_ABORTED();
AlterGroup((AlterGroupStmt *) parsetree, dest); AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
break; break;
case T_DropGroupStmt: case T_DropGroupStmt:
PS_SET_STATUS(commandTag = "DROP GROUP"); PS_SET_STATUS(commandTag = "DROP GROUP");
CHECK_IF_ABORTED(); CHECK_IF_ABORTED();
DropGroup((DropGroupStmt *) parsetree, dest); DropGroup((DropGroupStmt *) parsetree);
break; break;
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * DESCRIPTION
* See superuser(). * See superuser().
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "postgres.h" #include "postgres.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "miscadmin.h"
bool bool
superuser(void) superuser(void)
...@@ -26,12 +27,10 @@ superuser(void) ...@@ -26,12 +27,10 @@ superuser(void)
The Postgres user running this command has Postgres superuser The Postgres user running this command has Postgres superuser
privileges. privileges.
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
extern char *UserName; /* defined in global.c */
HeapTuple utup; HeapTuple utup;
utup = SearchSysCacheTuple(SHADOWNAME, utup = SearchSysCacheTuple(SHADOWNAME,
PointerGetDatum(UserName), PointerGetDatum(GetPgUserName()),
0, 0, 0); 0, 0, 0);
Assert(utup != NULL); Assert(utup != NULL);
return ((Form_pg_shadow) GETSTRUCT(utup))->usesuper; return ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
# #
# #
# IDENTIFICATION # 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. # Note - this should NOT be setuid.
# #
...@@ -193,7 +193,7 @@ QUERY="CREATE USER \"$NewUser\"" ...@@ -193,7 +193,7 @@ QUERY="CREATE USER \"$NewUser\""
SUBQUERY= SUBQUERY=
[ "$SysID" ] && SUBQUERY="$SUBQUERY SYSID $SysID" [ "$SysID" ] && SUBQUERY="$SUBQUERY SYSID $SysID"
[ "$Password" ] && SUBQUERY="$SUBQUERY PASSWORD \"$Password\"" [ "$Password" ] && SUBQUERY="$SUBQUERY PASSWORD '$Password'"
[ "$SUBQUERY" ] && QUERY="$QUERY WITH $SUBQUERY" [ "$SUBQUERY" ] && QUERY="$QUERY WITH $SUBQUERY"
[ "$CanCreateDb" = t ] && QUERY="$QUERY CREATEDB" [ "$CanCreateDb" = t ] && QUERY="$QUERY CREATEDB"
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -15,6 +15,6 @@
void DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, 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 */ #endif /* COPY_H */
...@@ -11,15 +11,15 @@ ...@@ -11,15 +11,15 @@
#define USER_H #define USER_H
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "tcop/dest.h" #include "access/htup.h"
extern void DefineUser(CreateUserStmt *stmt, CommandDest); extern void CreateUser(CreateUserStmt *stmt);
extern void AlterUser(AlterUserStmt *stmt, CommandDest); extern void AlterUser(AlterUserStmt *stmt);
extern void RemoveUser(char *user, CommandDest); extern void DropUser(DropUserStmt *stmt);
extern void CreateGroup(CreateGroupStmt *stmt, CommandDest dest); extern void CreateGroup(CreateGroupStmt *stmt);
extern void AlterGroup(AlterGroupStmt *stmt, CommandDest dest); extern void AlterGroup(AlterGroupStmt *stmt, const char * tag);
extern void DropGroup(DropGroupStmt *stmt, CommandDest dest); extern void DropGroup(DropGroupStmt *stmt);
extern HeapTuple update_pg_pwd(void); extern HeapTuple update_pg_pwd(void);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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 ...@@ -270,18 +270,26 @@ typedef struct CreateUserStmt
char *user; /* PostgreSQL user login */ char *user; /* PostgreSQL user login */
char *password; /* PostgreSQL user password */ char *password; /* PostgreSQL user password */
int sysid; /* PgSQL system id (-1 if don't care) */ int sysid; /* PgSQL system id (-1 if don't care) */
bool *createdb; /* Can the user create databases? */ bool createdb; /* Can the user create databases? */
bool *createuser; /* Can this user create users? */ bool createuser; /* Can this user create users? */
List *groupElts; /* The groups the user is a member of */ List *groupElts; /* The groups the user is a member of */
char *validUntil; /* The time the login is valid until */ char *validUntil; /* The time the login is valid until */
} CreateUserStmt; } 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 typedef struct DropUserStmt
{ {
NodeTag type; NodeTag type;
char *user; /* PostgreSQL user login */ List *users; /* List of users to remove */
} DropUserStmt; } DropUserStmt;
...@@ -301,7 +309,7 @@ typedef struct AlterGroupStmt ...@@ -301,7 +309,7 @@ typedef struct AlterGroupStmt
{ {
NodeTag type; NodeTag type;
char *name; /* name of group to alter */ 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 */ int sysid; /* sysid change */
List *listUsers; /* list of users to add/drop */ List *listUsers; /* list of users to add/drop */
} AlterGroupStmt; } AlterGroupStmt;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment