Thread: Re: [ADMIN] PAM

Re: [ADMIN] PAM

From
Bruce Momjian
Date:
I am not sure, but it is possible you are seeing a problem with the new
storage of passwords as MD5 encrypted on pg_shadow.  The attached patch
fixes this.

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

Tim Frank wrote:
> I was testing this on a 7.3 beta the other week to try to make it work
> with LDAP authentication, and I think I only got it working if I bypased
> the system-auth PAM file that everything was normally funneled through.
>   I don't know exactly why it wasn't working, but whenever I put a line
> that used pam_unix.so it would fail with the same error you are
> encountering.
>
> I didn't invest a huge amount of time figuring out why pam_unix.so was
> causing a problem because I wanted to use pam_ldap.so anyways.
>
> There doesn't seem to be many examples out there that I could find that
> I got to work.  FYI I am testing on RedHat 7.x and 8.0 machines.
>
> Tim
>
> EMOTO Masahiko wrote:
> > Does anyone show me a sample of PAM authenticate file?
> >
> > I want to use pam for client authentication, and I create pg_hba.cnf as,
> >
> >
> >>host    all         all         127.0.0.1         255.255.255.255   trust
> >>host    all         all         192.168.0.0        255.255.0.0   pam postgresql
> >
> >
> > and /etc/pam.d/postgresql as
> >
> >>auth       required     /lib/security/pam_stack.so service=system-auth
> >>account    required     /lib/security/pam_stack.so service=system-auth
> >
> >
> > I tried to connect to the server, but failed. The messages I received were follows;
> >
> >
> >>[CLIENT]
> >>% psql -h dgpc1 db1 -U emo
> >>Password:
> >>psql: FATAL:  PAM authentication failed for user "emo"
> >>
> >>[SERVER]
> >>DEBUG:  reaping dead processes
> >>DEBUG:  child process (pid 15642) exited with exit code 0
> >>DEBUG:  BackendStartup: forked pid=15643 socket=8
> >>DEBUG:  received PAM packet
> >>LOG:  CheckPAMAuth: pam_authenticate failed: 'Authentication failure'
> >>FATAL:  PAM authentication failed for user "emo"
> >>DEBUG:  proc_exit(0)
> >>DEBUG:  shmem_exit(0)
> >>DEBUG:  exit(0)
> >>DEBUG:  reaping dead processes
> >
> >
> > The user account exists in the database, and I typed the system password.
> >
> >
> > Environment:
> > OS : Linux Kernel 2.4.19
> > PostgreSQL 7.3
> >
> >
> > By the way, what really I want to do is to configure the server behave like FTP servers;
> > All the users except the guest (anonymous) requires the password authentication.
> > The guest user can only read the data, and cannot alter the data.
> > Are there any solutions to do this?
> >
> >
> >                                                         --- EMOTO Masahiko ---
> >
> > ---------------------------(end of broadcast)---------------------------
> > TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
> subscribe-nomail command to majordomo@postgresql.org so that your
> message can get through to the mailing list cleanly
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: src/backend/libpq/crypt.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/libpq/crypt.c,v
retrieving revision 1.49
diff -c -c -r1.49 crypt.c
*** src/backend/libpq/crypt.c    4 Sep 2002 20:31:19 -0000    1.49
--- src/backend/libpq/crypt.c    5 Dec 2002 18:03:53 -0000
***************
*** 29,35 ****


  int
! md5_crypt_verify(const Port *port, const char *user, const char *pgpass)
  {
      char       *passwd = NULL,
                 *valuntil = NULL,
--- 29,35 ----


  int
! md5_crypt_verify(const Port *port, const char *user, char *pgpass)
  {
      char       *passwd = NULL,
                 *valuntil = NULL,
***************
*** 37,42 ****
--- 37,43 ----
      int            retval = STATUS_ERROR;
      List      **line;
      List       *token;
+     char       *crypt_pgpass = pgpass;

      if ((line = get_user_line(user)) == NULL)
          return STATUS_ERROR;
***************
*** 54,64 ****
      if (passwd == NULL || *passwd == '\0')
          return STATUS_ERROR;

!     /* If they encrypt their password, force MD5 */
!     if (isMD5(passwd) && port->auth_method != uaMD5)
      {
          elog(LOG, "Password is stored MD5 encrypted.  "
!              "'password' and 'crypt' auth methods cannot be used.");
          return STATUS_ERROR;
      }

--- 55,65 ----
      if (passwd == NULL || *passwd == '\0')
          return STATUS_ERROR;

!     /* We can't do crypt with pg_shadow MD5 passwords */
!     if (isMD5(passwd) && port->auth_method == uaCrypt)
      {
          elog(LOG, "Password is stored MD5 encrypted.  "
!              "'crypt' auth method cannot be used.");
          return STATUS_ERROR;
      }

***************
*** 72,77 ****
--- 73,79 ----
              crypt_pwd = palloc(MD5_PASSWD_LEN + 1);
              if (isMD5(passwd))
              {
+                 /* pg_shadow already encrypted, only do salt */
                  if (!EncryptMD5(passwd + strlen("md5"),
                                  (char *) port->md5Salt,
                                  sizeof(port->md5Salt), crypt_pwd))
***************
*** 82,87 ****
--- 84,90 ----
              }
              else
              {
+                 /* pg_shadow plain, double-encrypt */
                  char       *crypt_pwd2 = palloc(MD5_PASSWD_LEN + 1);

                  if (!EncryptMD5(passwd, port->user, strlen(port->user),
***************
*** 110,120 ****
                  break;
              }
          default:
              crypt_pwd = passwd;
              break;
      }

!     if (strcmp(pgpass, crypt_pwd) == 0)
      {
          /*
           * Password OK, now check to be sure we are not past valuntil
--- 113,134 ----
                  break;
              }
          default:
+             if (isMD5(passwd))
+             {
+                 /* Encrypt user-supplied password to match MD5 in pg_shadow */
+                 crypt_pgpass = palloc(MD5_PASSWD_LEN + 1);
+                 if (!EncryptMD5(pgpass, port->user, strlen(port->user),
+                                 crypt_pgpass))
+                 {
+                     pfree(crypt_pgpass);
+                     return STATUS_ERROR;
+                 }
+             }
              crypt_pwd = passwd;
              break;
      }

!     if (strcmp(crypt_pgpass, crypt_pwd) == 0)
      {
          /*
           * Password OK, now check to be sure we are not past valuntil
***************
*** 136,141 ****
--- 150,157 ----

      if (port->auth_method == uaMD5)
          pfree(crypt_pwd);
+     if (crypt_pgpass != pgpass)
+         pfree(crypt_pgpass);

      return retval;
  }
Index: src/include/libpq/crypt.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/libpq/crypt.h,v
retrieving revision 1.22
diff -c -c -r1.22 crypt.h
*** src/include/libpq/crypt.h    4 Sep 2002 20:31:42 -0000    1.22
--- src/include/libpq/crypt.h    5 Dec 2002 18:03:54 -0000
***************
*** 23,29 ****


  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);
  extern bool CheckMD5Pwd(char *passwd, char *storedpwd, char *seed);

--- 23,29 ----


  extern int md5_crypt_verify(const Port *port, const char *user,
!                 char *pgpass);
  extern bool md5_hash(const void *buff, size_t len, char *hexsum);
  extern bool CheckMD5Pwd(char *passwd, char *storedpwd, char *seed);