From c62c877fa6a83f18df377dd753ff6b7abbadcacf Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Fri, 17 Nov 2006 19:29:54 +0000 Subject: [PATCH] pull up r18828 from trunk r18828@cathode-dark-space: jaltman | 2006-11-17 12:23:24 -0500 ticket: new subject: commits for KFW 3.1 Beta 4 tags: pullup KfW 3.1 beta 4 (NetIDMgr 1.1.6.0) nidmgr32.dll (1.1.6.0) - Fix a race condition where the initialization process might be flagged as complete even if the identity provider hasn't finished initialization yet. krb5cred.dll (1.1.6.0) - When assigning the default credentials cache for each identity, favor API and FILE caches over MSLSA if they exist. - When renewing an identity which was the result of importing credentials from the MSLSA cache, attempt to re-import the credentials from MSLSA instead of renewing the imported credentials. - Prevent possible crash if a Kerberos 5 context could not be obtained during the renewal operation. - Prevent memory leak in the credentials destroy handler due to the failure to free a Kerberos 5 context. - Properly match principals and realms when importing credentials from the MSLSA cache. - Determine the correct credentials cache to place imported credentials in by checking the configuration for preferred cache name. - Keep track of identities where credentials imports have occurred. - When setting the default identity, ignore the KRB5CCNAME environment variable. - Do not re-compute the credentials cache and timestamps when updating an identity. The cache and timestamp information is computed when listing credentials and do not change between listing and identity update. - When refreshing the default identity, also handle the case where the default credentials cache does not contain a principal, but the name of the cache can be used to infer the principal name. - Invoke a listing of credentials after a successful import. - Do not free a Kerberos 5 context prematurely during plug-in initialization. netidmgr.exe (1.1.6.0) - Fix the UI context logic to handle layouts which aren't based around identities. - Don't try to show a property sheet when there are no property pages supplied for the corresponding UI context. - Use consistent context menus. - Bring a modal dialog box to the foreground when it should be active. - Do not accept action triggers when the application is not ready to process actions yet. - Do not force the new credentials dialog to the top if there's already a modal dialog box showing. - Change the default per-identity layout to also group by location. ticket: 4798 version_fixed: 1.4.5 git-svn-id: svn://anonsvn.mit.edu/krb5/branches/krb5-1-4@18829 dc483132-0cff-0310-8789-dd5450dbe970 --- src/windows/identity/config/Makefile.w2k | 2 +- src/windows/identity/config/Makefile.w32 | 2 +- src/windows/identity/kcreddb/identity.c | 2 +- src/windows/identity/plugins/krb5/krb5funcs.c | 447 +++++++++++++++--- src/windows/identity/plugins/krb5/krb5funcs.h | 15 +- .../identity/plugins/krb5/krb5identpro.c | 254 +++++----- src/windows/identity/plugins/krb5/krb5main.c | 28 ++ .../identity/plugins/krb5/krb5newcreds.c | 13 +- .../identity/plugins/krb5/krb5plugin.c | 6 +- src/windows/identity/plugins/krb5/krbcred.h | 7 + src/windows/identity/ui/credwnd.c | 65 ++- src/windows/identity/ui/main.c | 9 +- src/windows/identity/ui/mainwnd.c | 15 + src/windows/identity/ui/newcredwnd.c | 11 +- src/windows/identity/ui/uiconfig.csv | 9 +- 15 files changed, 679 insertions(+), 206 deletions(-) diff --git a/src/windows/identity/config/Makefile.w2k b/src/windows/identity/config/Makefile.w2k index 9e62821ba..c3c7f030f 100644 --- a/src/windows/identity/config/Makefile.w2k +++ b/src/windows/identity/config/Makefile.w2k @@ -47,7 +47,7 @@ KHIMAIRA_WIN32_CONFIG=1 # Version info NETIDMGR_VERSION_MAJOR=1 NETIDMGR_VERSION_MINOR=1 -NETIDMGR_VERSION_PATCH=4 +NETIDMGR_VERSION_PATCH=6 NETIDMGR_VERSION_AUX=0 NETIDMGR_RELEASEDESC= diff --git a/src/windows/identity/config/Makefile.w32 b/src/windows/identity/config/Makefile.w32 index c63ed0d11..e5bb18f9a 100644 --- a/src/windows/identity/config/Makefile.w32 +++ b/src/windows/identity/config/Makefile.w32 @@ -47,7 +47,7 @@ KHIMAIRA_WIN32_CONFIG=1 # Version info NETIDMGR_VERSION_MAJOR=1 NETIDMGR_VERSION_MINOR=1 -NETIDMGR_VERSION_PATCH=4 +NETIDMGR_VERSION_PATCH=6 NETIDMGR_VERSION_AUX=0 NETIDMGR_RELEASEDESC= diff --git a/src/windows/identity/kcreddb/identity.c b/src/windows/identity/kcreddb/identity.c index 3e9f394ec..6057b6f2c 100644 --- a/src/windows/identity/kcreddb/identity.c +++ b/src/windows/identity/kcreddb/identity.c @@ -64,7 +64,7 @@ kcdb_identity_set_provider(khm_handle sub) kcdb_ident_sub = sub; if (kcdb_ident_sub) - kmq_post_sub_msg(kcdb_ident_sub, + kmq_send_sub_msg(kcdb_ident_sub, KMSG_IDENT, KMSG_IDENT_INIT, 0, diff --git a/src/windows/identity/plugins/krb5/krb5funcs.c b/src/windows/identity/plugins/krb5/krb5funcs.c index 331e789dc..0ce676caf 100644 --- a/src/windows/identity/plugins/krb5/krb5funcs.c +++ b/src/windows/identity/plugins/krb5/krb5funcs.c @@ -36,6 +36,7 @@ modified and adapted for NetIDMgr */ #include #include +#include #include #include @@ -199,6 +200,150 @@ int com_addr(void) } #endif +/* we use these structures to keep track of identities that we find + while going through the API, FILE and MSLSA caches and enumerating + credentials. The only identities we want to keep track of are the + ones that have an initial ticket. We collect information for each + of the identities we find that we have initial tickets for and + then set the properties for the identities at once. */ + +typedef struct tag_ident_data { + khm_handle ident; /* handle to the identity */ + khm_int32 count; /* number of initial tickets we have + found for this identity. */ + wchar_t ccname[MAX_PATH]; + FILETIME ft_issue; + FILETIME ft_expire; + FILETIME ft_renewexpire; + khm_int32 krb5_flags; +} ident_data; + +typedef struct tag_identlist { + ident_data * list; + khm_size n_list; + khm_size nc_list; +} identlist; + +#define IDLIST_ALLOC_INCR 8 + +static void +tc_prep_idlist(identlist * idlist) { + idlist->list = NULL; + idlist->n_list = 0; + idlist->nc_list = 0; +} + +static ident_data * +tc_add_ident_to_list(identlist * idlist, khm_handle ident) { + khm_size i; + ident_data * d; + + for (i=0; i < idlist->n_list; i++) { + if (kcdb_identity_is_equal(ident, idlist->list[i].ident)) + break; + } + + if (i < idlist->n_list) { + /* we already have this identity on our list. Increment the + count */ + idlist->list[i].count++; + return &idlist->list[i]; + } + + /* it wasn't in our list. Add it */ + + if (idlist->n_list + 1 > idlist->nc_list) { + idlist->nc_list = UBOUNDSS(idlist->n_list + 1, + IDLIST_ALLOC_INCR, + IDLIST_ALLOC_INCR); +#ifdef DEBUG + assert(idlist->n_list + 1 <= idlist->nc_list); +#endif + idlist->list = PREALLOC(idlist->list, + sizeof(idlist->list[0]) * idlist->nc_list); +#ifdef DEBUG + assert(idlist->list); +#endif + ZeroMemory(&idlist->list[idlist->n_list], + sizeof(idlist->list[0]) * + (idlist->nc_list - idlist->n_list)); + } + + d = &idlist->list[idlist->n_list]; + + ZeroMemory(d, sizeof(*d)); + + d->ident = ident; + d->count = 1; + + idlist->n_list++; + + kcdb_identity_hold(ident); + + return d; +} + +static void +tc_set_ident_data(identlist * idlist) { + khm_size i; + + for (i=0; i < idlist->n_list; i++) { +#ifdef DEBUG + assert(idlist->list[i].ident); +#endif + + kcdb_identity_set_attr(idlist->list[i].ident, + attr_id_krb5_ccname, + idlist->list[i].ccname, + KCDB_CBSIZE_AUTO); + + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_EXPIRE, + &idlist->list[i].ft_expire, + sizeof(idlist->list[i].ft_expire)); + + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_ISSUE, + &idlist->list[i].ft_issue, + sizeof(idlist->list[i].ft_issue)); + + kcdb_identity_set_attr(idlist->list[i].ident, + attr_id_krb5_flags, + &idlist->list[i].krb5_flags, + sizeof(idlist->list[i].krb5_flags)); + + if (idlist->list[i].ft_renewexpire.dwLowDateTime == 0 && + idlist->list[i].ft_renewexpire.dwHighDateTime == 0) { + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } else { + kcdb_identity_set_attr(idlist->list[i].ident, + KCDB_ATTR_RENEW_EXPIRE, + &idlist->list[i].ft_renewexpire, + sizeof(idlist->list[i].ft_renewexpire)); + } + } +} + +static void +tc_free_idlist(identlist * idlist) { + khm_size i; + + for (i=0; i < idlist->n_list; i++) { + if (idlist->list[i].ident != NULL) { + kcdb_identity_release(idlist->list[i].ident); + idlist->list[i].ident = NULL; + } + } + + if (idlist->list) + PFREE(idlist->list); + idlist->list = NULL; + idlist->n_list = 0; + idlist->nc_list = 0; +} + #ifndef ENCTYPE_LOCAL_RC4_MD4 #define ENCTYPE_LOCAL_RC4_MD4 0xFFFFFF80 #endif @@ -206,7 +351,8 @@ int com_addr(void) #define MAX_ADDRS 256 static long get_tickets_from_cache(krb5_context ctx, - krb5_ccache cache) + krb5_ccache cache, + identlist * idlist) { krb5_error_code code; krb5_principal KRBv5Principal; @@ -257,6 +403,8 @@ static long get_tickets_from_cache(krb5_context ctx, } } + _reportf(L"Getting tickets from cache [%s]", wcc_name); + if ((code = (*pkrb5_cc_set_flags)(ctx, cache, flags))) { if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND) @@ -305,6 +453,8 @@ static long get_tickets_from_cache(krb5_context ctx, goto _exit; } + _reportf(L"Found principal [%s]", wbuf); + (*pkrb5_free_principal)(ctx, KRBv5Principal); if ((code = (*pkrb5_cc_start_seq_get)(ctx, cache, &KRBv5Cursor))) @@ -478,12 +628,15 @@ static long get_tickets_from_cache(krb5_context ctx, FILETIME ft_issue_new; FILETIME ft_expire_old; FILETIME ft_expire_new; - khm_size cb; + ident_data * d; - /* an initial ticket! If we find one, we generally set - the lifetime, and primary ccache based on this, but - only if this initial cred has a greater lifetime than - the current primary credential. */ + /* an initial ticket! Add it to the list of identities we + have seen so far with initial tickets. */ + d = tc_add_ident_to_list(idlist, ident); +#ifdef DEBUG + assert(d); + assert(d->count > 0); +#endif tt = KRBv5Credentials.times.endtime; TimetToFileTime(tt, &ft_expire_new); @@ -491,37 +644,40 @@ static long get_tickets_from_cache(krb5_context ctx, tt = KRBv5Credentials.times.starttime; TimetToFileTime(tt, &ft_issue_new); - cb = sizeof(ft_expire_old); - if(KHM_FAILED(kcdb_identity_get_attr(tident, - KCDB_ATTR_EXPIRE, - NULL, &ft_expire_old, - &cb)) - || CompareFileTime(&ft_expire_new, &ft_expire_old) > 0) { - - kcdb_identity_set_attr(tident, attr_id_krb5_ccname, - wcc_name, KCDB_CBSIZE_AUTO); - kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, - &ft_expire_new, - sizeof(ft_expire_new)); - kcdb_identity_set_attr(tident, KCDB_ATTR_ISSUE, - &ft_issue_new, - sizeof(ft_issue_new)); + /* so now, we have to set the properties of the identity + based on the properties of this credential under the + following circumstances: + + - If this is the first time we are hitting this + identity. + + - If this is not the MSLSA: cache and the expiry time + for this credential is longer than the time already + found for this identity. + */ + + ft_expire_old = d->ft_expire; + + if(d->count == 1 + || (CompareFileTime(&ft_expire_new, &ft_expire_old) > 0 && + wcscmp(wcc_name, L"MSLSA:") != 0)) { + + _reportf(L"Setting properties for identity (count=%d)", d->count); + + StringCbCopy(d->ccname, sizeof(d->ccname), + wcc_name); + d->ft_expire = ft_expire_new; + d->ft_issue = ft_issue_new; if (KRBv5Credentials.times.renew_till > 0) { tt = KRBv5Credentials.times.renew_till; TimetToFileTime(tt, &ft); - kcdb_identity_set_attr(tident, - KCDB_ATTR_RENEW_EXPIRE, - &ft, sizeof(ft)); + d->ft_renewexpire = ft; } else { - kcdb_identity_set_attr(tident, - KCDB_ATTR_RENEW_EXPIRE, - NULL, 0); + ZeroMemory(&d->ft_renewexpire, sizeof(d->ft_renewexpire)); } - ti = KRBv5Credentials.ticket_flags; - kcdb_identity_set_attr(tident, attr_id_krb5_flags, - &ti, sizeof(ti)); + d->krb5_flags = KRBv5Credentials.ticket_flags; } } @@ -583,8 +739,10 @@ khm_krb5_list_tickets(krb5_context *krbv5Context) khm_int32 t; wchar_t * ms = NULL; khm_size cb; + identlist idl; kcdb_credset_flush(krb5_credset); + tc_prep_idlist(&idl); if((*krbv5Context == 0) && (code = (*pkrb5_init_context)(krbv5Context))) { goto _exit; @@ -621,7 +779,7 @@ khm_krb5_list_tickets(krb5_context *krbv5Context) if (code) continue; - code = get_tickets_from_cache(ctx, cache); + code = get_tickets_from_cache(ctx, cache, &idl); if(ctx != NULL && cache != NULL) (*pkrb5_cc_close)(ctx, cache); @@ -631,18 +789,6 @@ khm_krb5_list_tickets(krb5_context *krbv5Context) _skip_cc_iter: - if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) { - code = (*pkrb5_cc_resolve)(ctx, "MSLSA:", &cache); - - if (code == 0 && cache) { - code = get_tickets_from_cache(ctx, cache); - } - - if (ctx != NULL && cache != NULL) - (*pkrb5_cc_close)(ctx, cache); - cache = 0; - } - if (khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) == KHM_ERROR_TOO_LONG && cb > sizeof(wchar_t) * 2) { @@ -664,7 +810,7 @@ khm_krb5_list_tickets(krb5_context *krbv5Context) if (code) continue; - code = get_tickets_from_cache(ctx, cache); + code = get_tickets_from_cache(ctx, cache, &idl); if (ctx != NULL && cache != NULL) (*pkrb5_cc_close)(ctx, cache); @@ -674,6 +820,18 @@ khm_krb5_list_tickets(krb5_context *krbv5Context) PFREE(ms); } + if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) { + code = (*pkrb5_cc_resolve)(ctx, "MSLSA:", &cache); + + if (code == 0 && cache) { + code = get_tickets_from_cache(ctx, cache, &idl); + } + + if (ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + cache = 0; + } + _exit: if (pNCi) (*pcc_free_NC_info)(cc_ctx, &pNCi); @@ -681,6 +839,8 @@ _exit: (*pcc_shutdown)(&cc_ctx); kcdb_credset_collect(NULL, krb5_credset, NULL, credtype_id_krb5, NULL); + tc_set_ident_data(&idl); + tc_free_idlist(&idl); return(code); } @@ -842,12 +1002,34 @@ khm_krb5_renew_ident(khm_handle identity) krb5_principal server = NULL; krb5_creds my_creds; krb5_data *realm = NULL; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + char cidname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; memset(&my_creds, 0, sizeof(krb5_creds)); if ( !pkrb5_init_context ) goto cleanup; + cb = sizeof(idname); + kcdb_identity_get_name(identity, idname, &cb); + + if (khm_krb5_get_identity_flags(identity) & K5IDFLAG_IMPORTED) { + /* we are trying to renew the identity that was imported from + MSLSA: */ + BOOL imported; + + UnicodeStrToAnsi(cidname, sizeof(cidname), idname); + + imported = khm_krb5_ms2mit(cidname, FALSE, TRUE); + + if (imported) + goto cleanup; + + /* if the import failed, then we try to renew the identity via + the usual procedure. */ + } + code = khm_krb5_initialize(identity, &ctx, &cc); if (code) goto cleanup; @@ -896,16 +1078,18 @@ cleanup: if (my_creds.server == server) my_creds.server = NULL; - pkrb5_free_cred_contents(ctx, &my_creds); + if (ctx) { + pkrb5_free_cred_contents(ctx, &my_creds); - if (me) - pkrb5_free_principal(ctx, me); - if (server) - pkrb5_free_principal(ctx, server); - if (cc) - pkrb5_cc_close(ctx, cc); - if (ctx) + if (me) + pkrb5_free_principal(ctx, me); + if (server) + pkrb5_free_principal(ctx, server); + if (cc) + pkrb5_cc_close(ctx, cc); pkrb5_free_context(ctx); + } + return(code); } @@ -1356,7 +1540,7 @@ khm_krb5_destroy_by_credset(khm_handle p_cs) khm_handle d_cs = NULL; khm_int32 rv = KHM_ERROR_SUCCESS; khm_size s, cb; - krb5_context ctx; + krb5_context ctx = NULL; krb5_error_code code = 0; int i; wchar_t ccname[KRB5_MAXCCH_CCNAME]; @@ -1636,6 +1820,9 @@ khm_krb5_destroy_by_credset(khm_handle p_cs) if (d_cs) kcdb_credset_delete(&d_cs); + if (ctx != NULL) + pkrb5_free_context(ctx); + return rv; } @@ -1727,7 +1914,7 @@ IsKerberosLogon(VOID) BOOL -khm_krb5_ms2mit(BOOL save_creds) +khm_krb5_ms2mit(char * match_princ, BOOL match_realm, BOOL save_creds) { #ifdef NO_KRB5 return(FALSE); @@ -1739,6 +1926,9 @@ khm_krb5_ms2mit(BOOL save_creds) krb5_creds creds; krb5_cc_cursor cursor=0; krb5_principal princ = 0; + khm_handle ident = NULL; + wchar_t wname[KCDB_IDENT_MAXCCH_NAME]; + char cname[KCDB_IDENT_MAXCCH_NAME]; char *cache_name = NULL; char *princ_name = NULL; BOOL rc = FALSE; @@ -1765,10 +1955,89 @@ khm_krb5_ms2mit(BOOL save_creds) if (code = pkrb5_unparse_name(kcontext, princ, &princ_name)) goto cleanup; - kherr_reportf(L"Unparsed [%S]. Resolving target cache\n", princ_name); - /* TODO: actually look up the preferred ccache name */ - if (code = pkrb5_cc_resolve(kcontext, princ_name, &ccache)) { - kherr_reportf(L"Cannot resolve cache [%S] with code=%d. Trying default.\n", princ_name, code); + AnsiStrToUnicode(wname, sizeof(wname), princ_name); + + kherr_reportf(L"Unparsed name [%s]", wname); + + /* see if we have to match a specific principal */ + if (match_princ != NULL) { + if (strcmp(princ_name, match_princ)) { + kherr_reportf(L"Principal mismatch. Wanted [%S], found [%S]", + match_princ, princ_name); + goto cleanup; + } + } else if (match_realm) { + wchar_t * wdefrealm; + char defrealm[256]; + krb5_data * princ_realm; + + wdefrealm = khm_krb5_get_default_realm(); + if (wdefrealm == NULL) { + kherr_reportf(L"Can't determine default realm"); + goto cleanup; + } + + princ_realm = krb5_princ_realm(kcontext, princ); + UnicodeStrToAnsi(defrealm, sizeof(defrealm), wdefrealm); + + if (strncmp(defrealm, princ_realm->data, princ_realm->length)) { + kherr_reportf(L"Realm mismatch. Wanted [%S], found [%*S]", + defrealm, princ_realm->length, princ_realm->data); + PFREE(wdefrealm); + goto cleanup; + } + + PFREE(wdefrealm); + } + + if (KHM_SUCCEEDED(kcdb_identity_create(wname, + KCDB_IDENT_FLAG_CREATE, + &ident))) { + khm_handle idconfig = NULL; + khm_handle k5config = NULL; + khm_size cb; + + wname[0] = L'\0'; + + kcdb_identity_get_config(ident, 0, &idconfig); + if (idconfig == NULL) + goto _done_checking_config; + + khc_open_space(idconfig, CSNAME_KRB5CRED, 0, &k5config); + if (k5config == NULL) + goto _done_checking_config; + + cb = sizeof(wname); + khc_read_string(k5config, + L"DefaultCCName", + wname, &cb); + + _done_checking_config: + + if (idconfig) + khc_close_space(idconfig); + if (k5config) + khc_close_space(k5config); + + if (wname[0]) { + UnicodeStrToAnsi(cname, sizeof(cname), wname); + } else { + StringCbPrintfA(cname, sizeof(cname), "API:%s", princ_name); + } + + cache_name = cname; + + } else { + /* the identity could not be created. we just use the + name of the principal as the ccache name. */ + StringCbPrintfA(cname, sizeof(cname), "API:%s", princ_name); + cache_name = cname; + } + + kherr_reportf(L"Resolving target cache [%S]\n", cache_name); + + if (code = pkrb5_cc_resolve(kcontext, cache_name, &ccache)) { + kherr_reportf(L"Cannot resolve cache [%S] with code=%d. Trying default.\n", cache_name, code); if (code = pkrb5_cc_default(kcontext, &ccache)) { kherr_reportf(L"Failed to resolve default ccache. Code=%d", code); @@ -1784,6 +2053,11 @@ khm_krb5_ms2mit(BOOL save_creds) if (code = pkrb5_cc_copy_creds(kcontext, mslsa_ccache, ccache)) goto cleanup; + /* and mark the identity as having been imported */ + if (ident) { + khm_krb5_set_identity_flags(ident, K5IDFLAG_IMPORTED, K5IDFLAG_IMPORTED); + } + rc = TRUE; } else { /* Enumerate tickets from cache looking for an initial ticket */ @@ -2078,7 +2352,7 @@ khm_krb5_get_realm_list(void) \brief Get the default realm A string will be returned that specifies the default realm. The - caller should free the string using free(). + caller should free the string using PFREE(). Returns NULL if the operation fails. */ @@ -2259,3 +2533,58 @@ khm_krb5_creds_is_equal(khm_handle vcred1, khm_handle vcred2, void * dummy) { else return 0; } + +void +khm_krb5_set_identity_flags(khm_handle identity, + khm_int32 flag_mask, + khm_int32 flag_value) { + + khm_int32 t = 0; + khm_size cb; + + cb = sizeof(t); + if (KHM_FAILED(kcdb_identity_get_attr(identity, + attr_id_krb5_idflags, + NULL, + &t, &cb))) { + t = 0; + } + + t &= ~flag_mask; + t |= flag_value | flag_mask; + + kcdb_identity_set_attr(identity, + attr_id_krb5_idflags, + &t, sizeof(t)); +} + +khm_int32 +khm_krb5_get_identity_flags(khm_handle identity) { + khm_int32 t = 0; + khm_size cb; + + cb = sizeof(t); + kcdb_identity_get_attr(identity, + attr_id_krb5_idflags, + NULL, &t, &cb); + + return t; +} + +long +khm_krb5_get_temp_ccache(krb5_context ctx, + krb5_ccache * prcc) { + int rnd = rand(); + char ccname[MAX_PATH]; + long code = 0; + krb5_ccache cc = 0; + + StringCbPrintfA(ccname, sizeof(ccname), "API:TempCache%8x", rnd); + + code = pkrb5_cc_resolve(ctx, ccname, &cc); + + if (code == 0) + *prcc = cc; + + return code; +} diff --git a/src/windows/identity/plugins/krb5/krb5funcs.h b/src/windows/identity/plugins/krb5/krb5funcs.h index d69950836..ece4f7908 100644 --- a/src/windows/identity/plugins/krb5/krb5funcs.h +++ b/src/windows/identity/plugins/krb5/krb5funcs.h @@ -53,7 +53,9 @@ // Function Prototypes. BOOL -khm_krb5_ms2mit(BOOL); +khm_krb5_ms2mit(char * match_princ, + BOOL match_realm, + BOOL save_creds); int khm_krb5_kinit(krb5_context alt_ctx, @@ -130,4 +132,15 @@ khm_krb5_get_temp_profile_file(LPSTR confname, UINT szConfname); khm_int32 KHMAPI khm_krb5_creds_is_equal(khm_handle vcred1, khm_handle vcred2, void * dummy); +void +khm_krb5_set_identity_flags(khm_handle identity, + khm_int32 flag_mask, + khm_int32 flag_value); + +khm_int32 +khm_krb5_get_identity_flags(khm_handle identity); + +long +khm_krb5_get_temp_ccache(krb5_context ctx, + krb5_ccache * cc); #endif diff --git a/src/windows/identity/plugins/krb5/krb5identpro.c b/src/windows/identity/plugins/krb5/krb5identpro.c index 05f93fcd3..a8c91f955 100644 --- a/src/windows/identity/plugins/krb5/krb5identpro.c +++ b/src/windows/identity/plugins/krb5/krb5identpro.c @@ -807,149 +807,120 @@ k5_ident_set_default(khm_int32 msg_type, khm_ui_4 uparam, void * vparam) { - /* Logic for setting the default identity: - - When setting identity I as the default; - - - If KRB5CCNAME is set - - If I["Krb5CCName"] == %KRB5CCNAME% - - do nothing - - Else - - Copy the contents of I["Krb5CCName"] to %KRB5CCNAME - - Set I["Krb5CCName"] to %KRB5CCNAME - - Else - - Set HKCU\Software\MIT\kerberos5,ccname to - "API:".I["Krb5CCName"] + /* + Currently, setting the default identity simply sets the + "ccname" registry value at "Software\MIT\kerberos5". */ if (uparam) { /* an identity is being made default */ khm_handle def_ident = (khm_handle) vparam; - wchar_t env_ccname[KRB5_MAXCCH_CCNAME]; wchar_t id_ccname[KRB5_MAXCCH_CCNAME]; khm_size cb; DWORD dw; LONG l; + HKEY hk_ccname; + DWORD dwType; + DWORD dwSize; + wchar_t reg_ccname[KRB5_MAXCCH_CCNAME]; + + assert(FALSE); #ifdef DEBUG assert(def_ident != NULL); #endif + { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + cb = sizeof(idname); + kcdb_identity_get_name(def_ident, idname, &cb); + + _begin_task(0); + _report_cs1(KHERR_DEBUG_1, L"Setting default identity [%1!s!]", _cstr(idname)); + _describe(); + } + cb = sizeof(id_ccname); if (KHM_FAILED(kcdb_identity_get_attr(def_ident, attr_id_krb5_ccname, NULL, id_ccname, - &cb))) - return KHM_ERROR_UNKNOWN; + &cb))) { + _reportf(L"The specified identity does not have the Krb5CCName property"); + _end_task(); + return KHM_ERROR_NOT_FOUND; + } khm_krb5_canon_cc_name(id_ccname, sizeof(id_ccname)); + _reportf(L"Found Krb5CCName property : %s", id_ccname); + StringCbLength(id_ccname, sizeof(id_ccname), &cb); cb += sizeof(wchar_t); - dw = GetEnvironmentVariable(L"KRB5CCNAME", - env_ccname, - ARRAYLENGTH(env_ccname)); - - if (dw == 0 && - GetLastError() == ERROR_ENVVAR_NOT_FOUND) { - /* KRB5CCNAME not set */ - HKEY hk_ccname; - DWORD dwType; - DWORD dwSize; - wchar_t reg_ccname[KRB5_MAXCCH_CCNAME]; - - l = RegOpenKeyEx(HKEY_CURRENT_USER, - L"Software\\MIT\\kerberos5", - 0, - KEY_READ | KEY_WRITE, - &hk_ccname); - - if (l != ERROR_SUCCESS) - l = RegCreateKeyEx(HKEY_CURRENT_USER, - L"Software\\MIT\\kerberos5", - 0, - NULL, - REG_OPTION_NON_VOLATILE, - KEY_READ | KEY_WRITE, - NULL, - &hk_ccname, - &dw); - - if (l != ERROR_SUCCESS) - return KHM_ERROR_UNKNOWN; - - dwSize = sizeof(reg_ccname); + _reportf(L"Setting default CC name in the registry"); + + l = RegOpenKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + KEY_READ | KEY_WRITE, + &hk_ccname); + + if (l != ERROR_SUCCESS) + l = RegCreateKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hk_ccname, + &dw); - l = RegQueryValueEx(hk_ccname, - L"ccname", - NULL, - &dwType, - (LPBYTE) reg_ccname, - &dwSize); + if (l != ERROR_SUCCESS) { + _reportf(L"Can't create registry key : %d", l); + _end_task(); + return KHM_ERROR_UNKNOWN; + } - if (l != ERROR_SUCCESS || - dwType != REG_SZ || - khm_krb5_cc_name_cmp(reg_ccname, id_ccname)) { + dwSize = sizeof(reg_ccname); - /* we have to write the new value in */ + l = RegQueryValueEx(hk_ccname, + L"ccname", + NULL, + &dwType, + (LPBYTE) reg_ccname, + &dwSize); - l = RegSetValueEx(hk_ccname, - L"ccname", - 0, - REG_SZ, - (BYTE *) id_ccname, - (DWORD) cb); - } + if (l != ERROR_SUCCESS || + dwType != REG_SZ || + khm_krb5_cc_name_cmp(reg_ccname, id_ccname)) { - RegCloseKey(hk_ccname); + /* we have to write the new value in */ + + l = RegSetValueEx(hk_ccname, + L"ccname", + 0, + REG_SZ, + (BYTE *) id_ccname, + (DWORD) cb); + } - if (l == ERROR_SUCCESS) { - k5_update_last_default_identity(def_ident); - return KHM_ERROR_SUCCESS; - } else - return KHM_ERROR_UNKNOWN; + RegCloseKey(hk_ccname); - } else if (dw > ARRAYLENGTH(env_ccname)) { - /* buffer was not enough */ -#ifdef DEBUG - assert(FALSE); -#else - return KHM_ERROR_UNKNOWN; -#endif + if (l == ERROR_SUCCESS) { + _reportf(L"Successfully set the default ccache"); + k5_update_last_default_identity(def_ident); + _end_task(); + return KHM_ERROR_SUCCESS; } else { - /* KRB5CCNAME is set */ - long code; - krb5_context ctx; - - /* if the %KRB5CCNAME is the same as the identity - ccache, then it is already the default. */ - if (!khm_krb5_cc_name_cmp(id_ccname, env_ccname)) { - k5_update_last_default_identity(def_ident); - return KHM_ERROR_SUCCESS; - } - - /* if not, we have to copy the contents of id_ccname - to env_ccname */ - code = pkrb5_init_context(&ctx); - if (code) - return KHM_ERROR_UNKNOWN; - - code = khm_krb5_copy_ccache_by_name(ctx, - env_ccname, - id_ccname); - - if (code == 0) { - k5_update_last_default_identity(def_ident); - khm_krb5_list_tickets(&ctx); - } - - if (ctx) - pkrb5_free_context(ctx); - - return (code == 0)?KHM_ERROR_SUCCESS:KHM_ERROR_UNKNOWN; + _reportf(L"Can't set the registry value : %d", l); + _end_task(); + return KHM_ERROR_UNKNOWN; } + } else { /* the default identity is being forgotten */ @@ -1061,6 +1032,11 @@ struct k5_ident_update_data { khm_int32 k5_flags; }; +/* The logic here has to reflect the logic in khm_krb5_list_tickets(). + We use this to handle an identity update request because some other + plug-in or maybe NetIDMgr itself is about to do something + important(tm) with the identity and needs to make sure that the + properties of the identity are up-to-date. */ static khm_int32 KHMAPI k5_ident_update_apply_proc(khm_handle cred, void * rock) { @@ -1149,7 +1125,9 @@ k5_ident_update(khm_int32 msg_type, khm_ui_4 uparam, void * vparam) { +#if 0 struct k5_ident_update_data d; +#endif khm_handle ident; khm_handle tident; krb5_ccache cc = NULL; @@ -1163,6 +1141,13 @@ k5_ident_update(khm_int32 msg_type, if (ident == NULL) return KHM_ERROR_SUCCESS; +#if 0 + /* we are going to skip doing this here since + khm_krb5_list_tickets() performs this function for us each time + we enumerate tickets. Since it also gets run each time our + list of tickets changes and since we are basing this operation + on existing tickets, we are unlikely to find anything new + here. */ ZeroMemory(&d, sizeof(d)); d.identity = ident; @@ -1209,6 +1194,7 @@ k5_ident_update(khm_int32 msg_type, kcdb_identity_set_attr(ident, attr_id_krb5_flags, NULL, 0); kcdb_identity_set_attr(ident, attr_id_krb5_ccname, NULL, 0); } +#endif if (KHM_SUCCEEDED(kcdb_identity_get_default(&tident))) { kcdb_identity_release(tident); @@ -1258,18 +1244,54 @@ k5_refresh_default_identity(krb5_context ctx) { krb5_principal princ = NULL; char * princ_nameA = NULL; wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME]; + char * ccname = NULL; khm_handle ident = NULL; khm_boolean found_default = FALSE; assert(ctx != NULL); + _begin_task(0); + _report_cs0(KHERR_DEBUG_1, L"Refreshing default identity"); + _describe(); + code = pkrb5_cc_default(ctx, &cc); - if (code) + if (code) { + _reportf(L"Can't open default ccache. code=%d", code); goto _nc_cleanup; + } code = pkrb5_cc_get_principal(ctx, cc, &princ); - if (code) + if (code) { + /* try to determine the identity from the ccache name */ + ccname = pkrb5_cc_get_name(ctx, cc); + + if (ccname) { + char * namepart = strchr(ccname, ':'); + + _reportf(L"CC name is [%S]", ccname); + + if (namepart == NULL) + namepart = ccname; + else + namepart++; + + _reportf(L"Checking if [%S] is a valid identity name", namepart); + + AnsiStrToUnicode(princ_nameW, sizeof(princ_nameW), namepart); + if (kcdb_identity_is_valid_name(princ_nameW)) { + kcdb_identity_create(princ_nameW, KCDB_IDENT_FLAG_CREATE, &ident); + if (ident) { + _reportf(L"Setting [%S] as the default identity", namepart); + kcdb_identity_set_default_int(ident); + found_default = TRUE; + } + } + } else { + _reportf(L"Can't determine ccache name"); + } + goto _nc_cleanup; + } code = pkrb5_unparse_name(ctx, princ, &princ_nameA); if (code) @@ -1277,14 +1299,22 @@ k5_refresh_default_identity(krb5_context ctx) { AnsiStrToUnicode(princ_nameW, sizeof(princ_nameW), princ_nameA); - if (KHM_FAILED(kcdb_identity_create(princ_nameW, 0, &ident))) + _reportf(L"Found principal [%s]", princ_nameW); + + if (KHM_FAILED(kcdb_identity_create(princ_nameW, KCDB_IDENT_FLAG_CREATE, &ident))) { + _reportf(L"Failed to create identity"); goto _nc_cleanup; + } + _reportf(L"Setting default identity to [%s]", princ_nameW); kcdb_identity_set_default_int(ident); found_default = TRUE; _nc_cleanup: + + _end_task(); + if (princ_nameA) pkrb5_free_unparsed_name(ctx, princ_nameA); diff --git a/src/windows/identity/plugins/krb5/krb5main.c b/src/windows/identity/plugins/krb5/krb5main.c index f1b7f0549..3d2f2c0e9 100644 --- a/src/windows/identity/plugins/krb5/krb5main.c +++ b/src/windows/identity/plugins/krb5/krb5main.c @@ -50,6 +50,7 @@ khm_int32 attr_id_addr_list = -1; khm_int32 attr_id_krb5_flags = -1; khm_int32 attr_id_krb5_ccname = -1; khm_int32 attr_id_kvno = -1; +khm_int32 attr_id_krb5_idflags = -1; BOOL attr_regd_key_enctype = FALSE; BOOL attr_regd_tkt_enctype = FALSE; @@ -57,6 +58,7 @@ BOOL attr_regd_addr_list = FALSE; BOOL attr_regd_krb5_flags = FALSE; BOOL attr_regd_krb5_ccname = FALSE; BOOL attr_regd_kvno = FALSE; +BOOL attr_regd_krb5_idflags = FALSE; khm_handle csp_plugins = NULL; khm_handle csp_krbcred = NULL; @@ -383,6 +385,30 @@ KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { attr_regd_kvno = TRUE; } + if (KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_IDFLAGS, &attr_id_krb5_idflags))) { + kcdb_attrib attrib; + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KRB5_IDFLAGS; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = KCDB_TYPE_INT32; + attrib.flags = KCDB_ATTR_FLAG_PROPERTY | + KCDB_ATTR_FLAG_HIDDEN; + /* we don't bother localizing these strings since the + attribute is hidden. The user will not see these + descriptions anyway. */ + attrib.short_desc = L"Krb5 ID flags"; + attrib.long_desc = L"Kerberos 5 Identity Flags"; + + rv = kcdb_attrib_register(&attrib, &attr_id_krb5_idflags); + + if (KHM_FAILED(rv)) + goto _exit; + + attr_regd_krb5_idflags = TRUE; + } + rv = kmm_get_plugins_config(0, &csp_plugins); if(KHM_FAILED(rv)) goto _exit; @@ -416,6 +442,8 @@ KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { kcdb_attrib_unregister(attr_id_krb5_ccname); if(attr_regd_kvno) kcdb_attrib_unregister(attr_id_kvno); + if(attr_regd_krb5_idflags) + kcdb_attrib_unregister(attr_id_krb5_idflags); if(type_regd_enctype) kcdb_type_unregister(type_id_enctype); diff --git a/src/windows/identity/plugins/krb5/krb5newcreds.c b/src/windows/identity/plugins/krb5/krb5newcreds.c index 1bff68e3c..9be8c896a 100644 --- a/src/windows/identity/plugins/krb5/krb5newcreds.c +++ b/src/windows/identity/plugins/krb5/krb5newcreds.c @@ -2801,8 +2801,17 @@ k5_msg_cred_dialog(khm_int32 msg_type, #endif khc_read_int32(csp_params, L"MsLsaImport", &t); - if (t == 1) - khm_krb5_ms2mit(TRUE); + if (t != K5_LSAIMPORT_NEVER) { + krb5_context ctx = NULL; + BOOL imported; + + imported = khm_krb5_ms2mit(NULL, (t == K5_LSAIMPORT_MATCH), TRUE); + if (imported) { + khm_krb5_list_tickets(&ctx); + if (ctx) + pkrb5_free_context(ctx); + } + } } break; } diff --git a/src/windows/identity/plugins/krb5/krb5plugin.c b/src/windows/identity/plugins/krb5/krb5plugin.c index e80e01c47..bb481e0fb 100644 --- a/src/windows/identity/plugins/krb5/krb5plugin.c +++ b/src/windows/identity/plugins/krb5/krb5plugin.c @@ -111,9 +111,6 @@ k5_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, krb5_initialized = TRUE; - if(ctx != NULL) - pkrb5_free_context(ctx); - /* now convert this thread to a fiber and create a separate fiber to do kinit stuff */ k5_main_fiber = ConvertThreadToFiber(NULL); @@ -126,6 +123,9 @@ k5_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, k5_register_config_panels(); khm_krb5_list_tickets(&ctx); + + if(ctx != NULL) + pkrb5_free_context(ctx); } } break; diff --git a/src/windows/identity/plugins/krb5/krbcred.h b/src/windows/identity/plugins/krb5/krbcred.h index 694323ce3..44b7733e3 100644 --- a/src/windows/identity/plugins/krb5/krbcred.h +++ b/src/windows/identity/plugins/krb5/krbcred.h @@ -64,6 +64,12 @@ typedef enum tag_k5_lsa_import { #define ATTRNAME_KRB5_FLAGS L"Krb5Flags" #define ATTRNAME_KRB5_CCNAME L"Krb5CCName" #define ATTRNAME_KVNO L"Kvno" +#define ATTRNAME_KRB5_IDFLAGS L"Krb5IDFlags" + +/* Flag bits for Krb5IDFlags property */ + +/* identity was imported from MSLSA: */ +#define K5IDFLAG_IMPORTED 0x00000001 void init_krb(); void exit_krb(); @@ -90,6 +96,7 @@ extern khm_int32 attr_id_addr_list; extern khm_int32 attr_id_krb5_flags; extern khm_int32 attr_id_krb5_ccname; extern khm_int32 attr_id_kvno; +extern khm_int32 attr_id_krb5_idflags; extern khm_ui_4 k5_commctl_version; diff --git a/src/windows/identity/ui/credwnd.c b/src/windows/identity/ui/credwnd.c index 36e0572fe..c9b314b3d 100644 --- a/src/windows/identity/ui/credwnd.c +++ b/src/windows/identity/ui/credwnd.c @@ -2981,15 +2981,7 @@ cw_set_row_context(khui_credwnd_tbl * tbl, int row) o = (khui_credwnd_outline *) tbl->rows[row].data; if (tbl->cols[o->col].attr_id == KCDB_ATTR_ID_NAME) { - if (TPARENT(o) == NULL) { /* selected an identity */ - khui_context_set(KHUI_SCOPE_IDENT, - (khm_handle) o->data, - KCDB_CREDTYPE_INVALID, - NULL, - NULL, - 0, - tbl->credset); - } else { + if (TPARENT(o) != NULL) { khui_credwnd_outline * op; op = TPARENT(o); @@ -3005,8 +2997,30 @@ cw_set_row_context(khui_credwnd_tbl * tbl, int row) 0, tbl->credset); } else { - set_context = FALSE; + /* we can't narrow it down using the standard set + of scopes. We consider this to be an identity + selection because the user right-clicked on an + identity header. */ + khui_context_set(KHUI_SCOPE_IDENT, + (khm_handle) o->data, + KCDB_CREDTYPE_INVALID, + NULL, + NULL, + 0, + tbl->credset); } + } else { + /* The user clicked on an identity header. Even + though not all credentials belonging to the + identity maybe within the scope right now, we still + consider this to be an identity scope. */ + khui_context_set(KHUI_SCOPE_IDENT, + (khm_handle) o->data, + KCDB_CREDTYPE_INVALID, + NULL, + NULL, + 0, + tbl->credset); } } else if (tbl->cols[o->col].attr_id == KCDB_ATTR_TYPE_NAME) { if (TPARENT(o) == NULL) { @@ -3022,9 +3036,12 @@ cw_set_row_context(khui_credwnd_tbl * tbl, int row) khui_credwnd_outline * op; op = TPARENT(o); - if (tbl->cols[op->col].attr_id == KCDB_ATTR_ID_NAME && - TPARENT(op) == NULL) { - /* credtype under an identity */ + if (tbl->cols[op->col].attr_id == KCDB_ATTR_ID_NAME) { + /* credtype under an identity. Even though not + all the credentials of this credtype belonging + to this identity might be within the scope, we + still consider this to be a type selection + under a specific identity. */ khui_context_set(KHUI_SCOPE_CREDTYPE, (khm_handle) op->data, (khm_int32) (DWORD_PTR) o->data, @@ -4051,6 +4068,16 @@ cw_properties(HWND hwnd) khm_size t = 0; khm_int32 cred_type; + if (ctx.identity == NULL) { + /* currently, we can't show a property sheet at this point + since most credentials providers don't provide a + property sheet that works without an identity. */ + + khui_context_release(&ctx); + khui_ps_destroy_sheet(ps); + return TRUE; + } + cred_type = ctx.cred_type; ps->header.hInstance = khm_hInstance; @@ -4073,6 +4100,8 @@ cw_properties(HWND hwnd) ps->header.pszCaption = NULL; } } else { + /* we don't actually reach here since we handle this case + above */ kcdb_credtype_describe(cred_type, NULL, &t, KCDB_TS_LONG); if(t > 0) { ps->header.pszCaption = PMALLOC(t); @@ -4488,15 +4517,21 @@ cw_wm_contextmenu(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) cw_set_row_context(tbl, row); + khm_menu_show_panel(KHUI_MENU_IDENT_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + +#if 0 + /* calling cw_set_row_context() should take care of enabling or + disabling actions as appropriate. We don't need to + differentiate between IDENT_CTX and TOK_CTX here. */ if((tbl->rows[row].flags & KHUI_CW_ROW_HEADER) && - (tbl->cols[tbl->rows[row].col].attr_id == KCDB_ATTR_ID_NAME)) - { + (tbl->cols[tbl->rows[row].col].attr_id == KCDB_ATTR_ID_NAME)) { khm_menu_show_panel(KHUI_MENU_IDENT_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); //khui_context_reset(); } else { khm_menu_show_panel(KHUI_MENU_TOK_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); //khui_context_reset(); } +#endif return DefWindowProc(hwnd, uMsg, wParam, lParam); } diff --git a/src/windows/identity/ui/main.c b/src/windows/identity/ui/main.c index 80b7be3e5..e2210782f 100644 --- a/src/windows/identity/ui/main.c +++ b/src/windows/identity/ui/main.c @@ -192,12 +192,11 @@ void khm_add_dialog(HWND dlg) { meaningful value until we enter a modal loop */ khui_dialogs[n_khui_dialogs].active = FALSE; n_khui_dialogs++; - } + } else { #if DEBUG - else { - assert(FALSE); - } + assert(FALSE); #endif + } } /* should only be called from the UI thread */ @@ -254,6 +253,8 @@ void khm_enter_modal(HWND hwnd) { EnableWindow(khm_hwnd_main, FALSE); khui_modal_dialog = hwnd; + + SetForegroundWindow(hwnd); } } diff --git a/src/windows/identity/ui/mainwnd.c b/src/windows/identity/ui/mainwnd.c index c03d47f1d..eba23e40e 100644 --- a/src/windows/identity/ui/mainwnd.c +++ b/src/windows/identity/ui/mainwnd.c @@ -226,22 +226,37 @@ khm_main_wnd_proc(HWND hwnd, return 0; case KHUI_ACTION_PASSWD_ID: + if (khm_startup.processing) + return 0; + khm_cred_change_password(NULL); return 0; case KHUI_ACTION_NEW_CRED: + if (khm_startup.processing) + return 0; + khm_cred_obtain_new_creds(NULL); return 0; case KHUI_ACTION_RENEW_CRED: + if (khm_startup.processing) + return 0; + khm_cred_renew_creds(); return 0; case KHUI_ACTION_DESTROY_CRED: + if (khm_startup.processing) + return 0; + khm_cred_destroy_creds(FALSE, FALSE); return 0; case KHUI_ACTION_SET_DEF_ID: + if (khm_startup.processing) + return 0; + khm_cred_set_default(); return 0; diff --git a/src/windows/identity/ui/newcredwnd.c b/src/windows/identity/ui/newcredwnd.c index a0472e236..7bad1e24c 100644 --- a/src/windows/identity/ui/newcredwnd.c +++ b/src/windows/identity/ui/newcredwnd.c @@ -819,14 +819,12 @@ nc_handle_wm_create(HWND hwnd, #endif /* we defer the creation of the tab buttons for later */ - /* add this to the dialog chain */ - khm_add_dialog(hwnd); - /* bring the window to the top, if necessary */ if (KHM_SUCCEEDED(khc_read_int32(NULL, L"CredWindow\\Windows\\NewCred\\ForceToTop", &t)) && - t != 0) { + t != 0 && + !khm_is_dialog_active()) { /* if the main window is not visible, then the SetWindowPos() call is sufficient to bring the new creds window to the @@ -840,6 +838,9 @@ nc_handle_wm_create(HWND hwnd, } + /* add this to the dialog chain */ + khm_add_dialog(hwnd); + return TRUE; } @@ -1431,7 +1432,7 @@ static LRESULT nc_handle_wm_nc_notify(HWND hwnd, nc_update_credtext(d); - ShowWindow(hwnd, SW_SHOW); + ShowWindow(hwnd, SW_SHOWNOACTIVATE); SetFocus(hwnd); if (d->nc->n_identities == 0) diff --git a/src/windows/identity/ui/uiconfig.csv b/src/windows/identity/ui/uiconfig.csv index f1bb4b195..9f5e5e4b3 100644 --- a/src/windows/identity/ui/uiconfig.csv +++ b/src/windows/identity/ui/uiconfig.csv @@ -71,7 +71,7 @@ CredWindow,KC_SPACE,0,Options for the credentials window Custom_0,KC_ENDSPACE,0, ByIdentity,KC_SPACE,0,The default view Description,KC_STRING,View grouped by identity and credential type, - ColumnList,KC_STRING,"_CWFlags,IdentityName,TypeName,Name,TimeLeft", + ColumnList,KC_STRING,"_CWFlags,IdentityName,TypeName,Location,Name,TimeLeft", Columns,KC_SPACE,0,Columns _CWFlags,KC_SPACE,0, Width,KC_INT32,20, @@ -87,9 +87,14 @@ CredWindow,KC_SPACE,0,Options for the credentials window SortIndex,KC_INT32,1 Flags,KC_INT32,11 TypeName,KC_ENDSPACE,0 + Location,KC_SPACE,0, + Width,KC_INT32,50 + SortIndex,KC_INT32,2 + Flags,KC_INT32,11 + Location,KC_ENDSPACE,0, Name,KC_SPACE,0 Width,KC_INT32,200 - SortIndex,KC_INT32,2 + SortIndex,KC_INT32,3 Flags,KC_INT32,3 Name,KC_ENDSPACE,0 TimeLeft,KC_SPACE,0 -- 2.26.2