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 = GSS_C_NO_NAME,
94	gss_acceptor_name = GSS_C_NO_NAME;
95    gss_buffer_desc input_token, output_token;
96    OM_uint32 flags = 0, ret_cflags = 0, ret_sflags = 0;
97    gss_OID actual_mech_client = NULL;
98    gss_OID actual_mech_server = NULL;
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((size_t)(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 int
568check_sasl_names(void)
569{
570    gss_buffer_desc sasl_name, name, description;
571    OM_uint32 maj_stat, min_stat;
572    gss_OID desired_mech = GSS_C_NO_OID;
573    gss_OID oid = GSS_C_NO_OID;
574    gss_OID_set mech_set;
575    OM_uint32 n;
576
577    maj_stat = gss_indicate_mechs(&min_stat, &mech_set);
578    if (maj_stat != GSS_S_COMPLETE)
579	gssapi_err(maj_stat, min_stat, GSS_C_NO_OID);
580
581    for (n = 0; n < mech_set->count; n++) {
582
583	desired_mech = &mech_set->elements[n];
584	oid = GSS_C_NO_OID;
585
586	maj_stat = gss_inquire_saslname_for_mech(&min_stat,
587						 desired_mech,
588						 &sasl_name,
589						 &name,
590						 &description);
591	if (maj_stat)
592	    gssapi_err(maj_stat, min_stat, desired_mech);
593
594	gss_release_buffer(&min_stat, &name);
595	gss_release_buffer(&min_stat, &description);
596
597	maj_stat = gss_inquire_mech_for_saslname(&maj_stat,
598						 &sasl_name,
599						 &oid);
600	if (maj_stat)
601	    gssapi_err(maj_stat, min_stat, desired_mech);
602
603	gss_release_buffer(&min_stat, &sasl_name);
604#if 0
605	if (!gss_oid_equal(desired_mech, oid))
606	    errx(1, "mech oid not the expected out");
607#endif
608    }
609
610    gss_release_oid_set(&min_stat, &mech_set);
611
612    return 0;
613}
614
615/*
616 *
617 */
618
619static struct getargs args[] = {
620    {"name-type",0,	arg_string, &type_string,  "type of name", NULL },
621    {"mech-type",0,	arg_string, &mech_string,  "type of mech", NULL },
622    {"ret-mech-type",0,	arg_string, &ret_mech_string,
623     "type of return mech", NULL },
624    {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag,
625     "use dns to canonicalize", NULL },
626    {"mutual-auth",0,	arg_flag,	&mutual_auth_flag,"mutual auth", NULL },
627    {"cred-type",0,	arg_string,     &cred_string,  "type of cred", NULL },
628    {"client-name", 0,  arg_string,     &client_name, "client name", NULL },
629    {"acceptor-name", 0,  arg_string,   &acceptor_name_string, "acceptor name", NULL },
630    {"password", 0,     arg_string,     &password_string, "password", NULL },
631    {"client-password", 0,  arg_string, &client_password, "client password", NULL },
632    {"limit-enctype",0,	arg_string,	&limit_enctype_string, "enctype", NULL },
633    {"dce-style",0,	arg_flag,	&dce_style_flag, "dce-style", NULL },
634    {"wrapunwrap",0,	arg_flag,	&wrapunwrap_flag, "wrap/unwrap", NULL },
635    {"iov", 0, 		arg_flag,	&iov_flag, "wrap/unwrap iov", NULL },
636    {"getverifymic",0,	arg_flag,	&getverifymic_flag,
637     "get and verify mic", NULL },
638    {"import-export",0,	arg_flag,	&import_export_flag,
639     "test import and export sec context", NULL },
640    {"delegate",0,	arg_flag,	&deleg_flag, "delegate credential", NULL },
641    {"policy-delegate",0,	arg_flag,	&policy_deleg_flag, "policy delegate credential", NULL },
642    {"server-no-delegate",0,	arg_flag,	&server_no_deleg_flag,
643     "server should get a credential", NULL },
644    {"export-import-cred",0,	arg_flag,	&ei_flag, "test export/import cred", NULL },
645    {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL },
646    {"session-enctype",	0, arg_string,	&session_enctype_string, "enctype", NULL },
647    {"client-time-offset",	0, arg_integer,	&client_time_offset, "time", NULL },
648    {"server-time-offset",	0, arg_integer,	&server_time_offset, "time", NULL },
649    {"max-loops",	0, arg_integer,	&max_loops, "time", NULL },
650    {"channel-binding",	0, arg_string,	&gsschannel_appl_data, "string", NULL },
651    {"homedir",	0,	arg_negative_flag, &homedir_flag, "don't allow homedir access", NULL },
652    {"version",	0,	arg_flag,	&version_flag, "print version", NULL },
653    {"verbose",	'v',	arg_flag,	&verbose_flag, "verbose", NULL },
654    {"help",	0,	arg_flag,	&help_flag,  NULL, NULL }
655};
656
657static void
658usage (int ret)
659{
660    arg_printusage (args, sizeof(args)/sizeof(*args),
661		    NULL, "service@host");
662    exit (ret);
663}
664
665int
666main(int argc, char **argv)
667{
668    int optidx = 0;
669    OM_uint32 min_stat, maj_stat;
670    gss_ctx_id_t cctx, sctx;
671    void *ctx;
672    gss_OID actual_mech, actual_mech2;
673    gss_const_OID nameoid, mechoid;
674    gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL, deleg_cred = GSS_C_NO_CREDENTIAL;
675    gss_channel_bindings_t bindings = GSS_C_NO_CHANNEL_BINDINGS;
676    gss_buffer_desc buffer;
677    gss_name_t cname = GSS_C_NO_NAME;
678    gss_buffer_desc credential_data = GSS_C_EMPTY_BUFFER;
679
680    setprogname(argv[0]);
681
682    if (krb5_init_context(&context))
683	errx(1, "krb5_init_context");
684
685    cctx = sctx = GSS_C_NO_CONTEXT;
686
687    if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
688	usage(1);
689
690    if (help_flag)
691	usage (0);
692
693    if(version_flag){
694	print_version(NULL);
695	exit(0);
696    }
697
698    argc -= optidx;
699    argv += optidx;
700
701    if (argc != 1)
702	usage(1);
703
704    if (!homedir_flag)
705	krb5_set_home_dir_access(NULL, false);
706
707    if (dns_canon_flag != -1)
708	gsskrb5_set_dns_canonicalize(dns_canon_flag);
709
710    if (type_string == NULL)
711	nameoid = GSS_C_NT_HOSTBASED_SERVICE;
712    else if (strcmp(type_string, "hostbased-service") == 0)
713	nameoid = GSS_C_NT_HOSTBASED_SERVICE;
714    else if (strcmp(type_string, "krb5-principal-name") == 0)
715	nameoid = GSS_KRB5_NT_PRINCIPAL_NAME;
716    else if (strcmp(type_string, "krb5-principal-name-referral") == 0)
717	nameoid = GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL;
718    else
719	errx(1, "%s not suppported", type_string);
720
721    if (mech_string == NULL)
722	mechoid = GSS_KRB5_MECHANISM;
723    else {
724	mechoid = gss_name_to_oid(mech_string);
725	if (mechoid == GSS_C_NO_OID)
726	    errx(1, "failed to find mech oid: %s", mech_string);
727    }
728
729
730
731    if (gsskrb5_acceptor_identity) {
732	maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity);
733	if (maj_stat)
734	    errx(1, "gsskrb5_acceptor_identity: %s",
735		 gssapi_err(maj_stat, 0, GSS_C_NO_OID));
736    }
737
738    if (client_password) {
739	credential_data.value = client_password;
740	credential_data.length = strlen(client_password);
741    }
742
743    if (gsschannel_appl_data) {
744	if (strlen(gsschannel_appl_data) == 4)
745	    errx(1, "make channelbindings not 4 in length");
746
747	bindings = ecalloc(1, sizeof(*bindings));
748	bindings->application_data.value = gsschannel_appl_data;
749	bindings->application_data.length = strlen(gsschannel_appl_data);
750    }
751
752    if (client_name) {
753	gss_buffer_desc cn;
754	gss_const_OID credoid = GSS_C_NO_OID;
755
756	if (cred_string) {
757	    credoid = gss_name_to_oid(cred_string);
758	    if (credoid == GSS_C_NO_OID)
759		errx(1, "failed to find cred oid: %s", cred_string);
760	}
761
762	cn.value = client_name;
763	cn.length = strlen(client_name);
764
765	maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname);
766	if (maj_stat)
767	    errx(1, "gss_import_name: %s",
768		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
769
770
771	if (password_string) {
772	    gss_auth_identity_desc identity;
773	    OM_uint32 major;
774	    char *u, *r;
775
776	    /*
777	     * set the cred out to the same a mech since gss_acquire_cred_ex_f really wants one.
778	     */
779
780	    if (credoid == NULL)
781		credoid = mechoid;
782
783	    u = strdup(client_name);
784	    if (u == NULL)
785		errx(1, "out of memory");
786
787	    r = strchr(u, '@');
788	    if (r)
789		*r++ = '\0';
790	    else
791		r = NULL;
792
793	    memset(&identity, 0, sizeof(identity));
794
795	    identity.username = u;
796	    identity.realm = r;
797	    identity.password = password_string;
798
799	    major = gss_acquire_cred_ex_f(NULL,
800					  cname,
801					  0,
802					  GSS_C_INDEFINITE,
803					  credoid,
804					  GSS_C_INITIATE,
805					  &identity,
806					  &client_cred,
807					  ac_complete);
808	    if (major)
809		errx(1, "gss_acquire_cred_ex_f: %d", (int)major);
810
811	    free(u);
812
813	} else {
814	    gss_OID_set mechs = GSS_C_NULL_OID_SET;
815
816	    if (credoid != GSS_C_NO_OID) {
817		maj_stat = gss_create_empty_oid_set(&min_stat, &mechs);
818		if (maj_stat != GSS_S_COMPLETE)
819		    errx(1, "gss_create_empty_oid_set: %s",
820			 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
821
822		maj_stat = gss_add_oid_set_member(&min_stat, credoid, &mechs);
823		if (maj_stat != GSS_S_COMPLETE)
824		    errx(1, "gss_add_oid_set_member: %s",
825			 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
826	    }
827
828	    maj_stat = gss_acquire_cred(&min_stat, cname, 0, mechs,
829					GSS_C_INITIATE, &client_cred, NULL, NULL);
830	    if (GSS_ERROR(maj_stat))
831		errx(1, "gss_import_name: %s",
832		     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
833
834	    if (mechs != GSS_C_NULL_OID_SET)
835		gss_release_oid_set(&min_stat, &mechs);
836	}
837	gss_release_name(&min_stat, &cname);
838
839    } else if (client_password) {
840	maj_stat = gss_acquire_cred_with_password(&min_stat,
841						  cname,
842						  &credential_data,
843						  GSS_C_INDEFINITE,
844						  GSS_C_NO_OID_SET,
845						  GSS_C_INITIATE,
846						  &client_cred,
847						  NULL,
848						  NULL);
849	if (GSS_ERROR(maj_stat))
850	    errx(1, "gss_acquire_cred_with_password: %s",
851		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
852    } else {
853	maj_stat = gss_acquire_cred(&min_stat,
854				    cname,
855				    GSS_C_INDEFINITE,
856				    GSS_C_NO_OID_SET,
857				    GSS_C_INITIATE,
858				    &client_cred,
859				    NULL,
860				    NULL);
861	if (GSS_ERROR(maj_stat))
862	    errx(1, "gss_acquire_cred: %s",
863		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
864    }
865
866    /*
867     * Check that GSS_C_NT_UUID works with IAKERB
868     */
869
870    if (client_cred && gss_oid_equal(GSS_IAKERB_MECHANISM, mechoid)) {
871	gss_buffer_set_t buffers;
872	gss_name_t tname;
873
874	maj_stat = gss_inquire_cred_by_oid(&min_stat, client_cred, GSS_C_NT_UUID, &buffers);
875	if (maj_stat)
876	    errx(1, "failed to find GSS_C_NT_UUID");
877
878	gss_release_cred(&min_stat, &client_cred);
879
880	if (buffers->count != 1)
881	    errx(1, "wrong number of buffers for GSS_C_UUID");
882
883	maj_stat = gss_import_name(&min_stat, &buffers->elements[0], GSS_C_NT_UUID, &tname);
884	if (maj_stat != GSS_S_COMPLETE)
885	    errx(1, "import name failed");
886
887	maj_stat = gss_acquire_cred(&min_stat, tname, GSS_C_INDEFINITE, NULL, GSS_C_INITIATE, &client_cred, NULL, NULL);
888	if (maj_stat != GSS_S_COMPLETE)
889	    errx(1, "acquire IAKERB failed");
890
891	gss_release_name(&min_stat, &tname);
892	gss_release_buffer_set(&min_stat, &buffers);
893    }
894
895    if (limit_enctype_string) {
896	krb5_error_code ret;
897
898	ret = krb5_string_to_enctype(context,
899				     limit_enctype_string,
900				     &limit_enctype);
901	if (ret)
902	    krb5_err(context, 1, ret, "krb5_string_to_enctype");
903    }
904
905
906    if (limit_enctype) {
907	if (client_cred == NULL)
908	    errx(1, "client_cred missing");
909
910	maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred,
911						   1, &limit_enctype);
912	if (maj_stat)
913	    errx(1, "gss_krb5_set_allowable_enctypes: %s",
914		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
915    }
916
917    /*
918     * generic tests.
919     */
920
921    ctx = GSS_C_NO_CONTEXT;
922
923    maj_stat = gss_inquire_context(&min_stat, NULL, NULL, NULL,
924				   NULL, NULL, NULL, NULL, NULL);
925    if (maj_stat != GSS_S_NO_CONTEXT)
926	errx(1, "gss_inquire_context didn't fail");
927
928    maj_stat = gss_export_sec_context(&min_stat, &cctx, &buffer);
929    if (maj_stat != GSS_S_NO_CONTEXT)
930	errx(1, "gss_export_sec_context didn't fail");
931
932    maj_stat = gss_export_sec_context(&min_stat, &cctx, NULL);
933    if (maj_stat != GSS_S_CALL_INACCESSIBLE_READ)
934	errx(1, "gss_export_sec_context didn't fail");
935
936
937    /*
938     *
939     */
940
941
942    loop(rk_UNCONST(mechoid), nameoid, argv[0], acceptor_name_string, client_cred, bindings,
943	 &sctx, &cctx, &actual_mech, &deleg_cred);
944
945    if (verbose_flag)
946	printf("resulting mech: %s\n", gss_oid_to_name(actual_mech));
947
948    check_inquire_context(sctx, "server");
949    check_inquire_context(cctx, "client");
950
951    if (ret_mech_string) {
952	gss_const_OID retoid;
953
954	retoid = gss_name_to_oid(ret_mech_string);
955
956	if (gss_oid_equal(retoid, actual_mech) == 0)
957	    errx(1, "actual_mech mech is not the expected type %s",
958		 ret_mech_string);
959    }
960
961    /* XXX should be actual_mech */
962    if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)
963	|| gss_oid_equal(mechoid, GSS_IAKERB_MECHANISM)
964#ifdef PKINIT
965	|| gss_oid_equal(mechoid, GSS_PKU2U_MECHANISM)
966#endif
967	) {
968	time_t time;
969	gss_buffer_desc authz_data;
970	gss_buffer_desc in, out1, out2;
971	krb5_keyblock *keyblock, *keyblock2;
972	krb5_timestamp now;
973	krb5_error_code ret;
974
975	ret = krb5_timeofday(context, &now);
976	if (ret)
977	    errx(1, "krb5_timeofday failed");
978
979	/* client */
980	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
981						     &cctx,
982						     1, /* version */
983						     &ctx);
984	if (maj_stat != GSS_S_COMPLETE)
985	    errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
986		 gssapi_err(maj_stat, min_stat, actual_mech));
987
988
989	maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx);
990	if (maj_stat != GSS_S_COMPLETE)
991	    errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
992		     gssapi_err(maj_stat, min_stat, actual_mech));
993
994	/* server */
995	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
996						     &sctx,
997						     1, /* version */
998						     &ctx);
999	if (maj_stat != GSS_S_COMPLETE)
1000	    errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
1001		     gssapi_err(maj_stat, min_stat, actual_mech));
1002	maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx);
1003	if (maj_stat != GSS_S_COMPLETE)
1004	    errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
1005		     gssapi_err(maj_stat, min_stat, actual_mech));
1006
1007 	maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
1008							     sctx,
1009							     &time);
1010	if (maj_stat != GSS_S_COMPLETE)
1011	    errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
1012		     gssapi_err(maj_stat, min_stat, actual_mech));
1013
1014	if (time > now)
1015	    errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
1016		 "time authtime is before now: %ld %ld",
1017		 (long)time, (long)now);
1018
1019 	maj_stat = gsskrb5_extract_service_keyblock(&min_stat,
1020						    sctx,
1021						    &keyblock);
1022	if (maj_stat != GSS_S_COMPLETE)
1023	    errx(1, "gsskrb5_export_service_keyblock failed: %s",
1024		     gssapi_err(maj_stat, min_stat, actual_mech));
1025
1026	krb5_free_keyblock(context, keyblock);
1027
1028 	maj_stat = gsskrb5_get_subkey(&min_stat,
1029				      sctx,
1030				      &keyblock);
1031	if (maj_stat != GSS_S_COMPLETE
1032	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
1033	    errx(1, "gsskrb5_get_subkey server failed: %s",
1034		     gssapi_err(maj_stat, min_stat, actual_mech));
1035
1036	if (maj_stat != GSS_S_COMPLETE)
1037	    keyblock = NULL;
1038	else if (limit_enctype && keyblock->keytype != limit_enctype)
1039	    errx(1, "gsskrb5_get_subkey wrong enctype");
1040
1041 	maj_stat = gsskrb5_get_subkey(&min_stat,
1042				      cctx,
1043				      &keyblock2);
1044	if (maj_stat != GSS_S_COMPLETE
1045	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
1046	    errx(1, "gsskrb5_get_subkey client failed: %s",
1047		     gssapi_err(maj_stat, min_stat, actual_mech));
1048
1049	if (maj_stat != GSS_S_COMPLETE)
1050	    keyblock2 = NULL;
1051	else if (limit_enctype && keyblock2->keytype != limit_enctype)
1052	    errx(1, "gsskrb5_get_subkey wrong enctype");
1053
1054	if (keyblock || keyblock2) {
1055	    if (keyblock == NULL)
1056		errx(1, "server missing token keyblock");
1057	    if (keyblock2 == NULL)
1058		errx(1, "client missing token keyblock");
1059
1060	    if (keyblock->keytype != keyblock2->keytype)
1061		errx(1, "enctype mismatch");
1062	    if (keyblock->keyvalue.length != keyblock2->keyvalue.length)
1063		errx(1, "key length mismatch");
1064	    if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data,
1065		       keyblock2->keyvalue.length) != 0)
1066		errx(1, "key data mismatch");
1067	}
1068
1069	if (session_enctype_string) {
1070	    krb5_enctype enctype;
1071
1072	    if (keyblock == NULL)
1073		errx(1, "expected keyblock, didn't get one");
1074
1075	    ret = krb5_string_to_enctype(context,
1076					 session_enctype_string,
1077					 &enctype);
1078
1079	    if (ret)
1080		krb5_err(context, 1, ret, "krb5_string_to_enctype");
1081
1082	    if (enctype != keyblock->keytype)
1083		errx(1, "keytype is not the expected %d != %d",
1084		     (int)enctype, (int)keyblock2->keytype);
1085	}
1086
1087	if (keyblock)
1088	    krb5_free_keyblock(context, keyblock);
1089	if (keyblock2)
1090	    krb5_free_keyblock(context, keyblock2);
1091
1092 	maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
1093						sctx,
1094						&keyblock);
1095	if (maj_stat != GSS_S_COMPLETE
1096	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
1097	    errx(1, "gsskrb5_get_initiator_subkey failed: %s",
1098		     gssapi_err(maj_stat, min_stat, actual_mech));
1099
1100	if (maj_stat == GSS_S_COMPLETE) {
1101
1102	    if (limit_enctype && keyblock->keytype != limit_enctype)
1103		errx(1, "gsskrb5_get_initiator_subkey wrong enctype");
1104	    krb5_free_keyblock(context, keyblock);
1105	}
1106
1107 	maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
1108							       sctx,
1109							       128,
1110							       &authz_data);
1111	if (maj_stat == GSS_S_COMPLETE)
1112	    gss_release_buffer(&min_stat, &authz_data);
1113
1114
1115	memset(&out1, 0, sizeof(out1));
1116	memset(&out2, 0, sizeof(out2));
1117
1118	in.value = "foo";
1119	in.length = 3;
1120
1121	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
1122			  100, &out1);
1123	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,
1124			  100, &out2);
1125
1126	if (out1.length != out2.length)
1127	    errx(1, "prf len mismatch");
1128	if (memcmp(out1.value, out2.value, out1.length) != 0)
1129	    errx(1, "prf data mismatch");
1130
1131	gss_release_buffer(&min_stat, &out1);
1132
1133	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
1134			  100, &out1);
1135
1136	if (out1.length != out2.length)
1137	    errx(1, "prf len mismatch");
1138	if (memcmp(out1.value, out2.value, out1.length) != 0)
1139	    errx(1, "prf data mismatch");
1140
1141	gss_release_buffer(&min_stat, &out1);
1142	gss_release_buffer(&min_stat, &out2);
1143
1144	in.value = "bar";
1145	in.length = 3;
1146
1147	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,
1148			  100, &out1);
1149	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,
1150			  100, &out2);
1151
1152	if (out1.length != out2.length)
1153	    errx(1, "prf len mismatch");
1154	if (memcmp(out1.value, out2.value, out1.length) != 0)
1155	    errx(1, "prf data mismatch");
1156
1157	gss_release_buffer(&min_stat, &out1);
1158	gss_release_buffer(&min_stat, &out2);
1159
1160	wrapunwrap_flag = 1;
1161	getverifymic_flag = 1;
1162#ifdef ENABLE_NTLM
1163    } else if (gss_oid_equal(mechoid, GSS_NTLM_MECHANISM)) {
1164
1165	gss_buffer_set_t cds, sds;
1166	int server_no_session_key = 0,
1167	    client_no_session_key = 0;
1168
1169	maj_stat = gss_inquire_sec_context_by_oid(&min_stat,
1170						  sctx,
1171						  GSS_NTLM_GET_SESSION_KEY_X,
1172						  &sds);
1173	if (min_stat != GSS_S_COMPLETE || sds->count != 1)
1174	    server_no_session_key = 1;
1175
1176	maj_stat = gss_inquire_sec_context_by_oid(&min_stat,
1177						  cctx,
1178						  GSS_NTLM_GET_SESSION_KEY_X,
1179						  &cds);
1180	if (min_stat != GSS_S_COMPLETE || cds->count != 1)
1181	    client_no_session_key = 1;
1182
1183	if (client_no_session_key && server_no_session_key) {
1184	    OM_uint32 sflags;
1185
1186	    sflags = 0;
1187	    maj_stat = gss_inquire_context(&min_stat, sctx,
1188					   NULL, NULL, NULL, NULL, &sflags, NULL, NULL);
1189	    if (maj_stat)
1190		errx(1, "inquire_context");
1191
1192	    if ((sflags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG)) != 0)
1193		errx(1, "ntlm: server no key but int|conf flag(s)!");
1194
1195	    sflags = 0;
1196	    maj_stat = gss_inquire_context(&min_stat, cctx,
1197					   NULL, NULL, NULL, NULL, &sflags, NULL, NULL);
1198	    if (maj_stat)
1199		errx(1, "inquire_context");
1200
1201	    if ((sflags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG)) != 0)
1202		errx(1, "ntlm: client no key but int|conf flag(s)!");
1203
1204	} else if (client_no_session_key) {
1205	    errx(1, "ntlm: server had session key, but not server???");
1206	} else if (server_no_session_key) {
1207	    OM_uint32 sflags = 0;
1208
1209	    /*
1210	     * This case is ok. Even though we didn't negotiated a
1211	     * session key, the library hands one out so the client
1212	     * can force use it if it wants too, useful for SMB2.
1213	     *
1214	     * just check that the client doesn't announce it support
1215	     * signing in the ntlm flags.
1216	     */
1217
1218	    maj_stat = gss_inquire_context(&min_stat, cctx,
1219					   NULL, NULL, NULL, NULL, &sflags, NULL, NULL);
1220	    if (maj_stat)
1221		errx(1, "inquire_context");
1222
1223	    if ((sflags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG)) != 0)
1224		errx(1, "ntlm: client had key, server not, client had int|conf flag(s)!");
1225
1226	    warnx("ntlm: server didn't get session key, that's ok");
1227	} else {
1228	    if (cds->elements[0].length != sds->elements[0].length)
1229		errx(1, "key length wrong");
1230
1231	    if (memcmp(cds->elements[0].value, sds->elements[0].value,
1232		       cds->elements[0].length) != 0)
1233		errx(1, "key data wrong");
1234	}
1235
1236	gss_release_buffer_set(&min_stat, &sds);
1237	gss_release_buffer_set(&min_stat, &cds);
1238#endif /* ENABLE_NTLM */
1239    }
1240
1241    if (wrapunwrap_flag) {
1242	wrapunwrap(cctx, sctx, 0, actual_mech);
1243	wrapunwrap(cctx, sctx, 1, actual_mech);
1244	wrapunwrap(sctx, cctx, 0, actual_mech);
1245	wrapunwrap(sctx, cctx, 1, actual_mech);
1246    }
1247
1248    if (iov_flag) {
1249	wrapunwrap_iov(cctx, sctx, 0, actual_mech);
1250	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1251	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
1252	wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
1253	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
1254
1255	wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
1256	wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1257	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1258	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1259
1260	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1261	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1262	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1263
1264/* works */
1265	wrapunwrap_iov(cctx, sctx, 0, actual_mech);
1266	wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
1267
1268	wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
1269	wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1270
1271	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY, actual_mech);
1272	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1273
1274	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech);
1275	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1276
1277	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
1278	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1279
1280	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
1281	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1282    }
1283
1284    if (getverifymic_flag) {
1285	getverifymic(cctx, sctx, actual_mech);
1286	getverifymic(cctx, sctx, actual_mech);
1287	getverifymic(sctx, cctx, actual_mech);
1288	getverifymic(sctx, cctx, actual_mech);
1289    }
1290
1291
1292    if (import_export_flag) {
1293	check_export_import_sec_context(&cctx, &sctx, actual_mech);
1294    }
1295
1296    gss_delete_sec_context(&min_stat, &cctx, NULL);
1297    gss_delete_sec_context(&min_stat, &sctx, NULL);
1298
1299    if (deleg_cred != GSS_C_NO_CREDENTIAL) {
1300	gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
1301	gss_buffer_desc cb;
1302
1303	if (verbose_flag)
1304	    printf("if we delegated, try again, this time o/o catching the cred\n");
1305	loop(rk_UNCONST(mechoid), nameoid, argv[0], acceptor_name_string, client_cred, bindings,
1306	     &sctx, &cctx, &actual_mech, NULL);
1307	gss_delete_sec_context(&min_stat, &cctx, NULL);
1308	gss_delete_sec_context(&min_stat, &sctx, NULL);
1309
1310	if (verbose_flag)
1311	    printf("checking actual mech (%s) on delegated cred\n",
1312		   gss_oid_to_name(actual_mech));
1313	loop(actual_mech, nameoid, argv[0], acceptor_name_string,
1314	     deleg_cred, bindings,
1315	     &sctx, &cctx, &actual_mech2, &cred2);
1316
1317	gss_delete_sec_context(&min_stat, &cctx, NULL);
1318	gss_delete_sec_context(&min_stat, &sctx, NULL);
1319
1320	gss_release_cred(&min_stat, &cred2);
1321
1322	/* try again using SPNEGO */
1323	if (verbose_flag)
1324	    printf("checking spnego on delegated cred\n");
1325	loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], acceptor_name_string,
1326	     deleg_cred, bindings, &sctx, &cctx,
1327	     &actual_mech2, &cred2);
1328
1329	gss_delete_sec_context(&min_stat, &cctx, NULL);
1330	gss_delete_sec_context(&min_stat, &sctx, NULL);
1331
1332	gss_release_cred(&min_stat, &cred2);
1333
1334	/* check export/import */
1335	if (ei_flag) {
1336
1337	    maj_stat = gss_export_cred(&min_stat, deleg_cred, &cb);
1338	    if (maj_stat != GSS_S_COMPLETE)
1339		errx(1, "export failed: %s",
1340		     gssapi_err(maj_stat, min_stat, NULL));
1341
1342	    maj_stat = gss_import_cred(&min_stat, &cb, &cred2);
1343	    if (maj_stat != GSS_S_COMPLETE)
1344		errx(1, "import failed: %s",
1345		     gssapi_err(maj_stat, min_stat, NULL));
1346
1347	    gss_release_buffer(&min_stat, &cb);
1348	    gss_release_cred(&min_stat, &deleg_cred);
1349
1350	    if (verbose_flag)
1351		printf("checking actual mech (%s) on export/imported cred\n",
1352		       gss_oid_to_name(actual_mech));
1353	    loop(actual_mech, nameoid, argv[0], acceptor_name_string,
1354		 cred2, bindings, &sctx, &cctx,
1355		 &actual_mech2, &deleg_cred);
1356
1357	    gss_release_cred(&min_stat, &deleg_cred);
1358
1359	    gss_delete_sec_context(&min_stat, &cctx, NULL);
1360	    gss_delete_sec_context(&min_stat, &sctx, NULL);
1361
1362	    /* try again using SPNEGO */
1363	    if (verbose_flag)
1364		printf("checking SPNEGO on export/imported cred\n");
1365	    loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], acceptor_name_string,
1366		 cred2, bindings, &sctx, &cctx,
1367		 &actual_mech2, &deleg_cred);
1368
1369	    gss_release_cred(&min_stat, &deleg_cred);
1370
1371	    gss_delete_sec_context(&min_stat, &cctx, NULL);
1372	    gss_delete_sec_context(&min_stat, &sctx, NULL);
1373
1374	    gss_release_cred(&min_stat, &cred2);
1375
1376	} else  {
1377	    gss_release_cred(&min_stat, &deleg_cred);
1378	}
1379
1380    }
1381
1382    empty_release();
1383
1384    check_sasl_names();
1385
1386    krb5_free_context(context);
1387
1388    return 0;
1389}
1390