/* does the ccache have a valid TGT? */ static time_t get_tgt_time(const char *ccname) { krb5_context context; krb5_ccache ccache; krb5_cc_cursor cur; krb5_creds creds; krb5_principal principal; time_t credtime = 0; char *realm = NULL; if (krb5_init_context(&context)) { syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__); return 0; } if (krb5_cc_resolve(context, ccname, &ccache)) { syslog(LOG_DEBUG, "%s: unable to resolve krb5 cache", __func__); goto err_cache; } if (krb5_cc_set_flags(context, ccache, 0)) { syslog(LOG_DEBUG, "%s: unable to set flags", __func__); goto err_cache; } if (krb5_cc_get_principal(context, ccache, &principal)) { syslog(LOG_DEBUG, "%s: unable to get principal", __func__); goto err_princ; } if (krb5_cc_start_seq_get(context, ccache, &cur)) { syslog(LOG_DEBUG, "%s: unable to seq start", __func__); goto err_ccstart; } if ((realm = cifs_krb5_principal_get_realm(context, principal)) == NULL) { syslog(LOG_DEBUG, "%s: unable to get realm", __func__); goto err_ccstart; } while (!credtime && !krb5_cc_next_cred(context, ccache, &cur, &creds)) { char *name; if (krb5_unparse_name(context, creds.server, &name)) { syslog(LOG_DEBUG, "%s: unable to unparse name", __func__); goto err_endseq; } if (krb5_realm_compare(context, creds.server, principal) && !strncasecmp(name, KRB5_TGS_NAME, KRB5_TGS_NAME_SIZE) && !strncasecmp(name + KRB5_TGS_NAME_SIZE + 1, realm, strlen(realm)) && creds.times.endtime > time(NULL)) credtime = creds.times.endtime; krb5_free_cred_contents(context, &creds); krb5_free_unparsed_name(context, name); } err_endseq: krb5_cc_end_seq_get(context, ccache, &cur); err_ccstart: krb5_free_principal(context, principal); err_princ: #if defined(KRB5_TC_OPENCLOSE) krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); #endif krb5_cc_close(context, ccache); err_cache: krb5_free_context(context); return credtime; }
int main(int argc, char *argv[]) { krb5_context kcontext = NULL; krb5_error_code code; krb5_ccache ccache=NULL; krb5_ccache mslsa_ccache=NULL; krb5_cc_cursor cursor; krb5_creds creds; krb5_principal princ = NULL; int found_tgt = 0; int has_tickets; int option; char * ccachestr = 0; prog = strrchr(argv[0], '/'); prog = prog ? (prog + 1) : argv[0]; while ((option = getopt(argc, argv, "c:h")) != -1) { switch (option) { case 'c': ccachestr = optarg; break; case 'h': default: xusage(); break; } } if (code = krb5_init_context(&kcontext)) { com_err(argv[0], code, "while initializing kerberos library"); goto cleanup; } if (code = krb5_cc_resolve(kcontext, "MSLSA:", &mslsa_ccache)) { com_err(argv[0], code, "while opening MS LSA ccache"); goto cleanup; } /* Enumerate tickets from cache looking for a TGT */ if ((code = krb5_cc_start_seq_get(kcontext, mslsa_ccache, &cursor))) { com_err(argv[0], code, "while initiating the cred sequence of MS LSA ccache"); goto cleanup; } while (!found_tgt) { code = krb5_cc_next_cred(kcontext, mslsa_ccache, &cursor, &creds); if (code) break; /* Check if the ticket is a TGT */ if (is_local_tgt(creds.server)) found_tgt = 1; krb5_free_cred_contents(kcontext, &creds); } krb5_cc_end_seq_get(kcontext, mslsa_ccache, &cursor); if (!found_tgt) { fprintf(stderr, "%s: Initial Ticket Getting Tickets are not available from the MS LSA\n", argv[0]); /* Only set the LSA cache as the default if it actually has tickets. */ code = cc_has_tickets(kcontext, mslsa_ccache, &has_tickets); if (code) goto cleanup; if (has_tickets) code = krb5int_cc_user_set_default_name(kcontext, "MSLSA:"); goto cleanup; } if (code = krb5_cc_get_principal(kcontext, mslsa_ccache, &princ)) { com_err(argv[0], code, "while obtaining MS LSA principal"); goto cleanup; } if (ccachestr) code = krb5_cc_resolve(kcontext, ccachestr, &ccache); else code = krb5_cc_resolve(kcontext, "API:", &ccache); if (code) { com_err(argv[0], code, "while getting default ccache"); goto cleanup; } if (code = krb5_cc_initialize(kcontext, ccache, princ)) { com_err (argv[0], code, "when initializing ccache"); goto cleanup; } if (code = krb5_cc_copy_creds(kcontext, mslsa_ccache, ccache)) { com_err (argv[0], code, "while copying MS LSA ccache to default ccache"); goto cleanup; } /* Don't try and set the default cache if the cache name was specified. */ if (ccachestr == NULL) { /* On success set the default cache to API. */ code = krb5int_cc_user_set_default_name(kcontext, "API:"); if (code) { com_err(argv[0], code, "when setting default to API"); goto cleanup; } } cleanup: krb5_free_principal(kcontext, princ); if (ccache != NULL) krb5_cc_close(kcontext, ccache); if (mslsa_ccache != NULL) krb5_cc_close(kcontext, mslsa_ccache); krb5_free_context(kcontext); return code ? 1 : 0; }
krb5_error_code KRB5_CALLCONV krb5_cccol_have_content(krb5_context context) { krb5_error_code ret; krb5_cccol_cursor col_cursor; krb5_cc_cursor cache_cursor; krb5_ccache cache; krb5_creds creds; krb5_boolean found = FALSE; struct errinfo errsave = EMPTY_ERRINFO; const char *defname; ret = krb5_cccol_cursor_new(context, &col_cursor); save_first_error(context, ret, &errsave); if (ret) goto no_entries; while (!found) { ret = krb5_cccol_cursor_next(context, col_cursor, &cache); save_first_error(context, ret, &errsave); if (ret || cache == NULL) break; ret = krb5_cc_start_seq_get(context, cache, &cache_cursor); save_first_error(context, ret, &errsave); if (ret) continue; while (!found) { ret = krb5_cc_next_cred(context, cache, &cache_cursor, &creds); save_first_error(context, ret, &errsave); if (ret) break; if (!krb5_is_config_principal(context, creds.server)) found = TRUE; krb5_free_cred_contents(context, &creds); } krb5_cc_end_seq_get(context, cache, &cache_cursor); krb5_cc_close(context, cache); } krb5_cccol_cursor_free(context, &col_cursor); if (found) return 0; no_entries: if (errsave.code) { /* Report the first error we encountered. */ ret = k5_restore_ctx_error(context, &errsave); k5_wrapmsg(context, ret, KRB5_CC_NOTFOUND, _("No Kerberos credentials available")); } else { /* Report the default cache name. */ defname = krb5_cc_default_name(context); if (defname != NULL) { k5_setmsg(context, KRB5_CC_NOTFOUND, _("No Kerberos credentials available " "(default cache: %s)"), defname); } } return KRB5_CC_NOTFOUND; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_ccache src_cc = NULL; krb5_ccache dst_cc = NULL; krb5_cc_cursor cursor; krb5_principal me = NULL; krb5_creds cred; const char *during; Ticket t; size_t len; int make_kvno_absent = 0; int opt; memset(&cred, 0, sizeof (cred)); during = "init_context"; ret = krb5_init_context(&context); if (ret) goto err; while ((opt = getopt(argc, argv, "c:n")) != -1) { switch (opt) { case 'c': during = "cc_resolve of source ccache"; ret = krb5_cc_resolve(context, optarg, &src_cc); if (ret) goto err; break; case 'n': make_kvno_absent++; break; case 'h': default: fprintf(stderr, "Usage: %s [-n] [-c ccache]\n" "\tThis utility edits a ccache, setting all ticket\n" "\tenc_part kvnos to zero or absent (if -n is set).\n", argv[0]); return 1; } } if (!src_cc) { during = "cc_default"; ret = krb5_cc_default(context, &src_cc); if (ret) goto err; } during = "cc_get_principal"; ret = krb5_cc_get_principal(context, src_cc, &me); if (ret) goto err; if (optind != argc) { fprintf(stderr, "Usage: %s [-n] [-c ccache]\n" "\tThis utility edits a ccache, setting all ticket\n" "\tenc_part kvnos to zero or absent (if -n is set).\n", argv[0]); return 1; } during = "cc_new_unique of temporary ccache"; ret = krb5_cc_new_unique(context, krb5_cc_get_type(context, src_cc), NULL, &dst_cc); during = "cc_initialize of temporary ccache"; ret = krb5_cc_initialize(context, dst_cc, me); if (ret) goto err; during = "cc_start_seq_get"; ret = krb5_cc_start_seq_get(context, src_cc, &cursor); if (ret) goto err; while ((ret = krb5_cc_next_cred(context, src_cc, &cursor, &cred)) == 0) { krb5_data data; during = "decode_Ticket"; memset(&t, 0, sizeof (t)); ret = decode_Ticket(cred.ticket.data, cred.ticket.length, &t, &len); if (ret == ASN1_MISSING_FIELD) continue; if (ret) goto err; if (t.enc_part.kvno) { *t.enc_part.kvno = 0; if (make_kvno_absent) { free(t.enc_part.kvno); t.enc_part.kvno = NULL; } /* * The new Ticket has to need less or same space as before, so * we reuse cred->icket.data. */ during = "encode_Ticket"; ASN1_MALLOC_ENCODE(Ticket, data.data, data.length, &t, &len, ret); if (ret) { free_Ticket(&t); goto err; } krb5_data_free(&cred.ticket); cred.ticket = data; } free_Ticket(&t); during = "cc_store_cred"; ret = krb5_cc_store_cred(context, dst_cc, &cred); if (ret) goto err; krb5_free_cred_contents(context, &cred); memset(&cred, 0, sizeof (cred)); } during = "cc_next_cred"; if (ret != KRB5_CC_END) goto err; during = "cc_end_seq_get"; ret = krb5_cc_end_seq_get(context, src_cc, &cursor); if (ret) goto err; during = "cc_move"; ret = krb5_cc_move(context, dst_cc, src_cc); if (ret) goto err; dst_cc = NULL; during = "cc_switch"; ret = krb5_cc_switch(context, src_cc); if (ret) goto err; err: (void) krb5_free_principal(context, me); if (src_cc) (void) krb5_cc_close(context, src_cc); if (dst_cc) (void) krb5_cc_destroy(context, dst_cc); if (ret) { fprintf(stderr, "Failed while doing %s (%d)\n", during, ret); ret = 1; } return (ret); }
DWORD LwKrb5CopyFromUserCache( krb5_context ctx, krb5_ccache destCC, uid_t uid ) { DWORD dwError = LW_ERROR_SUCCESS; PSTR pszCachePath = NULL; krb5_ccache srcCC = NULL; krb5_cc_cursor srcPos = NULL; krb5_cc_cursor destPos = NULL; // Free with krb5_free_cred_contents krb5_creds srcCreds = {0}; // Free with krb5_free_cred_contents krb5_creds destCreds = {0}; krb5_error_code ret = 0; krb5_principal destClient = 0; BOOLEAN bIncludeTicket = TRUE; DWORD dwTime = 0; ret = krb5_cc_get_principal( ctx, destCC, &destClient); BAIL_ON_KRB_ERROR(ctx, ret); dwError = LwKrb5GetUserCachePath( uid, KRB5_File_Cache, &pszCachePath); BAIL_ON_LW_ERROR(dwError); ret = krb5_cc_resolve( ctx, pszCachePath, &srcCC); BAIL_ON_KRB_ERROR(ctx, ret); ret = krb5_cc_start_seq_get( ctx, srcCC, &srcPos); if (ret == KRB5_FCC_NOFILE) { // The cache file does not exist ret = 0; goto cleanup; } if (ret == KRB5_CC_FORMAT) { // Some other user put a bad cc in place - don't copy anything // from it. ret = 0; goto cleanup; } BAIL_ON_KRB_ERROR(ctx, ret); dwTime = time(NULL); while (1) { krb5_free_cred_contents( ctx, &srcCreds); ret = krb5_cc_next_cred( ctx, srcCC, &srcPos, &srcCreds); if (ret == KRB5_CC_FORMAT) { break; } else if (ret == KRB5_CC_END) { break; } else { BAIL_ON_KRB_ERROR(ctx, ret); } if (!krb5_principal_compare(ctx, destClient, srcCreds.client)) { /* Can't keep these creds. The client principal doesn't * match. */ continue; } if ( srcCreds.times.endtime < dwTime ) { /* Credentials are too old. */ continue; } if (destPos != NULL) { krb5_cc_end_seq_get( ctx, destCC, &destPos); destPos = NULL; } ret = krb5_cc_start_seq_get( ctx, destCC, &destPos); BAIL_ON_KRB_ERROR(ctx, ret); bIncludeTicket = TRUE; while(bIncludeTicket) { krb5_free_cred_contents( ctx, &destCreds); ret = krb5_cc_next_cred( ctx, destCC, &destPos, &destCreds); if (ret == KRB5_CC_END) { break; } else { BAIL_ON_KRB_ERROR(ctx, ret); } if (krb5_principal_compare( ctx, destCreds.server, srcCreds.server)) { /* These credentials are already in the dest cache */ bIncludeTicket = FALSE; } } if (bIncludeTicket) { // These creds can go in the new cache ret = krb5_cc_store_cred(ctx, destCC, &srcCreds); BAIL_ON_KRB_ERROR(ctx, ret); } } cleanup: LW_SAFE_FREE_STRING(pszCachePath); if (ctx != NULL) { if (srcPos != NULL) { krb5_cc_end_seq_get( ctx, srcCC, &srcPos); } if (destPos != NULL) { krb5_cc_end_seq_get( ctx, destCC, &destPos); } if (srcCC != NULL) { krb5_cc_close(ctx, srcCC); } krb5_free_cred_contents(ctx, &srcCreds); krb5_free_cred_contents(ctx, &destCreds); if (destClient != NULL) { krb5_free_principal(ctx, destClient); } } return dwError; error: goto cleanup; }
/* fill in service tickets data */ gboolean ka_get_service_tickets (GtkListStore * tickets, gboolean hide_conf_tickets) { krb5_cc_cursor cursor; krb5_creds creds; krb5_error_code ret; GtkTreeIter iter; krb5_ccache ccache; char *name; krb5_timestamp sec; gchar start_time[128], end_time[128], end_time_markup[256]; gboolean retval = FALSE; gtk_list_store_clear (tickets); krb5_timeofday (kcontext, &sec); ret = krb5_cc_default (kcontext, &ccache); g_return_val_if_fail (!ret, FALSE); ret = krb5_cc_start_seq_get (kcontext, ccache, &cursor); if (ret == KRB5_FCC_NOFILE) { ka_log_error_message_at_level (G_LOG_LEVEL_INFO, "krb5_cc_start_seq_get", kcontext, ret); gtk_list_store_append (tickets, &iter); gtk_list_store_set (tickets, &iter, PRINCIPAL_COLUMN, _("Your ticket cache is currently empty"), FORWARDABLE_COLUMN, FALSE, RENEWABLE_COLUMN, FALSE, PROXIABLE_COLUMN, FALSE, -1); retval = TRUE; goto out; } else if (ret) { goto out; } while ((ret = krb5_cc_next_cred (kcontext, ccache, &cursor, &creds)) == 0) { gboolean renewable, proxiable, forwardable; if (hide_conf_tickets && krb5_is_config_principal (kcontext, creds.server)) { krb5_free_cred_contents (kcontext, &creds); continue; } if (creds.times.starttime) ka_format_time (creds.times.starttime, start_time, sizeof (start_time)); else ka_format_time (creds.times.authtime, start_time, sizeof (start_time)); ka_format_time (creds.times.endtime, end_time, sizeof (end_time)); if (creds.times.endtime > sec) strcpy (end_time_markup, end_time); else g_snprintf (end_time_markup, sizeof (end_time_markup), "%s <span foreground=\"red\" style=\"italic\">(%s)</span>", end_time, _("Expired")); forwardable = get_cred_forwardable (&creds); renewable = get_cred_renewable (&creds); proxiable = get_cred_proxiable (&creds); ret = krb5_unparse_name (kcontext, creds.server, &name); if (!ret) { gtk_list_store_append (tickets, &iter); gtk_list_store_set (tickets, &iter, PRINCIPAL_COLUMN, name, START_TIME_COLUMN, start_time, END_TIME_COLUMN, end_time_markup, FORWARDABLE_COLUMN, forwardable, RENEWABLE_COLUMN, renewable, PROXIABLE_COLUMN, proxiable, -1); free (name); } else ka_log_error_message ("krb5_unparse_name", kcontext, ret); krb5_free_cred_contents (kcontext, &creds); } if (ret != KRB5_CC_END) ka_log_error_message ("krb5_cc_get_next", kcontext, ret); ret = krb5_cc_end_seq_get (kcontext, ccache, &cursor); if (ret) ka_log_error_message ("krb5_cc_end_seq_get", kcontext, ret); retval = TRUE; out: ret = krb5_cc_close (kcontext, ccache); g_return_val_if_fail (!ret, FALSE); return retval; }
/* * Class: sun_security_krb5_Credentials * Method: acquireDefaultNativeCreds * Signature: ()Lsun/security/krb5/Credentials; */ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds (JNIEnv *env, jclass krbcredsClass) { jobject krbCreds = NULL; krb5_error_code err = 0; krb5_ccache ccache = NULL; krb5_cc_cursor cursor = NULL; krb5_creds creds; krb5_flags flags = 0; krb5_context kcontext = NULL; /* Initialize the Kerberos 5 context */ err = krb5_init_context (&kcontext); if (!err) { err = krb5_cc_default (kcontext, &ccache); } if (!err) { err = krb5_cc_set_flags (kcontext, ccache, flags); /* turn off OPENCLOSE */ } if (!err) { err = krb5_cc_start_seq_get (kcontext, ccache, &cursor); } if (!err) { while ((err = krb5_cc_next_cred (kcontext, ccache, &cursor, &creds)) == 0) { char *serverName = NULL; if (!err) { err = krb5_unparse_name (kcontext, creds.server, &serverName); printiferr (err, "while unparsing server name"); } if (!err) { if (strncmp (serverName, "krbtgt", strlen("krbtgt")) == 0) { jobject ticket, clientPrincipal, targetPrincipal, encryptionKey; jobject ticketFlags, startTime, endTime; jobject authTime, renewTillTime, hostAddresses; ticket = clientPrincipal = targetPrincipal = encryptionKey = NULL; ticketFlags = startTime = endTime = NULL; authTime = renewTillTime = hostAddresses = NULL; // For the default credentials we're only interested in the krbtgt server. clientPrincipal = BuildClientPrincipal(env, kcontext, creds.client); if (clientPrincipal == NULL) goto cleanup; targetPrincipal = BuildClientPrincipal(env, kcontext, creds.server); if (targetPrincipal == NULL) goto cleanup; // Build a com.ibm.security.krb5.Ticket ticket = BuildTicket(env, &creds.ticket); if (ticket == NULL) goto cleanup; // Get the encryption key encryptionKey = BuildEncryptionKey(env, &creds.keyblock); if (encryptionKey == NULL) goto cleanup; // and the ticket flags ticketFlags = BuildTicketFlags(env, creds.ticket_flags); if (ticketFlags == NULL) goto cleanup; // Get the timestamps out. startTime = BuildKerberosTime(env, creds.times.starttime); if (startTime == NULL) goto cleanup; authTime = BuildKerberosTime(env, creds.times.authtime); if (authTime == NULL) goto cleanup; endTime = BuildKerberosTime(env, creds.times.endtime); if (endTime == NULL) goto cleanup; renewTillTime = BuildKerberosTime(env, creds.times.renew_till); if (renewTillTime == NULL) goto cleanup; // Create the addresses object. hostAddresses = BuildAddressList(env, creds.addresses); if (krbcredsConstructor == 0) { krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>", "(Lsun/security/krb5/internal/Ticket;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/EncryptionKey;Lsun/security/krb5/internal/TicketFlags;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/HostAddresses;)V"); if (krbcredsConstructor == 0) { printf("Couldn't find com.ibm.security.krb5.Credentials constructor\n"); break; } } // and now go build a KrbCreds object krbCreds = (*env)->NewObject( env, krbcredsClass, krbcredsConstructor, ticket, clientPrincipal, targetPrincipal, encryptionKey, ticketFlags, authTime, startTime, endTime, renewTillTime, hostAddresses); cleanup: if (ticket) (*env)->DeleteLocalRef(env, ticket); if (clientPrincipal) (*env)->DeleteLocalRef(env, clientPrincipal); if (targetPrincipal) (*env)->DeleteLocalRef(env, targetPrincipal); if (encryptionKey) (*env)->DeleteLocalRef(env, encryptionKey); if (ticketFlags) (*env)->DeleteLocalRef(env, ticketFlags); if (authTime) (*env)->DeleteLocalRef(env, authTime); if (startTime) (*env)->DeleteLocalRef(env, startTime); if (endTime) (*env)->DeleteLocalRef(env, endTime); if (renewTillTime) (*env)->DeleteLocalRef(env, renewTillTime); if (hostAddresses) (*env)->DeleteLocalRef(env, hostAddresses); } } if (serverName != NULL) { krb5_free_unparsed_name (kcontext, serverName); } krb5_free_cred_contents (kcontext, &creds); } if (err == KRB5_CC_END) { err = 0; } printiferr (err, "while retrieving a ticket"); } if (!err) { err = krb5_cc_end_seq_get (kcontext, ccache, &cursor); printiferr (err, "while finishing ticket retrieval"); } if (!err) { flags = KRB5_TC_OPENCLOSE; /* restore OPENCLOSE mode */ err = krb5_cc_set_flags (kcontext, ccache, flags); printiferr (err, "while finishing ticket retrieval"); } krb5_free_context (kcontext); return krbCreds; }
int main(int argc, const char **argv) { poptContext poptContext; int poptResult; uid_t uid; int kq; HANDLE lsaConnection = (HANDLE) NULL; PVOID pUserInfo = NULL; struct kevent event = { 0 }; int numChanges = 1; krb5_context krb5Context = NULL; char krb5FileCachePath[PATH_MAX]; krb5_ccache krb5FileCache = NULL; krb5_ccache krb5MemoryCache = NULL; krb5_cc_cursor krb5Cursor = NULL; krb5_creds krb5Credentials = { 0 }; krb5_principal krb5Principal = NULL; krb5_error_code krb5Error; int exitStatus = 0; DWORD dwError = LW_ERROR_SUCCESS; poptContext = poptGetContext(NULL, argc, argv, Options, 0); while ((poptResult = poptGetNextOpt(poptContext)) >= 0) { /* All options are processed automatically. */ } if (poptResult < -1) { fprintf(stderr, "%s: %s: %s\n", getprogname(), poptBadOption(poptContext, POPT_BADOPTION_NOALIAS), poptStrerror(poptResult)); exitStatus = 1; goto error; } uid = getuid(); /* Make sure we're running as an AD user. */ dwError = LsaOpenServer(&lsaConnection); BAIL_ON_LSA_ERROR(dwError); dwError = LsaFindUserById( lsaConnection, uid, 0, &pUserInfo); if (dwError == LW_ERROR_NO_SUCH_USER) { /* * Running as a non-AD user; exit 0 so launchd doesn't restart * the ticketcopy program (see com.beyondtrust.pbis.ticketcopy.plist). */ LSA_LOG_DEBUG( "uid %lu is not an AD user; exiting", (unsigned long) uid); dwError = LW_ERROR_SUCCESS; goto cleanup; } BAIL_ON_LSA_ERROR(dwError); kq = kqueue(); BAIL_ON_UNIX_ERROR(kq == -1); krb5Error = krb5_init_context(&krb5Context); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); krb5Error = krb5_cc_default(krb5Context, &krb5MemoryCache); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); snprintf( krb5FileCachePath, sizeof(krb5FileCachePath), "FILE:/tmp/krb5cc_%lu", (unsigned long) uid); while (1) /* Forever (or until an error occurs) */ { while ((event.ident = open(krb5FileCachePath + 5, O_RDONLY)) == -1) { sleep(5); } event.filter = EVFILT_VNODE; event.flags = EV_ADD | EV_ENABLE | EV_CLEAR; event.fflags = NOTE_DELETE | NOTE_WRITE; numChanges = 1; krb5Error = krb5_cc_resolve( krb5Context, krb5FileCachePath, &krb5FileCache); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); while (1) /* While the file continues to exist. */ { /* * Turn off KRB5_TC_OPENCLOSE so the file will be opened once * and kept open. This causes it to actually attempt to open * the file, so this is where we check for the file not * existing and retry after sleeping a bit. */ krb5Error = krb5_cc_set_flags(krb5Context, krb5FileCache, 0); if (krb5Error == KRB5_FCC_NOFILE) { break; } BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); /* Copy all credentials from the file to the memory cache. */ krb5Error = krb5_cc_start_seq_get( krb5Context, krb5FileCache, &krb5Cursor); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); while ((krb5Error = krb5_cc_next_cred( krb5Context, krb5FileCache, &krb5Cursor, &krb5Credentials)) == 0) { krb5Error = krb5_cc_store_cred( krb5Context, krb5MemoryCache, &krb5Credentials); if (krb5Error == KRB5_FCC_NOFILE) { krb5Error = krb5_cc_get_principal( krb5Context, krb5FileCache, &krb5Principal); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); /* The memory cache was destroyed; re-create it. */ krb5Error = krb5_cc_initialize( krb5Context, krb5MemoryCache, krb5Principal); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); krb5_free_principal(krb5Context, krb5Principal); krb5Principal = NULL; krb5Error = krb5_cc_store_cred( krb5Context, krb5MemoryCache, &krb5Credentials); } BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); krb5_free_cred_contents(krb5Context, &krb5Credentials); } if (krb5Error != KRB5_CC_END) { BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); } krb5Error = krb5_cc_end_seq_get( krb5Context, krb5FileCache, &krb5Cursor); krb5Cursor = NULL; BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); /* * Turn KRB5_TC_OPENCLOSE back on; this will cause * the file to be closed and any locks to be * released. */ krb5Error = krb5_cc_set_flags( krb5Context, krb5FileCache, KRB5_TC_OPENCLOSE); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); /* * Wait for the file to be modified or deleted. The first * time this is called after the file is opened, numChanges * will be 1, which will install the fd into the event * list. After that numChanges is changed to 0, so it will * just report events from the existing list. */ if (kevent(kq, &event, numChanges, &event, 1, NULL) != 1) { fprintf(stderr, "kevent failed\n"); exitStatus = 1; goto cleanup; } if (event.fflags & NOTE_DELETE) { break; } numChanges = 0; } krb5Error = krb5_cc_close(krb5Context, krb5FileCache); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); krb5FileCache = NULL; close(event.ident); event.ident = -1; /* * The cache file is usually removed as part of a * rename(2) system call, so only wait a short * time before the first attempt to re-open it. */ usleep(100000); } error: cleanup: krb5_free_cred_contents(krb5Context, &krb5Credentials); if (krb5Cursor) { krb5_cc_end_seq_get(krb5Context, krb5FileCache, &krb5Cursor); } if (krb5FileCache) { krb5_cc_close(krb5Context, krb5FileCache); } if (krb5Principal) { krb5_free_principal(krb5Context, krb5Principal); } if (krb5Context) { krb5_free_context(krb5Context); } if (event.ident != -1) { close(event.ident); } if (pUserInfo) { LsaFreeUserInfo(0, pUserInfo); } if (lsaConnection != (HANDLE) NULL) { LsaCloseServer(lsaConnection); } if (dwError) { exitStatus = 1; } return exitStatus; }