xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/iakerb.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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, &times);
556*7f2fe78bSCy Schubert             kg_cred_set_initial_refresh(ctx->k5c, cred, &times);
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, &times);
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