Greetings,

  The attached patch fixes a bug which was originally brought up in May
  of 2002 in this thread:

  http://archives.postgresql.org/pgsql-interfaces/2002-05/msg00083.php

  The original bug reporter also supplied a patch to fix the problem:

  http://archives.postgresql.org/pgsql-interfaces/2002-05/msg00090.php

  I ran into exactly the same issue using 8.1.2.  I've updated the
  original patch to work for HEAD and 8.1.2.  I've tested the patch on
  both HEAD and 8.1.2, both at home and at work, and it works quite
  nicely.  In fact, I hope to have a patch to phppgadmin which will make
  it properly handle Kerberized logins.

        Thanks,

                Stephen
Index: src/interfaces/libpq/fe-auth.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v
retrieving revision 1.110
diff -c -r1.110 fe-auth.c
*** src/interfaces/libpq/fe-auth.c      26 Dec 2005 14:58:05 -0000      1.110
--- src/interfaces/libpq/fe-auth.c      5 Feb 2006 20:03:21 -0000
***************
*** 101,122 ****
   * Various krb5 state which is not connection specific, and a flag to
   * indicate whether we have initialised it yet.
   */
  static int    pg_krb5_initialised;
  static krb5_context pg_krb5_context;
  static krb5_ccache pg_krb5_ccache;
  static krb5_principal pg_krb5_client;
  static char *pg_krb5_name;
  
  
  static int
! pg_krb5_init(char *PQerrormsg)
  {
        krb5_error_code retval;
  
!       if (pg_krb5_initialised)
                return STATUS_OK;
  
!       retval = krb5_init_context(&pg_krb5_context);
        if (retval)
        {
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
--- 101,133 ----
   * Various krb5 state which is not connection specific, and a flag to
   * indicate whether we have initialised it yet.
   */
+ /* 
  static int    pg_krb5_initialised;
  static krb5_context pg_krb5_context;
  static krb5_ccache pg_krb5_ccache;
  static krb5_principal pg_krb5_client;
  static char *pg_krb5_name;
+ */
+ 
+ struct krb5_info
+ {
+       int             pg_krb5_initialised;
+       krb5_context    pg_krb5_context;
+       krb5_ccache     pg_krb5_ccache;
+       krb5_principal  pg_krb5_client;
+       char            *pg_krb5_name;
+ };
  
  
  static int
! pg_krb5_init(char *PQerrormsg, struct krb5_info *info)
  {
        krb5_error_code retval;
  
!       if (info->pg_krb5_initialised)
                return STATUS_OK;
  
!       retval = krb5_init_context(&(info->pg_krb5_context));
        if (retval)
        {
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
***************
*** 125,170 ****
                return STATUS_ERROR;
        }
  
!       retval = krb5_cc_default(pg_krb5_context, &pg_krb5_ccache);
        if (retval)
        {
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                                 "pg_krb5_init: krb5_cc_default: %s\n",
                                 error_message(retval));
!               krb5_free_context(pg_krb5_context);
                return STATUS_ERROR;
        }
  
!       retval = krb5_cc_get_principal(pg_krb5_context, pg_krb5_ccache,
!                                                                  
&pg_krb5_client);
        if (retval)
        {
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                                 "pg_krb5_init: krb5_cc_get_principal: %s\n",
                                 error_message(retval));
!               krb5_cc_close(pg_krb5_context, pg_krb5_ccache);
!               krb5_free_context(pg_krb5_context);
                return STATUS_ERROR;
        }
  
!       retval = krb5_unparse_name(pg_krb5_context, pg_krb5_client, 
&pg_krb5_name);
        if (retval)
        {
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                                 "pg_krb5_init: krb5_unparse_name: %s\n",
                                 error_message(retval));
!               krb5_free_principal(pg_krb5_context, pg_krb5_client);
!               krb5_cc_close(pg_krb5_context, pg_krb5_ccache);
!               krb5_free_context(pg_krb5_context);
                return STATUS_ERROR;
        }
  
!       pg_krb5_name = pg_an_to_ln(pg_krb5_name);
  
!       pg_krb5_initialised = 1;
        return STATUS_OK;
  }
  
  
  /*
   * pg_krb5_authname -- returns a pointer to static space containing whatever
--- 136,191 ----
                return STATUS_ERROR;
        }
  
!       retval = krb5_cc_default(info->pg_krb5_context, 
&(info->pg_krb5_ccache));
        if (retval)
        {
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                                 "pg_krb5_init: krb5_cc_default: %s\n",
                                 error_message(retval));
!               krb5_free_context(info->pg_krb5_context);
                return STATUS_ERROR;
        }
  
!       retval = krb5_cc_get_principal(info->pg_krb5_context, 
info->pg_krb5_ccache,
!                                                                  
&(info->pg_krb5_client));
        if (retval)
        {
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                                 "pg_krb5_init: krb5_cc_get_principal: %s\n",
                                 error_message(retval));
!               krb5_cc_close(info->pg_krb5_context, info->pg_krb5_ccache);
!               krb5_free_context(info->pg_krb5_context);
                return STATUS_ERROR;
        }
  
!       retval = krb5_unparse_name(info->pg_krb5_context, info->pg_krb5_client, 
&(info->pg_krb5_name));
        if (retval)
        {
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                                 "pg_krb5_init: krb5_unparse_name: %s\n",
                                 error_message(retval));
!               krb5_free_principal(info->pg_krb5_context, 
info->pg_krb5_client);
!               krb5_cc_close(info->pg_krb5_context, info->pg_krb5_ccache);
!               krb5_free_context(info->pg_krb5_context);
                return STATUS_ERROR;
        }
  
!       info->pg_krb5_name = pg_an_to_ln(info->pg_krb5_name);
  
!       info->pg_krb5_initialised = 1;
        return STATUS_OK;
  }
  
+ static void 
+ pg_krb5_destroy(struct krb5_info *info)
+ {
+       krb5_free_principal(info->pg_krb5_context, info->pg_krb5_client);
+       krb5_cc_close(info->pg_krb5_context, info->pg_krb5_ccache);
+       krb5_free_context(info->pg_krb5_context);
+       free(info->pg_krb5_name);
+ }
+ 
+ 
  
  /*
   * pg_krb5_authname -- returns a pointer to static space containing whatever
***************
*** 173,182 ****
  static const char *
  pg_krb5_authname(char *PQerrormsg)
  {
!       if (pg_krb5_init(PQerrormsg) != STATUS_OK)
                return NULL;
  
!       return pg_krb5_name;
  }
  
  
--- 194,209 ----
  static const char *
  pg_krb5_authname(char *PQerrormsg)
  {
!       char *tmp_name;
!       struct krb5_info info;
!       info.pg_krb5_initialised = 0;
! 
!       if (pg_krb5_init(PQerrormsg, &info) != STATUS_OK)
                return NULL;
+       tmp_name = strdup(info.pg_krb5_name);
+       pg_krb5_destroy(&info);
  
!       return tmp_name;
  }
  
  
***************
*** 192,197 ****
--- 219,226 ----
        krb5_principal server;
        krb5_auth_context auth_context = NULL;
        krb5_error *err_ret = NULL;
+       struct krb5_info info;
+       info.pg_krb5_initialised = 0;
  
        if (!hostname)
        {
***************
*** 200,216 ****
                return STATUS_ERROR;
        }
  
!       ret = pg_krb5_init(PQerrormsg);
        if (ret != STATUS_OK)
                return ret;
  
!       retval = krb5_sname_to_principal(pg_krb5_context, hostname, servicename,
                                                                         
KRB5_NT_SRV_HST, &server);
        if (retval)
        {
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                                 "pg_krb5_sendauth: krb5_sname_to_principal: 
%s\n",
                                 error_message(retval));
                return STATUS_ERROR;
        }
  
--- 229,246 ----
                return STATUS_ERROR;
        }
  
!       ret = pg_krb5_init(PQerrormsg, &info);
        if (ret != STATUS_OK)
                return ret;
  
!       retval = krb5_sname_to_principal(info.pg_krb5_context, hostname, 
servicename,
                                                                         
KRB5_NT_SRV_HST, &server);
        if (retval)
        {
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                                 "pg_krb5_sendauth: krb5_sname_to_principal: 
%s\n",
                                 error_message(retval));
+               pg_krb5_destroy(&info);
                return STATUS_ERROR;
        }
  
***************
*** 225,240 ****
  
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                                 libpq_gettext("could not set socket to 
blocking mode: %s\n"), pqStrerror(errno, sebuf, sizeof(sebuf)));
!               krb5_free_principal(pg_krb5_context, server);
                return STATUS_ERROR;
        }
  
!       retval = krb5_sendauth(pg_krb5_context, &auth_context,
                                                   (krb5_pointer) & sock, (char 
*) servicename,
!                                                  pg_krb5_client, server,
                                                   AP_OPTS_MUTUAL_REQUIRED,
                                                   NULL, 0,             /* no 
creds, use ccache instead */
!                                                  pg_krb5_ccache, &err_ret, 
NULL, NULL);
        if (retval)
        {
                if (retval == KRB5_SENDAUTH_REJECTED && err_ret)
--- 255,271 ----
  
                snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                                 libpq_gettext("could not set socket to 
blocking mode: %s\n"), pqStrerror(errno, sebuf, sizeof(sebuf)));
!               krb5_free_principal(info.pg_krb5_context, server);
!               pg_krb5_destroy(&info);
                return STATUS_ERROR;
        }
  
!       retval = krb5_sendauth(info.pg_krb5_context, &auth_context,
                                                   (krb5_pointer) & sock, (char 
*) servicename,
!                                                  info.pg_krb5_client, server,
                                                   AP_OPTS_MUTUAL_REQUIRED,
                                                   NULL, 0,             /* no 
creds, use ccache instead */
!                                                  info.pg_krb5_ccache, 
&err_ret, NULL, NULL);
        if (retval)
        {
                if (retval == KRB5_SENDAUTH_REJECTED && err_ret)
***************
*** 259,270 ****
                }
  
                if (err_ret)
!                       krb5_free_error(pg_krb5_context, err_ret);
  
                ret = STATUS_ERROR;
        }
  
!       krb5_free_principal(pg_krb5_context, server);
  
        if (!pg_set_noblock(sock))
        {
--- 290,301 ----
                }
  
                if (err_ret)
!                       krb5_free_error(info.pg_krb5_context, err_ret);
  
                ret = STATUS_ERROR;
        }
  
!       krb5_free_principal(info.pg_krb5_context, server);
  
        if (!pg_set_noblock(sock))
        {
***************
*** 275,280 ****
--- 306,312 ----
                                 pqStrerror(errno, sebuf, sizeof(sebuf)));
                ret = STATUS_ERROR;
        }
+       pg_krb5_destroy(&info);
  
        return ret;
  }
***************
*** 487,492 ****
--- 519,527 ----
  char *
  pg_fe_getauthname(char *PQerrormsg)
  {
+ #ifdef KRB5
+       const char *krb5_name = NULL;
+ #endif
        const char *name = NULL;
        char       *authn;
  
***************
*** 511,517 ****
        pglock_thread();
  
  #ifdef KRB5
!       name = pg_krb5_authname(PQerrormsg);
  #endif
  
        if (!name)
--- 546,557 ----
        pglock_thread();
  
  #ifdef KRB5
!       /* pg_krb5_authname gives us a strdup'd value that we need
!        * to free later, however, we don't want to free 'name' directly
!        * in case it's *not* a Kerberos login and we fall through to
!        * name = pw->pw_name; */
!       krb5_name = pg_krb5_authname(PQerrormsg);
!       name = krb5_name;
  #endif
  
        if (!name)
***************
*** 527,532 ****
--- 567,578 ----
  
        authn = name ? strdup(name) : NULL;
  
+ #ifdef KRB5
+       /* Free the strdup'd string from pg_krb5_authname, if we got one */
+       if (krb5_name)
+               free(krb5_name);
+ #endif
+ 
        pgunlock_thread();
  
        return authn;
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

Reply via email to