1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert * Copyright 2009 by the Massachusetts Institute of Technology.
4*7f2fe78bSCy Schubert * All Rights Reserved.
5*7f2fe78bSCy Schubert *
6*7f2fe78bSCy Schubert * Export of this software from the United States of America may
7*7f2fe78bSCy Schubert * require a specific license from the United States Government.
8*7f2fe78bSCy Schubert * It is the responsibility of any person or organization contemplating
9*7f2fe78bSCy Schubert * export to obtain such a license before exporting.
10*7f2fe78bSCy Schubert *
11*7f2fe78bSCy Schubert * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12*7f2fe78bSCy Schubert * distribute this software and its documentation for any purpose and
13*7f2fe78bSCy Schubert * without fee is hereby granted, provided that the above copyright
14*7f2fe78bSCy Schubert * notice appear in all copies and that both that copyright notice and
15*7f2fe78bSCy Schubert * this permission notice appear in supporting documentation, and that
16*7f2fe78bSCy Schubert * the name of M.I.T. not be used in advertising or publicity pertaining
17*7f2fe78bSCy Schubert * to distribution of the software without specific, written prior
18*7f2fe78bSCy Schubert * permission. Furthermore if you modify this software you must label
19*7f2fe78bSCy Schubert * your software as modified software and not distribute it in such a
20*7f2fe78bSCy Schubert * fashion that it might be confused with the original M.I.T. software.
21*7f2fe78bSCy Schubert * M.I.T. makes no representations about the suitability of
22*7f2fe78bSCy Schubert * this software for any purpose. It is provided "as is" without express
23*7f2fe78bSCy Schubert * or implied warranty.
24*7f2fe78bSCy Schubert */
25*7f2fe78bSCy Schubert #include "k5-int.h"
26*7f2fe78bSCy Schubert #include "k5-der.h"
27*7f2fe78bSCy Schubert #include "gssapiP_krb5.h"
28*7f2fe78bSCy Schubert
29*7f2fe78bSCy Schubert /*
30*7f2fe78bSCy Schubert * IAKERB implementation
31*7f2fe78bSCy Schubert */
32*7f2fe78bSCy Schubert
33*7f2fe78bSCy Schubert enum iakerb_state {
34*7f2fe78bSCy Schubert IAKERB_AS_REQ, /* acquiring ticket with initial creds */
35*7f2fe78bSCy Schubert IAKERB_TGS_REQ, /* acquiring ticket with TGT */
36*7f2fe78bSCy Schubert IAKERB_AP_REQ /* hand-off to normal GSS AP-REQ exchange */
37*7f2fe78bSCy Schubert };
38*7f2fe78bSCy Schubert
39*7f2fe78bSCy Schubert struct _iakerb_ctx_id_rec {
40*7f2fe78bSCy Schubert krb5_magic magic; /* KG_IAKERB_CONTEXT */
41*7f2fe78bSCy Schubert krb5_context k5c;
42*7f2fe78bSCy Schubert gss_cred_id_t defcred; /* Initiator only */
43*7f2fe78bSCy Schubert enum iakerb_state state; /* Initiator only */
44*7f2fe78bSCy Schubert krb5_init_creds_context icc; /* Initiator only */
45*7f2fe78bSCy Schubert krb5_tkt_creds_context tcc; /* Initiator only */
46*7f2fe78bSCy Schubert gss_ctx_id_t gssc;
47*7f2fe78bSCy Schubert krb5_data conv; /* conversation for checksumming */
48*7f2fe78bSCy Schubert unsigned int count; /* number of round trips */
49*7f2fe78bSCy Schubert int initiate;
50*7f2fe78bSCy Schubert int established;
51*7f2fe78bSCy Schubert krb5_get_init_creds_opt *gic_opts;
52*7f2fe78bSCy Schubert };
53*7f2fe78bSCy Schubert
54*7f2fe78bSCy Schubert #define IAKERB_MAX_HOPS ( 16 /* MAX_IN_TKT_LOOPS */ + KRB5_REFERRAL_MAXHOPS )
55*7f2fe78bSCy Schubert
56*7f2fe78bSCy Schubert typedef struct _iakerb_ctx_id_rec iakerb_ctx_id_rec;
57*7f2fe78bSCy Schubert typedef iakerb_ctx_id_rec *iakerb_ctx_id_t;
58*7f2fe78bSCy Schubert
59*7f2fe78bSCy Schubert /*
60*7f2fe78bSCy Schubert * Release an IAKERB context
61*7f2fe78bSCy Schubert */
62*7f2fe78bSCy Schubert static void
iakerb_release_context(iakerb_ctx_id_t ctx)63*7f2fe78bSCy Schubert iakerb_release_context(iakerb_ctx_id_t ctx)
64*7f2fe78bSCy Schubert {
65*7f2fe78bSCy Schubert OM_uint32 tmp;
66*7f2fe78bSCy Schubert
67*7f2fe78bSCy Schubert if (ctx == NULL)
68*7f2fe78bSCy Schubert return;
69*7f2fe78bSCy Schubert
70*7f2fe78bSCy Schubert krb5_gss_release_cred(&tmp, &ctx->defcred);
71*7f2fe78bSCy Schubert krb5_init_creds_free(ctx->k5c, ctx->icc);
72*7f2fe78bSCy Schubert krb5_tkt_creds_free(ctx->k5c, ctx->tcc);
73*7f2fe78bSCy Schubert krb5_gss_delete_sec_context(&tmp, &ctx->gssc, NULL);
74*7f2fe78bSCy Schubert krb5_free_data_contents(ctx->k5c, &ctx->conv);
75*7f2fe78bSCy Schubert krb5_get_init_creds_opt_free(ctx->k5c, ctx->gic_opts);
76*7f2fe78bSCy Schubert krb5_free_context(ctx->k5c);
77*7f2fe78bSCy Schubert free(ctx);
78*7f2fe78bSCy Schubert }
79*7f2fe78bSCy Schubert
80*7f2fe78bSCy Schubert /*
81*7f2fe78bSCy Schubert * Create a IAKERB-FINISHED structure containing a checksum of
82*7f2fe78bSCy Schubert * the entire IAKERB exchange.
83*7f2fe78bSCy Schubert */
84*7f2fe78bSCy Schubert krb5_error_code
iakerb_make_finished(krb5_context context,krb5_key key,const krb5_data * conv,krb5_data ** finished)85*7f2fe78bSCy Schubert iakerb_make_finished(krb5_context context,
86*7f2fe78bSCy Schubert krb5_key key,
87*7f2fe78bSCy Schubert const krb5_data *conv,
88*7f2fe78bSCy Schubert krb5_data **finished)
89*7f2fe78bSCy Schubert {
90*7f2fe78bSCy Schubert krb5_error_code code;
91*7f2fe78bSCy Schubert krb5_iakerb_finished iaf;
92*7f2fe78bSCy Schubert
93*7f2fe78bSCy Schubert *finished = NULL;
94*7f2fe78bSCy Schubert
95*7f2fe78bSCy Schubert memset(&iaf, 0, sizeof(iaf));
96*7f2fe78bSCy Schubert
97*7f2fe78bSCy Schubert if (key == NULL)
98*7f2fe78bSCy Schubert return KRB5KDC_ERR_NULL_KEY;
99*7f2fe78bSCy Schubert
100*7f2fe78bSCy Schubert code = krb5_k_make_checksum(context, 0, key, KRB5_KEYUSAGE_IAKERB_FINISHED,
101*7f2fe78bSCy Schubert conv, &iaf.checksum);
102*7f2fe78bSCy Schubert if (code != 0)
103*7f2fe78bSCy Schubert return code;
104*7f2fe78bSCy Schubert
105*7f2fe78bSCy Schubert code = encode_krb5_iakerb_finished(&iaf, finished);
106*7f2fe78bSCy Schubert
107*7f2fe78bSCy Schubert krb5_free_checksum_contents(context, &iaf.checksum);
108*7f2fe78bSCy Schubert
109*7f2fe78bSCy Schubert return code;
110*7f2fe78bSCy Schubert }
111*7f2fe78bSCy Schubert
112*7f2fe78bSCy Schubert /*
113*7f2fe78bSCy Schubert * Verify a IAKERB-FINISHED structure submitted by the initiator
114*7f2fe78bSCy Schubert */
115*7f2fe78bSCy Schubert krb5_error_code
iakerb_verify_finished(krb5_context context,krb5_key key,const krb5_data * conv,const krb5_data * finished)116*7f2fe78bSCy Schubert iakerb_verify_finished(krb5_context context,
117*7f2fe78bSCy Schubert krb5_key key,
118*7f2fe78bSCy Schubert const krb5_data *conv,
119*7f2fe78bSCy Schubert const krb5_data *finished)
120*7f2fe78bSCy Schubert {
121*7f2fe78bSCy Schubert krb5_error_code code;
122*7f2fe78bSCy Schubert krb5_iakerb_finished *iaf;
123*7f2fe78bSCy Schubert krb5_boolean valid = FALSE;
124*7f2fe78bSCy Schubert
125*7f2fe78bSCy Schubert if (key == NULL)
126*7f2fe78bSCy Schubert return KRB5KDC_ERR_NULL_KEY;
127*7f2fe78bSCy Schubert
128*7f2fe78bSCy Schubert code = decode_krb5_iakerb_finished(finished, &iaf);
129*7f2fe78bSCy Schubert if (code != 0)
130*7f2fe78bSCy Schubert return code;
131*7f2fe78bSCy Schubert
132*7f2fe78bSCy Schubert code = krb5_k_verify_checksum(context, key, KRB5_KEYUSAGE_IAKERB_FINISHED,
133*7f2fe78bSCy Schubert conv, &iaf->checksum, &valid);
134*7f2fe78bSCy Schubert if (code == 0 && valid == FALSE)
135*7f2fe78bSCy Schubert code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
136*7f2fe78bSCy Schubert
137*7f2fe78bSCy Schubert krb5_free_iakerb_finished(context, iaf);
138*7f2fe78bSCy Schubert
139*7f2fe78bSCy Schubert return code;
140*7f2fe78bSCy Schubert }
141*7f2fe78bSCy Schubert
142*7f2fe78bSCy Schubert /*
143*7f2fe78bSCy Schubert * Save a token for future checksumming.
144*7f2fe78bSCy Schubert */
145*7f2fe78bSCy Schubert static krb5_error_code
iakerb_save_token(iakerb_ctx_id_t ctx,const gss_buffer_t token)146*7f2fe78bSCy Schubert iakerb_save_token(iakerb_ctx_id_t ctx, const gss_buffer_t token)
147*7f2fe78bSCy Schubert {
148*7f2fe78bSCy Schubert char *p;
149*7f2fe78bSCy Schubert
150*7f2fe78bSCy Schubert p = realloc(ctx->conv.data, ctx->conv.length + token->length);
151*7f2fe78bSCy Schubert if (p == NULL)
152*7f2fe78bSCy Schubert return ENOMEM;
153*7f2fe78bSCy Schubert
154*7f2fe78bSCy Schubert memcpy(p + ctx->conv.length, token->value, token->length);
155*7f2fe78bSCy Schubert ctx->conv.data = p;
156*7f2fe78bSCy Schubert ctx->conv.length += token->length;
157*7f2fe78bSCy Schubert
158*7f2fe78bSCy Schubert return 0;
159*7f2fe78bSCy Schubert }
160*7f2fe78bSCy Schubert
161*7f2fe78bSCy Schubert /*
162*7f2fe78bSCy Schubert * Parse a token into IAKERB-HEADER and KRB-KDC-REQ/REP
163*7f2fe78bSCy Schubert */
164*7f2fe78bSCy Schubert static krb5_error_code
iakerb_parse_token(iakerb_ctx_id_t ctx,int initialContextToken,const gss_buffer_t token,krb5_data * realm,krb5_data ** cookie,krb5_data * request)165*7f2fe78bSCy Schubert iakerb_parse_token(iakerb_ctx_id_t ctx,
166*7f2fe78bSCy Schubert int initialContextToken,
167*7f2fe78bSCy Schubert const gss_buffer_t token,
168*7f2fe78bSCy Schubert krb5_data *realm,
169*7f2fe78bSCy Schubert krb5_data **cookie,
170*7f2fe78bSCy Schubert krb5_data *request)
171*7f2fe78bSCy Schubert {
172*7f2fe78bSCy Schubert krb5_error_code code;
173*7f2fe78bSCy Schubert krb5_iakerb_header *iah = NULL;
174*7f2fe78bSCy Schubert unsigned int bodysize;
175*7f2fe78bSCy Schubert uint8_t *body;
176*7f2fe78bSCy Schubert int flags = 0;
177*7f2fe78bSCy Schubert krb5_data data;
178*7f2fe78bSCy Schubert struct k5input in, seq;
179*7f2fe78bSCy Schubert
180*7f2fe78bSCy Schubert if (token == GSS_C_NO_BUFFER || token->length == 0) {
181*7f2fe78bSCy Schubert code = KRB5_BAD_MSIZE;
182*7f2fe78bSCy Schubert goto cleanup;
183*7f2fe78bSCy Schubert }
184*7f2fe78bSCy Schubert
185*7f2fe78bSCy Schubert if (initialContextToken)
186*7f2fe78bSCy Schubert flags |= G_VFY_TOKEN_HDR_WRAPPER_REQUIRED;
187*7f2fe78bSCy Schubert
188*7f2fe78bSCy Schubert body = token->value;
189*7f2fe78bSCy Schubert code = g_verify_token_header(gss_mech_iakerb, &bodysize, &body,
190*7f2fe78bSCy Schubert IAKERB_TOK_PROXY, token->length, flags);
191*7f2fe78bSCy Schubert if (code != 0)
192*7f2fe78bSCy Schubert goto cleanup;
193*7f2fe78bSCy Schubert
194*7f2fe78bSCy Schubert /* Find the end of the DER sequence tag and decode it (with the tag) as the
195*7f2fe78bSCy Schubert * IAKERB jeader. */
196*7f2fe78bSCy Schubert k5_input_init(&in, body, bodysize);
197*7f2fe78bSCy Schubert if (!k5_der_get_value(&in, 0x30, &seq)) {
198*7f2fe78bSCy Schubert code = ASN1_BAD_ID;
199*7f2fe78bSCy Schubert goto cleanup;
200*7f2fe78bSCy Schubert }
201*7f2fe78bSCy Schubert data = make_data(body, seq.ptr + seq.len - body);
202*7f2fe78bSCy Schubert code = decode_krb5_iakerb_header(&data, &iah);
203*7f2fe78bSCy Schubert if (code != 0)
204*7f2fe78bSCy Schubert goto cleanup;
205*7f2fe78bSCy Schubert
206*7f2fe78bSCy Schubert if (realm != NULL) {
207*7f2fe78bSCy Schubert *realm = iah->target_realm;
208*7f2fe78bSCy Schubert iah->target_realm.data = NULL;
209*7f2fe78bSCy Schubert }
210*7f2fe78bSCy Schubert
211*7f2fe78bSCy Schubert if (cookie != NULL) {
212*7f2fe78bSCy Schubert *cookie = iah->cookie;
213*7f2fe78bSCy Schubert iah->cookie = NULL;
214*7f2fe78bSCy Schubert }
215*7f2fe78bSCy Schubert
216*7f2fe78bSCy Schubert /* The remainder of the token body is the request. */
217*7f2fe78bSCy Schubert *request = make_data((uint8_t *)in.ptr, in.len);
218*7f2fe78bSCy Schubert assert(request->data + request->length ==
219*7f2fe78bSCy Schubert (char *)token->value + token->length);
220*7f2fe78bSCy Schubert
221*7f2fe78bSCy Schubert cleanup:
222*7f2fe78bSCy Schubert krb5_free_iakerb_header(ctx->k5c, iah);
223*7f2fe78bSCy Schubert
224*7f2fe78bSCy Schubert return code;
225*7f2fe78bSCy Schubert }
226*7f2fe78bSCy Schubert
227*7f2fe78bSCy Schubert /*
228*7f2fe78bSCy Schubert * Create a token from IAKERB-HEADER and KRB-KDC-REQ/REP
229*7f2fe78bSCy Schubert */
230*7f2fe78bSCy Schubert static krb5_error_code
iakerb_make_token(iakerb_ctx_id_t ctx,krb5_data * realm,krb5_data * cookie,krb5_data * request,int initialContextToken,gss_buffer_t token)231*7f2fe78bSCy Schubert iakerb_make_token(iakerb_ctx_id_t ctx,
232*7f2fe78bSCy Schubert krb5_data *realm,
233*7f2fe78bSCy Schubert krb5_data *cookie,
234*7f2fe78bSCy Schubert krb5_data *request,
235*7f2fe78bSCy Schubert int initialContextToken,
236*7f2fe78bSCy Schubert gss_buffer_t token)
237*7f2fe78bSCy Schubert {
238*7f2fe78bSCy Schubert krb5_error_code code;
239*7f2fe78bSCy Schubert krb5_iakerb_header iah;
240*7f2fe78bSCy Schubert krb5_data *data = NULL;
241*7f2fe78bSCy Schubert char *p;
242*7f2fe78bSCy Schubert unsigned int tokenSize;
243*7f2fe78bSCy Schubert struct k5buf buf;
244*7f2fe78bSCy Schubert
245*7f2fe78bSCy Schubert token->value = NULL;
246*7f2fe78bSCy Schubert token->length = 0;
247*7f2fe78bSCy Schubert
248*7f2fe78bSCy Schubert /*
249*7f2fe78bSCy Schubert * Assemble the IAKERB-HEADER from the realm and cookie
250*7f2fe78bSCy Schubert */
251*7f2fe78bSCy Schubert iah.target_realm = *realm;
252*7f2fe78bSCy Schubert iah.cookie = cookie;
253*7f2fe78bSCy Schubert
254*7f2fe78bSCy Schubert code = encode_krb5_iakerb_header(&iah, &data);
255*7f2fe78bSCy Schubert if (code != 0)
256*7f2fe78bSCy Schubert goto cleanup;
257*7f2fe78bSCy Schubert
258*7f2fe78bSCy Schubert /*
259*7f2fe78bSCy Schubert * Concatenate Kerberos request.
260*7f2fe78bSCy Schubert */
261*7f2fe78bSCy Schubert p = realloc(data->data, data->length + request->length);
262*7f2fe78bSCy Schubert if (p == NULL) {
263*7f2fe78bSCy Schubert code = ENOMEM;
264*7f2fe78bSCy Schubert goto cleanup;
265*7f2fe78bSCy Schubert }
266*7f2fe78bSCy Schubert data->data = p;
267*7f2fe78bSCy Schubert
268*7f2fe78bSCy Schubert if (request->length > 0)
269*7f2fe78bSCy Schubert memcpy(data->data + data->length, request->data, request->length);
270*7f2fe78bSCy Schubert data->length += request->length;
271*7f2fe78bSCy Schubert
272*7f2fe78bSCy Schubert if (initialContextToken)
273*7f2fe78bSCy Schubert tokenSize = g_token_size(gss_mech_iakerb, data->length);
274*7f2fe78bSCy Schubert else
275*7f2fe78bSCy Schubert tokenSize = 2 + data->length;
276*7f2fe78bSCy Schubert
277*7f2fe78bSCy Schubert token->value = gssalloc_malloc(tokenSize);
278*7f2fe78bSCy Schubert if (token->value == NULL) {
279*7f2fe78bSCy Schubert code = ENOMEM;
280*7f2fe78bSCy Schubert goto cleanup;
281*7f2fe78bSCy Schubert }
282*7f2fe78bSCy Schubert token->length = tokenSize;
283*7f2fe78bSCy Schubert k5_buf_init_fixed(&buf, token->value, token->length);
284*7f2fe78bSCy Schubert
285*7f2fe78bSCy Schubert if (initialContextToken) {
286*7f2fe78bSCy Schubert g_make_token_header(&buf, gss_mech_iakerb, data->length,
287*7f2fe78bSCy Schubert IAKERB_TOK_PROXY);
288*7f2fe78bSCy Schubert } else {
289*7f2fe78bSCy Schubert k5_buf_add_uint16_be(&buf, IAKERB_TOK_PROXY);
290*7f2fe78bSCy Schubert }
291*7f2fe78bSCy Schubert k5_buf_add_len(&buf, data->data, data->length);
292*7f2fe78bSCy Schubert assert(buf.len == token->length);
293*7f2fe78bSCy Schubert
294*7f2fe78bSCy Schubert cleanup:
295*7f2fe78bSCy Schubert krb5_free_data(ctx->k5c, data);
296*7f2fe78bSCy Schubert
297*7f2fe78bSCy Schubert return code;
298*7f2fe78bSCy Schubert }
299*7f2fe78bSCy Schubert
300*7f2fe78bSCy Schubert /*
301*7f2fe78bSCy Schubert * Parse the IAKERB token in input_token and send the contained KDC
302*7f2fe78bSCy Schubert * request to the KDC for the realm.
303*7f2fe78bSCy Schubert *
304*7f2fe78bSCy Schubert * Wrap the KDC reply in output_token.
305*7f2fe78bSCy Schubert */
306*7f2fe78bSCy Schubert static krb5_error_code
iakerb_acceptor_step(iakerb_ctx_id_t ctx,int initialContextToken,const gss_buffer_t input_token,gss_buffer_t output_token)307*7f2fe78bSCy Schubert iakerb_acceptor_step(iakerb_ctx_id_t ctx,
308*7f2fe78bSCy Schubert int initialContextToken,
309*7f2fe78bSCy Schubert const gss_buffer_t input_token,
310*7f2fe78bSCy Schubert gss_buffer_t output_token)
311*7f2fe78bSCy Schubert {
312*7f2fe78bSCy Schubert krb5_error_code code;
313*7f2fe78bSCy Schubert krb5_data request = empty_data(), reply = empty_data();
314*7f2fe78bSCy Schubert krb5_data realm = empty_data();
315*7f2fe78bSCy Schubert OM_uint32 tmp;
316*7f2fe78bSCy Schubert int tcp_only, use_primary;
317*7f2fe78bSCy Schubert krb5_ui_4 kdc_code;
318*7f2fe78bSCy Schubert
319*7f2fe78bSCy Schubert output_token->length = 0;
320*7f2fe78bSCy Schubert output_token->value = NULL;
321*7f2fe78bSCy Schubert
322*7f2fe78bSCy Schubert if (ctx->count >= IAKERB_MAX_HOPS) {
323*7f2fe78bSCy Schubert code = KRB5_KDC_UNREACH;
324*7f2fe78bSCy Schubert goto cleanup;
325*7f2fe78bSCy Schubert }
326*7f2fe78bSCy Schubert
327*7f2fe78bSCy Schubert code = iakerb_parse_token(ctx, initialContextToken, input_token, &realm,
328*7f2fe78bSCy Schubert NULL, &request);
329*7f2fe78bSCy Schubert if (code != 0)
330*7f2fe78bSCy Schubert goto cleanup;
331*7f2fe78bSCy Schubert
332*7f2fe78bSCy Schubert if (realm.length == 0 || request.length == 0) {
333*7f2fe78bSCy Schubert code = KRB5_BAD_MSIZE;
334*7f2fe78bSCy Schubert goto cleanup;
335*7f2fe78bSCy Schubert }
336*7f2fe78bSCy Schubert
337*7f2fe78bSCy Schubert code = iakerb_save_token(ctx, input_token);
338*7f2fe78bSCy Schubert if (code != 0)
339*7f2fe78bSCy Schubert goto cleanup;
340*7f2fe78bSCy Schubert
341*7f2fe78bSCy Schubert for (tcp_only = 0; tcp_only <= 1; tcp_only++) {
342*7f2fe78bSCy Schubert use_primary = 0;
343*7f2fe78bSCy Schubert code = krb5_sendto_kdc(ctx->k5c, &request, &realm,
344*7f2fe78bSCy Schubert &reply, &use_primary, tcp_only);
345*7f2fe78bSCy Schubert if (code == 0 && krb5_is_krb_error(&reply)) {
346*7f2fe78bSCy Schubert krb5_error *error;
347*7f2fe78bSCy Schubert
348*7f2fe78bSCy Schubert code = decode_krb5_error(&reply, &error);
349*7f2fe78bSCy Schubert if (code != 0)
350*7f2fe78bSCy Schubert goto cleanup;
351*7f2fe78bSCy Schubert kdc_code = error->error;
352*7f2fe78bSCy Schubert krb5_free_error(ctx->k5c, error);
353*7f2fe78bSCy Schubert if (kdc_code == KRB_ERR_RESPONSE_TOO_BIG) {
354*7f2fe78bSCy Schubert krb5_free_data_contents(ctx->k5c, &reply);
355*7f2fe78bSCy Schubert reply = empty_data();
356*7f2fe78bSCy Schubert continue;
357*7f2fe78bSCy Schubert }
358*7f2fe78bSCy Schubert }
359*7f2fe78bSCy Schubert break;
360*7f2fe78bSCy Schubert }
361*7f2fe78bSCy Schubert
362*7f2fe78bSCy Schubert if (code == KRB5_KDC_UNREACH || code == KRB5_REALM_UNKNOWN) {
363*7f2fe78bSCy Schubert krb5_error error;
364*7f2fe78bSCy Schubert
365*7f2fe78bSCy Schubert memset(&error, 0, sizeof(error));
366*7f2fe78bSCy Schubert if (code == KRB5_KDC_UNREACH)
367*7f2fe78bSCy Schubert error.error = KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE;
368*7f2fe78bSCy Schubert else if (code == KRB5_REALM_UNKNOWN)
369*7f2fe78bSCy Schubert error.error = KRB_AP_ERR_IAKERB_KDC_NOT_FOUND;
370*7f2fe78bSCy Schubert
371*7f2fe78bSCy Schubert code = krb5_mk_error(ctx->k5c, &error, &reply);
372*7f2fe78bSCy Schubert if (code != 0)
373*7f2fe78bSCy Schubert goto cleanup;
374*7f2fe78bSCy Schubert } else if (code != 0)
375*7f2fe78bSCy Schubert goto cleanup;
376*7f2fe78bSCy Schubert
377*7f2fe78bSCy Schubert code = iakerb_make_token(ctx, &realm, NULL, &reply, 0, output_token);
378*7f2fe78bSCy Schubert if (code != 0)
379*7f2fe78bSCy Schubert goto cleanup;
380*7f2fe78bSCy Schubert
381*7f2fe78bSCy Schubert code = iakerb_save_token(ctx, output_token);
382*7f2fe78bSCy Schubert if (code != 0)
383*7f2fe78bSCy Schubert goto cleanup;
384*7f2fe78bSCy Schubert
385*7f2fe78bSCy Schubert ctx->count++;
386*7f2fe78bSCy Schubert
387*7f2fe78bSCy Schubert cleanup:
388*7f2fe78bSCy Schubert if (code != 0)
389*7f2fe78bSCy Schubert gss_release_buffer(&tmp, output_token);
390*7f2fe78bSCy Schubert /* request is a pointer into input_token, no need to free */
391*7f2fe78bSCy Schubert krb5_free_data_contents(ctx->k5c, &realm);
392*7f2fe78bSCy Schubert krb5_free_data_contents(ctx->k5c, &reply);
393*7f2fe78bSCy Schubert
394*7f2fe78bSCy Schubert return code;
395*7f2fe78bSCy Schubert }
396*7f2fe78bSCy Schubert
397*7f2fe78bSCy Schubert /*
398*7f2fe78bSCy Schubert * Initialise the krb5_init_creds context for the IAKERB context
399*7f2fe78bSCy Schubert */
400*7f2fe78bSCy Schubert static krb5_error_code
iakerb_init_creds_ctx(iakerb_ctx_id_t ctx,krb5_gss_cred_id_t cred,OM_uint32 time_req)401*7f2fe78bSCy Schubert iakerb_init_creds_ctx(iakerb_ctx_id_t ctx,
402*7f2fe78bSCy Schubert krb5_gss_cred_id_t cred,
403*7f2fe78bSCy Schubert OM_uint32 time_req)
404*7f2fe78bSCy Schubert {
405*7f2fe78bSCy Schubert krb5_error_code code;
406*7f2fe78bSCy Schubert
407*7f2fe78bSCy Schubert if (cred->iakerb_mech == 0) {
408*7f2fe78bSCy Schubert code = EINVAL;
409*7f2fe78bSCy Schubert goto cleanup;
410*7f2fe78bSCy Schubert }
411*7f2fe78bSCy Schubert
412*7f2fe78bSCy Schubert assert(cred->name != NULL);
413*7f2fe78bSCy Schubert assert(cred->name->princ != NULL);
414*7f2fe78bSCy Schubert
415*7f2fe78bSCy Schubert code = krb5_get_init_creds_opt_alloc(ctx->k5c, &ctx->gic_opts);
416*7f2fe78bSCy Schubert if (code != 0)
417*7f2fe78bSCy Schubert goto cleanup;
418*7f2fe78bSCy Schubert
419*7f2fe78bSCy Schubert if (time_req != 0 && time_req != GSS_C_INDEFINITE)
420*7f2fe78bSCy Schubert krb5_get_init_creds_opt_set_tkt_life(ctx->gic_opts, time_req);
421*7f2fe78bSCy Schubert
422*7f2fe78bSCy Schubert code = krb5_get_init_creds_opt_set_out_ccache(ctx->k5c, ctx->gic_opts,
423*7f2fe78bSCy Schubert cred->ccache);
424*7f2fe78bSCy Schubert if (code != 0)
425*7f2fe78bSCy Schubert goto cleanup;
426*7f2fe78bSCy Schubert
427*7f2fe78bSCy Schubert code = krb5_init_creds_init(ctx->k5c,
428*7f2fe78bSCy Schubert cred->name->princ,
429*7f2fe78bSCy Schubert NULL, /* prompter */
430*7f2fe78bSCy Schubert NULL, /* data */
431*7f2fe78bSCy Schubert 0, /* start_time */
432*7f2fe78bSCy Schubert ctx->gic_opts,
433*7f2fe78bSCy Schubert &ctx->icc);
434*7f2fe78bSCy Schubert if (code != 0)
435*7f2fe78bSCy Schubert goto cleanup;
436*7f2fe78bSCy Schubert
437*7f2fe78bSCy Schubert if (cred->password != NULL) {
438*7f2fe78bSCy Schubert code = krb5_init_creds_set_password(ctx->k5c, ctx->icc,
439*7f2fe78bSCy Schubert cred->password);
440*7f2fe78bSCy Schubert } else if (cred->client_keytab != NULL) {
441*7f2fe78bSCy Schubert code = krb5_init_creds_set_keytab(ctx->k5c, ctx->icc,
442*7f2fe78bSCy Schubert cred->client_keytab);
443*7f2fe78bSCy Schubert } else {
444*7f2fe78bSCy Schubert code = KRB5_KT_NOTFOUND;
445*7f2fe78bSCy Schubert }
446*7f2fe78bSCy Schubert if (code != 0)
447*7f2fe78bSCy Schubert goto cleanup;
448*7f2fe78bSCy Schubert
449*7f2fe78bSCy Schubert cleanup:
450*7f2fe78bSCy Schubert return code;
451*7f2fe78bSCy Schubert }
452*7f2fe78bSCy Schubert
453*7f2fe78bSCy Schubert /*
454*7f2fe78bSCy Schubert * Initialise the krb5_tkt_creds context for the IAKERB context
455*7f2fe78bSCy Schubert */
456*7f2fe78bSCy Schubert static krb5_error_code
iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx,krb5_gss_cred_id_t cred,krb5_gss_name_t name,OM_uint32 time_req)457*7f2fe78bSCy Schubert iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx,
458*7f2fe78bSCy Schubert krb5_gss_cred_id_t cred,
459*7f2fe78bSCy Schubert krb5_gss_name_t name,
460*7f2fe78bSCy Schubert OM_uint32 time_req)
461*7f2fe78bSCy Schubert
462*7f2fe78bSCy Schubert {
463*7f2fe78bSCy Schubert krb5_error_code code;
464*7f2fe78bSCy Schubert krb5_creds creds;
465*7f2fe78bSCy Schubert krb5_timestamp now;
466*7f2fe78bSCy Schubert
467*7f2fe78bSCy Schubert assert(cred->name != NULL);
468*7f2fe78bSCy Schubert assert(cred->name->princ != NULL);
469*7f2fe78bSCy Schubert
470*7f2fe78bSCy Schubert memset(&creds, 0, sizeof(creds));
471*7f2fe78bSCy Schubert
472*7f2fe78bSCy Schubert creds.client = cred->name->princ;
473*7f2fe78bSCy Schubert creds.server = name->princ;
474*7f2fe78bSCy Schubert
475*7f2fe78bSCy Schubert if (time_req != 0 && time_req != GSS_C_INDEFINITE) {
476*7f2fe78bSCy Schubert code = krb5_timeofday(ctx->k5c, &now);
477*7f2fe78bSCy Schubert if (code != 0)
478*7f2fe78bSCy Schubert goto cleanup;
479*7f2fe78bSCy Schubert
480*7f2fe78bSCy Schubert creds.times.endtime = ts_incr(now, time_req);
481*7f2fe78bSCy Schubert }
482*7f2fe78bSCy Schubert
483*7f2fe78bSCy Schubert if (cred->name->ad_context != NULL) {
484*7f2fe78bSCy Schubert code = krb5_authdata_export_authdata(ctx->k5c,
485*7f2fe78bSCy Schubert cred->name->ad_context,
486*7f2fe78bSCy Schubert AD_USAGE_TGS_REQ,
487*7f2fe78bSCy Schubert &creds.authdata);
488*7f2fe78bSCy Schubert if (code != 0)
489*7f2fe78bSCy Schubert goto cleanup;
490*7f2fe78bSCy Schubert }
491*7f2fe78bSCy Schubert
492*7f2fe78bSCy Schubert code = krb5_tkt_creds_init(ctx->k5c, cred->ccache, &creds, 0, &ctx->tcc);
493*7f2fe78bSCy Schubert if (code != 0)
494*7f2fe78bSCy Schubert goto cleanup;
495*7f2fe78bSCy Schubert
496*7f2fe78bSCy Schubert cleanup:
497*7f2fe78bSCy Schubert krb5_free_authdata(ctx->k5c, creds.authdata);
498*7f2fe78bSCy Schubert
499*7f2fe78bSCy Schubert return code;
500*7f2fe78bSCy Schubert }
501*7f2fe78bSCy Schubert
502*7f2fe78bSCy Schubert /*
503*7f2fe78bSCy Schubert * Parse the IAKERB token in input_token and process the KDC
504*7f2fe78bSCy Schubert * response.
505*7f2fe78bSCy Schubert *
506*7f2fe78bSCy Schubert * Emit the next KDC request, if any, in output_token.
507*7f2fe78bSCy Schubert */
508*7f2fe78bSCy Schubert static krb5_error_code
iakerb_initiator_step(iakerb_ctx_id_t ctx,krb5_gss_cred_id_t cred,krb5_gss_name_t name,OM_uint32 time_req,const gss_buffer_t input_token,gss_buffer_t output_token)509*7f2fe78bSCy Schubert iakerb_initiator_step(iakerb_ctx_id_t ctx,
510*7f2fe78bSCy Schubert krb5_gss_cred_id_t cred,
511*7f2fe78bSCy Schubert krb5_gss_name_t name,
512*7f2fe78bSCy Schubert OM_uint32 time_req,
513*7f2fe78bSCy Schubert const gss_buffer_t input_token,
514*7f2fe78bSCy Schubert gss_buffer_t output_token)
515*7f2fe78bSCy Schubert {
516*7f2fe78bSCy Schubert krb5_error_code code = 0;
517*7f2fe78bSCy Schubert krb5_data in = empty_data(), out = empty_data(), realm = empty_data();
518*7f2fe78bSCy Schubert krb5_data *cookie = NULL;
519*7f2fe78bSCy Schubert OM_uint32 tmp;
520*7f2fe78bSCy Schubert unsigned int flags = 0;
521*7f2fe78bSCy Schubert krb5_ticket_times times;
522*7f2fe78bSCy Schubert
523*7f2fe78bSCy Schubert output_token->length = 0;
524*7f2fe78bSCy Schubert output_token->value = NULL;
525*7f2fe78bSCy Schubert
526*7f2fe78bSCy Schubert if (input_token != GSS_C_NO_BUFFER) {
527*7f2fe78bSCy Schubert code = iakerb_parse_token(ctx, 0, input_token, NULL, &cookie, &in);
528*7f2fe78bSCy Schubert if (code != 0)
529*7f2fe78bSCy Schubert goto cleanup;
530*7f2fe78bSCy Schubert
531*7f2fe78bSCy Schubert code = iakerb_save_token(ctx, input_token);
532*7f2fe78bSCy Schubert if (code != 0)
533*7f2fe78bSCy Schubert goto cleanup;
534*7f2fe78bSCy Schubert }
535*7f2fe78bSCy Schubert
536*7f2fe78bSCy Schubert switch (ctx->state) {
537*7f2fe78bSCy Schubert case IAKERB_AS_REQ:
538*7f2fe78bSCy Schubert if (ctx->icc == NULL) {
539*7f2fe78bSCy Schubert code = iakerb_init_creds_ctx(ctx, cred, time_req);
540*7f2fe78bSCy Schubert if (code != 0)
541*7f2fe78bSCy Schubert goto cleanup;
542*7f2fe78bSCy Schubert }
543*7f2fe78bSCy Schubert
544*7f2fe78bSCy Schubert code = krb5_init_creds_step(ctx->k5c, ctx->icc, &in, &out, &realm,
545*7f2fe78bSCy Schubert &flags);
546*7f2fe78bSCy Schubert if (code != 0) {
547*7f2fe78bSCy Schubert if (cred->have_tgt) {
548*7f2fe78bSCy Schubert /* We were trying to refresh; keep going with current creds. */
549*7f2fe78bSCy Schubert ctx->state = IAKERB_TGS_REQ;
550*7f2fe78bSCy Schubert krb5_clear_error_message(ctx->k5c);
551*7f2fe78bSCy Schubert } else {
552*7f2fe78bSCy Schubert goto cleanup;
553*7f2fe78bSCy Schubert }
554*7f2fe78bSCy Schubert } else if (!(flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE)) {
555*7f2fe78bSCy Schubert krb5_init_creds_get_times(ctx->k5c, ctx->icc, ×);
556*7f2fe78bSCy Schubert kg_cred_set_initial_refresh(ctx->k5c, cred, ×);
557*7f2fe78bSCy Schubert cred->expire = times.endtime;
558*7f2fe78bSCy Schubert
559*7f2fe78bSCy Schubert krb5_init_creds_free(ctx->k5c, ctx->icc);
560*7f2fe78bSCy Schubert ctx->icc = NULL;
561*7f2fe78bSCy Schubert
562*7f2fe78bSCy Schubert ctx->state = IAKERB_TGS_REQ;
563*7f2fe78bSCy Schubert } else
564*7f2fe78bSCy Schubert break;
565*7f2fe78bSCy Schubert in = empty_data();
566*7f2fe78bSCy Schubert /* Done with AS request; fall through to TGS request. */
567*7f2fe78bSCy Schubert case IAKERB_TGS_REQ:
568*7f2fe78bSCy Schubert if (ctx->tcc == NULL) {
569*7f2fe78bSCy Schubert code = iakerb_tkt_creds_ctx(ctx, cred, name, time_req);
570*7f2fe78bSCy Schubert if (code != 0)
571*7f2fe78bSCy Schubert goto cleanup;
572*7f2fe78bSCy Schubert }
573*7f2fe78bSCy Schubert
574*7f2fe78bSCy Schubert code = krb5_tkt_creds_step(ctx->k5c, ctx->tcc, &in, &out, &realm,
575*7f2fe78bSCy Schubert &flags);
576*7f2fe78bSCy Schubert if (code != 0)
577*7f2fe78bSCy Schubert goto cleanup;
578*7f2fe78bSCy Schubert if (!(flags & KRB5_TKT_CREDS_STEP_FLAG_CONTINUE)) {
579*7f2fe78bSCy Schubert krb5_tkt_creds_get_times(ctx->k5c, ctx->tcc, ×);
580*7f2fe78bSCy Schubert cred->expire = times.endtime;
581*7f2fe78bSCy Schubert
582*7f2fe78bSCy Schubert krb5_tkt_creds_free(ctx->k5c, ctx->tcc);
583*7f2fe78bSCy Schubert ctx->tcc = NULL;
584*7f2fe78bSCy Schubert
585*7f2fe78bSCy Schubert ctx->state = IAKERB_AP_REQ;
586*7f2fe78bSCy Schubert } else
587*7f2fe78bSCy Schubert break;
588*7f2fe78bSCy Schubert /* Done with TGS request; fall through to AP request. */
589*7f2fe78bSCy Schubert case IAKERB_AP_REQ:
590*7f2fe78bSCy Schubert break;
591*7f2fe78bSCy Schubert }
592*7f2fe78bSCy Schubert
593*7f2fe78bSCy Schubert if (out.length != 0) {
594*7f2fe78bSCy Schubert assert(ctx->state != IAKERB_AP_REQ);
595*7f2fe78bSCy Schubert
596*7f2fe78bSCy Schubert code = iakerb_make_token(ctx, &realm, cookie, &out,
597*7f2fe78bSCy Schubert (input_token == GSS_C_NO_BUFFER),
598*7f2fe78bSCy Schubert output_token);
599*7f2fe78bSCy Schubert if (code != 0)
600*7f2fe78bSCy Schubert goto cleanup;
601*7f2fe78bSCy Schubert
602*7f2fe78bSCy Schubert /* Save the token for generating a future checksum */
603*7f2fe78bSCy Schubert code = iakerb_save_token(ctx, output_token);
604*7f2fe78bSCy Schubert if (code != 0)
605*7f2fe78bSCy Schubert goto cleanup;
606*7f2fe78bSCy Schubert
607*7f2fe78bSCy Schubert ctx->count++;
608*7f2fe78bSCy Schubert }
609*7f2fe78bSCy Schubert
610*7f2fe78bSCy Schubert cleanup:
611*7f2fe78bSCy Schubert if (code != 0)
612*7f2fe78bSCy Schubert gss_release_buffer(&tmp, output_token);
613*7f2fe78bSCy Schubert krb5_free_data(ctx->k5c, cookie);
614*7f2fe78bSCy Schubert krb5_free_data_contents(ctx->k5c, &out);
615*7f2fe78bSCy Schubert krb5_free_data_contents(ctx->k5c, &realm);
616*7f2fe78bSCy Schubert
617*7f2fe78bSCy Schubert return code;
618*7f2fe78bSCy Schubert }
619*7f2fe78bSCy Schubert
620*7f2fe78bSCy Schubert /*
621*7f2fe78bSCy Schubert * Determine the starting IAKERB state for a context. If we already
622*7f2fe78bSCy Schubert * have a ticket, we may not need to do IAKERB at all.
623*7f2fe78bSCy Schubert */
624*7f2fe78bSCy Schubert static krb5_error_code
iakerb_get_initial_state(iakerb_ctx_id_t ctx,krb5_gss_cred_id_t cred,krb5_gss_name_t target,OM_uint32 time_req,enum iakerb_state * state)625*7f2fe78bSCy Schubert iakerb_get_initial_state(iakerb_ctx_id_t ctx,
626*7f2fe78bSCy Schubert krb5_gss_cred_id_t cred,
627*7f2fe78bSCy Schubert krb5_gss_name_t target,
628*7f2fe78bSCy Schubert OM_uint32 time_req,
629*7f2fe78bSCy Schubert enum iakerb_state *state)
630*7f2fe78bSCy Schubert {
631*7f2fe78bSCy Schubert krb5_creds in_creds, *out_creds = NULL;
632*7f2fe78bSCy Schubert krb5_error_code code;
633*7f2fe78bSCy Schubert
634*7f2fe78bSCy Schubert memset(&in_creds, 0, sizeof(in_creds));
635*7f2fe78bSCy Schubert
636*7f2fe78bSCy Schubert in_creds.client = cred->name->princ;
637*7f2fe78bSCy Schubert in_creds.server = target->princ;
638*7f2fe78bSCy Schubert
639*7f2fe78bSCy Schubert if (cred->name->ad_context != NULL) {
640*7f2fe78bSCy Schubert code = krb5_authdata_export_authdata(ctx->k5c,
641*7f2fe78bSCy Schubert cred->name->ad_context,
642*7f2fe78bSCy Schubert AD_USAGE_TGS_REQ,
643*7f2fe78bSCy Schubert &in_creds.authdata);
644*7f2fe78bSCy Schubert if (code != 0)
645*7f2fe78bSCy Schubert goto cleanup;
646*7f2fe78bSCy Schubert }
647*7f2fe78bSCy Schubert
648*7f2fe78bSCy Schubert if (time_req != 0 && time_req != GSS_C_INDEFINITE) {
649*7f2fe78bSCy Schubert krb5_timestamp now;
650*7f2fe78bSCy Schubert
651*7f2fe78bSCy Schubert code = krb5_timeofday(ctx->k5c, &now);
652*7f2fe78bSCy Schubert if (code != 0)
653*7f2fe78bSCy Schubert goto cleanup;
654*7f2fe78bSCy Schubert
655*7f2fe78bSCy Schubert in_creds.times.endtime = ts_incr(now, time_req);
656*7f2fe78bSCy Schubert }
657*7f2fe78bSCy Schubert
658*7f2fe78bSCy Schubert /* Make an AS request if we have no creds or it's time to refresh them. */
659*7f2fe78bSCy Schubert if (cred->expire == 0 || kg_cred_time_to_refresh(ctx->k5c, cred)) {
660*7f2fe78bSCy Schubert *state = IAKERB_AS_REQ;
661*7f2fe78bSCy Schubert code = 0;
662*7f2fe78bSCy Schubert goto cleanup;
663*7f2fe78bSCy Schubert }
664*7f2fe78bSCy Schubert
665*7f2fe78bSCy Schubert code = krb5_get_credentials(ctx->k5c, KRB5_GC_CACHED, cred->ccache,
666*7f2fe78bSCy Schubert &in_creds, &out_creds);
667*7f2fe78bSCy Schubert if (code == KRB5_CC_NOTFOUND || code == KRB5_CC_NOT_KTYPE) {
668*7f2fe78bSCy Schubert *state = cred->have_tgt ? IAKERB_TGS_REQ : IAKERB_AS_REQ;
669*7f2fe78bSCy Schubert code = 0;
670*7f2fe78bSCy Schubert } else if (code == 0) {
671*7f2fe78bSCy Schubert *state = IAKERB_AP_REQ;
672*7f2fe78bSCy Schubert krb5_free_creds(ctx->k5c, out_creds);
673*7f2fe78bSCy Schubert }
674*7f2fe78bSCy Schubert
675*7f2fe78bSCy Schubert cleanup:
676*7f2fe78bSCy Schubert krb5_free_authdata(ctx->k5c, in_creds.authdata);
677*7f2fe78bSCy Schubert
678*7f2fe78bSCy Schubert return code;
679*7f2fe78bSCy Schubert }
680*7f2fe78bSCy Schubert
681*7f2fe78bSCy Schubert /*
682*7f2fe78bSCy Schubert * Allocate and initialise an IAKERB context
683*7f2fe78bSCy Schubert */
684*7f2fe78bSCy Schubert static krb5_error_code
iakerb_alloc_context(iakerb_ctx_id_t * pctx,int initiate)685*7f2fe78bSCy Schubert iakerb_alloc_context(iakerb_ctx_id_t *pctx, int initiate)
686*7f2fe78bSCy Schubert {
687*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx;
688*7f2fe78bSCy Schubert krb5_error_code code;
689*7f2fe78bSCy Schubert
690*7f2fe78bSCy Schubert *pctx = NULL;
691*7f2fe78bSCy Schubert
692*7f2fe78bSCy Schubert ctx = k5alloc(sizeof(*ctx), &code);
693*7f2fe78bSCy Schubert if (ctx == NULL)
694*7f2fe78bSCy Schubert goto cleanup;
695*7f2fe78bSCy Schubert ctx->defcred = GSS_C_NO_CREDENTIAL;
696*7f2fe78bSCy Schubert ctx->magic = KG_IAKERB_CONTEXT;
697*7f2fe78bSCy Schubert ctx->state = IAKERB_AS_REQ;
698*7f2fe78bSCy Schubert ctx->count = 0;
699*7f2fe78bSCy Schubert ctx->initiate = initiate;
700*7f2fe78bSCy Schubert ctx->established = 0;
701*7f2fe78bSCy Schubert
702*7f2fe78bSCy Schubert code = krb5_gss_init_context(&ctx->k5c);
703*7f2fe78bSCy Schubert if (code != 0)
704*7f2fe78bSCy Schubert goto cleanup;
705*7f2fe78bSCy Schubert
706*7f2fe78bSCy Schubert *pctx = ctx;
707*7f2fe78bSCy Schubert
708*7f2fe78bSCy Schubert cleanup:
709*7f2fe78bSCy Schubert if (code != 0)
710*7f2fe78bSCy Schubert iakerb_release_context(ctx);
711*7f2fe78bSCy Schubert
712*7f2fe78bSCy Schubert return code;
713*7f2fe78bSCy Schubert }
714*7f2fe78bSCy Schubert
715*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_delete_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_buffer_t output_token)716*7f2fe78bSCy Schubert iakerb_gss_delete_sec_context(OM_uint32 *minor_status,
717*7f2fe78bSCy Schubert gss_ctx_id_t *context_handle,
718*7f2fe78bSCy Schubert gss_buffer_t output_token)
719*7f2fe78bSCy Schubert {
720*7f2fe78bSCy Schubert iakerb_ctx_id_t iakerb_ctx = (iakerb_ctx_id_t)*context_handle;
721*7f2fe78bSCy Schubert
722*7f2fe78bSCy Schubert if (output_token != GSS_C_NO_BUFFER) {
723*7f2fe78bSCy Schubert output_token->length = 0;
724*7f2fe78bSCy Schubert output_token->value = NULL;
725*7f2fe78bSCy Schubert }
726*7f2fe78bSCy Schubert
727*7f2fe78bSCy Schubert *minor_status = 0;
728*7f2fe78bSCy Schubert *context_handle = GSS_C_NO_CONTEXT;
729*7f2fe78bSCy Schubert iakerb_release_context(iakerb_ctx);
730*7f2fe78bSCy Schubert
731*7f2fe78bSCy Schubert return GSS_S_COMPLETE;
732*7f2fe78bSCy Schubert }
733*7f2fe78bSCy Schubert
734*7f2fe78bSCy Schubert static krb5_boolean
iakerb_is_iakerb_token(const gss_buffer_t token)735*7f2fe78bSCy Schubert iakerb_is_iakerb_token(const gss_buffer_t token)
736*7f2fe78bSCy Schubert {
737*7f2fe78bSCy Schubert krb5_error_code code;
738*7f2fe78bSCy Schubert unsigned int bodysize = token->length;
739*7f2fe78bSCy Schubert unsigned char *ptr = token->value;
740*7f2fe78bSCy Schubert
741*7f2fe78bSCy Schubert code = g_verify_token_header(gss_mech_iakerb,
742*7f2fe78bSCy Schubert &bodysize, &ptr,
743*7f2fe78bSCy Schubert IAKERB_TOK_PROXY,
744*7f2fe78bSCy Schubert token->length, 0);
745*7f2fe78bSCy Schubert
746*7f2fe78bSCy Schubert return (code == 0);
747*7f2fe78bSCy Schubert }
748*7f2fe78bSCy Schubert
749*7f2fe78bSCy Schubert static void
iakerb_make_exts(iakerb_ctx_id_t ctx,krb5_gss_ctx_ext_rec * exts)750*7f2fe78bSCy Schubert iakerb_make_exts(iakerb_ctx_id_t ctx, krb5_gss_ctx_ext_rec *exts)
751*7f2fe78bSCy Schubert {
752*7f2fe78bSCy Schubert memset(exts, 0, sizeof(*exts));
753*7f2fe78bSCy Schubert
754*7f2fe78bSCy Schubert if (ctx->conv.length != 0)
755*7f2fe78bSCy Schubert exts->iakerb.conv = &ctx->conv;
756*7f2fe78bSCy Schubert }
757*7f2fe78bSCy Schubert
758*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_accept_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_cred_id_t verifier_cred_handle,gss_buffer_t input_token,gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle)759*7f2fe78bSCy Schubert iakerb_gss_accept_sec_context(OM_uint32 *minor_status,
760*7f2fe78bSCy Schubert gss_ctx_id_t *context_handle,
761*7f2fe78bSCy Schubert gss_cred_id_t verifier_cred_handle,
762*7f2fe78bSCy Schubert gss_buffer_t input_token,
763*7f2fe78bSCy Schubert gss_channel_bindings_t input_chan_bindings,
764*7f2fe78bSCy Schubert gss_name_t *src_name,
765*7f2fe78bSCy Schubert gss_OID *mech_type,
766*7f2fe78bSCy Schubert gss_buffer_t output_token,
767*7f2fe78bSCy Schubert OM_uint32 *ret_flags,
768*7f2fe78bSCy Schubert OM_uint32 *time_rec,
769*7f2fe78bSCy Schubert gss_cred_id_t *delegated_cred_handle)
770*7f2fe78bSCy Schubert {
771*7f2fe78bSCy Schubert OM_uint32 major_status = GSS_S_FAILURE;
772*7f2fe78bSCy Schubert OM_uint32 code;
773*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx;
774*7f2fe78bSCy Schubert int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
775*7f2fe78bSCy Schubert
776*7f2fe78bSCy Schubert if (initialContextToken) {
777*7f2fe78bSCy Schubert code = iakerb_alloc_context(&ctx, 0);
778*7f2fe78bSCy Schubert if (code != 0)
779*7f2fe78bSCy Schubert goto cleanup;
780*7f2fe78bSCy Schubert
781*7f2fe78bSCy Schubert } else
782*7f2fe78bSCy Schubert ctx = (iakerb_ctx_id_t)*context_handle;
783*7f2fe78bSCy Schubert
784*7f2fe78bSCy Schubert if (iakerb_is_iakerb_token(input_token)) {
785*7f2fe78bSCy Schubert if (ctx->gssc != GSS_C_NO_CONTEXT) {
786*7f2fe78bSCy Schubert /* We shouldn't get an IAKERB token now. */
787*7f2fe78bSCy Schubert code = G_WRONG_TOKID;
788*7f2fe78bSCy Schubert major_status = GSS_S_DEFECTIVE_TOKEN;
789*7f2fe78bSCy Schubert goto cleanup;
790*7f2fe78bSCy Schubert }
791*7f2fe78bSCy Schubert code = iakerb_acceptor_step(ctx, initialContextToken,
792*7f2fe78bSCy Schubert input_token, output_token);
793*7f2fe78bSCy Schubert if (code == (OM_uint32)KRB5_BAD_MSIZE)
794*7f2fe78bSCy Schubert major_status = GSS_S_DEFECTIVE_TOKEN;
795*7f2fe78bSCy Schubert if (code != 0)
796*7f2fe78bSCy Schubert goto cleanup;
797*7f2fe78bSCy Schubert if (initialContextToken) {
798*7f2fe78bSCy Schubert *context_handle = (gss_ctx_id_t)ctx;
799*7f2fe78bSCy Schubert ctx = NULL;
800*7f2fe78bSCy Schubert }
801*7f2fe78bSCy Schubert if (src_name != NULL)
802*7f2fe78bSCy Schubert *src_name = GSS_C_NO_NAME;
803*7f2fe78bSCy Schubert if (ret_flags != NULL)
804*7f2fe78bSCy Schubert *ret_flags = 0;
805*7f2fe78bSCy Schubert if (time_rec != NULL)
806*7f2fe78bSCy Schubert *time_rec = 0;
807*7f2fe78bSCy Schubert if (delegated_cred_handle != NULL)
808*7f2fe78bSCy Schubert *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
809*7f2fe78bSCy Schubert major_status = GSS_S_CONTINUE_NEEDED;
810*7f2fe78bSCy Schubert } else {
811*7f2fe78bSCy Schubert krb5_gss_ctx_ext_rec exts;
812*7f2fe78bSCy Schubert
813*7f2fe78bSCy Schubert iakerb_make_exts(ctx, &exts);
814*7f2fe78bSCy Schubert
815*7f2fe78bSCy Schubert major_status = krb5_gss_accept_sec_context_ext(&code,
816*7f2fe78bSCy Schubert &ctx->gssc,
817*7f2fe78bSCy Schubert verifier_cred_handle,
818*7f2fe78bSCy Schubert input_token,
819*7f2fe78bSCy Schubert input_chan_bindings,
820*7f2fe78bSCy Schubert src_name,
821*7f2fe78bSCy Schubert NULL,
822*7f2fe78bSCy Schubert output_token,
823*7f2fe78bSCy Schubert ret_flags,
824*7f2fe78bSCy Schubert time_rec,
825*7f2fe78bSCy Schubert delegated_cred_handle,
826*7f2fe78bSCy Schubert &exts);
827*7f2fe78bSCy Schubert if (major_status == GSS_S_COMPLETE)
828*7f2fe78bSCy Schubert ctx->established = 1;
829*7f2fe78bSCy Schubert }
830*7f2fe78bSCy Schubert
831*7f2fe78bSCy Schubert if (mech_type != NULL)
832*7f2fe78bSCy Schubert *mech_type = gss_mech_iakerb;
833*7f2fe78bSCy Schubert
834*7f2fe78bSCy Schubert cleanup:
835*7f2fe78bSCy Schubert if (initialContextToken && GSS_ERROR(major_status)) {
836*7f2fe78bSCy Schubert iakerb_release_context(ctx);
837*7f2fe78bSCy Schubert *context_handle = GSS_C_NO_CONTEXT;
838*7f2fe78bSCy Schubert }
839*7f2fe78bSCy Schubert
840*7f2fe78bSCy Schubert *minor_status = code;
841*7f2fe78bSCy Schubert return major_status;
842*7f2fe78bSCy Schubert }
843*7f2fe78bSCy Schubert
844*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_init_sec_context(OM_uint32 * minor_status,gss_cred_id_t claimant_cred_handle,gss_ctx_id_t * context_handle,gss_name_t target_name,gss_OID mech_type,OM_uint32 req_flags,OM_uint32 time_req,gss_channel_bindings_t input_chan_bindings,gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec)845*7f2fe78bSCy Schubert iakerb_gss_init_sec_context(OM_uint32 *minor_status,
846*7f2fe78bSCy Schubert gss_cred_id_t claimant_cred_handle,
847*7f2fe78bSCy Schubert gss_ctx_id_t *context_handle,
848*7f2fe78bSCy Schubert gss_name_t target_name,
849*7f2fe78bSCy Schubert gss_OID mech_type,
850*7f2fe78bSCy Schubert OM_uint32 req_flags,
851*7f2fe78bSCy Schubert OM_uint32 time_req,
852*7f2fe78bSCy Schubert gss_channel_bindings_t input_chan_bindings,
853*7f2fe78bSCy Schubert gss_buffer_t input_token,
854*7f2fe78bSCy Schubert gss_OID *actual_mech_type,
855*7f2fe78bSCy Schubert gss_buffer_t output_token,
856*7f2fe78bSCy Schubert OM_uint32 *ret_flags,
857*7f2fe78bSCy Schubert OM_uint32 *time_rec)
858*7f2fe78bSCy Schubert {
859*7f2fe78bSCy Schubert OM_uint32 major_status = GSS_S_FAILURE;
860*7f2fe78bSCy Schubert krb5_error_code code;
861*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx;
862*7f2fe78bSCy Schubert krb5_gss_cred_id_t kcred;
863*7f2fe78bSCy Schubert krb5_gss_name_t kname;
864*7f2fe78bSCy Schubert krb5_boolean cred_locked = FALSE;
865*7f2fe78bSCy Schubert int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
866*7f2fe78bSCy Schubert
867*7f2fe78bSCy Schubert if (initialContextToken) {
868*7f2fe78bSCy Schubert code = iakerb_alloc_context(&ctx, 1);
869*7f2fe78bSCy Schubert if (code != 0) {
870*7f2fe78bSCy Schubert *minor_status = code;
871*7f2fe78bSCy Schubert goto cleanup;
872*7f2fe78bSCy Schubert }
873*7f2fe78bSCy Schubert if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
874*7f2fe78bSCy Schubert major_status = iakerb_gss_acquire_cred(minor_status, NULL,
875*7f2fe78bSCy Schubert GSS_C_INDEFINITE,
876*7f2fe78bSCy Schubert GSS_C_NULL_OID_SET,
877*7f2fe78bSCy Schubert GSS_C_INITIATE,
878*7f2fe78bSCy Schubert &ctx->defcred, NULL, NULL);
879*7f2fe78bSCy Schubert if (GSS_ERROR(major_status))
880*7f2fe78bSCy Schubert goto cleanup;
881*7f2fe78bSCy Schubert claimant_cred_handle = ctx->defcred;
882*7f2fe78bSCy Schubert }
883*7f2fe78bSCy Schubert } else {
884*7f2fe78bSCy Schubert ctx = (iakerb_ctx_id_t)*context_handle;
885*7f2fe78bSCy Schubert if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
886*7f2fe78bSCy Schubert claimant_cred_handle = ctx->defcred;
887*7f2fe78bSCy Schubert }
888*7f2fe78bSCy Schubert
889*7f2fe78bSCy Schubert kname = (krb5_gss_name_t)target_name;
890*7f2fe78bSCy Schubert
891*7f2fe78bSCy Schubert major_status = kg_cred_resolve(minor_status, ctx->k5c,
892*7f2fe78bSCy Schubert claimant_cred_handle, target_name);
893*7f2fe78bSCy Schubert if (GSS_ERROR(major_status))
894*7f2fe78bSCy Schubert goto cleanup;
895*7f2fe78bSCy Schubert cred_locked = TRUE;
896*7f2fe78bSCy Schubert kcred = (krb5_gss_cred_id_t)claimant_cred_handle;
897*7f2fe78bSCy Schubert
898*7f2fe78bSCy Schubert major_status = GSS_S_FAILURE;
899*7f2fe78bSCy Schubert
900*7f2fe78bSCy Schubert if (initialContextToken) {
901*7f2fe78bSCy Schubert code = iakerb_get_initial_state(ctx, kcred, kname, time_req,
902*7f2fe78bSCy Schubert &ctx->state);
903*7f2fe78bSCy Schubert if (code != 0) {
904*7f2fe78bSCy Schubert *minor_status = code;
905*7f2fe78bSCy Schubert goto cleanup;
906*7f2fe78bSCy Schubert }
907*7f2fe78bSCy Schubert *context_handle = (gss_ctx_id_t)ctx;
908*7f2fe78bSCy Schubert }
909*7f2fe78bSCy Schubert
910*7f2fe78bSCy Schubert if (ctx->state != IAKERB_AP_REQ) {
911*7f2fe78bSCy Schubert /* We need to do IAKERB. */
912*7f2fe78bSCy Schubert code = iakerb_initiator_step(ctx,
913*7f2fe78bSCy Schubert kcred,
914*7f2fe78bSCy Schubert kname,
915*7f2fe78bSCy Schubert time_req,
916*7f2fe78bSCy Schubert input_token,
917*7f2fe78bSCy Schubert output_token);
918*7f2fe78bSCy Schubert if (code == KRB5_BAD_MSIZE)
919*7f2fe78bSCy Schubert major_status = GSS_S_DEFECTIVE_TOKEN;
920*7f2fe78bSCy Schubert if (code != 0) {
921*7f2fe78bSCy Schubert *minor_status = code;
922*7f2fe78bSCy Schubert goto cleanup;
923*7f2fe78bSCy Schubert }
924*7f2fe78bSCy Schubert }
925*7f2fe78bSCy Schubert
926*7f2fe78bSCy Schubert if (ctx->state == IAKERB_AP_REQ) {
927*7f2fe78bSCy Schubert krb5_gss_ctx_ext_rec exts;
928*7f2fe78bSCy Schubert
929*7f2fe78bSCy Schubert if (cred_locked) {
930*7f2fe78bSCy Schubert k5_mutex_unlock(&kcred->lock);
931*7f2fe78bSCy Schubert cred_locked = FALSE;
932*7f2fe78bSCy Schubert }
933*7f2fe78bSCy Schubert
934*7f2fe78bSCy Schubert iakerb_make_exts(ctx, &exts);
935*7f2fe78bSCy Schubert
936*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
937*7f2fe78bSCy Schubert input_token = GSS_C_NO_BUFFER;
938*7f2fe78bSCy Schubert
939*7f2fe78bSCy Schubert /* IAKERB is finished, or we skipped to Kerberos directly. */
940*7f2fe78bSCy Schubert major_status = krb5_gss_init_sec_context_ext(minor_status,
941*7f2fe78bSCy Schubert (gss_cred_id_t) kcred,
942*7f2fe78bSCy Schubert &ctx->gssc,
943*7f2fe78bSCy Schubert target_name,
944*7f2fe78bSCy Schubert (gss_OID)gss_mech_iakerb,
945*7f2fe78bSCy Schubert req_flags,
946*7f2fe78bSCy Schubert time_req,
947*7f2fe78bSCy Schubert input_chan_bindings,
948*7f2fe78bSCy Schubert input_token,
949*7f2fe78bSCy Schubert NULL,
950*7f2fe78bSCy Schubert output_token,
951*7f2fe78bSCy Schubert ret_flags,
952*7f2fe78bSCy Schubert time_rec,
953*7f2fe78bSCy Schubert &exts);
954*7f2fe78bSCy Schubert if (major_status == GSS_S_COMPLETE)
955*7f2fe78bSCy Schubert ctx->established = 1;
956*7f2fe78bSCy Schubert } else {
957*7f2fe78bSCy Schubert if (ret_flags != NULL)
958*7f2fe78bSCy Schubert *ret_flags = 0;
959*7f2fe78bSCy Schubert if (time_rec != NULL)
960*7f2fe78bSCy Schubert *time_rec = 0;
961*7f2fe78bSCy Schubert major_status = GSS_S_CONTINUE_NEEDED;
962*7f2fe78bSCy Schubert }
963*7f2fe78bSCy Schubert
964*7f2fe78bSCy Schubert if (actual_mech_type != NULL)
965*7f2fe78bSCy Schubert *actual_mech_type = gss_mech_iakerb;
966*7f2fe78bSCy Schubert
967*7f2fe78bSCy Schubert cleanup:
968*7f2fe78bSCy Schubert if (cred_locked)
969*7f2fe78bSCy Schubert k5_mutex_unlock(&kcred->lock);
970*7f2fe78bSCy Schubert if (initialContextToken && GSS_ERROR(major_status)) {
971*7f2fe78bSCy Schubert iakerb_release_context(ctx);
972*7f2fe78bSCy Schubert *context_handle = GSS_C_NO_CONTEXT;
973*7f2fe78bSCy Schubert }
974*7f2fe78bSCy Schubert
975*7f2fe78bSCy Schubert return major_status;
976*7f2fe78bSCy Schubert }
977*7f2fe78bSCy Schubert
978*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_unwrap(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state)979*7f2fe78bSCy Schubert iakerb_gss_unwrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
980*7f2fe78bSCy Schubert gss_buffer_t input_message_buffer,
981*7f2fe78bSCy Schubert gss_buffer_t output_message_buffer, int *conf_state,
982*7f2fe78bSCy Schubert gss_qop_t *qop_state)
983*7f2fe78bSCy Schubert {
984*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
985*7f2fe78bSCy Schubert
986*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
987*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
988*7f2fe78bSCy Schubert
989*7f2fe78bSCy Schubert return krb5_gss_unwrap(minor_status, ctx->gssc, input_message_buffer,
990*7f2fe78bSCy Schubert output_message_buffer, conf_state, qop_state);
991*7f2fe78bSCy Schubert }
992*7f2fe78bSCy Schubert
993*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_wrap(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)994*7f2fe78bSCy Schubert iakerb_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
995*7f2fe78bSCy Schubert int conf_req_flag, gss_qop_t qop_req,
996*7f2fe78bSCy Schubert gss_buffer_t input_message_buffer, int *conf_state,
997*7f2fe78bSCy Schubert gss_buffer_t output_message_buffer)
998*7f2fe78bSCy Schubert {
999*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1000*7f2fe78bSCy Schubert
1001*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1002*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1003*7f2fe78bSCy Schubert
1004*7f2fe78bSCy Schubert return krb5_gss_wrap(minor_status, ctx->gssc, conf_req_flag, qop_req,
1005*7f2fe78bSCy Schubert input_message_buffer, conf_state,
1006*7f2fe78bSCy Schubert output_message_buffer);
1007*7f2fe78bSCy Schubert }
1008*7f2fe78bSCy Schubert
1009*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_process_context_token(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_buffer_t token_buffer)1010*7f2fe78bSCy Schubert iakerb_gss_process_context_token(OM_uint32 *minor_status,
1011*7f2fe78bSCy Schubert const gss_ctx_id_t context_handle,
1012*7f2fe78bSCy Schubert const gss_buffer_t token_buffer)
1013*7f2fe78bSCy Schubert {
1014*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1015*7f2fe78bSCy Schubert
1016*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1017*7f2fe78bSCy Schubert return GSS_S_DEFECTIVE_TOKEN;
1018*7f2fe78bSCy Schubert
1019*7f2fe78bSCy Schubert return krb5_gss_process_context_token(minor_status, ctx->gssc,
1020*7f2fe78bSCy Schubert token_buffer);
1021*7f2fe78bSCy Schubert }
1022*7f2fe78bSCy Schubert
1023*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_context_time(OM_uint32 * minor_status,gss_ctx_id_t context_handle,OM_uint32 * time_rec)1024*7f2fe78bSCy Schubert iakerb_gss_context_time(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1025*7f2fe78bSCy Schubert OM_uint32 *time_rec)
1026*7f2fe78bSCy Schubert {
1027*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1028*7f2fe78bSCy Schubert
1029*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1030*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1031*7f2fe78bSCy Schubert
1032*7f2fe78bSCy Schubert return krb5_gss_context_time(minor_status, ctx->gssc, time_rec);
1033*7f2fe78bSCy Schubert }
1034*7f2fe78bSCy Schubert
1035*7f2fe78bSCy Schubert #ifndef LEAN_CLIENT
1036*7f2fe78bSCy Schubert
1037*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_export_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_buffer_t interprocess_token)1038*7f2fe78bSCy Schubert iakerb_gss_export_sec_context(OM_uint32 *minor_status,
1039*7f2fe78bSCy Schubert gss_ctx_id_t *context_handle,
1040*7f2fe78bSCy Schubert gss_buffer_t interprocess_token)
1041*7f2fe78bSCy Schubert {
1042*7f2fe78bSCy Schubert OM_uint32 maj;
1043*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle;
1044*7f2fe78bSCy Schubert
1045*7f2fe78bSCy Schubert /* We don't currently support exporting partially established contexts. */
1046*7f2fe78bSCy Schubert if (!ctx->established)
1047*7f2fe78bSCy Schubert return GSS_S_UNAVAILABLE;
1048*7f2fe78bSCy Schubert
1049*7f2fe78bSCy Schubert maj = krb5_gss_export_sec_context(minor_status, &ctx->gssc,
1050*7f2fe78bSCy Schubert interprocess_token);
1051*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT) {
1052*7f2fe78bSCy Schubert iakerb_release_context(ctx);
1053*7f2fe78bSCy Schubert *context_handle = GSS_C_NO_CONTEXT;
1054*7f2fe78bSCy Schubert }
1055*7f2fe78bSCy Schubert return maj;
1056*7f2fe78bSCy Schubert }
1057*7f2fe78bSCy Schubert
1058*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_import_sec_context(OM_uint32 * minor_status,gss_buffer_t interprocess_token,gss_ctx_id_t * context_handle)1059*7f2fe78bSCy Schubert iakerb_gss_import_sec_context(OM_uint32 *minor_status,
1060*7f2fe78bSCy Schubert gss_buffer_t interprocess_token,
1061*7f2fe78bSCy Schubert gss_ctx_id_t *context_handle)
1062*7f2fe78bSCy Schubert {
1063*7f2fe78bSCy Schubert OM_uint32 maj, tmpmin;
1064*7f2fe78bSCy Schubert krb5_error_code code;
1065*7f2fe78bSCy Schubert gss_ctx_id_t gssc;
1066*7f2fe78bSCy Schubert krb5_gss_ctx_id_t kctx;
1067*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx;
1068*7f2fe78bSCy Schubert
1069*7f2fe78bSCy Schubert maj = krb5_gss_import_sec_context(minor_status, interprocess_token, &gssc);
1070*7f2fe78bSCy Schubert if (maj != GSS_S_COMPLETE)
1071*7f2fe78bSCy Schubert return maj;
1072*7f2fe78bSCy Schubert kctx = (krb5_gss_ctx_id_t)gssc;
1073*7f2fe78bSCy Schubert
1074*7f2fe78bSCy Schubert if (!kctx->established) {
1075*7f2fe78bSCy Schubert /* We don't currently support importing partially established
1076*7f2fe78bSCy Schubert * contexts. */
1077*7f2fe78bSCy Schubert krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
1078*7f2fe78bSCy Schubert return GSS_S_FAILURE;
1079*7f2fe78bSCy Schubert }
1080*7f2fe78bSCy Schubert
1081*7f2fe78bSCy Schubert code = iakerb_alloc_context(&ctx, kctx->initiate);
1082*7f2fe78bSCy Schubert if (code != 0) {
1083*7f2fe78bSCy Schubert krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER);
1084*7f2fe78bSCy Schubert *minor_status = code;
1085*7f2fe78bSCy Schubert return GSS_S_FAILURE;
1086*7f2fe78bSCy Schubert }
1087*7f2fe78bSCy Schubert
1088*7f2fe78bSCy Schubert ctx->gssc = gssc;
1089*7f2fe78bSCy Schubert ctx->established = 1;
1090*7f2fe78bSCy Schubert *context_handle = (gss_ctx_id_t)ctx;
1091*7f2fe78bSCy Schubert return GSS_S_COMPLETE;
1092*7f2fe78bSCy Schubert }
1093*7f2fe78bSCy Schubert #endif /* LEAN_CLIENT */
1094*7f2fe78bSCy Schubert
1095*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_inquire_context(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_name_t * src_name,gss_name_t * targ_name,OM_uint32 * lifetime_rec,gss_OID * mech_type,OM_uint32 * ctx_flags,int * initiate,int * opened)1096*7f2fe78bSCy Schubert iakerb_gss_inquire_context(OM_uint32 *minor_status,
1097*7f2fe78bSCy Schubert gss_ctx_id_t context_handle, gss_name_t *src_name,
1098*7f2fe78bSCy Schubert gss_name_t *targ_name, OM_uint32 *lifetime_rec,
1099*7f2fe78bSCy Schubert gss_OID *mech_type, OM_uint32 *ctx_flags,
1100*7f2fe78bSCy Schubert int *initiate, int *opened)
1101*7f2fe78bSCy Schubert {
1102*7f2fe78bSCy Schubert OM_uint32 ret;
1103*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1104*7f2fe78bSCy Schubert
1105*7f2fe78bSCy Schubert if (src_name != NULL)
1106*7f2fe78bSCy Schubert *src_name = GSS_C_NO_NAME;
1107*7f2fe78bSCy Schubert if (targ_name != NULL)
1108*7f2fe78bSCy Schubert *targ_name = GSS_C_NO_NAME;
1109*7f2fe78bSCy Schubert if (lifetime_rec != NULL)
1110*7f2fe78bSCy Schubert *lifetime_rec = 0;
1111*7f2fe78bSCy Schubert if (mech_type != NULL)
1112*7f2fe78bSCy Schubert *mech_type = (gss_OID)gss_mech_iakerb;
1113*7f2fe78bSCy Schubert if (ctx_flags != NULL)
1114*7f2fe78bSCy Schubert *ctx_flags = 0;
1115*7f2fe78bSCy Schubert if (initiate != NULL)
1116*7f2fe78bSCy Schubert *initiate = ctx->initiate;
1117*7f2fe78bSCy Schubert if (opened != NULL)
1118*7f2fe78bSCy Schubert *opened = ctx->established;
1119*7f2fe78bSCy Schubert
1120*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1121*7f2fe78bSCy Schubert return GSS_S_COMPLETE;
1122*7f2fe78bSCy Schubert
1123*7f2fe78bSCy Schubert ret = krb5_gss_inquire_context(minor_status, ctx->gssc, src_name,
1124*7f2fe78bSCy Schubert targ_name, lifetime_rec, mech_type,
1125*7f2fe78bSCy Schubert ctx_flags, initiate, opened);
1126*7f2fe78bSCy Schubert
1127*7f2fe78bSCy Schubert if (!ctx->established) {
1128*7f2fe78bSCy Schubert /* Report IAKERB as the mech OID until the context is established. */
1129*7f2fe78bSCy Schubert if (mech_type != NULL)
1130*7f2fe78bSCy Schubert *mech_type = (gss_OID)gss_mech_iakerb;
1131*7f2fe78bSCy Schubert
1132*7f2fe78bSCy Schubert /* We don't support exporting partially-established contexts. */
1133*7f2fe78bSCy Schubert if (ctx_flags != NULL)
1134*7f2fe78bSCy Schubert *ctx_flags &= ~GSS_C_TRANS_FLAG;
1135*7f2fe78bSCy Schubert }
1136*7f2fe78bSCy Schubert
1137*7f2fe78bSCy Schubert return ret;
1138*7f2fe78bSCy Schubert }
1139*7f2fe78bSCy Schubert
1140*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_wrap_size_limit(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size)1141*7f2fe78bSCy Schubert iakerb_gss_wrap_size_limit(OM_uint32 *minor_status,
1142*7f2fe78bSCy Schubert gss_ctx_id_t context_handle, int conf_req_flag,
1143*7f2fe78bSCy Schubert gss_qop_t qop_req, OM_uint32 req_output_size,
1144*7f2fe78bSCy Schubert OM_uint32 *max_input_size)
1145*7f2fe78bSCy Schubert {
1146*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1147*7f2fe78bSCy Schubert
1148*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1149*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1150*7f2fe78bSCy Schubert
1151*7f2fe78bSCy Schubert return krb5_gss_wrap_size_limit(minor_status, ctx->gssc, conf_req_flag,
1152*7f2fe78bSCy Schubert qop_req, req_output_size, max_input_size);
1153*7f2fe78bSCy Schubert }
1154*7f2fe78bSCy Schubert
1155*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_get_mic(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_qop_t qop_req,gss_buffer_t message_buffer,gss_buffer_t message_token)1156*7f2fe78bSCy Schubert iakerb_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1157*7f2fe78bSCy Schubert gss_qop_t qop_req, gss_buffer_t message_buffer,
1158*7f2fe78bSCy Schubert gss_buffer_t message_token)
1159*7f2fe78bSCy Schubert {
1160*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1161*7f2fe78bSCy Schubert
1162*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1163*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1164*7f2fe78bSCy Schubert
1165*7f2fe78bSCy Schubert return krb5_gss_get_mic(minor_status, ctx->gssc, qop_req, message_buffer,
1166*7f2fe78bSCy Schubert message_token);
1167*7f2fe78bSCy Schubert }
1168*7f2fe78bSCy Schubert
1169*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_verify_mic(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_buffer_t msg_buffer,gss_buffer_t token_buffer,gss_qop_t * qop_state)1170*7f2fe78bSCy Schubert iakerb_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1171*7f2fe78bSCy Schubert gss_buffer_t msg_buffer, gss_buffer_t token_buffer,
1172*7f2fe78bSCy Schubert gss_qop_t *qop_state)
1173*7f2fe78bSCy Schubert {
1174*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1175*7f2fe78bSCy Schubert
1176*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1177*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1178*7f2fe78bSCy Schubert
1179*7f2fe78bSCy Schubert return krb5_gss_verify_mic(minor_status, ctx->gssc, msg_buffer,
1180*7f2fe78bSCy Schubert token_buffer, qop_state);
1181*7f2fe78bSCy Schubert }
1182*7f2fe78bSCy Schubert
1183*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_inquire_sec_context_by_oid(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_OID desired_object,gss_buffer_set_t * data_set)1184*7f2fe78bSCy Schubert iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status,
1185*7f2fe78bSCy Schubert const gss_ctx_id_t context_handle,
1186*7f2fe78bSCy Schubert const gss_OID desired_object,
1187*7f2fe78bSCy Schubert gss_buffer_set_t *data_set)
1188*7f2fe78bSCy Schubert {
1189*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1190*7f2fe78bSCy Schubert
1191*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1192*7f2fe78bSCy Schubert return GSS_S_UNAVAILABLE;
1193*7f2fe78bSCy Schubert
1194*7f2fe78bSCy Schubert return krb5_gss_inquire_sec_context_by_oid(minor_status, ctx->gssc,
1195*7f2fe78bSCy Schubert desired_object, data_set);
1196*7f2fe78bSCy Schubert }
1197*7f2fe78bSCy Schubert
1198*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_set_sec_context_option(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,const gss_OID desired_object,const gss_buffer_t value)1199*7f2fe78bSCy Schubert iakerb_gss_set_sec_context_option(OM_uint32 *minor_status,
1200*7f2fe78bSCy Schubert gss_ctx_id_t *context_handle,
1201*7f2fe78bSCy Schubert const gss_OID desired_object,
1202*7f2fe78bSCy Schubert const gss_buffer_t value)
1203*7f2fe78bSCy Schubert {
1204*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle;
1205*7f2fe78bSCy Schubert
1206*7f2fe78bSCy Schubert if (ctx == NULL || ctx->gssc == GSS_C_NO_CONTEXT)
1207*7f2fe78bSCy Schubert return GSS_S_UNAVAILABLE;
1208*7f2fe78bSCy Schubert
1209*7f2fe78bSCy Schubert return krb5_gss_set_sec_context_option(minor_status, &ctx->gssc,
1210*7f2fe78bSCy Schubert desired_object, value);
1211*7f2fe78bSCy Schubert }
1212*7f2fe78bSCy Schubert
1213*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_wrap_iov(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,int * conf_state,gss_iov_buffer_desc * iov,int iov_count)1214*7f2fe78bSCy Schubert iakerb_gss_wrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1215*7f2fe78bSCy Schubert int conf_req_flag, gss_qop_t qop_req, int *conf_state,
1216*7f2fe78bSCy Schubert gss_iov_buffer_desc *iov, int iov_count)
1217*7f2fe78bSCy Schubert {
1218*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1219*7f2fe78bSCy Schubert
1220*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1221*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1222*7f2fe78bSCy Schubert
1223*7f2fe78bSCy Schubert return krb5_gss_wrap_iov(minor_status, ctx->gssc, conf_req_flag, qop_req,
1224*7f2fe78bSCy Schubert conf_state, iov, iov_count);
1225*7f2fe78bSCy Schubert }
1226*7f2fe78bSCy Schubert
1227*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_unwrap_iov(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int * conf_state,gss_qop_t * qop_state,gss_iov_buffer_desc * iov,int iov_count)1228*7f2fe78bSCy Schubert iakerb_gss_unwrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1229*7f2fe78bSCy Schubert int *conf_state, gss_qop_t *qop_state,
1230*7f2fe78bSCy Schubert gss_iov_buffer_desc *iov, int iov_count)
1231*7f2fe78bSCy Schubert {
1232*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1233*7f2fe78bSCy Schubert
1234*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1235*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1236*7f2fe78bSCy Schubert
1237*7f2fe78bSCy Schubert return krb5_gss_unwrap_iov(minor_status, ctx->gssc, conf_state, qop_state,
1238*7f2fe78bSCy Schubert iov, iov_count);
1239*7f2fe78bSCy Schubert }
1240*7f2fe78bSCy Schubert
1241*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_wrap_iov_length(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,int * conf_state,gss_iov_buffer_desc * iov,int iov_count)1242*7f2fe78bSCy Schubert iakerb_gss_wrap_iov_length(OM_uint32 *minor_status,
1243*7f2fe78bSCy Schubert gss_ctx_id_t context_handle, int conf_req_flag,
1244*7f2fe78bSCy Schubert gss_qop_t qop_req, int *conf_state,
1245*7f2fe78bSCy Schubert gss_iov_buffer_desc *iov, int iov_count)
1246*7f2fe78bSCy Schubert {
1247*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1248*7f2fe78bSCy Schubert
1249*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1250*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1251*7f2fe78bSCy Schubert
1252*7f2fe78bSCy Schubert return krb5_gss_wrap_iov_length(minor_status, ctx->gssc, conf_req_flag,
1253*7f2fe78bSCy Schubert qop_req, conf_state, iov, iov_count);
1254*7f2fe78bSCy Schubert }
1255*7f2fe78bSCy Schubert
1256*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_pseudo_random(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int prf_key,const gss_buffer_t prf_in,ssize_t desired_output_len,gss_buffer_t prf_out)1257*7f2fe78bSCy Schubert iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1258*7f2fe78bSCy Schubert int prf_key, const gss_buffer_t prf_in,
1259*7f2fe78bSCy Schubert ssize_t desired_output_len, gss_buffer_t prf_out)
1260*7f2fe78bSCy Schubert {
1261*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1262*7f2fe78bSCy Schubert
1263*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1264*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1265*7f2fe78bSCy Schubert
1266*7f2fe78bSCy Schubert return krb5_gss_pseudo_random(minor_status, ctx->gssc, prf_key, prf_in,
1267*7f2fe78bSCy Schubert desired_output_len, prf_out);
1268*7f2fe78bSCy Schubert }
1269*7f2fe78bSCy Schubert
1270*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_get_mic_iov(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_qop_t qop_req,gss_iov_buffer_desc * iov,int iov_count)1271*7f2fe78bSCy Schubert iakerb_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1272*7f2fe78bSCy Schubert gss_qop_t qop_req, gss_iov_buffer_desc *iov,
1273*7f2fe78bSCy Schubert int iov_count)
1274*7f2fe78bSCy Schubert {
1275*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1276*7f2fe78bSCy Schubert
1277*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1278*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1279*7f2fe78bSCy Schubert
1280*7f2fe78bSCy Schubert return krb5_gss_get_mic_iov(minor_status, ctx->gssc, qop_req, iov,
1281*7f2fe78bSCy Schubert iov_count);
1282*7f2fe78bSCy Schubert }
1283*7f2fe78bSCy Schubert
1284*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_verify_mic_iov(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_qop_t * qop_state,gss_iov_buffer_desc * iov,int iov_count)1285*7f2fe78bSCy Schubert iakerb_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
1286*7f2fe78bSCy Schubert gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
1287*7f2fe78bSCy Schubert int iov_count)
1288*7f2fe78bSCy Schubert {
1289*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1290*7f2fe78bSCy Schubert
1291*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1292*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1293*7f2fe78bSCy Schubert
1294*7f2fe78bSCy Schubert return krb5_gss_verify_mic_iov(minor_status, ctx->gssc, qop_state, iov,
1295*7f2fe78bSCy Schubert iov_count);
1296*7f2fe78bSCy Schubert }
1297*7f2fe78bSCy Schubert
1298*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
iakerb_gss_get_mic_iov_length(OM_uint32 * minor_status,gss_ctx_id_t context_handle,gss_qop_t qop_req,gss_iov_buffer_desc * iov,int iov_count)1299*7f2fe78bSCy Schubert iakerb_gss_get_mic_iov_length(OM_uint32 *minor_status,
1300*7f2fe78bSCy Schubert gss_ctx_id_t context_handle, gss_qop_t qop_req,
1301*7f2fe78bSCy Schubert gss_iov_buffer_desc *iov, int iov_count)
1302*7f2fe78bSCy Schubert {
1303*7f2fe78bSCy Schubert iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
1304*7f2fe78bSCy Schubert
1305*7f2fe78bSCy Schubert if (ctx->gssc == GSS_C_NO_CONTEXT)
1306*7f2fe78bSCy Schubert return GSS_S_NO_CONTEXT;
1307*7f2fe78bSCy Schubert
1308*7f2fe78bSCy Schubert return krb5_gss_get_mic_iov_length(minor_status, ctx->gssc, qop_req, iov,
1309*7f2fe78bSCy Schubert iov_count);
1310*7f2fe78bSCy Schubert }
1311