From: Theodore Tso Date: Mon, 6 May 1991 15:14:31 +0000 (+0000) Subject: Initial Revision X-Git-Tag: krb5-1.0-alpha5~4 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=de8c3b49f993fa7583c710451cac8f7407f8859c;p=krb5.git Initial Revision git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@2099 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/gssapi/ac_cred.c b/src/lib/gssapi/ac_cred.c new file mode 100644 index 000000000..38102630c --- /dev/null +++ b/src/lib/gssapi/ac_cred.c @@ -0,0 +1,129 @@ +/* + * ac_cred.c --- gss_acquire_cred + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * Note: There are really two kinds of credentials in Kerberos V5... + * the first kind is for users, and we use a krb5_ccache to get at + * that. The second kind is for servers, and we use a krb5_keytab to + * point at that. + * + * It is possible to convert from one to another, but we don't address + * that right now. + * + * XXX We need to do something with time_rec. + */ + +#include + +char *gss_krb5_fetchfrom = NULL; + +OM_uint32 gss_acquire_cred(minor_status, desired_name, time_req, + desired_mechs, cred_usage, output_cred_handle, + actual_mechs, time_rec) + OM_uint32 *minor_status; + gss_name_t desired_name; + OM_uint32 time_req; + gss_OID_set desired_mechs; + int cred_usage; + gss_cred_id_t *output_cred_handle; + gss_OID_set *actual_mechs; + OM_uint32 *time_rec; +{ + krb5_keytab_entry entry; + krb5_keytab keytabid; + int do_kerberos = 0; + int i; + krb5_error_code retval; + + *minor_status = 0; + + /* + * Figure out which mechanism we should be using. + */ + if (desired_mechs == GSS_C_NULL_OID_SET) + do_kerberos++; + else { + for (i = 0; i <= desired_mechs->count; i++) { + if (gss_compare_OID(&desired_mechs->elements[i], + &gss_OID_krb5)) + do_kerberos++; + } + } + + /* + * Should we return failure here? + */ + if (!do_kerberos) + return(gss_make_re(GSS_RE_FAILURE)); + output_cred_handle->cred_flags = 0; + + /* + * This is Kerberos V5 specific stuff starting here. + * First, let's try to search the keytab file. + * Applications that know what they are doing can mess with + * the variable gss_krb_fetchfrom. Otherwise, we use the + * system default keytab file. + */ + if (*minor_status = krb5_copy_principal(desired_name, + &output_cred_handle->principal)) { + return(gss_make_re(GSS_RE_FAILURE)); + } + if (gss_krb5_fetchfrom) { + /* use the named keytab */ + retval = krb5_kt_resolve(gss_krb5_fetchfrom, &keytabid); + } else { + /* use default keytab */ + retval = krb5_kt_default(&keytabid); + } + if (!retval) { + retval = krb5_kt_get_entry(keytabid, desired_name, 0, + &entry); + (void) krb5_kt_close(keytabid); + if (!retval) { + output_cred_handle->cred_flags |= GSS_KRB_HAS_SRVTAB; + output_cred_handle->kvno = entry.vno; + output_cred_handle->srvtab = entry.key; + krb5_free_principal(entry.principal); + } + } + /* + * Now let's try opening the default credentials file and see + * if it contains the desired name. We could try searching + * some directory (like /tmp) if we really cared, but not for + * now. + * + * We're not even looking in the default credentials file + * right now. XXX + */ + + /* + * We're done, clean up and get out. + */ + if (actual_mechs) { + gss_OID_set set; + + if (!(set = (gss_OID_set) + malloc (sizeof(struct gss_OID_set_desc)))) { + *minor_status = ENOMEM; + return(gss_make_re(GSS_RE_FAILURE)); + } + set->count = 1; + set->elements = &gss_OID_krb5; + *actual_mechs = set; + } + return(GSS_S_COMPLETE); + +} + diff --git a/src/lib/gssapi/acc_sec.c b/src/lib/gssapi/acc_sec.c new file mode 100644 index 000000000..0cf361dea --- /dev/null +++ b/src/lib/gssapi/acc_sec.c @@ -0,0 +1,264 @@ +/* + * acc_sec.c --- accept security context + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +extern krb5_flags krb5_kdc_default_options; + +/* + * To do in the future: + * + * * Support replay cache + * + * * Support delegation of credentials + * + * * Do something with time_rec + * + * * Should handle Kerberos error packets being sent back and + * forth. + */ + +static krb5_error_code gss_krb5_keyproc(cred_handle, principal, vno, key) + krb5_pointer cred_handle; + krb5_principal principal; + krb5_kvno vno; + krb5_keyblock **key; +{ + gss_cred_id_t *creds; + + creds = (gss_cred_id_t *) cred_handle; + + if (krb5_principal_compare(creds->principal, principal)) { + if (creds->cred_flags & GSS_KRB_HAS_SRVTAB) { + *key = &creds->srvtab; + return(0); + } else + return(KRB5_KT_NOTFOUND); + } else + return(KRB5_KT_NOTFOUND); +} + + +OM_uint32 gss_accept_sec_context(minor_status, context_handle, + verifier_cred_handle, input_token, + channel, src_name, + mech_type, output_token, + ret_flags, time_rec, + delegated_cred_handle) + OM_uint32 *minor_status; + gss_ctx_id_t *context_handle; + gss_cred_id_t verifier_cred_handle; + gss_buffer_t input_token; + gss_channel_bindings channel; + gss_name_t *src_name; + gss_OID *mech_type; + gss_buffer_t output_token; + int *ret_flags; + OM_uint32 *time_rec; + gss_cred_id_t *delegated_cred_handle; +{ + krb5_rcache rcache; + krb5_address sender_addr; + krb5_data inbuf, outbuf; + krb5_principal server; + krb5_tkt_authent *authdat; + OM_uint32 retval; + gss_ctx_id_t context; + + *minor_status = 0; + + if (!context_handle) { + /* + * This is first call to accept_sec_context + * + * Make sure the input token is sane. + */ + if (retval = gss_check_token(minor_status, input_token, + GSS_API_KRB5_TYPE, + GSS_API_KRB5_REQ)) + return(retval); + inbuf.length = input_token->length-5; + inbuf.data = ( (char *) input_token->value)+5; + sender_addr.addrtype = channel.sender_addrtype; + sender_addr.length = channel.sender_address.length; + sender_addr.contents = channel.sender_address.value; + server = verifier_cred_handle.principal; + /* + * Setup the replay cache. + */ + if (*minor_status = krb5_get_server_rcache(server[1]->data, + &rcache)) + return(gss_make_re(GSS_RE_FAILURE)); + /* + * Now let's rip apart the packet + */ + if (*minor_status = krb5_rd_req(&inbuf, server, &sender_addr, + 0, gss_krb5_keyproc, + &verifier_cred_handle, + rcache, &authdat)) + return(gss_make_re(GSS_RE_FAILURE)); + if (*minor_status = krb5_rc_close(rcache)) + return(gss_make_re(GSS_RE_FAILURE)); + + /* + * Allocate the context handle structure + */ + if (!(context = malloc(sizeof(struct gss_ctx_id_desc)))) { + *minor_status = ENOMEM; + return(gss_make_re(GSS_RE_FAILURE)); + } + context->mech_type = &gss_OID_krb5; + context->flags = 0; + context->state = GSS_KRB_STATE_DOWN; + context->am_client = 0; + + context->my_address.addrtype = channel.sender_addrtype; + context->my_address.length = channel.sender_address.length; + if (!(context->my_address.contents = + malloc(context->my_address.length))) { + xfree(context); + return(gss_make_re(GSS_RE_FAILURE)); + } + memcpy((char *) context->my_address.contents, + (char *) channel.sender_address.value, + context->my_address.length); + context->his_address.addrtype = channel.receiver_addrtype; + context->his_address.length = channel.receiver_address.length; + if (!(context->his_address.contents = + malloc(context->my_address.length))) { + xfree(context->my_address.contents); + xfree(context); + return(gss_make_re(GSS_RE_FAILURE)); + } + memcpy((char *) context->his_address.contents, + (char *) channel.receiver_address.value, + context->his_address.length); + + /* + * Do mutual authentication if requested. + */ + output_token->length = 0; + if ((authdat->ap_options & AP_OPTS_MUTUAL_REQUIRED)) { + krb5_ap_rep_enc_part repl; + /* + * Generate a random sequence number + */ + if (*minor_status = + krb5_generate_seq_number(authdat->ticket->enc_part2->session, + &context->my_seq_num)) { + xfree(context->his_address.contents); + xfree(context->my_address.contents); + xfree(context); + krb5_free_tkt_authent(authdat); + return(gss_make_re(GSS_RE_FAILURE)); + } + + repl.ctime = authdat->authenticator->ctime; + repl.cusec = authdat->authenticator->cusec; + repl.subkey = authdat->authenticator->subkey; + repl.seq_number = context->my_seq_num; + + if (*minor_status = + krb5_mk_rep(&repl, + authdat->ticket->enc_part2->session, + &outbuf)) { + xfree(context->his_address.contents); + xfree(context->my_address.contents); + xfree(context); + krb5_free_tkt_authent(authdat); + return(gss_make_re(GSS_RE_FAILURE)); + } + if (*minor_status = gss_make_token(minor_status, + GSS_API_KRB5_TYPE, + GSS_API_KRB5_REQ, + outbuf.length, + outbuf.data, + output_token)) { + xfree(context->his_address.contents); + xfree(context->my_address.contents); + xfree(context); + xfree(outbuf.data); + krb5_free_tkt_authent(authdat); + return(gss_make_re(GSS_RE_FAILURE)); + } + } + + /* + * Fill in context handle structure + */ + if (*minor_status = + krb5_copy_principal(verifier_cred_handle.principal, + &context->me)) { + xfree(context->his_address.contents); + xfree(context->my_address.contents); + xfree(context); + return(gss_make_re(GSS_RE_FAILURE)); + } + if (*minor_status = + krb5_copy_principal(authdat->authenticator->client, + &context->him)) { + krb5_free_principal(context->me); + xfree(context->his_address.contents); + xfree(context->my_address.contents); + xfree(context); + return(gss_make_re(GSS_RE_FAILURE)); + } + if (*minor_status = + krb5_copy_keyblock(authdat->ticket->enc_part2->session, + &context->session_key)) { + krb5_free_principal(context->me); + krb5_free_principal(context->him); + xfree(context->his_address.contents); + xfree(context->my_address.contents); + xfree(context); + return(gss_make_re(GSS_RE_FAILURE)); + } + context->his_seq_num = authdat->authenticator->seq_number; + context->cusec = authdat->authenticator->cusec; + context->ctime = authdat->authenticator->ctime; + context->flags = ((char *) input_token->value)[4]; + /* + * Strip out flags we don't support (yet) XXX + */ + context->flags &= ~(GSS_C_DELEG_FLAG | GSS_C_REPLAY_FLAG); + /* + * Deliver output parameters + */ + if (src_name) { + if (*minor_status = krb5_copy_principal(context->him, + src_name)) { + xfree(context->session_key->contents); + krb5_free_principal(context->me); + krb5_free_principal(context->him); + xfree(context->his_address.contents); + xfree(context->my_address.contents); + xfree(context); + return(gss_make_re(GSS_RE_FAILURE)); + } + } + if (mech_type) + *mech_type = &gss_OID_krb5; + *ret_flags = context->flags; + if (time_rec) + *time_rec = GSS_TIME_REC_INDEFINITE; + return(GSS_S_COMPLETE); + } else { + /* + * Context is non-null, this is the second time through.... + */ + return(gss_make_re(GSS_RE_FAILURE)); + } +} + diff --git a/src/lib/gssapi/check_tok.c b/src/lib/gssapi/check_tok.c new file mode 100644 index 000000000..24073490a --- /dev/null +++ b/src/lib/gssapi/check_tok.c @@ -0,0 +1,47 @@ +/* + * check_tok.c --- Read a GSS API token and do error checking + * checking on it. + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_check_token(minor_status, input_token, mechanism, type) + OM_uint32 *minor_status; + gss_buffer_t input_token; + unsigned char mechanism; + unsigned char type; +{ + char *buf; + + *minor_status = 0; + + if (!input_token) + return(gss_make_ce(GSS_CE_CALL_INACCESSIBLE_READ)); + + if (input_token->length < 4) + return(gss_make_re(GSS_RE_DEFECTIVE_TOKEN)); + + buf = input_token->value; + + if (buf[0] != GSS_API_IMPL_VERSION) + return(gss_make_re(GSS_RE_DEFECTIVE_TOKEN)); + + if (mechanism && (mechanism != buf[1])) + return(gss_make_re(GSS_RE_BAD_MECH)); + + if (type && (type != buf[2])) + return(gss_make_re(GSS_RE_FAILURE) | GSS_SS_UNSEQ_TOKEN); + + return(GSS_S_COMPLETE); +} diff --git a/src/lib/gssapi/cmp_name.c b/src/lib/gssapi/cmp_name.c new file mode 100644 index 000000000..450c5ed4b --- /dev/null +++ b/src/lib/gssapi/cmp_name.c @@ -0,0 +1,28 @@ +/* + * imp_name.c --- import_name + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_compare_name(minor_status, name1, name2, name_equal) + OM_uint32 *minor_status; + gss_name_t name1, name2; + int *name_equal; +{ + *minor_status = 0; + + *name_equal = krb5_principal_compare(name1, name2); + return(GSS_S_COMPLETE); +} + diff --git a/src/lib/gssapi/comp_oid.c b/src/lib/gssapi/comp_oid.c new file mode 100644 index 000000000..3f24f0226 --- /dev/null +++ b/src/lib/gssapi/comp_oid.c @@ -0,0 +1,24 @@ +/* + * comp_oid.c --- compare OID's + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +int gss_compare_OID(oid1, oid2) + gss_OID oid1, oid2; +{ + if (oid1->length != oid2->length) + return(0); + return (!memcmp(oid1->elements, oid2->elements, oid1->length)); +} diff --git a/src/lib/gssapi/dsp_name.c b/src/lib/gssapi/dsp_name.c new file mode 100644 index 000000000..cdce73751 --- /dev/null +++ b/src/lib/gssapi/dsp_name.c @@ -0,0 +1,30 @@ +/* + * dsp_name.c --- display_name + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_display_name(minor_status, input_name, output_name_buffer) + OM_uint32 *minor_status; + gss_name_t input_name; + gss_buffer_t output_name_buffer; +{ + char *str; + + if (*minor_status = krb5_unparse_name(input_name, &str)) + return(gss_make_re(GSS_RE_FAILURE)); + output_name_buffer->value = str; + output_name_buffer->length = strlen(str); + return(GSS_S_COMPLETE); +} diff --git a/src/lib/gssapi/imp_name.c b/src/lib/gssapi/imp_name.c new file mode 100644 index 000000000..62a243371 --- /dev/null +++ b/src/lib/gssapi/imp_name.c @@ -0,0 +1,92 @@ +/* + * imp_name.c --- import_name + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_service_import_name(); + +OM_uint32 gss_import_name(minor_status, input_name_buffer, input_name_type, + output_name) + OM_uint32 *minor_status; + gss_buffer_t input_name_buffer; + gss_OID input_name_type; + gss_name_t *output_name; +{ + *minor_status = 0; + + if ((input_name_type == GSS_C_NULL_OID) || + gss_compare_OID(input_name_type, &gss_OID_krb5)) { + /* + * Kerberos V5 name + */ + if (!strncasecmp("service:", input_name_buffer->value, 8) && + input_name_buffer->length >= 8) { + return(gss_service_import_name(minor_status, + input_name_buffer, + output_name)); + } + if (*minor_status = krb5_parse_name(input_name_buffer->value, + output_name)) + return(gss_make_re(GSS_RE_FAILURE)); + else + return(GSS_S_COMPLETE); + } + /* + * It's of an unknown type. We don't know how to deal. + */ + return(gss_make_re(GSS_RE_BAD_NAMETYPE)); +} + + +OM_uint32 gss_service_import_name(minor_status, input_name_buffer, output_name) + OM_uint32 *minor_status; + gss_buffer_t input_name_buffer; + gss_name_t *output_name; +{ + char *str, *cp; + char *service, *kservice; + char *host; + char buf[512]; + + if (!(str = malloc(input_name_buffer->length+1))) { + *minor_status = ENOMEM; + return(gss_make_re(GSS_RE_FAILURE)); + } + memcpy(str, input_name_buffer->value, input_name_buffer->length); + str[input_name_buffer->length] = '\0'; + + /* + * Assume the first eight characters are "service:" + */ + service = cp = str + 8; + if (!(cp = index(cp, '@'))) { + free(str); + return(gss_make_re(GSS_RE_BAD_NAME)); + } + *cp++ = 0; + host = cp; + /* + * We will need to do some mapping here later... XXX + */ + kservice = service; + + sprintf(buf, "%s/%s", kservice, host); + + if (*minor_status = krb5_parse_name(buf, output_name)) + return(gss_make_re(GSS_RE_FAILURE)); + else + return(GSS_S_COMPLETE); +} + diff --git a/src/lib/gssapi/ind_mechs.c b/src/lib/gssapi/ind_mechs.c new file mode 100644 index 000000000..be9ba63eb --- /dev/null +++ b/src/lib/gssapi/ind_mechs.c @@ -0,0 +1,38 @@ +/* + * ind_mechs.c --- Indicate mechanisms (also where the OID's are declared) + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +struct gss_OID_desc gss_OID_krb5 = { 15, "KRB5.OSI.SUCKS"}; +struct gss_OID_desc gss_OID_krb5_name = { 20, "KRB5.NAME.OSI.SUCKS" }; + +OM_uint32 gss_indicate_mechs(minor_status, mech_set) + OM_uint32 *minor_status; + gss_OID_set *mech_set; +{ + gss_OID_set set; + + *minor_status = 0; + if (!(set = (gss_OID_set) malloc (sizeof(struct gss_OID_set_desc)))) { + *minor_status = ENOMEM; + return(gss_make_re(GSS_RE_FAILURE)); + } + set->count = 1; + set->elements = &gss_OID_krb5; + *mech_set = set; + return(GSS_S_COMPLETE); +} + + diff --git a/src/lib/gssapi/init_sec.c b/src/lib/gssapi/init_sec.c new file mode 100644 index 000000000..a4f03c527 --- /dev/null +++ b/src/lib/gssapi/init_sec.c @@ -0,0 +1,275 @@ +/* + * init_sec.c --- initialize security context + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +extern krb5_flags krb5_kdc_default_options; + +/* + * To do in the future: + * + * * Support replay cache + * + * * Support delegation of credentials + * + * * Do something with time_rec + * + * * Should handle Kerberos error packets being sent back and + * forth. + */ + +gss_cred_id_t gss_default_credentials = { + (krb5_principal) NULL, (gss_OID) NULL, 0, (krb5_ccache) NULL, + (krb5_kvno) 0, { (krb5_keytype) 0, 0, (krb5_octet *) NULL } +}; + + +OM_uint32 gss_init_sec_context(minor_status, claimant_cred_handle, + context_handle, target_name, + mech_type, req_flags, time_req, + channel, input_token, + actual_mech_type, output_token, + ret_flags, time_rec) + OM_uint32 *minor_status; + gss_cred_id_t claimant_cred_handle; + gss_ctx_id_t *context_handle; + gss_name_t target_name; + gss_OID mech_type; + int req_flags; + int time_req; + gss_channel_bindings channel; + gss_buffer_t input_token; + gss_OID *actual_mech_type; + gss_buffer_t output_token; + int *ret_flags; + OM_uint32 *time_rec; +{ + krb5_flags kdc_options = krb5_kdc_default_options; + krb5_flags ap_req_options = 0; + krb5_ccache ccache; + krb5_creds creds; + krb5_authenticator authent; + krb5_data inbuf, outbuf; + krb5_ap_rep_enc_part *repl; + OM_uint32 retval; + gss_ctx_id_t context; + + *minor_status = 0; + + if (!context_handle) { + /* + * This is first call to init_sec_context + * + * We only handle Kerberos V5... + */ + if ((mech_type != GSS_C_NULL_OID) && + !gss_compare_OID(mech_type, &gss_OID_krb5)) { + return(gss_make_re(GSS_RE_BAD_MECH)); + } + if (actual_mech_type) + *actual_mech_type = &gss_OID_krb5; + /* + * Sanitize the incoming flags + * + * We don't support delegation or replay detection --- yet. + */ + req_flags &= ~GSS_C_DELEG_FLAG; + req_flags &= ~GSS_C_REPLAY_FLAG; + /* + * If no credentials were passed in, get our own + */ + if (claimant_cred_handle.ccache) + ccache = claimant_cred_handle.ccache; + else { + /* + * Default (or NULL) credentials, we need to + * fill in with defaults. + */ + if (*minor_status = krb5_cc_default(&ccache)) { + return(gss_make_re(GSS_RE_FAILURE)); + } + claimant_cred_handle.ccache = ccache; + if (*minor_status = + krb5_cc_get_principal(ccache, + &claimant_cred_handle.principal)) + return(gss_make_re(GSS_RE_FAILURE)); + } + /* + * Allocate the context handle structure + */ + if (!(context = malloc(sizeof(struct gss_ctx_id_desc)))) { + *minor_status = ENOMEM; + return(gss_make_re(GSS_RE_FAILURE)); + } + context->mech_type = &gss_OID_krb5; + context->state = GSS_KRB_STATE_DOWN; + /* + * Fill in context handle structure + */ + if (*minor_status = + krb5_copy_principal(claimant_cred_handle.principal, + &context->me)) + return(gss_make_re(GSS_RE_FAILURE)); + if (*minor_status = + krb5_copy_principal(target_name, + &context->him)) + return(gss_make_re(GSS_RE_FAILURE)); + context->flags = req_flags | GSS_C_CONF_FLAG;; + context->am_client = 1; + context->session_key = NULL; + context->my_address.addrtype = channel.sender_addrtype; + context->my_address.length = channel.sender_address.length; + if (!(context->my_address.contents = + malloc(context->my_address.length))) { + xfree(context); + return(gss_make_re(GSS_RE_FAILURE)); + } + memcpy((char *) context->my_address.contents, + (char *) channel.sender_address.value, + context->my_address.length); + context->his_address.addrtype = channel.receiver_addrtype; + context->his_address.length = channel.receiver_address.length; + if (!(context->his_address.contents = + malloc(context->my_address.length))) { + xfree(context->my_address.contents); + xfree(context); + return(gss_make_re(GSS_RE_FAILURE)); + } + memcpy((char *) context->his_address.contents, + (char *) channel.receiver_address.value, + context->his_address.length); + /* + * Generate a random sequence number + */ + if (*minor_status = + krb5_generate_seq_number(&creds.keyblock, + &context->my_seq_num)) { + xfree(context->his_address.contents); + xfree(context->my_address.contents); + free((char *)context); + return(make_gss_re(GSS_RE_FAILURE)); + } + context->his_seq_num = 0; + /* + * Make a credentials structure + */ + memset((char *)&creds, 0, sizeof(creds)); + creds.server = context->him; + creds.client = context->me; + /* creds.times.endtime = 0; -- memset 0 takes care of this + zero means "as long as possible" */ + /* creds.keyblock.keytype = 0; -- as well as this. + zero means no session keytype + preference */ + if (*minor_status = krb5_get_credentials(0, + ccache, + &creds)) { + krb5_free_cred_contents(&creds); + free((char *)context); + return(gss_make_re(GSS_RE_FAILURE)); + } + /* + * Setup the ap_req_options + */ + if ((req_flags & GSS_C_MUTUAL_FLAG) || + (req_flags & GSS_C_SEQUENCE_FLAG)) + ap_req_options |= AP_OPTS_MUTUAL_REQUIRED; + /* + * OK, get the authentication header! + */ + if (*minor_status = krb5_mk_req_extended(ap_req_options, 0, + &creds.times, + kdc_options, + context->my_seq_num, 0, + ccache, &creds, &authent, + &outbuf)) { + memset((char *)&authent, 0, sizeof(authent)); + krb5_free_cred_contents(&creds); + free((char *)context); + return(gss_make_re(GSS_RE_FAILURE)); + } + context->cusec = authent.cusec; + context->ctime = authent.ctime; + memset((char *)&authent, 0, sizeof(authent)); + + if (*minor_status = + krb5_copy_keyblock(&creds.keyblock, + &context->session_key)) { + xfree(outbuf.data); + krb5_free_cred_contents(&creds); + free((char *)context); + return(gss_make_re(GSS_RE_FAILURE)); + } + + if (*minor_status = gss_make_token(minor_status, + GSS_API_KRB5_TYPE, + GSS_API_KRB5_REQ, + outbuf.length, + outbuf.data, + output_token)) { + xfree(outbuf.data); + krb5_free_cred_contents(&creds); + free((char *) context); + return(gss_make_re(GSS_RE_FAILURE)); + } + /* + * Send over the requested flags information + */ + ((char *) output_token->value)[4] = context->flags; + xfree(outbuf.data); + *context_handle = context; + context->state = GSS_KRB_STATE_DOWN; + *ret_flags = context->flags; + /* + * Don't free server and client because we need them + * for the context structure. + */ + creds.server = 0; + creds.client = 0; + krb5_free_cred_contents(&creds); + if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED) { + context->state = GSS_KRB_STATE_MUTWAIT; + return(GSS_SS_CONTINUE_NEEDED); + } else { + context->state = GSS_KRB_STATE_UP; + return(GSS_S_COMPLETE); + } + + } else { + context = *context_handle; + + if (context->state != GSS_KRB_STATE_MUTWAIT) + return(gss_make_re(GSS_RE_FAILURE)); + if (retval = gss_check_token(minor_status, input_token, + GSS_API_KRB5_TYPE, + GSS_API_KRB5_REP)) + return(retval); + inbuf.length = input_token->length-4; + inbuf.data = ((char *)input_token->value)+4; + + if (*minor_status = krb5_rd_rep(&inbuf, context->session_key, + &repl)) + return(gss_make_re(GSS_RE_FAILURE)); + if ((repl->ctime != context->ctime) || + (repl->cusec != context->cusec)) { + *minor_status = KRB5_SENDAUTH_MUTUAL_FAILED; + return(gss_make_re(GSS_RE_FAILURE)); + } + context->his_seq_num = repl->seq_number; + context->state = GSS_KRB_STATE_UP; + krb5_free_ap_rep_enc_part(repl); + return(GSS_S_COMPLETE); + } +} diff --git a/src/lib/gssapi/make_tok.c b/src/lib/gssapi/make_tok.c new file mode 100644 index 000000000..97a46bebb --- /dev/null +++ b/src/lib/gssapi/make_tok.c @@ -0,0 +1,49 @@ +/* + * make_tok.c --- Make a GSS API token + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_make_token(minor_status, mechanism, type, length, data, + output_token) + OM_uint32 *minor_status; + unsigned char mechanism; + unsigned char type; + size_t length; + void *data; + gss_buffer_t output_token; +{ + char *buf; + int offset = 4; + + *minor_status = 0; + /* + * The Kerberos initial request token needs an extra byte of + * flag information, so we reserve it here. + */ + if ((mechanism == GSS_API_KRB5_TYPE) && (type == GSS_API_KRB5_REQ)) + offset++; + if (!(buf = malloc(length+offset))) { + *minor_status = ENOMEM; + return(gss_make_re(GSS_RE_FAILURE)); + } + output_token->value = buf; + output_token->length = length+4; + buf[0] = GSS_API_IMPL_VERSION; + buf[1] = mechanism; /* Authentication mechanism */ + buf[2] = type; /* Token type */ + buf[3] = 0; /* Reserved */ + memcpy(buf+offset, data, length); + return(GSS_S_COMPLETE); +} diff --git a/src/lib/gssapi/rel_buffer.c b/src/lib/gssapi/rel_buffer.c new file mode 100644 index 000000000..022969c08 --- /dev/null +++ b/src/lib/gssapi/rel_buffer.c @@ -0,0 +1,28 @@ +/* + * rel_buffer.c --- release a gss_buffer_t + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_release_buffer(minor_status, buffer) + OM_uint32 *minor_status; + gss_buffer_t buffer; +{ + *minor_status = 0; + + free(buffer->value); + return(GSS_S_COMPLETE); +} + + diff --git a/src/lib/gssapi/rel_cred.c b/src/lib/gssapi/rel_cred.c new file mode 100644 index 000000000..e2f09d17d --- /dev/null +++ b/src/lib/gssapi/rel_cred.c @@ -0,0 +1,29 @@ +/* + * rel_cred.c --- release a gss_cred_id_t + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_release_cred(minor_status, cred_handle) + OM_uint32 *minor_status; + gss_cred_id_t *cred_handle; +{ + krb5_free_principal(cred_handle->principal); + if (*minor_status = krb5_cc_close(cred_handle->ccache)) + return(gss_make_re(GSS_RE_FAILURE)); + xfree(cred_handle->srvtab.contents); + return(GSS_S_COMPLETE); +} + + diff --git a/src/lib/gssapi/rel_name.c b/src/lib/gssapi/rel_name.c new file mode 100644 index 000000000..f04f5c0c9 --- /dev/null +++ b/src/lib/gssapi/rel_name.c @@ -0,0 +1,28 @@ +/* + * rel_name.c --- release a gss_name_t + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_release_name(minor_status, name) + OM_uint32 *minor_status; + gss_name_t *name; +{ + *minor_status = 0; + + krb5_free_principal(*name); + return(GSS_S_COMPLETE); +} + + diff --git a/src/lib/gssapi/rel_oidset.c b/src/lib/gssapi/rel_oidset.c new file mode 100644 index 000000000..216d9c9b8 --- /dev/null +++ b/src/lib/gssapi/rel_oidset.c @@ -0,0 +1,32 @@ +/* + * rel_oidset.c --- release a fgss_oid_set + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_release_oid_set(minor_status, set) + OM_uint32 *minor_status; + gss_OID_set set; +{ + *minor_status = 0; + + /* + * We don't free the OID parts themselves, since they will all + * be constant structures in this version + */ + free((char *)set); + return(GSS_S_COMPLETE); +} + + diff --git a/src/lib/gssapi/rel_sec.c b/src/lib/gssapi/rel_sec.c new file mode 100644 index 000000000..8702e9899 --- /dev/null +++ b/src/lib/gssapi/rel_sec.c @@ -0,0 +1,31 @@ +/* + * rel_buffer.c --- release a security context + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_release_security_context(minor_status, context) + OM_uint32 *minor_status; + gss_ctx_id_t context; +{ + *minor_status = 0; + + krb5_free_principal(context->me); + krb5_free_principal(context->him); + + context->state = GSS_KRB5_STATE_DOWN; + return(GSS_S_COMPLETE); +} + + diff --git a/src/lib/gssapi/seal.c b/src/lib/gssapi/seal.c new file mode 100644 index 000000000..d6e78e946 --- /dev/null +++ b/src/lib/gssapi/seal.c @@ -0,0 +1,127 @@ +/* + * seal.c --- seal message + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_seal(minor_status, context, conf_req_flag, qop_req, + input_message_buffer, conf_state, output_message_buffer) + OM_uint32 *minor_status; + gss_ctx_id_t context; + int conf_req_flag; + int qop_req; + gss_buffer_t input_message_buffer; + int *conf_state; + gss_buffer_t output_message_buffer; +{ + krb5_data inbuf, outbuf; + + *minor_status = 0; + + inbuf.length = input_message_buffer->length; + inbuf.data = input_message_buffer->value; + if (conf_req_flag) { + int priv_flags = 0; + int eblock_size; + char *i_vector; + + if (context->flags & GSS_C_SEQUENCE_FLAG) + priv_flags = KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME; + /* + * Initialize the initial vector. + */ + eblock_size = + krb5_keytype_array[context->session_key->keytype]-> + system->block_length; + if (!(i_vector=malloc(eblock_size))) { + return(gss_make_re(GSS_RE_FAILURE)); + } + memset(i_vector, 0, eblock_size); + if (*minor_status = krb5_mk_priv(&inbuf, ETYPE_DES_CBC_CRC, + context->session_key, + &context->my_address, + &context->his_address, + context->my_seq_num, + priv_flags, + 0, /* no rcache */ + i_vector, + &outbuf)) + return(gss_make_re(GSS_RE_FAILURE)); + if (*minor_status = gss_make_token(minor_status, + GSS_API_KRB5_TYPE, + GSS_API_KRB5_PRIV, + outbuf.length, + outbuf.data, + output_message_buffer)) { + xfree(outbuf.data); + return(gss_make_re(GSS_RE_FAILURE)); + } + if (conf_state) + *conf_state = 1; + if (context->flags & GSS_C_SEQUENCE_FLAG) + context->my_seq_num++; + return(GSS_S_COMPLETE); + } else { + int safe_flags = 0; + + if (context->flags & GSS_C_SEQUENCE_FLAG) + safe_flags = KRB5_SAFE_DOSEQUENCE|KRB5_SAFE_NOTIME; + if (*minor_status = krb5_mk_safe(&inbuf, + CKSUMTYPE_RSA_MD4_DES, + context->session_key, + &context->my_address, + &context->his_address, + context->my_seq_num, + safe_flags, + 0, /* no rcache */ + &outbuf)) + return(gss_make_re(GSS_RE_FAILURE)); + if (*minor_status = gss_make_token(minor_status, + GSS_API_KRB5_TYPE, + GSS_API_KRB5_SAFE, + outbuf.length, + outbuf.data, + output_message_buffer)) { + xfree(outbuf.data); + return(gss_make_re(GSS_RE_FAILURE)); + } + if (conf_state) + *conf_state = 0; + if (context->flags & GSS_C_SEQUENCE_FLAG) + context->my_seq_num++; + return(GSS_S_COMPLETE); + } +} + +/* + * XXX This is done inefficiently; the token in gss_sign does not need + * to include the text of the data, just a cryptographic checksum to + * act as a checksum. Nevertheless, this is a quick and dirty way to + * get it to work. When we fix this so that it works for real, we + * will need to let gss_verify accept both, and change the servers + * first. + */ + +OM_uint32 gss_sign(minor_status, context, qop_req, + input_message_buffer, output_message_buffer) + OM_uint32 *minor_status; + gss_ctx_id_t context; + int qop_req; + gss_buffer_t input_message_buffer; + gss_buffer_t output_message_buffer; +{ + return(gss_seal(minor_status, context, 0, qop_req, + input_message_buffer, NULL, output_message_buffer)); +} + diff --git a/src/lib/gssapi/unseal.c b/src/lib/gssapi/unseal.c new file mode 100644 index 000000000..fc51e551b --- /dev/null +++ b/src/lib/gssapi/unseal.c @@ -0,0 +1,120 @@ +/* + * seal.c --- seal message + * + * $Source$ + * $Author$ + * $Header$ + * + * Copyright 1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * For copying and distribution information, please see the file + * . + * + */ + +#include + +OM_uint32 gss_unseal(minor_status, context, input_message_buffer, + output_message_buffer, conf_state, qop_state) + OM_uint32 *minor_status; + gss_ctx_id_t context; + gss_buffer_t input_message_buffer; + gss_buffer_t output_message_buffer; + int *conf_state; + int *qop_state; +{ + OM_uint32 retval; + krb5_data inbuf, outbuf; + int token_type; + + *minor_status = 0; + + if (retval = gss_check_token(minor_status, input_message_buffer, + GSS_API_KRB5_TYPE, 0)) + return(retval); + token_type = ((char *) input_message_buffer->value)[4]; + if ((token_type != GSS_API_KRB5_SAFE) && + (token_type != GSS_API_KRB5_PRIV)) + return(gss_make_re(GSS_RE_DEFECTIVE_TOKEN)); + inbuf.length = input_message_buffer->length-4; + inbuf.data = ( (char *) input_message_buffer->value)+4; + if (token_type == GSS_API_KRB5_PRIV) { + int priv_flags = 0; + int eblock_size; + char *i_vector; + + if (context->flags & GSS_C_SEQUENCE_FLAG) + priv_flags = KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME; + /* + * Initialize the initial vector. + */ + eblock_size = + krb5_keytype_array[context->session_key->keytype]-> + system->block_length; + if (!(i_vector=malloc(eblock_size))) { + return(gss_make_re(GSS_RE_FAILURE)); + } + memset(i_vector, 0, eblock_size); + if (*minor_status = krb5_rd_priv(&inbuf, + context->session_key, + &context->his_address, + &context->my_address, + context->his_seq_num, + priv_flags, + i_vector, + 0, /* no rcache */ + &outbuf)) + return(gss_make_re(GSS_RE_FAILURE)); + if (conf_state) + *conf_state = 1; + } else { + int safe_flags = 0; + + if (context->flags & GSS_C_SEQUENCE_FLAG) + safe_flags = KRB5_SAFE_DOSEQUENCE|KRB5_SAFE_NOTIME; + if (*minor_status = krb5_rd_safe(&inbuf, + context->session_key, + &context->his_address, + &context->my_address, + context->his_seq_num, + safe_flags, + 0, /* no rcache */ + &outbuf)) + return(gss_make_re(GSS_RE_FAILURE)); + if (conf_state) + *conf_state = 0; + } + if (qop_state) + *qop_state = 0; + output_message_buffer->length = outbuf.length; + output_message_buffer->value = outbuf.data; + return(GSS_S_COMPLETE); +} + +OM_uint32 gss_verify(minor_status, context, message_buffer, + token_buffer, qop_state) + OM_uint32 *minor_status; + gss_ctx_id_t context; + gss_buffer_t message_buffer; + gss_buffer_t token_buffer; + int *qop_state; +{ + OM_uint32 retval, ret; + gss_buffer_desc buf; + gss_buffer_t output_message_buffer = &buf; + + + if (retval = gss_unseal(minor_status, context, message_buffer, + output_message_buffer, NULL, qop_state)) + return(retval); + if (token_buffer->length != output_message_buffer->length) + ret = gss_make_re(GSS_RE_BAD_SIG); + else if (!memcmp(token_buffer->value, output_message_buffer->value, + token_buffer->length)) + ret = gss_make_re(GSS_RE_BAD_SIG); + if (retval = gss_release_buffer(minor_status, output_message_buffer)) + return(retval); + return(ret); +} +