summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeffrey Altman <jaltman@secure-endpoints.com>2007-08-29 22:38:26 +0000
committerJeffrey Altman <jaltman@secure-endpoints.com>2007-08-29 22:38:26 +0000
commitbaa59c0e46ed256defe8f152be97546bb382aef9 (patch)
tree2adab8c40bc6fe1a0e42ecfbe61dad6638e841ce
parent0206706570d023965a0226a4fd644e8b6fea22c3 (diff)
downloadkrb5-baa59c0e46ed256defe8f152be97546bb382aef9.tar.gz
krb5-baa59c0e46ed256defe8f152be97546bb382aef9.tar.xz
krb5-baa59c0e46ed256defe8f152be97546bb382aef9.zip
NIM file ccache support improvements
NIM supports the ability of the user to specify an explicit ccache name for use with an identity. If this ccache is a FILE ccache, we need to be able to store credentials into the ccache. krb5cred.dll did not previously specify the KRB5_TC_OPENCLOSE flag on the ccache when setting other flags such as KRB5_TC_NOTICKET (which is used with MSLSA ccaches). As a result, open/close mode was turned off, the ccache file would be opened in read-only mode and attempts to store credentials into the ccache would fail. This is fixed by specifying KRB5_TC_OPENCLOSE when setting the ccache flags. When a CCAPI implementation is unavailable, we need to automatically generate the FILE ccache name if one has not already been specified. We default to a file stored in the user's Local Settings\Temp directory. The generated ccache is then added to the file ccache watch list. Finally, some users have complained about the behavior of Microsoft Vista's UAC mode and how it makes the CCAPI cache useless for storing credentials that must be used in conjunction with processes that do not have restricted privileges since those processes run in a separate logon session. For these users we have added a "DefaultToFileCache" registry value that can be specified to force the use of FILE ccaches in preference to CCAPI ccaches when there is no explicit ccache specified for a given identity. Unlike CCAPI ccaches, the FILE ccaches are accessible from both restricted and unrestricted processes when UAC is active. ticket: new component: windows git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@19897 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/windows/identity/plugins/krb5/krb5configid.c17
-rw-r--r--src/windows/identity/plugins/krb5/krb5funcs.c135
-rw-r--r--src/windows/identity/plugins/krb5/krb5newcreds.c70
-rw-r--r--src/windows/identity/plugins/krb5/krbconfig.csv1
4 files changed, 163 insertions, 60 deletions
diff --git a/src/windows/identity/plugins/krb5/krb5configid.c b/src/windows/identity/plugins/krb5/krb5configid.c
index a2688e1e7d..2f3fe62c84 100644
--- a/src/windows/identity/plugins/krb5/krb5configid.c
+++ b/src/windows/identity/plugins/krb5/krb5configid.c
@@ -61,8 +61,7 @@ k5_id_read_params(k5_id_dlg_data * d) {
khm_size cb;
khm_int32 rv;
khm_int32 t;
- khm_handle csp_ident;
- khm_handle csp_idroot = NULL;
+ khm_handle csp_ident = NULL;
cb = sizeof(idname);
rv = khui_cfg_get_name(d->cfg.ctx_node, idname, &cb);
@@ -75,17 +74,7 @@ k5_id_read_params(k5_id_dlg_data * d) {
assert(KHM_SUCCEEDED(rv));
#endif
- rv = kcdb_identity_get_config(d->ident, 0, &csp_idroot);
- if (KHM_SUCCEEDED(rv) &&
- KHM_SUCCEEDED(khc_open_space(csp_idroot, CSNAME_KRB5CRED, 0,
- &csp_ident))) {
- khc_shadow_space(csp_ident, csp_params);
- } else {
- csp_ident = csp_params;
- }
-
- if (csp_idroot)
- khc_close_space(csp_idroot);
+ khm_krb5_get_identity_config(d->ident, 0, &csp_ident);
rv = khc_read_int32(csp_ident, L"DefaultLifetime", &t);
if (KHM_SUCCEEDED(rv))
@@ -146,7 +135,7 @@ k5_id_read_params(k5_id_dlg_data * d) {
d->tc_renew.min = 0;
d->tc_renew.max = 3600 * 24 * 30;
- if (csp_ident != csp_params)
+ if (csp_ident)
khc_close_space(csp_ident);
}
diff --git a/src/windows/identity/plugins/krb5/krb5funcs.c b/src/windows/identity/plugins/krb5/krb5funcs.c
index 4dc854845c..9c8db75098 100644
--- a/src/windows/identity/plugins/krb5/krb5funcs.c
+++ b/src/windows/identity/plugins/krb5/krb5funcs.c
@@ -515,8 +515,6 @@ static long get_tickets_from_cache(krb5_context ctx,
#ifdef KRB5_TC_NOTICKET
flags = KRB5_TC_NOTICKET;
-#else
- flags = 0;
#endif
{
@@ -1005,6 +1003,7 @@ khm_krb5_renew_cred(khm_handle cred)
khm_boolean istgt = FALSE;
khm_int32 flags;
+ int ccflags = 0;
cbname = sizeof(wname);
kcdb_cred_get_name(cred, wname, &cbname);
@@ -1055,9 +1054,8 @@ khm_krb5_renew_cred(khm_handle cred)
in_creds.client = me;
in_creds.server = server;
-#ifdef KRB5_TC_NOTICKET
- pkrb5_cc_set_flags(ctx, cc, 0);
-#endif
+ ccflags = KRB5_TC_OPENCLOSE;
+ pkrb5_cc_set_flags(ctx, cc, ccflags);
if (strlen("krbtgt") != krb5_princ_name(ctx, server)->length ||
strncmp("krbtgt", krb5_princ_name(ctx, server)->data, krb5_princ_name(ctx, server)->length))
@@ -1080,9 +1078,6 @@ khm_krb5_renew_cred(khm_handle cred)
code = pkrb5_get_renewed_creds(ctx, &cc_creds, me, cc, NULL);
}
-#ifdef KRB5_TC_NOTICKET
- pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET);
-#endif
if (code) {
if ( code != KRB5KDC_ERR_ETYPE_NOSUPP ||
code != KRB5_KDC_UNREACH)
@@ -1094,6 +1089,8 @@ khm_krb5_renew_cred(khm_handle cred)
code = pkrb5_cc_initialize(ctx, cc, me);
if (code) goto cleanup;
+ ccflags = KRB5_TC_OPENCLOSE;
+ pkrb5_cc_set_flags(ctx, cc, ccflags);
}
code = pkrb5_cc_store_cred(ctx, cc, istgt ? &cc_creds : out_creds);
@@ -1101,7 +1098,6 @@ khm_krb5_renew_cred(khm_handle cred)
cleanup:
-
if (in_creds.client == me)
in_creds.client = NULL;
if (in_creds.server == server)
@@ -1147,6 +1143,7 @@ khm_krb5_renew_ident(khm_handle identity)
wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
khm_size cb;
khm_int32 k5_flags;
+ int ccflags;
memset(&my_creds, 0, sizeof(krb5_creds));
@@ -1304,13 +1301,13 @@ khm_krb5_renew_ident(khm_handle identity)
my_creds.client = me;
my_creds.server = server;
-#ifdef KRB5_TC_NOTICKET
- pkrb5_cc_set_flags(ctx, cc, 0);
-#endif
+ pkrb5_cc_set_flags(ctx, cc, KRB5_TC_OPENCLOSE);
code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);
+ ccflags = KRB5_TC_OPENCLOSE;
#ifdef KRB5_TC_NOTICKET
- pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET);
+ ccflags |= KRB5_TC_NOTICKET;
#endif
+ pkrb5_cc_set_flags(ctx, cc, ccflags);
if (code) {
if ( code != KRB5KDC_ERR_ETYPE_NOSUPP ||
code != KRB5_KDC_UNREACH)
@@ -1321,6 +1318,9 @@ khm_krb5_renew_ident(khm_handle identity)
code = pkrb5_cc_initialize(ctx, cc, me);
if (code) goto cleanup;
+ code = pkrb5_cc_set_flags(ctx, cc, KRB5_TC_OPENCLOSE);
+ if (code) goto cleanup;
+
code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
if (code) goto cleanup;
@@ -3057,31 +3057,130 @@ get_libdefault_string(profile_t profile, const char * realm,
return code;
}
+
+const struct escape_char_sequences {
+ wchar_t character;
+ wchar_t escape;
+} file_cc_escapes[] = {
+
+ /* in ASCII order */
+
+ {L'\"', L'd'},
+ {L'$', L'$'},
+ {L'%', L'r'},
+ {L'\'', L'i'},
+ {L'*', L's'},
+ {L'/', L'f'},
+ {L':', L'c'},
+ {L'<', L'l'},
+ {L'>', L'g'},
+ {L'?', L'q'},
+ {L'\\', L'b'},
+ {L'|', L'p'}
+};
+
+static void
+escape_string_for_filename(const wchar_t * s,
+ wchar_t * buf,
+ khm_size cb_buf)
+{
+ wchar_t * d;
+ int i;
+
+ for (d = buf; *s && cb_buf > sizeof(wchar_t) * 3; s++) {
+ if (iswpunct(*s)) {
+ for (i=0; i < ARRAYLENGTH(file_cc_escapes); i++) {
+ if (*s == file_cc_escapes[i].character)
+ break;
+ }
+
+ if (i < ARRAYLENGTH(file_cc_escapes)) {
+ *d++ = L'$';
+ *d++ = file_cc_escapes[i].escape;
+ cb_buf -= sizeof(wchar_t) * 2;
+ continue;
+ }
+ }
+
+ *d++ = *s;
+ cb_buf -= sizeof(wchar_t);
+ }
+
+#ifdef DEBUG
+ assert(cb_buf >= sizeof(wchar_t));
+#endif
+ *d++ = L'\0';
+}
+
+static khm_int32
+get_default_file_cache_for_identity(const wchar_t * idname,
+ wchar_t * ccname,
+ khm_size * pcb)
+{
+ wchar_t escf[MAX_PATH] = L"";
+ wchar_t tmppath[MAX_PATH] = L"";
+ wchar_t tccname[MAX_PATH];
+ khm_size cb;
+
+ escape_string_for_filename(idname, escf, sizeof(escf));
+ GetTempPath(ARRAYLENGTH(tmppath), tmppath);
+
+ StringCbPrintf(tccname, sizeof(tccname), L"FILE:%s\\krb5cc.%s", tmppath, escf);
+ StringCbLength(tccname, sizeof(tccname), &cb);
+ cb += sizeof(wchar_t);
+
+ if (ccname && *pcb >= cb) {
+ StringCbCopy(ccname, *pcb, tccname);
+ *pcb = cb;
+ return KHM_ERROR_SUCCESS;
+ } else {
+ *pcb = cb;
+ return KHM_ERROR_TOO_LONG;
+ }
+}
+
khm_int32
khm_krb5_get_identity_default_ccache(khm_handle ident, wchar_t * buf, khm_size * pcb) {
khm_handle csp_id = NULL;
khm_int32 rv = KHM_ERROR_SUCCESS;
+ khm_size cbt;
rv = khm_krb5_get_identity_config(ident, 0, &csp_id);
+ cbt = *pcb;
if (KHM_SUCCEEDED(rv))
- rv = khc_read_string(csp_id, L"DefaultCCName", buf, pcb);
+ rv = khc_read_string(csp_id, L"DefaultCCName", buf, &cbt);
- if (KHM_FAILED(rv) && rv != KHM_ERROR_TOO_LONG) {
+ if ((KHM_FAILED(rv) && rv != KHM_ERROR_TOO_LONG) ||
+ (KHM_SUCCEEDED(rv) && buf[0] == L'\0')) {
/* we need to figure out the default ccache from the principal
name */
wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
wchar_t ccname[MAX_PATH];
khm_size cb;
+ khm_int32 use_file_cache = 0;
+
+ khc_read_int32(csp_id, L"DefaultToFileCache", &use_file_cache);
cb = sizeof(idname);
kcdb_identity_get_name(ident, idname, &cb);
- StringCbCopy(ccname, sizeof(ccname), idname);
+
+ if (use_file_cache) {
+ cb = sizeof(ccname);
+ rv = get_default_file_cache_for_identity(idname, ccname, &cb);
+#ifdef DEBUG
+ assert(KHM_SUCCEEDED(rv));
+#endif
+ } else { /* generate an API: cache */
+ StringCbPrintf(ccname, sizeof(ccname), L"API:%s", idname);
+ }
khm_krb5_canon_cc_name(ccname, sizeof(ccname));
- StringCbLength(ccname, sizeof(ccname), &cb);
_reportf(L"Setting CCache [%s] for identity [%s]", ccname, idname);
+ StringCbLength(ccname, sizeof(ccname), &cb);
+ cb += sizeof(wchar_t);
+
if (buf && *pcb >= cb) {
StringCbCopy(buf, *pcb, ccname);
*pcb = cb;
@@ -3094,6 +3193,8 @@ khm_krb5_get_identity_default_ccache(khm_handle ident, wchar_t * buf, khm_size *
wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
khm_size cb;
+ *pcb = cbt;
+
cb = sizeof(idname);
kcdb_identity_get_name(ident, idname, &cb);
diff --git a/src/windows/identity/plugins/krb5/krb5newcreds.c b/src/windows/identity/plugins/krb5/krb5newcreds.c
index 67fb8dac01..410393cafa 100644
--- a/src/windows/identity/plugins/krb5/krb5newcreds.c
+++ b/src/windows/identity/plugins/krb5/krb5newcreds.c
@@ -181,7 +181,7 @@ k5_handle_wmnc_notify(HWND hwnd,
case WMNC_DIALOG_MOVE:
{
k5_dlg_data * d;
-
+
d = (k5_dlg_data *)(LONG_PTR)
GetWindowLongPtr(hwnd, DWLP_USER);
@@ -1355,34 +1355,9 @@ k5_read_dlg_params(k5_dlg_data * d, khm_handle identity)
d->sync = FALSE;
}
-void
-k5_write_dlg_params(k5_dlg_data * d, khm_handle identity, char * ccache)
+void
+k5_ensure_identity_ccache_is_watched(khm_handle identity, char * ccache)
{
-
- k5_params p;
-
- ZeroMemory(&p, sizeof(p));
-
- p.source_reg = K5PARAM_FM_ALL; /* we want to write all the
- settings to the registry, if
- necessary. */
-
- p.renewable = d->renewable;
- p.forwardable = d->forwardable;
- p.proxiable = d->proxiable;
- p.addressless = d->addressless;
- p.publicIP = d->publicIP;
-
- p.lifetime = (krb5_deltat) d->tc_lifetime.current;
- p.lifetime_max = (krb5_deltat) d->tc_lifetime.max;
- p.lifetime_min = (krb5_deltat) d->tc_lifetime.min;
-
- p.renew_life = (krb5_deltat) d->tc_renew.current;
- p.renew_life_max = (krb5_deltat) d->tc_renew.max;
- p.renew_life_min = (krb5_deltat) d->tc_renew.min;
-
- khm_krb5_set_identity_params(identity, &p);
-
/* if we used a FILE: ccache, we should add it to FileCCList.
Otherwise the tickets are not going to get listed. */
do {
@@ -1462,6 +1437,37 @@ k5_write_dlg_params(k5_dlg_data * d, khm_handle identity, char * ccache)
PFREE(mlist);
} while(FALSE);
+}
+
+void
+k5_write_dlg_params(k5_dlg_data * d, khm_handle identity, char * ccache)
+{
+
+ k5_params p;
+
+ ZeroMemory(&p, sizeof(p));
+
+ p.source_reg = K5PARAM_FM_ALL; /* we want to write all the
+ settings to the registry, if
+ necessary. */
+
+ p.renewable = d->renewable;
+ p.forwardable = d->forwardable;
+ p.proxiable = d->proxiable;
+ p.addressless = d->addressless;
+ p.publicIP = d->publicIP;
+
+ p.lifetime = (krb5_deltat) d->tc_lifetime.current;
+ p.lifetime_max = (krb5_deltat) d->tc_lifetime.max;
+ p.lifetime_min = (krb5_deltat) d->tc_lifetime.min;
+
+ p.renew_life = (krb5_deltat) d->tc_renew.current;
+ p.renew_life_max = (krb5_deltat) d->tc_renew.max;
+ p.renew_life_min = (krb5_deltat) d->tc_renew.min;
+
+ khm_krb5_set_identity_params(identity, &p);
+
+ k5_ensure_identity_ccache_is_watched(identity, ccache);
/* as in k5_read_dlg_params, once we write the data in, the local
data is no longer dirty */
@@ -2059,6 +2065,9 @@ k5_msg_cred_dialog(khm_int32 msg_type,
if(g_fjob.state == FIBER_STATE_NONE) {
wchar_t msg[KHUI_MAXCCH_BANNER];
khm_size cb;
+ int code;
+
+ code = g_fjob.code;
/* Special case. If the users' password has
expired, we force a password change dialog on
@@ -2143,7 +2152,7 @@ k5_msg_cred_dialog(khm_int32 msg_type,
k5_free_kinit_job();
if (is_k5_identpro) {
- if (g_fjob.code == 0)
+ if (code == 0)
kcdb_identity_set_flags(ident,
KCDB_IDENT_FLAG_VALID,
KCDB_IDENT_FLAG_VALID);
@@ -2832,6 +2841,9 @@ k5_msg_cred_dialog(khm_int32 msg_type,
imported = khm_krb5_ms2mit(NULL, (t == K5_LSAIMPORT_MATCH), TRUE,
&id_imported);
if (imported) {
+ if (id_imported)
+ k5_ensure_identity_ccache_is_watched(id_imported, NULL);
+
khm_krb5_list_tickets(&ctx);
if (ctx)
diff --git a/src/windows/identity/plugins/krb5/krbconfig.csv b/src/windows/identity/plugins/krb5/krbconfig.csv
index 4dc5b7d720..cb4a860d91 100644
--- a/src/windows/identity/plugins/krb5/krbconfig.csv
+++ b/src/windows/identity/plugins/krb5/krbconfig.csv
@@ -27,6 +27,7 @@ Krb5Cred,KC_SPACE,0,Kerberos V Credentials Provider
LastDefaultIdent,KC_STRING,,Last known default identity
PromptCacheLifetime,KC_INT32,172800,Lifetime of the prompt cache in seconds
DefaultCCName,KC_STRING,,Default CC name (only per identity)
+ DefaultToFileCache,KC_INT32,0,"If no DefaultCCName is specified for an identity, use a generated FILE: cache instead of an API: cache"
PromptCache,KC_SPACE,0,Cache of prompts (only per identity)
Name,KC_STRING,,
Banner,KC_STRING,,