OK, here is the patch with the suggested changes.  I am sending the
patch to hackers because there has been so much interest in this.

---------------------------------------------------------------------------

Tom Lane wrote:
> BTW, I just thought of a small improvement to your patch that eliminates
> some of the ugliness.  Suppose that when we recognize an attempt to
> connect as a global user (ie, feature flag is on and last character of
> username is '@'), we strip off the '@' before proceeding.  Then we would
> have:
>       global users appear in pg_shadow as foo
>       local users appear in pg_shadow as foo@db
> and what this would mean is that you can flip between feature-enabled
> and feature-disabled states without breaking your global logins.  So you
> don't need the extra step of creating a "postgres@" before turning on
> the feature.  (Which was pretty ugly anyway, since even though postgres@
> could be made a superuser, he wouldn't be the same user as postgres ---
> this affects table ownership, for example, and would be a serious issue
> if you wanted any non-superuser global users.)
> 
> I suppose some might argue that having to say postgres@ to log in,
> when your username is really just postgres as far as you can see in the
> database, is a tad confusing.  But the whole thing is an acknowledged
> wart anyway, and I think getting rid of the two problems mentioned above
> is worth it.
> 
> Also, if we do this then it's important to strip a trailing '@' only
> if it's the *only* one in the given username.  Else a local user
> 'foo@db1' could cheat to log into db2 by saying username = 'foo@db1@'
> with requested database db2.  But I can't see any other security hole.
> 
>                       regards, tom lane
> 

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  [EMAIL PROTECTED]               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: doc/src/sgml/runtime.sgml
===================================================================
RCS file: /cvsroot/pgsql-server/doc/src/sgml/runtime.sgml,v
retrieving revision 1.125
diff -c -r1.125 runtime.sgml
*** doc/src/sgml/runtime.sgml   15 Aug 2002 14:26:15 -0000      1.125
--- doc/src/sgml/runtime.sgml   17 Aug 2002 04:14:34 -0000
***************
*** 1191,1196 ****
--- 1191,1216 ----
       </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>
         <secondary>timeout</secondary>
Index: src/backend/libpq/auth.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/libpq/auth.c,v
retrieving revision 1.82
diff -c -r1.82 auth.c
*** src/backend/libpq/auth.c    20 Jun 2002 20:29:28 -0000      1.82
--- src/backend/libpq/auth.c    17 Aug 2002 04:14:35 -0000
***************
*** 117,123 ****
                         version, PG_KRB4_VERSION);
                return STATUS_ERROR;
        }
!       if (strncmp(port->user, auth_data.pname, SM_USER) != 0)
        {
                elog(LOG, "pg_krb4_recvauth: name \"%s\" != \"%s\"",
                         port->user, auth_data.pname);
--- 117,123 ----
                         version, PG_KRB4_VERSION);
                return STATUS_ERROR;
        }
!       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,296 ****
        }
  
        kusername = pg_an_to_ln(kusername);
!       if (strncmp(port->user, kusername, SM_USER))
        {
                elog(LOG, "pg_krb5_recvauth: user name \"%s\" != krb5 name \"%s\"",
                         port->user, kusername);
--- 290,296 ----
        }
  
        kusername = pg_an_to_ln(kusername);
!       if (strncmp(port->user, kusername, SM_DATABASE_USER))
        {
                elog(LOG, "pg_krb5_recvauth: user name \"%s\" != krb5 name \"%s\"",
                         port->user, kusername);
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/postmaster/postmaster.c,v
retrieving revision 1.283
diff -c -r1.283 postmaster.c
*** src/backend/postmaster/postmaster.c 10 Aug 2002 20:29:18 -0000      1.283
--- src/backend/postmaster/postmaster.c 17 Aug 2002 04:14:40 -0000
***************
*** 116,122 ****
  sigset_t      UnBlockSig,
                        BlockSig,
                        AuthBlockSig;
- 
  #else
  int                   UnBlockSig,
                        BlockSig,
--- 116,121 ----
***************
*** 191,196 ****
--- 190,197 ----
  bool          HostnameLookup;         /* for ps display */
  bool          ShowPortNumber;
  bool          Log_connections = false;
+ bool          Db_user_namespace = false;
+ 
  
  /* Startup/shutdown state */
  static pid_t StartupPID = 0,
***************
*** 1161,1166 ****
--- 1162,1182 ----
        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 '@' */
+               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.
***************
*** 2587,2597 ****
        if (FindExec(fullprogname, argv[0], "postmaster") < 0)
                return false;
  
!       filename = palloc(strlen(DataDir) + 20);
        sprintf(filename, "%s/postmaster.opts", DataDir);
  
!       fp = fopen(filename, "w");
!       if (fp == NULL)
        {
                postmaster_error("cannot create file %s: %s",
                                                 filename, strerror(errno));
--- 2603,2612 ----
        if (FindExec(fullprogname, argv[0], "postmaster") < 0)
                return false;
  
!       filename = palloc(strlen(DataDir) + 17);
        sprintf(filename, "%s/postmaster.opts", DataDir);
  
!       if ((fp = fopen(filename, "w")) == NULL)
        {
                postmaster_error("cannot create file %s: %s",
                                                 filename, strerror(errno));
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v
retrieving revision 1.82
diff -c -r1.82 guc.c
*** src/backend/utils/misc/guc.c        15 Aug 2002 02:51:26 -0000      1.82
--- src/backend/utils/misc/guc.c        17 Aug 2002 04:14:49 -0000
***************
*** 483,488 ****
--- 483,492 ----
                { "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
Index: src/backend/utils/misc/postgresql.conf.sample
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/postgresql.conf.sample,v
retrieving revision 1.44
diff -c -r1.44 postgresql.conf.sample
*** src/backend/utils/misc/postgresql.conf.sample       12 Aug 2002 00:36:12 -0000     
 1.44
--- src/backend/utils/misc/postgresql.conf.sample       17 Aug 2002 04:14:50 -0000
***************
*** 113,119 ****
  #
  #     Message display
  #
- 
  #server_min_messages = notice # Values, in order of decreasing detail:
                                #   debug5, debug4, debug3, debug2, debug1,
                                #   info, notice, warning, error, log, fatal,
--- 113,118 ----
***************
*** 201,203 ****
--- 200,203 ----
  #sql_inheritance = true
  #transform_null_equals = false
  #statement_timeout = 0                                # 0 is disabled
+ #db_user_namespace = false
Index: src/include/libpq/libpq-be.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/libpq/libpq-be.h,v
retrieving revision 1.32
diff -c -r1.32 libpq-be.h
*** src/include/libpq/libpq-be.h        20 Jun 2002 20:29:49 -0000      1.32
--- src/include/libpq/libpq-be.h        17 Aug 2002 04:14:50 -0000
***************
*** 59,65 ****
  
        ProtocolVersion proto;
        char            database[SM_DATABASE + 1];
!       char            user[SM_USER + 1];
        char            options[SM_OPTIONS + 1];
        char            tty[SM_TTY + 1];
        char            auth_arg[MAX_AUTH_ARG];
--- 59,65 ----
  
        ProtocolVersion proto;
        char            database[SM_DATABASE + 1];
!       char            user[SM_DATABASE_USER + 1];
        char            options[SM_OPTIONS + 1];
        char            tty[SM_TTY + 1];
        char            auth_arg[MAX_AUTH_ARG];
Index: src/include/libpq/pqcomm.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/libpq/pqcomm.h,v
retrieving revision 1.65
diff -c -r1.65 pqcomm.h
*** src/include/libpq/pqcomm.h  12 Aug 2002 14:35:26 -0000      1.65
--- src/include/libpq/pqcomm.h  17 Aug 2002 04:14:50 -0000
***************
*** 114,119 ****
--- 114,121 ----
  #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,135 ****
--- 126,139 ----
  {
        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. */
  

---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?

http://archives.postgresql.org

Reply via email to