#include "stdafx.h"
#include "lglobals.h"
#include "krb5.h"
static void
FreeTicketList(TicketList** ticketList)
{
TicketList* tempList = *ticketList, *killList;
while (tempList) {
killList = tempList;
tempList = tempList->next;
free(killList->service);
if (killList->encTypes)
free(killList->encTypes);
free(killList);
}
*ticketList = NULL;
}
void
LeashKRB5FreeTicketInfo(TICKETINFO *ticketinfo)
{
if (ticketinfo->principal) {
free(ticketinfo->principal);
ticketinfo->principal = NULL;
}
if (ticketinfo->ccache_name) {
pkrb5_free_string(NULL, ticketinfo->ccache_name);
ticketinfo->ccache_name = NULL;
}
if (ticketinfo->ticket_list)
FreeTicketList(&ticketinfo->ticket_list);
}
void
LeashKRB5FreeTickets(TICKETINFO **ticketinfolist)
{
TICKETINFO *ticketinfo = *ticketinfolist, *next;
while (ticketinfo) {
next = ticketinfo->next;
LeashKRB5FreeTicketInfo(ticketinfo);
free(ticketinfo);
ticketinfo = next;
}
*ticketinfolist = NULL;
}
/*
* LeashKRB5Error()
*/
int
LeashKRB5Error(krb5_error_code rc, LPCSTR FailedFunctionName)
{
#ifdef USE_MESSAGE_BOX
char message[256];
const char *errText;
errText = perror_message(rc);
_snprintf(message, sizeof(message),
"%s\n(Kerberos error %ld)\n\n%s failed",
errText,
rc,
FailedFunctionName);
message[sizeof(message)-1] = 0;
MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
MB_TASKMODAL |
MB_SETFOREGROUND);
#endif /* USE_MESSAGE_BOX */
return rc;
}
static char *
etype_string(krb5_enctype enctype)
{
static char buf[100];
krb5_error_code retval;
if ((retval = pkrb5_enctype_to_name(enctype, FALSE, buf, sizeof(buf)))) {
/* XXX if there's an error != EINVAL, I should probably report it */
sprintf_s(buf, "etype %d", enctype);
}
return buf;
}
static void
CredToTicketInfo(krb5_creds KRBv5Credentials, TICKETINFO *ticketinfo)
{
ticketinfo->issued = (DWORD)KRBv5Credentials.times.starttime;
ticketinfo->valid_until = (DWORD)KRBv5Credentials.times.endtime;
ticketinfo->renew_until = KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE ?
(DWORD)KRBv5Credentials.times.renew_till : (DWORD)0;
_tzset();
if ( ticketinfo->valid_until - time(0) <= 0L )
ticketinfo->btickets = EXPD_TICKETS;
else
ticketinfo->btickets = GOOD_TICKETS;
}
static int
CredToTicketList(krb5_context ctx, krb5_creds KRBv5Credentials,
char *PrincipalName, TicketList ***ticketListTail)
{
krb5_error_code code = 0;
krb5_ticket *tkt=NULL;
char *sServerName = NULL;
char Buffer[256];
char *functionName = NULL;
TicketList *list = NULL;
functionName = "krb5_unparse_name()";
code = (*pkrb5_unparse_name)(ctx, KRBv5Credentials.server, &sServerName);
if (code)
goto cleanup;
if (!KRBv5Credentials.times.starttime)
KRBv5Credentials.times.starttime = KRBv5Credentials.times.authtime;
memset(Buffer, '\0', sizeof(Buffer));
// @fixme: calloc for ptr init
list = (TicketList *)calloc(1, sizeof(TicketList));
if (!list) {
code = ENOMEM;
functionName = "calloc()";
goto cleanup;
}
list->service = strdup(sServerName);
if (!list->service) {
code = ENOMEM;
functionName = "calloc()";
goto cleanup;
}
list->issued = (DWORD)KRBv5Credentials.times.starttime;
list->valid_until = (DWORD)KRBv5Credentials.times.endtime;
if (KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE)
list->renew_until = (DWORD)KRBv5Credentials.times.renew_till;
else
list->renew_until = 0;
if (!pkrb5_decode_ticket(&KRBv5Credentials.ticket, &tkt)) {
wsprintf(Buffer, "Session Key: %s Ticket: %s",
etype_string(KRBv5Credentials.keyblock.enctype),
etype_string(tkt->enc_part.enctype));
pkrb5_free_ticket(ctx, tkt);
tkt = NULL;
} else {
wsprintf(Buffer, "Session Key: %s",
etype_string(KRBv5Credentials.keyblock.enctype));
}
list->encTypes = (char *)calloc(1, strlen(Buffer)+1);
if (!list->encTypes) {
functionName = "calloc()";
code = ENOMEM;
goto cleanup;
}
strcpy(list->encTypes, Buffer);
list->flags = KRBv5Credentials.ticket_flags;
cleanup:
if (code) {
LeashKRB5Error(code, functionName);
if (list)
FreeTicketList(&list);
} else {
**ticketListTail = list;
*ticketListTail = &list->next;
}
if (sServerName != NULL)
(*pkrb5_free_unparsed_name)(ctx, sServerName);
return code;
}
// return 0 if ticketinfo was successfully appended to list, 1 otherwise
int
do_ccache(krb5_context ctx,
krb5_ccache cache,
TICKETINFO **ticketInfoTail)
{
krb5_cc_cursor cur;
krb5_creds creds;
krb5_principal princ = NULL;
krb5_flags flags;
krb5_error_code code;
char *defname = NULL;
char *functionName = NULL;
TicketList **ticketListTail;
TICKETINFO *ticketinfo = NULL;
int retval = 1;
// Don't need the actual ticket.
flags = KRB5_TC_NOTICKET;
code = pkrb5_cc_set_flags(ctx, cache, flags);
if (code) {
if (code == KRB5_FCC_NOFILE || code == KRB5_CC_NOTFOUND) {
// Normal behavior; skip cache but suppress error message box
code = 0;
} else {
functionName = "krb5_cc_set_flags";
}
goto cleanup;
}
code = pkrb5_cc_get_principal(ctx, cache, &princ);
if (code) {
// Normal behavior; skip cache but suppress error message box
code = 0;
goto cleanup;
}
code = pkrb5_unparse_name(ctx, princ, &defname);
if (code) {
functionName = "krb5_unparse_name";
goto cleanup;
}
code = pkrb5_cc_start_seq_get(ctx, cache, &cur);
if (code) {
// MSLSA errors here if no TGT is found; suppress error message box
code = 0;
goto cleanup;
}
if (*ticketInfoTail)
ticketinfo = *ticketInfoTail;
else
// @fixme: calloc to init pointers
ticketinfo = (TICKETINFO *)calloc(1, sizeof(TICKETINFO));
if (ticketinfo == NULL) {
functionName = "calloc";
code = ENOMEM;
goto cleanup;
}
ticketinfo->next = NULL;
ticketinfo->ticket_list = NULL;
ticketinfo->principal = strdup(defname);
if (ticketinfo->principal == NULL) {
functionName = "strdup";
code = ENOMEM;
goto cleanup;
}
code = pkrb5_cc_get_full_name(ctx, cache, &ticketinfo->ccache_name);
if (code) {
functionName = "krb5_cc_get_full_name";
goto cleanup;
}
*ticketInfoTail = ticketinfo;
ticketListTail = &ticketinfo->ticket_list;
while (!(code = pkrb5_cc_next_cred(ctx, cache, &cur, &creds))) {
if (!pkrb5_is_config_principal(ctx, creds.server)) {
CredToTicketList(ctx, creds, defname, &ticketListTail);
CredToTicketInfo(creds, ticketinfo);
}
pkrb5_free_cred_contents(ctx, &creds);
}
if (code == KRB5_CC_END) {
code = pkrb5_cc_end_seq_get(ctx, cache, &cur);
if (code) {
functionName = "krb5_cc_end_seq_get";
goto cleanup;
}
flags = 0;
code = pkrb5_cc_set_flags(ctx, cache, flags);
if (code) {
functionName = "krb5_cc_set_flags";
goto cleanup;
}
} else {
functionName = "krb5_cc_next_cred";
goto cleanup;
}
cleanup:
if (code)
LeashKRB5Error(code, functionName);
if (ticketinfo) {
if (ticketinfo == *ticketInfoTail)
retval = 0;
else
LeashKRB5FreeTickets(&ticketinfo);
}
if (defname)
pkrb5_free_unparsed_name(ctx, defname);
if (princ)
pkrb5_free_principal(ctx, princ);
return retval;
}
//
// Returns 0 for success, 1 for failure
//
int
do_all_ccaches(krb5_context ctx, TICKETINFO **ticketinfotail)
{
krb5_error_code code;
krb5_ccache cache;
krb5_cccol_cursor cursor;
int retval = 1;
char *functionName = NULL;
code = pkrb5_cccol_cursor_new(ctx, &cursor);
if (code) {
functionName = "krb5_cccol_cursor_new";
goto cleanup;
}
retval = 0;
while (!(code = pkrb5_cccol_cursor_next(ctx, cursor, &cache)) &&
cache != NULL) {
// Note that ticketinfotail will be updated here to point to the tail
// of the list but the caller of this function will remain with a
// pointer to the head.
if (do_ccache(ctx, cache, ticketinfotail) == 0)
ticketinfotail = &((*ticketinfotail)->next);
pkrb5_cc_close(ctx, cache);
}
if (code)
functionName = "krb5_cccol_cursor_next";
pkrb5_cccol_cursor_free(ctx, &cursor);
cleanup:
if (code)
LeashKRB5Error(code, functionName);
return retval;
}
void
LeashKRB5ListDefaultTickets(TICKETINFO *ticketinfo)
{
krb5_error_code code;
krb5_context ctx = 0;
krb5_ccache cache = 0;
char *functionName = NULL;
ticketinfo->btickets = NO_TICKETS;
ticketinfo->principal = NULL;
ticketinfo->ccache_name = NULL;
ticketinfo->next = NULL;
ticketinfo->ticket_list = NULL;
ticketinfo->renew_until = 0;
ticketinfo->valid_until = 0;
ticketinfo->issued = 0;
code = pkrb5_init_context(&ctx);
if (code) {
functionName = "krb5_init_context";
goto cleanup;
}
code = pkrb5_cc_default(ctx, &cache);
if (code) {
functionName = "krb5_cc_default";
goto cleanup;
}
if (cache != NULL)
do_ccache(ctx, cache, &ticketinfo);
cleanup:
if (code)
LeashKRB5Error(code, functionName);
if (cache)
pkrb5_cc_close(ctx, cache);
if (ctx)
pkrb5_free_context(ctx);
}
/*
* LeashKRB5ListAllTickets()
*/
void
LeashKRB5ListAllTickets(TICKETINFO **ticketinfo)
{
krb5_error_code code;
krb5_context ctx = 0;
char *functionName = NULL;
code = pkrb5_init_context(&ctx);
if (code) {
functionName = "krb5_init_context";
goto cleanup;
}
do_all_ccaches(ctx, ticketinfo);
cleanup:
if (code)
LeashKRB5Error(code, functionName);
if (ctx)
pkrb5_free_context(ctx);
}