Home | History | Annotate | Download | only in mech
      1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      2 
      3 /*
      4  * Copyright 1993 by OpenVision Technologies, Inc.
      5  *
      6  * Permission to use, copy, modify, distribute, and sell this software
      7  * and its documentation for any purpose is hereby granted without fee,
      8  * provided that the above copyright notice appears in all copies and
      9  * that both that copyright notice and this permission notice appear in
     10  * supporting documentation, and that the name of OpenVision not be used
     11  * in advertising or publicity pertaining to distribution of the software
     12  * without specific, written prior permission. OpenVision makes no
     13  * representations about the suitability of this software for any
     14  * purpose.  It is provided "as is" without express or implied warranty.
     15  *
     16  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     18  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
     20  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
     21  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     22  * PERFORMANCE OF THIS SOFTWARE.
     23  */
     24 
     25 #include "gssapiP_generic.h"
     26 #include <string.h>
     27 #include <stdio.h>
     28 
     29 /*
     30  * $Id: disp_major_status.c 13236 2001-05-08 17:10:18Z epeisach $
     31  */
     32 
     33 /* XXXX these are not part of the GSSAPI C bindings!  (but should be) */
     34 /* SUNW15resync - MIT 1.5 has these in gssapi.h */
     35 
     36 #define GSS_CALLING_ERROR_FIELD(x) \
     37    (((x) >> GSS_C_CALLING_ERROR_OFFSET) & GSS_C_CALLING_ERROR_MASK)
     38 #define GSS_ROUTINE_ERROR_FIELD(x) \
     39    (((x) >> GSS_C_ROUTINE_ERROR_OFFSET) & GSS_C_ROUTINE_ERROR_MASK)
     40 #define GSS_SUPPLEMENTARY_INFO_FIELD(x) \
     41    (((x) >> GSS_C_SUPPLEMENTARY_OFFSET) & GSS_C_SUPPLEMENTARY_MASK)
     42 
     43 
     44 /* This code has knowledge of the min and max errors of each type
     45    within the gssapi major status */
     46 
     47 #define GSS_ERROR_STR(value, array, select, min, max, num) \
     48    (((select(value) < (min)) || (select(value) > (max))) ? NULL : \
     49     (array)[num(value)])
     50 
     51 /**/
     52 
     53 static const char * const calling_error_string[] = {
     54    NULL,
     55    "A required input parameter could not be read",
     56    "A required input parameter could not be written",
     57    "A parameter was malformed",
     58 };
     59 
     60 static const char * const calling_error = "calling error";
     61 
     62 #define GSS_CALLING_ERROR_STR(x) \
     63    GSS_ERROR_STR((x), calling_error_string, GSS_CALLING_ERROR, \
     64 		 GSS_S_CALL_INACCESSIBLE_READ, GSS_S_CALL_BAD_STRUCTURE, \
     65 		 GSS_CALLING_ERROR_FIELD)
     66 
     67 /**/
     68 
     69 static const char * const routine_error_string[] = {
     70    NULL,
     71    "An unsupported mechanism was requested",
     72    "An invalid name was supplied",
     73    "A supplied name was of an unsupported type",
     74    "Incorrect channel bindings were supplied",
     75    "An invalid status code was supplied",
     76    "A token had an invalid signature",
     77    "No credentials were supplied",
     78    "No context has been established",
     79    "A token was invalid",
     80    "A credential was invalid",
     81    "The referenced credentials have expired",
     82    "The context has expired",
     83    "Miscellaneous failure",
     84    "The quality-of-protection requested could not be provided",
     85    "The operation is forbidden by the local security policy",
     86    "The operation or option is not available",
     87 };
     88 
     89 static const char * const routine_error = "routine error";
     90 
     91 #define GSS_ROUTINE_ERROR_STR(x) \
     92    GSS_ERROR_STR((x), routine_error_string, GSS_ROUTINE_ERROR, \
     93 		 GSS_S_BAD_MECH, GSS_S_FAILURE, \
     94 		 GSS_ROUTINE_ERROR_FIELD)
     95 
     96 /**/
     97 
     98 /* this becomes overly gross after about 4 strings */
     99 
    100 static const char * const sinfo_string[] = {
    101    "The routine must be called again to complete its function",
    102    "The token was a duplicate of an earlier token",
    103    "The token's validity period has expired",
    104    "A later token has already been processed",
    105 };
    106 
    107 static const char * const sinfo_code = "supplementary info code";
    108 
    109 #define LSBGET(x) ((((x)^((x)-1))+1)>>1)
    110 #define LSBMASK(n) ((1<<(n))^((1<<(n))-1))
    111 
    112 #define GSS_SINFO_STR(x) \
    113    ((((1<<(x)) < GSS_S_CONTINUE_NEEDED) || ((1<<(x)) > GSS_S_UNSEQ_TOKEN)) ? \
    114     /**/NULL:sinfo_string[(x)])
    115 
    116 /**/
    117 
    118 static const char * const no_error = "No error";
    119 static const char * const unknown_error = "Unknown %s (field = %d)";
    120 
    121 /**/
    122 
    123 static int
    124 display_unknown(kind, value, buffer)
    125      const char *kind;
    126      OM_uint32 value;
    127      gss_buffer_t buffer;
    128 {
    129    char *str;
    130 
    131    if ((str =
    132 	(char *) xmalloc(strlen(unknown_error)+strlen(kind)+7)) == NULL)
    133       return(0);
    134 
    135    sprintf(str, unknown_error, kind, value);
    136 
    137    buffer->length = strlen(str);
    138    buffer->value = str;
    139 
    140    return(1);
    141 }
    142 
    143 /* code should be set to the calling error field */
    144 
    145 static OM_uint32 display_calling(minor_status, code, status_string)
    146      OM_uint32 *minor_status;
    147      OM_uint32 code;
    148      gss_buffer_t status_string;
    149 {
    150    const char *str;
    151 
    152    if ((str = GSS_CALLING_ERROR_STR(code))) {
    153       if (! g_make_string_buffer(str, status_string)) {
    154 	 *minor_status = ENOMEM;
    155 	 return(GSS_S_FAILURE);
    156       }
    157    } else {
    158       if (! display_unknown(calling_error, GSS_CALLING_ERROR_FIELD(code),
    159 			    status_string)) {
    160 	 *minor_status = ENOMEM;
    161 	 return(GSS_S_FAILURE);
    162       }
    163    }
    164    *minor_status = 0;
    165    return(GSS_S_COMPLETE);
    166 }
    167 
    168 /* code should be set to the routine error field */
    169 
    170 static OM_uint32 display_routine(minor_status, code, status_string)
    171      OM_uint32 *minor_status;
    172      OM_uint32 code;
    173      gss_buffer_t status_string;
    174 {
    175    const char *str;
    176 
    177    if ((str = GSS_ROUTINE_ERROR_STR(code))) {
    178       if (! g_make_string_buffer(str, status_string)) {
    179 	 *minor_status = ENOMEM;
    180 	 return(GSS_S_FAILURE);
    181       }
    182    } else {
    183       if (! display_unknown(routine_error, GSS_ROUTINE_ERROR_FIELD(code),
    184 			    status_string)) {
    185 	 *minor_status = ENOMEM;
    186 	 return(GSS_S_FAILURE);
    187       }
    188    }
    189    *minor_status = 0;
    190    return(GSS_S_COMPLETE);
    191 }
    192 
    193 /* code should be set to the bit offset (log_2) of a supplementary info bit */
    194 
    195 static OM_uint32 display_bit(minor_status, code, status_string)
    196      OM_uint32 *minor_status;
    197      OM_uint32 code;
    198      gss_buffer_t status_string;
    199 {
    200    const char *str;
    201 
    202    if ((str = GSS_SINFO_STR(code))) {
    203       if (! g_make_string_buffer(str, status_string)) {
    204 	 *minor_status = ENOMEM;
    205 	 return(GSS_S_FAILURE);
    206       }
    207    } else {
    208       if (! display_unknown(sinfo_code, 1<<code, status_string)) {
    209 	 *minor_status = ENOMEM;
    210 	 return(GSS_S_FAILURE);
    211       }
    212    }
    213    *minor_status = 0;
    214    return(GSS_S_COMPLETE);
    215 }
    216 
    217 /**/
    218 
    219 /* return error messages, for routine errors, call error, and status,
    220    in that order.
    221      message_context == 0 : print the routine error
    222      message_context == 1 : print the calling error
    223      message_context > 2  : print supplementary info bit (message_context-2)
    224      */
    225 
    226 OM_uint32 g_display_major_status(minor_status, status_value,
    227 				 message_context, status_string)
    228      OM_uint32 *minor_status;
    229      OM_uint32 status_value;
    230      OM_uint32 *message_context;
    231      gss_buffer_t status_string;
    232 {
    233    OM_uint32 ret, tmp;
    234    int bit;
    235 
    236    /*** deal with no error at all specially */
    237 
    238    if (status_value == 0) {
    239       if (! g_make_string_buffer(no_error, status_string)) {
    240 	 *minor_status = ENOMEM;
    241 	 return(GSS_S_FAILURE);
    242       }
    243       *message_context = 0;
    244       *minor_status = 0;
    245       return(GSS_S_COMPLETE);
    246    }
    247 
    248    /*** do routine error */
    249 
    250    if (*message_context == 0) {
    251       if ((tmp = GSS_ROUTINE_ERROR(status_value))) {
    252 	 status_value -= tmp;
    253 	 if ((ret = display_routine(minor_status, tmp, status_string)))
    254 	    return(ret);
    255 	 *minor_status = 0;
    256 	 if (status_value) {
    257 	    (*message_context)++;
    258 	    return(GSS_S_COMPLETE);
    259 	 } else {
    260 	    *message_context = 0;
    261 	    return(GSS_S_COMPLETE);
    262 	 }
    263       } else {
    264 	 (*message_context)++;
    265       }
    266    } else {
    267       status_value -= GSS_ROUTINE_ERROR(status_value);
    268    }
    269 
    270    /*** do calling error */
    271 
    272    if (*message_context == 1) {
    273       if ((tmp = GSS_CALLING_ERROR(status_value))) {
    274 	 status_value -= tmp;
    275 	 if ((ret = display_calling(minor_status, tmp, status_string)))
    276 	    return(ret);
    277 	 *minor_status = 0;
    278 	 if (status_value) {
    279 	    (*message_context)++;
    280 	    return(GSS_S_COMPLETE);
    281 	 } else {
    282 	    *message_context = 0;
    283 	    return(GSS_S_COMPLETE);
    284 	 }
    285       } else {
    286 	 (*message_context)++;
    287       }
    288    } else {
    289       status_value -= GSS_CALLING_ERROR(status_value);
    290    }
    291 
    292    /*** do sinfo bits (*message_context == 2 + number of bits done) */
    293 
    294    tmp = GSS_SUPPLEMENTARY_INFO_FIELD(status_value);
    295    /* mask off the bits which have been done */
    296    if (*message_context > 2) {
    297       tmp &= ~LSBMASK(*message_context-3);
    298       status_value &= ~LSBMASK(*message_context-3);
    299    }
    300 
    301    if (!tmp) {
    302       /* bogon input - there should be something left */
    303       *minor_status = (OM_uint32) G_BAD_MSG_CTX;
    304       return(GSS_S_FAILURE);
    305    }
    306 
    307    /* compute the bit offset */
    308    /*SUPPRESS 570*/
    309    for (bit=0; (((OM_uint32) 1)<<bit) != LSBGET(tmp); bit++) ;
    310 
    311    /* print it */
    312    if ((ret = display_bit(minor_status, bit, status_string)))
    313       return(ret);
    314 
    315    /* compute the new status_value/message_context */
    316    status_value -= ((OM_uint32) 1)<<bit;
    317 
    318    if (status_value) {
    319       *message_context = bit+3;
    320       return(GSS_S_COMPLETE);
    321    } else {
    322       *message_context = 0;
    323       return(GSS_S_COMPLETE);
    324    }
    325 }
    326