auth & [ak]log: Don't cast returns from malloc()
[openafs.git] / src / auth / ktc_nt.c
index d263f33..8a91720 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
 
 #include <afsconfig.h>
 #include <afs/param.h>
+#include <afs/stds.h>
 
-RCSID
-    ("$Header$");
+#include <roken.h>
 
-#include <afs/stds.h>
-#include <stdio.h>
-#include <afs/pthread_glock.h>
-#include <sys/types.h>
 #include <ctype.h>
-#include <sys/stat.h>
-#include <signal.h>
-#include <errno.h>
+
+#include <afs/pthread_glock.h>
 #include <rpc.h>
 #include <afs/smb_iocons.h>
 #include <afs/pioctl_nt.h>
@@ -30,9 +25,10 @@ RCSID
 #include <afs/vice.h>
 #include "auth.h"
 #include <afs/afsutil.h>
+#include "token.h"
 
 /* TBUFFERSIZE must be at least 512 larger than KTCMAXTICKETSIZE */
-#define TBUFFERSIZE 8192  
+#define TBUFFERSIZE 12512
 
 /* Forward declarations for local token cache. */
 static int SetLocalToken(struct ktc_principal *aserver,
@@ -49,7 +45,10 @@ static char AFSConfigKeyName[] =
     "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters";
 
 static char AFSGlobalKTCMutexName[] = "Global\\AFS_KTC_Mutex";
-static char AFSKTCMutexName[]       = "AFS_KTC_Mutex";
+static char AFSKTCMutexName[] = "AFS_KTC_Mutex";
+
+#define MAXPIOCTLTOKENLEN \
+(3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
 
 /*
  * Support for RPC's to send and receive session keys
@@ -65,7 +64,7 @@ char rpcErr[256];
 void __RPC_FAR *__RPC_USER
 midl_user_allocate(size_t cBytes)
 {
-    return ((void __RPC_FAR *)malloc(cBytes));
+    return malloc(cBytes);
 }
 
 void __RPC_USER
@@ -113,12 +112,12 @@ send_key(afs_uuid_t uuid, char sessionKey[8])
 
     /* Encryption on by default */
     if (GetEnvironmentVariable("AFS_RPC_ENCRYPT", encrypt, sizeof(encrypt)))
-       if (!strcmpi(encrypt, "OFF"))
+       if (!_stricmp(encrypt, "OFF"))
            encryptionOff = TRUE;
 
-    /* Protocol sequence is named pipe by default */
+    /* Protocol sequence is local by default */
     if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
-       strcpy(protseq, "ncacn_np");
+       strcpy(protseq, "ncalrpc");
 
     /* Server name */
     getservername(&serverNamep, sizeof(serverName));
@@ -186,12 +185,12 @@ receive_key(afs_uuid_t uuid, char sessionKey[8])
 
     /* Encryption on by default */
     if (GetEnvironmentVariable("AFS_RPC_ENCRYPT", encrypt, sizeof(encrypt)))
-       if (!strcmpi(encrypt, "OFF"))
+       if (!_stricmp(encrypt, "OFF"))
            encryptionOff = TRUE;
 
-    /* Protocol sequence is named pipe by default */
+    /* Protocol sequence is local by default */
     if (!GetEnvironmentVariable("AFS_RPC_PROTSEQ", protseq, sizeof(protseq)))
-       strcpy(protseq, "ncacn_np");
+       strcpy(protseq, "ncalrpc");
 
     /* Server name */
     getservername(&serverNamep, sizeof(serverName));
@@ -251,6 +250,7 @@ ktc_SetToken(struct ktc_principal *server, struct ktc_token *token,
 {
     struct ViceIoctl iob;
     char tbuffer[TBUFFERSIZE];
+    int len;
     char *tp;
     struct ClearToken ct;
     int temp;
@@ -271,11 +271,15 @@ ktc_SetToken(struct ktc_principal *server, struct ktc_token *token,
 
     /* ticket length */
     memcpy(tp, &token->ticketLen, sizeof(token->ticketLen));
-    tp += sizeof(&token->ticketLen);
+    tp += sizeof(token->ticketLen);
+    len = sizeof(token->ticketLen);
 
     /* ticket */
+    if (len + token->ticketLen > TBUFFERSIZE)
+        return KTC_INVAL;
     memcpy(tp, token->ticket, token->ticketLen);
     tp += token->ticketLen;
+    len += token->ticketLen;
 
     /* clear token */
     ct.AuthHandle = token->kvno;
@@ -302,131 +306,142 @@ ktc_SetToken(struct ktc_principal *server, struct ktc_token *token,
        ct.BeginTimestamp++;    /* force lifetime to be even */
 
     /* size of clear token */
+    if (len + sizeof(temp) > TBUFFERSIZE)
+        return KTC_INVAL;
     temp = sizeof(struct ClearToken);
     memcpy(tp, &temp, sizeof(temp));
     tp += sizeof(temp);
+    len += sizeof(temp);
 
     /* clear token itself */
+    if (len + sizeof(ct) > TBUFFERSIZE)
+        return KTC_INVAL;
     memcpy(tp, &ct, sizeof(ct));
     tp += sizeof(ct);
+    len += sizeof(ct);
 
     /* flags; on NT there is no setpag flag, but there is an
      * integrated logon flag */
+    if (len + sizeof(temp) > TBUFFERSIZE)
+        return KTC_INVAL;
     temp = ((flags & AFS_SETTOK_LOGON) ? PIOCTL_LOGON : 0);
     memcpy(tp, &temp, sizeof(temp));
     tp += sizeof(temp);
+    len += sizeof(temp);
 
     /* cell name */
-    temp = strlen(server->cell);
-    if (temp >= MAXKTCREALMLEN)
+    temp = (int)strlen(server->cell) + 1;
+    if (len + temp > TBUFFERSIZE ||
+        temp > MAXKTCREALMLEN)
        return KTC_INVAL;
     strcpy(tp, server->cell);
-    tp += temp + 1;
+    tp += temp;
+    len += temp;
 
     /* user name */
-    temp = strlen(client->name);
-    if (temp >= MAXKTCNAMELEN)
+    temp = (int)strlen(client->name) + 1;
+    if (len + temp > TBUFFERSIZE ||
+        temp > MAXKTCNAMELEN)
        return KTC_INVAL;
     strcpy(tp, client->name);
-    tp += temp + 1;
+    tp += temp;
+    len += temp;
 
     /* we need the SMB user name to associate the tokens with in the
      * integrated logon case. */
     if (flags & AFS_SETTOK_LOGON) {
        if (client->smbname == NULL)
-           temp = 0;
+           temp = 1;
        else
-           temp = strlen(client->smbname);
-       if (temp == 0 || temp >= MAXKTCNAMELEN)
+           temp = (int)strlen(client->smbname) + 1;
+       if (temp == 1 ||
+            len + temp > TBUFFERSIZE ||
+            temp > MAXKTCNAMELEN)
            return KTC_INVAL;
        strcpy(tp, client->smbname);
-       tp += temp + 1;
+       tp += temp;
+        len += temp;
     }
 
     /* uuid */
+    if (len + sizeof(uuid) > TBUFFERSIZE)
+        return KTC_INVAL;
     status = UuidCreate((UUID *) & uuid);
     memcpy(tp, &uuid, sizeof(uuid));
     tp += sizeof(uuid);
+    len += sizeof(uuid);
 
-
-#ifndef AFS_WIN95_ENV
     ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
-    if ( ktcMutex == NULL )
-        return KTC_PIOCTLFAIL;
-    if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
-        if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
-            CloseHandle(ktcMutex);
-            return KTC_PIOCTLFAIL;
-        }
+    if (ktcMutex == NULL)
+       return KTC_TOKEN_MUTEX_FAIL;
+    if (GetLastError() == ERROR_ALREADY_EXISTS) {
+       if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
+           CloseHandle(ktcMutex);
+            return KTC_TOKEN_MUTEX_FAIL;
+       }
     }
 
     /* RPC to send session key */
     status = send_key(uuid, token->sessionKey.data);
     if (status != RPC_S_OK) {
-        if (status == 1)
-            strcpy(rpcErr, "RPC failure in AFS gateway");
-        else
-            DceErrorInqText(status, rpcErr);
+       if (status == 1)
+           strcpy(rpcErr, "RPC failure in AFS gateway");
+       else
+           DceErrorInqText(status, rpcErr);
+
+        ReleaseMutex(ktcMutex);
+        CloseHandle(ktcMutex);
+
         if (status == RPC_S_SERVER_UNAVAILABLE ||
-            status == EPT_S_NOT_REGISTERED) 
-        {
-            ReleaseMutex(ktcMutex);
-            CloseHandle(ktcMutex);
-            return KTC_NOCMRPC;
-        }
-        else 
-        {
-            ReleaseMutex(ktcMutex);
-            CloseHandle(ktcMutex);
-            return KTC_RPC;
-        }
+           status == EPT_S_NOT_REGISTERED) {
+           return KTC_NOCMRPC;
+       } else {
+           return KTC_RPC;
+       }
     }
-#endif /* AFS_WIN95_ENV */
 
     /* set up for pioctl */
     iob.in = tbuffer;
-    iob.in_size = tp - tbuffer;
+    iob.in_size = (long)(tp - tbuffer);
     iob.out = tbuffer;
     iob.out_size = sizeof(tbuffer);
 
     code = pioctl(0, VIOCSETTOK, &iob, 0);
 
-#ifndef AFS_WIN95_ENV
     ReleaseMutex(ktcMutex);
     CloseHandle(ktcMutex);
-#endif /* AFS_WIN95_ENV */
 
     if (code) {
-        if (code == -1) {
-            if (errno == ESRCH)
-                return KTC_NOCELL;
-            else if (errno == ENODEV)
-                return KTC_NOCM;
-            else if (errno == EINVAL)
-                return KTC_INVAL;
-            else
-                return KTC_PIOCTLFAIL;
-        } else
-            return KTC_PIOCTLFAIL;
+       if (code == -1) {
+           if (errno == ESRCH)
+               return KTC_NOCELL;
+           else if (errno == ENODEV)
+               return KTC_NOCM;
+           else if (errno == EINVAL)
+               return KTC_INVAL;
+           else
+               return KTC_PIOCTLFAIL;
+       } else
+           return KTC_PIOCTLFAIL;
     }
 
     return 0;
 }
 
 int
+ktc_SetTokenEx(struct ktc_setTokenData *token)
+{
+    /* Not yet implemented */
+    return KTC_PIOCTLFAIL;
+}
+
+int
 ktc_GetToken(struct ktc_principal *server, struct ktc_token *token,
             int tokenLen, struct ktc_principal *client)
 {
     struct ViceIoctl iob;
-<<<<<<< ktc_nt.c
     char tbuffer[TBUFFERSIZE];
-=======
-<<<<<<< ktc_nt.c
-    char tbuffer[TBUFFERSIZE];
-=======
-    char tbuffer[MAXKTCTICKETLEN];
->>>>>>> 1.11
->>>>>>> 1.12
+    size_t len;
     char *tp, *cp;
     char *ticketP;
     int ticketLen, temp;
@@ -449,54 +464,51 @@ ktc_GetToken(struct ktc_principal *server, struct ktc_token *token,
     }
 
     /* cell name */
+    len = strlen(server->cell) + 1;
     strcpy(tp, server->cell);
-    tp += strlen(server->cell) + 1;
+    tp += len;
 
     /* uuid */
     status = UuidCreate((UUID *) & uuid);
     memcpy(tp, &uuid, sizeof(uuid));
     tp += sizeof(uuid);
+    len += sizeof(uuid);
 
     iob.in = tbuffer;
-    iob.in_size = tp - tbuffer;
+    iob.in_size = (long)(tp - tbuffer);
     iob.out = tbuffer;
     iob.out_size = sizeof(tbuffer);
 
-#ifndef AFS_WIN95_ENV          
     ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
-    if ( ktcMutex == NULL )
-        return KTC_PIOCTLFAIL;
-    if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
-        if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
-            CloseHandle(ktcMutex);
-            return KTC_PIOCTLFAIL;
-        }
+    if (ktcMutex == NULL)
+       return KTC_TOKEN_MUTEX_FAIL;
+    if (GetLastError() == ERROR_ALREADY_EXISTS) {
+       if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
+           CloseHandle(ktcMutex);
+            return KTC_TOKEN_MUTEX_FAIL;
+       }
     }
-#endif /* AFS_WIN95_ENV */
 
     code = pioctl(0, VIOCNEWGETTOK, &iob, 0);
     if (code) {
-#ifndef AFS_WIN95_ENV
-        ReleaseMutex(ktcMutex);
-        CloseHandle(ktcMutex);
-#endif /* AFS_WIN95_ENV */
-        if (code == -1) {
-            if (errno == ESRCH)
-                return KTC_NOCELL;
-            else if (errno == ENODEV)
-                return KTC_NOCM;
-            else if (errno == EINVAL)
-                return KTC_INVAL;
-            else if (errno == EDOM)
-                return KTC_NOENT;
-            else
-                return KTC_PIOCTLFAIL;
-        } else
-            return KTC_PIOCTLFAIL;
-    }                                                             
-
-#ifndef AFS_WIN95_ENV          
-    /* get rid of RPC for win95 build */
+       ReleaseMutex(ktcMutex);
+       CloseHandle(ktcMutex);
+
+       if (code == -1) {
+           if (errno == ESRCH)
+               return KTC_NOCELL;
+           else if (errno == ENODEV)
+               return KTC_NOCM;
+           else if (errno == EINVAL)
+               return KTC_INVAL;
+           else if (errno == EDOM)
+               return KTC_NOENT;
+           else
+               return KTC_PIOCTLFAIL;
+       } else
+           return KTC_PIOCTLFAIL;
+    }
+
     /* RPC to receive session key */
     status = receive_key(uuid, token->sessionKey.data);
 
@@ -508,47 +520,72 @@ ktc_GetToken(struct ktc_principal *server, struct ktc_token *token,
             strcpy(rpcErr, "RPC failure in AFS gateway");
         else
             DceErrorInqText(status, rpcErr);
-        if (status == RPC_S_SERVER_UNAVAILABLE
-             || status == EPT_S_NOT_REGISTERED)
+
+        if (status == RPC_S_SERVER_UNAVAILABLE ||
+            status == EPT_S_NOT_REGISTERED)
             return KTC_NOCMRPC;
-        else 
+        else
             return KTC_RPC;
     }
-#endif /* AFS_WIN95_ENV */
 
     cp = tbuffer;
 
     /* ticket length */
     memcpy(&ticketLen, cp, sizeof(ticketLen));
     cp += sizeof(ticketLen);
+    len = sizeof(ticketLen);
 
     /* remember where ticket is and skip over it */
+    if (len + ticketLen > TBUFFERSIZE ||
+        len + ticketLen > iob.out_size)
+        return KTC_ERROR;
     ticketP = cp;
     cp += ticketLen;
+    len += ticketLen;
 
     /* size of clear token */
+    if (len + sizeof(temp) > TBUFFERSIZE ||
+        len + sizeof(temp) > iob.out_size)
+        return KTC_ERROR;
     memcpy(&temp, cp, sizeof(temp));
     cp += sizeof(temp);
+    len += sizeof(temp);
     if (temp != sizeof(ct))
        return KTC_ERROR;
 
     /* clear token */
+    if (len + temp > TBUFFERSIZE ||
+        len + temp > iob.out_size)
+        return KTC_ERROR;
     memcpy(&ct, cp, temp);
     cp += temp;
+    len += temp;
 
     /* skip over primary flag */
+    if (len + sizeof(temp) > TBUFFERSIZE ||
+        len + sizeof(temp) > iob.out_size)
+        return KTC_ERROR;
     cp += sizeof(temp);
+    len += sizeof(temp);
 
     /* remember cell name and skip over it */
     cellName = cp;
-    cellNameSize = strlen(cp);
+    cellNameSize = (int)strlen(cp);
+    if (len + cellNameSize + 1 > TBUFFERSIZE ||
+        len + cellNameSize + 1 > iob.out_size)
+        return KTC_ERROR;
     cp += cellNameSize + 1;
+    len += cellNameSize + 1;
 
     /* user name is here */
 
-    /* check that ticket will fit */
-    if (MAXKTCTICKETLEN < ticketLen)
-               return KTC_TOOBIG;
+    /* check that ticket will fit
+     * this compares the size of the ktc_token allocated by the app
+     * which might be smaller than the current definition of MAXKTCTICKETLEN
+     */
+    maxLen = tokenLen - sizeof(struct ktc_token) + MAXKTCTICKETLEN;
+    if (maxLen < ticketLen)
+       return KTC_TOOBIG;
 
     /* set return values */
     memcpy(token->ticket, ticketP, ticketLen);
@@ -574,27 +611,134 @@ ktc_GetToken(struct ktc_principal *server, struct ktc_token *token,
     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;
+    HANDLE ktcMutex = NULL;
+
+    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);
+
+    ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
+    if (ktcMutex == NULL)
+       return KTC_TOKEN_MUTEX_FAIL;
+    if (GetLastError() == ERROR_ALREADY_EXISTS) {
+       if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
+           CloseHandle(ktcMutex);
+            return KTC_TOKEN_MUTEX_FAIL;
+       }
+    }
+
+#if 0
+    code = pioctl(0, VIOC_GETTOK2, &iob, 0);
+#else
+    code = -1;   /* not yet implemented */
+       errno = EINVAL;
+#endif
+
+    ReleaseMutex(ktcMutex);
+    CloseHandle(ktcMutex);
+
+    /* 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_principal client;
+       struct ktc_tokenUnion token;
+       struct ktc_token *ktcToken; /* too huge for the stack */
+
+       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");
+       strcpy(server.cell, cellName);
+       code = ktc_GetToken(&server, ktcToken, sizeof(struct ktc_token),
+                           &client);
+       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_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;
+}
+
 int
 ktc_ListTokens(int cellNum, int *cellNumP, struct ktc_principal *server)
 {
     struct ViceIoctl iob;
     char tbuffer[TBUFFERSIZE];
+    int len;
     char *tp, *cp;
     int newIter, ticketLen, temp;
     int code;
     HANDLE ktcMutex = NULL;
 
-#ifndef AFS_WIN95_ENV          
     ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
-    if ( ktcMutex == NULL )
-        return KTC_PIOCTLFAIL;
-    if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
-        if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
-            CloseHandle(ktcMutex);
-            return KTC_PIOCTLFAIL;
-        }
+    if (ktcMutex == NULL)
+       return KTC_TOKEN_MUTEX_FAIL;
+    if (GetLastError() == ERROR_ALREADY_EXISTS) {
+       if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
+           CloseHandle(ktcMutex);
+            return KTC_TOKEN_MUTEX_FAIL;
+       }
     }
-#endif /* AFS_WIN95_ENV */
 
     tp = tbuffer;
 
@@ -604,16 +748,14 @@ ktc_ListTokens(int cellNum, int *cellNumP, struct ktc_principal *server)
 
     /* do pioctl */
     iob.in = tbuffer;
-    iob.in_size = tp - tbuffer;
+    iob.in_size = (long)(tp - tbuffer);
     iob.out = tbuffer;
     iob.out_size = sizeof(tbuffer);
 
     code = pioctl(0, VIOCGETTOK, &iob, 0);
 
-#ifndef AFS_WIN95_ENV
-        ReleaseMutex(ktcMutex);
-        CloseHandle(ktcMutex);
-#endif /* AFS_WIN95_ENV */
+    ReleaseMutex(ktcMutex);
+    CloseHandle(ktcMutex);
 
     if (code) {
        if (code == -1) {
@@ -636,29 +778,47 @@ ktc_ListTokens(int cellNum, int *cellNumP, struct ktc_principal *server)
     /* new iterator */
     memcpy(&newIter, cp, sizeof(newIter));
     cp += sizeof(newIter);
+    len = sizeof(newIter);
 
     /* ticket length */
+    if (len + sizeof(ticketLen) > TBUFFERSIZE ||
+        len + sizeof(ticketLen) > iob.out_size)
+        return KTC_ERROR;
     memcpy(&ticketLen, cp, sizeof(ticketLen));
     cp += sizeof(ticketLen);
+    len += sizeof(ticketLen);
 
     /* skip over ticket */
     cp += ticketLen;
+    len += ticketLen;
 
     /* clear token size */
+    if (len + sizeof(temp) > TBUFFERSIZE ||
+        len + sizeof(temp) > iob.out_size)
+        return KTC_ERROR;
     memcpy(&temp, cp, sizeof(temp));
     cp += sizeof(temp);
+    len += sizeof(temp);
     if (temp != sizeof(struct ClearToken))
        return KTC_ERROR;
 
     /* skip over clear token */
     cp += sizeof(struct ClearToken);
+    len += sizeof(struct ClearToken);
 
     /* skip over primary flag */
     cp += sizeof(temp);
+    len += sizeof(temp);
+    if (len > TBUFFERSIZE ||
+        len > iob.out_size)
+        return KTC_ERROR;
 
     /* cell name is here */
 
     /* set return values */
+    if (len + temp > TBUFFERSIZE ||
+        temp > MAXKTCREALMLEN)
+        return KTC_ERROR;
     strcpy(server->cell, cp);
     server->instance[0] = '\0';
     strcpy(server->name, "afs");
@@ -679,18 +839,15 @@ ktc_ForgetToken(struct ktc_principal *server)
     if (strcmp(server->name, "afs")) {
        return ForgetOneLocalToken(server);
     }
-
-#ifndef AFS_WIN95_ENV          
     ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
-    if ( ktcMutex == NULL )
-        return KTC_PIOCTLFAIL;
-    if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
-        if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
-            CloseHandle(ktcMutex);
-            return KTC_PIOCTLFAIL;
-        }
+    if (ktcMutex == NULL)
+       return KTC_TOKEN_MUTEX_FAIL;
+    if (GetLastError() == ERROR_ALREADY_EXISTS) {
+       if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
+           CloseHandle(ktcMutex);
+            return KTC_TOKEN_MUTEX_FAIL;
+       }
     }
-#endif /* AFS_WIN95_ENV */
 
     tp = tbuffer;
 
@@ -700,15 +857,14 @@ ktc_ForgetToken(struct ktc_principal *server)
 
     /* do pioctl */
     iob.in = tbuffer;
-    iob.in_size = tp - tbuffer;
+    iob.in_size = (long)(tp - tbuffer);
     iob.out = tbuffer;
     iob.out_size = sizeof(tbuffer);
 
     code = pioctl(0, VIOCDELTOK, &iob, 0);
-#ifndef AFS_WIN95_ENV
     ReleaseMutex(ktcMutex);
     CloseHandle(ktcMutex);
-#endif /* AFS_WIN95_ENV */
+
     if (code) {
        if (code == -1) {
            if (errno == ESRCH)
@@ -735,17 +891,15 @@ ktc_ForgetAllTokens()
 
     (void)ForgetLocalTokens();
 
-#ifndef AFS_WIN95_ENV          
     ktcMutex = CreateMutex(NULL, TRUE, AFSGlobalKTCMutexName);
-    if ( ktcMutex == NULL )
-        return KTC_PIOCTLFAIL;
-    if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
-        if ( WaitForSingleObject( ktcMutex, INFINITE) != WAIT_OBJECT_0 ) {
-            CloseHandle(ktcMutex);
-            return KTC_PIOCTLFAIL;
-        }
+    if (ktcMutex == NULL)
+       return KTC_TOKEN_MUTEX_FAIL;
+    if (GetLastError() == ERROR_ALREADY_EXISTS) {
+       if (WaitForSingleObject(ktcMutex, INFINITE) != WAIT_OBJECT_0) {
+           CloseHandle(ktcMutex);
+            return KTC_TOKEN_MUTEX_FAIL;
+       }
     }
-#endif /* AFS_WIN95_ENV */
 
     /* do pioctl */
     iob.in = tbuffer;
@@ -754,10 +908,9 @@ ktc_ForgetAllTokens()
     iob.out_size = sizeof(tbuffer);
 
     code = pioctl(0, VIOCDELALLTOK, &iob, 0);
-#ifndef AFS_WIN95_ENV
     ReleaseMutex(ktcMutex);
     CloseHandle(ktcMutex);
-#endif /* AFS_WIN95_ENV */
+
     if (code) {
        if (code == -1) {
            if (errno == ENODEV)
@@ -794,7 +947,8 @@ SetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
     int found = -1;
     int i;
 
-    LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++)
+    LOCK_GLOBAL_MUTEX;
+    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)
@@ -806,7 +960,8 @@ SetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
        } else if (found == -1)
            found = i;          /* remember empty slot but keep looking for a match */
     if (found == -1) {
-       UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
+       UNLOCK_GLOBAL_MUTEX;
+       return KTC_NOENT;
     }
     memcpy(&local_tokens[found].token, atoken, sizeof(struct ktc_token));
     memcpy(&local_tokens[found].server, aserver,
@@ -814,7 +969,8 @@ SetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
     memcpy(&local_tokens[found].client, aclient,
           sizeof(struct ktc_principal));
     local_tokens[found].valid = 1;
-    UNLOCK_GLOBAL_MUTEX return 0;
+    UNLOCK_GLOBAL_MUTEX;
+    return 0;
 }
 
 
@@ -824,7 +980,8 @@ GetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
 {
     int i;
 
-    LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++)
+    LOCK_GLOBAL_MUTEX;
+    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) ==
@@ -834,9 +991,11 @@ GetLocalToken(struct ktc_principal *aserver, struct ktc_token *atoken,
                   min(atokenLen, sizeof(struct ktc_token)));
            memcpy(aclient, &local_tokens[i].client,
                   sizeof(struct ktc_principal));
-           UNLOCK_GLOBAL_MUTEX return 0;
+           UNLOCK_GLOBAL_MUTEX;
+           return 0;
        }
-    UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
+    UNLOCK_GLOBAL_MUTEX;
+    return KTC_NOENT;
 }
 
 
@@ -845,12 +1004,14 @@ ForgetLocalTokens()
 {
     int i;
 
-    LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++) {
+    LOCK_GLOBAL_MUTEX;
+    for (i = 0; i < MAXLOCALTOKENS; i++) {
        local_tokens[i].valid = 0;
        memset(&local_tokens[i].token.sessionKey, 0,
               sizeof(struct ktc_encryptionKey));
     }
-    UNLOCK_GLOBAL_MUTEX return 0;
+    UNLOCK_GLOBAL_MUTEX;
+    return 0;
 }
 
 
@@ -859,7 +1020,8 @@ ForgetOneLocalToken(struct ktc_principal *aserver)
 {
     int i;
 
-    LOCK_GLOBAL_MUTEX for (i = 0; i < MAXLOCALTOKENS; i++) {
+    LOCK_GLOBAL_MUTEX;
+    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) ==
@@ -868,8 +1030,95 @@ ForgetOneLocalToken(struct ktc_principal *aserver)
            local_tokens[i].valid = 0;
            memset(&local_tokens[i].token.sessionKey, 0,
                   sizeof(struct ktc_encryptionKey));
-           UNLOCK_GLOBAL_MUTEX return 0;
+           UNLOCK_GLOBAL_MUTEX;
+           return 0;
        }
     }
-    UNLOCK_GLOBAL_MUTEX return KTC_NOENT;
+    UNLOCK_GLOBAL_MUTEX;
+    return KTC_NOENT;
 }
+
+/*!
+ * 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;
+    HANDLE ktcMutex = NULL;
+
+    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);
+
+#if 0
+       code = pioctl(0, VIOC_GETTOK2, &iob, 0);
+#else
+    code = -1;      /* not yet implemented */
+       errno = EINVAL;
+#endif
+
+       /* 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;
+}
+