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)
79 targ.negResult = malloc(sizeof(*targ.negResult));
80 if (targ.negResult == NULL) {
81 *minor_status = ENOMEM;
84 *(targ.negResult) = reject;
86 targ.supportedMech = NULL;
87 targ.responseToken = NULL;
88 targ.mechListMIC = NULL;
90 ret = code_NegTokenArg (minor_status, &targ,
91 (unsigned char**) &output_token->value, &output_token->length);
92 free_NegTokenTarg(&targ);
96 return GSS_S_BAD_MECH;
100 send_accept (OM_uint32 *minor_status,
101 gss_buffer_t output_token,
102 gss_buffer_t mech_token)
107 memset(&targ, 0, sizeof(targ));
108 targ.negResult = malloc(sizeof(*targ.negResult));
109 if (targ.negResult == NULL) {
110 *minor_status = ENOMEM;
111 return GSS_S_FAILURE;
113 *(targ.negResult) = accept_completed;
115 targ.supportedMech = malloc(sizeof(*targ.supportedMech));
116 if (targ.supportedMech == NULL) {
117 free_NegTokenTarg(&targ);
118 *minor_status = ENOMEM;
119 return GSS_S_FAILURE;
122 ret = der_get_oid(GSS_KRB5_MECH->elements,
123 GSS_KRB5_MECH->length,
127 free_NegTokenTarg(&targ);
128 *minor_status = ENOMEM;
129 return GSS_S_FAILURE;
132 if (mech_token != NULL && mech_token->length != 0) {
133 targ.responseToken = malloc(sizeof(*targ.responseToken));
134 if (targ.responseToken == NULL) {
135 free_NegTokenTarg(&targ);
136 *minor_status = ENOMEM;
137 return GSS_S_FAILURE;
139 targ.responseToken->length = mech_token->length;
140 targ.responseToken->data = mech_token->value;
141 mech_token->length = 0;
142 mech_token->value = NULL;
144 targ.responseToken = NULL;
147 ret = code_NegTokenArg (minor_status, &targ,
148 (unsigned char**) &output_token->value, &output_token->length);
149 free_NegTokenTarg(&targ);
153 return GSS_S_COMPLETE;
156 OM_uint32 gss_accept_sec_context_spnego
157 (OM_uint32 * minor_status,
158 gss_ctx_id_t * context_handle,
159 const gss_cred_id_t acceptor_cred_handle,
160 const gss_buffer_t input_token_buffer,
161 const gss_channel_bindings_t input_chan_bindings,
162 gss_name_t * src_name,
164 gss_buffer_t output_token,
165 OM_uint32 * ret_flags,
166 OM_uint32 * time_rec,
167 gss_cred_id_t * delegated_cred_handle)
169 NegTokenInit init_token;
170 OM_uint32 major_status;
171 gss_buffer_desc ibuf, obuf;
172 gss_buffer_t ot = NULL;
176 size_t len, taglen, ni_len;
180 memset(&init_token, 0, sizeof(init_token));
182 ret = gssapi_spnego_decapsulate(minor_status, input_token_buffer,
183 &buf, &buf_size, GSS_SPNEGO_MECH);
187 ret = der_match_tag_and_length(buf, buf_size, CONTEXT, CONS,
192 ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len);
194 *minor_status = EINVAL; /* XXX */
195 return GSS_S_DEFECTIVE_TOKEN;
198 if (init_token.mechTypes == NULL)
199 return send_reject (minor_status, output_token);
201 for (i = 0; !found && i < init_token.mechTypes->len; ++i) {
205 ret = der_put_oid (mechbuf + sizeof(mechbuf) - 1,
207 &init_token.mechTypes->val[i],
210 return GSS_S_DEFECTIVE_TOKEN;
211 if (mech_len == GSS_KRB5_MECH->length
212 && memcmp(GSS_KRB5_MECH->elements,
213 mechbuf + sizeof(mechbuf) - mech_len,
219 return send_reject (minor_status, output_token);
221 if (init_token.mechToken != NULL) {
222 ibuf.length = init_token.mechToken->length;
223 ibuf.value = init_token.mechToken->data;
225 major_status = gss_accept_sec_context(&minor,
227 acceptor_cred_handle,
235 delegated_cred_handle);
236 if (GSS_ERROR(major_status)) {
237 send_reject (minor_status, output_token);
243 ret = send_accept (minor_status, output_token, ot);
245 gss_release_buffer(&minor, ot);