1/*
2 * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of KTH nor the names of its contributors may be
20 *    used to endorse or promote products derived from this software without
21 *    specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include "krb5/gsskrb5_locl.h"
37#include <err.h>
38#include <getarg.h>
39#include <gssapi.h>
40#include <gssapi_krb5.h>
41#include <gssapi_spnego.h>
42#include <gssapi_ntlm.h>
43#include <gssapi_spi.h>
44#include "test_common.h"
45
46static char *type_string;
47static char *mech_string;
48static char *cred_string;
49static char *ret_mech_string;
50static char *client_name;
51static char *acceptor_name_string;
52static char *password_string;
53static char *client_password;
54static int dns_canon_flag = -1;
55static int mutual_auth_flag = 0;
56static int dce_style_flag = 0;
57static int wrapunwrap_flag = 0;
58static int iov_flag = 0;
59static int getverifymic_flag = 0;
60static int deleg_flag = 0;
61static int policy_deleg_flag = 0;
62static int server_no_deleg_flag = 0;
63static int import_export_flag = 0;
64static int ei_flag = 0;
65static char *gsskrb5_acceptor_identity = NULL;
66static char *session_enctype_string = NULL;
67static char *gsschannel_appl_data = NULL;
68static int client_time_offset = 0;
69static int server_time_offset = 0;
70static int max_loops = 0;
71static char *limit_enctype_string = NULL;
72static int version_flag = 0;
73static int homedir_flag = 1;
74static int verbose_flag = 0;
75static int help_flag	= 0;
76
77static krb5_context context;
78static krb5_enctype limit_enctype = 0;
79
80static void
81loop(gss_OID mechoid,
82     gss_const_OID nameoid, const char *target,
83     const char *acceptor_name,
84     gss_cred_id_t init_cred,
85     gss_channel_bindings_t bindings,
86     gss_ctx_id_t *sctx, gss_ctx_id_t *cctx,
87     gss_OID *actual_mech,
88     gss_cred_id_t *deleg_cred)
89{
90    int server_done = 0, client_done = 0;
91    int num_loops = 0;
92    OM_uint32 maj_stat, min_stat;
93    gss_name_t gss_target_name,
94	gss_acceptor_name = GSS_C_NO_NAME;
95    gss_buffer_desc input_token, output_token;
96    OM_uint32 flags = 0, ret_cflags, ret_sflags;
97    gss_OID actual_mech_client;
98    gss_OID actual_mech_server;
99    gss_cred_id_t acceptor_cred = GSS_C_NO_CREDENTIAL;
100
101    *actual_mech = GSS_C_NO_OID;
102
103    flags |= GSS_C_INTEG_FLAG;
104    flags |= GSS_C_CONF_FLAG;
105
106    if (mutual_auth_flag)
107	flags |= GSS_C_MUTUAL_FLAG;
108    if (dce_style_flag)
109	flags |= GSS_C_DCE_STYLE;
110    if (deleg_flag)
111	flags |= GSS_C_DELEG_FLAG;
112    if (policy_deleg_flag)
113	flags |= GSS_C_DELEG_POLICY_FLAG;
114
115    input_token.value = rk_UNCONST(target);
116    input_token.length = strlen(target);
117
118    maj_stat = gss_import_name(&min_stat,
119			       &input_token,
120			       nameoid,
121			       &gss_target_name);
122    if (GSS_ERROR(maj_stat))
123	err(1, "import name creds failed with: %d", maj_stat);
124
125    if (acceptor_name) {
126	input_token.value = rk_UNCONST(acceptor_name);
127	input_token.length = strlen(acceptor_name);
128
129	maj_stat = gss_import_name(&min_stat,
130				   &input_token,
131				   nameoid,
132				   &gss_acceptor_name);
133	if (GSS_ERROR(maj_stat))
134	    err(1, "import acceptor name creds failed with: %d", maj_stat);
135
136	maj_stat = gss_acquire_cred(&min_stat, gss_acceptor_name,
137				    GSS_C_INDEFINITE, NULL,
138				    GSS_C_ACCEPT, &acceptor_cred,
139				    NULL, NULL);
140	if (maj_stat != GSS_S_COMPLETE)
141	    errx(1, "acquire acceptor cred failed");
142    }
143
144    input_token.length = 0;
145    input_token.value = NULL;
146
147    while (!server_done || !client_done) {
148	num_loops++;
149
150	gsskrb5_set_time_offset(client_time_offset);
151
152	maj_stat = gss_init_sec_context(&min_stat,
153					init_cred,
154					cctx,
155					gss_target_name,
156					mechoid,
157					flags,
158					0,
159					bindings,
160					&input_token,
161					&actual_mech_client,
162					&output_token,
163					&ret_cflags,
164					NULL);
165	if (GSS_ERROR(maj_stat))
166	    errx(1, "init_sec_context: %s",
167		 gssapi_err(maj_stat, min_stat, mechoid));
168	if (maj_stat & GSS_S_CONTINUE_NEEDED)
169	    ;
170	else
171	    client_done = 1;
172
173	gsskrb5_get_time_offset(&client_time_offset);
174
175	if (client_done && server_done)
176	    break;
177
178	if (input_token.length != 0)
179	    gss_release_buffer(&min_stat, &input_token);
180
181	gsskrb5_set_time_offset(server_time_offset);
182
183	maj_stat = gss_accept_sec_context(&min_stat,
184					  sctx,
185					  acceptor_cred,
186					  &output_token,
187					  bindings,
188					  NULL,
189					  &actual_mech_server,
190					  &input_token,
191					  &ret_sflags,
192					  NULL,
193					  deleg_cred);
194	if (GSS_ERROR(maj_stat))
195		errx(1, "accept_sec_context: %s",
196		     gssapi_err(maj_stat, min_stat, actual_mech_server));
197
198	gsskrb5_get_time_offset(&server_time_offset);
199
200	if (output_token.length != 0)
201	    gss_release_buffer(&min_stat, &output_token);
202
203	if (maj_stat & GSS_S_CONTINUE_NEEDED)
204	    ;
205	else
206	    server_done = 1;
207    }
208    if (output_token.length != 0)
209	gss_release_buffer(&min_stat, &output_token);
210    if (input_token.length != 0)
211	gss_release_buffer(&min_stat, &input_token);
212    gss_release_name(&min_stat, &gss_target_name);
213    gss_release_name(&min_stat, &gss_acceptor_name);
214    gss_release_cred(&min_stat, &acceptor_cred);
215
216    if (deleg_flag || policy_deleg_flag) {
217	if (server_no_deleg_flag) {
218	    if (deleg_cred && *deleg_cred != GSS_C_NO_CREDENTIAL)
219		errx(1, "got delegated cred but didn't expect one");
220	} else if (deleg_cred && *deleg_cred == GSS_C_NO_CREDENTIAL)
221	    errx(1, "asked for delegarated cred but did get one");
222    } else if (deleg_cred && *deleg_cred != GSS_C_NO_CREDENTIAL)
223	  errx(1, "got deleg_cred cred but didn't ask");
224
225    if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0)
226	errx(1, "mech mismatch");
227    *actual_mech = actual_mech_server;
228
229    if (!!(ret_sflags & GSS_C_INTEG_FLAG) != !!(ret_cflags & GSS_C_INTEG_FLAG))
230	errx(1, "client and server doesn't have same idea about INTEG: c: %d s: %d ",
231	     !!(ret_cflags & GSS_C_INTEG_FLAG), !!(ret_sflags & GSS_C_INTEG_FLAG));
232
233    if (!!(ret_sflags & GSS_C_CONF_FLAG) != !!(ret_cflags & GSS_C_CONF_FLAG))
234	errx(1, "client and server doesn't have same idea about CONF: c: %d s: %d",
235	     !!(ret_cflags & GSS_C_CONF_FLAG), !!(ret_sflags & GSS_C_CONF_FLAG));
236
237    if (verbose_flag)
238	printf("client and server agree on CONF/INT\n");
239
240    if (max_loops && num_loops > max_loops)
241	errx(1, "num loops %d was lager then max loops %d",
242	     num_loops, max_loops);
243
244    if (verbose_flag) {
245	printf("server time offset: %d\n", server_time_offset);
246	printf("client time offset: %d\n", client_time_offset);
247	printf("num loops %d\n", num_loops);
248    }
249}
250
251static void
252wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
253{
254    gss_buffer_desc input_token, output_token, output_token2;
255    OM_uint32 min_stat, maj_stat;
256    gss_qop_t qop_state;
257    int conf_state;
258
259    input_token.value = "foo";
260    input_token.length = 3;
261
262    maj_stat = gss_wrap(&min_stat, cctx, flags, 0, &input_token,
263			&conf_state, &output_token);
264    if (maj_stat != GSS_S_COMPLETE)
265	errx(1, "gss_wrap failed: %s",
266	     gssapi_err(maj_stat, min_stat, mechoid));
267
268    maj_stat = gss_unwrap(&min_stat, sctx, &output_token,
269			  &output_token2, &conf_state, &qop_state);
270    if (maj_stat != GSS_S_COMPLETE)
271	errx(1, "gss_unwrap failed: %s",
272	     gssapi_err(maj_stat, min_stat, mechoid));
273
274    gss_release_buffer(&min_stat, &output_token);
275    gss_release_buffer(&min_stat, &output_token2);
276
277#if 0 /* doesn't work for NTLM yet */
278    if (!!conf_state != !!flags)
279	errx(1, "conf_state mismatch");
280#endif
281}
282
283#define USE_CONF		1
284#define USE_HEADER_ONLY		2
285#define USE_SIGN_ONLY		4
286#define FORCE_IOV		8
287
288static void
289wrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
290{
291    krb5_data token, header, trailer;
292    OM_uint32 min_stat, maj_stat;
293    gss_qop_t qop_state;
294    int conf_state, conf_state2;
295    gss_iov_buffer_desc iov[6];
296    unsigned char *p;
297    int iov_len;
298    char header_data[9] = "ABCheader";
299    char trailer_data[10] = "trailerXYZ";
300
301    char token_data[16] = "0123456789abcdef";
302
303    memset(&iov, 0, sizeof(iov));
304
305    if (flags & USE_SIGN_ONLY) {
306	header.data = header_data;
307	header.length = 9;
308	trailer.data = trailer_data;
309	trailer.length = 10;
310    } else {
311	header.data = NULL;
312	header.length = 0;
313	trailer.data = NULL;
314	trailer.length = 0;
315    }
316
317    token.data = token_data;
318    token.length = 16;
319
320    iov_len = sizeof(iov)/sizeof(iov[0]);
321
322    memset(iov, 0, sizeof(iov));
323
324    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
325
326    if (header.length != 0) {
327	iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
328	iov[1].buffer.length = header.length;
329	iov[1].buffer.value = header.data;
330    } else {
331	iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
332	iov[1].buffer.length = 0;
333	iov[1].buffer.value = NULL;
334    }
335    iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
336    iov[2].buffer.length = token.length;
337    iov[2].buffer.value = token.data;
338    if (trailer.length != 0) {
339	iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
340	iov[3].buffer.length = trailer.length;
341	iov[3].buffer.value = trailer.data;
342    } else {
343	iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
344	iov[3].buffer.length = 0;
345	iov[3].buffer.value = NULL;
346    }
347    if (dce_style_flag) {
348	iov[4].type = GSS_IOV_BUFFER_TYPE_EMPTY;
349    } else {
350	iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
351    }
352    iov[4].buffer.length = 0;
353    iov[4].buffer.value = 0;
354    if (dce_style_flag) {
355	iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
356    } else if (flags & USE_HEADER_ONLY) {
357	iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
358    } else {
359	iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
360    }
361    iov[5].buffer.length = 0;
362    iov[5].buffer.value = 0;
363
364    maj_stat = gss_wrap_iov(&min_stat, cctx, dce_style_flag || flags & USE_CONF, 0, &conf_state,
365			    iov, iov_len);
366    if (maj_stat != GSS_S_COMPLETE)
367	errx(1, "gss_wrap_iov failed");
368
369    token.length =
370	iov[0].buffer.length +
371	iov[1].buffer.length +
372	iov[2].buffer.length +
373	iov[3].buffer.length +
374	iov[4].buffer.length +
375	iov[5].buffer.length;
376    token.data = emalloc(token.length);
377
378    p = token.data;
379    memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
380    p += iov[0].buffer.length;
381    memcpy(p, iov[1].buffer.value, iov[1].buffer.length);
382    p += iov[1].buffer.length;
383    memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
384    p += iov[2].buffer.length;
385    memcpy(p, iov[3].buffer.value, iov[3].buffer.length);
386    p += iov[3].buffer.length;
387    memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
388    p += iov[4].buffer.length;
389    memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
390    p += iov[5].buffer.length;
391
392    assert(p - ((unsigned char *)token.data) == token.length);
393
394    if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) {
395	gss_buffer_desc input, output;
396
397	input.value = token.data;
398	input.length = token.length;
399
400	maj_stat = gss_unwrap(&min_stat, sctx, &input,
401			      &output, &conf_state2, &qop_state);
402
403	if (maj_stat != GSS_S_COMPLETE)
404	    errx(1, "gss_unwrap from gss_wrap_iov failed: %s",
405		 gssapi_err(maj_stat, min_stat, mechoid));
406
407	gss_release_buffer(&min_stat, &output);
408    } else {
409	maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state,
410				  iov, iov_len);
411
412	if (maj_stat != GSS_S_COMPLETE)
413	    errx(1, "gss_unwrap_iov failed: %x %s", flags,
414		 gssapi_err(maj_stat, min_stat, mechoid));
415
416    }
417    if (conf_state2 != conf_state)
418	errx(1, "conf state wrong for iov: %x", flags);
419
420
421    free(token.data);
422}
423
424static void
425getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)
426{
427    gss_buffer_desc input_token, output_token;
428    OM_uint32 min_stat, maj_stat;
429    gss_qop_t qop_state;
430
431    input_token.value = "bar";
432    input_token.length = 3;
433
434    maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token,
435			   &output_token);
436    if (maj_stat != GSS_S_COMPLETE)
437	errx(1, "gss_get_mic failed: %s",
438	     gssapi_err(maj_stat, min_stat, mechoid));
439
440    maj_stat = gss_verify_mic(&min_stat, sctx, &input_token,
441			      &output_token, &qop_state);
442    if (maj_stat != GSS_S_COMPLETE)
443	errx(1, "gss_verify_mic failed: %s",
444	     gssapi_err(maj_stat, min_stat, mechoid));
445
446    gss_release_buffer(&min_stat, &output_token);
447}
448
449static void
450empty_release(void)
451{
452    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
453    gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
454    gss_name_t name = GSS_C_NO_NAME;
455    gss_OID_set oidset = GSS_C_NO_OID_SET;
456    OM_uint32 junk;
457
458    gss_delete_sec_context(&junk, &ctx, NULL);
459    gss_release_cred(&junk, &cred);
460    gss_release_name(&junk, &name);
461    gss_release_oid_set(&junk, &oidset);
462}
463
464static void
465check_inquire_context(gss_ctx_id_t ctx, const char *context_str)
466{
467    OM_uint32 maj_stat, min_stat;
468    gss_name_t source, target;
469
470    maj_stat = gss_inquire_context(&min_stat, ctx, &source, &target,
471				   NULL, NULL, NULL, NULL, NULL);
472    if (maj_stat != GSS_S_COMPLETE)
473	errx(1, "gss_inquire_context(%s): %s", context_str,
474	     gssapi_err(maj_stat, min_stat, NULL));
475
476    if (verbose_flag) {
477	gss_buffer_desc buf;
478
479	if (source) {
480	    maj_stat = gss_display_name(&min_stat, source, &buf, NULL);
481	    if (maj_stat == GSS_S_COMPLETE) {
482		printf("source(%s): %.*s\n", context_str, (int)buf.length, (char*)buf.value);
483		gss_release_buffer(&min_stat, &buf);
484	    } else {
485		printf("source(%s): have not name\n", context_str);
486	    }
487	}
488
489	if (target) {
490	    maj_stat = gss_display_name(&min_stat, target, &buf, NULL);
491	    if (maj_stat == GSS_S_COMPLETE) {
492		printf("target(%s): %.*s\n", context_str, (int)buf.length, (char*)buf.value);
493		gss_release_buffer(&min_stat, &buf);
494	    } else {
495		printf("source(%s): have not name\n", context_str);
496	    }
497	}
498    }
499
500    gss_release_name(&min_stat, &source);
501    gss_release_name(&min_stat, &target);
502}
503
504/*
505 *
506 */
507
508static void
509check_export_import_sec_context(gss_ctx_id_t *initiator, gss_ctx_id_t *acceptor, gss_OID mech)
510{
511    OM_uint32 maj_stat, min_stat;
512    gss_buffer_desc buffer;
513
514    maj_stat = gss_export_sec_context(&min_stat, initiator, &buffer);
515    if (maj_stat != GSS_S_COMPLETE)
516	gssapi_err(maj_stat, min_stat, mech);
517
518    maj_stat = gss_import_sec_context(&min_stat, &buffer, initiator);
519    if (maj_stat != GSS_S_COMPLETE)
520	gssapi_err(maj_stat, min_stat, mech);
521    gss_release_buffer(&min_stat, &buffer);
522
523    wrapunwrap(*initiator, *acceptor, 1, mech);
524    wrapunwrap(*initiator, *acceptor, 0, mech);
525
526    maj_stat = gss_export_sec_context(&min_stat, acceptor, &buffer);
527    if (maj_stat != GSS_S_COMPLETE)
528	gssapi_err(maj_stat, min_stat, mech);
529
530    maj_stat = gss_import_sec_context(&min_stat, &buffer, acceptor);
531    if (maj_stat != GSS_S_COMPLETE)
532	gssapi_err(maj_stat, min_stat, mech);
533    gss_release_buffer(&min_stat, &buffer);
534
535    wrapunwrap(*acceptor, *initiator, 0, mech);
536    wrapunwrap(*acceptor, *initiator, 1, mech);
537}
538
539/*
540 *
541 */
542
543
544static void
545ac_complete(void *ctx, OM_uint32 major, gss_status_id_t status,
546	    gss_cred_id_t cred, gss_OID_set oids, OM_uint32 time_rec)
547{
548    gss_cred_id_t *client_cred = ctx;
549    OM_uint32 junk;
550
551    if (major) {
552	fprintf(stderr, "error: %d", (int)major);
553	gss_release_cred(&junk, &cred);
554	goto out;
555    }
556
557    *client_cred = cred;
558
559 out:
560    gss_release_oid_set(&junk, &oids);
561}
562
563/*
564 *
565 */
566
567static struct getargs args[] = {
568    {"name-type",0,	arg_string, &type_string,  "type of name", NULL },
569    {"mech-type",0,	arg_string, &mech_string,  "type of mech", NULL },
570    {"ret-mech-type",0,	arg_string, &ret_mech_string,
571     "type of return mech", NULL },
572    {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag,
573     "use dns to canonicalize", NULL },
574    {"mutual-auth",0,	arg_flag,	&mutual_auth_flag,"mutual auth", NULL },
575    {"cred-type",0,	arg_string,     &cred_string,  "type of cred", NULL },
576    {"client-name", 0,  arg_string,     &client_name, "client name", NULL },
577    {"acceptor-name", 0,  arg_string,   &acceptor_name_string, "acceptor name", NULL },
578    {"password", 0,     arg_string,     &password_string, "password", NULL },
579    {"client-password", 0,  arg_string, &client_password, "client password", NULL },
580    {"limit-enctype",0,	arg_string,	&limit_enctype_string, "enctype", NULL },
581    {"dce-style",0,	arg_flag,	&dce_style_flag, "dce-style", NULL },
582    {"wrapunwrap",0,	arg_flag,	&wrapunwrap_flag, "wrap/unwrap", NULL },
583    {"iov", 0, 		arg_flag,	&iov_flag, "wrap/unwrap iov", NULL },
584    {"getverifymic",0,	arg_flag,	&getverifymic_flag,
585     "get and verify mic", NULL },
586    {"import-export",0,	arg_flag,	&import_export_flag,
587     "test import and export sec context", NULL },
588    {"delegate",0,	arg_flag,	&deleg_flag, "delegate credential", NULL },
589    {"policy-delegate",0,	arg_flag,	&policy_deleg_flag, "policy delegate credential", NULL },
590    {"server-no-delegate",0,	arg_flag,	&server_no_deleg_flag,
591     "server should get a credential", NULL },
592    {"export-import-cred",0,	arg_flag,	&ei_flag, "test export/import cred", NULL },
593    {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL },
594    {"session-enctype",	0, arg_string,	&session_enctype_string, "enctype", NULL },
595    {"client-time-offset",	0, arg_integer,	&client_time_offset, "time", NULL },
596    {"server-time-offset",	0, arg_integer,	&server_time_offset, "time", NULL },
597    {"max-loops",	0, arg_integer,	&max_loops, "time", NULL },
598    {"channel-binding",	0, arg_string,	&gsschannel_appl_data, "string", NULL },
599    {"homedir",	0,	arg_negative_flag, &homedir_flag, "don't allow homedir access", NULL },
600    {"version",	0,	arg_flag,	&version_flag, "print version", NULL },
601    {"verbose",	'v',	arg_flag,	&verbose_flag, "verbose", NULL },
602    {"help",	0,	arg_flag,	&help_flag,  NULL, NULL }
603};
604
605static void
606usage (int ret)
607{
608    arg_printusage (args, sizeof(args)/sizeof(*args),
609		    NULL, "service@host");
610    exit (ret);
611}
612
613int
614main(int argc, char **argv)
615{
616    int optidx = 0;
617    OM_uint32 min_stat, maj_stat;
618    gss_ctx_id_t cctx, sctx;
619    void *ctx;
620    gss_OID actual_mech, actual_mech2;
621    gss_const_OID nameoid, mechoid;
622    gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL, deleg_cred = GSS_C_NO_CREDENTIAL;
623    gss_channel_bindings_t bindings = GSS_C_NO_CHANNEL_BINDINGS;
624    gss_buffer_desc buffer;
625    gss_name_t cname = GSS_C_NO_NAME;
626    gss_buffer_desc credential_data = GSS_C_EMPTY_BUFFER;
627
628    setprogname(argv[0]);
629
630    if (krb5_init_context(&context))
631	errx(1, "krb5_init_context");
632
633    cctx = sctx = GSS_C_NO_CONTEXT;
634
635    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
636	usage(1);
637
638    if (help_flag)
639	usage (0);
640
641    if(version_flag){
642	print_version(NULL);
643	exit(0);
644    }
645
646    argc -= optidx;
647    argv += optidx;
648
649    if (argc != 1)
650	usage(1);
651
652    if (!homedir_flag)
653	krb5_set_home_dir_access(NULL, false);
654
655    if (dns_canon_flag != -1)
656	gsskrb5_set_dns_canonicalize(dns_canon_flag);
657
658    if (type_string == NULL)
659	nameoid = GSS_C_NT_HOSTBASED_SERVICE;
660    else if (strcmp(type_string, "hostbased-service") == 0)
661	nameoid = GSS_C_NT_HOSTBASED_SERVICE;
662    else if (strcmp(type_string, "krb5-principal-name") == 0)
663	nameoid = GSS_KRB5_NT_PRINCIPAL_NAME;
664    else if (strcmp(type_string, "krb5-principal-name-referral") == 0)
665	nameoid = GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL;
666    else
667	errx(1, "%s not suppported", type_string);
668
669    if (mech_string == NULL)
670	mechoid = GSS_KRB5_MECHANISM;
671    else {
672	mechoid = gss_name_to_oid(mech_string);
673	if (mechoid == GSS_C_NO_OID)
674	    errx(1, "failed to find mech oid: %s", mech_string);
675    }
676
677
678
679    if (gsskrb5_acceptor_identity) {
680	maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity);
681	if (maj_stat)
682	    errx(1, "gsskrb5_acceptor_identity: %s",
683		 gssapi_err(maj_stat, 0, GSS_C_NO_OID));
684    }
685
686    if (client_password) {
687	credential_data.value = client_password;
688	credential_data.length = strlen(client_password);
689    }
690
691    if (gsschannel_appl_data) {
692	if (strlen(gsschannel_appl_data) == 4)
693	    errx(1, "make channelbindings not 4 in length");
694
695	bindings = ecalloc(1, sizeof(*bindings));
696	bindings->application_data.value = gsschannel_appl_data;
697	bindings->application_data.length = strlen(gsschannel_appl_data);
698    }
699
700    if (client_name) {
701	gss_buffer_desc cn;
702	gss_const_OID credoid = GSS_C_NO_OID;
703
704	if (cred_string) {
705	    credoid = gss_name_to_oid(cred_string);
706	    if (credoid == GSS_C_NO_OID)
707		errx(1, "failed to find cred oid: %s", cred_string);
708	}
709
710	cn.value = client_name;
711	cn.length = strlen(client_name);
712
713	maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname);
714	if (maj_stat)
715	    errx(1, "gss_import_name: %s",
716		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
717
718
719	if (password_string) {
720	    gss_auth_identity_desc identity;
721	    OM_uint32 major;
722	    char *u, *r;
723
724	    /*
725	     * set the cred out to the same a mech since gss_acquire_cred_ex_f really wants one.
726	     */
727
728	    if (credoid == NULL)
729		credoid = mechoid;
730
731	    u = strdup(client_name);
732	    if (u == NULL)
733		errx(1, "out of memory");
734
735	    r = strchr(u, '@');
736	    if (r)
737		*r++ = '\0';
738	    else
739		r = NULL;
740
741	    memset(&identity, 0, sizeof(identity));
742
743	    identity.username = u;
744	    identity.realm = r;
745	    identity.password = password_string;
746
747	    major = gss_acquire_cred_ex_f(NULL,
748					  cname,
749					  0,
750					  GSS_C_INDEFINITE,
751					  credoid,
752					  GSS_C_INITIATE,
753					  &identity,
754					  &client_cred,
755					  ac_complete);
756	    if (major)
757		errx(1, "gss_acquire_cred_ex_f: %d", (int)major);
758
759	    free(u);
760
761	} else {
762	    gss_OID_set mechs = GSS_C_NULL_OID_SET;
763
764	    if (credoid != GSS_C_NO_OID) {
765		maj_stat = gss_create_empty_oid_set(&min_stat, &mechs);
766		if (maj_stat != GSS_S_COMPLETE)
767		    errx(1, "gss_create_empty_oid_set: %s",
768			 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
769
770		maj_stat = gss_add_oid_set_member(&min_stat, credoid, &mechs);
771		if (maj_stat != GSS_S_COMPLETE)
772		    errx(1, "gss_add_oid_set_member: %s",
773			 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
774	    }
775
776	    maj_stat = gss_acquire_cred(&min_stat, cname, 0, mechs,
777					GSS_C_INITIATE, &client_cred, NULL, NULL);
778	    if (GSS_ERROR(maj_stat))
779		errx(1, "gss_import_name: %s",
780		     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
781
782	    if (mechs != GSS_C_NULL_OID_SET)
783		gss_release_oid_set(&min_stat, &mechs);
784	}
785	gss_release_name(&min_stat, &cname);
786
787    } else if (client_password) {
788	maj_stat = gss_acquire_cred_with_password(&min_stat,
789						  cname,
790						  &credential_data,
791						  GSS_C_INDEFINITE,
792						  GSS_C_NO_OID_SET,
793						  GSS_C_INITIATE,
794						  &client_cred,
795						  NULL,
796						  NULL);
797	if (GSS_ERROR(maj_stat))
798	    errx(1, "gss_acquire_cred_with_password: %s",
799		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
800    } else {
801	maj_stat = gss_acquire_cred(&min_stat,
802				    cname,
803				    GSS_C_INDEFINITE,
804				    GSS_C_NO_OID_SET,
805				    GSS_C_INITIATE,
806				    &client_cred,
807				    NULL,
808				    NULL);
809	if (GSS_ERROR(maj_stat))
810	    errx(1, "gss_acquire_cred: %s",
811		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
812    }
813
814    /*
815     * Check that GSS_C_NT_UUID works with IAKERB
816     */
817
818    if (client_cred && gss_oid_equal(GSS_IAKERB_MECHANISM, mechoid)) {
819	gss_buffer_set_t buffers;
820	gss_name_t tname;
821
822	maj_stat = gss_inquire_cred_by_oid(&min_stat, client_cred, GSS_C_NT_UUID, &buffers);
823	if (maj_stat)
824	    errx(1, "failed to find GSS_C_NT_UUID");
825
826	gss_release_cred(&min_stat, &client_cred);
827
828	if (buffers->count != 1)
829	    errx(1, "wrong number of buffers for GSS_C_UUID");
830
831	maj_stat = gss_import_name(&min_stat, &buffers->elements[0], GSS_C_NT_UUID, &tname);
832	if (maj_stat != GSS_S_COMPLETE)
833	    errx(1, "import name failed");
834
835	maj_stat = gss_acquire_cred(&min_stat, tname, GSS_C_INDEFINITE, NULL, GSS_C_INITIATE, &client_cred, NULL, NULL);
836	if (maj_stat != GSS_S_COMPLETE)
837	    errx(1, "acquire IAKERB failed");
838
839	gss_release_name(&min_stat, &tname);
840	gss_release_buffer_set(&min_stat, &buffers);
841    }
842
843    if (limit_enctype_string) {
844	krb5_error_code ret;
845
846	ret = krb5_string_to_enctype(context,
847				     limit_enctype_string,
848				     &limit_enctype);
849	if (ret)
850	    krb5_err(context, 1, ret, "krb5_string_to_enctype");
851    }
852
853
854    if (limit_enctype) {
855	if (client_cred == NULL)
856	    errx(1, "client_cred missing");
857
858	maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred,
859						   1, &limit_enctype);
860	if (maj_stat)
861	    errx(1, "gss_krb5_set_allowable_enctypes: %s",
862		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
863    }
864
865    /*
866     * generic tests.
867     */
868
869    ctx = GSS_C_NO_CONTEXT;
870
871    maj_stat = gss_inquire_context(&min_stat, NULL, NULL, NULL,
872				   NULL, NULL, NULL, NULL, NULL);
873    if (maj_stat != GSS_S_NO_CONTEXT)
874	errx(1, "gss_inquire_context didn't fail");
875
876    maj_stat = gss_export_sec_context(&min_stat, &cctx, &buffer);
877    if (maj_stat != GSS_S_NO_CONTEXT)
878	errx(1, "gss_export_sec_context didn't fail");
879
880    maj_stat = gss_export_sec_context(&min_stat, &cctx, NULL);
881    if (maj_stat != GSS_S_CALL_INACCESSIBLE_READ)
882	errx(1, "gss_export_sec_context didn't fail");
883
884
885    /*
886     *
887     */
888
889
890    loop(rk_UNCONST(mechoid), nameoid, argv[0], acceptor_name_string, client_cred, bindings,
891	 &sctx, &cctx, &actual_mech, &deleg_cred);
892
893    if (verbose_flag)
894	printf("resulting mech: %s\n", gss_oid_to_name(actual_mech));
895
896    check_inquire_context(sctx, "server");
897    check_inquire_context(cctx, "client");
898
899    if (ret_mech_string) {
900	gss_const_OID retoid;
901
902	retoid = gss_name_to_oid(ret_mech_string);
903
904	if (gss_oid_equal(retoid, actual_mech) == 0)
905	    errx(1, "actual_mech mech is not the expected type %s",
906		 ret_mech_string);
907    }
908
909    /* XXX should be actual_mech */
910    if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)
911	|| gss_oid_equal(mechoid, GSS_IAKERB_MECHANISM)
912#ifdef PKINIT
913	|| gss_oid_equal(mechoid, GSS_PKU2U_MECHANISM)
914#endif
915	) {
916	time_t time;
917	gss_buffer_desc authz_data;
918	gss_buffer_desc in, out1, out2;
919	krb5_keyblock *keyblock, *keyblock2;
920	krb5_timestamp now;
921	krb5_error_code ret;
922
923	ret = krb5_timeofday(context, &now);
924	if (ret)
925	    errx(1, "krb5_timeofday failed");
926
927	/* client */
928	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
929						     &cctx,
930						     1, /* version */
931						     &ctx);
932	if (maj_stat != GSS_S_COMPLETE)
933	    errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
934		 gssapi_err(maj_stat, min_stat, actual_mech));
935
936
937	maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx);
938	if (maj_stat != GSS_S_COMPLETE)
939	    errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
940		     gssapi_err(maj_stat, min_stat, actual_mech));
941
942	/* server */
943	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
944						     &sctx,
945						     1, /* version */
946						     &ctx);
947	if (maj_stat != GSS_S_COMPLETE)
948	    errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
949		     gssapi_err(maj_stat, min_stat, actual_mech));
950	maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx);
951	if (maj_stat != GSS_S_COMPLETE)
952	    errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
953		     gssapi_err(maj_stat, min_stat, actual_mech));
954
955 	maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
956							     sctx,
957							     &time);
958	if (maj_stat != GSS_S_COMPLETE)
959	    errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
960		     gssapi_err(maj_stat, min_stat, actual_mech));
961
962	if (time > now)
963	    errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
964		 "time authtime is before now: %ld %ld",
965		 (long)time, (long)now);
966
967 	maj_stat = gsskrb5_extract_service_keyblock(&min_stat,
968						    sctx,
969						    &keyblock);
970	if (maj_stat != GSS_S_COMPLETE)
971	    errx(1, "gsskrb5_export_service_keyblock failed: %s",
972		     gssapi_err(maj_stat, min_stat, actual_mech));
973
974	krb5_free_keyblock(context, keyblock);
975
976 	maj_stat = gsskrb5_get_subkey(&min_stat,
977				      sctx,
978				      &keyblock);
979	if (maj_stat != GSS_S_COMPLETE
980	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
981	    errx(1, "gsskrb5_get_subkey server failed: %s",
982		     gssapi_err(maj_stat, min_stat, actual_mech));
983
984	if (maj_stat != GSS_S_COMPLETE)
985	    keyblock = NULL;
986	else if (limit_enctype && keyblock->keytype != limit_enctype)
987	    errx(1, "gsskrb5_get_subkey wrong enctype");
988
989 	maj_stat = gsskrb5_get_subkey(&min_stat,
990				      cctx,
991				      &keyblock2);
992	if (maj_stat != GSS_S_COMPLETE
993	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
994	    errx(1, "gsskrb5_get_subkey client failed: %s",
995		     gssapi_err(maj_stat, min_stat, actual_mech));
996
997	if (maj_stat != GSS_S_COMPLETE)
998	    keyblock2 = NULL;
999	else if (limit_enctype && keyblock2->keytype != limit_enctype)
1000	    errx(1, "gsskrb5_get_subkey wrong enctype");
1001
1002	if (keyblock || keyblock2) {
1003	    if (keyblock == NULL)
1004		errx(1, "server missing token keyblock");
1005	    if (keyblock2 == NULL)
1006		errx(1, "client missing token keyblock");
1007
1008	    if (keyblock->keytype != keyblock2->keytype)
1009		errx(1, "enctype mismatch");
1010	    if (keyblock->keyvalue.length != keyblock2->keyvalue.length)
1011		errx(1, "key length mismatch");
1012	    if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data,
1013		       keyblock2->keyvalue.length) != 0)
1014		errx(1, "key data mismatch");
1015	}
1016
1017	if (session_enctype_string) {
1018	    krb5_enctype enctype;
1019
1020	    if (keyblock == NULL)
1021		errx(1, "expected keyblock, didn't get one");
1022
1023	    ret = krb5_string_to_enctype(context,
1024					 session_enctype_string,
1025					 &enctype);
1026
1027	    if (ret)
1028		krb5_err(context, 1, ret, "krb5_string_to_enctype");
1029
1030	    if (enctype != keyblock->keytype)
1031		errx(1, "keytype is not the expected %d != %d",
1032		     (int)enctype, (int)keyblock2->keytype);
1033	}
1034
1035	if (keyblock)
1036	    krb5_free_keyblock(context, keyblock);
1037	if (keyblock2)
1038	    krb5_free_keyblock(context, keyblock2);
1039
1040 	maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
1041						sctx,
1042						&keyblock);
1043	if (maj_stat != GSS_S_COMPLETE
1044	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
1045	    errx(1, "gsskrb5_get_initiator_subkey failed: %s",
1046		     gssapi_err(maj_stat, min_stat, actual_mech));
1047
1048	if (maj_stat == GSS_S_COMPLETE) {
1049
1050	    if (limit_enctype && keyblock->keytype != limit_enctype)
1051		errx(1, "gsskrb5_get_initiator_subkey wrong enctype");
1052	    krb5_free_keyblock(context, keyblock);
1053	}
1054
1055 	maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
1056							       sctx,
1057							       128,
1058							       &authz_data);
1059	if (maj_stat == GSS_S_COMPLETE)
1060	    gss_release_buffer(&min_stat, &authz_data);
1061
1062
1063	memset(&out1, 0, sizeof(out1));
1064	memset(&out2, 0, sizeof(out2));
1065
1066	in.value = "foo";
1067	in.length = 3;
1068
1069	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
1070			  100, &out1);
1071	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,
1072			  100, &out2);
1073
1074	if (out1.length != out2.length)
1075	    errx(1, "prf len mismatch");
1076	if (memcmp(out1.value, out2.value, out1.length) != 0)
1077	    errx(1, "prf data mismatch");
1078
1079	gss_release_buffer(&min_stat, &out1);
1080
1081	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
1082			  100, &out1);
1083
1084	if (out1.length != out2.length)
1085	    errx(1, "prf len mismatch");
1086	if (memcmp(out1.value, out2.value, out1.length) != 0)
1087	    errx(1, "prf data mismatch");
1088
1089	gss_release_buffer(&min_stat, &out1);
1090	gss_release_buffer(&min_stat, &out2);
1091
1092	in.value = "bar";
1093	in.length = 3;
1094
1095	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,
1096			  100, &out1);
1097	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,
1098			  100, &out2);
1099
1100	if (out1.length != out2.length)
1101	    errx(1, "prf len mismatch");
1102	if (memcmp(out1.value, out2.value, out1.length) != 0)
1103	    errx(1, "prf data mismatch");
1104
1105	gss_release_buffer(&min_stat, &out1);
1106	gss_release_buffer(&min_stat, &out2);
1107
1108	wrapunwrap_flag = 1;
1109	getverifymic_flag = 1;
1110#ifdef ENABLE_NTLM
1111    } else if (gss_oid_equal(mechoid, GSS_NTLM_MECHANISM)) {
1112
1113	gss_buffer_set_t cds, sds;
1114	int server_no_session_key = 0,
1115	    client_no_session_key = 0;
1116
1117	maj_stat = gss_inquire_sec_context_by_oid(&min_stat,
1118						  sctx,
1119						  GSS_NTLM_GET_SESSION_KEY_X,
1120						  &sds);
1121	if (min_stat != GSS_S_COMPLETE || sds->count != 1)
1122	    server_no_session_key = 1;
1123
1124	maj_stat = gss_inquire_sec_context_by_oid(&min_stat,
1125						  cctx,
1126						  GSS_NTLM_GET_SESSION_KEY_X,
1127						  &cds);
1128	if (min_stat != GSS_S_COMPLETE || cds->count != 1)
1129	    client_no_session_key = 1;
1130
1131	if (client_no_session_key && server_no_session_key) {
1132	    OM_uint32 sflags;
1133
1134	    sflags = 0;
1135	    maj_stat = gss_inquire_context(&min_stat, sctx,
1136					   NULL, NULL, NULL, NULL, &sflags, NULL, NULL);
1137	    if (maj_stat)
1138		errx(1, "inquire_context");
1139
1140	    if ((sflags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG)) != 0)
1141		errx(1, "ntlm: server no key but int|conf flag(s)!");
1142
1143	    sflags = 0;
1144	    maj_stat = gss_inquire_context(&min_stat, cctx,
1145					   NULL, NULL, NULL, NULL, &sflags, NULL, NULL);
1146	    if (maj_stat)
1147		errx(1, "inquire_context");
1148
1149	    if ((sflags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG)) != 0)
1150		errx(1, "ntlm: client no key but int|conf flag(s)!");
1151
1152	} else if (client_no_session_key) {
1153	    errx(1, "ntlm: server had session key, but not server???");
1154	} else if (server_no_session_key) {
1155	    OM_uint32 sflags = 0;
1156
1157	    /*
1158	     * This case is ok. Even though we didn't negotiated a
1159	     * session key, the library hands one out so the client
1160	     * can force use it if it wants too, useful for SMB2.
1161	     *
1162	     * just check that the client doesn't announce it support
1163	     * signing in the ntlm flags.
1164	     */
1165
1166	    maj_stat = gss_inquire_context(&min_stat, cctx,
1167					   NULL, NULL, NULL, NULL, &sflags, NULL, NULL);
1168	    if (maj_stat)
1169		errx(1, "inquire_context");
1170
1171	    if ((sflags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG)) != 0)
1172		errx(1, "ntlm: client had key, server not, client had int|conf flag(s)!");
1173
1174	    warnx("ntlm: server didn't get session key, that's ok");
1175	} else {
1176	    if (cds->elements[0].length != sds->elements[0].length)
1177		errx(1, "key length wrong");
1178
1179	    if (memcmp(cds->elements[0].value, sds->elements[0].value,
1180		       cds->elements[0].length) != 0)
1181		errx(1, "key data wrong");
1182	}
1183
1184	gss_release_buffer_set(&min_stat, &sds);
1185	gss_release_buffer_set(&min_stat, &cds);
1186#endif /* ENABLE_NTLM */
1187    }
1188
1189    if (wrapunwrap_flag) {
1190	wrapunwrap(cctx, sctx, 0, actual_mech);
1191	wrapunwrap(cctx, sctx, 1, actual_mech);
1192	wrapunwrap(sctx, cctx, 0, actual_mech);
1193	wrapunwrap(sctx, cctx, 1, actual_mech);
1194    }
1195
1196    if (iov_flag) {
1197	wrapunwrap_iov(cctx, sctx, 0, actual_mech);
1198	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1199	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
1200	wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
1201	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
1202
1203	wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
1204	wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1205	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1206	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1207
1208	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1209	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1210	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1211
1212/* works */
1213	wrapunwrap_iov(cctx, sctx, 0, actual_mech);
1214	wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
1215
1216	wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
1217	wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1218
1219	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY, actual_mech);
1220	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1221
1222	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech);
1223	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1224
1225	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
1226	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1227
1228	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
1229	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1230    }
1231
1232    if (getverifymic_flag) {
1233	getverifymic(cctx, sctx, actual_mech);
1234	getverifymic(cctx, sctx, actual_mech);
1235	getverifymic(sctx, cctx, actual_mech);
1236	getverifymic(sctx, cctx, actual_mech);
1237    }
1238
1239
1240    if (import_export_flag) {
1241	check_export_import_sec_context(&cctx, &sctx, actual_mech);
1242    }
1243
1244    gss_delete_sec_context(&min_stat, &cctx, NULL);
1245    gss_delete_sec_context(&min_stat, &sctx, NULL);
1246
1247    if (deleg_cred != GSS_C_NO_CREDENTIAL) {
1248	gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
1249	gss_buffer_desc cb;
1250
1251	if (verbose_flag)
1252	    printf("if we delegated, try again, this time o/o catching the cred\n");
1253	loop(rk_UNCONST(mechoid), nameoid, argv[0], acceptor_name_string, client_cred, bindings,
1254	     &sctx, &cctx, &actual_mech, NULL);
1255	gss_delete_sec_context(&min_stat, &cctx, NULL);
1256	gss_delete_sec_context(&min_stat, &sctx, NULL);
1257
1258	if (verbose_flag)
1259	    printf("checking actual mech (%s) on delegated cred\n",
1260		   gss_oid_to_name(actual_mech));
1261	loop(actual_mech, nameoid, argv[0], acceptor_name_string,
1262	     deleg_cred, bindings,
1263	     &sctx, &cctx, &actual_mech2, &cred2);
1264
1265	gss_delete_sec_context(&min_stat, &cctx, NULL);
1266	gss_delete_sec_context(&min_stat, &sctx, NULL);
1267
1268	gss_release_cred(&min_stat, &cred2);
1269
1270	/* try again using SPNEGO */
1271	if (verbose_flag)
1272	    printf("checking spnego on delegated cred\n");
1273	loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], acceptor_name_string,
1274	     deleg_cred, bindings, &sctx, &cctx,
1275	     &actual_mech2, &cred2);
1276
1277	gss_delete_sec_context(&min_stat, &cctx, NULL);
1278	gss_delete_sec_context(&min_stat, &sctx, NULL);
1279
1280	gss_release_cred(&min_stat, &cred2);
1281
1282	/* check export/import */
1283	if (ei_flag) {
1284
1285	    maj_stat = gss_export_cred(&min_stat, deleg_cred, &cb);
1286	    if (maj_stat != GSS_S_COMPLETE)
1287		errx(1, "export failed: %s",
1288		     gssapi_err(maj_stat, min_stat, NULL));
1289
1290	    maj_stat = gss_import_cred(&min_stat, &cb, &cred2);
1291	    if (maj_stat != GSS_S_COMPLETE)
1292		errx(1, "import failed: %s",
1293		     gssapi_err(maj_stat, min_stat, NULL));
1294
1295	    gss_release_buffer(&min_stat, &cb);
1296	    gss_release_cred(&min_stat, &deleg_cred);
1297
1298	    if (verbose_flag)
1299		printf("checking actual mech (%s) on export/imported cred\n",
1300		       gss_oid_to_name(actual_mech));
1301	    loop(actual_mech, nameoid, argv[0], acceptor_name_string,
1302		 cred2, bindings, &sctx, &cctx,
1303		 &actual_mech2, &deleg_cred);
1304
1305	    gss_release_cred(&min_stat, &deleg_cred);
1306
1307	    gss_delete_sec_context(&min_stat, &cctx, NULL);
1308	    gss_delete_sec_context(&min_stat, &sctx, NULL);
1309
1310	    /* try again using SPNEGO */
1311	    if (verbose_flag)
1312		printf("checking SPNEGO on export/imported cred\n");
1313	    loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], acceptor_name_string,
1314		 cred2, bindings, &sctx, &cctx,
1315		 &actual_mech2, &deleg_cred);
1316
1317	    gss_release_cred(&min_stat, &deleg_cred);
1318
1319	    gss_delete_sec_context(&min_stat, &cctx, NULL);
1320	    gss_delete_sec_context(&min_stat, &sctx, NULL);
1321
1322	    gss_release_cred(&min_stat, &cred2);
1323
1324	} else  {
1325	    gss_release_cred(&min_stat, &deleg_cred);
1326	}
1327
1328    }
1329
1330    empty_release();
1331
1332    krb5_free_context(context);
1333
1334    return 0;
1335}
1336