2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/*
2N/A * Copyright 1993 by OpenVision Technologies, Inc.
2N/A *
2N/A * Permission to use, copy, modify, distribute, and sell this software
2N/A * and its documentation for any purpose is hereby granted without fee,
2N/A * provided that the above copyright notice appears in all copies and
2N/A * that both that copyright notice and this permission notice appear in
2N/A * supporting documentation, and that the name of OpenVision not be used
2N/A * in advertising or publicity pertaining to distribution of the software
2N/A * without specific, written prior permission. OpenVision makes no
2N/A * representations about the suitability of this software for any
2N/A * purpose. It is provided "as is" without express or implied warranty.
2N/A *
2N/A * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
2N/A * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
2N/A * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
2N/A * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
2N/A * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
2N/A * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2N/A * PERFORMANCE OF THIS SOFTWARE.
2N/A */
2N/A
2N/A#include "gssapiP_generic.h"
2N/A#include <string.h>
2N/A#include <stdio.h>
2N/A
2N/A/*
2N/A * $Id: disp_major_status.c 23457 2009-12-08 00:04:48Z tlyu $
2N/A */
2N/A
2N/A/*
2N/A * Solaris Kerberos: SUNW15resync XXX these are not part of the GSSAPI C
2N/A * bindings (but should be), MIT 1.5 has these in gssapi.h.
2N/A */
2N/A
2N/A#define GSS_CALLING_ERROR_FIELD(x) \
2N/A (((x) >> GSS_C_CALLING_ERROR_OFFSET) & GSS_C_CALLING_ERROR_MASK)
2N/A#define GSS_ROUTINE_ERROR_FIELD(x) \
2N/A (((x) >> GSS_C_ROUTINE_ERROR_OFFSET) & GSS_C_ROUTINE_ERROR_MASK)
2N/A#define GSS_SUPPLEMENTARY_INFO_FIELD(x) \
2N/A (((x) >> GSS_C_SUPPLEMENTARY_OFFSET) & GSS_C_SUPPLEMENTARY_MASK)
2N/A
2N/A/* This code has knowledge of the min and max errors of each type
2N/A within the gssapi major status */
2N/A
2N/A#define GSS_ERROR_STR(value, array, select, min, max, num) \
2N/A (((select(value) < (min)) || (select(value) > (max))) ? NULL : \
2N/A (array)[num(value)])
2N/A
2N/A/**/
2N/A
2N/Astatic const char * const calling_error_string[] = {
2N/A NULL,
2N/A "A required input parameter could not be read",
2N/A "A required input parameter could not be written",
2N/A "A parameter was malformed",
2N/A};
2N/A
2N/Astatic const char * const calling_error = "calling error";
2N/A
2N/A#define GSS_CALLING_ERROR_STR(x) \
2N/A GSS_ERROR_STR((x), calling_error_string, GSS_CALLING_ERROR, \
2N/A GSS_S_CALL_INACCESSIBLE_READ, GSS_S_CALL_BAD_STRUCTURE, \
2N/A GSS_CALLING_ERROR_FIELD)
2N/A
2N/A/**/
2N/A
2N/Astatic const char * const routine_error_string[] = {
2N/A NULL,
2N/A "An unsupported mechanism was requested",
2N/A "An invalid name was supplied",
2N/A "A supplied name was of an unsupported type",
2N/A "Incorrect channel bindings were supplied",
2N/A "An invalid status code was supplied",
2N/A "A token had an invalid signature",
2N/A "No credentials were supplied",
2N/A "No context has been established",
2N/A "A token was invalid",
2N/A "A credential was invalid",
2N/A "The referenced credentials have expired",
2N/A "The context has expired",
2N/A "Miscellaneous failure",
2N/A "The quality-of-protection requested could not be provided",
2N/A "The operation is forbidden by the local security policy",
2N/A "The operation or option is not available",
2N/A};
2N/A
2N/Astatic const char * const routine_error = "routine error";
2N/A
2N/A#define GSS_ROUTINE_ERROR_STR(x) \
2N/A GSS_ERROR_STR((x), routine_error_string, GSS_ROUTINE_ERROR, \
2N/A GSS_S_BAD_MECH, GSS_S_FAILURE, \
2N/A GSS_ROUTINE_ERROR_FIELD)
2N/A
2N/A/**/
2N/A
2N/A/* this becomes overly gross after about 4 strings */
2N/A
2N/Astatic const char * const sinfo_string[] = {
2N/A "The routine must be called again to complete its function",
2N/A "The token was a duplicate of an earlier token",
2N/A "The token's validity period has expired",
2N/A "A later token has already been processed",
2N/A};
2N/A
2N/Astatic const char * const sinfo_code = "supplementary info code";
2N/A
2N/A#define LSBGET(x) ((((x)^((x)-1))+1)>>1)
2N/A#define LSBMASK(n) ((1<<(n))^((1<<(n))-1))
2N/A
2N/A#define GSS_SINFO_STR(x) \
2N/A ((((1<<(x)) < GSS_S_CONTINUE_NEEDED) || ((1<<(x)) > GSS_S_UNSEQ_TOKEN)) ? \
2N/A /**/NULL:sinfo_string[(x)])
2N/A
2N/A/**/
2N/A
2N/Astatic const char * const no_error = "No error";
2N/Astatic const char * const unknown_error = "Unknown %s (field = %d)";
2N/A
2N/A/**/
2N/A
2N/Astatic int
2N/Adisplay_unknown(kind, value, buffer)
2N/A const char *kind;
2N/A OM_uint32 value;
2N/A gss_buffer_t buffer;
2N/A{
2N/A char *str;
2N/A
2N/A if (asprintf(&str, unknown_error, kind, value) < 0)
2N/A return(0);
2N/A
2N/A buffer->length = strlen(str);
2N/A buffer->value = str;
2N/A
2N/A return(1);
2N/A}
2N/A
2N/A/* code should be set to the calling error field */
2N/A
2N/Astatic OM_uint32 display_calling(minor_status, code, status_string)
2N/A OM_uint32 *minor_status;
2N/A OM_uint32 code;
2N/A gss_buffer_t status_string;
2N/A{
2N/A const char *str;
2N/A
2N/A if ((str = GSS_CALLING_ERROR_STR(code))) {
2N/A if (! g_make_string_buffer(str, status_string)) {
2N/A *minor_status = ENOMEM;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A } else {
2N/A if (! display_unknown(calling_error, GSS_CALLING_ERROR_FIELD(code),
2N/A status_string)) {
2N/A *minor_status = ENOMEM;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A }
2N/A *minor_status = 0;
2N/A return(GSS_S_COMPLETE);
2N/A}
2N/A
2N/A/* code should be set to the routine error field */
2N/A
2N/Astatic OM_uint32 display_routine(minor_status, code, status_string)
2N/A OM_uint32 *minor_status;
2N/A OM_uint32 code;
2N/A gss_buffer_t status_string;
2N/A{
2N/A const char *str;
2N/A
2N/A if ((str = GSS_ROUTINE_ERROR_STR(code))) {
2N/A if (! g_make_string_buffer(str, status_string)) {
2N/A *minor_status = ENOMEM;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A } else {
2N/A if (! display_unknown(routine_error, GSS_ROUTINE_ERROR_FIELD(code),
2N/A status_string)) {
2N/A *minor_status = ENOMEM;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A }
2N/A *minor_status = 0;
2N/A return(GSS_S_COMPLETE);
2N/A}
2N/A
2N/A/* code should be set to the bit offset (log_2) of a supplementary info bit */
2N/A
2N/Astatic OM_uint32 display_bit(minor_status, code, status_string)
2N/A OM_uint32 *minor_status;
2N/A OM_uint32 code;
2N/A gss_buffer_t status_string;
2N/A{
2N/A const char *str;
2N/A
2N/A if ((str = GSS_SINFO_STR(code))) {
2N/A if (! g_make_string_buffer(str, status_string)) {
2N/A *minor_status = ENOMEM;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A } else {
2N/A if (! display_unknown(sinfo_code, 1<<code, status_string)) {
2N/A *minor_status = ENOMEM;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A }
2N/A *minor_status = 0;
2N/A return(GSS_S_COMPLETE);
2N/A}
2N/A
2N/A/**/
2N/A
2N/A/* return error messages, for routine errors, call error, and status,
2N/A in that order.
2N/A message_context == 0 : print the routine error
2N/A message_context == 1 : print the calling error
2N/A message_context > 2 : print supplementary info bit (message_context-2)
2N/A*/
2N/A
2N/AOM_uint32 g_display_major_status(minor_status, status_value,
2N/A message_context, status_string)
2N/A OM_uint32 *minor_status;
2N/A OM_uint32 status_value;
2N/A OM_uint32 *message_context;
2N/A gss_buffer_t status_string;
2N/A{
2N/A OM_uint32 ret, tmp;
2N/A int bit;
2N/A
2N/A /*** deal with no error at all specially */
2N/A
2N/A if (status_value == 0) {
2N/A if (! g_make_string_buffer(no_error, status_string)) {
2N/A *minor_status = ENOMEM;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A *message_context = 0;
2N/A *minor_status = 0;
2N/A return(GSS_S_COMPLETE);
2N/A }
2N/A
2N/A /*** do routine error */
2N/A
2N/A if (*message_context == 0) {
2N/A if ((tmp = GSS_ROUTINE_ERROR(status_value))) {
2N/A status_value -= tmp;
2N/A if ((ret = display_routine(minor_status, tmp, status_string)))
2N/A return(ret);
2N/A *minor_status = 0;
2N/A if (status_value) {
2N/A (*message_context)++;
2N/A return(GSS_S_COMPLETE);
2N/A } else {
2N/A *message_context = 0;
2N/A return(GSS_S_COMPLETE);
2N/A }
2N/A } else {
2N/A (*message_context)++;
2N/A }
2N/A } else {
2N/A status_value -= GSS_ROUTINE_ERROR(status_value);
2N/A }
2N/A
2N/A /*** do calling error */
2N/A
2N/A if (*message_context == 1) {
2N/A if ((tmp = GSS_CALLING_ERROR(status_value))) {
2N/A status_value -= tmp;
2N/A if ((ret = display_calling(minor_status, tmp, status_string)))
2N/A return(ret);
2N/A *minor_status = 0;
2N/A if (status_value) {
2N/A (*message_context)++;
2N/A return(GSS_S_COMPLETE);
2N/A } else {
2N/A *message_context = 0;
2N/A return(GSS_S_COMPLETE);
2N/A }
2N/A } else {
2N/A (*message_context)++;
2N/A }
2N/A } else {
2N/A status_value -= GSS_CALLING_ERROR(status_value);
2N/A }
2N/A
2N/A /*** do sinfo bits (*message_context == 2 + number of bits done) */
2N/A
2N/A tmp = GSS_SUPPLEMENTARY_INFO_FIELD(status_value);
2N/A /* mask off the bits which have been done */
2N/A if (*message_context > 2) {
2N/A tmp &= ~LSBMASK(*message_context-3);
2N/A status_value &= ~LSBMASK(*message_context-3);
2N/A }
2N/A
2N/A if (!tmp) {
2N/A /* bogon input - there should be something left */
2N/A *minor_status = (OM_uint32) G_BAD_MSG_CTX;
2N/A return(GSS_S_FAILURE);
2N/A }
2N/A
2N/A /* compute the bit offset */
2N/A /*SUPPRESS 570*/
2N/A for (bit=0; (((OM_uint32) 1)<<bit) != LSBGET(tmp); bit++) ;
2N/A
2N/A /* print it */
2N/A if ((ret = display_bit(minor_status, bit, status_string)))
2N/A return(ret);
2N/A
2N/A /* compute the new status_value/message_context */
2N/A status_value -= ((OM_uint32) 1)<<bit;
2N/A
2N/A if (status_value) {
2N/A *message_context = bit+3;
2N/A return(GSS_S_COMPLETE);
2N/A } else {
2N/A *message_context = 0;
2N/A return(GSS_S_COMPLETE);
2N/A }
2N/A}