1178825Sdfr/*
2233294Sstas * Copyright (c) 2006 - 2008 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of KTH nor the names of its contributors may be
18178825Sdfr *    used to endorse or promote products derived from this software without
19178825Sdfr *    specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22178825Sdfr * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24178825Sdfr * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25178825Sdfr * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26178825Sdfr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27178825Sdfr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28178825Sdfr * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29178825Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30178825Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31178825Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "krb5/gsskrb5_locl.h"
35178825Sdfr#include <err.h>
36178825Sdfr#include <getarg.h>
37233294Sstas#include <gssapi.h>
38233294Sstas#include <gssapi_krb5.h>
39233294Sstas#include <gssapi_spnego.h>
40233294Sstas#include <gssapi_ntlm.h>
41178825Sdfr#include "test_common.h"
42178825Sdfr
43178825Sdfrstatic char *type_string;
44178825Sdfrstatic char *mech_string;
45178825Sdfrstatic char *ret_mech_string;
46233294Sstasstatic char *client_name;
47233294Sstasstatic char *client_password;
48178825Sdfrstatic int dns_canon_flag = -1;
49178825Sdfrstatic int mutual_auth_flag = 0;
50178825Sdfrstatic int dce_style_flag = 0;
51178825Sdfrstatic int wrapunwrap_flag = 0;
52233294Sstasstatic int iov_flag = 0;
53178825Sdfrstatic int getverifymic_flag = 0;
54178825Sdfrstatic int deleg_flag = 0;
55233294Sstasstatic int policy_deleg_flag = 0;
56233294Sstasstatic int server_no_deleg_flag = 0;
57233294Sstasstatic int ei_flag = 0;
58233294Sstasstatic char *gsskrb5_acceptor_identity = NULL;
59233294Sstasstatic char *session_enctype_string = NULL;
60233294Sstasstatic int client_time_offset = 0;
61233294Sstasstatic int server_time_offset = 0;
62233294Sstasstatic int max_loops = 0;
63233294Sstasstatic char *limit_enctype_string = NULL;
64178825Sdfrstatic int version_flag = 0;
65178825Sdfrstatic int verbose_flag = 0;
66178825Sdfrstatic int help_flag	= 0;
67178825Sdfr
68233294Sstasstatic krb5_context context;
69233294Sstasstatic krb5_enctype limit_enctype = 0;
70233294Sstas
71178825Sdfrstatic struct {
72178825Sdfr    const char *name;
73233294Sstas    gss_OID oid;
74178825Sdfr} o2n[] = {
75233294Sstas    { "krb5", NULL /* GSS_KRB5_MECHANISM */ },
76233294Sstas    { "spnego", NULL /* GSS_SPNEGO_MECHANISM */ },
77233294Sstas    { "ntlm", NULL /* GSS_NTLM_MECHANISM */ },
78233294Sstas    { "sasl-digest-md5", NULL /* GSS_SASL_DIGEST_MD5_MECHANISM */ }
79178825Sdfr};
80178825Sdfr
81233294Sstasstatic void
82233294Sstasinit_o2n(void)
83233294Sstas{
84233294Sstas    o2n[0].oid = GSS_KRB5_MECHANISM;
85233294Sstas    o2n[1].oid = GSS_SPNEGO_MECHANISM;
86233294Sstas    o2n[2].oid = GSS_NTLM_MECHANISM;
87233294Sstas    o2n[3].oid = GSS_SASL_DIGEST_MD5_MECHANISM;
88233294Sstas}
89233294Sstas
90178825Sdfrstatic gss_OID
91178825Sdfrstring_to_oid(const char *name)
92178825Sdfr{
93178825Sdfr    int i;
94178825Sdfr    for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
95178825Sdfr	if (strcasecmp(name, o2n[i].name) == 0)
96233294Sstas	    return o2n[i].oid;
97233294Sstas    errx(1, "name '%s' not unknown", name);
98178825Sdfr}
99178825Sdfr
100178825Sdfrstatic const char *
101178825Sdfroid_to_string(const gss_OID oid)
102178825Sdfr{
103178825Sdfr    int i;
104178825Sdfr    for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
105233294Sstas	if (gss_oid_equal(oid, o2n[i].oid))
106178825Sdfr	    return o2n[i].name;
107178825Sdfr    return "unknown oid";
108178825Sdfr}
109178825Sdfr
110178825Sdfrstatic void
111178825Sdfrloop(gss_OID mechoid,
112178825Sdfr     gss_OID nameoid, const char *target,
113178825Sdfr     gss_cred_id_t init_cred,
114178825Sdfr     gss_ctx_id_t *sctx, gss_ctx_id_t *cctx,
115233294Sstas     gss_OID *actual_mech,
116178825Sdfr     gss_cred_id_t *deleg_cred)
117178825Sdfr{
118178825Sdfr    int server_done = 0, client_done = 0;
119233294Sstas    int num_loops = 0;
120178825Sdfr    OM_uint32 maj_stat, min_stat;
121178825Sdfr    gss_name_t gss_target_name;
122178825Sdfr    gss_buffer_desc input_token, output_token;
123178825Sdfr    OM_uint32 flags = 0, ret_cflags, ret_sflags;
124233294Sstas    gss_OID actual_mech_client;
125233294Sstas    gss_OID actual_mech_server;
126178825Sdfr
127178825Sdfr    *actual_mech = GSS_C_NO_OID;
128178825Sdfr
129178825Sdfr    flags |= GSS_C_INTEG_FLAG;
130178825Sdfr    flags |= GSS_C_CONF_FLAG;
131178825Sdfr
132178825Sdfr    if (mutual_auth_flag)
133178825Sdfr	flags |= GSS_C_MUTUAL_FLAG;
134178825Sdfr    if (dce_style_flag)
135178825Sdfr	flags |= GSS_C_DCE_STYLE;
136178825Sdfr    if (deleg_flag)
137178825Sdfr	flags |= GSS_C_DELEG_FLAG;
138233294Sstas    if (policy_deleg_flag)
139233294Sstas	flags |= GSS_C_DELEG_POLICY_FLAG;
140178825Sdfr
141178825Sdfr    input_token.value = rk_UNCONST(target);
142178825Sdfr    input_token.length = strlen(target);
143178825Sdfr
144178825Sdfr    maj_stat = gss_import_name(&min_stat,
145178825Sdfr			       &input_token,
146178825Sdfr			       nameoid,
147178825Sdfr			       &gss_target_name);
148178825Sdfr    if (GSS_ERROR(maj_stat))
149178825Sdfr	err(1, "import name creds failed with: %d", maj_stat);
150178825Sdfr
151178825Sdfr    input_token.length = 0;
152178825Sdfr    input_token.value = NULL;
153178825Sdfr
154178825Sdfr    while (!server_done || !client_done) {
155233294Sstas	num_loops++;
156178825Sdfr
157233294Sstas	gsskrb5_set_time_offset(client_time_offset);
158233294Sstas
159178825Sdfr	maj_stat = gss_init_sec_context(&min_stat,
160178825Sdfr					init_cred,
161178825Sdfr					cctx,
162178825Sdfr					gss_target_name,
163233294Sstas					mechoid,
164178825Sdfr					flags,
165233294Sstas					0,
166178825Sdfr					NULL,
167178825Sdfr					&input_token,
168178825Sdfr					&actual_mech_client,
169178825Sdfr					&output_token,
170178825Sdfr					&ret_cflags,
171178825Sdfr					NULL);
172178825Sdfr	if (GSS_ERROR(maj_stat))
173178825Sdfr	    errx(1, "init_sec_context: %s",
174178825Sdfr		 gssapi_err(maj_stat, min_stat, mechoid));
175178825Sdfr	if (maj_stat & GSS_S_CONTINUE_NEEDED)
176178825Sdfr	    ;
177178825Sdfr	else
178178825Sdfr	    client_done = 1;
179178825Sdfr
180233294Sstas	gsskrb5_get_time_offset(&client_time_offset);
181233294Sstas
182178825Sdfr	if (client_done && server_done)
183178825Sdfr	    break;
184178825Sdfr
185178825Sdfr	if (input_token.length != 0)
186178825Sdfr	    gss_release_buffer(&min_stat, &input_token);
187178825Sdfr
188233294Sstas	gsskrb5_set_time_offset(server_time_offset);
189233294Sstas
190178825Sdfr	maj_stat = gss_accept_sec_context(&min_stat,
191178825Sdfr					  sctx,
192178825Sdfr					  GSS_C_NO_CREDENTIAL,
193178825Sdfr					  &output_token,
194178825Sdfr					  GSS_C_NO_CHANNEL_BINDINGS,
195178825Sdfr					  NULL,
196178825Sdfr					  &actual_mech_server,
197178825Sdfr					  &input_token,
198178825Sdfr					  &ret_sflags,
199178825Sdfr					  NULL,
200178825Sdfr					  deleg_cred);
201178825Sdfr	if (GSS_ERROR(maj_stat))
202178825Sdfr		errx(1, "accept_sec_context: %s",
203178825Sdfr		     gssapi_err(maj_stat, min_stat, actual_mech_server));
204178825Sdfr
205233294Sstas	gsskrb5_get_time_offset(&server_time_offset);
206178825Sdfr
207178825Sdfr	if (output_token.length != 0)
208178825Sdfr	    gss_release_buffer(&min_stat, &output_token);
209178825Sdfr
210178825Sdfr	if (maj_stat & GSS_S_CONTINUE_NEEDED)
211178825Sdfr	    ;
212178825Sdfr	else
213178825Sdfr	    server_done = 1;
214233294Sstas    }
215178825Sdfr    if (output_token.length != 0)
216178825Sdfr	gss_release_buffer(&min_stat, &output_token);
217178825Sdfr    if (input_token.length != 0)
218178825Sdfr	gss_release_buffer(&min_stat, &input_token);
219178825Sdfr    gss_release_name(&min_stat, &gss_target_name);
220178825Sdfr
221233294Sstas    if (deleg_flag || policy_deleg_flag) {
222233294Sstas	if (server_no_deleg_flag) {
223233294Sstas	    if (*deleg_cred != GSS_C_NO_CREDENTIAL)
224233294Sstas		errx(1, "got delegated cred but didn't expect one");
225233294Sstas	} else if (*deleg_cred == GSS_C_NO_CREDENTIAL)
226233294Sstas	    errx(1, "asked for delegarated cred but did get one");
227233294Sstas    } else if (*deleg_cred != GSS_C_NO_CREDENTIAL)
228233294Sstas	  errx(1, "got deleg_cred cred but didn't ask");
229233294Sstas
230178825Sdfr    if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0)
231178825Sdfr	errx(1, "mech mismatch");
232178825Sdfr    *actual_mech = actual_mech_server;
233233294Sstas
234233294Sstas    if (max_loops && num_loops > max_loops)
235233294Sstas	errx(1, "num loops %d was lager then max loops %d",
236233294Sstas	     num_loops, max_loops);
237233294Sstas
238233294Sstas    if (verbose_flag) {
239233294Sstas	printf("server time offset: %d\n", server_time_offset);
240233294Sstas	printf("client time offset: %d\n", client_time_offset);
241233294Sstas	printf("num loops %d\n", num_loops);
242233294Sstas    }
243178825Sdfr}
244178825Sdfr
245178825Sdfrstatic void
246233294Sstaswrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
247178825Sdfr{
248178825Sdfr    gss_buffer_desc input_token, output_token, output_token2;
249178825Sdfr    OM_uint32 min_stat, maj_stat;
250178825Sdfr    gss_qop_t qop_state;
251178825Sdfr    int conf_state;
252178825Sdfr
253178825Sdfr    input_token.value = "foo";
254178825Sdfr    input_token.length = 3;
255178825Sdfr
256178825Sdfr    maj_stat = gss_wrap(&min_stat, cctx, flags, 0, &input_token,
257178825Sdfr			&conf_state, &output_token);
258178825Sdfr    if (maj_stat != GSS_S_COMPLETE)
259178825Sdfr	errx(1, "gss_wrap failed: %s",
260178825Sdfr	     gssapi_err(maj_stat, min_stat, mechoid));
261178825Sdfr
262178825Sdfr    maj_stat = gss_unwrap(&min_stat, sctx, &output_token,
263178825Sdfr			  &output_token2, &conf_state, &qop_state);
264178825Sdfr    if (maj_stat != GSS_S_COMPLETE)
265178825Sdfr	errx(1, "gss_unwrap failed: %s",
266178825Sdfr	     gssapi_err(maj_stat, min_stat, mechoid));
267233294Sstas
268233294Sstas    gss_release_buffer(&min_stat, &output_token);
269233294Sstas    gss_release_buffer(&min_stat, &output_token2);
270233294Sstas
271233294Sstas#if 0 /* doesn't work for NTLM yet */
272233294Sstas    if (!!conf_state != !!flags)
273233294Sstas	errx(1, "conf_state mismatch");
274233294Sstas#endif
275178825Sdfr}
276178825Sdfr
277233294Sstas#define USE_CONF		1
278233294Sstas#define USE_HEADER_ONLY		2
279233294Sstas#define USE_SIGN_ONLY		4
280233294Sstas#define FORCE_IOV		8
281233294Sstas
282178825Sdfrstatic void
283233294Sstaswrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
284233294Sstas{
285233294Sstas    krb5_data token, header, trailer;
286233294Sstas    OM_uint32 min_stat, maj_stat;
287233294Sstas    gss_qop_t qop_state;
288233294Sstas    int conf_state, conf_state2;
289233294Sstas    gss_iov_buffer_desc iov[6];
290233294Sstas    unsigned char *p;
291233294Sstas    int iov_len;
292233294Sstas    char header_data[9] = "ABCheader";
293233294Sstas    char trailer_data[10] = "trailerXYZ";
294233294Sstas
295233294Sstas    char token_data[16] = "0123456789abcdef";
296233294Sstas
297233294Sstas    memset(&iov, 0, sizeof(iov));
298233294Sstas
299233294Sstas    if (flags & USE_SIGN_ONLY) {
300233294Sstas	header.data = header_data;
301233294Sstas	header.length = 9;
302233294Sstas	trailer.data = trailer_data;
303233294Sstas	trailer.length = 10;
304233294Sstas    } else {
305233294Sstas	header.data = NULL;
306233294Sstas	header.length = 0;
307233294Sstas	trailer.data = NULL;
308233294Sstas	trailer.length = 0;
309233294Sstas    }
310233294Sstas
311233294Sstas    token.data = token_data;
312233294Sstas    token.length = 16;
313233294Sstas
314233294Sstas    iov_len = sizeof(iov)/sizeof(iov[0]);
315233294Sstas
316233294Sstas    memset(iov, 0, sizeof(iov));
317233294Sstas
318233294Sstas    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
319233294Sstas
320233294Sstas    if (header.length != 0) {
321233294Sstas	iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
322233294Sstas	iov[1].buffer.length = header.length;
323233294Sstas	iov[1].buffer.value = header.data;
324233294Sstas    } else {
325233294Sstas	iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
326233294Sstas	iov[1].buffer.length = 0;
327233294Sstas	iov[1].buffer.value = NULL;
328233294Sstas    }
329233294Sstas    iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
330233294Sstas    iov[2].buffer.length = token.length;
331233294Sstas    iov[2].buffer.value = token.data;
332233294Sstas    if (trailer.length != 0) {
333233294Sstas	iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
334233294Sstas	iov[3].buffer.length = trailer.length;
335233294Sstas	iov[3].buffer.value = trailer.data;
336233294Sstas    } else {
337233294Sstas	iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
338233294Sstas	iov[3].buffer.length = 0;
339233294Sstas	iov[3].buffer.value = NULL;
340233294Sstas    }
341233294Sstas    if (dce_style_flag) {
342233294Sstas	iov[4].type = GSS_IOV_BUFFER_TYPE_EMPTY;
343233294Sstas    } else {
344233294Sstas	iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
345233294Sstas    }
346233294Sstas    iov[4].buffer.length = 0;
347233294Sstas    iov[4].buffer.value = 0;
348233294Sstas    if (dce_style_flag) {
349233294Sstas	iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
350233294Sstas    } else if (flags & USE_HEADER_ONLY) {
351233294Sstas	iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
352233294Sstas    } else {
353233294Sstas	iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
354233294Sstas    }
355233294Sstas    iov[5].buffer.length = 0;
356233294Sstas    iov[5].buffer.value = 0;
357233294Sstas
358233294Sstas    maj_stat = gss_wrap_iov(&min_stat, cctx, dce_style_flag || flags & USE_CONF, 0, &conf_state,
359233294Sstas			    iov, iov_len);
360233294Sstas    if (maj_stat != GSS_S_COMPLETE)
361233294Sstas	errx(1, "gss_wrap_iov failed");
362233294Sstas
363233294Sstas    token.length =
364233294Sstas	iov[0].buffer.length +
365233294Sstas	iov[1].buffer.length +
366233294Sstas	iov[2].buffer.length +
367233294Sstas	iov[3].buffer.length +
368233294Sstas	iov[4].buffer.length +
369233294Sstas	iov[5].buffer.length;
370233294Sstas    token.data = emalloc(token.length);
371233294Sstas
372233294Sstas    p = token.data;
373233294Sstas    memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
374233294Sstas    p += iov[0].buffer.length;
375233294Sstas    memcpy(p, iov[1].buffer.value, iov[1].buffer.length);
376233294Sstas    p += iov[1].buffer.length;
377233294Sstas    memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
378233294Sstas    p += iov[2].buffer.length;
379233294Sstas    memcpy(p, iov[3].buffer.value, iov[3].buffer.length);
380233294Sstas    p += iov[3].buffer.length;
381233294Sstas    memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
382233294Sstas    p += iov[4].buffer.length;
383233294Sstas    memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
384233294Sstas    p += iov[5].buffer.length;
385233294Sstas
386233294Sstas    assert(p - ((unsigned char *)token.data) == token.length);
387233294Sstas
388233294Sstas    if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) {
389233294Sstas	gss_buffer_desc input, output;
390233294Sstas
391233294Sstas	input.value = token.data;
392233294Sstas	input.length = token.length;
393233294Sstas
394233294Sstas	maj_stat = gss_unwrap(&min_stat, sctx, &input,
395233294Sstas			      &output, &conf_state2, &qop_state);
396233294Sstas
397233294Sstas	if (maj_stat != GSS_S_COMPLETE)
398233294Sstas	    errx(1, "gss_unwrap from gss_wrap_iov failed: %s",
399233294Sstas		 gssapi_err(maj_stat, min_stat, mechoid));
400233294Sstas
401233294Sstas	gss_release_buffer(&min_stat, &output);
402233294Sstas    } else {
403233294Sstas	maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state,
404233294Sstas				  iov, iov_len);
405233294Sstas
406233294Sstas	if (maj_stat != GSS_S_COMPLETE)
407233294Sstas	    errx(1, "gss_unwrap_iov failed: %x %s", flags,
408233294Sstas		 gssapi_err(maj_stat, min_stat, mechoid));
409233294Sstas
410233294Sstas    }
411233294Sstas    if (conf_state2 != conf_state)
412233294Sstas	errx(1, "conf state wrong for iov: %x", flags);
413233294Sstas
414233294Sstas
415233294Sstas    free(token.data);
416233294Sstas}
417233294Sstas
418233294Sstasstatic void
419178825Sdfrgetverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)
420178825Sdfr{
421178825Sdfr    gss_buffer_desc input_token, output_token;
422178825Sdfr    OM_uint32 min_stat, maj_stat;
423178825Sdfr    gss_qop_t qop_state;
424178825Sdfr
425178825Sdfr    input_token.value = "bar";
426178825Sdfr    input_token.length = 3;
427178825Sdfr
428178825Sdfr    maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token,
429178825Sdfr			   &output_token);
430178825Sdfr    if (maj_stat != GSS_S_COMPLETE)
431178825Sdfr	errx(1, "gss_get_mic failed: %s",
432178825Sdfr	     gssapi_err(maj_stat, min_stat, mechoid));
433178825Sdfr
434178825Sdfr    maj_stat = gss_verify_mic(&min_stat, sctx, &input_token,
435178825Sdfr			      &output_token, &qop_state);
436178825Sdfr    if (maj_stat != GSS_S_COMPLETE)
437178825Sdfr	errx(1, "gss_verify_mic failed: %s",
438178825Sdfr	     gssapi_err(maj_stat, min_stat, mechoid));
439233294Sstas
440233294Sstas    gss_release_buffer(&min_stat, &output_token);
441178825Sdfr}
442178825Sdfr
443233294Sstasstatic void
444233294Sstasempty_release(void)
445233294Sstas{
446233294Sstas    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
447233294Sstas    gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
448233294Sstas    gss_name_t name = GSS_C_NO_NAME;
449233294Sstas    gss_OID_set oidset = GSS_C_NO_OID_SET;
450233294Sstas    OM_uint32 junk;
451178825Sdfr
452233294Sstas    gss_delete_sec_context(&junk, &ctx, NULL);
453233294Sstas    gss_release_cred(&junk, &cred);
454233294Sstas    gss_release_name(&junk, &name);
455233294Sstas    gss_release_oid_set(&junk, &oidset);
456233294Sstas}
457233294Sstas
458178825Sdfr/*
459178825Sdfr *
460178825Sdfr */
461178825Sdfr
462178825Sdfrstatic struct getargs args[] = {
463178825Sdfr    {"name-type",0,	arg_string, &type_string,  "type of name", NULL },
464178825Sdfr    {"mech-type",0,	arg_string, &mech_string,  "type of mech", NULL },
465178825Sdfr    {"ret-mech-type",0,	arg_string, &ret_mech_string,
466178825Sdfr     "type of return mech", NULL },
467233294Sstas    {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag,
468178825Sdfr     "use dns to canonicalize", NULL },
469178825Sdfr    {"mutual-auth",0,	arg_flag,	&mutual_auth_flag,"mutual auth", NULL },
470233294Sstas    {"client-name", 0,  arg_string,     &client_name, "client name", NULL },
471233294Sstas    {"client-password", 0,  arg_string, &client_password, "client password", NULL },
472233294Sstas    {"limit-enctype",0,	arg_string,	&limit_enctype_string, "enctype", NULL },
473178825Sdfr    {"dce-style",0,	arg_flag,	&dce_style_flag, "dce-style", NULL },
474178825Sdfr    {"wrapunwrap",0,	arg_flag,	&wrapunwrap_flag, "wrap/unwrap", NULL },
475233294Sstas    {"iov", 0, 		arg_flag,	&iov_flag, "wrap/unwrap iov", NULL },
476233294Sstas    {"getverifymic",0,	arg_flag,	&getverifymic_flag,
477178825Sdfr     "get and verify mic", NULL },
478178825Sdfr    {"delegate",0,	arg_flag,	&deleg_flag, "delegate credential", NULL },
479233294Sstas    {"policy-delegate",0,	arg_flag,	&policy_deleg_flag, "policy delegate credential", NULL },
480233294Sstas    {"server-no-delegate",0,	arg_flag,	&server_no_deleg_flag,
481233294Sstas     "server should get a credential", NULL },
482233294Sstas    {"export-import-cred",0,	arg_flag,	&ei_flag, "test export/import cred", NULL },
483233294Sstas    {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL },
484233294Sstas    {"session-enctype",	0, arg_string,	&session_enctype_string, "enctype", NULL },
485233294Sstas    {"client-time-offset",	0, arg_integer,	&client_time_offset, "time", NULL },
486233294Sstas    {"server-time-offset",	0, arg_integer,	&server_time_offset, "time", NULL },
487233294Sstas    {"max-loops",	0, arg_integer,	&max_loops, "time", NULL },
488178825Sdfr    {"version",	0,	arg_flag,	&version_flag, "print version", NULL },
489178825Sdfr    {"verbose",	'v',	arg_flag,	&verbose_flag, "verbose", NULL },
490178825Sdfr    {"help",	0,	arg_flag,	&help_flag,  NULL, NULL }
491178825Sdfr};
492178825Sdfr
493178825Sdfrstatic void
494178825Sdfrusage (int ret)
495178825Sdfr{
496178825Sdfr    arg_printusage (args, sizeof(args)/sizeof(*args),
497178825Sdfr		    NULL, "service@host");
498178825Sdfr    exit (ret);
499178825Sdfr}
500178825Sdfr
501178825Sdfrint
502178825Sdfrmain(int argc, char **argv)
503178825Sdfr{
504178825Sdfr    int optind = 0;
505178825Sdfr    OM_uint32 min_stat, maj_stat;
506178825Sdfr    gss_ctx_id_t cctx, sctx;
507178825Sdfr    void *ctx;
508233294Sstas    gss_OID nameoid, mechoid, actual_mech, actual_mech2;
509233294Sstas    gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL, deleg_cred = GSS_C_NO_CREDENTIAL;
510233294Sstas    gss_name_t cname = GSS_C_NO_NAME;
511233294Sstas    gss_buffer_desc credential_data = GSS_C_EMPTY_BUFFER;
512178825Sdfr
513178825Sdfr    setprogname(argv[0]);
514178825Sdfr
515233294Sstas    init_o2n();
516233294Sstas
517233294Sstas    if (krb5_init_context(&context))
518233294Sstas	errx(1, "krb5_init_context");
519233294Sstas
520178825Sdfr    cctx = sctx = GSS_C_NO_CONTEXT;
521178825Sdfr
522178825Sdfr    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))
523178825Sdfr	usage(1);
524233294Sstas
525178825Sdfr    if (help_flag)
526178825Sdfr	usage (0);
527178825Sdfr
528178825Sdfr    if(version_flag){
529178825Sdfr	print_version(NULL);
530178825Sdfr	exit(0);
531178825Sdfr    }
532178825Sdfr
533178825Sdfr    argc -= optind;
534178825Sdfr    argv += optind;
535178825Sdfr
536178825Sdfr    if (argc != 1)
537178825Sdfr	usage(1);
538178825Sdfr
539178825Sdfr    if (dns_canon_flag != -1)
540178825Sdfr	gsskrb5_set_dns_canonicalize(dns_canon_flag);
541178825Sdfr
542178825Sdfr    if (type_string == NULL)
543178825Sdfr	nameoid = GSS_C_NT_HOSTBASED_SERVICE;
544178825Sdfr    else if (strcmp(type_string, "hostbased-service") == 0)
545178825Sdfr	nameoid = GSS_C_NT_HOSTBASED_SERVICE;
546178825Sdfr    else if (strcmp(type_string, "krb5-principal-name") == 0)
547178825Sdfr	nameoid = GSS_KRB5_NT_PRINCIPAL_NAME;
548178825Sdfr    else
549178825Sdfr	errx(1, "%s not suppported", type_string);
550178825Sdfr
551178825Sdfr    if (mech_string == NULL)
552178825Sdfr	mechoid = GSS_KRB5_MECHANISM;
553233294Sstas    else
554178825Sdfr	mechoid = string_to_oid(mech_string);
555178825Sdfr
556233294Sstas    if (gsskrb5_acceptor_identity) {
557233294Sstas	maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity);
558233294Sstas	if (maj_stat)
559233294Sstas	    errx(1, "gsskrb5_acceptor_identity: %s",
560233294Sstas		 gssapi_err(maj_stat, 0, GSS_C_NO_OID));
561233294Sstas    }
562233294Sstas
563233294Sstas    if (client_password) {
564233294Sstas	credential_data.value = client_password;
565233294Sstas	credential_data.length = strlen(client_password);
566233294Sstas    }
567233294Sstas
568233294Sstas    if (client_name) {
569233294Sstas	gss_buffer_desc cn;
570233294Sstas
571233294Sstas	cn.value = client_name;
572233294Sstas	cn.length = strlen(client_name);
573233294Sstas
574233294Sstas	maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname);
575233294Sstas	if (maj_stat)
576233294Sstas	    errx(1, "gss_import_name: %s",
577233294Sstas		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
578233294Sstas    }
579233294Sstas
580233294Sstas    if (client_password) {
581233294Sstas	maj_stat = gss_acquire_cred_with_password(&min_stat,
582233294Sstas						  cname,
583233294Sstas						  &credential_data,
584233294Sstas						  GSS_C_INDEFINITE,
585233294Sstas						  GSS_C_NO_OID_SET,
586233294Sstas						  GSS_C_INITIATE,
587233294Sstas						  &client_cred,
588233294Sstas						  NULL,
589233294Sstas						  NULL);
590233294Sstas	if (GSS_ERROR(maj_stat))
591233294Sstas	    errx(1, "gss_acquire_cred_with_password: %s",
592233294Sstas		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
593233294Sstas    } else {
594233294Sstas	maj_stat = gss_acquire_cred(&min_stat,
595233294Sstas				    cname,
596233294Sstas				    GSS_C_INDEFINITE,
597233294Sstas				    GSS_C_NO_OID_SET,
598233294Sstas				    GSS_C_INITIATE,
599233294Sstas				    &client_cred,
600233294Sstas				    NULL,
601233294Sstas				    NULL);
602233294Sstas	if (GSS_ERROR(maj_stat))
603233294Sstas	    errx(1, "gss_acquire_cred: %s",
604233294Sstas		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
605233294Sstas    }
606233294Sstas
607233294Sstas    if (limit_enctype_string) {
608233294Sstas	krb5_error_code ret;
609233294Sstas
610233294Sstas	ret = krb5_string_to_enctype(context,
611233294Sstas				     limit_enctype_string,
612233294Sstas				     &limit_enctype);
613233294Sstas	if (ret)
614233294Sstas	    krb5_err(context, 1, ret, "krb5_string_to_enctype");
615233294Sstas    }
616233294Sstas
617233294Sstas
618233294Sstas    if (limit_enctype) {
619233294Sstas	if (client_cred == NULL)
620233294Sstas	    errx(1, "client_cred missing");
621233294Sstas
622233294Sstas	maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred,
623233294Sstas						   1, &limit_enctype);
624233294Sstas	if (maj_stat)
625233294Sstas	    errx(1, "gss_krb5_set_allowable_enctypes: %s",
626233294Sstas		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
627233294Sstas    }
628233294Sstas
629233294Sstas    loop(mechoid, nameoid, argv[0], client_cred,
630178825Sdfr	 &sctx, &cctx, &actual_mech, &deleg_cred);
631233294Sstas
632178825Sdfr    if (verbose_flag)
633178825Sdfr	printf("resulting mech: %s\n", oid_to_string(actual_mech));
634178825Sdfr
635178825Sdfr    if (ret_mech_string) {
636178825Sdfr	gss_OID retoid;
637178825Sdfr
638178825Sdfr	retoid = string_to_oid(ret_mech_string);
639178825Sdfr
640178825Sdfr	if (gss_oid_equal(retoid, actual_mech) == 0)
641233294Sstas	    errx(1, "actual_mech mech is not the expected type %s",
642178825Sdfr		 ret_mech_string);
643178825Sdfr    }
644178825Sdfr
645178825Sdfr    /* XXX should be actual_mech */
646233294Sstas    if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) {
647233294Sstas	time_t time;
648178825Sdfr	gss_buffer_desc authz_data;
649178825Sdfr	gss_buffer_desc in, out1, out2;
650178825Sdfr	krb5_keyblock *keyblock, *keyblock2;
651178825Sdfr	krb5_timestamp now;
652178825Sdfr	krb5_error_code ret;
653178825Sdfr
654233294Sstas	ret = krb5_timeofday(context, &now);
655178825Sdfr	if (ret)
656233294Sstas	    errx(1, "krb5_timeofday failed");
657178825Sdfr
658178825Sdfr	/* client */
659178825Sdfr	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
660178825Sdfr						     &cctx,
661178825Sdfr						     1, /* version */
662178825Sdfr						     &ctx);
663178825Sdfr	if (maj_stat != GSS_S_COMPLETE)
664233294Sstas	    errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
665233294Sstas		 gssapi_err(maj_stat, min_stat, actual_mech));
666233294Sstas
667233294Sstas
668178825Sdfr	maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx);
669178825Sdfr	if (maj_stat != GSS_S_COMPLETE)
670178825Sdfr	    errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
671178825Sdfr		     gssapi_err(maj_stat, min_stat, actual_mech));
672233294Sstas
673178825Sdfr	/* server */
674178825Sdfr	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
675178825Sdfr						     &sctx,
676178825Sdfr						     1, /* version */
677178825Sdfr						     &ctx);
678178825Sdfr	if (maj_stat != GSS_S_COMPLETE)
679178825Sdfr	    errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
680178825Sdfr		     gssapi_err(maj_stat, min_stat, actual_mech));
681178825Sdfr	maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx);
682178825Sdfr	if (maj_stat != GSS_S_COMPLETE)
683178825Sdfr	    errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
684178825Sdfr		     gssapi_err(maj_stat, min_stat, actual_mech));
685178825Sdfr
686178825Sdfr 	maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
687178825Sdfr							     sctx,
688178825Sdfr							     &time);
689178825Sdfr	if (maj_stat != GSS_S_COMPLETE)
690178825Sdfr	    errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
691178825Sdfr		     gssapi_err(maj_stat, min_stat, actual_mech));
692178825Sdfr
693233294Sstas	if (time > now)
694178825Sdfr	    errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
695233294Sstas		 "time authtime is before now: %ld %ld",
696233294Sstas		 (long)time, (long)now);
697178825Sdfr
698178825Sdfr 	maj_stat = gsskrb5_extract_service_keyblock(&min_stat,
699178825Sdfr						    sctx,
700178825Sdfr						    &keyblock);
701178825Sdfr	if (maj_stat != GSS_S_COMPLETE)
702178825Sdfr	    errx(1, "gsskrb5_export_service_keyblock failed: %s",
703178825Sdfr		     gssapi_err(maj_stat, min_stat, actual_mech));
704178825Sdfr
705178825Sdfr	krb5_free_keyblock(context, keyblock);
706178825Sdfr
707178825Sdfr 	maj_stat = gsskrb5_get_subkey(&min_stat,
708178825Sdfr				      sctx,
709178825Sdfr				      &keyblock);
710233294Sstas	if (maj_stat != GSS_S_COMPLETE
711178825Sdfr	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
712178825Sdfr	    errx(1, "gsskrb5_get_subkey server failed: %s",
713178825Sdfr		     gssapi_err(maj_stat, min_stat, actual_mech));
714178825Sdfr
715178825Sdfr	if (maj_stat != GSS_S_COMPLETE)
716178825Sdfr	    keyblock = NULL;
717233294Sstas	else if (limit_enctype && keyblock->keytype != limit_enctype)
718233294Sstas	    errx(1, "gsskrb5_get_subkey wrong enctype");
719233294Sstas
720178825Sdfr 	maj_stat = gsskrb5_get_subkey(&min_stat,
721178825Sdfr				      cctx,
722178825Sdfr				      &keyblock2);
723233294Sstas	if (maj_stat != GSS_S_COMPLETE
724178825Sdfr	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
725178825Sdfr	    errx(1, "gsskrb5_get_subkey client failed: %s",
726178825Sdfr		     gssapi_err(maj_stat, min_stat, actual_mech));
727178825Sdfr
728178825Sdfr	if (maj_stat != GSS_S_COMPLETE)
729178825Sdfr	    keyblock2 = NULL;
730233294Sstas	else if (limit_enctype && keyblock->keytype != limit_enctype)
731233294Sstas	    errx(1, "gsskrb5_get_subkey wrong enctype");
732178825Sdfr
733178825Sdfr	if (keyblock || keyblock2) {
734178825Sdfr	    if (keyblock == NULL)
735178825Sdfr		errx(1, "server missing token keyblock");
736178825Sdfr	    if (keyblock2 == NULL)
737178825Sdfr		errx(1, "client missing token keyblock");
738178825Sdfr
739178825Sdfr	    if (keyblock->keytype != keyblock2->keytype)
740178825Sdfr		errx(1, "enctype mismatch");
741178825Sdfr	    if (keyblock->keyvalue.length != keyblock2->keyvalue.length)
742178825Sdfr		errx(1, "key length mismatch");
743233294Sstas	    if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data,
744178825Sdfr		       keyblock2->keyvalue.length) != 0)
745178825Sdfr		errx(1, "key data mismatch");
746178825Sdfr	}
747178825Sdfr
748233294Sstas	if (session_enctype_string) {
749233294Sstas	    krb5_enctype enctype;
750233294Sstas
751233294Sstas	    ret = krb5_string_to_enctype(context,
752233294Sstas					 session_enctype_string,
753233294Sstas					 &enctype);
754233294Sstas
755233294Sstas	    if (ret)
756233294Sstas		krb5_err(context, 1, ret, "krb5_string_to_enctype");
757233294Sstas
758233294Sstas	    if (enctype != keyblock->keytype)
759233294Sstas		errx(1, "keytype is not the expected %d != %d",
760233294Sstas		     (int)enctype, (int)keyblock2->keytype);
761233294Sstas	}
762233294Sstas
763178825Sdfr	if (keyblock)
764178825Sdfr	    krb5_free_keyblock(context, keyblock);
765178825Sdfr	if (keyblock2)
766178825Sdfr	    krb5_free_keyblock(context, keyblock2);
767178825Sdfr
768178825Sdfr 	maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
769178825Sdfr						sctx,
770178825Sdfr						&keyblock);
771233294Sstas	if (maj_stat != GSS_S_COMPLETE
772178825Sdfr	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
773178825Sdfr	    errx(1, "gsskrb5_get_initiator_subkey failed: %s",
774178825Sdfr		     gssapi_err(maj_stat, min_stat, actual_mech));
775178825Sdfr
776233294Sstas	if (maj_stat == GSS_S_COMPLETE) {
777233294Sstas
778233294Sstas	    if (limit_enctype && keyblock->keytype != limit_enctype)
779233294Sstas		errx(1, "gsskrb5_get_initiator_subkey wrong enctype");
780178825Sdfr	    krb5_free_keyblock(context, keyblock);
781233294Sstas	}
782178825Sdfr
783178825Sdfr 	maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
784178825Sdfr							       sctx,
785178825Sdfr							       128,
786178825Sdfr							       &authz_data);
787178825Sdfr	if (maj_stat == GSS_S_COMPLETE)
788178825Sdfr	    gss_release_buffer(&min_stat, &authz_data);
789178825Sdfr
790178825Sdfr
791178825Sdfr	memset(&out1, 0, sizeof(out1));
792178825Sdfr	memset(&out2, 0, sizeof(out2));
793178825Sdfr
794178825Sdfr	in.value = "foo";
795178825Sdfr	in.length = 3;
796178825Sdfr
797233294Sstas	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
798178825Sdfr			  100, &out1);
799233294Sstas	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,
800178825Sdfr			  100, &out2);
801178825Sdfr
802178825Sdfr	if (out1.length != out2.length)
803178825Sdfr	    errx(1, "prf len mismatch");
804178825Sdfr	if (memcmp(out1.value, out2.value, out1.length) != 0)
805178825Sdfr	    errx(1, "prf data mismatch");
806233294Sstas
807178825Sdfr	gss_release_buffer(&min_stat, &out1);
808178825Sdfr
809233294Sstas	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
810178825Sdfr			  100, &out1);
811178825Sdfr
812178825Sdfr	if (out1.length != out2.length)
813178825Sdfr	    errx(1, "prf len mismatch");
814178825Sdfr	if (memcmp(out1.value, out2.value, out1.length) != 0)
815178825Sdfr	    errx(1, "prf data mismatch");
816178825Sdfr
817178825Sdfr	gss_release_buffer(&min_stat, &out1);
818178825Sdfr	gss_release_buffer(&min_stat, &out2);
819178825Sdfr
820178825Sdfr	in.value = "bar";
821178825Sdfr	in.length = 3;
822178825Sdfr
823233294Sstas	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,
824178825Sdfr			  100, &out1);
825233294Sstas	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,
826178825Sdfr			  100, &out2);
827178825Sdfr
828178825Sdfr	if (out1.length != out2.length)
829178825Sdfr	    errx(1, "prf len mismatch");
830178825Sdfr	if (memcmp(out1.value, out2.value, out1.length) != 0)
831178825Sdfr	    errx(1, "prf data mismatch");
832178825Sdfr
833178825Sdfr	gss_release_buffer(&min_stat, &out1);
834178825Sdfr	gss_release_buffer(&min_stat, &out2);
835178825Sdfr
836178825Sdfr	wrapunwrap_flag = 1;
837178825Sdfr	getverifymic_flag = 1;
838178825Sdfr    }
839178825Sdfr
840178825Sdfr    if (wrapunwrap_flag) {
841233294Sstas	wrapunwrap(cctx, sctx, 0, actual_mech);
842233294Sstas	wrapunwrap(cctx, sctx, 1, actual_mech);
843233294Sstas	wrapunwrap(sctx, cctx, 0, actual_mech);
844233294Sstas	wrapunwrap(sctx, cctx, 1, actual_mech);
845178825Sdfr    }
846233294Sstas
847233294Sstas    if (iov_flag) {
848233294Sstas	wrapunwrap_iov(cctx, sctx, 0, actual_mech);
849233294Sstas	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
850233294Sstas	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
851233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
852233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
853233294Sstas
854233294Sstas	wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
855233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
856233294Sstas	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
857233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
858233294Sstas
859233294Sstas	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
860233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
861233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
862233294Sstas
863233294Sstas/* works */
864233294Sstas	wrapunwrap_iov(cctx, sctx, 0, actual_mech);
865233294Sstas	wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
866233294Sstas
867233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
868233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
869233294Sstas
870233294Sstas	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY, actual_mech);
871233294Sstas	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
872233294Sstas
873233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech);
874233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
875233294Sstas
876233294Sstas	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
877233294Sstas	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
878233294Sstas
879233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
880233294Sstas	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
881233294Sstas    }
882233294Sstas
883178825Sdfr    if (getverifymic_flag) {
884178825Sdfr	getverifymic(cctx, sctx, actual_mech);
885178825Sdfr	getverifymic(cctx, sctx, actual_mech);
886178825Sdfr	getverifymic(sctx, cctx, actual_mech);
887178825Sdfr	getverifymic(sctx, cctx, actual_mech);
888178825Sdfr    }
889178825Sdfr
890233294Sstas
891178825Sdfr    gss_delete_sec_context(&min_stat, &cctx, NULL);
892178825Sdfr    gss_delete_sec_context(&min_stat, &sctx, NULL);
893178825Sdfr
894178825Sdfr    if (deleg_cred != GSS_C_NO_CREDENTIAL) {
895233294Sstas	gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
896233294Sstas	gss_buffer_desc cb;
897178825Sdfr
898233294Sstas	if (verbose_flag)
899233294Sstas	    printf("checking actual mech (%s) on delegated cred\n",
900233294Sstas		   oid_to_string(actual_mech));
901233294Sstas	loop(actual_mech, nameoid, argv[0], deleg_cred, &sctx, &cctx, &actual_mech2, &cred2);
902178825Sdfr
903178825Sdfr	gss_delete_sec_context(&min_stat, &cctx, NULL);
904178825Sdfr	gss_delete_sec_context(&min_stat, &sctx, NULL);
905178825Sdfr
906233294Sstas	gss_release_cred(&min_stat, &cred2);
907233294Sstas
908233294Sstas	/* try again using SPNEGO */
909233294Sstas	if (verbose_flag)
910233294Sstas	    printf("checking spnego on delegated cred\n");
911233294Sstas	loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], deleg_cred, &sctx, &cctx,
912233294Sstas	     &actual_mech2, &cred2);
913233294Sstas
914233294Sstas	gss_delete_sec_context(&min_stat, &cctx, NULL);
915233294Sstas	gss_delete_sec_context(&min_stat, &sctx, NULL);
916233294Sstas
917233294Sstas	gss_release_cred(&min_stat, &cred2);
918233294Sstas
919233294Sstas	/* check export/import */
920233294Sstas	if (ei_flag) {
921233294Sstas
922233294Sstas	    maj_stat = gss_export_cred(&min_stat, deleg_cred, &cb);
923233294Sstas	    if (maj_stat != GSS_S_COMPLETE)
924233294Sstas		errx(1, "export failed: %s",
925233294Sstas		     gssapi_err(maj_stat, min_stat, NULL));
926233294Sstas
927233294Sstas	    maj_stat = gss_import_cred(&min_stat, &cb, &cred2);
928233294Sstas	    if (maj_stat != GSS_S_COMPLETE)
929233294Sstas		errx(1, "import failed: %s",
930233294Sstas		     gssapi_err(maj_stat, min_stat, NULL));
931233294Sstas
932233294Sstas	    gss_release_buffer(&min_stat, &cb);
933233294Sstas	    gss_release_cred(&min_stat, &deleg_cred);
934233294Sstas
935233294Sstas	    if (verbose_flag)
936233294Sstas		printf("checking actual mech (%s) on export/imported cred\n",
937233294Sstas		       oid_to_string(actual_mech));
938233294Sstas	    loop(actual_mech, nameoid, argv[0], cred2, &sctx, &cctx,
939233294Sstas		 &actual_mech2, &deleg_cred);
940233294Sstas
941233294Sstas	    gss_release_cred(&min_stat, &deleg_cred);
942233294Sstas
943233294Sstas	    gss_delete_sec_context(&min_stat, &cctx, NULL);
944233294Sstas	    gss_delete_sec_context(&min_stat, &sctx, NULL);
945233294Sstas
946233294Sstas	    /* try again using SPNEGO */
947233294Sstas	    if (verbose_flag)
948233294Sstas		printf("checking SPNEGO on export/imported cred\n");
949233294Sstas	    loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], cred2, &sctx, &cctx,
950233294Sstas		 &actual_mech2, &deleg_cred);
951233294Sstas
952233294Sstas	    gss_release_cred(&min_stat, &deleg_cred);
953233294Sstas
954233294Sstas	    gss_delete_sec_context(&min_stat, &cctx, NULL);
955233294Sstas	    gss_delete_sec_context(&min_stat, &sctx, NULL);
956233294Sstas
957233294Sstas	    gss_release_cred(&min_stat, &cred2);
958233294Sstas
959233294Sstas	} else  {
960233294Sstas	    gss_release_cred(&min_stat, &deleg_cred);
961233294Sstas	}
962233294Sstas
963178825Sdfr    }
964178825Sdfr
965233294Sstas    empty_release();
966233294Sstas
967233294Sstas    krb5_free_context(context);
968233294Sstas
969178825Sdfr    return 0;
970178825Sdfr}
971