OM_uint32 gss_delete_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_buffer_t output_token) { OM_uint32 major_status; struct _gss_context *ctx = (struct _gss_context *) *context_handle; if (output_token) _gss_buffer_zero(output_token); *minor_status = 0; if (ctx) { /* * If we have an implementation ctx, delete it, * otherwise fake an empty token. */ if (ctx->gc_ctx) { major_status = ctx->gc_mech->gm_delete_sec_context( minor_status, &ctx->gc_ctx, output_token); } free(ctx); *context_handle = GSS_C_NO_CONTEXT; } return (GSS_S_COMPLETE); }
OM_uint32 gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context, int prf_key, const gss_buffer_t prf_in, ssize_t desired_output_len, gss_buffer_t prf_out) { struct _gss_context *ctx = (struct _gss_context *) context; struct _gss_mech_switch *m = ctx->gc_mech; OM_uint32 major_status; _gss_buffer_zero(prf_out); *minor_status = 0; if (ctx == NULL) { *minor_status = 0; return GSS_S_NO_CONTEXT; } if (m->gm_pseudo_random == NULL) return GSS_S_UNAVAILABLE; major_status = (*m->gm_pseudo_random)(minor_status, ctx->gc_ctx, prf_key, prf_in, desired_output_len, prf_out); if (major_status != GSS_S_COMPLETE) _gss_mg_error(m, major_status, *minor_status); return major_status; }
OM_uint32 gss_wrap(OM_uint32 *minor_status, const gss_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) { struct _gss_context *ctx = (struct _gss_context *) context_handle; struct _gss_mech_switch *m; if (conf_state) *conf_state = 0; _gss_buffer_zero(output_message_buffer); if (ctx == NULL) { *minor_status = 0; return (GSS_S_NO_CONTEXT); } m = ctx->gc_mech; return (m->gm_wrap(minor_status, ctx->gc_ctx, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer)); }
OM_uint32 gss_export_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_buffer_t interprocess_token) { OM_uint32 major_status; struct _gss_context *ctx = (struct _gss_context *) *context_handle; struct _gss_mech_switch *m = ctx->gc_mech; gss_buffer_desc buf; _gss_buffer_zero(interprocess_token); major_status = m->gm_export_sec_context(minor_status, &ctx->gc_ctx, &buf); if (major_status == GSS_S_COMPLETE) { unsigned char *p; free(ctx); *context_handle = GSS_C_NO_CONTEXT; interprocess_token->length = buf.length + 2 + m->gm_mech_oid.length; interprocess_token->value = malloc(interprocess_token->length); if (!interprocess_token->value) { /* * We are in trouble here - the context is * already gone. This is allowed as long as we * set the caller's context_handle to * GSS_C_NO_CONTEXT, which we did above. * Return GSS_S_FAILURE. */ _gss_buffer_zero(interprocess_token); *minor_status = ENOMEM; return (GSS_S_FAILURE); } p = interprocess_token->value; p[0] = m->gm_mech_oid.length >> 8; p[1] = m->gm_mech_oid.length; memcpy(p + 2, m->gm_mech_oid.elements, m->gm_mech_oid.length); memcpy(p + 2 + m->gm_mech_oid.length, buf.value, buf.length); gss_release_buffer(minor_status, &buf); } else {
OM_uint32 gss_release_buffer(OM_uint32 *minor_status, gss_buffer_t buffer) { *minor_status = 0; if (buffer->value) free(buffer->value); _gss_buffer_zero(buffer); return (GSS_S_COMPLETE); }
OM_uint32 gss_get_mic(OM_uint32 *minor_status, const gss_ctx_id_t context_handle, gss_qop_t qop_req, const gss_buffer_t message_buffer, gss_buffer_t message_token) { struct _gss_context *ctx = (struct _gss_context *) context_handle; struct _gss_mech_switch *m; _gss_buffer_zero(message_token); if (ctx == NULL) { *minor_status = 0; return (GSS_S_NO_CONTEXT); } m = ctx->gc_mech; return (m->gm_get_mic(minor_status, ctx->gc_ctx, qop_req, message_buffer, message_token)); }
OM_uint32 gss_export_name(OM_uint32 *minor_status, const gss_name_t input_name, gss_buffer_t exported_name) { struct _gss_name *name = (struct _gss_name *) input_name; struct _gss_mechanism_name *mn; _gss_buffer_zero(exported_name); /* * If this name already has any attached MNs, export the first * one, otherwise export based on the first mechanism in our * list. */ mn = SLIST_FIRST(&name->gn_mn); if (!mn) { *minor_status = 0; return (GSS_S_NAME_NOT_MN); } return mn->gmn_mech->gm_export_name(minor_status, mn->gmn_name, exported_name); }
OM_uint32 gss_encapsulate_token(const gss_buffer_t input_token, gss_OID oid, gss_buffer_t output_token) { unsigned char *p; size_t len, inside_len; size_t a, b; int i; _gss_buffer_zero(output_token); /* * First time around, we calculate the size, second time, we * encode the token. */ p = 0; for (i = 0; i < 2; i++) { len = 0; /* * Token starts with [APPLICATION 0] SEQUENCE. */ if (p) *p++ = 0x60; len++; /* * The length embedded in the token is the space * needed for the encapsulated oid plus the length of * the inner token. */ if (oid->length > 127) return (GSS_S_DEFECTIVE_TOKEN); inside_len = 2 + oid->length + input_token->length; /* * Figure out how to encode the length */ if (inside_len < 128) { if (p) *p++ = inside_len; len++; } else { b = 1; if (inside_len >= 0x100) b++; if (inside_len >= 0x10000) b++; if (inside_len >= 0x1000000) b++; if (p) *p++ = b | 0x80; len++; a = inside_len << 8*(4 - b); while (b) { if (p) *p++ = (a >> 24); a <<= 8; len++; b--; } } /* * Encode the OID for the mechanism. Simplify life by * assuming that the OID length is less than 128 bytes. */ if (p) *p++ = 0x06; len++; if (p) *p++ = oid->length; len++; if (p) { memcpy(p, oid->elements, oid->length); p += oid->length; } len += oid->length; if (p) { memcpy(p, input_token->value, input_token->length); p += input_token->length; } len += input_token->length; if (i == 0) { output_token->length = len; output_token->value = malloc(len); if (!output_token->value) return (GSS_S_DEFECTIVE_TOKEN); p = output_token->value; } } return (GSS_S_COMPLETE); }
OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle, const gss_cred_id_t acceptor_cred_handle, const gss_buffer_t input_token, 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 major_status, mech_ret_flags; struct _gss_mech_switch *m; struct _gss_context *ctx = (struct _gss_context *) *context_handle; struct _gss_cred *cred = (struct _gss_cred *) acceptor_cred_handle; struct _gss_mechanism_cred *mc; gss_cred_id_t acceptor_mc, delegated_mc; gss_name_t src_mn; *minor_status = 0; if (src_name) *src_name = GSS_C_NO_NAME; if (mech_type) *mech_type = GSS_C_NO_OID; if (ret_flags) *ret_flags = 0; if (time_rec) *time_rec = 0; if (delegated_cred_handle) *delegated_cred_handle = GSS_C_NO_CREDENTIAL; _gss_buffer_zero(output_token); /* * If this is the first call (*context_handle is NULL), we must * parse the input token to figure out the mechanism to use. */ if (*context_handle == GSS_C_NO_CONTEXT) { gss_OID_desc mech_oid; major_status = choose_mech(input_token, &mech_oid); if (major_status != GSS_S_COMPLETE) return (major_status); /* * Now that we have a mechanism, we can find the * implementation. */ ctx = malloc(sizeof(struct _gss_context)); if (!ctx) { *minor_status = ENOMEM; return (GSS_S_DEFECTIVE_TOKEN); } memset(ctx, 0, sizeof(struct _gss_context)); m = ctx->gc_mech = _gss_find_mech_switch(&mech_oid); if (!m) { free(ctx); return (GSS_S_BAD_MECH); } } else m = ctx->gc_mech; if (cred) { SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) if (mc->gmc_mech == m) break; if (!mc) return (GSS_S_BAD_MECH); acceptor_mc = mc->gmc_cred; } else {
OM_uint32 gss_display_status(OM_uint32 *minor_status, OM_uint32 status_value, int status_type, const gss_OID mech_type, OM_uint32 *message_content, gss_buffer_t status_string) { OM_uint32 major_status; _gss_buffer_zero(status_string); *message_content = 0; major_status = _gss_mg_get_error(mech_type, status_type, status_value, status_string); if (major_status == GSS_S_COMPLETE) { *message_content = 0; *minor_status = 0; return (GSS_S_COMPLETE); } *minor_status = 0; switch (status_type) { case GSS_C_GSS_CODE: { char *buf; if (GSS_SUPPLEMENTARY_INFO(status_value)) asprintf(&buf, "%s", supplementary_error( GSS_SUPPLEMENTARY_INFO(status_value))); else asprintf (&buf, "%s %s", calling_error(GSS_CALLING_ERROR(status_value)), routine_error(GSS_ROUTINE_ERROR(status_value))); if (buf == NULL) break; status_string->length = strlen(buf); status_string->value = buf; return (GSS_S_COMPLETE); } case GSS_C_MECH_CODE: { OM_uint32 maj_junk, min_junk; gss_buffer_desc oid; char *buf; maj_junk = gss_oid_to_str(&min_junk, mech_type, &oid); if (maj_junk != GSS_S_COMPLETE) { oid.value = strdup("unknown"); oid.length = 7; } asprintf (&buf, "unknown mech-code %lu for mech %.*s", (unsigned long)status_value, (int)oid.length, (char *)oid.value); if (maj_junk == GSS_S_COMPLETE) gss_release_buffer(&min_junk, &oid); if (buf == NULL) break; status_string->length = strlen(buf); status_string->value = buf; return (GSS_S_COMPLETE); } } _gss_buffer_zero(status_string); return (GSS_S_BAD_STATUS); }