2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * glue routine gss_display_status
2N/A *
2N/A */
2N/A
2N/A#include <mglueP.h>
2N/A#include "gssapiP_generic.h"
2N/A#include <stdio.h>
2N/A#ifdef HAVE_STDLIB_H
2N/A#include <stdlib.h>
2N/A#endif
2N/A#include <string.h>
2N/A#include <libintl.h>
2N/A#include <errno.h>
2N/A#include <syslog.h>
2N/A#ifndef TEXT_DOMAIN
2N/A#error TEXT_DOMAIN not defined
2N/A#endif
2N/A
2N/A/* local function */
2N/Astatic OM_uint32 displayMajor(OM_uint32, OM_uint32 *, gss_buffer_t);
2N/A
2N/A
2N/AOM_uint32
2N/Agss_display_status(minor_status,
2N/A status_value,
2N/A status_type,
2N/A req_mech_type,
2N/A message_context,
2N/A status_string)
2N/A
2N/AOM_uint32 *minor_status;
2N/AOM_uint32 status_value;
2N/Aint status_type;
2N/Aconst gss_OID req_mech_type;
2N/AOM_uint32 *message_context;
2N/Agss_buffer_t status_string;
2N/A{
2N/A gss_OID mech_type = (gss_OID) req_mech_type;
2N/A gss_mechanism mech;
2N/A gss_OID_desc m_oid = { 0, 0 };
2N/A
2N/A if (minor_status != NULL)
2N/A *minor_status = 0;
2N/A
2N/A if (status_string != GSS_C_NO_BUFFER) {
2N/A status_string->length = 0;
2N/A status_string->value = NULL;
2N/A }
2N/A
2N/A if (minor_status == NULL ||
2N/A message_context == NULL ||
2N/A status_string == GSS_C_NO_BUFFER)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A /* we handle major status codes, and the mechs do the minor */
2N/A if (status_type == GSS_C_GSS_CODE)
2N/A return (displayMajor(status_value, message_context,
2N/A status_string));
2N/A
2N/A /*
2N/A * must be the minor status - let mechs do the work
2N/A * select the appropriate underlying mechanism routine and
2N/A * call it.
2N/A */
2N/A
2N/A /*
2N/A * In this version, we only handle status codes that have been
2N/A * mapped to a flat numbering space. Look up the value we got
2N/A * passed. If it's not found, complain.
2N/A */
2N/A if (status_value == 0) {
2N/A status_string->value = strdup("Unknown error");
2N/A if (status_string->value == NULL) {
2N/A *minor_status = ENOMEM;
2N/A map_errcode(minor_status);
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A status_string->length = strlen(status_string->value);
2N/A *message_context = 0;
2N/A *minor_status = 0;
2N/A return (GSS_S_COMPLETE);
2N/A }
2N/A {
2N/A int err;
2N/A OM_uint32 m_status = 0, status;
2N/A
2N/A err = gssint_mecherrmap_get(status_value, &m_oid, &m_status);
2N/A if (err) {
2N/A *minor_status = err;
2N/A map_errcode(minor_status);
2N/A return (GSS_S_BAD_STATUS);
2N/A }
2N/A
2N/A if (m_oid.length == 0) {
2N/A /* Magic flag for com_err values. */
2N/A status = gssint_g_display_com_err_status(minor_status,
2N/A m_status,
2N/A status_string);
2N/A if (status != GSS_S_COMPLETE)
2N/A map_errcode(minor_status);
2N/A return (status);
2N/A }
2N/A mech_type = &m_oid;
2N/A status_value = m_status;
2N/A }
2N/A
2N/A mech = __gss_get_mechanism(mech_type);
2N/A
2N/A if (mech && mech->gss_display_status) {
2N/A OM_uint32 r;
2N/A
2N/A if (mech_type == GSS_C_NULL_OID)
2N/A mech_type = &mech->mech_type;
2N/A
2N/A r = mech->gss_display_status(minor_status,
2N/A status_value, status_type, mech_type,
2N/A message_context, status_string);
2N/A /*
2N/A * How's this for weird? If we get an error returning the
2N/A * mechanism-specific error code, we save away the
2N/A * mechanism-specific error code describing the error.
2N/A */
2N/A if (r != GSS_S_COMPLETE)
2N/A map_error(minor_status, mech);
2N/A return (r);
2N/A }
2N/A
2N/A if (!mech)
2N/A return (GSS_S_BAD_MECH);
2N/A
2N/A return (GSS_S_UNAVAILABLE);
2N/A} /* gss_display_status */
2N/A
2N/A
2N/A/*
2N/A * function to map the major error codes
2N/A * it uses case statements so that the strings could be wrapped by gettext
2N/A * msgCtxt is interpreted as:
2N/A * 0 - first call
2N/A * 1 - routine error
2N/A * >= 2 - the supplementary error code bit shifted by 1
2N/A */
2N/Astatic OM_uint32
2N/AdisplayMajor(status, msgCtxt, outStr)
2N/AOM_uint32 status;
2N/AOM_uint32 *msgCtxt;
2N/Agss_buffer_t outStr;
2N/A{
2N/A OM_uint32 oneVal, mask = 0x1, currErr;
2N/A char *errStr = NULL;
2N/A int i, haveErr = 0;
2N/A
2N/A /* take care of the success value first */
2N/A if (status == GSS_S_COMPLETE)
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "The routine completed successfully");
2N/A else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) {
2N/A switch (oneVal) {
2N/A case GSS_S_CALL_INACCESSIBLE_READ:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "A required input parameter"
2N/A " could not be read");
2N/A break;
2N/A
2N/A case GSS_S_CALL_INACCESSIBLE_WRITE:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "A required output parameter"
2N/A " could not be written");
2N/A break;
2N/A
2N/A case GSS_S_CALL_BAD_STRUCTURE:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "A parameter was malformed");
2N/A break;
2N/A
2N/A default:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "An invalid status code was supplied");
2N/A break;
2N/A }
2N/A
2N/A /* we now need to determine new value of msgCtxt */
2N/A if (GSS_ROUTINE_ERROR(status))
2N/A *msgCtxt = 1;
2N/A else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
2N/A *msgCtxt = (OM_uint32)(oneVal << 1);
2N/A else
2N/A *msgCtxt = 0;
2N/A
2N/A } else if ((*msgCtxt == 0 || *msgCtxt == 1) &&
2N/A (oneVal = GSS_ROUTINE_ERROR(status))) {
2N/A switch (oneVal) {
2N/A case GSS_S_BAD_MECH:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "An unsupported mechanism"
2N/A " was requested");
2N/A break;
2N/A
2N/A case GSS_S_BAD_NAME:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "An invalid name was supplied");
2N/A break;
2N/A
2N/A case GSS_S_BAD_NAMETYPE:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "A supplied name was of an"
2N/A " unsupported type");
2N/A break;
2N/A
2N/A case GSS_S_BAD_BINDINGS:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "Incorrect channel bindings"
2N/A " were supplied");
2N/A break;
2N/A
2N/A case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "A token had an invalid Message"
2N/A " Integrity Check (MIC)");
2N/A break;
2N/A
2N/A case GSS_S_NO_CRED:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "No credentials were supplied, or the"
2N/A " credentials were unavailable or"
2N/A " inaccessible");
2N/A break;
2N/A
2N/A case GSS_S_NO_CONTEXT:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "No context has been established");
2N/A break;
2N/A
2N/A case GSS_S_DEFECTIVE_TOKEN:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "Invalid token was supplied");
2N/A break;
2N/A
2N/A case GSS_S_DEFECTIVE_CREDENTIAL:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "Invalid credential was supplied");
2N/A break;
2N/A
2N/A case GSS_S_CREDENTIALS_EXPIRED:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "The referenced credential has"
2N/A " expired");
2N/A break;
2N/A
2N/A case GSS_S_CONTEXT_EXPIRED:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "The referenced context has expired");
2N/A break;
2N/A
2N/A case GSS_S_FAILURE:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "Unspecified GSS failure. Minor code"
2N/A " may provide more information");
2N/A break;
2N/A
2N/A case GSS_S_BAD_QOP:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "The quality-of-protection (QOP) "
2N/A "requested could not be provided");
2N/A break;
2N/A
2N/A case GSS_S_UNAUTHORIZED:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "The operation is forbidden by local"
2N/A " security policy");
2N/A break;
2N/A
2N/A case GSS_S_UNAVAILABLE:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "The operation or option is not"
2N/A " available or unsupported");
2N/A break;
2N/A
2N/A case GSS_S_DUPLICATE_ELEMENT:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "The requested credential element"
2N/A " already exists");
2N/A break;
2N/A
2N/A case GSS_S_NAME_NOT_MN:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "The provided name was not mechanism"
2N/A " specific (MN)");
2N/A break;
2N/A
2N/A case GSS_S_BAD_STATUS:
2N/A default:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "An invalid status code was supplied");
2N/A }
2N/A
2N/A /* we must determine if the caller should call us again */
2N/A if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
2N/A *msgCtxt = (OM_uint32)(oneVal << 1);
2N/A else
2N/A *msgCtxt = 0;
2N/A
2N/A } else if ((*msgCtxt == 0 || *msgCtxt >= 2) &&
2N/A (oneVal = GSS_SUPPLEMENTARY_INFO(status))) {
2N/A /*
2N/A * if msgCtxt is not 0, then it should encode
2N/A * the supplementary error code we should be printing
2N/A */
2N/A if (*msgCtxt >= 2)
2N/A oneVal = (OM_uint32) (*msgCtxt) >> 1;
2N/A else
2N/A oneVal = GSS_SUPPLEMENTARY_INFO(status);
2N/A
2N/A /* we display the errors LSB first */
2N/A for (i = 0; i < 16; i++) {
2N/A if (oneVal & mask) {
2N/A haveErr = 1;
2N/A break;
2N/A }
2N/A mask <<= 1;
2N/A }
2N/A
2N/A /* isolate the bit or if not found set to illegal value */
2N/A if (haveErr)
2N/A currErr = oneVal & mask;
2N/A else
2N/A currErr = 1 << 17; /* illegal value */
2N/A
2N/A switch (currErr) {
2N/A case GSS_S_CONTINUE_NEEDED:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "The routine must be called again to"
2N/A " complete its function");
2N/A break;
2N/A
2N/A case GSS_S_DUPLICATE_TOKEN:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "The token was a duplicate of an"
2N/A " earlier token");
2N/A break;
2N/A
2N/A case GSS_S_OLD_TOKEN:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "The token's validity period"
2N/A " has expired");
2N/A break;
2N/A
2N/A case GSS_S_UNSEQ_TOKEN:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "A later token has already been"
2N/A " processed");
2N/A break;
2N/A
2N/A case GSS_S_GAP_TOKEN:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "An expected per-message token was"
2N/A " not received");
2N/A break;
2N/A
2N/A default:
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "An invalid status code was supplied");
2N/A }
2N/A
2N/A /*
2N/A * we must check if there is any other supplementary errors
2N/A * if found, then turn off current bit, and store next value
2N/A * in msgCtxt shifted by 1 bit
2N/A */
2N/A if (!haveErr)
2N/A *msgCtxt = 0;
2N/A else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask)
2N/A *msgCtxt = (OM_uint32)
2N/A ((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1);
2N/A else
2N/A *msgCtxt = 0;
2N/A }
2N/A
2N/A if (errStr == NULL)
2N/A errStr = dgettext(TEXT_DOMAIN,
2N/A "An invalid status code was supplied");
2N/A
2N/A /* now copy the status code and return to caller */
2N/A outStr->length = strlen(errStr);
2N/A outStr->value = strdup(errStr);
2N/A if (outStr->value == NULL) {
2N/A outStr->length = 0;
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A return (GSS_S_COMPLETE);
2N/A} /* displayMajor */