Re: Open 7.3 items - Mailing list pgsql-hackers

From Bruce Momjian
Subject Re: Open 7.3 items
Date
Msg-id 200208140136.g7E1ahQ20870@candle.pha.pa.us
Whole thread Raw
In response to Re: Open 7.3 items  (Bruce Momjian <pgman@candle.pha.pa.us>)
Responses Re: Open 7.3 items
List pgsql-hackers
OK, here is the patch to implement db_user_namespace.  It includes
documentation.

I had to add to initdb to create a file /data/PG_INSTALLER and have the
postmaster read that on startup to determine the installing user.

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

Bruce Momjian wrote:
>
> I would like to address this email.
>
> Lamar is mentioning that it is unfair to remove a feature without
> warning.
>
> Let me give a little history.  The secondary password file was created
> at a time when we didn't encrypt with random salt over the wire, and we
> had people who wanted to share their /etc/passwd file with PostgreSQL.
>
> Later, people wanted to use the secondary password file for just
> usernames, so you could list usernames in the file and limit db access
> by user.  This is the current usage for 99% of secondary password users.
> This capability is better served in 7.3 with the new USER column in
> pg_shadow and the ability to specify filenames or groups in that file.
> Keeping the secondary password file to specify a user list while a new
> USER column exists in 7.3 is just confusing to administrators.  Our
> pg_hba.conf system is pretty complex, so anything we can do to simplify
> helps.
>
> Now, on to Marc's case, where he does use the file for usernames _and_
> passwords.  However, he is using it only so he can have more than one
> person with the same username and restrict access based on the password
> in the secondary password file.  While this does work, my submitted
> patch makes this much easier and cleaner.
>
> Marc had mentioned that this should be an initdb flag.  However, our
> standard procedure is to put stuff in initdb only when it can't be
> changed after initdb.  While strange, this feature can be
> enabled-disabled after initdb.  A quick update of pg_shadow can change
> usernames and you can go in and out of this mode.
>
> Someone talked about pushing this capability into a separate pg_shadow
> column, and making CREATE/ALTER user and createuser aware of this.
> While this can be done, and it sort of becomes user schemas, there isn't
> enough people wanting this to add complexity to those commands.  A GUC
> flag will meet most peoples needs at this point.
>
> Some mentioned using user@dbname, though the idea of sorting made
> several recant their votes.
>
> So, based on the voting, I think dbname.username is an agreed-upon
> feature addition for 7.3.  I will work on a final patch with
> documentation and post it to the patches list for more comment.
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (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.124
diff -c -r1.124 runtime.sgml
*** doc/src/sgml/runtime.sgml    12 Aug 2002 00:36:11 -0000    1.124
--- doc/src/sgml/runtime.sgml    14 Aug 2002 01:30:15 -0000
***************
*** 1191,1196 ****
--- 1191,1208 ----
       </varlistentry>

       <varlistentry>
+       <term><varname>DB_USER_NAMESPACE</varname> (<type>boolean</type>)</term>
+       <listitem>
+        <para>
+         Prepends the database name and a period to the username when
+         connecting to the database.  This allows per-database users.
+         The user who ran <command>initdb</> is excluded from this
+         handling.
+        </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    14 Aug 2002 01:30:15 -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    14 Aug 2002 01:30:17 -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,
***************
*** 208,213 ****
--- 209,216 ----

  bool ClientAuthInProgress = false;    /* T during new-client authentication */

+ static char InstallUser[SM_USER+1];
+
  /*
   * State for assigning random salts and cancel keys.
   * Also, the global MyCancelKey passes the cancel key assigned to a given
***************
*** 258,263 ****
--- 261,267 ----
  static void SignalChildren(int signal);
  static int    CountChildren(void);
  static bool CreateOptsFile(int argc, char *argv[]);
+ static bool GetInstallUser(void);
  static pid_t SSDataBase(int xlop);
         void
  postmaster_error(const char *fmt,...)
***************
*** 690,695 ****
--- 694,702 ----
      if (!CreateOptsFile(argc, argv))
          ExitPostmaster(1);

+     if (!GetInstallUser())
+         ExitPostmaster(1);
+
      /*
       * Set up signal handlers for the postmaster process.
       *
***************
*** 1161,1166 ****
--- 1168,1182 ----
      if (port->user[0] == '\0')
          elog(FATAL, "no PostgreSQL user name specified in startup packet");

+     /* Prefix database name for per-db user namespace */
+     if (Db_user_namespace && strcmp(port->user, InstallUser))
+     {
+         char hold_user[SM_DATABASE_USER];
+         snprintf(hold_user, SM_DATABASE_USER, "%s.%s", port->database,
+                  port->user);
+         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));
***************
*** 2614,2619 ****
--- 2629,2669 ----
      return true;
  }

+ /*
+  * Load install user so db_user_namespace can skip it.
+  */
+ static bool
+ GetInstallUser(void)
+ {
+     char       *filename;
+     FILE       *fp;
+
+     filename = palloc(strlen(DataDir) + 14);
+     sprintf(filename, "%s/PG_INSTALLER", DataDir);
+
+     if ((fp = fopen(filename, "r")) == NULL)
+     {
+         postmaster_error("cannot open file %s: %s",
+                          filename, strerror(errno));
+         return false;
+     }
+
+     if (fgets(InstallUser, SM_USER+1, fp) == NULL)
+     {
+         postmaster_error("cannot read file %s: %s",
+                          filename, strerror(errno));
+         return false;
+     }
+
+     /* Trim off trailing newline */
+     if (strchr(InstallUser, '\n') != NULL)
+         *strchr(InstallUser, '\n') = '\0';
+
+     fclose(fp);
+     return true;
+ }
+
+
  /*
   * This should be used only for reporting "interactive" errors (ie, errors
   * during startup.  Once the postmaster is launched, use elog.
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v
retrieving revision 1.79
diff -c -r1.79 guc.c
*** src/backend/utils/misc/guc.c    12 Aug 2002 00:36:11 -0000    1.79
--- src/backend/utils/misc/guc.c    14 Aug 2002 01:30:20 -0000
***************
*** 482,487 ****
--- 482,491 ----
          { "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    14 Aug 2002 01:30:20 -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/bin/initdb/initdb.sh
===================================================================
RCS file: /cvsroot/pgsql-server/src/bin/initdb/initdb.sh,v
retrieving revision 1.165
diff -c -r1.165 initdb.sh
*** src/bin/initdb/initdb.sh    8 Aug 2002 19:39:05 -0000    1.165
--- src/bin/initdb/initdb.sh    14 Aug 2002 01:30:20 -0000
***************
*** 603,608 ****
--- 603,613 ----
  # Top level PG_VERSION is checked by bootstrapper, so make it first
  echo "$short_version" > "$PGDATA/PG_VERSION" || exit_nicely

+ # Top level PG_INSTALLER is used by db_user_namespace to prevent username
+ # mapping just for the install user.
+ echo "$POSTGRES_SUPERUSERNAME" > "$PGDATA/PG_INSTALLER" || exit_nicely
+
+
  cat "$POSTGRES_BKI" \
  | sed -e "s/POSTGRES/$POSTGRES_SUPERUSERNAME/g" \
        -e "s/ENCODING/$MULTIBYTEID/g" \
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    14 Aug 2002 01:30:20 -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];
***************
*** 72,78 ****
      SSL           *ssl;
      X509       *peer;
      char        peer_dn[128 + 1];
!     char        peer_cn[SM_USER + 1];
      unsigned long count;
  #endif
  } Port;
--- 72,78 ----
      SSL           *ssl;
      X509       *peer;
      char        peer_dn[128 + 1];
!     char        peer_cn[SM_DATABASE_USER + 1];
      unsigned long count;
  #endif
  } Port;
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    14 Aug 2002 01:30:20 -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 prepend database name if db_user_namespace true. */
+ #define SM_DATABASE_USER (SM_DATABASE+SM_USER)
  #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 prepends 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. */


pgsql-hackers by date:

Previous
From: Don Baccus
Date:
Subject: Re: OOP real life example (was Re: Why is MySQL more
Next
From: Bruce Momjian
Date:
Subject: Re: OOP real life example (was Re: Why is MySQL more