LINUX: Copy session keys to parent in SetToken
[openafs.git] / src / auth / ktc.c
index 2c38483..c04bc86 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
 /* ticket caching code */
 
 #include <afsconfig.h>
-#if defined(UKERNEL)
-#include "afs/param.h"
-#else
 #include <afs/param.h>
-#endif
 
-RCSID("$Header$");
+#include <roken.h>
 
-#if defined(UKERNEL)
-#include "afs/sysincludes.h"
-#include "afsincludes.h"
-#include "afs/stds.h"
-#include "afs/pthread_glock.h"
-#include "afs/vice.h"
-#include "afs/auth.h"
-#include "afs/venus.h"
-#include "afs/pthread_glock.h"
-#include "afs/dirpath.h"
-
-#if !defined(min)
-#define min(a,b) ((a)<(b)?(a):(b))
-#endif /* !defined(min) */
-
-#else /* defined(UKERNEL) */
-
-#ifdef AFS_SUN5_ENV
-#include <unistd.h>
-#endif
-#include <stdio.h>
 #include <afs/stds.h>
+#include <afs/opr.h>
 #include <afs/pthread_glock.h>
-#include <sys/types.h>
 #include <ctype.h>
-#include <sys/stat.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <netinet/in.h>
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
+
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
 #endif
+
+#if defined(UKERNEL)
+#include "afsincludes.h"
 #endif
-#include <afs/vice.h>
+
 #ifdef AFS_AIX_ENV
 #include <sys/lockf.h>
+#ifdef AFS_AIX51_ENV
+#include <sys/cred.h>
+#ifdef HAVE_SYS_PAG_H
+#include <sys/pag.h>
+#endif
 #endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
 #endif
+
+#ifdef HAVE_CRT_EXTERNS_H
+#include <crt_externs.h>
+#endif
+
+#include <afs/vice.h>
 #include "auth.h"
 #include <afs/venus.h>
 #include <afs/afsutil.h>
 
-#endif /* defined(UKERNEL) */
-
-/* For malloc() */
-#include <stdlib.h>
-
+#if !defined(UKERNEL)
+#include <afs/sys_prototypes.h>
+#endif
 
-#ifdef notdef
-/* AFS_KERBEROS_ENV is now conditionally defined in the Makefile */
-#define AFS_KERBEROS_ENV
+#if defined(AFS_LINUX26_ENV)
+#include <sys/syscall.h>
+#if defined(SYS_keyctl)
+/* Open code this value to avoid a dependency on keyutils */
+#define KEYCTL_SESSION_TO_PARENT        18
+#endif
 #endif
 
-#ifdef AFS_KERBEROS_ENV 
-#include <fcntl.h>
-#include <sys/file.h>
+#include "token.h"
+#include "ktc.h"
+
+#ifdef AFS_KERBEROS_ENV
 #include "cellconfig.h"
 static char lcell[MAXCELLCHARS];
+
 #define TKT_ROOT "/tmp/tkt"
+
 #define KSUCCESS 0
 #define KFAILURE 255
+
 /* Definitions for ticket file utilities */
 #define        R_TKT_FIL       0
 #define        W_TKT_FIL       1
+
 /* Error codes returned by ticket file utilities */
 #define                NO_TKT_FIL      76      /* No ticket file found */
 #define                TKT_FIL_ACC     77      /* Couldn't access tkt file */
 #define                TKT_FIL_LCK     78      /* Couldn't lock ticket file */
 #define                TKT_FIL_FMT     79      /* Bad ticket file format */
 #define                TKT_FIL_INI     80      /* afs_tf_init not called first */
-  
+
 /* Values returned by get_credentials */
 #define                RET_TKFIL      21       /* Can't read ticket file */
+
 #ifndef BUFSIZ
 #define BUFSIZ 4096
 #endif
 
-#ifdef AFS_HPUX_ENV
-#include <unistd.h>
-#endif
 #if    defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV)
 static struct flock fileWlock = { F_WRLCK, 0, 0, 0, 0, 0 };
 static struct flock fileRlock = { F_RDLCK, 0, 0, 0, 0, 0 };
@@ -123,114 +102,37 @@ static struct flock fileUlock = { F_UNLCK, 0, 0, 0, 0 };
 #ifndef EOF
 #define EOF (-1)
 #endif
+
 /* the following routines aren't static anymore on behalf of the kerberos IV
  * compatibility library built in subtree krb.
  */
-int afs_tf_init(), afs_tf_get_pname(), afs_tf_get_pinst(), afs_tf_get_cred(); 
-int afs_tf_save_cred(), afs_tf_close(), afs_tf_create(); 
-int afs_tf_dest_tkt();
-static void ktc_LocalCell();
-char *ktc_tkt_string();
-#endif  /* AFS_KERBEROS_ENV */
-
-#ifdef AFS_DUX40_ENV
-#define PIOCTL afs_pioctl
-#elif defined(UKERNEL)
-#define PIOCTL(A,B,C,D) call_syscall(AFSCALL_PIOCTL,A,B,C,D)
+int afs_tf_init(char *, int);
+int afs_tf_get_pname(char *);
+int afs_tf_get_pinst(char *);
+int afs_tf_get_cred(struct ktc_principal *, struct ktc_token *);
+int afs_tf_save_cred(struct ktc_principal *, struct ktc_token *,
+                    struct ktc_principal *);
+int afs_tf_close(void);
+int afs_tf_create(char *, char *);
+int afs_tf_dest_tkt(void);
+static void ktc_LocalCell(void);
+#endif /* AFS_KERBEROS_ENV */
+
+#if defined(UKERNEL)
+#define PIOCTL(A,B,C,D) (errno = (call_syscall(AFSCALL_PIOCTL,A,B,C,D)), errno?-1:0)
 #else
 #define PIOCTL pioctl
 #endif
 
-
-#ifdef KERNEL_KTC_COMPAT
-
-#ifndef KTC_SYSCALL
-#define KTC_SYSCALL    32
-#endif
-
-/* Kernel call opcode definitions */
-#define KTC_OPCODE_BASE                4300
-#define KTC_NO_OP              (0+KTC_OPCODE_BASE)
-#define KTC_SETTOKEN_OP        (1+KTC_OPCODE_BASE)
-#define KTC_GETTOKEN_OP        (2+KTC_OPCODE_BASE)
-#define KTC_LISTTOKENS_OP      (3+KTC_OPCODE_BASE)
-#define KTC_FORGETTOKEN_OP     (4+KTC_OPCODE_BASE)
-#define KTC_FORGETALLTOKENS_OP  (5+KTC_OPCODE_BASE)
-#define KTC_STATUS_OP          (6+KTC_OPCODE_BASE)
-#define KTC_GC_OP              (7+KTC_OPCODE_BASE)
-
-#define KTC_INTERFACE_VERSION 3
-
-/* We have to determine if the kernel supports the ktc system call.  To do so
- * we attempt to execute its noop function.  If this is successful we use the
- * kernel calls in the future otherwise we let the old code run. */
-
-/* To safely check to see whether a system call exists we have to intercept the
- * SIGSYS signal which is caused by executing a non-existant system call.  If
- * it is ignored the syscall routine returns EINVAL.  The SIGSYS is reset to
- * its old value after the return from syscall.  */
-
-static int kernelKTC = 0;
-
-#ifdef AFS_DECOSF_ENV
-/*
- * SIGSYS semantics are broken on Dec AXP OSF/1 v1.2 systems.  You need
- * to ignore SIGTRAP too.  It is claimed to be fixed under v1.3, but...
- */
-
-#define CHECK_KERNEL                                                           \
-    if (kernelKTC == 0) {                                              \
-       int code, ecode;                                                \
-       int (*old)();                                                   \
-       int (*old_t)();                                                 \
-       old = (int (*)())signal(SIGSYS, SIG_IGN);                       \
-       old_t = (int (*)())signal(SIGTRAP, SIG_IGN);                    \
-       code = syscall (KTC_SYSCALL, KTC_NO_OP, 0,0,0,0,0);             \
-       ecode = errno;                                                  \
-       signal(SIGSYS, old);                                            \
-       signal(SIGTRAP, old_t);                                         \
-       if (code == 0) kernelKTC = 1;                                   \
-       else kernelKTC = 2;                                             \
-/* printf ("returned from KTC_NO_OP kernelKTC <= %d; code=%d, errno=%d\n", kernelKTC, code, errno); */\
-    }
-
-#else  /* AFS_DECOSF_ENV */
-
-#define CHECK_KERNEL                                                           \
-    if (kernelKTC == 0) {                                              \
-       int code, ecode;                                                \
-       int (*old)();                                                   \
-       old = (int (*)())signal(SIGSYS, SIG_IGN);                       \
-       code = syscall (KTC_SYSCALL, KTC_NO_OP, 0,0,0,0,0);             \
-       ecode = errno;                                                  \
-       signal(SIGSYS, old);                                            \
-       if (code == 0) kernelKTC = 1;                                   \
-       else kernelKTC = 2;                                             \
-/* printf ("returned from KTC_NO_OP kernelKTC <= %d; code=%d, errno=%d\n", kernelKTC, code, errno); */\
-    }
-#endif /* AFS_DECOSF_ENV */
-
-#define TRY_KERNEL(cmd,a1,a2,a3,a4)                                    \
-{   CHECK_KERNEL;                                                      \
-    if (kernelKTC == 1)                                                        \
-       return syscall (KTC_SYSCALL, cmd,                               \
-                       KTC_INTERFACE_VERSION, a1,a2,a3,a4);            \
-}
-
-#else
-#define TRY_KERNEL(cmd,a1,a2,a3,a4)
-#endif /* KERNEL_KTC_COMPAT */
-
 #if !defined(UKERNEL)
 /* this is a structure used to communicate with the afs cache mgr, but is
  * otherwise irrelevant */
 struct ClearToken {
-       afs_int32 AuthHandle;
-       char HandShakeKey[8];
-       afs_int32 ViceId;
-       afs_int32 BeginTimestamp;
-       afs_int32 EndTimestamp;
+    afs_int32 AuthHandle;
+    char HandShakeKey[8];
+    afs_int32 ViceId;
+    afs_int32 BeginTimestamp;
+    afs_int32 EndTimestamp;
 };
 #endif /* !defined(UKERNEL) */
 
@@ -240,62 +142,62 @@ static struct {
     int valid;
     struct ktc_principal server;
     struct ktc_principal client;
-    struct ktc_token    token;
-} local_tokens[MAXLOCALTOKENS] = {{0}, {0}, {0}, {0}};
+    struct ktc_token token;
+} local_tokens[MAXLOCALTOKENS];
 
-/* new interface routines to the ticket cache.  Only handle afs service right
- * now. */
+static int
+GetToken(struct ktc_principal *aserver, struct ktc_token *atoken,
+          int atokenLen, struct ktc_principal *alicnet, afs_int32 *aviceid);
 
-static int NewSetToken (aserver, atoken, aclient, flags)
-  struct ktc_principal *aserver;
-  struct ktc_principal *aclient;
-  struct ktc_token *atoken;
-  afs_int32 flags;
-{
-    TRY_KERNEL (KTC_SETTOKEN_OP,
-               aserver, aclient, atoken, sizeof(struct ktc_token));
-    /* no kernel ticket cache */
-    return EINVAL;
-}
 
-static int OldSetToken (aserver, atoken, aclient, flags)
-struct ktc_principal *aserver, *aclient;
-struct ktc_token *atoken; 
-afs_int32 flags;
+#define MAXPIOCTLTOKENLEN \
+(3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
+
+static int
+SetToken(struct ktc_principal *aserver, struct ktc_token *atoken,
+           struct ktc_principal *aclient, afs_int32 flags)
 {
     struct ViceIoctl iob;
-    char tbuffer[1024];
-    register char *tp;
+    char tbuffer[MAXPIOCTLTOKENLEN];
+    char *tp;
     struct ClearToken ct;
-    register afs_int32 code;
+    afs_int32 code;
     afs_int32 temp;
 
     if (strcmp(aserver->name, "afs") != 0) {
        int found = -1;
        int i;
-       for (i=0; i<MAXLOCALTOKENS; i++)
+       for (i = 0; i < MAXLOCALTOKENS; i++)
            if (local_tokens[i].valid) {
-               if ((strcmp (local_tokens[i].server.name, aserver->name) == 0) &&
-                   (strcmp (local_tokens[i].server.instance, aserver->instance) == 0) &&
-                   (strcmp (local_tokens[i].server.cell, aserver->cell) == 0)) {
-                   found = i;          /* replace existing entry */
+               if ((strcmp(local_tokens[i].server.name, aserver->name) == 0)
+                   &&
+                   (strcmp
+                    (local_tokens[i].server.instance,
+                     aserver->instance) == 0)
+                   && (strcmp(local_tokens[i].server.cell, aserver->cell) ==
+                       0)) {
+                   found = i;  /* replace existing entry */
                    break;
+               } else {
+                   /* valid, but no match */
                }
-               else /* valid, but no match */ ;
-           } else found = i;           /* remember this empty slot */
-       if (found == -1) return KTC_NOENT;
+           } else
+               found = i;      /* remember this empty slot */
+       if (found == -1)
+           return KTC_NOENT;
        memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
        local_tokens[found].server = *aserver;
        local_tokens[found].client = *aclient;
        local_tokens[found].valid = 1;
        return 0;
     }
-    tp = tbuffer;   /* start copying here */
-    if ((atoken->ticketLen < MINKTCTICKETLEN) ||
-       (atoken->ticketLen > MAXKTCTICKETLEN)) return KTC_TOOBIG;
-    memcpy(tp, &atoken->ticketLen, sizeof(afs_int32));    /* copy in ticket length */
+    tp = tbuffer;              /* start copying here */
+    if ((atoken->ticketLen < MINKTCTICKETLEN)
+       || (atoken->ticketLen > MAXKTCTICKETLEN))
+       return KTC_TOOBIG;
+    memcpy(tp, &atoken->ticketLen, sizeof(afs_int32)); /* copy in ticket length */
     tp += sizeof(afs_int32);
-    memcpy(tp, atoken->ticket, atoken->ticketLen);   /* copy in ticket */
+    memcpy(tp, atoken->ticket, atoken->ticketLen);     /* copy in ticket */
     tp += atoken->ticketLen;
     /* next, copy in the "clear token", describing who we are */
     ct.AuthHandle = atoken->kvno;      /* hide auth handle here */
@@ -303,25 +205,31 @@ afs_int32 flags;
 
     ct.BeginTimestamp = atoken->startTime;
     ct.EndTimestamp = atoken->endTime;
-    if (ct.BeginTimestamp == 0) ct.BeginTimestamp = 1;
+    if (ct.BeginTimestamp == 0)
+       ct.BeginTimestamp = 1;
 
-    if ((strlen(aclient->name) > strlen ("AFS ID ")) &&
-       (aclient->instance[0] == 0)) {
+    if ((strlen(aclient->name) > strlen("AFS ID "))
+       && (aclient->instance[0] == 0)) {
        int sign = 1;
        afs_int32 viceId = 0;
-       char *cp = aclient->name + strlen ("AFS ID ");
-       if (*cp == '-') { sign = -1; cp++; }
+       char *cp = aclient->name + strlen("AFS ID ");
+       if (*cp == '-') {
+           sign = -1;
+           cp++;
+       }
        while (*cp) {
-           if (isdigit(*cp)) viceId = viceId*10 + (int)(*cp - '0');
-           else goto not_vice_id;
+           if (isdigit(*cp))
+               viceId = viceId * 10 + (int)(*cp - '0');
+           else
+               goto not_vice_id;
            cp++;
        }
        ct.ViceId = viceId * sign;      /* OK to let any value here? */
        if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 0)
            ct.BeginTimestamp++;        /* force lifetime to be odd */
     } else {
-not_vice_id:
-       ct.ViceId = getuid();           /* wrong, but works in primary cell */
+      not_vice_id:
+       ct.ViceId = getuid();   /* wrong, but works in primary cell */
        if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1)
            ct.BeginTimestamp++;        /* force lifetime to be even */
     }
@@ -330,8 +238,8 @@ not_vice_id:
     /*
      * Information needed by the user space cache manager
      */
-    u.u_expiration = ct.EndTimestamp;
-    u.u_viceid = ct.ViceId;
+    get_user_struct()->u_expiration = ct.EndTimestamp;
+    get_user_struct()->u_viceid = ct.ViceId;
 #endif
 
     temp = sizeof(struct ClearToken);
@@ -350,7 +258,7 @@ not_vice_id:
      * The following means that setpag will affect the parent process as
      * well as the current process.
      */
-    if (flags & AFS_SETTOK_SETPAG)     
+    if (flags & AFS_SETTOK_SETPAG)
        temp |= 0x8000;
 
     memcpy(tp, &temp, sizeof(afs_int32));
@@ -358,183 +266,379 @@ not_vice_id:
 
     /* finally copy in the cell name */
     temp = strlen(aserver->cell);
-    if (temp >= MAXKTCREALMLEN) return KTC_TOOBIG;
+    if (temp >= MAXKTCREALMLEN)
+       return KTC_TOOBIG;
     strcpy(tp, aserver->cell);
-    tp += temp+1;
+    tp += temp + 1;
 
     /* now setup for the pioctl */
     iob.in = tbuffer;
-    iob.in_size = tp-tbuffer;
+    iob.in_size = tp - tbuffer;
     iob.out = tbuffer;
     iob.out_size = sizeof(tbuffer);
 
 #if defined(NO_AFS_CLIENT)
-    { int fd;  /* DEBUG */
-      char *tkfile;
-      if ((tkfile=getenv("TKTFILE")) &&
-          ((fd=open(tkfile, O_WRONLY|O_APPEND|O_TRUNC|O_CREAT, 0644)) >= 0)) {
-        printf("Writing ticket to: %s\n", tkfile);
-        code = (write(fd, iob.in, iob.in_size) != iob.in_size);
-        close(fd);
-      }
-      else
-        code = KTC_PIOCTLFAIL;
+    {
+       int fd;                 /* DEBUG */
+       char *tkfile;
+       if ((tkfile = getenv("TKTFILE"))
+           &&
+           ((fd =
+             open(tkfile, O_WRONLY | O_APPEND | O_TRUNC | O_CREAT,
+                  0644)) >= 0)) {
+           printf("Writing ticket to: %s\n", tkfile);
+           code = (write(fd, iob.in, iob.in_size) != iob.in_size);
+           close(fd);
+       } else
+           code = KTC_PIOCTLFAIL;
     }
 #else /* NO_AFS_CLIENT */
     code = PIOCTL(0, VIOCSETTOK, &iob, 0);
 #endif /* NO_AFS_CLIENT */
-    if (code) return KTC_PIOCTLFAIL;
+    if (code)
+       return KTC_PIOCTLFAIL;
+#if defined(AFS_LINUX26_ENV) && defined(SYS_keyctl)
+    else
+        /*
+         * If we're using keyring based PAGs and the SESSION_TO_PARENT keyctl
+         * is available, use it to copy the session keyring to the parent process
+         */
+        if (flags & AFS_SETTOK_SETPAG)
+            syscall(SYS_keyctl, KEYCTL_SESSION_TO_PARENT);
+#endif
     return 0;
 }
 
+int
+ktc_SetTokenEx(struct ktc_setTokenData *token) {
+    struct ViceIoctl iob;
+    afs_int32 code;
+    XDR xdrs;
+
+    xdrlen_create(&xdrs);
+    if (!xdr_ktc_setTokenData(&xdrs, token))
+       return EINVAL;
+    iob.in_size = xdr_getpos(&xdrs);
+    xdr_destroy(&xdrs);
+
+    iob.in = malloc(iob.in_size);
+    if (iob.in == NULL)
+       return ENOMEM;
+
+    xdrmem_create(&xdrs, iob.in, iob.in_size, XDR_ENCODE);
+    if (!xdr_ktc_setTokenData(&xdrs, token))
+       return KTC_INVAL;
+    xdr_destroy(&xdrs);
+
+    iob.out = NULL;
+    iob.out_size = 0;
+
+    code = PIOCTL(0, VIOC_SETTOK2, &iob, 0);
+
+    free(iob.in);
+
+    /* If we can't use the new pioctl, then fallback to using the old
+     * one, with just the rxkad portion of the token we're being asked to
+     * set
+     */
+    if (code == -1 && errno == EINVAL) {
+       struct ktc_principal server, client;
+       struct ktc_token *rxkadToken;
+       afs_int32 flags;
+
+       /* With the growth of ticket sizes, a ktc_token is now 12k. Don't
+        * allocate it on the stack! */
+       rxkadToken = malloc(sizeof(*rxkadToken));
+       if (rxkadToken == NULL)
+           return ENOMEM;
+
+       code = token_extractRxkad(token, rxkadToken, &flags, &client);
+       if (code) {
+           free(rxkadToken);
+           return KTC_INVAL;
+       }
+
+       memset(&server, 0, sizeof(server));
+       strcpy(server.name, "afs");
+       if (strlcpy(server.cell, token->cell, sizeof(server.cell))
+               >= sizeof(server.cell)) {
+           free(rxkadToken);
+           return KTC_INVAL;
+       }
+       code = ktc_SetToken(&server, rxkadToken, &client, flags);
+       free(rxkadToken);
+       return code;
+    }
+
+    if (code)
+       return KTC_PIOCTLFAIL;
+#if defined(AFS_LINUX26_ENV) && defined(SYS_keyctl)
+    else
+       /*
+        * If we're using keyring based PAGs and the SESSION_TO_PARENT keyctl
+        * is available, use it to copy the session keyring to the parent process
+        */
+       if (token->flags & AFS_SETTOK_SETPAG)
+           syscall(SYS_keyctl, KEYCTL_SESSION_TO_PARENT);
+#endif
+
+    return 0;
+}
 
-ktc_SetToken (aserver, atoken, aclient, flags)
-  struct ktc_principal *aserver;
-  struct ktc_principal *aclient;
-  struct ktc_token *atoken;
-  afs_int32 flags;
+int
+ktc_SetToken(struct ktc_principal *aserver,
+    struct ktc_token *atoken,
+    struct ktc_principal *aclient,
+    afs_int32 flags)
 {
-    int ncode, ocode;
+    int code;
 
-    LOCK_GLOBAL_MUTEX
+    LOCK_GLOBAL_MUTEX;
 #ifdef AFS_KERBEROS_ENV
-    if (!lcell[0]) ktc_LocalCell();
-    if (/*!strcmp(aclient->cell, lcell) && this would only store local creds*/
-       (strcmp(aserver->name, "AuthServer") ||
-                                         strcmp(aserver->instance, "Admin"))){
-       if (strcmp(aserver->name, "krbtgt") == 0) {
-           static char lrealm[MAXKTCREALMLEN];
-           if (!lrealm[0]) ucstring(lrealm, lcell, MAXKTCREALMLEN);
-           if (strcmp(aserver->instance, lrealm) == 0) {
-               afs_tf_create(aclient->name, aclient->instance);
-           }
-       }
-       ncode = afs_tf_init(ktc_tkt_string(), W_TKT_FIL);
-       if (ncode == NO_TKT_FIL) {
-           (void) afs_tf_create(aclient->name, aclient->instance);
-           ncode = afs_tf_init(ktc_tkt_string(), W_TKT_FIL);
-       }
-       if (!ncode) {
-           afs_tf_save_cred(aserver, atoken, aclient);
-       }
-       afs_tf_close();
+    if (!lcell[0])
+       ktc_LocalCell();
+
+    if (                       /*!strcmp(aclient->cell, lcell) && this would only store local creds */
+          (strcmp(aserver->name, "AuthServer")
+           || strcmp(aserver->instance, "Admin"))) {
+       if (strcmp(aserver->name, "krbtgt") == 0) {
+           static char lrealm[MAXKTCREALMLEN];
+
+           if (!lrealm[0])
+               ucstring(lrealm, lcell, MAXKTCREALMLEN);
+           if (strcmp(aserver->instance, lrealm) == 0) {
+               afs_tf_create(aclient->name, aclient->instance);
+           }
+       }
+
+       code = afs_tf_init(ktc_tkt_string(), W_TKT_FIL);
+       if (code == NO_TKT_FIL) {
+           (void)afs_tf_create(aclient->name, aclient->instance);
+           code = afs_tf_init(ktc_tkt_string(), W_TKT_FIL);
+       }
+
+       if (!code) {
+           afs_tf_save_cred(aserver, atoken, aclient);
+       }
+       afs_tf_close();
 #ifdef NO_AFS_CLIENT
-        UNLOCK_GLOBAL_MUTEX
-        return ncode;
+       UNLOCK_GLOBAL_MUTEX;
+       return code;
 #endif /* NO_AFS_CLIENT */
-     }
+    }
 #endif
 
 #ifndef NO_AFS_CLIENT
-    ncode = NewSetToken (aserver, atoken, aclient, flags);
-    if (ncode ||                       /* new style failed */
-       (strcmp (aserver->name, "afs") == 0)) { /* for afs tokens do both */
-       ocode = OldSetToken (aserver, atoken, aclient, flags);
-    } else ocode = 0;
-    if (ncode && ocode) {
-       UNLOCK_GLOBAL_MUTEX
-       if (ocode == -1) ocode = errno;
-       else if (ocode == KTC_PIOCTLFAIL) ocode = errno;
-       if (ocode == ESRCH) return KTC_NOCELL;
-       if (ocode == EINVAL) return KTC_NOPIOCTL;
-       if (ocode == EIO) return KTC_NOCM;
+    code = SetToken(aserver, atoken, aclient, flags);
+    if (code) {
+       UNLOCK_GLOBAL_MUTEX;
+       if (code == -1)
+           code = errno;
+       else if (code == KTC_PIOCTLFAIL)
+           code = errno;
+       if (code == ESRCH)
+           return KTC_NOCELL;
+       if (code == EINVAL)
+           return KTC_NOPIOCTL;
+       if (code == EIO)
+           return KTC_NOCM;
        return KTC_PIOCTLFAIL;
     }
 #endif /* NO_AFS_CLIENT */
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
+    return 0;
+}
+
+/*!
+ * Get a token, given the cell that we need to get information for
+ *
+ * @param cellName
+ *     The name of the cell we're getting the token for - if NULL, we'll
+ *     get information for the primary cell
+ */
+int
+ktc_GetTokenEx(char *cellName, struct ktc_setTokenData **tokenSet) {
+    struct ViceIoctl iob;
+    char tbuffer[MAXPIOCTLTOKENLEN];
+    char *tp;
+    afs_int32 code;
+    XDR xdrs;
+
+    tp = tbuffer;
+
+    /* If we have a cellName, write it out here */
+    if (cellName) {
+       memcpy(tp, cellName, strlen(cellName) +1);
+       tp += strlen(cellName)+1;
+    }
+
+    iob.in = tbuffer;
+    iob.in_size = tp - tbuffer;
+    iob.out = tbuffer;
+    iob.out_size = sizeof(tbuffer);
+
+    code = PIOCTL(0, VIOC_GETTOK2, &iob, 0);
+
+    /* If we can't use the new pioctl, the fall back to the old one. We then
+     * need to convert the rxkad token we get back into the new format
+     */
+    if (code == -1 && errno == EINVAL) {
+       struct ktc_principal server;
+       struct ktc_tokenUnion token;
+       struct ktc_token *ktcToken; /* too huge for the stack */
+       afs_int32 viceid;
+
+       memset(&server, 0, sizeof(server));
+       ktcToken = malloc(sizeof(struct ktc_token));
+       if (ktcToken == NULL)
+           return ENOMEM;
+       memset(ktcToken, 0, sizeof(struct ktc_token));
+
+       strcpy(server.name, "afs");
+
+       if (cellName != NULL)
+           strcpy(server.cell, cellName);
+
+       code = GetToken(&server, ktcToken, sizeof(struct ktc_token),
+                        NULL /*client*/, &viceid);
+       if (code == 0) {
+           *tokenSet = token_buildTokenJar(cellName);
+           token.at_type = AFSTOKEN_UNION_KAD;
+           token.ktc_tokenUnion_u.at_kad.rk_kvno = ktcToken->kvno;
+           memcpy(token.ktc_tokenUnion_u.at_kad.rk_key,
+                  ktcToken->sessionKey.data, 8);
+
+           token.ktc_tokenUnion_u.at_kad.rk_begintime = ktcToken->startTime;
+           token.ktc_tokenUnion_u.at_kad.rk_endtime   = ktcToken->endTime;
+           token.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len
+               = ktcToken->ticketLen;
+           token.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val
+               = ktcToken->ticket;
+           token.ktc_tokenUnion_u.at_kad.rk_viceid = viceid;
+
+           token_addToken(*tokenSet, &token);
+
+           memset(ktcToken, 0, sizeof(struct ktc_token));
+       }
+       free(ktcToken);
+        return code;
+    }
+    if (code)
+       return KTC_PIOCTLFAIL;
+
+    *tokenSet = malloc(sizeof(struct ktc_setTokenData));
+    if (*tokenSet == NULL)
+       return ENOMEM;
+    memset(*tokenSet, 0, sizeof(struct ktc_setTokenData));
+
+    xdrmem_create(&xdrs, iob.out, iob.out_size, XDR_DECODE);
+    if (!xdr_ktc_setTokenData(&xdrs, *tokenSet)) {
+       free(*tokenSet);
+       *tokenSet = NULL;
+       xdr_destroy(&xdrs);
+       return EINVAL;
+    }
+    xdr_destroy(&xdrs);
     return 0;
 }
 
 /* get token, given server we need and token buffer.  aclient will eventually
  * be set to our identity to the server.
  */
-ktc_GetToken(aserver, atoken, atokenLen, aclient)
-struct ktc_principal *aserver, *aclient;
-int atokenLen;
-struct ktc_token *atoken; {
+int
+ktc_GetToken(struct ktc_principal *aserver, struct ktc_token *atoken,
+            int atokenLen, struct ktc_principal *aclient)
+{
+    return GetToken(aserver, atoken, atokenLen, aclient, NULL);
+}
+
+static int
+GetToken(struct ktc_principal *aserver, struct ktc_token *atoken,
+          int atokenLen, struct ktc_principal *aclient, afs_int32 *aviceid)
+{
     struct ViceIoctl iob;
-    char tbuffer[1024];
-    register afs_int32 code;
+    char tbuffer[MAXPIOCTLTOKENLEN];
+    afs_int32 code = 0;
     int index;
-    char *stp, *cellp; /* secret token ptr */
+    char *stp, *cellp;         /* secret token ptr */
     struct ClearToken ct;
-    register char *tp;
+    char *tp;
     afs_int32 temp;
-    int        maxLen; /* biggest ticket we can copy */
-    int        tktLen; /* server ticket length */
+    int maxLen;                        /* biggest ticket we can copy */
+    int tktLen;                        /* server ticket length */
+#ifdef AFS_KERBEROS_ENV
     char found = 0;
-    
-    LOCK_GLOBAL_MUTEX
-#ifndef NO_AFS_CLIENT
-    TRY_KERNEL (KTC_GETTOKEN_OP, aserver, aclient, atoken, atokenLen);
-#endif /* NO_AFS_CLIENT */
+#endif
+    if (aviceid) {
+       *aviceid = 0;
+    }
+
+    LOCK_GLOBAL_MUTEX;
 
 #ifdef AFS_KERBEROS_ENV
-    if (!lcell[0]) ktc_LocalCell();
+    if (!lcell[0])
+       ktc_LocalCell();
 #endif
 #ifndef NO_AFS_CLIENT
-    if (strcmp(aserver->name, "afs") != 0) 
+    if (strcmp(aserver->name, "afs") != 0)
 #endif /* NO_AFS_CLIENT */
-      {
+    {
        int i;
        /* try the local tokens */
-       for (i=0; i<MAXLOCALTOKENS; i++)
-           if (local_tokens[i].valid &&
-               (strcmp (local_tokens[i].server.name, aserver->name) == 0) &&
-               (strcmp (local_tokens[i].server.instance, aserver->instance) == 0) &&
-               (strcmp (local_tokens[i].server.cell, aserver->cell) == 0)) {
-               memcpy (atoken, &local_tokens[i].token, min (atokenLen, sizeof(struct ktc_token)));
+       for (i = 0; i < MAXLOCALTOKENS; i++)
+           if (local_tokens[i].valid
+               && (strcmp(local_tokens[i].server.name, aserver->name) == 0)
+               && (strcmp(local_tokens[i].server.instance, aserver->instance)
+                   == 0)
+               && (strcmp(local_tokens[i].server.cell, aserver->cell) == 0)) {
+               memcpy(atoken, &local_tokens[i].token,
+                      min(atokenLen, sizeof(struct ktc_token)));
                if (aclient)
                    *aclient = local_tokens[i].client;
-               UNLOCK_GLOBAL_MUTEX
+               UNLOCK_GLOBAL_MUTEX;
                return 0;
            }
 #ifdef AFS_KERBEROS_ENV
-        if (!afs_tf_init(ktc_tkt_string(), R_TKT_FIL)) {
-            if  (aclient) {
-                if (!afs_tf_get_pname(aclient->name) &&
-                !afs_tf_get_pinst(aclient->instance))
-                    found = 1;
-            } else {
-                char tmpstring[MAXHOSTCHARS];
-                afs_tf_get_pname(&tmpstring);
-                afs_tf_get_pinst(&tmpstring);
-                found = 1;
-            }
-        }
-        if (found) {
-           struct ktc_principal cprincipal;
-           struct ktc_token ctoken;
-           while (!afs_tf_get_cred(&cprincipal, &ctoken)) {
-               if (strcmp(cprincipal.name, aserver->name) == 0 &&
-                   strcmp(cprincipal.instance, aserver->instance) == 0 &&
-                   strcmp(cprincipal.cell, aserver->cell) == 0) {
+       if (!afs_tf_init(ktc_tkt_string(), R_TKT_FIL)) {
+           if (aclient) {
+               if (!afs_tf_get_pname(aclient->name)
+                   && !afs_tf_get_pinst(aclient->instance))
+                   found = 1;
+           } else {
+               char tmpstring[MAXHOSTCHARS];
+               afs_tf_get_pname(tmpstring);
+               afs_tf_get_pinst(tmpstring);
+               found = 1;
+           }
+       }
+       if (found) {
+           struct ktc_principal cprincipal;
+           struct ktc_token ctoken;
+
+           while (!afs_tf_get_cred(&cprincipal, &ctoken)) {
+               if (strcmp(cprincipal.name, aserver->name) == 0
+                   && strcmp(cprincipal.instance, aserver->instance) == 0
+                   && strcmp(cprincipal.cell, aserver->cell) == 0) {
+
                    if (aclient)
                        strcpy(aclient->cell, lcell);
-                   memcpy(atoken, &ctoken, 
-                         min (atokenLen, sizeof(struct ktc_token)));
-                   
-                   afs_tf_close();
-                   UNLOCK_GLOBAL_MUTEX
-                   return 0;
-               }
-           }
-       }
-       afs_tf_close();
+                   memcpy(atoken, &ctoken,
+                          min(atokenLen, sizeof(struct ktc_token)));
+
+                   afs_tf_close();
+                   UNLOCK_GLOBAL_MUTEX;
+                   return 0;
+               }
+           }
+       }
+       afs_tf_close();
 #endif
-       UNLOCK_GLOBAL_MUTEX
+       UNLOCK_GLOBAL_MUTEX;
        return KTC_NOENT;
     }
-
 #ifndef NO_AFS_CLIENT
-    for (index=0; index<200; index++) {        /* sanity check in case pioctl fails */
-       iob.in = (char *) &index;
+    for (index = 0; index < 200; index++) {    /* sanity check in case pioctl fails */
+       iob.in = (char *)&index;
        iob.in_size = sizeof(afs_int32);
        iob.out = tbuffer;
        iob.out_size = sizeof(tbuffer);
@@ -544,7 +648,7 @@ struct ktc_token *atoken; {
        if (code) {
            /* failed to retrieve specified token */
            if (code < 0 && errno == EDOM) {
-               UNLOCK_GLOBAL_MUTEX
+               UNLOCK_GLOBAL_MUTEX;
                return KTC_NOENT;
            }
        } else {
@@ -563,7 +667,7 @@ struct ktc_token *atoken; {
            /* get size of clear token and verify */
            memcpy(&temp, tp, sizeof(afs_int32));
            if (temp != sizeof(struct ClearToken)) {
-               UNLOCK_GLOBAL_MUTEX
+               UNLOCK_GLOBAL_MUTEX;
                return KTC_ERROR;
            }
            tp += sizeof(afs_int32);
@@ -584,9 +688,10 @@ struct ktc_token *atoken; {
 #endif
                ) {
                /* got token for cell; check that it will fit */
-               maxLen = atokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
-               if (maxLen < tktLen) {
-                   UNLOCK_GLOBAL_MUTEX
+               maxLen =
+                   atokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
+               if (tktLen < 0 || tktLen > maxLen) {
+                   UNLOCK_GLOBAL_MUTEX;
                    return KTC_TOOBIG;
                }
 
@@ -598,30 +703,39 @@ struct ktc_token *atoken; {
                    ct.AuthHandle = 999;
                }
                atoken->kvno = ct.AuthHandle;
-               memcpy(&atoken->sessionKey, ct.HandShakeKey, sizeof(struct ktc_encryptionKey));
+               memcpy(&atoken->sessionKey, ct.HandShakeKey,
+                      sizeof(struct ktc_encryptionKey));
                atoken->ticketLen = tktLen;
 
-               if (aclient) {
-                   strcpy(aclient->cell, cellp);
-                   aclient->instance[0] = 0;
+               if (aclient || aviceid) {
+                   if (aclient) {
+                       strlcpy(aclient->cell, cellp, sizeof(aclient->cell));
+                       aclient->instance[0] = 0;
+                   }
 
-                   if ((atoken->kvno == 999) || /* old style bcrypt ticket */
-                       (ct.BeginTimestamp &&    /* new w/ prserver lookup */
+                   if ((atoken->kvno == 999) ||        /* old style bcrypt ticket */
+                       (ct.BeginTimestamp &&   /* new w/ prserver lookup */
                         (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1))) {
-                       sprintf(aclient->name, "AFS ID %d", ct.ViceId);
-                   } else {
+                       if (aclient) {
+                           sprintf(aclient->name, "AFS ID %d", ct.ViceId);
+                       }
+                       if (aviceid) {
+                           *aviceid = ct.ViceId;
+                       }
+                   } else if (aclient) {
                        sprintf(aclient->name, "Unix UID %d", ct.ViceId);
                    }
                }
-               UNLOCK_GLOBAL_MUTEX
+               UNLOCK_GLOBAL_MUTEX;
                return 0;
            }
        }
     }
 #endif /* NO_AFS_CLIENT */
 
-    UNLOCK_GLOBAL_MUTEX
-    if ((code < 0) && (errno == EINVAL)) return KTC_NOPIOCTL;
+    UNLOCK_GLOBAL_MUTEX;
+    if ((code < 0) && (errno == EINVAL))
+       return KTC_NOPIOCTL;
     return KTC_PIOCTLFAIL;     /* probable cause */
 }
 
@@ -630,117 +744,197 @@ struct ktc_token *atoken; {
  * NOT IMPLEMENTED YET!
  */
 #ifndef NO_AFS_CLIENT
-ktc_ForgetToken(aserver)
-struct ktc_principal *aserver; {
+int
+ktc_ForgetToken(struct ktc_principal *aserver)
+{
     int rc;
 
-    LOCK_GLOBAL_MUTEX
-    TRY_KERNEL (KTC_FORGETTOKEN_OP, aserver, 0,0,0);
-
+    LOCK_GLOBAL_MUTEX;
     rc = ktc_ForgetAllTokens();        /* bogus, but better */
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return rc;
 }
 #endif /* NO_AFS_CLIENT */
 
+/*!
+ * An iterator which can list all cells with tokens in the cache
+ *
+ * This function may be used to list the names of all cells for which
+ * tokens exist in the current cache. The first time that it is called,
+ * prevIndex should be set to 0. On all subsequent calls, prevIndex
+ * should be set to the value returned in newIndex by the last call
+ * to the function. Note that there is no guarantee that the index value
+ * is monotonically increasing.
+ *
+ * @param prevIndex
+ *     The index returned by the last call, or 0 if this is the first
+ *     call in an iteration
+ * @param newIndex
+ *     A pointer to an int which, upon return, will hold the next value
+ *     to be used.
+ * @param cellName
+ *     A pointer to a char * which, upon return, will hold a cellname.
+ *     This must be freed by the caller using free()
+ */
+
+int
+ktc_ListTokensEx(int prevIndex, int *newIndex, char **cellName) {
+    struct ViceIoctl iob;
+    char tbuffer[MAXPIOCTLTOKENLEN];
+    afs_int32 code;
+    afs_int32 index;
+    struct ktc_setTokenData tokenSet;
+    XDR xdrs;
+
+    memset(&tokenSet, 0, sizeof(tokenSet));
+
+    *cellName = NULL;
+    *newIndex = prevIndex;
+
+    index = prevIndex;
+
+    while (index<100) { /* Safety, incase of pioctl failure */
+       memset(tbuffer, 0, sizeof(tbuffer));
+       iob.in = tbuffer;
+       memcpy(tbuffer, &index, sizeof(afs_int32));
+       iob.in_size = sizeof(afs_int32);
+       iob.out = tbuffer;
+       iob.out_size = sizeof(tbuffer);
+
+       code = PIOCTL(0, VIOC_GETTOK2, &iob, 0);
+
+       if (code == -1 && errno == EDOM)
+           return KTC_NOENT;   /* no more tokens to be found */
+
+       /* Can't use new pioctl, so must use old one */
+       if (code == -1 && errno == EINVAL) {
+           struct ktc_principal server;
+
+           code = ktc_ListTokens(index, newIndex, &server);
+           if (code == 0)
+               *cellName = strdup(server.cell);
+           return code;
+       }
+
+       if (code == 0) {
+           /* Got a token from the pioctl. Now we throw it away,
+            * so we can return just a cellname. This is rather wasteful,
+            * but it's what the old API does. Ho hum.  */
+
+           xdrmem_create(&xdrs, iob.out, iob.out_size, XDR_DECODE);
+           if (!xdr_ktc_setTokenData(&xdrs, &tokenSet)) {
+               xdr_destroy(&xdrs);
+               return EINVAL;
+           }
+           xdr_destroy(&xdrs);
+           *cellName = strdup(tokenSet.cell);
+           xdr_free((xdrproc_t)xdr_ktc_setTokenData, &tokenSet);
+           *newIndex = index + 1;
+           return 0;
+       }
+       index++;
+    }
+    return KTC_PIOCTLFAIL;
+}
+
 /* ktc_ListTokens - list all tokens.  start aprevIndex at 0, it returns the
  * next rock in (*aindex).  (*aserver) is set to the relevant ticket on
  * success.  */
 
-ktc_ListTokens(aprevIndex, aindex, aserver)
-int aprevIndex, *aindex;
-struct ktc_principal *aserver; {
+int
+ktc_ListTokens(int aprevIndex,
+    int *aindex,
+    struct ktc_principal *aserver)
+{
     struct ViceIoctl iob;
-    char tbuffer[1024];
-    register afs_int32 code;
-    register char *tp;
+    char tbuffer[MAXPIOCTLTOKENLEN];
+    afs_int32 code = 0 ;
+    char *tp;
     afs_int32 temp, index;
 
     memset(tbuffer, 0, sizeof(tbuffer));
 
-    LOCK_GLOBAL_MUTEX
-#ifndef NO_AFS_CLIENT
-    TRY_KERNEL (KTC_LISTTOKENS_OP, aserver, aprevIndex, aindex, 0);
-#endif /* NO_AFS_CLIENT */
+    LOCK_GLOBAL_MUTEX;
 
     index = aprevIndex;
 #ifdef NO_AFS_CLIENT
-    if (index < 214) index = 214;
+    if (index < 214)
+       index = 214;
 #endif /* NO_AFS_CLIENT */
 #ifdef AFS_KERBEROS_ENV
-     if (index >= 214) {
-       int i;
-       struct ktc_principal cprincipal;
-       struct ktc_token ctoken;
-       if (afs_tf_init(ktc_tkt_string(), R_TKT_FIL) ||
-           afs_tf_get_pname(tbuffer) ||
-           afs_tf_get_pinst(tbuffer)) {
-           afs_tf_close();
-           UNLOCK_GLOBAL_MUTEX
-           return KTC_NOENT;
-       }
-       for (i=214; i<index; i++) {
-           if (afs_tf_get_cred(&cprincipal, &ctoken)) {
-               afs_tf_close();
-               UNLOCK_GLOBAL_MUTEX
-               return KTC_NOENT;
-           }
-       }
-     again:
-       if (afs_tf_get_cred(&cprincipal, &ctoken)) {
-           afs_tf_close();
-           UNLOCK_GLOBAL_MUTEX
-           return KTC_NOENT;
-       }           
-       index++;
+    if (index >= 214) {
+       int i;
+       struct ktc_principal cprincipal;
+       struct ktc_token ctoken;
+
+       if (afs_tf_init(ktc_tkt_string(), R_TKT_FIL)
+           || afs_tf_get_pname(tbuffer) || afs_tf_get_pinst(tbuffer)) {
+           afs_tf_close();
+           UNLOCK_GLOBAL_MUTEX;
+           return KTC_NOENT;
+       }
+
+       for (i = 214; i < index; i++) {
+           if (afs_tf_get_cred(&cprincipal, &ctoken)) {
+               afs_tf_close();
+               UNLOCK_GLOBAL_MUTEX;
+               return KTC_NOENT;
+           }
+       }
+
+      again:
+       if (afs_tf_get_cred(&cprincipal, &ctoken)) {
+           afs_tf_close();
+           UNLOCK_GLOBAL_MUTEX;
+           return KTC_NOENT;
+       }
+       index++;
+
 #ifndef NO_AFS_CLIENT
-       if (!strcmp(cprincipal.name, "afs") && cprincipal.instance[0]==0) {
-           goto again;
-       }
+       if (!strcmp(cprincipal.name, "afs") && cprincipal.instance[0] == 0) {
+           goto again;
+       }
 #endif /* NO_AFS_CLIENT */
-       for (i=0; i < MAXLOCALTOKENS; i++) {
-           if (!strcmp(cprincipal.name, local_tokens[i].server.name) &&
-               !strcmp(cprincipal.instance, local_tokens[i].server.instance) &&
-               !strcmp(cprincipal.cell, local_tokens[i].server.cell)) {
-               goto again;
-               }
-       }
-       *aserver = cprincipal;
-       *aindex = index;
-       afs_tf_close();
-       UNLOCK_GLOBAL_MUTEX
-       return 0;
-     }
+
+       for (i = 0; i < MAXLOCALTOKENS; i++) {
+           if (!strcmp(cprincipal.name, local_tokens[i].server.name)
+               && !strcmp(cprincipal.instance,
+                          local_tokens[i].server.instance)
+               && !strcmp(cprincipal.cell, local_tokens[i].server.cell)) {
+               goto again;
+           }
+       }
+
+       *aserver = cprincipal;
+       *aindex = index;
+       afs_tf_close();
+       UNLOCK_GLOBAL_MUTEX;
+       return 0;
+    }
 #endif
 
 #ifndef NO_AFS_CLIENT
-    if (index >= 123) {                        /* special hack for returning TCS */
-       while (index-123 < MAXLOCALTOKENS) {
-           if (local_tokens[index-123].valid) {
-               *aserver = local_tokens[index-123].server;
-               *aindex = index+1;
-               UNLOCK_GLOBAL_MUTEX
+    if (index >= 123) {                /* special hack for returning TCS */
+       while (index - 123 < MAXLOCALTOKENS) {
+           if (local_tokens[index - 123].valid) {
+               *aserver = local_tokens[index - 123].server;
+               *aindex = index + 1;
+               UNLOCK_GLOBAL_MUTEX;
                return 0;
            }
            index++;
        }
-       UNLOCK_GLOBAL_MUTEX
+       UNLOCK_GLOBAL_MUTEX;
 #ifdef AFS_KERBEROS_ENV
-       return ktc_ListTokens(214, aindex, aserver);
+       return ktc_ListTokens(214, aindex, aserver);
 #else
        return KTC_NOENT;
 #endif
     }
 
     /* get tokens from the kernel */
-    while (index<200) {                        /* sanity check in case pioctl fails */
-       iob.in = (char *) &index;
+    while (index < 200) {      /* sanity check in case pioctl fails */
+       iob.in = (char *)&index;
        iob.in_size = sizeof(afs_int32);
        iob.out = tbuffer;
        iob.out_size = sizeof(tbuffer);
@@ -748,22 +942,23 @@ struct ktc_principal *aserver; {
        if (code < 0 && errno == EDOM) {
            if (index < 123) {
                int rc;
-               rc = ktc_ListTokens (123, aindex, aserver);
-               UNLOCK_GLOBAL_MUTEX
+               rc = ktc_ListTokens(123, aindex, aserver);
+               UNLOCK_GLOBAL_MUTEX;
                return rc;
-           }
-           else {
-               UNLOCK_GLOBAL_MUTEX
+           } else {
+               UNLOCK_GLOBAL_MUTEX;
                return KTC_NOENT;
            }
        }
-       if (code == 0) break;   /* got a ticket */
+       if (code == 0)
+           break;              /* got a ticket */
        /* otherwise we should skip this ticket slot */
        index++;
     }
     if (code < 0) {
-       UNLOCK_GLOBAL_MUTEX
-       if (errno == EINVAL) return KTC_NOPIOCTL;
+       UNLOCK_GLOBAL_MUTEX;
+       if (errno == EINVAL)
+           return KTC_NOPIOCTL;
        return KTC_PIOCTLFAIL;
     }
 
@@ -771,45 +966,37 @@ struct ktc_principal *aserver; {
     tp = tbuffer;
 
     /* next iterator determined by earlier loop */
-    *aindex = index+1;
+    *aindex = index + 1;
 
-    memcpy(&temp, tp, sizeof(afs_int32)); /* get size of secret token */
+    memcpy(&temp, tp, sizeof(afs_int32));      /* get size of secret token */
     tp += sizeof(afs_int32);
-    tp += temp;        /* skip ticket for now */
-    memcpy(&temp, tp, sizeof(afs_int32)); /* get size of clear token */
+    tp += temp;                        /* skip ticket for now */
+    memcpy(&temp, tp, sizeof(afs_int32));      /* get size of clear token */
     if (temp != sizeof(struct ClearToken)) {
-       UNLOCK_GLOBAL_MUTEX
+       UNLOCK_GLOBAL_MUTEX;
        return KTC_ERROR;
     }
-    tp += sizeof(afs_int32);       /* skip length */
-    tp += temp;                    /* skip clear token itself */
-    tp += sizeof(afs_int32);       /* skip primary flag */
+    tp += sizeof(afs_int32);   /* skip length */
+    tp += temp;                        /* skip clear token itself */
+    tp += sizeof(afs_int32);   /* skip primary flag */
     /* tp now points to the cell name */
-    strcpy(aserver->cell, tp);
+    strlcpy(aserver->cell, tp, sizeof(aserver->cell));
     aserver->instance[0] = 0;
     strcpy(aserver->name, "afs");
 #endif /* NO_AFS_CLIENT */
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return 0;
 }
 
-/* discard all tokens from this user's cache */
-
-static int NewForgetAll ()
-{
-#ifndef NO_AFS_CLIENT
-    TRY_KERNEL (KTC_FORGETALLTOKENS_OP, 0,0,0,0);
-#endif /* NO_AFS_CLIENT */
-    return EINVAL;
-}
-
-static int OldForgetAll ()
+static int
+ForgetAll(void)
 {
     struct ViceIoctl iob;
-    register afs_int32 code;
+    afs_int32 code;
     int i;
 
-    for (i=0; i<MAXLOCALTOKENS; i++) local_tokens[i].valid = 0;
+    for (i = 0; i < MAXLOCALTOKENS; i++)
+       local_tokens[i].valid = 0;
 
     iob.in = 0;
     iob.in_size = 0;
@@ -817,48 +1004,110 @@ static int OldForgetAll ()
     iob.out_size = 0;
 #ifndef NO_AFS_CLIENT
     code = PIOCTL(0, VIOCUNPAG, &iob, 0);
-    if (code) return KTC_PIOCTLFAIL;
+    if (code)
+       return KTC_PIOCTLFAIL;
 #endif /* NO_AFS_CLIENT */
     return 0;
 }
 
-int ktc_ForgetAllTokens()
+int
+ktc_ForgetAllTokens(void)
 {
-    int ncode, ocode;
+    int ocode;
 
-    LOCK_GLOBAL_MUTEX
+    LOCK_GLOBAL_MUTEX;
 #ifdef AFS_KERBEROS_ENV
-     (void) afs_tf_dest_tkt();
+    (void)afs_tf_dest_tkt();
 #endif
 
-    ncode = NewForgetAll ();
-    ocode = OldForgetAll ();
-    if (ncode && ocode) {
-       if (ocode == -1) ocode = errno;
-       else if (ocode == KTC_PIOCTLFAIL) ocode = errno;
-       UNLOCK_GLOBAL_MUTEX
-       if (ocode == EINVAL) return KTC_NOPIOCTL;
+    ocode = ForgetAll();
+    if (ocode) {
+       if (ocode == -1)
+           ocode = errno;
+       else if (ocode == KTC_PIOCTLFAIL)
+           ocode = errno;
+       UNLOCK_GLOBAL_MUTEX;
+       if (ocode == EINVAL)
+           return KTC_NOPIOCTL;
        return KTC_PIOCTLFAIL;
     }
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return 0;
 }
 
 /* ktc_OldPioctl - returns a boolean true if the kernel supports only the old
  * pioctl interface for delivering AFS tickets to the cache manager. */
 
-ktc_OldPioctl ()
+int
+ktc_OldPioctl(void)
 {
-    int rc;
-    LOCK_GLOBAL_MUTEX
-#ifdef KERNEL_KTC_COMPAT
-    CHECK_KERNEL;
-    rc = (kernelKTC != 1);             /* old style interface */
+    return 1;
+}
+
+afs_uint32
+ktc_curpag(void)
+{
+    int code;
+    struct ViceIoctl iob;
+    afs_uint32 pag;
+
+    /* now setup for the pioctl */
+    iob.in = NULL;
+    iob.in_size = 0;
+    iob.out = (caddr_t) &pag;
+    iob.out_size = sizeof(afs_uint32);
+
+    code = PIOCTL(0, VIOC_GETPAG, &iob, 0);
+    if (code < 0) {
+#if defined(AFS_AIX52_ENV)
+       code = getpagvalue("afs");
+       if (code < 0 && errno == EINVAL)
+           code = 0;
+       return code;
+#elif defined(AFS_AIX51_ENV)
+       return -1;
 #else
-    rc = 1;
+       gid_t groups[NGROUPS_MAX];
+       afs_uint32 g0, g1;
+       afs_uint32 h, l, ret;
+       int ngroups;
+#ifdef AFS_PAG_ONEGROUP_ENV
+       int i;
 #endif
-    UNLOCK_GLOBAL_MUTEX
-    return rc;
+
+       ngroups = getgroups(sizeof groups / sizeof groups[0], groups);
+
+#ifdef AFS_PAG_ONEGROUP_ENV
+       /* Check for one-group PAGs. */
+       for (i = 0; i < ngroups; i++) {
+           if (((groups[i] >> 24) & 0xff) == 'A') {
+               return groups[i];
+           }
+       }
+#endif
+
+       if (ngroups < 2)
+           return 0;
+
+       g0 = groups[0] & 0xffff;
+       g1 = groups[1] & 0xffff;
+       g0 -= 0x3f00;
+       g1 -= 0x3f00;
+       if (g0 < 0xc000 && g1 < 0xc000) {
+           l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
+           h = (g0 >> 14);
+           h = (g1 >> 14) + h + h + h;
+           ret = ((h << 28) | l);
+           /* Additional testing */
+           if (((ret >> 24) & 0xff) == 'A')
+               return ret;
+           else
+               return -1;
+       }
+       return -1;
+#endif
+    }
+    return pag;
 }
 
 
@@ -869,21 +1118,12 @@ ktc_OldPioctl ()
   * For copying and distribution information, please see the file
   * <mit-copyright.h>.
   */
-#if 0
-#include <stdio.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <krb.h>
-#endif
+
 #define TOO_BIG -1
 #define TF_LCK_RETRY ((unsigned)2)     /* seconds to sleep before
-                                        * retry if ticket file is
-                                        * locked */
+                                        * retry if ticket file is
+                                        * locked */
+
 /*
  * 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
@@ -895,15 +1135,16 @@ ktc_OldPioctl ()
  *        are invalid (ie. when deciding whether afs_tf_init has been
  *        called.)
  *     c. In tf_close, be sure it gets reinitialized to a negative
- *        number. 
+ *        number.
  */
-static  fd = -1;
-static curpos;                         /* Position in tfbfr */
-static lastpos;                        /* End of tfbfr */
-static char tfbfr[BUFSIZ];             /* Buffer for ticket data */
-static tf_gets(), tf_read();
+static int fd = -1;
+static int curpos;                     /* Position in tfbfr */
+static int lastpos;                    /* End of tfbfr */
+static char tfbfr[BUFSIZ];     /* Buffer for ticket data */
+
+static int tf_gets(char *, int);
+static int tf_read(char *, int);
+
 /*
  * This file contains routines for manipulating the ticket cache file.
  *
@@ -944,7 +1185,7 @@ static tf_gets(), tf_read();
  * afs_tf_close() closes the ticket file and releases the lock.
  *
  * tf_gets() returns the next null-terminated string.  It's an internal
- * routine used by afs_tf_get_pname(), afs_tf_get_pinst(), and 
+ * routine used by afs_tf_get_pname(), afs_tf_get_pinst(), and
  * afs_tf_get_cred().
  *
  * tf_read() reads a given number of bytes.  It's an internal routine
@@ -954,53 +1195,53 @@ static tf_gets(), tf_read();
 /*
  * afs_tf_init() should be called before the other ticket file routines.
  * It takes the name of the ticket file to use, "tf_name", and a
- * read/write flag "rw" as arguments. 
+ * read/write flag "rw" as arguments.
  *
  * It tries to open the ticket file, checks the mode, and if everything
  * is okay, locks the file.  If it's opened for reading, the lock is
- * shared.  If it's opened for writing, the lock is exclusive. 
+ * shared.  If it's opened for writing, the lock is exclusive.
  *
- * Returns 0 if all went well, otherwise one of the following: 
+ * Returns 0 if all went well, otherwise one of the following:
  *
  * NO_TKT_FIL   - file wasn't there
  * TKT_FIL_ACC  - file was in wrong mode, etc.
  * TKT_FIL_LCK  - couldn't lock the file, even after a retry
  */
-afs_tf_init(tf_name, rw)
-    char   *tf_name;
+
+int
+afs_tf_init(char *tf_name, int rw)
 {
-    int     wflag;
-    int   me;
-     struct stat stat_buf;
-
-     switch (rw) {
-     case R_TKT_FIL:
-       wflag = 0;
-       break;
-     case W_TKT_FIL:
-       wflag = 1;
-       break;
-     default:
-       return TKT_FIL_ACC;
-     }
-     if (lstat(tf_name, &stat_buf) < 0)
-       switch (errno) {
-       case ENOENT:
-           return NO_TKT_FIL;
-       default:
-           return TKT_FIL_ACC;
-       }
-     me = getuid();
-     if ((stat_buf.st_uid != me && me != 0) ||
-       ((stat_buf.st_mode & S_IFMT) != S_IFREG))
-       return TKT_FIL_ACC;
-     /*
-      * If "wflag" is set, open the ticket file in append-writeonly mode
-      * and lock the ticket file in exclusive mode.  If unable to lock
+    int wflag;
+    int me;
+    struct stat stat_buf;
+
+    switch (rw) {
+    case R_TKT_FIL:
+       wflag = 0;
+       break;
+    case W_TKT_FIL:
+       wflag = 1;
+       break;
+    default:
+       return TKT_FIL_ACC;
+    }
+    if (lstat(tf_name, &stat_buf) < 0)
+       switch (errno) {
+       case ENOENT:
+           return NO_TKT_FIL;
+       default:
+           return TKT_FIL_ACC;
+       }
+    me = getuid();
+    if ((stat_buf.st_uid != me && me != 0)
+       || ((stat_buf.st_mode & S_IFMT) != S_IFREG))
+       return TKT_FIL_ACC;
+
+    /*
+     * If "wflag" is set, open the ticket file in append-writeonly mode
+     * and lock the ticket file in exclusive mode.  If unable to lock
      * the file, sleep and try again.  If we fail again, return with the
-     * proper error message. 
+     * proper error message.
      */
 
     curpos = sizeof(tfbfr);
@@ -1011,15 +1252,15 @@ afs_tf_init(tf_name, rw)
            return TKT_FIL_ACC;
        }
 #if defined(AFS_AIX_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
-       if  (fcntl(fd, F_SETLK, &fileWlock) == -1) {
+       if (fcntl(fd, F_SETLK, &fileWlock) == -1) {
            sleep(TF_LCK_RETRY);
-           if  (fcntl(fd, F_SETLK, &fileWlock) == -1) {
+           if (fcntl(fd, F_SETLK, &fileWlock) == -1) {
 #else
        if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
            sleep(TF_LCK_RETRY);
            if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
 #endif
-               (void) close(fd);
+               (void)close(fd);
                fd = -1;
                return TKT_FIL_LCK;
            }
@@ -1028,7 +1269,7 @@ afs_tf_init(tf_name, rw)
     }
     /*
      * Otherwise "wflag" is not set and the ticket file should be opened
-     * for read-only operations and locked for shared access. 
+     * for read-only operations and locked for shared access.
      */
 
     fd = open(tf_name, O_RDONLY, 0600);
@@ -1036,15 +1277,15 @@ afs_tf_init(tf_name, rw)
        return TKT_FIL_ACC;
     }
 #if defined(AFS_AIX_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
-    if  (fcntl(fd, F_SETLK, &fileRlock) == -1) {
+    if (fcntl(fd, F_SETLK, &fileRlock) == -1) {
        sleep(TF_LCK_RETRY);
-       if  (fcntl(fd, F_SETLK, &fileRlock) == -1) {
+       if (fcntl(fd, F_SETLK, &fileRlock) == -1) {
 #else
     if (flock(fd, LOCK_SH | LOCK_NB) < 0) {
        sleep(TF_LCK_RETRY);
        if (flock(fd, LOCK_SH | LOCK_NB) < 0) {
 #endif
-           (void) close(fd);
+           (void)close(fd);
            fd = -1;
            return TKT_FIL_LCK;
        }
@@ -1058,11 +1299,11 @@ afs_tf_init(tf_name, rw)
  * principal's name is filled into the "p" parameter.  If all goes well,
  * 0 is returned.  If afs_tf_init() wasn't called, TKT_FIL_INI is
  * returned.  If the name was null, or EOF was encountered, or the name
- * was longer than MAXKTCNAMELEN, TKT_FIL_FMT is returned. 
+ * was longer than MAXKTCNAMELEN, TKT_FIL_FMT is returned.
  */
 
-afs_tf_get_pname(p)
-    char   *p;
+int
+afs_tf_get_pname(char *p)
 {
     if (fd < 0) {
        return TKT_FIL_INI;
@@ -1079,11 +1320,11 @@ afs_tf_get_pname(p)
  * goes well, 0 is returned.  If afs_tf_init() wasn't called,
  * TKT_FIL_INI is returned.  If EOF was encountered, or the instance
  * was longer than MAXKTCNAMELEN, TKT_FIL_FMT is returned.  Note that the
- * instance may be null. 
+ * instance may be null.
  */
 
-afs_tf_get_pinst(inst)
-    char   *inst;
+int
+afs_tf_get_pinst(char *inst)
 {
     if (fd < 0) {
        return TKT_FIL_INI;
@@ -1096,20 +1337,20 @@ afs_tf_get_pinst(inst)
 /*
  * afs_tf_get_cred() reads a CREDENTIALS record from a ticket file and fills
  * in the given structure "c".  It should only be called after afs_tf_init(),
- * afs_tf_get_pname(), and afs_tf_get_pinst() have been called. If all goes 
- * well, 0 is returned.  Possible error codes are: 
+ * afs_tf_get_pname(), and afs_tf_get_pinst() have been called. If all goes
+ * well, 0 is returned.  Possible error codes are:
  *
  * TKT_FIL_INI  - afs_tf_init wasn't called first
  * TKT_FIL_FMT  - bad format
  * EOF          - end of file encountered
  */
 
-afs_tf_get_cred(principal, token)
-    struct ktc_principal *principal;
-    struct ktc_token *token;
+int
+afs_tf_get_cred(struct ktc_principal *principal, struct ktc_token *token)
 {
-    int     k_errno;
-    int     kvno, lifetime;
+    int k_errno;
+    int kvno, lifetime;
+    long mit_compat;           /* MIT Kerberos 5 with Krb4 uses a "long" for issue_date */
 
     if (fd < 0) {
        return TKT_FIL_INI;
@@ -1138,19 +1379,18 @@ afs_tf_get_cred(principal, token)
            return EOF;
        }
     lcstring(principal->cell, principal->cell, MAXKTCREALMLEN);
-    if (
-       tf_read((char *) &(token->sessionKey), 8) < 1 ||
-       tf_read((char *) &(lifetime), sizeof(lifetime)) < 1 ||
-       tf_read((char *) &(kvno), sizeof(kvno)) < 1 ||
-       tf_read((char *) &(token->ticketLen), sizeof(token->ticketLen))
+    if (tf_read((char *)&(token->sessionKey), 8) < 1
+       || tf_read((char *)&(lifetime), sizeof(lifetime)) < 1
+       || tf_read((char *)&(kvno), sizeof(kvno)) < 1
+       || tf_read((char *)&(token->ticketLen), sizeof(token->ticketLen))
        < 1 ||
-    /* don't try to read a silly amount into ticket->dat */
-       token->ticketLen > MAXKTCTICKETLEN ||
-       tf_read((char *) (token->ticket), token->ticketLen) < 1 ||
-       tf_read((char *) &(token->startTime), sizeof(token->startTime)) < 1
-       ) {
+       /* don't try to read a silly amount into ticket->dat */
+       token->ticketLen > MAXKTCTICKETLEN
+       || tf_read((char *)(token->ticket), token->ticketLen) < 1
+       || tf_read((char *)&mit_compat, sizeof(mit_compat)) < 1) {
        return TKT_FIL_FMT;
     }
+    token->startTime = mit_compat;
     token->endTime = life_to_time(token->startTime, lifetime);
     token->kvno = kvno;
     return 0;
@@ -1164,18 +1404,20 @@ afs_tf_get_cred(principal, token)
  * The return value is not defined.
  */
 
-afs_tf_close()
+int
+afs_tf_close(void)
 {
     if (!(fd < 0)) {
 #if defined(AFS_AIX_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_SUN5_ENV)
-       (void) fcntl(fd, F_SETLK, &fileUlock);
+       (void)fcntl(fd, F_SETLK, &fileUlock);
 #else
-       (void) flock(fd, LOCK_UN);
-#endif 
-       (void) close(fd);
+       (void)flock(fd, LOCK_UN);
+#endif
+       (void)close(fd);
        fd = -1;                /* see declaration of fd above */
     }
     memset(tfbfr, 0, sizeof(tfbfr));
+    return 0;
 }
 
 /*
@@ -1196,11 +1438,10 @@ afs_tf_close()
  *             file is seriously ill.
  */
 
-static 
-tf_gets(s, n)
-    register char *s;
+static int
+tf_gets(char *s, int n)
 {
-    register count;
+    int count;
 
     if (fd < 0) {
        return TKT_FIL_INI;
@@ -1214,7 +1455,7 @@ tf_gets(s, n)
            return 0;
        }
        *s = tfbfr[curpos++];
-       if (*s++== '\0')
+       if (*s++ == '\0')
            return (n - count);
     }
     return TOO_BIG;
@@ -1232,13 +1473,11 @@ tf_gets(s, n)
  * 0           on end of file or read error
  */
 
-static
-tf_read(s, n)
-    register char *s;
-    register n;
+static int
+tf_read(char *s, int n)
 {
-    register count;
-    
+    int count;
+
     for (count = n; count > 0; --count) {
        if (curpos >= sizeof(tfbfr)) {
            lastpos = read(fd, tfbfr, sizeof(tfbfr));
@@ -1251,8 +1490,6 @@ tf_read(s, n)
     }
     return n;
 }
-     
-char   *tkt_string();
 
 /*
  * afs_tf_save_cred() appends an incoming ticket to the end of the ticket
@@ -1265,48 +1502,52 @@ char   *tkt_string();
  * called previously, and KFAILURE for anything else that went wrong.
  */
 
-afs_tf_save_cred(aserver, atoken, aclient)
-    struct ktc_principal *aserver;
-    struct ktc_principal *aclient;
-    struct ktc_token *atoken;  /* Token */
+int
+afs_tf_save_cred(struct ktc_principal *aserver,
+                struct ktc_token *atoken,
+                struct ktc_principal *aclient)
 {
-    char realm[MAXKTCREALMLEN+1];
+    char realm[MAXKTCREALMLEN + 1];
     char junk[MAXKTCNAMELEN];
     struct ktc_principal principal;
     struct ktc_token token;
-    int     status;
-    off_t   start;
-    int     lifetime, kvno;
-    int     count;             /* count for write */
+    int status;
+    off_t start;
+    int lifetime, kvno;
+    int count;                 /* count for write */
+    long mit_compat;           /* MIT Kerberos 5 with Krb4 uses a "long" for issue_date */
 
     if (fd < 0) {              /* fd is ticket file as set by afs_tf_init */
-         return TKT_FIL_INI;
+       return TKT_FIL_INI;
     }
 
     ucstring(realm, aserver->cell, MAXKTCREALMLEN);
     realm[MAXKTCREALMLEN] = '\0';
 
     /* Look for a duplicate ticket */
-    (void) lseek(fd, (off_t) 0L, 0);
+    (void)lseek(fd, (off_t) 0L, 0);
     curpos = sizeof(tfbfr);
 
-    if (afs_tf_get_pname(junk) || strcmp(junk, aclient->name) ||
-       afs_tf_get_pinst(junk) || strcmp(junk, aclient->instance)) goto bad;
+    if (afs_tf_get_pname(junk) || strcmp(junk, aclient->name)
+       || afs_tf_get_pinst(junk) || strcmp(junk, aclient->instance))
+       goto bad;
 
     do {
        start = lseek(fd, (off_t) 0L, 1) - lastpos + curpos;
        status = afs_tf_get_cred(&principal, &token);
-    } while (status == 0 &&
-            (strcmp(aserver->name, principal.name) != 0 ||
-             strcmp(aserver->instance, principal.instance) != 0 ||
-             strcmp(aserver->cell, principal.cell) != 0));
+    } while (status == 0
+            && (strcmp(aserver->name, principal.name) != 0
+                || strcmp(aserver->instance, principal.instance) != 0
+                || strcmp(aserver->cell, principal.cell) != 0));
 
     /*
      * Two tickets for the same user authenticating to the same service
      * should be the same length, but we check here just to make sure.
      */
-    if (status == 0 && token.ticketLen != atoken->ticketLen) return KFAILURE;
-    if (status && status != EOF) return status;
+    if (status == 0 && token.ticketLen != atoken->ticketLen)
+       return KFAILURE;
+    if (status && status != EOF)
+       return status;
 
     /* Position over the credential we just matched (or the EOF) */
     lseek(fd, start, 0);
@@ -1326,32 +1567,32 @@ afs_tf_save_cred(aserver, atoken, aclient)
     if (write(fd, realm, count) != count)
        goto bad;
     /* Session key */
-    if (write(fd, (char *) &atoken->sessionKey, 8) != 8)
+    if (write(fd, (char *)&atoken->sessionKey, 8) != 8)
        goto bad;
     /* Lifetime */
     lifetime = time_to_life(atoken->startTime, atoken->endTime);
-    if (write(fd, (char *) &lifetime, sizeof(int)) != sizeof(int))
+    if (write(fd, (char *)&lifetime, sizeof(int)) != sizeof(int))
        goto bad;
     /* Key vno */
     kvno = atoken->kvno;
-    if (write(fd, (char *) &kvno, sizeof(int)) != sizeof(int))
+    if (write(fd, (char *)&kvno, sizeof(int)) != sizeof(int))
        goto bad;
     /* Tkt length */
-    if (write(fd, (char *) &(atoken->ticketLen), sizeof(int)) !=
-       sizeof(int))
+    if (write(fd, (char *)&(atoken->ticketLen), sizeof(int)) != sizeof(int))
        goto bad;
     /* Ticket */
     count = atoken->ticketLen;
     if (write(fd, atoken->ticket, count) != count)
        goto bad;
     /* Issue date */
-    if (write(fd, (char *) &atoken->startTime, sizeof(afs_int32))
-       != sizeof(afs_int32))
+    mit_compat = atoken->startTime;
+    if (write(fd, (char *)&mit_compat, sizeof(mit_compat))
+       != sizeof(mit_compat))
        goto bad;
 
     /* Actually, we should check each write for success */
     return (0);
-bad:
+  bad:
     return (KFAILURE);
 }
 
@@ -1363,8 +1604,6 @@ bad:
  * <mit-copyright.h>.
  */
 
-char *getenv();
-
 /*
  * This routine is used to generate the name of the file that holds
  * the user's cache of server tickets and associated session keys.
@@ -1381,23 +1620,30 @@ char *getenv();
 
 static char krb_ticket_string[4096] = "";
 
-char *ktc_tkt_string()
+char *
+ktc_tkt_string(void)
+{
+    return ktc_tkt_string_uid(getuid());
+}
+
+char *
+ktc_tkt_string_uid(afs_uint32 uid)
 {
     char *env;
 
-    LOCK_GLOBAL_MUTEX
+    LOCK_GLOBAL_MUTEX;
     if (!*krb_ticket_string) {
-        if (env = getenv("KRBTKFILE")) {
-           (void) strncpy(krb_ticket_string, env,
-                          sizeof(krb_ticket_string)-1);
-           krb_ticket_string[sizeof(krb_ticket_string)-1] = '\0';
+       if ((env = getenv("KRBTKFILE"))) {
+           (void)strncpy(krb_ticket_string, env,
+                         sizeof(krb_ticket_string) - 1);
+           krb_ticket_string[sizeof(krb_ticket_string) - 1] = '\0';
        } else {
            /* 32 bits of signed integer will always fit in 11 characters
-            (including the sign), so no need to worry about overflow */
-           (void) sprintf(krb_ticket_string, "%s%d",TKT_ROOT,getuid());
-        }
+            * (including the sign), so no need to worry about overflow */
+           (void)sprintf(krb_ticket_string, "%s%d", TKT_ROOT, uid);
+       }
     }
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return krb_ticket_string;
 }
 
@@ -1413,15 +1659,13 @@ char *ktc_tkt_string()
  */
 
 void
-ktc_set_tkt_string(val)
-char *val;
+ktc_set_tkt_string(char * val)
 {
 
-    LOCK_GLOBAL_MUTEX
-    (void) strncpy(krb_ticket_string, val, sizeof(krb_ticket_string)-1);
-    krb_ticket_string[sizeof(krb_ticket_string)-1] = '\0';
-    UNLOCK_GLOBAL_MUTEX
-
+    LOCK_GLOBAL_MUTEX;
+    (void)strncpy(krb_ticket_string, val, sizeof(krb_ticket_string) - 1);
+    krb_ticket_string[sizeof(krb_ticket_string) - 1] = '\0';
+    UNLOCK_GLOBAL_MUTEX;
     return;
 }
 
@@ -1432,76 +1676,75 @@ char *val;
  * success, or KFAILURE if something goes wrong.
  */
 
-afs_tf_create(pname,pinst)
-    char *pname;
-    char *pinst;
+int
+afs_tf_create(char *pname, char *pinst)
 {
     int tktfile;
     int me, metoo;
     int count;
     char *file = ktc_tkt_string();
     int fd;
-    register int i;
+    int i;
     char zerobuf[1024];
     struct stat sbuf;
 
-    me = getuid ();
+    me = getuid();
     metoo = geteuid();
 
-    if (lstat(file,&sbuf) == 0) {
-       if ((sbuf.st_uid != me && me != 0) || ((sbuf.st_mode & S_IFMT) != S_IFREG) ||
-           sbuf.st_mode & 077) {
+    if (lstat(file, &sbuf) == 0) {
+       if ((sbuf.st_uid != me && me != 0)
+           || ((sbuf.st_mode & S_IFMT) != S_IFREG) || sbuf.st_mode & 077) {
            return KFAILURE;
        }
        /* file already exists, and permissions appear ok, so nuke it */
        if ((fd = open(file, O_RDWR, 0)) < 0)
-           goto out; /* can't zero it, but we can still try truncating it */
+           goto out;           /* can't zero it, but we can still try truncating it */
 
        memset(zerobuf, 0, sizeof(zerobuf));
 
        for (i = 0; i < sbuf.st_size; i += sizeof(zerobuf))
            if (write(fd, zerobuf, sizeof(zerobuf)) != sizeof(zerobuf)) {
-               (void) fsync(fd);
-               (void) close(fd);
+               (void)fsync(fd);
+               (void)close(fd);
                goto out;
            }
-       
-       (void) fsync(fd);
-       (void) close(fd);
+
+       (void)fsync(fd);
+       (void)close(fd);
     }
 
- out:
+  out:
     /* arrange so the file is owned by the ruid
-       (swap real & effective uid if necessary).
-       This isn't a security problem, since the ticket file, if it already
-       exists, has the right uid (== ruid) and mode. */
+     * (swap real & effective uid if necessary).
+     * This isn't a security problem, since the ticket file, if it already
+     * exists, has the right uid (== ruid) and mode. */
     if (me != metoo) {
        if (setreuid(metoo, me) < 0) {
-           return(KFAILURE);
+           return (KFAILURE);
        }
     }
     tktfile = creat(file, 0600);
     if (me != metoo) {
        if (setreuid(me, metoo) < 0) {
            /* can't switch??? fail! */
-           return(KFAILURE);
+           return (KFAILURE);
        }
     }
     if (tktfile < 0) {
-        return(KFAILURE);
+       return (KFAILURE);
     }
-    count = strlen(pname)+1;
-    if (write(tktfile,pname,count) != count) {
-        (void) close(tktfile);
-        return(KFAILURE);
+    count = strlen(pname) + 1;
+    if (write(tktfile, pname, count) != count) {
+       (void)close(tktfile);
+       return (KFAILURE);
     }
-    count = strlen(pinst)+1;
-    if (write(tktfile,pinst,count) != count) {
-        (void) close(tktfile);
-        return(KFAILURE);
+    count = strlen(pinst) + 1;
+    if (write(tktfile, pinst, count) != count) {
+       (void)close(tktfile);
+       return (KFAILURE);
     }
-    (void) close(tktfile);
-    return(KSUCCESS);
+    (void)close(tktfile);
+    return (KSUCCESS);
 }
 
 /*
@@ -1511,15 +1754,16 @@ afs_tf_create(pname,pinst)
  * failure.
  */
 
-afs_tf_dest_tkt()
+int
+afs_tf_dest_tkt(void)
 {
     char *file = ktc_tkt_string();
-    int i,fd;
+    int i, fd;
     struct stat statb;
     char buf[BUFSIZ];
 
     errno = 0;
-    if (lstat(file,&statb) < 0)
+    if (lstat(file, &statb) < 0)
        goto out;
 
     if (!(statb.st_mode & S_IFREG))
@@ -1532,101 +1776,95 @@ afs_tf_dest_tkt()
 
     for (i = 0; i < statb.st_size; i += BUFSIZ)
        if (write(fd, buf, BUFSIZ) != BUFSIZ) {
-           (void) fsync(fd);
-           (void) close(fd);
+           (void)fsync(fd);
+           (void)close(fd);
            goto out;
        }
 
-    (void) fsync(fd);
-    (void) close(fd);
+    (void)fsync(fd);
+    (void)close(fd);
 
-    (void) unlink(file);
+    (void)unlink(file);
 
-out:
-    if (errno == ENOENT) return RET_TKFIL;
-    else if (errno != 0) return KFAILURE;
+  out:
+    if (errno == ENOENT)
+       return RET_TKFIL;
+    else if (errno != 0)
+       return KFAILURE;
     return 0;
 }
 
-static afs_uint32 curpag()
-{
-    gid_t groups[NGROUPS_MAX];
-    afs_uint32 g0, g1;
-    afs_uint32 h, l, ret;
-
-    if (getgroups(sizeof groups/sizeof groups[0], groups) < 2) return 0;
-
-    g0 = groups[0]  & 0xffff;
-    g1 = groups[1]  & 0xffff;
-    g0 -= 0x3f00;
-    g1 -= 0x3f00;
-    if (g0 < 0xc000 && g1 < 0xc000) {
-       l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
-       h = (g0 >> 14);
-       h = (g1 >> 14) + h + h + h;
-       ret = ((h << 28) | l);
-       /* Additional testing */
-       if (((ret >> 24) & 0xff) == 'A')
-           return ret;
-       else
-           return -1;
-    }
-    return -1;
-}
-  
-
-ktc_newpag()
+int
+ktc_newpag(void)
 {
-    extern char **environ;
+#if !defined(AFS_DARWIN100_ENV) || defined(HAVE_CRT_EXTERNS_H)
+# if defined(AFS_DARWIN100_ENV)
+#  define environ (*_NSGetEnviron())
+# else
+extern char **environ;
+# endif
 
     afs_uint32 pag;
     struct stat sbuf;
     char fname[256], *prefix = "/ticket/";
+    char fname5[256], *prefix5 = "FILE:/ticket/krb5cc_";
     int numenv;
     char **newenv, **senv, **denv;
 
-    LOCK_GLOBAL_MUTEX
+    LOCK_GLOBAL_MUTEX;
     if (stat("/ticket", &sbuf) == -1) {
        prefix = "/tmp/tkt";
+       prefix5 = "FILE:/tmp/krb5cc_";
     }
 
-    pag = curpag() & 0xffffffff;
+    pag = ktc_curpag() & 0xffffffff;
     if (pag == -1) {
        sprintf(fname, "%s%d", prefix, getuid());
-    }
-    else {
-       sprintf(fname, "%sp%ld", prefix, pag);
+       sprintf(fname5, "%s%d", prefix5, getuid());
+    } else {
+       sprintf(fname, "%sp%lu", prefix, afs_printable_uint32_lu(pag));
+       sprintf(fname5, "%sp%lud", prefix5, afs_printable_uint32_lu(pag));
     }
     ktc_set_tkt_string(fname);
 
-    for (senv=environ, numenv=0; *senv; senv++) numenv++;
-    newenv = (char **)malloc((numenv+2) * sizeof(char *));
+    for (senv = environ, numenv = 0; *senv; senv++)
+       numenv++;
+    newenv = malloc((numenv + 2) * sizeof(char *));
 
-    for (senv=environ, denv=newenv; *senv; *senv++) {
-       if (strncmp(*senv, "KRBTKFILE=", 10) != 0) *denv++ = *senv;
+    for (senv = environ, denv = newenv; *senv; senv++) {
+       if (strncmp(*senv, "KRBTKFILE=", 10) != 0 &&
+           strncmp(*senv, "KRB5CCNAME=", 11) != 0)
+           *denv++ = *senv;
     }
 
-    *denv = (char *)malloc(10 + strlen(fname) + 1);
+    *denv = malloc(10+11 + strlen(fname) + strlen(fname5) + 2);
     strcpy(*denv, "KRBTKFILE=");
     strcat(*denv, fname);
+    *(denv+1) = *denv + strlen(*denv) + 1;
+    denv++;
+    strcpy(*denv, "KRB5CCNAME=");
+    strcat(*denv, fname5);
     *++denv = 0;
     environ = newenv;
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
+#endif
+    return 0;
 }
 
 /*
  * BLETCH!  We have to invoke the entire afsconf package just to
  * find out what the local cell is.
  */
-static void ktc_LocalCell()
+static void
+ktc_LocalCell(void)
 {
-    int code;
+    int code = 0;
     struct afsconf_dir *conf;
 
-    if ((conf = afsconf_Open (AFSDIR_CLIENT_ETC_DIRPATH)) ||
-       (conf = afsconf_Open (AFSDIR_SERVER_ETC_DIRPATH ))) {
-       code = afsconf_GetLocalCell (conf, lcell, sizeof(lcell));
-       afsconf_Close (conf);
+    if ((conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))
+       || (conf = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH))) {
+       code = afsconf_GetLocalCell(conf, lcell, sizeof(lcell));
+       afsconf_Close(conf);
     }
     if (!conf || code) {
        printf("** Can't determine local cell name!\n");