/* Note: This callback runs under the UI thread */ INT_PTR handle_wm_initdialog(HWND hwnd, WPARAM wParam, LPARAM lParam) { khui_new_creds * nc = NULL; khui_new_creds_by_type * nct = NULL; struct nc_dialog_data * d = NULL; nc = (khui_new_creds *) lParam; khui_cw_find_type(nc, credtype_id, &nct); assert(nct); d = malloc(sizeof(*d)); ZeroMemory(d, sizeof(*d)); d->nc = nc; d->nct = nct; #pragma warning(push) #pragma warning(disable: 4244) SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); #pragma warning(pop) nct->aux = (LPARAM) d; /* we can use the auxiliary field to hold a pointer to d */ /* TODO: Perform any additional initialization here */ return FALSE; }
/* this is called by khm_cred_dispatch_process_message and the kmsg_cred_completion to initiate and continue checked broadcasts of KMSG_CRED_DIALOG_PROCESS messages. Returns TRUE if more KMSG_CRED_DIALOG_PROCESS messages were posted. */ BOOL khm_cred_dispatch_process_level(khui_new_creds *nc) { khm_size i,j; khm_handle subs[KHUI_MAX_NCTYPES]; int n_subs = 0; BOOL cont = FALSE; khui_new_creds_by_type *t, *d; /* at each level, we dispatch a wave of notifications to plug-ins who's dependencies are all satisfied */ EnterCriticalSection(&nc->cs); /* if any types have already completed, we mark them are processed and skip them */ for (i=0; i < nc->n_types; i++) { t = nc->types[i]; if(t->flags & KHUI_NC_RESPONSE_COMPLETED) t->flags |= KHUI_NCT_FLAG_PROCESSED; } for(i=0; i<nc->n_types; i++) { t = nc->types[i]; if((t->flags & KHUI_NCT_FLAG_PROCESSED) || (t->flags & KHUI_NC_RESPONSE_COMPLETED)) continue; for(j=0; j<t->n_type_deps; j++) { if(KHM_FAILED(khui_cw_find_type(nc, t->type_deps[j], &d))) break; if(!(d->flags & KHUI_NC_RESPONSE_COMPLETED)) break; } if(j<t->n_type_deps) /* there are unmet dependencies */ continue; /* all dependencies for this type have been met. */ subs[n_subs++] = kcdb_credtype_get_sub(t->type); t->flags |= KHUI_NCT_FLAG_PROCESSED; cont = TRUE; } LeaveCriticalSection(&nc->cs); /* the reason why we are posting messages in batches is because when the message has completed we know that all the types that have the KHUI_NCT_FLAG_PROCESSED set have completed processing. Otherwise we have to individually track each message and update the type */ if(n_subs > 0) kmq_post_subs_msg(subs, n_subs, KMSG_CRED, KMSG_CRED_PROCESS, 0, (void *) nc); return cont; }
/* Note: This callback runs under the UI thread */ INT_PTR handle_wm_initdialog(HWND hwnd, WPARAM wParam, LPARAM lParam) { khui_new_creds * nc = NULL; struct nc_dialog_data * d = NULL; nc = (khui_new_creds *) lParam; khui_cw_find_type(nc, credtype_id, (khui_new_creds_by_type **) &d); assert(d); #pragma warning(push) #pragma warning(disable: 4244) SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); #pragma warning(pop) /* TODO: Perform any additional initialization here */ return FALSE; }
/* Handler for KMSG_CRED_END */ khm_int32 handle_kmsg_cred_end(khui_new_creds * nc) { struct nc_dialog_data * d; /* TODO: Perform any additional uninitialization as needed. */ khui_cw_find_type(nc, credtype_id, (khui_new_creds_by_type **) &d); if (d) { khui_cw_del_type(nc, credtype_id); if (d->nct.name) free(d->nct.name); free(d); } return KHM_ERROR_SUCCESS; }
/* Handler for KMSG_CRED_END */ khm_int32 handle_kmsg_cred_end(khui_new_creds * nc) { khui_new_creds_by_type * nct = NULL; /* TODO: Perform any additional uninitialization as needed. */ khui_cw_find_type(nc, credtype_id, &nct); if (nct) { khui_cw_del_type(nc, credtype_id); if (nct->name) free(nct->name); if (nct->credtext) free(nct->credtext); free(nct); } return KHM_ERROR_SUCCESS; }
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; }
INT_PTR CALLBACK k4_nc_dlg_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { k4_dlg_data * d; switch(uMsg) { case WM_INITDIALOG: { d = PMALLOC(sizeof(*d)); ZeroMemory(d, sizeof(*d)); d->nc = (khui_new_creds *) lParam; khui_cw_find_type(d->nc, credtype_id_krb4, &d->nct); #pragma warning(push) #pragma warning(disable: 4244) SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); #pragma warning(pop) d->nct->aux = (LPARAM) d; d->hwnd = hwnd; d->k4_enabled = TRUE; d->method = K4_METHOD_AUTO; k4_update_display(d, TRUE); } break; case WM_COMMAND: { if (HIWORD(wParam) == BN_CLICKED) { d = (k4_dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); if (d == NULL) break; k4_update_data(d); if (LOWORD(wParam) == IDC_NCK4_OBTAIN) { k4_update_display(d, TRUE); } return TRUE; } } break; case KHUI_WM_NC_NOTIFY: { d = (k4_dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); if (d == NULL) break; k4_handle_wmnc_notify(d, wParam, lParam); } break; case WM_DESTROY: { d = (k4_dlg_data *) (LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); if (d == NULL) break; d->nct->aux = 0; PFREE(d); SetWindowLongPtr(hwnd, DWLP_USER, 0); } 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; }