diff options
author | Ken Raeburn <raeburn@mit.edu> | 2007-06-20 01:19:59 +0000 |
---|---|---|
committer | Ken Raeburn <raeburn@mit.edu> | 2007-06-20 01:19:59 +0000 |
commit | 78ec90d925e1f672639762e6c9fa674bf7ff0a64 (patch) | |
tree | 3aad3df3133e6e0f2922f575b9da94630543f433 /src/windows/identity/ui/timer.c | |
parent | d275e06d0cb0f248aa54a6f134a59f84aa563e14 (diff) | |
download | krb5-78ec90d925e1f672639762e6c9fa674bf7ff0a64.tar.gz krb5-78ec90d925e1f672639762e6c9fa674bf7ff0a64.tar.xz krb5-78ec90d925e1f672639762e6c9fa674bf7ff0a64.zip |
set svn:eol-style to native for *.[ch]
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@19596 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/windows/identity/ui/timer.c')
-rw-r--r-- | src/windows/identity/ui/timer.c | 2030 |
1 files changed, 1015 insertions, 1015 deletions
diff --git a/src/windows/identity/ui/timer.c b/src/windows/identity/ui/timer.c index 7024481c4a..9a270c3eed 100644 --- a/src/windows/identity/ui/timer.c +++ b/src/windows/identity/ui/timer.c @@ -1,1015 +1,1015 @@ -/*
- * Copyright (c) 2005 Massachusetts Institute of Technology
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/* $Id$ */
-
-#include<khmapp.h>
-#include<assert.h>
-
-/* The minimum half time interval is 60 seconds*/
-#define TT_MIN_HALFLIFE_INTERVAL 60
-
-/* as above, in FILETIME units of 100ns */
-#define FT_MIN_HALFLIFE_INTERVAL (TT_MIN_HALFLIFE_INTERVAL * 10000000i64)
-
-/* in seconds */
-#if 0
-khm_int32 khui_timeout_warn = KHUI_DEF_TIMEOUT_WARN;
-khm_int32 khui_timeout_crit = KHUI_DEF_TIMEOUT_CRIT;
-khm_int32 khui_timeout_renew = KHUI_DEF_TIMEOUT_RENEW;
-
-khm_boolean khui_do_renew = TRUE;
-khm_boolean khui_do_warn = TRUE;
-khm_boolean khui_do_crit = TRUE;
-#endif
-
-khui_timer_event * khui_timers = NULL;
-khm_size khui_n_timers = 0;
-khm_size khui_nc_timers = 0;
-
-CRITICAL_SECTION cs_timers;
-
-/*********************************************************************
- Timers
- *********************************************************************/
-
-
-#define KHUI_TIMER_ALLOC_INCR 16
-
-void
-khm_timer_init(void) {
-#ifdef DEBUG
- assert(khui_timers == NULL);
-#endif
-
- khui_nc_timers = KHUI_TIMER_ALLOC_INCR;
- khui_n_timers = 0;
- khui_timers = PMALLOC(sizeof(*khui_timers) * khui_nc_timers);
-
-#ifdef DEBUG
- assert(khui_timers != NULL);
-#endif
-
- InitializeCriticalSection(&cs_timers);
-}
-
-void
-khm_timer_exit(void) {
- EnterCriticalSection(&cs_timers);
-
- if (khui_timers)
- PFREE(khui_timers);
- khui_timers = NULL;
- khui_n_timers = 0;
- khui_nc_timers = 0;
-
- LeaveCriticalSection(&cs_timers);
- DeleteCriticalSection(&cs_timers);
-}
-
-/* called with cs_timers held */
-static void
-tmr_fire_timer(void) {
- int i;
- khm_int64 curtime;
- khm_int64 err;
- khm_int64 next_event;
- int tmr_count[KHUI_N_TTYPES];
- khm_int64 tmr_offset[KHUI_N_TTYPES];
- int t;
- khm_handle eff_ident = NULL;
- khui_timer_type eff_type = 0; /* meaningless */
- int fire_count = 0;
- FILETIME ft;
-
- _begin_task(0);
- _report_cs0(KHERR_DEBUG_1, L"Checking for expired timers");
- _describe();
-
- TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, &ft);
- err = FtToInt(&ft);
- GetSystemTimeAsFileTime(&ft);
- curtime = FtToInt(&ft);
-
- next_event = 0;
-
- ZeroMemory(tmr_count, sizeof(tmr_count));
- ZeroMemory(tmr_offset, sizeof(tmr_offset));
-
- for (i=0; i < (int) khui_n_timers; i++) {
- if (!(khui_timers[i].flags &
- (KHUI_TE_FLAG_STALE | KHUI_TE_FLAG_EXPIRED)) &&
- khui_timers[i].type != KHUI_TTYPE_ID_MARK &&
- khui_timers[i].expire < curtime + err) {
-
- _report_cs3(KHERR_DEBUG_1, L"Expiring timer index=%1!d!, type=%2!d!, key=%3!p!",
- _int32(i), _int32(khui_timers[i].type),
- _cptr(khui_timers[i].key));
-
- t = khui_timers[i].type;
-
- switch(t) {
- case KHUI_TTYPE_ID_RENEW:
- _report_cs1(KHERR_DEBUG_1, L"Renewing identity %1!p!",
- _cptr(khui_timers[i].key));
- khm_cred_renew_identity(khui_timers[i].key);
- khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED;
- break;
-
- case KHUI_TTYPE_CRED_RENEW:
- /* the equivalence threshold for setting the timer is
- a lot larger than what we are testing for here
- (KHUI_TIMEEQ_ERROR vs KHUI_TIMEEQ_ERROR_SMALL) so
- we assume that it is safe to trigger a renew_cred
- call here without checking if there's an imminent
- renew_identity call. */
- _report_cs1(KHERR_DEBUG_1, L"Renewing credential %1!p!",
- _cptr(khui_timers[i].key));
- khm_cred_renew_cred(khui_timers[i].key);
- khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED;
- break;
-
- default:
- if (t < KHUI_N_TTYPES) {
- tmr_count[t]++;
- if (tmr_offset[t] == 0 ||
- tmr_offset[t] > khui_timers[i].offset)
- tmr_offset[t] = khui_timers[i].offset;
- if (next_event == 0 ||
- next_event >
- khui_timers[i].expire + khui_timers[i].offset)
- next_event = khui_timers[i].expire +
- khui_timers[i].offset;
-
- if (eff_ident == NULL &&
- (t == KHUI_TTYPE_ID_EXP ||
- t == KHUI_TTYPE_ID_CRIT ||
- t == KHUI_TTYPE_ID_WARN)) {
- /* we don't need a hold since we will be done
- with the handle before the marker is
- expired (the marker is the timer with the
- KHUI_TTYPE_ID_MARK which contains a held
- handle and is not really a timer.) */
- eff_ident = khui_timers[i].key;
- eff_type = t;
- }
-
- fire_count++;
-
- khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED;
- }
- else {
-#ifdef DEBUG
- assert(FALSE);
-#endif
- }
- }
- }
- }
-
- /* See if we have anything to do */
- if (next_event == 0)
- return;
- else {
- wchar_t fmt[128];
- wchar_t wtime[128];
- wchar_t wmsg[256];
- wchar_t wtitle[64];
- khm_int64 second;
- khui_alert * alert = NULL;
-
- khm_size cb;
-
- next_event -= curtime;
-
- /* Due to measurement errors we may be slightly off on our
- next_event calculation which shows up as '4 mins 59
- seconds' instead of '5 mins' and so on when converting to a
- string. So we add half a second to make the message
- neater. */
- TimetToFileTimeInterval(1, &ft);
- second = FtToInt(&ft);
- next_event += second / 2;
-
- cb = sizeof(wtime);
- ft = IntToFt(next_event);
- FtIntervalToString(&ft,
- wtime,
- &cb);
-
- if (fire_count == 1 &&
- eff_ident != NULL &&
- (eff_type == KHUI_TTYPE_ID_EXP ||
- eff_type == KHUI_TTYPE_ID_CRIT ||
- eff_type == KHUI_TTYPE_ID_WARN)) {
-
- wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
-
- cb = sizeof(idname);
- kcdb_identity_get_name(eff_ident, idname, &cb);
-
- if (next_event < second) {
- LoadString(khm_hInstance, IDS_WARN_EXPIRED_ID,
- fmt, ARRAYLENGTH(fmt));
-
- StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname);
- } else {
- LoadString(khm_hInstance, IDS_WARN_EXPIRE_ID,
- fmt, ARRAYLENGTH(fmt));
-
- StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname, wtime);
- }
- } else {
- if (next_event < second) {
- LoadString(khm_hInstance, IDS_WARN_EXPIRED,
- wmsg, ARRAYLENGTH(wmsg));
- } else {
- LoadString(khm_hInstance, IDS_WARN_EXPIRE,
- fmt, ARRAYLENGTH(fmt));
-
- StringCbPrintf(wmsg, sizeof(wmsg), fmt, wtime);
- }
- }
-
- LoadString(khm_hInstance, IDS_WARN_TITLE,
- wtitle, ARRAYLENGTH(wtitle));
-
- khui_alert_create_simple(wtitle, wmsg, KHERR_WARNING, &alert);
- khui_alert_set_flags(alert,
- KHUI_ALERT_FLAG_REQUEST_BALLOON | KHUI_ALERT_FLAG_DISPATCH_CMD,
- KHUI_ALERT_FLAG_REQUEST_BALLOON | KHUI_ALERT_FLAG_DISPATCH_CMD);
-
- if (eff_ident != NULL) {
- khm_int32 cmd;
-
- cmd = khm_get_identity_new_creds_action(eff_ident);
-
- if (cmd) {
- khui_alert_add_command(alert, cmd);
- khui_alert_add_command(alert, KHUI_PACTION_CLOSE);
- }
- }
-
- khui_alert_show(alert);
- khui_alert_release(alert);
- }
-
- _end_task();
-
-}
-
-void
-khm_timer_fire(HWND hwnd) {
- EnterCriticalSection(&cs_timers);
- tmr_fire_timer();
- LeaveCriticalSection(&cs_timers);
-
- khm_timer_refresh(hwnd);
-}
-
-static int
-tmr_update(khm_handle key, khui_timer_type type, __int64 expire,
- __int64 offset, void * data, khm_boolean reinstate) {
- int i;
- wchar_t name[KCDB_MAXCCH_NAME];
- wchar_t tstamp[128];
- wchar_t *type_str = NULL;
- SYSTEMTIME st;
- FILETIME ft;
- FILETIME ftl;
- khm_size cb;
-
- switch(type) {
- case KHUI_TTYPE_ID_MARK:
- type_str = L"marker";
- break;
-
- case KHUI_TTYPE_CRED_WARN:
- case KHUI_TTYPE_ID_WARN:
- type_str = L"warning";
- break;
-
- case KHUI_TTYPE_CRED_CRIT:
- case KHUI_TTYPE_ID_CRIT:
- type_str = L"critical";
- break;
-
- case KHUI_TTYPE_CRED_EXP:
- case KHUI_TTYPE_ID_EXP:
- type_str = L"expiry";
- break;
-
- case KHUI_TTYPE_CRED_RENEW:
- case KHUI_TTYPE_ID_RENEW:
- type_str = L"renew";
- break;
- }
-
- ft = IntToFt(expire);
- FileTimeToLocalFileTime(&ft, &ftl);
- FileTimeToSystemTime(&ftl, &st);
- StringCbPrintf(tstamp, sizeof(tstamp),
- L"%d-%d-%d %d:%d:%d",
- st.wYear, st.wMonth, st.wDay,
- st.wHour, st.wMinute, st.wSecond);
-
- cb = sizeof(name); name[0] = L'\0';
- if (type_str == NULL) {
-
- _report_cs2(KHERR_DEBUG_1,
- L"Updating uknown timer of type %1!d! exp(%2!s!)",
- _int32(type),
- _cstr(tstamp));
- _resolve();
-
- } else if (type == KHUI_TTYPE_ID_MARK ||
- type == KHUI_TTYPE_ID_WARN ||
- type == KHUI_TTYPE_ID_CRIT ||
- type == KHUI_TTYPE_ID_EXP ||
- type == KHUI_TTYPE_ID_RENEW) {
-
- kcdb_identity_get_name(key, name, &cb);
- _report_cs3(KHERR_DEBUG_1,
- L"Updating identity %1!s! timer for %2!s! exp(%3!s!)",
- _cstr(type_str),
- _cstr(name),
- _cstr(tstamp));
- _resolve();
-
- } else if (type == KHUI_TTYPE_CRED_RENEW ||
- type == KHUI_TTYPE_CRED_WARN ||
- type == KHUI_TTYPE_CRED_CRIT ||
- type == KHUI_TTYPE_CRED_EXP) {
-
- kcdb_cred_get_name(key, name, &cb);
- _report_cs3(KHERR_DEBUG_1,
- L"Updating credential %1!s! timer for %2!s! exp(%3!s!)",
- _cstr(type_str),
- _cstr(name),
- _cstr(tstamp));
- _resolve();
-
- }
-
- for (i=0; i < (int) khui_n_timers; i++) {
- if (khui_timers[i].key == key &&
- khui_timers[i].type == type)
- break;
- }
-
- if (i >= (int) khui_n_timers) {
- i = (int) khui_n_timers;
-
- if (i >= (int) khui_nc_timers) {
- khui_timer_event * nt;
-#ifdef DEBUG
- assert(khui_timers);
-#endif
- khui_nc_timers = UBOUNDSS(i+1, KHUI_TIMER_ALLOC_INCR,
- KHUI_TIMER_ALLOC_INCR);
- nt = PMALLOC(sizeof(*nt) * khui_nc_timers);
-#ifdef DEBUG
- assert(nt);
-#endif
- memcpy(nt, khui_timers, sizeof(*nt) * khui_n_timers);
-
- PFREE(khui_timers);
- khui_timers = nt;
- }
-
- khui_timers[i].key = key;
- khui_timers[i].type = type;
- khui_timers[i].flags = 0;
- khui_n_timers++;
- }
-
- khui_timers[i].expire = expire;
- khui_timers[i].offset = offset;
- khui_timers[i].data = data;
-
- khui_timers[i].flags &= ~KHUI_TE_FLAG_STALE;
- if (reinstate)
- khui_timers[i].flags &= ~KHUI_TE_FLAG_EXPIRED;
-
- return i;
-}
-
-/* called with cs_timers held */
-static int
-tmr_find(khm_handle key, khui_timer_type type,
- khm_int32 and_flags, khm_int32 eq_flags) {
- int i;
-
- eq_flags &= and_flags;
-
- for (i=0; i < (int) khui_n_timers; i++) {
- if (khui_timers[i].key == key &&
- khui_timers[i].type == type &&
- (khui_timers[i].flags & and_flags) == eq_flags)
- break;
- }
-
- if (i < (int) khui_n_timers)
- return i;
- else
- return -1;
-}
-
-/* called with cs_timers held. */
-static FILETIME
-tmr_next_halflife_timeout(int idx, FILETIME * issue, FILETIME * expire) {
- FILETIME lifetime;
- FILETIME current;
- FILETIME ret;
-
- khm_int64 ilife;
- khm_int64 icurrent;
- khm_int64 iexpire;
-
- khm_int64 iret;
-
- GetSystemTimeAsFileTime(¤t);
-
- /* wha?? */
- if (CompareFileTime(issue, expire) >= 0)
- return current;
-
- lifetime = FtSub(expire, issue);
- icurrent = FtToInt(¤t);
- iexpire = FtToInt(expire);
-
- ilife = FtToInt(&lifetime);
-
- while(ilife / 2 > FT_MIN_HALFLIFE_INTERVAL) {
- ilife /= 2;
-
- /* is this the next renewal time? */
- if (iexpire - ilife > icurrent) {
- if (idx >= 0 &&
- khui_timers[idx].expire == iexpire - ilife &&
- (khui_timers[idx].flags & KHUI_TE_FLAG_EXPIRED)) {
-
- /* if this renewal time has already been triggered
- (note that when the timer fires, it also fires all
- events that are within a few seconds of the current
- time) then we need to set the alarm for the next
- slot down the line. */
-
- continue;
-
- } else {
- break;
- }
- }
- }
-
- iret = iexpire - ilife;
-
- ret = IntToFt(iret);
-
- /* if the previous renew timer had fired, we need to mark it as
- not expired. However, we leave it to the caller to update the
- actual timer and mark it as not stale. */
- if (idx >= 0 &&
- khui_timers[idx].expire < iret) {
-
- khui_timers[idx].flags &= ~KHUI_TE_FLAG_EXPIRED;
- khui_timers[idx].expire = iret;
- }
-
- return ret;
-}
-
-/* called with cs_timers held. Called once for each credential in the
- root credentials set. */
-static khm_int32 KHMAPI
-tmr_cred_apply_proc(khm_handle cred, void * rock) {
- khm_handle ident = NULL;
- int mark_idx;
- int idx;
- FILETIME ft_expiry;
- FILETIME ft_current;
- FILETIME ft_creinst;
- FILETIME ft_cred_expiry;
- FILETIME ft_cred_issue;
- FILETIME ft_issue;
- FILETIME ft;
- FILETIME fte;
- FILETIME ft_reinst;
- khm_size cb;
- wchar_t wname[KCDB_MAXCCH_NAME];
-
- cb = sizeof(wname);
- wname[0] = L'\0';
- kcdb_cred_get_name(cred, wname, &cb);
-
- _report_cs1(KHERR_DEBUG_1, L"Looking at cred [%1!s!]",
- _cstr(wname));
- _resolve();
-
- kcdb_cred_get_identity(cred, &ident);
-#ifdef DEBUG
- assert(ident);
-#endif
-
- /* now get the expiry for the identity*/
- cb = sizeof(ft_expiry);
- if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE,
- NULL,
- &ft_expiry, &cb))) {
-
- /* failing which, we get the expiry for this credential */
- cb = sizeof(ft_expiry);
- if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE,
- NULL,
- &ft_expiry, &cb))) {
- /* we don't have an expiry time to work with */
- _report_cs1(KHERR_DEBUG_1, L"Skipping cred [%1!s!]. No expiry time",
- _cstr(wname));
- _resolve();
-
- kcdb_identity_release(ident);
- return KHM_ERROR_SUCCESS;
- } else {
- /* and the time of issue */
- cb = sizeof(ft_issue);
- if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE,
- NULL, &ft_issue, &cb)))
- ZeroMemory(&ft_issue, sizeof(ft_issue));
- }
-
- } else {
- /* also try to get the time of issue. */
- cb = sizeof(ft_issue);
- if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_ISSUE,
- NULL, &ft_issue, &cb)))
- /* if we fail, we just zero out the time of issue and
- failover to using the threshold value to set the expiry
- timer instead of the half life algorithm. */
- ZeroMemory(&ft_issue, sizeof(ft_issue));
- }
-
- /* and the current time */
- GetSystemTimeAsFileTime(&ft_current);
-
- TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR, &ft_reinst);
-
- ft_creinst = FtAdd(&ft_current, &ft_reinst);
-
- mark_idx = tmr_find(ident, KHUI_TTYPE_ID_MARK, 0, 0);
-
- if (mark_idx < 0) {
- mark_idx = tmr_update(ident, KHUI_TTYPE_ID_MARK, 0, 0, 0, FALSE);
- kcdb_identity_hold(ident);
-#ifdef DEBUG
- assert(mark_idx >= 0);
-#endif
- khui_timers[mark_idx].flags |= KHUI_TE_FLAG_STALE;
- }
-
- if (khui_timers[mark_idx].flags & KHUI_TE_FLAG_STALE) {
- /* first time we are touching this */
- khm_handle csp_cw = NULL;
- khm_handle csp_id = NULL;
- khm_int32 rv;
- khm_int32 t;
- khm_boolean do_warn = TRUE;
- khm_boolean do_crit = TRUE;
- khm_boolean do_renew = TRUE;
- khm_boolean do_halflife = TRUE;
- khm_boolean renew_done = FALSE;
- khm_boolean monitor = TRUE;
- khm_int32 to_warn = KHUI_DEF_TIMEOUT_WARN;
- khm_int32 to_crit = KHUI_DEF_TIMEOUT_CRIT;
- khm_int32 to_renew = KHUI_DEF_TIMEOUT_RENEW;
-
- if (CompareFileTime(&ft_expiry, &ft_current) < 0)
- /* already expired */
- goto _done_with_ident;
-
- rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_READ,
- &csp_cw);
-
- assert(KHM_SUCCEEDED(rv));
-
- rv = kcdb_identity_get_config(ident, KHM_PERM_READ, &csp_id);
- if (KHM_SUCCEEDED(rv)) {
- khc_shadow_space(csp_id, csp_cw);
- khc_close_space(csp_cw);
- } else {
- csp_id = csp_cw;
- }
- csp_cw = NULL;
-
- rv = khc_read_int32(csp_id, L"Monitor", &t);
- if (KHM_SUCCEEDED(rv))
- monitor = t;
-
- rv = khc_read_int32(csp_id, L"AllowWarn", &t);
- if (KHM_SUCCEEDED(rv))
- do_warn = t;
-
- rv = khc_read_int32(csp_id, L"AllowCritical", &t);
- if (KHM_SUCCEEDED(rv))
- do_crit = t;
-
- rv = khc_read_int32(csp_id, L"AllowAutoRenew", &t);
- if (KHM_SUCCEEDED(rv))
- do_renew = t;
-
- rv = khc_read_int32(csp_id, L"RenewAtHalfLife", &t);
- if (KHM_SUCCEEDED(rv))
- do_halflife = t;
-
- rv = khc_read_int32(csp_id, L"WarnThreshold", &t);
- if (KHM_SUCCEEDED(rv))
- to_warn = t;
-
- rv = khc_read_int32(csp_id, L"CriticalThreshold", &t);
- if (KHM_SUCCEEDED(rv))
- to_crit = t;
-
- rv = khc_read_int32(csp_id, L"AutoRenewThreshold", &t);
- if (KHM_SUCCEEDED(rv))
- to_renew = t;
-
- khc_close_space(csp_id);
-
- if (monitor && do_renew) {
- int prev;
-
- TimetToFileTimeInterval(to_renew, &ft);
-
- prev =
- tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0);
-
- if (do_halflife && (ft_issue.dwLowDateTime != 0 ||
- ft_issue.dwHighDateTime != 0))
- fte = tmr_next_halflife_timeout(prev, &ft_issue, &ft_expiry);
- else
- fte = FtSub(&ft_expiry, &ft);
-
- /* we set off a renew notification immediately if the
- renew threshold has passed but a renew was never sent.
- This maybe because that NetIDMgr was started at the
- last minute, or because for some reason the renew timer
- could not be triggered earlier. */
-
- if (CompareFileTime(&fte, &ft_current) > 0 ||
- prev == -1 ||
- !(khui_timers[prev].flags & KHUI_TE_FLAG_EXPIRED)) {
-
- if (CompareFileTime(&fte, &ft_current) < 0)
- fte = ft_current;
-
- tmr_update(ident, KHUI_TTYPE_ID_RENEW,
- FtToInt(&fte), FtToInt(&ft), 0,
- CompareFileTime(&fte,&ft_creinst) > 0);
- renew_done = TRUE;
-
- } else {
-
- /* special case. If the renew timer was in the past
- and it was expired, then we retain the record as
- long as the credentials are around. If the renewal
- failed we don't want to automatically retry
- everytime we check the timers. */
-
- tmr_update(ident, KHUI_TTYPE_ID_RENEW,
- FtToInt(&fte), FtToInt(&ft), 0, FALSE);
-
- }
- }
-
- if (monitor && do_warn && !renew_done) {
-
- TimetToFileTimeInterval(to_warn, &ft);
- fte = FtSub(&ft_expiry, &ft);
-
- if (CompareFileTime(&fte, &ft_current) > 0)
- tmr_update(ident, KHUI_TTYPE_ID_WARN,
- FtToInt(&fte), FtToInt(&ft), 0,
- CompareFileTime(&fte, &ft_creinst) > 0);
- }
-
- if (monitor && do_crit && !renew_done) {
- TimetToFileTimeInterval(to_crit, &ft);
- fte = FtSub(&ft_expiry, &ft);
-
- if (CompareFileTime(&fte, &ft_current) > 0)
- tmr_update(ident, KHUI_TTYPE_ID_CRIT,
- FtToInt(&fte), FtToInt(&ft), 0,
- CompareFileTime(&fte, &ft_creinst) > 0);
- }
-
- if (monitor && !renew_done) {
- if (CompareFileTime(&ft_expiry, &ft_current) > 0)
- tmr_update(ident, KHUI_TTYPE_ID_EXP,
- FtToInt(&ft_expiry), 0, 0,
- CompareFileTime(&fte, &ft_creinst) > 0);
- }
-
- _done_with_ident:
- khui_timers[mark_idx].flags &= ~KHUI_TE_FLAG_STALE;
- }
-
- cb = sizeof(ft_cred_expiry);
- if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE,
- NULL,
- &ft_cred_expiry,
- &cb))) {
- _report_cs1(KHERR_DEBUG_1, L"Skipping cred [%1!s!]. Can't lookup cred expiry",
- _cstr(wname));
- _resolve();
- goto _cleanup;
- }
-
- cb = sizeof(ft_cred_issue);
- if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE,
- NULL,
- &ft_cred_issue,
- &cb))) {
-
- ZeroMemory(&ft_cred_issue, sizeof(ft_cred_issue));
-
- }
-
- TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR, &ft);
-
- {
- /* if the credential has a longer lifetime than the identity,
- or it expires within KHUI_TIMEEQ_ERROR seconds of the
- identity, then we don't need to set any alerts for this
- credential. */
-
- FILETIME ft_delta;
-
- ft_delta = FtSub(&ft_expiry, &ft_cred_expiry);
-
- if (CompareFileTime(&ft_cred_expiry, &ft_expiry) >= 0 ||
- CompareFileTime(&ft_delta, &ft) < 0) {
-
- _report_cs1(KHERR_DEBUG_1,
- L"Skipping credential [%1!s!]. The expiry time is too close to the identity expiry.",
- _cstr(wname));
- _resolve();
- goto _cleanup;
- }
- }
-
- if ((idx = tmr_find(ident, KHUI_TTYPE_ID_WARN, 0, 0)) >= 0 &&
- !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) {
-
- fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset);
- if (CompareFileTime(&fte, &ft_current) > 0) {
- tmr_update(cred, KHUI_TTYPE_CRED_WARN,
- FtToInt(&fte),
- khui_timers[idx].offset, 0,
- CompareFileTime(&fte, &ft_creinst) > 0);
- kcdb_cred_hold(cred);
- }
- }
-
- if ((idx = tmr_find(ident, KHUI_TTYPE_ID_CRIT, 0, 0)) >= 0 &&
- !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) {
-
- fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset);
- if (CompareFileTime(&fte, &ft_current) > 0) {
- tmr_update(cred, KHUI_TTYPE_CRED_CRIT,
- FtToInt(&fte),
- khui_timers[idx].offset, 0,
- CompareFileTime(&fte, &ft_creinst) > 0);
- kcdb_cred_hold(cred);
- }
- }
-
- if ((idx = tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0)) >= 0 &&
- !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) {
-
- int cidx = tmr_find(cred, KHUI_TTYPE_CRED_RENEW, 0, 0);
-
- if (ft_cred_issue.dwLowDateTime == 0 &&
- ft_cred_issue.dwHighDateTime == 0) {
- fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset);
- /* a special case, for a credential whose remaining
- lifetime is less than the offset, we try half life on
- the current time and the expiry. */
- if (CompareFileTime(&fte, &ft_current) <= 0 &&
- CompareFileTime(&ft_current, &ft_expiry) < 0) {
- fte = tmr_next_halflife_timeout(cidx, &ft_current, &ft_cred_expiry);
-#if 0
- /* now, if we already have a renew timer for this
- credential that hasn't expired yet and that is set
- for earlier than fte, we let it be. */
- if (cidx >= 0 &&
- khui_timers[cidx].expire < FtToInt(&fte) &&
- khui_timers[cidx].expire > FtToInt(&ft_current) &&
- !(khui_timers[cidx].flags & KHUI_TE_FLAG_EXPIRED)) {
-
- fte = IntToFt(khui_timers[cidx].expire);
-
- }
-#endif
- }
- } else {
- fte = tmr_next_halflife_timeout(cidx, &ft_cred_issue, &ft_cred_expiry);
- }
-
- if (CompareFileTime(&fte, &ft_current) > 0) {
- tmr_update(cred, KHUI_TTYPE_CRED_RENEW,
- FtToInt(&fte),
- khui_timers[idx].offset, 0,
- CompareFileTime(&fte, &ft_creinst) > 0);
- kcdb_cred_hold(cred);
- }
- }
-
- if ((idx = tmr_find(ident, KHUI_TTYPE_ID_EXP, 0, 0)) >= 0 &&
- !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) {
-
- if (CompareFileTime(&ft_cred_expiry, &ft_current) > 0) {
- tmr_update(cred, KHUI_TTYPE_CRED_EXP,
- FtToInt(&ft_cred_expiry),
- 0, 0,
- CompareFileTime(&ft_cred_expiry, &ft_creinst) > 0);
- }
- }
-
- _cleanup:
-
- if (ident)
- kcdb_identity_release(ident);
-
- return KHM_ERROR_SUCCESS;
-}
-
-/* called with cs_timers held */
-static void
-tmr_purge(void) {
- int i, j;
-
- for (i=0,j=0; i < (int) khui_n_timers; i++) {
- if (khui_timers[i].flags & KHUI_TE_FLAG_STALE) {
- if (khui_timers[i].type == KHUI_TTYPE_ID_MARK) {
- kcdb_identity_release(khui_timers[i].key);
-#ifdef DEBUG
- {
- int idx;
-
- idx = tmr_find(khui_timers[i].key,
- KHUI_TTYPE_ID_CRIT, 0, 0);
- assert(idx < 0 ||
- (khui_timers[idx].flags &
- KHUI_TE_FLAG_STALE));
-
- idx = tmr_find(khui_timers[i].key,
- KHUI_TTYPE_ID_RENEW, 0, 0);
- assert(idx < 0 ||
- (khui_timers[idx].flags &
- KHUI_TE_FLAG_STALE));
-
- idx = tmr_find(khui_timers[i].key,
- KHUI_TTYPE_ID_WARN, 0, 0);
- assert(idx < 0 ||
- (khui_timers[idx].flags &
- KHUI_TE_FLAG_STALE));
-
- idx = tmr_find(khui_timers[i].key,
- KHUI_TTYPE_ID_EXP, 0, 0);
- assert(idx < 0 ||
- (khui_timers[idx].flags &
- KHUI_TE_FLAG_STALE));
- }
-#endif
- } else if (khui_timers[i].type == KHUI_TTYPE_CRED_WARN ||
- khui_timers[i].type == KHUI_TTYPE_CRED_CRIT ||
- khui_timers[i].type == KHUI_TTYPE_CRED_RENEW ||
- khui_timers[i].type == KHUI_TTYPE_CRED_EXP) {
- kcdb_cred_release(khui_timers[i].key);
- }
- } else {
- if (i != j)
- khui_timers[j] = khui_timers[i];
- j++;
- }
- }
-
- khui_n_timers = j;
-}
-
-/* go through all the credentials and set timers as appropriate. hwnd
- is the window that will receive the timer events.*/
-void
-khm_timer_refresh(HWND hwnd) {
- int i;
- khm_int64 next_event = 0;
- khm_int64 curtime;
- khm_int64 diff;
-
- _begin_task(0);
- _report_cs0(KHERR_DEBUG_1, L"Refreshing timers");
- _describe();
-
- EnterCriticalSection(&cs_timers);
-
- KillTimer(hwnd, KHUI_TRIGGER_TIMER_ID);
-
- /* When refreshing timers, we go through all of them and mark them
- as stale. Then we go through the credentials in the root
- credential set and add or refresh the timers associated with
- each identity and credential. Once this is done, we remove the
- timers that are still stale, since they are no longer in
- use. */
-
- for (i=0; i < (int) khui_n_timers; i++) {
-#ifdef NOT_IMPLEMENTED_YET
- if (khui_timers[i].type == KHUI_TTYPE_BMSG ||
- khui_timers[i].type == KHUI_TTYPE_SMSG) {
- khui_timers[i].flags &= ~KHUI_TE_FLAG_STALE;
- } else {
-#endif
-
- khui_timers[i].flags |= KHUI_TE_FLAG_STALE;
-
-#ifdef NOT_IMPLEMENTED_YET
- }
-#endif
- }
-
- _report_cs1(KHERR_DEBUG_1, L"Starting with %1!d! timers",
- _int32(khui_n_timers));
-
- kcdb_credset_apply(NULL,
- tmr_cred_apply_proc,
- NULL);
-
- tmr_purge();
-
- _report_cs1(KHERR_DEBUG_1, L"Leaving with %1!d! timers",
- _int32(khui_n_timers));
-
- _check_next_event:
-
- /* Before we return, we should check if any timers are set to
- expire right now. If there are, we should fire the timer
- before returning. */
-
- next_event = 0;
- for (i=0; i < (int) khui_n_timers; i++) {
- if (!(khui_timers[i].flags & KHUI_TE_FLAG_EXPIRED) &&
- khui_timers[i].type != KHUI_TTYPE_ID_MARK &&
- (next_event == 0 ||
- next_event > khui_timers[i].expire)) {
-
- next_event = khui_timers[i].expire;
-
- }
- }
-
- if (next_event != 0) {
- FILETIME ft;
-
- GetSystemTimeAsFileTime(&ft);
- curtime = FtToInt(&ft);
-
- TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, &ft);
- diff = FtToInt(&ft);
-
- if (curtime + diff > next_event) {
- tmr_fire_timer();
- goto _check_next_event;
- } else {
- diff = next_event - curtime;
- ft = IntToFt(diff);
- SetTimer(hwnd,
- KHUI_TRIGGER_TIMER_ID,
- FtIntervalToMilliseconds(&ft),
- NULL);
- }
- }
-
- LeaveCriticalSection(&cs_timers);
-
- _end_task();
-}
+/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +/* The minimum half time interval is 60 seconds*/ +#define TT_MIN_HALFLIFE_INTERVAL 60 + +/* as above, in FILETIME units of 100ns */ +#define FT_MIN_HALFLIFE_INTERVAL (TT_MIN_HALFLIFE_INTERVAL * 10000000i64) + +/* in seconds */ +#if 0 +khm_int32 khui_timeout_warn = KHUI_DEF_TIMEOUT_WARN; +khm_int32 khui_timeout_crit = KHUI_DEF_TIMEOUT_CRIT; +khm_int32 khui_timeout_renew = KHUI_DEF_TIMEOUT_RENEW; + +khm_boolean khui_do_renew = TRUE; +khm_boolean khui_do_warn = TRUE; +khm_boolean khui_do_crit = TRUE; +#endif + +khui_timer_event * khui_timers = NULL; +khm_size khui_n_timers = 0; +khm_size khui_nc_timers = 0; + +CRITICAL_SECTION cs_timers; + +/********************************************************************* + Timers + *********************************************************************/ + + +#define KHUI_TIMER_ALLOC_INCR 16 + +void +khm_timer_init(void) { +#ifdef DEBUG + assert(khui_timers == NULL); +#endif + + khui_nc_timers = KHUI_TIMER_ALLOC_INCR; + khui_n_timers = 0; + khui_timers = PMALLOC(sizeof(*khui_timers) * khui_nc_timers); + +#ifdef DEBUG + assert(khui_timers != NULL); +#endif + + InitializeCriticalSection(&cs_timers); +} + +void +khm_timer_exit(void) { + EnterCriticalSection(&cs_timers); + + if (khui_timers) + PFREE(khui_timers); + khui_timers = NULL; + khui_n_timers = 0; + khui_nc_timers = 0; + + LeaveCriticalSection(&cs_timers); + DeleteCriticalSection(&cs_timers); +} + +/* called with cs_timers held */ +static void +tmr_fire_timer(void) { + int i; + khm_int64 curtime; + khm_int64 err; + khm_int64 next_event; + int tmr_count[KHUI_N_TTYPES]; + khm_int64 tmr_offset[KHUI_N_TTYPES]; + int t; + khm_handle eff_ident = NULL; + khui_timer_type eff_type = 0; /* meaningless */ + int fire_count = 0; + FILETIME ft; + + _begin_task(0); + _report_cs0(KHERR_DEBUG_1, L"Checking for expired timers"); + _describe(); + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, &ft); + err = FtToInt(&ft); + GetSystemTimeAsFileTime(&ft); + curtime = FtToInt(&ft); + + next_event = 0; + + ZeroMemory(tmr_count, sizeof(tmr_count)); + ZeroMemory(tmr_offset, sizeof(tmr_offset)); + + for (i=0; i < (int) khui_n_timers; i++) { + if (!(khui_timers[i].flags & + (KHUI_TE_FLAG_STALE | KHUI_TE_FLAG_EXPIRED)) && + khui_timers[i].type != KHUI_TTYPE_ID_MARK && + khui_timers[i].expire < curtime + err) { + + _report_cs3(KHERR_DEBUG_1, L"Expiring timer index=%1!d!, type=%2!d!, key=%3!p!", + _int32(i), _int32(khui_timers[i].type), + _cptr(khui_timers[i].key)); + + t = khui_timers[i].type; + + switch(t) { + case KHUI_TTYPE_ID_RENEW: + _report_cs1(KHERR_DEBUG_1, L"Renewing identity %1!p!", + _cptr(khui_timers[i].key)); + khm_cred_renew_identity(khui_timers[i].key); + khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; + break; + + case KHUI_TTYPE_CRED_RENEW: + /* the equivalence threshold for setting the timer is + a lot larger than what we are testing for here + (KHUI_TIMEEQ_ERROR vs KHUI_TIMEEQ_ERROR_SMALL) so + we assume that it is safe to trigger a renew_cred + call here without checking if there's an imminent + renew_identity call. */ + _report_cs1(KHERR_DEBUG_1, L"Renewing credential %1!p!", + _cptr(khui_timers[i].key)); + khm_cred_renew_cred(khui_timers[i].key); + khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; + break; + + default: + if (t < KHUI_N_TTYPES) { + tmr_count[t]++; + if (tmr_offset[t] == 0 || + tmr_offset[t] > khui_timers[i].offset) + tmr_offset[t] = khui_timers[i].offset; + if (next_event == 0 || + next_event > + khui_timers[i].expire + khui_timers[i].offset) + next_event = khui_timers[i].expire + + khui_timers[i].offset; + + if (eff_ident == NULL && + (t == KHUI_TTYPE_ID_EXP || + t == KHUI_TTYPE_ID_CRIT || + t == KHUI_TTYPE_ID_WARN)) { + /* we don't need a hold since we will be done + with the handle before the marker is + expired (the marker is the timer with the + KHUI_TTYPE_ID_MARK which contains a held + handle and is not really a timer.) */ + eff_ident = khui_timers[i].key; + eff_type = t; + } + + fire_count++; + + khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; + } + else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } + } + } + + /* See if we have anything to do */ + if (next_event == 0) + return; + else { + wchar_t fmt[128]; + wchar_t wtime[128]; + wchar_t wmsg[256]; + wchar_t wtitle[64]; + khm_int64 second; + khui_alert * alert = NULL; + + khm_size cb; + + next_event -= curtime; + + /* Due to measurement errors we may be slightly off on our + next_event calculation which shows up as '4 mins 59 + seconds' instead of '5 mins' and so on when converting to a + string. So we add half a second to make the message + neater. */ + TimetToFileTimeInterval(1, &ft); + second = FtToInt(&ft); + next_event += second / 2; + + cb = sizeof(wtime); + ft = IntToFt(next_event); + FtIntervalToString(&ft, + wtime, + &cb); + + if (fire_count == 1 && + eff_ident != NULL && + (eff_type == KHUI_TTYPE_ID_EXP || + eff_type == KHUI_TTYPE_ID_CRIT || + eff_type == KHUI_TTYPE_ID_WARN)) { + + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + + cb = sizeof(idname); + kcdb_identity_get_name(eff_ident, idname, &cb); + + if (next_event < second) { + LoadString(khm_hInstance, IDS_WARN_EXPIRED_ID, + fmt, ARRAYLENGTH(fmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname); + } else { + LoadString(khm_hInstance, IDS_WARN_EXPIRE_ID, + fmt, ARRAYLENGTH(fmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname, wtime); + } + } else { + if (next_event < second) { + LoadString(khm_hInstance, IDS_WARN_EXPIRED, + wmsg, ARRAYLENGTH(wmsg)); + } else { + LoadString(khm_hInstance, IDS_WARN_EXPIRE, + fmt, ARRAYLENGTH(fmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), fmt, wtime); + } + } + + LoadString(khm_hInstance, IDS_WARN_TITLE, + wtitle, ARRAYLENGTH(wtitle)); + + khui_alert_create_simple(wtitle, wmsg, KHERR_WARNING, &alert); + khui_alert_set_flags(alert, + KHUI_ALERT_FLAG_REQUEST_BALLOON | KHUI_ALERT_FLAG_DISPATCH_CMD, + KHUI_ALERT_FLAG_REQUEST_BALLOON | KHUI_ALERT_FLAG_DISPATCH_CMD); + + if (eff_ident != NULL) { + khm_int32 cmd; + + cmd = khm_get_identity_new_creds_action(eff_ident); + + if (cmd) { + khui_alert_add_command(alert, cmd); + khui_alert_add_command(alert, KHUI_PACTION_CLOSE); + } + } + + khui_alert_show(alert); + khui_alert_release(alert); + } + + _end_task(); + +} + +void +khm_timer_fire(HWND hwnd) { + EnterCriticalSection(&cs_timers); + tmr_fire_timer(); + LeaveCriticalSection(&cs_timers); + + khm_timer_refresh(hwnd); +} + +static int +tmr_update(khm_handle key, khui_timer_type type, __int64 expire, + __int64 offset, void * data, khm_boolean reinstate) { + int i; + wchar_t name[KCDB_MAXCCH_NAME]; + wchar_t tstamp[128]; + wchar_t *type_str = NULL; + SYSTEMTIME st; + FILETIME ft; + FILETIME ftl; + khm_size cb; + + switch(type) { + case KHUI_TTYPE_ID_MARK: + type_str = L"marker"; + break; + + case KHUI_TTYPE_CRED_WARN: + case KHUI_TTYPE_ID_WARN: + type_str = L"warning"; + break; + + case KHUI_TTYPE_CRED_CRIT: + case KHUI_TTYPE_ID_CRIT: + type_str = L"critical"; + break; + + case KHUI_TTYPE_CRED_EXP: + case KHUI_TTYPE_ID_EXP: + type_str = L"expiry"; + break; + + case KHUI_TTYPE_CRED_RENEW: + case KHUI_TTYPE_ID_RENEW: + type_str = L"renew"; + break; + } + + ft = IntToFt(expire); + FileTimeToLocalFileTime(&ft, &ftl); + FileTimeToSystemTime(&ftl, &st); + StringCbPrintf(tstamp, sizeof(tstamp), + L"%d-%d-%d %d:%d:%d", + st.wYear, st.wMonth, st.wDay, + st.wHour, st.wMinute, st.wSecond); + + cb = sizeof(name); name[0] = L'\0'; + if (type_str == NULL) { + + _report_cs2(KHERR_DEBUG_1, + L"Updating uknown timer of type %1!d! exp(%2!s!)", + _int32(type), + _cstr(tstamp)); + _resolve(); + + } else if (type == KHUI_TTYPE_ID_MARK || + type == KHUI_TTYPE_ID_WARN || + type == KHUI_TTYPE_ID_CRIT || + type == KHUI_TTYPE_ID_EXP || + type == KHUI_TTYPE_ID_RENEW) { + + kcdb_identity_get_name(key, name, &cb); + _report_cs3(KHERR_DEBUG_1, + L"Updating identity %1!s! timer for %2!s! exp(%3!s!)", + _cstr(type_str), + _cstr(name), + _cstr(tstamp)); + _resolve(); + + } else if (type == KHUI_TTYPE_CRED_RENEW || + type == KHUI_TTYPE_CRED_WARN || + type == KHUI_TTYPE_CRED_CRIT || + type == KHUI_TTYPE_CRED_EXP) { + + kcdb_cred_get_name(key, name, &cb); + _report_cs3(KHERR_DEBUG_1, + L"Updating credential %1!s! timer for %2!s! exp(%3!s!)", + _cstr(type_str), + _cstr(name), + _cstr(tstamp)); + _resolve(); + + } + + for (i=0; i < (int) khui_n_timers; i++) { + if (khui_timers[i].key == key && + khui_timers[i].type == type) + break; + } + + if (i >= (int) khui_n_timers) { + i = (int) khui_n_timers; + + if (i >= (int) khui_nc_timers) { + khui_timer_event * nt; +#ifdef DEBUG + assert(khui_timers); +#endif + khui_nc_timers = UBOUNDSS(i+1, KHUI_TIMER_ALLOC_INCR, + KHUI_TIMER_ALLOC_INCR); + nt = PMALLOC(sizeof(*nt) * khui_nc_timers); +#ifdef DEBUG + assert(nt); +#endif + memcpy(nt, khui_timers, sizeof(*nt) * khui_n_timers); + + PFREE(khui_timers); + khui_timers = nt; + } + + khui_timers[i].key = key; + khui_timers[i].type = type; + khui_timers[i].flags = 0; + khui_n_timers++; + } + + khui_timers[i].expire = expire; + khui_timers[i].offset = offset; + khui_timers[i].data = data; + + khui_timers[i].flags &= ~KHUI_TE_FLAG_STALE; + if (reinstate) + khui_timers[i].flags &= ~KHUI_TE_FLAG_EXPIRED; + + return i; +} + +/* called with cs_timers held */ +static int +tmr_find(khm_handle key, khui_timer_type type, + khm_int32 and_flags, khm_int32 eq_flags) { + int i; + + eq_flags &= and_flags; + + for (i=0; i < (int) khui_n_timers; i++) { + if (khui_timers[i].key == key && + khui_timers[i].type == type && + (khui_timers[i].flags & and_flags) == eq_flags) + break; + } + + if (i < (int) khui_n_timers) + return i; + else + return -1; +} + +/* called with cs_timers held. */ +static FILETIME +tmr_next_halflife_timeout(int idx, FILETIME * issue, FILETIME * expire) { + FILETIME lifetime; + FILETIME current; + FILETIME ret; + + khm_int64 ilife; + khm_int64 icurrent; + khm_int64 iexpire; + + khm_int64 iret; + + GetSystemTimeAsFileTime(¤t); + + /* wha?? */ + if (CompareFileTime(issue, expire) >= 0) + return current; + + lifetime = FtSub(expire, issue); + icurrent = FtToInt(¤t); + iexpire = FtToInt(expire); + + ilife = FtToInt(&lifetime); + + while(ilife / 2 > FT_MIN_HALFLIFE_INTERVAL) { + ilife /= 2; + + /* is this the next renewal time? */ + if (iexpire - ilife > icurrent) { + if (idx >= 0 && + khui_timers[idx].expire == iexpire - ilife && + (khui_timers[idx].flags & KHUI_TE_FLAG_EXPIRED)) { + + /* if this renewal time has already been triggered + (note that when the timer fires, it also fires all + events that are within a few seconds of the current + time) then we need to set the alarm for the next + slot down the line. */ + + continue; + + } else { + break; + } + } + } + + iret = iexpire - ilife; + + ret = IntToFt(iret); + + /* if the previous renew timer had fired, we need to mark it as + not expired. However, we leave it to the caller to update the + actual timer and mark it as not stale. */ + if (idx >= 0 && + khui_timers[idx].expire < iret) { + + khui_timers[idx].flags &= ~KHUI_TE_FLAG_EXPIRED; + khui_timers[idx].expire = iret; + } + + return ret; +} + +/* called with cs_timers held. Called once for each credential in the + root credentials set. */ +static khm_int32 KHMAPI +tmr_cred_apply_proc(khm_handle cred, void * rock) { + khm_handle ident = NULL; + int mark_idx; + int idx; + FILETIME ft_expiry; + FILETIME ft_current; + FILETIME ft_creinst; + FILETIME ft_cred_expiry; + FILETIME ft_cred_issue; + FILETIME ft_issue; + FILETIME ft; + FILETIME fte; + FILETIME ft_reinst; + khm_size cb; + wchar_t wname[KCDB_MAXCCH_NAME]; + + cb = sizeof(wname); + wname[0] = L'\0'; + kcdb_cred_get_name(cred, wname, &cb); + + _report_cs1(KHERR_DEBUG_1, L"Looking at cred [%1!s!]", + _cstr(wname)); + _resolve(); + + kcdb_cred_get_identity(cred, &ident); +#ifdef DEBUG + assert(ident); +#endif + + /* now get the expiry for the identity*/ + cb = sizeof(ft_expiry); + if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, + NULL, + &ft_expiry, &cb))) { + + /* failing which, we get the expiry for this credential */ + cb = sizeof(ft_expiry); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE, + NULL, + &ft_expiry, &cb))) { + /* we don't have an expiry time to work with */ + _report_cs1(KHERR_DEBUG_1, L"Skipping cred [%1!s!]. No expiry time", + _cstr(wname)); + _resolve(); + + kcdb_identity_release(ident); + return KHM_ERROR_SUCCESS; + } else { + /* and the time of issue */ + cb = sizeof(ft_issue); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE, + NULL, &ft_issue, &cb))) + ZeroMemory(&ft_issue, sizeof(ft_issue)); + } + + } else { + /* also try to get the time of issue. */ + cb = sizeof(ft_issue); + if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_ISSUE, + NULL, &ft_issue, &cb))) + /* if we fail, we just zero out the time of issue and + failover to using the threshold value to set the expiry + timer instead of the half life algorithm. */ + ZeroMemory(&ft_issue, sizeof(ft_issue)); + } + + /* and the current time */ + GetSystemTimeAsFileTime(&ft_current); + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR, &ft_reinst); + + ft_creinst = FtAdd(&ft_current, &ft_reinst); + + mark_idx = tmr_find(ident, KHUI_TTYPE_ID_MARK, 0, 0); + + if (mark_idx < 0) { + mark_idx = tmr_update(ident, KHUI_TTYPE_ID_MARK, 0, 0, 0, FALSE); + kcdb_identity_hold(ident); +#ifdef DEBUG + assert(mark_idx >= 0); +#endif + khui_timers[mark_idx].flags |= KHUI_TE_FLAG_STALE; + } + + if (khui_timers[mark_idx].flags & KHUI_TE_FLAG_STALE) { + /* first time we are touching this */ + khm_handle csp_cw = NULL; + khm_handle csp_id = NULL; + khm_int32 rv; + khm_int32 t; + khm_boolean do_warn = TRUE; + khm_boolean do_crit = TRUE; + khm_boolean do_renew = TRUE; + khm_boolean do_halflife = TRUE; + khm_boolean renew_done = FALSE; + khm_boolean monitor = TRUE; + khm_int32 to_warn = KHUI_DEF_TIMEOUT_WARN; + khm_int32 to_crit = KHUI_DEF_TIMEOUT_CRIT; + khm_int32 to_renew = KHUI_DEF_TIMEOUT_RENEW; + + if (CompareFileTime(&ft_expiry, &ft_current) < 0) + /* already expired */ + goto _done_with_ident; + + rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, + &csp_cw); + + assert(KHM_SUCCEEDED(rv)); + + rv = kcdb_identity_get_config(ident, KHM_PERM_READ, &csp_id); + if (KHM_SUCCEEDED(rv)) { + khc_shadow_space(csp_id, csp_cw); + khc_close_space(csp_cw); + } else { + csp_id = csp_cw; + } + csp_cw = NULL; + + rv = khc_read_int32(csp_id, L"Monitor", &t); + if (KHM_SUCCEEDED(rv)) + monitor = t; + + rv = khc_read_int32(csp_id, L"AllowWarn", &t); + if (KHM_SUCCEEDED(rv)) + do_warn = t; + + rv = khc_read_int32(csp_id, L"AllowCritical", &t); + if (KHM_SUCCEEDED(rv)) + do_crit = t; + + rv = khc_read_int32(csp_id, L"AllowAutoRenew", &t); + if (KHM_SUCCEEDED(rv)) + do_renew = t; + + rv = khc_read_int32(csp_id, L"RenewAtHalfLife", &t); + if (KHM_SUCCEEDED(rv)) + do_halflife = t; + + rv = khc_read_int32(csp_id, L"WarnThreshold", &t); + if (KHM_SUCCEEDED(rv)) + to_warn = t; + + rv = khc_read_int32(csp_id, L"CriticalThreshold", &t); + if (KHM_SUCCEEDED(rv)) + to_crit = t; + + rv = khc_read_int32(csp_id, L"AutoRenewThreshold", &t); + if (KHM_SUCCEEDED(rv)) + to_renew = t; + + khc_close_space(csp_id); + + if (monitor && do_renew) { + int prev; + + TimetToFileTimeInterval(to_renew, &ft); + + prev = + tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0); + + if (do_halflife && (ft_issue.dwLowDateTime != 0 || + ft_issue.dwHighDateTime != 0)) + fte = tmr_next_halflife_timeout(prev, &ft_issue, &ft_expiry); + else + fte = FtSub(&ft_expiry, &ft); + + /* we set off a renew notification immediately if the + renew threshold has passed but a renew was never sent. + This maybe because that NetIDMgr was started at the + last minute, or because for some reason the renew timer + could not be triggered earlier. */ + + if (CompareFileTime(&fte, &ft_current) > 0 || + prev == -1 || + !(khui_timers[prev].flags & KHUI_TE_FLAG_EXPIRED)) { + + if (CompareFileTime(&fte, &ft_current) < 0) + fte = ft_current; + + tmr_update(ident, KHUI_TTYPE_ID_RENEW, + FtToInt(&fte), FtToInt(&ft), 0, + CompareFileTime(&fte,&ft_creinst) > 0); + renew_done = TRUE; + + } else { + + /* special case. If the renew timer was in the past + and it was expired, then we retain the record as + long as the credentials are around. If the renewal + failed we don't want to automatically retry + everytime we check the timers. */ + + tmr_update(ident, KHUI_TTYPE_ID_RENEW, + FtToInt(&fte), FtToInt(&ft), 0, FALSE); + + } + } + + if (monitor && do_warn && !renew_done) { + + TimetToFileTimeInterval(to_warn, &ft); + fte = FtSub(&ft_expiry, &ft); + + if (CompareFileTime(&fte, &ft_current) > 0) + tmr_update(ident, KHUI_TTYPE_ID_WARN, + FtToInt(&fte), FtToInt(&ft), 0, + CompareFileTime(&fte, &ft_creinst) > 0); + } + + if (monitor && do_crit && !renew_done) { + TimetToFileTimeInterval(to_crit, &ft); + fte = FtSub(&ft_expiry, &ft); + + if (CompareFileTime(&fte, &ft_current) > 0) + tmr_update(ident, KHUI_TTYPE_ID_CRIT, + FtToInt(&fte), FtToInt(&ft), 0, + CompareFileTime(&fte, &ft_creinst) > 0); + } + + if (monitor && !renew_done) { + if (CompareFileTime(&ft_expiry, &ft_current) > 0) + tmr_update(ident, KHUI_TTYPE_ID_EXP, + FtToInt(&ft_expiry), 0, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + } + + _done_with_ident: + khui_timers[mark_idx].flags &= ~KHUI_TE_FLAG_STALE; + } + + cb = sizeof(ft_cred_expiry); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE, + NULL, + &ft_cred_expiry, + &cb))) { + _report_cs1(KHERR_DEBUG_1, L"Skipping cred [%1!s!]. Can't lookup cred expiry", + _cstr(wname)); + _resolve(); + goto _cleanup; + } + + cb = sizeof(ft_cred_issue); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_ISSUE, + NULL, + &ft_cred_issue, + &cb))) { + + ZeroMemory(&ft_cred_issue, sizeof(ft_cred_issue)); + + } + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR, &ft); + + { + /* if the credential has a longer lifetime than the identity, + or it expires within KHUI_TIMEEQ_ERROR seconds of the + identity, then we don't need to set any alerts for this + credential. */ + + FILETIME ft_delta; + + ft_delta = FtSub(&ft_expiry, &ft_cred_expiry); + + if (CompareFileTime(&ft_cred_expiry, &ft_expiry) >= 0 || + CompareFileTime(&ft_delta, &ft) < 0) { + + _report_cs1(KHERR_DEBUG_1, + L"Skipping credential [%1!s!]. The expiry time is too close to the identity expiry.", + _cstr(wname)); + _resolve(); + goto _cleanup; + } + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_WARN, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); + if (CompareFileTime(&fte, &ft_current) > 0) { + tmr_update(cred, KHUI_TTYPE_CRED_WARN, + FtToInt(&fte), + khui_timers[idx].offset, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + kcdb_cred_hold(cred); + } + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_CRIT, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); + if (CompareFileTime(&fte, &ft_current) > 0) { + tmr_update(cred, KHUI_TTYPE_CRED_CRIT, + FtToInt(&fte), + khui_timers[idx].offset, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + kcdb_cred_hold(cred); + } + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + int cidx = tmr_find(cred, KHUI_TTYPE_CRED_RENEW, 0, 0); + + if (ft_cred_issue.dwLowDateTime == 0 && + ft_cred_issue.dwHighDateTime == 0) { + fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); + /* a special case, for a credential whose remaining + lifetime is less than the offset, we try half life on + the current time and the expiry. */ + if (CompareFileTime(&fte, &ft_current) <= 0 && + CompareFileTime(&ft_current, &ft_expiry) < 0) { + fte = tmr_next_halflife_timeout(cidx, &ft_current, &ft_cred_expiry); +#if 0 + /* now, if we already have a renew timer for this + credential that hasn't expired yet and that is set + for earlier than fte, we let it be. */ + if (cidx >= 0 && + khui_timers[cidx].expire < FtToInt(&fte) && + khui_timers[cidx].expire > FtToInt(&ft_current) && + !(khui_timers[cidx].flags & KHUI_TE_FLAG_EXPIRED)) { + + fte = IntToFt(khui_timers[cidx].expire); + + } +#endif + } + } else { + fte = tmr_next_halflife_timeout(cidx, &ft_cred_issue, &ft_cred_expiry); + } + + if (CompareFileTime(&fte, &ft_current) > 0) { + tmr_update(cred, KHUI_TTYPE_CRED_RENEW, + FtToInt(&fte), + khui_timers[idx].offset, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + kcdb_cred_hold(cred); + } + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_EXP, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + if (CompareFileTime(&ft_cred_expiry, &ft_current) > 0) { + tmr_update(cred, KHUI_TTYPE_CRED_EXP, + FtToInt(&ft_cred_expiry), + 0, 0, + CompareFileTime(&ft_cred_expiry, &ft_creinst) > 0); + } + } + + _cleanup: + + if (ident) + kcdb_identity_release(ident); + + return KHM_ERROR_SUCCESS; +} + +/* called with cs_timers held */ +static void +tmr_purge(void) { + int i, j; + + for (i=0,j=0; i < (int) khui_n_timers; i++) { + if (khui_timers[i].flags & KHUI_TE_FLAG_STALE) { + if (khui_timers[i].type == KHUI_TTYPE_ID_MARK) { + kcdb_identity_release(khui_timers[i].key); +#ifdef DEBUG + { + int idx; + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_CRIT, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_RENEW, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_WARN, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_EXP, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + } +#endif + } else if (khui_timers[i].type == KHUI_TTYPE_CRED_WARN || + khui_timers[i].type == KHUI_TTYPE_CRED_CRIT || + khui_timers[i].type == KHUI_TTYPE_CRED_RENEW || + khui_timers[i].type == KHUI_TTYPE_CRED_EXP) { + kcdb_cred_release(khui_timers[i].key); + } + } else { + if (i != j) + khui_timers[j] = khui_timers[i]; + j++; + } + } + + khui_n_timers = j; +} + +/* go through all the credentials and set timers as appropriate. hwnd + is the window that will receive the timer events.*/ +void +khm_timer_refresh(HWND hwnd) { + int i; + khm_int64 next_event = 0; + khm_int64 curtime; + khm_int64 diff; + + _begin_task(0); + _report_cs0(KHERR_DEBUG_1, L"Refreshing timers"); + _describe(); + + EnterCriticalSection(&cs_timers); + + KillTimer(hwnd, KHUI_TRIGGER_TIMER_ID); + + /* When refreshing timers, we go through all of them and mark them + as stale. Then we go through the credentials in the root + credential set and add or refresh the timers associated with + each identity and credential. Once this is done, we remove the + timers that are still stale, since they are no longer in + use. */ + + for (i=0; i < (int) khui_n_timers; i++) { +#ifdef NOT_IMPLEMENTED_YET + if (khui_timers[i].type == KHUI_TTYPE_BMSG || + khui_timers[i].type == KHUI_TTYPE_SMSG) { + khui_timers[i].flags &= ~KHUI_TE_FLAG_STALE; + } else { +#endif + + khui_timers[i].flags |= KHUI_TE_FLAG_STALE; + +#ifdef NOT_IMPLEMENTED_YET + } +#endif + } + + _report_cs1(KHERR_DEBUG_1, L"Starting with %1!d! timers", + _int32(khui_n_timers)); + + kcdb_credset_apply(NULL, + tmr_cred_apply_proc, + NULL); + + tmr_purge(); + + _report_cs1(KHERR_DEBUG_1, L"Leaving with %1!d! timers", + _int32(khui_n_timers)); + + _check_next_event: + + /* Before we return, we should check if any timers are set to + expire right now. If there are, we should fire the timer + before returning. */ + + next_event = 0; + for (i=0; i < (int) khui_n_timers; i++) { + if (!(khui_timers[i].flags & KHUI_TE_FLAG_EXPIRED) && + khui_timers[i].type != KHUI_TTYPE_ID_MARK && + (next_event == 0 || + next_event > khui_timers[i].expire)) { + + next_event = khui_timers[i].expire; + + } + } + + if (next_event != 0) { + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + curtime = FtToInt(&ft); + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, &ft); + diff = FtToInt(&ft); + + if (curtime + diff > next_event) { + tmr_fire_timer(); + goto _check_next_event; + } else { + diff = next_event - curtime; + ft = IntToFt(diff); + SetTimer(hwnd, + KHUI_TRIGGER_TIMER_ID, + FtIntervalToMilliseconds(&ft), + NULL); + } + } + + LeaveCriticalSection(&cs_timers); + + _end_task(); +} |