#define _NIMLIB_
#include<khuidefs.h>
#include<utils.h>
#include<assert.h>
#include<strsafe.h>
#define CW_ALLOC_INCR 8
static void cw_free_prompts(khui_new_creds * c);
static void cw_free_prompt(khui_new_creds_prompt * p);
static khui_new_creds_prompt *
cw_create_prompt(
khm_size idx,
khm_int32 type,
wchar_t * prompt,
wchar_t * def,
khm_int32 flags);
KHMEXP khm_int32 KHMAPI
khui_cw_create_cred_blob(khui_new_creds ** ppnc)
{
khui_new_creds * c;
c = PMALLOC(sizeof(*c));
ZeroMemory(c, sizeof(*c));
c->magic = KHUI_NC_MAGIC;
InitializeCriticalSection(&c->cs);
c->result = KHUI_NC_RESULT_CANCEL;
c->mode = KHUI_NC_MODE_MINI;
khui_context_create(&c->ctx, KHUI_SCOPE_NONE, NULL, KCDB_CREDTYPE_INVALID, NULL);
*ppnc = c;
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_destroy_cred_blob(khui_new_creds *c)
{
khm_size i;
size_t len;
EnterCriticalSection(&c->cs);
for(i=0;i<c->n_identities;i++) {
kcdb_identity_release(c->identities[i]);
}
cw_free_prompts(c);
khui_context_release(&c->ctx);
LeaveCriticalSection(&c->cs);
DeleteCriticalSection(&c->cs);
if (c->password) {
len = wcslen(c->password);
SecureZeroMemory(c->password, sizeof(wchar_t) * len);
PFREE(c->password);
}
if (c->identities)
PFREE(c->identities);
if (c->types)
PFREE(c->types);
if (c->type_subs)
PFREE(c->type_subs);
if (c->window_title)
PFREE(c->window_title);
PFREE(c);
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_lock_nc(khui_new_creds * c)
{
EnterCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_unlock_nc(khui_new_creds * c)
{
LeaveCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
#define NC_N_IDENTITIES 4
KHMEXP khm_int32 KHMAPI
khui_cw_add_identity(khui_new_creds * c,
khm_handle id)
{
if(id == NULL)
return KHM_ERROR_SUCCESS;
EnterCriticalSection(&(c->cs));
if(c->identities == NULL) {
c->nc_identities = NC_N_IDENTITIES;
c->identities = PMALLOC(sizeof(*(c->identities)) *
c->nc_identities);
c->n_identities = 0;
} else if(c->n_identities + 1 > c->nc_identities) {
khm_handle * ni;
c->nc_identities = UBOUNDSS(c->n_identities + 1,
NC_N_IDENTITIES,
NC_N_IDENTITIES);
ni = PMALLOC(sizeof(*(c->identities)) * c->nc_identities);
memcpy(ni, c->identities,
sizeof(*(c->identities)) * c->n_identities);
PFREE(c->identities);
c->identities = ni;
}
kcdb_identity_hold(id);
c->identities[c->n_identities++] = id;
LeaveCriticalSection(&(c->cs));
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_set_primary_id(khui_new_creds * c,
khm_handle id)
{
khm_size i;
khm_int32 rv;
EnterCriticalSection(&c->cs);
if((c->n_identities > 0 && c->identities[0] == id) ||
(c->n_identities == 0 && id == NULL)) {
LeaveCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
for(i=0; i<c->n_identities; i++) {
kcdb_identity_release(c->identities[i]);
}
c->n_identities = 0;
LeaveCriticalSection(&(c->cs));
rv = khui_cw_add_identity(c,id);
if(c->hwnd != NULL) {
PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY,
MAKEWPARAM(0, WMNC_IDENTITY_CHANGE), 0);
}
return rv;
}
KHMEXP khm_int32 KHMAPI
khui_cw_add_type(khui_new_creds * c,
khui_new_creds_by_type * t)
{
EnterCriticalSection(&c->cs);
if(c->n_types >= KHUI_MAX_NCTYPES) {
LeaveCriticalSection(&c->cs);
return KHM_ERROR_OUT_OF_BOUNDS;
}
if(c->types == NULL) {
c->nc_types = CW_ALLOC_INCR;
c->types = PMALLOC(sizeof(*(c->types)) * c->nc_types);
c->type_subs = PMALLOC(sizeof(*(c->type_subs)) * c->nc_types);
c->n_types = 0;
}
if(c->nc_types < c->n_types + 1) {
void * t;
khm_size n;
n = UBOUNDSS(c->n_types + 1, CW_ALLOC_INCR, CW_ALLOC_INCR);
t = PMALLOC(sizeof(*(c->types)) * n);
memcpy(t, (void *) c->types, sizeof(*(c->types)) * c->n_types);
PFREE(c->types);
c->types = t;
t = PMALLOC(sizeof(*(c->type_subs)) * n);
memcpy(t, (void *) c->type_subs, sizeof(*(c->type_subs)) * c->n_types);
PFREE(c->type_subs);
c->type_subs = t;
c->nc_types = n;
}
c->type_subs[c->n_types] = kcdb_credtype_get_sub(t->type);
c->types[c->n_types++] = t;
t->nc = c;
LeaveCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_del_type(khui_new_creds * c,
khm_int32 type_id)
{
khm_size i;
EnterCriticalSection(&c->cs);
for(i=0; i < c->n_types; i++) {
if(c->types[i]->type == type_id)
break;
}
if(i >= c->n_types) {
LeaveCriticalSection(&c->cs);
return KHM_ERROR_NOT_FOUND;
}
c->n_types--;
for(;i < c->n_types; i++) {
c->types[i] = c->types[i+1];
c->type_subs[i] = c->type_subs[i+1];
}
LeaveCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_find_type(khui_new_creds * c,
khm_int32 type,
khui_new_creds_by_type **t)
{
khm_size i;
EnterCriticalSection(&c->cs);
*t = NULL;
for(i=0;i<c->n_types;i++) {
if(c->types[i]->type == type) {
*t = c->types[i];
break;
}
}
LeaveCriticalSection(&c->cs);
if(*t)
return KHM_ERROR_SUCCESS;
return KHM_ERROR_NOT_FOUND;
}
KHMEXP khm_int32 KHMAPI
khui_cw_enable_type(khui_new_creds * c,
khm_int32 type,
khm_boolean enable)
{
khui_new_creds_by_type * t = NULL;
BOOL delta = FALSE;
EnterCriticalSection(&c->cs);
if(KHM_SUCCEEDED(khui_cw_find_type(c, type, &t))) {
if(enable) {
delta = t->flags & KHUI_NCT_FLAG_DISABLED;
t->flags &= ~KHUI_NCT_FLAG_DISABLED;
}
else {
delta = !(t->flags & KHUI_NCT_FLAG_DISABLED);
t->flags |= KHUI_NCT_FLAG_DISABLED;
}
}
LeaveCriticalSection(&c->cs);
if(delta)
PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0,WMNC_TYPE_STATE), (LPARAM) type);
return (t)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND;
}
KHMEXP khm_boolean KHMAPI
khui_cw_type_succeeded(khui_new_creds * c,
khm_int32 type)
{
khui_new_creds_by_type * t;
khm_boolean s;
EnterCriticalSection(&c->cs);
if(KHM_SUCCEEDED(khui_cw_find_type(c, type, &t))) {
s = (t->flags & KHUI_NCT_FLAG_PROCESSED) && !(t->flags & KHUI_NC_RESPONSE_FAILED);
} else {
s = FALSE;
}
LeaveCriticalSection(&c->cs);
return s;
}
static khui_new_creds_prompt *
cw_create_prompt(khm_size idx,
khm_int32 type,
wchar_t * prompt,
wchar_t * def,
khm_int32 flags)
{
khui_new_creds_prompt * p;
size_t cb_prompt = 0;
size_t cb_def = 0;
if(prompt && FAILED(StringCbLength(prompt, KHUI_MAXCB_PROMPT, &cb_prompt)))
return NULL;
if(def && FAILED(StringCbLength(def, KHUI_MAXCB_PROMPT_VALUE, &cb_def)))
return NULL;
p = PMALLOC(sizeof(*p));
ZeroMemory(p, sizeof(*p));
if(prompt) {
cb_prompt += sizeof(wchar_t);
p->prompt = PMALLOC(cb_prompt);
StringCbCopy(p->prompt, cb_prompt, prompt);
}
if(def && cb_def > 0) {
cb_def += sizeof(wchar_t);
p->def = PMALLOC(cb_def);
StringCbCopy(p->def, cb_def, def);
}
p->value = PMALLOC(KHUI_MAXCB_PROMPT_VALUE);
ZeroMemory(p->value, KHUI_MAXCB_PROMPT_VALUE);
p->type = type;
p->flags = flags;
p->index = idx;
return p;
}
static void
cw_free_prompt(khui_new_creds_prompt * p) {
size_t cb;
if(p->prompt) {
if(SUCCEEDED(StringCbLength(p->prompt, KHUI_MAXCB_PROMPT, &cb)))
SecureZeroMemory(p->prompt, cb);
PFREE(p->prompt);
}
if(p->def) {
if(SUCCEEDED(StringCbLength(p->def, KHUI_MAXCB_PROMPT, &cb)))
SecureZeroMemory(p->def, cb);
PFREE(p->def);
}
if(p->value) {
if(SUCCEEDED(StringCbLength(p->value, KHUI_MAXCB_PROMPT_VALUE, &cb)))
SecureZeroMemory(p->value, cb);
PFREE(p->value);
}
PFREE(p);
}
static void
cw_free_prompts(khui_new_creds * c)
{
khm_size i;
if(c->banner != NULL) {
PFREE(c->banner);
c->banner = NULL;
}
if(c->pname != NULL) {
PFREE(c->pname);
c->pname = NULL;
}
for(i=0;i < c->n_prompts; i++) {
if(c->prompts[i]) {
cw_free_prompt(c->prompts[i]);
c->prompts[i] = NULL;
}
}
if(c->prompts != NULL) {
PFREE(c->prompts);
c->prompts = NULL;
}
c->nc_prompts = 0;
c->n_prompts = 0;
}
KHMEXP khm_int32 KHMAPI
khui_cw_clear_prompts(khui_new_creds * c)
{
SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY,
MAKEWPARAM(0,WMNC_CLEAR_PROMPTS), (LPARAM) c);
EnterCriticalSection(&c->cs);
cw_free_prompts(c);
LeaveCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_begin_custom_prompts(khui_new_creds * c,
khm_size n_prompts,
wchar_t * banner,
wchar_t * pname)
{
size_t cb;
PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY,
MAKEWPARAM(0,WMNC_CLEAR_PROMPTS), (LPARAM) c);
EnterCriticalSection(&c->cs);
#ifdef DEBUG
assert(c->n_prompts == 0);
#endif
cw_free_prompts(c);
if(SUCCEEDED(StringCbLength(banner, KHUI_MAXCB_BANNER, &cb)) &&
cb > 0) {
cb += sizeof(wchar_t);
c->banner = PMALLOC(cb);
StringCbCopy(c->banner, cb, banner);
} else {
c->banner = NULL;
}
if(SUCCEEDED(StringCbLength(pname, KHUI_MAXCB_PNAME, &cb)) &&
cb > 0) {
cb += sizeof(wchar_t);
c->pname = PMALLOC(cb);
StringCbCopy(c->pname, cb, pname);
} else {
c->pname = NULL;
}
if(n_prompts > 0) {
c->prompts = PMALLOC(sizeof(*(c->prompts)) * n_prompts);
ZeroMemory(c->prompts, sizeof(*(c->prompts)) * n_prompts);
c->nc_prompts = n_prompts;
c->n_prompts = 0;
} else {
c->prompts = NULL;
c->n_prompts = 0;
c->nc_prompts = 0;
PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY,
MAKEWPARAM(0, WMNC_SET_PROMPTS), (LPARAM) c);
}
LeaveCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_add_prompt(khui_new_creds * c,
khm_int32 type,
wchar_t * prompt,
wchar_t * def,
khm_int32 flags)
{
khui_new_creds_prompt * p;
if(c->nc_prompts == 0 ||
c->n_prompts == c->nc_prompts)
return KHM_ERROR_INVALID_OPERATION;
#ifdef DEBUG
assert(c->prompts != NULL);
#endif
EnterCriticalSection(&c->cs);
p = cw_create_prompt(c->n_prompts, type, prompt, def, flags);
if(p == NULL) {
LeaveCriticalSection(&c->cs);
return KHM_ERROR_INVALID_PARAM;
}
c->prompts[c->n_prompts++] = p;
LeaveCriticalSection(&c->cs);
if(c->n_prompts == c->nc_prompts) {
PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY,
MAKEWPARAM(0, WMNC_SET_PROMPTS), (LPARAM) c);
#if 0
SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY,
MAKEWPARAM(0, WMNC_DIALOG_SWITCH_PANEL),
(LPARAM) c);
#endif
}
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_get_prompt_count(khui_new_creds * c,
khm_size * np) {
EnterCriticalSection(&c->cs);
*np = c->n_prompts;
LeaveCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_get_prompt(khui_new_creds * c,
khm_size idx,
khui_new_creds_prompt ** prompt)
{
khm_int32 rv;
EnterCriticalSection(&c->cs);
if(c->n_prompts <= idx ||
c->prompts == NULL) {
rv = KHM_ERROR_OUT_OF_BOUNDS;
*prompt = NULL;
} else {
*prompt = c->prompts[idx];
rv = KHM_ERROR_SUCCESS;
}
LeaveCriticalSection(&c->cs);
return rv;
}
void
khuiint_trim_str(wchar_t * s, khm_size cch) {
wchar_t * c, * last_ws;
for (c = s; *c && iswspace(*c) && ((khm_size)(c - s)) < cch; c++);
if (((khm_size)(c - s)) >= cch)
return;
if (c != s && ((khm_size)(c - s)) < cch) {
#if _MSC_VER >= 1400 && __STDC_WANT_SECURE_LIB__
wmemmove_s(s, cch, c, cch - ((khm_size)(c - s)));
#else
memmove(s, c, (cch - ((khm_size)(c - s)))* sizeof(wchar_t));
#endif
}
last_ws = NULL;
for (c = s; *c && ((khm_size)(c - s)) < cch; c++) {
if (!iswspace(*c))
last_ws = NULL;
else if (last_ws == NULL)
last_ws = c;
}
if (last_ws)
*last_ws = L'\0';
}
KHMEXP khm_int32 KHMAPI
khui_cw_sync_prompt_values(khui_new_creds * c)
{
khm_size i;
khm_size n;
HWND hw;
wchar_t tmpbuf[KHUI_MAXCCH_PROMPT_VALUE];
EnterCriticalSection(&c->cs);
redo_loop:
n = c->n_prompts;
for(i=0; i<n; i++) {
khui_new_creds_prompt * p;
p = c->prompts[i];
if(p->hwnd_edit) {
hw = p->hwnd_edit;
LeaveCriticalSection(&c->cs);
GetWindowText(hw, tmpbuf, ARRAYLENGTH(tmpbuf));
khuiint_trim_str(tmpbuf, ARRAYLENGTH(tmpbuf));
EnterCriticalSection(&c->cs);
if (n != c->n_prompts)
goto redo_loop;
SecureZeroMemory(p->value, KHUI_MAXCB_PROMPT_VALUE);
StringCchCopy(p->value, KHUI_MAXCCH_PROMPT_VALUE,
tmpbuf);
}
}
LeaveCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_get_prompt_value(khui_new_creds * c,
khm_size idx,
wchar_t * buf,
khm_size *cbbuf)
{
khui_new_creds_prompt * p;
khm_int32 rv;
size_t cb;
rv = khui_cw_get_prompt(c, idx, &p);
if(KHM_FAILED(rv))
return rv;
EnterCriticalSection(&c->cs);
if(FAILED(StringCbLength(p->value, KHUI_MAXCB_PROMPT_VALUE, &cb))) {
*cbbuf = 0;
if(buf != NULL)
*buf = 0;
LeaveCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
cb += sizeof(wchar_t);
if(buf == NULL || *cbbuf < cb) {
*cbbuf = cb;
LeaveCriticalSection(&c->cs);
return KHM_ERROR_TOO_LONG;
}
StringCbCopy(buf, *cbbuf, p->value);
*cbbuf = cb;
LeaveCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_set_response(khui_new_creds * c,
khm_int32 type,
khm_int32 response)
{
khui_new_creds_by_type * t = NULL;
EnterCriticalSection(&c->cs);
khui_cw_find_type(c, type, &t);
c->response |= response & KHUI_NCMASK_RESPONSE;
if(t) {
t->flags &= ~KHUI_NCMASK_RESULT;
t->flags |= (response & KHUI_NCMASK_RESULT);
if (!(response & KHUI_NC_RESPONSE_NOEXIT) &&
!(response & KHUI_NC_RESPONSE_PENDING))
t->flags |= KHUI_NC_RESPONSE_COMPLETED;
}
LeaveCriticalSection(&c->cs);
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khui_cw_add_control_row(khui_new_creds * c,
HWND label,
HWND input,
khui_control_size size)
{
if (c && c->hwnd) {
khui_control_row row;
row.label = label;
row.input = input;
row.size = size;
SendMessage(c->hwnd,
KHUI_WM_NC_NOTIFY,
MAKEWPARAM(0, WMNC_ADD_CONTROL_ROW),
(LPARAM) &row);
return KHM_ERROR_SUCCESS;
} else {
return KHM_ERROR_INVALID_PARAM;
}
}