--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+/*
+ * 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 <gssapi.h>
+
+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);
+
+}
+
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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));
+ }
+}
+
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
+
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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));
+}
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
+
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
+
+
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+ }
+}
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
+
+
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
+
+
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
+
+
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
+
+
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
+
+
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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));
+}
+
--- /dev/null
+/*
+ * 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
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <gssapi.h>
+
+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);
+}
+