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 = malloc(buf_len);
68 if (*outbuf == NULL) {
69 *minor_status = ENOMEM;
74 memcpy(*outbuf, buf + buf_size - buf_len, buf_len);
75 *outbuf_size = buf_len;
79 return GSS_S_COMPLETE;
83 send_reject (OM_uint32 *minor_status,
84 gss_buffer_t output_token)
89 targ.negResult = malloc(sizeof(*targ.negResult));
90 if (targ.negResult == NULL) {
91 *minor_status = ENOMEM;
94 *(targ.negResult) = reject;
96 targ.supportedMech = NULL;
97 targ.responseToken = NULL;
98 targ.mechListMIC = NULL;
100 ret = code_NegTokenArg (minor_status, &targ,
101 (unsigned char**) &output_token->value, &output_token->length);
102 free_NegTokenTarg(&targ);
106 return GSS_S_BAD_MECH;
110 send_accept (OM_uint32 *minor_status,
111 gss_buffer_t output_token,
112 gss_buffer_t mech_token)
117 memset(&targ, 0, sizeof(targ));
118 targ.negResult = malloc(sizeof(*targ.negResult));
119 if (targ.negResult == NULL) {
120 *minor_status = ENOMEM;
121 return GSS_S_FAILURE;
123 *(targ.negResult) = accept_completed;
125 targ.supportedMech = malloc(sizeof(*targ.supportedMech));
126 if (targ.supportedMech == NULL) {
127 free_NegTokenTarg(&targ);
128 *minor_status = ENOMEM;
129 return GSS_S_FAILURE;
132 ret = der_get_oid(GSS_KRB5_MECH->elements,
133 GSS_KRB5_MECH->length,
137 free_NegTokenTarg(&targ);
138 *minor_status = ENOMEM;
139 return GSS_S_FAILURE;
142 if (mech_token != NULL && mech_token->length != 0) {
143 targ.responseToken = malloc(sizeof(*targ.responseToken));
144 if (targ.responseToken == NULL) {
145 free_NegTokenTarg(&targ);
146 *minor_status = ENOMEM;
147 return GSS_S_FAILURE;
149 targ.responseToken->length = mech_token->length;
150 targ.responseToken->data = mech_token->value;
151 mech_token->length = 0;
152 mech_token->value = NULL;
154 targ.responseToken = NULL;
157 ret = code_NegTokenArg (minor_status, &targ,
158 (unsigned char **) &output_token->value, &output_token->length);
159 free_NegTokenTarg(&targ);
163 return GSS_S_COMPLETE;
166 OM_uint32 gss_accept_sec_context_spnego
167 (OM_uint32 * minor_status,
168 gss_ctx_id_t * context_handle,
169 const gss_cred_id_t acceptor_cred_handle,
170 const gss_buffer_t input_token_buffer,
171 const gss_channel_bindings_t input_chan_bindings,
172 gss_name_t * src_name,
174 gss_buffer_t output_token,
175 OM_uint32 * ret_flags,
176 OM_uint32 * time_rec,
177 gss_cred_id_t * delegated_cred_handle)
179 NegTokenInit init_token;
180 OM_uint32 major_status;
181 OM_uint32 minor_status2;
182 gss_buffer_desc ibuf, obuf;
183 gss_buffer_t ot = NULL;
186 size_t len, taglen, ni_len;
190 memset(&init_token, 0, sizeof(init_token));
192 ret = gssapi_spnego_decapsulate(minor_status, input_token_buffer,
193 &buf, &buf_size, GSS_SPNEGO_MECH);
197 ret = der_match_tag_and_length(buf, buf_size, CONTEXT, CONS,
202 ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len);
204 *minor_status = EINVAL; /* XXX */
205 return GSS_S_DEFECTIVE_TOKEN;
208 if (init_token.mechTypes == NULL)
209 return send_reject (minor_status, output_token);
211 for (i = 0; !found && i < init_token.mechTypes->len; ++i) {
215 ret = der_put_oid (mechbuf + sizeof(mechbuf) - 1,
217 &init_token.mechTypes->val[i],
220 return GSS_S_DEFECTIVE_TOKEN;
221 if (mech_len == GSS_KRB5_MECH->length
222 && memcmp(GSS_KRB5_MECH->elements,
223 mechbuf + sizeof(mechbuf) - mech_len,
229 return send_reject (minor_status, output_token);
231 if (init_token.mechToken != NULL) {
232 ibuf.length = init_token.mechToken->length;
233 ibuf.value = init_token.mechToken->data;
235 major_status = gss_accept_sec_context(minor_status,
237 acceptor_cred_handle,
245 delegated_cred_handle);
246 if (GSS_ERROR(major_status)) {
247 send_reject (&minor_status2, output_token);
253 ret = send_accept (&minor_status2, output_token, ot);
255 gss_release_buffer(&minor_status2, ot);