pr_init-fix-20050623
[openafs.git] / src / WINNT / afsd / afskfw.c
index c0b31ec..a7b78ab 100644 (file)
 
 
 #define USE_MS2MIT
-#define USE_KRB4
+#undef  USE_KRB4
 #include "afskfw-int.h"
 #include "afskfw.h"
 
 #include <osilog.h>
 #include <rxkad_prototypes.h>   /* for life_to_time */
 #include <afs/ptserver.h>
+#include <afs/ptuser.h>
+
+#include <WINNT\afsreg.h>
 
 /*
  * TIMING _____________________________________________________________________
@@ -99,6 +102,7 @@ DECL_FUNC_PTR(Leash_get_default_life_max);
 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);
 
 // krb5 functions
 DECL_FUNC_PTR(krb5_change_password);
@@ -153,6 +157,7 @@ DECL_FUNC_PTR(krb5_get_renewed_creds);
 DECL_FUNC_PTR(krb5_get_default_config_files);
 DECL_FUNC_PTR(krb5_free_config_files);
 DECL_FUNC_PTR(krb5_get_default_realm);
+DECL_FUNC_PTR(krb5_free_default_realm);
 DECL_FUNC_PTR(krb5_free_ticket);
 DECL_FUNC_PTR(krb5_decode_ticket);
 DECL_FUNC_PTR(krb5_get_host_realm);
@@ -225,6 +230,11 @@ FUNC_INFO leash_fi[] = {
     END_FUNC_INFO
 };
 
+FUNC_INFO leash_opt_fi[] = {
+    MAKE_FUNC_INFO(Leash_get_default_mslsa_import),
+    END_FUNC_INFO
+};
+
 FUNC_INFO k5_fi[] = {
     MAKE_FUNC_INFO(krb5_change_password),
     MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
@@ -279,6 +289,7 @@ FUNC_INFO k5_fi[] = {
     MAKE_FUNC_INFO(krb5_get_default_config_files),
     MAKE_FUNC_INFO(krb5_free_config_files),
     MAKE_FUNC_INFO(krb5_get_default_realm),
+    MAKE_FUNC_INFO(krb5_free_default_realm),
     MAKE_FUNC_INFO(krb5_free_ticket),
     MAKE_FUNC_INFO(krb5_decode_ticket),
     MAKE_FUNC_INFO(krb5_get_host_realm),
@@ -288,6 +299,7 @@ FUNC_INFO k5_fi[] = {
     END_FUNC_INFO
 };
 
+#ifdef USE_KRB4
 FUNC_INFO k4_fi[] = {
     MAKE_FUNC_INFO(krb_get_cred),
     MAKE_FUNC_INFO(krb_get_tf_realm),
@@ -295,6 +307,7 @@ FUNC_INFO k4_fi[] = {
     MAKE_FUNC_INFO(tkt_string),
     END_FUNC_INFO
 };
+#endif
 
 FUNC_INFO k524_fi[] = {
     MAKE_FUNC_INFO(krb524_init_ets),
@@ -354,7 +367,9 @@ static int                inited = 0;
 static int                mid_cnt = 0;
 static struct textField * mid_tb = NULL;
 static HINSTANCE hKrb5 = 0;
+#ifdef USE_KRB4
 static HINSTANCE hKrb4 = 0;
+#endif /* USE_KRB4 */
 static HINSTANCE hKrb524 = 0;
 #ifdef USE_MS2MIT
 static HINSTANCE hSecur32 = 0;
@@ -364,6 +379,7 @@ static HINSTANCE hComErr = 0;
 static HINSTANCE hService = 0;
 static HINSTANCE hProfile = 0;
 static HINSTANCE hLeash = 0;
+static HINSTANCE hLeashOpt = 0;
 static HINSTANCE hCCAPI = 0;
 static struct principal_ccache_data * princ_cc_data = NULL;
 static struct cell_principal_map    * cell_princ_map = NULL;
@@ -388,7 +404,9 @@ KFW_initialize(void)
         if ( !inited ) {
             inited = 1;
             LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
+#ifdef USE_KRB4
             LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
+#endif /* USE_KRB4 */
             LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
             LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
 #ifdef USE_MS2MIT
@@ -398,6 +416,7 @@ KFW_initialize(void)
             LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
             LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
             LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
+            LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0);
 
             if ( KFW_is_available() ) {
                 char rootcell[MAXCELLCHARS+1];
@@ -420,30 +439,32 @@ KFW_initialize(void)
 void
 KFW_cleanup(void)
 {
-    if (hKrb5)
-        FreeLibrary(hKrb5);
-    if (hKrb4)
-        FreeLibrary(hKrb4);
-    if (hProfile)
-        FreeLibrary(hProfile);
-    if (hComErr)
-        FreeLibrary(hComErr);
-    if (hService)
-        FreeLibrary(hService);
+    if (hLeashOpt)
+        FreeLibrary(hLeashOpt);
+    if (hCCAPI)
+        FreeLibrary(hCCAPI);
+    if (hLeash)
+        FreeLibrary(hLeash);
+    if (hKrb524)
+        FreeLibrary(hKrb524);
 #ifdef USE_MS2MIT
     if (hSecur32)
         FreeLibrary(hSecur32);
 #endif /* USE_MS2MIT */
-    if (hKrb524)
-        FreeLibrary(hKrb524);
-    if (hLeash)
-        FreeLibrary(hLeash);
-    if (hCCAPI)
-        FreeLibrary(hCCAPI);
+    if (hService)
+        FreeLibrary(hService);
+    if (hComErr)
+        FreeLibrary(hComErr);
+    if (hProfile)
+        FreeLibrary(hProfile);
+#ifdef USE_KRB4
+    if (hKrb4)
+        FreeLibrary(hKrb4);
+#endif /* USE_KRB4 */
+    if (hKrb5)
+        FreeLibrary(hKrb5);
 }
 
-static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client";
-
 int
 KFW_use_krb524(void)
 {
@@ -451,7 +472,7 @@ KFW_use_krb524(void)
     DWORD code, len;
     DWORD use524 = 0;
 
-    code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
+    code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
                          0, KEY_QUERY_VALUE, &parmKey);
     if (code == ERROR_SUCCESS) {
         len = sizeof(use524);
@@ -460,7 +481,7 @@ KFW_use_krb524(void)
         RegCloseKey(parmKey);
     }
     if (code != ERROR_SUCCESS) {
-        code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
+        code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
                              0, KEY_QUERY_VALUE, &parmKey);
         if (code == ERROR_SUCCESS) {
             len = sizeof(use524);
@@ -479,7 +500,7 @@ KFW_is_available(void)
     DWORD code, len;
     DWORD enableKFW = 1;
 
-    code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
+    code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
                          0, KEY_QUERY_VALUE, &parmKey);
     if (code == ERROR_SUCCESS) {
         len = sizeof(enableKFW);
@@ -489,7 +510,7 @@ KFW_is_available(void)
     }
     
     if (code != ERROR_SUCCESS) {
-        code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
+        code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
                              0, KEY_QUERY_VALUE, &parmKey);
         if (code == ERROR_SUCCESS) {
             len = sizeof(enableKFW);
@@ -896,8 +917,9 @@ KFW_import_windows_lsa(void)
     char * pname = NULL;
     krb5_data *  princ_realm;
     krb5_error_code code;
-    char cell[128]="", realm[128]="";
+    char cell[128]="", realm[128]="", *def_realm = 0;
     int i;
+    DWORD dwMsLsaImport;
          
     if (!pkrb5_init_context)
         return;
@@ -918,6 +940,32 @@ KFW_import_windows_lsa(void)
     code = pkrb5_cc_get_principal(ctx, cc, &princ);
     if ( code ) goto cleanup;
 
+    dwMsLsaImport = pLeash_get_default_mslsa_import ? pLeash_get_default_mslsa_import() : 1;
+    switch ( dwMsLsaImport ) {
+    case 0: /* do not import */
+        goto cleanup;
+    case 1: /* always import */
+        break;
+    case 2: { /* matching realm */
+        char ms_realm[128] = "", *r;
+        int i;
+
+        for ( r=ms_realm, i=0; i<krb5_princ_realm(ctx, princ)->length; r++, i++ ) {
+            *r = krb5_princ_realm(ctx, princ)->data[i];
+        }
+        *r = '\0';
+
+        if (code = pkrb5_get_default_realm(ctx, &def_realm))
+            goto cleanup;
+
+        if (strcmp(def_realm, ms_realm))
+            goto cleanup;
+        break;
+    }
+    default:
+        break;
+    }
+
     code = pkrb5_unparse_name(ctx,princ,&pname);
     if ( code ) goto cleanup;
 
@@ -944,6 +992,8 @@ KFW_import_windows_lsa(void)
         pkrb5_free_unparsed_name(ctx,pname);
     if (princ)
         pkrb5_free_principal(ctx,princ);
+    if (def_realm)
+        pkrb5_free_default_realm(ctx, def_realm);
     if (cc)
         pkrb5_cc_close(ctx,cc);
     if (ctx)
@@ -1030,7 +1080,7 @@ KFW_import_ccache_data(void)
                     code = pkrb5_cc_close(ctx,cc);
                     cc = 0;
                     code = pkrb5_cc_close(ctx,oldcc);
-                    cc = 0;
+                    oldcc = 0;
                     KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
                     continue;
                 }
@@ -1161,8 +1211,7 @@ KFW_AFS_get_cred( char * username,
 {
     krb5_context ctx = 0;
     krb5_ccache cc = 0;
-    char * realm = 0;
-    char ** realmlist = 0;
+    char * realm = 0, * userrealm = 0;
     krb5_principal principal = 0;
     char * pname = 0;
     krb5_error_code code;
@@ -1190,19 +1239,20 @@ KFW_AFS_get_cred( char * username,
     code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
     if ( code ) goto cleanup;
 
-    realm = strchr(username,'@');
-    if ( realm ) {
+    realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
+
+    userrealm = strchr(username,'@');
+    if ( userrealm ) {
         pname = strdup(username);
-        realm = strchr(pname, '@');
-        *realm = '\0';
+        userrealm = strchr(pname, '@');
+        *userrealm = '\0';
 
         /* handle kerberos iv notation */
         while ( dot = strchr(pname,'.') ) {
             *dot = '/';
         }
-        *realm++ = '@';
+        *userrealm++ = '@';
     } else {
-        realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
         pname = malloc(strlen(username) + strlen(realm) + 2);
 
         strcpy(pname, username);
@@ -1215,7 +1265,6 @@ KFW_AFS_get_cred( char * username,
         strcat(pname,"@");
         strcat(pname,realm);
     }
-
     if ( IsDebuggerPresent() ) {
         OutputDebugString("Realm: ");
         OutputDebugString(realm);
@@ -1321,7 +1370,7 @@ KFW_AFS_destroy_tickets_for_cell(char * cell)
         return 0;
 
     if ( IsDebuggerPresent() ) {
-        OutputDebugString("KFW_AFS_destroy_ticets_for_cell: ");
+        OutputDebugString("KFW_AFS_destroy_tickets_for_cell: ");
         OutputDebugString(cell);
         OutputDebugString("\n");
     }
@@ -1373,6 +1422,60 @@ KFW_AFS_destroy_tickets_for_cell(char * cell)
     return 0;
 }
 
+int 
+KFW_AFS_destroy_tickets_for_principal(char * user)
+{
+    krb5_context               ctx = 0;
+    krb5_error_code            code;
+    int count;
+    char ** cells = NULL;
+    krb5_principal      princ = 0;
+    krb5_ccache                        cc  = 0;
+
+    if (!pkrb5_init_context)
+        return 0;
+
+    if ( IsDebuggerPresent() ) {
+        OutputDebugString("KFW_AFS_destroy_tickets_for_user: ");
+        OutputDebugString(user);
+        OutputDebugString("\n");
+    }
+
+    code = pkrb5_init_context(&ctx);
+    if (code) ctx = 0;
+
+    code = pkrb5_parse_name(ctx, user, &princ);
+    if (code) goto loop_cleanup;
+
+    code = KFW_get_ccache(ctx, princ, &cc);
+    if (code) goto loop_cleanup;
+
+    code = pkrb5_cc_destroy(ctx, cc);
+    if (!code) cc = 0;
+
+  loop_cleanup:
+    if ( cc ) {
+        pkrb5_cc_close(ctx, cc);
+        cc = 0;
+    }
+    if ( princ ) {
+        pkrb5_free_principal(ctx, princ);
+        princ = 0;
+    }
+
+    count = KFW_AFS_find_cells_for_princ(ctx, user, &cells, TRUE);
+    if ( count >= 1 ) {
+        while ( count-- ) {
+            KFW_AFS_update_cell_princ_map(ctx, cells[count], user, FALSE);
+            free(cells[count]);
+        }
+        free(cells);
+    }
+
+    pkrb5_free_context(ctx);
+    return 0;
+}
+
 int
 KFW_AFS_renew_expiring_tokens(void)
 {
@@ -2425,7 +2528,9 @@ ViceIDToUsername(char *username,
 {
     static char lastcell[MAXCELLCHARS+1] = { 0 };
     static char confname[512] = { 0 };
+#ifdef AFS_ID_TO_NAME
     char username_copy[BUFSIZ];
+#endif /* AFS_ID_TO_NAME */
     long viceId;                       /* AFS uid of user */
     int  status = 0;
 #ifdef ALLOW_REGISTER
@@ -2437,26 +2542,6 @@ ViceIDToUsername(char *username,
         confname[sizeof(confname) - 2] = '\0';
     }
 
-    /*
-     * Talk about DUMB!  It turns out that there is a bug in
-     * pr_Initialize -- even if you give a different cell name
-     * to it, it still uses a connection to a previous AFS server
-     * if one exists.  The way to fix this is to change the
-     * _filename_ argument to pr_Initialize - that forces it to
-     * re-initialize the connection.  We do this by adding and
-     * removing a "/" on the end of the configuration directory name.
-     */
-
-    if (lastcell[0] != '\0' && (strcmp(lastcell, aserver->cell) != 0)) {
-        int i = strlen(confname);
-        if (confname[i - 1] == '/') {
-            confname[i - 1] = '\0';
-        } else {
-            confname[i] = '/';
-            confname[i + 1] = '\0';
-        }
-    }
-
     strcpy(lastcell, aserver->cell);
 
     if (!pr_Initialize (0, confname, aserver->cell))
@@ -2497,15 +2582,7 @@ ViceIDToUsername(char *username,
             strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1);
             if (status = ktc_SetToken(aserver, atoken, aclient, 0))
                 return status;
-
-            /*                                    
-             * In case you're wondering, we don't need to change the
-             * filename here because we're still connecting to the
-             * same cell -- we're just using a different authentication
-             * level
-             */
-
-            if (status = pr_Initialize(1L, confname, aserver->cell, 0))
+            if (status = pr_Initialize(1L, confname, aserver->cell))
                 return status;
             if (status = pr_CreateUser(username, &id))
                 return status;
@@ -2533,7 +2610,9 @@ KFW_AFS_klog(
 {
     long       rc = 0;
     CREDENTIALS        creds;
+#ifdef USE_KRB4
     KTEXT_ST    ticket;
+#endif /* USE_KRB4 */
     struct ktc_principal       aserver;
     struct ktc_principal       aclient;
     char       realm_of_user[REALM_SZ]; /* Kerberos realm of user */
@@ -2555,6 +2634,7 @@ KFW_AFS_klog(
     krb5_creds * k5creds = 0;
     krb5_error_code code;
     krb5_principal client_principal = 0;
+    krb5_data * k5data;
     int i, retry = 0;
 
     CurrentState = 0;
@@ -2616,7 +2696,15 @@ KFW_AFS_klog(
         goto skip_krb5_init;
     }
 
-    if ( strchr(krb5_princ_component(ctx,client_principal,0),'.') != NULL )
+    /* look for client principals which cannot be distinguished 
+     * from Kerberos 4 multi-component principal names
+     */
+    k5data = krb5_princ_component(ctx,client_principal,0);
+    for ( i=0; i<k5data->length; i++ ) {
+        if ( k5data->data[i] == '.' )
+            break;
+    }
+    if (i != k5data->length)
     {
         OutputDebugString("Illegal Principal name contains dot in first component\n");
         rc = KRB5KRB_ERR_GENERIC;
@@ -2639,7 +2727,8 @@ KFW_AFS_klog(
         }       
     }
 #else
-    goto cleanup;
+    if (!try_krb5)
+        goto cleanup;
 #endif
     strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
 
@@ -2696,7 +2785,7 @@ 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) {
+             code == KRB5KRB_AP_ERR_MSG_TYPE) {
             /* Or service@REALM */
             pkrb5_free_principal(ctx,increds.server);
             increds.server = 0;
@@ -2726,7 +2815,7 @@ KFW_AFS_klog(
 
         if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
               code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
-                         code == KRB5KRB_AP_ERR_MSG_TYPE) &&
+              code == KRB5KRB_AP_ERR_MSG_TYPE) &&
              strcmp(RealmName, realm_of_cell)) {
             /* Or service/cell@REALM_OF_CELL */
             strcpy(RealmName, realm_of_cell);
@@ -3017,7 +3106,7 @@ KFW_AFS_klog(
     if (ctx && (ctx != alt_ctx))
         pkrb5_free_context(ctx);
 
-       return(rc? rc : code);
+    return(rc? rc : code);
 }
 
 /**************************************/
@@ -3346,3 +3435,176 @@ BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
     return serverReachable;
 }
 
+BOOL
+KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
+{
+    krb5_context   ctx = 0;
+    krb5_error_code code;
+    krb5_ccache mslsa_ccache=0;
+    krb5_principal princ = 0;
+    char * pname = 0;
+    BOOL success = 0;
+
+    if (!KFW_is_available())
+        return FALSE;
+
+    if (code = pkrb5_init_context(&ctx))
+        goto cleanup;
+
+    if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
+        goto cleanup;
+
+    if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
+        goto cleanup;
+
+    if (code = pkrb5_unparse_name(ctx, princ, &pname))
+        goto cleanup;
+
+    if ( strlen(pname) < *dwSize ) {
+        strncpy(szUser, pname, *dwSize);
+        szUser[*dwSize-1] = '\0';
+        success = 1;
+    }
+    *dwSize = strlen(pname);
+
+  cleanup:
+    if (pname)
+        pkrb5_free_unparsed_name(ctx, pname);
+
+    if (princ)
+        pkrb5_free_principal(ctx, princ);
+
+    if (mslsa_ccache)
+        pkrb5_cc_close(ctx, mslsa_ccache);
+
+    if (ctx)
+        pkrb5_free_context(ctx);
+    return success;
+}
+
+void
+KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
+{
+    char filename[256];
+    DWORD count;
+    char cachename[264] = "FILE:";
+    krb5_context               ctx = 0;
+    krb5_error_code            code;
+    krb5_principal              princ = 0;
+    krb5_ccache                        cc  = 0;
+    krb5_ccache                 ncc = 0;
+
+    if (!pkrb5_init_context)
+        return;
+
+    count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
+    if ( count > sizeof(filename) || count == 0 ) {
+        GetWindowsDirectory(filename, sizeof(filename));
+    }
+
+    if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
+        return;
+
+    strcat(filename, "\\");
+    strcat(filename, szLogonId);    
+
+    strcat(cachename, filename);
+
+    DeleteFile(filename);
+
+    code = pkrb5_init_context(&ctx);
+    if (code) ctx = 0;
+
+    code = pkrb5_parse_name(ctx, user, &princ);
+    if (code) goto cleanup;
+
+    code = KFW_get_ccache(ctx, princ, &cc);
+    if (code) goto cleanup;
+
+    code = pkrb5_cc_resolve(ctx, cachename, &ncc);
+    if (code) goto cleanup;
+
+    code = pkrb5_cc_initialize(ctx, ncc, princ);
+    if (code) goto cleanup;
+
+    code = pkrb5_cc_copy_creds(ctx,cc,ncc);
+
+  cleanup:
+    if ( cc ) {
+        pkrb5_cc_close(ctx, cc);
+        cc = 0;
+    }
+    if ( ncc ) {
+        pkrb5_cc_close(ctx, ncc);
+        ncc = 0;
+    }
+    if ( princ ) {
+        pkrb5_free_principal(ctx, princ);
+        princ = 0;
+    }
+
+    if (ctx)
+        pkrb5_free_context(ctx);
+}
+
+int
+KFW_AFS_copy_system_file_to_default_cache(char * filename)
+{
+    DWORD count;
+    char cachename[264] = "FILE:";
+    HANDLE hFile;
+    krb5_context               ctx = 0;
+    krb5_error_code            code;
+    krb5_principal              princ = 0;
+    krb5_ccache                        cc  = 0;
+    krb5_ccache                 ncc = 0;
+    int retval = 1;
+
+    if (!pkrb5_init_context)
+        return 1;
+
+    if ( strlen(filename) + 6 > sizeof(cachename) )
+        return 1;
+
+    strcat(cachename, filename);
+
+    code = pkrb5_init_context(&ctx);
+    if (code) ctx = 0;
+
+    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);
+    if (!code) {
+        code = pkrb5_cc_initialize(ctx, ncc, princ);
+
+        if (!code)
+            code = pkrb5_cc_copy_creds(ctx,cc,ncc);
+    }
+    if ( ncc ) {
+        pkrb5_cc_close(ctx, ncc);
+        ncc = 0;
+    }
+
+    retval=0;   /* success */
+
+  cleanup:
+    if ( cc ) {
+        pkrb5_cc_close(ctx, cc);
+        cc = 0;
+    }
+
+    DeleteFile(filename);
+
+    if ( princ ) {
+        pkrb5_free_principal(ctx, princ);
+        princ = 0;
+    }
+
+    if (ctx)
+        pkrb5_free_context(ctx);
+
+    return 0;
+}