Windows: remove warnings afskfw.c
[openafs.git] / src / WINNT / afsd / afskfw.c
index 160d928..2671e1b 100644 (file)
@@ -1,21 +1,21 @@
 /*
- * Copyright (c) 2004, 2005, 2006, 2007 Secure Endpoints Inc.
+ * Copyright (c) 2004, 2005, 2006, 2007, 2008 Secure Endpoints Inc.
  * Copyright (c) 2003 SkyRope, LLC
  * All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without 
+ *
+ * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
- * 
- * - Redistributions of source code must retain the above copyright notice, 
+ *
+ * - Redistributions of source code must retain the above copyright notice,
  *   this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice, 
- *   this list of conditions and the following disclaimer in the documentation 
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
  *   and/or other materials provided with the distribution.
- * - Neither the name of Skyrope, LLC nor the names of its contributors may be 
- *   used to endorse or promote products derived from this software without 
+ * - Neither the name of Skyrope, LLC nor the names of its contributors may be
+ *   used to endorse or promote products derived from this software without
  *   specific prior written permission from Skyrope, LLC.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
  *
  */
 
-
 #undef  USE_KRB4
 #ifndef _WIN64
 #define USE_KRB524 1
 #endif
 #define USE_MS2MIT 1
-#define USE_LEASH 1
 
-#include "afskfw-int.h"
-#include "afskfw.h"
-#include <userenv.h>
-
-#include <Sddl.h>
-#include <Aclapi.h>
+#include <afsconfig.h>
+#include <afs/param.h>
+#include <roken.h>
 
 #include <osilog.h>
 #include <afs/ptserver.h>
 #include <afs/ptuser.h>
+#include <afs/auth.h>
+#include <afs/com_err.h>
 #include <rx/rxkad.h>
-
 #include <WINNT\afsreg.h>
+#include "cm.h"
+
+#include "afskfw.h"
+#include "afskfw-int.h"
+#include <userenv.h>
+#include "strsafe.h"
+
+#include <Sddl.h>
+#include <Aclapi.h>
 
 /*
  * TIMING _____________________________________________________________________
@@ -114,7 +119,7 @@ DECL_FUNC_PTR(Leash_get_default_renew_min);
 DECL_FUNC_PTR(Leash_get_default_renew_max);
 DECL_FUNC_PTR(Leash_get_default_renewable);
 DECL_FUNC_PTR(Leash_get_default_mslsa_import);
-#endif 
+#endif
 
 // krb5 functions
 DECL_FUNC_PTR(krb5_change_password);
@@ -177,6 +182,10 @@ DECL_FUNC_PTR(krb5_free_host_realm);
 DECL_FUNC_PTR(krb5_free_addresses);
 DECL_FUNC_PTR(krb5_c_random_make_octets);
 
+// Krb5 KFW 3.2 functions
+DECL_FUNC_PTR(krb5_get_error_message);
+DECL_FUNC_PTR(krb5_free_error_message);
+
 #ifdef USE_KRB524
 // Krb524 functions
 DECL_FUNC_PTR(krb524_init_ets);
@@ -317,6 +326,12 @@ FUNC_INFO k5_fi[] = {
     END_FUNC_INFO
 };
 
+FUNC_INFO k5_kfw_32_fi[] = {
+    MAKE_FUNC_INFO(krb5_get_error_message),
+    MAKE_FUNC_INFO(krb5_free_error_message),
+    END_FUNC_INFO
+};
+
 #ifdef USE_KRB4
 FUNC_INFO k4_fi[] = {
     MAKE_FUNC_INFO(krb_get_cred),
@@ -375,7 +390,7 @@ FUNC_INFO lsa_fi[] = {
 
 /* Static Prototypes */
 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
-static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
+static long get_cellconfig_callback(void *, struct sockaddr_in *, char *, unsigned short);
 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
            void *data, const char *name, const char *banner, int num_prompts,
@@ -387,6 +402,7 @@ static int                inited = 0;
 static int                mid_cnt = 0;
 static struct textField * mid_tb = NULL;
 static HINSTANCE hKrb5 = 0;
+static HINSTANCE hKrb5_kfw_32 = 0;
 #ifdef USE_KRB4
 static HINSTANCE hKrb4 = 0;
 #endif /* USE_KRB4 */
@@ -408,6 +424,12 @@ static HINSTANCE hCCAPI = 0;
 static struct principal_ccache_data * princ_cc_data = NULL;
 static struct cell_principal_map    * cell_princ_map = NULL;
 
+#ifdef USE_LEASH
+#define DEFAULT_LIFETIME pLeash_get_default_lifetime()
+#else
+#define DEFAULT_LIFETIME (24 * 60)
+#endif
+
 void
 KFW_initialize(void)
 {
@@ -417,8 +439,8 @@ KFW_initialize(void)
         char mutexName[MAX_PATH];
         HANDLE hMutex = NULL;
 
-        sprintf(mutexName, "AFS KFW Init pid=%d", getpid());
-        
+        StringCbPrintf( mutexName, sizeof(mutexName), "AFS KFW Init pid=%d", getpid());
+
         hMutex = CreateMutex( NULL, TRUE, mutexName );
         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
             if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
@@ -428,6 +450,7 @@ KFW_initialize(void)
         if ( !inited ) {
             inited = 1;
             LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
+            LoadFuncs(KRB5_DLL, k5_kfw_32_fi, &hKrb5_kfw_32, 0, 1, 0, 0);
             LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
             LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
 #ifdef USE_KRB4
@@ -447,7 +470,7 @@ KFW_initialize(void)
             LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
 
             if ( KFW_is_available() ) {
-                char rootcell[MAXCELLCHARS+1];
+                char rootcell[CELL_MAXNAMELEN+1];
 #ifdef USE_MS2MIT
                 KFW_import_windows_lsa();
 #endif /* USE_MS2MIT */
@@ -461,6 +484,9 @@ KFW_initialize(void)
         }
         ReleaseMutex(hMutex);
         CloseHandle(hMutex);
+
+        initialize_KTC_error_table();
+        initialize_PT_error_table();
     }
 }
 
@@ -495,8 +521,38 @@ KFW_cleanup(void)
 #endif /* USE_KRB4 */
     if (hKrb5)
         FreeLibrary(hKrb5);
+    if (hKrb5_kfw_32)
+        FreeLibrary(hKrb5_kfw_32);
 }
 
+typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+static int IsWow64()
+{
+    static int init = TRUE;
+    static int bIsWow64 = FALSE;
+
+    if (init) {
+        HMODULE hModule;
+        LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
+
+        hModule = GetModuleHandle(TEXT("kernel32"));
+        if (hModule) {
+            fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process");
+
+            if (NULL != fnIsWow64Process)
+            {
+                if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
+                {
+                    // on error, assume FALSE.
+                    // in other words, do nothing.
+                }
+            }
+            FreeLibrary(hModule);
+        }
+        init = FALSE;
+    }
+    return bIsWow64;
+}
 
 int
 KFW_accept_dotted_usernames(void)
@@ -506,7 +562,7 @@ KFW_accept_dotted_usernames(void)
     DWORD value = 1;
 
     code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
-                         0, KEY_QUERY_VALUE, &parmKey);
+                         0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
     if (code == ERROR_SUCCESS) {
         len = sizeof(value);
         code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
@@ -515,7 +571,7 @@ KFW_accept_dotted_usernames(void)
     }
     if (code != ERROR_SUCCESS) {
         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
-                             0, KEY_QUERY_VALUE, &parmKey);
+                             0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
         if (code == ERROR_SUCCESS) {
             len = sizeof(value);
             code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
@@ -535,7 +591,7 @@ KFW_use_krb524(void)
     DWORD use524 = 0;
 
     code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
-                         0, KEY_QUERY_VALUE, &parmKey);
+                         0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
     if (code == ERROR_SUCCESS) {
         len = sizeof(use524);
         code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
@@ -544,7 +600,7 @@ KFW_use_krb524(void)
     }
     if (code != ERROR_SUCCESS) {
         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
-                             0, KEY_QUERY_VALUE, &parmKey);
+                             0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
         if (code == ERROR_SUCCESS) {
             len = sizeof(use524);
             code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
@@ -555,7 +611,7 @@ KFW_use_krb524(void)
     return use524;
 }
 
-int 
+int
 KFW_is_available(void)
 {
     HKEY parmKey;
@@ -563,32 +619,32 @@ KFW_is_available(void)
     DWORD enableKFW = 1;
 
     code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
-                         0, KEY_QUERY_VALUE, &parmKey);
+                         0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
     if (code == ERROR_SUCCESS) {
         len = sizeof(enableKFW);
         code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
                                 (BYTE *) &enableKFW, &len);
         RegCloseKey (parmKey);
     }
-    
+
     if (code != ERROR_SUCCESS) {
         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
-                             0, KEY_QUERY_VALUE, &parmKey);
+                             0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
         if (code == ERROR_SUCCESS) {
             len = sizeof(enableKFW);
             code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
                                     (BYTE *) &enableKFW, &len);
             RegCloseKey (parmKey);
         }
-    } 
+    }
 
     if ( !enableKFW )
         return FALSE;
 
     KFW_initialize();
-    if ( hKrb5 && hComErr && hService && 
+    if ( hKrb5 && hComErr && hService &&
 #ifdef USE_MS2MIT
-         hSecur32 && 
+         hSecur32 &&
 #endif /* USE_MS2MIT */
 #ifdef USE_KRB524
          hKrb524 &&
@@ -601,15 +657,15 @@ KFW_is_available(void)
     return FALSE;
 }
 
-int 
-KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName, 
-                 int FreeContextFlag, krb5_context * ctx, 
+int
+KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
+                 int FreeContextFlag, krb5_context * ctx,
                  krb5_ccache * cache)
 {
     char message[256];
     const char *errText;
-    int krb5Error = ((int)(rc & 255));  
-    
+    int krb5Error = ((int)(rc & 255));
+
     /*
     switch (krb5Error)
     {
@@ -619,19 +675,24 @@ KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
             return;
     }
     */
-        
-    errText = perror_message(rc);   
-    _snprintf(message, sizeof(message), 
-              "%s\n(Kerberos error %ld)\n\n%s failed", 
-              errText, 
-              krb5Error, 
+
+    if (pkrb5_get_error_message)
+        errText = pkrb5_get_error_message(*ctx, rc);
+    else
+        errText = perror_message(rc);
+    StringCbPrintf(message, sizeof(message),
+              "%s\n(Kerberos error %ld)\n\n%s failed",
+              errText,
+              krb5Error,
               FailedFunctionName);
+    if (pkrb5_free_error_message)
+        pkrb5_free_error_message(*ctx, (char *)errText);
 
     if ( IsDebuggerPresent() )
         OutputDebugString(message);
 
-    MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | 
-               MB_TASKMODAL | 
+    MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
+               MB_TASKMODAL |
                MB_SETFOREGROUND);
     if (FreeContextFlag == 1)
     {
@@ -639,11 +700,11 @@ KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
         {
             if (cache && *cache != NULL) {
                 pkrb5_cc_close(*ctx, *cache);
-                               *cache = NULL;
-                       }
-       
+                *cache = NULL;
+            }
+
             pkrb5_free_context(*ctx);
-                       *ctx = NULL;
+            *ctx = NULL;
         }
     }
 
@@ -658,6 +719,7 @@ KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
     char * pname = NULL;
     const char * ccname = NULL;
     const char * cctype = NULL;
+    char * ccfullname = NULL;
     krb5_error_code code = 0;
     krb5_error_code cc_code = 0;
     krb5_cc_cursor cur;
@@ -680,13 +742,18 @@ KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
     cctype = pkrb5_cc_get_type(ctx, cc);
     if (!cctype) goto cleanup;
 
-    // Search the existing list to see if we have a match 
+    ccfullname = malloc(strlen(ccname) + strlen(cctype) + 2);
+    if (!ccfullname) goto cleanup;
+
+    StringCbPrintf(ccfullname, sizeof(ccfullname), "%s:%s", cctype, ccname);
+
+    // Search the existing list to see if we have a match
     if ( next ) {
         for ( ; next ; next = next->next ) {
-            if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) )
+            if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccfullname) )
                 break;
         }
-    } 
+    }
 
     // If not, match add a new node to the beginning of the list and assign init it
     if ( !next ) {
@@ -694,9 +761,8 @@ KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
         next->next = princ_cc_data;
         princ_cc_data = next;
         next->principal = _strdup(pname);
-        next->ccache_name = malloc(strlen(ccname) + strlen(cctype) + 2);
-        if (next->ccache_name) 
-            sprintf(next->ccache_name, "%s:%s", cctype, ccname);
+        next->ccache_name = ccfullname;
+        ccfullname = NULL;
         next->from_lsa = lsa;
         next->expired = 1;
         next->expiration_time = 0;
@@ -710,12 +776,13 @@ KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
     code = pkrb5_timeofday(ctx, &now);
 
     cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
+    if (cc_code) goto cleanup;
 
     while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
         if ( creds.ticket_flags & TKT_FLG_INITIAL ) {
             int valid;
             // we found the ticket we are looking for
-            // check validity of timestamp 
+            // check validity of timestamp
             // We add a 5 minutes fudge factor to compensate for potential
             // clock skew errors between the KDC and client OS
 
@@ -731,7 +798,7 @@ KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
             } else if ( valid ) {
                 next->expired = 0;
                 next->expiration_time = creds.times.endtime;
-                next->renew = (creds.times.renew_till > creds.times.endtime) && 
+                next->renew = (creds.times.renew_till > creds.times.endtime) &&
                                (creds.ticket_flags & TKT_FLG_RENEWABLE);
             } else {
                 next->expired = 1;
@@ -755,11 +822,13 @@ KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa)
     flags = KRB5_TC_OPENCLOSE;  //turn on OPENCLOSE
     code = pkrb5_cc_set_flags(ctx, cc, flags);
 
+    if ( ccfullname)
+        free(ccfullname);
     if ( pname )
         pkrb5_free_unparsed_name(ctx,pname);
     if ( principal )
         pkrb5_free_principal(ctx,principal);
-}   
+}
 
 int
 KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only)
@@ -781,7 +850,7 @@ KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **cca
             }
             response = _strdup(next->ccache_name);
             // MS Kerberos LSA is our best option so use it and quit
-            if ( next->from_lsa )   
+            if ( next->from_lsa )
                 break;
         }
         next = next->next;
@@ -794,7 +863,7 @@ KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **cca
     return 0;
 }
 
-void 
+void
 KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
 {
     struct principal_ccache_data ** next = &princ_cc_data;
@@ -803,7 +872,7 @@ KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
         return;
 
     while ( (*next) ) {
-        if ( !strcmp((*next)->principal,pname) || 
+        if ( !strcmp((*next)->principal,pname) ||
              !strcmp((*next)->ccache_name,ccname) ) {
             void * temp;
             free((*next)->principal);
@@ -815,12 +884,12 @@ KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname)
     }
 }
 
-void 
+void
 KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active)
 {
     struct cell_principal_map * next = cell_princ_map;
 
-    // Search the existing list to see if we have a match 
+    // Search the existing list to see if we have a match
     if ( next ) {
         for ( ; next ; next = next->next ) {
             if ( !strcmp(next->cell, cell) ) {
@@ -836,7 +905,7 @@ KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int ac
                 }
             }
         }
-    } 
+    }
 
     // If not, match add a new node to the beginning of the list and assign init it
     if ( !next ) {
@@ -849,7 +918,7 @@ KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int ac
     }
 }
 
-void 
+void
 KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
 {
     struct cell_principal_map ** next = &cell_princ_map;
@@ -858,7 +927,7 @@ KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
         return;
 
     while ( (*next) ) {
-        if ( !strcmp((*next)->principal,pname) || 
+        if ( !strcmp((*next)->principal,pname) ||
              !strcmp((*next)->cell,cell) ) {
             void * temp;
             free((*next)->principal);
@@ -870,9 +939,9 @@ KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell)
     }
 }
 
-// Returns (if possible) a principal which has been known in 
+// Returns (if possible) a principal which has been known in
 // the past to have been used to obtain tokens for the specified
-// cell.  
+// cell.
 // TODO: Attempt to return one which has not yet expired by checking
 // the principal/ccache data
 int
@@ -911,7 +980,7 @@ KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int
     int     count = 0, i;
     struct cell_principal_map * next_map = cell_princ_map;
     const char * princ = NULL;
-    
+
     if ( !pname )
         return 0;
 
@@ -945,7 +1014,7 @@ KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
     krb5_error_code code;
 
     if (!pkrb5_init_context)
-        return 0;
+        return KRB5_CONFIG_CANTOPEN;
 
     if ( alt_ctx ) {
         ctx = alt_ctx;
@@ -960,8 +1029,9 @@ KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
 
         if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) &&
              !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) {
-            ccname = (char *)malloc(strlen(pname) + 5);
-            sprintf(ccname,"API:%s",pname);
+            size_t len = strlen(pname) + 5;
+            ccname = (char *)malloc(len);
+            StringCbPrintf(ccname, len, "API:%s", pname);
         }
         code = pkrb5_cc_resolve(ctx, ccname, cc);
     } else {
@@ -991,9 +1061,9 @@ KFW_import_windows_lsa(void)
     krb5_data *  princ_realm;
     krb5_error_code code;
     char cell[128]="", realm[128]="", *def_realm = 0;
-    int i;
+    unsigned int i;
     DWORD dwMsLsaImport;
-         
+
     if (!pkrb5_init_context)
         return;
 
@@ -1008,7 +1078,11 @@ KFW_import_windows_lsa(void)
     code = pkrb5_cc_get_principal(ctx, cc, &princ);
     if ( code ) goto cleanup;
 
+#ifdef USE_LEASH
     dwMsLsaImport = pLeash_get_default_mslsa_import ? pLeash_get_default_mslsa_import() : 1;
+#else
+    dwMsLsaImport = 1;
+#endif
     switch ( dwMsLsaImport ) {
     case 0: /* do not import */
         goto cleanup;
@@ -1016,10 +1090,10 @@ KFW_import_windows_lsa(void)
         break;
     case 2: { /* matching realm */
         char ms_realm[128] = "", *r;
-        int i;
+        unsigned int j;
 
-        for ( r=ms_realm, i=0; i<krb5_princ_realm(ctx, princ)->length; r++, i++ ) {
-            *r = krb5_princ_realm(ctx, princ)->data[i];
+        for ( r=ms_realm, j=0; j<krb5_princ_realm(ctx, princ)->length; r++, j++ ) {
+            *r = krb5_princ_realm(ctx, princ)->data[j];
         }
         *r = '\0';
 
@@ -1045,10 +1119,10 @@ KFW_import_windows_lsa(void)
     cell[i] = '\0';
     realm[i] = '\0';
 
-    code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
+    code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, DEFAULT_LIFETIME, NULL);
     if ( IsDebuggerPresent() ) {
         char message[256];
-        sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
+        StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
         OutputDebugString(message);
     }
     if ( code ) goto cleanup;
@@ -1117,7 +1191,7 @@ KFW_import_ccache_data(void)
             OutputDebugString("\n");
         }
         if ( strcmp(pNCi[i]->name,pNCi[i]->principal)
-             && strcmp(pNCi[i]->name,LSA_CCNAME) 
+             && strcmp(pNCi[i]->name,LSA_CCNAME)
              ) {
             int found = 0;
             for ( j=0; pNCi[j]; j++ ) {
@@ -1126,7 +1200,7 @@ KFW_import_ccache_data(void)
                     break;
                 }
             }
-            
+
             code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc);
             if (code) goto loop_cleanup;
 
@@ -1166,6 +1240,7 @@ KFW_import_ccache_data(void)
         KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME));
 
         cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
+        if (cc_code) goto cleanup;
 
         while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
             krb5_data * sname = krb5_princ_name(ctx, creds.server);
@@ -1190,8 +1265,10 @@ KFW_import_ccache_data(void)
                 }
 
                 memset(&aserver, '\0', sizeof(aserver));
-                strcpy(aserver.name, sname->data);
-                strcpy(aserver.cell, cell->data);
+                StringCbCopyN( aserver.name, sizeof(aserver.name),
+                               sname->data, sizeof(aserver.name) - 1);
+                StringCbCopyN( aserver.cell, sizeof(aserver.cell),
+                               cell->data, sizeof(aserver.cell) - 1);
 
                 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
                 if (!code) {
@@ -1220,16 +1297,10 @@ KFW_import_ccache_data(void)
                         OutputDebugString("Calling KFW_AFS_klog() to obtain token\n");
                     }
 
-                    code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, 
-#ifndef USE_LEASH
-                                        600,
-#else
-                                        pLeash_get_default_lifetime(),
-#endif /* USE_LEASH */
-                                        NULL);
+                    code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, DEFAULT_LIFETIME, NULL);
                     if ( IsDebuggerPresent() ) {
                         char message[256];
-                        sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
+                        StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
                         OutputDebugString(message);
                     }
                 }
@@ -1276,27 +1347,28 @@ KFW_import_ccache_data(void)
 
 
 int
-KFW_AFS_get_cred( char * username, 
+KFW_AFS_get_cred( char * username,
                   char * cell,
                   char * password,
                   int lifetime,
                   char * smbname,
                   char ** reasonP )
 {
+    static char reason[1024]="";
     krb5_context ctx = NULL;
     krb5_ccache cc = NULL;
     char * realm = NULL, * userrealm = NULL;
     krb5_principal principal = NULL;
     char * pname = NULL;
     krb5_error_code code;
-    char local_cell[MAXCELLCHARS+1];
+    char local_cell[CELL_MAXNAMELEN+1];
     char **cells = NULL;
     int  cell_count=0;
     struct afsconf_cell cellconfig;
     char * dot;
 
     if (!pkrb5_init_context)
-        return 0;
+        return KRB5_CONFIG_CANTOPEN;
 
     if ( IsDebuggerPresent() ) {
         OutputDebugString("KFW_AFS_get_cred for token ");
@@ -1306,6 +1378,8 @@ KFW_AFS_get_cred( char * username,
         OutputDebugString("\n");
     }
 
+    memset(&cellconfig, 0, sizeof(cellconfig));
+
     code = pkrb5_init_context(&ctx);
     if ( code ) goto cleanup;
 
@@ -1325,12 +1399,17 @@ KFW_AFS_get_cred( char * username,
             while ( dot = strchr(pname,'.') ) {
                 *dot = '/';
             }
-            *userrealm++ = '@';
+            *userrealm = '@';
         }
+        userrealm++;
     } else {
-        pname = malloc(strlen(username) + strlen(realm) + 2);
-
-        strcpy(pname, username);
+        size_t len = strlen(username) + strlen(realm) + 2;
+        pname = malloc(len);
+        if (pname == NULL) {
+            code = KRB5KRB_ERR_GENERIC;
+            goto cleanup;
+        }
+        StringCbCopy(pname, len, username);
 
         if (!KFW_accept_dotted_usernames()) {
             /* handle kerberos iv notation */
@@ -1338,13 +1417,16 @@ KFW_AFS_get_cred( char * username,
                 *dot = '/';
             }
         }
-        strcat(pname,"@");
-        strcat(pname,realm);
+        StringCbCat( pname, len, "@");
+        StringCbCat( pname, len, realm);
     }
     if ( IsDebuggerPresent() ) {
-        OutputDebugString("Realm: ");
+        OutputDebugString("Realm of Cell: ");
         OutputDebugString(realm);
         OutputDebugString("\n");
+        OutputDebugString("Realm of User: ");
+        OutputDebugString(userrealm?userrealm:"<NULL>");
+        OutputDebugString("\n");
     }
 
     code = pkrb5_parse_name(ctx, pname, &principal);
@@ -1354,19 +1436,22 @@ KFW_AFS_get_cred( char * username,
     if ( code ) goto cleanup;
 
     if ( lifetime == 0 )
-#ifndef USE_LEASH
-        lifetime = 600;
-#else
-        lifetime = pLeash_get_default_lifetime();
-#endif
+        lifetime = DEFAULT_LIFETIME;
 
-    if ( password && password[0] ) {
-        code = KFW_kinit( ctx, cc, HWND_DESKTOP, 
-                          pname, 
+    code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime, smbname);
+    if ( IsDebuggerPresent() ) {
+        char message[256];
+        StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
+        OutputDebugString(message);
+    }
+
+    if (code && password && password[0] ) {
+        code = KFW_kinit( ctx, cc, HWND_DESKTOP,
+                          pname,
                           password,
                           lifetime,
 #ifndef USE_LEASH
-                          1, /* forwardable */
+                          0, /* forwardable */
                           0, /* not proxiable */
                           1, /* renewable */
                           1, /* noaddresses */
@@ -1382,7 +1467,7 @@ KFW_AFS_get_cred( char * username,
 
         if ( IsDebuggerPresent() ) {
             char message[256];
-            sprintf(message,"KFW_kinit() returns: %d\n",code);
+            StringCbPrintf(message, sizeof(message), "KFW_kinit() returns: %d\n", code);
             OutputDebugString(message);
         }
         if ( code ) goto cleanup;
@@ -1393,14 +1478,14 @@ KFW_AFS_get_cred( char * username,
     code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime, smbname);
     if ( IsDebuggerPresent() ) {
         char message[256];
-        sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
+        StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
         OutputDebugString(message);
     }
     if ( code ) goto cleanup;
 
     KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE);
 
-    // Attempt to obtain new tokens for other cells supported by the same 
+    // Attempt to obtain new tokens for other cells supported by the same
     // principal
     cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE);
     if ( cell_count > 1 ) {
@@ -1408,23 +1493,29 @@ KFW_AFS_get_cred( char * username,
             if ( strcmp(cells[cell_count],cell) ) {
                 if ( IsDebuggerPresent() ) {
                     char message[256];
-                    sprintf(message,"found another cell for the same principal: %s\n",cell);
+                    StringCbPrintf(message, sizeof(message),
+                                   "found another cell for the same principal: %s\n", cell);
                     OutputDebugString(message);
                 }
+
+                if (cellconfig.linkedCell) {
+                    free(cellconfig.linkedCell);
+                    cellconfig.linkedCell = NULL;
+                }
                 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
                 if ( code ) continue;
-    
+
                 realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
                 if ( IsDebuggerPresent() ) {
                     OutputDebugString("Realm: ");
                     OutputDebugString(realm);
                     OutputDebugString("\n");
                 }
-                
+
                 code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime, smbname);
                 if ( IsDebuggerPresent() ) {
                     char message[256];
-                    sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
+                    StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
                     OutputDebugString(message);
                 }
             }
@@ -1441,14 +1532,29 @@ KFW_AFS_get_cred( char * username,
         free(pname);
     if ( cc )
         pkrb5_cc_close(ctx, cc);
+    if ( cellconfig.linkedCell )
+        free(cellconfig.linkedCell);
 
     if ( code && reasonP ) {
-        *reasonP = (char *)perror_message(code);
+        int freemsg = 0;
+        char *msg = (char *)afs_error_message(code);
+        if (strncmp(msg, "unknown", strlen(msg)) == 0) {
+            if (pkrb5_get_error_message) {
+                msg = pkrb5_get_error_message(ctx, code);
+                freemsg = 1;
+            } else
+                msg = (char *)perror_message(code);
+        }
+        StringCbCopyN( reason, sizeof(reason),
+                       msg, sizeof(reason) - 1);
+        *reasonP = reason;
+        if (freemsg)
+            pkrb5_free_error_message(ctx, msg);
     }
     return(code);
 }
 
-int 
+int
 KFW_AFS_destroy_tickets_for_cell(char * cell)
 {
     krb5_context       ctx = NULL;
@@ -1457,7 +1563,7 @@ KFW_AFS_destroy_tickets_for_cell(char * cell)
     char ** principals = NULL;
 
     if (!pkrb5_init_context)
-        return 0;
+        return KRB5_CONFIG_CANTOPEN;
 
     if ( IsDebuggerPresent() ) {
         OutputDebugString("KFW_AFS_destroy_tickets_for_cell: ");
@@ -1513,7 +1619,7 @@ KFW_AFS_destroy_tickets_for_cell(char * cell)
     return 0;
 }
 
-int 
+int
 KFW_AFS_destroy_tickets_for_principal(char * user)
 {
     krb5_context       ctx = NULL;
@@ -1524,7 +1630,7 @@ KFW_AFS_destroy_tickets_for_principal(char * user)
     krb5_ccache                cc  = NULL;
 
     if (!pkrb5_init_context)
-        return 0;
+        return KRB5_CONFIG_CANTOPEN;
 
     if ( IsDebuggerPresent() ) {
         OutputDebugString("KFW_AFS_destroy_tickets_for_user: ");
@@ -1564,7 +1670,7 @@ KFW_AFS_destroy_tickets_for_principal(char * user)
     }
 
     if (ctx)
-               pkrb5_free_context(ctx);
+        pkrb5_free_context(ctx);
     return 0;
 }
 
@@ -1579,11 +1685,11 @@ KFW_AFS_renew_expiring_tokens(void)
     int cell_count;
     char ** cells=NULL;
     const char * realm = NULL;
-    char local_cell[MAXCELLCHARS+1]="";
+    char local_cell[CELL_MAXNAMELEN+1]="";
     struct afsconf_cell cellconfig;
 
     if (!pkrb5_init_context)
-        return 0;
+        return KRB5_CONFIG_CANTOPEN;
 
     if ( pcc_next == NULL ) // nothing to do
         return 0;
@@ -1592,14 +1698,16 @@ KFW_AFS_renew_expiring_tokens(void)
         OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
     }
 
+    memset(&cellconfig, 0, sizeof(cellconfig));
+
     code = pkrb5_init_context(&ctx);
     if (code) goto cleanup;
 
     code = pkrb5_timeofday(ctx, &now);
-    if (code) goto cleanup; 
+    if (code) goto cleanup;
 
     for ( ; pcc_next ; pcc_next = pcc_next->next ) {
-        if ( pcc_next->expired ) 
+        if ( pcc_next->expired )
             continue;
 
         if ( now >= (pcc_next->expiration_time) ) {
@@ -1611,7 +1719,7 @@ KFW_AFS_renew_expiring_tokens(void)
 
         if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
             code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc);
-            if ( code ) 
+            if ( code )
                                goto loop_cleanup;
             code = KFW_renew(ctx,cc);
 #ifdef USE_MS2MIT
@@ -1623,7 +1731,7 @@ KFW_AFS_renew_expiring_tokens(void)
             KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa);
             if (code) goto loop_cleanup;
 
-            // Attempt to obtain new tokens for other cells supported by the same 
+            // Attempt to obtain new tokens for other cells supported by the same
             // principal
             cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE);
             if ( cell_count > 0 ) {
@@ -1633,6 +1741,10 @@ KFW_AFS_renew_expiring_tokens(void)
                         OutputDebugString(cells[cell_count]);
                         OutputDebugString("\n");
                     }
+                    if (cellconfig.linkedCell) {
+                        free(cellconfig.linkedCell);
+                        cellconfig.linkedCell = NULL;
+                    }
                     code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
                     if ( code ) continue;
                     realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
@@ -1644,7 +1756,7 @@ KFW_AFS_renew_expiring_tokens(void)
                     code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
                     if ( IsDebuggerPresent() ) {
                         char message[256];
-                        sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
+                        StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
                         OutputDebugString(message);
                     }
                     free(cells[cell_count]);
@@ -1665,6 +1777,8 @@ KFW_AFS_renew_expiring_tokens(void)
         pkrb5_cc_close(ctx,cc);
     if ( ctx )
         pkrb5_free_context(ctx);
+    if (cellconfig.linkedCell)
+        free(cellconfig.linkedCell);
 
     return 0;
 }
@@ -1679,7 +1793,7 @@ KFW_AFS_renew_token_for_cell(char * cell)
     char ** principals = NULL;
 
     if (!pkrb5_init_context)
-        return 0;
+        return KRB5_CONFIG_CANTOPEN;
 
     if ( IsDebuggerPresent() ) {
         OutputDebugString("KFW_AFS_renew_token_for_cell:");
@@ -1707,7 +1821,9 @@ KFW_AFS_renew_token_for_cell(char * cell)
         krb5_ccache                    cc  = 0;
         const char * realm = NULL;
         struct afsconf_cell cellconfig;
-        char local_cell[MAXCELLCHARS+1];
+        char local_cell[CELL_MAXNAMELEN+1];
+
+        memset(&cellconfig, 0, sizeof(cellconfig));
 
         while ( count-- ) {
             code = pkrb5_parse_name(ctx, principals[count], &princ);
@@ -1716,6 +1832,10 @@ KFW_AFS_renew_token_for_cell(char * cell)
             code = KFW_get_ccache(ctx, princ, &cc);
             if (code) goto loop_cleanup;
 
+            if (cellconfig.linkedCell) {
+                free(cellconfig.linkedCell);
+                cellconfig.linkedCell = NULL;
+            }
             code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
             if ( code ) goto loop_cleanup;
 
@@ -1727,8 +1847,8 @@ KFW_AFS_renew_token_for_cell(char * cell)
             }
 
 #ifdef COMMENT
-            /* krb5_cc_remove_cred() is not implemented 
-             * for a single cred 
+            /* krb5_cc_remove_cred() is not implemented
+             * for a single cred
              */
             code = pkrb5_build_principal(ctx, &service, strlen(realm),
                                           realm, "afs", cell, NULL);
@@ -1762,7 +1882,7 @@ KFW_AFS_renew_token_for_cell(char * cell)
             code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, 0,NULL);
             if ( IsDebuggerPresent() ) {
                 char message[256];
-                sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
+                StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
                 OutputDebugString(message);
             }
 
@@ -1779,17 +1899,21 @@ KFW_AFS_renew_token_for_cell(char * cell)
                 pkrb5_free_principal(ctx, service);
                 princ = 0;
             }
+            if (cellconfig.linkedCell) {
+                free(cellconfig.linkedCell);
+                cellconfig.linkedCell = NULL;
+            }
 
             KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
             free(principals[count]);
         }
         free(principals);
     } else
-        code = -1;      // we did not renew the tokens 
+        code = -1;      // we did not renew the tokens
 
   cleanup:
-    if (ctx) 
-               pkrb5_free_context(ctx);
+    if (ctx)
+        pkrb5_free_context(ctx);
     return (code ? FALSE : TRUE);
 
 }
@@ -1824,7 +1948,7 @@ KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
     krb5_data           *realm = NULL;
 
     if (!pkrb5_init_context)
-        return 0;
+        return KRB5_CONFIG_CANTOPEN;
 
        memset(&my_creds, 0, sizeof(krb5_creds));
 
@@ -1852,7 +1976,7 @@ KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
                                     KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
                                     realm->length,realm->data,
                                     0);
-    if ( code ) 
+    if ( code )
         goto cleanup;
 
     if ( IsDebuggerPresent() ) {
@@ -1875,7 +1999,7 @@ KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
     if (code) {
         if ( IsDebuggerPresent() ) {
             char message[256];
-            sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code);
+            StringCbPrintf(message, sizeof(message), "krb5_get_renewed_creds() failed: %d\n", code);
             OutputDebugString(message);
         }
         goto cleanup;
@@ -1885,7 +2009,7 @@ KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
     if (code) {
         if ( IsDebuggerPresent() ) {
             char message[256];
-            sprintf(message,"krb5_cc_initialize() failed: %d\n",code);
+            StringCbPrintf(message, sizeof(message), "krb5_cc_initialize() failed: %d\n", code);
             OutputDebugString(message);
         }
         goto cleanup;
@@ -1895,7 +2019,7 @@ KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
     if (code) {
         if ( IsDebuggerPresent() ) {
             char message[256];
-            sprintf(message,"krb5_cc_store_cred() failed: %d\n",code);
+            StringCbPrintf(message, sizeof(message), "krb5_cc_store_cred() failed: %d\n", code);
             OutputDebugString(message);
         }
         goto cleanup;
@@ -1943,7 +2067,7 @@ KFW_kinit( krb5_context alt_ctx,
     int                         i = 0, addr_count = 0;
 
     if (!pkrb5_init_context)
-        return 0;
+        return KRB5_CONFIG_CANTOPEN;
 
     pkrb5_get_init_creds_opt_init(&options);
     memset(&my_creds, 0, sizeof(my_creds));
@@ -1961,24 +2085,20 @@ KFW_kinit( krb5_context alt_ctx,
     if ( alt_cc ) {
         cc = alt_cc;
     } else {
-        code = pkrb5_cc_default(ctx, &cc);  
+        code = pkrb5_cc_default(ctx, &cc);
         if (code) goto cleanup;
     }
 
     code = pkrb5_parse_name(ctx, principal_name, &me);
-    if (code) 
+    if (code)
        goto cleanup;
 
     code = pkrb5_unparse_name(ctx, me, &name);
-    if (code) 
+    if (code)
        goto cleanup;
 
     if (lifetime == 0)
-#ifndef USE_LEASH
-        lifetime = 600;
-#else
-        lifetime = pLeash_get_default_lifetime();
-#endif /* USE_LEASH */
+        lifetime = DEFAULT_LIFETIME;
     lifetime *= 60;
 
     if (renew_life > 0)
@@ -2048,14 +2168,14 @@ KFW_kinit( krb5_context alt_ctx,
 
             netIPAddr = htonl(publicIP);
             memcpy(addrs[i]->contents,&netIPAddr,4);
-        
+
             pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
 
         }
     }
 
-    code = pkrb5_get_init_creds_password(ctx, 
-                                       &my_creds, 
+    code = pkrb5_get_init_creds_password(ctx,
+                                       &my_creds,
                                        me,
                                        password, // password
                                        KRB5_prompter, // prompter
@@ -2063,15 +2183,15 @@ KFW_kinit( krb5_context alt_ctx,
                                        0, // start time
                                        0, // service name
                                        &options);
-    if (code) 
+    if (code)
        goto cleanup;
 
     code = pkrb5_cc_initialize(ctx, cc, me);
-    if (code) 
+    if (code)
        goto cleanup;
 
     code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
-    if (code) 
+    if (code)
        goto cleanup;
 
  cleanup:
@@ -2107,7 +2227,7 @@ KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
     krb5_error_code            code;
 
     if (!pkrb5_init_context)
-        return 0;
+        return KRB5_CONFIG_CANTOPEN;
 
     if (alt_ctx)
     {
@@ -2122,7 +2242,7 @@ KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
     if ( alt_cc ) {
         cc = alt_cc;
     } else {
-        code = pkrb5_cc_default(ctx, &cc);  
+        code = pkrb5_cc_default(ctx, &cc);
         if (code) goto cleanup;
     }
 
@@ -2170,11 +2290,11 @@ GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
 }
 
 //
-// MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the 
-// cache.  It validates whether or not it is reasonable to assume that if we 
-// attempted to retrieve valid tickets we could do so.  Microsoft does not 
+// MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
+// cache.  It validates whether or not it is reasonable to assume that if we
+// attempted to retrieve valid tickets we could do so.  Microsoft does not
 // automatically renew expired tickets.  Therefore, the cache could contain
-// expired or invalid tickets.  Microsoft also caches the user's password 
+// expired or invalid tickets.  Microsoft also caches the user's password
 // and will use it to retrieve new TGTs if the cache is empty and tickets
 // are requested.
 
@@ -2195,8 +2315,8 @@ MSLSA_IsKerberosLogon(VOID)
             usLength = (pSessionData->AuthenticationPackage).Length;
             if (usLength < 256)
             {
-                lstrcpynW (buffer, usBuffer, usLength);
-                lstrcatW (buffer,L"");
+                StringCbCopyNW( buffer, sizeof(buffer)/sizeof(WCHAR),
+                                usBuffer, usLength);
                 if ( !lstrcmpW(L"Kerberos",buffer) )
                     Success = TRUE;
             }
@@ -2207,7 +2327,7 @@ MSLSA_IsKerberosLogon(VOID)
 }
 #endif /* USE_MS2MIT */
 
-static BOOL CALLBACK 
+static BOOL CALLBACK
 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
 {
     int i;
@@ -2222,7 +2342,7 @@ MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
                for ( i=0; i < mid_cnt ; i++ ) {
                        if (mid_tb[i].echo == 0)
                                SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
-                   else if (mid_tb[i].echo == 2) 
+                   else if (mid_tb[i].echo == 2)
                                SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
                }
         return TRUE;
@@ -2243,7 +2363,7 @@ MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
     return FALSE;
 }
 
-static LPWORD 
+static LPWORD
 lpwAlign( LPWORD lpIn )
 {
     ULONG_PTR ul;
@@ -2261,8 +2381,8 @@ lpwAlign( LPWORD lpIn )
  */
 
 static LRESULT
-MultiInputDialog( HINSTANCE hinst, HWND hwndOwner, 
-                  char * ptext[], int numlines, int width, 
+MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
+                  char * ptext[], int numlines, int width,
                   int tb_cnt, struct textField * tb)
 {
     HGLOBAL hgbl;
@@ -2276,22 +2396,22 @@ MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
     hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
     if (!hgbl)
         return -1;
+
     mid_cnt = tb_cnt;
     mid_tb = tb;
 
     lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
+
     // Define a dialog box.
+
     lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
-                   | DS_MODALFRAME | WS_CAPTION | DS_CENTER 
+                   | DS_MODALFRAME | WS_CAPTION | DS_CENTER
                    | DS_SETFOREGROUND | DS_3DLOOK
                    | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
     lpdt->cdit = numlines + (2 * tb_cnt) + 2;  // number of controls
-    lpdt->x  = 10;  
+    lpdt->x  = 10;
     lpdt->y  = 10;
-    lpdt->cx = 20 + width * 4; 
+    lpdt->cx = 20 + width * 4;
     lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
 
     lpw = (LPWORD) (lpdt + 1);
@@ -2303,7 +2423,7 @@ MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
     lpw   += nchar;
     *lpw++ = 8;                        // font size (points)
     lpwsz = (LPWSTR) lpw;
-    nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg", 
+    nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
                                     -1, lpwsz, 128);
     lpw   += nchar;
 
@@ -2314,9 +2434,9 @@ MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
     lpdit = (LPDLGITEMTEMPLATE) lpw;
     lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
     lpdit->dwExtendedStyle = 0;
-    lpdit->x  = (lpdt->cx - 14)/4 - 20; 
+    lpdit->x  = (lpdt->cx - 14)/4 - 20;
     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
-    lpdit->cx = 40; 
+    lpdit->cx = 40;
     lpdit->cy = 14;
     lpdit->id = IDOK;  // OK button identifier
 
@@ -2336,9 +2456,9 @@ MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
     lpdit = (LPDLGITEMTEMPLATE) lpw;
     lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
     lpdit->dwExtendedStyle = 0;
-    lpdit->x  = (lpdt->cx - 14)*3/4 - 20; 
+    lpdit->x  = (lpdt->cx - 14)*3/4 - 20;
     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
-    lpdit->cx = 40; 
+    lpdit->cx = 40;
     lpdit->cy = 14;
     lpdit->id = IDCANCEL;  // CANCEL button identifier
 
@@ -2360,9 +2480,9 @@ MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
         lpdit = (LPDLGITEMTEMPLATE) lpw;
         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
         lpdit->dwExtendedStyle = 0;
-        lpdit->x  = 10; 
+        lpdit->x  = 10;
         lpdit->y  = 10 + i * 14;
-        lpdit->cx = (short)strlen(ptext[i]) * 4 + 10; 
+        lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
         lpdit->cy = 14;
         lpdit->id = ID_TEXT + i;  // text identifier
 
@@ -2371,12 +2491,12 @@ MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
         *lpw++ = 0x0082;                         // static class
 
         lpwsz = (LPWSTR) lpw;
-        nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i], 
+        nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
                                          -1, lpwsz, 2*width);
         lpw   += nchar;
         *lpw++ = 0;           // no creation data
     }
-    
+
     for ( i=0, pwid = 0; i<tb_cnt; i++) {
        int len = (int)strlen(tb[i].label);
         if ( pwid < len )
@@ -2392,9 +2512,9 @@ MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
         lpdit = (LPDLGITEMTEMPLATE) lpw;
         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
         lpdit->dwExtendedStyle = 0;
-        lpdit->x  = 10; 
+        lpdit->x  = 10;
         lpdit->y  = 10 + (numlines + i + 1) * 14;
-        lpdit->cx = pwid * 4; 
+        lpdit->cx = pwid * 4;
         lpdit->cy = 14;
         lpdit->id = ID_TEXT + numlines + i;  // text identifier
 
@@ -2403,7 +2523,7 @@ MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
         *lpw++ = 0x0082;                         // static class
 
         lpwsz = (LPWSTR) lpw;
-        nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "", 
+        nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
                                      -1, lpwsz, 128);
         lpw   += nchar;
         *lpw++ = 0;           // no creation data
@@ -2415,9 +2535,9 @@ MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
         lpdit = (LPDLGITEMTEMPLATE) lpw;
         lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
         lpdit->dwExtendedStyle = 0;
-        lpdit->x  = 10 + (pwid + 1) * 4; 
+        lpdit->x  = 10 + (pwid + 1) * 4;
         lpdit->y  = 10 + (numlines + i + 1) * 14;
-        lpdit->cx = (width - (pwid + 1)) * 4; 
+        lpdit->cx = (width - (pwid + 1)) * 4;
         lpdit->cy = 14;
         lpdit->id = ID_MID_TEXT + i;             // identifier
 
@@ -2426,16 +2546,16 @@ MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
         *lpw++ = 0x0081;                         // edit class
 
         lpwsz = (LPWSTR) lpw;
-        nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "", 
+        nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
                                      -1, lpwsz, 128);
         lpw   += nchar;
         *lpw++ = 0;           // no creation data
     }
 
-    GlobalUnlock(hgbl); 
-    ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, 
-                                                       hwndOwner, (DLGPROC) MultiInputDialogProc); 
-    GlobalFree(hgbl); 
+    GlobalUnlock(hgbl);
+    ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
+                            hwndOwner, (DLGPROC) MultiInputDialogProc);
+    GlobalFree(hgbl);
 
     switch ( ret ) {
     case 0:     /* Timeout */
@@ -2446,7 +2566,7 @@ MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
         return 0;
     default: {
         char buf[256];
-        sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());
+        StringCbPrintf(buf, sizeof(buf), "DialogBoxIndirect() failed: %d", GetLastError());
         MessageBox(hwndOwner,
                     buf,
                     "GetLastError()",
@@ -2460,13 +2580,13 @@ static int
 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
 {
     HINSTANCE hInst = 0;
-    int maxwidth = 0;
+    size_t maxwidth = 0;
     int numlines = 0;
-    int len;
+    size_t len;
     char * plines[16], *p = preface ? preface : "";
     int i;
 
-    for ( i=0; i<16; i++ ) 
+    for ( i=0; i<16; i++ )
         plines[i] = NULL;
 
     while (*p && numlines < 16) {
@@ -2477,9 +2597,9 @@ multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
             p++;
         } else if ( *p == '\n' ) {
             *p++ = '\0';
-        } 
+        }
         if ( strlen(plines[numlines-1]) > maxwidth )
-            maxwidth = (int)strlen(plines[numlines-1]);
+            maxwidth = strlen(plines[numlines-1]);
     }
 
     for ( i=0;i<n;i++ ) {
@@ -2521,7 +2641,7 @@ KRB5_prompter( krb5_context context,
             tb[i].label = prompts[i].prompt;
             tb[i].def = NULL;
             tb[i].echo = (prompts[i].hidden ? 2 : 1);
-        }   
+        }
 
         ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
         if ( ok ) {
@@ -2615,16 +2735,16 @@ KFW_AFS_unlog(void)
 
 #define ALLOW_REGISTER 1
 static int
-ViceIDToUsername(char *username, 
-                 char *realm_of_user, 
+ViceIDToUsername(char *username,
+                 char *realm_of_user,
                  char *realm_of_cell,
                  char * cell_to_use,
-                 struct ktc_principal *aclient, 
-                 struct ktc_principal *aserver, 
+                 struct ktc_principal *aclient,
+                 struct ktc_principal *aserver,
                  struct ktc_token *atoken)
 {
-    static char lastcell[MAXCELLCHARS+1] = { 0 };
-    static char confname[512] = { 0 };
+    static char lastcell[CELL_MAXNAMELEN+1] = { 0 };
+    static char confdir[512] = { 0 };
 #ifdef AFS_ID_TO_NAME
     char username_copy[BUFSIZ];
 #endif /* AFS_ID_TO_NAME */
@@ -2634,17 +2754,16 @@ ViceIDToUsername(char *username,
     afs_int32 id;
 #endif /* ALLOW_REGISTER */
 
-    if (confname[0] == '\0') {
-        strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
-        confname[sizeof(confname) - 2] = '\0';
-    }
+    if (confdir[0] == '\0')
+        cm_GetConfigDir(confdir, sizeof(confdir));
 
-    strcpy(lastcell, aserver->cell);
+    StringCbCopyN( lastcell, sizeof(lastcell),
+                   aserver->cell, sizeof(lastcell) - 1);
 
-    if (!pr_Initialize (0, confname, aserver->cell)) {
+    if (!pr_Initialize (0, confdir, aserver->cell)) {
         char sname[PR_MAXNAMELEN];
-        strncpy(sname, username, PR_MAXNAMELEN);
-        sname[PR_MAXNAMELEN-1] = '\0';    
+        StringCbCopyN( sname, sizeof(sname),
+                       username, sizeof(sname) - 1);
         status = pr_SNameToId (sname, &viceId);
        pr_End();
     }
@@ -2672,26 +2791,30 @@ ViceIDToUsername(char *username,
 #endif /* ALLOW_REGISTER */
             {
 #ifdef AFS_ID_TO_NAME
-                strncpy(username_copy, username, BUFSIZ);
+                StringCbCopyN( username_copy, sizeof(username_copy),
+                               username, sizeof(username_copy) - 1);
                 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
 #endif /* AFS_ID_TO_NAME */
             }
 #ifdef ALLOW_REGISTER
         } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
             id = 0;
-            strncpy(aclient->name, username, MAXKTCNAMELEN - 1);
-            strcpy(aclient->instance, "");
-            strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1);
+            StringCbCopyN( aclient->name, sizeof(aclient->name),
+                           username, sizeof(aclient->name) - 1);
+            aclient->instance[0] = '\0';
+            StringCbCopyN( aclient->cell, sizeof(aclient->cell),
+                           realm_of_user, sizeof(aclient->cell) - 1);
             if (status = ktc_SetToken(aserver, atoken, aclient, 0))
                 return status;
-            if (status = pr_Initialize(1L, confname, aserver->cell))
+            if (status = pr_Initialize(1L, confdir, aserver->cell))
                 return status;
             status = pr_CreateUser(username, &id);
            pr_End();
            if (status)
                return status;
 #ifdef AFS_ID_TO_NAME
-            strncpy(username_copy, username, BUFSIZ);
+            StringCbCopyN( username_copy, sizeof(username_copy),
+                           username, sizeof(username_copy) - 1);
             snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
 #endif /* AFS_ID_TO_NAME */
         }
@@ -2701,6 +2824,24 @@ ViceIDToUsername(char *username,
 }
 
 
+static void
+copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
+    krb5_error_code code;
+    krb5_ticket *ticket;
+    size_t len;
+
+    code = pkrb5_decode_ticket(&v5cred->ticket, &ticket);
+    if (code == 0) {
+        len = krb5_princ_realm(context, ticket->server)->length;
+        if (len > destlen - 1)
+            len = destlen - 1;
+
+        StringCbCopyN(dest, destlen, krb5_princ_realm(context, ticket->server)->data, len);
+
+        pkrb5_free_ticket(context, ticket);
+    }
+}
+
 int
 KFW_AFS_klog(
     krb5_context alt_ctx,
@@ -2721,8 +2862,8 @@ KFW_AFS_klog(
     struct ktc_principal       aclient;
     char       realm_of_user[REALM_SZ]; /* Kerberos realm of user */
     char       realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
-    char       local_cell[MAXCELLCHARS+1];
-    char       Dmycell[MAXCELLCHARS+1];
+    char       local_cell[CELL_MAXNAMELEN+1];
+    char       Dmycell[CELL_MAXNAMELEN+1];
     struct ktc_token   atoken;
     struct ktc_token   btoken;
     struct afsconf_cell        ak_cellconfig; /* General information about the cell */
@@ -2739,7 +2880,7 @@ KFW_AFS_klog(
     krb5_error_code code;
     krb5_principal client_principal = NULL;
     krb5_data * k5data = NULL;
-    int i, retry = 0;
+    unsigned int i, retry = 0;
 
     CurrentState = 0;
     memset(HostName, '\0', sizeof(HostName));
@@ -2756,15 +2897,17 @@ KFW_AFS_klog(
     }
 
     if (!pkrb5_init_context)
-        return 0;
+        return KRB5_CONFIG_CANTOPEN;
 
+    memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
     memset(RealmName, '\0', sizeof(RealmName));
     memset(CellName, '\0', sizeof(CellName));
     memset(ServiceName, '\0', sizeof(ServiceName));
     memset(realm_of_user, '\0', sizeof(realm_of_user));
     memset(realm_of_cell, '\0', sizeof(realm_of_cell));
     if (cell && cell[0])
-        strcpy(Dmycell, cell);
+        StringCbCopyN( Dmycell, sizeof(Dmycell),
+                       cell, sizeof(Dmycell) - 1);
     else
         memset(Dmycell, '\0', sizeof(Dmycell));
 
@@ -2789,11 +2932,11 @@ KFW_AFS_klog(
         if (code) goto skip_krb5_init;
     }
 
-    memset((char *)&increds, 0, sizeof(increds));
+    memset(&increds, 0, sizeof(increds));
 
     code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
     if (code) {
-        if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() ) 
+        if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
         {
             OutputDebugString("Principal Not Found for ccache\n");
         }
@@ -2801,7 +2944,7 @@ KFW_AFS_klog(
     }
 
     if (!KFW_accept_dotted_usernames()) {
-        /* look for client principals which cannot be distinguished 
+        /* look for client principals which cannot be distinguished
          * from Kerberos 4 multi-component principal names
          */
         k5data = krb5_princ_component(ctx,client_principal,0);
@@ -2818,10 +2961,10 @@ KFW_AFS_klog(
     }
 
     i = krb5_princ_realm(ctx, client_principal)->length;
-    if (i > REALM_SZ-1) 
+    if (i > REALM_SZ-1)
         i = REALM_SZ-1;
-    strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i);
-    realm_of_user[i] = 0;
+    StringCbCopyN( realm_of_user, sizeof(realm_of_user),
+                   krb5_princ_realm(ctx, client_principal)->data, i);
     try_krb5 = 1;
 
   skip_krb5_init:
@@ -2830,50 +2973,59 @@ KFW_AFS_klog(
         if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS)
         {
             goto cleanup;
-        }       
+        }
     }
 #else
     if (!try_krb5)
         goto cleanup;
 #endif
-    strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
+    StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
+                   afs_realm_of_cell(ctx, &ak_cellconfig),
+                   sizeof(realm_of_cell) - 1);
 
     if (strlen(service) == 0)
-        strcpy(ServiceName, "afs");
+        StringCbCopy( ServiceName, sizeof(ServiceName), "afs");
     else
-        strcpy(ServiceName, service);
+        StringCbCopyN( ServiceName, sizeof(ServiceName),
+                       service, sizeof(ServiceName) - 1);
 
     if (strlen(cell) == 0)
-        strcpy(CellName, local_cell);
+        StringCbCopyN( CellName, sizeof(CellName),
+                       local_cell, sizeof(CellName) - 1);
     else
-        strcpy(CellName, cell);
+        StringCbCopyN( CellName, sizeof(CellName),
+                       cell, sizeof(CellName) - 1);
 
+    /* This is for Kerberos v4 only */
     if (strlen(realm) == 0)
-        strcpy(RealmName, realm_of_cell);
+        StringCbCopyN( RealmName, sizeof(RealmName),
+                       realm_of_cell, sizeof(RealmName) - 1);
     else
-        strcpy(RealmName, realm);
+        StringCbCopyN( RealmName, sizeof(RealmName),
+                       realm, sizeof(RealmName) - 1);
 
     memset(&creds, '\0', sizeof(creds));
 
     if ( try_krb5 ) {
         int len;
+        code = KRB5KRB_ERR_GENERIC;
 
-        /* First try service/cell@REALM */
-        if (code = pkrb5_build_principal(ctx, &increds.server,
-                                          (int)strlen(RealmName),
-                                          RealmName,
-                                          ServiceName,
-                                          CellName,
-                                          0)) 
-        {
-            goto cleanup;
-        }
 
         increds.client = client_principal;
         increds.times.endtime = 0;
         /* Ask for DES since that is what V4 understands */
         increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
 
+        /* ALWAYS first try service/cell@CLIENT_REALM */
+        if (code = pkrb5_build_principal(ctx, &increds.server,
+                                          (int)strlen(realm_of_user),
+                                          realm_of_user,
+                                          ServiceName,
+                                          CellName,
+                                          0))
+        {
+            goto cleanup;
+        }
 
         if ( IsDebuggerPresent() ) {
             char * cname, *sname;
@@ -2889,87 +3041,37 @@ KFW_AFS_klog(
         }
 
         code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
-        if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
-             code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
-             code == KRB5KRB_AP_ERR_MSG_TYPE) {
-            /* Or service@REALM */
-            pkrb5_free_principal(ctx,increds.server);
-            increds.server = 0;
-            code = pkrb5_build_principal(ctx, &increds.server,
-                                          (int)strlen(RealmName),
-                                          RealmName,
-                                          ServiceName,
-                                          0);
-
-            if ( IsDebuggerPresent() ) {
-                char * cname, *sname;
-                pkrb5_unparse_name(ctx, increds.client, &cname);
-                pkrb5_unparse_name(ctx, increds.server, &sname);
-                OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
-                OutputDebugString("Trying again: getting tickets for \"");
-                OutputDebugString(cname);
-                OutputDebugString("\" and service \"");
-                OutputDebugString(sname);
-                OutputDebugString("\"\n");
-                pkrb5_free_unparsed_name(ctx,cname);
-                pkrb5_free_unparsed_name(ctx,sname);
-            }
-
-            if (!code)
-                code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
-        }
-
-        if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
-              code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
-              code == KRB5KRB_AP_ERR_MSG_TYPE) &&
-             strcmp(RealmName, realm_of_cell)) {
-            /* Or service/cell@REALM_OF_CELL */
-            strcpy(RealmName, realm_of_cell);
-            pkrb5_free_principal(ctx,increds.server);
-            increds.server = 0;
-            code = pkrb5_build_principal(ctx, &increds.server,
-                                         (int)strlen(RealmName),
-                                         RealmName,
-                                         ServiceName,
-                                         CellName,
-                                         0);
-
-            if ( IsDebuggerPresent() ) {
-                char * cname, *sname;
-                pkrb5_unparse_name(ctx, increds.client, &cname);
-                pkrb5_unparse_name(ctx, increds.server, &sname);
-                OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
-                OutputDebugString("Trying again: getting tickets for \"");
-                OutputDebugString(cname);
-                OutputDebugString("\" and service \"");
-                OutputDebugString(sname);
-                OutputDebugString("\"\n");
-                pkrb5_free_unparsed_name(ctx,cname);
-                pkrb5_free_unparsed_name(ctx,sname);
-            }
+        if (code == 0) {
+            /* The client's realm is a local realm for the cell.
+            * Save it so that later the pts registration will not
+            * be performed.
+            */
+            StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
+                           realm_of_user, sizeof(realm_of_cell) - 1);
+        }
 
-            if (!code)
-                code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
 
-        
-            if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
-                 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
-                                code == KRB5KRB_AP_ERR_MSG_TYPE) {
-                /* Or service@REALM_OF_CELL */
-                pkrb5_free_principal(ctx,increds.server);
+        if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+            code == KRB5_ERR_HOST_REALM_UNKNOWN ||
+            code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
+            code == KRB5KRB_AP_ERR_MSG_TYPE) {
+            /* If there was a specific realm we are supposed to try
+             * then use it
+             */
+            if (strlen(realm) != 0) {
+                /* service/cell@REALM */
                 increds.server = 0;
                 code = pkrb5_build_principal(ctx, &increds.server,
-                                              (int)strlen(RealmName),
-                                              RealmName,
-                                              ServiceName,
-                                              0);
-
+                                             (int)strlen(realm),
+                                             realm,
+                                             ServiceName,
+                                             CellName,
+                                             0);
                 if ( IsDebuggerPresent() ) {
                     char * cname, *sname;
                     pkrb5_unparse_name(ctx, increds.client, &cname);
                     pkrb5_unparse_name(ctx, increds.server, &sname);
-                    OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
-                    OutputDebugString("Trying again: getting tickets for \"");
+                    OutputDebugString("Getting tickets for \"");
                     OutputDebugString(cname);
                     OutputDebugString("\" and service \"");
                     OutputDebugString(sname);
@@ -2980,13 +3082,114 @@ KFW_AFS_klog(
 
                 if (!code)
                     code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
+
+                if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+                    code == KRB5_ERR_HOST_REALM_UNKNOWN ||
+                    code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
+                    code == KRB5KRB_AP_ERR_MSG_TYPE) {
+                    /* Or service@REALM */
+                    pkrb5_free_principal(ctx,increds.server);
+                    increds.server = 0;
+                    code = pkrb5_build_principal(ctx, &increds.server,
+                                                 (int)strlen(realm),
+                                                 realm,
+                                                 ServiceName,
+                                                 0);
+
+                    if ( IsDebuggerPresent() ) {
+                        char * cname, *sname;
+                        pkrb5_unparse_name(ctx, increds.client, &cname);
+                        pkrb5_unparse_name(ctx, increds.server, &sname);
+                        OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
+                        OutputDebugString("Trying again: getting tickets for \"");
+                        OutputDebugString(cname);
+                        OutputDebugString("\" and service \"");
+                        OutputDebugString(sname);
+                        OutputDebugString("\"\n");
+                        pkrb5_free_unparsed_name(ctx,cname);
+                        pkrb5_free_unparsed_name(ctx,sname);
+                    }
+
+                    if (!code)
+                        code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
+                }
+
+                if (code == 0) {
+                    /* we have a local realm for the cell */
+                    StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
+                                   realm, sizeof(realm_of_cell) - 1);
+                }
+            } else {
+                if (strcmp(realm_of_user, realm_of_cell)) {
+                    /* Then service/cell@CELL_REALM */
+                    pkrb5_free_principal(ctx,increds.server);
+                    increds.server = 0;
+                    code = pkrb5_build_principal(ctx, &increds.server,
+                                                 (int)strlen(realm_of_cell),
+                                                 realm_of_cell,
+                                                 ServiceName,
+                                                 CellName,
+                                                 0);
+                    if ( IsDebuggerPresent() ) {
+                        char * cname, *sname;
+                        pkrb5_unparse_name(ctx, increds.client, &cname);
+                        pkrb5_unparse_name(ctx, increds.server, &sname);
+                        OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
+                        OutputDebugString("Trying again: getting tickets for \"");
+                        OutputDebugString(cname);
+                        OutputDebugString("\" and service \"");
+                        OutputDebugString(sname);
+                        OutputDebugString("\"\n");
+                        pkrb5_free_unparsed_name(ctx,cname);
+                        pkrb5_free_unparsed_name(ctx,sname);
+                    }
+
+                    if (!code)
+                        code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
+
+                    if (!code && !strlen(realm_of_cell))
+                        copy_realm_of_ticket(ctx, realm_of_cell, sizeof(realm_of_cell), k5creds);
+                }
+
+                if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+                    code == KRB5_ERR_HOST_REALM_UNKNOWN ||
+                    code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
+                    code == KRB5KRB_AP_ERR_MSG_TYPE) {
+                    /* Finally service@CELL_REALM */
+                    pkrb5_free_principal(ctx,increds.server);
+                    increds.server = 0;
+                    code = pkrb5_build_principal(ctx, &increds.server,
+                                                 (int)strlen(realm_of_cell),
+                                                 realm_of_cell,
+                                                 ServiceName,
+                                                 0);
+
+                    if ( IsDebuggerPresent() ) {
+                        char * cname, *sname;
+                        pkrb5_unparse_name(ctx, increds.client, &cname);
+                        pkrb5_unparse_name(ctx, increds.server, &sname);
+                        OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
+                        OutputDebugString("Trying again: getting tickets for \"");
+                        OutputDebugString(cname);
+                        OutputDebugString("\" and service \"");
+                        OutputDebugString(sname);
+                        OutputDebugString("\"\n");
+                        pkrb5_free_unparsed_name(ctx,cname);
+                        pkrb5_free_unparsed_name(ctx,sname);
+                    }
+
+                    if (!code)
+                        code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
+                    if (!code && !strlen(realm_of_cell))
+                        copy_realm_of_ticket(ctx, realm_of_cell, sizeof(realm_of_cell), k5creds);
+                }
             }
         }
 
         if (code) {
             if ( IsDebuggerPresent() ) {
                 char message[256];
-                sprintf(message,"krb5_get_credentials returns: %d\n",code);
+                StringCbPrintf(message, sizeof(message), "krb5_get_credentials returns: %d\n", code);
                 OutputDebugString(message);
             }
             try_krb5 = 0;
@@ -2994,16 +3197,25 @@ KFW_AFS_klog(
         }
 
         /* This code inserts the entire K5 ticket into the token
-         * No need to perform a krb524 translation which is 
+         * No need to perform a krb524 translation which is
          * commented out in the code below
          */
         if (KFW_use_krb524() ||
-            k5creds->ticket.length > MAXKTCTICKETLEN)
+            k5creds->ticket.length > MAXKTCTICKETLEN) {
+            if ( IsDebuggerPresent() ) {
+                char message[256];
+                StringCbPrintf(message, sizeof(message),
+                               "switching to krb524 .. ticket length %u\n",
+                               k5creds->ticket.length);
+                OutputDebugString(message);
+            }
             goto try_krb524d;
-
+        }
         memset(&aserver, '\0', sizeof(aserver));
-        strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
-        strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
+        StringCbCopyN(aserver.name, sizeof(aserver.name),
+                      ServiceName, sizeof(aserver.name) - 1);
+        StringCbCopyN(aserver.cell, sizeof(aserver.cell),
+                      CellName, sizeof(aserver.cell) - 1);
 
         memset(&atoken, '\0', sizeof(atoken));
         atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
@@ -3015,19 +3227,24 @@ KFW_AFS_klog(
 
       retry_gettoken5:
         rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
+        if ( IsDebuggerPresent() ) {
+            char message[256];
+            StringCbPrintf(message, sizeof(message), "ktc_GetToken returns: %d\n", rc);
+            OutputDebugString(message);
+        }
         if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
             if ( rc == KTC_NOCM && retry < 20 ) {
                 Sleep(500);
                 retry++;
                 goto retry_gettoken5;
             }
-            goto try_krb524d;
+            goto cleanup;
         }
 
         if (atoken.kvno == btoken.kvno &&
              atoken.ticketLen == btoken.ticketLen &&
              !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
-             !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) 
+             !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
         {
             /* Success - Nothing to do */
             goto cleanup;
@@ -3037,46 +3254,51 @@ KFW_AFS_klog(
         // * This structure was first set by the ktc_GetToken call when
         // * we were comparing whether identical tokens already existed.
 
-        len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
-        strncpy(aclient.name, k5creds->client->data[0].data, len);
-        aclient.name[len] = '\0';
+        len = min(k5creds->client->data[0].length, sizeof(aclient.name) - 1);
+        StringCbCopyN( aclient.name, sizeof(aclient.name),
+                       k5creds->client->data[0].data, len);
 
         if ( k5creds->client->length > 1 ) {
-            char * p;
-            strcat(aclient.name, ".");
-            p = aclient.name + strlen(aclient.name);
-            len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
-            strncpy(p, k5creds->client->data[1].data, len);
-            p[len] = '\0';
+            StringCbCat( aclient.name, sizeof(aclient.name), ".");
+            len = min(k5creds->client->data[1].length, (int)(sizeof(aclient.name) - strlen(aclient.name) - 1));
+            StringCbCatN( aclient.name, sizeof(aclient.name),
+                          k5creds->client->data[1].data, len);
         }
         aclient.instance[0] = '\0';
 
-        strcpy(aclient.cell, realm_of_cell);
+        StringCbCopyN( aclient.cell, sizeof(aclient.cell),
+                       realm_of_cell, sizeof(aclient.cell) - 1);
 
-        len = min(k5creds->client->realm.length,(int)strlen(realm_of_cell));
         /* For Khimaira, always append the realm name */
-        if ( 1 /* strncmp(realm_of_cell, k5creds->client->realm.data, len) */ ) {
-            char * p;
-            strcat(aclient.name, "@");
-            p = aclient.name + strlen(aclient.name);
-            len = min(k5creds->client->realm.length,MAXKTCNAMELEN - (int)strlen(aclient.name) - 1);
-            strncpy(p, k5creds->client->realm.data, len);
-            p[len] = '\0';
-        }
+        StringCbCat( aclient.name, sizeof(aclient.name), "@");
+        len = min(k5creds->client->realm.length, (int)(sizeof(aclient.name) - strlen(aclient.name) - 1));
+        StringCbCatN( aclient.name, sizeof(aclient.name), k5creds->client->realm.data, len);
 
        GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
        if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
-           ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
+           ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
                             &aclient, &aserver, &atoken);
 
         if ( smbname ) {
-            strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
-            aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
+            StringCbCopyN( aclient.smbname, sizeof(aclient.smbname),
+                           smbname, sizeof(aclient.smbname) - 1);
         } else {
             aclient.smbname[0] = '\0';
         }
+        if ( IsDebuggerPresent() ) {
+            char message[256];
+            StringCbPrintf(message, sizeof(message), "aclient.name: %s\n", aclient.name);
+            OutputDebugString(message);
+            StringCbPrintf(message, sizeof(message), "aclient.smbname: %s\n", aclient.smbname);
+            OutputDebugString(message);
+        }
 
         rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
+        if ( IsDebuggerPresent() ) {
+            char message[256];
+            StringCbPrintf(message, sizeof(message), "ktc_SetToken returns: %d\n", rc);
+            OutputDebugString(message);
+        }
         if (!rc)
             goto cleanup;   /* We have successfully inserted the token */
 
@@ -3085,14 +3307,14 @@ KFW_AFS_klog(
         goto cleanup;
 #else
         /* Otherwise, the ticket could have been too large so try to
-         * convert using the krb524d running with the KDC 
+         * convert using the krb524d running with the KDC
          */
         code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds);
         pkrb5_free_creds(ctx, k5creds);
         if (code) {
             if ( IsDebuggerPresent() ) {
                 char message[256];
-                sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code);
+                StringCbPrintf(message, sizeof(message), "krb524_convert_creds_kdc returns: %d\n", code);
                 OutputDebugString(message);
             }
             try_krb5 = 0;
@@ -3138,8 +3360,8 @@ KFW_AFS_klog(
     }
 
     memset(&aserver, '\0', sizeof(aserver));
-    strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1);
-    strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1);
+    StringCbCopyN( aserver.name, sizeof(aserver.name), ServiceName, sizeof(aserver.name) - 1);
+    StringCbCopyN( aserver.cell, sizeof(aserver.cell), CellName, sizeof(aserver.cell) - 1);
 
     memset(&atoken, '\0', sizeof(atoken));
     atoken.kvno = creds.kvno;
@@ -3151,6 +3373,11 @@ KFW_AFS_klog(
 
   retry_gettoken:
     rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
+    if ( IsDebuggerPresent() ) {
+        char message[256];
+        StringCbPrintf(message, sizeof(message), "ktc_GetToken returns: %d\n", rc);
+        OutputDebugString(message);
+    }
     if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
         if ( rc == KTC_NOCM && retry < 20 ) {
             Sleep(500);
@@ -3165,7 +3392,7 @@ KFW_AFS_klog(
     if (atoken.kvno == btoken.kvno &&
         atoken.ticketLen == btoken.ticketLen &&
         !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
-        !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) 
+        !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
     {
         goto cleanup;
     }
@@ -3174,32 +3401,41 @@ KFW_AFS_klog(
     // * This structure was first set by the ktc_GetToken call when
     // * we were comparing whether identical tokens already existed.
 
-    strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1);
+    StringCbCopyN( aclient.name, sizeof(aclient.name), creds.pname, sizeof(aclient.name) - 1);
     if (creds.pinst[0])
     {
         strncat(aclient.name, ".", MAXKTCNAMELEN - 1);
         strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1);
     }
-    strcpy(aclient.instance, "");
+    aclient.instance[0] = '\0';
 
     strncat(aclient.name, "@", MAXKTCNAMELEN - 1);
     strncat(aclient.name, creds.realm, MAXKTCREALMLEN - 1);
     aclient.name[MAXKTCREALMLEN-1] = '\0';
 
-    strcpy(aclient.cell, CellName);
+    StringCbCopyN( aclient.cell, sizeof(aclient.cell),
+                   CellName, sizeof(aclient.cell) - 1);
 
     GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
     if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
-       ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
+       ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
                         &aclient, &aserver, &atoken);
 
     if ( smbname ) {
-        strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
-        aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
+        StringCbCopyN( aclient.smbname, sizeof(aclient.smbname),
+                       smbname, sizeof(aclient.smbname) - 1);
     } else {
         aclient.smbname[0] = '\0';
     }
 
+    if ( IsDebuggerPresent() ) {
+        char message[256];
+        StringCbPrintf(message, sizeof(message), "aclient.name: %s\n", aclient.name);
+        OutputDebugString(message);
+        StringCbPrintf(message, sizeof(message), "aclient.smbname: %s\n", aclient.smbname);
+        OutputDebugString(message);
+    }
+
     if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
     {
         KFW_AFS_error(rc, "ktc_SetToken()");
@@ -3217,6 +3453,8 @@ KFW_AFS_klog(
         pkrb5_cc_close(ctx, cc);
     if (ctx && (ctx != alt_ctx))
         pkrb5_free_context(ctx);
+    if (ak_cellconfig.linkedCell)
+        free(ak_cellconfig.linkedCell);
 
     return(rc? rc : code);
 }
@@ -3236,7 +3474,8 @@ afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
 
     r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
     if ( !r && realmlist && realmlist[0] ) {
-        strcpy(krbrlm, realmlist[0]);
+        StringCbCopyN( krbrlm, sizeof(krbrlm),
+                       realmlist[0], sizeof(krbrlm) - 1);
         pkrb5_free_host_realm(ctx, realmlist);
     }
 
@@ -3259,11 +3498,12 @@ afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
 /**************************************/
 /* KFW_AFS_get_cellconfig():          */
 /**************************************/
-int 
+int
 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
 {
     int        rc;
-    char newcell[MAXCELLCHARS+1];
+    char newcell[CELL_MAXNAMELEN+1];
+    char linkedcell[CELL_MAXNAMELEN+1]="";
 
     local_cell[0] = (char)0;
     memset(cellconfig, 0, sizeof(*cellconfig));
@@ -3277,29 +3517,34 @@ KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_
     if (strlen(cell) == 0)
         strcpy(cell, local_cell);
 
-    /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
-    strcpy(cellconfig->name, cell);
-
-    rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
-#ifdef AFS_AFSDB_ENV
+    rc = cm_SearchCellRegistry(1, cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
+    if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
+        rc = cm_SearchCellFileEx(cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
     if (rc != 0) {
         int ttl;
         rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
     }
-#endif
+
+    if (rc == 0) {
+        StringCbCopyN( cellconfig->name, sizeof(cellconfig->name),
+                       newcell, sizeof(cellconfig->name) - 1);
+        if (linkedcell[0])
+            cellconfig->linkedCell = strdup(linkedcell);
+    }
     return rc;
 }
 
 /**************************************/
 /* get_cellconfig_callback():         */
 /**************************************/
-static long 
-get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep)
+static long
+get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep, unsigned short ipRank)
 {
     struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
 
     cc->hostAddr[cc->numServers] = *addrp;
-    strcpy(cc->hostName[cc->numServers], namep);
+    StringCbCopyN( cc->hostName[cc->numServers], sizeof(cc->hostName[cc->numServers]),
+                   namep, sizeof(cc->hostName[cc->numServers]) - 1);
     cc->numServers++;
     return(0);
 }
@@ -3312,11 +3557,11 @@ void
 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
 {
     char message[256];
-    const char *errText; 
+    const char *errText;
 
-    // Using AFS defines as error messages for now, until Transarc 
-    // gets back to me with "string" translations of each of these 
-    // const. defines. 
+    // Using AFS defines as error messages for now, until Transarc
+    // gets back to me with "string" translations of each of these
+    // const. defines.
     if (rc == KTC_ERROR)
       errText = "KTC_ERROR";
     else if (rc == KTC_TOOBIG)
@@ -3336,7 +3581,7 @@ KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
     else
       errText = "Unknown error!";
 
-    sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
+    StringCbPrintf(message, sizeof(message), "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
 
     if ( IsDebuggerPresent() ) {
         OutputDebugString(message);
@@ -3346,65 +3591,65 @@ KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
     return;
 }
 
-static DWORD 
+static DWORD
 GetServiceStatus(
-    LPSTR lpszMachineName, 
+    LPSTR lpszMachineName,
     LPSTR lpszServiceName,
-    DWORD *lpdwCurrentState) 
-{ 
-    DWORD           hr               = NOERROR; 
-    SC_HANDLE       schSCManager     = NULL; 
-    SC_HANDLE       schService       = NULL; 
-    DWORD           fdwDesiredAccess = 0; 
-    SERVICE_STATUS  ssServiceStatus  = {0}; 
-    BOOL            fRet             = FALSE; 
-
-    *lpdwCurrentState = 0; 
-    fdwDesiredAccess = GENERIC_READ; 
-    schSCManager = OpenSCManager(lpszMachineName,  
+    DWORD *lpdwCurrentState)
+{
+    DWORD           hr               = NOERROR;
+    SC_HANDLE       schSCManager     = NULL;
+    SC_HANDLE       schService       = NULL;
+    DWORD           fdwDesiredAccess = 0;
+    SERVICE_STATUS  ssServiceStatus  = {0};
+    BOOL            fRet             = FALSE;
+
+    *lpdwCurrentState = 0;
+
+    fdwDesiredAccess = GENERIC_READ;
+
+    schSCManager = OpenSCManager(lpszMachineName,
                                  NULL,
-                                 fdwDesiredAccess); 
-    if(schSCManager == NULL) 
-    { 
+                                 fdwDesiredAccess);
+
+    if(schSCManager == NULL)
+    {
         hr = GetLastError();
-        goto cleanup; 
-    } 
+        goto cleanup;
+    }
+
     schService = OpenService(schSCManager,
                              lpszServiceName,
-                             fdwDesiredAccess); 
-    if(schService == NULL) 
-    { 
+                             fdwDesiredAccess);
+
+    if(schService == NULL)
+    {
         hr = GetLastError();
-        goto cleanup; 
-    } 
+        goto cleanup;
+    }
+
     fRet = QueryServiceStatus(schService,
-                              &ssServiceStatus); 
-    if(fRet == FALSE) 
-    { 
-        hr = GetLastError(); 
-        goto cleanup; 
-    } 
-    *lpdwCurrentState = ssServiceStatus.dwCurrentState; 
-cleanup: 
-    CloseServiceHandle(schService); 
-    CloseServiceHandle(schSCManager); 
-    return(hr); 
-} 
+                              &ssServiceStatus);
+
+    if(fRet == FALSE)
+    {
+        hr = GetLastError();
+        goto cleanup;
+    }
+
+    *lpdwCurrentState = ssServiceStatus.dwCurrentState;
+
+cleanup:
+
+    CloseServiceHandle(schService);
+    CloseServiceHandle(schSCManager);
+
+    return(hr);
+}
 
 void
 UnloadFuncs(
-    FUNC_INFO fi[], 
+    FUNC_INFO fi[],
     HINSTANCE h
     )
 {
@@ -3417,8 +3662,8 @@ UnloadFuncs(
 
 int
 LoadFuncs(
-    const char* dll_name, 
-    FUNC_INFO fi[], 
+    const char* dll_name,
+    FUNC_INFO fi[],
     HINSTANCE* ph,  // [out, optional] - DLL handle
     int* pindex,    // [out, optional] - index of last func loaded (-1 if none)
     int cleanup,    // cleanup function pointers and unload on error
@@ -3484,7 +3729,7 @@ BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
     BOOL serverReachable = 0;
 
     if (!pkrb5_init_context)
-        return 0;
+        return KRB5_CONFIG_CANTOPEN;
 
     code = pkrb5_init_context(&ctx);
     if (code) goto cleanup;
@@ -3512,8 +3757,8 @@ BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
     }
     password[PROBE_PASSWORD_LEN] = '\0';
 
-    code = KFW_kinit(NULL, NULL, HWND_DESKTOP, 
-                      pname, 
+    code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
+                      pname,
                       password,
                       5,
                       0,
@@ -3573,8 +3818,7 @@ KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
         goto cleanup;
 
     if ( strlen(pname) < *dwSize ) {
-        strncpy(szUser, pname, *dwSize);
-        szUser[*dwSize-1] = '\0';
+        StringCbCopyN(szUser, *dwSize, pname, (*dwSize) - 1);
         success = 1;
     }
     *dwSize = (DWORD)strlen(pname);
@@ -3594,7 +3838,7 @@ KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
     return success;
 }
 
-int 
+int
 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
 {
     // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
@@ -3605,7 +3849,7 @@ KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
     PTOKEN_USER pTokenUser = NULL;
     DWORD retLen;
     DWORD gle;
-    int ret = 0;  
+    int ret = 0;
 
     if (!filename) {
        return 1;
@@ -3629,13 +3873,13 @@ KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
                pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
 
                GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
-           }            
+           }
        }
 
        if (pTokenUser) {
            UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
 
-           ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength 
+           ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
                - sizeof(DWORD);
        }
     }
@@ -3656,7 +3900,7 @@ KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
        if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
                                   DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
                                   NULL,
-                                  NULL, 
+                                  NULL,
                                   ccacheACL,
                                   NULL)) {
            gle = GetLastError();
@@ -3666,7 +3910,7 @@ KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
        if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
                                   OWNER_SECURITY_INFORMATION,
                                   pTokenUser->User.Sid,
-                                  NULL, 
+                                  NULL,
                                   NULL,
                                   NULL)) {
            gle = GetLastError();
@@ -3677,7 +3921,7 @@ KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
        if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
                                   DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
                                   NULL,
-                                  NULL, 
+                                  NULL,
                                   ccacheACL,
                                   NULL)) {
            gle = GetLastError();
@@ -3696,24 +3940,24 @@ KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
     return ret;
 }
 
-int 
+int
 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
 {
     int  retval = 0;
     DWORD dwSize = size-1;     /* leave room for nul */
     DWORD dwLen  = 0;
+
     if (!hUserToken || !newfilename || size <= 0)
        return 1;
+
      *newfilename = '\0';
+
      dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
      if ( !dwLen || dwLen > dwSize )
        dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
      if ( !dwLen || dwLen > dwSize )
        return 1;
+
      newfilename[dwSize] = '\0';
     return 0;
 }
@@ -3741,10 +3985,10 @@ KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
     if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
         return;
 
-    strcat(filename, "\\");
-    strcat(filename, szLogonId);    
+    StringCbCat( filename, sizeof(filename), "\\");
+    StringCbCat( filename, sizeof(filename), szLogonId);
 
-    strcat(cachename, filename);
+    StringCbCat( cachename, sizeof(cachename), filename);
 
     DeleteFile(filename);
 
@@ -3806,11 +4050,11 @@ KFW_AFS_copy_file_cache_to_default_cache(char * filename)
     code = pkrb5_init_context(&ctx);
     if (code) return 1;
 
-    strcat(cachename, filename);
+    StringCbCat( cachename, sizeof(cachename), filename);
 
     code = pkrb5_cc_resolve(ctx, cachename, &cc);
     if (code) goto cleanup;
-    
+
     code = pkrb5_cc_get_principal(ctx, cc, &princ);
 
     code = pkrb5_cc_default(ctx, &ncc);
@@ -3846,7 +4090,7 @@ KFW_AFS_copy_file_cache_to_default_cache(char * filename)
     return 0;
 }
 
-/* We are including this 
+/* We are including this
 
 /* Ticket lifetime.  This defines the table used to lookup lifetime for the
    fixed part of rande of the one byte lifetime field.  Values less than 0x80