2 * SPNEGO wrapper for Kerberos5 GSS-API
3 * kouril@ics.muni.cz, 2003
4 * (mostly based on Heimdal code)
7 #include "spnegokrb5_locl.h"
9 #define OID_cmp(o1, o2) \
10 (((o1)->length == (o2)->length) && \
11 (memcmp((o1)->components, (o2)->components,(int) (o1)->length) == 0))
14 code_NegTokenArg(OM_uint32 *minor_status,
15 const NegTokenTarg *targ,
16 unsigned char **outbuf,
21 size_t buf_size, buf_len;
24 buf = malloc(buf_size);
26 *minor_status = ENOMEM;
31 ret = encode_NegTokenTarg(buf + buf_size -1,
37 ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
48 if (ret == ASN1_OVERFLOW) {
52 tmp = realloc (buf, buf_size);
54 *minor_status = ENOMEM;
65 } while (ret == ASN1_OVERFLOW);
67 *outbuf = buf + buf_size - buf_len;
68 *outbuf_size = buf_len;
69 return GSS_S_COMPLETE;
73 send_reject (OM_uint32 *minor_status,
74 gss_buffer_t output_token)
81 targ.negResult = malloc(sizeof(*targ.negResult));
82 if (targ.negResult == NULL) {
83 *minor_status = ENOMEM;
86 *(targ.negResult) = reject;
87 targ.supportedMech = NULL;
88 targ.responseToken = NULL;
89 targ.mechListMIC = NULL;
91 ret = code_NegTokenArg (minor_status, &targ, &buf, &buf_size);
92 free_NegTokenTarg(&targ);
96 ret = gssapi_spnego_encapsulate(minor_status,
103 return GSS_S_BAD_MECH;
107 send_accept (OM_uint32 *minor_status,
108 gss_buffer_t output_token,
109 gss_buffer_t mech_token)
116 memset(&targ, 0, sizeof(targ));
117 targ.negResult = malloc(sizeof(*targ.negResult));
118 if (targ.negResult == NULL) {
119 *minor_status = ENOMEM;
120 return GSS_S_FAILURE;
122 *(targ.negResult) = accept_completed;
124 targ.supportedMech = malloc(sizeof(*targ.supportedMech));
125 if (targ.supportedMech == NULL) {
126 free_NegTokenTarg(&targ);
127 *minor_status = ENOMEM;
128 return GSS_S_FAILURE;
131 ret = der_get_oid(GSS_KRB5_MECH->elements,
132 GSS_KRB5_MECH->length,
136 free_NegTokenTarg(&targ);
137 *minor_status = ENOMEM;
138 return GSS_S_FAILURE;
141 if (mech_token != NULL && mech_token->length != 0) {
142 targ.responseToken = malloc(sizeof(*targ.responseToken));
143 if (targ.responseToken == NULL) {
144 free_NegTokenTarg(&targ);
145 *minor_status = ENOMEM;
146 return GSS_S_FAILURE;
148 targ.responseToken->length = mech_token->length;
149 targ.responseToken->data = mech_token->value;
150 mech_token->length = 0;
151 mech_token->value = NULL;
153 targ.responseToken = NULL;
156 ret = code_NegTokenArg (minor_status, &targ, &buf, &buf_size);
157 free_NegTokenTarg(&targ);
161 ret = gssapi_spnego_encapsulate(minor_status,
167 return GSS_S_COMPLETE;
170 OM_uint32 gss_accept_sec_context_spnego
171 (OM_uint32 * minor_status,
172 gss_ctx_id_t * context_handle,
173 const gss_cred_id_t acceptor_cred_handle,
174 const gss_buffer_t input_token_buffer,
175 const gss_channel_bindings_t input_chan_bindings,
176 gss_name_t * src_name,
178 gss_buffer_t output_token,
179 OM_uint32 * ret_flags,
180 OM_uint32 * time_rec,
181 gss_cred_id_t * delegated_cred_handle)
183 NegTokenInit init_token;
184 OM_uint32 major_status;
185 gss_buffer_desc ibuf, obuf;
186 gss_buffer_t ot = NULL;
190 size_t len, taglen, ni_len;
194 memset(&init_token, 0, sizeof(init_token));
196 ret = gssapi_spnego_decapsulate(minor_status, input_token_buffer,
197 &buf, &buf_size, GSS_SPNEGO_MECH);
201 ret = der_match_tag_and_length(buf, buf_size, CONTEXT, CONS,
206 ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len);
208 *minor_status = EINVAL; /* XXX */
209 return GSS_S_DEFECTIVE_TOKEN;
212 if (init_token.mechTypes == NULL)
213 return send_reject (minor_status, output_token);
215 for (i = 0; !found && i < init_token.mechTypes->len; ++i) {
219 ret = der_put_oid (mechbuf + sizeof(mechbuf) - 1,
221 &init_token.mechTypes->val[i],
224 return GSS_S_DEFECTIVE_TOKEN;
225 if (mech_len == GSS_KRB5_MECH->length
226 && memcmp(GSS_KRB5_MECH->elements,
227 mechbuf + sizeof(mechbuf) - mech_len,
233 return send_reject (minor_status, output_token);
235 if (init_token.mechToken != NULL) {
236 ibuf.length = init_token.mechToken->length;
237 ibuf.value = init_token.mechToken->data;
239 major_status = gss_accept_sec_context(&minor,
241 acceptor_cred_handle,
249 delegated_cred_handle);
250 if (GSS_ERROR(major_status)) {
251 send_reject (minor_status, output_token);
257 ret = send_accept (minor_status, output_token, ot);
259 gss_release_buffer(&minor, ot);