Authentication improvements:
authorBruce Momjian
Thu, 4 Apr 2002 04:25:54 +0000 (04:25 +0000)
committerBruce Momjian
Thu, 4 Apr 2002 04:25:54 +0000 (04:25 +0000)
A new pg_hba.conf column, USER
Allow specifiction of lists of users separated by commas
Allow group names specified by +
Allow include files containing lists of users specified by @
Allow lists of databases, and database files
Allow samegroup in database column to match group name matching dbname
Removal of secondary password files
Remove pg_passwd utility
Lots of code cleanup in user.c and hba.c
New data/global/pg_pwd format
New data/global/pg_group file

25 files changed:
doc/src/sgml/client-auth.sgml
doc/src/sgml/ref/allfiles.sgml
doc/src/sgml/ref/pg_passwd.sgml [deleted file]
doc/src/sgml/reference.sgml
src/backend/commands/user.c
src/backend/libpq/Makefile
src/backend/libpq/auth.c
src/backend/libpq/crypt.c
src/backend/libpq/hba.c
src/backend/libpq/password.c [deleted file]
src/backend/libpq/pg_hba.conf.sample
src/backend/postmaster/postmaster.c
src/backend/utils/adt/quote.c
src/backend/utils/init/miscinit.c
src/bin/Makefile
src/bin/initdb/initdb.sh
src/bin/pg_passwd/Makefile [deleted file]
src/bin/pg_passwd/pg_passwd.c [deleted file]
src/include/catalog/pg_proc.h
src/include/commands/user.h
src/include/libpq/crypt.h
src/include/libpq/hba.h
src/include/miscadmin.h
src/test/regress/expected/opr_sanity.out
src/test/regress/sql/opr_sanity.sql

index 76542f987206319ff13e490b078245918dfa2d59..4afd179a4b1cd4ab3f71b088c9de99367ecb6d95 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -10,14 +10,13 @@ $Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.33 2002/03/22 19:20:06
  
 
  
-  When a client application connects to the database server, it specifies which
-  PostgreSQL user name it wants to connect as,
-  much the same way one logs into a Unix computer as a particular user.
-  Within the SQL environment the active
-  database user name determines access privileges to database
-  objects -- see  for more information
-  about that. It is therefore obviously essential to restrict which
-  database user name(s) a given client can connect as.
+  When a client application connects to the database server, it
+  specifies which PostgreSQL user name it
+  wants to connect as, much the same way one logs into a Unix computer
+  as a particular user. Within the SQL environment the active database
+  user name determines access privileges to database objects -- see
+   for more information. Therefore, it is
+  essential to restrict which database users can connect.
  
 
  
@@ -30,20 +29,19 @@ $Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.33 2002/03/22 19:20:06
 
  
   PostgreSQL offers a number of different
-  client authentication methods.  The method to be used can be selected
-  on the basis of (client) host and database; some authentication methods
-  allow you to restrict by user name as well.
+  client authentication methods. The method to be used can be selected
+  on the basis of (client) host, database, and user.
  
 
  
-  PostgreSQL database user names are logically
+  PostgreSQL user names are logically
   separate from user names of the operating system in which the server
-  runs.  If all the users of a particular server also have accounts on
+  runs. If all the users of a particular server also have accounts on
   the server's machine, it makes sense to assign database user names
-  that match their operating system user names.  However, a server that accepts remote
-  connections may have many users who have no local account, and in such
-  cases there need be no connection between database user names and OS
-  user names.
+  that match their operating system user names. However, a server that
+  accepts remote connections may have many users who have no local
+  account, and in such cases there need be no connection between
+  database user names and OS user names.
  
 
  
@@ -56,39 +54,39 @@ $Header: /cvsroot/pgsql/doc/src/sgml/client-auth.sgml,v 1.33 2002/03/22 19:20:06
   
    Client authentication is controlled by the file
    pg_hba.conf in the data directory, e.g.,
-   /usr/local/pgsql/data/pg_hba.conf. (HBA stands
-   for host-based authentication.) A default pg_hba.conf
-   file is installed when the
-   data area is initialized by initdb.
+   /usr/local/pgsql/data/pg_hba.conf.
+   (HBA stands for host-based authentication.) A default
+   pg_hba.conf file is installed when the data area
+   is initialized by initdb.
   
 
   
-   The general format of the pg_hba.conf file is
-   of a set of records, one per line. Blank lines and lines beginning
-   with a hash character (#) are ignored. A record is
-   made up of a number of fields which are separated by spaces and/or
-   tabs.  Records cannot be continued across lines.
+   The general format of the pg_hba.conf file is of
+   a set of records, one per line. Blank lines are ignored, as is any
+   text after the # comment character. A record is made
+   up of a number of fields which are separated by spaces and/or tabs.
+   Fields can contain white space if the field value is quoted. Records
+   cannot be continued across lines.
   
 
   
    Each record specifies a connection type, a client IP address range
-   (if relevant for the connection type), a database name or names,
+   (if relevant for the connection type), a database name, a user name,
    and the authentication method to be used for connections matching
-   these parameters.
-   The first record that matches the type, client address, and requested
-   database name of a connection attempt is used to do the
-   authentication step.  There is no fall-through or
+   these parameters. The first record with a matching connection type,
+   client address, requested database, and user name is used to perform
+   authentication. There is no fall-through or
    backup: if one record is chosen and the authentication
-   fails, the following records are not considered. If no record
-   matches, the access will be denied.
+   fails, subsequent records are not considered. If no record matches,
+   access is denied.
   
 
   
    A record may have one of the three formats
    
-local   database authentication-method [ authentication-option ]
-host    database IP-address IP-mask authentication-method [ authentication-option ]
-hostssl database IP-address IP-mask authentication-method [ authentication-option ]
+local   database user authentication-method [ authentication-option ]
+host    database user IP-address IP-mask authentication-method
+hostssl database user IP-address IP-mask authentication-method
     
    The meaning of the fields is as follows:
 
@@ -97,7 +95,7 @@ hostssl database IP-address
      local
      
       
-       This record pertains to connection attempts over Unix domain
+       This record applies to connection attempts using Unix domain
        sockets.
       
      
@@ -107,10 +105,11 @@ hostssl database IP-address
      host
      
       
-       This record pertains to connection attempts over TCP/IP
-       networks. Note that TCP/IP connections are completely disabled
-       unless the server is started with the  switch or
-       the equivalent configuration parameter is set.
+       This record applied to connection attempts using TCP/IP networks.
+       Note that TCP/IP connections are disabled unless the server is
+       started with the  option or the
+       tcpip_socket postgresql.conf
+       configuration parameter is enabled.
       
      
     
@@ -119,13 +118,13 @@ hostssl database IP-address
      hostssl
      
       
-       This record pertains to connection attempts with SSL over
+       This record applies to connection attempts using SSL over
        TCP/IP. To make use of this option the server must be
        built with SSL support enabled. Furthermore, SSL must be
        enabled with the 
        setting when the server is started.  (Note: host
        records will match either SSL or non-SSL connection attempts, but
-       hostssl records match only SSL connections.)
+       hostssl records requires SSL connections.)
       
      
     
@@ -134,12 +133,35 @@ hostssl database IP-address
      database
      
       
-       Specifies the database that this record applies to. The value
+       Specifies the database for this record. The value
        all specifies that it applies to all
        databases, while the value sameuser identifies the
-       database with the same name as the connecting user.  Otherwise,
-       this is the name of a specific PostgreSQL
-       database.
+       database with the same name as the connecting user. The value
+       samegroup identifies a group with the same name as
+       the database name. Only members of this group can connect to the
+       database. Otherwise, this is the name of a specific
+       PostgreSQL database. Multiple database
+       names can be supplied by separating them with commas. A file
+       containing database names can be specified by preceding the file
+       name with @. The file must be in the same directory
+       as pg_hba.conf.
+      
+     
+    
+
+    
+     user
+     
+      
+       Specifies the user for this record. The value
+       all specifies that it applies to all users.
+       Otherwise, this is the name of a specific
+       PostgreSQL user. Multiple user names
+       can be supplied by separating them with commas. Group names can
+       be specified by preceding the group name with +. A
+       file containing user names can be specified by preceding the file
+       name with @. The file must be in the same directory
+       as pg_hba.conf.
       
      
     
@@ -149,10 +171,9 @@ hostssl database IP-address
      IP mask
      
       
-       These two fields specify to which client machines a
-       host or hostssl
-       record applies, based on their IP
-       address. (Of course IP addresses can be spoofed but this
+       These two fields specify the client machine IP addresses
+       (host or hostssl) for this
+       record. (Of course IP addresses can be spoofed but this
        consideration is beyond the scope of
        PostgreSQL.) The precise logic is that
        
@@ -169,10 +190,9 @@ hostssl database IP-address
      authentication method
      
       
-       Specifies the method that users must use to authenticate themselves
-       when connecting under the control of this authentication record.
-       The possible choices are summarized here,
-       details are in .
+       Specifies the authentication method to use when connecting via
+       this record. The possible choices are summarized here; details
+       are in .
 
        
         
@@ -190,66 +210,41 @@ hostssl database IP-address
         reject
         
          
-          The connection is rejected unconditionally. This is mostly
-          useful to filter out certain hosts from a group.
+          The connection is rejected unconditionally. This is useful for
+          filtering out certain hosts from a group.
          
         
        
 
        
-        password
+        md5
         
          
-          The client is required to supply a password which is required to
-     match the database password that was set up for the user.
-         
-
-         
-          An optional file name may be specified after the
-          password keyword. This file is expected to
-          contain a list of users who may connect using this record,
-          and optionally alternative passwords for them.
-         
-
-         
-          The password is sent over the wire in clear text. For better
-          protection, use the md5 or 
-          crypt methods.
+          Requires the client to supply an MD5 encrypted password for
+          authentication. This is the only method that allows encrypted
+          passwords to be stored in pg_shadow.
          
         
        
 
        
-        md5
+        crypt
         
          
-          Like the password method, but the password
-          is sent over the wire encrypted using a simple
-          challenge-response protocol. This protects against incidental
-          wire-sniffing.  This is now the recommended choice for
-     password-based authentication.
-         
-
-         
-     The name of a file may follow the
-          md5 keyword.  It contains a list of users
-          who may connect using this record.
+          Like md5 method but uses older crypt
+          encryption, which is needed for pre-7.2 clients.
+          md5 is preferred for 7.2 and later clients.
          
         
        
 
        
-        crypt
+        password
         
          
-          Like the md5 method but uses older crypt
-          encryption, which is needed for pre-7.2
-     clients. md5 is
-          preferred for 7.2 and later clients. The crypt
-          method is not compatible with encrypting passwords in
-          pg_shadow, and may fail if client and server
-          machines have different implementations of the crypt() library
-          routine.
+          Same as "md5", but the password is sent in cleartext over the
+          network. This should not be used on untrusted networks.
+         
          
         
        
@@ -278,34 +273,36 @@ hostssl database IP-address
         ident
         
     
-     The identity of the user as determined on login to the
-     operating system is used by PostgreSQL
-     to determine whether the user
-          is allowed to connect as the requested database user.
-     For TCP/IP connections the user's identity is determined by
-     contacting the ident server on the client
-     host.  (Note that this is only as reliable as the remote ident
-     server; ident authentication should never be used for remote hosts
-     whose administrators are not trustworthy.)
-     On operating systems
-     supporting SO_PEERCRED requests for Unix domain sockets,
-     ident authentication is possible for local connections;
-     the system is then asked for the connecting user's identity.
-    
+          For TCP/IP connections, authentication is done by contacting
+          the ident server on the client host.
+          This is only as secure as the client machine. You must specify
+          the map name after the 'ident' keyword. It determines how to
+          map remote user names to PostgreSQL user names. If you use
+          "sameuser", the user names are assumed to be identical. If
+          not, the map name is looked up in the $PGDATA/pg_ident.conf
+          file. The connection is accepted if that file contains an
+          entry for this map name with the ident-supplied user name and
+          the requested PostgreSQL user name.
+         
+         
+          On machines that support unix-domain socket credentials
+          (currently Linux, FreeBSD, NetBSD, and BSD/OS), ident allows
+          reliable authentication of 'local' connections without ident
+          running on the local machine.
+         
          
-     On systems without SO_PEERCRED requests, ident authentication
-     is only available for TCP/IP connections.  As a workaround,
-     it is possible to
-     specify the localhost address
-          127.0.0.1 and make connections
-     to this address.
+     On systems without SO_PEERCRED requests, ident
+     authentication is only available for TCP/IP connections. As a
+     work around, it is possible to specify the 
+     class="systemname">localhost address 
+     class="systemname">127.0.0.1 and make connections to this
+     address.
     
          
-          The authentication option following
-          the ident keyword specifies the name of an
-          ident map that specifies which operating
-          system users equate with which database users. See below for
-          details.
+          Following the ident keyword, an ident
+          map name should be supplied which specifies which
+          operating system users equate with which database users. See
+          below for details.
          
         
        
@@ -315,17 +312,16 @@ hostssl database IP-address
         
          
           This authentication type operates similarly to
-          password, with the main difference that
-          it will use PAM (Pluggable Authentication Modules) as the
-          authentication mechanism. The authentication
-          option following the pam keyword
-          specifies the service name that will be passed to PAM. The
-          default service name is postgresql.
-          For more information about PAM, please read the 
-          url="http://www.kernel.org/pub/linux/libs/pam/">Linux-PAM
-          Page and/or the 
-          url="http://www.sun.com/software/solaris/pam/">Solaris PAM
-          Page.
+          password except that it uses PAM
+          (Pluggable Authentication Modules) as the authentication
+          mechanism. The default PAM service name is
+          postgresql. You can optionally supply you
+          own service name after the pam keyword in the
+          file. For more information about PAM, please read the 
+          url="http://www.kernel.org/pub/linux/libs/pam/">L
+          inux-PAM Page and the 
+          url="http://www.sun.com/software/solaris/pam/">
+          class="osname">Solaris PAM Page.
          
         
        
@@ -336,42 +332,33 @@ hostssl database IP-address
      
     
 
-    
-     authentication option
-     
-      
-       This field is interpreted differently depending on the
-       authentication method, as described above.
-      
-     
-    
    
   
 
   
    Since the pg_hba.conf records are examined
    sequentially for each connection attempt, the order of the records is
-   very significant.  Typically, earlier records will have tight
-   connection match parameters and weaker authentication methods,
-   while later records will have looser match parameters and stronger
-   authentication methods.  For example, one might wish to use
-   trust authentication for local TCP connections but
-   require a password for remote TCP connections.  In this case a
-   record specifying trust authentication for connections
-   from 127.0.0.1 would appear before a record specifying password
-   authentication for a wider range of allowed client IP addresses.
+   significant. Typically, earlier records will have tight connection
+   match parameters and weaker authentication methods, while later
+   records will have looser match parameters and stronger authentication
+   methods. For example, one might wish to use trust
+   authentication for local TCP connections but require a password for
+   remote TCP connections. In this case a record specifying
+   trust authentication for connections from 127.0.0.1 would
+   appear before a record specifying password authentication for a wider
+   range of allowed client IP addresses.
   
 
   
     
      SIGHUP
     
-   The pg_hba.conf file is read on start-up
-   and when the postmaster receives a
+   The pg_hba.conf file is read on start-up and when
+   the postmaster receives a
    SIGHUP signal. If you edit the file on an
    active system, you will need to signal the postmaster
-   (using pg_ctl reload or kill -HUP)
-   to make it re-read the file.
+   (using pg_ctl reload or kill -HUP) to make it
+   re-read the file.
   
 
   
@@ -382,27 +369,27 @@ hostssl database IP-address
    
     An example <filename>pg_hba.conf</filename> file
 
-# TYPE       DATABASE    IP_ADDRESS    MASK               AUTHTYPE  MAP
+# TYPE       DATABASE    USER       IP_ADDRESS    MASK               AUTHTYPE
 
 # Allow any user on the local system to connect to any
-# database under any username, but only via an IP connection:
+# database under any user name, but only via an IP connection:
 
-host         all         127.0.0.1     255.255.255.255    trust     
+host         all         all        127.0.0.1     255.255.255.255    trust     
 
 # The same, over Unix-socket connections:
 
-local        all                                          trust
+local        all         all                                         trust
 
 # Allow any user from any host with IP address 192.168.93.x to
-# connect to database "template1" as the same username that ident on that
-# host identifies him as (typically his Unix username):
+# connect to database "template1" as the same user name that ident on that
+# host identifies him as (typically his Unix user name):
 
-host         template1   192.168.93.0  255.255.255.0      ident     sameuser
+host         template1   all        192.168.93.0  255.255.255.0      ident sameuser
 
 # Allow a user from host 192.168.12.10 to connect to database "template1"
-# if the user's password in pg_shadow is correctly supplied:
+# if the user's password is correctly supplied:
 
-host         template1   192.168.12.10 255.255.255.255    md5
+host         template1   all        192.168.12.10 255.255.255.255    md5
 
 # In the absence of preceding "host" lines, these two lines will reject
 # all connection attempts from 192.168.54.1 (since that entry will be
@@ -410,8 +397,8 @@ host         template1   192.168.12.10 255.255.255.255    md5
 # else on the Internet. The zero mask means that no bits of the host IP
 # address are considered, so it matches any host:
 
-host         all        192.168.54.1   255.255.255.255    reject
-host         all        0.0.0.0        0.0.0.0            krb5
+host         all        all         192.168.54.1   255.255.255.255    reject
+host         all        all         0.0.0.0        0.0.0.0            krb5
 
 # Allow users from 192.168.x.x hosts to connect to any database, if they
 # pass the ident check.  If, for example, ident says the user is "bryanh"
@@ -419,7 +406,7 @@ host         all        0.0.0.0        0.0.0.0            krb5
 # is allowed if there is an entry in pg_ident.conf for map "omicron" that
 # says "bryanh" is allowed to connect as "guest1":
 
-host         all        192.168.0.0    255.255.0.0        ident     omicron
+host         all        all         192.168.0.0    255.255.0.0        ident omicron
 
 # If these are the only two lines for local connections, they will allow
 # local users to connect only to their own databases (database named the
@@ -429,8 +416,8 @@ host         all        192.168.0.0    255.255.0.0        ident     omicron
 # cases.  (If you prefer to use ident authorization, an ident map can
 # serve a parallel purpose to the password list file used here.)
 
-local        sameuser                                     md5
-local        all                                          md5  admins
+local        sameuser   all                                            md5
+local        all        @admins                                        md5
 
    
   
@@ -490,86 +477,49 @@ local        all                                          md5  admins
    Password authentication
 
    
-    password>
+    MD5>
    
    
-    MD5
+    crypt
+   
+   
+    password
    
 
    
     Password-based authentication methods include md5,
-    crypt, and password.  These methods operate
+    crypt, and password. These methods operate
     similarly except for the way that the password is sent across the
-    connection.  If you are at all concerned about password sniffing
-    attacks then md5 is preferred, with crypt a
-    second choice if you must support obsolete clients.  Plain
-    password should especially be avoided for connections over
-    the open Internet (unless you use SSL, SSH, or other communications
-    security wrappers around the connection).
+    connection. If you are at all concerned about password
+    sniffing attacks then md5 is preferred, with
+    crypt a second choice if you must support pre-7.2
+    clients. Plain password should especially be avoided for
+    connections over the open Internet (unless you use SSL, SSH, or
+    other communications security wrappers around the connection).
    
 
    
-    PostgreSQL database passwords are separate from
-    operating system user passwords. Ordinarily, the password for each
-    database user is stored in the pg_shadow system catalog table.
-    Passwords can be managed with the query language commands
-    CREATE USER and ALTER USER,
-    e.g., CREATE USER foo WITH PASSWORD
-    'secret';. By default, that is, if no password has
-    been set up, the stored password is NULL
-    and password authentication will always fail for that user.
+    PostgreSQL database passwords are
+    separate from operating system user passwords. Ordinarily, the
+    password for each database user is stored in the pg_shadow system
+    catalog table. Passwords can be managed with the query language
+    commands CREATE USER and ALTER
+    USER, e.g., CREATE USER foo WITH PASSWORD
+    'secret';. By default, that is, if no password has been
+    set up, the stored password is NULL and password
+    authentication will always fail for that user.
    
 
    
     To restrict the set of users that are allowed to connect to certain
-    databases, list the set of users in a separate file (one user name
-    per line) in the same directory that pg_hba.conf is in,
-    and mention the (base) name of the file after the
-    password, md5, or crypt keyword,
-    respectively, in pg_hba.conf. If you do not use this
-    feature, then any user that is known to the database system can
-    connect to any database (so long as he supplies the correct password,
-    of course).
-   
-
-   
-    These files can also be used to apply a different set of passwords
-    to a particular database or set thereof. In that case, the files
-    have a format similar to the standard Unix password file
-    /etc/passwd, that is,
-
-username:password
-
-    Any extra colon-separated fields following the password are
-    ignored. The password is expected to be encrypted using the
-    system's crypt() function. The utility
-    program pg_passwd that is installed
-    with PostgreSQL can be used to manage
-    these password files.
-   
-
-   
-    Lines with and without passwords can be mixed in secondary
-    password files. Lines without password indicate use of the main
-    password in pg_shadow that is managed by
-    CREATE USER and ALTER USER. Lines with
-    passwords will cause that password to be used. A password entry of
-    + also means using the pg_shadow password.
-   
-
-   
-    Alternative passwords cannot be used when using the md5
-    or crypt methods. The file will be read as
-    usual, but the password field will simply be ignored and the
-    pg_shadow password will always be used.
-   
-
-   
-    Note that using alternative passwords like this means that one can
-    no longer use ALTER USER to change one's
-    password. It will appear to work but the password one is
-    changing is not the password that the system will end up
-    using.
+    databases, list the users separated by commas, or in a separate
+    file. The file should contain user names separated by commas or one
+    user name per line, and be in the same directory as
+    pg_hba.conf. Mention the (base) name of the file
+    preceded with @in the USER column. The
+    DATABASE column can similarly accept a list of values or
+    a file name. You can also specify group names by preceding the group
+    name with +.
    
 
   
@@ -588,10 +538,10 @@ local        all                                          md5  admins
     Kerberos system is far beyond the scope
     of this document; in all generality it can be quite complex (yet
     powerful). The 
-    url="http://www.nrl.navy.mil/CCS/people/kenh/kerberos-faq.html">Kerberos
-    FAQ or 
-    url="ftp://athena-dist.mit.edu">MIT Project Athena can be
-    good starting point for exploration. Several sources for
+    url="http://www.nrl.navy.mil/CCS/people/kenh/kerberos-faq.html">Kerb
+    eros FAQ or 
+    url="ftp://athena-dist.mit.edu">MIT Project Athena can be a
+    good starting point for exploration. Several sources for
     Kerberos distributions exist.
    
 
@@ -606,34 +556,33 @@ local        all                                          md5  admins
    
     PostgreSQL operates like a normal Kerberos service.
     The name of the service principal is
-    servicename/hostname@realm, where 
-    servicename is postgres
-    (unless a different service name was selected at configure time
-    with ./configure --with-krb-srvnam=whatever).
-    hostname is the fully qualified domain name of the server
-    machine.  The service principal's realm is the preferred realm of the
-    server machine.
+    servicename/hostname@realm, where
+    servicename is postgres (unless a
+    different service name was selected at configure time with
+    ./configure --with-krb-srvnam=whatever).
+    hostname is the fully qualified domain name of the
+    server machine. The service principal's realm is the preferred realm
+    of the server machine.
    
 
    
-    Client principals must have their PostgreSQL user name as
-    their first component, for example
-    pgusername/otherstuff@realm.
-    At present the realm of the client is not checked by
-    PostgreSQL; so
-    if you have cross-realm authentication enabled, then any principal
-    in any realm that can communicate with yours will be accepted.
+    Client principals must have their PostgreSQL user
+    name as their first component, for example
+    pgusername/otherstuff@realm. At present the realm of
+    the client is not checked by PostgreSQL; so if you
+    have cross-realm authentication enabled, then any principal in any
+    realm that can communicate with yours will be accepted.
    
 
    
-    Make sure that your server key file is readable (and
-    preferably only readable) by the
-    PostgreSQL server account (see 
-    ). The location of the key file
-    is specified with the krb_server_keyfile run time
-    configuration parameter. (See also .)
-    The default is /etc/srvtab if you are using Kerberos 4
-    and FILE:/usr/local/pgsql/etc/krb5.keytab (or whichever
+    Make sure that your server key file is readable (and preferably only
+    readable) by the PostgreSQL server
+    account (see ). The location of the
+    key file is specified with the krb_server_keyfile run
+    time configuration parameter. (See also 
+    linkend="runtime-config">.) The default is /etc/srvtab
+    if you are using Kerberos 4 and
+    FILE:/usr/local/pgsql/etc/krb5.keytab (or whichever
     directory was specified as sysconfdir at build time)
     with Kerberos 5.
    
@@ -649,18 +598,20 @@ local        all                                          md5  admins
 
    
     When connecting to the database make sure you have a ticket for a
-    principal matching the requested database user name. 
-    An example: For database user name fred, both principal
+    principal matching the requested database user name. An example: For
+    database user name fred, both principal
     [email protected] and
-    fred/[email protected] can be
-    used to authenticate to the database server. 
+    fred/[email protected] can be used to
+    authenticate to the database server.
    
 
    
-    If you use mod_auth_krb and mod_perl on your Apache web server,
-    you can use AuthType KerberosV5SaveCredentials with a mod_perl
-    script. This gives secure database access over the web, no extra
-    passwords required.
+    If you use mod_auth_krb and
+    mod_perl on your
+    Apache web server, you can use
+    AuthType KerberosV5SaveCredentials with a
+    mod_perl script. This gives secure
+    database access over the web, no extra passwords required.
    
 
   
@@ -707,55 +658,54 @@ local        all                                          md5  admins
    
 
    
-    On systems supporting SO_PEERCRED requests for Unix-domain sockets,
-    ident authentication can also be applied to local connections.  In this
-    case, no security risk is added by using ident authentication; indeed
-    it is a preferable choice for local connections on such a system.
+    On systems supporting SO_PEERCRED requests for
+    Unix-domain sockets, ident authentication can also be applied to
+    local connections. In this case, no security risk is added by using
+    ident authentication; indeed it is a preferable choice for local
+    connections on such systems.
    
 
    
     When using ident-based authentication, after having determined the
     name of the operating system user that initiated the connection,
-    PostgreSQL checks whether that user is allowed
-    to connect as the database user he is requesting to connect as.
-    This is controlled by the ident map
-    argument that follows the ident keyword in the
-    pg_hba.conf file. There is a predefined ident map
-    sameuser, which allows any operating system
-    user to connect as the database user of the same name (if the
-    latter exists). Other maps must be created manually.
+    PostgreSQL checks whether that user is
+    allowed to connect as the database user he is requesting to connect
+    as. This is controlled by the ident map argument that follows the
+    ident keyword in the pg_hba.conf
+    file. There is a predefined ident map sameuser,
+    which allows any operating system user to connect as the database
+    user of the same name (if the latter exists). Other maps must be
+    created manually.
    
 
    
-    pg_ident.conf
-    Ident maps other than sameuser are defined
-    in the file pg_ident.conf
-    in the data directory, which contains lines of the general form:
+    pg_ident.conf Ident maps
+    other than sameuser are defined in the file
+    pg_ident.conf in the data directory, which
+    contains lines of the general form:
 
 map-name ident-username database-username
 
-    Comments and whitespace are handled in the usual way.
-    The map-name is an arbitrary name that will be
-    used to refer to this mapping in pg_hba.conf.
-    The other two fields specify which operating system user is
-    allowed to connect as which database user. The same
-    map-name can be used repeatedly to specify more
-    user-mappings within a single map. There is no restriction regarding
-    how many 
-    database users a given operating system user may correspond to and vice
-    versa.
+    Comments and whitespace are handled in the usual way. The
+    map-name is an arbitrary name that will be used to
+    refer to this mapping in pg_hba.conf. The other
+    two fields specify which operating system user is allowed to connect
+    as which database user. The same map-name can be
+    used repeatedly to specify more user-mappings within a single map.
+    There is no restriction regarding how many database users a given
+    operating system user may correspond to and vice versa.
    
 
   
     
      SIGHUP
     
-   The pg_ident.conf file is read on start-up
-   and when the postmaster receives a
+   The pg_ident.conf file is read on start-up and
+   when the postmaster receives a
    SIGHUP signal. If you edit the file on an
    active system, you will need to signal the postmaster
-   (using pg_ctl reload or kill -HUP)
-   to make it re-read the file.
+   (using pg_ctl reload or kill -HUP) to make it
+   re-read the file.
   
 
    
@@ -763,13 +713,14 @@ local        all                                          md5  admins
     conjunction with the pg_hba.conf file in 
     linkend="example-pg-hba.conf"> is shown in 
     linkend="example-pg-ident.conf">. In this example setup, anyone
-    logged in to a machine on the 192.168 network that does not have
-    the Unix user name bryanh, ann, or robert would not be granted access.
-    Unix user robert would only be allowed access when he tries to
-    connect as PostgreSQL user bob,
-      not as robert
-    or anyone else. ann would only be allowed to connect as
-    ann. User bryanh would be allowed to connect as either
+    logged in to a machine on the 192.168 network that does not have the
+    Unix user name bryanh, ann, or
+    robert would not be granted access. Unix user
+    robert would only be allowed access when he tries to
+    connect as PostgreSQL user bob, not
+    as robert or anyone else. ann would
+    only be allowed to connect as ann. User
+    bryanh would be allowed to connect as either
     bryanh himself or as guest1.
    
 
@@ -780,7 +731,7 @@ local        all                                          md5  admins
 
 omicron        bryanh       bryanh
 omicron        ann          ann
-# bob has username robert on these machines
+# bob has user name robert on these machines
 omicron        robert       bob
 # bryanh can also connect as guest1
 omicron        bryanh       guest1
@@ -799,30 +750,30 @@ omicron        bryanh       guest1
 
    
 
-No pg_hba.conf entry for host 123.123.123.123, user joeblow, database testdb
+No pg_hba.conf entry for host 123.123.123.123, user andym, database testdb
 
-    This is what you are most likely to get if you succeed in
-    contacting the server, but it does not want to talk to you. As the
-    message suggests, the server refused the connection request
-    because it found no authorizing entry in its pg_hba.conf
+    This is what you are most likely to get if you succeed in contacting
+    the server, but it does not want to talk to you. As the message
+    suggests, the server refused the connection request because it found
+    no authorizing entry in its pg_hba.conf
     configuration file.
    
 
    
 
-Password authentication failed for user 'joeblow'
+Password authentication failed for user 'andym'
 
-    Messages like this indicate that you contacted the server, and
-    it is willing to talk to you, but not until you pass the
-    authorization method specified in the
-    pg_hba.conf file. Check the password you are
-    providing, or check your Kerberos or ident software if the
-    complaint mentions one of those authentication types.
+    Messages like this indicate that you contacted the server, and it is
+    willing to talk to you, but not until you pass the authorization
+    method specified in the pg_hba.conf file. Check
+    the password you are providing, or check your Kerberos or ident
+    software if the complaint mentions one of those authentication
+    types.
    
 
    
 
-FATAL 1:  user "joeblow" does not exist
+FATAL 1:  user "andym" does not exist
 
     The indicated user name was not found.
    
@@ -837,9 +788,9 @@ FATAL 1:  Database "testdb" does not exist in the system catalog.
    
 
    
-    Note that the server log may contain more information
-    about an authentication failure than is reported to the client.
-    If you are confused about the reason for a failure, check the log.
+    Note that the server log may contain more information about an
+    authentication failure than is reported to the client. If you are
+    confused about the reason for a failure, check the log.
    
   
 
index 460f150bc893036958acdb73a91d626e2d3d5c8b..61d979a56437b6341730285f8bd8a060b4771c49 100644 (file)
@@ -1,5 +1,5 @@
 
@@ -125,7 +125,6 @@ Complete list of usable sgml source files in this directory.
 
 
 
-
 
 
 
diff --git a/doc/src/sgml/ref/pg_passwd.sgml b/doc/src/sgml/ref/pg_passwd.sgml
deleted file mode 100644 (file)
index 13125b0..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-
-
-
-  2000-11-18
-
-  pg_passwd
-  1
-  Application
-
-  pg_passwd
-  change a secondary PostgreSQL password file
-
-  
-   pg_passwd
-   filename
-  
-
-  Description
-  
-   pg_passwd is a tool for manipulating flat
-   text password files. These files can control client authentication of
-   the PostgreSQL server. More information
-   about setting up this authentication mechanism can be found in the
-   Administrator's Guide.
-  
-
-  
-   The format of a text password file is one entry per line; the fields
-   of each entry are separated by colons. The first field is the user
-   name, the second field is the encrypted password. Other fields are
-   ignored (to allow password files to be shared between applications
-   that use similar formats). pg_passwd
-   enables users to interactively add entries to such a file, to alter
-   passwords of existing entries, and to encrypt such passwords.
-  
-
-  
-   Supply the name of the password file as argument to the
-   pg_passwd command. To be used by
-   PostgreSQL, the file needs to be located in the server's data
-   directory, and the base name of the file needs to be specified in the
-   pg_hba.conf access control file.
-
-
-$ pg_passwd /usr/local/pgsql/data/passwords
-File "/usr/local/pgsql/data/passwords" does not exist.  Create? (y/n): y
-Username: guest
-Password:
-Re-enter password:
-
-
-   where the Password: and Re-enter
-   password: prompts require the same password input which
-   is not displayed on the terminal.  Note that the password is limited
-   to eight useful characters by restrictions of the standard crypt(3)
-   library routine.
-  
-
-  
-   The original password file is renamed to
-   passwords.bk.
-  
-
-  
-   To make use of this password file, put a line like the following in
-   pg_hba.conf:
-
-
-host  mydb     133.65.96.250   255.255.255.255 password passwords
-
-
-   which would allow access to database mydb from host 133.65.96.250 using
-   the passwords listed in the passwords file (and
-   only to the users listed in that file).
-  
-
-  
-   
-    It is also useful to have entries in a password file with empty
-    password fields. (This is different from an empty password.) Such
-    entries allow you to restrict users who can access the system. These
-    entries cannot be managed by pg_passwd,
-    but you can edit password files manually.
-   
-  
-
-  See also
-  
-   PostgreSQL Administrator's Guide
-  
-
-
-
index b6b63254462addb3c97992f9fcac129dfc6c19c6..41d419dd2ea2458bb59f5388ddcc4e6aa32aa287 100644 (file)
@@ -1,5 +1,5 @@
 
@@ -191,7 +191,6 @@ Disable this chapter until we have more functions documented.
    &initlocation;
    &ipcclean;
    &pgCtl;
-   &pgPasswd;
    &postgres;
    &postmaster;
 
index 98ee43089751bb21ea6b73e4ee6e8657ee692719..9ebd6fa3a2dc69f6532f6f88ac4a9b8805b7006c 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.94 2002/03/26 19:15:48 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.95 2002/04/04 04:25:45 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "access/heapam.h"
@@ -27,6 +28,7 @@
 #include "libpq/crypt.h"
 #include "miscadmin.h"
 #include "storage/pmsignal.h"
+#include "utils/acl.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
@@ -39,8 +41,205 @@ extern bool Password_encryption;
 
 static void CheckPgUserAclNotNull(void);
 
-/*---------------------------------------------------------------------
- * write_password_file / update_pg_pwd
+
+
+/*
+ * fputs_quote
+ *
+ * Outputs string in quotes, with double-quotes duplicated.
+ * We could use quote_ident(), but that expects varlena.
+ */
+static void fputs_quote(char *str, FILE *fp)
+{
+   fputc('"', fp);
+   while (*str)
+   {
+       fputc(*str, fp);
+       if (*str == '"')
+           fputc('"', fp);
+       str++;
+   }
+   fputc('"', fp);
+}
+
+
+
+/*
+ * group_getfilename --- get full pathname of group file
+ *
+ * Note that result string is palloc'd, and should be freed by the caller.
+ */
+char *
+group_getfilename(void)
+{
+   int         bufsize;
+   char       *pfnam;
+
+   bufsize = strlen(DataDir) + strlen("/global/") +
+             strlen(USER_GROUP_FILE) + 1;
+   pfnam = (char *) palloc(bufsize);
+   snprintf(pfnam, bufsize, "%s/global/%s", DataDir, USER_GROUP_FILE);
+
+   return pfnam;
+}
+
+
+
+/*
+ * Get full pathname of password file.
+ * Note that result string is palloc'd, and should be freed by the caller.
+ */
+char *
+user_getfilename(void)
+{
+   int         bufsize;
+   char       *pfnam;
+
+   bufsize = strlen(DataDir) + strlen("/global/") +
+             strlen(PWD_FILE) + 1;
+   pfnam = (char *) palloc(bufsize);
+   snprintf(pfnam, bufsize, "%s/global/%s", DataDir, PWD_FILE);
+
+   return pfnam;
+}
+
+
+
+/*
+ * write_group_file for trigger update_pg_pwd_and_pg_group
+ */
+static void
+write_group_file(Relation urel, Relation grel)
+{
+   char       *filename,
+              *tempname;
+   int         bufsize;
+   FILE       *fp;
+   mode_t      oumask;
+   HeapScanDesc scan;
+   HeapTuple   tuple;
+   TupleDesc   dsc = RelationGetDescr(grel);
+
+   /*
+    * Create a temporary filename to be renamed later.  This prevents the
+    * backend from clobbering the pg_group file while the postmaster might
+    * be reading from it.
+    */
+   filename = group_getfilename();
+   bufsize = strlen(filename) + 12;
+   tempname = (char *) palloc(bufsize);
+
+   snprintf(tempname, bufsize, "%s.%d", filename, MyProcPid);
+   oumask = umask((mode_t) 077);
+   fp = AllocateFile(tempname, "w");
+   umask(oumask);
+   if (fp == NULL)
+       elog(ERROR, "write_group_file: unable to write %s: %m", tempname);
+
+   /* read table */
+   scan = heap_beginscan(grel, false, SnapshotSelf, 0, NULL);
+   while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
+   {
+       Datum       datum, grolist_datum;
+       bool        isnull;
+       char       *groname;
+       IdList     *grolist_p;
+       AclId      *aidp;
+       int         i, j,
+                   num;
+       char       *usename;
+       bool        first_user = true;
+
+       datum = heap_getattr(tuple, Anum_pg_group_groname, dsc, &isnull);
+       if (isnull)
+           continue;           /* ignore NULL groupnames */
+       groname = (char *) DatumGetName(datum);
+
+       grolist_datum = heap_getattr(tuple, Anum_pg_group_grolist, dsc, &isnull);
+       /* Ignore NULL group lists */
+       if (isnull)
+           continue;
+
+       grolist_p = DatumGetIdListP(grolist_datum);
+       /*
+        * Check for illegal characters in the group name.
+        */
+       i = strcspn(groname, "\n");
+       if (groname[i] != '\0')
+       {
+           elog(LOG, "Invalid group name '%s'", groname);
+           continue;
+       }
+
+       /* be sure the IdList is not toasted */
+       /* scan it */
+       num = IDLIST_NUM(grolist_p);
+       aidp = IDLIST_DAT(grolist_p);
+       for (i = 0; i < num; ++i)
+       {
+           tuple = SearchSysCache(SHADOWSYSID,
+                                  PointerGetDatum(aidp[i]),
+                                  0, 0, 0);
+           if (HeapTupleIsValid(tuple))
+           {
+               usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
+
+               /*
+                * Check for illegal characters in the user name.
+                */
+               j = strcspn(usename, "\n");
+               if (usename[j] != '\0')
+               {
+                   elog(LOG, "Invalid user name '%s'", usename);
+                   continue;
+               }
+
+               /* File format is:
+                *      "dbname"    "user1","user2","user3"
+                * This matches pg_hba.conf.
+                */
+               if (first_user)
+               {
+                   fputs_quote(groname, fp);
+                   fputs("\t", fp);
+               }
+               else
+                   fputs(" ", fp);
+
+               first_user = false;
+               fputs_quote(usename, fp);
+
+               ReleaseSysCache(tuple);
+           }
+       }
+       if (!first_user)
+           fputs("\n", fp);
+       /* if IdList was toasted, free detoasted copy */
+       if ((Pointer) grolist_p != DatumGetPointer(grolist_datum))
+           pfree(grolist_p);
+   }
+   heap_endscan(scan);
+
+   fflush(fp);
+   if (ferror(fp))
+       elog(ERROR, "%s: %m", tempname);
+   FreeFile(fp);
+
+   /*
+    * Rename the temp file to its final name, deleting the old pg_pwd. We
+    * expect that rename(2) is an atomic action.
+    */
+   if (rename(tempname, filename))
+       elog(ERROR, "rename %s to %s: %m", tempname, filename);
+
+   pfree((void *) tempname);
+   pfree((void *) filename);
+}
+
+
+
+/*
+ * write_password_file for trigger update_pg_pwd_and_pg_group
  *
  * copy the modified contents of pg_shadow to a file used by the postmaster
  * for user authentication.  The file is stored as $PGDATA/global/pg_pwd.
@@ -51,10 +250,9 @@ static void CheckPgUserAclNotNull(void);
  * We raise an error to force transaction rollback if we detect an illegal
  * username or password --- illegal being defined as values that would
  * mess up the pg_pwd parser.
- *---------------------------------------------------------------------
  */
 static void
-write_password_file(Relation rel)
+write_user_file(Relation urel)
 {
    char       *filename,
               *tempname;
@@ -63,14 +261,14 @@ write_password_file(Relation rel)
    mode_t      oumask;
    HeapScanDesc scan;
    HeapTuple   tuple;
-   TupleDesc   dsc = RelationGetDescr(rel);
+   TupleDesc   dsc = RelationGetDescr(urel);
 
    /*
     * Create a temporary filename to be renamed later.  This prevents the
     * backend from clobbering the pg_pwd file while the postmaster might
     * be reading from it.
     */
-   filename = crypt_getpwdfilename();
+   filename = user_getfilename();
    bufsize = strlen(filename) + 12;
    tempname = (char *) palloc(bufsize);
 
@@ -82,26 +280,22 @@ write_password_file(Relation rel)
        elog(ERROR, "write_password_file: unable to write %s: %m", tempname);
 
    /* read table */
-   scan = heap_beginscan(rel, false, SnapshotSelf, 0, NULL);
+   scan = heap_beginscan(urel, 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;
-       char       *str_n,
-                  *str_p,
-                  *str_v;
+       Datum       datum;
+       bool        isnull;
+       char       *usename,
+                  *passwd,
+                  *valuntil;
        int         i;
 
-       datum_n = heap_getattr(tuple, Anum_pg_shadow_usename, dsc, &null_n);
-       if (null_n)
+       datum = heap_getattr(tuple, Anum_pg_shadow_usename, dsc, &isnull);
+       if (isnull)
            continue;           /* ignore NULL usernames */
-       str_n = DatumGetCString(DirectFunctionCall1(nameout, datum_n));
+       usename = (char *) DatumGetName(datum);
 
-       datum_p = heap_getattr(tuple, Anum_pg_shadow_passwd, dsc, &null_p);
+       datum = heap_getattr(tuple, Anum_pg_shadow_passwd, dsc, &isnull);
 
        /*
         * It can be argued that people having a null password shouldn't
@@ -110,57 +304,40 @@ write_password_file(Relation rel)
         * assuming an empty password in that case is better, change this
         * logic to look something like the code for valuntil.
         */
-       if (null_p)
-       {
-           pfree(str_n);
+       if (isnull)
            continue;
-       }
-       str_p = DatumGetCString(DirectFunctionCall1(textout, datum_p));
 
-       datum_v = heap_getattr(tuple, Anum_pg_shadow_valuntil, dsc, &null_v);
-       if (null_v)
-           str_v = pstrdup("\\N");
+       passwd = DatumGetCString(DirectFunctionCall1(textout, datum));
+
+       datum = heap_getattr(tuple, Anum_pg_shadow_valuntil, dsc, &isnull);
+       if (isnull)
+           valuntil = pstrdup("");
        else
-           str_v = DatumGetCString(DirectFunctionCall1(nabstimeout, datum_v));
+           valuntil = DatumGetCString(DirectFunctionCall1(nabstimeout, datum));
 
        /*
         * Check for illegal characters in the username and password.
         */
-       i = strcspn(str_n, CRYPT_PWD_FILE_SEPSTR "\n");
-       if (str_n[i] != '\0')
-           elog(ERROR, "Invalid user name '%s'", str_n);
-       i = strcspn(str_p, CRYPT_PWD_FILE_SEPSTR "\n");
-       if (str_p[i] != '\0')
-           elog(ERROR, "Invalid user password '%s'", str_p);
+       i = strcspn(usename, "\n");
+       if (usename[i] != '\0')
+           elog(ERROR, "Invalid user name '%s'", usename);
+       i = strcspn(passwd, "\n");
+       if (passwd[i] != '\0')
+           elog(ERROR, "Invalid user password '%s'", passwd);
 
        /*
         * The extra columns we emit here are not really necessary. To
         * remove them, the parser in backend/libpq/crypt.c would need to
         * be adjusted.
         */
-       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",
-               str_n,
-               str_p,
-               str_v);
-
-       pfree(str_n);
-       pfree(str_p);
-       pfree(str_v);
+       fputs_quote(usename, fp);
+       fputs(" ", fp);
+       fputs_quote(passwd, fp);
+       fputs(" ", fp);
+       fputs_quote(valuntil, fp);
+
+       pfree(passwd);
+       pfree(valuntil);
    }
    heap_endscan(scan);
 
@@ -178,29 +355,33 @@ write_password_file(Relation rel)
 
    pfree((void *) tempname);
    pfree((void *) filename);
-
-   /*
-    * Signal the postmaster to reload its password-file cache.
-    */
-   SendPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE);
 }
 
 
 
 /* This is the wrapper for triggers. */
 Datum
-update_pg_pwd(PG_FUNCTION_ARGS)
+update_pg_pwd_and_pg_group(PG_FUNCTION_ARGS)
 {
    /*
     * ExclusiveLock ensures no one modifies pg_shadow while we read it,
     * and that only one backend rewrites the flat file at a time.  It's
     * OK to allow normal reads of pg_shadow in parallel, however.
     */
-   Relation    rel = heap_openr(ShadowRelationName, ExclusiveLock);
+   Relation    urel = heap_openr(ShadowRelationName, ExclusiveLock);
+   Relation    grel = heap_openr(GroupRelationName, ExclusiveLock);
 
-   write_password_file(rel);
+   write_user_file(urel);
+   write_group_file(urel, grel);
    /* OK to release lock, since we did not modify the relation */
-   heap_close(rel, ExclusiveLock);
+   heap_close(grel, ExclusiveLock);
+   heap_close(urel, ExclusiveLock);
+
+   /*
+    * Signal the postmaster to reload its password & group-file cache.
+    */
+   SendPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE);
+
    return PointerGetDatum(NULL);
 }
 
@@ -446,14 +627,14 @@ CreateUser(CreateUserStmt *stmt)
    }
 
    /*
-    * Write the updated pg_shadow data to the flat password file.
+    * Now we can clean up; but keep lock until commit.
     */
-   write_password_file(pg_shadow_rel);
+   heap_close(pg_shadow_rel, NoLock);
 
    /*
-    * Now we can clean up; but keep lock until commit.
+    * Write the updated pg_shadow and pg_group data to the flat file.
     */
-   heap_close(pg_shadow_rel, NoLock);
+   update_pg_pwd_and_pg_group(NULL);
 }
 
 
@@ -680,14 +861,14 @@ AlterUser(AlterUserStmt *stmt)
    heap_freetuple(new_tuple);
 
    /*
-    * Write the updated pg_shadow data to the flat password file.
+    * Now we can clean up.
     */
-   write_password_file(pg_shadow_rel);
+   heap_close(pg_shadow_rel, NoLock);
 
    /*
-    * Now we can clean up.
+    * Write the updated pg_shadow and pg_group data to the flat file.
     */
-   heap_close(pg_shadow_rel, NoLock);
+   update_pg_pwd_and_pg_group(NULL);
 }
 
 
@@ -733,7 +914,7 @@ AlterUserSet(AlterUserSetStmt *stmt)
    {
        Datum datum;
        bool isnull;
-       ArrayType *a;
+       ArrayType *array;
 
        repl_null[Anum_pg_shadow_useconfig-1] = ' ';
 
@@ -741,17 +922,17 @@ AlterUserSet(AlterUserSetStmt *stmt)
                                Anum_pg_shadow_useconfig, &isnull);
 
        if (valuestr)
-           a = GUCArrayAdd(isnull
+           array = GUCArrayAdd(isnull
                            ? NULL
                            : (ArrayType *) pg_detoast_datum((struct varlena *)datum),
                            stmt->variable, valuestr);
        else
-           a = GUCArrayDelete(isnull
+           array = GUCArrayDelete(isnull
                               ? NULL
                               : (ArrayType *) pg_detoast_datum((struct varlena *)datum),
                               stmt->variable);
 
-       repl_val[Anum_pg_shadow_useconfig-1] = PointerGetDatum(a);
+       repl_val[Anum_pg_shadow_useconfig-1] = PointerGetDatum(array);
    }
 
    newtuple = heap_modifytuple(oldtuple, rel, repl_val, repl_null, repl_repl);
@@ -846,7 +1027,7 @@ DropUser(DropUserStmt *stmt)
            datum = heap_getattr(tmp_tuple, Anum_pg_database_datname,
                                 pg_dsc, &null);
            Assert(!null);
-           dbname = DatumGetCString(DirectFunctionCall1(nameout, datum));
+           dbname = (char *) DatumGetName(datum);
            elog(ERROR, "DROP USER: user \"%s\" owns database \"%s\", cannot be removed%s",
                 user, dbname,
                 (length(stmt->users) > 1) ? " (no users removed)" : "");
@@ -901,14 +1082,14 @@ DropUser(DropUserStmt *stmt)
    }
 
    /*
-    * Write the updated pg_shadow data to the flat password file.
+    * Now we can clean up.
     */
-   write_password_file(pg_shadow_rel);
+   heap_close(pg_shadow_rel, NoLock);
 
    /*
-    * Now we can clean up.
+    * Write the updated pg_shadow and pg_group data to the flat file.
     */
-   heap_close(pg_shadow_rel, NoLock);
+   update_pg_pwd_and_pg_group(NULL);
 }
 
 
@@ -1111,6 +1292,11 @@ CreateGroup(CreateGroupStmt *stmt)
    }
 
    heap_close(pg_group_rel, NoLock);
+
+   /*
+    * Write the updated pg_shadow and pg_group data to the flat file.
+    */
+   update_pg_pwd_and_pg_group(NULL);
 }
 
 
@@ -1366,7 +1552,15 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag)
 
    ReleaseSysCache(group_tuple);
 
+   /*
+    * Write the updated pg_shadow and pg_group data to the flat files.
+    */
    heap_close(pg_group_rel, NoLock);
+
+   /*
+    * Write the updated pg_shadow and pg_group data to the flat file.
+    */
+   update_pg_pwd_and_pg_group(NULL);
 }
 
 
@@ -1419,4 +1613,9 @@ DropGroup(DropGroupStmt *stmt)
        elog(ERROR, "DROP GROUP: group \"%s\" does not exist", stmt->name);
 
    heap_close(pg_group_rel, NoLock);
+
+   /*
+    * Write the updated pg_shadow and pg_group data to the flat file.
+    */
+   update_pg_pwd_and_pg_group(NULL);
 }
index f5c2339f1c32643e93bf424cb5950daa13f98656..d0f05e802d998a70669167c1560674b3a4f7c4e9 100644 (file)
@@ -4,7 +4,7 @@
 #    Makefile for libpq subsystem (backend half of libpq interface)
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.29 2002/03/04 01:46:02 tgl Exp $
+#    $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.30 2002/04/04 04:25:46 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -14,9 +14,7 @@ include $(top_builddir)/src/Makefile.global
 
 # be-fsstubs is here for historical reasons, probably belongs elsewhere
 
-OBJS = be-fsstubs.o \
-   auth.o crypt.o hba.o md5.o password.o \
-   pqcomm.o pqformat.o pqsignal.o
+OBJS = be-fsstubs.o auth.o crypt.o hba.o md5.o pqcomm.o pqformat.o pqsignal.o
 
 
 all: SUBSYS.o
index 637e2a623ebe0d0c694ad10a72e04c7054c82ab0..81a494905eaeeedc7169fdcc1be0ecf6593443fe 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.79 2002/03/05 07:57:45 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.80 2002/04/04 04:25:47 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,7 +34,6 @@
 #include "miscadmin.h"
 
 static void sendAuthRequest(Port *port, AuthRequest areq);
-static int checkPassword(Port *port, char *user, char *password);
 static int old_be_recvauth(Port *port);
 static int map_old_to_new(Port *port, UserAuth old, int status);
 static void auth_failed(Port *port, int status);
@@ -381,7 +380,7 @@ recv_and_check_passwordv0(Port *port)
        saved = port->auth_method;
        port->auth_method = uaPassword;
 
-       status = checkPassword(port, user, password);
+       status = md5_crypt_verify(port, user, password);
 
        port->auth_method = saved;
 
@@ -663,7 +662,7 @@ pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_re
 
        initStringInfo(&buf);
        pq_getstr(&buf);
-       
+
        /* Do not echo failed password to logs, for security. */
        elog(DEBUG5, "received PAM packet");
 
@@ -810,26 +809,13 @@ recv_and_check_password_packet(Port *port)
    /* Do not echo failed password to logs, for security. */
    elog(DEBUG5, "received password packet");
 
-   result = checkPassword(port, port->user, buf.data);
+   result = md5_crypt_verify(port, port->user, buf.data);
+
    pfree(buf.data);
    return result;
 }
 
 
-/*
- * Handle `password' and `crypt' records. If an auth argument was
- * specified, use the respective file. Else use pg_shadow passwords.
- */
-static int
-checkPassword(Port *port, char *user, char *password)
-{
-   if (port->auth_arg[0] != '\0')
-       return verify_password(port, user, password);
-
-   return md5_crypt_verify(port, user, password);
-}
-
-
 /*
  * Server demux routine for incoming authentication information for protocol
  * version 0.
index 6ab63ddffe0c7d44b18764d85ce0856eff745e34..7c665300c85ef285cd5c6aea58c16868db5647dc 100644 (file)
@@ -9,13 +9,12 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.44 2002/03/04 01:46:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.45 2002/04/04 04:25:47 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
-#include 
 #include 
 #ifdef HAVE_CRYPT_H
 #include 
 #include "libpq/libpq.h"
 #include "miscadmin.h"
 #include "storage/fd.h"
+#include "nodes/pg_list.h"
 #include "utils/nabstime.h"
 
 
-#define CRYPT_PWD_FILE "pg_pwd"
-
-
-static char **pwd_cache = NULL;
-static int pwd_cache_count = 0;
-
-/*
- * crypt_getpwdfilename --- get full pathname of password file
- *
- * Note that result string is palloc'd, and should be freed by the caller.
- */
-char *
-crypt_getpwdfilename(void)
-{
-   int         bufsize;
-   char       *pfnam;
-
-   bufsize = strlen(DataDir) + 8 + strlen(CRYPT_PWD_FILE) + 1;
-   pfnam = (char *) palloc(bufsize);
-   snprintf(pfnam, bufsize, "%s/global/%s", DataDir, CRYPT_PWD_FILE);
-
-   return pfnam;
-}
-
-/*
- * Open the password file if possible (return NULL if not)
- */
-static FILE *
-crypt_openpwdfile(void)
-{
-   char       *filename;
-   FILE       *pwdfile;
-
-   filename = crypt_getpwdfilename();
-   pwdfile = AllocateFile(filename, "r");
-
-   if (pwdfile == NULL && errno != ENOENT)
-       elog(LOG, "could not open %s: %m", filename);
-
-   pfree(filename);
-
-   return pwdfile;
-}
-
-/*
- * Compare two password-file lines on the basis of their usernames.
- *
- * Can also be used to compare just a username against a password-file
- * line (for bsearch).
- */
-static int
-compar_user(const void *user_a, const void *user_b)
-{
-   char       *login_a;
-   char       *login_b;
-   int         len_a,
-               len_b,
-               result;
-
-   login_a = *((char **) user_a);
-   login_b = *((char **) user_b);
-
-   /*
-    * We only really want to compare the user logins which are first and
-    * are terminated by CRYPT_PWD_FILE_SEPSTR.  (NB: this code
-    * effectively assumes that CRYPT_PWD_FILE_SEPSTR is just one char.)
-    */
-   len_a = strcspn(login_a, CRYPT_PWD_FILE_SEPSTR);
-   len_b = strcspn(login_b, CRYPT_PWD_FILE_SEPSTR);
-
-   result = strncmp(login_a, login_b, Min(len_a, len_b));
-
-   if (result == 0)            /* one could be a prefix of the other */
-       result = (len_a - len_b);
-
-   return result;
-}
-
-/*
- * Load or reload the password-file cache
- */
-void
-load_password_cache(void)
-{
-   FILE       *pwd_file;
-   char        buffer[1024];
-
-   /*
-    * If for some reason we fail to open the password file, preserve the
-    * old cache contents; this seems better than dropping the cache if,
-    * say, we are temporarily out of filetable slots.
-    */
-   if (!(pwd_file = crypt_openpwdfile()))
-       return;
-
-   /* free any old data */
-   if (pwd_cache)
-   {
-       while (--pwd_cache_count >= 0)
-           pfree(pwd_cache[pwd_cache_count]);
-       pfree(pwd_cache);
-       pwd_cache = NULL;
-       pwd_cache_count = 0;
-   }
-
-   /*
-    * Read the file and store its lines in current memory context, which
-    * we expect will be PostmasterContext.  That context will live as
-    * long as we need the cache to live, ie, until just after each
-    * postmaster child has completed client authentication.
-    */
-   while (fgets(buffer, sizeof(buffer), pwd_file) != NULL)
-   {
-       int         blen;
-
-       /*
-        * We must remove the return char at the end of the string, as
-        * this will affect the correct parsing of the password entry.
-        */
-       if (buffer[(blen = strlen(buffer) - 1)] == '\n')
-           buffer[blen] = '\0';
-
-       if (pwd_cache == NULL)
-           pwd_cache = (char **)
-               palloc(sizeof(char *) * (pwd_cache_count + 1));
-       else
-           pwd_cache = (char **)
-               repalloc((void *) pwd_cache,
-                        sizeof(char *) * (pwd_cache_count + 1));
-       pwd_cache[pwd_cache_count++] = pstrdup(buffer);
-   }
-
-   FreeFile(pwd_file);
-
-   /*
-    * Now sort the entries in the cache for faster searching later.
-    */
-   qsort((void *) pwd_cache, pwd_cache_count, sizeof(char *), compar_user);
-}
-
-/*
- * Parse a line of the password file to extract password and valid-until date.
- */
-static bool
-crypt_parsepwdentry(char *buffer, char **pwd, char **valdate)
-{
-   char       *parse = buffer;
-   int         count,
-               i;
-
-   *pwd = NULL;
-   *valdate = NULL;
-
-   /*
-    * skip to the password field
-    */
-   for (i = 0; i < 6; i++)
-   {
-       parse += strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
-       if (*parse == '\0')
-           return false;
-       parse++;
-   }
-
-   /*
-    * store a copy of user password to return
-    */
-   count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
-   *pwd = (char *) palloc(count + 1);
-   memcpy(*pwd, parse, count);
-   (*pwd)[count] = '\0';
-   parse += count;
-   if (*parse == '\0')
-   {
-       pfree(*pwd);
-       *pwd = NULL;
-       return false;
-   }
-   parse++;
-
-   /*
-    * store a copy of the date login becomes invalid
-    */
-   count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
-   *valdate = (char *) palloc(count + 1);
-   memcpy(*valdate, parse, count);
-   (*valdate)[count] = '\0';
-
-   return true;
-}
-
-/*
- * Lookup a username in the password-file cache,
- * return his password and valid-until date.
- */
-static bool
-crypt_getloginfo(const char *user, char **passwd, char **valuntil)
-{
-   *passwd = NULL;
-   *valuntil = NULL;
-
-   if (pwd_cache)
-   {
-       char      **pwd_entry;
-
-       pwd_entry = (char **) bsearch((void *) &user,
-                                     (void *) pwd_cache,
-                                     pwd_cache_count,
-                                     sizeof(char *),
-                                     compar_user);
-       if (pwd_entry)
-       {
-           if (crypt_parsepwdentry(*pwd_entry, passwd, valuntil))
-               return true;
-       }
-   }
-
-   return false;
-}
-
-/*-------------------------------------------------------------------------*/
-
 int
 md5_crypt_verify(const Port *port, const char *user, const char *pgpass)
 {
@@ -257,10 +35,14 @@ md5_crypt_verify(const Port *port, const char *user, const char *pgpass)
               *valuntil,
               *crypt_pwd;
    int         retval = STATUS_ERROR;
+   List       **line;
 
-   if (!crypt_getloginfo(user, &passwd, &valuntil))
+   if ((line = get_user_line(user)) == NULL)
        return STATUS_ERROR;
 
+   passwd = lfirst(lnext(lnext(*line)));
+   valuntil = lfirst(lnext(lnext(lnext(*line))));
+
    if (passwd == NULL || *passwd == '\0')
    {
        if (passwd)
index b86cb817302d443b201fa31bbbe3427246034072..fce63ab2436d721cd7d762f206fbf21db4bd7d9b 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.80 2002/03/04 01:46:03 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.81 2002/04/04 04:25:47 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include 
 #include 
 
+#include "commands/user.h"
+#include "libpq/crypt.h"
 #include "libpq/libpq.h"
 #include "miscadmin.h"
 #include "nodes/pg_list.h"
 #include "storage/fd.h"
 
 
-#define MAX_TOKEN 80
-/* Maximum size of one token in the configuration file */
-
 #define IDENT_USERNAME_MAX 512
 /* Max size of username ident server can return */
 
+/* This is used to separate values in multi-valued column strings */
+#define MULTI_VALUE_SEP    "\001"
+
 /*
  * These variables hold the pre-parsed contents of the hba and ident
  * configuration files.  Each is a list of sublists, one sublist for
  */
 static List *hba_lines = NIL;  /* pre-parsed contents of hba file */
 static List *ident_lines = NIL; /* pre-parsed contents of ident file */
+static List *group_lines = NIL;    /* pre-parsed contents of group file */
+static List *user_lines = NIL; /* pre-parsed contents of user password file */
+
+/* sorted entries so we can do binary search lookups */
+static List **user_sorted = NULL;  /* sorted user list, for bsearch() */
+static List **group_sorted = NULL; /* sorted group list, for bsearch() */
+static int  user_length;
+static int  group_length;
 
+static List *tokenize_file(FILE *file);
+static char *tokenize_inc_file(const char *inc_filename);
 
 /*
  * Some standard C libraries, including GNU, have an isblank() function.
@@ -67,41 +79,76 @@ isblank(const char c)
 
 
 /*
- * Grab one token out of fp.  Tokens are strings of non-blank
- * characters bounded by blank characters, beginning of line, and end
- * of line.    Blank means space or tab.  Return the token as *buf.
- * Leave file positioned to character immediately after the token or
- * EOF, whichever comes first.  If no more tokens on line, return null
- * string as *buf and position file to beginning of next line or EOF,
- * whichever comes first.
+ *   Grab one token out of fp. Tokens are strings of non-blank
+ *   characters bounded by blank characters, beginning of line, and
+ *   end of line. Blank means space or tab. Return the token as
+ *   *buf. Leave file positioned to character immediately after the
+ *   token or EOF, whichever comes first. If no more tokens on line,
+ *   return null string as *buf and position file to beginning of
+ *   next line or EOF, whichever comes first. Allow spaces in quoted
+ *   strings. Terminate on unquoted commas. Handle comments.
  */
-static void
+void
 next_token(FILE *fp, char *buf, const int bufsz)
 {
    int         c;
-   char       *eb = buf + (bufsz - 1);
+   char       *end_buf = buf + (bufsz - 1);
+   bool        in_quote = false;
+   bool        was_quote = false;
 
-   /* Move over initial token-delimiting blanks */
-   while ((c = getc(fp)) != EOF && isblank(c))
+   /* Move over initial whitespace and commas */
+   while ((c = getc(fp)) != EOF && (isblank(c) || c == ','))
        ;
 
    if (c != EOF && c != '\n')
    {
        /*
-        * build a token in buf of next characters up to EOF, eol, or
-        * blank.  If the token gets too long, we still parse it
-        * correctly, but the excess characters are not stored into *buf.
+        * Build a token in buf of next characters up to EOF, EOL, unquoted
+        * comma, or unquoted whitespace.
         */
-       while (c != EOF && c != '\n' && !isblank(c))
+       while (c != EOF && c != '\n' &&
+              (!isblank(c) || in_quote == true))
        {
-           if (buf < eb)
+           if (c == '"')
+               in_quote = !in_quote;
+
+           /* skip comments to EOL */
+           if (c == '#' && !in_quote)
+           {
+               while ((c = getc(fp)) != EOF && c != '\n')
+                   ;
+               continue;
+           }
+
+           if (buf >= end_buf)
+           {
+               elog(LOG, "Token too long in authentication file, skipping, %s", buf);
+               /* Discard remainder of line */
+               while ((c = getc(fp)) != EOF && c != '\n')
+                   ;
+               buf[0] = '\0';
+               break;
+           }
+
+           if (c != '"' || (c == '"' && was_quote))
                *buf++ = c;
+
+           /* We pass back the comma so the caller knows there is more */
+           if ((isblank(c) || c == ',') && !in_quote)
+               break;
+
+           /* Literal double-quote is two double-quotes */
+           if (c == '"')
+               was_quote = !was_quote;
+           else
+               was_quote = false;
+
            c = getc(fp);
        }
 
        /*
         * Put back the char right after the token (critical in case it is
-        * eol, since we need to detect end-of-line at next call).
+        * EOL, since we need to detect end-of-line at next call).
         */
        if (c != EOF)
            ungetc(c, fp);
@@ -109,17 +156,142 @@ next_token(FILE *fp, char *buf, const int bufsz)
    *buf = '\0';
 }
 
+/*
+ *   Tokenize file and handle file inclusion and comma lists. We have
+ *   to  break  apart  the  commas  to  expand  any  file names then
+ *   reconstruct with commas.
+ */
+static char *
+next_token_expand(FILE *file)
+{
+   char        buf[MAX_TOKEN];
+   char       *comma_str = pstrdup("");
+   bool        trailing_comma;
+   char       *incbuf;
+
+   do
+   {
+       next_token(file, buf, sizeof(buf));
+       if (!*buf)
+           break;
+
+       if (buf[strlen(buf)-1] == ',')
+       {
+           trailing_comma = true;
+           buf[strlen(buf)-1] = '\0';
+       }
+       else
+           trailing_comma = false;
+
+       /* Is this referencing a file? */
+       if (buf[0] == '@')
+           incbuf = tokenize_inc_file(buf+1);
+       else
+           incbuf = pstrdup(buf);
+
+       comma_str = repalloc(comma_str,
+                            strlen(comma_str) + strlen(incbuf) + 1);
+       strcat(comma_str, incbuf);
+       pfree(incbuf);
+
+       if (trailing_comma)
+       {
+           comma_str = repalloc(comma_str, strlen(comma_str) + 1 + 1);
+           strcat(comma_str, MULTI_VALUE_SEP);
+       }
+   } while (trailing_comma);
+
+   return comma_str;
+}
+
 
+/*
+ * Free memory used by lines/tokens (i.e., structure built by tokenize_file)
+ */
 static void
-read_through_eol(FILE *file)
+free_lines(List **lines)
 {
-   int         c;
+   if (*lines)
+   {
+       List       *line,
+                  *token;
 
-   while ((c = getc(file)) != EOF && c != '\n')
-       ;
+       foreach(line, *lines)
+       {
+           List       *ln = lfirst(line);
+
+           /* free the pstrdup'd tokens (don't try it on the line number) */
+           foreach(token, lnext(ln))
+               pfree(lfirst(token));
+           /* free the sublist structure itself */
+           freeList(ln);
+       }
+       /* free the list structure itself */
+       freeList(*lines);
+       /* clear the static variable */
+       *lines = NIL;
+   }
+}
+
+
+static char *
+tokenize_inc_file(const char *inc_filename)
+{
+   char       *inc_fullname;
+   FILE       *inc_file;
+   List       *inc_lines;
+   List       *line;
+   char       *comma_str = pstrdup("");
+
+   inc_fullname = (char *) palloc(strlen(DataDir) + 1 +
+                                  strlen(inc_filename) + 1);
+   strcpy(inc_fullname, DataDir);
+   strcat(inc_fullname, "/");
+   strcat(inc_fullname, inc_filename);
+
+   inc_file = AllocateFile(inc_fullname, "r");
+   if (!inc_file)
+   {
+       elog(LOG, "tokenize_inc_file: Unable to open secondary authentication file \"@%s\" as \"%s\": %m",
+            inc_filename, inc_fullname);
+       pfree(inc_fullname);
+
+       /* return empty string, it matches nothing */
+       return pstrdup("");
+   }
+   pfree(inc_fullname);
+
+   /* There is possible recursion here if the file contains @ */
+   inc_lines = tokenize_file(inc_file);
+   FreeFile(inc_file);
+
+   /* Create comma-separate string from List */
+   foreach(line, inc_lines)
+   {
+       List       *ln = lfirst(line);
+       List       *token;
+
+       /* First entry is line number */
+       foreach(token, lnext(ln))
+       {
+           if (strlen(comma_str))
+           {
+               comma_str = repalloc(comma_str, strlen(comma_str) + 1);
+               strcat(comma_str, MULTI_VALUE_SEP);
+           }
+           comma_str = repalloc(comma_str,
+                       strlen(comma_str) + strlen(lfirst(token)) + 1);
+           strcat(comma_str, lfirst(token));
+       }
+   }
+
+   free_lines(&inc_lines);
+
+   return comma_str;
 }
 
 
+
 /*
  * Read the given file and create a list of line sublists.
  */
@@ -129,19 +301,13 @@ tokenize_file(FILE *file)
    List       *lines = NIL;
    List       *next_line = NIL;
    int         line_number = 1;
-   char        buf[MAX_TOKEN];
-   char       *comment_ptr;
+   char       *buf;
 
    while (!feof(file))
    {
-       next_token(file, buf, sizeof(buf));
-
-       /* trim off comment, even if inside a token */
-       comment_ptr = strchr(buf, '#');
-       if (comment_ptr != NULL)
-           *comment_ptr = '\0';
+       buf = next_token_expand(file);
 
-       /* add token to list, unless we are at eol or comment start */
+       /* add token to list, unless we are at EOL or comment start */
        if (buf[0] != '\0')
        {
            if (next_line == NIL)
@@ -151,22 +317,15 @@ tokenize_file(FILE *file)
                lines = lappend(lines, next_line);
            }
            /* append token to current line's list */
-           next_line = lappend(next_line, pstrdup(buf));
+           next_line = lappend(next_line, buf);
        }
        else
        {
-           /* we are at real or logical eol, so force a new line List */
+           /* we are at real or logical EOL, so force a new line List */
            next_line = NIL;
        }
 
-       if (comment_ptr != NULL)
-       {
-           /* Found a comment, so skip the rest of the line */
-           read_through_eol(file);
-           next_line = NIL;
-       }
-
-       /* Advance line number whenever we reach eol */
+       /* Advance line number whenever we reach EOL */
        if (next_line == NIL)
            line_number++;
    }
@@ -176,31 +335,116 @@ tokenize_file(FILE *file)
 
 
 /*
- * Free memory used by lines/tokens (ie, structure built by tokenize_file)
+ * Compare two password-file lines on the basis of their user names.
+ *
+ * Used for qsort() sorting and bsearch() lookup.
  */
-static void
-free_lines(List **lines)
+static int
+user_group_cmp(const void *user, const void *list)
 {
-   if (*lines)
+                       /* first node is line number */
+   char       *user1 = (char *)user;
+   char       *user2 = lfirst(lnext(*(List **)list));
+
+   return strcmp(user1, user2);
+}
+
+
+/*
+ * Lookup a group name in the pg_group file
+ */
+static List **
+get_group_line(const char *group)
+{
+   return (List **) bsearch((void *) group,
+                           (void *) group_sorted,
+                           group_length,
+                           sizeof(List *),
+                           user_group_cmp);
+}
+
+
+/*
+ * Lookup a user name in the pg_shadow file
+ */
+List **
+get_user_line(const char *user)
+{
+   return (List **) bsearch((void *) user,
+                           (void *) user_sorted,
+                           user_length,
+                           sizeof(List *),
+                           user_group_cmp);
+}
+
+
+/*
+ * Check group for a specific user.
+ */
+static int
+check_group(char *group, char *user)
+{
+   List       **line, *l;
+
+   if ((line = get_group_line(group)) != NULL)
    {
-       List       *line,
-                  *token;
+       foreach(l, lnext(lnext(*line)))
+           if (strcmp(lfirst(l), user) == 0)
+               return 1;
+   }
 
-       foreach(line, *lines)
+   return 0;
+}
+
+/*
+ * Check comma user list for a specific user, handle group names.
+ */
+static int
+check_user(char *user, char *param_str)
+{
+   char *tok;
+
+   for (tok = strtok(param_str, MULTI_VALUE_SEP); tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP))
+   {
+       if (tok[0] == '+')
        {
-           List       *ln = lfirst(line);
+           if (check_group(tok+1, user))
+               return 1;
+       }
+       else if (strcmp(tok, user) == 0 ||
+           strcmp(tok, "all") == 0)
+           return 1;
+   }
 
-           /* free the pstrdup'd tokens (don't try it on the line number) */
-           foreach(token, lnext(ln))
-               pfree(lfirst(token));
-           /* free the sublist structure itself */
-           freeList(ln);
+   return 0;
+}
+
+/*
+ * Check to see if db/user combination matches param string.
+ */
+static int
+check_db(char *dbname, char *user, char *param_str)
+{
+   char *tok;
+
+   for (tok = strtok(param_str, MULTI_VALUE_SEP); tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP))
+   {
+       if (strcmp(tok, "all") == 0)
+           return 1;
+       else if (strcmp(tok, "sameuser") == 0)
+       {
+           if (strcmp(dbname, user) == 0)
+               return 1;
        }
-       /* free the list structure itself */
-       freeList(*lines);
-       /* clear the static variable */
-       *lines = NIL;
+       else if (strcmp(tok, "samegroup") == 0)
+       {
+           if (check_group(dbname, user))
+               return 1;
+       }
+       else if (strcmp(tok, dbname) == 0)
+           return 1;
    }
+   return 0;
 }
 
 
@@ -278,6 +522,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
    int         line_number;
    char       *token;
    char       *db;
+   char       *user;
 
    Assert(line != NIL);
    line_number = lfirsti(line);
@@ -293,10 +538,17 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
            goto hba_syntax;
        db = lfirst(line);
 
-       /* Read the rest of the line. */
+       /* Get the user. */
+       line = lnext(line);
+       if (!line)
+           goto hba_syntax;
+       user = lfirst(line);
+
        line = lnext(line);
        if (!line)
            goto hba_syntax;
+
+       /* Read the rest of the line. */
        parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p);
        if (*error_p)
            goto hba_syntax;
@@ -308,15 +560,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
            port->auth_method == uaKrb5)
            goto hba_syntax;
 
-       /*
-        * If this record doesn't match the parameters of the connection
-        * attempt, ignore it.
-        */
-       if ((strcmp(db, port->database) != 0 &&
-            strcmp(db, "all") != 0 &&
-            (strcmp(db, "sameuser") != 0 ||
-             strcmp(port->database, port->user) != 0)) ||
-           port->raddr.sa.sa_family != AF_UNIX)
+       if (port->raddr.sa.sa_family != AF_UNIX)
            return;
    }
    else if (strcmp(token, "host") == 0 || strcmp(token, "hostssl") == 0)
@@ -347,6 +591,12 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
            goto hba_syntax;
        db = lfirst(line);
 
+       /* Get the user. */
+       line = lnext(line);
+       if (!line)
+           goto hba_syntax;
+       user = lfirst(line);
+
        /* Read the IP address field. */
        line = lnext(line);
        if (!line)
@@ -371,21 +621,19 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
        if (*error_p)
            goto hba_syntax;
 
-       /*
-        * If this record doesn't match the parameters of the connection
-        * attempt, ignore it.
-        */
-       if ((strcmp(db, port->database) != 0 &&
-            strcmp(db, "all") != 0 &&
-            (strcmp(db, "sameuser") != 0 ||
-             strcmp(port->database, port->user) != 0)) ||
-           port->raddr.sa.sa_family != AF_INET ||
+       /* Must meet network restrictions */
+       if (port->raddr.sa.sa_family != AF_INET ||
            ((file_ip_addr.s_addr ^ port->raddr.in.sin_addr.s_addr) & mask.s_addr) != 0)
            return;
    }
    else
        goto hba_syntax;
 
+   if (!check_db(port->database, port->user, db))
+       return;
+   if (!check_user(port->user, user))
+       return;
+
    /* Success */
    *found_p = true;
    return;
@@ -430,6 +678,127 @@ check_hba(hbaPort *port)
 }
 
 
+
+/*
+ * Open the group file if possible (return NULL if not)
+ */
+static FILE *
+group_openfile(void)
+{
+   char       *filename;
+   FILE       *groupfile;
+
+   filename = group_getfilename();
+   groupfile = AllocateFile(filename, "r");
+
+   if (groupfile == NULL && errno != ENOENT)
+       elog(LOG, "could not open %s: %m", filename);
+
+   pfree(filename);
+
+   return groupfile;
+}
+
+
+
+/*
+ * Open the password file if possible (return NULL if not)
+ */
+static FILE *
+user_openfile(void)
+{
+   char       *filename;
+   FILE       *pwdfile;
+
+   filename = user_getfilename();
+   pwdfile = AllocateFile(filename, "r");
+
+   if (pwdfile == NULL && errno != ENOENT)
+       elog(LOG, "could not open %s: %m", filename);
+
+   pfree(filename);
+
+   return pwdfile;
+}
+
+
+
+/*
+ *  Load group/user name mapping file
+ */
+void
+load_group()
+{
+   FILE       *group_file;
+   List        *line;
+
+   if (group_lines)
+       free_lines(&group_lines);
+
+   group_file = group_openfile();
+   if (!group_file)
+       return;
+   group_lines = tokenize_file(group_file);
+   FreeFile(group_file);
+
+   /* create sorted lines for binary searching */
+   if (group_sorted)
+       pfree(group_sorted);
+   group_length = length(group_lines);
+   if (group_length)
+   {
+       int i = 0;
+
+       group_sorted = palloc(group_length * sizeof(List *));
+
+       foreach(line, group_lines)
+           group_sorted[i++] = lfirst(line);
+
+       qsort((void *) group_sorted, group_length, sizeof(List *), user_group_cmp);
+   }
+   else
+       group_sorted = NULL;
+}
+
+
+/*
+ *  Load user/password mapping file
+ */
+void
+load_user()
+{
+   FILE       *user_file;
+   List       *line;
+
+   if (user_lines)
+       free_lines(&user_lines);
+
+   user_file = user_openfile();
+   if (!user_file)
+       return;
+   user_lines = tokenize_file(user_file);
+   FreeFile(user_file);
+
+   /* create sorted lines for binary searching */
+   if (user_sorted)
+       pfree(user_sorted);
+   user_length = length(user_lines);
+   if (user_length)
+   {
+       int i = 0;
+
+       user_sorted = palloc(user_length * sizeof(List *));
+
+       foreach(line, user_lines)
+           user_sorted[i++] = lfirst(line);
+
+       qsort((void *) user_sorted, user_length, sizeof(List *), user_group_cmp);
+   }
+   else
+       user_sorted = NULL;
+}
+
+
 /*
  * Read the config file and create a List of Lists of tokens in the file.
  * If we find a file by the old name of the config file (pg_hba), we issue
@@ -437,60 +806,35 @@ check_hba(hbaPort *port)
  * follow directions and just installed his old hba file in the new database
  * system.
  */
-static void
+void
 load_hba(void)
 {
-   int         fd,
-               bufsize;
+   int         bufsize;
    FILE       *file;           /* The config file we have to read */
-   char       *old_conf_file;
+   char       *conf_file;  /* The name of the config file */
 
    if (hba_lines)
        free_lines(&hba_lines);
 
-   /*
-    * The name of old config file that better not exist. Fail if config
-    * file by old name exists. Put together the full pathname to the old
-    * config file.
-    */
-   bufsize = (strlen(DataDir) + strlen(OLD_CONF_FILE) + 2) * sizeof(char);
-   old_conf_file = (char *) palloc(bufsize);
-   snprintf(old_conf_file, bufsize, "%s/%s", DataDir, OLD_CONF_FILE);
+   /* Put together the full pathname to the config file. */
+   bufsize = (strlen(DataDir) + strlen(CONF_FILE) + 2) * sizeof(char);
+   conf_file = (char *) palloc(bufsize);
+   snprintf(conf_file, bufsize, "%s/%s", DataDir, CONF_FILE);
 
-   if ((fd = open(old_conf_file, O_RDONLY | PG_BINARY, 0)) != -1)
+   file = AllocateFile(conf_file, "r");
+   if (file == NULL)
    {
-       /* Old config file exists.  Tell this guy he needs to upgrade. */
-       close(fd);
-       elog(LOG, "A file exists by the name used for host-based authentication "
-            "in prior releases of Postgres (%s).  The name and format of "
-            "the configuration file have changed, so this file should be "
-            "converted.", old_conf_file);
+       /* The open of the config file failed.  */
+       elog(LOG, "load_hba: Unable to open authentication config file \"%s\": %m",
+            conf_file);
+       pfree(conf_file);
    }
    else
    {
-       char       *conf_file;  /* The name of the config file we have to
-                                * read */
-
-       /* put together the full pathname to the config file */
-       bufsize = (strlen(DataDir) + strlen(CONF_FILE) + 2) * sizeof(char);
-       conf_file = (char *) palloc(bufsize);
-       snprintf(conf_file, bufsize, "%s/%s", DataDir, CONF_FILE);
-
-       file = AllocateFile(conf_file, "r");
-       if (file == NULL)
-       {
-           /* The open of the config file failed.  */
-           elog(LOG, "load_hba: Unable to open authentication config file \"%s\": %m",
-                conf_file);
-       }
-       else
-       {
-           hba_lines = tokenize_file(file);
-           FreeFile(file);
-       }
-       pfree(conf_file);
+       hba_lines = tokenize_file(file);
+       FreeFile(file);
    }
-   pfree(old_conf_file);
+   pfree(conf_file);
 }
 
 
@@ -606,7 +950,7 @@ check_ident_usermap(const char *usermap_name,
 /*
  * Read the ident config file and create a List of Lists of tokens in the file.
  */
-static void
+void
 load_ident(void)
 {
    FILE       *file;           /* The map file we have to read */
@@ -622,7 +966,7 @@ load_ident(void)
    map_file = (char *) palloc(bufsize);
    snprintf(map_file, bufsize, "%s/%s", DataDir, USERMAP_FILE);
 
-   file = AllocateFile(map_file, PG_BINARY_R);
+   file = AllocateFile(map_file, "r");
    if (file == NULL)
    {
        /* The open of the map file failed.  */
@@ -640,8 +984,8 @@ load_ident(void)
 
 /*
  * Parse the string "*ident_response" as a response from a query to an Ident
- * server.  If it's a normal response indicating a username, return true
- * and store the username at *ident_user.  If it's anything else,
+ * server.  If it's a normal response indicating a user name, return true
+ * and store the user name at *ident_user. If it's anything else,
  * return false.
  */
 static bool
@@ -708,7 +1052,7 @@ interpret_ident_response(char *ident_response,
                        cursor++;       /* Go over colon */
                        while (isblank(*cursor))
                            cursor++;   /* skip blanks */
-                       /* Rest of line is username.  Copy it over. */
+                       /* Rest of line is user name.  Copy it over. */
                        i = 0;
                        while (*cursor != '\r' && i < IDENT_USERNAME_MAX)
                            ident_user[i++] = *cursor++;
@@ -725,7 +1069,7 @@ interpret_ident_response(char *ident_response,
 /*
  * Talk to the ident server on host "remote_ip_addr" and find out who
  * owns the tcp connection from his port "remote_port" to port
- * "local_port_addr" on host "local_ip_addr".  Return the username the
+ * "local_port_addr" on host "local_ip_addr".  Return the user name the
  * ident server gives as "*ident_user".
  *
  * IP addresses and port numbers are in network byte order.
@@ -955,6 +1299,8 @@ ident_unix(int sock, char *ident_user)
 #endif
 }
 
+
+
 /*
  * Determine the username of the initiator of the connection described
  * by "port".  Then look in the usermap file under the usermap
@@ -1010,211 +1356,3 @@ hba_getauthmethod(hbaPort *port)
        return STATUS_ERROR;
 }
 
-/*
- * Clear and reload tokenized file contents.
- */
-void
-load_hba_and_ident(void)
-{
-   load_hba();
-   load_ident();
-}
-
-
-/* Character set stuff.  Not sure it really belongs in this file. */
-
-#ifdef CYR_RECODE
-
-#define CHARSET_FILE "charset.conf"
-#define MAX_CHARSETS   10
-#define KEY_HOST      1
-#define KEY_BASE      2
-#define KEY_TABLE     3
-
-struct CharsetItem
-{
-   char        Orig[MAX_TOKEN];
-   char        Dest[MAX_TOKEN];
-   char        Table[MAX_TOKEN];
-};
-
-
-static bool
-CharSetInRange(char *buf, int host)
-{
-   int         valid,
-               i,
-               FromAddr,
-               ToAddr,
-               tmp;
-   struct in_addr file_ip_addr;
-   char       *p;
-   unsigned int one = 0x80000000,
-               NetMask = 0;
-   unsigned char mask;
-
-   p = strchr(buf, '/');
-   if (p)
-   {
-       *p++ = '\0';
-       valid = inet_aton(buf, &file_ip_addr);
-       if (valid)
-       {
-           mask = strtoul(p, 0, 0);
-           FromAddr = ntohl(file_ip_addr.s_addr);
-           ToAddr = ntohl(file_ip_addr.s_addr);
-           for (i = 0; i < mask; i++)
-           {
-               NetMask |= one;
-               one >>= 1;
-           }
-           FromAddr &= NetMask;
-           ToAddr = ToAddr | ~NetMask;
-           tmp = ntohl(host);
-           return ((unsigned) tmp >= (unsigned) FromAddr &&
-                   (unsigned) tmp <= (unsigned) ToAddr);
-       }
-   }
-   else
-   {
-       p = strchr(buf, '-');
-       if (p)
-       {
-           *p++ = '\0';
-           valid = inet_aton(buf, &file_ip_addr);
-           if (valid)
-           {
-               FromAddr = ntohl(file_ip_addr.s_addr);
-               valid = inet_aton(p, &file_ip_addr);
-               if (valid)
-               {
-                   ToAddr = ntohl(file_ip_addr.s_addr);
-                   tmp = ntohl(host);
-                   return ((unsigned) tmp >= (unsigned) FromAddr &&
-                           (unsigned) tmp <= (unsigned) ToAddr);
-               }
-           }
-       }
-       else
-       {
-           valid = inet_aton(buf, &file_ip_addr);
-           if (valid)
-           {
-               FromAddr = file_ip_addr.s_addr;
-               return (unsigned) FromAddr == (unsigned) host;
-           }
-       }
-   }
-   return false;
-}
-
-void
-GetCharSetByHost(char *TableName, int host, const char *DataDir)
-{
-   FILE       *file;
-   char        buf[MAX_TOKEN],
-               BaseCharset[MAX_TOKEN],
-               OrigCharset[MAX_TOKEN],
-               DestCharset[MAX_TOKEN],
-               HostCharset[MAX_TOKEN],
-              *map_file;
-   int         key,
-               ChIndex = 0,
-               c,
-               i,
-               bufsize;
-   struct CharsetItem *ChArray[MAX_CHARSETS];
-
-   *TableName = '\0';
-   bufsize = (strlen(DataDir) + strlen(CHARSET_FILE) + 2) * sizeof(char);
-   map_file = (char *) palloc(bufsize);
-   snprintf(map_file, bufsize, "%s/%s", DataDir, CHARSET_FILE);
-   file = AllocateFile(map_file, PG_BINARY_R);
-   pfree(map_file);
-   if (file == NULL)
-   {
-       /* XXX should we log a complaint? */
-       return;
-   }
-   while ((c = getc(file)) != EOF)
-   {
-       if (c == '#')
-           read_through_eol(file);
-       else
-       {
-           /* Read the key */
-           ungetc(c, file);
-           next_token(file, buf, sizeof(buf));
-           if (buf[0] != '\0')
-           {
-               key = 0;
-               if (strcasecmp(buf, "HostCharset") == 0)
-                   key = KEY_HOST;
-               if (strcasecmp(buf, "BaseCharset") == 0)
-                   key = KEY_BASE;
-               if (strcasecmp(buf, "RecodeTable") == 0)
-                   key = KEY_TABLE;
-               switch (key)
-               {
-                   case KEY_HOST:
-                       /* Read the host */
-                       next_token(file, buf, sizeof(buf));
-                       if (buf[0] != '\0')
-                       {
-                           if (CharSetInRange(buf, host))
-                           {
-                               /* Read the charset */
-                               next_token(file, buf, sizeof(buf));
-                               if (buf[0] != '\0')
-                                   strcpy(HostCharset, buf);
-                           }
-                       }
-                       break;
-                   case KEY_BASE:
-                       /* Read the base charset */
-                       next_token(file, buf, sizeof(buf));
-                       if (buf[0] != '\0')
-                           strcpy(BaseCharset, buf);
-                       break;
-                   case KEY_TABLE:
-                       /* Read the original charset */
-                       next_token(file, buf, sizeof(buf));
-                       if (buf[0] != '\0')
-                       {
-                           strcpy(OrigCharset, buf);
-                           /* Read the destination charset */
-                           next_token(file, buf, sizeof(buf));
-                           if (buf[0] != '\0')
-                           {
-                               strcpy(DestCharset, buf);
-                               /* Read the table filename */
-                               next_token(file, buf, sizeof(buf));
-                               if (buf[0] != '\0')
-                               {
-                                   ChArray[ChIndex] =
-                                       (struct CharsetItem *) palloc(sizeof(struct CharsetItem));
-                                   strcpy(ChArray[ChIndex]->Orig, OrigCharset);
-                                   strcpy(ChArray[ChIndex]->Dest, DestCharset);
-                                   strcpy(ChArray[ChIndex]->Table, buf);
-                                   ChIndex++;
-                               }
-                           }
-                       }
-                       break;
-               }
-               read_through_eol(file);
-           }
-       }
-   }
-   FreeFile(file);
-
-   for (i = 0; i < ChIndex; i++)
-   {
-       if (strcasecmp(BaseCharset, ChArray[i]->Orig) == 0 &&
-           strcasecmp(HostCharset, ChArray[i]->Dest) == 0)
-           strncpy(TableName, ChArray[i]->Table, 79);
-       pfree(ChArray[i]);
-   }
-}
-
-#endif   /* CYR_RECODE */
diff --git a/src/backend/libpq/password.c b/src/backend/libpq/password.c
deleted file mode 100644 (file)
index f8490f8..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: password.c,v 1.41 2002/03/04 01:46:03 tgl Exp $
- *
- */
-
-#include 
-#include 
-
-#include "postgres.h"
-
-#ifdef HAVE_CRYPT_H
-#include 
-#endif
-
-#include "libpq/libpq.h"
-#include "libpq/password.h"
-#include "libpq/crypt.h"
-#include "miscadmin.h"
-#include "storage/fd.h"
-
-
-int
-verify_password(const Port *port, const char *user, const char *password)
-{
-   char       *pw_file_fullname;
-   FILE       *pw_file;
-
-   pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(port->auth_arg) + 2);
-   strcpy(pw_file_fullname, DataDir);
-   strcat(pw_file_fullname, "/");
-   strcat(pw_file_fullname, port->auth_arg);
-
-   pw_file = AllocateFile(pw_file_fullname, PG_BINARY_R);
-   if (!pw_file)
-   {
-       elog(LOG, "verify_password: Unable to open password file \"%s\": %m",
-            pw_file_fullname);
-
-       pfree(pw_file_fullname);
-
-       return STATUS_ERROR;
-   }
-
-   pfree(pw_file_fullname);
-
-   while (!feof(pw_file))
-   {
-       char        pw_file_line[255],
-                  *p,
-                  *test_user,
-                  *test_pw;
-
-       if (fgets(pw_file_line, sizeof(pw_file_line), pw_file) == NULL)
-           pw_file_line[0] = '\0';
-       /* kill the newline */
-       if (strlen(pw_file_line) > 0 &&
-           pw_file_line[strlen(pw_file_line) - 1] == '\n')
-           pw_file_line[strlen(pw_file_line) - 1] = '\0';
-
-       p = pw_file_line;
-
-       test_user = strtok(p, ":");
-       if (!test_user || test_user[0] == '\0')
-           continue;
-       test_pw = strtok(NULL, ":");
-
-       if (strcmp(user, test_user) == 0)
-       {
-           /* we're outta here one way or the other, so close file */
-           FreeFile(pw_file);
-
-           /*
-            * If the password is empty or "+" then we use the regular
-            * pg_shadow passwords. If we use crypt then we have to use
-            * pg_shadow passwords no matter what.  This is because the
-            * current code needs non-encrypted passwords to encrypt with
-            * a random salt.
-            */
-           if (port->auth_method == uaMD5 ||
-               port->auth_method == uaCrypt ||
-               test_pw == NULL ||
-               test_pw[0] == '\0' ||
-               strcmp(test_pw, "+") == 0)
-               return md5_crypt_verify(port, user, password);
-
-           /* external password file is crypt-only */
-           if (strcmp(crypt(password, test_pw), test_pw) == 0)
-           {
-               /* it matched. */
-               return STATUS_OK;
-           }
-
-           elog(LOG, "verify_password: password mismatch for '%s'",
-                user);
-
-           return STATUS_ERROR;
-       }
-   }
-
-   FreeFile(pw_file);
-
-   elog(LOG, "verify_password: user '%s' not found in password file",
-        user);
-
-   return STATUS_ERROR;
-}
index 669588e517cc08ffd8bd480055b5ca2bf7fc2946..05e6959b4dec0e7c48baecb92a48ce4ebeddf9e0 100644 (file)
 # 
 # Format:
 # 
-#   host  DBNAME  IP_ADDRESS  ADDRESS_MASK  AUTH_TYPE  [AUTH_ARGUMENT]
-# 
-# DBNAME can be:
-#  o a database name
-#  o "all", which means the record matches all databases
-#   o "sameuser", which means users can only access databases whose name
-#     is the same as their username
+#   host       DATABASE    USER      IP_ADDRESS    MASK               AUTH_TYPE
+# 
+# DATABASE can be:
+#  o a database name
+#  o "sameuser", which means a user can only access a database with the
+#    same name as their user name
+#  o "samegroup", which means a user can only access databases when they
+#    are members of a group with the same name as the database name
+#  o "all", which matches all databases
+#  o a list of database names, separated by commas
+#  o a file name containing database names, starting with '@'
+#
+# USER can be:
+#  o a user name
+#  o "all", which matches all users
+#  o a list of user names, separated by commas
+#  o a group name, starting with '+'
+#  o a file name containing user names, starting with '@'
+#
+# Files read using '@' can contain comma-separated database/user names,
+# or one name per line.  The files can also contain comments using '#'.
 #
-# IP_ADDRESS and ADDRESS_MASK are standard dotted decimal IP address and
+# IP_ADDRESS and MASK are standard dotted decimal IP address and
 # mask values. IP addresses can only be specified numerically, not as
 # domain or host names.
 # 
 # Do not prevent the superuser from accessing the template1 database.
 # Various utility commands need access to template1.
 # 
-# AUTH_TYPE and AUTH_ARGUMENT are described below.
+# AUTH_TYPE is described below.
 #
 # 
 # hostssl
 # 
 # The format of this record is identical to "host".
 # 
-# 
-#
-# It specifies hosts that required connection via secure SSL. "host"
-# records allow SSL connections too, but "hostssl" only allows SSL-secured
+# It specifies hosts that require connection via secure SSL. "host"
+# allows SSL connections too, but "hostssl" requires SSL-secured
 # connections.
 # 
 # This keyword is only available if the server was compiled with SSL
 # connections. Without this record, UNIX-socket connections are disallowed
 # 
 # Format:
-#   local  DBNAME  AUTH_TYPE  [AUTH_ARGUMENT]
+#   local      DATABASE    USER      AUTH_TYPE
 # 
 # This format is identical to the "host" record type except there are no
-# IP_ADDRESS and ADDRESS_MASK fields.
+# IP_ADDRESS and MASK fields.
 #
 # 
 # 
 # has an AUTH_TYPE.
 #
 #   trust: 
-#      No authentication is done. Any valid username is accepted,
+#      No authentication is done. Any valid user name is accepted,
 #      including the PostgreSQL superuser. This option should
 #      be used only for hosts where all users are trusted.
 # 
-#   password:
-#      Authentication is done by matching a password supplied
-#      in clear by the host. If no AUTH_ARGUMENT is used, the
-#      password is compared with the user's entry in the
-#      pg_shadow table.
-# 
-#      If AUTH_ARGUMENT is specified, the username is looked up
-#      in that file in the $PGDATA directory. If the username
-#      is found but there is no password, the password is looked
-#      up in pg_shadow. If a password exists in the file, it is
-#      used instead. These secondary files allow fine-grained
-#      control over who can access which databases and whether
-#      a non-default password is required. The same file can be
-#      used in multiple records for easier administration.
-#      Password files can be maintained with the pg_passwd(1)
-#      utility. Remember, these passwords override pg_shadow
-#      passwords.  Also, such passwords are passed over the network
-#      in cleartext, meaning this should not be used on untrusted
-#      networks.
-# 
 #   md5:
-#      Same as "password", except the password is encrypted over the
-#      network. This method is preferable to "password" and "crypt"
-#      except for pre-7.2 clients that don't support it. NOTE: md5 can
-#      use usernames stored in secondary password files but ignores
-#      passwords stored there. The pg_shadow password will always be
-#      used.
+#      Requires the client to supply an MD5 encrypted password for
+#      authentication.  This is the only method that allows encrypted
+#      passwords to be stored in pg_shadow.
 # 
 #   crypt:
-#      Same as "md5", but uses crypt for pre-7.2 clients.  You can
-#      not store encrypted passwords in pg_shadow if you use this
-#      method.
+#      Same as "md5", but uses crypt for pre-7.2 clients.
 #
+#   password:
+#      Same as "md5", but the password is sent in cleartext over
+#      the network.  This should not be used on untrusted
+#      networks.
+# 
 #   ident:
 #      For TCP/IP connections, authentication is done by contacting the
 #      ident server on the client host. This is only as secure as the
-#      client machine. On machines that support unix-domain socket
-#      credentials (currently Linux, FreeBSD, NetBSD, and BSD/OS), this
-#      method also works for "local" connections.
+#      client machine. You must specify the map name after the 'ident'
+#      keyword. It determines how to map remote user names to
+#      PostgreSQL user names. If you use "sameuser", the user names are
+#      assumed to be identical. If not, the map name is looked up
+#      in the $PGDATA/pg_ident.conf file. The connection is accepted if
+#      that file contains an entry for this map name with the
+#      ident-supplied username and the requested PostgreSQL username.
 #
-#      AUTH_ARGUMENT is required. It determines how to map remote user
-#      names to PostgreSQL user names. If you use "sameuser", the user
-#      names are assumed to be the identical. If not, AUTH_ARGUMENT is
-#      assumed to be a map name found in the $PGDATA/pg_ident.conf
-#      file. The connection is accepted if that file contains an entry
-#      for this map name with the ident-supplied username and the
-#      requested PostgreSQL username.
+#      On machines that support unix-domain socket credentials
+#      (currently Linux, FreeBSD, NetBSD, and BSD/OS), ident allows
+#      reliable authentication of 'local' connections without ident 
+#      running on the local machine.
 #
 #   krb4:
 #      Kerberos V4 authentication is used.  Allowed only for
 #      TCP/IP connections, not for local UNIX-domain sockets.
 # 
 #   pam:
-#      Authentication is passed off to PAM (PostgreSQL must be
-#      configured --with-pam), using the default service name
-#      "postgresql" - you can specify your own service name by
-#      setting AUTH_ARGUMENT to the desired service name.
+#      Authentication is done by PAM using the default service name
+#      "postgresql". You can specify your own service name by adding
+#      the service name after the 'pam' keyword. To use this option,
+#      PostgreSQL must be configured --with-pam.
 #
 #   reject:
 #      Reject the connection. This is used to reject certain hosts
 # Allow any user on the local system to connect to any database under any
 # username using Unix-domain sockets (the default for local connections):
 #
-# TYPE       DATABASE    IP_ADDRESS    MASK               AUTH_TYPE  AUTH_ARGUMENT
-# local      all                                          trust
+# TYPE       DATABASE    USER       IP_ADDRESS    MASK               AUTH_TYPE
+# local      all         all                                         trust
 # 
 # The same using local loopback TCP/IP connections:
 #
-# TYPE       DATABASE    IP_ADDRESS    MASK               AUTH_TYPE  AUTH_ARGUMENT
-# host       all         127.0.0.1     255.255.255.255    trust     
+# TYPE      DATABASE     USER    IP_ADDRESS    MASK               AUTH_TYPE
+# host      all          all     127.0.0.1     255.255.255.255    trust     
 # 
 # Allow any user from any host with IP address 192.168.93.x to
 # connect to database "template1" as the same username that ident reports
 # for the connection (typically his Unix username):
 # 
-# TYPE       DATABASE    IP_ADDRESS    MASK               AUTH_TYPE  AUTH_ARGUMENT
-# host       template1   192.168.93.0  255.255.255.0      ident      sameuser
+# TYPE       DATABASE    USER    IP_ADDRESS    MASK               AUTH_TYPE
+# host       template1   all     192.168.93.0  255.255.255.0      ident sameuser
 # 
 # Allow a user from host 192.168.12.10 to connect to database "template1"
-# if the user's password in pg_shadow is correctly supplied:
+# if the user's password is correctly supplied:
 # 
-# TYPE       DATABASE    IP_ADDRESS    MASK               AUTH_TYPE  AUTH_ARGUMENT
-# host       template1   192.168.12.10 255.255.255.255    md5
+# TYPE       DATABASE    USER     IP_ADDRESS    MASK               AUTH_TYPE
+# host       template1   all      192.168.12.10 255.255.255.255    md5
 # 
 # In the absence of preceding "host" lines, these two lines will reject
 # all connection from 192.168.54.1 (since that entry will be matched
 # first), but allow Kerberos V5 connections from anywhere else on the
 # Internet. The zero mask means that no bits of the host IP address are
-# considered, so it matches any host:
+# considered so it matches any host:
 # 
 # 
-# TYPE       DATABASE    IP_ADDRESS    MASK               AUTH_TYPE  AUTH_ARGUMENT
-# host       all        192.168.54.1   255.255.255.255    reject
-# host       all        0.0.0.0        0.0.0.0            krb5
+# TYPE       DATABASE    USER     IP_ADDRESS    MASK               AUTH_TYPE
+# host       all         all      192.168.54.1  255.255.255.255    reject
+# host       all         all      0.0.0.0       0.0.0.0            krb5
 # 
 # Allow users from 192.168.x.x hosts to connect to any database if they
 # pass the ident check. For example, if ident says the user is "james" and
 # he requests to connect as PostgreSQL user "guest", the connection is
 # allowed if there is an entry in $PGDATA/pg_ident.conf with map name 
 # "phoenix" that says "james" is allowed to connect as "guest":
+# See $PGDATA/pg_ident.conf for more information on Ident maps.
 # 
-# TYPE       DATABASE    IP_ADDRESS    MASK               AUTH_TYPE  AUTH_ARGUMENT
-# host       all        192.168.0.0    255.255.0.0        ident      phoenix
+# TYPE       DATABASE    USER     IP_ADDRESS    MASK               AUTH_TYPE
+# host       all         all      192.168.0.0    255.255.0.0       ident phoenix
+#
+# If these are the only three lines for local connections, they will
+# allow local users to connect only to their own databases (databases
+# with the same name as their user name) except for administrators and
+# members of group 'support' who may connect to all databases . The file
+# $PGDATA/admins contains a list of user names. Passwords are required in
+# all cases.
+#
+# TYPE       DATABASE    USER      IP_ADDRESS    MASK               AUTH_TYPE
+# local      sameuser    all                                        md5
+# local      all         @admins                                    md5
+# local      all         +support                                   md5
+#
+# The last two lines above can be combined into a single line:
+#
+# local      all         @admins,+support                           md5
+#
+# The database column can also use lists and file names, but not groups:
+#
+# local      db1,db2,@demodbs  all                                  md5
 #
-# If these are the only two lines for local connections, they will allow
-# local users to connect only to their own databases (databases with the
-# same name as their user name) except for administrators who may connect
-# to all databases. The file $PGDATA/admins lists the user names who are
-# permitted to connect to all databases. Passwords are required in all
-# cases. (If you prefer to use ident authorization, an ident map can
-# serve a parallel purpose to the password list file used here.)
 #
-# TYPE       DATABASE    IP_ADDRESS    MASK               AUTH_TYPE  AUTH_ARGUMENT
-# local      sameuser                                     md5
-# local      all                                          md5  admins
 # 
-# See $PGDATA/pg_ident.conf for more information on Ident maps.
 #
 #
 # 
 # configuration is probably too liberal for you. Change it to use
 # something other than "trust" authentication.
 # 
-# TYPE     DATABASE    IP_ADDRESS    MASK               AUTH_TYPE  AUTH_ARGUMENT
+# TYPE       DATABASE      USER      IP_ADDRESS    MASK               AUTH_TYPE
 
-local      all                                          trust
-host       all         127.0.0.1     255.255.255.255    trust
+local        all           all                                        trust
+host         all           all       127.0.0.1     255.255.255.255    trust
index a6d6097a54c7e39f2a88435a3a07bc99dc880629..0ce817b5b39baa85b32ae522d293c4fbf0843a14 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.271 2002/03/15 19:20:35 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.272 2002/04/04 04:25:48 momjian Exp $
  *
  * NOTES
  *
@@ -748,8 +748,10 @@ PostmasterMain(int argc, char *argv[])
    /*
     * Load cached files for client authentication.
     */
-   load_hba_and_ident();
-   load_password_cache();
+   load_hba();
+   load_ident();
+   load_user();
+   load_group();
 
    /*
     * We're ready to rock and roll...
@@ -1389,7 +1391,8 @@ SIGHUP_handler(SIGNAL_ARGS)
        elog(LOG, "Received SIGHUP, reloading configuration files");
        SignalChildren(SIGHUP);
        ProcessConfigFile(PGC_SIGHUP);
-       load_hba_and_ident();
+       load_hba();
+       load_ident();
    }
 
    PG_SETMASK(&UnBlockSig);
@@ -2288,9 +2291,10 @@ sigusr1_handler(SIGNAL_ARGS)
    if (CheckPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE))
    {
        /*
-        * Password file has changed.
+        * Password or group file has changed.
         */
-       load_password_cache();
+       load_user();
+       load_group();
    }
 
    if (CheckPostmasterSignal(PMSIGNAL_WAKEN_CHILDREN))
index 39a1ec4df1659f653931060a043194d75253d604..537e97a50eec3438752d1c57c09196cd839266e1 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/adt/quote.c,v 1.6 2001/10/28 06:25:53 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/adt/quote.c,v 1.7 2002/04/04 04:25:49 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -124,8 +124,6 @@ do_quote_ident(text *iptr)
    {
        if (*cp1 == '"')
            *cp2++ = '"';
-       if (*cp1 == '\\')
-           *cp2++ = '\\';
        *cp2++ = *cp1++;
    }
    *cp2++ = '"';
@@ -234,8 +232,6 @@ do_quote_ident(text *iptr)
 
        if (*cp1 == '"')
            *cp2++ = '"';
-       if (*cp1 == '\\')
-           *cp2++ = '\\';
        *cp2++ = *cp1++;
 
        len--;
index dceb8b9cd6f79800fbc39cddb6e9d83ccccb72a7..9ef8b1c87c54a15b1c210bf35853fd575f4ffde0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.85 2002/03/04 04:45:27 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.86 2002/04/04 04:25:49 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -236,85 +236,17 @@ pg_convert2(PG_FUNCTION_ARGS)
 
 #ifdef CYR_RECODE
 
-#define MAX_TOKEN  80
-
-/*
- * Some standard C libraries, including GNU, have an isblank() function.
- * Others, including Solaris, do not.  So we have our own.
- */
-static bool
-isblank(const char c)
-{
-   return c == ' ' || c == '\t';
-}
-
-
-/*
- * Grab one token out of fp.  Tokens are strings of non-blank
- * characters bounded by blank characters, beginning of line, and end
- * of line.    Blank means space or tab.  Return the token as *buf.
- * Leave file positioned to character immediately after the token or
- * EOF, whichever comes first.  If no more tokens on line, return null
- * string as *buf and position file to beginning of next line or EOF,
- * whichever comes first.
- */
-static void
-next_token(FILE *fp, char *buf, const int bufsz)
-{
-   int         c;
-   char       *eb = buf + (bufsz - 1);
-
-   /* Move over initial token-delimiting blanks */
-   while ((c = getc(fp)) != EOF && isblank(c))
-       ;
-
-   if (c != EOF && c != '\n')
-   {
-       /*
-        * build a token in buf of next characters up to EOF, eol, or
-        * blank.  If the token gets too long, we still parse it
-        * correctly, but the excess characters are not stored into *buf.
-        */
-       while (c != EOF && c != '\n' && !isblank(c))
-       {
-           if (buf < eb)
-               *buf++ = c;
-           c = getc(fp);
-       }
-
-       /*
-        * Put back the char right after the token (critical in case it is
-        * eol, since we need to detect end-of-line at next call).
-        */
-       if (c != EOF)
-           ungetc(c, fp);
-   }
-   *buf = '\0';
-}
-
-
-static void
-read_through_eol(FILE *file)
-{
-   int         c;
-
-   while ((c = getc(file)) != EOF && c != '\n')
-       ;
-}
-
-
-void
 SetCharSet(void)
 {
    FILE       *file;
-   char       *p;
+   char       *filename;
    char       *map_file;
    char        buf[MAX_TOKEN];
    int         i,
                c;
    unsigned char FromChar,
                ToChar;
-   char        ChTable[80];
+   char        ChTable[MAX_TOKEN];
 
    for (i = 0; i < 128; i++)
    {
@@ -325,39 +257,40 @@ SetCharSet(void)
    if (IsUnderPostmaster)
    {
        GetCharSetByHost(ChTable, MyProcPort->raddr.in.sin_addr.s_addr, DataDir);
-       p = ChTable;
+       filename = ChTable;
    }
    else
-       p = getenv("PG_RECODETABLE");
+       filename = getenv("PG_RECODETABLE");
 
-   if (p && *p != '\0')
+   if (filename && *filename != '\0')
    {
-       map_file = palloc(strlen(DataDir) + strlen(p) + 2);
-       sprintf(map_file, "%s/%s", DataDir, p);
-       file = AllocateFile(map_file, PG_BINARY_R);
+       map_file = palloc(strlen(DataDir) + strlen(filename) + 2);
+       sprintf(map_file, "%s/%s", DataDir, filename);
+       file = AllocateFile(map_file, "r");
        pfree(map_file);
        if (file == NULL)
            return;
-       while ((c = getc(file)) != EOF)
+
+       while (!feof(file))
        {
-           if (c == '#')
-               read_through_eol(file);
-           else
+           next_token(file, buf, sizeof(buf));
+           if (buf[0] != '\0')
            {
-               /* Read the FromChar */
-               ungetc(c, file);
+               FromChar = strtoul(buf, 0, 0);
+               /* Read the ToChar */
                next_token(file, buf, sizeof(buf));
                if (buf[0] != '\0')
                {
-                   FromChar = strtoul(buf, 0, 0);
-                   /* Read the ToChar */
-                   next_token(file, buf, sizeof(buf));
-                   if (buf[0] != '\0')
+                   ToChar = strtoul(buf, 0, 0);
+                   RecodeForwTable[FromChar - 128] = ToChar;
+                   RecodeBackTable[ToChar - 128] = FromChar;
+
+                   /* read to EOL */
+                   while (!feof(file) && buf[0])
                    {
-                       ToChar = strtoul(buf, 0, 0);
-                       RecodeForwTable[FromChar - 128] = ToChar;
-                       RecodeBackTable[ToChar - 128] = FromChar;
-                       read_through_eol(file);
+                       next_token(file, buf, sizeof(buf));
+                       elog(LOG, "SetCharSet: unknown tag %s in file %s"
+                           buf, filename);
                    }
                }
            }
@@ -366,6 +299,7 @@ SetCharSet(void)
    }
 }
 
+
 char *
 convertstr(unsigned char *buff, int len, int dest)
 {
@@ -384,7 +318,206 @@ convertstr(unsigned char *buff, int len, int dest)
    }
    return ch;
 }
-#endif
+
+#define CHARSET_FILE "charset.conf"
+#define MAX_CHARSETS   10
+#define KEY_HOST      1
+#define KEY_BASE      2
+#define KEY_TABLE     3
+
+struct CharsetItem
+{
+   char        Orig[MAX_TOKEN];
+   char        Dest[MAX_TOKEN];
+   char        Table[MAX_TOKEN];
+};
+
+
+static bool
+CharSetInRange(char *buf, int host)
+{
+   int         valid,
+               i,
+               FromAddr,
+               ToAddr,
+               tmp;
+   struct in_addr file_ip_addr;
+   char       *p;
+   unsigned int one = 0x80000000,
+               NetMask = 0;
+   unsigned char mask;
+
+   p = strchr(buf, '/');
+   if (p)
+   {
+       *p++ = '\0';
+       valid = inet_aton(buf, &file_ip_addr);
+       if (valid)
+       {
+           mask = strtoul(p, 0, 0);
+           FromAddr = ntohl(file_ip_addr.s_addr);
+           ToAddr = ntohl(file_ip_addr.s_addr);
+           for (i = 0; i < mask; i++)
+           {
+               NetMask |= one;
+               one >>= 1;
+           }
+           FromAddr &= NetMask;
+           ToAddr = ToAddr | ~NetMask;
+           tmp = ntohl(host);
+           return ((unsigned) tmp >= (unsigned) FromAddr &&
+                   (unsigned) tmp <= (unsigned) ToAddr);
+       }
+   }
+   else
+   {
+       p = strchr(buf, '-');
+       if (p)
+       {
+           *p++ = '\0';
+           valid = inet_aton(buf, &file_ip_addr);
+           if (valid)
+           {
+               FromAddr = ntohl(file_ip_addr.s_addr);
+               valid = inet_aton(p, &file_ip_addr);
+               if (valid)
+               {
+                   ToAddr = ntohl(file_ip_addr.s_addr);
+                   tmp = ntohl(host);
+                   return ((unsigned) tmp >= (unsigned) FromAddr &&
+                           (unsigned) tmp <= (unsigned) ToAddr);
+               }
+           }
+       }
+       else
+       {
+           valid = inet_aton(buf, &file_ip_addr);
+           if (valid)
+           {
+               FromAddr = file_ip_addr.s_addr;
+               return (unsigned) FromAddr == (unsigned) host;
+           }
+       }
+   }
+   return false;
+}
+
+
+static void
+GetCharSetByHost(char *TableName, int host, const char *DataDir)
+{
+   FILE       *file;
+   char        buf[MAX_TOKEN],
+               BaseCharset[MAX_TOKEN],
+               OrigCharset[MAX_TOKEN],
+               DestCharset[MAX_TOKEN],
+               HostCharset[MAX_TOKEN],
+              *map_file;
+   int         key,
+               ChIndex = 0,
+               c,
+               i,
+               bufsize;
+   struct CharsetItem *ChArray[MAX_CHARSETS];
+
+   *TableName = '\0';
+   bufsize = (strlen(DataDir) + strlen(CHARSET_FILE) + 2) * sizeof(char);
+   map_file = (char *) palloc(bufsize);
+   snprintf(map_file, bufsize, "%s/%s", DataDir, CHARSET_FILE);
+   file = AllocateFile(map_file, "r");
+   pfree(map_file);
+   if (file == NULL)
+   {
+       /* XXX should we log a complaint? */
+       return;
+   }
+
+   while (!feof(file))
+   {
+       next_token(file, buf, sizeof(buf));
+       if (buf[0] != '\0')
+       {
+           key = 0;
+           if (strcasecmp(buf, "HostCharset") == 0)
+               key = KEY_HOST;
+           else if (strcasecmp(buf, "BaseCharset") == 0)
+               key = KEY_BASE;
+           else if (strcasecmp(buf, "RecodeTable") == 0)
+               key = KEY_TABLE;
+           else
+               elog(LOG, "GetCharSetByHost: unknown tag %s in file %s"
+                   buf, CHARSET_FILE);
+
+           switch (key)
+           {
+               case KEY_HOST:
+                   /* Read the host */
+                   next_token(file, buf, sizeof(buf));
+                   if (buf[0] != '\0')
+                   {
+                       if (CharSetInRange(buf, host))
+                       {
+                           /* Read the charset */
+                           next_token(file, buf, sizeof(buf));
+                           if (buf[0] != '\0')
+                               strcpy(HostCharset, buf);
+                       }
+                   }
+                   break;
+               case KEY_BASE:
+                   /* Read the base charset */
+                   next_token(file, buf, sizeof(buf));
+                   if (buf[0] != '\0')
+                       strcpy(BaseCharset, buf);
+                   break;
+               case KEY_TABLE:
+                   /* Read the original charset */
+                   next_token(file, buf, sizeof(buf));
+                   if (buf[0] != '\0')
+                   {
+                       strcpy(OrigCharset, buf);
+                       /* Read the destination charset */
+                       next_token(file, buf, sizeof(buf));
+                       if (buf[0] != '\0')
+                       {
+                           strcpy(DestCharset, buf);
+                           /* Read the table filename */
+                           next_token(file, buf, sizeof(buf));
+                           if (buf[0] != '\0')
+                           {
+                               ChArray[ChIndex] =
+                                   (struct CharsetItem *) palloc(sizeof(struct CharsetItem));
+                               strcpy(ChArray[ChIndex]->Orig, OrigCharset);
+                               strcpy(ChArray[ChIndex]->Dest, DestCharset);
+                               strcpy(ChArray[ChIndex]->Table, buf);
+                               ChIndex++;
+                           }
+                       }
+                   }
+                   break;
+           }
+
+           /* read to EOL */
+           while (!feof(file) && buf[0])
+           {
+               next_token(file, buf, sizeof(buf));
+               elog(LOG, "GetCharSetByHost: unknown tag %s in file %s"
+                   buf, CHARSET_FILE);
+           }
+       }
+   }
+   FreeFile(file);
+
+   for (i = 0; i < ChIndex; i++)
+   {
+       if (strcasecmp(BaseCharset, ChArray[i]->Orig) == 0 &&
+           strcasecmp(HostCharset, ChArray[i]->Dest) == 0)
+           strncpy(TableName, ChArray[i]->Table, 79);
+       pfree(ChArray[i]);
+   }
+}
+
+#endif   /* CYR_RECODE */
 
 
 
index a1d4b1e8fc0b66c2b7ede428d1b9a0e813097943..7a293c35a265140ff58f0d728df92aeca5a97ad4 100644 (file)
@@ -5,7 +5,7 @@
 # Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/bin/Makefile,v 1.34 2001/02/18 18:33:59 momjian Exp $
+# $Header: /cvsroot/pgsql/src/bin/Makefile,v 1.35 2002/04/04 04:25:50 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -14,7 +14,7 @@ top_builddir = ../..
 include $(top_builddir)/src/Makefile.global
 
 DIRS := initdb initlocation ipcclean pg_ctl pg_dump pg_id \
-   pg_passwd psql scripts pg_config
+   psql scripts pg_config
 
 ifdef MULTIBYTE
 DIRS += pg_encoding
index e028ac1b10e82cdff2551af920d36d8063a43dc4..30f7de1f201668d7a30986023961b8209fb0d447 100644 (file)
@@ -27,7 +27,7 @@
 # Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.146 2002/04/03 05:39:32 petere Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.147 2002/04/04 04:25:50 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -603,9 +603,11 @@ $ECHO_N "initializing pg_shadow... "$ECHO_C
 
 "$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <
 -- Create a trigger so that direct updates to pg_shadow will be written
--- to the flat password file pg_pwd
+-- to the flat password/group files pg_pwd and pg_group
 CREATE TRIGGER pg_sync_pg_pwd AFTER INSERT OR UPDATE OR DELETE ON pg_shadow \
-FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd();
+FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();
+CREATE TRIGGER pg_sync_pg_group AFTER INSERT OR UPDATE OR DELETE ON pg_group \
+FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();
 -- needs to be done before alter user, because alter user checks that
 -- pg_shadow is secure ...
 REVOKE ALL on pg_shadow FROM public;
@@ -643,6 +645,11 @@ EOF
         echo "The password file wasn't generated. Please report this problem." 1>&2
         exit_nicely
     fi
+    if [ ! -f "$PGDATA"/global/pg_group ]; then
+        echo
+        echo "The group file wasn't generated. Please report this problem." 1>&2
+        exit_nicely
+    fi
     echo "ok"
 fi
 
diff --git a/src/bin/pg_passwd/Makefile b/src/bin/pg_passwd/Makefile
deleted file mode 100644 (file)
index f6f4acd..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-# $Header: /cvsroot/pgsql/src/bin/pg_passwd/Attic/Makefile,v 1.14 2001/05/12 19:49:47 petere Exp $
-
-subdir = src/bin/pg_passwd
-top_builddir = ../../..
-include $(top_builddir)/src/Makefile.global
-
-OBJS = pg_passwd.o
-ifdef STRDUP
-OBJS += $(top_builddir)/src/utils/strdup.o
-endif
-
-all: pg_passwd
-
-pg_passwd: $(OBJS)
-   $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@
-
-$(top_builddir)/src/utils/strdup.o:
-   $(MAKE) -C $(top_builddir)/src/utils strdup.o
-
-install: all installdirs
-   $(INSTALL_PROGRAM) pg_passwd$(X) $(DESTDIR)$(bindir)/pg_passwd$(X)
-
-installdirs:
-   $(mkinstalldirs) $(DESTDIR)$(bindir)
-
-uninstall:
-   rm -f $(DESTDIR)$(bindir)/pg_passwd$(X)
-
-depend dep:
-   $(CC) -MM $(CFLAGS) *.c >depend
-
-clean distclean maintainer-clean:
-   rm -f pg_passwd$(X) pg_passwd.o
-
-ifeq (depend,$(wildcard depend))
-include depend
-endif
diff --git a/src/bin/pg_passwd/pg_passwd.c b/src/bin/pg_passwd/pg_passwd.c
deleted file mode 100644 (file)
index 831c382..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * @(#) pg_passwd.c 1.8 09:13:16 97/07/02      Y. Ichikawa
- */
-#include "postgres_fe.h"
-
-#include 
-#include 
-#include 
-#include 
-#define issaltchar(c)  (isalnum((unsigned char) (c)) || (c) == '.' || (c) == '/')
-
-#ifdef HAVE_TERMIOS_H
-#include 
-#endif
-#ifdef HAVE_CRYPT_H
-#include 
-#else
-extern char *crypt(const char *, const char *);
-#endif
-
-/*
- * We assume that the output of crypt(3) is always 13 characters,
- * and that at most 8 characters can usefully be sent to it.
- *
- * Postgres usernames are assumed to be less than NAMEDATALEN chars long.
- */
-#define CLEAR_PASSWD_LEN 8     /* not including null */
-#define CRYPTED_PASSWD_LEN 13  /* not including null */
-
-const char *progname;
-
-static void usage(void);
-static void read_pwd_file(char *filename);
-static void write_pwd_file(char *filename, char *bkname);
-static void encrypt_pwd(char key[CLEAR_PASSWD_LEN + 1],
-           char salt[3],
-           char passwd[CRYPTED_PASSWD_LEN + 1]);
-static void prompt_for_username(char *username);
-static void prompt_for_password(char *prompt, char *password);
-
-static void
-usage(void)
-{
-   printf("%s manipulates flat text password files for PostgreSQL.\n\n", progname);
-   printf("Usage:\n  %s PASSWORD-FILE\n\n", progname);
-   printf("Report bugs to .\n");
-}
-
-typedef struct
-{
-   char       *uname;
-   char       *pwd;
-   char       *rest;
-} pg_pwd;
-
-#define MAXPWDS 1024
-
-pg_pwd     pwds[MAXPWDS];
-int            npwds = 0;
-
-
-static void
-read_pwd_file(char *filename)
-{
-   FILE       *fp;
-   static char line[512];
-   static char ans[128];
-   int         i;
-
-try_again:
-   fp = fopen(filename, PG_BINARY_R);
-   if (fp == NULL)
-   {
-       if (errno == ENOENT)
-       {
-           printf("File \"%s\" does not exist.  Create? (y/n): ", filename);
-           fflush(stdout);
-           if (fgets(ans, sizeof(ans), stdin) == NULL)
-               exit(1);
-           switch (ans[0])
-           {
-               case 'y':
-               case 'Y':
-                   fp = fopen(filename, PG_BINARY_W);
-                   if (fp == NULL)
-                   {
-                       perror(filename);
-                       exit(1);
-                   }
-                   fclose(fp);
-                   goto try_again;
-               default:
-                   /* cannot continue */
-                   exit(1);
-           }
-       }
-       else
-       {
-           perror(filename);
-           exit(1);
-       }
-   }
-
-   /* read all the entries */
-   for (npwds = 0;
-        npwds < MAXPWDS && fgets(line, sizeof(line), fp) != NULL;
-        ++npwds)
-   {
-       int         l;
-       char       *p,
-                  *q;
-
-       l = strlen(line);
-       if (line[l - 1] == '\n')
-           line[l - 1] = '\0';
-       else
-       {
-           fprintf(stderr, "%s:%d: line too long\n",
-                   filename, npwds + 1);
-           exit(1);
-       }
-
-       /* get user name */
-       p = line;
-       if ((q = strchr(p, ':')) != NULL)
-           *q = '\0';
-
-       if (strlen(p) == 0)
-       {
-           fprintf(stderr, "%s:%d: null user name\n",
-                   filename, npwds + 1);
-           exit(1);
-       }
-       pwds[npwds].uname = strdup(p);
-
-       /* check for duplicate user name */
-       for (i = 0; i < npwds; ++i)
-       {
-           if (strcmp(pwds[i].uname, pwds[npwds].uname) == 0)
-           {
-               fprintf(stderr, "Duplicate username %s in entry %d\n",
-                       pwds[npwds].uname, npwds + 1);
-               exit(1);
-           }
-       }
-
-       /* get password field */
-       if (q)
-       {
-           p = q + 1;
-           q = strchr(p, ':');
-
-           if (q != NULL)
-               *(q++) = '\0';
-
-           if (strlen(p) != CRYPTED_PASSWD_LEN && strcmp(p, "+") != 0)
-           {
-               fprintf(stderr, "%s:%d: warning: invalid password length\n",
-                       filename, npwds + 1);
-           }
-           pwds[npwds].pwd = strdup(p);
-       }
-       else
-           pwds[npwds].pwd = NULL;
-
-       /* rest of the line is treated as is */
-       if (q == NULL)
-           pwds[npwds].rest = NULL;
-       else
-           pwds[npwds].rest = strdup(q);
-   }
-
-   fclose(fp);
-}
-
-static void
-write_pwd_file(char *filename, char *bkname)
-{
-   FILE       *fp;
-   int         i;
-
-   /* make the backup file */
-link_again:
-   if (link(filename, bkname))
-   {
-       if (errno == EEXIST)
-       {
-           unlink(bkname);
-           goto link_again;
-       }
-       perror(bkname);
-       exit(1);
-   }
-   if (unlink(filename))
-   {
-       perror(filename);
-       exit(1);
-   }
-
-   /* open file */
-   if ((fp = fopen(filename, PG_BINARY_W)) == NULL)
-   {
-       perror(filename);
-       exit(1);
-   }
-
-   /* write file */
-   for (i = 0; i < npwds; ++i)
-   {
-       fprintf(fp, "%s", pwds[i].uname);
-       if (pwds[i].pwd)
-           fprintf(fp, ":%s", pwds[i].pwd);
-       if (pwds[i].rest)
-           fprintf(fp, ":%s", pwds[i].rest);
-       fprintf(fp, "\n");
-   }
-
-   fclose(fp);
-}
-
-static void
-encrypt_pwd(char key[CLEAR_PASSWD_LEN + 1],
-           char salt[3],
-           char passwd[CRYPTED_PASSWD_LEN + 1])
-{
-   int         n;
-
-   /* select a salt, if not already given */
-   if (salt[0] == '\0')
-   {
-       srand(time(NULL));
-       do
-       {
-           n = rand() % 256;
-       } while (!issaltchar(n));
-       salt[0] = n;
-       do
-       {
-           n = rand() % 256;
-       } while (!issaltchar(n));
-       salt[1] = n;
-       salt[2] = '\0';
-   }
-
-   /* get encrypted password */
-   strcpy(passwd, crypt(key, salt));
-
-#ifdef PG_PASSWD_DEBUG
-   /* show it */
-   fprintf(stderr, "key = %s, salt = %s, password = %s\n",
-           key, salt, passwd);
-#endif
-}
-
-static void
-prompt_for_username(char *username)
-{
-   int         length;
-
-   printf("Username: ");
-   fflush(stdout);
-   if (fgets(username, NAMEDATALEN, stdin) == NULL)
-       username[0] = '\0';
-
-   length = strlen(username);
-   if (length > 0 && username[length - 1] != '\n')
-   {
-       /* eat rest of the line */
-       char        buf[128];
-       int         buflen;
-
-       do
-       {
-           if (fgets(buf, sizeof(buf), stdin) == NULL)
-               break;
-           buflen = strlen(buf);
-       } while (buflen > 0 && buf[buflen - 1] != '\n');
-   }
-   if (length > 0 && username[length - 1] == '\n')
-       username[length - 1] = '\0';
-}
-
-static void
-prompt_for_password(char *prompt, char *password)
-{
-   int         length;
-
-#ifdef HAVE_TERMIOS_H
-   struct termios t_orig,
-               t;
-#endif
-
-#ifdef HAVE_TERMIOS_H
-   tcgetattr(0, &t);
-   t_orig = t;
-   t.c_lflag &= ~ECHO;
-   tcsetattr(0, TCSADRAIN, &t);
-#endif
-
-   printf(prompt);
-   fflush(stdout);
-
-   if (fgets(password, CLEAR_PASSWD_LEN + 1, stdin) == NULL)
-       password[0] = '\0';
-
-#ifdef HAVE_TERMIOS_H
-   tcsetattr(0, TCSADRAIN, &t_orig);
-#endif
-
-   length = strlen(password);
-   if (length > 0 && password[length - 1] != '\n')
-   {
-       /* eat rest of the line */
-       char        buf[128];
-       int         buflen;
-
-       do
-       {
-           if (fgets(buf, sizeof(buf), stdin) == NULL)
-               break;
-           buflen = strlen(buf);
-       } while (buflen > 0 && buf[buflen - 1] != '\n');
-   }
-   if (length > 0 && password[length - 1] == '\n')
-       password[length - 1] = '\0';
-   printf("\n");
-}
-
-
-int
-main(int argc, char *argv[])
-{
-   char       *filename;
-   char        bkname[MAXPGPATH];
-   char        username[NAMEDATALEN];
-   char        salt[3];
-   char        key[CLEAR_PASSWD_LEN + 1],
-               key2[CLEAR_PASSWD_LEN + 1];
-   char        e_passwd[CRYPTED_PASSWD_LEN + 1];
-   int         i;
-
-   progname = argv[0];
-
-   if (argc != 2)
-   {
-       fprintf(stderr, "%s: too %s arguments\nTry '%s --help' for more information.\n",
-               progname, argc > 2 ? "many" : "few", progname);
-       exit(1);
-   }
-
-   if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
-   {
-       usage();
-       exit(0);
-   }
-   if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
-   {
-       puts("pg_passwd (PostgreSQL) " PG_VERSION);
-       exit(0);
-   }
-   if (argv[1][0] == '-')
-   {
-       fprintf(stderr, "%s: invalid option: %s\nTry '%s --help' for more information.\n",
-               progname, argv[1], progname);
-       exit(1);
-   }
-
-   filename = argv[1];
-
-   /* open file */
-   read_pwd_file(filename);
-
-   /* ask for the user name and the password */
-   prompt_for_username(username);
-   prompt_for_password("New password: ", key);
-   prompt_for_password("Re-enter new password: ", key2);
-   if (strcmp(key, key2) != 0)
-   {
-       fprintf(stderr, "Password mismatch\n");
-       exit(1);
-   }
-   salt[0] = '\0';
-   encrypt_pwd(key, salt, e_passwd);
-
-   /* check password entry */
-   for (i = 0; i < npwds; ++i)
-   {
-       if (strcmp(pwds[i].uname, username) == 0)
-       {                       /* found */
-           pwds[i].pwd = strdup(e_passwd);
-           break;
-       }
-   }
-   if (i == npwds)
-   {                           /* did not exist */
-       if (npwds == MAXPWDS)
-       {
-           fprintf(stderr, "Cannot handle so many entries\n");
-           exit(1);
-       }
-       pwds[npwds].uname = strdup(username);
-       pwds[npwds].pwd = strdup(e_passwd);
-       pwds[npwds].rest = NULL;
-       ++npwds;
-   }
-
-   /* write back the file */
-   sprintf(bkname, "%s.bk", filename);
-   write_pwd_file(filename, bkname);
-
-   return 0;
-}
index ac32bd69aa0ee46ab21a8af4997c5eb8aab06e93..cd939a9c10a39e37da12ac34cfec8e3129db37e6 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.224 2002/03/29 19:06:19 tgl Exp $
+ * $Id: pg_proc.h,v 1.225 2002/04/04 04:25:52 momjian Exp $
  *
  * NOTES
  *   The script catalog/genbki.sh reads this file and generates .bki
@@ -2101,8 +2101,8 @@ DESCR("does not match LIKE expression, case-insensitive");
 DATA(insert OID = 1637 (  like_escape      PGUID 12 f t t t 2 f 25 "25 25" 100 0 0 100 like_escape - _null_ ));
 DESCR("convert match pattern to use backslash escapes");
 
-DATA(insert OID = 1689 (  update_pg_pwd          PGUID 12 f t f t 0 f 0  ""  100 0 0 100  update_pg_pwd - _null_ ));
-DESCR("update pg_pwd file");
+DATA(insert OID = 1689 (  update_pg_pwd_and_pg_group  PGUID 12 f t f t 0 f 0  ""  100 0 0 100  update_pg_pwd_and_pg_group - _null_ ));
+DESCR("update pg_pwd and pg_group files");
 
 /* Oracle Compatibility Related Functions - By Edmund Mergl  */
 DATA(insert OID =  868 (  strpos      PGUID 12 f t t t 2 f 23 "25 25" 100 0 0 100  textpos - _null_ ));
index 351c2d6ef6dd7d677404f730d349cc05229d6f9d..046e022ae8fea6c53722184a6473691fa18a2530 100644 (file)
@@ -3,15 +3,23 @@
  * user.h
  *
  *
- * $Id: user.h,v 1.17 2002/03/01 22:45:17 petere Exp $
+ * $Id: user.h,v 1.18 2002/04/04 04:25:53 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef USER_H
 #define USER_H
 
+#include "fmgr.h"
 #include "nodes/parsenodes.h"
 
+#define PWD_FILE   "pg_pwd"
+
+#define USER_GROUP_FILE    "pg_group"
+
+
+extern char *group_getfilename(void);
+extern char *user_getfilename(void);
 extern void CreateUser(CreateUserStmt *stmt);
 extern void AlterUser(AlterUserStmt *stmt);
 extern void AlterUserSet(AlterUserSetStmt *stmt);
@@ -21,6 +29,6 @@ extern void CreateGroup(CreateGroupStmt *stmt);
 extern void AlterGroup(AlterGroupStmt *stmt, const char *tag);
 extern void DropGroup(DropGroupStmt *stmt);
 
-extern Datum update_pg_pwd(PG_FUNCTION_ARGS);
+extern Datum update_pg_pwd_and_pg_group(PG_FUNCTION_ARGS);
 
 #endif   /* USER_H */
index 458be1fd2cfc584414fb104a6e963782198e9651..a521a0e2ceeacb84c96a841ac674662fde9615fb 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: crypt.h,v 1.19 2001/11/12 01:52:46 momjian Exp $
+ * $Id: crypt.h,v 1.20 2002/04/04 04:25:53 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,8 +15,6 @@
 
 #include "libpq/libpq-be.h"
 
-#define CRYPT_PWD_FILE_SEPSTR  "\t"
-
 /* Also defined in interfaces/odbc/md5.h */
 #define MD5_PASSWD_LEN 35
 
@@ -24,9 +22,6 @@
                         strlen(passwd) == MD5_PASSWD_LEN)
 
 
-extern char *crypt_getpwdfilename(void);
-extern void load_password_cache(void);
-
 extern int md5_crypt_verify(const Port *port, const char *user,
                 const char *pgpass);
 extern bool md5_hash(const void *buff, size_t len, char *hexsum);
index 0d5ddbaf7020e147e68304ad998c7311fa99f4cf..b9daf985f5c47996c0083818dd4d0af39c7201e5 100644 (file)
@@ -4,7 +4,7 @@
  *   Interface to hba.c
  *
  *
- * $Id: hba.h,v 1.31 2001/11/05 17:46:33 momjian Exp $
+ * $Id: hba.h,v 1.32 2002/04/04 04:25:54 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include 
 #endif
 
+#include "nodes/pg_list.h"
+
 #define CONF_FILE "pg_hba.conf"
  /* Name of the config file  */
 
 #define USERMAP_FILE "pg_ident.conf"
  /* Name of the usermap file */
 
-#define OLD_CONF_FILE "pg_hba"
- /* Name of the config file in prior releases of Postgres. */
-
 #define IDENT_PORT 113
  /* Standard TCP port number for Ident service.  Assigned by IANA */
 
@@ -46,8 +45,15 @@ typedef enum UserAuth
 
 typedef struct Port hbaPort;
 
+#define MAX_TOKEN  256
+
+extern void next_token(FILE *fp, char *buf, const int bufsz);
+extern List **get_user_line(const char *user);
+extern void load_hba(void);
+extern void load_ident(void);
+extern void load_user(void);
+extern void load_group(void);
 extern int hba_getauthmethod(hbaPort *port);
 extern int authident(hbaPort *port);
-extern void load_hba_and_ident(void);
 
 #endif
index 4fb6447392427f9b3d70268670189eb73185c537..99f7fae88bf9cfaad0fffc9c393f4fc42b89a2e9 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: miscadmin.h,v 1.101 2002/03/04 01:46:04 tgl Exp $
+ * $Id: miscadmin.h,v 1.102 2002/04/04 04:25:51 momjian Exp $
  *
  * NOTES
  *   some of the information in this file should be moved to
@@ -219,7 +219,6 @@ extern int FindExec(char *full_path, const char *argv0,
 extern int CheckPathAccess(char *path, char *name, int open_mode);
 
 #ifdef CYR_RECODE
-extern void GetCharSetByHost(char *TableName, int host, const char *DataDir);
 extern void SetCharSet(void);
 extern char *convertstr(unsigned char *buff, int len, int dest);
 #endif
index be08da8237108dc8d49c293ce63f6322ee1095be..39130f2a5e3b2feaec32a0ccaeec7d43f3404755 100644 (file)
@@ -30,7 +30,7 @@ WHERE (p1.prolang = 0 OR p1.prorettype = 0 OR
    AND p1.proname !~ '^pl[^_]+_call_handler$'
    AND p1.proname !~ '^RI_FKey_'
    AND p1.proname !~ 'costestimate$'
-   AND p1.proname != 'update_pg_pwd';
+   AND p1.proname != 'update_pg_pwd_and_pg_group';
  oid | proname 
 -----+---------
 (0 rows)
index 7a5991a74a1794a34164a2fc5d0135a040df7c36..6a95c4cd1bea1c53f70861ee9a0d85e6c5bbb006 100644 (file)
@@ -33,7 +33,7 @@ WHERE (p1.prolang = 0 OR p1.prorettype = 0 OR
    AND p1.proname !~ '^pl[^_]+_call_handler$'
    AND p1.proname !~ '^RI_FKey_'
    AND p1.proname !~ 'costestimate$'
-   AND p1.proname != 'update_pg_pwd';
+   AND p1.proname != 'update_pg_pwd_and_pg_group';
 
 -- Look for conflicting proc definitions (same names and input datatypes).
 -- (This test should be dead code now that we have the unique index