summaryrefslogtreecommitdiffstats
path: root/src/windows/leash/KrbListTickets.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/leash/KrbListTickets.cpp')
-rw-r--r--src/windows/leash/KrbListTickets.cpp393
1 files changed, 393 insertions, 0 deletions
diff --git a/src/windows/leash/KrbListTickets.cpp b/src/windows/leash/KrbListTickets.cpp
new file mode 100644
index 0000000000..71a4c635cc
--- /dev/null
+++ b/src/windows/leash/KrbListTickets.cpp
@@ -0,0 +1,393 @@
+#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) {
+ free(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 = KRBv5Credentials.times.starttime;
+ ticketinfo->valid_until = KRBv5Credentials.times.endtime;
+ ticketinfo->renew_until = KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE ?
+ KRBv5Credentials.times.renew_till : 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 = KRBv5Credentials.times.starttime;
+ list->valid_until = KRBv5Credentials.times.endtime;
+ if (KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE)
+ list->renew_until = 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, also turns off OPENCLOSE mode
+ 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) {
+ functionName = "krb5_cc_start_seq_get";
+ 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 = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */
+ 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);
+}