void khm_cred_end_dialog(khui_new_creds * nc) { dialog_sync_init(); EnterCriticalSection(&cs_dialog); if (in_dialog) { in_dialog = FALSE; SetEvent(in_dialog_evt); } dialog_result = nc->result; #ifdef DEBUG assert(dialog_nc == nc); #endif dialog_nc = NULL; if (nc->subtype == KMSG_CRED_NEW_CREDS && nc->n_identities > 0 && nc->identities[0]) { khm_size cb; cb = sizeof(dialog_identity); if (KHM_FAILED(kcdb_identity_get_name(nc->identities[0], dialog_identity, &cb))) dialog_identity[0] = 0; } else { dialog_identity[0] = 0; } LeaveCriticalSection(&cs_dialog); }
void khm_cred_destroy_identity(khm_handle identity) { khui_action_context * pctx; wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; khm_size cb; if (identity == NULL) return; pctx = PMALLOC(sizeof(*pctx)); #ifdef DEBUG assert(pctx); #endif khui_context_create(pctx, KHUI_SCOPE_IDENT, identity, KCDB_CREDTYPE_INVALID, NULL); cb = sizeof(idname); kcdb_identity_get_name(identity, idname, &cb); _begin_task(KHERR_CF_TRANSITIVE); _report_sr1(KHERR_NONE, IDS_CTX_DESTROY_ID, _dupstr(idname)); _describe(); kmq_post_message(KMSG_CRED, KMSG_CRED_DESTROY_CREDS, 0, (void *) pctx); _end_task(); }
khm_int32 krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam) { switch(msg_subtype) { case KMSG_CRED_NEW_CREDS: { khui_new_creds * nc; khui_new_creds_by_type * nct; khm_size cbsize; wchar_t wbuf[256]; nc = (khui_new_creds *) vparam; nct = PMALLOC(sizeof(*nct)); #ifdef DEBUG assert(nct); #endif ZeroMemory(nct, sizeof(*nct)); nct->type = credtype_id_krb4; nct->ordinal = 3; LoadString(hResModule, IDS_NC_K4_SHORT, wbuf, ARRAYLENGTH(wbuf)); StringCbLength(wbuf, sizeof(wbuf), &cbsize); cbsize += sizeof(wchar_t); nct->name = PMALLOC(cbsize); StringCbCopy(nct->name, cbsize, wbuf); nct->type_deps[nct->n_type_deps++] = credtype_id_krb5; nct->h_module = hResModule; nct->dlg_proc = k4_nc_dlg_proc; nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB4); khui_cw_add_type(nc, nct); } break; case KMSG_CRED_RENEW_CREDS: { khui_new_creds * nc; khui_new_creds_by_type * nct; khm_size cbsize; wchar_t wbuf[256]; khui_action_context * pctx = NULL; nc = (khui_new_creds *) vparam; pctx = khui_cw_get_ctx(nc); if (!pctx->identity) break; nct = PMALLOC(sizeof(*nct)); #ifdef DEBUG assert(nct); #endif ZeroMemory(nct, sizeof(*nct)); nct->type = credtype_id_krb4; nct->ordinal = 3; LoadString(hResModule, IDS_NC_K4_SHORT, wbuf, ARRAYLENGTH(wbuf)); StringCbLength(wbuf, sizeof(wbuf), &cbsize); cbsize += sizeof(wchar_t); nct->name = PMALLOC(cbsize); StringCbCopy(nct->name, cbsize, wbuf); nct->type_deps[nct->n_type_deps++] = credtype_id_krb5; khui_cw_add_type(nc, nct); } break; case KMSG_CRED_DIALOG_SETUP: break; case KMSG_CRED_PROCESS: { khui_new_creds * nc; khui_new_creds_by_type * nct = NULL; khm_handle ident = NULL; khui_action_context * pctx = NULL; k4_dlg_data * d = NULL; long code = 0; wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; khm_size cb; khm_int32 subtype; nc = (khui_new_creds *) vparam; if (KHM_FAILED(khui_cw_find_type(nc, credtype_id_krb4, &nct))) break; subtype = khui_cw_get_subtype(nc); if (subtype == KMSG_CRED_NEW_CREDS || subtype == KMSG_CRED_RENEW_CREDS) { khm_int32 method; if (subtype == KMSG_CRED_NEW_CREDS) { d = (k4_dlg_data *) nct->aux; if (KHM_FAILED(khui_cw_get_primary_id(nc, &ident))) break; if (!d || khui_cw_get_result(nc) != KHUI_NC_RESULT_PROCESS) { khui_cw_set_response(nc, credtype_id_krb4, KHUI_NC_RESPONSE_SUCCESS | KHUI_NC_RESPONSE_EXIT); kcdb_identity_release(ident); break; } if (!d->k4_enabled) { k4_write_identity_data(d); khui_cw_set_response(nc, credtype_id_krb4, KHUI_NC_RESPONSE_SUCCESS | KHUI_NC_RESPONSE_EXIT); kcdb_identity_release(ident); break; } method = d->method; cb = sizeof(idname); kcdb_identity_get_name(ident, idname, &cb); _begin_task(0); _report_sr0(KHERR_NONE, IDS_MSG_K4NEW); _resolve(); _describe(); } else if (subtype == KMSG_CRED_RENEW_CREDS) { pctx = khui_cw_get_ctx(nc); if ((pctx->scope == KHUI_SCOPE_IDENT && pctx->identity != NULL) || (pctx->scope == KHUI_SCOPE_CREDTYPE && pctx->cred_type == credtype_id_krb4 && pctx->identity != NULL) || (pctx->scope == KHUI_SCOPE_CRED && pctx->cred_type == credtype_id_krb4 && pctx->identity != NULL && pctx->cred != NULL)) { ident = pctx->identity; kcdb_identity_hold(ident); if (!k4_should_identity_get_k4(ident)) { _reportf(L"Kerberos 4 is not enabled for this identity. Skipping"); khui_cw_set_response(nc, credtype_id_krb4, KHUI_NC_RESPONSE_FAILED | KHUI_NC_RESPONSE_EXIT); kcdb_identity_release(ident); break; } } else { _reportf(L"Kerberos 4 is not within renewal scope. Skipping"); khui_cw_set_response(nc, credtype_id_krb4, KHUI_NC_RESPONSE_FAILED | KHUI_NC_RESPONSE_EXIT); break; } method = K4_METHOD_K524; /* only k524 is supported for renewals */ _begin_task(0); cb = sizeof(idname); kcdb_identity_get_name(ident, idname, &cb); _report_sr0(KHERR_NONE, IDS_MSG_K4RENEW); _resolve(); _describe(); } else { assert(FALSE); break; } _progress(0,1); if ((method == K4_METHOD_AUTO || method == K4_METHOD_K524) && khui_cw_type_succeeded(nc, credtype_id_krb5)) { khm_handle tgt; FILETIME ft_prev; FILETIME ft_new; khm_size cb; _report_cs0(KHERR_INFO, L"Trying K524..."); tgt = khm_krb4_find_tgt(NULL, ident); _progress(1,3); if (tgt) { cb = sizeof(ft_prev); if (KHM_FAILED(kcdb_cred_get_attr(tgt, KCDB_ATTR_EXPIRE, NULL, &ft_prev, &cb))) ZeroMemory(&ft_prev, sizeof(ft_prev)); kcdb_cred_release(tgt); } code = khm_convert524(ident); _progress(2,3); _reportf(L"khm_convert524 returns code %d", code); if (code == 0) { khui_cw_set_response(nc, credtype_id_krb4, KHUI_NC_RESPONSE_SUCCESS | KHUI_NC_RESPONSE_EXIT); if (subtype == KMSG_CRED_NEW_CREDS) { assert(d != NULL); k4_write_identity_data(d); } else if (subtype == KMSG_CRED_RENEW_CREDS && (pctx->scope == KHUI_SCOPE_CREDTYPE || pctx->scope == KHUI_SCOPE_CRED)) { khm_krb4_list_tickets(); tgt = khm_krb4_find_tgt(NULL, ident); if (tgt) { cb = sizeof(ft_new); ZeroMemory(&ft_new, sizeof(ft_new)); kcdb_cred_get_attr(tgt, KCDB_ATTR_EXPIRE, NULL, &ft_new, &cb); kcdb_cred_release(tgt); } if (!tgt || CompareFileTime(&ft_new, &ft_prev) <= 0) { /* The new TGT wasn't much of an improvement over what we already had. We should go out and try to renew the identity now. */ khui_action_context ctx; _reportf(L"Renewal of Krb4 creds failed to get a longer TGT. Triggering identity renewal"); khui_context_create(&ctx, KHUI_SCOPE_IDENT, pctx->identity, KCDB_CREDTYPE_INVALID, NULL); khui_action_trigger(KHUI_ACTION_RENEW_CRED, &ctx); khui_context_release(&ctx); } } _progress(1,1); _end_task(); if (ident) kcdb_identity_release(ident); break; } else if (method == K4_METHOD_K524) { khui_cw_set_response(nc, credtype_id_krb4, KHUI_NC_RESPONSE_FAILED | KHUI_NC_RESPONSE_EXIT); if (subtype == KMSG_CRED_RENEW_CREDS && (pctx->scope == KHUI_SCOPE_CREDTYPE || pctx->scope == KHUI_SCOPE_CRED)) { /* We were trying to get a new Krb4 TGT for this identity. Sometimes this fails because of restrictions placed on K524d regarding the lifetime of the issued K4 TGT. In this case, we trigger a renewal of the identity in the hope that the new K5 TGT will allow us to successfully get a new K4 TGT next time over using the new K5 TGT. */ khui_action_context ctx; _reportf(L"Renewal of Krb4 creds failed using k524. Triggerring identity renewal."); khui_context_create(&ctx, KHUI_SCOPE_IDENT, pctx->identity, KCDB_CREDTYPE_INVALID, NULL); khui_action_trigger(KHUI_ACTION_RENEW_CRED, &ctx); khui_context_release(&ctx); } _progress(1,1); _end_task(); if (ident) kcdb_identity_release(ident); break; } } /* only supported for new credentials */ if (method == K4_METHOD_AUTO || method == K4_METHOD_PASSWORD) { khm_size n_prompts = 0; khm_size idx; khm_size cb; wchar_t wpwd[KHUI_MAXCCH_PROMPT_VALUE]; char pwd[KHUI_MAXCCH_PROMPT_VALUE]; wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; char idname[KCDB_IDENT_MAXCCH_NAME]; char * aname = NULL; char * inst = NULL; char * realm = NULL; assert(subtype == KMSG_CRED_NEW_CREDS); _report_cs0(KHERR_INFO, L"Trying password ..."); code = TRUE; /* just has to be non-zero */ khui_cw_get_prompt_count(nc, &n_prompts); if (n_prompts == 0) goto _skip_pwd; for (idx = 0; idx < n_prompts; idx++) { khui_new_creds_prompt * p; if (KHM_FAILED(khui_cw_get_prompt(nc, idx, &p))) continue; if (p->type == KHUI_NCPROMPT_TYPE_PASSWORD) break; } if (idx >= n_prompts) { _reportf(L"Password prompt not found"); goto _skip_pwd; } khui_cw_sync_prompt_values(nc); cb = sizeof(wpwd); if (KHM_FAILED(khui_cw_get_prompt_value(nc, idx, wpwd, &cb))) { _reportf(L"Failed to obtain password value"); goto _skip_pwd; } UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd); cb = sizeof(widname); kcdb_identity_get_name(ident, widname, &cb); UnicodeStrToAnsi(idname, sizeof(idname), widname); { char * atsign; atsign = strchr(idname, '@'); if (atsign == NULL) { _reportf(L"Identity name does not contain an '@'"); goto _skip_pwd; } *atsign++ = 0; realm = atsign; } { char * slash; slash = strchr(idname, '/'); if (slash != NULL) { *slash++ = 0; inst = slash; } else { inst = ""; } } aname = idname; code = khm_krb4_kinit(aname, inst, realm, (long) d->lifetime, pwd); _progress(2,3); _reportf(L"khm_krb4_kinit returns code %d", code); _skip_pwd: if (code) { khui_cw_set_response(nc, credtype_id_krb4, KHUI_NC_RESPONSE_EXIT | KHUI_NC_RESPONSE_FAILED); } else { khui_cw_set_response(nc, credtype_id_krb4, KHUI_NC_RESPONSE_EXIT | KHUI_NC_RESPONSE_SUCCESS); if (subtype == KMSG_CRED_NEW_CREDS) { assert(d != NULL); k4_write_identity_data(d); } } } _progress(1,1); _end_task(); } if (ident) kcdb_identity_release(ident); } break; case KMSG_CRED_END: { khui_new_creds * nc; khui_new_creds_by_type * nct = NULL; nc = (khui_new_creds *) vparam; if (KHM_FAILED(khui_cw_find_type(nc, credtype_id_krb4, &nct))) break; khui_cw_del_type(nc, credtype_id_krb4); if (nct->name) PFREE(nct->name); if (nct->credtext) PFREE(nct->credtext); PFREE(nct); } break; } return KHM_ERROR_SUCCESS; }
/* dialog box procedure for the "Add new identity" dialog */ INT_PTR CALLBACK khm_cfg_add_ident_proc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) { add_ident_data * d; switch(umsg) { case WM_INITDIALOG: /* we create a new credentials blob and pull in the identity selectors from the identity provider. */ d = PMALLOC(sizeof(*d)); ZeroMemory(d, sizeof(*d)); khui_cw_create_cred_blob(&d->nc); #ifdef DEBUG assert(d->nc != NULL); #endif if (d->nc == NULL) { PFREE(d); break; } if (KHM_FAILED(kcdb_identpro_get_ui_cb(&d->nc->ident_cb))) { /* this should have worked. The only reason it would fail is if there is no identity provider or if the identity provider does not support providing idnetity selectors. */ khui_cw_destroy_cred_blob(d->nc); PFREE(d); break; } #pragma warning(push) #pragma warning(disable: 4244) SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); #pragma warning(pop) /* get metrics for dynamic controls */ get_ctrl_row_metrics(&d->dim_small, GetDlgItem(hwnd, IDC_SM_LBL), GetDlgItem(hwnd, IDC_SM_CTL)); get_ctrl_row_metrics(&d->dim_medium, GetDlgItem(hwnd, IDC_MED_LBL), GetDlgItem(hwnd, IDC_MED_CTL)); get_ctrl_row_metrics(&d->dim_large, GetDlgItem(hwnd, IDC_LG_LBL), GetDlgItem(hwnd, IDC_LG_CTL)); { RECT rlbl; RECT rctl; RECT rwnd; GetWindowRect(GetDlgItem(hwnd, IDC_SM_LBL), &rlbl); GetWindowRect(GetDlgItem(hwnd, IDC_SM_CTL), &rctl); GetWindowRect(hwnd, &rwnd); OffsetRect(&rlbl, -rwnd.left, -rwnd.top); OffsetRect(&rctl, -rwnd.left, -rwnd.top); d->current_x = rlbl.left; d->current_y = rctl.top - GetSystemMetrics(SM_CYCAPTION); GetWindowRect(GetDlgItem(hwnd, IDC_MED_CTL), &rlbl); OffsetRect(&rlbl, -rwnd.left, -rwnd.top); d->row_gap = rlbl.top - rctl.bottom; } d->nc->hwnd = hwnd; /* now call the UI callback and make it create the controls. */ d->nc->ident_cb(d->nc, WMNC_IDENT_INIT, NULL, 0, 0, (LPARAM) hwnd); break; case WM_DESTROY: d = (add_ident_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); if (d == NULL) break; d->nc->ident_cb(d->nc, WMNC_IDENT_EXIT, NULL, 0, 0, 0); khui_cw_destroy_cred_blob(d->nc); PFREE(d); break; case KHUI_WM_NC_NOTIFY: d = (add_ident_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); switch(HIWORD(wParam)) { case WMNC_ADD_CONTROL_ROW: { khui_control_row * row; RECT r_lbl, r_inp, r_enc; struct ctrl_row_dimensions * dim; HFONT hf; row = (khui_control_row *) lParam; #ifdef DEBUG assert(row->label); assert(row->input); assert(d); #endif if (row->size == KHUI_CTRLSIZE_SMALL) { dim = &d->dim_small; } else if (row->size == KHUI_CTRLSIZE_HALF) { dim = &d->dim_medium; } else { dim = &d->dim_large; #ifdef DEBUG assert(row->size == KHUI_CTRLSIZE_FULL); #endif } CopyRect(&r_enc, &dim->enclosure); CopyRect(&r_lbl, &dim->label); CopyRect(&r_inp, &dim->control); OffsetRect(&r_enc, d->current_x, d->current_y); OffsetRect(&r_lbl, r_enc.left, r_enc.top); OffsetRect(&r_inp, r_enc.left, r_enc.top); d->current_y += r_enc.bottom - r_enc.top; hf = (HFONT) SendDlgItemMessage(hwnd, IDOK, WM_GETFONT, 0, 0); if (row->label) { SetWindowPos(row->label, ((d->hwnd_last_ctrl != NULL)? d->hwnd_last_ctrl : HWND_TOP), r_lbl.left, r_lbl.top, r_lbl.right - r_lbl.left, r_lbl.bottom - r_lbl.top, SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOOWNERZORDER); if (hf) SendMessage(row->label, WM_SETFONT, (WPARAM) hf, TRUE); d->hwnd_last_ctrl = row->label; } if (row->input) { SetWindowPos(row->input, ((d->hwnd_last_ctrl != NULL)? d->hwnd_last_ctrl : HWND_TOP), r_inp.left, r_inp.top, r_inp.right - r_inp.left, r_inp.bottom - r_inp.top, SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOOWNERZORDER); if (hf) SendMessage(row->input, WM_SETFONT, (WPARAM) hf, TRUE); d->hwnd_last_ctrl = row->input; } } break; case WMNC_IDENTITY_CHANGE: break; } return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK) { wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; wchar_t err_msg[1024]; khm_handle ident = NULL; khm_handle csp_ident = NULL; khm_size cb; khm_int32 rv = KHM_ERROR_SUCCESS; d = (add_ident_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); if (!d || !d->nc) break; /* check if there was an identity selected */ if (d->nc->n_identities == 0 || d->nc->identities[0] == NULL) { StringCbCopy(idname, sizeof(idname), L""); LoadString(khm_hInstance, IDS_CFG_IDNAME_NON, err_msg, ARRAYLENGTH(err_msg)); goto show_failure; } ident = d->nc->identities[0]; kcdb_identity_hold(ident); cb = sizeof(idname); kcdb_identity_get_name(ident, idname, &cb); /* now we have to create the identity configuration. */ if (KHM_FAILED(rv = kcdb_identity_get_config(ident, KHM_FLAG_CREATE, &csp_ident))) { wchar_t fmt[256]; LoadString(khm_hInstance, IDS_CFG_IDNAME_CCC, fmt, ARRAYLENGTH(fmt)); StringCbPrintf(err_msg, sizeof(err_msg), fmt, rv); kcdb_identity_release(ident); goto show_failure; } /* create a value so that the configuration space will actually be created in the registry. We don't want this new identity to be sticky. */ khc_write_int32(csp_ident, L"Sticky", 0); khm_refresh_config(); kcdb_identity_release(ident); khc_close_space(csp_ident); EndDialog(hwnd, 0); break; show_failure: { wchar_t title[512]; wchar_t fmt[256]; if (!err_msg[0]) break; LoadString(khm_hInstance, IDS_CFG_IDNAME_PRB, fmt, ARRAYLENGTH(fmt)); StringCbPrintf(title, sizeof(title), fmt, idname); MessageBox(hwnd, err_msg, title, MB_OK | MB_ICONSTOP); /* don't end the dialog yet */ break; } break; } else if (LOWORD(wParam) == IDCANCEL) { EndDialog(hwnd, 1); } else { d = (add_ident_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); if (d && d->nc && d->nc->ident_cb) { return d->nc->ident_cb(d->nc, WMNC_IDENT_WMSG, hwnd, umsg, wParam, lParam); } } break; } return FALSE; }
k5_kinit_task * k5_kinit_task_create(khui_new_creds * nc) { k5_kinit_task * kt; k5_dlg_data * d; wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; khm_size cbbuf; LPNETID_DLGINFO pdlginfo; khui_action_context * pctx = NULL; khm_handle hsub = NULL; khui_cw_find_type(nc, credtype_id_krb5, (khui_new_creds_by_type **) &d); if (!d) return NULL; kt = (k5_kinit_task *) PMALLOC(sizeof(*kt)); memset(kt, 0, sizeof(*kt)); kt->magic = K5_KINIT_TASK_MAGIC; kt->nc = nc; kt->dlg_data = d; kt->nct = &d->nct; kt->context = 0; khui_cw_get_primary_id(nc, &kt->identity); cbbuf = sizeof(idname); kcdb_identity_get_name(kt->identity, idname, &cbbuf); cbbuf = (cbbuf * sizeof(char)) / sizeof(wchar_t); kt->principal = PMALLOC(cbbuf); UnicodeStrToAnsi(kt->principal, cbbuf, idname); kt->password = NULL; kt->params = d->params; kt->params.lifetime = (krb5_deltat) d->tc_lifetime.current; kt->params.renew_life = (krb5_deltat) d->tc_renew.current; /* if we have external parameters, we should use them as well */ pctx = khui_cw_get_ctx(nc); if (pctx && pctx->cb_vparam == sizeof(NETID_DLGINFO) && (pdlginfo = pctx->vparam) != NULL && pdlginfo->size == NETID_DLGINFO_V1_SZ) { wchar_t * t; size_t size; if (pdlginfo->in.ccache[0] && SUCCEEDED(StringCchLength(pdlginfo->in.ccache, NETID_CCACHE_NAME_SZ, &size))) { kt->ccache = PMALLOC(sizeof(char) * (size + 1)); UnicodeStrToAnsi(kt->ccache, size + 1, pdlginfo->in.ccache); /* this is the same as the output cache */ StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), pdlginfo->in.ccache); } else { wchar_t ccache[KRB5_MAXCCH_CCNAME]; size = sizeof(ccache); khm_krb5_get_identity_default_ccache(kt->identity, ccache, &size); StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), ccache); } t = khm_get_realm_from_princ(idname); if (t) { StringCbCopy(pdlginfo->out.realm, sizeof(pdlginfo->out.realm), t); if ((t - idname) > 1) { StringCchCopyN(pdlginfo->out.username, ARRAYLENGTH(pdlginfo->out.username), idname, (t - idname) - 1); } else { StringCbCopy(pdlginfo->out.username, sizeof(pdlginfo->out.username), L""); } } else { StringCbCopy(pdlginfo->out.username, sizeof(pdlginfo->out.username), idname); StringCbCopy(pdlginfo->out.realm, sizeof(pdlginfo->out.realm), L""); } } kt->state = K5_KINIT_STATE_PREP; InitializeCriticalSection(&kt->cs); kt->h_task_wait = CreateEvent(NULL, FALSE, FALSE, NULL); kt->h_parent_wait = CreateEvent(NULL, FALSE, FALSE, NULL); kt->refcount = 2; /* One hold for the caller, one hold for the thread */ kmq_create_subscription(k5_msg_callback, &hsub); kt->task = task_create(NULL, 32 * 4096, kinit_task_proc, kt, hsub, 0); return kt; }
void k4_handle_wmnc_notify(k4_dlg_data * d, WPARAM wParam, LPARAM lParam) { switch(HIWORD(wParam)) { case WMNC_UPDATE_CREDTEXT: { if (d->nct->credtext) { PFREE(d->nct->credtext); d->nct->credtext = NULL; } if (d->nc->n_identities > 0 && d->nc->identities[0]) { khm_int32 flags = 0; wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; wchar_t * atsign; wchar_t * realm; khm_size cb; kcdb_identity_get_flags(d->nc->identities[0], &flags); if (!(flags & KCDB_IDENT_FLAG_VALID)) { break; } cb = sizeof(idname); kcdb_identity_get_name(d->nc->identities[0], idname, &cb); atsign = wcsrchr(idname, L'@'); if (atsign == NULL || !atsign[1]) break; realm = ++atsign; if (d->k4_enabled) { wchar_t wmethod[128]; wchar_t wfmt[128]; wchar_t wct[512]; LoadString(hResModule, IDS_CT_TGTFOR, wfmt, ARRAYLENGTH(wfmt)); if (d->method == K4_METHOD_AUTO) LoadString(hResModule, IDS_METHOD_AUTO, wmethod, ARRAYLENGTH(wmethod)); else if (d->method == K4_METHOD_PASSWORD) LoadString(hResModule, IDS_METHOD_PWD, wmethod, ARRAYLENGTH(wmethod)); else if (d->method == K4_METHOD_K524) LoadString(hResModule, IDS_METHOD_K524, wmethod, ARRAYLENGTH(wmethod)); else { assert(FALSE); } StringCbPrintf(wct, sizeof(wct), wfmt, realm, wmethod); StringCbLength(wct, sizeof(wct), &cb); cb += sizeof(wchar_t); d->nct->credtext = PMALLOC(cb); StringCbCopy(d->nct->credtext, cb, wct); } else { wchar_t wct[256]; LoadString(hResModule, IDS_CT_DISABLED, wct, ARRAYLENGTH(wct)); StringCbLength(wct, sizeof(wct), &cb); cb += sizeof(wchar_t); d->nct->credtext = PMALLOC(cb); StringCbCopy(d->nct->credtext, cb, wct); } } /* no identities were selected. it is not the responsibility of krb4 to complain about this. */ } break; case WMNC_IDENTITY_CHANGE: k4_read_identity_data(d); k4_update_display(d, TRUE); break; case WMNC_CREDTEXT_LINK: { wchar_t wid[KHUI_MAXCCH_HTLINK_FIELD]; wchar_t * wids; khui_htwnd_link * l; l = (khui_htwnd_link *) lParam; StringCchCopyN(wid, ARRAYLENGTH(wid), l->id, l->id_len); wids = wcschr(wid, L':'); if (!wids) break; else wids++; if (!wcscmp(wids, L"Enable")) { d->k4_enabled = TRUE; k4_update_display(d, TRUE); khui_cw_enable_type(d->nc, credtype_id_krb4, TRUE); } } break; } }
/* Completion handler for KMSG_CRED messages. We control the overall logic of credentials acquisition and other operations here. Once a credentials operation is triggered, each successive message completion notification will be used to dispatch the messages for the next step in processing the operation. */ void KHMAPI kmsg_cred_completion(kmq_message *m) { khui_new_creds * nc; #ifdef DEBUG assert(m->type == KMSG_CRED); #else if(m->type != KMSG_CRED) return; /* huh? */ #endif switch(m->subtype) { case KMSG_CRED_PASSWORD: /* fallthrough */ case KMSG_CRED_NEW_CREDS: /* Cred types have attached themselves. Trigger the next phase. */ kmq_post_message(KMSG_CRED, KMSG_CRED_DIALOG_SETUP, 0, m->vparam); break; case KMSG_CRED_RENEW_CREDS: nc = (khui_new_creds *) m->vparam; /* khm_cred_dispatch_process_message() deals with the case where there are no credential types that wants to participate in this operation. */ khm_cred_dispatch_process_message(nc); break; case KMSG_CRED_DIALOG_SETUP: nc = (khui_new_creds *) m->vparam; khm_prep_newcredwnd(nc->hwnd); /* all the controls have been created. Now initialize them */ if (nc->n_types > 0) { kmq_post_subs_msg(nc->type_subs, nc->n_types, KMSG_CRED, KMSG_CRED_DIALOG_PRESTART, 0, m->vparam); } else { PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), 0); } break; case KMSG_CRED_DIALOG_PRESTART: /* all prestart stuff is done. Now to activate the dialog */ nc = (khui_new_creds *) m->vparam; khm_show_newcredwnd(nc->hwnd); kmq_post_subs_msg(nc->type_subs, nc->n_types, KMSG_CRED, KMSG_CRED_DIALOG_START, 0, m->vparam); /* at this point, the dialog window takes over. We let it run the show until KMSG_CRED_DIALOG_END is posted by the dialog procedure. */ break; case KMSG_CRED_PROCESS: /* a wave of these messages have completed. We should check if there's more */ nc = (khui_new_creds *) m->vparam; /* if we are done processing all the plug-ins, then check if there were any errors reported. Otherwise we dispatch another set of messages. */ if(!khm_cred_dispatch_process_level(nc)) { if(kherr_is_error()) { khui_alert * alert; kherr_event * evt; kherr_context * ctx; wchar_t ws_tfmt[512]; wchar_t w_idname[KCDB_IDENT_MAXCCH_NAME]; wchar_t ws_title[ARRAYLENGTH(ws_tfmt) + KCDB_IDENT_MAXCCH_NAME]; khm_size cb; /* For renewals, we suppress the error message for the following case: - The renewal was for an identity - There are no identity credentials for the identity (no credentials that have the same type as the identity provider). */ if (nc->subtype == KMSG_CRED_RENEW_CREDS && nc->ctx.scope == KHUI_SCOPE_IDENT && nc->ctx.identity != NULL) { khm_handle tcs = NULL; /* credential set */ khm_size count = 0; khm_int32 id_ctype = KCDB_CREDTYPE_INVALID; khm_int32 delta = 0; kcdb_identity_get_type(&id_ctype); kcdb_credset_create(&tcs); kcdb_credset_collect(tcs, NULL, nc->ctx.identity, id_ctype, &delta); kcdb_credset_get_size(tcs, &count); kcdb_credset_delete(tcs); if (count == 0) { goto done_with_op; } } ctx = kherr_peek_context(); evt = kherr_get_err_event(ctx); kherr_evaluate_event(evt); khui_alert_create_empty(&alert); if (nc->subtype == KMSG_CRED_NEW_CREDS) { khui_alert_set_type(alert, KHUI_ALERTTYPE_ACQUIREFAIL); cb = sizeof(w_idname); if (nc->n_identities == 0 || KHM_FAILED(kcdb_identity_get_name(nc->identities[0], w_idname, &cb))) { /* an identity could not be determined */ LoadString(khm_hInstance, IDS_NC_FAILED_TITLE, ws_title, ARRAYLENGTH(ws_title)); } else { LoadString(khm_hInstance, IDS_NC_FAILED_TITLE_I, ws_tfmt, ARRAYLENGTH(ws_tfmt)); StringCbPrintf(ws_title, sizeof(ws_title), ws_tfmt, w_idname); khui_alert_set_ctx(alert, KHUI_SCOPE_IDENT, nc->identities[0], KCDB_CREDTYPE_INVALID, NULL); } } else if (nc->subtype == KMSG_CRED_PASSWORD) { khui_alert_set_type(alert, KHUI_ALERTTYPE_CHPW); cb = sizeof(w_idname); if (nc->n_identities == 0 || KHM_FAILED(kcdb_identity_get_name(nc->identities[0], w_idname, &cb))) { LoadString(khm_hInstance, IDS_NC_PWD_FAILED_TITLE, ws_title, ARRAYLENGTH(ws_title)); } else { LoadString(khm_hInstance, IDS_NC_PWD_FAILED_TITLE_I, ws_tfmt, ARRAYLENGTH(ws_tfmt)); StringCbPrintf(ws_title, sizeof(ws_title), ws_tfmt, w_idname); khui_alert_set_ctx(alert, KHUI_SCOPE_IDENT, nc->identities[0], KCDB_CREDTYPE_INVALID, NULL); } } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { khui_alert_set_type(alert, KHUI_ALERTTYPE_RENEWFAIL); cb = sizeof(w_idname); if (nc->ctx.identity == NULL || KHM_FAILED(kcdb_identity_get_name(nc->ctx.identity, w_idname, &cb))) { LoadString(khm_hInstance, IDS_NC_REN_FAILED_TITLE, ws_title, ARRAYLENGTH(ws_title)); } else { LoadString(khm_hInstance, IDS_NC_REN_FAILED_TITLE_I, ws_tfmt, ARRAYLENGTH(ws_tfmt)); StringCbPrintf(ws_title, sizeof(ws_title), ws_tfmt, w_idname); khui_alert_set_ctx(alert, KHUI_SCOPE_IDENT, nc->ctx.identity, KCDB_CREDTYPE_INVALID, NULL); } } else { #ifdef DEBUG assert(FALSE); #endif } khui_alert_set_title(alert, ws_title); khui_alert_set_severity(alert, evt->severity); if(!evt->long_desc) khui_alert_set_message(alert, evt->short_desc); else khui_alert_set_message(alert, evt->long_desc); if(evt->suggestion) khui_alert_set_suggestion(alert, evt->suggestion); if (nc->subtype == KMSG_CRED_RENEW_CREDS && nc->ctx.identity != NULL) { khm_int32 n_cmd; n_cmd = khm_get_identity_new_creds_action(nc->ctx.identity); if (n_cmd != 0) { khui_alert_add_command(alert, n_cmd); khui_alert_add_command(alert, KHUI_PACTION_CLOSE); khui_alert_set_flags(alert, KHUI_ALERT_FLAG_DISPATCH_CMD, KHUI_ALERT_FLAG_DISPATCH_CMD); } } khui_alert_show(alert); khui_alert_release(alert); kherr_release_context(ctx); kherr_clear_error(); } done_with_op: if (nc->subtype == KMSG_CRED_RENEW_CREDS) { kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, m->vparam); } else { PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), 0); } } break; case KMSG_CRED_END: /* all is done. */ { khui_new_creds * nc; khm_boolean continue_cmdline = TRUE; nc = (khui_new_creds *) m->vparam; if (nc->subtype == KMSG_CRED_NEW_CREDS || nc->subtype == KMSG_CRED_PASSWORD) { khm_cred_end_dialog(nc); } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { /* if this is a renewal that was triggered while we were processing the commandline, then we need to update the pending renewal count. */ if (khm_startup.processing) { LONG renewals; renewals = InterlockedDecrement(&khm_startup.pending_renewals); if (renewals != 0) { continue_cmdline = FALSE; } } } khui_cw_destroy_cred_blob(nc); kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); if (continue_cmdline) kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); } break; /* property sheet stuff */ case KMSG_CRED_PP_BEGIN: /* all the pages should have been added by now. Just send out the precreate message */ kmq_post_message(KMSG_CRED, KMSG_CRED_PP_PRECREATE, 0, m->vparam); break; case KMSG_CRED_PP_END: kmq_post_message(KMSG_CRED, KMSG_CRED_PP_DESTROY, 0, m->vparam); break; case KMSG_CRED_DESTROY_CREDS: #ifdef DEBUG assert(m->vparam != NULL); #endif khui_context_release((khui_action_context *) m->vparam); PFREE(m->vparam); kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); break; case KMSG_CRED_IMPORT: { khm_boolean continue_cmdline = FALSE; LONG pending_renewals; /* once an import operation ends, we have to trigger a renewal so that other plug-ins that didn't participate in the import operation can have a chance at getting the necessary credentials. If we are in the middle of processing the commandline, we have to be a little bit careful. We can't issue a commandline conituation message right now because the import action is still ongoing (since the renewals are part of the action). Once the renewals have completed, the completion handler will automatically issue a commandline continuation message. However, if there were no identities to renew, then we have to issue the message ourselves. */ InterlockedIncrement(&khm_startup.pending_renewals); khm_cred_renew_all_identities(); pending_renewals = InterlockedDecrement(&khm_startup.pending_renewals); if (pending_renewals == 0 && khm_startup.processing) kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); } break; case KMSG_CRED_REFRESH: kcdb_identity_refresh_all(); break; } }
void khm_cred_dispatch_process_message(khui_new_creds *nc) { khm_size i; BOOL pending; wchar_t wsinsert[512]; khm_size cbsize; /* see if there's anything to do. We can check this without obtaining a lock */ if(nc->n_types == 0 || (nc->subtype == KMSG_CRED_NEW_CREDS && nc->n_identities == 0) || (nc->subtype == KMSG_CRED_PASSWORD && nc->n_identities == 0)) goto _terminate_job; /* check dependencies and stuff first */ EnterCriticalSection(&nc->cs); for(i=0; i<nc->n_types; i++) { nc->types[i]->flags &= ~ KHUI_NCT_FLAG_PROCESSED; } LeaveCriticalSection(&nc->cs); /* Consindering all that can go wrong here and the desire to handle errors here separately from others, we create a new task for the purpose of tracking the credentials acquisition process. */ _begin_task(KHERR_CF_TRANSITIVE); /* Describe the context */ if(nc->subtype == KMSG_CRED_NEW_CREDS) { cbsize = sizeof(wsinsert); kcdb_identity_get_name(nc->identities[0], wsinsert, &cbsize); _report_sr1(KHERR_NONE, IDS_CTX_PROC_NEW_CREDS, _cstr(wsinsert)); _resolve(); } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { cbsize = sizeof(wsinsert); if (nc->ctx.scope == KHUI_SCOPE_IDENT) kcdb_identity_get_name(nc->ctx.identity, wsinsert, &cbsize); else if (nc->ctx.scope == KHUI_SCOPE_CREDTYPE) { if (nc->ctx.identity != NULL) kcdb_identity_get_name(nc->ctx.identity, wsinsert, &cbsize); else kcdb_credtype_get_name(nc->ctx.cred_type, wsinsert, &cbsize); } else if (nc->ctx.scope == KHUI_SCOPE_CRED) { kcdb_cred_get_name(nc->ctx.cred, wsinsert, &cbsize); } else { StringCbCopy(wsinsert, sizeof(wsinsert), L"(?)"); } _report_sr1(KHERR_NONE, IDS_CTX_PROC_RENEW_CREDS, _cstr(wsinsert)); _resolve(); } else if (nc->subtype == KMSG_CRED_PASSWORD) { cbsize = sizeof(wsinsert); kcdb_identity_get_name(nc->identities[0], wsinsert, &cbsize); _report_sr1(KHERR_NONE, IDS_CTX_PROC_PASSWORD, _cstr(wsinsert)); _resolve(); } else { assert(FALSE); } _describe(); pending = khm_cred_dispatch_process_level(nc); _end_task(); if(!pending) goto _terminate_job; return; _terminate_job: if (nc->subtype == KMSG_CRED_RENEW_CREDS) kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, (void *) nc); else PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), 0); }
khm_int32 KHMAPI khm_get_identity_expiration_time(krb5_context ctx, krb5_ccache cc, khm_handle ident, krb5_timestamp * pexpiration) { krb5_principal principal = 0; char * princ_name = NULL; krb5_creds creds; krb5_error_code code; krb5_error_code cc_code; krb5_cc_cursor cur; krb5_timestamp now, expiration = 0; wchar_t w_ident_name[KCDB_IDENT_MAXCCH_NAME]; char ident_name[KCDB_IDENT_MAXCCH_NAME]; khm_size cb; khm_int32 rv = KHM_ERROR_NOT_FOUND; if (!ctx || !cc || !ident || !pexpiration) return KHM_ERROR_GENERAL; code = pkrb5_cc_get_principal(ctx, cc, &principal); if ( code ) return KHM_ERROR_INVALID_PARAM; cb = sizeof(w_ident_name); kcdb_identity_get_name(ident, w_ident_name, &cb); UnicodeStrToAnsi(ident_name, sizeof(ident_name), w_ident_name); code = pkrb5_unparse_name(ctx, principal, &princ_name); /* compare principal to ident. */ if ( code || !princ_name || strcmp(princ_name, ident_name) ) { if (princ_name) pkrb5_free_unparsed_name(ctx, princ_name); pkrb5_free_principal(ctx, principal); return KHM_ERROR_UNKNOWN; } pkrb5_free_unparsed_name(ctx, princ_name); pkrb5_free_principal(ctx, principal); code = pkrb5_timeofday(ctx, &now); if (code) return KHM_ERROR_UNKNOWN; 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 + TIMET_TOLERANCE) && (creds.times.endtime + TIMET_TOLERANCE) > 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 = KHM_ERROR_SUCCESS; *pexpiration = expiration; } return rv; }