diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /third_party/heimdal/lib/gssapi/krb5 | |
parent | Initial commit. (diff) | |
download | samba-4f5791ebd03eaec1c7da0865a383175b05102712.tar.xz samba-4f5791ebd03eaec1c7da0865a383175b05102712.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/heimdal/lib/gssapi/krb5')
63 files changed, 17400 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/gssapi/krb5/8003.c b/third_party/heimdal/lib/gssapi/krb5/8003.c new file mode 100644 index 0000000..3e21336 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/8003.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 1997 - 2003 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" + +krb5_error_code +_gsskrb5_encode_om_uint32(OM_uint32 n, u_char *p) +{ + p[0] = (n >> 0) & 0xFF; + p[1] = (n >> 8) & 0xFF; + p[2] = (n >> 16) & 0xFF; + p[3] = (n >> 24) & 0xFF; + return 0; +} + +krb5_error_code +_gsskrb5_encode_be_om_uint32(OM_uint32 n, u_char *p) +{ + p[0] = (n >> 24) & 0xFF; + p[1] = (n >> 16) & 0xFF; + p[2] = (n >> 8) & 0xFF; + p[3] = (n >> 0) & 0xFF; + return 0; +} + +krb5_error_code +_gsskrb5_decode_om_uint32(const void *ptr, OM_uint32 *n) +{ + const u_char *p = ptr; + *n = ((uint32_t)p[0]) + | ((uint32_t)p[1] << 8) + | ((uint32_t)p[2] << 16) + | ((uint32_t)p[3] << 24); + return 0; +} + +krb5_error_code +_gsskrb5_decode_be_om_uint32(const void *ptr, OM_uint32 *n) +{ + const u_char *p = ptr; + *n = ((uint32_t)p[0] <<24) + | ((uint32_t)p[1] << 16) + | ((uint32_t)p[2] << 8) + | ((uint32_t)p[3]); + return 0; +} + +static krb5_error_code +hash_input_chan_bindings (const gss_channel_bindings_t b, + u_char *p) +{ + u_char num[4]; + EVP_MD_CTX *ctx; + + ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(ctx, EVP_md5(), NULL); + + _gsskrb5_encode_om_uint32 (b->initiator_addrtype, num); + EVP_DigestUpdate(ctx, num, sizeof(num)); + _gsskrb5_encode_om_uint32 (b->initiator_address.length, num); + EVP_DigestUpdate(ctx, num, sizeof(num)); + if (b->initiator_address.length) + EVP_DigestUpdate(ctx, + b->initiator_address.value, + b->initiator_address.length); + _gsskrb5_encode_om_uint32 (b->acceptor_addrtype, num); + EVP_DigestUpdate(ctx, num, sizeof(num)); + _gsskrb5_encode_om_uint32 (b->acceptor_address.length, num); + EVP_DigestUpdate(ctx, num, sizeof(num)); + if (b->acceptor_address.length) + EVP_DigestUpdate(ctx, + b->acceptor_address.value, + b->acceptor_address.length); + _gsskrb5_encode_om_uint32 (b->application_data.length, num); + EVP_DigestUpdate(ctx, num, sizeof(num)); + if (b->application_data.length) + EVP_DigestUpdate(ctx, + b->application_data.value, + b->application_data.length); + EVP_DigestFinal_ex(ctx, p, NULL); + EVP_MD_CTX_destroy(ctx); + + return 0; +} + +/* + * create a checksum over the chanel bindings in + * `input_chan_bindings', `flags' and `fwd_data' and return it in + * `result' + */ + +OM_uint32 +_gsskrb5_create_8003_checksum ( + OM_uint32 *minor_status, + const gss_channel_bindings_t input_chan_bindings, + OM_uint32 flags, + const krb5_data *fwd_data, + Checksum *result) +{ + u_char *p; + + /* + * see rfc1964 (section 1.1.1 (Initial Token), and the checksum value + * field's format) */ + result->cksumtype = CKSUMTYPE_GSSAPI; + if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG)) + result->checksum.length = 24 + 4 + fwd_data->length; + else + result->checksum.length = 24; + result->checksum.data = malloc (result->checksum.length); + if (result->checksum.data == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = result->checksum.data; + _gsskrb5_encode_om_uint32 (16, p); + p += 4; + if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS) { + memset (p, 0, 16); + } else { + hash_input_chan_bindings (input_chan_bindings, p); + } + p += 16; + _gsskrb5_encode_om_uint32 (flags, p); + p += 4; + + if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG)) { + + *p++ = (1 >> 0) & 0xFF; /* DlgOpt */ /* == 1 */ + *p++ = (1 >> 8) & 0xFF; /* DlgOpt */ /* == 0 */ + *p++ = (fwd_data->length >> 0) & 0xFF; /* Dlgth */ + *p++ = (fwd_data->length >> 8) & 0xFF; /* Dlgth */ + memcpy(p, (unsigned char *) fwd_data->data, fwd_data->length); + + /* p += fwd_data->length; */ /* commented out to quiet warning */ + } + + return GSS_S_COMPLETE; +} + +static krb5_error_code +check_ap_options_cbt(void *ad_data, size_t ad_len, + krb5_boolean *client_asserted_cb) +{ + uint32_t ad_ap_options; + + *client_asserted_cb = FALSE; + + if (ad_len != sizeof(uint32_t)) + return KRB5KRB_AP_ERR_MSG_TYPE; + + _gss_mg_decode_le_uint32(ad_data, &ad_ap_options); + + if (ad_ap_options & KERB_AP_OPTIONS_CBT) + *client_asserted_cb = TRUE; + + return 0; +} + +static krb5_error_code +find_ap_options(krb5_context context, + krb5_authenticator authenticator, + krb5_boolean *client_asserted_cb) +{ + krb5_error_code ret; + krb5_authdata *ad; + krb5_data data; + + *client_asserted_cb = FALSE; + + ad = authenticator->authorization_data; + if (ad == NULL) + return 0; + + ret = _krb5_get_ad(context, ad, NULL, KRB5_AUTHDATA_AP_OPTIONS, &data); + if (ret) + return ret == ENOENT ? 0 : ret; + + ret = check_ap_options_cbt(data.data, data.length, client_asserted_cb); + krb5_data_free(&data); + + return ret; +} + +/* + * verify the checksum in `cksum' over `input_chan_bindings' + * returning `flags' and `fwd_data' + */ + +OM_uint32 +_gsskrb5_verify_8003_checksum( + krb5_context context, + OM_uint32 *minor_status, + const gss_channel_bindings_t input_chan_bindings, + krb5_authenticator authenticator, + OM_uint32 *flags, + krb5_data *fwd_data) +{ + unsigned char hash[16]; + unsigned char *p; + OM_uint32 length; + int DlgOpt; + static unsigned char zeros[16]; + krb5_boolean channel_bound = FALSE; + const Checksum *cksum = authenticator->cksum; + krb5_boolean client_asserted_cb; + krb5_error_code ret; + + /* XXX should handle checksums > 24 bytes */ + if(cksum->cksumtype != CKSUMTYPE_GSSAPI || cksum->checksum.length < 24) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + p = cksum->checksum.data; + _gsskrb5_decode_om_uint32(p, &length); + if(length != sizeof(hash)) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + p += 4; + + ret = find_ap_options(context, authenticator, &client_asserted_cb); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS + && (memcmp(p, zeros, sizeof(zeros)) != 0 || client_asserted_cb)) { + if(hash_input_chan_bindings(input_chan_bindings, hash) != 0) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + if(ct_memcmp(hash, p, sizeof(hash)) != 0) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + channel_bound = TRUE; + } + + p += sizeof(hash); + + _gsskrb5_decode_om_uint32(p, flags); + p += 4; + + if (cksum->checksum.length > 24 && (*flags & GSS_C_DELEG_FLAG)) { + if(cksum->checksum.length < 28) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + DlgOpt = (p[0] << 0) | (p[1] << 8); + p += 2; + if (DlgOpt != 1) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + fwd_data->length = (p[0] << 0) | (p[1] << 8); + p += 2; + if(cksum->checksum.length < 28 + fwd_data->length) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + fwd_data->data = malloc(fwd_data->length); + if (fwd_data->data == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(fwd_data->data, p, fwd_data->length); + } + + if (channel_bound) { + *flags |= GSS_C_CHANNEL_BOUND_FLAG; + } else { + *flags &= ~GSS_C_CHANNEL_BOUND_FLAG; + } + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/accept_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/accept_sec_context.c new file mode 100644 index 0000000..3f8e274 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/accept_sec_context.c @@ -0,0 +1,978 @@ +/* + * Copyright (c) 1997 - 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" + +HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER; +krb5_keytab _gsskrb5_keytab; + +static krb5_error_code +validate_keytab(krb5_context context, const char *name, krb5_keytab *id) +{ + krb5_error_code ret; + + ret = krb5_kt_resolve(context, name, id); + if (ret) + return ret; + + ret = krb5_kt_have_content(context, *id); + if (ret) { + krb5_kt_close(context, *id); + *id = NULL; + } + + return ret; +} + +OM_uint32 +_gsskrb5_register_acceptor_identity(OM_uint32 *min_stat, const char *identity) +{ + krb5_context context; + krb5_error_code ret; + + *min_stat = 0; + + ret = _gsskrb5_init(&context); + if(ret) + return GSS_S_FAILURE; + + HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); + + if(_gsskrb5_keytab != NULL) { + krb5_kt_close(context, _gsskrb5_keytab); + _gsskrb5_keytab = NULL; + } + if (identity == NULL) { + ret = krb5_kt_default(context, &_gsskrb5_keytab); + } else { + /* + * First check if we can the keytab as is and if it has content... + */ + ret = validate_keytab(context, identity, &_gsskrb5_keytab); + /* + * if it doesn't, lets prepend FILE: and try again + */ + if (ret) { + char *p = NULL; + ret = asprintf(&p, "FILE:%s", identity); + if(ret < 0 || p == NULL) { + HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); + return GSS_S_FAILURE; + } + ret = validate_keytab(context, p, &_gsskrb5_keytab); + free(p); + } + } + HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); + if(ret) { + *min_stat = ret; + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} + +void +_gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor) +{ + krb5_keyblock *key; + + if (acceptor) { + if (ctx->auth_context->local_subkey) + key = ctx->auth_context->local_subkey; + else + key = ctx->auth_context->remote_subkey; + } else { + if (ctx->auth_context->remote_subkey) + key = ctx->auth_context->remote_subkey; + else + key = ctx->auth_context->local_subkey; + } + if (key == NULL) + key = ctx->auth_context->keyblock; + + if (key == NULL) + return; + + switch (key->keytype) { + case ETYPE_DES_CBC_CRC: + case ETYPE_DES_CBC_MD4: + case ETYPE_DES_CBC_MD5: + case ETYPE_DES3_CBC_MD5: + case ETYPE_OLD_DES3_CBC_SHA1: + case ETYPE_DES3_CBC_SHA1: + case ETYPE_ARCFOUR_HMAC_MD5: + case ETYPE_ARCFOUR_HMAC_MD5_56: + break; + default : + ctx->more_flags |= IS_CFX; + + if ((acceptor && ctx->auth_context->local_subkey) || + (!acceptor && ctx->auth_context->remote_subkey)) + ctx->more_flags |= ACCEPTOR_SUBKEY; + break; + } + if (ctx->crypto) + krb5_crypto_destroy(context, ctx->crypto); + /* XXX We really shouldn't ignore this; will come back to this */ + (void) krb5_crypto_init(context, key, 0, &ctx->crypto); +} + + +static OM_uint32 +gsskrb5_accept_delegated_token(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + gss_cred_id_t *delegated_cred_handle) +{ + krb5_ccache ccache = NULL; + krb5_error_code kret; + int32_t ac_flags, ret = GSS_S_COMPLETE; + gsskrb5_cred handle; + + *minor_status = 0; + + /* XXX Create a new delegated_cred_handle? */ + if (delegated_cred_handle == NULL) + return GSS_S_COMPLETE; + + *delegated_cred_handle = NULL; + kret = krb5_cc_resolve(context, "MEMORY:anonymous", &ccache); + if (kret == 0) + kret = krb5_cc_initialize(context, ccache, ctx->source); + if (kret == 0) { + (void) krb5_auth_con_removeflags(context, + ctx->auth_context, + KRB5_AUTH_CONTEXT_DO_TIME, + &ac_flags); + kret = krb5_rd_cred2(context, + ctx->auth_context, + ccache, + &ctx->fwd_data); + (void) krb5_auth_con_setflags(context, + ctx->auth_context, + ac_flags); + } + if (kret) { + ctx->flags &= ~GSS_C_DELEG_FLAG; + ret = GSS_S_FAILURE; + *minor_status = kret; + goto out; + } + + ret = _gsskrb5_krb5_import_cred(minor_status, + &ccache, + NULL, + NULL, + delegated_cred_handle); + if (ret != GSS_S_COMPLETE) + goto out; + + handle = (gsskrb5_cred) *delegated_cred_handle; + handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; + + /* + * A root TGT is one of the form krbtgt/REALM@SAME-REALM. + * + * A destination TGT is a root TGT for the same realm as the acceptor + * service's realm. + * + * Normally clients delegate a root TGT for the client's realm. + * + * In some deployments clients may want to delegate destination TGTs as + * a form of constrained delegation: so that the destination service + * cannot use the delegated credential to impersonate the client + * principal to services in its home realm (due to KDC lineage/transit + * checks). In those deployments there may not even be a route back to + * the KDCs of the client's realm, and attempting to use a + * non-destination TGT might even lead to timeouts. + * + * We could simply pretend not to have obtained a credential, except + * that a) we don't (yet) have an app name here for the appdefault we + * need to check, b) the application really wants to be able to log a + * message about the delegated credential being no good. + * + * Thus we leave it to _gsskrb5_store_cred_into2() to decide what to do + * with non-destination TGTs. To do that, it needs the realm of the + * acceptor service, which we record here. + */ + handle->destination_realm = + strdup(krb5_principal_get_realm(context, ctx->target)); + if (handle->destination_realm == NULL) { + _gsskrb5_release_cred(minor_status, delegated_cred_handle); + *minor_status = krb5_enomem(context); + ret = GSS_S_FAILURE; + goto out; + } + +out: + if (ccache) { + krb5_cc_close(context, ccache); + } + return ret; +} + +static OM_uint32 +gsskrb5_acceptor_ready(OM_uint32 * minor_status, + gsskrb5_ctx ctx, + krb5_context context, + gss_cred_id_t *delegated_cred_handle) +{ + OM_uint32 ret; + int32_t seq_number; + int is_cfx = 0; + + krb5_auth_con_getremoteseqnumber (context, + ctx->auth_context, + &seq_number); + + _gsskrb5i_is_cfx(context, ctx, 1); + is_cfx = (ctx->more_flags & IS_CFX); + + ret = _gssapi_msg_order_create(minor_status, + &ctx->order, + _gssapi_msg_order_f(ctx->flags), + seq_number, 0, is_cfx); + if (ret) + return ret; + + /* + * If requested, set local sequence num to remote sequence if this + * isn't a mutual authentication context + */ + if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) { + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + seq_number); + } + + /* + * We should handle the delegation ticket, in case it's there + */ + if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) { + ret = gsskrb5_accept_delegated_token(minor_status, + ctx, + context, + delegated_cred_handle); + if (ret != GSS_S_COMPLETE) + return ret; + } else { + /* Well, looks like it wasn't there after all */ + ctx->flags &= ~GSS_C_DELEG_FLAG; + } + + ctx->state = ACCEPTOR_READY; + ctx->more_flags |= OPEN; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +send_error_token(OM_uint32 *minor_status, + krb5_context context, + krb5_error_code kret, + krb5_principal server, + krb5_data *indata, + gss_buffer_t output_token) +{ + krb5_principal ap_req_server = NULL; + krb5_error_code ret; + krb5_data outbuf; + /* this e_data value encodes KERB_AP_ERR_TYPE_SKEW_RECOVERY which + tells windows to try again with the corrected timestamp. See + [MS-KILE] 2.2.1 KERB-ERROR-DATA */ + krb5_data e_data = { 7, rk_UNCONST("\x30\x05\xa1\x03\x02\x01\x02") }; + + /* build server from request if the acceptor had not selected one */ + if (server == NULL) { + AP_REQ ap_req; + + ret = krb5_decode_ap_req(context, indata, &ap_req); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = _krb5_principalname2krb5_principal(context, + &ap_req_server, + ap_req.ticket.sname, + ap_req.ticket.realm); + free_AP_REQ(&ap_req); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + server = ap_req_server; + } + + ret = krb5_mk_error(context, kret, NULL, &e_data, NULL, + server, NULL, NULL, &outbuf); + if (ap_req_server) + krb5_free_principal(context, ap_req_server); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = _gsskrb5_encapsulate(minor_status, + &outbuf, + output_token, + "\x03\x00", + GSS_KRB5_MECHANISM); + krb5_data_free (&outbuf); + if (ret) + return ret; + + *minor_status = 0; + return GSS_S_CONTINUE_NEEDED; +} + + +static OM_uint32 +gsskrb5_acceptor_start(OM_uint32 * minor_status, + gsskrb5_ctx ctx, + krb5_context context, + 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, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle) +{ + krb5_error_code kret; + OM_uint32 ret = GSS_S_COMPLETE; + krb5_data indata; + 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; + + /* + * We may, or may not, have an escapsulation. + */ + ret = _gsskrb5_decapsulate (minor_status, + input_token_buffer, + &indata, + "\x01\x00", + GSS_KRB5_MECHANISM); + + if (ret) { + /* Could be a raw AP-REQ (check for APPLICATION tag) */ + if (input_token_buffer->length == 0 || + ((const uint8_t *)input_token_buffer->value)[0] != 0x6E) { + *minor_status = ASN1_MISPLACED_FIELD; + return GSS_S_DEFECTIVE_TOKEN; + } + + /* Assume that there is no OID wrapping. */ + indata.length = input_token_buffer->length; + indata.data = input_token_buffer->value; + } + + /* + * We need to get our keytab + */ + if (acceptor_cred == NULL) { + 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; + } + + /* + * We need to check the ticket and create the AP-REP packet + */ + + { + krb5_rd_req_in_ctx in = NULL; + krb5_rd_req_out_ctx out = NULL; + krb5_principal server = NULL; + + if (acceptor_cred) + server = acceptor_cred->principal; + + kret = krb5_rd_req_in_ctx_alloc(context, &in); + if (kret == 0) + kret = krb5_rd_req_in_set_keytab(context, in, keytab); + 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; + } + + kret = krb5_rd_req_ctx(context, + &ctx->auth_context, + &indata, + 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 + * non-MUTUAL mode yet, thats inside the 8003 checksum, so + * lets only send the error token on clock skew, that + * limit when send error token for non-MUTUAL. + */ + krb5_auth_con_free(context, ctx->auth_context); + krb5_auth_con_free(context, ctx->deleg_auth_context); + ctx->deleg_auth_context = NULL; + ctx->auth_context = NULL; + return send_error_token(minor_status, context, kret, + server, &indata, output_token); + } else if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + /* + * we need to remember some data on the context_handle. + */ + kret = krb5_rd_req_out_get_ap_req_options(context, out, + &ap_options); + if (kret == 0) + kret = krb5_rd_req_out_get_ticket(context, out, + &ctx->ticket); + if (kret == 0) + kret = krb5_rd_req_out_get_keyblock(context, out, + &ctx->service_keyblock); + ctx->endtime = ctx->ticket->ticket.endtime; + + krb5_rd_req_out_ctx_free(context, out); + if (kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + } + + + /* + * We need to copy the principal names to the context and the + * calling layer. + */ + kret = krb5_copy_principal(context, + ctx->ticket->client, + &ctx->source); + if (kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + + kret = krb5_copy_principal(context, + ctx->ticket->server, + &ctx->target); + if (kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + + /* + * We need to setup some compat stuff, this assumes that + * context_handle->target is already set. + */ + ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); + if (ret) + return ret; + + if (src_name != NULL) { + kret = krb5_copy_principal (context, + ctx->ticket->client, + (gsskrb5_name*)src_name); + if (kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + } + + /* + * We need to get the flags out of the 8003 checksum. + */ + + { + krb5_authenticator authenticator; + + kret = krb5_auth_con_getauthenticator(context, + ctx->auth_context, + &authenticator); + if(kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + return ret; + } + + if (authenticator->cksum != NULL + && authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) { + ret = _gsskrb5_verify_8003_checksum(context, + minor_status, + input_chan_bindings, + authenticator, + &ctx->flags, + &ctx->fwd_data); + + if (ret) { + krb5_free_authenticator(context, &authenticator); + return ret; + } + } else { + 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 + */ + + _krb5_crypto_set_flags(context, crypto, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM); + 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; + } + } + + /* + * If there is no checksum or a kerberos checksum (which Windows + * and Samba accept), we use the ap_options to guess the mutual + * 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) { + krb5_data outbuf; + int use_subkey = 0; + + _gsskrb5i_is_cfx(context, ctx, 1); + is_cfx = (ctx->more_flags & IS_CFX); + + if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) { + use_subkey = 1; + } else { + krb5_keyblock *rkey; + + /* + * If there is a initiator subkey, copy that to acceptor + * subkey to match Windows behavior + */ + kret = krb5_auth_con_getremotesubkey(context, + ctx->auth_context, + &rkey); + if (kret == 0) { + kret = krb5_auth_con_setlocalsubkey(context, + ctx->auth_context, + rkey); + if (kret == 0) + use_subkey = 1; + } + krb5_free_keyblock(context, rkey); + } + if (use_subkey) { + ctx->more_flags |= ACCEPTOR_SUBKEY; + krb5_auth_con_addflags(context, ctx->auth_context, + KRB5_AUTH_CONTEXT_USE_SUBKEY, + NULL); + } + + kret = krb5_mk_rep(context, + ctx->auth_context, + &outbuf); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (IS_DCE_STYLE(ctx)) { + output_token->length = outbuf.length; + output_token->value = outbuf.data; + } else { + ret = _gsskrb5_encapsulate(minor_status, + &outbuf, + output_token, + "\x02\x00", + GSS_KRB5_MECHANISM); + krb5_data_free (&outbuf); + if (ret) + return ret; + } + } + + ctx->flags |= GSS_C_TRANS_FLAG; + + /* Remember the flags */ + + ctx->endtime = ctx->ticket->ticket.endtime; + ctx->more_flags |= OPEN; + + if (mech_type) + *mech_type = GSS_KRB5_MECHANISM; + + if (time_rec) { + ret = _gsskrb5_lifetime_left(minor_status, + context, + ctx->endtime, + time_rec); + if (ret) { + return ret; + } + } + + /* + * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from + * the client. + */ + if (IS_DCE_STYLE(ctx)) { + /* + * Return flags to caller, but we haven't processed + * delgations yet + */ + if (ret_flags) + *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG); + + ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE; + return GSS_S_CONTINUE_NEEDED; + } + + ret = gsskrb5_acceptor_ready(minor_status, ctx, context, + delegated_cred_handle); + + if (ret_flags) + *ret_flags = ctx->flags; + + return ret; +} + +static OM_uint32 +acceptor_wait_for_dcestyle(OM_uint32 * minor_status, + gsskrb5_ctx ctx, + krb5_context context, + 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, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle) +{ + OM_uint32 ret; + krb5_error_code kret; + krb5_data inbuf; + int32_t r_seq_number, l_seq_number; + + /* + * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP + */ + + inbuf.length = input_token_buffer->length; + inbuf.data = input_token_buffer->value; + + /* + * We need to remeber the old remote seq_number, then check if the + * client has replied with our local seq_number, and then reset + * the remote seq_number to the old value + */ + { + kret = krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &l_seq_number); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_getremoteseqnumber(context, + ctx->auth_context, + &r_seq_number); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_setremoteseqnumber(context, + ctx->auth_context, + l_seq_number); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + /* + * We need to verify the AP_REP, but we need to flag that this is + * DCE_STYLE, so don't check the timestamps this time, but put the + * flag DO_TIME back afterward. + */ + { + krb5_ap_rep_enc_part *repl; + int32_t auth_flags; + + krb5_auth_con_removeflags(context, + ctx->auth_context, + KRB5_AUTH_CONTEXT_DO_TIME, + &auth_flags); + + kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + krb5_free_ap_rep_enc_part(context, repl); + krb5_auth_con_setflags(context, ctx->auth_context, auth_flags); + } + + /* We need to check the liftime */ + { + OM_uint32 lifetime_rec; + + ret = _gsskrb5_lifetime_left(minor_status, + context, + ctx->endtime, + &lifetime_rec); + if (ret) { + return ret; + } + if (lifetime_rec == 0) { + return GSS_S_CONTEXT_EXPIRED; + } + + if (time_rec) *time_rec = lifetime_rec; + } + + /* We need to give the caller the flags which are in use */ + if (ret_flags) *ret_flags = ctx->flags; + + if (src_name) { + kret = krb5_copy_principal(context, + ctx->source, + (gsskrb5_name*)src_name); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + /* + * After the krb5_rd_rep() the remote and local seq_number should + * be the same, because the client just replies the seq_number + * from our AP-REP in its AP-REP, but then the client uses the + * seq_number from its AP-REQ for GSS_wrap() + */ + { + int32_t tmp_r_seq_number, tmp_l_seq_number; + + kret = krb5_auth_con_getremoteseqnumber(context, + ctx->auth_context, + &tmp_r_seq_number); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &tmp_l_seq_number); + if (kret) { + + *minor_status = kret; + return GSS_S_FAILURE; + } + + /* + * Here we check if the client has responsed with our local seq_number, + */ + if (tmp_r_seq_number != tmp_l_seq_number) { + return GSS_S_UNSEQ_TOKEN; + } + } + + /* + * We need to reset the remote seq_number, because the client will use, + * the old one for the GSS_wrap() calls + */ + { + kret = krb5_auth_con_setremoteseqnumber(context, + ctx->auth_context, + r_seq_number); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + return gsskrb5_acceptor_ready(minor_status, ctx, context, + delegated_cred_handle); +} + + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_accept_sec_context(OM_uint32 * minor_status, + gss_ctx_id_t * context_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, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle) +{ + krb5_context context; + OM_uint32 ret; + gsskrb5_ctx ctx; + + GSSAPI_KRB5_INIT(&context); + + output_token->length = 0; + output_token->value = NULL; + + if (src_name != NULL) + *src_name = NULL; + if (mech_type) + *mech_type = GSS_KRB5_MECHANISM; + + if (*context_handle == GSS_C_NO_CONTEXT) { + ret = _gsskrb5_create_ctx(minor_status, + context_handle, + context, + input_chan_bindings, + ACCEPTOR_START); + if (ret) + return ret; + } + + ctx = (gsskrb5_ctx)*context_handle; + + + /* + * TODO: check the channel_bindings + * (above just sets them to krb5 layer) + */ + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + switch (ctx->state) { + case ACCEPTOR_START: + ret = gsskrb5_acceptor_start(minor_status, + ctx, + context, + acceptor_cred_handle, + input_token_buffer, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + break; + case ACCEPTOR_WAIT_FOR_DCESTYLE: + ret = acceptor_wait_for_dcestyle(minor_status, + ctx, + context, + acceptor_cred_handle, + input_token_buffer, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + break; + case ACCEPTOR_READY: + /* + * If we get there, the caller have called + * gss_accept_sec_context() one time too many. + */ + ret = GSS_S_BAD_STATUS; + break; + default: + /* TODO: is this correct here? --metze */ + ret = GSS_S_BAD_STATUS; + break; + } + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + if (GSS_ERROR(ret)) { + OM_uint32 min2; + _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); + } + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/acquire_cred.c b/third_party/heimdal/lib/gssapi/krb5/acquire_cred.c new file mode 100644 index 0000000..211dcaa --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/acquire_cred.c @@ -0,0 +1,686 @@ +/* + * Copyright (c) 1997 - 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 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" + +/* + * Find an element in a cred store. Returns GSS_S_COMPLETE if the cred store + * is absent or well formed, irrespective of whether the element exists. The + * caller should check for *value != NULL before using; values are typically + * optional, hence this behavior. (The caller should validate the return + * value at least once though, to check it is well-formed.) + */ +OM_uint32 +__gsskrb5_cred_store_find(OM_uint32 *minor_status, + gss_const_key_value_set_t cred_store, + const char *key, + const char **value) +{ + size_t i; + + *value = NULL; + + if (cred_store == GSS_C_NO_CRED_STORE) + return GSS_S_COMPLETE; + else if (cred_store->count == 0) { + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_NO_CRED; + } + + for (i = 0; i < cred_store->count; i++) { + if (strcmp(key, cred_store->elements[i].key) == 0) { + if (*value) { + *value = NULL; + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_DUPLICATE_ELEMENT; + } + *value = cred_store->elements[i].value; + } + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +__gsskrb5_ccache_lifetime(OM_uint32 *minor_status, + krb5_context context, + krb5_ccache id, + krb5_principal principal, + OM_uint32 *lifetime) +{ + krb5_error_code kret; + time_t left; + + kret = krb5_cc_get_lifetime(context, id, &left); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + *lifetime = left; + + return GSS_S_COMPLETE; +} + + + + +static krb5_error_code +get_system_keytab(krb5_context context, + gss_const_key_value_set_t cred_store, + krb5_keytab *keytab) +{ + krb5_error_code kret; + const char *cs_ktname; + OM_uint32 tmp; + + __gsskrb5_cred_store_find(&tmp, cred_store, "keytab", &cs_ktname); + + HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); + + if (cs_ktname) + kret = krb5_kt_resolve(context, cs_ktname, keytab); + else 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); + } + } else + kret = krb5_kt_default(context, keytab); + + HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); + + return (kret); +} + +static krb5_error_code +get_client_keytab(krb5_context context, + gss_const_key_value_set_t cred_store, + krb5_const_principal principal, + krb5_keytab *keytab) +{ + krb5_error_code ret; + const char *cs_ktname; + OM_uint32 tmp; + + __gsskrb5_cred_store_find(&tmp, cred_store, "client_keytab", &cs_ktname); + + if (cs_ktname) + ret = krb5_kt_resolve(context, cs_ktname, keytab); + else { + char *name = NULL; + ret = _krb5_kt_client_default_name(context, &name); + if (ret == 0) + ret = krb5_kt_resolve(context, name, keytab); + krb5_xfree(name); + } + + if (ret == 0 && principal) { + krb5_keytab_entry entry; + + ret = krb5_kt_get_entry(context, *keytab, principal, + 0, 0, &entry); + if (ret == 0) + krb5_kt_free_entry(context, &entry); + } + + if (ret) { + if (*keytab) { + krb5_kt_close(context, *keytab); + *keytab = NULL; + } + + ret = get_system_keytab(context, GSS_C_NO_CRED_STORE, keytab); + } + + return ret; +} + +static krb5_boolean +is_valid_password_cred_store(gss_const_key_value_set_t cred_store) +{ + size_t i; + + if (cred_store == GSS_C_NO_CRED_STORE) + return TRUE; + + /* XXX don't check keytab, someday we will allow password+acceptor creds */ + for (i = 0; i < cred_store->count; i++) { + if (strcmp(cred_store->elements[i].key, "ccache") == 0 || + strcmp(cred_store->elements[i].key, "client_keytab") == 0) + return FALSE; + } + + return TRUE; +} + +/* + * 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_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gsskrb5_cred handle) +{ + OM_uint32 ret = GSS_S_FAILURE; + krb5_creds cred; + krb5_init_creds_context ctx = NULL; + krb5_get_init_creds_opt *opt = NULL; + krb5_ccache ccache = NULL; + krb5_error_code kret; + time_t now; + OM_uint32 left; + const char *realm; + + if (!is_valid_password_cred_store(cred_store)) { + *minor_status = GSS_KRB5_S_G_BAD_PASSWORD_CRED_STORE; + return GSS_S_NO_CRED; + } + + 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; + } + realm = krb5_principal_get_realm(context, handle->principal); + + kret = krb5_get_init_creds_opt_alloc(context, &opt); + if (kret == 0) { + krb5_get_init_creds_opt_set_default_flags(context, "gss_krb5", realm, + opt); + kret = krb5_init_creds_init(context, handle->principal, NULL, NULL, 0, + opt, &ctx); + } + if (kret == 0) + kret = _krb5_init_creds_set_fast_anon_pkinit_optimistic(context, ctx); + if (kret == 0) + kret = krb5_init_creds_set_password(context, ctx, password); + + /* + * 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); + + if (kret == 0) + kret = krb5_init_creds_get(context, ctx); + if (kret == 0) + kret = krb5_init_creds_get_creds(context, ctx, &cred); + if (kret == 0) + kret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache); + if (kret == 0) + kret = krb5_cc_initialize(context, ccache, cred.client); + if (kret == 0) + kret = krb5_init_creds_store(context, ctx, ccache); + if (kret == 0) + 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; + ret = GSS_S_COMPLETE; + +end: + krb5_get_init_creds_opt_free(context, opt); + if (ctx) + krb5_init_creds_free(context, ctx); + if (ccache != NULL) + krb5_cc_destroy(context, ccache); + if (cred.client != NULL) + krb5_free_cred_contents(context, &cred); + if (ret != GSS_S_COMPLETE) + *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_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gsskrb5_cred handle) +{ + OM_uint32 ret; + 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; + const char *cs_ccache_name; + time_t lifetime = 0; + time_t now; + + memset(&cred, 0, sizeof(cred)); + + ret = __gsskrb5_cred_store_find(minor_status, cred_store, + "ccache", &cs_ccache_name); + if (GSS_ERROR(ret)) + return ret; + + ret = GSS_S_FAILURE; + + /* + * 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); + + /* + * First look for a ccache that has the desired_name (which may be + * the default credential name), unless a specific credential cache + * was included in cred_store. + * + * 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 != NULL && cs_ccache_name == 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) { + 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. + */ + } + + /* + * Either desired_name was GSS_C_NO_NAME (default cred) or + * krb5_cc_cache_match() failed (or found expired). + */ + if (cs_ccache_name) + kret = krb5_cc_resolve(context, cs_ccache_name, &def_ccache); + else + 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 */ + } + +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; + } + kret = get_client_keytab(context, cred_store, handle->principal, &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) + krb5_free_principal(context, def_princ); + if (keytab != NULL) + krb5_kt_close(context, keytab); + if (ret != GSS_S_COMPLETE && kret != 0) + *minor_status = kret; + return (ret); +} + +static OM_uint32 +acquire_acceptor_cred(OM_uint32 * minor_status, + krb5_context context, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gsskrb5_cred handle) +{ + OM_uint32 ret; + krb5_error_code kret; + + ret = GSS_S_FAILURE; + + kret = get_system_keytab(context, cred_store, &handle->keytab); + if (kret) + goto end; + + /* check that the requested principal exists in the keytab */ + if (handle->principal) { + krb5_keytab_entry entry; + + kret = krb5_kt_get_entry(context, handle->keytab, + handle->principal, 0, 0, &entry); + if (kret) + goto end; + krb5_kt_free_entry(context, &entry); + ret = GSS_S_COMPLETE; + } else { + /* + * Check if there is at least one entry in the keytab before + * declaring it as an useful keytab. + */ + krb5_keytab_entry tmp; + krb5_kt_cursor c; + + kret = krb5_kt_start_seq_get (context, handle->keytab, &c); + if (kret) + goto end; + if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) { + krb5_kt_free_entry(context, &tmp); + ret = GSS_S_COMPLETE; /* ok found one entry */ + } + krb5_kt_end_seq_get (context, handle->keytab, &c); + } +end: + if (ret != GSS_S_COMPLETE) { + if (handle->keytab != NULL) + krb5_kt_close(context, handle->keytab); + if (kret != 0) { + *minor_status = kret; + } + } + return (ret); +} + + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_from +(OM_uint32 * minor_status, + gss_const_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_const_key_value_set_t cred_store, + gss_cred_id_t * output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec + ) +{ + krb5_context context; + gsskrb5_cred handle; + OM_uint32 ret; + const char *password = NULL; + + if (desired_mechs) { + int present = 0; + + ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + desired_mechs, &present); + if (ret) + return ret; + if (!present) { + *minor_status = 0; + return GSS_S_BAD_MECH; + } + } + + cred_usage &= GSS_C_OPTION_MASK; + + 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; + } + + ret = __gsskrb5_cred_store_find(minor_status, cred_store, + "password", &password); + if (GSS_ERROR(ret)) + return ret; + + GSSAPI_KRB5_INIT(&context); + + *output_cred_handle = GSS_C_NO_CREDENTIAL; + + handle = calloc(1, sizeof(*handle)); + if (handle == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + handle->destination_realm = NULL; + HEIMDAL_MUTEX_init(&handle->cred_id_mutex); + + if (desired_name != GSS_C_NO_NAME) { + ret = _gsskrb5_canon_name(minor_status, context, + desired_name, &handle->principal); + if (ret) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + free(handle); + return ret; + } + } + + if (password) { + ret = acquire_cred_with_password(minor_status, context, password, time_req, + desired_mechs, cred_usage, cred_store, handle); + if (ret != GSS_S_COMPLETE) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(context, handle->principal); + free(handle); + return (ret); + } + } else { + /* + * Acquire a credential from the specified or 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_mechs, cred_usage, + cred_store, 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_mechs, cred_usage, + cred_store, 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) + ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &handle->mechanisms); + handle->usage = cred_usage; + if (ret == GSS_S_COMPLETE) + ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)handle, + NULL, time_rec, NULL, actual_mechs); + if (ret != GSS_S_COMPLETE) { + if (handle->mechanisms != NULL) + gss_release_oid_set(NULL, &handle->mechanisms); + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(context, handle->principal); + free(handle); + return (ret); + } + *minor_status = 0; + *output_cred_handle = (gss_cred_id_t)handle; + return (GSS_S_COMPLETE); +} diff --git a/third_party/heimdal/lib/gssapi/krb5/add_cred.c b/third_party/heimdal/lib/gssapi/krb5/add_cred.c new file mode 100644 index 0000000..0bc61a7 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/add_cred.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred_from ( + OM_uint32 *minor_status, + gss_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, + OM_uint32 acceptor_time_req, + gss_const_key_value_set_t cred_store, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *initiator_time_rec, + OM_uint32 *acceptor_time_rec) +{ + krb5_context context; + OM_uint32 major, lifetime; + gsskrb5_cred cred, handle; + krb5_const_principal dname; + + handle = NULL; + 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 (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) { + /* + * 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_from(minor_status, desired_name, + min(initiator_time_req, + acceptor_time_req), + GSS_C_NO_OID_SET, + cred_usage, + cred_store, + 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. + */ + + 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) { + 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) { + if (cred != NULL) + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + + handle->usage = cred_usage; + handle->endtime = cred->endtime; + handle->principal = NULL; + handle->destination_realm = NULL; + handle->keytab = NULL; + handle->ccache = NULL; + handle->mechanisms = NULL; + HEIMDAL_MUTEX_init(&handle->cred_id_mutex); + + major = GSS_S_FAILURE; + + *minor_status = krb5_copy_principal(context, cred->principal, + &handle->principal); + if (*minor_status) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + free(handle); + return GSS_S_FAILURE; + } + + if (cred->keytab) { + char *name = NULL; + + *minor_status = krb5_kt_get_full_name(context, cred->keytab, + &name); + if (*minor_status) + goto failure; + + *minor_status = krb5_kt_resolve(context, name, &handle->keytab); + krb5_xfree(name); + if (*minor_status) + goto failure; + } + + if (cred->ccache) { + const char *type, *name; + char *type_name = NULL; + + type = krb5_cc_get_type(context, cred->ccache); + if (type == NULL){ + *minor_status = ENOMEM; + goto failure; + } + + if (strcmp(type, "MEMORY") == 0) { + *minor_status = krb5_cc_new_unique(context, type, + NULL, &handle->ccache); + if (*minor_status) + goto failure; + + *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); + if (name == NULL) { + *minor_status = ENOMEM; + goto failure; + } + + if (asprintf(&type_name, "%s:%s", type, name) == -1 || + type_name == NULL) { + *minor_status = ENOMEM; + goto failure; + } + + *minor_status = krb5_cc_resolve(context, type_name, + &handle->ccache); + free(type_name); + if (*minor_status) + goto failure; + } + } + major = gss_create_empty_oid_set(minor_status, &handle->mechanisms); + if (major != GSS_S_COMPLETE) + goto failure; + + 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); + + 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; + + *minor_status = 0; + return major; + +failure: + if (handle) { + if (handle->principal) + krb5_free_principal(context, handle->principal); + if (handle->keytab) + krb5_kt_close(context, handle->keytab); + if (handle->ccache) + krb5_cc_destroy(context, handle->ccache); + if (handle->mechanisms) + gss_release_oid_set(NULL, &handle->mechanisms); + free(handle); + } + if (cred && output_cred_handle) + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + return major; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/address_to_krb5addr.c b/third_party/heimdal/lib/gssapi/krb5/address_to_krb5addr.c new file mode 100644 index 0000000..fa115d9 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/address_to_krb5addr.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2000 - 2001 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" + +#include <roken.h> + +krb5_error_code +_gsskrb5i_address_to_krb5addr(krb5_context context, + OM_uint32 gss_addr_type, + gss_buffer_desc *gss_addr, + int16_t port, + krb5_address *address) +{ + int addr_type; + struct sockaddr sa; + krb5_socklen_t sa_size = sizeof(sa); + krb5_error_code problem; + + if (gss_addr == NULL) + return GSS_S_FAILURE; + + switch (gss_addr_type) { +#ifdef HAVE_IPV6 + case GSS_C_AF_INET6: addr_type = AF_INET6; + break; +#endif /* HAVE_IPV6 */ + + case GSS_C_AF_INET: addr_type = AF_INET; + break; + default: + return GSS_S_FAILURE; + } + + problem = krb5_h_addr2sockaddr (context, + addr_type, + gss_addr->value, + &sa, + &sa_size, + port); + if (problem) + return GSS_S_FAILURE; + + problem = krb5_sockaddr2address (context, &sa, address); + + return problem; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/aeap.c b/third_party/heimdal/lib/gssapi/krb5/aeap.c new file mode 100644 index 0000000..fe95ecf --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/aeap.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2008 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" + +#include <roken.h> + +OM_uint32 GSSAPI_CALLCONV +_gk_wrap_iov(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int * conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + 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); + + 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; + + default: + ret = GSS_S_FAILURE; + break; + } + + krb5_free_keyblock(context, key); + return ret; +} + +OM_uint32 GSSAPI_CALLCONV +_gk_unwrap_iov(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + 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); + + if (ctx->more_flags & IS_CFX) + return _gssapi_unwrap_cfx_iov(minor_status, ctx, context, + conf_state, qop_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); + + 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 +_gk_wrap_iov_length(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + 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); + + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_iov_length_cfx(minor_status, ctx, context, + conf_req_flag, qop_req, 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); + + 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/third_party/heimdal/lib/gssapi/krb5/arcfour.c b/third_party/heimdal/lib/gssapi/krb5/arcfour.c new file mode 100644 index 0000000..5c754bc --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/arcfour.c @@ -0,0 +1,1391 @@ +/* + * Copyright (c) 2003 - 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" + +/* + * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt + * + * The arcfour message have the following formats: + * + * MIC token + * TOK_ID[2] = 01 01 + * SGN_ALG[2] = 11 00 + * Filler[4] + * SND_SEQ[8] + * SGN_CKSUM[8] + * + * WRAP token + * TOK_ID[2] = 02 01 + * SGN_ALG[2]; + * SEAL_ALG[2] + * Filler[2] + * SND_SEQ[2] + * SGN_CKSUM[8] + * Confounder[8] + */ + +/* + * WRAP in DCE-style have a fixed size header, the oid and length over + * the WRAP header is a total of + * GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE + + * GSS_ARCFOUR_WRAP_TOKEN_SIZE byte (ie total of 45 bytes overhead, + * remember the 2 bytes from APPL [0] SEQ). + */ + +#define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32 +#define GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE 13 + + +static krb5_error_code +arcfour_mic_key(krb5_context context, krb5_keyblock *key, + const void *cksum_data, size_t cksum_size, + void *key6_data, size_t key6_size) +{ + krb5_error_code ret; + + Checksum cksum_k5; + krb5_keyblock key5; + char k5_data[16]; + + Checksum cksum_k6; + + char T[4]; + + memset(T, 0, 4); + cksum_k5.checksum.data = k5_data; + cksum_k5.checksum.length = sizeof(k5_data); + + if (key->keytype == KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56) { + char L40[14] = "fortybits"; + + memcpy(L40 + 10, T, sizeof(T)); + ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5, + L40, 14, 0, key, &cksum_k5); + memset(&k5_data[7], 0xAB, 9); + } else { + ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5, + T, 4, 0, key, &cksum_k5); + } + if (ret) + return ret; + + key5.keytype = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5; + key5.keyvalue = cksum_k5.checksum; + + cksum_k6.checksum.data = key6_data; + cksum_k6.checksum.length = key6_size; + + return krb5_hmac(context, CKSUMTYPE_RSA_MD5, + cksum_data, cksum_size, 0, &key5, &cksum_k6); +} + + +static krb5_error_code +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; + + 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 + 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; + } + + if (iov[i].buffer.length > 0) { + assert(iov[i].buffer.value != NULL); + 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) { + free(ptr); + return ret; + } + + ret = krb5_create_checksum(context, + crypto, + usage, + 0, + ptr, len, + &CKSUM); + memset(ptr, 0, len); + free(ptr); + if (ret == 0) { + memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz); + free_Checksum(&CKSUM); + } + krb5_crypto_destroy(context, crypto); + + 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, + const gsskrb5_ctx context_handle, + krb5_context context, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key) +{ + krb5_error_code ret; + int32_t seq_number; + size_t len, total_len; + u_char k6_data[16], *p0, *p; + EVP_CIPHER_CTX rc4_key; + + _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM); + + message_token->length = total_len; + message_token->value = malloc (total_len); + if (message_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p0 = _gssapi_make_mech_header(message_token->value, + len, + GSS_KRB5_MECHANISM); + p = p0; + + *p++ = 0x01; /* TOK_ID */ + *p++ = 0x01; + *p++ = 0x11; /* SGN_ALG */ + *p++ = 0x00; + *p++ = 0xff; /* Filler */ + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + + p = NULL; + + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SIGN, + p0 + 16, 8, /* SGN_CKSUM */ + p0, 8, /* TOK_ID, SGN_ALG, Filer */ + message_buffer->value, message_buffer->length, + NULL, 0); + if (ret) { + _gsskrb5_release_buffer(minor_status, message_token); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = arcfour_mic_key(context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (ret) { + _gsskrb5_release_buffer(minor_status, message_token); + *minor_status = ret; + return GSS_S_FAILURE; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber (context, + context_handle->auth_context, + &seq_number); + p = p0 + 8; /* SND_SEQ */ + _gsskrb5_encode_be_om_uint32(seq_number, p); + + krb5_auth_con_setlocalseqnumber (context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4); + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); + EVP_Cipher(&rc4_key, p, p, 8); + EVP_CIPHER_CTX_cleanup(&rc4_key); + + memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data)); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + + +OM_uint32 +_gssapi_verify_mic_arcfour(OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + krb5_keyblock *key, + const char *type) +{ + krb5_error_code ret; + uint32_t seq_number; + OM_uint32 omret; + u_char SND_SEQ[8], cksum_data[8], *p; + char k6_data[16]; + int cmp; + + if (qop_state) + *qop_state = 0; + + p = token_buffer->value; + omret = _gsskrb5_verify_header (&p, + token_buffer->length, + type, + GSS_KRB5_MECHANISM); + if (omret) + return omret; + + if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\xff\xff\xff\xff", 4) != 0) + return GSS_S_BAD_MIC; + p += 4; + + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SIGN, + cksum_data, sizeof(cksum_data), + p - 8, 8, + message_buffer->value, message_buffer->length, + NULL, 0); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = arcfour_mic_key(context, key, + cksum_data, sizeof(cksum_data), + k6_data, sizeof(k6_data)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + cmp = (ct_memcmp(cksum_data, p + 8, 8) != 0); + if (cmp) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + { + EVP_CIPHER_CTX rc4_key; + + EVP_CIPHER_CTX_init(&rc4_key); + EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, (void *)k6_data, NULL, 0); + EVP_Cipher(&rc4_key, SND_SEQ, p, 8); + EVP_CIPHER_CTX_cleanup(&rc4_key); + + memset(k6_data, 0, sizeof(k6_data)); + } + + _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0); + else + cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0); + + memset_s(SND_SEQ, sizeof(SND_SEQ), 0, sizeof(SND_SEQ)); + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + omret = _gssapi_msg_order_check(context_handle->order, seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (omret) + return omret; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_wrap_arcfour(OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer, + krb5_keyblock *key) +{ + u_char Klocaldata[16], k6_data[16], *p, *p0; + size_t len, total_len, datalen; + krb5_keyblock Klocal; + krb5_error_code ret; + int32_t seq_number; + + if (conf_state) + *conf_state = 0; + + datalen = input_message_buffer->length; + + if (IS_DCE_STYLE(context_handle)) { + len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + total_len += datalen; + } else { + datalen += 1; /* padding */ + len = datalen + GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + } + + output_message_buffer->length = total_len; + output_message_buffer->value = malloc (total_len); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p0 = _gssapi_make_mech_header(output_message_buffer->value, + 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(&context_handle->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber (context, + context_handle->auth_context, + &seq_number); + + _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8); + + krb5_auth_con_setlocalseqnumber (context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + memset (p0 + 8 + 4, + (context_handle->more_flags & LOCAL) ? 0 : 0xff, + 4); + + krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */ + + /* p points to data */ + p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE; + memcpy(p, input_message_buffer->value, input_message_buffer->length); + + if (!IS_DCE_STYLE(context_handle)) + p[input_message_buffer->length] = 1; /* padding */ + + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SEAL, + p0 + 16, 8, /* SGN_CKSUM */ + p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */ + p0 + 24, 8, /* Confounder */ + p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, + datalen); + if (ret) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + + { + int i; + + 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; + } + ret = arcfour_mic_key(context, &Klocal, + p0 + 8, 4, /* SND_SEQ */ + k6_data, sizeof(k6_data)); + memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata)); + if (ret) { + _gsskrb5_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_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); + EVP_Cipher(&rc4_key, p0 + 24, p0 + 24, 8 + datalen); + EVP_CIPHER_CTX_cleanup(&rc4_key); + } + memset(k6_data, 0, sizeof(k6_data)); + + ret = arcfour_mic_key(context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (ret) { + _gsskrb5_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + 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, p0 + 8, p0 + 8 /* SND_SEQ */, 8); + EVP_CIPHER_CTX_cleanup(&rc4_key); + memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data)); + } + + if (conf_state) + *conf_state = conf_req_flag; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state, + krb5_keyblock *key) +{ + u_char Klocaldata[16]; + krb5_keyblock Klocal; + krb5_error_code ret; + uint32_t seq_number; + size_t datalen; + OM_uint32 omret; + u_char k6_data[16], SND_SEQ[8], Confounder[8]; + u_char cksum_data[8]; + u_char *p, *p0; + int cmp; + int conf_flag; + size_t padlen = 0, len; + + if (conf_state) + *conf_state = 0; + if (qop_state) + *qop_state = 0; + + p0 = input_message_buffer->value; + + if (IS_DCE_STYLE(context_handle)) { + len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + + GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE; + if (input_message_buffer->length < len) + return GSS_S_BAD_MECH; + } else { + len = input_message_buffer->length; + } + + omret = _gssapi_verify_mech_header(&p0, + len, + GSS_KRB5_MECHANISM); + if (omret) + return omret; + + /* length of mech header */ + len = (p0 - (u_char *)input_message_buffer->value) + + GSS_ARCFOUR_WRAP_TOKEN_SIZE; + + if (len > input_message_buffer->length) + return GSS_S_BAD_MECH; + + /* length of data */ + datalen = input_message_buffer->length - len; + + 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_flag = 1; + else if (memcmp (p, "\xff\xff", 2) == 0) + conf_flag = 0; + else + return GSS_S_BAD_SIG; + + p += 2; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_BAD_MIC; + p = NULL; + + ret = arcfour_mic_key(context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (ret) { + *minor_status = ret; + 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); + EVP_CIPHER_CTX_cleanup(&rc4_key); + memset_s(k6_data, sizeof(k6_data), 0, sizeof(k6_data)); + } + + _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0); + else + cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0); + + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + { + int i; + + 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; + } + ret = arcfour_mic_key(context, &Klocal, + SND_SEQ, 4, + k6_data, sizeof(k6_data)); + memset_s(Klocaldata, sizeof(Klocaldata), 0, sizeof(Klocaldata)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + output_message_buffer->value = malloc(datalen); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + output_message_buffer->length = datalen; + + if(conf_flag) { + 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, Confounder, p0 + 24, 8); + EVP_Cipher(&rc4_key, output_message_buffer->value, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen); + EVP_CIPHER_CTX_cleanup(&rc4_key); + } else { + memcpy(Confounder, p0 + 24, 8); /* Confounder */ + memcpy(output_message_buffer->value, + p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, + datalen); + } + memset(k6_data, 0, sizeof(k6_data)); + + if (!IS_DCE_STYLE(context_handle)) { + ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen); + if (ret) { + _gsskrb5_release_buffer(minor_status, output_message_buffer); + *minor_status = 0; + return ret; + } + output_message_buffer->length -= padlen; + } + + ret = arcfour_mic_cksum(context, + key, KRB5_KU_USAGE_SEAL, + cksum_data, sizeof(cksum_data), + p0, 8, + Confounder, sizeof(Confounder), + output_message_buffer->value, + output_message_buffer->length + padlen); + if (ret) { + _gsskrb5_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_FAILURE; + } + + cmp = ct_memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ + if (cmp) { + _gsskrb5_release_buffer(minor_status, output_message_buffer); + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + omret = _gssapi_msg_order_check(context_handle->order, seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (omret) + return omret; + + if (conf_state) + *conf_state = conf_flag; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +max_wrap_length_arcfour(const gsskrb5_ctx ctx, + krb5_crypto crypto, + size_t input_length, + OM_uint32 *max_input_size) +{ + /* + * if GSS_C_DCE_STYLE is in use: + * - we only need to encapsulate the WRAP token + * However, since this is a fixed since, we just + */ + if (IS_DCE_STYLE(ctx)) { + size_t len, total_len; + + len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + + if (input_length < len) + *max_input_size = 0; + else + *max_input_size = input_length - len; + + } else { + size_t extrasize = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + size_t blocksize = 8; + size_t len, total_len; + + len = 8 + input_length + blocksize + extrasize; + + _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + + total_len -= input_length; /* token length */ + if (total_len < input_length) { + *max_input_size = (input_length - total_len); + (*max_input_size) &= (~(OM_uint32)(blocksize - 1)); + } else { + *max_input_size = 0; + } + } + + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_wrap_size_arcfour(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size, + krb5_keyblock *key) +{ + krb5_error_code ret; + krb5_crypto crypto; + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret != 0) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = max_wrap_length_arcfour(ctx, crypto, + req_output_size, max_input_size); + if (ret != 0) { + *minor_status = ret; + krb5_crypto_destroy(context, crypto); + return GSS_S_FAILURE; + } + + krb5_crypto_destroy(context, crypto); + + 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; + } + } + + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + major_status = _gk_verify_buffers(minor_status, ctx, header, + padding, trailer, FALSE); + 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, FALSE); + 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_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_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_s(Klocaldata, sizeof(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, + FALSE); /* behaves as stream cipher */ + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + if (padding != NULL && padding->buffer.length != 1) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + verify_len = header->buffer.length; + + if (!IS_DCE_STYLE(ctx)) { + for (i = 0; i < iov_count; i++) { + /* length in header also includes data and padding */ + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) + verify_len += iov[i].buffer.length; + } + + if (padding) + verify_len += padding->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 = (ct_memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4) != 0); + } else { + cmp = (ct_memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4) != 0); + } + 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_s(Klocaldata, sizeof(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 = (ct_memcmp(cksum_data, p0 + 16, 8) != 0); /* SGN_CKSUM */ + if (cmp) { + *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/third_party/heimdal/lib/gssapi/krb5/authorize_localname.c b/third_party/heimdal/lib/gssapi/krb5/authorize_localname.c new file mode 100644 index 0000000..5621c1f --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/authorize_localname.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011, PADL Software Pty Ltd. + * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_authorize_localname(OM_uint32 *minor_status, + gss_const_name_t input_name, + gss_const_buffer_t user_name, + gss_const_OID user_name_type) +{ + krb5_context context; + krb5_principal princ = (krb5_principal)input_name; + char *user; + int user_ok; + + if (!gss_oid_equal(user_name_type, GSS_C_NT_USER_NAME)) + return GSS_S_BAD_NAMETYPE; + + GSSAPI_KRB5_INIT(&context); + + user = malloc(user_name->length + 1); + if (user == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy(user, user_name->value, user_name->length); + user[user_name->length] = '\0'; + + *minor_status = 0; + user_ok = krb5_kuserok(context, princ, user); + + free(user); + + return user_ok ? GSS_S_COMPLETE : GSS_S_UNAUTHORIZED; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/canonicalize_name.c b/third_party/heimdal/lib/gssapi/krb5/canonicalize_name.c new file mode 100644 index 0000000..62de423 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/canonicalize_name.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1997 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_canonicalize_name ( + OM_uint32 * minor_status, + gss_const_name_t input_name, + const gss_OID mech_type, + gss_name_t * output_name + ) +{ + krb5_context context; + krb5_principal name; + OM_uint32 ret; + + *output_name = NULL; + + GSSAPI_KRB5_INIT (&context); + + ret = _gsskrb5_canon_name(minor_status, context, input_name, &name); + if (ret) + return ret; + + *output_name = (gss_name_t)name; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/ccache_name.c b/third_party/heimdal/lib/gssapi/krb5/ccache_name.c new file mode 100644 index 0000000..0a2d596 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/ccache_name.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 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 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" + +static heim_base_atomic(char *) last_out_name; /* XXX should be thread-specific */ + +OM_uint32 +_gsskrb5_krb5_ccache_name(OM_uint32 *minor_status, + const char *name, + const char **out_name) +{ + krb5_context context; + krb5_error_code kret; + + *minor_status = 0; + + GSSAPI_KRB5_INIT(&context); + + if (out_name) { + const char *def_name; + + *out_name = NULL; + + def_name = krb5_cc_default_name(context); + if (def_name) { + char *s = strdup(def_name); + if (s) { + s = heim_base_exchange_pointer(&last_out_name, s); + free(s); + + *out_name = last_out_name; + } + } + + if (*out_name == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + } + + kret = krb5_cc_set_default_name(context, name); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/cfx.c b/third_party/heimdal/lib/gssapi/krb5/cfx.c new file mode 100644 index 0000000..8d806f9 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/cfx.c @@ -0,0 +1,1797 @@ +/* + * Copyright (c) 2003, PADL Software Pty Ltd. + * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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" + +/* + * Implementation of RFC 4121 + */ + +#define CFXSentByAcceptor (1 << 0) +#define CFXSealed (1 << 1) +#define CFXAcceptorSubkey (1 << 2) + +krb5_error_code +_gsskrb5cfx_wrap_length_cfx(krb5_context context, + krb5_crypto crypto, + int conf_req_flag, + int dce_style, + size_t input_length, + size_t *output_length, + size_t *cksumsize, + uint16_t *padlength) +{ + krb5_error_code ret; + krb5_cksumtype type; + + /* 16-byte header is always first */ + *output_length = sizeof(gss_cfx_wrap_token_desc); + *padlength = 0; + + ret = krb5_crypto_get_checksum_type(context, crypto, &type); + if (ret) + return ret; + + ret = krb5_checksumsize(context, type, cksumsize); + if (ret) + return ret; + + if (conf_req_flag) { + size_t padsize; + + /* Header is concatenated with data before encryption */ + input_length += sizeof(gss_cfx_wrap_token_desc); + + if (dce_style) { + ret = krb5_crypto_getblocksize(context, crypto, &padsize); + } else { + ret = krb5_crypto_getpadsize(context, crypto, &padsize); + } + if (ret) { + return ret; + } + if (padsize > 1) { + /* XXX check this */ + *padlength = padsize - (input_length % padsize); + + /* We add the pad ourselves (noted here for completeness only) */ + input_length += *padlength; + } + + *output_length += krb5_get_wrapped_length(context, + crypto, input_length); + } else { + /* Checksum is concatenated with data */ + *output_length += input_length + *cksumsize; + } + + assert(*output_length > input_length); + + return 0; +} + +OM_uint32 +_gssapi_wrap_size_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size) +{ + krb5_error_code ret; + + *max_input_size = 0; + + /* 16-byte header is always first */ + if (req_output_size < 16) + return 0; + req_output_size -= 16; + + if (conf_req_flag) { + size_t wrapped_size, sz; + + wrapped_size = req_output_size + 1; + do { + wrapped_size--; + sz = krb5_get_wrapped_length(context, + ctx->crypto, wrapped_size); + } while (wrapped_size && sz > req_output_size); + if (wrapped_size == 0) + return 0; + + /* inner header */ + if (wrapped_size < 16) + return 0; + + wrapped_size -= 16; + + *max_input_size = wrapped_size; + } else { + krb5_cksumtype type; + size_t cksumsize; + + ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &type); + if (ret) + return ret; + + ret = krb5_checksumsize(context, type, &cksumsize); + if (ret) + return ret; + + if (req_output_size < cksumsize) + return 0; + + /* Checksum is concatenated with data */ + *max_input_size = req_output_size - cksumsize; + } + + return 0; +} + +/* + * Rotate "rrc" bytes to the front or back + */ + +static krb5_error_code +rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate) +{ + u_char *tmp, buf[256]; + size_t left; + + if (len == 0) + return 0; + + rrc %= len; + + if (rrc == 0) + return 0; + + left = len - rrc; + + if (rrc <= sizeof(buf)) { + tmp = buf; + } else { + tmp = malloc(rrc); + if (tmp == NULL) + return ENOMEM; + } + + if (unrotate) { + memcpy(tmp, data, rrc); + memmove(data, (u_char *)data + rrc, left); + memcpy((u_char *)data + left, tmp, rrc); + } else { + memcpy(tmp, (u_char *)data + left, rrc); + memmove((u_char *)data + rrc, data, left); + memcpy(data, tmp, rrc); + } + + if (rrc > sizeof(buf)) + free(tmp); + + return 0; +} + +gss_iov_buffer_desc * +_gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type) +{ + int i; + gss_iov_buffer_t iovp = GSS_C_NO_IOV_BUFFER; + + if (iov == GSS_C_NO_IOV_BUFFER) + return GSS_C_NO_IOV_BUFFER; + + /* + * This function is used to find header, padding or trailer buffers + * which are singletons; return NULL if multiple instances are found. + */ + for (i = 0; i < iov_count; i++) { + if (type == GSS_IOV_BUFFER_TYPE(iov[i].type)) { + if (iovp == GSS_C_NO_IOV_BUFFER) + iovp = &iov[i]; + else + return GSS_C_NO_IOV_BUFFER; + } + } + + /* + * For compatibility with SSPI, an empty padding buffer is treated + * equivalent to an absent padding buffer (unless the caller is + * requesting that a padding buffer be allocated). + */ + if (iovp && + iovp->buffer.length == 0 && + type == GSS_IOV_BUFFER_TYPE_PADDING && + (GSS_IOV_BUFFER_FLAGS(iovp->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) == 0) + iovp = NULL; + + return iovp; +} + +OM_uint32 +_gk_allocate_buffer(OM_uint32 *minor_status, gss_iov_buffer_desc *buffer, size_t size) +{ + if (buffer->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) { + if (buffer->buffer.length == size) + return GSS_S_COMPLETE; + free(buffer->buffer.value); + } + + buffer->buffer.value = malloc(size); + buffer->buffer.length = size; + if (buffer->buffer.value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + buffer->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED; + + return GSS_S_COMPLETE; +} + + +OM_uint32 +_gk_verify_buffers(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + const gss_iov_buffer_desc *header, + const gss_iov_buffer_desc *padding, + const gss_iov_buffer_desc *trailer, + int block_cipher) +{ + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (IS_DCE_STYLE(ctx)) { + /* + * In DCE style mode we reject having a padding or trailer buffer + */ + if (padding) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + if (trailer) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } else { + /* + * In non-DCE style mode we require having a padding buffer for + * encryption types that do not behave as stream ciphers. This + * check is superfluous for now, as only RC4 and RFC4121 enctypes + * are presently implemented for the IOV APIs; be defensive. + */ + if (block_cipher && padding == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_wrap_cfx_iov(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) +{ + OM_uint32 major_status, junk; + gss_iov_buffer_desc *header, *trailer, *padding; + size_t gsshsize, k5hsize; + size_t gsstsize, k5tsize; + size_t rrc = 0, ec = 0; + int i; + gss_cfx_wrap_token token; + krb5_error_code ret; + int32_t seq_number; + unsigned usage; + krb5_crypto_iov *data = NULL; + + header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + if (padding != NULL) { + padding->buffer.length = 0; + } + + trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + major_status = _gk_verify_buffers(minor_status, ctx, header, + padding, trailer, FALSE); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + if (conf_req_flag) { + size_t k5psize = 0; + size_t k5pbase = 0; + size_t k5bsize = 0; + size_t size = 0; + + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + size += iov[i].buffer.length; + break; + default: + break; + } + } + + size += sizeof(gss_cfx_wrap_token_desc); + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_HEADER, + &k5hsize); + if (*minor_status) + return GSS_S_FAILURE; + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_TRAILER, + &k5tsize); + if (*minor_status) + return GSS_S_FAILURE; + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_PADDING, + &k5pbase); + if (*minor_status) + return GSS_S_FAILURE; + + if (k5pbase > 1) { + k5psize = k5pbase - (size % k5pbase); + } else { + k5psize = 0; + } + + if (k5psize == 0 && IS_DCE_STYLE(ctx)) { + *minor_status = krb5_crypto_getblocksize(context, ctx->crypto, + &k5bsize); + if (*minor_status) + return GSS_S_FAILURE; + ec = k5bsize; + } else { + ec = k5psize; + } + + gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize; + gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize; + } else { + if (IS_DCE_STYLE(ctx)) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + k5hsize = 0; + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_CHECKSUM, + &k5tsize); + if (*minor_status) + return GSS_S_FAILURE; + + gsshsize = sizeof(gss_cfx_wrap_token_desc); + gsstsize = k5tsize; + } + + /* + * + */ + + if (trailer == NULL) { + rrc = gsstsize; + if (IS_DCE_STYLE(ctx)) + rrc -= ec; + gsshsize += gsstsize; + } 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) + goto failure; + } else if (trailer->buffer.length < gsstsize) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else + trailer->buffer.length = gsstsize; + + /* + * + */ + + if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) { + major_status = _gk_allocate_buffer(minor_status, header, gsshsize); + if (major_status != GSS_S_COMPLETE) + goto failure; + } else if (header->buffer.length < gsshsize) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else + header->buffer.length = gsshsize; + + token = (gss_cfx_wrap_token)header->buffer.value; + + token->TOK_ID[0] = 0x05; + token->TOK_ID[1] = 0x04; + token->Flags = 0; + token->Filler = 0xFF; + + if ((ctx->more_flags & LOCAL) == 0) + token->Flags |= CFXSentByAcceptor; + + if (ctx->more_flags & ACCEPTOR_SUBKEY) + token->Flags |= CFXAcceptorSubkey; + + if (ctx->more_flags & LOCAL) + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + else + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + + if (conf_req_flag) { + /* + * In Wrap tokens with confidentiality, the EC field is + * used to encode the size (in bytes) of the random filler. + */ + token->Flags |= CFXSealed; + token->EC[0] = (ec >> 8) & 0xFF; + token->EC[1] = (ec >> 0) & 0xFF; + + } else { + /* + * In Wrap tokens without confidentiality, the EC field is + * used to encode the size (in bytes) of the trailing + * checksum. + * + * This is not used in the checksum calcuation itself, + * because the checksum length could potentially vary + * depending on the data length. + */ + token->EC[0] = 0; + token->EC[1] = 0; + } + + /* + * In Wrap tokens that provide for confidentiality, the RRC + * field in the header contains the hex value 00 00 before + * encryption. + * + * In Wrap tokens that do not provide for confidentiality, + * both the EC and RRC fields in the appended checksum + * contain the hex value 00 00 for the purpose of calculating + * the checksum. + */ + token->RRC[0] = 0; + token->RRC[1] = 0; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &seq_number); + _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); + _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + data = calloc(iov_count + 3, sizeof(data[0])); + if (data == NULL) { + *minor_status = ENOMEM; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (conf_req_flag) { + /* + plain packet: + + {"header" | encrypt(plaintext-data | ec-padding | E"header")} + + Expanded, this is with with RRC = 0: + + {"header" | krb5-header | plaintext-data | ec-padding | E"header" | krb5-trailer } + + In DCE-RPC mode == no trailer: RRC = gss "trailer" == length(ec-padding | E"header" | krb5-trailer) + + {"header" | ec-padding | E"header" | krb5-trailer | krb5-header | plaintext-data } + */ + + i = 0; + data[i].flags = KRB5_CRYPTO_TYPE_HEADER; + data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize; + data[i].data.length = k5hsize; + + for (i = 1; i < iov_count + 1; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[i - 1].buffer.length; + data[i].data.data = iov[i - 1].buffer.value; + } + + /* + * Any necessary padding is added here to ensure that the + * encrypted token header is always at the end of the + * ciphertext. + */ + + /* encrypted CFX header in trailer (or after the header if in + DCE mode). Copy in header into E"header" + */ + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + if (trailer) + data[i].data.data = trailer->buffer.value; + else + data[i].data.data = ((uint8_t *)header->buffer.value) + sizeof(*token); + + data[i].data.length = ec + sizeof(*token); + memset(data[i].data.data, 0xFF, ec); + memcpy(((uint8_t *)data[i].data.data) + ec, token, sizeof(*token)); + i++; + + /* Kerberos trailer comes after the gss trailer */ + data[i].flags = KRB5_CRYPTO_TYPE_TRAILER; + data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token); + data[i].data.length = k5tsize; + i++; + + ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL); + if (ret != 0) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (rrc) { + token->RRC[0] = (rrc >> 8) & 0xFF; + token->RRC[1] = (rrc >> 0) & 0xFF; + } + + } else { + /* + plain packet: + + {data | "header" | gss-trailer (krb5 checksum) + + don't do RRC != 0 + + */ + + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[i].buffer.length; + data[i].data.data = iov[i].buffer.value; + } + + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + data[i].data.data = header->buffer.value; + data[i].data.length = sizeof(gss_cfx_wrap_token_desc); + i++; + + data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + if (trailer) { + data[i].data.data = trailer->buffer.value; + } else { + data[i].data.data = (uint8_t *)header->buffer.value + + sizeof(gss_cfx_wrap_token_desc); + } + data[i].data.length = k5tsize; + i++; + + ret = krb5_create_checksum_iov(context, ctx->crypto, usage, data, i, NULL); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (rrc) { + token->RRC[0] = (rrc >> 8) & 0xFF; + token->RRC[1] = (rrc >> 0) & 0xFF; + } + + token->EC[0] = (k5tsize >> 8) & 0xFF; + token->EC[1] = (k5tsize >> 0) & 0xFF; + } + + if (conf_state != NULL) + *conf_state = conf_req_flag; + + free(data); + + *minor_status = 0; + return GSS_S_COMPLETE; + + failure: + if (data) + free(data); + + gss_release_iov_buffer(&junk, iov, iov_count); + + return major_status; +} + +/* This is slowpath */ +static OM_uint32 +unrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int iov_count) +{ + uint8_t *p, *q; + size_t len = 0, skip; + int i; + + for (i = 0; i < iov_count; i++) + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) + len += iov[i].buffer.length; + + p = malloc(len); + if (p == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + q = p; + + /* copy up */ + + for (i = 0; i < iov_count; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + 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, iov[i].buffer.length); + q += iov[i].buffer.length; + } + } + assert((size_t)(q - p) == len); + + /* unrotate first part */ + q = p + rrc; + skip = rrc; + for (i = 0; i < iov_count; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) + { + 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; + } + } + } + /* copy trailer */ + q = p; + skip = rrc; + for (i = 0; i < iov_count; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + 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(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; +} + + +OM_uint32 +_gssapi_unwrap_cfx_iov(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 seq_number_lo, seq_number_hi, major_status, junk; + gss_iov_buffer_desc *header, *trailer, *padding; + gss_cfx_wrap_token token, ttoken; + u_char token_flags; + krb5_error_code ret; + unsigned usage; + uint16_t ec, rrc; + krb5_crypto_iov *data = NULL; + int i, j; + + *minor_status = 0; + + header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (header->buffer.length < sizeof(*token)) /* we check exact below */ + return GSS_S_DEFECTIVE_TOKEN; + + padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + if (padding != NULL && padding->buffer.length != 0) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + major_status = _gk_verify_buffers(minor_status, ctx, header, + padding, trailer, FALSE); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + token = (gss_cfx_wrap_token)header->buffer.value; + + if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) + return GSS_S_DEFECTIVE_TOKEN; + + /* Ignore unknown flags */ + token_flags = token->Flags & + (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey); + + if (token_flags & CFXSentByAcceptor) { + if ((ctx->more_flags & LOCAL) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (ctx->more_flags & ACCEPTOR_SUBKEY) { + if ((token_flags & CFXAcceptorSubkey) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } else { + if (token_flags & CFXAcceptorSubkey) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (token->Filler != 0xFF) + return GSS_S_DEFECTIVE_TOKEN; + + if (conf_state != NULL) + *conf_state = (token_flags & CFXSealed) ? 1 : 0; + + ec = (token->EC[0] << 8) | token->EC[1]; + rrc = (token->RRC[0] << 8) | token->RRC[1]; + + /* + * Check sequence number + */ + _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); + _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); + if (seq_number_hi) { + /* no support for 64-bit sequence numbers */ + *minor_status = ERANGE; + return GSS_S_UNSEQ_TOKEN; + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); + if (ret != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; + } + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* + * Decrypt and/or verify checksum + */ + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + } else { + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + } + + data = calloc(iov_count + 3, sizeof(data[0])); + if (data == NULL) { + *minor_status = ENOMEM; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (token_flags & CFXSealed) { + size_t k5tsize, k5hsize; + + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize); + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5tsize); + + /* Rotate by RRC; bogus to do this in-place XXX */ + /* Check RRC */ + + if (trailer == NULL) { + size_t gsstsize = k5tsize + sizeof(*token); + size_t gsshsize = k5hsize + sizeof(*token); + + if (rrc != gsstsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + + if (IS_DCE_STYLE(ctx)) + gsstsize += ec; + + gsshsize += gsstsize; + + if (header->buffer.length != gsshsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + } else if (trailer->buffer.length != sizeof(*token) + k5tsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } else if (header->buffer.length != sizeof(*token) + k5hsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } else if (rrc != 0) { + /* go though slowpath */ + major_status = unrotate_iov(minor_status, rrc, iov, iov_count); + if (major_status) + goto failure; + } + + i = 0; + data[i].flags = KRB5_CRYPTO_TYPE_HEADER; + data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize; + data[i].data.length = k5hsize; + i++; + + for (j = 0; j < iov_count; i++, j++) { + switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[j].buffer.length; + data[i].data.data = iov[j].buffer.value; + } + + /* encrypted CFX header in trailer (or after the header if in + DCE mode). Copy in header into E"header" + */ + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + if (trailer) { + data[i].data.data = trailer->buffer.value; + } else { + data[i].data.data = ((uint8_t *)header->buffer.value) + + header->buffer.length - k5hsize - k5tsize - ec- sizeof(*token); + } + + data[i].data.length = ec + sizeof(*token); + ttoken = (gss_cfx_wrap_token)(((uint8_t *)data[i].data.data) + ec); + i++; + + /* Kerberos trailer comes after the gss trailer */ + data[i].flags = KRB5_CRYPTO_TYPE_TRAILER; + data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token); + data[i].data.length = k5tsize; + i++; + + ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL); + if (ret != 0) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + + ttoken->RRC[0] = token->RRC[0]; + ttoken->RRC[1] = token->RRC[1]; + + /* Check the integrity of the header */ + if (ct_memcmp(ttoken, token, sizeof(*token)) != 0) { + major_status = GSS_S_BAD_MIC; + goto failure; + } + } else { + size_t gsstsize = ec; + size_t gsshsize = sizeof(*token); + + if (trailer == NULL) { + /* Check RRC */ + if (rrc != gsstsize) { + *minor_status = EINVAL; + major_status = GSS_S_FAILURE; + goto failure; + } + + gsshsize += gsstsize; + } else if (trailer->buffer.length != gsstsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } else if (rrc != 0) { + /* Check RRC */ + *minor_status = EINVAL; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (header->buffer.length != gsshsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[i].buffer.length; + data[i].data.data = iov[i].buffer.value; + } + + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + data[i].data.data = header->buffer.value; + data[i].data.length = sizeof(*token); + i++; + + data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + if (trailer) { + data[i].data.data = trailer->buffer.value; + } else { + data[i].data.data = (uint8_t *)header->buffer.value + + sizeof(*token); + } + data[i].data.length = ec; + i++; + + token = (gss_cfx_wrap_token)header->buffer.value; + token->EC[0] = 0; + token->EC[1] = 0; + token->RRC[0] = 0; + token->RRC[1] = 0; + + ret = krb5_verify_checksum_iov(context, ctx->crypto, usage, data, i, NULL); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + } + + if (qop_state != NULL) { + *qop_state = GSS_C_QOP_DEFAULT; + } + + free(data); + + *minor_status = 0; + return GSS_S_COMPLETE; + + failure: + if (data) + free(data); + + gss_release_iov_buffer(&junk, iov, iov_count); + + return major_status; +} + +OM_uint32 +_gssapi_wrap_iov_length_cfx(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 size; + int i; + gss_iov_buffer_desc *header = NULL; + gss_iov_buffer_desc *padding = NULL; + gss_iov_buffer_desc *trailer = NULL; + size_t gsshsize = 0; + size_t gsstsize = 0; + size_t k5hsize = 0; + size_t k5tsize = 0; + + GSSAPI_KRB5_INIT (&context); + *minor_status = 0; + + for (size = 0, 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: + size += iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_HEADER: + if (header != NULL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + header = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_TRAILER: + if (trailer != NULL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + trailer = &iov[i]; + break; + case GSS_IOV_BUFFER_TYPE_PADDING: + if (padding != NULL) { + *minor_status = 0; + 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, FALSE); + if (major_status != GSS_S_COMPLETE) { + return major_status; + } + + if (conf_req_flag) { + size_t k5psize = 0; + size_t k5pbase = 0; + size_t k5bsize = 0; + size_t ec = 0; + + size += sizeof(gss_cfx_wrap_token_desc); + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_HEADER, + &k5hsize); + if (*minor_status) + return GSS_S_FAILURE; + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_TRAILER, + &k5tsize); + if (*minor_status) + return GSS_S_FAILURE; + + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_PADDING, + &k5pbase); + if (*minor_status) + return GSS_S_FAILURE; + + if (k5pbase > 1) { + k5psize = k5pbase - (size % k5pbase); + } else { + k5psize = 0; + } + + if (k5psize == 0 && IS_DCE_STYLE(ctx)) { + *minor_status = krb5_crypto_getblocksize(context, ctx->crypto, + &k5bsize); + if (*minor_status) + return GSS_S_FAILURE; + + ec = k5bsize; + } else { + ec = k5psize; + } + + gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize; + gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize; + } else { + *minor_status = krb5_crypto_length(context, ctx->crypto, + KRB5_CRYPTO_TYPE_CHECKSUM, + &k5tsize); + if (*minor_status) + return GSS_S_FAILURE; + + gsshsize = sizeof(gss_cfx_wrap_token_desc); + gsstsize = k5tsize; + } + + if (trailer != NULL) { + trailer->buffer.length = gsstsize; + } else { + gsshsize += gsstsize; + } + + header->buffer.length = gsshsize; + + if (padding) { + /* padding is done via EC and is contained in the header or trailer */ + padding->buffer.length = 0; + } + + if (conf_state) { + *conf_state = conf_req_flag; + } + + return GSS_S_COMPLETE; +} + + + + +OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + const gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) +{ + gss_cfx_wrap_token token; + krb5_error_code ret; + unsigned usage; + krb5_data cipher; + size_t wrapped_len, cksumsize; + uint16_t padlength, rrc = 0; + int32_t seq_number; + u_char *p; + + ret = _gsskrb5cfx_wrap_length_cfx(context, + ctx->crypto, conf_req_flag, + IS_DCE_STYLE(ctx), + input_message_buffer->length, + &wrapped_len, &cksumsize, &padlength); + if (ret != 0) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* Always rotate encrypted token (if any) and checksum to header */ + rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize; + + output_message_buffer->length = wrapped_len; + output_message_buffer->value = malloc(output_message_buffer->length); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = output_message_buffer->value; + token = (gss_cfx_wrap_token)p; + token->TOK_ID[0] = 0x05; + token->TOK_ID[1] = 0x04; + token->Flags = 0; + token->Filler = 0xFF; + if ((ctx->more_flags & LOCAL) == 0) + token->Flags |= CFXSentByAcceptor; + if (ctx->more_flags & ACCEPTOR_SUBKEY) + token->Flags |= CFXAcceptorSubkey; + if (conf_req_flag) { + /* + * In Wrap tokens with confidentiality, the EC field is + * used to encode the size (in bytes) of the random filler. + */ + token->Flags |= CFXSealed; + token->EC[0] = (padlength >> 8) & 0xFF; + token->EC[1] = (padlength >> 0) & 0xFF; + } else { + /* + * In Wrap tokens without confidentiality, the EC field is + * used to encode the size (in bytes) of the trailing + * checksum. + * + * This is not used in the checksum calcuation itself, + * because the checksum length could potentially vary + * depending on the data length. + */ + token->EC[0] = 0; + token->EC[1] = 0; + } + + /* + * In Wrap tokens that provide for confidentiality, the RRC + * field in the header contains the hex value 00 00 before + * encryption. + * + * In Wrap tokens that do not provide for confidentiality, + * both the EC and RRC fields in the appended checksum + * contain the hex value 00 00 for the purpose of calculating + * the checksum. + */ + token->RRC[0] = 0; + token->RRC[1] = 0; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &seq_number); + _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); + _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* + * If confidentiality is requested, the token header is + * appended to the plaintext before encryption; the resulting + * token is {"header" | encrypt(plaintext | pad | "header")}. + * + * If no confidentiality is requested, the checksum is + * calculated over the plaintext concatenated with the + * token header. + */ + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + } else { + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + } + + if (conf_req_flag) { + /* + * Any necessary padding is added here to ensure that the + * encrypted token header is always at the end of the + * ciphertext. + * + * The specification does not require that the padding + * bytes are initialized. + */ + p += sizeof(*token); + memcpy(p, input_message_buffer->value, input_message_buffer->length); + memset(p + input_message_buffer->length, 0xFF, padlength); + memcpy(p + input_message_buffer->length + padlength, + token, sizeof(*token)); + + ret = krb5_encrypt(context, ctx->crypto, + usage, p, + input_message_buffer->length + padlength + + sizeof(*token), + &cipher); + if (ret != 0) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + assert(sizeof(*token) + cipher.length == wrapped_len); + token->RRC[0] = (rrc >> 8) & 0xFF; + token->RRC[1] = (rrc >> 0) & 0xFF; + + /* + * this is really ugly, but needed against windows + * for DCERPC, as windows rotates by EC+RRC. + */ + if (IS_DCE_STYLE(ctx)) { + ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE); + } else { + ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE); + } + if (ret != 0) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + memcpy(p, cipher.data, cipher.length); + krb5_data_free(&cipher); + } else { + char *buf; + Checksum cksum; + + buf = malloc(input_message_buffer->length + sizeof(*token)); + if (buf == NULL) { + *minor_status = ENOMEM; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + memcpy(buf, input_message_buffer->value, input_message_buffer->length); + memcpy(buf + input_message_buffer->length, token, sizeof(*token)); + + ret = krb5_create_checksum(context, ctx->crypto, + usage, 0, buf, + input_message_buffer->length + + sizeof(*token), + &cksum); + if (ret != 0) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + free(buf); + return GSS_S_FAILURE; + } + + free(buf); + + assert(cksum.checksum.length == cksumsize); + token->EC[0] = (cksum.checksum.length >> 8) & 0xFF; + token->EC[1] = (cksum.checksum.length >> 0) & 0xFF; + token->RRC[0] = (rrc >> 8) & 0xFF; + token->RRC[1] = (rrc >> 0) & 0xFF; + + p += sizeof(*token); + memcpy(p, input_message_buffer->value, input_message_buffer->length); + memcpy(p + input_message_buffer->length, + cksum.checksum.data, cksum.checksum.length); + + ret = rrc_rotate(p, + input_message_buffer->length + cksum.checksum.length, rrc, FALSE); + if (ret != 0) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + free_Checksum(&cksum); + return GSS_S_FAILURE; + } + free_Checksum(&cksum); + } + + if (conf_state != NULL) { + *conf_state = conf_req_flag; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state) +{ + gss_cfx_wrap_token token; + u_char token_flags; + krb5_error_code ret; + unsigned usage; + krb5_data data; + uint16_t ec, rrc; + OM_uint32 seq_number_lo, seq_number_hi; + size_t len; + u_char *p; + + *minor_status = 0; + + if (input_message_buffer->length < sizeof(*token)) { + return GSS_S_DEFECTIVE_TOKEN; + } + + p = input_message_buffer->value; + + token = (gss_cfx_wrap_token)p; + + if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) { + return GSS_S_DEFECTIVE_TOKEN; + } + + /* Ignore unknown flags */ + token_flags = token->Flags & + (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey); + + if (token_flags & CFXSentByAcceptor) { + if ((ctx->more_flags & LOCAL) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (ctx->more_flags & ACCEPTOR_SUBKEY) { + if ((token_flags & CFXAcceptorSubkey) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } else { + if (token_flags & CFXAcceptorSubkey) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (token->Filler != 0xFF) { + return GSS_S_DEFECTIVE_TOKEN; + } + + if (conf_state != NULL) { + *conf_state = (token_flags & CFXSealed) ? 1 : 0; + } + + ec = (token->EC[0] << 8) | token->EC[1]; + rrc = (token->RRC[0] << 8) | token->RRC[1]; + + /* + * Check sequence number + */ + _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); + _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); + if (seq_number_hi) { + /* no support for 64-bit sequence numbers */ + *minor_status = ERANGE; + return GSS_S_UNSEQ_TOKEN; + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); + if (ret != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return ret; + } + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* + * Decrypt and/or verify checksum + */ + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + } else { + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + } + + p += sizeof(*token); + len = input_message_buffer->length; + len -= (p - (u_char *)input_message_buffer->value); + + if (token_flags & CFXSealed) { + /* + * this is really ugly, but needed against windows + * for DCERPC, as windows rotates by EC+RRC. + */ + if (IS_DCE_STYLE(ctx)) { + *minor_status = rrc_rotate(p, len, rrc+ec, TRUE); + } else { + *minor_status = rrc_rotate(p, len, rrc, TRUE); + } + if (*minor_status != 0) { + return GSS_S_FAILURE; + } + + ret = krb5_decrypt(context, ctx->crypto, usage, + p, len, &data); + if (ret != 0) { + *minor_status = ret; + return GSS_S_BAD_MIC; + } + + /* Check that there is room for the pad and token header */ + if (data.length < ec + sizeof(*token)) { + krb5_data_free(&data); + return GSS_S_DEFECTIVE_TOKEN; + } + p = data.data; + p += data.length - sizeof(*token); + + /* RRC is unprotected; don't modify input buffer */ + ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0]; + ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1]; + + /* Check the integrity of the header */ + if (ct_memcmp(p, token, sizeof(*token)) != 0) { + krb5_data_free(&data); + return GSS_S_BAD_MIC; + } + + output_message_buffer->value = data.data; + output_message_buffer->length = data.length - ec - sizeof(*token); + } else { + Checksum cksum; + + /* Rotate by RRC; bogus to do this in-place XXX */ + *minor_status = rrc_rotate(p, len, rrc, TRUE); + if (*minor_status != 0) { + return GSS_S_FAILURE; + } + + /* Determine checksum type */ + ret = krb5_crypto_get_checksum_type(context, + ctx->crypto, + &cksum.cksumtype); + if (ret != 0) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + cksum.checksum.length = ec; + + /* Check we have at least as much data as the checksum */ + if (len < cksum.checksum.length) { + *minor_status = ERANGE; + return GSS_S_BAD_MIC; + } + + /* Length now is of the plaintext only, no checksum */ + len -= cksum.checksum.length; + cksum.checksum.data = p + len; + + output_message_buffer->length = len; /* for later */ + output_message_buffer->value = malloc(len + sizeof(*token)); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + /* Checksum is over (plaintext-data | "header") */ + memcpy(output_message_buffer->value, p, len); + memcpy((u_char *)output_message_buffer->value + len, + token, sizeof(*token)); + + /* EC is not included in checksum calculation */ + token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value + + len); + token->EC[0] = 0; + token->EC[1] = 0; + token->RRC[0] = 0; + token->RRC[1] = 0; + + ret = krb5_verify_checksum(context, ctx->crypto, + usage, + output_message_buffer->value, + len + sizeof(*token), + &cksum); + if (ret != 0) { + *minor_status = ret; + _gsskrb5_release_buffer(minor_status, output_message_buffer); + return GSS_S_BAD_MIC; + } + } + + if (qop_state != NULL) { + *qop_state = GSS_C_QOP_DEFAULT; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token) +{ + gss_cfx_mic_token token; + krb5_error_code ret; + unsigned usage; + Checksum cksum; + u_char *buf; + size_t len; + int32_t seq_number; + + len = message_buffer->length + sizeof(*token); + buf = malloc(len); + if (buf == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy(buf, message_buffer->value, message_buffer->length); + + token = (gss_cfx_mic_token)(buf + message_buffer->length); + token->TOK_ID[0] = 0x04; + token->TOK_ID[1] = 0x04; + token->Flags = 0; + if ((ctx->more_flags & LOCAL) == 0) + token->Flags |= CFXSentByAcceptor; + if (ctx->more_flags & ACCEPTOR_SUBKEY) + token->Flags |= CFXAcceptorSubkey; + memset(token->Filler, 0xFF, 5); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &seq_number); + _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); + _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_INITIATOR_SIGN; + } else { + usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; + } + + ret = krb5_create_checksum(context, ctx->crypto, + usage, 0, buf, len, &cksum); + if (ret != 0) { + *minor_status = ret; + free(buf); + return GSS_S_FAILURE; + } + + /* Determine MIC length */ + message_token->length = sizeof(*token) + cksum.checksum.length; + message_token->value = malloc(message_token->length); + if (message_token->value == NULL) { + *minor_status = ENOMEM; + free_Checksum(&cksum); + free(buf); + return GSS_S_FAILURE; + } + + /* Token is { "header" | get_mic("header" | plaintext-data) } */ + memcpy(message_token->value, token, sizeof(*token)); + memcpy((u_char *)message_token->value + sizeof(*token), + cksum.checksum.data, cksum.checksum.length); + + free_Checksum(&cksum); + free(buf); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t *qop_state) +{ + gss_cfx_mic_token token; + u_char token_flags; + krb5_error_code ret; + unsigned usage; + OM_uint32 seq_number_lo, seq_number_hi; + u_char *buf, *p; + Checksum cksum; + + *minor_status = 0; + + if (token_buffer->length < sizeof(*token)) { + return GSS_S_DEFECTIVE_TOKEN; + } + + p = token_buffer->value; + + token = (gss_cfx_mic_token)p; + + if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) { + return GSS_S_DEFECTIVE_TOKEN; + } + + /* Ignore unknown flags */ + token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey); + + if (token_flags & CFXSentByAcceptor) { + if ((ctx->more_flags & LOCAL) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } + if (ctx->more_flags & ACCEPTOR_SUBKEY) { + if ((token_flags & CFXAcceptorSubkey) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } else { + if (token_flags & CFXAcceptorSubkey) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (ct_memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) { + return GSS_S_DEFECTIVE_TOKEN; + } + + /* + * Check sequence number + */ + _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); + _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); + if (seq_number_hi) { + *minor_status = ERANGE; + return GSS_S_UNSEQ_TOKEN; + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); + if (ret != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; + } + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* + * Verify checksum + */ + ret = krb5_crypto_get_checksum_type(context, ctx->crypto, + &cksum.cksumtype); + if (ret != 0) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + cksum.checksum.data = p + sizeof(*token); + cksum.checksum.length = token_buffer->length - sizeof(*token); + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; + } else { + usage = KRB5_KU_USAGE_INITIATOR_SIGN; + } + + buf = malloc(message_buffer->length + sizeof(*token)); + if (buf == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(buf, message_buffer->value, message_buffer->length); + memcpy(buf + message_buffer->length, token, sizeof(*token)); + + ret = krb5_verify_checksum(context, ctx->crypto, + usage, + buf, + sizeof(*token) + message_buffer->length, + &cksum); + if (ret != 0) { + *minor_status = ret; + free(buf); + return GSS_S_BAD_MIC; + } + + free(buf); + + if (qop_state != NULL) { + *qop_state = GSS_C_QOP_DEFAULT; + } + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/cfx.h b/third_party/heimdal/lib/gssapi/krb5/cfx.h new file mode 100644 index 0000000..c30ed07 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/cfx.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2003, PADL Software Pty Ltd. + * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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. + */ + +/* $Id$ */ + +#ifndef GSSAPI_CFX_H_ +#define GSSAPI_CFX_H_ 1 + +/* + * Implementation of draft-ietf-krb-wg-gssapi-cfx-01.txt + */ + +typedef struct gss_cfx_mic_token_desc_struct { + u_char TOK_ID[2]; /* 04 04 */ + u_char Flags; + u_char Filler[5]; + u_char SND_SEQ[8]; +} gss_cfx_mic_token_desc, *gss_cfx_mic_token; + +typedef struct gss_cfx_wrap_token_desc_struct { + u_char TOK_ID[2]; /* 04 05 */ + u_char Flags; + u_char Filler; + u_char EC[2]; + u_char RRC[2]; + u_char SND_SEQ[8]; +} gss_cfx_wrap_token_desc, *gss_cfx_wrap_token; + +typedef struct gss_cfx_delete_token_desc_struct { + u_char TOK_ID[2]; /* 05 04 */ + u_char Flags; + u_char Filler[5]; + u_char SND_SEQ[8]; +} gss_cfx_delete_token_desc, *gss_cfx_delete_token; + +#endif /* GSSAPI_CFX_H_ */ diff --git a/third_party/heimdal/lib/gssapi/krb5/compare_name.c b/third_party/heimdal/lib/gssapi/krb5/compare_name.c new file mode 100644 index 0000000..4a37e87 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/compare_name.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1997-2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_compare_name + (OM_uint32 * minor_status, + gss_const_name_t name1, + gss_const_name_t name2, + int * name_equal + ) +{ + krb5_const_principal princ1 = (krb5_const_principal)name1; + krb5_const_principal princ2 = (krb5_const_principal)name2; + krb5_context context; + + GSSAPI_KRB5_INIT(&context); + + *name_equal = krb5_principal_compare (context, + princ1, princ2); + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/compat.c b/third_party/heimdal/lib/gssapi/krb5/compat.c new file mode 100644 index 0000000..3381dff --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/compat.c @@ -0,0 +1,125 @@ +/* + * 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 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" + +static krb5_error_code +check_compat(OM_uint32 *minor_status, + krb5_context context, krb5_const_principal name, + const char *option, krb5_boolean *compat, + krb5_boolean match_val) +{ + krb5_error_code ret = 0; + char **p, **q; + krb5_principal match; + + + p = krb5_config_get_strings(context, NULL, "gssapi", + option, NULL); + if(p == NULL) + return 0; + + match = NULL; + for(q = p; *q; q++) { + ret = krb5_parse_name(context, *q, &match); + if (ret) + break; + + if (krb5_principal_match(context, name, match)) { + *compat = match_val; + break; + } + + krb5_free_principal(context, match); + match = NULL; + } + if (match) + krb5_free_principal(context, match); + krb5_config_free_strings(p); + + if (ret) { + if (minor_status) + *minor_status = ret; + return GSS_S_FAILURE; + } + + return 0; +} + +/* + * ctx->ctx_id_mutex is assumed to be locked + */ + +OM_uint32 +_gss_DES3_get_mic_compat(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context) +{ + krb5_boolean use_compat = FALSE; + OM_uint32 ret; + + if ((ctx->more_flags & COMPAT_OLD_DES3_SELECTED) == 0) { + ret = check_compat(minor_status, context, ctx->target, + "broken_des3_mic", &use_compat, TRUE); + if (ret) + return ret; + ret = check_compat(minor_status, context, ctx->target, + "correct_des3_mic", &use_compat, FALSE); + if (ret) + return ret; + + if (use_compat) + ctx->more_flags |= COMPAT_OLD_DES3; + ctx->more_flags |= COMPAT_OLD_DES3_SELECTED; + } + return 0; +} + +#if 0 +OM_uint32 +gss_krb5_compat_des3_mic(OM_uint32 *minor_status, gss_ctx_id_t ctx, int on) +{ + *minor_status = 0; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + if (on) { + ctx->more_flags |= COMPAT_OLD_DES3; + } else { + ctx->more_flags &= ~COMPAT_OLD_DES3; + } + ctx->more_flags |= COMPAT_OLD_DES3_SELECTED; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + return 0; +} +#endif diff --git a/third_party/heimdal/lib/gssapi/krb5/context_time.c b/third_party/heimdal/lib/gssapi/krb5/context_time.c new file mode 100644 index 0000000..58249cb --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/context_time.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1997 - 2003 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" + +OM_uint32 +_gsskrb5_lifetime_left(OM_uint32 *minor_status, + krb5_context context, + OM_uint32 endtime, + OM_uint32 *lifetime_rec) +{ + krb5_timestamp now; + krb5_error_code kret; + + if (endtime == 0) { + *lifetime_rec = GSS_C_INDEFINITE; + return GSS_S_COMPLETE; + } + + kret = krb5_timeofday(context, &now); + if (kret) { + *lifetime_rec = 0; + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (endtime < now) + *lifetime_rec = 0; + else + *lifetime_rec = endtime - now; + + return GSS_S_COMPLETE; +} + + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_context_time + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + OM_uint32 * time_rec + ) +{ + krb5_context context; + 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); + endtime = ctx->endtime; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + major_status = _gsskrb5_lifetime_left(minor_status, context, + endtime, time_rec); + if (major_status != GSS_S_COMPLETE) + return major_status; + + *minor_status = 0; + + if (*time_rec == 0) + return GSS_S_CONTEXT_EXPIRED; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/copy_ccache.c b/third_party/heimdal/lib/gssapi/krb5/copy_ccache.c new file mode 100644 index 0000000..fc0b9b1 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/copy_ccache.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2000 - 2001, 2003 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" + +#if 0 +OM_uint32 +gss_krb5_copy_ccache(OM_uint32 *minor_status, + krb5_context context, + gss_cred_id_t cred, + krb5_ccache out) +{ + krb5_error_code kret; + + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + if (cred->ccache == NULL) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + kret = krb5_cc_copy_cache(context, cred->ccache, out); + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + *minor_status = 0; + return GSS_S_COMPLETE; +} +#endif + + +/* + * WARNING: Takes ownership of `id'. Because MEMORY:anonymous is now not + * linked into to the MEMORY ccache namespace, we can't use krb5_cc_resolve() + * with the cache's name anymore. We need a krb5_cc_clone() or some such, with + * attendant new method for ccops. Or we could create a new MEMORY:anonymous + * ccache and copy all the creds from `id' into it. But we know callers of + * this function don't need `id' after calling it, so for now we'll just take + * ownershipd of it. + */ +OM_uint32 +_gsskrb5_krb5_import_cred(OM_uint32 *minor_status, + krb5_ccache *id, + krb5_principal keytab_principal, + krb5_keytab keytab, + gss_cred_id_t *cred) +{ + krb5_context context; + krb5_error_code kret; + gsskrb5_cred handle; + OM_uint32 ret; + int id_given = (*id != NULL); + + *cred = NULL; + + GSSAPI_KRB5_INIT (&context); + + handle = calloc(1, sizeof(*handle)); + if (handle == NULL) { + _gsskrb5_clear_status (); + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + HEIMDAL_MUTEX_init(&handle->cred_id_mutex); + + handle->usage = 0; + handle->destination_realm = NULL; + + if (*id) { + time_t now; + OM_uint32 left; + + handle->usage |= GSS_C_INITIATE; + + kret = krb5_cc_get_principal(context, *id, + &handle->principal); + if (kret) { + free(handle); + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (keytab_principal) { + krb5_boolean match; + + match = krb5_principal_compare(context, + handle->principal, + keytab_principal); + if (match == FALSE) { + krb5_free_principal(context, handle->principal); + free(handle); + _gsskrb5_clear_status (); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + + krb5_timeofday(context, &now); + ret = __gsskrb5_ccache_lifetime(minor_status, + context, + *id, + handle->principal, + &left); + if (ret != GSS_S_COMPLETE) { + krb5_free_principal(context, handle->principal); + free(handle); + return ret; + } + handle->endtime = now + left; + + handle->ccache = *id; + *id = NULL; + } + + + if (keytab) { + char *str; + + handle->usage |= GSS_C_ACCEPT; + + if (keytab_principal && handle->principal == NULL) { + kret = krb5_copy_principal(context, + keytab_principal, + &handle->principal); + if (kret) + goto out; + } + + kret = krb5_kt_get_full_name(context, keytab, &str); + if (kret) + goto out; + + kret = krb5_kt_resolve(context, str, &handle->keytab); + free(str); + if (kret) + goto out; + } + + + if (id_given || keytab) { + ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); + if (ret == GSS_S_COMPLETE) + ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &handle->mechanisms); + if (ret != GSS_S_COMPLETE) { + kret = *minor_status; + goto out; + } + } + + *minor_status = 0; + *cred = (gss_cred_id_t)handle; + return GSS_S_COMPLETE; + +out: + gss_release_oid_set(minor_status, &handle->mechanisms); + if (handle->ccache) + krb5_cc_close(context, handle->ccache); + if (handle->keytab) + krb5_kt_close(context, handle->keytab); + if (handle->principal) + krb5_free_principal(context, handle->principal); + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + free(handle); + *minor_status = kret; + return GSS_S_FAILURE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/creds.c b/third_party/heimdal/lib/gssapi/krb5/creds.c new file mode 100644 index 0000000..efb0a23 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/creds.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2009 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" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_export_cred(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + gss_buffer_t cred_token) +{ + OM_uint32 major_status; + gsskrb5_cred handle = (gsskrb5_cred)cred_handle; + krb5_context context; + krb5_error_code ret; + krb5_storage *sp; + krb5_data data; + const char *type; + char *str; + + GSSAPI_KRB5_INIT (&context); + + if (handle->usage != GSS_C_INITIATE && handle->usage != GSS_C_BOTH) { + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_FAILURE; + } + + sp = krb5_storage_emem(); + if (sp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + 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); + *minor_status = ret; + return GSS_S_FAILURE; + } + + 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; + return GSS_S_FAILURE; + } + + ret = krb5_store_creds(sp, creds); + krb5_free_creds(context, creds); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + + } else { + ret = krb5_store_uint32(sp, 1); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_cc_get_full_name(context, handle->ccache, &str); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_store_string(sp, str); + free(str); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + } + ret = krb5_storage_to_data(sp, &data); + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + sp = krb5_storage_emem(); + if (sp == NULL) { + krb5_data_free(&data); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + major_status = _gss_mg_store_oid(minor_status, sp, GSS_KRB5_MECHANISM); + if (major_status != GSS_S_COMPLETE) { + krb5_data_free(&data); + krb5_storage_free(sp); + return major_status; + } + + ret = krb5_store_data(sp, data); + krb5_data_free(&data); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_storage_to_data(sp, &data); + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + cred_token->value = data.data; + cred_token->length = data.length; + + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_import_cred(OM_uint32 * minor_status, + gss_buffer_t cred_token, + gss_cred_id_t * cred_handle) +{ + krb5_context context; + krb5_error_code ret; + gsskrb5_cred handle; + krb5_ccache id; + krb5_storage *sp; + char *str; + uint32_t type; + int flags = 0; + + *cred_handle = GSS_C_NO_CREDENTIAL; + + GSSAPI_KRB5_INIT (&context); + + sp = krb5_storage_from_mem(cred_token->value, cred_token->length); + if (sp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ret = krb5_ret_uint32(sp, &type); + if (ret) { + krb5_storage_free(sp); + *minor_status = ret; + return GSS_S_FAILURE; + } + switch (type) { + case 0: { + krb5_creds creds; + + ret = krb5_ret_creds(sp, &creds); + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_cc_initialize(context, id, creds.client); + if (ret) { + krb5_cc_destroy(context, id); + *minor_status = ret; + return GSS_S_FAILURE; + } + + 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; + + break; + } + case 1: + ret = krb5_ret_string(sp, &str); + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_cc_resolve(context, str, &id); + krb5_xfree(str); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + break; + + default: + krb5_storage_free(sp); + *minor_status = 0; + return GSS_S_NO_CRED; + } + + handle = calloc(1, sizeof(*handle)); + if (handle == NULL) { + krb5_cc_close(context, id); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + handle->usage = GSS_C_INITIATE; + handle->destination_realm = NULL; + krb5_cc_get_principal(context, id, &handle->principal); + handle->ccache = id; + handle->cred_flags = flags; + + *cred_handle = (gss_cred_id_t)handle; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/decapsulate.c b/third_party/heimdal/lib/gssapi/krb5/decapsulate.c new file mode 100644 index 0000000..d7b75a6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/decapsulate.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1997 - 2001 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" + +/* + * return the length of the mechanism in token or -1 + * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN + */ + +ssize_t +_gsskrb5_get_mech (const u_char *ptr, + size_t total_len, + const u_char **mech_ret) +{ + size_t len, len_len, mech_len, foo; + const u_char *p = ptr; + int e; + + if (total_len < 1) + return -1; + if (*p++ != 0x60) + return -1; + e = der_get_length (p, total_len - 1, &len, &len_len); + if (e || 1 + len_len + len != total_len) + return -1; + if (total_len < 1 + len_len + 1) + return -1; + p += len_len; + if (*p++ != 0x06) + return -1; + e = der_get_length (p, total_len - 1 - len_len - 1, + &mech_len, &foo); + if (e) + return -1; + p += foo; + *mech_ret = p; + return mech_len; +} + +OM_uint32 +_gssapi_verify_mech_header(u_char **str, + size_t total_len, + gss_OID mech) +{ + const u_char *p; + ssize_t mech_len; + + mech_len = _gsskrb5_get_mech (*str, total_len, &p); + if (mech_len < 0) + return GSS_S_DEFECTIVE_TOKEN; + + if (mech_len != mech->length) + return GSS_S_BAD_MECH; + if (mech_len > total_len) + return GSS_S_BAD_MECH; + if (p - *str > total_len - mech_len) + return GSS_S_BAD_MECH; + if (ct_memcmp(p, + mech->elements, + mech->length) != 0) + return GSS_S_BAD_MECH; + p += mech_len; + *str = rk_UNCONST(p); + return GSS_S_COMPLETE; +} + +OM_uint32 +_gsskrb5_verify_header(u_char **str, + size_t total_len, + const void *type, + gss_OID oid) +{ + OM_uint32 ret; + size_t len; + u_char *p = *str; + + ret = _gssapi_verify_mech_header(str, total_len, oid); + if (ret) + return ret; + + len = total_len - (*str - p); + + if (len < 2) + return GSS_S_DEFECTIVE_TOKEN; + + if (ct_memcmp (*str, type, 2) != 0) + return GSS_S_DEFECTIVE_TOKEN; + *str += 2; + + return 0; +} + +/* + * Remove the GSS-API wrapping from `in_token' giving `out_data. + * Does not copy data, so just free `in_token'. + */ + +OM_uint32 +_gssapi_decapsulate( + OM_uint32 *minor_status, + gss_buffer_t input_token_buffer, + krb5_data *out_data, + const gss_OID mech +) +{ + u_char *p; + OM_uint32 ret; + + p = input_token_buffer->value; + ret = _gssapi_verify_mech_header(&p, + input_token_buffer->length, + mech); + if (ret) { + *minor_status = 0; + return ret; + } + + out_data->length = input_token_buffer->length - + (p - (u_char *)input_token_buffer->value); + out_data->data = p; + return GSS_S_COMPLETE; +} + +/* + * Remove the GSS-API wrapping from `in_token' giving `out_data. + * Does not copy data, so just free `in_token'. + */ + +OM_uint32 +_gsskrb5_decapsulate(OM_uint32 *minor_status, + gss_buffer_t input_token_buffer, + krb5_data *out_data, + const void *type, + gss_OID oid) +{ + u_char *p; + OM_uint32 ret; + + p = input_token_buffer->value; + ret = _gsskrb5_verify_header(&p, + input_token_buffer->length, + type, + oid); + if (ret) { + *minor_status = 0; + return ret; + } + + out_data->length = input_token_buffer->length - + (p - (u_char *)input_token_buffer->value); + out_data->data = p; + return GSS_S_COMPLETE; +} + +/* + * Verify padding of a gss wrapped message and return its length. + */ + +OM_uint32 +_gssapi_verify_pad(gss_buffer_t wrapped_token, + size_t datalen, + size_t *padlen) +{ + u_char *pad; + size_t padlength; + int i; + + if (wrapped_token->length < 1) + return GSS_S_BAD_MECH; + + pad = (u_char *)wrapped_token->value + wrapped_token->length; + padlength = pad[-1]; + + if (padlength > datalen) + return GSS_S_BAD_MECH; + + for (i = padlength; i > 0 && *--pad == padlength; i--) + ; + if (i != 0) + return GSS_S_BAD_MIC; + + *padlen = padlength; + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/delete_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/delete_sec_context.c new file mode 100644 index 0000000..a480079 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/delete_sec_context.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1997 - 2003 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" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_delete_sec_context(OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_buffer_t output_token) +{ + krb5_context context; + gsskrb5_ctx ctx; + + GSSAPI_KRB5_INIT (&context); + + *minor_status = 0; + + if (output_token) { + output_token->length = 0; + output_token->value = NULL; + } + + if (*context_handle == GSS_C_NO_CONTEXT) + return GSS_S_COMPLETE; + + ctx = (gsskrb5_ctx) *context_handle; + *context_handle = GSS_C_NO_CONTEXT; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + krb5_auth_con_free (context, ctx->auth_context); + krb5_auth_con_free (context, ctx->deleg_auth_context); + if (ctx->kcred) + krb5_free_creds(context, ctx->kcred); + if(ctx->source) + krb5_free_principal (context, ctx->source); + if(ctx->target) + krb5_free_principal (context, ctx->target); + if (ctx->ticket) + krb5_free_ticket (context, ctx->ticket); + if(ctx->order) + _gssapi_msg_order_destroy(&ctx->order); + if (ctx->service_keyblock) + krb5_free_keyblock (context, ctx->service_keyblock); + krb5_data_free(&ctx->fwd_data); + if (ctx->crypto) + krb5_crypto_destroy(context, ctx->crypto); + if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) + krb5_cc_close(context, ctx->ccache); + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + memset(ctx, 0, sizeof(*ctx)); + free (ctx); + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/display_name.c b/third_party/heimdal/lib/gssapi/krb5/display_name.c new file mode 100644 index 0000000..67cb61e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/display_name.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1997 - 2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_display_name + (OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID * output_name_type + ) +{ + krb5_context context; + krb5_const_principal name = (krb5_const_principal)input_name; + krb5_error_code kret; + char *buf; + size_t len; + + GSSAPI_KRB5_INIT (&context); + + kret = krb5_unparse_name_flags (context, name, + KRB5_PRINCIPAL_UNPARSE_DISPLAY, &buf); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + len = strlen (buf); + output_name_buffer->length = len; + output_name_buffer->value = malloc(len + 1); + if (output_name_buffer->value == NULL) { + free (buf); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (output_name_buffer->value, buf, len); + ((char *)output_name_buffer->value)[len] = '\0'; + free (buf); + if (output_name_type) + *output_name_type = GSS_KRB5_NT_PRINCIPAL_NAME; + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/display_status.c b/third_party/heimdal/lib/gssapi/krb5/display_status.c new file mode 100644 index 0000000..cca5f67 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/display_status.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 1998 - 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" + +static const char * +calling_error(OM_uint32 v) +{ + static const char *msgs[] = { + NULL, /* 0 */ + "A required input parameter could not be read.", /* */ + "A required output parameter could not be written.", /* */ + "A parameter was malformed" + }; + + v >>= GSS_C_CALLING_ERROR_OFFSET; + + if (v == 0) + return ""; + else if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown calling error"; + else + return msgs[v]; +} + +static const char * +routine_error(OM_uint32 v) +{ + static const char *msgs[] = { + NULL, /* 0 */ + "An unsupported mechanism was requested", + "An invalid name was supplied", + "A supplied name was of an unsupported type", + "Incorrect channel bindings were supplied", + "An invalid status code was supplied", + "A token had an invalid MIC", + "No credentials were supplied, or the credentials were unavailable or inaccessible.", + "No context has been established", + "A token was invalid", + "A credential was invalid", + "The referenced credentials have expired", + "The context has expired", + "Miscellaneous failure (see text)", + "The quality-of-protection requested could not be provide", + "The operation is forbidden by local security policy", + "The operation or option is not available", + "The requested credential element already exists", + "The provided name was not a mechanism name.", + }; + + v >>= GSS_C_ROUTINE_ERROR_OFFSET; + + if (v == 0) + return ""; + else if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown routine error"; + else + return msgs[v]; +} + +static const char * +supplementary_error(OM_uint32 v) +{ + static const char *msgs[] = { + "normal completion", + "continuation call to routine required", + "duplicate per-message token detected", + "timed-out per-message token detected", + "reordered (early) per-message token detected", + "skipped predecessor token(s) detected" + }; + + v >>= GSS_C_SUPPLEMENTARY_OFFSET; + + if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown routine error"; + else + return msgs[v]; +} + +void +_gsskrb5_clear_status (void) +{ + krb5_context context; + + if (_gsskrb5_init (&context) != 0) + return; + krb5_clear_error_message(context); +} + +void +_gsskrb5_set_status (int ret, const char *fmt, ...) +{ + krb5_context context; + va_list args; + char *str; + int e; + + if (_gsskrb5_init (&context) != 0) + return; + + va_start(args, fmt); + e = vasprintf(&str, fmt, args); + va_end(args); + if (e >= 0 && str) { + krb5_set_error_message(context, ret, "%s", str); + free(str); + } +} + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_display_status +(OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) +{ + krb5_context context; + char *buf = NULL; + int e = 0; + + GSSAPI_KRB5_INIT (&context); + + status_string->length = 0; + status_string->value = NULL; + + if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 && + gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) { + *minor_status = 0; + return GSS_S_BAD_MECH; + } + + if (status_type == GSS_C_GSS_CODE) { + if (GSS_SUPPLEMENTARY_INFO(status_value)) + e = asprintf(&buf, "%s", + supplementary_error(GSS_SUPPLEMENTARY_INFO(status_value))); + else + e = asprintf (&buf, "%s %s", + calling_error(GSS_CALLING_ERROR(status_value)), + routine_error(GSS_ROUTINE_ERROR(status_value))); + } else if (status_type == GSS_C_MECH_CODE) { + const char *buf2 = krb5_get_error_message(context, status_value); + if (buf2) { + buf = strdup(buf2); + krb5_free_error_message(context, buf2); + } else { + e = asprintf(&buf, "unknown mech error-code %u", + (unsigned)status_value); + } + } else { + *minor_status = EINVAL; + return GSS_S_BAD_STATUS; + } + + if (e < 0 || buf == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + *message_context = 0; + *minor_status = 0; + + status_string->length = strlen(buf); + status_string->value = buf; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/duplicate_cred.c b/third_party/heimdal/lib/gssapi/krb5/duplicate_cred.c new file mode 100644 index 0000000..f5b34c5 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/duplicate_cred.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2018 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_duplicate_cred ( + OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_id_t *output_cred_handle) +{ + krb5_context context; + gsskrb5_cred cred, dup; + OM_uint32 major, junk; + + dup = NULL; + + if (output_cred_handle == NULL) { + *minor_status = EINVAL; + return GSS_S_CALL_INACCESSIBLE_WRITE; + } + + GSSAPI_KRB5_INIT (&context); + + if (input_cred_handle == GSS_C_NO_CREDENTIAL) { + /* Duplicate the default credential */ + return _gsskrb5_acquire_cred_from(minor_status, GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_BOTH, + GSS_C_NO_CRED_STORE, + output_cred_handle, + NULL, NULL); + } + + /* Duplicate the input credential */ + + dup = calloc(1, sizeof(*dup)); + if (dup == NULL) { + *minor_status = krb5_enomem(context); + return (GSS_S_FAILURE); + } + + *output_cred_handle = (gss_cred_id_t)dup; /* making sure to release on error */ + + cred = (gsskrb5_cred)input_cred_handle; + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + dup->destination_realm = NULL; + if (cred->destination_realm && + (dup->destination_realm = strdup(cred->destination_realm)) == NULL) { + *minor_status = krb5_enomem(context); + free(dup); + return (GSS_S_FAILURE); + } + dup->usage = cred->usage; + dup->endtime = cred->endtime; + dup->principal = NULL; + dup->keytab = NULL; + dup->ccache = NULL; + dup->mechanisms = NULL; + + major = GSS_S_FAILURE; + + HEIMDAL_MUTEX_init(&dup->cred_id_mutex); + *minor_status = krb5_copy_principal(context, cred->principal, + &dup->principal); + if (*minor_status) + goto fail; + + if (cred->keytab) { + char *name = NULL; + + *minor_status = krb5_kt_get_full_name(context, cred->keytab, &name); + if (*minor_status) + goto fail; + *minor_status = krb5_kt_resolve(context, name, &dup->keytab); + krb5_xfree(name); + if (*minor_status) + goto fail; + } + + if (cred->ccache) { + const char *type, *name; + char *type_name = NULL; + + type = krb5_cc_get_type(context, cred->ccache); /* can't fail */ + if (strcmp(type, "MEMORY") == 0) { + *minor_status = krb5_cc_new_unique(context, type, NULL, + &dup->ccache); + if (*minor_status) + goto fail; + + *minor_status = krb5_cc_copy_cache(context, cred->ccache, + dup->ccache); + if (*minor_status) + goto fail; + + } else { + name = krb5_cc_get_name(context, cred->ccache); + if (name == NULL) { + *minor_status = ENOMEM; + goto fail; + } + + if (asprintf(&type_name, "%s:%s", type, name) == -1 || + type_name == NULL) { + *minor_status = ENOMEM; + goto fail; + } + + *minor_status = krb5_cc_resolve(context, type_name, + &dup->ccache); + free(type_name); + if (*minor_status) + goto fail; + } + } + + major = gss_create_empty_oid_set(minor_status, &dup->mechanisms); + if (major != GSS_S_COMPLETE) + goto fail; + + major = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &dup->mechanisms); + if (major != GSS_S_COMPLETE) + goto fail; + + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *output_cred_handle = (gss_cred_id_t)dup; + *minor_status = 0; + return major; + +fail: + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *output_cred_handle = (gss_cred_id_t)dup; + _gsskrb5_release_cred(&junk, output_cred_handle); + return major; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/duplicate_name.c b/third_party/heimdal/lib/gssapi/krb5/duplicate_name.c new file mode 100644 index 0000000..43519d6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/duplicate_name.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1997 - 2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_duplicate_name ( + OM_uint32 * minor_status, + gss_const_name_t src_name, + gss_name_t * dest_name + ) +{ + krb5_const_principal src = (krb5_const_principal)src_name; + krb5_context context; + krb5_principal dest; + krb5_error_code kret; + + GSSAPI_KRB5_INIT (&context); + + kret = krb5_copy_principal (context, src, &dest); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } else { + *dest_name = (gss_name_t)dest; + *minor_status = 0; + return GSS_S_COMPLETE; + } +} diff --git a/third_party/heimdal/lib/gssapi/krb5/encapsulate.c b/third_party/heimdal/lib/gssapi/krb5/encapsulate.c new file mode 100644 index 0000000..3b390ce --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/encapsulate.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1997 - 2003 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" + +void +_gssapi_encap_length (size_t data_len, + size_t *len, + size_t *total_len, + const gss_OID mech) +{ + size_t len_len; + + *len = 1 + 1 + mech->length + data_len; + + len_len = der_length_len(*len); + + *total_len = 1 + len_len + *len; +} + +void +_gsskrb5_encap_length (size_t data_len, + size_t *len, + size_t *total_len, + const gss_OID mech) +{ + _gssapi_encap_length(data_len + 2, len, total_len, mech); +} + +void * +_gssapi_make_mech_header(void *ptr, + size_t len, + const gss_OID mech) +{ + u_char *p = ptr; + int e; + size_t len_len, foo; + + *p++ = 0x60; + len_len = der_length_len(len); + e = der_put_length (p + len_len - 1, len_len, len, &foo); + if(e || foo != len_len) + abort (); + p += len_len; + *p++ = 0x06; + *p++ = mech->length; + memcpy (p, mech->elements, mech->length); + p += mech->length; + return p; +} + +void * +_gsskrb5_make_header (void *ptr, + size_t len, + const void *type, + const gss_OID mech) +{ + u_char *p = ptr; + p = _gssapi_make_mech_header(p, len, mech); + memcpy (p, type, 2); + p += 2; + return p; +} + +/* + * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings. + */ + +OM_uint32 +_gssapi_encapsulate( + OM_uint32 *minor_status, + const krb5_data *in_data, + gss_buffer_t output_token, + const gss_OID mech +) +{ + size_t len, outer_len; + void *p; + + _gssapi_encap_length (in_data->length, &len, &outer_len, mech); + + output_token->length = outer_len; + output_token->value = malloc (outer_len); + if (output_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gssapi_make_mech_header (output_token->value, len, mech); + memcpy (p, in_data->data, in_data->length); + return GSS_S_COMPLETE; +} + +/* + * Give it a krb5_data and it will encapsulate with extra GSS-API krb5 + * wrappings. + */ + +OM_uint32 +_gsskrb5_encapsulate( + OM_uint32 *minor_status, + const krb5_data *in_data, + gss_buffer_t output_token, + const void *type, + const gss_OID mech +) +{ + size_t len, outer_len; + u_char *p; + + _gsskrb5_encap_length (in_data->length, &len, &outer_len, mech); + + output_token->length = outer_len; + output_token->value = malloc (outer_len); + if (output_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gsskrb5_make_header (output_token->value, len, type, mech); + memcpy (p, in_data->data, in_data->length); + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/export_name.c b/third_party/heimdal/lib/gssapi/krb5/export_name.c new file mode 100644 index 0000000..1686a65 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/export_name.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1997, 1999, 2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_export_name + (OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_buffer_t exported_name + ) +{ + krb5_context context; + krb5_const_principal princ = (krb5_const_principal)input_name; + krb5_error_code kret; + char *buf, *name; + size_t len; + + GSSAPI_KRB5_INIT (&context); + + kret = krb5_unparse_name (context, princ, &name); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + len = strlen (name); + + exported_name->length = 10 + len + GSS_KRB5_MECHANISM->length; + exported_name->value = malloc(exported_name->length); + if (exported_name->value == NULL) { + free (name); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + buf = exported_name->value; + memcpy(buf, "\x04\x01", 2); + buf += 2; + buf[0] = ((GSS_KRB5_MECHANISM->length + 2) >> 8) & 0xff; + buf[1] = (GSS_KRB5_MECHANISM->length + 2) & 0xff; + buf+= 2; + buf[0] = 0x06; + buf[1] = (GSS_KRB5_MECHANISM->length) & 0xFF; + buf+= 2; + + memcpy(buf, GSS_KRB5_MECHANISM->elements, GSS_KRB5_MECHANISM->length); + buf += GSS_KRB5_MECHANISM->length; + + buf[0] = (len >> 24) & 0xff; + buf[1] = (len >> 16) & 0xff; + buf[2] = (len >> 8) & 0xff; + buf[3] = (len) & 0xff; + buf += 4; + + memcpy (buf, name, len); + + free (name); + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/export_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/export_sec_context.c new file mode 100644 index 0000000..c298415 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/export_sec_context.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 1999 - 2003 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" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_export_sec_context( + OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t interprocess_token + ) +{ + krb5_context context; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) *context_handle; + krb5_storage *sp; + krb5_auth_context ac; + OM_uint32 ret = GSS_S_COMPLETE; + krb5_data data; + int flags; + OM_uint32 minor; + krb5_error_code kret; + + GSSAPI_KRB5_INIT (&context); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + if (!(ctx->flags & GSS_C_TRANS_FLAG)) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + *minor_status = 0; + return GSS_S_UNAVAILABLE; + } + + sp = krb5_storage_emem (); + if (sp == NULL) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + ac = ctx->auth_context; + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_PACKED); + krb5_storage_set_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE); + + /* flagging included fields */ + + flags = 0; + if (ac->local_address) + flags |= SC_LOCAL_ADDRESS; + if (ac->remote_address) + flags |= SC_REMOTE_ADDRESS; + if (ac->keyblock) + flags |= SC_KEYBLOCK; + if (ac->local_subkey) + flags |= SC_LOCAL_SUBKEY; + if (ac->remote_subkey) + flags |= SC_REMOTE_SUBKEY; + if (ac->authenticator) + flags |= SC_AUTHENTICATOR; + if (ctx->source) + flags |= SC_SOURCE_NAME; + if (ctx->target) + flags |= SC_TARGET_NAME; + if (ctx->order) + flags |= SC_ORDER; + + kret = krb5_store_int32 (sp, flags); + if (kret) { + *minor_status = kret; + goto failure; + } + + /* marshall auth context */ + + kret = krb5_store_int32 (sp, ac->flags); + if (kret) { + *minor_status = kret; + goto failure; + } + if (ac->local_address) { + kret = krb5_store_address (sp, *ac->local_address); + if (kret) { + *minor_status = kret; + goto failure; + } + } + if (ac->remote_address) { + kret = krb5_store_address (sp, *ac->remote_address); + if (kret) { + *minor_status = kret; + goto failure; + } + } + kret = krb5_store_int16 (sp, ac->local_port); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int16 (sp, ac->remote_port); + if (kret) { + *minor_status = kret; + goto failure; + } + if (ac->keyblock) { + kret = krb5_store_keyblock (sp, *ac->keyblock); + if (kret) { + *minor_status = kret; + goto failure; + } + } + if (ac->local_subkey) { + kret = krb5_store_keyblock (sp, *ac->local_subkey); + if (kret) { + *minor_status = kret; + goto failure; + } + } + if (ac->remote_subkey) { + kret = krb5_store_keyblock (sp, *ac->remote_subkey); + if (kret) { + *minor_status = kret; + goto failure; + } + } + kret = krb5_store_int32 (sp, ac->local_seqnumber); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int32 (sp, ac->remote_seqnumber); + if (kret) { + *minor_status = kret; + goto failure; + } + if (ac->authenticator) { + kret = krb5_store_int64(sp, ac->authenticator->ctime); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int32(sp, ac->authenticator->cusec); + if (kret) { + *minor_status = kret; + goto failure; + } + } + + kret = krb5_store_int32 (sp, ac->keytype); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int32 (sp, ac->cksumtype); + if (kret) { + *minor_status = kret; + goto failure; + } + + /* names */ + if (ctx->source) { + kret = krb5_store_principal(sp, ctx->source); + if (kret) { + *minor_status = kret; + goto failure; + } + } + + if (ctx->target) { + kret = krb5_store_principal(sp, ctx->target); + if (kret) { + *minor_status = kret; + goto failure; + } + } + + kret = krb5_store_int32 (sp, ctx->flags); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int32 (sp, ctx->more_flags); + if (kret) { + *minor_status = kret; + goto failure; + } + kret = krb5_store_int32 (sp, ctx->state); + if (kret) { + *minor_status = kret; + goto failure; + } + /* + * 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; + } + if (ctx->order) { + kret = _gssapi_msg_order_export(sp, ctx->order); + if (kret) { + *minor_status = kret; + goto failure; + } + } + + kret = krb5_storage_to_data (sp, &data); + krb5_storage_free (sp); + if (kret) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + *minor_status = kret; + return GSS_S_FAILURE; + } + interprocess_token->length = data.length; + interprocess_token->value = data.data; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + ret = _gsskrb5_delete_sec_context (minor_status, context_handle, + GSS_C_NO_BUFFER); + if (ret != GSS_S_COMPLETE) + _gss_secure_release_buffer (&minor, interprocess_token); + *minor_status = 0; + return ret; + failure: + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + krb5_storage_free (sp); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/external.c b/third_party/heimdal/lib/gssapi/krb5/external.c new file mode 100644 index 0000000..e58df18 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/external.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 1997 - 2018 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" +#include <gssapi_mech.h> + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x01"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant + * GSS_C_NT_USER_NAME should be initialized to point + * to that gss_OID_desc. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_user_name_oid_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12" "\x01\x02\x01\x01")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x02"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}. + * The constant GSS_C_NT_MACHINE_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_machine_uid_name_oid_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12" "\x01\x02\x01\x02")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x03"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) string_uid_name(3)}. + * The constant GSS_C_NT_STRING_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_string_uid_name_oid_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12" "\x01\x02\x01\x03")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x02"}, + * corresponding to an object-identifier value of + * {iso(1) org(3) dod(6) internet(1) security(5) + * nametypes(6) gss-host-based-services(2)). The constant + * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point + * to that gss_OID_desc. This is a deprecated OID value, and + * implementations wishing to support hostbased-service names + * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID, + * defined below, to identify such names; + * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym + * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input + * parameter, but should not be emitted by GSS-API + * implementations + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_hostbased_service_x_oid_desc = + {6, rk_UNCONST("\x2b\x06\x01\x05\x06\x02")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x04"}, corresponding to an + * object-identifier value of {iso(1) member-body(2) + * Unites States(840) mit(113554) infosys(1) gssapi(2) + * generic(1) service_name(4)}. The constant + * GSS_C_NT_HOSTBASED_SERVICE should be initialized + * to point to that gss_OID_desc. + */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_hostbased_service_oid_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12" "\x01\x02\x01\x04")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\01\x05\x06\x03"}, + * corresponding to an object identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 3(gss-anonymous-name)}. The constant + * and GSS_C_NT_ANONYMOUS should be initialized to point + * to that gss_OID_desc. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_anonymous_oid_desc = + {6, rk_UNCONST("\x2b\x06\01\x05\x06\x03")}; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x04"}, + * corresponding to an object-identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 4(gss-api-exported-name)}. The constant + * GSS_C_NT_EXPORT_NAME should be initialized to point + * to that gss_OID_desc. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_export_name_oid_desc = + {6, rk_UNCONST("\x2b\x06\x01\x05\x06\x04") }; + +/* + * This name form shall be represented by the Object Identifier {iso(1) + * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) + * krb5(2) krb5_name(1)}. The recommended symbolic name for this type + * is "GSS_KRB5_NT_PRINCIPAL_NAME". + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_nt_principal_name_oid_desc = + {10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01") }; + +/* + * GSS_C_NT_COMPOSITE_EXPORT [RFC6680], OID {iso(1) identified-organization(3) + * dod(6) internet(1) security(5) nametypes(6) gss-composite-export(6)}. + */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_composite_export_oid_desc = + {6, rk_UNCONST("\x2b\x06\x01\x05\x06\x06")}; + +/* + * draft-ietf-cat-iakerb-09, IAKERB: + * The mechanism ID for IAKERB proxy GSS-API Kerberos, in accordance + * with the mechanism proposed by SPNEGO [7] for negotiating protocol + * variations, is: {iso(1) org(3) dod(6) internet(1) security(5) + * mechanisms(5) iakerb(10) iakerbProxyProtocol(1)}. The proposed + * mechanism ID for IAKERB minimum messages GSS-API Kerberos, in + * accordance with the mechanism proposed by SPNEGO for negotiating + * protocol variations, is: {iso(1) org(3) dod(6) internet(1) + * security(5) mechanisms(5) iakerb(10) + * iakerbMinimumMessagesProtocol(2)}. + */ + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_iakerb_proxy_mechanism_oid_desc = + {7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0a\x01")}; + +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_iakerb_min_msg_mechanism_oid_desc = + {7, rk_UNCONST("\x2b\x06\x01\x05\x05\x0a\x02") }; + +/* + * Context for krb5 calls. + */ + +static gss_mo_desc krb5_mo[] = { + { + GSS_C_MA_SASL_MECH_NAME, + GSS_MO_MA, + "SASL mech name", + rk_UNCONST("GS2-KRB5"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_NAME, + GSS_MO_MA, + "Mechanism name", + rk_UNCONST("KRB5"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_DESCRIPTION, + GSS_MO_MA, + "Mechanism description", + rk_UNCONST("Heimdal Kerberos 5 mech"), + _gss_mo_get_ctx_as_string, + NULL + }, + { + GSS_C_MA_MECH_CONCRETE, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_ITOK_FRAMED, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_AUTH_INIT, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_AUTH_TARG, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_DELEG_CRED, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_INTEG_PROT, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_CONF_PROT, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_MIC, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_WRAP, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_PROT_READY, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_REPLAY_DET, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_OOS_DET, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_CBINDINGS, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_PFS, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + }, + { + GSS_C_MA_CTX_TRANS, + GSS_MO_MA, + NULL, + NULL, + NULL, + NULL + } +}; + +/* + * + */ + +static gssapi_mech_interface_desc krb5_mech = { + GMI_VERSION, + "krb5", + {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") }, + 0, + NULL, /* gm_acquire_cred */ + _gsskrb5_release_cred, + _gsskrb5_init_sec_context, + _gsskrb5_accept_sec_context, + _gsskrb5_process_context_token, + _gsskrb5_delete_sec_context, + _gsskrb5_context_time, + _gsskrb5_get_mic, + _gsskrb5_verify_mic, + _gsskrb5_wrap, + _gsskrb5_unwrap, + _gsskrb5_display_status, + _gsskrb5_indicate_mechs, + _gsskrb5_compare_name, + _gsskrb5_display_name, + _gsskrb5_import_name, + _gsskrb5_export_name, + _gsskrb5_release_name, + _gsskrb5_inquire_cred, + _gsskrb5_inquire_context, + _gsskrb5_wrap_size_limit, + NULL, /* gm_add_cred */ + _gsskrb5_inquire_cred_by_mech, + _gsskrb5_export_sec_context, + _gsskrb5_import_sec_context, + _gsskrb5_inquire_names_for_mech, + _gsskrb5_inquire_mechs_for_name, + _gsskrb5_canonicalize_name, + _gsskrb5_duplicate_name, + _gsskrb5_inquire_sec_context_by_oid, + _gsskrb5_inquire_cred_by_oid, + _gsskrb5_set_sec_context_option, + _gsskrb5_set_cred_option, + _gsskrb5_pseudo_random, + _gk_wrap_iov, + _gk_unwrap_iov, + _gk_wrap_iov_length, + NULL, /* gm_store_cred */ + _gsskrb5_export_cred, + _gsskrb5_import_cred, + _gsskrb5_acquire_cred_from, + NULL, /* gm_acquire_cred_impersonate_name */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + krb5_mo, + sizeof(krb5_mo) / sizeof(krb5_mo[0]), + _gsskrb5_localname, + _gsskrb5_authorize_localname, + _gsskrb5_display_name_ext, + _gsskrb5_inquire_name, + _gsskrb5_get_name_attribute, + _gsskrb5_set_name_attribute, + _gsskrb5_delete_name_attribute, + _gsskrb5_export_name_composite, + _gsskrb5_duplicate_cred, + _gsskrb5_add_cred_from, + _gsskrb5_store_cred_into, + NULL, /* gm_query_mechanism_info */ + NULL, /* gm_query_meta_data */ + NULL, /* gm_exchange_meta_data */ + _gsskrb5_store_cred_into2, + NULL /* gm_compat */ +}; + +gssapi_mech_interface +__gss_krb5_initialize(void) +{ + return &krb5_mech; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/get_mic.c b/third_party/heimdal/lib/gssapi/krb5/get_mic.c new file mode 100644 index 0000000..d9cf9d7 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/get_mic.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 1997 - 2003 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" + +#ifdef HEIM_WEAK_CRYPTO + +static OM_uint32 +mic_des + (OM_uint32 * minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key + ) +{ + u_char *p; + EVP_MD_CTX *md5; + u_char hash[16]; + DES_key_schedule schedule; + EVP_CIPHER_CTX des_ctx; + DES_cblock deskey; + DES_cblock zero; + int32_t seq_number; + size_t len, total_len; + + _gsskrb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM); + + message_token->length = total_len; + message_token->value = malloc (total_len); + if (message_token->value == NULL) { + message_token->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gsskrb5_make_header(message_token->value, + len, + "\x01\x01", /* TOK_ID */ + GSS_KRB5_MECHANISM); + + memcpy (p, "\x00\x00", 2); /* SGN_ALG = DES MAC MD5 */ + p += 2; + + memcpy (p, "\xff\xff\xff\xff", 4); /* Filler */ + p += 4; + + /* Fill in later (SND-SEQ) */ + memset (p, 0, 16); + p += 16; + + /* checksum */ + md5 = EVP_MD_CTX_create(); + EVP_DigestInit_ex(md5, EVP_md5(), NULL); + EVP_DigestUpdate(md5, p - 24, 8); + EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length); + EVP_DigestFinal_ex(md5, hash, NULL); + EVP_MD_CTX_destroy(md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + DES_set_key_unchecked (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + memcpy (p - 8, hash, 8); /* SGN_CKSUM */ + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + /* sequence number */ + krb5_auth_con_getlocalseqnumber (context, + ctx->auth_context, + &seq_number); + + p -= 16; /* SND_SEQ */ + p[0] = (seq_number >> 0) & 0xFF; + p[1] = (seq_number >> 8) & 0xFF; + p[2] = (seq_number >> 16) & 0xFF; + p[3] = (seq_number >> 24) & 0xFF; + memset (p + 4, + (ctx->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1); + EVP_Cipher(&des_ctx, p, p, 8); + EVP_CIPHER_CTX_cleanup(&des_ctx); + + krb5_auth_con_setlocalseqnumber (context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + memset_s(deskey, sizeof(deskey), 0, sizeof(deskey)); + memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule)); + + *minor_status = 0; + return GSS_S_COMPLETE; +} +#endif + +static OM_uint32 +mic_des3 + (OM_uint32 * minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key + ) +{ + u_char *p; + Checksum cksum; + u_char seq[8]; + + int32_t seq_number; + size_t len, total_len; + + krb5_crypto crypto; + krb5_error_code kret; + krb5_data encdata; + char *tmp; + char ivec[8]; + + _gsskrb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM); + + message_token->length = total_len; + message_token->value = malloc (total_len); + if (message_token->value == NULL) { + message_token->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gsskrb5_make_header(message_token->value, + len, + "\x01\x01", /* TOK-ID */ + GSS_KRB5_MECHANISM); + + memcpy (p, "\x04\x00", 2); /* SGN_ALG = HMAC SHA1 DES3-KD */ + p += 2; + + memcpy (p, "\xff\xff\xff\xff", 4); /* filler */ + p += 4; + + /* this should be done in parts */ + + tmp = malloc (message_buffer->length + 8); + if (tmp == NULL) { + free (message_token->value); + message_token->value = NULL; + message_token->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (tmp, p - 8, 8); + memcpy (tmp + 8, message_buffer->value, message_buffer->length); + + kret = krb5_crypto_init(context, key, 0, &crypto); + if (kret) { + free (message_token->value); + message_token->value = NULL; + message_token->length = 0; + free (tmp); + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_create_checksum (context, + crypto, + KRB5_KU_USAGE_SIGN, + 0, + tmp, + message_buffer->length + 8, + &cksum); + free (tmp); + krb5_crypto_destroy (context, crypto); + if (kret) { + free (message_token->value); + message_token->value = NULL; + message_token->length = 0; + *minor_status = kret; + return GSS_S_FAILURE; + } + + memcpy (p + 8, cksum.checksum.data, cksum.checksum.length); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + /* sequence number */ + krb5_auth_con_getlocalseqnumber (context, + ctx->auth_context, + &seq_number); + + seq[0] = (seq_number >> 0) & 0xFF; + seq[1] = (seq_number >> 8) & 0xFF; + seq[2] = (seq_number >> 16) & 0xFF; + seq[3] = (seq_number >> 24) & 0xFF; + memset (seq + 4, + (ctx->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + kret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (kret) { + free (message_token->value); + message_token->value = NULL; + message_token->length = 0; + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (ctx->more_flags & COMPAT_OLD_DES3) + memset(ivec, 0, 8); + else + memcpy(ivec, p + 8, 8); + + kret = krb5_encrypt_ivec (context, + crypto, + KRB5_KU_USAGE_SEQ, + seq, 8, &encdata, ivec); + krb5_crypto_destroy (context, crypto); + if (kret) { + free (message_token->value); + message_token->value = NULL; + message_token->length = 0; + *minor_status = kret; + return GSS_S_FAILURE; + } + + assert (encdata.length == 8); + + memcpy (p, encdata.data, encdata.length); + krb5_data_free (&encdata); + + krb5_auth_con_setlocalseqnumber (context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + free_Checksum (&cksum); + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_get_mic + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token + ) +{ + krb5_context context; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + krb5_keyblock *key; + OM_uint32 ret; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_mic_cfx (minor_status, ctx, context, qop_req, + message_buffer, message_token); + + 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; + } + + 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); +#else + ret = GSS_S_FAILURE; +#endif + break; + 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 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; + default : + abort(); + break; + } + krb5_free_keyblock (context, key); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/gkrb5_err.et b/third_party/heimdal/lib/gssapi/krb5/gkrb5_err.et new file mode 100644 index 0000000..109876e --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/gkrb5_err.et @@ -0,0 +1,33 @@ +# +# extended gss krb5 error messages +# + +id "$Id$" + +error_table gk5 + +prefix GSS_KRB5_S + +error_code G_BAD_SERVICE_NAME, "No @ in SERVICE-NAME name string" +error_code G_BAD_STRING_UID, "STRING-UID-NAME contains nondigits" +error_code G_NOUSER, "UID does not resolve to username" +error_code G_VALIDATE_FAILED, "Validation error" +error_code G_BUFFER_ALLOC, "Couldn't allocate gss_buffer_t data" +error_code G_BAD_MSG_CTX, "Message context invalid" +error_code G_WRONG_SIZE, "Buffer is the wrong size" +error_code G_BAD_USAGE, "Credential usage type is unknown" +error_code G_UNKNOWN_QOP, "Unknown quality of protection specified" +error_code G_UNKNOWN_CRED_STORE_ELEMENT, "Credential store contained unknown elements" +error_code G_BAD_PASSWORD_CRED_STORE, "Credential store cannot contain both a password and a credentials cache or client keytab" + +index 128 + +error_code KG_CCACHE_NOMATCH, "Principal in credential cache does not match desired name" +error_code KG_KEYTAB_NOMATCH, "No principal in keytab matches desired name" +error_code KG_TGT_MISSING, "Credential cache has no TGT" +error_code KG_NO_SUBKEY, "Authenticator has no subkey" +error_code KG_CONTEXT_ESTABLISHED, "Context is already fully established" +error_code KG_BAD_SIGN_TYPE, "Unknown signature type in token" +error_code KG_BAD_LENGTH, "Invalid field length in token" +error_code KG_CTX_INCOMPLETE, "Attempt to use incomplete security context" +error_code KG_INPUT_TOO_LONG, "Input too long" diff --git a/third_party/heimdal/lib/gssapi/krb5/gsskrb5_locl.h b/third_party/heimdal/lib/gssapi/krb5/gsskrb5_locl.h new file mode 100644 index 0000000..fbbb168 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/gsskrb5_locl.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1997 - 2008 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. + */ + +/* $Id$ */ + +#ifndef GSSKRB5_LOCL_H +#define GSSKRB5_LOCL_H + +#include <config.h> + +#include <krb5_locl.h> +#include <gkrb5_err.h> +#include <gssapi.h> +#include <gssapi_mech.h> +#include <gssapi_krb5.h> +#include <assert.h> +#include <mech/utils.h> + +#include "cfx.h" + +/* + * + */ + +struct gss_msg_order; + +typedef struct gsskrb5_ctx { + struct krb5_auth_context_data *auth_context; + struct krb5_auth_context_data *deleg_auth_context; + krb5_principal source, target; + OM_uint32 flags; + enum { LOCAL = 1, OPEN = 2, + COMPAT_OLD_DES3 = 4, + COMPAT_OLD_DES3_SELECTED = 8, + ACCEPTOR_SUBKEY = 16, + RETRIED = 32, + CLOSE_CCACHE = 64, + IS_CFX = 128 + } more_flags; + enum gss_ctx_id_t_state { + /* initiator states */ + INITIATOR_START, + INITIATOR_RESTART, + INITIATOR_WAIT_FOR_MUTUAL, + INITIATOR_READY, + /* acceptor states */ + ACCEPTOR_START, + ACCEPTOR_WAIT_FOR_DCESTYLE, + ACCEPTOR_READY + } state; + krb5_creds *kcred; + krb5_ccache ccache; + struct krb5_ticket *ticket; + time_t endtime; + HEIMDAL_MUTEX ctx_id_mutex; + struct gss_msg_order *order; + krb5_keyblock *service_keyblock; + krb5_data fwd_data; + krb5_crypto crypto; +} *gsskrb5_ctx; + +static inline krb5_boolean +IS_DCE_STYLE(gsskrb5_ctx ctx) +{ + return (ctx->flags & GSS_C_DCE_STYLE) != 0; +} + +typedef struct { + krb5_principal principal; + char *destination_realm; /* Realm of acceptor service, if delegated */ + int cred_flags; +#define GSS_CF_DESTROY_CRED_ON_RELEASE 1 +#define GSS_CF_NO_CI_FLAGS 2 + struct krb5_keytab_data *keytab; + time_t endtime; + gss_cred_usage_t usage; + gss_OID_set mechanisms; + struct krb5_ccache_data *ccache; + HEIMDAL_MUTEX cred_id_mutex; + krb5_enctype *enctypes; +} *gsskrb5_cred; + +typedef struct Principal *gsskrb5_name; + +/* + * + */ + +extern krb5_keytab _gsskrb5_keytab; +extern HEIMDAL_MUTEX gssapi_keytab_mutex; + +/* + * Prototypes + */ + +#include "krb5/gsskrb5-private.h" + +#define GSSAPI_KRB5_INIT(ctx) do { \ + krb5_error_code kret_gss_init; \ + if((kret_gss_init = _gsskrb5_init (ctx)) != 0) { \ + *minor_status = kret_gss_init; \ + return GSS_S_FAILURE; \ + } \ +} while (0) + +/* sec_context flags */ + +#define SC_LOCAL_ADDRESS 0x0001 +#define SC_REMOTE_ADDRESS 0x0002 +#define SC_KEYBLOCK 0x0004 +#define SC_LOCAL_SUBKEY 0x0008 +#define SC_REMOTE_SUBKEY 0x0010 +#define SC_SOURCE_NAME 0x0020 +#define SC_TARGET_NAME 0x0040 +#define SC_ORDER 0x0080 +#define SC_AUTHENTICATOR 0x0100 + +struct gsskrb5_ccache_name_args { + const char *name; + const char *out_name; +}; + +#endif diff --git a/third_party/heimdal/lib/gssapi/krb5/import_name.c b/third_party/heimdal/lib/gssapi/krb5/import_name.c new file mode 100644 index 0000000..f4ee231 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/import_name.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 1997 - 2003 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" + +static OM_uint32 +parse_krb5_name (OM_uint32 *minor_status, + krb5_context context, + const char *name, + gss_name_t *output_name) +{ + krb5_principal princ; + krb5_error_code kerr; + + kerr = krb5_parse_name (context, name, &princ); + + if (kerr == 0) { + *output_name = (gss_name_t)princ; + return GSS_S_COMPLETE; + } + *minor_status = kerr; + + if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) + return GSS_S_BAD_NAME; + + return GSS_S_FAILURE; +} + +static OM_uint32 +import_krb5_name (OM_uint32 *minor_status, + krb5_context context, + const gss_buffer_t input_name_buffer, + gss_name_t *output_name) +{ + OM_uint32 ret; + char *tmp; + + tmp = malloc (input_name_buffer->length + 1); + if (tmp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (tmp, + input_name_buffer->value, + input_name_buffer->length); + tmp[input_name_buffer->length] = '\0'; + + ret = parse_krb5_name(minor_status, context, tmp, output_name); + free(tmp); + + return ret; +} + +OM_uint32 +_gsskrb5_canon_name(OM_uint32 *minor_status, krb5_context context, + gss_const_name_t targetname, krb5_principal *out) +{ + 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 */ + 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) + hostname = p->name.name_string.val[1]; + + service = p->name.name_string.val[0]; + + ret = krb5_sname_to_principal(context, + hostname, + service, + KRB5_NT_SRV_HST, + out); + if (ret == 0) { + const char *in_realm = krb5_principal_get_realm(context, + p); + const char *out_realm = krb5_principal_get_realm(context, + *out); + + /* + * Avoid loss of information, check for the "referral + * realm" and set back what was specified. + */ + if (out_realm != NULL && out_realm[0] == '\0') { + ret = krb5_principal_set_realm(context, *out, in_realm); + } + } + } else { + ret = krb5_copy_principal(context, p, out); + } + + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + return 0; +} + + +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) +{ + krb5_principal princ = NULL; + krb5_error_code kerr; + char *tmp, *p, *host = NULL; + + tmp = malloc (input_name_buffer->length + 1); + if (tmp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (tmp, + input_name_buffer->value, + input_name_buffer->length); + tmp[input_name_buffer->length] = '\0'; + + p = strchr (tmp, '@'); + if (p != NULL) { + *p = '\0'; + host = p + 1; + } + + kerr = krb5_make_principal(context, &princ, "", tmp, host, NULL); + free (tmp); + *minor_status = kerr; + if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) + return GSS_S_BAD_NAME; + else if (kerr) + return GSS_S_FAILURE; + + krb5_principal_set_type(context, princ, KRB5_NT_SRV_HST); + *output_name = (gss_name_t)princ; + + return 0; +} + +static OM_uint32 +import_export_name (OM_uint32 *minor_status, + krb5_context context, + const gss_buffer_t input_name_buffer, + gss_name_t *output_name) +{ + CompositePrincipal *composite; + unsigned char *p; + uint32_t length; + size_t sz; + OM_uint32 ret; + int is_composite; + char *name; + + if (input_name_buffer->length < 10 + GSS_KRB5_MECHANISM->length) + return GSS_S_BAD_NAME; + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + p = input_name_buffer->value; + + if (p[0] != 0x04 || + (p[1] != 0x01 && p[1] != 0x02) || + p[2] != 0x00 || + p[3] != GSS_KRB5_MECHANISM->length + 2 || + p[4] != 0x06 || + p[5] != GSS_KRB5_MECHANISM->length || + memcmp(&p[6], GSS_KRB5_MECHANISM->elements, + GSS_KRB5_MECHANISM->length) != 0) + return GSS_S_BAD_NAME; + + is_composite = p[1] == 0x02; + + p += 6 + GSS_KRB5_MECHANISM->length; + + length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + p += 4; + + if (length > input_name_buffer->length - 10 - GSS_KRB5_MECHANISM->length) + return GSS_S_BAD_NAME; + + if (is_composite) { + if ((composite = calloc(1, sizeof(*composite))) == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ret = decode_CompositePrincipal(p, length, composite, &sz); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + if (sz != length) { + free_CompositePrincipal(composite); + free(composite); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + *output_name = (void *)composite; + return GSS_S_COMPLETE; + } + + name = malloc(length + 1); + if (name == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(name, p, length); + name[length] = '\0'; + + ret = parse_krb5_name(minor_status, context, name, output_name); + free(name); + return ret; +} + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_import_name + (OM_uint32 * minor_status, + const gss_buffer_t input_name_buffer, + const gss_OID input_name_type, + gss_name_t * output_name + ) +{ + krb5_context context; + + *minor_status = 0; + *output_name = GSS_C_NO_NAME; + + GSSAPI_KRB5_INIT (&context); + + if (gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE) || + gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE_X)) + return import_hostbased_name (minor_status, + context, + input_name_buffer, + output_name); + else if (input_name_type == GSS_C_NO_OID + || gss_oid_equal(input_name_type, GSS_C_NT_USER_NAME) + || gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME)) + /* default printable syntax */ + return import_krb5_name (minor_status, + context, + input_name_buffer, + output_name); + else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME) || + gss_oid_equal(input_name_type, GSS_C_NT_COMPOSITE_EXPORT)) { + return import_export_name(minor_status, + context, + input_name_buffer, + output_name); + } else { + *minor_status = 0; + return GSS_S_BAD_NAMETYPE; + } +} diff --git a/third_party/heimdal/lib/gssapi/krb5/import_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/import_sec_context.c new file mode 100644 index 0000000..2255a71 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/import_sec_context.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 1999 - 2003 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" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_import_sec_context ( + OM_uint32 * minor_status, + const gss_buffer_t interprocess_token, + gss_ctx_id_t * context_handle + ) +{ + OM_uint32 ret = GSS_S_FAILURE; + krb5_context context; + krb5_error_code kret; + krb5_storage *sp; + krb5_auth_context ac; + krb5_address local, remote; + krb5_address *localp, *remotep; + krb5_keyblock keyblock; + int32_t flags, tmp; + int64_t tmp64; + gsskrb5_ctx ctx; + + GSSAPI_KRB5_INIT (&context); + + *context_handle = GSS_C_NO_CONTEXT; + + localp = remotep = NULL; + + sp = krb5_storage_from_mem (interprocess_token->value, + interprocess_token->length); + if (sp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_PACKED); + krb5_storage_set_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE); + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + *minor_status = ENOMEM; + krb5_storage_free (sp); + return GSS_S_FAILURE; + } + HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); + + kret = krb5_auth_con_init (context, + &ctx->auth_context); + if (kret) { + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + + /* flags */ + + *minor_status = 0; + + if (krb5_ret_int32 (sp, &flags) != 0) + goto failure; + + /* retrieve the auth context */ + + ac = ctx->auth_context; + if (krb5_ret_int32 (sp, &tmp) != 0) + goto failure; + ac->flags = tmp; + if (flags & SC_LOCAL_ADDRESS) { + if (krb5_ret_address (sp, localp = &local) != 0) + goto failure; + } + + if (flags & SC_REMOTE_ADDRESS) { + if (krb5_ret_address (sp, remotep = &remote) != 0) + goto failure; + } + + krb5_auth_con_setaddrs (context, ac, localp, remotep); + if (localp) + krb5_free_address (context, localp); + if (remotep) + krb5_free_address (context, remotep); + localp = remotep = NULL; + + if (krb5_ret_int16 (sp, &ac->local_port) != 0) + goto failure; + + if (krb5_ret_int16 (sp, &ac->remote_port) != 0) + goto failure; + if (flags & SC_KEYBLOCK) { + if (krb5_ret_keyblock (sp, &keyblock) != 0) + goto failure; + krb5_auth_con_setkey (context, ac, &keyblock); + krb5_free_keyblock_contents (context, &keyblock); + } + if (flags & SC_LOCAL_SUBKEY) { + if (krb5_ret_keyblock (sp, &keyblock) != 0) + goto failure; + krb5_auth_con_setlocalsubkey (context, ac, &keyblock); + krb5_free_keyblock_contents (context, &keyblock); + } + if (flags & SC_REMOTE_SUBKEY) { + if (krb5_ret_keyblock (sp, &keyblock) != 0) + goto failure; + krb5_auth_con_setremotesubkey (context, ac, &keyblock); + krb5_free_keyblock_contents (context, &keyblock); + } + if (krb5_ret_uint32 (sp, &ac->local_seqnumber)) + goto failure; + if (krb5_ret_uint32 (sp, &ac->remote_seqnumber)) + goto failure; + + if (flags & SC_AUTHENTICATOR) { + if (krb5_ret_int64(sp, &tmp64)) + goto failure; + ac->authenticator->ctime = tmp64; + if (krb5_ret_int32(sp, &tmp)) + goto failure; + ac->authenticator->cusec = tmp; + } + + if (krb5_ret_int32 (sp, &tmp) != 0) + goto failure; + ac->keytype = tmp; + if (krb5_ret_int32 (sp, &tmp) != 0) + goto failure; + ac->cksumtype = tmp; + + /* names */ + if (flags & SC_SOURCE_NAME) { + if (krb5_ret_principal(sp, &ctx->source)) + goto failure; + } + + if (flags & SC_TARGET_NAME) { + if (krb5_ret_principal(sp, &ctx->target)) + goto failure; + } + + if (krb5_ret_int32 (sp, &tmp)) + goto failure; + ctx->flags = tmp; + if (krb5_ret_int32 (sp, &tmp)) + goto failure; + ctx->more_flags = tmp; + if (krb5_ret_int32 (sp, &tmp)) + goto failure; + ctx->state = 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->endtime = tmp; + + if (flags & SC_ORDER) { + ret = _gssapi_msg_order_import(minor_status, sp, &ctx->order); + if (ret) + goto failure; + } + + krb5_storage_free (sp); + + _gsskrb5i_is_cfx(context, ctx, (ctx->more_flags & LOCAL) == 0); + + *context_handle = (gss_ctx_id_t)ctx; + + return GSS_S_COMPLETE; + +failure: + krb5_auth_con_free (context, + ctx->auth_context); + if (ctx->source != NULL) + krb5_free_principal(context, ctx->source); + if (ctx->target != NULL) + krb5_free_principal(context, ctx->target); + if (localp) + krb5_free_address (context, localp); + if (remotep) + krb5_free_address (context, remotep); + if(ctx->order) + _gssapi_msg_order_destroy(&ctx->order); + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + krb5_storage_free (sp); + free (ctx); + *context_handle = GSS_C_NO_CONTEXT; + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/indicate_mechs.c b/third_party/heimdal/lib/gssapi/krb5/indicate_mechs.c new file mode 100644 index 0000000..6201378 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/indicate_mechs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997 - 2001, 2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_indicate_mechs + (OM_uint32 * minor_status, + gss_OID_set * mech_set + ) +{ + OM_uint32 ret, junk; + + ret = gss_create_empty_oid_set(minor_status, mech_set); + if (ret) + return ret; + + ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, mech_set); + if (ret) { + gss_release_oid_set(&junk, mech_set); + return ret; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/init.c b/third_party/heimdal/lib/gssapi/krb5/init.c new file mode 100644 index 0000000..325b2c4 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/init.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1997 - 2001, 2003, 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" + +static HEIMDAL_MUTEX context_mutex = HEIMDAL_MUTEX_INITIALIZER; +static int created_key; +static HEIMDAL_thread_key context_key; + +static void +destroy_context(void *ptr) +{ + krb5_context context = ptr; + + if (context == NULL) + return; + krb5_free_context(context); +} + +krb5_error_code +_gsskrb5_init (krb5_context *context) +{ + krb5_error_code ret = 0; + + HEIMDAL_MUTEX_lock(&context_mutex); + + if (!created_key) { + HEIMDAL_key_create(&context_key, destroy_context, ret); + if (ret) { + HEIMDAL_MUTEX_unlock(&context_mutex); + return ret; + } + created_key = 1; + } + HEIMDAL_MUTEX_unlock(&context_mutex); + + *context = HEIMDAL_getspecific(context_key); + if (*context == NULL) { + + ret = krb5_init_context(context); + if (ret == 0) { + krb5_add_et_list(*context, initialize_gk5_error_table_r); + HEIMDAL_setspecific(context_key, *context, ret); + if (ret) { + krb5_free_context(*context); + *context = NULL; + } + } + } + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c b/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c new file mode 100644 index 0000000..62b26ed --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/init_sec_context.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 1997 - 2008 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" + +static OM_uint32 +gsskrb5_set_authorization_data(OM_uint32 *, + krb5_context, + krb5_auth_context, + gss_const_name_t); + +/* + * copy the addresses from `input_chan_bindings' (if any) to + * the auth context `ac' + */ + +static OM_uint32 +set_addresses (krb5_context context, + krb5_auth_context ac, + const gss_channel_bindings_t input_chan_bindings) +{ + /* Port numbers are expected to be in application_data.value, + * initator's port first */ + + krb5_address initiator_addr, acceptor_addr; + krb5_error_code kret; + + if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS + || input_chan_bindings->application_data.length != + 2 * sizeof(ac->local_port)) + return 0; + + memset(&initiator_addr, 0, sizeof(initiator_addr)); + memset(&acceptor_addr, 0, sizeof(acceptor_addr)); + + ac->local_port = + *(int16_t *) input_chan_bindings->application_data.value; + + ac->remote_port = + *((int16_t *) input_chan_bindings->application_data.value + 1); + + kret = _gsskrb5i_address_to_krb5addr(context, + input_chan_bindings->acceptor_addrtype, + &input_chan_bindings->acceptor_address, + ac->remote_port, + &acceptor_addr); + if (kret) + return kret; + + kret = _gsskrb5i_address_to_krb5addr(context, + input_chan_bindings->initiator_addrtype, + &input_chan_bindings->initiator_address, + ac->local_port, + &initiator_addr); + if (kret) { + krb5_free_address (context, &acceptor_addr); + return kret; + } + + kret = krb5_auth_con_setaddrs(context, + ac, + &initiator_addr, /* local address */ + &acceptor_addr); /* remote address */ + + krb5_free_address (context, &initiator_addr); + krb5_free_address (context, &acceptor_addr); + +#if 0 + free(input_chan_bindings->application_data.value); + input_chan_bindings->application_data.value = NULL; + input_chan_bindings->application_data.length = 0; +#endif + + return kret; +} + +OM_uint32 +_gsskrb5_create_ctx( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + krb5_context context, + const gss_channel_bindings_t input_chan_bindings, + enum gss_ctx_id_t_state state) +{ + krb5_error_code kret; + gsskrb5_ctx ctx; + + *context_handle = NULL; + + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + ctx->auth_context = NULL; + ctx->deleg_auth_context = NULL; + ctx->source = NULL; + ctx->target = NULL; + ctx->kcred = NULL; + ctx->ccache = NULL; + ctx->state = state; + ctx->flags = 0; + ctx->more_flags = 0; + ctx->service_keyblock = NULL; + ctx->ticket = NULL; + krb5_data_zero(&ctx->fwd_data); + ctx->endtime = 0; + ctx->order = NULL; + ctx->crypto = NULL; + HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); + + kret = krb5_auth_con_init (context, &ctx->auth_context); + if (kret) { + *minor_status = kret; + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + free(ctx); + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_init (context, &ctx->deleg_auth_context); + if (kret) { + *minor_status = kret; + krb5_auth_con_free(context, ctx->auth_context); + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + free(ctx); + return GSS_S_FAILURE; + } + + kret = set_addresses(context, ctx->auth_context, input_chan_bindings); + if (kret) { + *minor_status = kret; + + krb5_auth_con_free(context, ctx->auth_context); + krb5_auth_con_free(context, ctx->deleg_auth_context); + + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + free(ctx); + return GSS_S_BAD_BINDINGS; + } + + kret = set_addresses(context, ctx->deleg_auth_context, input_chan_bindings); + if (kret) { + *minor_status = kret; + + krb5_auth_con_free(context, ctx->auth_context); + krb5_auth_con_free(context, ctx->deleg_auth_context); + + HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); + free(ctx); + return GSS_S_BAD_BINDINGS; + } + + /* + * We need a sequence number + */ + + krb5_auth_con_addflags(context, + ctx->auth_context, + KRB5_AUTH_CONTEXT_DO_SEQUENCE | + KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, + NULL); + + /* + * We need a sequence number + */ + + krb5_auth_con_addflags(context, + ctx->deleg_auth_context, + KRB5_AUTH_CONTEXT_DO_SEQUENCE | + KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, + NULL); + + *context_handle = (gss_ctx_id_t)ctx; + + return GSS_S_COMPLETE; +} + + +static OM_uint32 +gsskrb5_get_creds( + OM_uint32 * minor_status, + krb5_context context, + krb5_ccache ccache, + gsskrb5_ctx ctx, + gss_const_name_t target_name, + OM_uint32 time_req, + OM_uint32 * time_rec) +{ + OM_uint32 ret; + krb5_error_code kret; + krb5_creds this_cred; + OM_uint32 lifetime_rec; + + if (ctx->target) { + krb5_free_principal(context, ctx->target); + ctx->target = NULL; + } + if (ctx->kcred) { + krb5_free_creds(context, ctx->kcred); + ctx->kcred = NULL; + } + + ret = _gsskrb5_canon_name(minor_status, context, target_name, + &ctx->target); + if (ret) + return ret; + + memset(&this_cred, 0, sizeof(this_cred)); + this_cred.client = ctx->source; + this_cred.server = ctx->target; + + if (time_req && time_req != GSS_C_INDEFINITE) { + krb5_timestamp ts; + + krb5_timeofday (context, &ts); + this_cred.times.endtime = ts + time_req; + } else { + this_cred.times.endtime = 0; + } + + this_cred.session.keytype = KEYTYPE_NULL; + + kret = krb5_get_credentials(context, + 0, + ccache, + &this_cred, + &ctx->kcred); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + krb5_free_principal(context, ctx->target); + kret = krb5_copy_principal(context, ctx->kcred->server, &ctx->target); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + ctx->endtime = ctx->kcred->times.endtime; + + ret = _gsskrb5_lifetime_left(minor_status, context, + ctx->endtime, &lifetime_rec); + if (ret) return ret; + + if (lifetime_rec == 0) { + *minor_status = 0; + return GSS_S_CONTEXT_EXPIRED; + } + + if (time_rec) *time_rec = lifetime_rec; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +gsskrb5_initiator_ready( + OM_uint32 * minor_status, + gsskrb5_ctx ctx, + krb5_context context) +{ + OM_uint32 ret; + int32_t seq_number; + int is_cfx = 0; + OM_uint32 flags = ctx->flags; + + krb5_free_creds(context, ctx->kcred); + ctx->kcred = NULL; + + if (ctx->more_flags & CLOSE_CCACHE) + krb5_cc_close(context, ctx->ccache); + ctx->ccache = NULL; + + krb5_auth_con_getremoteseqnumber (context, ctx->auth_context, &seq_number); + + _gsskrb5i_is_cfx(context, ctx, 0); + is_cfx = (ctx->more_flags & IS_CFX); + + ret = _gssapi_msg_order_create(minor_status, + &ctx->order, + _gssapi_msg_order_f(flags), + seq_number, 0, is_cfx); + if (ret) return ret; + + ctx->state = INITIATOR_READY; + ctx->more_flags |= OPEN; + + return GSS_S_COMPLETE; +} + +/* + * handle delegated creds in init-sec-context + */ + +static void +do_delegation (krb5_context context, + krb5_auth_context ac, + krb5_ccache ccache, + krb5_creds *cred, + krb5_data *fwd_data, + uint32_t flagmask, + uint32_t *flags) +{ + krb5_error_code kret; + krb5_principal client; + const char *host; + + krb5_data_zero (fwd_data); + + kret = krb5_cc_get_principal(context, ccache, &client); + if (kret) + goto out; + + /* We can't generally enforce server.name_type == KRB5_NT_SRV_HST */ + if (cred->server->name.name_string.len < 2) + goto out; + host = krb5_principal_get_comp_string(context, cred->server, 1); + +#define FWDABLE 1 + kret = krb5_fwd_tgt_creds(context, ac, host, client, cred->server, ccache, + FWDABLE, fwd_data); + + out: + if (kret) + *flags &= ~flagmask; + else + *flags |= flagmask; + + if (client) + krb5_free_principal(context, client); +} + +/* + * first stage of init-sec-context + */ + +static OM_uint32 +init_auth +(OM_uint32 * minor_status, + gsskrb5_cred cred, + gsskrb5_ctx ctx, + krb5_context context, + gss_const_name_t name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret = GSS_S_FAILURE; + krb5_error_code kret; + krb5_data fwd_data; + OM_uint32 lifetime_rec; + + krb5_data_zero(&fwd_data); + + *minor_status = 0; + + if (actual_mech_type) + *actual_mech_type = GSS_KRB5_MECHANISM; + + if (cred == NULL) { + kret = krb5_cc_default (context, &ctx->ccache); + if (kret) { + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + ctx->more_flags |= CLOSE_CCACHE; + } else + ctx->ccache = cred->ccache; + + kret = krb5_cc_get_principal (context, ctx->ccache, &ctx->source); + if (kret) { + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + + /* + * This is hideous glue for (NFS) clients that wants to limit the + * available enctypes to what it can support (encryption in + * kernel). + */ + if (cred && cred->enctypes) + krb5_set_default_in_tkt_etypes(context, cred->enctypes); + + ret = gsskrb5_get_creds(minor_status, context, ctx->ccache, + ctx, name, time_req, time_rec); + if (ret) + goto failure; + + ret = gsskrb5_set_authorization_data(minor_status, context, + ctx->auth_context, name); + if (ret) + goto failure; + + ctx->endtime = ctx->kcred->times.endtime; + + ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); + if (ret) + goto failure; + + ret = _gsskrb5_lifetime_left(minor_status, + context, + ctx->endtime, + &lifetime_rec); + if (ret) + goto failure; + + if (lifetime_rec == 0) { + *minor_status = 0; + ret = GSS_S_CONTEXT_EXPIRED; + goto failure; + } + + krb5_auth_con_setkey(context, + ctx->auth_context, + &ctx->kcred->session); + + kret = krb5_auth_con_generatelocalsubkey(context, + ctx->auth_context, + &ctx->kcred->session); + if(kret) { + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + + return GSS_S_COMPLETE; + +failure: + if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) + krb5_cc_close(context, ctx->ccache); + ctx->ccache = NULL; + + return ret; + +} + +static OM_uint32 +init_auth_restart +(OM_uint32 * minor_status, + gsskrb5_cred cred, + gsskrb5_ctx ctx, + krb5_context context, + OM_uint32 req_flags, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret = GSS_S_FAILURE; + krb5_error_code kret; + krb5_flags ap_options; + krb5_data outbuf; + uint32_t flags; + krb5_data authenticator; + Checksum cksum; + krb5_enctype enctype; + krb5_data fwd_data, timedata; + int32_t offset = 0, oldoffset = 0; + uint32_t flagmask; + + krb5_data_zero(&outbuf); + krb5_data_zero(&fwd_data); + + *minor_status = 0; + + /* + * Check if our configuration requires us to follow the KDC's + * guidance. If so, we transmogrify the GSS_C_DELEG_FLAG into + * the GSS_C_DELEG_POLICY_FLAG. + */ + if ((context->flags & KRB5_CTX_F_ENFORCE_OK_AS_DELEGATE) + && (req_flags & GSS_C_DELEG_FLAG)) { + req_flags &= ~GSS_C_DELEG_FLAG; + req_flags |= GSS_C_DELEG_POLICY_FLAG; + } + + /* + * If the credential doesn't have ok-as-delegate, check if there + * is a realm setting and use that. + */ + if (!ctx->kcred->flags.b.ok_as_delegate) { + krb5_data data; + + ret = krb5_cc_get_config(context, ctx->ccache, NULL, + "realm-config", &data); + if (ret == 0) { + /* XXX 1 is use ok-as-delegate */ + if (data.length < 1 || ((((unsigned char *)data.data)[0]) & 1) == 0) + req_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG); + krb5_data_free(&data); + } + } + + flagmask = 0; + + /* if we used GSS_C_DELEG_POLICY_FLAG, trust KDC */ + if ((req_flags & GSS_C_DELEG_POLICY_FLAG) + && ctx->kcred->flags.b.ok_as_delegate) + flagmask |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG; + /* if there still is a GSS_C_DELEG_FLAG, use that */ + if (req_flags & GSS_C_DELEG_FLAG) + flagmask |= GSS_C_DELEG_FLAG; + + + flags = 0; + ap_options = 0; + if (flagmask & GSS_C_DELEG_FLAG) { + do_delegation (context, + ctx->deleg_auth_context, + ctx->ccache, ctx->kcred, + &fwd_data, flagmask, &flags); + } + + if (req_flags & GSS_C_MUTUAL_FLAG) { + flags |= GSS_C_MUTUAL_FLAG; + ap_options |= AP_OPTS_MUTUAL_REQUIRED; + } + + if (req_flags & GSS_C_REPLAY_FLAG) + flags |= GSS_C_REPLAY_FLAG; + if (req_flags & GSS_C_SEQUENCE_FLAG) + flags |= GSS_C_SEQUENCE_FLAG; +#if 0 + if (req_flags & GSS_C_ANON_FLAG) + ; /* XXX */ +#endif + if (req_flags & GSS_C_DCE_STYLE) { + /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */ + flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG; + ap_options |= AP_OPTS_MUTUAL_REQUIRED; + } + if (req_flags & GSS_C_IDENTIFY_FLAG) + flags |= GSS_C_IDENTIFY_FLAG; + if (req_flags & GSS_C_EXTENDED_ERROR_FLAG) + flags |= GSS_C_EXTENDED_ERROR_FLAG; + + if (req_flags & GSS_C_CONF_FLAG) { + flags |= GSS_C_CONF_FLAG; + } + if (req_flags & GSS_C_INTEG_FLAG) { + flags |= GSS_C_INTEG_FLAG; + } + if (cred == NULL || !(cred->cred_flags & GSS_CF_NO_CI_FLAGS)) { + flags |= GSS_C_CONF_FLAG; + flags |= GSS_C_INTEG_FLAG; + } + flags |= GSS_C_TRANS_FLAG; + + if (ret_flags) + *ret_flags = flags; + ctx->flags = flags; + ctx->more_flags |= LOCAL; + + ret = _gsskrb5_create_8003_checksum (minor_status, + input_chan_bindings, + flags, + &fwd_data, + &cksum); + krb5_data_free (&fwd_data); + if (ret) + goto failure; + + enctype = ctx->auth_context->keyblock->keytype; + + ret = krb5_cc_get_config(context, ctx->ccache, ctx->target, + "time-offset", &timedata); + if (ret == 0) { + if (timedata.length == 4) { + const u_char *p = timedata.data; + offset = ((uint32_t)p[0] << 24) + | ((uint32_t)p[1] << 16) + | ((uint32_t)p[2] << 8) + | ((uint32_t)p[3] << 0); + } + krb5_data_free(&timedata); + } + + if (offset) { + krb5_get_kdc_sec_offset (context, &oldoffset, NULL); + krb5_set_kdc_sec_offset (context, offset, -1); + } + + kret = _krb5_build_authenticator(context, + ctx->auth_context, + enctype, + ctx->kcred, + &cksum, + &authenticator, + KRB5_KU_AP_REQ_AUTH); + + if (kret) { + if (offset) + krb5_set_kdc_sec_offset (context, oldoffset, -1); + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + + kret = krb5_build_ap_req (context, + enctype, + ctx->kcred, + ap_options, + authenticator, + &outbuf); + if (offset) + krb5_set_kdc_sec_offset (context, oldoffset, -1); + if (kret) { + *minor_status = kret; + ret = GSS_S_FAILURE; + goto failure; + } + + if (flags & GSS_C_DCE_STYLE) { + output_token->value = outbuf.data; + output_token->length = outbuf.length; + } else { + ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token, + (u_char *)(intptr_t)"\x01\x00", + GSS_KRB5_MECHANISM); + krb5_data_free (&outbuf); + if (ret) + goto failure; + } + + free_Checksum(&cksum); + + if (flags & GSS_C_MUTUAL_FLAG) { + ctx->state = INITIATOR_WAIT_FOR_MUTUAL; + return GSS_S_CONTINUE_NEEDED; + } + + return gsskrb5_initiator_ready(minor_status, ctx, context); +failure: + if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) + krb5_cc_close(context, ctx->ccache); + ctx->ccache = NULL; + + return ret; +} + +static krb5_error_code +handle_error_packet(krb5_context context, + gsskrb5_ctx ctx, + krb5_data indata) +{ + krb5_error_code kret; + KRB_ERROR error; + + kret = krb5_rd_error(context, &indata, &error); + if (kret == 0) { + kret = krb5_error_from_rd_error(context, &error, NULL); + + /* save the time skrew for this host */ + if (kret == KRB5KRB_AP_ERR_SKEW) { + krb5_data timedata; + unsigned char p[4]; + int32_t t = error.stime - time(NULL); + + p[0] = (t >> 24) & 0xFF; + p[1] = (t >> 16) & 0xFF; + p[2] = (t >> 8) & 0xFF; + p[3] = (t >> 0) & 0xFF; + + timedata.data = p; + timedata.length = sizeof(p); + + krb5_cc_set_config(context, ctx->ccache, ctx->target, + "time-offset", &timedata); + + if ((ctx->more_flags & RETRIED) == 0) + ctx->state = INITIATOR_RESTART; + ctx->more_flags |= RETRIED; + } + free_KRB_ERROR (&error); + } + return kret; +} + + +static OM_uint32 +repl_mutual +(OM_uint32 * minor_status, + gsskrb5_ctx ctx, + krb5_context context, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret; + krb5_error_code kret; + krb5_data indata; + krb5_ap_rep_enc_part *repl; + + output_token->length = 0; + output_token->value = NULL; + + if (actual_mech_type) + *actual_mech_type = GSS_KRB5_MECHANISM; + + if (IS_DCE_STYLE(ctx)) { + /* There is no OID wrapping. */ + indata.length = input_token->length; + indata.data = input_token->value; + kret = krb5_rd_rep(context, + ctx->auth_context, + &indata, + &repl); + if (kret) { + ret = _gsskrb5_decapsulate(minor_status, + input_token, + &indata, + "\x03\x00", + GSS_KRB5_MECHANISM); + if (ret == GSS_S_COMPLETE) { + *minor_status = handle_error_packet(context, ctx, indata); + } else { + *minor_status = kret; + } + return GSS_S_FAILURE; + } + } else { + ret = _gsskrb5_decapsulate (minor_status, + input_token, + &indata, + "\x02\x00", + GSS_KRB5_MECHANISM); + if (ret == GSS_S_DEFECTIVE_TOKEN) { + /* check if there is an error token sent instead */ + ret = _gsskrb5_decapsulate (minor_status, + input_token, + &indata, + "\x03\x00", + GSS_KRB5_MECHANISM); + if (ret == GSS_S_COMPLETE) { + *minor_status = handle_error_packet(context, ctx, indata); + return GSS_S_FAILURE; + } + } + kret = krb5_rd_rep (context, + ctx->auth_context, + &indata, + &repl); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + krb5_free_ap_rep_enc_part (context, + repl); + + *minor_status = 0; + if (time_rec) + _gsskrb5_lifetime_left(minor_status, + context, + ctx->endtime, + time_rec); + if (ret_flags) + *ret_flags = ctx->flags; + + if (req_flags & GSS_C_DCE_STYLE) { + int32_t local_seq, remote_seq; + krb5_data outbuf; + + /* + * So DCE_STYLE is strange. The client echos the seq number + * that the server used in the server's mk_rep in its own + * mk_rep(). After when done, it resets to it's own seq number + * for the gss_wrap calls. + */ + + krb5_auth_con_getremoteseqnumber(context, ctx->auth_context, &remote_seq); + krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &local_seq); + krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, remote_seq); + + kret = krb5_mk_rep(context, ctx->auth_context, &outbuf); + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + /* reset local seq number */ + krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, local_seq); + + output_token->length = outbuf.length; + output_token->value = outbuf.data; + } + + return gsskrb5_initiator_ready(minor_status, ctx, context); +} + +/* + * gss_init_sec_context + */ + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context +(OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + gss_ctx_id_t * context_handle, + gss_const_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + krb5_context context; + gsskrb5_cred cred = (gsskrb5_cred)cred_handle; + gsskrb5_ctx ctx; + OM_uint32 ret; + + GSSAPI_KRB5_INIT (&context); + + output_token->length = 0; + output_token->value = NULL; + + if (context_handle == NULL) { + *minor_status = 0; + return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; + } + + if (ret_flags) + *ret_flags = 0; + if (time_rec) + *time_rec = 0; + + if (target_name == GSS_C_NO_NAME) { + if (actual_mech_type) + *actual_mech_type = GSS_C_NO_OID; + *minor_status = 0; + return GSS_S_BAD_NAME; + } + + if (mech_type != GSS_C_NO_OID && + !gss_oid_equal(mech_type, GSS_KRB5_MECHANISM)) + return GSS_S_BAD_MECH; + + if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) { + OM_uint32 ret1; + + if (*context_handle != GSS_C_NO_CONTEXT) { + *minor_status = 0; + return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; + } + + ret1 = _gsskrb5_create_ctx(minor_status, + context_handle, + context, + input_chan_bindings, + INITIATOR_START); + if (ret1) + return ret1; + } + + if (*context_handle == GSS_C_NO_CONTEXT) { + *minor_status = 0; + return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; + } + + ctx = (gsskrb5_ctx) *context_handle; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + again: + switch (ctx->state) { + case INITIATOR_START: + ret = init_auth(minor_status, + cred, + ctx, + context, + target_name, + mech_type, + req_flags, + time_req, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + if (ret != GSS_S_COMPLETE) + break; + fallthrough; + case INITIATOR_RESTART: + ret = init_auth_restart(minor_status, + cred, + ctx, + context, + req_flags, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + break; + case INITIATOR_WAIT_FOR_MUTUAL: + ret = repl_mutual(minor_status, + ctx, + context, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + if (ctx->state == INITIATOR_RESTART) + goto again; + break; + case INITIATOR_READY: + /* + * If we get there, the caller have called + * gss_init_sec_context() one time too many. + */ + _gsskrb5_set_status(EINVAL, "init_sec_context " + "called one time too many"); + *minor_status = EINVAL; + ret = GSS_S_BAD_STATUS; + break; + default: + _gsskrb5_set_status(EINVAL, "init_sec_context " + "invalid state %d for client", + (int)ctx->state); + *minor_status = EINVAL; + ret = GSS_S_BAD_STATUS; + break; + } + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* destroy context in case of error */ + if (GSS_ERROR(ret)) { + OM_uint32 min2; + _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); + } + + return ret; + +} + +static OM_uint32 +gsskrb5_set_authorization_data(OM_uint32 *minor_status, + krb5_context context, + krb5_auth_context auth_context, + gss_const_name_t gn) +{ + const CompositePrincipal *name = (const void *)gn; + AuthorizationData *ad; + krb5_error_code kret = 0; + size_t i; + + if (name->nameattrs == NULL || name->nameattrs->want_ad == NULL) + return GSS_S_COMPLETE; + + ad = name->nameattrs->want_ad; + for (i = 0; kret == 0 && i < ad->len; i++) { + kret = krb5_auth_con_add_AuthorizationData(context, auth_context, + ad->val[0].ad_type, + &ad->val[0].ad_data); + } + + if (kret) { + *minor_status = kret; + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_context.c b/third_party/heimdal/lib/gssapi/krb5/inquire_context.c new file mode 100644 index 0000000..e225c33 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_context.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1997, 2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_context ( + OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + gss_name_t * src_name, + gss_name_t * targ_name, + OM_uint32 * lifetime_rec, + gss_OID * mech_type, + OM_uint32 * ctx_flags, + int * locally_initiated, + int * open_context + ) +{ + krb5_context context; + OM_uint32 ret; + gsskrb5_ctx ctx = (gsskrb5_ctx)context_handle; + gss_name_t name; + + if (src_name) + *src_name = GSS_C_NO_NAME; + if (targ_name) + *targ_name = GSS_C_NO_NAME; + + GSSAPI_KRB5_INIT (&context); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + if (src_name) { + name = (gss_name_t)ctx->source; + ret = _gsskrb5_duplicate_name (minor_status, name, src_name); + if (ret) + goto failed; + } + + if (targ_name) { + name = (gss_name_t)ctx->target; + ret = _gsskrb5_duplicate_name (minor_status, name, targ_name); + if (ret) + goto failed; + } + + if (lifetime_rec) { + ret = _gsskrb5_lifetime_left(minor_status, + context, + ctx->endtime, + lifetime_rec); + if (ret) + goto failed; + } + + if (mech_type) + *mech_type = GSS_KRB5_MECHANISM; + + if (ctx_flags) + *ctx_flags = ctx->flags; + + if (locally_initiated) + *locally_initiated = ctx->more_flags & LOCAL; + + if (open_context) + *open_context = ctx->more_flags & OPEN; + + *minor_status = 0; + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return GSS_S_COMPLETE; + +failed: + if (src_name) + _gsskrb5_release_name(NULL, src_name); + if (targ_name) + _gsskrb5_release_name(NULL, targ_name); + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_cred.c b/third_party/heimdal/lib/gssapi/krb5/inquire_cred.c new file mode 100644 index 0000000..b7b67f7 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_cred.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1997, 2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred +(OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + gss_name_t * output_name, + OM_uint32 * lifetime, + gss_cred_usage_t * cred_usage, + gss_OID_set * mechanisms + ) +{ + 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 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 = GSS_C_NO_NAME; + if (cred_usage) + *cred_usage = GSS_C_BOTH; /* There's no NONE */ + if (mechanisms) + *mechanisms = GSS_C_NO_OID_SET; + + GSSAPI_KRB5_INIT (&context); + + if (cred_handle == GSS_C_NO_CREDENTIAL) { + /* + * 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_from(&aminor, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_ACCEPT, + GSS_C_NO_CRED_STORE, + &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_from(minor_status, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_INITIATE, + GSS_C_NO_CRED_STORE, + &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; + } + + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + if (output_name != NULL) { + 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 (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) { + 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; + ret = gss_add_oid_set_member(minor_status, + &cred->mechanisms->elements[0], + mechanisms); + if (ret) + goto out; + } + ret = GSS_S_COMPLETE; + +out: + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c b/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c new file mode 100644 index 0000000..6ce4994 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_mech.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2003, 2006, 2007 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred_by_mech ( + OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + const gss_OID mech_type, + gss_name_t * name, + OM_uint32 * initiator_lifetime, + OM_uint32 * acceptor_lifetime, + gss_cred_usage_t * cred_usage + ) +{ + gss_cred_usage_t usage; + 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); + if (maj_stat) + return maj_stat; + + if (initiator_lifetime) { + if (usage == GSS_C_INITIATE || usage == GSS_C_BOTH) + *initiator_lifetime = lifetime; + else + *initiator_lifetime = 0; + } + + if (acceptor_lifetime) { + if (usage == GSS_C_ACCEPT || usage == GSS_C_BOTH) + *acceptor_lifetime = lifetime; + else + *acceptor_lifetime = 0; + } + + if (cred_usage) + *cred_usage = usage; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c b/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c new file mode 100644 index 0000000..7dae3d2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_cred_by_oid.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_cred_by_oid + (OM_uint32 * minor_status, + gss_const_cred_id_t cred_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + krb5_context context; + gsskrb5_cred cred = (gsskrb5_cred)cred_handle; + krb5_error_code ret; + gss_buffer_desc buffer; + char *str; + + GSSAPI_KRB5_INIT (&context); + + if (gss_oid_equal(desired_object, GSS_KRB5_COPY_CCACHE_X) == 0) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + if (cred->ccache == NULL) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = krb5_cc_get_full_name(context, cred->ccache, &str); + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + buffer.value = str; + buffer.length = strlen(str); + + ret = gss_add_buffer_set_member(minor_status, &buffer, data_set); + if (ret != GSS_S_COMPLETE) + _gsskrb5_clear_status (); + + free(str); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c b/third_party/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c new file mode 100644 index 0000000..c6c6746 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_mechs_for_name.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_mechs_for_name ( + OM_uint32 * minor_status, + gss_const_name_t input_name, + gss_OID_set * mech_types + ) +{ + OM_uint32 ret; + + ret = gss_create_empty_oid_set(minor_status, mech_types); + if (ret) + return ret; + + ret = gss_add_oid_set_member(minor_status, + GSS_KRB5_MECHANISM, + mech_types); + if (ret) + gss_release_oid_set(NULL, mech_types); + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c b/third_party/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c new file mode 100644 index 0000000..65bd49c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_names_for_mech.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2003 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" + +static gss_OID name_list[] = { + GSS_C_NT_HOSTBASED_SERVICE, + GSS_C_NT_USER_NAME, + GSS_KRB5_NT_PRINCIPAL_NAME, + GSS_C_NT_EXPORT_NAME, + NULL +}; + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_names_for_mech ( + OM_uint32 * minor_status, + const gss_OID mechanism, + gss_OID_set * name_types + ) +{ + OM_uint32 ret; + int i; + + *minor_status = 0; + + if (gss_oid_equal(mechanism, GSS_KRB5_MECHANISM) == 0 && + gss_oid_equal(mechanism, GSS_C_NULL_OID) == 0) { + *name_types = GSS_C_NO_OID_SET; + return GSS_S_BAD_MECH; + } + + ret = gss_create_empty_oid_set(minor_status, name_types); + if (ret != GSS_S_COMPLETE) + return ret; + + for (i = 0; name_list[i] != NULL; i++) { + ret = gss_add_oid_set_member(minor_status, + name_list[i], + name_types); + if (ret != GSS_S_COMPLETE) + break; + } + + if (ret != GSS_S_COMPLETE) + gss_release_oid_set(NULL, name_types); + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c b/third_party/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c new file mode 100644 index 0000000..f572774 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/inquire_sec_context_by_oid.c @@ -0,0 +1,598 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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" + +static int +oid_prefix_equal(gss_OID oid_enc, gss_OID prefix_enc, unsigned *suffix) +{ + int ret; + heim_oid oid; + heim_oid prefix; + + *suffix = 0; + + ret = der_get_oid(oid_enc->elements, oid_enc->length, + &oid, NULL); + if (ret) { + return 0; + } + + ret = der_get_oid(prefix_enc->elements, prefix_enc->length, + &prefix, NULL); + if (ret) { + der_free_oid(&oid); + return 0; + } + + ret = 0; + + if (oid.length - 1 == prefix.length) { + *suffix = oid.components[oid.length - 1]; + oid.length--; + ret = (der_heim_oid_cmp(&oid, &prefix) == 0); + oid.length++; + } + + der_free_oid(&oid); + der_free_oid(&prefix); + + return ret; +} + +static OM_uint32 inquire_sec_context_tkt_flags + (OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + gss_buffer_set_t *data_set) +{ + OM_uint32 tkt_flags; + unsigned char buf[4]; + gss_buffer_desc value; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + if (context_handle->ticket == NULL) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + _gsskrb5_set_status(EINVAL, "No ticket from which to obtain flags"); + *minor_status = EINVAL; + return GSS_S_BAD_MECH; + } + + tkt_flags = TicketFlags2int(context_handle->ticket->ticket.flags); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + _gsskrb5_encode_om_uint32(tkt_flags, buf); + value.length = sizeof(buf); + value.value = buf; + + return gss_add_buffer_set_member(minor_status, + &value, + data_set); +} + +enum keytype { ACCEPTOR_KEY, INITIATOR_KEY, TOKEN_KEY }; + +static OM_uint32 inquire_sec_context_get_subkey + (OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + enum keytype keytype, + gss_buffer_set_t *data_set) +{ + krb5_keyblock *key = NULL; + krb5_storage *sp = NULL; + krb5_data data; + OM_uint32 maj_stat = GSS_S_COMPLETE; + krb5_error_code ret; + + krb5_data_zero(&data); + + sp = krb5_storage_emem(); + if (sp == NULL) { + _gsskrb5_clear_status(); + ret = ENOMEM; + goto out; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + switch(keytype) { + case ACCEPTOR_KEY: + ret = _gsskrb5i_get_acceptor_subkey(context_handle, context, &key); + break; + case INITIATOR_KEY: + ret = _gsskrb5i_get_initiator_subkey(context_handle, context, &key); + break; + case TOKEN_KEY: + ret = _gsskrb5i_get_token_key(context_handle, context, &key); + break; + default: + _gsskrb5_set_status(EINVAL, "%d is not a valid subkey type", keytype); + ret = EINVAL; + break; + } + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (ret) + goto out; + if (key == NULL) { + _gsskrb5_set_status(EINVAL, "have no subkey of type %d", keytype); + ret = EINVAL; + goto out; + } + + ret = krb5_store_keyblock(sp, *key); + if (ret) + goto out; + + ret = krb5_storage_to_data(sp, &data); + if (ret) + goto out; + + { + gss_buffer_desc value; + + value.length = data.length; + value.value = data.data; + + maj_stat = gss_add_buffer_set_member(minor_status, + &value, + data_set); + } + +out: + krb5_free_keyblock(context, key); + krb5_data_free(&data); + if (sp) + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + maj_stat = GSS_S_FAILURE; + } + return maj_stat; +} + +static OM_uint32 inquire_sec_context_get_sspi_session_key + (OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + gss_buffer_set_t *data_set) +{ + krb5_keyblock *key; + OM_uint32 maj_stat = GSS_S_COMPLETE; + krb5_error_code ret; + gss_buffer_desc value; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + ret = _gsskrb5i_get_token_key(context_handle, context, &key); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + if (ret) + goto out; + if (key == NULL) { + ret = EINVAL; + goto out; + } + + value.length = key->keyvalue.length; + value.value = key->keyvalue.data; + + maj_stat = gss_add_buffer_set_member(minor_status, + &value, + data_set); + krb5_free_keyblock(context, key); + + /* MIT also returns the enctype encoded as an OID in data_set[1] */ + +out: + if (ret) { + *minor_status = ret; + maj_stat = GSS_S_FAILURE; + } + return maj_stat; +} + +static OM_uint32 inquire_sec_context_authz_data + (OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + unsigned ad_type, + gss_buffer_set_t *data_set) +{ + krb5_data data; + gss_buffer_desc ad_data; + OM_uint32 ret; + + *minor_status = 0; + *data_set = GSS_C_NO_BUFFER_SET; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + if (context_handle->ticket == NULL) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + *minor_status = EINVAL; + _gsskrb5_set_status(EINVAL, "No ticket to obtain authz data from"); + return GSS_S_NO_CONTEXT; + } + + ret = krb5_ticket_get_authorization_data_type(context, + context_handle->ticket, + ad_type, + &data); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ad_data.value = data.data; + ad_data.length = data.length; + + ret = gss_add_buffer_set_member(minor_status, + &ad_data, + data_set); + + krb5_data_free(&data); + + return ret; +} + +static OM_uint32 inquire_sec_context_has_buggy_spnego + (OM_uint32 *minor_status, + const gsskrb5_ctx context_handle, + gss_buffer_set_t *data_set) +{ + uint8_t old_enctype; + gss_buffer_desc buffer; + + *minor_status = 0; + *data_set = GSS_C_NO_BUFFER_SET; + + /* + * For Windows SPNEGO implementations, the initiator or acceptor + * are presumed to be "buggy" (Windows 2003 or earlier) if an + * "older" (i.e. pre-AES per RFC 4121) encryption type was used. + */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + old_enctype = ((context_handle->more_flags & IS_CFX) == 0); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + buffer.value = &old_enctype; + buffer.length = sizeof(old_enctype); + + return gss_add_buffer_set_member(minor_status, &buffer, data_set); +} + +/* + * + */ + +static OM_uint32 +export_lucid_sec_context_v1(OM_uint32 *minor_status, + gsskrb5_ctx context_handle, + krb5_context context, + gss_buffer_set_t *data_set) +{ + krb5_storage *sp = NULL; + OM_uint32 major_status = GSS_S_COMPLETE; + krb5_error_code ret; + krb5_keyblock *key = NULL; + int32_t number; + int is_cfx; + krb5_data data; + + *minor_status = 0; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + is_cfx = (context_handle->more_flags & IS_CFX); + + sp = krb5_storage_emem(); + if (sp == NULL) { + _gsskrb5_clear_status(); + ret = ENOMEM; + goto out; + } + + ret = krb5_store_int32(sp, 1); + if (ret) goto out; + ret = krb5_store_int32(sp, (context_handle->more_flags & LOCAL) ? 1 : 0); + if (ret) goto out; + /* 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, + &number); + ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */ + if (ret) goto out; + ret = krb5_store_uint32(sp, (uint32_t)number); + if (ret) goto out; + krb5_auth_con_getremoteseqnumber (context, + context_handle->auth_context, + &number); + ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */ + if (ret) goto out; + ret = krb5_store_uint32(sp, (uint32_t)number); + if (ret) goto out; + ret = krb5_store_int32(sp, (is_cfx) ? 1 : 0); + if (ret) goto out; + + ret = _gsskrb5i_get_token_key(context_handle, context, &key); + if (ret) goto out; + + if (is_cfx == 0) { + int sign_alg, seal_alg; + + switch (key->keytype) { + case ETYPE_DES_CBC_CRC: + case ETYPE_DES_CBC_MD4: + case ETYPE_DES_CBC_MD5: + sign_alg = 0; + seal_alg = 0; + break; + case ETYPE_DES3_CBC_MD5: + case ETYPE_DES3_CBC_SHA1: + sign_alg = 4; + seal_alg = 2; + break; + case ETYPE_ARCFOUR_HMAC_MD5: + case ETYPE_ARCFOUR_HMAC_MD5_56: + sign_alg = 17; + seal_alg = 16; + break; + default: + sign_alg = -1; + seal_alg = -1; + break; + } + ret = krb5_store_int32(sp, sign_alg); + if (ret) goto out; + ret = krb5_store_int32(sp, seal_alg); + if (ret) goto out; + /* ctx_key */ + ret = krb5_store_keyblock(sp, *key); + if (ret) goto out; + } else { + int subkey_p = (context_handle->more_flags & ACCEPTOR_SUBKEY) ? 1 : 0; + + /* have_acceptor_subkey */ + ret = krb5_store_int32(sp, subkey_p); + if (ret) goto out; + /* ctx_key */ + ret = krb5_store_keyblock(sp, *key); + if (ret) goto out; + /* acceptor_subkey */ + if (subkey_p) { + ret = krb5_store_keyblock(sp, *key); + if (ret) goto out; + } + } + ret = krb5_storage_to_data(sp, &data); + if (ret) goto out; + + { + gss_buffer_desc ad_data; + + ad_data.value = data.data; + ad_data.length = data.length; + + ret = gss_add_buffer_set_member(minor_status, &ad_data, data_set); + krb5_data_free(&data); + if (ret) + goto out; + } + +out: + if (key) + krb5_free_keyblock (context, key); + if (sp) + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + } + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return major_status; +} + +static OM_uint32 +get_authtime(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + gss_buffer_set_t *data_set) + +{ + gss_buffer_desc value; + unsigned char buf[4]; + OM_uint32 authtime; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + if (ctx->ticket == NULL) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + _gsskrb5_set_status(EINVAL, "No ticket to obtain auth time from"); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + authtime = ctx->ticket->ticket.authtime; + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + _gsskrb5_encode_om_uint32(authtime, buf); + value.length = sizeof(buf); + value.value = buf; + + return gss_add_buffer_set_member(minor_status, + &value, + data_set); +} + + +static OM_uint32 +get_service_keyblock + (OM_uint32 *minor_status, + gsskrb5_ctx ctx, + gss_buffer_set_t *data_set) +{ + krb5_storage *sp = NULL; + krb5_data data; + OM_uint32 maj_stat = GSS_S_COMPLETE; + krb5_error_code ret = EINVAL; + + sp = krb5_storage_emem(); + if (sp == NULL) { + _gsskrb5_clear_status(); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + if (ctx->service_keyblock == NULL) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + krb5_storage_free(sp); + _gsskrb5_set_status(EINVAL, "No service keyblock on gssapi context"); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + krb5_data_zero(&data); + + ret = krb5_store_keyblock(sp, *ctx->service_keyblock); + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + if (ret) + goto out; + + ret = krb5_storage_to_data(sp, &data); + if (ret) + goto out; + + { + gss_buffer_desc value; + + value.length = data.length; + value.value = data.data; + + maj_stat = gss_add_buffer_set_member(minor_status, + &value, + data_set); + } + +out: + krb5_data_free(&data); + if (sp) + krb5_storage_free(sp); + if (ret) { + *minor_status = ret; + maj_stat = GSS_S_FAILURE; + } + return maj_stat; +} +/* + * + */ + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_sec_context_by_oid + (OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_OID desired_object, + gss_buffer_set_t *data_set) +{ + krb5_context context; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + unsigned suffix; + + if (ctx == NULL) { + *minor_status = EINVAL; + return GSS_S_NO_CONTEXT; + } + + GSSAPI_KRB5_INIT (&context); + + if (gss_oid_equal(desired_object, GSS_KRB5_GET_TKT_FLAGS_X)) { + return inquire_sec_context_tkt_flags(minor_status, + ctx, + data_set); + } else if (gss_oid_equal(desired_object, GSS_C_INQ_PEER_HAS_BUGGY_SPNEGO)) { + return inquire_sec_context_has_buggy_spnego(minor_status, + ctx, + data_set); + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) { + return inquire_sec_context_get_subkey(minor_status, + ctx, + context, + TOKEN_KEY, + data_set); + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X)) { + return inquire_sec_context_get_subkey(minor_status, + ctx, + context, + INITIATOR_KEY, + data_set); + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X)) { + return inquire_sec_context_get_subkey(minor_status, + ctx, + context, + ACCEPTOR_KEY, + data_set); + } else if (gss_oid_equal(desired_object, GSS_C_INQ_SSPI_SESSION_KEY)) { + return inquire_sec_context_get_sspi_session_key(minor_status, + ctx, + context, + data_set); + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_AUTHTIME_X)) { + return get_authtime(minor_status, ctx, data_set); + } else if (oid_prefix_equal(desired_object, + GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X, + &suffix)) { + return inquire_sec_context_authz_data(minor_status, + ctx, + context, + suffix, + data_set); + } else if (oid_prefix_equal(desired_object, + GSS_KRB5_EXPORT_LUCID_CONTEXT_X, + &suffix)) { + if (suffix == 1) + return export_lucid_sec_context_v1(minor_status, + ctx, + context, + data_set); + *minor_status = 0; + return GSS_S_FAILURE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SERVICE_KEYBLOCK_X)) { + return get_service_keyblock(minor_status, ctx, data_set); + } else { + *minor_status = 0; + return GSS_S_FAILURE; + } +} + diff --git a/third_party/heimdal/lib/gssapi/krb5/name_attrs.c b/third_party/heimdal/lib/gssapi/krb5/name_attrs.c new file mode 100644 index 0000000..11fc2ef --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/name_attrs.c @@ -0,0 +1,1171 @@ +/* + * Copyright (c) 2021 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" + +/* + * (Not-yet-)Standard name attributes for Kerberos MNs, + * GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "...". + * + * I.e., "urn:ietf:kerberos:nameattr-...". (XXX Register this URN namespace + * with IANA.) + * + * Note that we do use URN fragments. + * + * Specific attributes below the base URN: + * + * - name access attributes: + * - "realm" -> realm of name + * - "name-ncomp" -> count of name components + * - "name-ncomp#<digit>" -> name component N (0 <= N <= 9) + * + * Ticket and Authenticator access attributes: + * + * - "transit-path" -> encoding of the transited path + * - "authenticator-authz-data" -> encoding of all of the authz-data from + * the AP-REQ's Authenticator + * - "ticket-authz-data" -> encoding of all of the authz-data from + * the AP-REQ's Ticket + * - "ticket-authz-data#pac" -> the PAC + * - "authz-data#<N>" -> encoding of all of a specific auth-data + * element type N (e.g., 2, meaning + * AD-INTENDED-FOR-SERVER) + * + * Misc. attributes: + * + * - "peer-realm" -> name of peer's realm (if this is an MN + * resulting for establishing a security + * context) + * - "canonical-name" -> exported name token and RFC1964 display + * syntax of the name's canonical name + * + * Compatibility with MIT: + * + * - "urn:mspac:" -> the PAC and its individual info buffers + * + * TODO: + * + * - Add some sort of display syntax for transit path + * - Add support for URN q-components or attribute prefixes to specify + * alternative raw and/or display value encodings (JSON?) + * - Add support for attributes for accessing other parts of the Ticket / KDC + * reply enc-parts, like auth times + * - Add support for getting PAC logon fields, including SIDs (one at a time) + * - Add support for CAMMAC? + */ + +static int +attr_eq(gss_const_buffer_t attr, const char *aname, size_t aname_len, \ + int prefix_check) +{ + if (attr->length < aname_len) + return 0; + + if (strncmp((char *)attr->value, aname, aname_len) != 0) + return 0; + + return prefix_check || attr->length == aname_len; +} + +#define ATTR_EQ(a, an) (attr_eq(a, an, sizeof(an) - 1, FALSE)) +#define ATTR_EQ_PREFIX(a, an) (attr_eq(a, an, sizeof(an) - 1, TRUE)) + +/* Split attribute into prefix, suffix, and fragment. See RFC6680. */ +static void +split_attr(gss_const_buffer_t orig, + gss_buffer_t prefix, + gss_buffer_t attr, + gss_buffer_t frag, + int *is_urn) +{ + char *last = NULL; + char *p = orig->value; + + *attr = *orig; + prefix->value = orig->value; + prefix->length = 0; + frag->length = 0; + frag->value = NULL; + + /* FIXME We don't have a memrchr() in lib/roken */ + for (p = memchr(p, ' ', orig->length); + p; + p = memchr(p + 1, ' ', orig->length)) { + last = p; + prefix->length = last - (const char *)orig->value; + attr->value = last + 1; + attr->length = orig->length - (prefix->length + 1); + } + if (prefix->length == 0) + prefix->value = NULL; + + if ((*is_urn = (strncmp(attr->value, "urn:", sizeof("urn:") - 1) == 0)) && + (p = memchr((char *)attr->value + 1, '#', attr->length - 1))) { + frag->value = ++p; + frag->length = attr->length - (p - (const char *)attr->value); + attr->length = --p - (const char *)attr->value; + } +} + +typedef OM_uint32 get_name_attr_f(OM_uint32 *, + const CompositePrincipal *, + gss_const_buffer_t, + gss_const_buffer_t, + gss_const_buffer_t, + int *, + int *, + gss_buffer_t, + gss_buffer_t, + int *); + +typedef OM_uint32 set_name_attr_f(OM_uint32 *, + CompositePrincipal *, + gss_const_buffer_t, + gss_const_buffer_t, + gss_const_buffer_t, + int, + gss_buffer_t); + +typedef OM_uint32 del_name_attr_f(OM_uint32 *, + CompositePrincipal *, + gss_const_buffer_t, + gss_const_buffer_t, + gss_const_buffer_t); +typedef get_name_attr_f *get_name_attr_fp; +typedef set_name_attr_f *set_name_attr_fp; +typedef del_name_attr_f *del_name_attr_fp; + +static get_name_attr_f get_realm; +static get_name_attr_f get_ncomps; +static get_name_attr_f get_peer_realm; +static get_name_attr_f get_pac; +static get_name_attr_f get_pac_buffer; +static get_name_attr_f get_authz_data; +static get_name_attr_f get_ticket_authz_data; +static get_name_attr_f get_authenticator_authz_data; +static set_name_attr_f set_authenticator_authz_data; +static get_name_attr_f get_transited; +static get_name_attr_f get_canonical_name; + +#define NB(n) \ + GSS_KRB5_NAME_ATTRIBUTE_BASE_URN n, n, \ + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN n) - 1, \ + sizeof(n) - 1 +#define NM(n) \ + "urn:mspac:" n, n, sizeof("urn:mspac:" n) - 1, sizeof(n) - 1 + +static struct krb5_name_attrs { + const char *fullname; + const char *name; + size_t fullnamelen; + size_t namelen; + get_name_attr_fp getter; + set_name_attr_fp setter; + del_name_attr_fp deleter; + unsigned int indicate:1; + unsigned int is_krb5_name_attr_urn:1; +} name_attrs[] = { + /* XXX We should sort these so we can binary search them */ + { NB("realm"), get_realm, NULL, NULL, 1, 1 }, + { NB("name-ncomp"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#0"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#1"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#2"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#3"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#4"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#5"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#6"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#7"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#8"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("name-ncomp#9"), get_ncomps, NULL, NULL, 1, 1 }, + { NB("peer-realm"), get_peer_realm, NULL, NULL, 1, 1 }, + { NB("ticket-authz-data#pac"), get_pac, NULL, NULL, 1, 1 }, + { NM(""), get_pac, NULL, NULL, 1, 0 }, + { NM("logon-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("credentials-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("server-checksum"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("privsvr-checksum"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("client-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("delegation-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("upn-dns-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("ticket-checksum"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("attributes-info"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NM("requestor-sid"), get_pac_buffer, NULL, NULL, 1, 0 }, + { NB("ticket-authz-data#kdc-issued"), + get_ticket_authz_data, NULL, NULL, 1, 1 }, + { NB("ticket-authz-data"), + get_ticket_authz_data, NULL, NULL, 1, 1 }, + { NB("authenticator-authz-data"), + get_authenticator_authz_data, + set_authenticator_authz_data, NULL, 1, 1 }, + { NB("authz-data"), get_authz_data, NULL, NULL, 1, 1 }, + { NB("transit-path"), get_transited, NULL, NULL, 1, 1 }, + { NB("canonical-name"), get_canonical_name, NULL, NULL, 1, 1 }, +}; + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_get_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t original_attr, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + gss_buffer_desc prefix, attr, suffix, frag; + size_t i; + int is_krb5_name_attr_urn = 0; + int is_urn = 0; + + *minor_status = 0; + if (authenticated) + *authenticated = 0; + if (complete) + *complete = 0; + if (more) + *more = 0; + if (value) { + value->length = 0; + value->value = NULL; + } + if (display_value) { + display_value->length = 0; + display_value->value = NULL; + } + + suffix.value = NULL; + suffix.length = 0; + + split_attr(original_attr, &prefix, &attr, &frag, &is_urn); + + if (prefix.length || !is_urn) + return GSS_S_UNAVAILABLE; + + is_krb5_name_attr_urn = + ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN); + if (is_krb5_name_attr_urn) { + suffix.value = + (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1; + suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1); + } + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].getter) + continue; + if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) { + if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) { + if (!attr_eq(&attr, name_attrs[i].fullname, name_attrs[i].fullnamelen, 0)) + continue; + } else + continue; + + return name_attrs[i].getter(minor_status, + (const CompositePrincipal *)name, + &prefix, &attr, &frag, authenticated, + complete, value, display_value, more); + } + return GSS_S_UNAVAILABLE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_set_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + int complete, + gss_buffer_t original_attr, + gss_buffer_t value) +{ + gss_buffer_desc prefix, attr, suffix, frag; + size_t i; + int is_krb5_name_attr_urn = 0; + int is_urn = 0; + + *minor_status = 0; + + suffix.value = NULL; + suffix.length = 0; + + split_attr(original_attr, &prefix, &attr, &frag, &is_urn); + + if (prefix.length || !is_urn) + return GSS_S_UNAVAILABLE; + + is_krb5_name_attr_urn = + ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN); + if (is_krb5_name_attr_urn) { + suffix.value = + (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1; + suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1); + } + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].setter) + continue; + if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) { + if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) { + if (!attr_eq(&attr, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else + continue; + + return name_attrs[i].setter(minor_status, (CompositePrincipal *)name, + &prefix, &attr, &frag, complete, value); + } + return GSS_S_UNAVAILABLE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_delete_name_attribute(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t original_attr) +{ + gss_buffer_desc prefix, attr, suffix, frag; + size_t i; + int is_krb5_name_attr_urn = 0; + int is_urn = 0; + + *minor_status = 0; + + suffix.value = NULL; + suffix.length = 0; + + split_attr(original_attr, &prefix, &attr, &frag, &is_urn); + + if (prefix.length || !is_urn) + return GSS_S_UNAVAILABLE; + + is_krb5_name_attr_urn = + ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN); + if (is_krb5_name_attr_urn) { + suffix.value = + (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1; + suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1); + } + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].deleter) + continue; + if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) { + if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0)) + continue; + } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) { + if (!attr_eq(&attr, name_attrs[i].fullname, name_attrs[i].fullnamelen, 0)) + continue; + } else + continue; + + return name_attrs[i].deleter(minor_status, (CompositePrincipal *)name, + &prefix, &attr, &frag); + } + return GSS_S_UNAVAILABLE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_inquire_name(OM_uint32 *minor_status, + gss_name_t name, + int *name_is_MN, + gss_OID *MN_mech, + gss_buffer_set_t *attrs) +{ + gss_buffer_desc prefix, attr, frag, a; + OM_uint32 major = GSS_S_UNAVAILABLE; + size_t i; + int authenticated, is_urn; + + *minor_status = 0; + if (name_is_MN) + *name_is_MN = 1; + if (MN_mech) + *MN_mech = GSS_KRB5_MECHANISM; + if (name == GSS_C_NO_NAME) + return GSS_S_CALL_INACCESSIBLE_READ; + if (attrs == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) { + if (!name_attrs[i].indicate) + continue; + a.value = (void *)(uintptr_t)name_attrs[i].fullname; + a.length = name_attrs[i].fullnamelen; + split_attr(&a, &prefix, &attr, &frag, &is_urn); + major = name_attrs[i].getter(minor_status, + (const CompositePrincipal *)name, + &prefix, &attr, &frag, &authenticated, + NULL, NULL, NULL, NULL); + if (major == GSS_S_UNAVAILABLE) + continue; + if (major != GSS_S_COMPLETE) + break; + major = gss_add_buffer_set_member(minor_status, &a, attrs); + } + if (major == GSS_S_UNAVAILABLE) + major = GSS_S_COMPLETE; + return major; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_display_name_ext(OM_uint32 *minor_status, + gss_name_t name, + gss_OID display_as_name_type, + gss_buffer_t display_name) +{ + krb5_const_principal p = (void *)name; + char *s = NULL; + + *minor_status = 0; + if (display_name == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + display_name->length = 0; + display_name->value = NULL; + + if (gss_oid_equal(display_as_name_type, GSS_C_NT_USER_NAME)) { + if (p->name.name_string.len != 1) + return GSS_S_UNAVAILABLE; + return _gsskrb5_localname(minor_status, name, GSS_KRB5_MECHANISM, + display_name); + } + if (!gss_oid_equal(display_as_name_type, GSS_C_NT_HOSTBASED_SERVICE) || + p->name.name_string.len != 2 || + strchr(p->name.name_string.val[0], '@') || + strchr(p->name.name_string.val[1], '.') == NULL) + return GSS_S_UNAVAILABLE; + if (asprintf(&s, "%s@%s", p->name.name_string.val[0], + p->name.name_string.val[1]) == -1 || s == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + display_name->length = strlen(s); + display_name->value = s; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_export_name_composite(OM_uint32 *minor_status, + gss_name_t name, + gss_buffer_t exported_name) +{ + krb5_error_code kret; + gss_buffer_desc inner = GSS_C_EMPTY_BUFFER; + unsigned char *buf; + size_t sz; + + if (name == NULL) + return GSS_S_CALL_INACCESSIBLE_READ; + if (exported_name == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + + ASN1_MALLOC_ENCODE(CompositePrincipal, inner.value, inner.length, + (void *)name, &sz, kret); + if (kret != 0) { + *minor_status = kret; + return GSS_S_FAILURE; + } + + exported_name->length = 10 + inner.length + GSS_KRB5_MECHANISM->length; + exported_name->value = malloc(exported_name->length); + if (exported_name->value == NULL) { + free(inner.value); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + buf = exported_name->value; + buf[0] = 0x04; + buf[1] = 0x02; + buf[2] = ((GSS_KRB5_MECHANISM->length + 2) >> 8) & 0xff; + buf[3] = (GSS_KRB5_MECHANISM->length + 2) & 0xff; + buf[4] = 0x06; + buf[5] = (GSS_KRB5_MECHANISM->length) & 0xFF; + + memcpy(buf + 6, GSS_KRB5_MECHANISM->elements, GSS_KRB5_MECHANISM->length); + buf += 6 + GSS_KRB5_MECHANISM->length; + + buf[0] = (inner.length >> 24) & 0xff; + buf[1] = (inner.length >> 16) & 0xff; + buf[2] = (inner.length >> 8) & 0xff; + buf[3] = (inner.length) & 0xff; + buf += 4; + + memcpy(buf, inner.value, inner.length); + free(inner.value); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +#define CHECK_ENOMEM(v, dv) \ + do { \ + if (((v) && !(v)->value) || ((dv) && !(dv)->value)) { \ + if ((v) && (v)->value) { \ + free((v)->value); \ + (v)->length = 0; \ + (v)->value = NULL; \ + } \ + *minor_status = ENOMEM; \ + return GSS_S_FAILURE; \ + } \ + } while (0) + +static OM_uint32 +get_realm(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + PrincipalNameAttrs *nameattrs = name->nameattrs; + + if (prefix->length || frag->length || !name->realm) + return GSS_S_UNAVAILABLE; + if (authenticated && nameattrs && nameattrs->authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + if (value && (value->value = strdup(name->realm))) + value->length = strlen(name->realm); + if (display_value && (display_value->value = strdup(name->realm))) + display_value->length = strlen(name->realm); + CHECK_ENOMEM(value, display_value); + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_ncomps(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + PrincipalNameAttrs *nameattrs = name->nameattrs; + int n = -1; + + if (authenticated && nameattrs && nameattrs->authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + + if (frag->length == 1 && + ((const char *)frag->value)[0] >= '0' && + ((const char *)frag->value)[0] <= '9') { + n = ((const char *)frag->value)[0] - '0'; + } else if (frag->length == sizeof("all") - 1 && + strncmp(frag->value, "all", sizeof("all") - 1) == 0) { + if (!more || *more < -1 || *more == 0 || *more > CHAR_MAX || + *more > (int)name->name.name_string.len) { + *minor_status = EINVAL; + return GSS_S_UNAVAILABLE; + } + if (*more == -1) { + *more = name->name.name_string.len - 1; + n = 0; + } else { + n = name->name.name_string.len - *more; + (*more)--; + } + } + + if (frag->length == 0) { + char *s = NULL; + + /* Outut count of components */ + if (value && (value->value = malloc(sizeof(size_t)))) { + *((size_t *)value->value) = name->name.name_string.len; + value->length = sizeof(size_t); + } + if (display_value && + asprintf(&s, "%u", (unsigned int)name->name.name_string.len) > 0) { + display_value->value = s; + display_value->length = strlen(display_value->value); + } + } else { + /* + * Output a component. The value and the display value are the same in + * this case. + */ + if (n < 0 || n >= name->name.name_string.len) { + *minor_status = EINVAL; + return GSS_S_UNAVAILABLE; + } + if (value && (value->value = strdup(name->name.name_string.val[n]))) + value->length = strlen(name->name.name_string.val[n]); + if (display_value && + (display_value->value = strdup(name->name.name_string.val[n]))) + display_value->length = strlen(name->name.name_string.val[n]); + } + + CHECK_ENOMEM(value, display_value); + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_peer_realm(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + PrincipalNameAttrs *nameattrs = name->nameattrs; + + if (prefix->length || frag->length || !nameattrs || !nameattrs->peer_realm) + return GSS_S_UNAVAILABLE; + if (authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + if (value && (value->value = strdup(nameattrs->peer_realm[0]))) + value->length = strlen(value->value); + if (display_value && + (display_value->value = strdup(nameattrs->peer_realm[0]))) + display_value->length = strlen(display_value->value); + + CHECK_ENOMEM(value, display_value); + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_pac(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret; + krb5_context context; + krb5_data data; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + + krb5_data_zero(&data); + + if (src == NULL || + src->element != choice_PrincipalNameAttrSrc_enc_ticket_part) + return GSS_S_UNAVAILABLE; + + ticket = &src->u.enc_ticket_part; + + if (prefix->length || !authenticated || !ticket) + return GSS_S_UNAVAILABLE; + + GSSAPI_KRB5_INIT(&context); + + *authenticated = nameattrs->pac_verified; + if (complete) + *complete = 1; + + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, KRB5_AUTHDATA_WIN2K_PAC, + value ? &data : NULL); + + if (value) { + value->length = data.length; + value->value = data.data; + } + + *minor_status = kret; + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_pac_buffer(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret; + krb5_context context; + krb5_data data; + PrincipalNameAttrs *nameattrs = name->nameattrs; + krb5_data suffix; + + krb5_data_zero(&data); + + if (prefix->length || !authenticated || + !nameattrs || !nameattrs->pac) + return GSS_S_UNAVAILABLE; + + GSSAPI_KRB5_INIT(&context); + + if (ATTR_EQ_PREFIX(attr, "urn:mspac:")) { + suffix.length = attr->length - (sizeof("urn:mspac:") - 1); + suffix.data = (char *)attr->value + sizeof("urn:mspac:") - 1; + } else if (ATTR_EQ_PREFIX(frag, "pac-")) { + suffix.length = frag->length - sizeof("pac-") - 1; + suffix.data = (char *)frag->value + sizeof("pac-") - 1; + } else + return GSS_S_UNAVAILABLE; /* should not be reached */ + + *authenticated = nameattrs->pac_verified; + if (complete) + *complete = 1; + + kret = _krb5_pac_get_buffer_by_name(context, nameattrs->pac, &suffix, + value ? &data : NULL); + + if (value) { + value->length = data.length; + value->value = data.data; + } + + *minor_status = kret; + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_authz_data(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + krb5_context context; + krb5_data data; + char s[22]; + char *end; + int64_t n; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + default: + return GSS_S_UNAVAILABLE; + } + + if (!nameattrs || !frag->length || frag->length > sizeof(s) - 1) + return GSS_S_UNAVAILABLE; + + /* Output a specific AD element from the ticket or authenticator */ + krb5_data_zero(&data); + memcpy(s, frag->value, frag->length); + s[frag->length] = '\0'; + errno = 0; + n = strtoll(s, &end, 10); + if (end[0] == '\0' && (errno || n > INT_MAX || n < INT_MIN)) { + *minor_status = ERANGE; + return GSS_S_UNAVAILABLE; + } + if (end[0] != '\0') { + *minor_status = EINVAL; + return GSS_S_UNAVAILABLE; + } + + if (authenticated) + *authenticated = 0; + if (complete) + *complete = 1; + + GSSAPI_KRB5_INIT(&context); + + kret = ENOENT; + if (ticket && ticket->authorization_data) { + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, n, value ? &data : NULL); + + /* If it's from the ticket, it _may_ be authenticated: */ + if (kret == 0 && authenticated) { + if (n == KRB5_AUTHDATA_KDC_ISSUED) + *authenticated = nameattrs->kdc_issued_verified; + else if (n == KRB5_AUTHDATA_WIN2K_PAC) + *authenticated = nameattrs->pac_verified; + } + } + if (kret == ENOENT && nameattrs->authenticator_ad && + n != KRB5_AUTHDATA_KDC_ISSUED && + n != KRB5_AUTHDATA_WIN2K_PAC) { + kret = _krb5_get_ad(context, nameattrs->authenticator_ad, + NULL, n, value ? &data : NULL); + } + + if (value) { + value->length = data.length; + value->value = data.data; + } + *minor_status = kret; + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_ticket_authz_data(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + size_t sz; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + default: + return GSS_S_UNAVAILABLE; + } + + if (!ticket) + return GSS_S_UNAVAILABLE; + + if (complete) + *complete = 1; + + if (frag->length == sizeof("kdc-issued") - 1 && + strncmp(frag->value, "kdc-issued", sizeof("kdc-issued") - 1) == 0) { + krb5_context context; + krb5_data data; + + GSSAPI_KRB5_INIT(&context); + if (authenticated) + *authenticated = nameattrs->kdc_issued_verified; + + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, KRB5_AUTHDATA_KDC_ISSUED, + value ? &data : NULL); + if (value) { + value->length = data.length; + value->value = data.data; + } + if (kret == ENOENT) + return GSS_S_UNAVAILABLE; + *minor_status = kret; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; + } else if (frag->length) { + return GSS_S_UNAVAILABLE; + } + + /* Just because it's in the Ticket doesn't make it authenticated */ + if (authenticated) + *authenticated = 0; + + if (value) { + ASN1_MALLOC_ENCODE(AuthorizationData, value->value, value->length, + ticket->authorization_data, &sz, kret); + *minor_status = kret; + } + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_authenticator_authz_data(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + size_t sz; + + if (!nameattrs || !nameattrs->authenticator_ad) + return GSS_S_UNAVAILABLE; + if (authenticated) + *authenticated = 0; + if (complete) + *complete = 1; + + if (value) { + ASN1_MALLOC_ENCODE(AuthorizationData, value->value, value->length, + nameattrs->authenticator_ad, &sz, kret); + *minor_status = kret; + } + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +set_authenticator_authz_data(OM_uint32 *minor_status, + CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int complete, + gss_buffer_t value) +{ + AuthorizationDataElement e; + krb5_error_code kret; + size_t sz; + + if (!value) + return GSS_S_CALL_INACCESSIBLE_READ; + if (frag->length && + !ATTR_EQ(frag, "if-relevant")) + return GSS_S_UNAVAILABLE; + + if ((name->nameattrs == NULL && + (name->nameattrs = calloc(1, sizeof(*name->nameattrs))) == NULL) || + (name->nameattrs->want_ad == NULL && + (name->nameattrs->want_ad = + calloc(1, sizeof(*name->nameattrs->want_ad))) == NULL)) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memset(&e, 0, sizeof(e)); + kret = decode_AuthorizationDataElement(value->value, value->length, &e, + &sz); + if (kret == 0) { + if (frag->length) { + AuthorizationData ir; + + ir.len = 0; + ir.val = NULL; + kret = add_AuthorizationData(&ir, &e); + free_AuthorizationDataElement(&e); + if (kret == 0) { + e.ad_type = KRB5_AUTHDATA_IF_RELEVANT; + ASN1_MALLOC_ENCODE(AuthorizationData, e.ad_data.data, + e.ad_data.length, &ir, &sz, kret); + kret = add_AuthorizationData(name->nameattrs->want_ad, &e); + } + free_AuthorizationData(&ir); + } else { + kret = add_AuthorizationData(name->nameattrs->want_ad, &e); + free_AuthorizationDataElement(&e); + } + } + + *minor_status = kret; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_transited(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + EncTicketPart *ticket = NULL; + size_t sz; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + break; + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + default: + return GSS_S_UNAVAILABLE; + } + + if (!nameattrs && !ticket) + return GSS_S_UNAVAILABLE; + if (nameattrs && !nameattrs->transited && !ticket) + return GSS_S_UNAVAILABLE; + + if (authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + + if (value && ticket) + ASN1_MALLOC_ENCODE(TransitedEncoding, value->value, value->length, + &ticket->transited, &sz, kret); + else if (value && nameattrs->transited) + ASN1_MALLOC_ENCODE(TransitedEncoding, value->value, value->length, + nameattrs->transited, &sz, kret); + *minor_status = kret; + return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; +} + +static OM_uint32 +get_canonical_name(OM_uint32 *minor_status, + const CompositePrincipal *name, + gss_const_buffer_t prefix, + gss_const_buffer_t attr, + gss_const_buffer_t frag, + int *authenticated, + int *complete, + gss_buffer_t value, + gss_buffer_t display_value, + int *more) +{ + krb5_error_code kret = 0; + PrincipalNameAttrs *nameattrs = name->nameattrs; + PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL; + krb5_principal p = NULL; + krb5_context context; + EncTicketPart *ticket = NULL; + EncKDCRepPart *kdcrep = NULL; + + if (src) switch (src->element) { + case choice_PrincipalNameAttrSrc_enc_kdc_rep_part: + kdcrep = &src->u.enc_kdc_rep_part; + break; + case choice_PrincipalNameAttrSrc_enc_ticket_part: + ticket = &src->u.enc_ticket_part; + break; + default: + return GSS_S_UNAVAILABLE; + } + + GSSAPI_KRB5_INIT(&context); + + if (authenticated) + *authenticated = 1; + if (complete) + *complete = 1; + + if (kdcrep) { + kret = _krb5_principalname2krb5_principal(context, &p, + kdcrep->sname, + kdcrep->srealm); + } else if (nameattrs && nameattrs->pac && + (_krb5_pac_get_canon_principal(context, nameattrs->pac, &p)) == 0) { + if (authenticated) + *authenticated = nameattrs->pac_verified; + } else if (ticket) { + krb5_data data; + krb5_pac pac = NULL; + + krb5_data_zero(&data); + + /* Use canonical name from PAC if available */ + kret = _krb5_get_ad(context, ticket->authorization_data, + NULL, KRB5_AUTHDATA_WIN2K_PAC, &data); + if (kret == 0) + kret = krb5_pac_parse(context, data.data, data.length, &pac); + if (kret == 0) + kret = _krb5_pac_get_canon_principal(context, pac, &p); + if (kret == 0 && authenticated) + *authenticated = nameattrs->pac_verified; + else if (kret == ENOENT) + kret = _krb5_principalname2krb5_principal(context, &p, + ticket->cname, + ticket->crealm); + + krb5_data_free(&data); + krb5_pac_free(context, pac); + } else + return GSS_S_UNAVAILABLE; + if (kret == 0 && value) { + OM_uint32 major; + /* + * Value is exported name token (exported composite name token + * should also work). + */ + major = _gsskrb5_export_name(minor_status, (gss_name_t)p, value); + if (major != GSS_S_COMPLETE) { + krb5_free_principal(context, p); + return major; + } + } + if (kret == 0 && display_value) { + /* Display value is principal name display form */ + kret = krb5_unparse_name(context, p, + (char **)&display_value->value); + if (kret == 0) + display_value->length = strlen(display_value->value); + } + + krb5_free_principal(context, p); + if (kret) { + if (value) { + free(value->value); + value->length = 0; + value->value = NULL; + } + *minor_status = kret; + return GSS_S_UNAVAILABLE; + } + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/pname_to_uid.c b/third_party/heimdal/lib/gssapi/krb5/pname_to_uid.c new file mode 100644 index 0000000..dca7464 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/pname_to_uid.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011, PADL Software Pty Ltd. + * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_localname(OM_uint32 *minor_status, + gss_const_name_t pname, + const gss_OID mech_type, + gss_buffer_t localname) +{ + krb5_error_code ret; + krb5_context context; + krb5_const_principal princ = (krb5_const_principal)pname; + char lnamebuf[256]; + + GSSAPI_KRB5_INIT(&context); + + *minor_status = 0; + + ret = krb5_aname_to_localname(context, princ, + sizeof(lnamebuf), lnamebuf); + if (ret != 0) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + localname->length = strlen(lnamebuf); + + localname->value = malloc(localname->length + 1); + if (localname->value == NULL) { + localname->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy(localname->value, lnamebuf, localname->length + 1); + *minor_status = 0; + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/prf.c b/third_party/heimdal/lib/gssapi/krb5/prf.c new file mode 100644 index 0000000..671ab2c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/prf.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2007 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" + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_pseudo_random(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int prf_key, + const gss_buffer_t prf_in, + ssize_t desired_output_len, + gss_buffer_t prf_out) +{ + gsskrb5_ctx ctx = (gsskrb5_ctx)context_handle; + krb5_context context; + krb5_error_code ret; + krb5_crypto crypto; + krb5_data input, output; + uint32_t num; + OM_uint32 junk; + unsigned char *p; + krb5_keyblock *key = NULL; + size_t dol; + + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + + if (desired_output_len <= 0 || prf_in->length + 4 < prf_in->length) { + *minor_status = 0; + return GSS_S_FAILURE; + } + dol = desired_output_len; + + GSSAPI_KRB5_INIT (&context); + + switch(prf_key) { + case GSS_C_PRF_KEY_FULL: + _gsskrb5i_get_acceptor_subkey(ctx, context, &key); + break; + case GSS_C_PRF_KEY_PARTIAL: + _gsskrb5i_get_initiator_subkey(ctx, context, &key); + break; + default: + _gsskrb5_set_status(EINVAL, "unknown kerberos prf_key"); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (key == NULL) { + _gsskrb5_set_status(EINVAL, "no prf_key found"); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = krb5_crypto_init(context, key, 0, &crypto); + krb5_free_keyblock (context, key); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + prf_out->value = malloc(dol); + if (prf_out->value == NULL) { + _gsskrb5_set_status(GSS_KRB5_S_KG_INPUT_TOO_LONG, "Out of memory"); + *minor_status = GSS_KRB5_S_KG_INPUT_TOO_LONG; + krb5_crypto_destroy(context, crypto); + return GSS_S_FAILURE; + } + prf_out->length = dol; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + input.length = prf_in->length + 4; + input.data = malloc(prf_in->length + 4); + if (input.data == NULL) { + _gsskrb5_set_status(GSS_KRB5_S_KG_INPUT_TOO_LONG, "Out of memory"); + *minor_status = GSS_KRB5_S_KG_INPUT_TOO_LONG; + gss_release_buffer(&junk, prf_out); + krb5_crypto_destroy(context, crypto); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return GSS_S_FAILURE; + } + memcpy(((uint8_t *)input.data) + 4, prf_in->value, prf_in->length); + + num = 0; + p = prf_out->value; + while(dol > 0) { + size_t tsize; + + _gsskrb5_encode_be_om_uint32(num, input.data); + + ret = krb5_crypto_prf(context, crypto, &input, &output); + if (ret) { + *minor_status = ret; + free(input.data); + gss_release_buffer(&junk, prf_out); + krb5_crypto_destroy(context, crypto); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return GSS_S_FAILURE; + } + + tsize = min(dol, output.length); + memcpy(p, output.data, tsize); + p += tsize; + dol -= tsize; + krb5_data_free(&output); + num++; + } + free(input.data); + + krb5_crypto_destroy(context, crypto); + + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/process_context_token.c b/third_party/heimdal/lib/gssapi/krb5/process_context_token.c new file mode 100644 index 0000000..601b0e8 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/process_context_token.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_process_context_token ( + OM_uint32 *minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t token_buffer + ) +{ + krb5_context context; + OM_uint32 ret = GSS_S_FAILURE; + gss_buffer_desc empty_buffer; + + empty_buffer.length = 0; + empty_buffer.value = NULL; + + GSSAPI_KRB5_INIT (&context); + + ret = _gsskrb5_verify_mic_internal(minor_status, + (gsskrb5_ctx)context_handle, + context, + token_buffer, &empty_buffer, + GSS_C_QOP_DEFAULT, + "\x01\x02"); + + if (ret == GSS_S_COMPLETE) + ret = _gsskrb5_delete_sec_context(minor_status, + rk_UNCONST(&context_handle), + GSS_C_NO_BUFFER); + if (ret == GSS_S_COMPLETE) + *minor_status = 0; + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/release_buffer.c b/third_party/heimdal/lib/gssapi/krb5/release_buffer.c new file mode 100644 index 0000000..b704e00 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/release_buffer.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1997 - 2000, 2003 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" + +OM_uint32 _gsskrb5_release_buffer + (OM_uint32 * minor_status, + gss_buffer_t buffer + ) +{ + *minor_status = 0; + free (buffer->value); + buffer->value = NULL; + buffer->length = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/release_cred.c b/third_party/heimdal/lib/gssapi/krb5/release_cred.c new file mode 100644 index 0000000..e1bb870 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/release_cred.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1997-2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_release_cred + (OM_uint32 * minor_status, + gss_cred_id_t * cred_handle + ) +{ + krb5_context context; + gsskrb5_cred cred; + OM_uint32 junk; + + *minor_status = 0; + + if (*cred_handle == NULL) + return GSS_S_COMPLETE; + + cred = (gsskrb5_cred)*cred_handle; + *cred_handle = GSS_C_NO_CREDENTIAL; + + GSSAPI_KRB5_INIT (&context); + + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + free(cred->destination_realm); + if (cred->principal != NULL) + krb5_free_principal(context, cred->principal); + if (cred->keytab != NULL) + krb5_kt_close(context, cred->keytab); + if (cred->ccache != NULL) { + if (cred->cred_flags & GSS_CF_DESTROY_CRED_ON_RELEASE) + krb5_cc_destroy(context, cred->ccache); + else + krb5_cc_close(context, cred->ccache); + } + gss_release_oid_set(&junk, &cred->mechanisms); + if (cred->enctypes) + free(cred->enctypes); + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + HEIMDAL_MUTEX_destroy(&cred->cred_id_mutex); + memset(cred, 0, sizeof(*cred)); + free(cred); + return GSS_S_COMPLETE; +} + diff --git a/third_party/heimdal/lib/gssapi/krb5/release_name.c b/third_party/heimdal/lib/gssapi/krb5/release_name.c new file mode 100644 index 0000000..57fc8a4 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/release_name.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1997 - 2003 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" + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_release_name + (OM_uint32 * minor_status, + gss_name_t * input_name + ) +{ + krb5_context context; + krb5_principal name = (krb5_principal)*input_name; + + *minor_status = 0; + + GSSAPI_KRB5_INIT (&context); + + *input_name = GSS_C_NO_NAME; + + krb5_free_principal(context, name); + + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/sequence.c b/third_party/heimdal/lib/gssapi/krb5/sequence.c new file mode 100644 index 0000000..2e0e7b2 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/sequence.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2003 - 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" + +#define DEFAULT_JITTER_WINDOW 20 + +struct gss_msg_order { + OM_uint32 flags; + OM_uint32 start; + OM_uint32 length; + OM_uint32 jitter_window; + OM_uint32 first_seq; + OM_uint32 elem[1]; +}; + + +/* + * + */ + +static OM_uint32 +msg_order_alloc(OM_uint32 *minor_status, + struct gss_msg_order **o, + OM_uint32 jitter_window) +{ + size_t len; + + len = jitter_window * sizeof((*o)->elem[0]); + len += sizeof(**o); + len -= sizeof((*o)->elem[0]); + + *o = calloc(1, len); + if (*o == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +/* + * + */ + +OM_uint32 +_gssapi_msg_order_create(OM_uint32 *minor_status, + struct gss_msg_order **o, + OM_uint32 flags, + OM_uint32 seq_num, + OM_uint32 jitter_window, + int use_64) +{ + OM_uint32 ret; + + if (jitter_window == 0) + jitter_window = DEFAULT_JITTER_WINDOW; + + ret = msg_order_alloc(minor_status, o, jitter_window); + if(ret != GSS_S_COMPLETE) + return ret; + + (*o)->flags = flags; + (*o)->length = 0; + (*o)->first_seq = seq_num; + (*o)->jitter_window = jitter_window; + (*o)->elem[0] = seq_num - 1; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_msg_order_destroy(struct gss_msg_order **m) +{ + free(*m); + *m = NULL; + return GSS_S_COMPLETE; +} + +static void +elem_set(struct gss_msg_order *o, unsigned int slot, OM_uint32 val) +{ + o->elem[slot % o->jitter_window] = val; +} + +static void +elem_insert(struct gss_msg_order *o, + unsigned int after_slot, + OM_uint32 seq_num) +{ + assert(o->jitter_window > after_slot); + + if (o->length > after_slot) + memmove(&o->elem[after_slot + 1], &o->elem[after_slot], + (o->length - after_slot - 1) * sizeof(o->elem[0])); + + elem_set(o, after_slot, seq_num); + + if (o->length < o->jitter_window) + o->length++; +} + +/* rule 1: expected sequence number */ +/* rule 2: > expected sequence number */ +/* rule 3: seqnum < seqnum(first) */ +/* rule 4+5: seqnum in [seqnum(first),seqnum(last)] */ + +OM_uint32 +_gssapi_msg_order_check(struct gss_msg_order *o, OM_uint32 seq_num) +{ + OM_uint32 r; + size_t i; + + if (o == NULL) + return GSS_S_COMPLETE; + + if ((o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) == 0) + return GSS_S_COMPLETE; + + /* check if the packet is the next in order */ + if (o->elem[0] == seq_num - 1) { + elem_insert(o, 0, seq_num); + return GSS_S_COMPLETE; + } + + r = (o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG))==GSS_C_REPLAY_FLAG; + + /* sequence number larger then largest sequence number + * or smaller then the first sequence number */ + if (seq_num > o->elem[0] + || seq_num < o->first_seq + || o->length == 0) + { + elem_insert(o, 0, seq_num); + if (r) { + return GSS_S_COMPLETE; + } else { + return GSS_S_GAP_TOKEN; + } + } + + assert(o->length > 0); + + /* sequence number smaller the first sequence number */ + if (seq_num < o->elem[o->length - 1]) { + if (r) + return(GSS_S_OLD_TOKEN); + else + return(GSS_S_UNSEQ_TOKEN); + } + + if (seq_num == o->elem[o->length - 1]) { + return GSS_S_DUPLICATE_TOKEN; + } + + for (i = 0; i < o->length - 1; i++) { + if (o->elem[i] == seq_num) + return GSS_S_DUPLICATE_TOKEN; + if (o->elem[i + 1] < seq_num && o->elem[i] < seq_num) { + elem_insert(o, i, seq_num); + if (r) + return GSS_S_COMPLETE; + else + return GSS_S_UNSEQ_TOKEN; + } + } + + return GSS_S_FAILURE; +} + +OM_uint32 +_gssapi_msg_order_f(OM_uint32 flags) +{ + return flags & (GSS_C_SEQUENCE_FLAG|GSS_C_REPLAY_FLAG); +} + +/* + * Translate `o` into inter-process format and export in to `sp'. + */ + +krb5_error_code +_gssapi_msg_order_export(krb5_storage *sp, struct gss_msg_order *o) +{ + krb5_error_code kret; + OM_uint32 i; + + kret = krb5_store_int32(sp, o->flags); + if (kret) + return kret; + kret = krb5_store_int32(sp, o->start); + if (kret) + return kret; + kret = krb5_store_int32(sp, o->length); + if (kret) + return kret; + kret = krb5_store_int32(sp, o->jitter_window); + if (kret) + return kret; + kret = krb5_store_int32(sp, o->first_seq); + if (kret) + return kret; + + for (i = 0; i < o->jitter_window; i++) { + kret = krb5_store_int32(sp, o->elem[i]); + if (kret) + return kret; + } + + return 0; +} + +OM_uint32 +_gssapi_msg_order_import(OM_uint32 *minor_status, + krb5_storage *sp, + struct gss_msg_order **o) +{ + OM_uint32 ret; + krb5_error_code kret; + int32_t i, flags, start, length, jitter_window, first_seq; + + kret = krb5_ret_int32(sp, &flags); + if (kret) + goto failed; + kret = krb5_ret_int32(sp, &start); + if (kret) + goto failed; + kret = krb5_ret_int32(sp, &length); + if (kret) + goto failed; + kret = krb5_ret_int32(sp, &jitter_window); + if (kret) + goto failed; + kret = krb5_ret_int32(sp, &first_seq); + if (kret) + goto failed; + + ret = msg_order_alloc(minor_status, o, jitter_window); + if (ret != GSS_S_COMPLETE) + return ret; + + (*o)->flags = flags; + (*o)->start = start; + (*o)->length = length; + (*o)->jitter_window = jitter_window; + (*o)->first_seq = first_seq; + + for( i = 0; i < jitter_window; i++ ) { + kret = krb5_ret_int32(sp, (int32_t*)&((*o)->elem[i])); + if (kret) + goto failed; + } + + *minor_status = 0; + return GSS_S_COMPLETE; + +failed: + _gssapi_msg_order_destroy(o); + *minor_status = kret; + return GSS_S_FAILURE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/set_cred_option.c b/third_party/heimdal/lib/gssapi/krb5/set_cred_option.c new file mode 100644 index 0000000..ef177a0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/set_cred_option.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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" + +static OM_uint32 +import_cred(OM_uint32 *minor_status, + krb5_context context, + gss_cred_id_t *cred_handle, + const gss_buffer_t value) +{ + OM_uint32 major_stat; + krb5_error_code ret; + krb5_principal keytab_principal = NULL; + krb5_keytab keytab = NULL; + krb5_storage *sp = NULL; + krb5_ccache id = NULL; + char *str; + + if (cred_handle == NULL || *cred_handle != GSS_C_NO_CREDENTIAL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + + sp = krb5_storage_from_mem(value->value, value->length); + if (sp == NULL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + + /* credential cache name */ + ret = krb5_ret_string(sp, &str); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + if (str[0]) { + ret = krb5_cc_resolve(context, str, &id); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + } + free(str); + str = NULL; + + /* keytab principal name */ + ret = krb5_ret_string(sp, &str); + if (ret == 0 && str[0]) + ret = krb5_parse_name(context, str, &keytab_principal); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + free(str); + str = NULL; + + /* keytab principal */ + ret = krb5_ret_string(sp, &str); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + if (str[0]) { + ret = krb5_kt_resolve(context, str, &keytab); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + } + free(str); + str = NULL; + + major_stat = _gsskrb5_krb5_import_cred(minor_status, &id, keytab_principal, + keytab, cred_handle); +out: + if (id) + krb5_cc_close(context, id); + if (keytab_principal) + krb5_free_principal(context, keytab_principal); + if (keytab) + krb5_kt_close(context, keytab); + if (str) + free(str); + if (sp) + krb5_storage_free(sp); + + return major_stat; +} + + +static OM_uint32 +allowed_enctypes(OM_uint32 *minor_status, + krb5_context context, + gss_cred_id_t *cred_handle, + const gss_buffer_t value) +{ + OM_uint32 major_stat; + krb5_error_code ret; + size_t len, i; + krb5_enctype *enctypes = NULL; + krb5_storage *sp = NULL; + gsskrb5_cred cred; + + if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + + cred = (gsskrb5_cred)*cred_handle; + + if ((value->length % 4) != 0) { + *minor_status = 0; + major_stat = GSS_S_FAILURE; + goto out; + } + + /* serialized as int32_t[], but stored as krb5_enctype[] */ + len = value->length / 4; + enctypes = malloc((len + 1) * sizeof(krb5_enctype)); + if (enctypes == NULL) { + *minor_status = ENOMEM; + major_stat = GSS_S_FAILURE; + goto out; + } + + sp = krb5_storage_from_mem(value->value, value->length); + if (sp == NULL) { + *minor_status = ENOMEM; + major_stat = GSS_S_FAILURE; + goto out; + } + + for (i = 0; i < len; i++) { + int32_t e; + + ret = krb5_ret_int32(sp, &e); + if (ret) { + *minor_status = ret; + major_stat = GSS_S_FAILURE; + goto out; + } + enctypes[i] = e; + } + enctypes[i] = KRB5_ENCTYPE_NULL; + + if (cred->enctypes) + free(cred->enctypes); + cred->enctypes = enctypes; + + krb5_storage_free(sp); + + return GSS_S_COMPLETE; + +out: + if (sp) + krb5_storage_free(sp); + if (enctypes) + free(enctypes); + + return major_stat; +} + +static OM_uint32 +no_ci_flags(OM_uint32 *minor_status, + krb5_context context, + gss_cred_id_t *cred_handle, + const gss_buffer_t value) +{ + gsskrb5_cred cred; + + if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + + cred = (gsskrb5_cred)*cred_handle; + cred->cred_flags |= GSS_CF_NO_CI_FLAGS; + + *minor_status = 0; + return GSS_S_COMPLETE; + +} + + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_set_cred_option + (OM_uint32 *minor_status, + gss_cred_id_t *cred_handle, + const gss_OID desired_object, + const gss_buffer_t value) +{ + krb5_context context; + + GSSAPI_KRB5_INIT (&context); + + if (value == GSS_C_NO_BUFFER) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (gss_oid_equal(desired_object, GSS_KRB5_IMPORT_CRED_X)) + return import_cred(minor_status, context, cred_handle, value); + + if (gss_oid_equal(desired_object, GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X)) + return allowed_enctypes(minor_status, context, cred_handle, value); + + if (gss_oid_equal(desired_object, GSS_KRB5_CRED_NO_CI_FLAGS_X)) { + return no_ci_flags(minor_status, context, cred_handle, value); + } + + + *minor_status = EINVAL; + return GSS_S_FAILURE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/set_sec_context_option.c b/third_party/heimdal/lib/gssapi/krb5/set_sec_context_option.c new file mode 100644 index 0000000..3a6f86b --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/set_sec_context_option.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2004, PADL Software Pty Ltd. + * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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. + */ + +/* + * glue routine for _gsskrb5_inquire_sec_context_by_oid + */ + +#include "gsskrb5_locl.h" + +static OM_uint32 +get_bool(OM_uint32 *minor_status, + const gss_buffer_t value, + int *flag) +{ + if (value->value == NULL || value->length != 1) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + *flag = *((const char *)value->value) != 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_string(OM_uint32 *minor_status, + const gss_buffer_t value, + char **str) +{ + if (value == NULL || value->length == 0) { + *str = NULL; + } else { + *str = malloc(value->length + 1); + if (*str == NULL) { + *minor_status = 0; + return GSS_S_UNAVAILABLE; + } + memcpy(*str, value->value, value->length); + (*str)[value->length] = '\0'; + } + return GSS_S_COMPLETE; +} + +static OM_uint32 +get_int32(OM_uint32 *minor_status, + const gss_buffer_t value, + OM_uint32 *ret) +{ + *minor_status = 0; + if (value == NULL || value->length == 0) + *ret = 0; + else if (value->length == sizeof(*ret)) + memcpy(ret, value->value, sizeof(*ret)); + else + return GSS_S_UNAVAILABLE; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +set_int32(OM_uint32 *minor_status, + const gss_buffer_t value, + OM_uint32 set) +{ + *minor_status = 0; + if (value->length == sizeof(set)) + memcpy(value->value, &set, sizeof(set)); + else + return GSS_S_UNAVAILABLE; + + return GSS_S_COMPLETE; +} + +/* + * GSS_KRB5_IMPORT_RFC4121_CONTEXT_X is an internal, private interface + * to allow SAnon to create a skeletal context for using RFC4121 message + * protection services. + * + * rfc4121_args ::= initiator_flag || flags || enctype || session key + */ +static OM_uint32 +make_rfc4121_context(OM_uint32 *minor, + krb5_context context, + gss_ctx_id_t *context_handle, + gss_const_buffer_t rfc4121_args) +{ + OM_uint32 major = GSS_S_FAILURE, tmp; + krb5_error_code ret; + krb5_storage *sp = NULL; + gsskrb5_ctx ctx = NULL; + uint8_t initiator_flag; + int32_t enctype; + size_t keysize; + krb5_keyblock *key; + + *minor = 0; + + sp = krb5_storage_from_readonly_mem(rfc4121_args->value, rfc4121_args->length); + if (sp == NULL) { + ret = ENOMEM; + goto out; + } + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST); + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + ret = ENOMEM; + goto out; + } + + ret = krb5_ret_uint8(sp, &initiator_flag); + if (ret != 0) + goto out; + + ret = krb5_ret_uint32(sp, &ctx->flags); + if (ret != 0) + goto out; + + ctx->more_flags = IS_CFX | ACCEPTOR_SUBKEY | OPEN; + if (initiator_flag) + ctx->more_flags |= LOCAL; + + ctx->state = initiator_flag ? INITIATOR_READY : ACCEPTOR_READY; + + ret = krb5_ret_int32(sp, &enctype); + if (ret != 0) + goto out; + + ret = krb5_enctype_keysize(context, enctype, &keysize); + if (ret != 0) + goto out; + + ctx->auth_context = calloc(1, sizeof(*ctx->auth_context)); + if (ctx->auth_context == NULL) { + ret = ENOMEM; + goto out; + } + + key = calloc(1, sizeof(*key)); + if (key == NULL) { + ret = ENOMEM; + goto out; + } + if (initiator_flag) + ctx->auth_context->remote_subkey = key; + else + ctx->auth_context->local_subkey = key; + + key->keytype = enctype; + key->keyvalue.data = malloc(keysize); + if (key->keyvalue.data == NULL) { + ret = ENOMEM; + goto out; + } + + if (krb5_storage_read(sp, key->keyvalue.data, keysize) != keysize) { + ret = EINVAL; + goto out; + } + key->keyvalue.length = keysize; + + ret = krb5_crypto_init(context, key, 0, &ctx->crypto); + if (ret != 0) + goto out; + + major = _gssapi_msg_order_create(minor, &ctx->order, + _gssapi_msg_order_f(ctx->flags), + 0, 0, 1); + if (major != GSS_S_COMPLETE) + goto out; + +out: + krb5_storage_free(sp); + + if (major != GSS_S_COMPLETE) { + if (*minor == 0) + *minor = ret; + _gsskrb5_delete_sec_context(&tmp, (gss_ctx_id_t *)&ctx, GSS_C_NO_BUFFER); + } else { + *context_handle = (gss_ctx_id_t)ctx; + } + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_set_sec_context_option + (OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + const gss_OID desired_object, + const gss_buffer_t value) +{ + krb5_context context; + OM_uint32 maj_stat; + + GSSAPI_KRB5_INIT (&context); + + if (value == GSS_C_NO_BUFFER) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (gss_oid_equal(desired_object, GSS_KRB5_COMPAT_DES3_MIC_X)) { + gsskrb5_ctx ctx; + int flag; + + if (*context_handle == GSS_C_NO_CONTEXT) { + *minor_status = EINVAL; + return GSS_S_NO_CONTEXT; + } + + maj_stat = get_bool(minor_status, value, &flag); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + ctx = (gsskrb5_ctx)*context_handle; + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + if (flag) + ctx->more_flags |= COMPAT_OLD_DES3; + else + ctx->more_flags &= ~COMPAT_OLD_DES3; + ctx->more_flags |= COMPAT_OLD_DES3_SELECTED; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return GSS_S_COMPLETE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DNS_CANONICALIZE_X)) { + int flag; + + maj_stat = get_bool(minor_status, value, &flag); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + krb5_set_dns_canonicalize_hostname(context, flag); + return GSS_S_COMPLETE; + + } else if (gss_oid_equal(desired_object, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X)) { + char *str; + + maj_stat = get_string(minor_status, value, &str); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + maj_stat = _gsskrb5_register_acceptor_identity(minor_status, str); + free(str); + + return maj_stat; + + } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DEFAULT_REALM_X)) { + char *str; + + maj_stat = get_string(minor_status, value, &str); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + if (str == NULL) { + *minor_status = 0; + return GSS_S_CALL_INACCESSIBLE_READ; + } + + krb5_set_default_realm(context, str); + free(str); + + *minor_status = 0; + return GSS_S_COMPLETE; + + } else if (gss_oid_equal(desired_object, GSS_KRB5_SEND_TO_KDC_X)) { + + *minor_status = EINVAL; + return GSS_S_FAILURE; + + } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_TIME_OFFSET_X)) { + OM_uint32 offset; + time_t t; + + maj_stat = get_int32(minor_status, value, &offset); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + t = time(NULL) + offset; + + krb5_set_real_time(context, t, 0); + + *minor_status = 0; + return GSS_S_COMPLETE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_TIME_OFFSET_X)) { + krb5_timestamp sec; + int32_t usec; + time_t t; + + t = time(NULL); + + krb5_us_timeofday (context, &sec, &usec); + + maj_stat = set_int32(minor_status, value, sec - t); + if (maj_stat != GSS_S_COMPLETE) + return maj_stat; + + *minor_status = 0; + return GSS_S_COMPLETE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_PLUGIN_REGISTER_X)) { + struct gsskrb5_krb5_plugin c; + + if (value->length != sizeof(c)) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + memcpy(&c, value->value, sizeof(c)); + krb5_plugin_register(context, c.type, c.name, c.symbol); + + *minor_status = 0; + return GSS_S_COMPLETE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_CCACHE_NAME_X)) { + struct gsskrb5_ccache_name_args *args = value->value; + + if (value->length != sizeof(*args)) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + return _gsskrb5_krb5_ccache_name(minor_status, args->name, &args->out_name); + } else if (gss_oid_equal(desired_object, GSS_KRB5_IMPORT_RFC4121_CONTEXT_X)) { + return make_rfc4121_context(minor_status, context, context_handle, value); + } + + *minor_status = EINVAL; + return GSS_S_FAILURE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/store_cred.c b/third_party/heimdal/lib/gssapi/krb5/store_cred.c new file mode 100644 index 0000000..6d727b4 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/store_cred.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2003 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" + +static int +same_princ(krb5_context context, krb5_ccache id1, krb5_ccache id2) +{ + krb5_error_code ret; + krb5_principal p1 = NULL; + krb5_principal p2 = NULL; + int same = 0; + + ret = krb5_cc_get_principal(context, id1, &p1); + if (ret == 0) + ret = krb5_cc_get_principal(context, id2, &p2); + /* If either principal is absent, it's the same for our purposes */ + same = ret ? 1 : krb5_principal_compare(context, p1, p2); + krb5_free_principal(context, p1); + krb5_free_principal(context, p2); + return same; +} + +static OM_uint32 +add_env(OM_uint32 *minor, + gss_buffer_set_t *env, + const char *var, + const char *val) +{ + OM_uint32 major; + gss_buffer_desc b; + char *varval = NULL; + + if (asprintf(&varval, "%s=%s", var, val) == -1 || varval == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + b.value = varval; + b.length = strlen(varval) + 1; + major = gss_add_buffer_set_member(minor, &b, env); + free(varval); + return major; +} + +static OM_uint32 +set_proc(OM_uint32 *minor, gss_buffer_set_t env) +{ + /* + * XXX On systems with setpag(), call setpag(). On WIN32... create a + * session, set the access token, ...? + */ +#ifndef WIN32 + size_t i; + + for (i = 0; i < env->count; i++) + putenv(env->elements[i].value); +#endif + return GSS_S_COMPLETE; +} + +/* + * A principal is the best principal for a user IFF + * + * - it has one component + * - the one component is the same as the user's name + * - the real is the user_realm from configuration + */ +static int +principal_is_best_for_user(krb5_context context, + const char *app, + krb5_const_principal p, + const char *user) +{ + char *default_realm = NULL; + char *user_realm = NULL; + int ret; + + (void) krb5_get_default_realm(context, &default_realm); + krb5_appdefault_string(context, app, NULL, "user_realm", default_realm, + &user_realm); + ret = user_realm && + krb5_principal_get_num_comp(context, p) == 1 && + strcmp(user_realm, krb5_principal_get_realm(context, p)) == 0 && + (!user || + strcmp(user, krb5_principal_get_comp_string(context, p, 0)) == 0); + free(default_realm); + free(user_realm); + return ret; +} + +static krb5_error_code +check_destination_tgt_policy(krb5_context context, + const char *appname, + gsskrb5_cred input_cred) +{ + krb5_error_code ret; + krb5_boolean want_dst_tgt = 0; + krb5_data v; + + if (input_cred->destination_realm == NULL) + /* + * Not a delegated credential, so we can't check the destination TGT + * policy for the realm of the service -- we don't know the realm of + * the service. + */ + return 0; + + krb5_appdefault_boolean(context, appname, input_cred->destination_realm, + "require_delegate_destination_tgt", FALSE, + &want_dst_tgt); + if (!want_dst_tgt) + return 0; + + krb5_data_zero(&v); + ret = krb5_cc_get_config(context, input_cred->ccache, NULL, + "start_realm", &v); + if (ret == 0 && + v.length != strlen(input_cred->destination_realm)) + ret = KRB5_CC_NOTFOUND; + if (ret == 0 && + strncmp(input_cred->destination_realm, v.data, v.length) != 0) + ret = KRB5_CC_NOTFOUND; + if (ret) + krb5_set_error_message(context, ret, + "Delegated TGT is not a destination TGT for " + "realm \"%s\" but for \"%.*s\"", + input_cred->destination_realm, + (int)(v.length ? v.length : sizeof("<UNKNOWN>") - 1), + v.data ? (const char *)v.data : "<UNKNOWN>"); + krb5_data_free(&v); + return ret; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_store_cred_into2(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_usage_t cred_usage, + const gss_OID desired_mech, + OM_uint32 store_cred_flags, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored, + gss_buffer_set_t *envp) +{ + krb5_context context; + krb5_error_code ret; + gsskrb5_cred input_cred; + krb5_ccache id = NULL; + time_t exp_current; + time_t exp_new; + gss_buffer_set_t env = GSS_C_NO_BUFFER_SET; + const char *cs_unique_ccache = NULL; + const char *cs_ccache_name = NULL; + const char *cs_user_name = NULL; + const char *cs_app_name = NULL; + char *ccache_name = NULL; + OM_uint32 major_status = GSS_S_FAILURE; + OM_uint32 junk; + OM_uint32 overwrite_cred = store_cred_flags & GSS_C_STORE_CRED_OVERWRITE; + int default_for = 0; + + *minor_status = 0; + + /* Sanity check inputs */ + if (cred_usage != GSS_C_INITIATE) { + /* It'd be nice if we could also do accept, writing a keytab */ + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_FAILURE; + } + if (desired_mech != GSS_C_NO_OID && + gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) + return GSS_S_BAD_MECH; + if (input_cred_handle == GSS_C_NO_CREDENTIAL) + return GSS_S_CALL_INACCESSIBLE_READ; + input_cred = (gsskrb5_cred)input_cred_handle; + + /* Sanity check the input_cred */ + if (input_cred->usage != cred_usage && input_cred->usage != GSS_C_BOTH) { + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_NO_CRED; + } + if (input_cred->principal == NULL) { + *minor_status = GSS_KRB5_S_KG_TGT_MISSING; + return GSS_S_NO_CRED; + } + + /* Extract the ccache name from the store if given */ + if (cred_store != GSS_C_NO_CRED_STORE) { + major_status = __gsskrb5_cred_store_find(minor_status, cred_store, + "unique_ccache_type", + &cs_unique_ccache); + if (GSS_ERROR(major_status)) + return major_status; + major_status = __gsskrb5_cred_store_find(minor_status, cred_store, + "ccache", &cs_ccache_name); + if (GSS_ERROR(major_status)) + return major_status; + major_status = __gsskrb5_cred_store_find(minor_status, cred_store, + "username", &cs_user_name); + if (GSS_ERROR(major_status)) + return major_status; + major_status = __gsskrb5_cred_store_find(minor_status, cred_store, + "appname", &cs_app_name); + if (GSS_ERROR(major_status)) + return major_status; + } + + GSSAPI_KRB5_INIT (&context); + HEIMDAL_MUTEX_lock(&input_cred->cred_id_mutex); + + if (cs_ccache_name && strchr(cs_ccache_name, '%')) { + ret = _krb5_expand_default_cc_name(context, cs_ccache_name, + &ccache_name); + if (ret) { + HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex); + *minor_status = ret; + return GSS_S_FAILURE; + } + cs_ccache_name = ccache_name; + } + + /* More sanity checking of the input_cred (good to fail early) */ + ret = krb5_cc_get_lifetime(context, input_cred->ccache, &exp_new); + if (ret) { + HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex); + *minor_status = ret; + free(ccache_name); + return GSS_S_NO_CRED; + } + + ret = check_destination_tgt_policy(context, cs_app_name, input_cred); + if (ret) { + HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex); + *minor_status = ret; + free(ccache_name); + return GSS_S_NO_CRED; + } + + /* + * Find an appropriate ccache, which will be one of: + * + * - the one given in the cred_store, if given + * - a new unique one for some ccache type in the cred_store, if given + * - a subsidiary cache named for the principal in the default collection, + * if the principal is the "best principal for the user" + * - the default ccache + */ + if (cs_ccache_name) { + ret = krb5_cc_resolve(context, cs_ccache_name, &id); + } else if (cs_unique_ccache) { + overwrite_cred = 1; + ret = krb5_cc_new_unique(context, cs_unique_ccache, NULL, &id); + } else if (principal_is_best_for_user(context, cs_app_name, + input_cred->principal, + cs_user_name)) { + ret = krb5_cc_default(context, &id); + if (ret == 0 && !same_princ(context, id, input_cred->ccache)) { + krb5_cc_close(context, id); + ret = krb5_cc_default_for(context, input_cred->principal, &id); + default_for = 1; + } + } else { + ret = krb5_cc_default_for(context, input_cred->principal, &id); + default_for = 1; + } + + if (ret || id == NULL) { + HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex); + *minor_status = ret; + free(ccache_name); + return ret == 0 ? GSS_S_NO_CRED : GSS_S_FAILURE; + } + + /* + * If we're using a subsidiary ccache for this principal and it has some + * other principal's tickets in it -> overwrite. + */ + if (!overwrite_cred && default_for && + !same_princ(context, id, input_cred->ccache)) + overwrite_cred = 1; + if (!overwrite_cred && same_princ(context, id, input_cred->ccache)) { + /* + * If current creds are for the same princ as we already had creds for, + * and the new creds live longer than the old, overwrite. + */ + ret = krb5_cc_get_lifetime(context, id, &exp_current); + if (ret != 0 || exp_new > exp_current) + overwrite_cred = 1; + } + + if (overwrite_cred) { + ret = krb5_cc_initialize(context, id, input_cred->principal); + if (ret == 0) + ret = krb5_cc_copy_match_f(context, input_cred->ccache, id, NULL, NULL, + NULL); + } + + if ((store_cred_flags & GSS_C_STORE_CRED_SET_PROCESS) && envp == NULL) + envp = &env; + if (envp != NULL) { + char *fullname = NULL; + + if ((ret = krb5_cc_get_full_name(context, id, &fullname)) == 0) { + major_status = add_env(minor_status, envp, "KRB5CCNAME", fullname); + free(fullname); + if (major_status) + ret = *minor_status; + } + } + (void) krb5_cc_close(context, id); + + HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex); + if (ret == 0 && (store_cred_flags & GSS_C_STORE_CRED_SET_PROCESS) && + (major_status = set_proc(minor_status, *envp)) != GSS_S_COMPLETE) + ret = *minor_status; + (void) gss_release_buffer_set(&junk, &env); + free(ccache_name); + *minor_status = ret; + return ret ? major_status : GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_store_cred_into(OM_uint32 *minor_status, + gss_const_cred_id_t input_cred_handle, + gss_cred_usage_t cred_usage, + const gss_OID desired_mech, + OM_uint32 overwrite_cred, + OM_uint32 default_cred, + gss_const_key_value_set_t cred_store, + gss_OID_set *elements_stored, + gss_cred_usage_t *cred_usage_stored) +{ + OM_uint32 store_cred_flags = + (overwrite_cred ? GSS_C_STORE_CRED_OVERWRITE : 0) | + (default_cred ? GSS_C_STORE_CRED_DEFAULT : 0); + + return _gsskrb5_store_cred_into2(minor_status, input_cred_handle, + cred_usage, desired_mech, + store_cred_flags, cred_store, + elements_stored, cred_usage_stored, NULL); +} diff --git a/third_party/heimdal/lib/gssapi/krb5/test_acquire_cred.c b/third_party/heimdal/lib/gssapi/krb5/test_acquire_cred.c new file mode 100644 index 0000000..812fce6 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/test_acquire_cred.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2003-2018 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 +test_add_mutate(gss_cred_id_t cred_handle) +{ + OM_uint32 major_status, minor_status; + 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, + NULL, + NULL, + &time_rec, + NULL); + + if (GSS_ERROR(major_status)) + errx(1, "add_cred failed"); + + print_time(time_rec); +} + +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); + test_add_mutate(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/third_party/heimdal/lib/gssapi/krb5/test_cfx.c b/third_party/heimdal/lib/gssapi/krb5/test_cfx.c new file mode 100644 index 0000000..15f853c --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/test_cfx.c @@ -0,0 +1,173 @@ +/* + * 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 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" + +struct range { + size_t lower; + size_t upper; +}; + +struct range tests[] = { + { 0, 1040 }, + { 2040, 2080 }, + { 4080, 5000 }, + { 8180, 8292 }, + { 9980, 10010 } +}; + +static void +test_range(const struct range *r, int integ, + krb5_context context, krb5_crypto crypto) +{ + krb5_error_code ret; + size_t size, rsize; + struct gsskrb5_ctx ctx; + + for (size = r->lower; size < r->upper; size++) { + size_t cksumsize; + uint16_t padsize; + OM_uint32 minor; + OM_uint32 max_wrap_size; + + ctx.crypto = crypto; + + ret = _gssapi_wrap_size_cfx(&minor, + &ctx, + context, + integ, + 0, + size, + &max_wrap_size); + if (ret) + krb5_errx(context, 1, "_gsskrb5cfx_max_wrap_length_cfx: %d", ret); + if (max_wrap_size == 0) + continue; + + ret = _gsskrb5cfx_wrap_length_cfx(context, + crypto, + integ, + 0, + max_wrap_size, + &rsize, &cksumsize, &padsize); + if (ret) + krb5_errx(context, 1, "_gsskrb5cfx_wrap_length_cfx: %d", ret); + + if (size < rsize) + krb5_errx(context, 1, + "size (%d) < rsize (%d) for max_wrap_size %d", + (int)size, (int)rsize, (int)max_wrap_size); + } +} + +static void +test_special(krb5_context context, krb5_crypto crypto, + int integ, size_t testsize) +{ + krb5_error_code ret; + size_t rsize; + OM_uint32 max_wrap_size; + size_t cksumsize; + uint16_t padsize; + struct gsskrb5_ctx ctx; + OM_uint32 minor; + + ctx.crypto = crypto; + + ret = _gssapi_wrap_size_cfx(&minor, + &ctx, + context, + integ, + 0, + testsize, + &max_wrap_size); + if (ret) + krb5_errx(context, 1, "_gsskrb5cfx_max_wrap_length_cfx: %d", ret); + if (ret) + krb5_errx(context, 1, "_gsskrb5cfx_max_wrap_length_cfx: %d", ret); + + ret = _gsskrb5cfx_wrap_length_cfx(context, + crypto, + integ, + 0, + max_wrap_size, + &rsize, &cksumsize, &padsize); + if (ret) + krb5_errx(context, 1, "_gsskrb5cfx_wrap_length_cfx: %d", ret); + + if (testsize < rsize) + krb5_errx(context, 1, + "testsize (%d) < rsize (%d) for max_wrap_size %d", + (int)testsize, (int)rsize, (int)max_wrap_size); +} + + + + +int +main(int argc, char **argv) +{ + krb5_keyblock keyblock; + krb5_error_code ret; + krb5_context context; + krb5_crypto crypto; + int i; + + ret = krb5_init_context(&context); + if (ret) + errx(1, "krb5_context_init: %d", ret); + + ret = krb5_generate_random_keyblock(context, + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, + &keyblock); + if (ret) + krb5_err(context, 1, ret, "krb5_generate_random_keyblock"); + + ret = krb5_crypto_init(context, &keyblock, 0, &crypto); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_init"); + + test_special(context, crypto, 1, 60); + test_special(context, crypto, 0, 60); + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + test_range(&tests[i], 1, context, crypto); + test_range(&tests[i], 0, context, crypto); + } + + krb5_free_keyblock_contents(context, &keyblock); + krb5_crypto_destroy(context, crypto); + krb5_free_context(context); + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/test_cred.c b/third_party/heimdal/lib/gssapi/krb5/test_cred.c new file mode 100644 index 0000000..e0395f0 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/test_cred.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2003-2018 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 void +add_add_release_add(gss_name_t name, gss_cred_usage_t usage) +{ + OM_uint32 maj_stat, min_stat; + gss_cred_id_t cred, cred2; + + maj_stat = gss_add_cred(&min_stat, + GSS_C_NO_CREDENTIAL, + name, + GSS_KRB5_MECHANISM, + usage, + GSS_C_INDEFINITE, + GSS_C_INDEFINITE, + &cred, + 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_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, + NULL, + 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); +} + +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); + + add_add_release_add(name, GSS_C_ACCEPT); + add_add_release_add(name, GSS_C_INITIATE); + add_add_release_add(name, GSS_C_BOTH); + + gss_release_name(&min_stat, &name); + + return 0; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/test_kcred.c b/third_party/heimdal/lib/gssapi/krb5/test_kcred.c new file mode 100644 index 0000000..c90a144 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/test_kcred.c @@ -0,0 +1,155 @@ +/* + * 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"); + + /* This check is racy! */ + if (getenv("TESTS_ENVIRONMENT") == NULL) && lifetime1 != lifetime2) + errx(1, "lifetime not equal"); + if (lifetime1 != lifetime2) + warnx("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/third_party/heimdal/lib/gssapi/krb5/test_oid.c b/third_party/heimdal/lib/gssapi/krb5/test_oid.c new file mode 100644 index 0000000..00219b9 --- /dev/null +++ b/third_party/heimdal/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/third_party/heimdal/lib/gssapi/krb5/test_sequence.c b/third_party/heimdal/lib/gssapi/krb5/test_sequence.c new file mode 100644 index 0000000..33a4aac --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/test_sequence.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2003 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" + +/* correct ordering */ +OM_uint32 pattern1[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 +}; + +/* gap 10 */ +OM_uint32 pattern2[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13 +}; + +/* dup 9 */ +OM_uint32 pattern3[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11, 12, 13 +}; + +/* gaps */ +OM_uint32 pattern4[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15, 16, 18, 100 +}; + +/* 11 before 10 */ +OM_uint32 pattern5[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 +}; + +/* long */ +OM_uint32 pattern6[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59 +}; + +/* don't start at 0 */ +OM_uint32 pattern7[] = { + 11, 12, 13 +}; + +/* wrap around */ +OM_uint32 pattern8[] = { + 4294967293U, 4294967294U, 4294967295U, 0, 1, 2 +}; + +static int +test_seq(int t, OM_uint32 flags, OM_uint32 start_seq, + OM_uint32 *pattern, int pattern_len, OM_uint32 expected_error) +{ + struct gss_msg_order *o; + OM_uint32 maj_stat, min_stat; + krb5_storage *sp; + int i; + + maj_stat = _gssapi_msg_order_create(&min_stat, &o, flags, + start_seq, 20, 0); + if (maj_stat) + errx(1, "create: %d %d", maj_stat, min_stat); + + sp = krb5_storage_emem(); + if (sp == NULL) + errx(1, "krb5_storage_from_emem"); + + _gssapi_msg_order_export(sp, o); + + for (i = 0; i < pattern_len; i++) { + maj_stat = _gssapi_msg_order_check(o, pattern[i]); + if (maj_stat) + break; + } + if (maj_stat != expected_error) { + printf("test pattern %d failed with %d (should have been %d)\n", + t, maj_stat, expected_error); + krb5_storage_free(sp); + _gssapi_msg_order_destroy(&o); + return 1; + } + + + _gssapi_msg_order_destroy(&o); + + /* try again, now with export/imported blob */ + krb5_storage_seek(sp, 0, SEEK_SET); + + maj_stat = _gssapi_msg_order_import(&min_stat, sp, &o); + if (maj_stat) + errx(1, "import: %d %d", maj_stat, min_stat); + + for (i = 0; i < pattern_len; i++) { + maj_stat = _gssapi_msg_order_check(o, pattern[i]); + if (maj_stat) + break; + } + if (maj_stat != expected_error) { + printf("import/export test pattern %d failed " + "with %d (should have been %d)\n", + t, maj_stat, expected_error); + _gssapi_msg_order_destroy(&o); + krb5_storage_free(sp); + return 1; + } + + _gssapi_msg_order_destroy(&o); + krb5_storage_free(sp); + + return 0; +} + +struct { + OM_uint32 flags; + OM_uint32 *pattern; + int pattern_len; + OM_uint32 error_code; + OM_uint32 start_seq; +} pl[] = { + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern1, + sizeof(pattern1)/sizeof(pattern1[0]), + 0 + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern2, + sizeof(pattern2)/sizeof(pattern2[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern3, + sizeof(pattern3)/sizeof(pattern3[0]), + GSS_S_DUPLICATE_TOKEN + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern4, + sizeof(pattern4)/sizeof(pattern4[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern5, + sizeof(pattern5)/sizeof(pattern5[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern6, + sizeof(pattern6)/sizeof(pattern6[0]), + GSS_S_COMPLETE + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern7, + sizeof(pattern7)/sizeof(pattern7[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG, + pattern8, + sizeof(pattern8)/sizeof(pattern8[0]), + GSS_S_COMPLETE, + 4294967293U + }, + { + 0, + pattern1, + sizeof(pattern1)/sizeof(pattern1[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern2, + sizeof(pattern2)/sizeof(pattern2[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern3, + sizeof(pattern3)/sizeof(pattern3[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern4, + sizeof(pattern4)/sizeof(pattern4[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern5, + sizeof(pattern5)/sizeof(pattern5[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern6, + sizeof(pattern6)/sizeof(pattern6[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern7, + sizeof(pattern7)/sizeof(pattern7[0]), + GSS_S_COMPLETE + }, + { + 0, + pattern8, + sizeof(pattern8)/sizeof(pattern8[0]), + GSS_S_COMPLETE, + 4294967293U + + }, + { + GSS_C_REPLAY_FLAG, + pattern1, + sizeof(pattern1)/sizeof(pattern1[0]), + GSS_S_COMPLETE + }, + { + GSS_C_REPLAY_FLAG, + pattern2, + sizeof(pattern2)/sizeof(pattern2[0]), + GSS_S_COMPLETE + }, + { + GSS_C_REPLAY_FLAG, + pattern3, + sizeof(pattern3)/sizeof(pattern3[0]), + GSS_S_DUPLICATE_TOKEN + }, + { + GSS_C_REPLAY_FLAG, + pattern4, + sizeof(pattern4)/sizeof(pattern4[0]), + GSS_S_COMPLETE + }, + { + GSS_C_REPLAY_FLAG, + pattern5, + sizeof(pattern5)/sizeof(pattern5[0]), + 0 + }, + { + GSS_C_REPLAY_FLAG, + pattern6, + sizeof(pattern6)/sizeof(pattern6[0]), + GSS_S_COMPLETE + }, + { + GSS_C_REPLAY_FLAG, + pattern7, + sizeof(pattern7)/sizeof(pattern7[0]), + GSS_S_COMPLETE + }, + { + GSS_C_SEQUENCE_FLAG, + pattern8, + sizeof(pattern8)/sizeof(pattern8[0]), + GSS_S_COMPLETE, + 4294967293U + }, + { + GSS_C_SEQUENCE_FLAG, + pattern1, + sizeof(pattern1)/sizeof(pattern1[0]), + 0 + }, + { + GSS_C_SEQUENCE_FLAG, + pattern2, + sizeof(pattern2)/sizeof(pattern2[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_SEQUENCE_FLAG, + pattern3, + sizeof(pattern3)/sizeof(pattern3[0]), + GSS_S_DUPLICATE_TOKEN + }, + { + GSS_C_SEQUENCE_FLAG, + pattern4, + sizeof(pattern4)/sizeof(pattern4[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_SEQUENCE_FLAG, + pattern5, + sizeof(pattern5)/sizeof(pattern5[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_SEQUENCE_FLAG, + pattern6, + sizeof(pattern6)/sizeof(pattern6[0]), + GSS_S_COMPLETE + }, + { + GSS_C_SEQUENCE_FLAG, + pattern7, + sizeof(pattern7)/sizeof(pattern7[0]), + GSS_S_GAP_TOKEN + }, + { + GSS_C_REPLAY_FLAG, + pattern8, + sizeof(pattern8)/sizeof(pattern8[0]), + GSS_S_COMPLETE, + 4294967293U + } +}; + +int +main(int argc, char **argv) +{ + int i, failed = 0; + + for (i = 0; i < sizeof(pl)/sizeof(pl[0]); i++) { + if (test_seq(i, + pl[i].flags, + pl[i].start_seq, + pl[i].pattern, + pl[i].pattern_len, + pl[i].error_code)) + failed++; + } + if (failed) + printf("FAILED %d tests\n", failed); + return failed != 0; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/ticket_flags.c b/third_party/heimdal/lib/gssapi/krb5/ticket_flags.c new file mode 100644 index 0000000..df5f11d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/ticket_flags.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 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 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" + +OM_uint32 +_gsskrb5_get_tkt_flags(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + OM_uint32 *tkt_flags) +{ + if (ctx == NULL) { + *minor_status = EINVAL; + return GSS_S_NO_CONTEXT; + } + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + + if (ctx->ticket == NULL) { + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + *minor_status = EINVAL; + return GSS_S_BAD_MECH; + } + + *tkt_flags = TicketFlags2int(ctx->ticket->ticket.flags); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/unwrap.c b/third_party/heimdal/lib/gssapi/krb5/unwrap.c new file mode 100644 index 0000000..6461369 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/unwrap.c @@ -0,0 +1,468 @@ +/* + * Copyright (c) 1997 - 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 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" + +#ifdef HEIM_WEAK_CRYPTO + +static OM_uint32 +unwrap_des + (OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int * conf_state, + gss_qop_t * qop_state, + krb5_keyblock *key + ) +{ + u_char *p, *seq; + size_t len; + EVP_MD_CTX *md5; + u_char hash[16]; + EVP_CIPHER_CTX des_ctx; + DES_key_schedule schedule; + DES_cblock deskey; + DES_cblock zero; + size_t i; + uint32_t seq_number; + size_t padlength; + OM_uint32 ret; + int cstate; + int cmp; + int token_len; + + if (IS_DCE_STYLE(context_handle)) { + token_len = 22 + 8 + 15; /* 45 */ + if (input_message_buffer->length < token_len) + return GSS_S_BAD_MECH; + } else { + token_len = input_message_buffer->length; + } + + p = input_message_buffer->value; + ret = _gsskrb5_verify_header (&p, + token_len, + "\x02\x01", + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + len = (p - (u_char *)input_message_buffer->value) + + 22 + 8; + if (input_message_buffer->length < len) + return GSS_S_BAD_MECH; + + if (memcmp (p, "\x00\x00", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\x00\x00", 2) == 0) { + cstate = 1; + } else if (memcmp (p, "\xFF\xFF", 2) == 0) { + cstate = 0; + } else + return GSS_S_BAD_MIC; + p += 2; + if(conf_state != NULL) + *conf_state = cstate; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_DEFECTIVE_TOKEN; + p += 2; + p += 16; + + len = p - (u_char *)input_message_buffer->value; + + if(cstate) { + /* decrypt data */ + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + memset (&zero, 0, sizeof(zero)); + + for (i = 0; i < sizeof(deskey); ++i) + deskey[i] ^= 0xf0; + + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, deskey, zero, 0); + EVP_Cipher(&des_ctx, p, p, input_message_buffer->length - len); + EVP_CIPHER_CTX_cleanup(&des_ctx); + + memset (&deskey, 0, sizeof(deskey)); + } + + if (IS_DCE_STYLE(context_handle)) { + padlength = 0; + } else { + /* check pad */ + ret = _gssapi_verify_pad(input_message_buffer, + input_message_buffer->length - len - 8, + &padlength); + if (ret) + return ret; + } + + md5 = EVP_MD_CTX_create(); + EVP_DigestInit_ex(md5, EVP_md5(), NULL); + EVP_DigestUpdate(md5, p - 24, 8); + EVP_DigestUpdate(md5, p, input_message_buffer->length - len); + EVP_DigestFinal_ex(md5, hash, NULL); + EVP_MD_CTX_destroy(md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + DES_set_key_unchecked (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + if (ct_memcmp (p - 8, hash, 8) != 0) { + memset_s(&deskey, sizeof(deskey), 0, sizeof(deskey)); + memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule)); + return GSS_S_BAD_MIC; + } + + /* verify sequence number */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + p -= 16; + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash, 0); + EVP_Cipher(&des_ctx, p, p, 8); + EVP_CIPHER_CTX_cleanup(&des_ctx); + + memset (deskey, 0, sizeof(deskey)); + memset (&schedule, 0, sizeof(schedule)); + + seq = p; + _gsskrb5_decode_om_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + if (cmp != 0) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + /* copy out data */ + + output_message_buffer->length = input_message_buffer->length + - len - padlength - 8; + output_message_buffer->value = malloc(output_message_buffer->length); + if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) + return GSS_S_FAILURE; + if (output_message_buffer->value != NULL) + memcpy (output_message_buffer->value, + p + 24, + output_message_buffer->length); + return GSS_S_COMPLETE; +} +#endif + +static OM_uint32 +unwrap_des3 + (OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int * conf_state, + gss_qop_t * qop_state, + krb5_keyblock *key + ) +{ + u_char *p; + size_t len; + u_char *seq; + krb5_data seq_data; + u_char cksum[20]; + uint32_t seq_number; + size_t padlength; + OM_uint32 ret; + int cstate; + krb5_crypto crypto; + Checksum csum; + int cmp; + int token_len; + + if (IS_DCE_STYLE(context_handle)) { + token_len = 34 + 8 + 15; /* 57 */ + if (input_message_buffer->length < token_len) + return GSS_S_BAD_MECH; + } else { + token_len = input_message_buffer->length; + } + + p = input_message_buffer->value; + ret = _gsskrb5_verify_header (&p, + token_len, + "\x02\x01", + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + len = (p - (u_char *)input_message_buffer->value) + + 34 + 8; + if (input_message_buffer->length < len) + return GSS_S_BAD_MECH; + + if (ct_memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */ + return GSS_S_BAD_SIG; + p += 2; + if (ct_memcmp (p, "\x02\x00", 2) == 0) { + cstate = 1; + } else if (ct_memcmp (p, "\xff\xff", 2) == 0) { + cstate = 0; + } else + return GSS_S_BAD_MIC; + p += 2; + if(conf_state != NULL) + *conf_state = cstate; + if (ct_memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_DEFECTIVE_TOKEN; + p += 2; + p += 28; + + len = p - (u_char *)input_message_buffer->value; + + if(cstate) { + /* decrypt data */ + krb5_data tmp; + + ret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = krb5_decrypt(context, crypto, KRB5_KU_USAGE_SEAL, + p, input_message_buffer->length - len, &tmp); + krb5_crypto_destroy(context, crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + assert (tmp.length == input_message_buffer->length - len); + + memcpy (p, tmp.data, tmp.length); + krb5_data_free(&tmp); + } + + if (IS_DCE_STYLE(context_handle)) { + padlength = 0; + } else { + /* check pad */ + ret = _gssapi_verify_pad(input_message_buffer, + input_message_buffer->length - len - 8, + &padlength); + if (ret) + return ret; + } + + /* verify sequence number */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + p -= 28; + + ret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret) { + *minor_status = ret; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_FAILURE; + } + { + DES_cblock ivec; + + memcpy(&ivec, p + 8, 8); + ret = krb5_decrypt_ivec (context, + crypto, + KRB5_KU_USAGE_SEQ, + p, 8, &seq_data, + &ivec); + } + krb5_crypto_destroy (context, crypto); + if (ret) { + *minor_status = ret; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_FAILURE; + } + if (seq_data.length != 8) { + krb5_data_free (&seq_data); + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + seq = seq_data.data; + _gsskrb5_decode_om_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + krb5_data_free (&seq_data); + if (cmp != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + /* verify checksum */ + + memcpy (cksum, p + 8, 20); + + memcpy (p + 20, p - 8, 8); + + csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3; + csum.checksum.length = 20; + csum.checksum.data = cksum; + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_verify_checksum (context, crypto, + KRB5_KU_USAGE_SIGN, + p + 20, + input_message_buffer->length - len + 8, + &csum); + krb5_crypto_destroy (context, crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* copy out data */ + + output_message_buffer->length = input_message_buffer->length + - len - padlength - 8; + output_message_buffer->value = malloc(output_message_buffer->length); + if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) + return GSS_S_FAILURE; + if (output_message_buffer->value != NULL) + memcpy (output_message_buffer->value, + p + 36, + output_message_buffer->length); + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int * conf_state, + gss_qop_t * qop_state + ) +{ + krb5_keyblock *key; + krb5_context context; + OM_uint32 ret; + gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle; + + output_message_buffer->value = NULL; + output_message_buffer->length = 0; + if (qop_state != NULL) + *qop_state = GSS_C_QOP_DEFAULT; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_unwrap_cfx (minor_status, ctx, context, + input_message_buffer, output_message_buffer, + conf_state, qop_state); + + 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; + } + + *minor_status = 0; + + 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, + conf_state, qop_state, key); +#else + ret = GSS_S_FAILURE; +#endif + break; + 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 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); + break; + default : + abort(); + break; + } + krb5_free_keyblock (context, key); + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/verify_mic.c b/third_party/heimdal/lib/gssapi/krb5/verify_mic.c new file mode 100644 index 0000000..7070f3d --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/verify_mic.c @@ -0,0 +1,360 @@ +/* + * Copyright (c) 1997 - 2003 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" + +#ifdef HEIM_WEAK_CRYPTO + +static OM_uint32 +verify_mic_des + (OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + krb5_keyblock *key, + const char *type + ) +{ + u_char *p; + EVP_MD_CTX *md5; + u_char hash[16], *seq; + DES_key_schedule schedule; + EVP_CIPHER_CTX des_ctx; + DES_cblock zero; + DES_cblock deskey; + uint32_t seq_number; + OM_uint32 ret; + int cmp; + + p = token_buffer->value; + ret = _gsskrb5_verify_header (&p, + token_buffer->length, + type, + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + if (memcmp(p, "\x00\x00", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\xff\xff\xff\xff", 4) != 0) + return GSS_S_BAD_MIC; + p += 4; + p += 16; + + /* verify checksum */ + md5 = EVP_MD_CTX_create(); + EVP_DigestInit_ex(md5, EVP_md5(), NULL); + EVP_DigestUpdate(md5, p - 24, 8); + EVP_DigestUpdate(md5, message_buffer->value, message_buffer->length); + EVP_DigestFinal_ex(md5, hash, NULL); + EVP_MD_CTX_destroy(md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + + DES_set_key_unchecked (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + if (ct_memcmp (p - 8, hash, 8) != 0) { + memset_s(deskey, sizeof(deskey), 0, sizeof(deskey)); + memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule)); + return GSS_S_BAD_MIC; + } + + /* verify sequence number */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + p -= 16; + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash, 0); + EVP_Cipher(&des_ctx, p, p, 8); + EVP_CIPHER_CTX_cleanup(&des_ctx); + + memset_s(deskey, sizeof(deskey), 0, sizeof(deskey)); + memset_s(&schedule, sizeof(schedule), 0, sizeof(schedule)); + + seq = p; + _gsskrb5_decode_om_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + if (cmp != 0) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + return GSS_S_COMPLETE; +} +#endif + +static OM_uint32 +verify_mic_des3 + (OM_uint32 * minor_status, + const gsskrb5_ctx context_handle, + krb5_context context, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + krb5_keyblock *key, + const char *type + ) +{ + u_char *p; + u_char *seq; + uint32_t seq_number; + OM_uint32 ret; + krb5_crypto crypto; + krb5_data seq_data; + int cmp, docompat; + Checksum csum; + char *tmp; + char ivec[8]; + + p = token_buffer->value; + ret = _gsskrb5_verify_header (&p, + token_buffer->length, + type, + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */ + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\xff\xff\xff\xff", 4) != 0) + return GSS_S_BAD_MIC; + p += 4; + + ret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret){ + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* verify sequence number */ + docompat = 0; +retry: + if (docompat) + memset(ivec, 0, 8); + else + memcpy(ivec, p + 8, 8); + + ret = krb5_decrypt_ivec (context, + crypto, + KRB5_KU_USAGE_SEQ, + p, 8, &seq_data, ivec); + if (ret) { + if (docompat++) { + krb5_crypto_destroy (context, crypto); + *minor_status = ret; + return GSS_S_FAILURE; + } else + goto retry; + } + + if (seq_data.length != 8) { + krb5_data_free (&seq_data); + if (docompat++) { + krb5_crypto_destroy (context, crypto); + return GSS_S_BAD_MIC; + } else + goto retry; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + seq = seq_data.data; + _gsskrb5_decode_om_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + krb5_data_free (&seq_data); + if (cmp != 0) { + krb5_crypto_destroy (context, crypto); + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + krb5_crypto_destroy (context, crypto); + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + /* verify checksum */ + + tmp = malloc (message_buffer->length + 8); + if (tmp == NULL) { + krb5_crypto_destroy (context, crypto); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy (tmp, p - 8, 8); + memcpy (tmp + 8, message_buffer->value, message_buffer->length); + + csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3; + csum.checksum.length = 20; + csum.checksum.data = p + 8; + + krb5_crypto_destroy (context, crypto); + ret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_SHA1, &crypto); + 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); + *minor_status = ret; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + krb5_crypto_destroy (context, crypto); + return GSS_S_COMPLETE; +} + +OM_uint32 +_gsskrb5_verify_mic_internal + (OM_uint32 * minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + const char * type + ) +{ + krb5_keyblock *key; + OM_uint32 ret; + + if (ctx->more_flags & IS_CFX) + return _gssapi_verify_mic_cfx (minor_status, ctx, + context, message_buffer, token_buffer, + qop_state); + + 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; + } + *minor_status = 0; + + 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, + type); +#else + ret = GSS_S_FAILURE; +#endif + break; + 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 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, + qop_state, key, type); + break; + default : + abort(); + } + krb5_free_keyblock (context, key); + + return ret; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_verify_mic + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state + ) +{ + krb5_context context; + OM_uint32 ret; + + GSSAPI_KRB5_INIT (&context); + + if (qop_state != NULL) + *qop_state = GSS_C_QOP_DEFAULT; + + ret = _gsskrb5_verify_mic_internal(minor_status, + (gsskrb5_ctx)context_handle, + context, + message_buffer, token_buffer, + qop_state, (void *)(intptr_t)"\x01\x01"); + + return ret; +} diff --git a/third_party/heimdal/lib/gssapi/krb5/wrap.c b/third_party/heimdal/lib/gssapi/krb5/wrap.c new file mode 100644 index 0000000..481e303 --- /dev/null +++ b/third_party/heimdal/lib/gssapi/krb5/wrap.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 1997 - 2003 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" + +/* + * Return initiator subkey, or if that doesn't exists, the subkey. + */ + +krb5_error_code +_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx, + krb5_context context, + krb5_keyblock **key) +{ + krb5_error_code ret; + *key = NULL; + + if (ctx->more_flags & LOCAL) { + ret = krb5_auth_con_getlocalsubkey(context, + ctx->auth_context, + key); + } else { + ret = krb5_auth_con_getremotesubkey(context, + ctx->auth_context, + key); + } + if (ret == 0 && *key == NULL) + ret = krb5_auth_con_getkey(context, + ctx->auth_context, + key); + if (ret == 0 && *key == NULL) { + krb5_set_error_message(context, 0, "No initiator subkey available"); + return GSS_KRB5_S_KG_NO_SUBKEY; + } + return ret; +} + +krb5_error_code +_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx, + krb5_context context, + krb5_keyblock **key) +{ + krb5_error_code ret; + *key = NULL; + + if (ctx->more_flags & LOCAL) { + ret = krb5_auth_con_getremotesubkey(context, + ctx->auth_context, + key); + } else { + ret = krb5_auth_con_getlocalsubkey(context, + ctx->auth_context, + key); + } + if (ret == 0 && *key == NULL) { + krb5_set_error_message(context, 0, "No acceptor subkey available"); + return GSS_KRB5_S_KG_NO_SUBKEY; + } + return ret; +} + +OM_uint32 +_gsskrb5i_get_token_key(const gsskrb5_ctx ctx, + krb5_context context, + krb5_keyblock **key) +{ + _gsskrb5i_get_acceptor_subkey(ctx, context, key); + if(*key == NULL) { + /* + * Only use the initiator subkey or ticket session key if an + * acceptor subkey was not required. + */ + if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0) + _gsskrb5i_get_initiator_subkey(ctx, context, key); + } + if (*key == NULL) { + krb5_set_error_message(context, 0, "No token key available"); + return GSS_KRB5_S_KG_NO_SUBKEY; + } + return 0; +} + +static OM_uint32 +sub_wrap_size ( + OM_uint32 req_output_size, + OM_uint32 * max_input_size, + int blocksize, + int extrasize + ) +{ + size_t len, total_len; + + len = 8 + req_output_size + blocksize + extrasize; + + _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + + total_len -= req_output_size; /* token length */ + if (total_len < req_output_size) { + *max_input_size = (req_output_size - total_len); + (*max_input_size) &= (~(OM_uint32)(blocksize - 1)); + } else { + *max_input_size = 0; + } + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_wrap_size_limit ( + OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 * max_input_size + ) +{ + krb5_context context; + krb5_keyblock *key; + OM_uint32 ret; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_size_cfx(minor_status, ctx, context, + conf_req_flag, qop_req, + req_output_size, max_input_size); + + 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; + } + + 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 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 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 : + abort(); + break; + } + krb5_free_keyblock (context, key); + *minor_status = 0; + return ret; +} + +#ifdef HEIM_WEAK_CRYPTO + +static OM_uint32 +wrap_des + (OM_uint32 * minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer, + krb5_keyblock *key + ) +{ + u_char *p; + EVP_MD_CTX *md5; + u_char hash[16]; + DES_key_schedule schedule; + EVP_CIPHER_CTX des_ctx; + DES_cblock deskey; + DES_cblock zero; + size_t i; + int32_t seq_number; + size_t len, total_len, padlength, datalen; + + if (IS_DCE_STYLE(ctx)) { + padlength = 0; + datalen = input_message_buffer->length; + len = 22 + 8; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + total_len += datalen; + datalen += 8; + } else { + padlength = 8 - (input_message_buffer->length % 8); + datalen = input_message_buffer->length + padlength + 8; + len = datalen + 22; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + } + + output_message_buffer->length = total_len; + output_message_buffer->value = malloc (total_len); + if (output_message_buffer->value == NULL) { + output_message_buffer->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gsskrb5_make_header(output_message_buffer->value, + len, + "\x02\x01", /* TOK_ID */ + GSS_KRB5_MECHANISM); + + /* SGN_ALG */ + memcpy (p, "\x00\x00", 2); + p += 2; + /* SEAL_ALG */ + if(conf_req_flag) + memcpy (p, "\x00\x00", 2); + else + memcpy (p, "\xff\xff", 2); + p += 2; + /* Filler */ + memcpy (p, "\xff\xff", 2); + p += 2; + + /* fill in later */ + memset (p, 0, 16); + p += 16; + + /* confounder + data + pad */ + krb5_generate_random_block(p, 8); + memcpy (p + 8, input_message_buffer->value, + input_message_buffer->length); + memset (p + 8 + input_message_buffer->length, padlength, padlength); + + /* checksum */ + md5 = EVP_MD_CTX_create(); + EVP_DigestInit_ex(md5, EVP_md5(), NULL); + EVP_DigestUpdate(md5, p - 24, 8); + EVP_DigestUpdate(md5, p, datalen); + EVP_DigestFinal_ex(md5, hash, NULL); + EVP_MD_CTX_destroy(md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + DES_set_key_unchecked (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + memcpy (p - 8, hash, 8); + + /* sequence number */ + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber (context, + ctx->auth_context, + &seq_number); + + p -= 16; + p[0] = (seq_number >> 0) & 0xFF; + p[1] = (seq_number >> 8) & 0xFF; + p[2] = (seq_number >> 16) & 0xFF; + p[3] = (seq_number >> 24) & 0xFF; + memset (p + 4, + (ctx->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1); + EVP_Cipher(&des_ctx, p, p, 8); + EVP_CIPHER_CTX_cleanup(&des_ctx); + + krb5_auth_con_setlocalseqnumber (context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* encrypt the data */ + p += 16; + + if(conf_req_flag) { + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + + for (i = 0; i < sizeof(deskey); ++i) + deskey[i] ^= 0xf0; + + EVP_CIPHER_CTX_init(&des_ctx); + EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1); + EVP_Cipher(&des_ctx, p, p, datalen); + EVP_CIPHER_CTX_cleanup(&des_ctx); + } + memset (deskey, 0, sizeof(deskey)); + memset (&schedule, 0, sizeof(schedule)); + + if(conf_state != NULL) + *conf_state = conf_req_flag; + *minor_status = 0; + return GSS_S_COMPLETE; +} + +#endif + +static OM_uint32 +wrap_des3 + (OM_uint32 * minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer, + krb5_keyblock *key + ) +{ + u_char *p; + u_char seq[8]; + int32_t seq_number; + size_t len, total_len, padlength, datalen; + uint32_t ret; + krb5_crypto crypto; + Checksum cksum; + krb5_data encdata; + + if (IS_DCE_STYLE(ctx)) { + padlength = 0; + datalen = input_message_buffer->length; + len = 34 + 8; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + total_len += datalen; + datalen += 8; + } else { + padlength = 8 - (input_message_buffer->length % 8); + datalen = input_message_buffer->length + padlength + 8; + len = datalen + 34; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + } + + output_message_buffer->length = total_len; + output_message_buffer->value = malloc (total_len); + if (output_message_buffer->value == NULL) { + output_message_buffer->length = 0; + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gsskrb5_make_header(output_message_buffer->value, + len, + "\x02\x01", /* TOK_ID */ + GSS_KRB5_MECHANISM); + + /* SGN_ALG */ + memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */ + p += 2; + /* SEAL_ALG */ + if(conf_req_flag) + memcpy (p, "\x02\x00", 2); /* DES3-KD */ + else + memcpy (p, "\xff\xff", 2); + p += 2; + /* Filler */ + memcpy (p, "\xff\xff", 2); + p += 2; + + /* calculate checksum (the above + confounder + data + pad) */ + + memcpy (p + 20, p - 8, 8); + krb5_generate_random_block(p + 28, 8); + memcpy (p + 28 + 8, input_message_buffer->value, + input_message_buffer->length); + memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength); + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_create_checksum (context, + crypto, + KRB5_KU_USAGE_SIGN, + 0, + p + 20, + datalen + 8, + &cksum); + krb5_crypto_destroy (context, crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* zero out SND_SEQ + SGN_CKSUM in case */ + memset (p, 0, 28); + + memcpy (p + 8, cksum.checksum.data, cksum.checksum.length); + free_Checksum (&cksum); + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + /* sequence number */ + krb5_auth_con_getlocalseqnumber (context, + ctx->auth_context, + &seq_number); + + seq[0] = (seq_number >> 0) & 0xFF; + seq[1] = (seq_number >> 8) & 0xFF; + seq[2] = (seq_number >> 16) & 0xFF; + seq[3] = (seq_number >> 24) & 0xFF; + memset (seq + 4, + (ctx->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + + ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, + &crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + + { + DES_cblock ivec; + + memcpy (&ivec, p + 8, 8); + ret = krb5_encrypt_ivec (context, + crypto, + KRB5_KU_USAGE_SEQ, + seq, 8, &encdata, + &ivec); + } + krb5_crypto_destroy (context, crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + + assert (encdata.length == 8); + + memcpy (p, encdata.data, encdata.length); + krb5_data_free (&encdata); + + krb5_auth_con_setlocalseqnumber (context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* encrypt the data */ + p += 28; + + if(conf_req_flag) { + krb5_data tmp; + + ret = krb5_crypto_init(context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL, + p, datalen, &tmp); + krb5_crypto_destroy(context, crypto); + if (ret) { + free (output_message_buffer->value); + output_message_buffer->length = 0; + output_message_buffer->value = NULL; + *minor_status = ret; + return GSS_S_FAILURE; + } + assert (tmp.length == datalen); + + memcpy (p, tmp.data, datalen); + krb5_data_free(&tmp); + } + if(conf_state != NULL) + *conf_state = conf_req_flag; + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 GSSAPI_CALLCONV +_gsskrb5_wrap + (OM_uint32 * minor_status, + gss_const_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer + ) +{ + krb5_context context; + krb5_keyblock *key; + OM_uint32 ret; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + + output_message_buffer->value = NULL; + output_message_buffer->length = 0; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag, + input_message_buffer, conf_state, + output_message_buffer); + + 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; + } + + 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, + output_message_buffer, key); +#else + ret = GSS_S_FAILURE; +#endif + break; + 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 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); + break; + default : + abort(); + break; + } + krb5_free_keyblock (context, key); + return ret; +} |