-
Notifications
You must be signed in to change notification settings - Fork 25
/
status.go
247 lines (210 loc) · 6.85 KB
/
status.go
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")
}