diff options
Diffstat (limited to 'lib/gssapi/krb5')
44 files changed, 2382 insertions, 758 deletions
diff --git a/lib/gssapi/krb5/8003.c b/lib/gssapi/krb5/8003.c index d4555c51042b..5af477fe99fc 100644 --- a/lib/gssapi/krb5/8003.c +++ b/lib/gssapi/krb5/8003.c @@ -157,7 +157,7 @@ _gsskrb5_create_8003_checksum ( *p++ = (fwd_data->length >> 8) & 0xFF; /* Dlgth */ memcpy(p, (unsigned char *) fwd_data->data, fwd_data->length); - p += fwd_data->length; + /* p += fwd_data->length; */ /* commented out to quiet warning */ } return GSS_S_COMPLETE; diff --git a/lib/gssapi/krb5/accept_sec_context.c b/lib/gssapi/krb5/accept_sec_context.c index 5a00e124c2cf..d4680e9e8fb6 100644 --- a/lib/gssapi/krb5/accept_sec_context.c +++ b/lib/gssapi/krb5/accept_sec_context.c @@ -104,7 +104,6 @@ _gsskrb5_register_acceptor_identity(OM_uint32 *min_stat, const char *identity) void _gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor) { - krb5_error_code ret; krb5_keyblock *key; if (acceptor) { @@ -144,7 +143,8 @@ _gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor) } if (ctx->crypto) krb5_crypto_destroy(context, ctx->crypto); - ret = krb5_crypto_init(context, key, 0, &ctx->crypto); + /* XXX We really shouldn't ignore this; will come back to this */ + (void) krb5_crypto_init(context, key, 0, &ctx->crypto); } @@ -164,12 +164,13 @@ gsskrb5_accept_delegated_token /* XXX Create a new delegated_cred_handle? */ if (delegated_cred_handle == NULL) { - kret = krb5_cc_default (context, &ccache); - } else { - *delegated_cred_handle = NULL; - kret = krb5_cc_new_unique (context, krb5_cc_type_memory, - NULL, &ccache); + ret = GSS_S_COMPLETE; + goto out; } + + *delegated_cred_handle = NULL; + kret = krb5_cc_new_unique (context, krb5_cc_type_memory, + NULL, &ccache); if (kret) { ctx->flags &= ~GSS_C_DELEG_FLAG; goto out; @@ -270,7 +271,7 @@ gsskrb5_acceptor_ready(OM_uint32 * minor_status, ctx, context, delegated_cred_handle); - if (ret) + if (ret != GSS_S_COMPLETE) return ret; } else { /* Well, looks like it wasn't there after all */ @@ -347,7 +348,7 @@ static OM_uint32 gsskrb5_acceptor_start(OM_uint32 * minor_status, gsskrb5_ctx ctx, krb5_context context, - const gss_cred_id_t acceptor_cred_handle, + gss_const_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, gss_name_t * src_name, @@ -363,6 +364,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, krb5_flags ap_options; krb5_keytab keytab = NULL; int is_cfx = 0; + int close_kt = 0; const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle; /* @@ -384,8 +386,20 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, * We need to get our keytab */ if (acceptor_cred == NULL) { - if (_gsskrb5_keytab != NULL) - keytab = _gsskrb5_keytab; + HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); + if (_gsskrb5_keytab != NULL) { + char *name = NULL; + kret = krb5_kt_get_full_name(context, _gsskrb5_keytab, &name); + if (kret == 0) { + kret = krb5_kt_resolve(context, name, &keytab); + krb5_xfree(name); + } + if (kret == 0) + close_kt = 1; + else + keytab = NULL; + } + HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); } else if (acceptor_cred->keytab != NULL) { keytab = acceptor_cred->keytab; } @@ -408,6 +422,8 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, if (kret) { if (in) krb5_rd_req_in_ctx_free(context, in); + if (close_kt) + krb5_kt_close(context, keytab); *minor_status = kret; return GSS_S_FAILURE; } @@ -418,6 +434,8 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, server, in, &out); krb5_rd_req_in_ctx_free(context, in); + if (close_kt) + krb5_kt_close(context, keytab); if (kret == KRB5KRB_AP_ERR_SKEW || kret == KRB5KRB_AP_ERR_TKT_NYV) { /* * No reply in non-MUTUAL mode, but we don't know that its @@ -443,7 +461,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, if (kret == 0) kret = krb5_rd_req_out_get_keyblock(context, out, &ctx->service_keyblock); - ctx->lifetime = ctx->ticket->ticket.endtime; + ctx->endtime = ctx->ticket->ticket.endtime; krb5_rd_req_out_ctx_free(context, out); if (kret) { @@ -464,6 +482,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, if (kret) { ret = GSS_S_FAILURE; *minor_status = kret; + return ret; } kret = krb5_copy_principal(context, @@ -510,62 +529,61 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, return ret; } - if (authenticator->cksum == NULL) { - krb5_free_authenticator(context, &authenticator); - *minor_status = 0; - return GSS_S_BAD_BINDINGS; - } - - if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) { + if (authenticator->cksum != NULL + && authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) { ret = _gsskrb5_verify_8003_checksum(minor_status, input_chan_bindings, authenticator->cksum, &ctx->flags, &ctx->fwd_data); - krb5_free_authenticator(context, &authenticator); if (ret) { + krb5_free_authenticator(context, &authenticator); return ret; } } else { - krb5_crypto crypto; - - kret = krb5_crypto_init(context, - ctx->auth_context->keyblock, - 0, &crypto); - if(kret) { - krb5_free_authenticator(context, &authenticator); - - ret = GSS_S_FAILURE; - *minor_status = kret; - return ret; + if (authenticator->cksum != NULL) { + krb5_crypto crypto; + + kret = krb5_crypto_init(context, + ctx->auth_context->keyblock, + 0, &crypto); + if (kret) { + krb5_free_authenticator(context, &authenticator); + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + + /* + * Windows accepts Samba3's use of a kerberos, rather than + * GSSAPI checksum here + */ + + kret = krb5_verify_checksum(context, + crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0, + authenticator->cksum); + krb5_crypto_destroy(context, crypto); + + if (kret) { + krb5_free_authenticator(context, &authenticator); + ret = GSS_S_BAD_SIG; + *minor_status = kret; + return ret; + } } /* - * Windows accepts Samba3's use of a kerberos, rather than - * GSSAPI checksum here + * If there is no checksum or a kerberos checksum (which Windows + * and Samba accept), we use the ap_options to guess the mutual + * flag. */ - kret = krb5_verify_checksum(context, - crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0, - authenticator->cksum); - krb5_free_authenticator(context, &authenticator); - krb5_crypto_destroy(context, crypto); - - if(kret) { - ret = GSS_S_BAD_SIG; - *minor_status = kret; - return ret; - } - - /* - * Samba style get some flags (but not DCE-STYLE), use - * ap_options to guess the mutual flag. - */ - ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG; + ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG; if (ap_options & AP_OPTS_MUTUAL_REQUIRED) ctx->flags |= GSS_C_MUTUAL_FLAG; - } + } + krb5_free_authenticator(context, &authenticator); } if(ctx->flags & GSS_C_MUTUAL_FLAG) { @@ -593,8 +611,8 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, rkey); if (kret == 0) use_subkey = 1; - krb5_free_keyblock(context, rkey); } + krb5_free_keyblock(context, rkey); } if (use_subkey) { ctx->more_flags |= ACCEPTOR_SUBKEY; @@ -630,7 +648,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, /* Remember the flags */ - ctx->lifetime = ctx->ticket->ticket.endtime; + ctx->endtime = ctx->ticket->ticket.endtime; ctx->more_flags |= OPEN; if (mech_type) @@ -639,7 +657,7 @@ gsskrb5_acceptor_start(OM_uint32 * minor_status, if (time_rec) { ret = _gsskrb5_lifetime_left(minor_status, context, - ctx->lifetime, + ctx->endtime, time_rec); if (ret) { return ret; @@ -675,7 +693,7 @@ static OM_uint32 acceptor_wait_for_dcestyle(OM_uint32 * minor_status, gsskrb5_ctx ctx, krb5_context context, - const gss_cred_id_t acceptor_cred_handle, + gss_const_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, gss_name_t * src_name, @@ -757,7 +775,7 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status, ret = _gsskrb5_lifetime_left(minor_status, context, - ctx->lifetime, + ctx->endtime, &lifetime_rec); if (ret) { return ret; @@ -838,7 +856,7 @@ acceptor_wait_for_dcestyle(OM_uint32 * minor_status, OM_uint32 GSSAPI_CALLCONV _gsskrb5_accept_sec_context(OM_uint32 * minor_status, gss_ctx_id_t * context_handle, - const gss_cred_id_t acceptor_cred_handle, + gss_const_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, gss_name_t * src_name, diff --git a/lib/gssapi/krb5/acquire_cred.c b/lib/gssapi/krb5/acquire_cred.c index 0f1f5f81cffc..9c880b334fd6 100644 --- a/lib/gssapi/krb5/acquire_cred.c +++ b/lib/gssapi/krb5/acquire_cred.c @@ -40,37 +40,16 @@ __gsskrb5_ccache_lifetime(OM_uint32 *minor_status, krb5_principal principal, OM_uint32 *lifetime) { - krb5_creds in_cred, out_cred; - krb5_const_realm realm; krb5_error_code kret; + time_t left; - memset(&in_cred, 0, sizeof(in_cred)); - in_cred.client = principal; - - realm = krb5_principal_get_realm(context, principal); - if (realm == NULL) { - _gsskrb5_clear_status (); - *minor_status = KRB5_PRINC_NOMATCH; /* XXX */ - return GSS_S_FAILURE; - } - - kret = krb5_make_principal(context, &in_cred.server, - realm, KRB5_TGS_NAME, realm, NULL); - if (kret) { - *minor_status = kret; - return GSS_S_FAILURE; - } - - kret = krb5_cc_retrieve_cred(context, id, 0, &in_cred, &out_cred); - krb5_free_principal(context, in_cred.server); + kret = krb5_cc_get_lifetime(context, id, &left); if (kret) { - *minor_status = 0; - *lifetime = 0; - return GSS_S_COMPLETE; + *minor_status = kret; + return GSS_S_FAILURE; } - *lifetime = out_cred.times.endtime; - krb5_free_cred_contents(context, &out_cred); + *lifetime = left; return GSS_S_COMPLETE; } @@ -101,146 +80,282 @@ get_keytab(krb5_context context, krb5_keytab *keytab) return (kret); } -static OM_uint32 acquire_initiator_cred - (OM_uint32 * minor_status, - krb5_context context, - gss_const_OID credential_type, - const void *credential_data, - const gss_name_t desired_name, - OM_uint32 time_req, - gss_const_OID desired_mech, - gss_cred_usage_t cred_usage, - gsskrb5_cred handle - ) +/* + * This function produces a cred with a MEMORY ccache containing a TGT + * acquired with a password. + */ +static OM_uint32 +acquire_cred_with_password(OM_uint32 *minor_status, + krb5_context context, + const char *password, + OM_uint32 time_req, + gss_const_OID desired_mech, + gss_cred_usage_t cred_usage, + gsskrb5_cred handle) { - OM_uint32 ret; + OM_uint32 ret = GSS_S_FAILURE; krb5_creds cred; - krb5_principal def_princ; krb5_get_init_creds_opt *opt; - krb5_ccache ccache; - krb5_keytab keytab; + krb5_ccache ccache = NULL; krb5_error_code kret; + time_t now; + OM_uint32 left; + + if (cred_usage == GSS_C_ACCEPT) { + /* + * TODO: Here we should eventually support user2user (when we get + * support for that via an extension to the mechanism + * allowing for more than two security context tokens), + * and/or new unique MEMORY keytabs (we have MEMORY keytab + * support, but we don't have a keytab equivalent of + * krb5_cc_new_unique()). Either way, for now we can't + * support this. + */ + *minor_status = ENOTSUP; /* XXX Better error? */ + return GSS_S_FAILURE; + } + + memset(&cred, 0, sizeof(cred)); + + if (handle->principal == NULL) { + kret = krb5_get_default_principal(context, &handle->principal); + if (kret) + goto end; + } + kret = krb5_get_init_creds_opt_alloc(context, &opt); + if (kret) + goto end; + + /* + * Get the current time before the AS exchange so we don't + * accidentally end up returning a value that puts advertised + * expiration past the real expiration. + * + * We need to do this because krb5_cc_get_lifetime() returns a + * relative time that we need to add to the current time. We ought + * to have a version of krb5_cc_get_lifetime() that returns absolute + * time... + */ + krb5_timeofday(context, &now); + + kret = krb5_get_init_creds_password(context, &cred, handle->principal, + password, NULL, NULL, 0, NULL, opt); + krb5_get_init_creds_opt_free(context, opt); + if (kret) + goto end; + + kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); + if (kret) + goto end; + + kret = krb5_cc_initialize(context, ccache, cred.client); + if (kret) + goto end; - keytab = NULL; + kret = krb5_cc_store_cred(context, ccache, &cred); + if (kret) + goto end; + + handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; + + ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, + handle->principal, &left); + if (ret != GSS_S_COMPLETE) + goto end; + handle->endtime = now + left; + handle->ccache = ccache; ccache = NULL; - def_princ = NULL; - ret = GSS_S_FAILURE; + ret = GSS_S_COMPLETE; + kret = 0; + +end: + if (ccache != NULL) + krb5_cc_destroy(context, ccache); + if (cred.client != NULL) + krb5_free_cred_contents(context, &cred); + if (ret != GSS_S_COMPLETE && kret != 0) + *minor_status = kret; + return (ret); +} + +/* + * Acquires an initiator credential from a ccache or using a keytab. + */ +static OM_uint32 +acquire_initiator_cred(OM_uint32 *minor_status, + krb5_context context, + OM_uint32 time_req, + gss_const_OID desired_mech, + gss_cred_usage_t cred_usage, + gsskrb5_cred handle) +{ + OM_uint32 ret = GSS_S_FAILURE; + krb5_creds cred; + krb5_get_init_creds_opt *opt; + krb5_principal def_princ = NULL; + krb5_ccache def_ccache = NULL; + krb5_ccache ccache = NULL; /* we may store into this ccache */ + krb5_keytab keytab = NULL; + krb5_error_code kret = 0; + OM_uint32 left; + time_t lifetime = 0; + time_t now; + memset(&cred, 0, sizeof(cred)); /* - * If we have a preferred principal, lets try to find it in all - * caches, otherwise, fall back to default cache, ignore all - * errors while searching. + * Get current time early so we can set handle->endtime to a value that + * cannot accidentally be past the real endtime. We need a variant of + * krb5_cc_get_lifetime() that returns absolute endtime. */ + krb5_timeofday(context, &now); - if (credential_type != GSS_C_NO_OID && - !gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { - kret = KRB5_NOCREDS_SUPPLIED; /* XXX */ - goto end; - } + /* + * First look for a ccache that has the desired_name (which may be + * the default credential name). + * + * If we don't have an unexpired credential, acquire one with a + * keytab. + * + * If we acquire one with a keytab, save it in the ccache we found + * with the expired credential, if any. + * + * If we don't have any such ccache, then use a MEMORY ccache. + */ - if (handle->principal) { - kret = krb5_cc_cache_match (context, - handle->principal, - &ccache); + if (handle->principal != NULL) { + /* + * Not default credential case. See if we can find a ccache in + * the cccol for the desired_name. + */ + kret = krb5_cc_cache_match(context, + handle->principal, + &ccache); if (kret == 0) { - ret = GSS_S_COMPLETE; - goto found; + kret = krb5_cc_get_lifetime(context, ccache, &lifetime); + if (kret == 0) { + if (lifetime > 0) + goto found; + else + goto try_keytab; + } } + /* + * Fall through. We shouldn't find this in the default ccache + * either, but we'll give it a try, then we'll try using a keytab. + */ } - if (ccache == NULL) { - kret = krb5_cc_default(context, &ccache); - if (kret) - goto end; - } - kret = krb5_cc_get_principal(context, ccache, &def_princ); - if (kret != 0) { - /* we'll try to use a keytab below */ - krb5_cc_close(context, ccache); - def_princ = NULL; - kret = 0; - } else if (handle->principal == NULL) { - kret = krb5_copy_principal(context, def_princ, &handle->principal); - if (kret) - goto end; - } else if (handle->principal != NULL && - krb5_principal_compare(context, handle->principal, - def_princ) == FALSE) { - krb5_free_principal(context, def_princ); - def_princ = NULL; - krb5_cc_close(context, ccache); - ccache = NULL; + /* + * Either desired_name was GSS_C_NO_NAME (default cred) or + * krb5_cc_cache_match() failed (or found expired). + */ + kret = krb5_cc_default(context, &def_ccache); + if (kret != 0) + goto try_keytab; + kret = krb5_cc_get_lifetime(context, def_ccache, &lifetime); + if (kret != 0) + lifetime = 0; + kret = krb5_cc_get_principal(context, def_ccache, &def_princ); + if (kret != 0) + goto try_keytab; + /* + * Have a default ccache; see if it matches desired_name. + */ + if (handle->principal == NULL || + krb5_principal_compare(context, handle->principal, + def_princ) == TRUE) { + /* + * It matches. + * + * If we end up trying a keytab then we can write the result to + * the default ccache. + */ + if (handle->principal == NULL) { + kret = krb5_copy_principal(context, def_princ, &handle->principal); + if (kret) + goto end; + } + if (ccache != NULL) + krb5_cc_close(context, ccache); + ccache = def_ccache; + def_ccache = NULL; + if (lifetime > 0) + goto found; + /* else we fall through and try using a keytab */ } - if (def_princ == NULL) { - /* We have no existing credentials cache, - * so attempt to get a TGT using a keytab. - */ - if (handle->principal == NULL) { - kret = krb5_get_default_principal(context, &handle->principal); - if (kret) - goto end; - } - kret = krb5_get_init_creds_opt_alloc(context, &opt); - if (kret) - goto end; - if (credential_type != GSS_C_NO_OID && - gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { - gss_buffer_t password = (gss_buffer_t)credential_data; - - /* XXX are we requiring password to be NUL terminated? */ - - kret = krb5_get_init_creds_password(context, &cred, - handle->principal, - password->value, - NULL, NULL, 0, NULL, opt); - } else { - kret = get_keytab(context, &keytab); - if (kret) { - krb5_get_init_creds_opt_free(context, opt); - goto end; - } - kret = krb5_get_init_creds_keytab(context, &cred, - handle->principal, keytab, - 0, NULL, opt); - } - krb5_get_init_creds_opt_free(context, opt); - if (kret) - goto end; - kret = krb5_cc_new_unique(context, krb5_cc_type_memory, - NULL, &ccache); - if (kret) - goto end; - kret = krb5_cc_initialize(context, ccache, cred.client); - if (kret) { - krb5_cc_destroy(context, ccache); - goto end; - } - kret = krb5_cc_store_cred(context, ccache, &cred); - if (kret) { - krb5_cc_destroy(context, ccache); - goto end; - } - handle->lifetime = cred.times.endtime; - handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; - } else { - ret = __gsskrb5_ccache_lifetime(minor_status, - context, - ccache, - handle->principal, - &handle->lifetime); - if (ret != GSS_S_COMPLETE) { - krb5_cc_close(context, ccache); - goto end; - } - kret = 0; +try_keytab: + if (handle->principal == NULL) { + /* We need to know what client principal to use */ + kret = krb5_get_default_principal(context, &handle->principal); + if (kret) + goto end; } - found: + kret = get_keytab(context, &keytab); + if (kret) + goto end; + + kret = krb5_get_init_creds_opt_alloc(context, &opt); + if (kret) + goto end; + krb5_timeofday(context, &now); + kret = krb5_get_init_creds_keytab(context, &cred, handle->principal, + keytab, 0, NULL, opt); + krb5_get_init_creds_opt_free(context, opt); + if (kret) + goto end; + + /* + * We got a credential with a keytab. Save it if we can. + */ + if (ccache == NULL) { + /* + * There's no ccache we can overwrite with the credentials we acquired + * with a keytab. We'll use a MEMORY ccache then. + * + * Note that an application that falls into this repeatedly will do an + * AS exchange every time it acquires a credential handle. Hopefully + * this doesn't happen much. A workaround is to kinit -k once so that + * we always re-initialize the matched/default ccache here. I.e., once + * there's a FILE/DIR ccache, we'll keep it frash automatically if we + * have a keytab, but if there's no FILE/DIR ccache, then we'll + * get a fresh credential *every* time we're asked. + */ + kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); + if (kret) + goto end; + handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; + } /* else we'll re-initialize whichever ccache we matched above */ + + kret = krb5_cc_initialize(context, ccache, cred.client); + if (kret) + goto end; + kret = krb5_cc_store_cred(context, ccache, &cred); + if (kret) + goto end; + +found: + assert(handle->principal != NULL); + ret = __gsskrb5_ccache_lifetime(minor_status, context, ccache, + handle->principal, &left); + if (ret != GSS_S_COMPLETE) + goto end; + handle->endtime = now + left; handle->ccache = ccache; + ccache = NULL; ret = GSS_S_COMPLETE; + kret = 0; end: + if (ccache != NULL) { + if ((handle->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) != 0) + krb5_cc_destroy(context, ccache); + else + krb5_cc_close(context, ccache); + } + if (def_ccache != NULL) + krb5_cc_close(context, def_ccache); if (cred.client != NULL) krb5_free_cred_contents(context, &cred); if (def_princ != NULL) @@ -252,28 +367,19 @@ end: return (ret); } -static OM_uint32 acquire_acceptor_cred - (OM_uint32 * minor_status, - krb5_context context, - gss_const_OID credential_type, - const void *credential_data, - const gss_name_t desired_name, - OM_uint32 time_req, - gss_const_OID desired_mech, - gss_cred_usage_t cred_usage, - gsskrb5_cred handle - ) +static OM_uint32 +acquire_acceptor_cred(OM_uint32 * minor_status, + krb5_context context, + OM_uint32 time_req, + gss_const_OID desired_mech, + gss_cred_usage_t cred_usage, + gsskrb5_cred handle) { OM_uint32 ret; krb5_error_code kret; ret = GSS_S_FAILURE; - if (credential_type != GSS_C_NO_OID) { - kret = EINVAL; - goto end; - } - kret = get_keytab(context, &handle->keytab); if (kret) goto end; @@ -318,7 +424,7 @@ end: OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred (OM_uint32 * minor_status, - const gss_name_t desired_name, + gss_const_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, @@ -366,7 +472,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext (OM_uint32 * minor_status, - const gss_name_t desired_name, + gss_const_name_t desired_name, gss_const_OID credential_type, const void *credential_data, OM_uint32 time_req, @@ -381,25 +487,26 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext cred_usage &= GSS_C_OPTION_MASK; - if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { + if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && + cred_usage != GSS_C_BOTH) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } GSSAPI_KRB5_INIT(&context); - *output_cred_handle = NULL; + *output_cred_handle = GSS_C_NO_CREDENTIAL; handle = calloc(1, sizeof(*handle)); if (handle == NULL) { *minor_status = ENOMEM; - return (GSS_S_FAILURE); + return GSS_S_FAILURE; } HEIMDAL_MUTEX_init(&handle->cred_id_mutex); if (desired_name != GSS_C_NO_NAME) { - ret = _gsskrb5_canon_name(minor_status, context, 1, NULL, + ret = _gsskrb5_canon_name(minor_status, context, desired_name, &handle->principal); if (ret) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); @@ -407,29 +514,75 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext return ret; } } - if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { - ret = acquire_initiator_cred(minor_status, context, - credential_type, credential_data, - desired_name, time_req, - desired_mech, cred_usage, handle); - if (ret != GSS_S_COMPLETE) { - HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); - krb5_free_principal(context, handle->principal); - free(handle); - return (ret); - } - } - if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { - ret = acquire_acceptor_cred(minor_status, context, - credential_type, credential_data, - desired_name, time_req, - desired_mech, cred_usage, handle); - if (ret != GSS_S_COMPLETE) { - HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); - krb5_free_principal(context, handle->principal); - free(handle); - return (ret); - } + + if (credential_type != GSS_C_NO_OID && + gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { + /* Acquire a cred with a password */ + gss_const_buffer_t pwbuf = credential_data; + char *pw; + + if (pwbuf == NULL) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + free(handle); + *minor_status = KRB5_NOCREDS_SUPPLIED; /* see below */ + return GSS_S_CALL_INACCESSIBLE_READ; + } + + /* NUL-terminate the password, if it wasn't already */ + pw = strndup(pwbuf->value, pwbuf->length); + if (pw == NULL) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + free(handle); + *minor_status = krb5_enomem(context); + return GSS_S_CALL_INACCESSIBLE_READ; + } + ret = acquire_cred_with_password(minor_status, context, pw, time_req, + desired_mech, cred_usage, handle); + free(pw); + if (ret != GSS_S_COMPLETE) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(context, handle->principal); + free(handle); + return (ret); + } + } else if (credential_type != GSS_C_NO_OID) { + /* + * _gss_acquire_cred_ext() called with something other than a password. + * + * Not supported. + * + * _gss_acquire_cred_ext() is not a supported public interface, so + * we don't have to try too hard as to minor status codes here. + */ + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + free(handle); + *minor_status = ENOTSUP; + return GSS_S_FAILURE; + } else { + /* + * Acquire a credential from the background credential store (ccache, + * keytab). + */ + if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { + ret = acquire_initiator_cred(minor_status, context, time_req, + desired_mech, cred_usage, handle); + if (ret != GSS_S_COMPLETE) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(context, handle->principal); + free(handle); + return (ret); + } + } + if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { + ret = acquire_acceptor_cred(minor_status, context, time_req, + desired_mech, cred_usage, handle); + if (ret != GSS_S_COMPLETE) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(context, handle->principal); + free(handle); + return (ret); + } + } } ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret == GSS_S_COMPLETE) diff --git a/lib/gssapi/krb5/add_cred.c b/lib/gssapi/krb5/add_cred.c index 00cf55f62d65..42f6b48181b4 100644 --- a/lib/gssapi/krb5/add_cred.c +++ b/lib/gssapi/krb5/add_cred.c @@ -35,8 +35,8 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred ( OM_uint32 *minor_status, - const gss_cred_id_t input_cred_handle, - const gss_name_t desired_name, + gss_const_cred_id_t input_cred_handle, + gss_const_name_t desired_name, const gss_OID desired_mech, gss_cred_usage_t cred_usage, OM_uint32 initiator_time_req, @@ -47,7 +47,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred ( OM_uint32 *acceptor_time_rec) { krb5_context context; - OM_uint32 ret, lifetime; + OM_uint32 major, lifetime; gsskrb5_cred cred, handle; krb5_const_principal dname; @@ -55,99 +55,120 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred ( cred = (gsskrb5_cred)input_cred_handle; dname = (krb5_const_principal)desired_name; + if (cred == NULL && output_cred_handle == NULL) { + *minor_status = EINVAL; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + GSSAPI_KRB5_INIT (&context); - if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) { + if (desired_mech != GSS_C_NO_OID && + gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) { *minor_status = 0; return GSS_S_BAD_MECH; } - if (cred == NULL && output_cred_handle == NULL) { - *minor_status = 0; - return GSS_S_NO_CRED; - } - - if (cred == NULL) { /* XXX standard conformance failure */ - *minor_status = 0; - return GSS_S_NO_CRED; - } + if (cred == NULL) { + /* + * Acquire a credential; output_cred_handle can't be NULL, see above. + */ + heim_assert(output_cred_handle != NULL, + "internal error in _gsskrb5_add_cred()"); + + major = _gsskrb5_acquire_cred(minor_status, desired_name, + min(initiator_time_req, + acceptor_time_req), + GSS_C_NO_OID_SET, + cred_usage, + output_cred_handle, + actual_mechs, &lifetime); + if (major != GSS_S_COMPLETE) + goto failure; + + } else { + /* + * Check that we're done or copy input to output if + * output_cred_handle != NULL. + */ - /* check if requested output usage is compatible with output usage */ - if (output_cred_handle != NULL) { HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + /* Check if requested output usage is compatible with output usage */ if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = GSS_KRB5_S_G_BAD_USAGE; return(GSS_S_FAILURE); } - } - - /* check that we have the same name */ - if (dname != NULL && - krb5_principal_compare(context, dname, - cred->principal) != FALSE) { - if (output_cred_handle) - HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); - *minor_status = 0; - return GSS_S_BAD_NAME; - } - /* make a copy */ - if (output_cred_handle) { - krb5_error_code kret; + /* Check that we have the same name */ + if (dname != NULL && + krb5_principal_compare(context, dname, + cred->principal) != FALSE) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = 0; + return GSS_S_BAD_NAME; + } + + if (output_cred_handle == NULL) { + /* + * This case is basically useless as we implement a single + * mechanism here, so we can't add elements to the + * input_cred_handle. + */ + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = 0; + return GSS_S_COMPLETE; + } + + /* + * Copy input to output -- this works as if we were a + * GSS_Duplicate_cred() for one mechanism element. + */ handle = calloc(1, sizeof(*handle)); if (handle == NULL) { - HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + if (cred != NULL) + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = ENOMEM; return (GSS_S_FAILURE); } handle->usage = cred_usage; - handle->lifetime = cred->lifetime; + handle->endtime = cred->endtime; handle->principal = NULL; handle->keytab = NULL; handle->ccache = NULL; handle->mechanisms = NULL; HEIMDAL_MUTEX_init(&handle->cred_id_mutex); - ret = GSS_S_FAILURE; + major = GSS_S_FAILURE; - kret = krb5_copy_principal(context, cred->principal, - &handle->principal); - if (kret) { + *minor_status = krb5_copy_principal(context, cred->principal, + &handle->principal); + if (*minor_status) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); free(handle); - *minor_status = kret; return GSS_S_FAILURE; } if (cred->keytab) { char *name = NULL; - ret = GSS_S_FAILURE; - - kret = krb5_kt_get_full_name(context, cred->keytab, &name); - if (kret) { - *minor_status = kret; + *minor_status = krb5_kt_get_full_name(context, cred->keytab, + &name); + if (*minor_status) goto failure; - } - kret = krb5_kt_resolve(context, name, - &handle->keytab); + *minor_status = krb5_kt_resolve(context, name, &handle->keytab); krb5_xfree(name); - if (kret){ - *minor_status = kret; + if (*minor_status) goto failure; - } } if (cred->ccache) { const char *type, *name; char *type_name = NULL; - ret = GSS_S_FAILURE; - type = krb5_cc_get_type(context, cred->ccache); if (type == NULL){ *minor_status = ENOMEM; @@ -155,19 +176,15 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred ( } if (strcmp(type, "MEMORY") == 0) { - ret = krb5_cc_new_unique(context, type, - NULL, &handle->ccache); - if (ret) { - *minor_status = ret; + *minor_status = krb5_cc_new_unique(context, type, + NULL, &handle->ccache); + if (*minor_status) goto failure; - } - ret = krb5_cc_copy_cache(context, cred->ccache, - handle->ccache); - if (ret) { - *minor_status = ret; + *minor_status = krb5_cc_copy_cache(context, cred->ccache, + handle->ccache); + if (*minor_status) goto failure; - } } else { name = krb5_cc_get_name(context, cred->ccache); @@ -176,52 +193,47 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred ( goto failure; } - kret = asprintf(&type_name, "%s:%s", type, name); - if (kret < 0 || type_name == NULL) { + if (asprintf(&type_name, "%s:%s", type, name) == -1 || + type_name == NULL) { *minor_status = ENOMEM; goto failure; } - kret = krb5_cc_resolve(context, type_name, - &handle->ccache); + *minor_status = krb5_cc_resolve(context, type_name, + &handle->ccache); free(type_name); - if (kret) { - *minor_status = kret; + if (*minor_status) goto failure; - } } } - ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); - if (ret) + major = gss_create_empty_oid_set(minor_status, &handle->mechanisms); + if (major != GSS_S_COMPLETE) goto failure; - ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, - &handle->mechanisms); - if (ret) + major = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &handle->mechanisms); + if (major != GSS_S_COMPLETE) goto failure; - } - HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); - ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, - NULL, &lifetime, NULL, actual_mechs); - if (ret) - goto failure; + major = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, + NULL, &lifetime, NULL, actual_mechs); + if (major != GSS_S_COMPLETE) + goto failure; + + *output_cred_handle = (gss_cred_id_t)handle; + } if (initiator_time_rec) *initiator_time_rec = lifetime; if (acceptor_time_rec) *acceptor_time_rec = lifetime; - if (output_cred_handle) { - *output_cred_handle = (gss_cred_id_t)handle; - } - *minor_status = 0; - return ret; - - failure: + return major; +failure: if (handle) { if (handle->principal) krb5_free_principal(context, handle->principal); @@ -233,7 +245,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred ( gss_release_oid_set(NULL, &handle->mechanisms); free(handle); } - if (output_cred_handle) + if (cred && output_cred_handle) HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); - return ret; + return major; } diff --git a/lib/gssapi/krb5/aeap.c b/lib/gssapi/krb5/aeap.c index 47913e4aec03..fe95ecf0b9cc 100644 --- a/lib/gssapi/krb5/aeap.c +++ b/lib/gssapi/krb5/aeap.c @@ -44,17 +44,43 @@ _gk_wrap_iov(OM_uint32 * minor_status, gss_iov_buffer_desc *iov, int iov_count) { - const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; - krb5_context context; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + krb5_context context; + OM_uint32 ret; + krb5_keyblock *key; + krb5_keytype keytype; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_cfx_iov(minor_status, ctx, context, + conf_req_flag, conf_state, + iov, iov_count); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype(context, key->keytype, &keytype); - GSSAPI_KRB5_INIT (&context); + switch (keytype) { + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_wrap_iov_arcfour(minor_status, ctx, context, + conf_req_flag, conf_state, + iov, iov_count, key); + break; - if (ctx->more_flags & IS_CFX) - return _gssapi_wrap_cfx_iov(minor_status, ctx, context, - conf_req_flag, conf_state, - iov, iov_count); + default: + ret = GSS_S_FAILURE; + break; + } - return GSS_S_FAILURE; + krb5_free_keyblock(context, key); + return ret; } OM_uint32 GSSAPI_CALLCONV @@ -67,6 +93,9 @@ _gk_unwrap_iov(OM_uint32 *minor_status, { const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; krb5_context context; + OM_uint32 ret; + krb5_keytype keytype; + krb5_keyblock *key; GSSAPI_KRB5_INIT (&context); @@ -74,7 +103,30 @@ _gk_unwrap_iov(OM_uint32 *minor_status, return _gssapi_unwrap_cfx_iov(minor_status, ctx, context, conf_state, qop_state, iov, iov_count); - return GSS_S_FAILURE; + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype(context, key->keytype, &keytype); + + switch (keytype) { + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_unwrap_iov_arcfour(minor_status, ctx, context, + conf_state, qop_state, + iov, iov_count, key); + break; + + default: + ret = GSS_S_FAILURE; + break; + } + + krb5_free_keyblock(context, key); + return ret; } OM_uint32 GSSAPI_CALLCONV @@ -88,6 +140,9 @@ _gk_wrap_iov_length(OM_uint32 * minor_status, { const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; krb5_context context; + OM_uint32 ret; + krb5_keytype keytype; + krb5_keyblock *key; GSSAPI_KRB5_INIT (&context); @@ -96,5 +151,28 @@ _gk_wrap_iov_length(OM_uint32 * minor_status, conf_req_flag, qop_req, conf_state, iov, iov_count); - return GSS_S_FAILURE; + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(ctx, context, &key); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype(context, key->keytype, &keytype); + + switch (keytype) { + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_wrap_iov_length_arcfour(minor_status, ctx, context, + conf_req_flag, qop_req, conf_state, + iov, iov_count); + break; + + default: + ret = GSS_S_FAILURE; + break; + } + + krb5_free_keyblock(context, key); + return ret; } diff --git a/lib/gssapi/krb5/arcfour.c b/lib/gssapi/krb5/arcfour.c index 15b1b343409a..0aa2da0808bf 100644 --- a/lib/gssapi/krb5/arcfour.c +++ b/lib/gssapi/krb5/arcfour.c @@ -69,7 +69,7 @@ static krb5_error_code arcfour_mic_key(krb5_context context, krb5_keyblock *key, - void *cksum_data, size_t cksum_size, + const void *cksum_data, size_t cksum_size, void *key6_data, size_t key6_size) { krb5_error_code ret; @@ -86,7 +86,7 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, cksum_k5.checksum.data = k5_data; cksum_k5.checksum.length = sizeof(k5_data); - if (key->keytype == ENCTYPE_ARCFOUR_HMAC_MD5_56) { + if (key->keytype == KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56) { char L40[14] = "fortybits"; memcpy(L40 + 10, T, sizeof(T)); @@ -100,7 +100,7 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, if (ret) return ret; - key5.keytype = ENCTYPE_ARCFOUR_HMAC_MD5; + key5.keytype = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5; key5.keyvalue = cksum_k5.checksum; cksum_k6.checksum.data = key6_data; @@ -112,30 +112,73 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, static krb5_error_code -arcfour_mic_cksum(krb5_context context, - krb5_keyblock *key, unsigned usage, - u_char *sgn_cksum, size_t sgn_cksum_sz, - const u_char *v1, size_t l1, - const void *v2, size_t l2, - const void *v3, size_t l3) +arcfour_mic_cksum_iov(krb5_context context, + krb5_keyblock *key, unsigned usage, + u_char *sgn_cksum, size_t sgn_cksum_sz, + const u_char *v1, size_t l1, + const void *v2, size_t l2, + const gss_iov_buffer_desc *iov, + int iov_count, + const gss_iov_buffer_desc *padding) { Checksum CKSUM; u_char *ptr; size_t len; + size_t ofs = 0; + int i; krb5_crypto crypto; krb5_error_code ret; assert(sgn_cksum_sz == 8); - len = l1 + l2 + l3; + len = l1 + l2; + + for (i=0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + continue; + } + + len += iov[i].buffer.length; + } + + if (padding) { + len += padding->buffer.length; + } ptr = malloc(len); if (ptr == NULL) return ENOMEM; - memcpy(ptr, v1, l1); - memcpy(ptr + l1, v2, l2); - memcpy(ptr + l1 + l2, v3, l3); + memcpy(ptr + ofs, v1, l1); + ofs += l1; + memcpy(ptr + ofs, v2, l2); + ofs += l2; + + for (i=0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + continue; + } + + memcpy(ptr + ofs, + iov[i].buffer.value, + iov[i].buffer.length); + ofs += iov[i].buffer.length; + } + + if (padding) { + memcpy(ptr + ofs, + padding->buffer.value, + padding->buffer.length); + ofs += padding->buffer.length; + } ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) { @@ -149,6 +192,7 @@ arcfour_mic_cksum(krb5_context context, 0, ptr, len, &CKSUM); + memset(ptr, 0, len); free(ptr); if (ret == 0) { memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz); @@ -159,6 +203,26 @@ arcfour_mic_cksum(krb5_context context, return ret; } +static krb5_error_code +arcfour_mic_cksum(krb5_context context, + krb5_keyblock *key, unsigned usage, + u_char *sgn_cksum, size_t sgn_cksum_sz, + const u_char *v1, size_t l1, + const void *v2, size_t l2, + const void *v3, size_t l3) +{ + gss_iov_buffer_desc iov; + + iov.type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; + iov.buffer.value = rk_UNCONST(v3); + iov.buffer.length = l3; + + return arcfour_mic_cksum_iov(context, key, usage, + sgn_cksum, sgn_cksum_sz, + v1, l1, v2, l2, + &iov, 1, NULL); +} + OM_uint32 _gssapi_get_mic_arcfour(OM_uint32 * minor_status, @@ -760,3 +824,563 @@ _gssapi_wrap_size_arcfour(OM_uint32 *minor_status, return GSS_S_COMPLETE; } + +OM_uint32 +_gssapi_wrap_iov_length_arcfour(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 major_status; + size_t data_len = 0; + int i; + gss_iov_buffer_desc *header = NULL; + gss_iov_buffer_desc *padding = NULL; + gss_iov_buffer_desc *trailer = NULL; + + *minor_status = 0; + + for (i = 0; i < iov_count; i++) { + switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_EMPTY: + break; + case GSS_IOV_BUFFER_TYPE_DATA: + data_len += iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_HEADER: + if (header != NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + header = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_TRAILER: + if (trailer != NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + trailer = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_PADDING: + if (padding != NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + padding = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + + major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + if (IS_DCE_STYLE(ctx)) { + size_t len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + size_t total_len; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + header->buffer.length = total_len; + } else { + size_t len; + size_t total_len; + if (padding) { + data_len += 1; /* padding */ + } + len = data_len + GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + header->buffer.length = total_len - data_len; + } + + if (trailer) { + trailer->buffer.length = 0; + } + + if (padding) { + padding->buffer.length = 1; + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_wrap_iov_arcfour(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count, + krb5_keyblock *key) +{ + OM_uint32 major_status, junk; + gss_iov_buffer_desc *header, *padding, *trailer; + krb5_error_code kret; + int32_t seq_number; + u_char Klocaldata[16], k6_data[16], *p, *p0; + size_t make_len = 0; + size_t header_len = 0; + size_t data_len = 0; + krb5_keyblock Klocal; + int i; + + header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + break; + default: + continue; + } + + data_len += iov[i].buffer.length; + } + + if (padding) { + data_len += 1; + } + + if (IS_DCE_STYLE(ctx)) { + size_t unwrapped_len; + unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(unwrapped_len, + &make_len, + &header_len, + GSS_KRB5_MECHANISM); + } else { + size_t unwrapped_len; + unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + data_len; + _gssapi_encap_length(unwrapped_len, + &make_len, + &header_len, + GSS_KRB5_MECHANISM); + header_len -= data_len; + } + + if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) { + major_status = _gk_allocate_buffer(minor_status, header, + header_len); + if (major_status != GSS_S_COMPLETE) + goto failure; + } else if (header->buffer.length < header_len) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else { + header->buffer.length = header_len; + } + + if (padding) { + if (GSS_IOV_BUFFER_FLAGS(padding->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) { + major_status = _gk_allocate_buffer(minor_status, padding, 1); + if (major_status != GSS_S_COMPLETE) + goto failure; + } else if (padding->buffer.length < 1) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else { + padding->buffer.length = 1; + } + memset(padding->buffer.value, 1, 1); + } + + if (trailer) { + trailer->buffer.length = 0; + trailer->buffer.value = NULL; + } + + p0 = _gssapi_make_mech_header(header->buffer.value, + make_len, + GSS_KRB5_MECHANISM); + p = p0; + + *p++ = 0x02; /* TOK_ID */ + *p++ = 0x01; + *p++ = 0x11; /* SGN_ALG */ + *p++ = 0x00; + if (conf_req_flag) { + *p++ = 0x10; /* SEAL_ALG */ + *p++ = 0x00; + } else { + *p++ = 0xff; /* SEAL_ALG */ + *p++ = 0xff; + } + *p++ = 0xff; /* Filler */ + *p++ = 0xff; + + p = NULL; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &seq_number); + _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8); + + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + memset(p0 + 8 + 4, + (ctx->more_flags & LOCAL) ? 0 : 0xff, + 4); + + krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */ + + /* Sign Data */ + kret = arcfour_mic_cksum_iov(context, + key, KRB5_KU_USAGE_SEAL, + p0 + 16, 8, /* SGN_CKSUM */ + p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */ + p0 + 24, 8, /* Confounder */ + iov, iov_count, /* Data + SignOnly */ + padding); /* padding */ + if (kret) { + *minor_status = kret; + major_status = GSS_S_FAILURE; + goto failure; + } + + Klocal.keytype = key->keytype; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) { + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + kret = arcfour_mic_key(context, &Klocal, + p0 + 8, 4, /* SND_SEQ */ + k6_data, sizeof(k6_data)); + memset(Klocaldata, 0, sizeof(Klocaldata)); + if (kret) { + *minor_status = kret; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (conf_req_flag) { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + + /* Confounder */ + EVP_Cipher(&rc4_key, p0 + 24, p0 + 24, 8); + + /* Seal Data */ + for (i=0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + break; + default: + continue; + } + + EVP_Cipher(&rc4_key, iov[i].buffer.value, + iov[i].buffer.value, iov[i].buffer.length); + } + + /* Padding */ + if (padding) { + EVP_Cipher(&rc4_key, padding->buffer.value, + padding->buffer.value, padding->buffer.length); + } + + EVP_CIPHER_CTX_cleanup(&rc4_key); + } + memset(k6_data, 0, sizeof(k6_data)); + + kret = arcfour_mic_key(context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (kret) { + *minor_status = kret; + major_status = GSS_S_FAILURE; + return major_status; + } + + { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, p0 + 8, p0 + 8, 8); /* SND_SEQ */ + EVP_CIPHER_CTX_cleanup(&rc4_key); + + memset(k6_data, 0, sizeof(k6_data)); + } + + if (conf_state) + *conf_state = conf_req_flag; + + *minor_status = 0; + return GSS_S_COMPLETE; + +failure: + + gss_release_iov_buffer(&junk, iov, iov_count); + + return major_status; +} + +OM_uint32 +_gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int *pconf_state, + gss_qop_t *pqop_state, + gss_iov_buffer_desc *iov, + int iov_count, + krb5_keyblock *key) +{ + OM_uint32 major_status; + gss_iov_buffer_desc *header, *padding, *trailer; + krb5_keyblock Klocal; + uint8_t Klocaldata[16]; + uint8_t k6_data[16], snd_seq[8], Confounder[8]; + uint8_t cksum_data[8]; + uint8_t *_p = NULL; + const uint8_t *p, *p0; + size_t verify_len = 0; + uint32_t seq_number; + size_t hlen = 0; + int conf_state; + int cmp; + size_t i; + krb5_error_code kret; + OM_uint32 ret; + + if (pconf_state != NULL) { + *pconf_state = 0; + } + if (pqop_state != NULL) { + *pqop_state = 0; + } + + header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + /* Check if the packet is correct */ + major_status = _gk_verify_buffers(minor_status, + ctx, + header, + padding, + trailer); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + if (padding != NULL && padding->buffer.length != 1) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (IS_DCE_STYLE(context)) { + verify_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + + GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE; + if (header->buffer.length > verify_len) { + return GSS_S_BAD_MECH; + } + } else { + verify_len = header->buffer.length; + } + _p = header->buffer.value; + + ret = _gssapi_verify_mech_header(&_p, + verify_len, + GSS_KRB5_MECHANISM); + if (ret) { + return ret; + } + p0 = _p; + + /* length of mech header */ + hlen = (p0 - (uint8_t *)header->buffer.value); + hlen += GSS_ARCFOUR_WRAP_TOKEN_SIZE; + + if (hlen > header->buffer.length) { + return GSS_S_BAD_MECH; + } + + p = p0; + + if (memcmp(p, "\x02\x01", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ + return GSS_S_BAD_SIG; + p += 2; + + if (memcmp (p, "\x10\x00", 2) == 0) + conf_state = 1; + else if (memcmp (p, "\xff\xff", 2) == 0) + conf_state = 0; + else + return GSS_S_BAD_SIG; + + p += 2; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_BAD_MIC; + p = NULL; + + kret = arcfour_mic_key(context, + key, + p0 + 16, /* SGN_CKSUM */ + 8, /* SGN_CKSUM_LEN */ + k6_data, + sizeof(k6_data)); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, snd_seq, p0 + 8, 8); /* SND_SEQ */ + EVP_CIPHER_CTX_cleanup(&rc4_key); + + memset(k6_data, 0, sizeof(k6_data)); + } + + _gsskrb5_decode_be_om_uint32(snd_seq, &seq_number); + + if (ctx->more_flags & LOCAL) { + cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4); + } else { + cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); + } + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + if (ctx->more_flags & LOCAL) { + cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4); + } else { + cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); + } + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + /* keyblock */ + Klocal.keytype = key->keytype; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) { + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + + kret = arcfour_mic_key(context, + &Klocal, + snd_seq, + 4, + k6_data, sizeof(k6_data)); + memset(Klocaldata, 0, sizeof(Klocaldata)); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (conf_state == 1) { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + + /* Confounder */ + EVP_Cipher(&rc4_key, Confounder, p0 + 24, 8); + + /* Data */ + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + break; + default: + continue; + } + + EVP_Cipher(&rc4_key, iov[i].buffer.value, + iov[i].buffer.value, iov[i].buffer.length); + } + + /* Padding */ + if (padding) { + EVP_Cipher(&rc4_key, padding->buffer.value, + padding->buffer.value, padding->buffer.length); + } + + EVP_CIPHER_CTX_cleanup(&rc4_key); + } else { + /* Confounder */ + memcpy(Confounder, p0 + 24, 8); + } + memset(k6_data, 0, sizeof(k6_data)); + + /* Prepare the buffer for signing */ + kret = arcfour_mic_cksum_iov(context, + key, KRB5_KU_USAGE_SEAL, + cksum_data, sizeof(cksum_data), + p0, 8, + Confounder, sizeof(Confounder), + iov, iov_count, + padding); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + if (padding) { + size_t plen; + + ret = _gssapi_verify_pad(&padding->buffer, 1, &plen); + if (ret) { + *minor_status = 0; + return ret; + } + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + if (ret != 0) { + return ret; + } + + if (pconf_state) { + *pconf_state = conf_state; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/lib/gssapi/krb5/authorize_localname.c b/lib/gssapi/krb5/authorize_localname.c index 4bab062ac4ce..5621c1f9cfe0 100644 --- a/lib/gssapi/krb5/authorize_localname.c +++ b/lib/gssapi/krb5/authorize_localname.c @@ -34,7 +34,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_authorize_localname(OM_uint32 *minor_status, - const gss_name_t input_name, + gss_const_name_t input_name, gss_const_buffer_t user_name, gss_const_OID user_name_type) { diff --git a/lib/gssapi/krb5/canonicalize_name.c b/lib/gssapi/krb5/canonicalize_name.c index 7fc921bac095..62de42358f62 100644 --- a/lib/gssapi/krb5/canonicalize_name.c +++ b/lib/gssapi/krb5/canonicalize_name.c @@ -35,7 +35,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_canonicalize_name ( OM_uint32 * minor_status, - const gss_name_t input_name, + gss_const_name_t input_name, const gss_OID mech_type, gss_name_t * output_name ) @@ -48,7 +48,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_canonicalize_name ( GSSAPI_KRB5_INIT (&context); - ret = _gsskrb5_canon_name(minor_status, context, 1, NULL, input_name, &name); + ret = _gsskrb5_canon_name(minor_status, context, input_name, &name); if (ret) return ret; diff --git a/lib/gssapi/krb5/cfx.c b/lib/gssapi/krb5/cfx.c index 3c1536b60ea5..29fecca861ce 100644 --- a/lib/gssapi/krb5/cfx.c +++ b/lib/gssapi/krb5/cfx.c @@ -391,7 +391,6 @@ _gssapi_wrap_cfx_iov(OM_uint32 *minor_status, if (IS_DCE_STYLE(ctx)) rrc -= ec; gsshsize += gsstsize; - gsstsize = 0; } else if (GSS_IOV_BUFFER_FLAGS(trailer->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) { major_status = _gk_allocate_buffer(minor_status, trailer, gsstsize); if (major_status) @@ -683,6 +682,7 @@ unrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int if (iov[i].buffer.length <= skip) { skip -= iov[i].buffer.length; } else { + /* copy back to original buffer */ memcpy(((uint8_t *)iov[i].buffer.value) + skip, q, iov[i].buffer.length - skip); q += iov[i].buffer.length - skip; skip = 0; @@ -697,13 +697,14 @@ unrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) { - memcpy(q, iov[i].buffer.value, min(iov[i].buffer.length, skip)); + memcpy(iov[i].buffer.value, q, min(iov[i].buffer.length, skip)); if (iov[i].buffer.length > skip) break; skip -= iov[i].buffer.length; q += iov[i].buffer.length; } } + free(p); return GSS_S_COMPLETE; } @@ -930,7 +931,6 @@ _gssapi_unwrap_cfx_iov(OM_uint32 *minor_status, } gsshsize += gsstsize; - gsstsize = 0; } else if (trailer->buffer.length != gsstsize) { major_status = GSS_S_DEFECTIVE_TOKEN; goto failure; diff --git a/lib/gssapi/krb5/compare_name.c b/lib/gssapi/krb5/compare_name.c index 7409d45fcb89..4a37e877df5d 100644 --- a/lib/gssapi/krb5/compare_name.c +++ b/lib/gssapi/krb5/compare_name.c @@ -35,8 +35,8 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_compare_name (OM_uint32 * minor_status, - const gss_name_t name1, - const gss_name_t name2, + gss_const_name_t name1, + gss_const_name_t name2, int * name_equal ) { diff --git a/lib/gssapi/krb5/context_time.c b/lib/gssapi/krb5/context_time.c index cb1550011cd7..58249cb5a311 100644 --- a/lib/gssapi/krb5/context_time.c +++ b/lib/gssapi/krb5/context_time.c @@ -36,27 +36,28 @@ OM_uint32 _gsskrb5_lifetime_left(OM_uint32 *minor_status, krb5_context context, - OM_uint32 lifetime, + OM_uint32 endtime, OM_uint32 *lifetime_rec) { - krb5_timestamp timeret; + krb5_timestamp now; krb5_error_code kret; - if (lifetime == 0) { + if (endtime == 0) { *lifetime_rec = GSS_C_INDEFINITE; return GSS_S_COMPLETE; } - kret = krb5_timeofday(context, &timeret); + kret = krb5_timeofday(context, &now); if (kret) { + *lifetime_rec = 0; *minor_status = kret; return GSS_S_FAILURE; } - if (lifetime < timeret) + if (endtime < now) *lifetime_rec = 0; else - *lifetime_rec = lifetime - timeret; + *lifetime_rec = endtime - now; return GSS_S_COMPLETE; } @@ -64,23 +65,23 @@ _gsskrb5_lifetime_left(OM_uint32 *minor_status, OM_uint32 GSSAPI_CALLCONV _gsskrb5_context_time (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, + gss_const_ctx_id_t context_handle, OM_uint32 * time_rec ) { krb5_context context; - OM_uint32 lifetime; + OM_uint32 endtime; OM_uint32 major_status; const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; GSSAPI_KRB5_INIT (&context); HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); - lifetime = ctx->lifetime; + endtime = ctx->endtime; HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); major_status = _gsskrb5_lifetime_left(minor_status, context, - lifetime, time_rec); + endtime, time_rec); if (major_status != GSS_S_COMPLETE) return major_status; diff --git a/lib/gssapi/krb5/copy_ccache.c b/lib/gssapi/krb5/copy_ccache.c index e332d29c84aa..14296bccd7e2 100644 --- a/lib/gssapi/krb5/copy_ccache.c +++ b/lib/gssapi/krb5/copy_ccache.c @@ -89,6 +89,8 @@ _gsskrb5_krb5_import_cred(OM_uint32 *minor_status, handle->usage = 0; if (id) { + time_t now; + OM_uint32 left; char *str; handle->usage |= GSS_C_INITIATE; @@ -116,17 +118,18 @@ _gsskrb5_krb5_import_cred(OM_uint32 *minor_status, } } + krb5_timeofday(context, &now); ret = __gsskrb5_ccache_lifetime(minor_status, context, id, handle->principal, - &handle->lifetime); + &left); if (ret != GSS_S_COMPLETE) { krb5_free_principal(context, handle->principal); free(handle); return ret; } - + handle->endtime = now + left; kret = krb5_cc_get_full_name(context, id, &str); if (kret) diff --git a/lib/gssapi/krb5/creds.c b/lib/gssapi/krb5/creds.c index fa45d19b9812..1cc3ac848ad0 100644 --- a/lib/gssapi/krb5/creds.c +++ b/lib/gssapi/krb5/creds.c @@ -62,6 +62,9 @@ _gsskrb5_export_cred(OM_uint32 *minor_status, type = krb5_cc_get_type(context, handle->ccache); if (strcmp(type, "MEMORY") == 0) { krb5_creds *creds; + krb5_data config_start_realm; + char *start_realm; + ret = krb5_store_uint32(sp, 0); if (ret) { krb5_storage_free(sp); @@ -69,9 +72,25 @@ _gsskrb5_export_cred(OM_uint32 *minor_status, return GSS_S_FAILURE; } - ret = _krb5_get_krbtgt(context, handle->ccache, - handle->principal->realm, - &creds); + ret = krb5_cc_get_config(context, handle->ccache, NULL, "start_realm", + &config_start_realm); + if (ret == 0) { + start_realm = strndup(config_start_realm.data, + config_start_realm.length); + krb5_data_free(&config_start_realm); + } else { + start_realm = strdup(krb5_principal_get_realm(context, + handle->principal)); + } + if (start_realm == NULL) { + *minor_status = krb5_enomem(context); + krb5_storage_free(sp); + return GSS_S_FAILURE; + } + + ret = _krb5_get_krbtgt(context, handle->ccache, start_realm, &creds); + free(start_realm); + start_realm = NULL; if (ret) { krb5_storage_free(sp); *minor_status = ret; @@ -210,6 +229,10 @@ _gsskrb5_import_cred(OM_uint32 * minor_status, ret = krb5_cc_store_cred(context, id, &creds); krb5_free_cred_contents(context, &creds); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; diff --git a/lib/gssapi/krb5/decapsulate.c b/lib/gssapi/krb5/decapsulate.c index 640c064d0bf1..86085f569501 100644 --- a/lib/gssapi/krb5/decapsulate.c +++ b/lib/gssapi/krb5/decapsulate.c @@ -190,6 +190,9 @@ _gssapi_verify_pad(gss_buffer_t wrapped_token, size_t padlength; int i; + if (wrapped_token->length < 1) + return GSS_S_BAD_MECH; + pad = (u_char *)wrapped_token->value + wrapped_token->length - 1; padlength = *pad; diff --git a/lib/gssapi/krb5/display_name.c b/lib/gssapi/krb5/display_name.c index a296399cecad..67cb61e7cb81 100644 --- a/lib/gssapi/krb5/display_name.c +++ b/lib/gssapi/krb5/display_name.c @@ -35,7 +35,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_display_name (OM_uint32 * minor_status, - const gss_name_t input_name, + gss_const_name_t input_name, gss_buffer_t output_name_buffer, gss_OID * output_name_type ) diff --git a/lib/gssapi/krb5/duplicate_name.c b/lib/gssapi/krb5/duplicate_name.c index 0bc57e8a03ed..43519d6a2d53 100644 --- a/lib/gssapi/krb5/duplicate_name.c +++ b/lib/gssapi/krb5/duplicate_name.c @@ -35,7 +35,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_duplicate_name ( OM_uint32 * minor_status, - const gss_name_t src_name, + gss_const_name_t src_name, gss_name_t * dest_name ) { diff --git a/lib/gssapi/krb5/export_name.c b/lib/gssapi/krb5/export_name.c index 32368d3ccefd..1686a6570af5 100644 --- a/lib/gssapi/krb5/export_name.c +++ b/lib/gssapi/krb5/export_name.c @@ -35,7 +35,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_export_name (OM_uint32 * minor_status, - const gss_name_t input_name, + gss_const_name_t input_name, gss_buffer_t exported_name ) { diff --git a/lib/gssapi/krb5/export_sec_context.c b/lib/gssapi/krb5/export_sec_context.c index eeb2743b4322..b500f4230cd3 100644 --- a/lib/gssapi/krb5/export_sec_context.c +++ b/lib/gssapi/krb5/export_sec_context.c @@ -34,9 +34,9 @@ #include "gsskrb5_locl.h" OM_uint32 GSSAPI_CALLCONV -_gsskrb5_export_sec_context ( - OM_uint32 * minor_status, - gss_ctx_id_t * context_handle, +_gsskrb5_export_sec_context( + OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, gss_buffer_t interprocess_token ) { @@ -204,7 +204,11 @@ _gsskrb5_export_sec_context ( *minor_status = kret; goto failure; } - kret = krb5_store_int32 (sp, ctx->lifetime); + /* + * XXX We should put a 64-bit int here, but we don't have a + * krb5_store_int64() yet. + */ + kret = krb5_store_int32 (sp, ctx->endtime); if (kret) { *minor_status = kret; goto failure; diff --git a/lib/gssapi/krb5/external.c b/lib/gssapi/krb5/external.c index 26ede2487d30..deae016bc96b 100644 --- a/lib/gssapi/krb5/external.c +++ b/lib/gssapi/krb5/external.c @@ -202,67 +202,131 @@ static gss_mo_desc krb5_mo[] = { }, { GSS_C_MA_MECH_CONCRETE, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_ITOK_FRAMED, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_AUTH_INIT, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_AUTH_TARG, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_AUTH_INIT_ANON, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_DELEG_CRED, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_INTEG_PROT, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_CONF_PROT, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_MIC, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_WRAP, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_PROT_READY, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_REPLAY_DET, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_OOS_DET, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_CBINDINGS, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_PFS, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL }, { GSS_C_MA_CTX_TRANS, - GSS_MO_MA + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL } }; @@ -324,7 +388,7 @@ static gssapi_mech_interface_desc krb5_mech = { NULL, krb5_mo, sizeof(krb5_mo) / sizeof(krb5_mo[0]), - _gsskrb5_pname_to_uid, + _gsskrb5_localname, _gsskrb5_authorize_localname, NULL, NULL, diff --git a/lib/gssapi/krb5/get_mic.c b/lib/gssapi/krb5/get_mic.c index 0109ca7c6e76..643385d9e892 100644 --- a/lib/gssapi/krb5/get_mic.c +++ b/lib/gssapi/krb5/get_mic.c @@ -275,7 +275,7 @@ mic_des3 OM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, + gss_const_ctx_id_t context_handle, gss_qop_t qop_req, const gss_buffer_t message_buffer, gss_buffer_t message_token @@ -285,7 +285,6 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; krb5_keyblock *key; OM_uint32 ret; - krb5_keytype keytype; GSSAPI_KRB5_INIT (&context); @@ -300,10 +299,11 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic *minor_status = ret; return GSS_S_FAILURE; } - krb5_enctype_to_keytype (context, key->keytype, &keytype); - switch (keytype) { - case KEYTYPE_DES : + switch (key->keytype) { + case KRB5_ENCTYPE_DES_CBC_CRC : + case KRB5_ENCTYPE_DES_CBC_MD4 : + case KRB5_ENCTYPE_DES_CBC_MD5 : #ifdef HEIM_WEAK_CRYPTO ret = mic_des (minor_status, ctx, context, qop_req, message_buffer, message_token, key); @@ -311,12 +311,13 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic ret = GSS_S_FAILURE; #endif break; - case KEYTYPE_DES3 : + case KRB5_ENCTYPE_DES3_CBC_MD5 : + case KRB5_ENCTYPE_DES3_CBC_SHA1 : ret = mic_des3 (minor_status, ctx, context, qop_req, message_buffer, message_token, key); break; - case KEYTYPE_ARCFOUR: - case KEYTYPE_ARCFOUR_56: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: ret = _gssapi_get_mic_arcfour (minor_status, ctx, context, qop_req, message_buffer, message_token, key); break; diff --git a/lib/gssapi/krb5/gsskrb5-private.h b/lib/gssapi/krb5/gsskrb5-private.h index 2a669d867f16..e05d4a6b6da6 100644 --- a/lib/gssapi/krb5/gsskrb5-private.h +++ b/lib/gssapi/krb5/gsskrb5-private.h @@ -179,6 +179,17 @@ _gssapi_unwrap_cfx_iov ( int /*iov_count*/); OM_uint32 +_gssapi_unwrap_iov_arcfour ( + OM_uint32 */*minor_status*/, + gsskrb5_ctx /*ctx*/, + krb5_context /*context*/, + int */*pconf_state*/, + gss_qop_t */*pqop_state*/, + gss_iov_buffer_desc */*iov*/, + int /*iov_count*/, + krb5_keyblock */*key*/); + +OM_uint32 _gssapi_verify_mech_header ( u_char **/*str*/, size_t /*total_len*/, @@ -243,6 +254,28 @@ _gssapi_wrap_cfx_iov ( int /*iov_count*/); OM_uint32 +_gssapi_wrap_iov_arcfour ( + OM_uint32 */*minor_status*/, + gsskrb5_ctx /*ctx*/, + krb5_context /*context*/, + int /*conf_req_flag*/, + int */*conf_state*/, + gss_iov_buffer_desc */*iov*/, + int /*iov_count*/, + krb5_keyblock */*key*/); + +OM_uint32 +_gssapi_wrap_iov_length_arcfour ( + OM_uint32 */*minor_status*/, + gsskrb5_ctx /*ctx*/, + krb5_context /*context*/, + int /*conf_req_flag*/, + gss_qop_t /*qop_req*/, + int */*conf_state*/, + gss_iov_buffer_desc */*iov*/, + int /*iov_count*/); + +OM_uint32 _gssapi_wrap_iov_length_cfx ( OM_uint32 */*minor_status*/, gsskrb5_ctx /*ctx*/, @@ -278,7 +311,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_accept_sec_context ( OM_uint32 * /*minor_status*/, gss_ctx_id_t * /*context_handle*/, - const gss_cred_id_t /*acceptor_cred_handle*/, + gss_const_cred_id_t /*acceptor_cred_handle*/, const gss_buffer_t /*input_token_buffer*/, const gss_channel_bindings_t /*input_chan_bindings*/, gss_name_t * /*src_name*/, @@ -291,7 +324,7 @@ _gsskrb5_accept_sec_context ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred ( OM_uint32 * /*minor_status*/, - const gss_name_t /*desired_name*/, + gss_const_name_t /*desired_name*/, OM_uint32 /*time_req*/, const gss_OID_set /*desired_mechs*/, gss_cred_usage_t /*cred_usage*/, @@ -302,7 +335,7 @@ _gsskrb5_acquire_cred ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext ( OM_uint32 * /*minor_status*/, - const gss_name_t /*desired_name*/, + gss_const_name_t /*desired_name*/, gss_const_OID /*credential_type*/, const void */*credential_data*/, OM_uint32 /*time_req*/, @@ -313,8 +346,8 @@ _gsskrb5_acquire_cred_ext ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred ( OM_uint32 */*minor_status*/, - const gss_cred_id_t /*input_cred_handle*/, - const gss_name_t /*desired_name*/, + gss_const_cred_id_t /*input_cred_handle*/, + gss_const_name_t /*desired_name*/, const gss_OID /*desired_mech*/, gss_cred_usage_t /*cred_usage*/, OM_uint32 /*initiator_time_req*/, @@ -327,7 +360,7 @@ _gsskrb5_add_cred ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_authorize_localname ( OM_uint32 */*minor_status*/, - const gss_name_t /*input_name*/, + gss_const_name_t /*input_name*/, gss_const_buffer_t /*user_name*/, gss_const_OID /*user_name_type*/); @@ -335,15 +368,13 @@ OM_uint32 _gsskrb5_canon_name ( OM_uint32 */*minor_status*/, krb5_context /*context*/, - int /*use_dns*/, - krb5_const_principal /*sourcename*/, - gss_name_t /*targetname*/, + gss_const_name_t /*targetname*/, krb5_principal */*out*/); OM_uint32 GSSAPI_CALLCONV _gsskrb5_canonicalize_name ( OM_uint32 * /*minor_status*/, - const gss_name_t /*input_name*/, + gss_const_name_t /*input_name*/, const gss_OID /*mech_type*/, gss_name_t * output_name ); @@ -353,14 +384,14 @@ _gsskrb5_clear_status (void); OM_uint32 GSSAPI_CALLCONV _gsskrb5_compare_name ( OM_uint32 * /*minor_status*/, - const gss_name_t /*name1*/, - const gss_name_t /*name2*/, + gss_const_name_t /*name1*/, + gss_const_name_t /*name2*/, int * name_equal ); OM_uint32 GSSAPI_CALLCONV _gsskrb5_context_time ( OM_uint32 * /*minor_status*/, - const gss_ctx_id_t /*context_handle*/, + gss_const_ctx_id_t /*context_handle*/, OM_uint32 * time_rec ); OM_uint32 @@ -406,7 +437,7 @@ _gsskrb5_delete_sec_context ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_display_name ( OM_uint32 * /*minor_status*/, - const gss_name_t /*input_name*/, + gss_const_name_t /*input_name*/, gss_buffer_t /*output_name_buffer*/, gss_OID * output_name_type ); @@ -422,7 +453,7 @@ _gsskrb5_display_status ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_duplicate_name ( OM_uint32 * /*minor_status*/, - const gss_name_t /*src_name*/, + gss_const_name_t /*src_name*/, gss_name_t * dest_name ); void @@ -459,13 +490,13 @@ _gsskrb5_export_cred ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_export_name ( OM_uint32 * /*minor_status*/, - const gss_name_t /*input_name*/, + gss_const_name_t /*input_name*/, gss_buffer_t exported_name ); OM_uint32 GSSAPI_CALLCONV _gsskrb5_export_sec_context ( - OM_uint32 * /*minor_status*/, - gss_ctx_id_t * /*context_handle*/, + OM_uint32 */*minor_status*/, + gss_ctx_id_t */*context_handle*/, gss_buffer_t interprocess_token ); ssize_t @@ -477,7 +508,7 @@ _gsskrb5_get_mech ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic ( OM_uint32 * /*minor_status*/, - const gss_ctx_id_t /*context_handle*/, + gss_const_ctx_id_t /*context_handle*/, gss_qop_t /*qop_req*/, const gss_buffer_t /*message_buffer*/, gss_buffer_t message_token ); @@ -518,9 +549,9 @@ _gsskrb5_init (krb5_context */*context*/); OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context ( OM_uint32 * /*minor_status*/, - const gss_cred_id_t /*cred_handle*/, + gss_const_cred_id_t /*cred_handle*/, gss_ctx_id_t * /*context_handle*/, - const gss_name_t /*target_name*/, + gss_const_name_t /*target_name*/, const gss_OID /*mech_type*/, OM_uint32 /*req_flags*/, OM_uint32 /*time_req*/, @@ -534,7 +565,7 @@ _gsskrb5_init_sec_context ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_context ( OM_uint32 * /*minor_status*/, - const gss_ctx_id_t /*context_handle*/, + gss_const_ctx_id_t /*context_handle*/, gss_name_t * /*src_name*/, gss_name_t * /*targ_name*/, OM_uint32 * /*lifetime_rec*/, @@ -546,7 +577,7 @@ _gsskrb5_inquire_context ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred ( OM_uint32 * /*minor_status*/, - const gss_cred_id_t /*cred_handle*/, + gss_const_cred_id_t /*cred_handle*/, gss_name_t * /*output_name*/, OM_uint32 * /*lifetime*/, gss_cred_usage_t * /*cred_usage*/, @@ -555,7 +586,7 @@ _gsskrb5_inquire_cred ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred_by_mech ( OM_uint32 * /*minor_status*/, - const gss_cred_id_t /*cred_handle*/, + gss_const_cred_id_t /*cred_handle*/, const gss_OID /*mech_type*/, gss_name_t * /*name*/, OM_uint32 * /*initiator_lifetime*/, @@ -565,14 +596,14 @@ _gsskrb5_inquire_cred_by_mech ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred_by_oid ( OM_uint32 * /*minor_status*/, - const gss_cred_id_t /*cred_handle*/, + gss_const_cred_id_t /*cred_handle*/, const gss_OID /*desired_object*/, gss_buffer_set_t */*data_set*/); OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_mechs_for_name ( OM_uint32 * /*minor_status*/, - const gss_name_t /*input_name*/, + gss_const_name_t /*input_name*/, gss_OID_set * mech_types ); OM_uint32 GSSAPI_CALLCONV @@ -584,7 +615,7 @@ _gsskrb5_inquire_names_for_mech ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_sec_context_by_oid ( OM_uint32 */*minor_status*/, - const gss_ctx_id_t /*context_handle*/, + gss_const_ctx_id_t /*context_handle*/, const gss_OID /*desired_object*/, gss_buffer_set_t */*data_set*/); @@ -606,9 +637,16 @@ OM_uint32 _gsskrb5_lifetime_left ( OM_uint32 */*minor_status*/, krb5_context /*context*/, - OM_uint32 /*lifetime*/, + OM_uint32 /*endtime*/, OM_uint32 */*lifetime_rec*/); +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_localname ( + OM_uint32 */*minor_status*/, + gss_const_name_t /*pname*/, + const gss_OID /*mech_type*/, + gss_buffer_t /*localname*/); + void * _gsskrb5_make_header ( void */*ptr*/, @@ -617,16 +655,9 @@ _gsskrb5_make_header ( const gss_OID /*mech*/); OM_uint32 GSSAPI_CALLCONV -_gsskrb5_pname_to_uid ( - OM_uint32 */*minor_status*/, - const gss_name_t /*pname*/, - const gss_OID /*mech_type*/, - uid_t */*uidp*/); - -OM_uint32 GSSAPI_CALLCONV _gsskrb5_process_context_token ( OM_uint32 */*minor_status*/, - const gss_ctx_id_t /*context_handle*/, + gss_const_ctx_id_t /*context_handle*/, const gss_buffer_t token_buffer ); OM_uint32 GSSAPI_CALLCONV @@ -692,7 +723,7 @@ _gsskrb5_store_cred ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap ( OM_uint32 * /*minor_status*/, - const gss_ctx_id_t /*context_handle*/, + gss_const_ctx_id_t /*context_handle*/, const gss_buffer_t /*input_message_buffer*/, gss_buffer_t /*output_message_buffer*/, int * /*conf_state*/, @@ -716,7 +747,7 @@ _gsskrb5_verify_header ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_verify_mic ( OM_uint32 * /*minor_status*/, - const gss_ctx_id_t /*context_handle*/, + gss_const_ctx_id_t /*context_handle*/, const gss_buffer_t /*message_buffer*/, const gss_buffer_t /*token_buffer*/, gss_qop_t * qop_state ); @@ -734,7 +765,7 @@ _gsskrb5_verify_mic_internal ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_wrap ( OM_uint32 * /*minor_status*/, - const gss_ctx_id_t /*context_handle*/, + gss_const_ctx_id_t /*context_handle*/, int /*conf_req_flag*/, gss_qop_t /*qop_req*/, const gss_buffer_t /*input_message_buffer*/, @@ -744,7 +775,7 @@ _gsskrb5_wrap ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_wrap_size_limit ( OM_uint32 * /*minor_status*/, - const gss_ctx_id_t /*context_handle*/, + gss_const_ctx_id_t /*context_handle*/, int /*conf_req_flag*/, gss_qop_t /*qop_req*/, OM_uint32 /*req_output_size*/, diff --git a/lib/gssapi/krb5/gsskrb5_locl.h b/lib/gssapi/krb5/gsskrb5_locl.h index 6b9b03f34908..4119730576fc 100644 --- a/lib/gssapi/krb5/gsskrb5_locl.h +++ b/lib/gssapi/krb5/gsskrb5_locl.h @@ -81,7 +81,7 @@ typedef struct gsskrb5_ctx { krb5_creds *kcred; krb5_ccache ccache; struct krb5_ticket *ticket; - OM_uint32 lifetime; + time_t endtime; HEIMDAL_MUTEX ctx_id_mutex; struct gss_msg_order *order; krb5_keyblock *service_keyblock; @@ -95,7 +95,7 @@ typedef struct { #define GSS_CF_DESTROY_CRED_ON_RELEASE 1 #define GSS_CF_NO_CI_FLAGS 2 struct krb5_keytab_data *keytab; - OM_uint32 lifetime; + time_t endtime; gss_cred_usage_t usage; gss_OID_set mechanisms; struct krb5_ccache_data *ccache; @@ -134,7 +134,4 @@ extern HEIMDAL_MUTEX gssapi_keytab_mutex; #define SC_LOCAL_SUBKEY 0x08 #define SC_REMOTE_SUBKEY 0x10 -/* type to signal that that dns canon maybe should be done */ -#define MAGIC_HOSTBASED_NAME_TYPE 4711 - #endif diff --git a/lib/gssapi/krb5/import_name.c b/lib/gssapi/krb5/import_name.c index 5fe512672f95..6a362640b6fe 100644 --- a/lib/gssapi/krb5/import_name.c +++ b/lib/gssapi/krb5/import_name.c @@ -83,26 +83,21 @@ import_krb5_name (OM_uint32 *minor_status, OM_uint32 _gsskrb5_canon_name(OM_uint32 *minor_status, krb5_context context, - int use_dns, krb5_const_principal sourcename, gss_name_t targetname, - krb5_principal *out) + gss_const_name_t targetname, krb5_principal *out) { - krb5_principal p = (krb5_principal)targetname; + krb5_const_principal p = (krb5_const_principal)targetname; krb5_error_code ret; char *hostname = NULL, *service; + int type; + const char *comp; *minor_status = 0; /* If its not a hostname */ - if (krb5_principal_get_type(context, p) != MAGIC_HOSTBASED_NAME_TYPE) { - ret = krb5_copy_principal(context, p, out); - } else if (!use_dns) { - ret = krb5_copy_principal(context, p, out); - if (ret) - goto out; - krb5_principal_set_type(context, *out, KRB5_NT_SRV_HST); - if (sourcename) - ret = krb5_principal_set_realm(context, *out, sourcename->realm); - } else { + type = krb5_principal_get_type(context, p); + comp = krb5_principal_get_comp_string(context, p, 0); + if (type == KRB5_NT_SRV_HST || type == KRB5_NT_SRV_HST_NEEDS_CANON || + (type == KRB5_NT_UNKNOWN && comp != NULL && strcmp(comp, "host") == 0)) { if (p->name.name_string.len == 0) return GSS_S_BAD_NAME; else if (p->name.name_string.len > 1) @@ -115,9 +110,10 @@ _gsskrb5_canon_name(OM_uint32 *minor_status, krb5_context context, service, KRB5_NT_SRV_HST, out); + } else { + ret = krb5_copy_principal(context, p, out); } - out: if (ret) { *minor_status = ret; return GSS_S_FAILURE; @@ -128,10 +124,10 @@ _gsskrb5_canon_name(OM_uint32 *minor_status, krb5_context context, static OM_uint32 -import_hostbased_name (OM_uint32 *minor_status, - krb5_context context, - const gss_buffer_t input_name_buffer, - gss_name_t *output_name) +import_hostbased_name(OM_uint32 *minor_status, + krb5_context context, + const gss_buffer_t input_name_buffer, + gss_name_t *output_name) { krb5_principal princ = NULL; krb5_error_code kerr; @@ -153,7 +149,7 @@ import_hostbased_name (OM_uint32 *minor_status, host = p + 1; } - kerr = krb5_make_principal(context, &princ, NULL, tmp, host, NULL); + kerr = krb5_make_principal(context, &princ, "", tmp, host, NULL); free (tmp); *minor_status = kerr; if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) @@ -161,7 +157,7 @@ import_hostbased_name (OM_uint32 *minor_status, else if (kerr) return GSS_S_FAILURE; - krb5_principal_set_type(context, princ, MAGIC_HOSTBASED_NAME_TYPE); + krb5_principal_set_type(context, princ, KRB5_NT_SRV_HST); *output_name = (gss_name_t)princ; return 0; diff --git a/lib/gssapi/krb5/import_sec_context.c b/lib/gssapi/krb5/import_sec_context.c index 3bab1802b3c9..e34e07115a5f 100644 --- a/lib/gssapi/krb5/import_sec_context.c +++ b/lib/gssapi/krb5/import_sec_context.c @@ -192,9 +192,13 @@ _gsskrb5_import_sec_context ( if (krb5_ret_int32 (sp, &tmp)) goto failure; ctx->more_flags = tmp; + /* + * XXX endtime should be a 64-bit int, but we don't have + * krb5_ret_int64() yet. + */ if (krb5_ret_int32 (sp, &tmp)) goto failure; - ctx->lifetime = tmp; + ctx->endtime = tmp; ret = _gssapi_msg_order_import(minor_status, sp, &ctx->order); if (ret) diff --git a/lib/gssapi/krb5/init_sec_context.c b/lib/gssapi/krb5/init_sec_context.c index 5f8b01b72707..4ef5c9c7123a 100644 --- a/lib/gssapi/krb5/init_sec_context.c +++ b/lib/gssapi/krb5/init_sec_context.c @@ -128,7 +128,7 @@ _gsskrb5_create_ctx( ctx->service_keyblock = NULL; ctx->ticket = NULL; krb5_data_zero(&ctx->fwd_data); - ctx->lifetime = GSS_C_INDEFINITE; + ctx->endtime = 0; ctx->order = NULL; ctx->crypto = NULL; HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); @@ -137,6 +137,7 @@ _gsskrb5_create_ctx( if (kret) { *minor_status = kret; HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + free(ctx); return GSS_S_FAILURE; } @@ -145,6 +146,7 @@ _gsskrb5_create_ctx( *minor_status = kret; krb5_auth_con_free(context, ctx->auth_context); HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + free(ctx); return GSS_S_FAILURE; } @@ -156,7 +158,7 @@ _gsskrb5_create_ctx( krb5_auth_con_free(context, ctx->deleg_auth_context); HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); - + free(ctx); return GSS_S_BAD_BINDINGS; } @@ -168,7 +170,7 @@ _gsskrb5_create_ctx( krb5_auth_con_free(context, ctx->deleg_auth_context); HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); - + free(ctx); return GSS_S_BAD_BINDINGS; } @@ -204,8 +206,7 @@ gsskrb5_get_creds( krb5_context context, krb5_ccache ccache, gsskrb5_ctx ctx, - const gss_name_t target_name, - int use_dns, + gss_const_name_t target_name, OM_uint32 time_req, OM_uint32 * time_rec) { @@ -223,8 +224,8 @@ gsskrb5_get_creds( ctx->kcred = NULL; } - ret = _gsskrb5_canon_name(minor_status, context, use_dns, - ctx->source, target_name, &ctx->target); + ret = _gsskrb5_canon_name(minor_status, context, target_name, + &ctx->target); if (ret) return ret; @@ -253,10 +254,10 @@ gsskrb5_get_creds( return GSS_S_FAILURE; } - ctx->lifetime = ctx->kcred->times.endtime; + ctx->endtime = ctx->kcred->times.endtime; ret = _gsskrb5_lifetime_left(minor_status, context, - ctx->lifetime, &lifetime_rec); + ctx->endtime, &lifetime_rec); if (ret) return ret; if (lifetime_rec == 0) { @@ -344,8 +345,7 @@ do_delegation (krb5_context context, fwd_flags.forwarded = 1; fwd_flags.forwardable = 1; - if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/ - name->name.name_string.len < 2) + if (name->name.name_string.len < 2) goto out; kret = krb5_get_forwarded_creds(context, @@ -378,7 +378,7 @@ init_auth gsskrb5_cred cred, gsskrb5_ctx ctx, krb5_context context, - gss_name_t name, + gss_const_name_t name, const gss_OID mech_type, OM_uint32 req_flags, OM_uint32 time_req, @@ -391,12 +391,9 @@ init_auth { OM_uint32 ret = GSS_S_FAILURE; krb5_error_code kret; - krb5_data outbuf; krb5_data fwd_data; OM_uint32 lifetime_rec; - int allow_dns = 1; - krb5_data_zero(&outbuf); krb5_data_zero(&fwd_data); *minor_status = 0; @@ -425,44 +422,17 @@ init_auth /* * This is hideous glue for (NFS) clients that wants to limit the * available enctypes to what it can support (encryption in - * kernel). If there is no enctypes selected for this credential, - * reset it to the default set of enctypes. + * kernel). */ - { - krb5_enctype *enctypes = NULL; + if (cred && cred->enctypes) + krb5_set_default_in_tkt_etypes(context, cred->enctypes); - if (cred && cred->enctypes) - enctypes = cred->enctypes; - krb5_set_default_in_tkt_etypes(context, enctypes); - } - - /* canon name if needed for client + target realm */ - kret = krb5_cc_get_config(context, ctx->ccache, NULL, - "realm-config", &outbuf); - if (kret == 0) { - /* XXX 2 is no server canon */ - if (outbuf.length < 1 || ((((unsigned char *)outbuf.data)[0]) & 2)) - allow_dns = 0; - krb5_data_free(&outbuf); - } - - /* - * First we try w/o dns, hope that the KDC have register alias - * (and referrals if cross realm) for this principal. If that - * fails and if we are allowed to using this realm try again with - * DNS canonicalizion. - */ ret = gsskrb5_get_creds(minor_status, context, ctx->ccache, - ctx, name, 0, time_req, - time_rec); - if (ret && allow_dns) - ret = gsskrb5_get_creds(minor_status, context, ctx->ccache, - ctx, name, 1, time_req, - time_rec); + ctx, name, time_req, time_rec); if (ret) goto failure; - ctx->lifetime = ctx->kcred->times.endtime; + ctx->endtime = ctx->kcred->times.endtime; ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); if (ret) @@ -470,7 +440,7 @@ init_auth ret = _gsskrb5_lifetime_left(minor_status, context, - ctx->lifetime, + ctx->endtime, &lifetime_rec); if (ret) goto failure; @@ -817,14 +787,11 @@ repl_mutual repl); *minor_status = 0; - if (time_rec) { - ret = _gsskrb5_lifetime_left(minor_status, - context, - ctx->lifetime, - time_rec); - } else { - ret = GSS_S_COMPLETE; - } + if (time_rec) + _gsskrb5_lifetime_left(minor_status, + context, + ctx->endtime, + time_rec); if (ret_flags) *ret_flags = ctx->flags; @@ -865,9 +832,9 @@ repl_mutual OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context (OM_uint32 * minor_status, - const gss_cred_id_t cred_handle, + gss_const_cred_id_t cred_handle, gss_ctx_id_t * context_handle, - const gss_name_t target_name, + gss_const_name_t target_name, const gss_OID mech_type, OM_uint32 req_flags, OM_uint32 time_req, diff --git a/lib/gssapi/krb5/inquire_context.c b/lib/gssapi/krb5/inquire_context.c index ade8ec4b9cb6..e225c33ba2be 100644 --- a/lib/gssapi/krb5/inquire_context.c +++ b/lib/gssapi/krb5/inquire_context.c @@ -35,7 +35,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_context ( OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, + gss_const_ctx_id_t context_handle, gss_name_t * src_name, gss_name_t * targ_name, OM_uint32 * lifetime_rec, @@ -76,7 +76,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_context ( if (lifetime_rec) { ret = _gsskrb5_lifetime_left(minor_status, context, - ctx->lifetime, + ctx->endtime, lifetime_rec); if (ret) goto failed; diff --git a/lib/gssapi/krb5/inquire_cred.c b/lib/gssapi/krb5/inquire_cred.c index f88199692cd7..1770fec76eab 100644 --- a/lib/gssapi/krb5/inquire_cred.c +++ b/lib/gssapi/krb5/inquire_cred.c @@ -35,7 +35,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred (OM_uint32 * minor_status, - const gss_cred_id_t cred_handle, + gss_const_cred_id_t cred_handle, gss_name_t * output_name, OM_uint32 * lifetime, gss_cred_usage_t * cred_usage, @@ -45,136 +45,179 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred krb5_context context; gss_cred_id_t aqcred_init = GSS_C_NO_CREDENTIAL; gss_cred_id_t aqcred_accept = GSS_C_NO_CREDENTIAL; - gsskrb5_cred acred = NULL, icred = NULL; + gsskrb5_cred cred = (gsskrb5_cred)cred_handle; + gss_OID_set amechs = GSS_C_NO_OID_SET; + gss_OID_set imechs = GSS_C_NO_OID_SET; + OM_uint32 junk; + OM_uint32 aminor; OM_uint32 ret; + OM_uint32 aret; + OM_uint32 alife = GSS_C_INDEFINITE; + OM_uint32 ilife = GSS_C_INDEFINITE; + + /* + * XXX This function is more complex than it has to be. It should call + * _gsskrb5_inquire_cred_by_mech() twice and merge the results in the + * cred_handle == GSS_C_NO_CREDENTIAL case, but since + * _gsskrb5_inquire_cred_by_mech() is implemented in terms of this + * function, first we must fix _gsskrb5_inquire_cred_by_mech(). + */ *minor_status = 0; if (output_name) - *output_name = NULL; + *output_name = GSS_C_NO_NAME; + if (cred_usage) + *cred_usage = GSS_C_BOTH; /* There's no NONE */ if (mechanisms) - *mechanisms = GSS_C_NO_OID_SET; + *mechanisms = GSS_C_NO_OID_SET; GSSAPI_KRB5_INIT (&context); if (cred_handle == GSS_C_NO_CREDENTIAL) { - ret = _gsskrb5_acquire_cred(minor_status, - GSS_C_NO_NAME, - GSS_C_INDEFINITE, - GSS_C_NO_OID_SET, - GSS_C_ACCEPT, - &aqcred_accept, - NULL, - NULL); - if (ret == GSS_S_COMPLETE) - acred = (gsskrb5_cred)aqcred_accept; - - ret = _gsskrb5_acquire_cred(minor_status, - GSS_C_NO_NAME, - GSS_C_INDEFINITE, - GSS_C_NO_OID_SET, - GSS_C_INITIATE, - &aqcred_init, - NULL, - NULL); - if (ret == GSS_S_COMPLETE) - icred = (gsskrb5_cred)aqcred_init; - - if (icred == NULL && acred == NULL) { - *minor_status = 0; - return GSS_S_NO_CRED; - } - } else - acred = (gsskrb5_cred)cred_handle; + /* + * From here to the end of this if we should refactor into a separate + * function. + */ + /* Get the info for the default ACCEPT credential */ + aret = _gsskrb5_acquire_cred(&aminor, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_ACCEPT, + &aqcred_accept, + NULL, + NULL); + if (aret == GSS_S_COMPLETE) { + aret = _gsskrb5_inquire_cred(&aminor, + aqcred_accept, + output_name, + &alife, + NULL, + &amechs); + (void) _gsskrb5_release_cred(&junk, &aqcred_accept); + if (aret == GSS_S_COMPLETE) { + output_name = NULL; /* Can't merge names; output only one */ + if (cred_usage) + *cred_usage = GSS_C_ACCEPT; + if (lifetime) + *lifetime = alife; + if (mechanisms) { + *mechanisms = amechs; + amechs = GSS_C_NO_OID_SET; + } + (void) gss_release_oid_set(&junk, &amechs); + } else if (aret != GSS_S_NO_CRED) { + *minor_status = aminor; + return aret; + } else { + alife = GSS_C_INDEFINITE; + } + } + + /* Get the info for the default INITIATE credential */ + ret = _gsskrb5_acquire_cred(minor_status, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_INITIATE, + &aqcred_init, + NULL, + NULL); + if (ret == GSS_S_COMPLETE) { + ret = _gsskrb5_inquire_cred(minor_status, + aqcred_init, + output_name, + &ilife, + NULL, + &imechs); + (void) _gsskrb5_release_cred(&junk, &aqcred_init); + if (ret == GSS_S_COMPLETE) { + /* + * Merge results for INITIATE with ACCEPT if we had ACCEPT and + * for those outputs that are desired. + */ + if (cred_usage) { + *cred_usage = (*cred_usage == GSS_C_ACCEPT) ? + GSS_C_BOTH : GSS_C_INITIATE; + } + if (lifetime) + *lifetime = min(alife, ilife); + if (mechanisms) { + /* + * This is just one mechanism (IAKERB and such would live + * elsewhere). imechs will be equal to amechs, though not + * ==. + */ + if (aret != GSS_S_COMPLETE) { + *mechanisms = imechs; + imechs = GSS_C_NO_OID_SET; + } + } + (void) gss_release_oid_set(&junk, &amechs); + } else if (ret != GSS_S_NO_CRED) { + *minor_status = aminor; + return aret; + } + } + + if (aret != GSS_S_COMPLETE && ret != GSS_S_COMPLETE) { + *minor_status = aminor; + return aret; + } + *minor_status = 0; /* Even though 0 is not specified to be special */ + return GSS_S_COMPLETE; + } - if (acred) - HEIMDAL_MUTEX_lock(&acred->cred_id_mutex); - if (icred) - HEIMDAL_MUTEX_lock(&icred->cred_id_mutex); + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); if (output_name != NULL) { - if (icred && icred->principal != NULL) { - gss_name_t name; - - if (acred && acred->principal) - name = (gss_name_t)acred->principal; - else - name = (gss_name_t)icred->principal; - + if (cred->principal != NULL) { + gss_name_t name = (gss_name_t)cred->principal; ret = _gsskrb5_duplicate_name(minor_status, name, output_name); if (ret) - goto out; - } else if (acred && acred->usage == GSS_C_ACCEPT) { - krb5_principal princ; - *minor_status = krb5_sname_to_principal(context, NULL, - NULL, KRB5_NT_SRV_HST, - &princ); - if (*minor_status) { - ret = GSS_S_FAILURE; - goto out; - } - *output_name = (gss_name_t)princ; - } else { - krb5_principal princ; - *minor_status = krb5_get_default_principal(context, - &princ); - if (*minor_status) { - ret = GSS_S_FAILURE; - goto out; - } - *output_name = (gss_name_t)princ; - } + goto out; + } else if (cred->usage == GSS_C_ACCEPT) { + /* + * Keytab case, princ may not be set (yet, ever, whatever). + * + * We used to unconditionally output the krb5_sname_to_principal() + * of the host service for the hostname, but we didn't know if we + * had keytab entries for it, so it was incorrect. We can't be + * breaking anything in tree by outputting GSS_C_NO_NAME, but we + * might be breaking other callers. + */ + *output_name = GSS_C_NO_NAME; + } else { + /* This shouldn't happen */ + *minor_status = KRB5_NOCREDS_SUPPLIED; /* XXX */ + ret = GSS_S_NO_CRED; + goto out; + } } if (lifetime != NULL) { - OM_uint32 alife = GSS_C_INDEFINITE, ilife = GSS_C_INDEFINITE; - - if (acred) alife = acred->lifetime; - if (icred) ilife = icred->lifetime; - - ret = _gsskrb5_lifetime_left(minor_status, - context, - min(alife,ilife), - lifetime); - if (ret) - goto out; - } - if (cred_usage != NULL) { - if (acred && icred) - *cred_usage = GSS_C_BOTH; - else if (acred) - *cred_usage = GSS_C_ACCEPT; - else if (icred) - *cred_usage = GSS_C_INITIATE; - else - abort(); + ret = _gsskrb5_lifetime_left(minor_status, + context, + cred->endtime, + lifetime); + if (ret) + goto out; } - + if (cred_usage != NULL) + *cred_usage = cred->usage; if (mechanisms != NULL) { ret = gss_create_empty_oid_set(minor_status, mechanisms); if (ret) - goto out; - if (acred) - ret = gss_add_oid_set_member(minor_status, - &acred->mechanisms->elements[0], - mechanisms); - if (ret == GSS_S_COMPLETE && icred) - ret = gss_add_oid_set_member(minor_status, - &icred->mechanisms->elements[0], - mechanisms); + goto out; + ret = gss_add_oid_set_member(minor_status, + &cred->mechanisms->elements[0], + mechanisms); if (ret) - goto out; + goto out; } ret = GSS_S_COMPLETE; -out: - if (acred) - HEIMDAL_MUTEX_unlock(&acred->cred_id_mutex); - if (icred) - HEIMDAL_MUTEX_unlock(&icred->cred_id_mutex); - - if (aqcred_init != GSS_C_NO_CREDENTIAL) - ret = _gsskrb5_release_cred(minor_status, &aqcred_init); - if (aqcred_accept != GSS_C_NO_CREDENTIAL) - ret = _gsskrb5_release_cred(minor_status, &aqcred_accept); +out: + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); return ret; } diff --git a/lib/gssapi/krb5/inquire_cred_by_mech.c b/lib/gssapi/krb5/inquire_cred_by_mech.c index 7bd9c11c6056..6ce4994ebe08 100644 --- a/lib/gssapi/krb5/inquire_cred_by_mech.c +++ b/lib/gssapi/krb5/inquire_cred_by_mech.c @@ -35,7 +35,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred_by_mech ( OM_uint32 * minor_status, - const gss_cred_id_t cred_handle, + gss_const_cred_id_t cred_handle, const gss_OID mech_type, gss_name_t * name, OM_uint32 * initiator_lifetime, @@ -47,6 +47,10 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred_by_mech ( OM_uint32 maj_stat; OM_uint32 lifetime; + /* + * XXX This is busted. _gsskrb5_inquire_cred() should be implemented in + * terms of _gsskrb5_inquire_cred_by_mech(), NOT the other way around. + */ maj_stat = _gsskrb5_inquire_cred (minor_status, cred_handle, name, &lifetime, &usage, NULL); diff --git a/lib/gssapi/krb5/inquire_cred_by_oid.c b/lib/gssapi/krb5/inquire_cred_by_oid.c index d560ed4ba1c6..7dae3d25c4ff 100644 --- a/lib/gssapi/krb5/inquire_cred_by_oid.c +++ b/lib/gssapi/krb5/inquire_cred_by_oid.c @@ -34,7 +34,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred_by_oid (OM_uint32 * minor_status, - const gss_cred_id_t cred_handle, + gss_const_cred_id_t cred_handle, const gss_OID desired_object, gss_buffer_set_t *data_set) { diff --git a/lib/gssapi/krb5/inquire_mechs_for_name.c b/lib/gssapi/krb5/inquire_mechs_for_name.c index 6197a81b40a7..c6c67464fc55 100644 --- a/lib/gssapi/krb5/inquire_mechs_for_name.c +++ b/lib/gssapi/krb5/inquire_mechs_for_name.c @@ -35,7 +35,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_mechs_for_name ( OM_uint32 * minor_status, - const gss_name_t input_name, + gss_const_name_t input_name, gss_OID_set * mech_types ) { diff --git a/lib/gssapi/krb5/inquire_sec_context_by_oid.c b/lib/gssapi/krb5/inquire_sec_context_by_oid.c index b57217a4e830..f1ed99320975 100644 --- a/lib/gssapi/krb5/inquire_sec_context_by_oid.c +++ b/lib/gssapi/krb5/inquire_sec_context_by_oid.c @@ -149,7 +149,6 @@ static OM_uint32 inquire_sec_context_get_subkey } ret = krb5_store_keyblock(sp, *key); - krb5_free_keyblock (context, key); if (ret) goto out; @@ -169,6 +168,7 @@ static OM_uint32 inquire_sec_context_get_subkey } out: + krb5_free_keyblock(context, key); krb5_data_free(&data); if (sp) krb5_storage_free(sp); @@ -333,7 +333,8 @@ export_lucid_sec_context_v1(OM_uint32 *minor_status, if (ret) goto out; ret = krb5_store_int32(sp, (context_handle->more_flags & LOCAL) ? 1 : 0); if (ret) goto out; - ret = krb5_store_int32(sp, context_handle->lifetime); + /* XXX need krb5_store_int64() */ + ret = krb5_store_int32(sp, context_handle->endtime); if (ret) goto out; krb5_auth_con_getlocalseqnumber (context, context_handle->auth_context, @@ -529,7 +530,7 @@ out: OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_sec_context_by_oid (OM_uint32 *minor_status, - const gss_ctx_id_t context_handle, + gss_const_ctx_id_t context_handle, const gss_OID desired_object, gss_buffer_set_t *data_set) { diff --git a/lib/gssapi/krb5/pname_to_uid.c b/lib/gssapi/krb5/pname_to_uid.c index ff754e779813..dca74645de6d 100644 --- a/lib/gssapi/krb5/pname_to_uid.c +++ b/lib/gssapi/krb5/pname_to_uid.c @@ -33,53 +33,38 @@ #include "gsskrb5_locl.h" OM_uint32 GSSAPI_CALLCONV -_gsskrb5_pname_to_uid(OM_uint32 *minor_status, - const gss_name_t pname, - const gss_OID mech_type, - uid_t *uidp) +_gsskrb5_localname(OM_uint32 *minor_status, + gss_const_name_t pname, + const gss_OID mech_type, + gss_buffer_t localname) { -#ifdef NO_LOCALNAME - *minor_status = KRB5_NO_LOCALNAME; - return GSS_S_FAILURE; -#else krb5_error_code ret; krb5_context context; krb5_const_principal princ = (krb5_const_principal)pname; - char localname[256]; -#ifdef POSIX_GETPWNAM_R - char pwbuf[2048]; - struct passwd pw, *pwd; -#else - struct passwd *pwd; -#endif + char lnamebuf[256]; GSSAPI_KRB5_INIT(&context); *minor_status = 0; ret = krb5_aname_to_localname(context, princ, - sizeof(localname), localname); + sizeof(lnamebuf), lnamebuf); if (ret != 0) { *minor_status = ret; return GSS_S_FAILURE; } -#ifdef POSIX_GETPWNAM_R - if (getpwnam_r(localname, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0) { - *minor_status = KRB5_NO_LOCALNAME; - return GSS_S_FAILURE; - } -#else - pwd = getpwnam(localname); -#endif + localname->length = strlen(lnamebuf); - if (pwd == NULL) { - *minor_status = KRB5_NO_LOCALNAME; + localname->value = malloc(localname->length + 1); + if (localname->value == NULL) { + localname->length = 0; + *minor_status = ENOMEM; return GSS_S_FAILURE; } - *uidp = pwd->pw_uid; + memcpy(localname->value, lnamebuf, localname->length + 1); + *minor_status = 0; return GSS_S_COMPLETE; -#endif /* NO_LOCALNAME */ } diff --git a/lib/gssapi/krb5/prf.c b/lib/gssapi/krb5/prf.c index 162a3097099f..671ab2c6d982 100644 --- a/lib/gssapi/krb5/prf.c +++ b/lib/gssapi/krb5/prf.c @@ -119,7 +119,7 @@ _gsskrb5_pseudo_random(OM_uint32 *minor_status, while(dol > 0) { size_t tsize; - _gsskrb5_encode_om_uint32(num, input.data); + _gsskrb5_encode_be_om_uint32(num, input.data); ret = krb5_crypto_prf(context, crypto, &input, &output); if (ret) { @@ -133,7 +133,7 @@ _gsskrb5_pseudo_random(OM_uint32 *minor_status, tsize = min(dol, output.length); memcpy(p, output.data, tsize); - p += output.length; + p += tsize; dol -= tsize; krb5_data_free(&output); num++; diff --git a/lib/gssapi/krb5/process_context_token.c b/lib/gssapi/krb5/process_context_token.c index 0cc1c07cfbe9..601b0e8a5a8a 100644 --- a/lib/gssapi/krb5/process_context_token.c +++ b/lib/gssapi/krb5/process_context_token.c @@ -35,7 +35,7 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_process_context_token ( OM_uint32 *minor_status, - const gss_ctx_id_t context_handle, + gss_const_ctx_id_t context_handle, const gss_buffer_t token_buffer ) { diff --git a/lib/gssapi/krb5/set_sec_context_option.c b/lib/gssapi/krb5/set_sec_context_option.c index 141ff722fb64..a0e6fd02c59a 100644 --- a/lib/gssapi/krb5/set_sec_context_option.c +++ b/lib/gssapi/krb5/set_sec_context_option.c @@ -178,23 +178,9 @@ _gsskrb5_set_sec_context_option } else if (gss_oid_equal(desired_object, GSS_KRB5_SEND_TO_KDC_X)) { - if (value == NULL || value->length == 0) { - krb5_set_send_to_kdc_func(context, NULL, NULL); - } else { - struct gsskrb5_send_to_kdc c; - - if (value->length != sizeof(c)) { - *minor_status = EINVAL; - return GSS_S_FAILURE; - } - memcpy(&c, value->value, sizeof(c)); - krb5_set_send_to_kdc_func(context, - (krb5_send_to_kdc_func)c.func, - c.ptr); - } + *minor_status = EINVAL; + return GSS_S_FAILURE; - *minor_status = 0; - return GSS_S_COMPLETE; } else if (gss_oid_equal(desired_object, GSS_KRB5_CCACHE_NAME_X)) { char *str; diff --git a/lib/gssapi/krb5/store_cred.c b/lib/gssapi/krb5/store_cred.c index a3aa2fb83e71..40b75771dd17 100644 --- a/lib/gssapi/krb5/store_cred.c +++ b/lib/gssapi/krb5/store_cred.c @@ -46,8 +46,11 @@ _gsskrb5_store_cred(OM_uint32 *minor_status, krb5_context context; krb5_error_code ret; gsskrb5_cred cred; - krb5_ccache id; - int destroy = 0; + krb5_ccache id = NULL; + krb5_ccache def_ccache = NULL; + const char *def_type = NULL; + time_t exp_current; + time_t exp_new; *minor_status = 0; @@ -56,7 +59,8 @@ _gsskrb5_store_cred(OM_uint32 *minor_status, return GSS_S_FAILURE; } - if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) + if (desired_mech != GSS_C_NO_OID && + gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) return GSS_S_BAD_MECH; cred = (gsskrb5_cred)input_cred_handle; @@ -69,48 +73,87 @@ _gsskrb5_store_cred(OM_uint32 *minor_status, if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = GSS_KRB5_S_G_BAD_USAGE; - return(GSS_S_FAILURE); + return GSS_S_FAILURE; + } + + ret = krb5_cc_get_lifetime(context, cred->ccache, &exp_new); + if (ret) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = ret; + return GSS_S_NO_CRED; } if (cred->principal == NULL) { HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = GSS_KRB5_S_KG_TGT_MISSING; - return(GSS_S_FAILURE); + return GSS_S_FAILURE; } - /* write out cred to credential cache */ + ret = krb5_cc_default(context, &def_ccache); + if (ret == 0) { + def_type = krb5_cc_get_type(context, def_ccache); + krb5_cc_close(context, def_ccache); + } + def_ccache = NULL; + /* write out cred to credential cache */ ret = krb5_cc_cache_match(context, cred->principal, &id); if (ret) { - ret = krb5_cc_new_unique(context, NULL, NULL, &id); - if (ret) { - HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); - *minor_status = ret; - return(GSS_S_FAILURE); - } - destroy = 1; + if (default_cred) { + ret = krb5_cc_default(context, &id); + if (ret) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = ret; + return GSS_S_FAILURE; + } + } else { + if (def_type == NULL || + !krb5_cc_support_switch(context, def_type)) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = 0; /* XXX */ + return GSS_S_NO_CRED; /* XXX */ + } + ret = krb5_cc_new_unique(context, def_type, NULL, &id); + if (ret) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = ret; + return GSS_S_FAILURE; + } + overwrite_cred = 1; + } + } + + if (!overwrite_cred) { + /* If current creds are expired or near it, overwrite */ + ret = krb5_cc_get_lifetime(context, id, &exp_current); + if (ret != 0 || exp_new > exp_current) + overwrite_cred = 1; + } + + if (!overwrite_cred) { + /* Nothing to do */ + krb5_cc_close(context, id); + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = 0; + return GSS_S_DUPLICATE_ELEMENT; } ret = krb5_cc_initialize(context, id, cred->principal); if (ret == 0) ret = krb5_cc_copy_match_f(context, cred->ccache, id, NULL, NULL, NULL); if (ret) { - if (destroy) - krb5_cc_destroy(context, id); - else - krb5_cc_close(context, id); + krb5_cc_close(context, id); HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); *minor_status = ret; return(GSS_S_FAILURE); } - if (default_cred) + if (default_cred && def_type != NULL && + krb5_cc_support_switch(context, def_type)) krb5_cc_switch(context, id); krb5_cc_close(context, id); - HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); - *minor_status = 0; return GSS_S_COMPLETE; } diff --git a/lib/gssapi/krb5/test_acquire_cred.c b/lib/gssapi/krb5/test_acquire_cred.c new file mode 100644 index 000000000000..9f7c9ef4e430 --- /dev/null +++ b/lib/gssapi/krb5/test_acquire_cred.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2003-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" +#include <err.h> + +static void +print_time(OM_uint32 time_rec) +{ + if (time_rec == GSS_C_INDEFINITE) { + printf("cred never expire\n"); + } else { + time_t t = time_rec + time(NULL); + printf("expiration time: %s", ctime(&t)); + } +} + +static void +test_add(gss_cred_id_t cred_handle) +{ + OM_uint32 major_status, minor_status; + gss_cred_id_t copy_cred; + OM_uint32 time_rec; + + major_status = gss_add_cred (&minor_status, + cred_handle, + GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, + GSS_C_INITIATE, + 0, + 0, + ©_cred, + NULL, + &time_rec, + NULL); + + if (GSS_ERROR(major_status)) + errx(1, "add_cred failed"); + + print_time(time_rec); + + major_status = gss_release_cred(&minor_status, + ©_cred); + if (GSS_ERROR(major_status)) + errx(1, "release_cred failed"); +} + +static void +copy_cred(void) +{ + OM_uint32 major_status, minor_status; + gss_cred_id_t cred_handle; + OM_uint32 time_rec; + + major_status = gss_acquire_cred(&minor_status, + GSS_C_NO_NAME, + 0, + NULL, + GSS_C_INITIATE, + &cred_handle, + NULL, + &time_rec); + if (GSS_ERROR(major_status)) + errx(1, "acquire_cred failed"); + + print_time(time_rec); + + test_add(cred_handle); + test_add(cred_handle); + test_add(cred_handle); + + major_status = gss_release_cred(&minor_status, + &cred_handle); + if (GSS_ERROR(major_status)) + errx(1, "release_cred failed"); +} + +static void +acquire_cred_service(const char *service) +{ + OM_uint32 major_status, minor_status; + gss_cred_id_t cred_handle; + OM_uint32 time_rec; + gss_buffer_desc name_buffer; + gss_name_t name; + + name_buffer.value = rk_UNCONST(service); + name_buffer.length = strlen(service); + + major_status = gss_import_name(&minor_status, + &name_buffer, + GSS_C_NT_HOSTBASED_SERVICE, + &name); + if (GSS_ERROR(major_status)) + errx(1, "import_name failed"); + + + major_status = gss_acquire_cred(&minor_status, + name, + 0, + NULL, + GSS_C_ACCEPT, + &cred_handle, + NULL, + &time_rec); + if (GSS_ERROR(major_status)) + errx(1, "acquire_cred failed"); + + print_time(time_rec); + + major_status = gss_release_cred(&minor_status, + &cred_handle); + if (GSS_ERROR(major_status)) + errx(1, "release_cred failed"); + + + major_status = gss_release_name(&minor_status, + &name); + if (GSS_ERROR(major_status)) + errx(1, "release_name failed"); + +} + +int +main(int argc, char **argv) +{ + copy_cred(); + + acquire_cred_service("host@xen2-heimdal-linux.lab.it.su.se"); + + return 0; +} diff --git a/lib/gssapi/krb5/test_cfx.c b/lib/gssapi/krb5/test_cfx.c index 0b196fcad24d..15f853c6b602 100644 --- a/lib/gssapi/krb5/test_cfx.c +++ b/lib/gssapi/krb5/test_cfx.c @@ -148,7 +148,7 @@ main(int argc, char **argv) errx(1, "krb5_context_init: %d", ret); ret = krb5_generate_random_keyblock(context, - ENCTYPE_AES256_CTS_HMAC_SHA1_96, + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, &keyblock); if (ret) krb5_err(context, 1, ret, "krb5_generate_random_keyblock"); diff --git a/lib/gssapi/krb5/test_cred.c b/lib/gssapi/krb5/test_cred.c new file mode 100644 index 000000000000..06dd6632d0be --- /dev/null +++ b/lib/gssapi/krb5/test_cred.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2003-2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" +#include <err.h> +#include <getarg.h> + +static void +gss_print_errors (int min_stat) +{ + OM_uint32 new_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + OM_uint32 ret; + + do { + ret = gss_display_status (&new_stat, + min_stat, + GSS_C_MECH_CODE, + GSS_C_NO_OID, + &msg_ctx, + &status_string); + fprintf (stderr, "%.*s\n", (int)status_string.length, + (char *)status_string.value); + gss_release_buffer (&new_stat, &status_string); + } while (!GSS_ERROR(ret) && msg_ctx != 0); +} + +static void +gss_err(int exitval, int status, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vwarnx (fmt, args); + gss_print_errors (status); + va_end(args); + exit (exitval); +} + +static void +acquire_release_loop(gss_name_t name, int counter, gss_cred_usage_t usage) +{ + OM_uint32 maj_stat, min_stat; + gss_cred_id_t cred; + int i; + + for (i = 0; i < counter; i++) { + maj_stat = gss_acquire_cred(&min_stat, name, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + usage, + &cred, + NULL, + NULL); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "aquire %d %d != GSS_S_COMPLETE", + i, (int)maj_stat); + + maj_stat = gss_release_cred(&min_stat, &cred); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release %d %d != GSS_S_COMPLETE", + i, (int)maj_stat); + } +} + + +static void +acquire_add_release_add(gss_name_t name, gss_cred_usage_t usage) +{ + OM_uint32 maj_stat, min_stat; + gss_cred_id_t cred, cred2, cred3; + + maj_stat = gss_acquire_cred(&min_stat, name, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + usage, + &cred, + NULL, + NULL); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "aquire %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_add_cred(&min_stat, + cred, + GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, + usage, + GSS_C_INDEFINITE, + GSS_C_INDEFINITE, + &cred2, + NULL, + NULL, + NULL); + + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "add_cred %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_release_cred(&min_stat, &cred); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_add_cred(&min_stat, + cred2, + GSS_C_NO_NAME, + GSS_KRB5_MECHANISM, + GSS_C_BOTH, + GSS_C_INDEFINITE, + GSS_C_INDEFINITE, + &cred3, + NULL, + NULL, + NULL); + + maj_stat = gss_release_cred(&min_stat, &cred2); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release 2 %d != GSS_S_COMPLETE", (int)maj_stat); + + maj_stat = gss_release_cred(&min_stat, &cred3); + if (maj_stat != GSS_S_COMPLETE) + gss_err(1, min_stat, "release 2 %d != GSS_S_COMPLETE", (int)maj_stat); +} + +static int version_flag = 0; +static int help_flag = 0; + +static struct getargs args[] = { + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, sizeof(args)/sizeof(*args), + NULL, "service@host"); + exit (ret); +} + + +int +main(int argc, char **argv) +{ + struct gss_buffer_desc_struct name_buffer; + OM_uint32 maj_stat, min_stat; + gss_name_t name; + int optidx = 0; + + setprogname(argv[0]); + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= optidx; + argv += optidx; + + if (argc < 1) + errx(1, "argc < 1"); + + name_buffer.value = argv[0]; + name_buffer.length = strlen(argv[0]); + + maj_stat = gss_import_name(&min_stat, &name_buffer, + GSS_C_NT_HOSTBASED_SERVICE, + &name); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "import name error"); + + acquire_release_loop(name, 100, GSS_C_ACCEPT); + acquire_release_loop(name, 100, GSS_C_INITIATE); + acquire_release_loop(name, 100, GSS_C_BOTH); + + acquire_add_release_add(name, GSS_C_ACCEPT); + acquire_add_release_add(name, GSS_C_INITIATE); + acquire_add_release_add(name, GSS_C_BOTH); + + gss_release_name(&min_stat, &name); + + return 0; +} diff --git a/lib/gssapi/krb5/test_kcred.c b/lib/gssapi/krb5/test_kcred.c new file mode 100644 index 000000000000..f53ce783bb07 --- /dev/null +++ b/lib/gssapi/krb5/test_kcred.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2003-2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" +#include <err.h> +#include <getarg.h> + +static int version_flag = 0; +static int help_flag = 0; + +static void +copy_import(void) +{ + gss_cred_id_t cred1, cred2; + OM_uint32 maj_stat, min_stat; + gss_name_t name1, name2; + OM_uint32 lifetime1, lifetime2; + gss_cred_usage_t usage1, usage2; + gss_OID_set mechs1, mechs2; + krb5_ccache id; + krb5_error_code ret; + krb5_context context; + int equal; + + maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_INITIATE, + &cred1, NULL, NULL); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_acquire_cred"); + + maj_stat = gss_inquire_cred(&min_stat, cred1, &name1, &lifetime1, + &usage1, &mechs1); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_inquire_cred"); + + ret = krb5_init_context(&context); + if (ret) + errx(1, "krb5_init_context"); + + ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_new_unique"); + + maj_stat = gss_krb5_copy_ccache(&min_stat, context, cred1, id); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_krb5_copy_ccache"); + + maj_stat = gss_krb5_import_cred(&min_stat, id, NULL, NULL, &cred2); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_krb5_import_cred"); + + maj_stat = gss_inquire_cred(&min_stat, cred2, &name2, &lifetime2, + &usage2, &mechs2); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_inquire_cred 2"); + + maj_stat = gss_compare_name(&min_stat, name1, name2, &equal); + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_compare_name"); + if (!equal) + errx(1, "names not equal"); + + if (lifetime1 != lifetime1) + errx(1, "lifetime not equal"); + + if (usage1 != usage1) + errx(1, "usage not equal"); + + gss_release_cred(&min_stat, &cred1); + gss_release_cred(&min_stat, &cred2); + + gss_release_name(&min_stat, &name1); + gss_release_name(&min_stat, &name2); + +#if 0 + compare(mechs1, mechs2); +#endif + + gss_release_oid_set(&min_stat, &mechs1); + gss_release_oid_set(&min_stat, &mechs2); + + krb5_cc_destroy(context, id); + krb5_free_context(context); +} + +static struct getargs args[] = { + {"version", 0, arg_flag, &version_flag, "print version", NULL }, + {"help", 0, arg_flag, &help_flag, NULL, NULL } +}; + +static void +usage (int ret) +{ + arg_printusage (args, sizeof(args)/sizeof(*args), + NULL, ""); + exit (ret); +} + +int +main(int argc, char **argv) +{ + int optidx = 0; + + setprogname(argv[0]); + if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) + usage(1); + + if (help_flag) + usage (0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + argc -= optidx; + argv += optidx; + + copy_import(); + + return 0; +} diff --git a/lib/gssapi/krb5/test_oid.c b/lib/gssapi/krb5/test_oid.c new file mode 100644 index 000000000000..00219b91e066 --- /dev/null +++ b/lib/gssapi/krb5/test_oid.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gsskrb5_locl.h" + +int +main(int argc, char **argv) +{ + OM_uint32 minor_status, maj_stat; + gss_buffer_desc data; + int ret; + + maj_stat = gss_oid_to_str(&minor_status, GSS_KRB5_MECHANISM, &data); + if (GSS_ERROR(maj_stat)) + errx(1, "gss_oid_to_str failed"); + ret = strncmp(data.value, "1 2 840 113554 1 2 2", data.length); + gss_release_buffer(&maj_stat, &data); + if (ret) + return 1; + return 0; +} diff --git a/lib/gssapi/krb5/unwrap.c b/lib/gssapi/krb5/unwrap.c index d6bc20477787..da939c052930 100644 --- a/lib/gssapi/krb5/unwrap.c +++ b/lib/gssapi/krb5/unwrap.c @@ -382,7 +382,7 @@ unwrap_des3 OM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, + gss_const_ctx_id_t context_handle, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int * conf_state, @@ -392,7 +392,6 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap krb5_keyblock *key; krb5_context context; OM_uint32 ret; - krb5_keytype keytype; gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle; output_message_buffer->value = NULL; @@ -414,12 +413,13 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap *minor_status = ret; return GSS_S_FAILURE; } - krb5_enctype_to_keytype (context, key->keytype, &keytype); *minor_status = 0; - switch (keytype) { - case KEYTYPE_DES : + switch (key->keytype) { + case KRB5_ENCTYPE_DES_CBC_CRC : + case KRB5_ENCTYPE_DES_CBC_MD4 : + case KRB5_ENCTYPE_DES_CBC_MD5 : #ifdef HEIM_WEAK_CRYPTO ret = unwrap_des (minor_status, ctx, input_message_buffer, output_message_buffer, @@ -428,13 +428,14 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap ret = GSS_S_FAILURE; #endif break; - case KEYTYPE_DES3 : + case KRB5_ENCTYPE_DES3_CBC_MD5 : + case KRB5_ENCTYPE_DES3_CBC_SHA1 : ret = unwrap_des3 (minor_status, ctx, context, input_message_buffer, output_message_buffer, conf_state, qop_state, key); break; - case KEYTYPE_ARCFOUR: - case KEYTYPE_ARCFOUR_56: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: ret = _gssapi_unwrap_arcfour (minor_status, ctx, context, input_message_buffer, output_message_buffer, conf_state, qop_state, key); diff --git a/lib/gssapi/krb5/verify_mic.c b/lib/gssapi/krb5/verify_mic.c index 3814ef7062c1..9968ce403ef7 100644 --- a/lib/gssapi/krb5/verify_mic.c +++ b/lib/gssapi/krb5/verify_mic.c @@ -254,15 +254,11 @@ retry: krb5_crypto_destroy (context, crypto); ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_SHA1, &crypto); - if (ret){ - *minor_status = ret; - return GSS_S_FAILURE; - } - - ret = krb5_verify_checksum (context, crypto, - KRB5_KU_USAGE_SIGN, - tmp, message_buffer->length + 8, - &csum); + if (ret == 0) + ret = krb5_verify_checksum(context, crypto, + KRB5_KU_USAGE_SIGN, + tmp, message_buffer->length + 8, + &csum); free (tmp); if (ret) { krb5_crypto_destroy (context, crypto); @@ -289,7 +285,6 @@ _gsskrb5_verify_mic_internal { krb5_keyblock *key; OM_uint32 ret; - krb5_keytype keytype; if (ctx->more_flags & IS_CFX) return _gssapi_verify_mic_cfx (minor_status, ctx, @@ -304,9 +299,11 @@ _gsskrb5_verify_mic_internal return GSS_S_FAILURE; } *minor_status = 0; - krb5_enctype_to_keytype (context, key->keytype, &keytype); - switch (keytype) { - case KEYTYPE_DES : + + switch (key->keytype) { + case KRB5_ENCTYPE_DES_CBC_CRC : + case KRB5_ENCTYPE_DES_CBC_MD4 : + case KRB5_ENCTYPE_DES_CBC_MD5 : #ifdef HEIM_WEAK_CRYPTO ret = verify_mic_des (minor_status, ctx, context, message_buffer, token_buffer, qop_state, key, @@ -315,13 +312,14 @@ _gsskrb5_verify_mic_internal ret = GSS_S_FAILURE; #endif break; - case KEYTYPE_DES3 : + case KRB5_ENCTYPE_DES3_CBC_MD5 : + case KRB5_ENCTYPE_DES3_CBC_SHA1 : ret = verify_mic_des3 (minor_status, ctx, context, message_buffer, token_buffer, qop_state, key, type); break; - case KEYTYPE_ARCFOUR : - case KEYTYPE_ARCFOUR_56 : + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: ret = _gssapi_verify_mic_arcfour (minor_status, ctx, context, message_buffer, token_buffer, @@ -338,7 +336,7 @@ _gsskrb5_verify_mic_internal OM_uint32 GSSAPI_CALLCONV _gsskrb5_verify_mic (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, + gss_const_ctx_id_t context_handle, const gss_buffer_t message_buffer, const gss_buffer_t token_buffer, gss_qop_t * qop_state diff --git a/lib/gssapi/krb5/wrap.c b/lib/gssapi/krb5/wrap.c index 1026e41914e9..481e30375a44 100644 --- a/lib/gssapi/krb5/wrap.c +++ b/lib/gssapi/krb5/wrap.c @@ -137,7 +137,7 @@ sub_wrap_size ( OM_uint32 GSSAPI_CALLCONV _gsskrb5_wrap_size_limit ( OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, + gss_const_ctx_id_t context_handle, int conf_req_flag, gss_qop_t qop_req, OM_uint32 req_output_size, @@ -147,7 +147,6 @@ _gsskrb5_wrap_size_limit ( krb5_context context; krb5_keyblock *key; OM_uint32 ret; - krb5_keytype keytype; const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; GSSAPI_KRB5_INIT (&context); @@ -164,23 +163,25 @@ _gsskrb5_wrap_size_limit ( *minor_status = ret; return GSS_S_FAILURE; } - krb5_enctype_to_keytype (context, key->keytype, &keytype); - switch (keytype) { - case KEYTYPE_DES : + switch (key->keytype) { + case KRB5_ENCTYPE_DES_CBC_CRC : + case KRB5_ENCTYPE_DES_CBC_MD4 : + case KRB5_ENCTYPE_DES_CBC_MD5 : #ifdef HEIM_WEAK_CRYPTO ret = sub_wrap_size(req_output_size, max_input_size, 8, 22); #else ret = GSS_S_FAILURE; #endif break; - case ENCTYPE_ARCFOUR_HMAC_MD5: - case ENCTYPE_ARCFOUR_HMAC_MD5_56: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context, conf_req_flag, qop_req, req_output_size, max_input_size, key); break; - case KEYTYPE_DES3 : + case KRB5_ENCTYPE_DES3_CBC_MD5 : + case KRB5_ENCTYPE_DES3_CBC_SHA1 : ret = sub_wrap_size(req_output_size, max_input_size, 8, 34); break; default : @@ -527,7 +528,7 @@ wrap_des3 OM_uint32 GSSAPI_CALLCONV _gsskrb5_wrap (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, + gss_const_ctx_id_t context_handle, int conf_req_flag, gss_qop_t qop_req, const gss_buffer_t input_message_buffer, @@ -538,7 +539,6 @@ _gsskrb5_wrap krb5_context context; krb5_keyblock *key; OM_uint32 ret; - krb5_keytype keytype; const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; output_message_buffer->value = NULL; @@ -558,10 +558,11 @@ _gsskrb5_wrap *minor_status = ret; return GSS_S_FAILURE; } - krb5_enctype_to_keytype (context, key->keytype, &keytype); - switch (keytype) { - case KEYTYPE_DES : + switch (key->keytype) { + case KRB5_ENCTYPE_DES_CBC_CRC : + case KRB5_ENCTYPE_DES_CBC_MD4 : + case KRB5_ENCTYPE_DES_CBC_MD5 : #ifdef HEIM_WEAK_CRYPTO ret = wrap_des (minor_status, ctx, context, conf_req_flag, qop_req, input_message_buffer, conf_state, @@ -570,13 +571,14 @@ _gsskrb5_wrap ret = GSS_S_FAILURE; #endif break; - case KEYTYPE_DES3 : + case KRB5_ENCTYPE_DES3_CBC_MD5 : + case KRB5_ENCTYPE_DES3_CBC_SHA1 : ret = wrap_des3 (minor_status, ctx, context, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer, key); break; - case KEYTYPE_ARCFOUR: - case KEYTYPE_ARCFOUR_56: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5: + case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56: ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer, key); |