From 2c6b34d95980a102ab0c7f1049ec2869ab01ac74 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Sun, 18 Aug 2002 03:03:26 +0000
Subject: [PATCH] Add db-local user names, per discussion on hackers.

---
 doc/src/sgml/runtime.sgml                     | 22 +++++++++++++-
 src/backend/libpq/auth.c                      |  6 ++--
 src/backend/postmaster/postmaster.c           | 30 +++++++++++++++----
 src/backend/utils/misc/guc.c                  |  6 +++-
 src/backend/utils/misc/postgresql.conf.sample |  2 +-
 src/include/libpq/libpq-be.h                  |  4 +--
 src/include/libpq/pqcomm.h                    |  6 +++-
 7 files changed, 62 insertions(+), 14 deletions(-)

diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index d14a123da00..05efc505661 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.125 2002/08/15 14:26:15 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.126 2002/08/18 03:03:25 momjian Exp $
 -->
 
 <Chapter Id="runtime">
@@ -1190,6 +1190,26 @@ env PGOPTIONS='-c geqo=off' psql
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><varname>DB_USER_NAMESPACE</varname> (<type>boolean</type>)</term>
+      <listitem>
+       <para>
+        This allows per-database user names.  You can create users as <literal>
+        username@dbname</>.  When <literal>username</> is passed by the client,
+        <literal>@</> and the database name is appended to the user name and
+        that database-specific user name is looked up by the server. 
+        When creating user names containing <literal>@</>, you will need
+        to quote the user name.
+       </para>
+       <para>
+        With this option enabled, you can still create ordinary global 
+        users.  Simply append <literal>@</> when specifying the user name
+        in the client.  The <literal>@</> will be stripped off and looked up
+        by the server. 
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <indexterm>
        <primary>deadlock</primary>
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 2168ddf9374..83f7cb10c22 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.82 2002/06/20 20:29:28 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.83 2002/08/18 03:03:25 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -117,7 +117,7 @@ pg_krb4_recvauth(Port *port)
 			 version, PG_KRB4_VERSION);
 		return STATUS_ERROR;
 	}
-	if (strncmp(port->user, auth_data.pname, SM_USER) != 0)
+	if (strncmp(port->user, auth_data.pname, SM_DATABASE_USER) != 0)
 	{
 		elog(LOG, "pg_krb4_recvauth: name \"%s\" != \"%s\"",
 			 port->user, auth_data.pname);
@@ -290,7 +290,7 @@ pg_krb5_recvauth(Port *port)
 	}
 
 	kusername = pg_an_to_ln(kusername);
-	if (strncmp(port->user, kusername, SM_USER))
+	if (strncmp(port->user, kusername, SM_DATABASE_USER))
 	{
 		elog(LOG, "pg_krb5_recvauth: user name \"%s\" != krb5 name \"%s\"",
 			 port->user, kusername);
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index f67a8b64a34..bc8b859f300 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.284 2002/08/17 15:12:06 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.285 2002/08/18 03:03:25 momjian Exp $
  *
  * NOTES
  *
@@ -116,7 +116,6 @@
 sigset_t	UnBlockSig,
 			BlockSig,
 			AuthBlockSig;
-
 #else
 int			UnBlockSig,
 			BlockSig,
@@ -191,6 +190,8 @@ int			CheckPointTimeout = 300;
 bool		HostnameLookup;		/* for ps display */
 bool		ShowPortNumber;
 bool		Log_connections = false;
+bool		Db_user_namespace = false;
+
 
 /* Startup/shutdown state */
 static pid_t StartupPID = 0,
@@ -1155,6 +1156,26 @@ ProcessStartupPacket(Port *port, bool SSLdone)
 	if (port->user[0] == '\0')
 		elog(FATAL, "no PostgreSQL user name specified in startup packet");
 
+	if (Db_user_namespace)
+    {
+		/*
+		 *	If user@, it is a global user, remove '@'.
+		 *	We only want to do this if there is an '@' at the end and no
+		 *	earlier in the user string or they may fake as a local user
+		 *	of another database attaching to this database.
+		 */
+		if (strchr(port->user, '@') == port->user + strlen(port->user)-1)
+			*strchr(port->user, '@') = '\0';
+		else
+		{
+			/* Append '@' and dbname */
+			char hold_user[SM_DATABASE_USER+1];
+			snprintf(hold_user, SM_DATABASE_USER+1, "%s@%s", port->user,
+					 port->database);
+			strcpy(port->user, hold_user);
+		}
+	}
+
 	/*
 	 * If we're going to reject the connection due to database state, say
 	 * so now instead of wasting cycles on an authentication exchange.
@@ -2581,11 +2602,10 @@ CreateOptsFile(int argc, char *argv[])
 	if (FindExec(fullprogname, argv[0], "postmaster") < 0)
 		return false;
 
-	filename = palloc(strlen(DataDir) + 20);
+	filename = palloc(strlen(DataDir) + 17);
 	sprintf(filename, "%s/postmaster.opts", DataDir);
 
-	fp = fopen(filename, "w");
-	if (fp == NULL)
+	if ((fp = fopen(filename, "w")) == NULL)
 	{
 		postmaster_error("cannot create file %s: %s",
 						 filename, strerror(errno));
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 3cfa84191c7..a759b3f5271 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -5,7 +5,7 @@
  * command, configuration file, and command line options.
  * See src/backend/utils/misc/README for more information.
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.82 2002/08/15 02:51:26 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.83 2002/08/18 03:03:25 momjian Exp $
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
@@ -483,6 +483,10 @@ static struct config_bool
 		{ "transform_null_equals", PGC_USERSET }, &Transform_null_equals,
 		false, NULL, NULL
 	},
+	{
+		{ "db_user_namespace", PGC_SIGHUP }, &Db_user_namespace,
+		false, NULL, NULL
+	},
 
 	{
 		{ NULL, 0 }, NULL, false, NULL, NULL
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index c9511ad7fb1..da456606129 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -113,7 +113,6 @@
 #
 #	Message display
 #
-
 #server_min_messages = notice	# Values, in order of decreasing detail:
 				#   debug5, debug4, debug3, debug2, debug1,
 				#   info, notice, warning, error, log, fatal,
@@ -201,3 +200,4 @@
 #sql_inheritance = true
 #transform_null_equals = false
 #statement_timeout = 0				# 0 is disabled
+#db_user_namespace = false
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 3dc0a6f4cd0..1a2382026c5 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq-be.h,v 1.32 2002/06/20 20:29:49 momjian Exp $
+ * $Id: libpq-be.h,v 1.33 2002/08/18 03:03:26 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,7 +59,7 @@ typedef struct Port
 
 	ProtocolVersion proto;
 	char		database[SM_DATABASE + 1];
-	char		user[SM_USER + 1];
+	char		user[SM_DATABASE_USER + 1];
 	char		options[SM_OPTIONS + 1];
 	char		tty[SM_TTY + 1];
 	char		auth_arg[MAX_AUTH_ARG];
diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h
index e215e8a7f04..f0ea4e35943 100644
--- a/src/include/libpq/pqcomm.h
+++ b/src/include/libpq/pqcomm.h
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pqcomm.h,v 1.65 2002/08/12 14:35:26 tgl Exp $
+ * $Id: pqcomm.h,v 1.66 2002/08/18 03:03:26 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -114,6 +114,8 @@ typedef uint32 PacketLen;
 #define SM_DATABASE		64
 /* SM_USER should be the same size as the others.  bjm 2002-06-02 */
 #define SM_USER			32
+/* We append database name if db_user_namespace true. */
+#define SM_DATABASE_USER (SM_DATABASE+SM_USER+1) /* +1 for @ */
 #define SM_OPTIONS		64
 #define SM_UNUSED		64
 #define SM_TTY			64
@@ -124,12 +126,14 @@ typedef struct StartupPacket
 {
 	ProtocolVersion protoVersion;		/* Protocol version */
 	char		database[SM_DATABASE];	/* Database name */
+				/* Db_user_namespace appends dbname */
 	char		user[SM_USER];	/* User name */
 	char		options[SM_OPTIONS];	/* Optional additional args */
 	char		unused[SM_UNUSED];		/* Unused */
 	char		tty[SM_TTY];	/* Tty for debug output */
 } StartupPacket;
 
+extern bool Db_user_namespace;
 
 /* These are the authentication requests sent by the backend. */
 
-- 
GitLab