1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
|
// Copyright 2013-2015 Apcera Inc. All rights reserved.
// GSS status and errors
package gssapi
/*
#include <gssapi/gssapi.h>
OM_uint32
wrap_gss_display_status(void *fp,
OM_uint32 *minor_status,
OM_uint32 status_value,
int status_type,
const gss_OID mech_type,
OM_uint32 *message_context,
gss_buffer_t status_string)
{
return ((OM_uint32(*)(
OM_uint32 *,
OM_uint32,
int,
const gss_OID,
OM_uint32 *,
gss_buffer_t)
)fp)(minor_status,
status_value,
status_type,
mech_type,
message_context,
status_string);
}
*/
import "C"
import (
"errors"
"fmt"
"strings"
)
// Constant values are specified for C-language bindings in RFC 2744.
/*
"""
These errors are encoded into the 32-bit GSS status code as follows:
MSB LSB
|------------------------------------------------------------|
| Calling Error | Routine Error | Supplementary Info |
|------------------------------------------------------------|
Bit 31 24 23 16 15 0
"""
Note that the first two fields hold integer consts, whereas Supplementary Info
is a bit-field.
*/
const (
shiftCALLING = 24
shiftROUTINE = 16
maskCALLING = 0xFF000000
maskROUTINE = 0x00FF0000
maskSUPPINFO = 0x0000FFFF
)
// Status values are returned by gssapi calls to indicate the result of a call.
// Declared according to: https://tools.ietf.org/html/rfc2743#page-17
const (
GSS_S_COMPLETE MajorStatus = 0
GSS_S_CALL_INACCESSIBLE_READ MajorStatus = 1 << shiftCALLING
GSS_S_CALL_INACCESSIBLE_WRITE = 2 << shiftCALLING
GSS_S_CALL_BAD_STRUCTURE = 3 << shiftCALLING
GSS_S_BAD_MECH MajorStatus = 1 << shiftROUTINE
GSS_S_BAD_NAME = 2 << shiftROUTINE
GSS_S_BAD_NAMETYPE = 3 << shiftROUTINE
GSS_S_BAD_BINDINGS = 4 << shiftROUTINE
GSS_S_BAD_STATUS = 5 << shiftROUTINE
GSS_S_BAD_MIC = 6 << shiftROUTINE
GSS_S_BAD_SIG = 6 << shiftROUTINE // duplication deliberate
GSS_S_NO_CRED = 7 << shiftROUTINE
GSS_S_NO_CONTEXT = 8 << shiftROUTINE
GSS_S_DEFECTIVE_TOKEN = 9 << shiftROUTINE
GSS_S_DEFECTIVE_CREDENTIAL = 10 << shiftROUTINE
GSS_S_CREDENTIALS_EXPIRED = 11 << shiftROUTINE
GSS_S_CONTEXT_EXPIRED = 12 << shiftROUTINE
GSS_S_FAILURE = 13 << shiftROUTINE
GSS_S_BAD_QOP = 14 << shiftROUTINE
GSS_S_UNAUTHORIZED = 15 << shiftROUTINE
GSS_S_UNAVAILABLE = 16 << shiftROUTINE
GSS_S_DUPLICATE_ELEMENT = 17 << shiftROUTINE
GSS_S_NAME_NOT_MN = 18 << shiftROUTINE
field_GSS_S_CONTINUE_NEEDED = 1 << 0
field_GSS_S_DUPLICATE_TOKEN = 1 << 1
field_GSS_S_OLD_TOKEN = 1 << 2
field_GSS_S_UNSEQ_TOKEN = 1 << 3
field_GSS_S_GAP_TOKEN = 1 << 4
)
// These are GSSAPI-defined:
// TODO: should MajorStatus be defined as C.OM_uint32?
type MajorStatus uint32
// CallingError is equivalent to C GSS_CALLING_ERROR() macro.
func (st MajorStatus) CallingError() MajorStatus {
return st & maskCALLING
}
// RoutineError is equivalent to C GSS_ROUTINE_ERROR() macro.
func (st MajorStatus) RoutineError() MajorStatus {
return st & maskROUTINE
}
// SupplementaryInfo is equivalent to C GSS_SUPPLEMENTARY_INFO() macro.
func (st MajorStatus) SupplementaryInfo() MajorStatus {
return st & maskSUPPINFO
}
// IsError is equivalent to C GSS_ERROR() macro. Not written as 'Error' because
// that's special in Go conventions. (i.e. conforming to error interface)
func (st MajorStatus) IsError() bool {
return st&(maskCALLING|maskROUTINE) != 0
}
// ContinueNeeded is equivalent to a C bitfield set test against the
// GSS_S_CONTINUE_NEEDED macro.
func (st MajorStatus) ContinueNeeded() bool {
return st&field_GSS_S_CONTINUE_NEEDED != 0
}
// DuplicateToken is equivalent to a C bitfield set test against the
// GSS_S_DUPLICATE_TOKEN macro.
func (st MajorStatus) DuplicateToken() bool {
return st&field_GSS_S_DUPLICATE_TOKEN != 0
}
// OldToken is equivalent to a C bitfield set test against the
// GSS_S_OLD_TOKEN macro.
func (st MajorStatus) OldToken() bool {
return st&field_GSS_S_OLD_TOKEN != 0
}
// UnseqToken is equivalent to a C bitfield set test against the
// GSS_S_UNSEQ_TOKEN macro.
func (st MajorStatus) UnseqToken() bool {
return st&field_GSS_S_UNSEQ_TOKEN != 0
}
// GapToken is equivalent to a C bitfield set test against the
// GSS_S_GAP_TOKEN macro.
func (st MajorStatus) GapToken() bool {
return st&field_GSS_S_GAP_TOKEN != 0
}
// Error is designed to serve both as an error, and as a general gssapi status
// container. If Major is GSS_S_FAILURE, then information will be in Minor.
// The GoError method will return a nil if it doesn't represent a real error.
type Error struct {
// gssapi lib binding, so that we can convert the results of an
// operation to a string for diagnosis.
*Lib
// Specified by gssapi
Major MajorStatus
// Mechanism-specific:
Minor C.OM_uint32
}
// MakeError creates a golang Error object from a gssapi major & minor status.
func (lib *Lib) MakeError(major, minor C.OM_uint32) *Error {
return &Error{
Lib: lib,
Major: MajorStatus(major),
Minor: minor,
}
}
// ErrContinueNeeded may be returned by InitSecContext or AcceptSecContext to
// indicate that another iteration is needed
var ErrContinueNeeded = errors.New("continue needed")
func (lib *Lib) stashLastStatus(major, minor C.OM_uint32) error {
lib.LastStatus = lib.MakeError(major, minor)
return lib.LastStatus.GoError()
}
// GoError returns an untyped error interface object.
func (e *Error) GoError() error {
if e.Major.IsError() {
return e
}
return nil
}
// Error returns a string representation of an Error object.
func (e *Error) Error() string {
messages := []string{}
nOther := 0
context := C.OM_uint32(0)
inquiry := C.OM_uint32(0)
code_type := 0
first := true
if e.Major.RoutineError() == GSS_S_FAILURE {
inquiry = e.Minor
code_type = GSS_C_MECH_CODE
} else {
inquiry = C.OM_uint32(e.Major)
code_type = GSS_C_GSS_CODE
}
for first || context != C.OM_uint32(0) {
first = false
min := C.OM_uint32(0)
b, err := e.MakeBuffer(allocGSSAPI)
if err != nil {
break
}
// TODO: store a mech_type at the lib level? Or context? For now GSS_C_NO_OID...
maj := C.wrap_gss_display_status(
e.Fp_gss_display_status,
&min,
inquiry,
C.int(code_type),
nil,
&context,
b.C_gss_buffer_t)
err = e.MakeError(maj, min).GoError()
if err != nil {
nOther = nOther + 1
}
messages = append(messages, b.String())
b.Release()
}
if nOther > 0 {
messages = append(messages, fmt.Sprintf("additionally, %d conversions failed", nOther))
}
messages = append(messages, "")
return strings.Join(messages, "\n")
}
|