COMMAND

    kth-krb

SYSTEMS AFFECTED

    - MIT Kerberos 5, all releases prior to krb5-1.2.2-beta1
    - MIT Kerberos 4 patch 10, and likely earlier releases as well
    - Kerbnet (Cygnus implementation of Kerberos 5)
    - Cygnus Network Security (CNS -- Cygnus implementation of Kerberos 4)

PROBLEM

    Jouko  Pynnonen  and  Assar  Westerlund  discovered  and  reported
    following.    A  /tmp   race  condition   exists  in   MIT-derived
    implementations of Kerberos 4.  On a system running login  daemons
    with Kerberos  4 support,  a local  user may  be able to overwrite
    arbitrary  files  as  root,  with  limited  contents.   This could
    potentially result in unauthorized root access.

    A filesystem  race condition  exists in  the ticket  file handling
    code in the krb4 library.   This race condition has existed  since
    the early MIT implementations of Kerberos 4.  By winning this race
    condition, especially while new ticket files are being created  by
    login  daemons  running  as  root,  a user may overwrite arbitrary
    files as root, but with  limited contents.  The possible  contents
    of the overwritten files are limited to the initial contents of  a
    normal Kerberos 4 ticket file.

SOLUTION

    The MIT krb5-1.2.2 release  contains a fix for  this bug.  If  you
    are unable to upgrade to krb5-1.2.2, the best course of action  is
    to patch  the krb4  library, and  recompile or  relink your  login
    daemons.   Patches  below   are  only  provided  for   krb5-1.2.1;
    additional patches  against other  releases may  be generated  and
    posted if  requested.   These patches  are against  the krb5-1.2.1
    release.  They  may apply against  earlier releases, though.   The
    patches may also be found at:

        http://web.mit.edu/kerberos/www/advisories/krb4tkt_121_patch.txt

    Patches:

    Index: lib/krb4/dest_tkt.c
    ===================================================================
    RCS file: /cvs/krbdev/krb5/src/lib/krb4/dest_tkt.c,v
    retrieving revision 1.5.8.1
    retrieving revision 1.5.8.2
    diff -c -r1.5.8.1 -r1.5.8.2
    *** dest_tkt.c	2000/04/29 01:48:10	1.5.8.1
    --- dest_tkt.c	2001/01/27 04:43:31	1.5.8.2
    ***************
    *** 1,14 ****
      /*
    !  * dest_tkt.c
       *
    !  * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
    !  * of Technology.
       *
    !  * For copying and distribution information, please see the file
    !  * <mit-copyright.h>.
       */

    - #include "mit-copyright.h"
      #include "krb.h"
      #include <stdio.h>
      #include <string.h>
    --- 1,29 ----
      /*
    !  * lib/krb4/dest_tkt.c
       *
    !  * Copyright 1985, 1986, 1987, 1988, 2000, 2001 by the Massachusetts
    !  * Institute of Technology.  All Rights Reserved.
       *
    !  * Export of this software from the United States of America may
    !  *   require a specific license from the United States Government.
    !  *   It is the responsibility of any person or organization contemplating
    !  *   export to obtain such a license before exporting.
    !  *
    !  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
    !  * distribute this software and its documentation for any purpose and
    !  * without fee is hereby granted, provided that the above copyright
    !  * notice appear in all copies and that both that copyright notice and
    !  * this permission notice appear in supporting documentation, and that
    !  * the name of M.I.T. not be used in advertising or publicity pertaining
    !  * to distribution of the software without specific, written prior
    !  * permission.  Furthermore if you modify this software you must label
    !  * your software as modified software and not distribute it in such a
    !  * fashion that it might be confused with the original M.I.T. software.
    !  * M.I.T. makes no representations about the suitability of
    !  * this software for any purpose.  It is provided "as is" without express
    !  * or implied warranty.
       */

      #include "krb.h"
      #include <stdio.h>
      #include <string.h>
    ***************
    *** 17,28 ****
    --- 32,60 ----
      #ifdef TKT_SHMEM
      #include <sys/param.h>
      #endif
    + #ifdef HAVE_UNISTD_H
    + #include <unistd.h>
    + #endif
      #include <errno.h>

      #ifndef O_SYNC
      #define O_SYNC 0
      #endif

    + #ifdef HAVE_SETEUID
    + #define do_seteuid(e) seteuid((e))
    + #else
    + #ifdef HAVE_SETRESUID
    + #define do_seteuid(e) setresuid(-1, (e), -1)
    + #else
    + #ifdef HAVE_SETREUID
    + #define do_seteuid(e) setreuid(geteuid(), (e))
    + #else
    + #define do_seteuid(e) (errno = EPERM, -1)
    + #endif
    + #endif
    + #endif
    +
      /*
       * dest_tkt() is used to destroy the ticket store upon logout.
       * If the ticket file does not exist, dest_tkt() returns RET_TKFIL.
    ***************
    *** 38,47 ****
          char *file = TKT_FILE;
          int i,fd;
          extern int errno;
    !     struct stat statb;
          char buf[BUFSIZ];
      #ifdef TKT_SHMEM
          char shmidname[MAXPATHLEN];
      #endif /* TKT_SHMEM */

          /* If ticket cache selector is null, use default cache.  */
    --- 70,82 ----
          char *file = TKT_FILE;
          int i,fd;
          extern int errno;
    !     int ret;
    !     struct stat statpre, statpost;
          char buf[BUFSIZ];
    +     uid_t me, metoo;
      #ifdef TKT_SHMEM
          char shmidname[MAXPATHLEN];
    +     size_t shmidlen;
      #endif /* TKT_SHMEM */

          /* If ticket cache selector is null, use default cache.  */
    ***************
    *** 49,70 ****
  	    file = tkt_string();

          errno = 0;
    !     if (lstat(file,&statb) < 0)
  	    goto out;
    !
    !     if (!(statb.st_mode & S_IFREG)
    ! #ifdef notdef
    ! 	|| statb.st_mode & 077
    ! #endif
    ! 	)
  	    goto out;
    !
    !     if ((fd = open(file, O_RDWR|O_SYNC, 0)) < 0)
  	    goto out;

          memset(buf, 0, BUFSIZ);
    !
    !     for (i = 0; i < statb.st_size; i += BUFSIZ)
  	    if (write(fd, buf, BUFSIZ) != BUFSIZ) {
      #ifndef NO_FSYNC
  	        (void) fsync(fd);
    --- 84,139 ----
  	    file = tkt_string();

          errno = 0;
    !     ret = KSUCCESS;
    !     me = getuid();
    !     metoo = geteuid();
    !
    !     if (lstat(file, &statpre) < 0)
    ! 	return (errno == ENOENT) ? RET_TKFIL : KFAILURE;
    !     /*
    !      * This does not guard against certain cases that are vulnerable
    !      * to race conditions, such as world-writable or group-writable
    !      * directories that are not stickybitted, or untrusted path
    !      * components.  In all other cases, the following checks should be
    !      * sufficient.  It is assumed that the aforementioned certain
    !      * vulnerable cases are unlikely to arise on a well-administered
    !      * system where the user is not deliberately being stupid.
    !      */
    !     if (!(statpre.st_mode & S_IFREG) || me != statpre.st_uid
    ! 	|| statpre.st_nlink != 1)
    ! 	return KFAILURE;
    !     /*
    !      * Yes, we do uid twiddling here.  It's not optimal, but some
    !      * applications may expect that the ruid is what should really own
    !      * the ticket file, e.g. setuid applications.
    !      */
    !     if (me != metoo && do_seteuid(me) < 0)
    ! 	return KFAILURE;
    !     if ((fd = open(file, O_RDWR|O_SYNC, 0)) < 0) {
    ! 	ret = (errno == ENOENT) ? RET_TKFIL : KFAILURE;
  	    goto out;
    !     }
    !     /*
    !      * Do some additional paranoid things.  The worst-case situation
    !      * is that a user may be fooled into opening a non-regular file
    !      * briefly if the file is in a directory with improper
    !      * permissions.
    !      */
    !     if (fstat(fd, &statpost) < 0) {
    ! 	(void)close(fd);
    ! 	ret = KFAILURE;
  	    goto out;
    !     }
    !     if (statpre.st_dev != statpost.st_dev
    ! 	|| statpre.st_ino != statpost.st_ino) {
    ! 	(void)close(fd);
    ! 	errno = 0;
    ! 	ret = KFAILURE;
  	    goto out;
    +     }

          memset(buf, 0, BUFSIZ);
    !     for (i = 0; i < statpost.st_size; i += BUFSIZ)
  	    if (write(fd, buf, BUFSIZ) != BUFSIZ) {
      #ifndef NO_FSYNC
  	        (void) fsync(fd);
    ***************
    *** 81,97 ****
          (void) unlink(file);

      out:
    !     if (errno == ENOENT) return RET_TKFIL;
    !     else if (errno != 0) return KFAILURE;
      #ifdef TKT_SHMEM
          /*
           * handle the shared memory case
           */
    !     (void) strncpy(shmidname, file, sizeof(shmidname) - 1);
    !     shmidname[sizeof(shmidname) - 1] = '\0';
    !     (void) strcat(shmidname, ".shm", sizeof(shmidname) - 1 - strlen(shmidname));
    !     if ((i = krb_shm_dest(shmidname)) != KSUCCESS)
    ! 	return(i);
    ! #endif /* TKT_SHMEM */
    !     return(KSUCCESS);
      }
    --- 150,171 ----
          (void) unlink(file);

      out:
    !     if (me != metoo && do_seteuid(metoo) < 0)
    ! 	return KFAILURE;
    !     if (ret != KSUCCESS)
    ! 	return ret;
    !
      #ifdef TKT_SHMEM
          /*
           * handle the shared memory case
           */
    !     shmidlen = strlen(file) + sizeof(".shm");
    !     if (shmidlen > sizeof(shmidname))
    ! 	return RET_TKFIL;
    !     (void)strcpy(shmidname, file);
    !     (void)strcat(shmidname, ".shm");
    !     return krb_shm_dest(shmidname);
    ! #else  /* !TKT_SHMEM */
    !     return KSUCCESS;
    ! #endif /* !TKT_SHMEM */
      }
    Index: lib/krb4/in_tkt.c
    ===================================================================
    RCS file: /cvs/krbdev/krb5/src/lib/krb4/in_tkt.c,v
    retrieving revision 1.6.8.1
    retrieving revision 1.6.8.2
    diff -c -r1.6.8.1 -r1.6.8.2
    *** in_tkt.c	2000/04/29 01:48:10	1.6.8.1
    --- in_tkt.c	2001/01/27 04:43:32	1.6.8.2
    ***************
    *** 1,14 ****
      /*
    !  * in_tkt.c
       *
    !  * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
    !  * of Technology.
       *
    !  * For copying and distribution information, please see the file
    !  * <mit-copyright.h>.
       */

    - #include "mit-copyright.h"
      #include <stdio.h>
      #include <string.h>
      #include "krb.h"
    --- 1,29 ----
      /*
    !  * lib/krb4/in_tkt.c
       *
    !  * Copyright 1985, 1986, 1987, 1988, 2000, 2001 by the Massachusetts
    !  * Institute of Technology.  All Rights Reserved.
       *
    !  * Export of this software from the United States of America may
    !  *   require a specific license from the United States Government.
    !  *   It is the responsibility of any person or organization contemplating
    !  *   export to obtain such a license before exporting.
    !  *
    !  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
    !  * distribute this software and its documentation for any purpose and
    !  * without fee is hereby granted, provided that the above copyright
    !  * notice appear in all copies and that both that copyright notice and
    !  * this permission notice appear in supporting documentation, and that
    !  * the name of M.I.T. not be used in advertising or publicity pertaining
    !  * to distribution of the software without specific, written prior
    !  * permission.  Furthermore if you modify this software you must label
    !  * your software as modified software and not distribute it in such a
    !  * fashion that it might be confused with the original M.I.T. software.
    !  * M.I.T. makes no representations about the suitability of
    !  * this software for any purpose.  It is provided "as is" without express
    !  * or implied warranty.
       */

      #include <stdio.h>
      #include <string.h>
      #include "krb.h"
    ***************
    *** 34,40 ****
      #define do_seteuid(e) seteuid((e))
      #else
      #ifdef HAVE_SETRESUID
    ! #define do_seteuid(e) setresuid(getuid(), (e), geteuid())
      #else
      #ifdef HAVE_SETREUID
      #define do_seteuid(e) setreuid(geteuid(), (e))
    --- 49,55 ----
      #define do_seteuid(e) seteuid((e))
      #else
      #ifdef HAVE_SETRESUID
    ! #define do_seteuid(e) setresuid(-1, (e), -1)
      #else
      #ifdef HAVE_SETREUID
      #define do_seteuid(e) setreuid(geteuid(), (e))
    ***************
    *** 55,61 ****
      {
          int tktfile;
          uid_t me, metoo, getuid(), geteuid();
    !     struct stat buf;
          int count;
          char *file = TKT_FILE;
          int fd;
    --- 70,76 ----
      {
          int tktfile;
          uid_t me, metoo, getuid(), geteuid();
    !     struct stat statpre, statpost;
          int count;
          char *file = TKT_FILE;
          int fd;
    ***************
    *** 72,91 ****

          me = getuid ();
          metoo = geteuid();
    !     if (lstat(file,&buf) == 0) {
    ! 	if (buf.st_uid != me || !(buf.st_mode & S_IFREG) ||
    ! 	    buf.st_mode & 077) {
  	        if (krb_debug)
  		    fprintf(stderr,"Error initializing %s",file);
  	        return(KFAILURE);
  	    }
  	    /* file already exists, and permissions appear ok, so nuke it */
    ! 	if ((fd = open(file, O_RDWR|O_SYNC, 0)) < 0)
  	        goto out; /* can't zero it, but we can still try truncating it */

  	    memset(charbuf, 0, sizeof(charbuf));

    ! 	for (i = 0; i < buf.st_size; i += sizeof(charbuf))
  	        if (write(fd, charbuf, sizeof(charbuf)) != sizeof(charbuf)) {
      #ifndef NO_FSYNC
  		    (void) fsync(fd);
    --- 87,135 ----

          me = getuid ();
          metoo = geteuid();
    !     if (lstat(file, &statpre) == 0) {
    ! 	if (statpre.st_uid != me || !(statpre.st_mode & S_IFREG)
    ! 	    || statpre.st_nlink != 1 || statpre.st_mode & 077) {
  	        if (krb_debug)
  		    fprintf(stderr,"Error initializing %s",file);
  	        return(KFAILURE);
  	    }
    + 	/*
    + 	 * Yes, we do uid twiddling here.  It's not optimal, but some
    + 	 * applications may expect that the ruid is what should really
    + 	 * own the ticket file, e.g. setuid applications.
    + 	 */
    + 	if (me != metoo && do_seteuid(me) < 0)
    + 	    return KFAILURE;
  	    /* file already exists, and permissions appear ok, so nuke it */
    ! 	fd = open(file, O_RDWR|O_SYNC, 0);
    ! 	(void)unlink(file);
    ! 	if (me != metoo && do_seteuid(metoo) < 0)
    ! 	    return KFAILURE;
    ! 	if (fd < 0) {
  	        goto out; /* can't zero it, but we can still try truncating it */
    + 	}
    +
    + 	/*
    + 	 * Do some additional paranoid things.  The worst-case
    + 	 * situation is that a user may be fooled into opening a
    + 	 * non-regular file briefly if the file is in a directory with
    + 	 * improper permissions.
    + 	 */
    + 	if (fstat(fd, &statpost) < 0) {
    + 	    (void)close(fd);
    + 	    goto out;
    + 	}
    + 	if (statpre.st_dev != statpost.st_dev
    + 	    || statpre.st_ino != statpost.st_ino) {
    + 	    (void)close(fd);
    + 	    errno = 0;
    + 	    goto out;
    + 	}

  	    memset(charbuf, 0, sizeof(charbuf));

    ! 	for (i = 0; i < statpost.st_size; i += sizeof(charbuf))
  	        if (write(fd, charbuf, sizeof(charbuf)) != sizeof(charbuf)) {
      #ifndef NO_FSYNC
  		    (void) fsync(fd);
    ***************
    *** 117,128 ****
          /* Set umask to ensure that we have write access on the created
             ticket file.  */
          mask = umask(077);
    !     if ((tktfile = creat(file,0600)) < 0) {
    ! 	umask(mask);
    ! 	if (krb_debug)
    ! 	    fprintf(stderr,"Error initializing %s",TKT_FILE);
    !         return(KFAILURE);
    !     }
          umask(mask);
          if (me != metoo) {
  	    if (do_seteuid(metoo) < 0) {
    --- 161,167 ----
          /* Set umask to ensure that we have write access on the created
             ticket file.  */
          mask = umask(077);
    !     tktfile = open(file, O_RDWR|O_SYNC|O_CREAT|O_EXCL, 0600);
          umask(mask);
          if (me != metoo) {
  	    if (do_seteuid(metoo) < 0) {
    ***************
    *** 134,152 ****
  	        if (krb_debug)
  		    printf("swapped UID's %d and %d\n",me,metoo);
          }
    !     if (lstat(file,&buf) < 0) {
  	    if (krb_debug)
  	        fprintf(stderr,"Error initializing %s",TKT_FILE);
              return(KFAILURE);
          }
    -
    -     if (buf.st_uid != me || !(buf.st_mode & S_IFREG) ||
    -         buf.st_mode & 077) {
    - 	if (krb_debug)
    - 	    fprintf(stderr,"Error initializing %s",TKT_FILE);
    -         return(KFAILURE);
    -     }
    -
          count = strlen(pname)+1;
          if (write(tktfile,pname,count) != count) {
              (void) close(tktfile);
    --- 173,183 ----
  	        if (krb_debug)
  		    printf("swapped UID's %d and %d\n",me,metoo);
          }
    !     if (tktfile < 0) {
  	    if (krb_debug)
  	        fprintf(stderr,"Error initializing %s",TKT_FILE);
              return(KFAILURE);
          }
          count = strlen(pname)+1;
          if (write(tktfile,pname,count) != count) {
              (void) close(tktfile);
    Index: lib/krb4/tf_util.c
    ===================================================================
    RCS file: /cvs/krbdev/krb5/src/lib/krb4/tf_util.c,v
    retrieving revision 1.12.4.1
    retrieving revision 1.12.4.2
    diff -c -r1.12.4.1 -r1.12.4.2
    *** tf_util.c	2000/04/29 01:48:11	1.12.4.1
    --- tf_util.c	2001/01/27 04:43:32	1.12.4.2
    ***************
    *** 1,20 ****
      /*
    !  * tf_util.c
       *
    !  * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
       *
    !  * For copying and distribution information, please see the file
    !  * <mit-copyright.h>.
       */

    - #include "mit-copyright.h"
    -
      #include "krb.h"
      #include "k5-int.h"

      #include <stdio.h>
      #include <string.h>
      #include <errno.h>
      #include <sys/stat.h>
      #include <fcntl.h>

    --- 1,38 ----
      /*
    !  * lib/krb4/tf_util.c
       *
    !  * Copyright 1985, 1986, 1987, 1988, 2000, 2001 by the Massachusetts
    !  * Institute of Technology.  All Rights Reserved.
       *
    !  * Export of this software from the United States of America may
    !  *   require a specific license from the United States Government.
    !  *   It is the responsibility of any person or organization contemplating
    !  *   export to obtain such a license before exporting.
    !  *
    !  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
    !  * distribute this software and its documentation for any purpose and
    !  * without fee is hereby granted, provided that the above copyright
    !  * notice appear in all copies and that both that copyright notice and
    !  * this permission notice appear in supporting documentation, and that
    !  * the name of M.I.T. not be used in advertising or publicity pertaining
    !  * to distribution of the software without specific, written prior
    !  * permission.  Furthermore if you modify this software you must label
    !  * your software as modified software and not distribute it in such a
    !  * fashion that it might be confused with the original M.I.T. software.
    !  * M.I.T. makes no representations about the suitability of
    !  * this software for any purpose.  It is provided "as is" without express
    !  * or implied warranty.
       */

      #include "krb.h"
      #include "k5-int.h"

      #include <stdio.h>
      #include <string.h>
      #include <errno.h>
    + #ifdef HAVE_UNISTD_H
    + #include <unistd.h>
    + #endif
      #include <sys/stat.h>
      #include <fcntl.h>

    ***************
    *** 44,50 ****
      #ifdef NEED_UTIMES

      #include <sys/time.h>
    - #include <unistd.h>
      #ifdef __SCO__
      #include <utime.h>
      #endif
    --- 62,67 ----
    ***************
    *** 62,67 ****
    --- 79,98 ----
      }
      #endif

    + #ifdef HAVE_SETEUID
    + #define do_seteuid(e) seteuid((e))
    + #else
    + #ifdef HAVE_SETRESUID
    + #define do_seteuid(e) setresuid(-1, (e), -1)
    + #else
    + #ifdef HAVE_SETREUID
    + #define do_seteuid(e) setreuid(geteuid(), (e))
    + #else
    + #define do_seteuid(e) (errno = EPERM, -1)
    + #endif
    + #endif
    + #endif
    +
      /*
       * fd must be initialized to something that won't ever occur as a real
       * file descriptor. Since open(2) returns only non-negative numbers as
    ***************
    *** 149,155 ****
          int rw;
      {
          int     wflag;
    !     uid_t   me= getuid();
          struct stat stat_buf, stat_buffd;
      #ifdef TKT_SHMEM
          char shmidname[MAXPATHLEN];
    --- 180,186 ----
          int rw;
      {
          int     wflag;
    !     uid_t   me, metoo;
          struct stat stat_buf, stat_buffd;
      #ifdef TKT_SHMEM
          char shmidname[MAXPATHLEN];
    ***************
    *** 163,168 ****
    --- 194,200 ----
          }

          me = getuid();
    +     metoo = geteuid();

          switch (rw) {
          case R_TKT_FIL:
    ***************
    *** 196,203 ****
    --- 228,257 ----
          curpos = sizeof(tfbfr);

      #ifdef TKT_SHMEM
    +     if (lstat(shmidname, &stat_buf) < 0) {
    + 	switch (errno) {
    + 	case ENOENT:
    + 	    return NO_TKT_FIL;
    + 	default:
    + 	    return TKT_FIL_ACC;
    + 	}
    +     }
    +     if (stat_buf.st_uid != me || !(stat_buf.st_mode & S_IFREG)
    + 	|| stat_buf.st_nlink != 1 || stat_buf.st_mode & 077) {
    + 	return TKT_FIL_ACC;
    +     }
    +
    +     /*
    +      * Yes, we do uid twiddling here.  It's not optimal, but some
    +      * applications may expect that the ruid is what should really own
    +      * the ticket file, e.g. setuid applications.
    +      */
    +     if (me != metoo && do_seteuid(me) < 0)
    + 	return KFAILURE;
          sfp = fopen(shmidname, "r");	/* only need read/write on the
  					       actual tickets */
    +     if (me != metoo && do_seteuid(metoo) < 0)
    + 	return KFAILURE;
          if (sfp == 0) {
              switch(errno) {
              case ENOENT:
    ***************
    *** 207,216 ****
  	    }
          }

    !     /* lstat() and fstat() the file to check that the file we opened is the *
    !      * one we think it is, and to check ownership.                          */
    !     if ((fstat(sfp->_file, &stat_buffd) < 0) ||
    ! 	(lstat(shmidname, &stat_buf) < 0)) {
              (void) close(fd);
  	    fd = -1;
  	    switch(errno) {
    --- 261,271 ----
  	    }
          }

    !     /*
    !      * fstat() the file to check that the file we opened is the one we
    !      * think it is.
    !      */
    !     if (fstat(fileno(sfp), &stat_buffd) < 0) {
              (void) close(fd);
  	    fd = -1;
  	    switch(errno) {
    ***************
    *** 271,278 ****
    --- 326,350 ----
          tmp_shm_addr = krb_shm_addr;
      #endif /* TKT_SHMEM */

    +     if (lstat(tf_name, &stat_buf) < 0) {
    + 	switch (errno) {
    + 	case ENOENT:
    + 	    return NO_TKT_FIL;
    + 	default:
    + 	    return TKT_FIL_ACC;
    + 	}
    +     }
    +     if (stat_buf.st_uid != me || !(stat_buf.st_mode & S_IFREG)
    + 	|| stat_buf.st_nlink != 1 || stat_buf.st_mode & 077) {
    + 	return TKT_FIL_ACC;
    +     }
    +
          if (wflag) {
    + 	if (me != metoo && do_seteuid(me) < 0)
    + 	    return KFAILURE;
  	    fd = open(tf_name, O_RDWR, 0600);
    + 	if (me != metoo && do_seteuid(metoo) < 0)
    + 	    return KFAILURE;
  	    if (fd < 0) {
  	        switch(errno) {
  	        case ENOENT:
    ***************
    *** 281,290 ****
  	            return TKT_FIL_ACC;
  	      }
  	    }
    ! 	/* lstat() and fstat() the file to check that the file we opened is the *
    ! 	 * one we think it is, and to check ownership.                          */
    ! 	if ((fstat(fd, &stat_buffd) < 0) ||
    ! 	    (lstat(tf_name, &stat_buf) < 0)) {
  	        (void) close(fd);
  	        fd = -1;
  	        switch(errno) {
    --- 353,363 ----
  	            return TKT_FIL_ACC;
  	      }
  	    }
    ! 	/*
    ! 	 * fstat() the file to check that the file we opened is the
    ! 	 * one we think it is, and to check ownership.
    ! 	 */
    ! 	if (fstat(fd, &stat_buffd) < 0) {
  	        (void) close(fd);
  	        fd = -1;
  	        switch(errno) {
    ***************
    *** 327,333 ****
    --- 400,410 ----
           * for read-only operations and locked for shared access.
           */

    +     if (me != metoo && do_seteuid(me) < 0)
    + 	return KFAILURE;
          fd = open(tf_name, O_RDONLY, 0600);
    +     if (me != metoo && do_seteuid(metoo) < 0)
    + 	return KFAILURE;
          if (fd < 0) {
              switch(errno) {
  	    case ENOENT:
    ***************
    *** 336,345 ****
  	        return TKT_FIL_ACC;
  	    }
          }
    !     /* lstat() and fstat() the file to check that the file we opened is the *
    !      * one we think it is, and to check ownership.                          */
    !     if ((fstat(fd, &stat_buffd) < 0) ||
    ! 	(lstat(tf_name, &stat_buf) < 0)) {
              (void) close(fd);
  	    fd = -1;
  	    switch(errno) {
    --- 413,423 ----
  	        return TKT_FIL_ACC;
  	    }
          }
    !     /*
    !      * fstat() the file to check that the file we opened is the one we
    !      * think it is, and to check ownership.
    !      */
    !     if (fstat(fd, &stat_buffd) < 0) {
              (void) close(fd);
  	    fd = -1;
  	    switch(errno) {

    For Red Hat:

        ftp://updates.redhat.com/6.2/SRPMS/krb5-1.1.1-26.src.rpm
        ftp://updates.redhat.com/6.2/alpha/krb5-configs-1.1.1-26.alpha.rpm
        ftp://updates.redhat.com/6.2/alpha/krb5-devel-1.1.1-26.alpha.rpm
        ftp://updates.redhat.com/6.2/alpha/krb5-libs-1.1.1-26.alpha.rpm
        ftp://updates.redhat.com/6.2/alpha/krb5-server-1.1.1-26.alpha.rpm
        ftp://updates.redhat.com/6.2/alpha/krb5-workstation-1.1.1-26.alpha.rpm
        ftp://updates.redhat.com/6.2/i386/krb5-configs-1.1.1-26.i386.rpm
        ftp://updates.redhat.com/6.2/i386/krb5-devel-1.1.1-26.i386.rpm
        ftp://updates.redhat.com/6.2/i386/krb5-libs-1.1.1-26.i386.rpm
        ftp://updates.redhat.com/6.2/i386/krb5-server-1.1.1-26.i386.rpm
        ftp://updates.redhat.com/6.2/i386/krb5-workstation-1.1.1-26.i386.rpm
        ftp://updates.redhat.com/6.2/sparc/krb5-configs-1.1.1-26.sparc.rpm
        ftp://updates.redhat.com/6.2/sparc/krb5-devel-1.1.1-26.sparc.rpm
        ftp://updates.redhat.com/6.2/sparc/krb5-libs-1.1.1-26.sparc.rpm
        ftp://updates.redhat.com/6.2/sparc/krb5-server-1.1.1-26.sparc.rpm
        ftp://updates.redhat.com/6.2/sparc/krb5-workstation-1.1.1-26.sparc.rpm
        ftp://updates.redhat.com/7.0/SRPMS/krb5-1.2.2-3.src.rpm
        ftp://updates.redhat.com/7.0/SRPMS/pam_krb5-1.29-1.src.rpm
        ftp://updates.redhat.com/7.0/alpha/krb5-devel-1.2.2-3.alpha.rpm
        ftp://updates.redhat.com/7.0/alpha/krb5-libs-1.2.2-3.alpha.rpm
        ftp://updates.redhat.com/7.0/alpha/krb5-server-1.2.2-3.alpha.rpm
        ftp://updates.redhat.com/7.0/alpha/krb5-workstation-1.2.2-3.alpha.rpm
        ftp://updates.redhat.com/7.0/alpha/pam_krb5-1.29-1.alpha.rpm
        ftp://updates.redhat.com/7.0/i386/krb5-devel-1.2.2-3.i386.rpm
        ftp://updates.redhat.com/7.0/i386/krb5-libs-1.2.2-3.i386.rpm
        ftp://updates.redhat.com/7.0/i386/krb5-server-1.2.2-3.i386.rpm
        ftp://updates.redhat.com/7.0/i386/krb5-workstation-1.2.2-3.i386.rpm
        ftp://updates.redhat.com/7.0/i386/pam_krb5-1.29-1.i386.rpm

    For Immunix:

        http://immunix.org/ImmunixOS/6.2/updates/RPMS/krb5-configs-1.1.1-26_StackGuard.i386.rpm
        http://immunix.org/ImmunixOS/6.2/updates/RPMS/krb5-devel-1.1.1-26_StackGuard.i386.rpm
        http://immunix.org/ImmunixOS/6.2/updates/RPMS/krb5-libs-1.1.1-26_StackGuard.i386.rpm
        http://immunix.org/ImmunixOS/6.2/updates/RPMS/krb5-server-1.1.1-26_StackGuard.i386.rpm
        http://immunix.org/ImmunixOS/6.2/updates/RPMS/krb5-workstation-1.1.1-26_StackGuard.i386.rpm
        http://immunix.org/ImmunixOS/6.2/updates/SRPMS/krb5-1.1.1-26_StackGuard.src.rpm
        http://immunix.org/ImmunixOS/7.0/updates/RPMS/krb5-devel-1.2.2-3_imnx.i386.rpm
        http://immunix.org/ImmunixOS/7.0/updates/RPMS/krb5-libs-1.2.2-3_imnx.i386.rpm
        http://immunix.org/ImmunixOS/7.0/updates/RPMS/krb5-server-1.2.2-3_imnx.i386.rpm
        http://immunix.org/ImmunixOS/7.0/updates/RPMS/krb5-workstation-1.2.2-3_imnx.i386.rpm
        http://immunix.org/ImmunixOS/7.0/updates/RPMS/pam_krb5-1.29-1_imnx.i386.rpm
        http://immunix.org/ImmunixOS/7.0/updates/SRPMS/krb5-1.2.2-3_imnx.src.rpm
        http://immunix.org/ImmunixOS/7.0/updates/SRPMS/pam_krb5-1.29-1_imnx.src.rpm