krb5 commit: Fix leashdll code to search for existing tickets
Benjamin Kaduk
kaduk at MIT.EDU
Mon Aug 27 11:52:09 EDT 2012
https://github.com/krb5/krb5/commit/0fa2c69633bfcb6c10e50c25c8e7802e7b060d8c
commit 0fa2c69633bfcb6c10e50c25c8e7802e7b060d8c
Author: Kevin Wasserman <kevin.wasserman at painless-security.com>
Date: Tue Jul 17 13:17:46 2012 -0400
Fix leashdll code to search for existing tickets
When we have a desired principal, search the entire credential cache
collection for existing tickets for that principal before using a prompter.
If no principal is specified, check only the default cache.
Signed-off-by: Kevin Wasserman <kevin.wasserman at painless-security.com>
ticket: 7278 (new)
queue: kfw
target_version: 1.10.4
tags: pullup
src/windows/leashdll/lshfunc.c | 395 ++++++++++++----------------------------
1 files changed, 120 insertions(+), 275 deletions(-)
diff --git a/src/windows/leashdll/lshfunc.c b/src/windows/leashdll/lshfunc.c
index bc86634..90fb4b3 100644
--- a/src/windows/leashdll/lshfunc.c
+++ b/src/windows/leashdll/lshfunc.c
@@ -2878,17 +2878,121 @@ acquire_tkt_send_msg(krb5_context ctx, const char * title,
return 0;
}
+static BOOL cc_have_tickets(krb5_context ctx, krb5_ccache cache)
+{
+ krb5_cc_cursor cur = NULL;
+ krb5_creds creds;
+ krb5_flags flags;
+ krb5_error_code code;
+ BOOL have_tickets = FALSE;
+
+ // Don't need the actual ticket, also turns off OPENCLOSE mode
+ flags = KRB5_TC_NOTICKET;
+ code = pkrb5_cc_set_flags(ctx, cache, flags);
+ if (code)
+ goto cleanup;
+ code = pkrb5_cc_start_seq_get(ctx, cache, &cur);
+ if (code)
+ goto cleanup;
+
+ _tzset();
+ while (!(code = pkrb5_cc_next_cred(ctx, cache, &cur, &creds))) {
+ if ((!pkrb5_is_config_principal(ctx, creds.server)) &&
+ (creds.times.endtime - time(0) > 0))
+ have_tickets = TRUE;
+
+ pkrb5_free_cred_contents(ctx, &creds);
+ }
+ if (code == KRB5_CC_END) {
+ code = pkrb5_cc_end_seq_get(ctx, cache, &cur);
+ if (code)
+ goto cleanup;
+ flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */
+ code = pkrb5_cc_set_flags(ctx, cache, flags);
+ if (code)
+ goto cleanup;
+ }
+cleanup:
+ return have_tickets;
+}
+
+static BOOL
+cc_have_tickets_for_princ(krb5_context ctx,
+ krb5_ccache cache,
+ krb5_principal princ)
+{
+ krb5_error_code code;
+ krb5_principal cc_princ = NULL;
+ BOOL have_tickets = FALSE;
+ code = pkrb5_cc_get_principal(ctx, cache, &cc_princ);
+ if (code)
+ goto cleanup;
+
+ if (pkrb5_principal_compare(ctx, princ, cc_princ))
+ have_tickets = cc_have_tickets(ctx, cache);
+
+cleanup:
+ if (cc_princ != NULL)
+ pkrb5_free_principal(ctx, cc_princ);
+ return have_tickets;
+}
+
+static BOOL cc_default_have_tickets(krb5_context ctx)
+{
+ krb5_ccache cache = NULL;
+ BOOL have_tickets = FALSE;
+ if (pkrb5_cc_default(ctx, &cache) == 0)
+ have_tickets = cc_have_tickets(ctx, cache);
+ if (cache != NULL)
+ pkrb5_cc_close(ctx, cache);
+ return have_tickets;
+}
+
+static BOOL
+cccol_have_tickets_for_princ(krb5_context ctx,
+ krb5_principal princ,
+ char *ccname,
+ int cclen)
+{
+ krb5_error_code code;
+ krb5_ccache cache;
+ krb5_cccol_cursor cursor;
+ BOOL have_tickets = FALSE;
+ char *ccfullname;
+
+ code = pkrb5_cccol_cursor_new(ctx, &cursor);
+ if (code)
+ goto cleanup;
+
+ while (!have_tickets &&
+ !(code = pkrb5_cccol_cursor_next(ctx, cursor, &cache)) &&
+ cache != NULL) {
+ if (cc_have_tickets_for_princ(ctx, cache, princ)) {
+ if (pkrb5_cc_get_full_name(ctx, cache, &ccfullname)==0) {
+ strcpy_s(ccname, cclen, ccfullname);
+ pkrb5_free_string(ctx, ccfullname);
+ have_tickets = TRUE;
+ }
+ }
+ pkrb5_cc_close(ctx, cache);
+ }
+ pkrb5_cccol_cursor_free(ctx, &cursor);
+cleanup:
+
+ return have_tickets;
+}
+
static void
acquire_tkt_no_princ(krb5_context context, char * ccname, int cclen)
{
TicketList *list = NULL;
- TICKETINFO ticketinfo;
krb5_context ctx;
DWORD dwMsLsaImport = Leash_get_default_mslsa_import();
DWORD gle;
char ccachename[272]="";
char loginenv[16];
BOOL prompt;
+ BOOL haveTickets;
GetEnvironmentVariable("KERBEROSLOGIN_NEVER_PROMPT", loginenv, sizeof(loginenv));
prompt = (GetLastError() == ERROR_ENVVAR_NOT_FOUND);
@@ -2904,10 +3008,9 @@ acquire_tkt_no_princ(krb5_context context, char * ccname, int cclen)
GetEnvironmentVariable("KRB5CCNAME", ccachename, sizeof(ccachename));
}
- not_an_API_LeashKRB5GetTickets(&ticketinfo,&ctx);
-
- if ( ticketinfo.btickets != GOOD_TICKETS &&
- dwMsLsaImport && Leash_importable() ) {
+ haveTickets = cc_default_have_tickets(ctx);
+ if ((!haveTickets) &&
+ dwMsLsaImport && Leash_importable() ) {
// We have the option of importing tickets from the MSLSA
// but should we? Do the tickets in the MSLSA cache belong
// to the default realm used by Leash? Does the default
@@ -2968,13 +3071,11 @@ acquire_tkt_no_princ(krb5_context context, char * ccname, int cclen)
if ( import ) {
Leash_import();
-
- not_an_API_LeashKRB5FreeTickets(&ticketinfo);
- not_an_API_LeashKRB5GetTickets(&ticketinfo,&ctx);
+ haveTickets = cc_default_have_tickets(ctx);
}
}
- if ( prompt && ticketinfo.btickets != GOOD_TICKETS ) {
+ if ( prompt && !haveTickets ) {
acquire_tkt_send_msg(ctx, NULL, ccachename, NULL, ccname, cclen);
/*
* If the ticket manager returned an alternative credential cache
@@ -2988,313 +3089,57 @@ acquire_tkt_no_princ(krb5_context context, char * ccname, int cclen)
strncpy(ccname, ccachename, cclen);
ccname[cclen-1] = '\0';
}
- not_an_API_LeashKRB5FreeTickets(&ticketinfo);
if ( !context )
pkrb5_free_context(ctx);
}
static void
-acquire_tkt_for_princ(krb5_context context, krb5_principal desiredPrincipal,
+acquire_tkt_for_princ(krb5_context ctx, krb5_principal desiredPrincipal,
char * ccname, int cclen)
{
- TICKETINFO ticketinfo;
- krb5_context ctx;
- DWORD dwMsLsaImport = Leash_get_default_mslsa_import();
DWORD gle;
char ccachename[272]="";
char loginenv[16];
BOOL prompt;
- char *name = NULL;
GetEnvironmentVariable("KERBEROSLOGIN_NEVER_PROMPT", loginenv, sizeof(loginenv));
prompt = (GetLastError() == ERROR_ENVVAR_NOT_FOUND);
- ctx = context;
-
SetLastError(0);
GetEnvironmentVariable("KRB5CCNAME", ccachename, sizeof(ccachename));
gle = GetLastError();
- if ( ((gle == ERROR_ENVVAR_NOT_FOUND) || !ccachename[0]) && context ) {
+ if ((gle == ERROR_ENVVAR_NOT_FOUND || !ccachename[0]) && ctx != NULL) {
const char * ccdef = pkrb5_cc_default_name(ctx);
SetEnvironmentVariable("KRB5CCNAME", ccdef ? ccdef : NULL);
GetEnvironmentVariable("KRB5CCNAME", ccachename, sizeof(ccachename));
}
-
- not_an_API_LeashKRB5GetTickets(&ticketinfo,&ctx);
-
- pkrb5_unparse_name(ctx, desiredPrincipal, &name);
-
- if ( ticketinfo.btickets != GOOD_TICKETS &&
- dwMsLsaImport && Leash_importable() ) {
- // We have the option of importing tickets from the MSLSA
- // but should we? Does the MSLSA principal match the requested
- // principal? If not, there is no benefit to importing.
- int import = 0;
- krb5_error_code code;
- krb5_ccache mslsa_ccache=NULL;
- krb5_principal princ = NULL;
-
- if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache))
- goto cleanup;
-
- if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ))
- goto cleanup;
-
- import = pkrb5_principal_compare(ctx, desiredPrincipal, princ);
-
- cleanup:
- if (princ)
- pkrb5_free_principal(ctx, princ);
-
- if (mslsa_ccache)
- pkrb5_cc_close(ctx, mslsa_ccache);
-
-
- if ( import ) {
- /* Construct a new default ccache name into which the MSLSA:
- * credentials can be imported, set the default ccache to that
- * ccache, and then only import if that ccache does not already
- * contain valid tickets */
- sprintf(ccachename, "API:%s", name);
-
- SetEnvironmentVariable("KRB5CCNAME", ccachename);
-
- not_an_API_LeashKRB5FreeTickets(&ticketinfo);
- not_an_API_LeashKRB5GetTickets(&ticketinfo,&ctx);
-
- if (ticketinfo.btickets != GOOD_TICKETS) {
- Leash_import();
-
- not_an_API_LeashKRB5FreeTickets(&ticketinfo);
- not_an_API_LeashKRB5GetTickets(&ticketinfo,&ctx);
- }
- }
- }
-
- if (prompt) {
- if (ticketinfo.btickets != GOOD_TICKETS || strcmp(name,ticketinfo.principal)) {
- acquire_tkt_send_msg(ctx, NULL, ccachename, desiredPrincipal, ccname, cclen);
+ if (!cccol_have_tickets_for_princ(ctx, desiredPrincipal, ccname, cclen)) {
+ if (prompt) {
+ acquire_tkt_send_msg(ctx, NULL,
+ ccachename, desiredPrincipal, ccname, cclen);
/*
* If the ticket manager returned an alternative credential cache
* remember it as the default for this process.
*/
- if ( ccname && ccname[0] && strcmp(ccachename,ccname) ) {
+ if (ccname != NULL && ccname[0] &&
+ strcmp(ccachename, ccname)) {
SetEnvironmentVariable("KRB5CCNAME",ccname);
}
- } else if (ccachename[0] && ccname) {
- strncpy(ccname, ccachename, cclen);
- ccname[cclen-1] = '\0';
- }
- }
- not_an_API_LeashKRB5FreeTickets(&ticketinfo);
-
- if (name)
- pkrb5_free_unparsed_name(ctx, name);
-
- if ( !context )
- pkrb5_free_context(ctx);
-}
-
-
-static int
-leash_int_get_princ_expiration_time(krb5_context ctx, krb5_ccache cc,
- krb5_principal desiredPrincipal,
- krb5_timestamp * pexpiration)
-{
- krb5_principal principal = 0;
- char * princ_name = NULL;
- char * desired_name = NULL;
- krb5_creds creds;
- krb5_error_code code, code2;
- krb5_error_code cc_code;
- krb5_cc_cursor cur;
- krb5_timestamp now, expiration = 0;
-
- int rv = -1;
-
- if (!ctx || !cc || !desiredPrincipal || !pexpiration)
- return -1;
-
- code = pkrb5_cc_get_principal(ctx, cc, &principal);
- if ( code )
- return -1;
-
-
- code = pkrb5_unparse_name(ctx, desiredPrincipal, &desired_name);
- code2 = pkrb5_unparse_name(ctx, principal, &princ_name);
-
- /* compare principal to ident. */
- if ( code || !princ_name || code2 || !desired_name ||
- strcmp(princ_name, desired_name) ) {
- if (princ_name)
- pkrb5_free_unparsed_name(ctx, princ_name);
- if (desired_name)
- pkrb5_free_unparsed_name(ctx, desired_name);
- pkrb5_free_principal(ctx, principal);
- return -1;
- }
-
- pkrb5_free_unparsed_name(ctx, princ_name);
- pkrb5_free_unparsed_name(ctx, desired_name);
- pkrb5_free_principal(ctx, principal);
-
- code = pkrb5_timeofday(ctx, &now);
-
- if (code)
- return -1;
-
- cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur);
-
- while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) {
- krb5_data * c0 = krb5_princ_name(ctx, creds.server);
- krb5_data * c1 = krb5_princ_component(ctx, creds.server, 1);
- krb5_data * r = krb5_princ_realm(ctx, creds.server);
-
- if ( c0 && c1 && r && c1->length == r->length &&
- !strncmp(c1->data,r->data,r->length) &&
- !strncmp("krbtgt",c0->data,c0->length) ) {
-
- /* we have a TGT, check for the expiration time.
- * if it is valid and renewable, use the renew time
- */
-
- if (!(creds.ticket_flags & TKT_FLG_INVALID) &&
- creds.times.starttime < now && creds.times.endtime > now) {
- expiration = creds.times.endtime;
-
- if ((creds.ticket_flags & TKT_FLG_RENEWABLE) &&
- (creds.times.renew_till > creds.times.endtime)) {
- expiration = creds.times.renew_till;
- }
- }
}
- }
-
- if (cc_code == KRB5_CC_END) {
- cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur);
- rv = 0;
- *pexpiration = expiration;
- }
-
- return rv;
-}
-
-/* returns 0 on success */
-static int
-leash_int_find_ccache_for_princ(krb5_context ctx, krb5_principal princ,
- char * buffer, int * pcbbuf)
-{
- krb5_ccache cache = 0;
- krb5_error_code code;
- apiCB * cc_ctx = 0;
- struct _infoNC ** pNCi = NULL;
- int i;
- krb5_timestamp expiration = 0;
- krb5_timestamp best_match_expiration = 0;
- char best_match_ccname[256] = "";
- DWORD dwMsLsaImport = Leash_get_default_mslsa_import();
-
- if (!buffer || !pcbbuf)
- return -1;
-
- code = cc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
- if (code)
- goto _exit;
-
- code = cc_get_NC_info(cc_ctx, &pNCi);
- if (code)
- goto _exit;
-
- for(i=0; pNCi[i]; i++) {
- if (pNCi[i]->vers != CC_CRED_V5)
- continue;
-
- code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cache);
- if (code)
- continue;
-
- /* need a function to check the cache for the identity
- * and determine if it has valid tickets. If it has
- * the right identity and valid tickets, store the
- * expiration time and the cache name. If it has the
- * right identity but no valid tickets, store the ccache
- * name and an expiration time of zero. if it does not
- * have the right identity don't save the name.
- *
- * Keep searching to find the best cache available.
- */
-
- if (!leash_int_get_princ_expiration_time(ctx, cache, princ,
- &expiration)) {
- if ( expiration > best_match_expiration ) {
- best_match_expiration = expiration;
- strncpy(best_match_ccname, "API:",
- sizeof(best_match_ccname));
- strncat(best_match_ccname, pNCi[i]->name,
- sizeof(best_match_ccname));
- best_match_ccname[sizeof(best_match_ccname)-1] = '\0';
- expiration = 0;
- }
- }
-
- if(ctx != NULL && cache != NULL)
- pkrb5_cc_close(ctx, cache);
- cache = 0;
- }
-
- if (dwMsLsaImport) {
- code = pkrb5_cc_resolve(ctx, "MSLSA:", &cache);
- if (code == 0 && cache) {
- if (!leash_int_get_princ_expiration_time(ctx, cache, princ,
- &expiration)) {
- if ( expiration > best_match_expiration ) {
- best_match_expiration = expiration;
- strcpy(best_match_ccname, "MSLSA:");
- expiration = 0;
- }
- }
}
- }
-
- if (ctx != NULL && cache != NULL)
- pkrb5_cc_close(ctx, cache);
-
- cache = 0;
-
- _exit:
- if (pNCi)
- cc_free_NC_info(cc_ctx, &pNCi);
-
- if (cc_ctx)
- cc_shutdown(&cc_ctx);
-
- if (best_match_ccname[0]) {
- strncpy(buffer, best_match_ccname, *pcbbuf);
- buffer[*pcbbuf-1]='\0';
-
- *pcbbuf = strlen(buffer) + 1;
- return 0;
- }
-
- return -1;
}
+
void FAR
not_an_API_Leash_AcquireInitialTicketsIfNeeded(krb5_context context,
krb5_principal desiredKrb5Principal,
char * ccname, int cclen)
{
- char *desiredName = 0;
- char *desiredRealm = 0;
- TicketList *list = NULL;
- char ccachename[272]="";
-
if (!desiredKrb5Principal) {
acquire_tkt_no_princ(context, ccname, cclen);
} else {
- if (leash_int_find_ccache_for_princ(context, desiredKrb5Principal, ccname, &cclen))
- acquire_tkt_for_princ(context, desiredKrb5Principal, ccname, cclen);
+ acquire_tkt_for_princ(context, desiredKrb5Principal, ccname, cclen);
}
return;
}
More information about the cvs-krb5
mailing list