-<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.88 2006/04/30 02:09:06 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.89 2006/04/30 21:15:32 tgl Exp $ -->
<chapter id="client-authentication">
<title>Client Authentication</title>
Multiple user names can be supplied by separating them with commas.
A separate file containing user names can be specified by preceding the
file name with <literal>@</>.
- User and group connectivity can also be restricted by <command>GRANT
- CONNECTION ON DATABASE</>.
</para>
</listitem>
</varlistentry>
re-read the file.
</para>
+ <tip>
+ <para>
+ To connect to a particular database, a user must not only pass the
+ <filename>pg_hba.conf</filename> checks, but must have the
+ <literal>CONNECT</> privilege for the database. If you wish to
+ restrict which users can connect to which databases, it's usually
+ easier to control this by granting/revoking <literal>CONNECT</> privilege
+ than to put the rules into <filename>pg_hba.conf</filename> entries.
+ </para>
+ </tip>
+
<para>
Some examples of <filename>pg_hba.conf</filename> entries are shown in
<xref linkend="example-pg-hba.conf">. See the next section for details on the
-<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.56 2006/04/23 03:39:50 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.57 2006/04/30 21:15:32 tgl Exp $ -->
<chapter id="ddl">
<title>Data Definition</title>
There are several different privileges: <literal>SELECT</>,
<literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
<literal>RULE</>, <literal>REFERENCES</>, <literal>TRIGGER</>,
- <literal>CREATE</>, <literal>TEMPORARY</>, <literal>EXECUTE</>, and
- <literal>USAGE</>. The privileges applicable to a particular
+ <literal>CREATE</>, <literal>CONNECT</>, <literal>TEMPORARY</>,
+ <literal>EXECUTE</>, and <literal>USAGE</>.
+ The privileges applicable to a particular
object vary depending on the object's type (table, function, etc).
For complete information on the different types of privileges
supported by <productname>PostgreSQL</productname>, refer to the
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.315 2006/04/25 00:25:15 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.316 2006/04/30 21:15:32 tgl Exp $ -->
<chapter id="functions">
<title>Functions and Operators</title>
arguments are analogous to <function>has_table_privilege</function>.
The desired access privilege type must evaluate to
<literal>CREATE</literal>,
+ <literal>CONNECT</literal>,
<literal>TEMPORARY</literal>, or
<literal>TEMP</literal> (which is equivalent to
<literal>TEMPORARY</literal>).
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.53 2006/04/30 02:09:06 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.54 2006/04/30 21:15:33 tgl Exp $
PostgreSQL documentation
-->
ON SEQUENCE <replaceable class="PARAMETER">sequencename</replaceable> [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
-GRANT { { CREATE | TEMPORARY | TEMP | CONNECTION } [,...] | ALL [ PRIVILEGES ] }
+GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
ON DATABASE <replaceable>dbname</replaceable> [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
Depending on the type of object, the initial default privileges may
include granting some privileges to <literal>PUBLIC</literal>.
The default is no public access for tables, schemas, and tablespaces;
- <literal>TEMP</> table creation privilege for databases;
+ <literal>CONNECT</> privilege and <literal>TEMP</> table creation privilege
+ for databases;
<literal>EXECUTE</> privilege for functions; and
<literal>USAGE</> privilege for languages.
The object owner may of course revoke these privileges. (For maximum
</varlistentry>
<varlistentry>
- <term>CONNECTION</term>
+ <term>CONNECT</term>
<listitem>
<para>
- Allows the ability to connect to the specified database.
- By default, Grant permissions allow users to connect to any database,
- though <filename>pg_hba.conf</> can add additional connection
- restrictions.
+ Allows the user to connect to the specified database. This
+ privilege is checked at connection startup (in addition to checking
+ any restrictions imposed by <filename>pg_hba.conf</>).
</para>
</listitem>
</varlistentry>
X -- EXECUTE
U -- USAGE
C -- CREATE
- c -- CONNECTION
+ c -- CONNECT
T -- TEMPORARY
arwdRxt -- ALL PRIVILEGES (for tables)
* -- grant option for preceding privilege
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/revoke.sgml,v 1.37 2006/04/30 02:09:06 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/revoke.sgml,v 1.38 2006/04/30 21:15:33 tgl Exp $
PostgreSQL documentation
-->
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
- { { CREATE | TEMPORARY | TEMP | CONNECTION } [,...] | ALL [ PRIVILEGES ] }
+ { { CREATE | CONNECT | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
ON DATABASE <replaceable>dbname</replaceable> [, ...]
FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
-<!-- $PostgreSQL: pgsql/doc/src/sgml/user-manag.sgml,v 1.34 2006/03/10 19:10:49 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/user-manag.sgml,v 1.35 2006/04/30 21:15:32 tgl Exp $ -->
<chapter id="user-manag">
<title>Database Roles and Privileges</title>
There are several different kinds of privilege: <literal>SELECT</>,
<literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
<literal>RULE</>, <literal>REFERENCES</>, <literal>TRIGGER</>,
- <literal>CREATE</>, <literal>TEMPORARY</>, <literal>EXECUTE</>,
- and <literal>USAGE</>. For more
- information on the different types of privileges supported by
+ <literal>CREATE</>, <literal>CONNECT</>, <literal>TEMPORARY</>,
+ <literal>EXECUTE</>, and <literal>USAGE</>.
+ For more information on the different types of privileges supported by
<productname>PostgreSQL</productname>, see the
<xref linkend="sql-grant" endterm="sql-grant-title"> reference page.
</para>
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.126 2006/04/30 02:09:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.127 2006/04/30 21:15:33 tgl Exp $
*
* NOTES
* See acl.h.
return ACL_CREATE_TEMP;
if (strcmp(privname, "temp") == 0)
return ACL_CREATE_TEMP;
- if (strcmp(privname, "connection") == 0)
+ if (strcmp(privname, "connect") == 0)
return ACL_CONNECT;
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
case ACL_CREATE_TEMP:
return "TEMP";
case ACL_CONNECT:
- return "CONNECTION";
+ return "CONNECT";
default:
elog(ERROR, "unrecognized privilege: %d", (int) privilege);
}
ScanKeyData entry[1];
SysScanDesc scan;
HeapTuple tuple;
- Datum aclDatum;
- bool isNull;
- Acl *acl;
- Oid ownerId;
/* Superusers bypass all permission checking. */
if (superuser_arg(roleid))
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database with OID %u does not exist", db_oid)));
- ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
+ result = pg_database_tuple_aclmask(tuple, RelationGetDescr(pg_database),
+ roleid, mask, how);
+
+ systable_endscan(scan);
+ heap_close(pg_database, AccessShareLock);
+
+ return result;
+}
+
+/*
+ * This is split out so that ReverifyMyDatabase can perform an ACL check
+ * without a whole extra search of pg_database
+ */
+AclMode
+pg_database_tuple_aclmask(HeapTuple db_tuple, TupleDesc tupdesc,
+ Oid roleid, AclMode mask, AclMaskHow how)
+{
+ AclMode result;
+ Datum aclDatum;
+ bool isNull;
+ Acl *acl;
+ Oid ownerId;
+
+ ownerId = ((Form_pg_database) GETSTRUCT(db_tuple))->datdba;
- aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
- RelationGetDescr(pg_database), &isNull);
+ aclDatum = heap_getattr(db_tuple, Anum_pg_database_datacl,
+ tupdesc, &isNull);
if (isNull)
{
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
- systable_endscan(scan);
- heap_close(pg_database, AccessShareLock);
-
return result;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.132 2006/04/30 02:09:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.133 2006/04/30 21:15:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
owner_default = ACL_ALL_RIGHTS_SEQUENCE;
break;
case ACL_OBJECT_DATABASE:
- world_default = ACL_CREATE_TEMP | ACL_CONNECT; /* not NO_RIGHTS! */
+ /* for backwards compatibility, grant some rights by default */
+ world_default = ACL_CREATE_TEMP | ACL_CONNECT;
owner_default = ACL_ALL_RIGHTS_DATABASE;
break;
case ACL_OBJECT_FUNCTION:
return ACL_CREATE_TEMP;
if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
return ACL_CREATE_TEMP;
+ if (pg_strcasecmp(priv_type, "CONNECT") == 0)
+ return ACL_CONNECT;
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
if (pg_strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
+ if (pg_strcasecmp(priv_type, "CONNECT") == 0)
+ return ACL_CONNECT;
+ if (pg_strcasecmp(priv_type, "CONNECT WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_CONNECT);
+
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized privilege type: \"%s\"", priv_type)));
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.163 2006/04/30 02:09:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.164 2006/04/30 21:15:33 tgl Exp $
*
*
*-------------------------------------------------------------------------
static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace);
-static void ReverifyMyDatabase(const char *name, const char *user_name);
+static void ReverifyMyDatabase(const char *name, bool am_superuser);
static void InitCommunication(void);
static void ShutdownPostgres(int code, Datum arg);
static bool ThereIsAtLeastOneRole(void);
* of pg_database.
*
* To avoid having to read pg_database more times than necessary
- * during session startup, this place is also fitting to set up any
- * database-specific configuration variables.
+ * during session startup, this place is also fitting to check CONNECT
+ * privilege and set up any database-specific configuration variables.
*/
-
static void
-ReverifyMyDatabase(const char *name, const char *user_name)
+ReverifyMyDatabase(const char *name, bool am_superuser)
{
Relation pgdbrel;
SysScanDesc pgdbscan;
errmsg("database \"%s\" is not currently accepting connections",
name)));
+ /*
+ * Check privilege to connect to the database. To avoid making
+ * a whole extra search of pg_database here, we don't go through
+ * pg_database_aclcheck, but instead use a lower-level routine
+ * that we can pass the pg_database tuple to.
+ */
+ if (!am_superuser &&
+ pg_database_tuple_aclmask(tup, RelationGetDescr(pgdbrel),
+ GetUserId(),
+ ACL_CONNECT, ACLMASK_ANY) == 0)
+ ereport(FATAL,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied for database %s",
+ NameStr(dbform->datname)),
+ errdetail("User does not have CONNECT privilege.")));
+
/*
* Check connection limit for this database.
*
* just document that the connection limit is approximate.
*/
if (dbform->datconnlimit >= 0 &&
- !superuser() &&
+ !am_superuser &&
CountDBBackends(MyDatabaseId) > dbform->datconnlimit)
ereport(FATAL,
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("too many connections for database \"%s\"",
name)));
-
- /*
- * Checking for privilege to connect to the database
- * We want to bypass the test if we are running in bootstrap mode
- */
- if (!IsBootstrapProcessingMode())
- {
- if(pg_database_aclcheck(MyDatabaseId,GetUserId()
- ,ACL_CONNECT) != ACLCHECK_OK )
- {
- ereport(FATAL,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("couldn't connect to database %s", NameStr(dbform->datname)),
- errdetail("User %s doesn't have the CONNECTION privilege for database %s.",
- user_name, NameStr(dbform->datname))));
- }
- }
}
/*
RelationCacheInitializePhase2();
/*
- * Figure out our postgres user id. In standalone mode and in the
- * autovacuum process, we use a fixed id, otherwise we figure it out from
- * the authenticated user name.
+ * Figure out our postgres user id, and see if we are a superuser.
+ *
+ * In standalone mode and in the autovacuum process, we use a fixed id,
+ * otherwise we figure it out from the authenticated user name.
*/
if (bootstrap || autovacuum)
+ {
InitializeSessionUserIdStandalone();
+ am_superuser = true;
+ }
else if (!IsUnderPostmaster)
{
InitializeSessionUserIdStandalone();
+ am_superuser = true;
if (!ThereIsAtLeastOneRole())
ereport(WARNING,
(errcode(ERRCODE_UNDEFINED_OBJECT),
{
/* normal multiuser case */
InitializeSessionUserId(username);
+ am_superuser = superuser();
}
+ /* set up ACL framework (so ReverifyMyDatabase can check permissions) */
+ initialize_acl();
+
/*
* Unless we are bootstrapping, double-check that InitMyDatabaseInfo() got
* a correct result. We can't do this until all the database-access
* superuser, so the above stuff has to happen first.)
*/
if (!bootstrap)
- ReverifyMyDatabase(dbname,username);
+ ReverifyMyDatabase(dbname, am_superuser);
/*
* Final phase of relation cache startup: write a new cache file if
*/
RelationCacheInitializePhase3();
- /*
- * Check if user is a superuser.
- */
- if (bootstrap || autovacuum)
- am_superuser = true;
- else
- am_superuser = superuser();
-
/*
* Check a normal user hasn't connected to a superuser reserved slot.
*/
/* set default namespace search path */
InitializeSearchPath();
- /* set up ACL framework (currently just sets RolMemCache callback) */
- initialize_acl();
-
/* initialize client encoding */
InitializeClientEncoding();
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.26 2006/03/05 15:58:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.27 2006/04/30 21:15:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
else if (strcmp(type, "DATABASE") == 0)
{
CONVERT_PRIV('C', "CREATE");
+ CONVERT_PRIV('c', "CONNECT");
CONVERT_PRIV('T', "TEMPORARY");
}
else if (strcmp(type, "TABLESPACE") == 0)
*
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.150 2006/04/02 09:02:41 alvherre Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.151 2006/04/30 21:15:33 tgl Exp $
*/
/*----------------------------------------------------------------------
{
static const char *const list_privileg[] =
{"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES",
- "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
+ "TRIGGER", "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE",
+ "ALL", NULL};
COMPLETE_WITH_LIST(list_privileg);
}
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.94 2006/04/30 02:09:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.95 2006/04/30 21:15:33 tgl Exp $
*
* NOTES
* An ACL array is simply an array of AclItems, representing the union
#ifndef ACL_H
#define ACL_H
+#include "access/htup.h"
+#include "access/tupdesc.h"
#include "nodes/parsenodes.h"
#include "utils/array.h"
*/
#define ACL_ALL_RIGHTS_RELATION (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER)
#define ACL_ALL_RIGHTS_SEQUENCE (ACL_USAGE|ACL_SELECT|ACL_UPDATE)
-#define ACL_ALL_RIGHTS_DATABASE (ACL_CREATE|ACL_CREATE_TEMP|ACL_CONNECT )
+#define ACL_ALL_RIGHTS_DATABASE (ACL_CREATE|ACL_CREATE_TEMP|ACL_CONNECT)
#define ACL_ALL_RIGHTS_FUNCTION (ACL_EXECUTE)
#define ACL_ALL_RIGHTS_LANGUAGE (ACL_USAGE)
#define ACL_ALL_RIGHTS_NAMESPACE (ACL_USAGE|ACL_CREATE)
AclMode mask, AclMaskHow how);
extern AclMode pg_database_aclmask(Oid db_oid, Oid roleid,
AclMode mask, AclMaskHow how);
+extern AclMode pg_database_tuple_aclmask(HeapTuple db_tuple, TupleDesc tupdesc,
+ Oid roleid, AclMode mask, AclMaskHow how);
extern AclMode pg_proc_aclmask(Oid proc_oid, Oid roleid,
AclMode mask, AclMaskHow how);
extern AclMode pg_language_aclmask(Oid lang_oid, Oid roleid,