1 /*	$NetBSD: test_context.c,v 1.1.1.2 2014/04/24 12:45:29 pettai Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * 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 <krb5/getarg.h>
39 #include <gssapi/gssapi.h>
40 #include <gssapi/gssapi_krb5.h>
41 #include <gssapi/gssapi_spnego.h>
42 #include <gssapi/gssapi_ntlm.h>
43 #include "test_common.h"
44 
45 static char *type_string;
46 static char *mech_string;
47 static char *ret_mech_string;
48 static char *client_name;
49 static char *client_password;
50 static int dns_canon_flag = -1;
51 static int mutual_auth_flag = 0;
52 static int dce_style_flag = 0;
53 static int wrapunwrap_flag = 0;
54 static int iov_flag = 0;
55 static int getverifymic_flag = 0;
56 static int deleg_flag = 0;
57 static int policy_deleg_flag = 0;
58 static int server_no_deleg_flag = 0;
59 static int ei_flag = 0;
60 static char *gsskrb5_acceptor_identity = NULL;
61 static char *session_enctype_string = NULL;
62 static int client_time_offset = 0;
63 static int server_time_offset = 0;
64 static int max_loops = 0;
65 static char *limit_enctype_string = NULL;
66 static int version_flag = 0;
67 static int verbose_flag = 0;
68 static int help_flag	= 0;
69 
70 static krb5_context context;
71 static krb5_enctype limit_enctype = 0;
72 
73 static struct {
74     const char *name;
75     gss_OID oid;
76 } o2n[] = {
77     { "krb5", NULL /* GSS_KRB5_MECHANISM */ },
78     { "spnego", NULL /* GSS_SPNEGO_MECHANISM */ },
79     { "ntlm", NULL /* GSS_NTLM_MECHANISM */ },
80     { "sasl-digest-md5", NULL /* GSS_SASL_DIGEST_MD5_MECHANISM */ }
81 };
82 
83 static void
init_o2n(void)84 init_o2n(void)
85 {
86     o2n[0].oid = GSS_KRB5_MECHANISM;
87     o2n[1].oid = GSS_SPNEGO_MECHANISM;
88     o2n[2].oid = GSS_NTLM_MECHANISM;
89     o2n[3].oid = GSS_SASL_DIGEST_MD5_MECHANISM;
90 }
91 
92 static gss_OID
string_to_oid(const char * name)93 string_to_oid(const char *name)
94 {
95     int i;
96     for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
97 	if (strcasecmp(name, o2n[i].name) == 0)
98 	    return o2n[i].oid;
99     errx(1, "name '%s' not unknown", name);
100 }
101 
102 static const char *
oid_to_string(const gss_OID oid)103 oid_to_string(const gss_OID oid)
104 {
105     int i;
106     for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++)
107 	if (gss_oid_equal(oid, o2n[i].oid))
108 	    return o2n[i].name;
109     return "unknown oid";
110 }
111 
112 static void
loop(gss_OID mechoid,gss_OID nameoid,const char * target,gss_cred_id_t init_cred,gss_ctx_id_t * sctx,gss_ctx_id_t * cctx,gss_OID * actual_mech,gss_cred_id_t * deleg_cred)113 loop(gss_OID mechoid,
114      gss_OID nameoid, const char *target,
115      gss_cred_id_t init_cred,
116      gss_ctx_id_t *sctx, gss_ctx_id_t *cctx,
117      gss_OID *actual_mech,
118      gss_cred_id_t *deleg_cred)
119 {
120     int server_done = 0, client_done = 0;
121     int num_loops = 0;
122     OM_uint32 maj_stat, min_stat;
123     gss_name_t gss_target_name;
124     gss_buffer_desc input_token, output_token;
125     OM_uint32 flags = 0, ret_cflags, ret_sflags;
126     gss_OID actual_mech_client;
127     gss_OID actual_mech_server;
128 
129     *actual_mech = GSS_C_NO_OID;
130 
131     flags |= GSS_C_INTEG_FLAG;
132     flags |= GSS_C_CONF_FLAG;
133 
134     if (mutual_auth_flag)
135 	flags |= GSS_C_MUTUAL_FLAG;
136     if (dce_style_flag)
137 	flags |= GSS_C_DCE_STYLE;
138     if (deleg_flag)
139 	flags |= GSS_C_DELEG_FLAG;
140     if (policy_deleg_flag)
141 	flags |= GSS_C_DELEG_POLICY_FLAG;
142 
143     input_token.value = rk_UNCONST(target);
144     input_token.length = strlen(target);
145 
146     maj_stat = gss_import_name(&min_stat,
147 			       &input_token,
148 			       nameoid,
149 			       &gss_target_name);
150     if (GSS_ERROR(maj_stat))
151 	err(1, "import name creds failed with: %d", maj_stat);
152 
153     input_token.length = 0;
154     input_token.value = NULL;
155 
156     while (!server_done || !client_done) {
157 	num_loops++;
158 
159 	gsskrb5_set_time_offset(client_time_offset);
160 
161 	maj_stat = gss_init_sec_context(&min_stat,
162 					init_cred,
163 					cctx,
164 					gss_target_name,
165 					mechoid,
166 					flags,
167 					0,
168 					NULL,
169 					&input_token,
170 					&actual_mech_client,
171 					&output_token,
172 					&ret_cflags,
173 					NULL);
174 	if (GSS_ERROR(maj_stat))
175 	    errx(1, "init_sec_context: %s",
176 		 gssapi_err(maj_stat, min_stat, mechoid));
177 	if (maj_stat & GSS_S_CONTINUE_NEEDED)
178 	    ;
179 	else
180 	    client_done = 1;
181 
182 	gsskrb5_get_time_offset(&client_time_offset);
183 
184 	if (client_done && server_done)
185 	    break;
186 
187 	if (input_token.length != 0)
188 	    gss_release_buffer(&min_stat, &input_token);
189 
190 	gsskrb5_set_time_offset(server_time_offset);
191 
192 	maj_stat = gss_accept_sec_context(&min_stat,
193 					  sctx,
194 					  GSS_C_NO_CREDENTIAL,
195 					  &output_token,
196 					  GSS_C_NO_CHANNEL_BINDINGS,
197 					  NULL,
198 					  &actual_mech_server,
199 					  &input_token,
200 					  &ret_sflags,
201 					  NULL,
202 					  deleg_cred);
203 	if (GSS_ERROR(maj_stat))
204 		errx(1, "accept_sec_context: %s",
205 		     gssapi_err(maj_stat, min_stat, actual_mech_server));
206 
207 	gsskrb5_get_time_offset(&server_time_offset);
208 
209 	if (output_token.length != 0)
210 	    gss_release_buffer(&min_stat, &output_token);
211 
212 	if (maj_stat & GSS_S_CONTINUE_NEEDED)
213 	    ;
214 	else
215 	    server_done = 1;
216     }
217     if (output_token.length != 0)
218 	gss_release_buffer(&min_stat, &output_token);
219     if (input_token.length != 0)
220 	gss_release_buffer(&min_stat, &input_token);
221     gss_release_name(&min_stat, &gss_target_name);
222 
223     if (deleg_flag || policy_deleg_flag) {
224 	if (server_no_deleg_flag) {
225 	    if (*deleg_cred != GSS_C_NO_CREDENTIAL)
226 		errx(1, "got delegated cred but didn't expect one");
227 	} else if (*deleg_cred == GSS_C_NO_CREDENTIAL)
228 	    errx(1, "asked for delegarated cred but did get one");
229     } else if (*deleg_cred != GSS_C_NO_CREDENTIAL)
230 	  errx(1, "got deleg_cred cred but didn't ask");
231 
232     if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0)
233 	errx(1, "mech mismatch");
234     *actual_mech = actual_mech_server;
235 
236     if (max_loops && num_loops > max_loops)
237 	errx(1, "num loops %d was lager then max loops %d",
238 	     num_loops, max_loops);
239 
240     if (verbose_flag) {
241 	printf("server time offset: %d\n", server_time_offset);
242 	printf("client time offset: %d\n", client_time_offset);
243 	printf("num loops %d\n", num_loops);
244     }
245 }
246 
247 static void
wrapunwrap(gss_ctx_id_t cctx,gss_ctx_id_t sctx,int flags,gss_OID mechoid)248 wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
249 {
250     gss_buffer_desc input_token, output_token, output_token2;
251     OM_uint32 min_stat, maj_stat;
252     gss_qop_t qop_state;
253     int conf_state;
254 
255     input_token.value = "foo";
256     input_token.length = 3;
257 
258     maj_stat = gss_wrap(&min_stat, cctx, flags, 0, &input_token,
259 			&conf_state, &output_token);
260     if (maj_stat != GSS_S_COMPLETE)
261 	errx(1, "gss_wrap failed: %s",
262 	     gssapi_err(maj_stat, min_stat, mechoid));
263 
264     maj_stat = gss_unwrap(&min_stat, sctx, &output_token,
265 			  &output_token2, &conf_state, &qop_state);
266     if (maj_stat != GSS_S_COMPLETE)
267 	errx(1, "gss_unwrap failed: %s",
268 	     gssapi_err(maj_stat, min_stat, mechoid));
269 
270     gss_release_buffer(&min_stat, &output_token);
271     gss_release_buffer(&min_stat, &output_token2);
272 
273 #if 0 /* doesn't work for NTLM yet */
274     if (!!conf_state != !!flags)
275 	errx(1, "conf_state mismatch");
276 #endif
277 }
278 
279 #define USE_CONF		1
280 #define USE_HEADER_ONLY		2
281 #define USE_SIGN_ONLY		4
282 #define FORCE_IOV		8
283 
284 static void
wrapunwrap_iov(gss_ctx_id_t cctx,gss_ctx_id_t sctx,int flags,gss_OID mechoid)285 wrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
286 {
287     krb5_data token, header, trailer;
288     OM_uint32 min_stat, maj_stat;
289     gss_qop_t qop_state;
290     int conf_state, conf_state2;
291     gss_iov_buffer_desc iov[6];
292     unsigned char *p;
293     int iov_len;
294     char header_data[9] = "ABCheader";
295     char trailer_data[10] = "trailerXYZ";
296 
297     char token_data[16] = "0123456789abcdef";
298 
299     memset(&iov, 0, sizeof(iov));
300 
301     if (flags & USE_SIGN_ONLY) {
302 	header.data = header_data;
303 	header.length = 9;
304 	trailer.data = trailer_data;
305 	trailer.length = 10;
306     } else {
307 	header.data = NULL;
308 	header.length = 0;
309 	trailer.data = NULL;
310 	trailer.length = 0;
311     }
312 
313     token.data = token_data;
314     token.length = 16;
315 
316     iov_len = sizeof(iov)/sizeof(iov[0]);
317 
318     memset(iov, 0, sizeof(iov));
319 
320     iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
321 
322     if (header.length != 0) {
323 	iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
324 	iov[1].buffer.length = header.length;
325 	iov[1].buffer.value = header.data;
326     } else {
327 	iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
328 	iov[1].buffer.length = 0;
329 	iov[1].buffer.value = NULL;
330     }
331     iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
332     iov[2].buffer.length = token.length;
333     iov[2].buffer.value = token.data;
334     if (trailer.length != 0) {
335 	iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
336 	iov[3].buffer.length = trailer.length;
337 	iov[3].buffer.value = trailer.data;
338     } else {
339 	iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
340 	iov[3].buffer.length = 0;
341 	iov[3].buffer.value = NULL;
342     }
343     if (dce_style_flag) {
344 	iov[4].type = GSS_IOV_BUFFER_TYPE_EMPTY;
345     } else {
346 	iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
347     }
348     iov[4].buffer.length = 0;
349     iov[4].buffer.value = 0;
350     if (dce_style_flag) {
351 	iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
352     } else if (flags & USE_HEADER_ONLY) {
353 	iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
354     } else {
355 	iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE;
356     }
357     iov[5].buffer.length = 0;
358     iov[5].buffer.value = 0;
359 
360     maj_stat = gss_wrap_iov(&min_stat, cctx, dce_style_flag || flags & USE_CONF, 0, &conf_state,
361 			    iov, iov_len);
362     if (maj_stat != GSS_S_COMPLETE)
363 	errx(1, "gss_wrap_iov failed");
364 
365     token.length =
366 	iov[0].buffer.length +
367 	iov[1].buffer.length +
368 	iov[2].buffer.length +
369 	iov[3].buffer.length +
370 	iov[4].buffer.length +
371 	iov[5].buffer.length;
372     token.data = emalloc(token.length);
373 
374     p = token.data;
375     memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
376     p += iov[0].buffer.length;
377     memcpy(p, iov[1].buffer.value, iov[1].buffer.length);
378     p += iov[1].buffer.length;
379     memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
380     p += iov[2].buffer.length;
381     memcpy(p, iov[3].buffer.value, iov[3].buffer.length);
382     p += iov[3].buffer.length;
383     memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
384     p += iov[4].buffer.length;
385     memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
386     p += iov[5].buffer.length;
387 
388     assert(p - ((unsigned char *)token.data) == token.length);
389 
390     if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) {
391 	gss_buffer_desc input, output;
392 
393 	input.value = token.data;
394 	input.length = token.length;
395 
396 	maj_stat = gss_unwrap(&min_stat, sctx, &input,
397 			      &output, &conf_state2, &qop_state);
398 
399 	if (maj_stat != GSS_S_COMPLETE)
400 	    errx(1, "gss_unwrap from gss_wrap_iov failed: %s",
401 		 gssapi_err(maj_stat, min_stat, mechoid));
402 
403 	gss_release_buffer(&min_stat, &output);
404     } else {
405 	maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state,
406 				  iov, iov_len);
407 
408 	if (maj_stat != GSS_S_COMPLETE)
409 	    errx(1, "gss_unwrap_iov failed: %x %s", flags,
410 		 gssapi_err(maj_stat, min_stat, mechoid));
411 
412     }
413     if (conf_state2 != conf_state)
414 	errx(1, "conf state wrong for iov: %x", flags);
415 
416 
417     free(token.data);
418 }
419 
420 static void
getverifymic(gss_ctx_id_t cctx,gss_ctx_id_t sctx,gss_OID mechoid)421 getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)
422 {
423     gss_buffer_desc input_token, output_token;
424     OM_uint32 min_stat, maj_stat;
425     gss_qop_t qop_state;
426 
427     input_token.value = "bar";
428     input_token.length = 3;
429 
430     maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token,
431 			   &output_token);
432     if (maj_stat != GSS_S_COMPLETE)
433 	errx(1, "gss_get_mic failed: %s",
434 	     gssapi_err(maj_stat, min_stat, mechoid));
435 
436     maj_stat = gss_verify_mic(&min_stat, sctx, &input_token,
437 			      &output_token, &qop_state);
438     if (maj_stat != GSS_S_COMPLETE)
439 	errx(1, "gss_verify_mic failed: %s",
440 	     gssapi_err(maj_stat, min_stat, mechoid));
441 
442     gss_release_buffer(&min_stat, &output_token);
443 }
444 
445 static void
empty_release(void)446 empty_release(void)
447 {
448     gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
449     gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
450     gss_name_t name = GSS_C_NO_NAME;
451     gss_OID_set oidset = GSS_C_NO_OID_SET;
452     OM_uint32 junk;
453 
454     gss_delete_sec_context(&junk, &ctx, NULL);
455     gss_release_cred(&junk, &cred);
456     gss_release_name(&junk, &name);
457     gss_release_oid_set(&junk, &oidset);
458 }
459 
460 /*
461  *
462  */
463 
464 static struct getargs args[] = {
465     {"name-type",0,	arg_string, &type_string,  "type of name", NULL },
466     {"mech-type",0,	arg_string, &mech_string,  "type of mech", NULL },
467     {"ret-mech-type",0,	arg_string, &ret_mech_string,
468      "type of return mech", NULL },
469     {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag,
470      "use dns to canonicalize", NULL },
471     {"mutual-auth",0,	arg_flag,	&mutual_auth_flag,"mutual auth", NULL },
472     {"client-name", 0,  arg_string,     &client_name, "client name", NULL },
473     {"client-password", 0,  arg_string, &client_password, "client password", NULL },
474     {"limit-enctype",0,	arg_string,	&limit_enctype_string, "enctype", NULL },
475     {"dce-style",0,	arg_flag,	&dce_style_flag, "dce-style", NULL },
476     {"wrapunwrap",0,	arg_flag,	&wrapunwrap_flag, "wrap/unwrap", NULL },
477     {"iov", 0, 		arg_flag,	&iov_flag, "wrap/unwrap iov", NULL },
478     {"getverifymic",0,	arg_flag,	&getverifymic_flag,
479      "get and verify mic", NULL },
480     {"delegate",0,	arg_flag,	&deleg_flag, "delegate credential", NULL },
481     {"policy-delegate",0,	arg_flag,	&policy_deleg_flag, "policy delegate credential", NULL },
482     {"server-no-delegate",0,	arg_flag,	&server_no_deleg_flag,
483      "server should get a credential", NULL },
484     {"export-import-cred",0,	arg_flag,	&ei_flag, "test export/import cred", NULL },
485     {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL },
486     {"session-enctype",	0, arg_string,	&session_enctype_string, "enctype", NULL },
487     {"client-time-offset",	0, arg_integer,	&client_time_offset, "time", NULL },
488     {"server-time-offset",	0, arg_integer,	&server_time_offset, "time", NULL },
489     {"max-loops",	0, arg_integer,	&max_loops, "time", NULL },
490     {"version",	0,	arg_flag,	&version_flag, "print version", NULL },
491     {"verbose",	'v',	arg_flag,	&verbose_flag, "verbose", NULL },
492     {"help",	0,	arg_flag,	&help_flag,  NULL, NULL }
493 };
494 
495 static void
usage(int ret)496 usage (int ret)
497 {
498     arg_printusage (args, sizeof(args)/sizeof(*args),
499 		    NULL, "service@host");
500     exit (ret);
501 }
502 
503 int
main(int argc,char ** argv)504 main(int argc, char **argv)
505 {
506     int optind = 0;
507     OM_uint32 min_stat, maj_stat;
508     gss_ctx_id_t cctx, sctx;
509     void *ctx;
510     gss_OID nameoid, mechoid, actual_mech, actual_mech2;
511     gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL, deleg_cred = GSS_C_NO_CREDENTIAL;
512     gss_name_t cname = GSS_C_NO_NAME;
513     gss_buffer_desc credential_data = GSS_C_EMPTY_BUFFER;
514 
515     setprogname(argv[0]);
516 
517     init_o2n();
518 
519     if (krb5_init_context(&context))
520 	errx(1, "krb5_init_context");
521 
522     cctx = sctx = GSS_C_NO_CONTEXT;
523 
524     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))
525 	usage(1);
526 
527     if (help_flag)
528 	usage (0);
529 
530     if(version_flag){
531 	print_version(NULL);
532 	exit(0);
533     }
534 
535     argc -= optind;
536     argv += optind;
537 
538     if (argc != 1)
539 	usage(1);
540 
541     if (dns_canon_flag != -1)
542 	gsskrb5_set_dns_canonicalize(dns_canon_flag);
543 
544     if (type_string == NULL)
545 	nameoid = GSS_C_NT_HOSTBASED_SERVICE;
546     else if (strcmp(type_string, "hostbased-service") == 0)
547 	nameoid = GSS_C_NT_HOSTBASED_SERVICE;
548     else if (strcmp(type_string, "krb5-principal-name") == 0)
549 	nameoid = GSS_KRB5_NT_PRINCIPAL_NAME;
550     else
551 	errx(1, "%s not suppported", type_string);
552 
553     if (mech_string == NULL)
554 	mechoid = GSS_KRB5_MECHANISM;
555     else
556 	mechoid = string_to_oid(mech_string);
557 
558     if (gsskrb5_acceptor_identity) {
559 	maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity);
560 	if (maj_stat)
561 	    errx(1, "gsskrb5_acceptor_identity: %s",
562 		 gssapi_err(maj_stat, 0, GSS_C_NO_OID));
563     }
564 
565     if (client_password) {
566 	credential_data.value = client_password;
567 	credential_data.length = strlen(client_password);
568     }
569 
570     if (client_name) {
571 	gss_buffer_desc cn;
572 
573 	cn.value = client_name;
574 	cn.length = strlen(client_name);
575 
576 	maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname);
577 	if (maj_stat)
578 	    errx(1, "gss_import_name: %s",
579 		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
580     }
581 
582     if (client_password) {
583 	maj_stat = gss_acquire_cred_with_password(&min_stat,
584 						  cname,
585 						  &credential_data,
586 						  GSS_C_INDEFINITE,
587 						  GSS_C_NO_OID_SET,
588 						  GSS_C_INITIATE,
589 						  &client_cred,
590 						  NULL,
591 						  NULL);
592 	if (GSS_ERROR(maj_stat))
593 	    errx(1, "gss_acquire_cred_with_password: %s",
594 		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
595     } else {
596 	maj_stat = gss_acquire_cred(&min_stat,
597 				    cname,
598 				    GSS_C_INDEFINITE,
599 				    GSS_C_NO_OID_SET,
600 				    GSS_C_INITIATE,
601 				    &client_cred,
602 				    NULL,
603 				    NULL);
604 	if (GSS_ERROR(maj_stat))
605 	    errx(1, "gss_acquire_cred: %s",
606 		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
607     }
608 
609     if (limit_enctype_string) {
610 	krb5_error_code ret;
611 
612 	ret = krb5_string_to_enctype(context,
613 				     limit_enctype_string,
614 				     &limit_enctype);
615 	if (ret)
616 	    krb5_err(context, 1, ret, "krb5_string_to_enctype");
617     }
618 
619 
620     if (limit_enctype) {
621 	if (client_cred == NULL)
622 	    errx(1, "client_cred missing");
623 
624 	maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred,
625 						   1, &limit_enctype);
626 	if (maj_stat)
627 	    errx(1, "gss_krb5_set_allowable_enctypes: %s",
628 		 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
629     }
630 
631     loop(mechoid, nameoid, argv[0], client_cred,
632 	 &sctx, &cctx, &actual_mech, &deleg_cred);
633 
634     if (verbose_flag)
635 	printf("resulting mech: %s\n", oid_to_string(actual_mech));
636 
637     if (ret_mech_string) {
638 	gss_OID retoid;
639 
640 	retoid = string_to_oid(ret_mech_string);
641 
642 	if (gss_oid_equal(retoid, actual_mech) == 0)
643 	    errx(1, "actual_mech mech is not the expected type %s",
644 		 ret_mech_string);
645     }
646 
647     /* XXX should be actual_mech */
648     if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) {
649 	time_t time;
650 	gss_buffer_desc authz_data;
651 	gss_buffer_desc in, out1, out2;
652 	krb5_keyblock *keyblock, *keyblock2;
653 	krb5_timestamp now;
654 	krb5_error_code ret;
655 
656 	ret = krb5_timeofday(context, &now);
657 	if (ret)
658 	    errx(1, "krb5_timeofday failed");
659 
660 	/* client */
661 	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
662 						     &cctx,
663 						     1, /* version */
664 						     &ctx);
665 	if (maj_stat != GSS_S_COMPLETE)
666 	    errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
667 		 gssapi_err(maj_stat, min_stat, actual_mech));
668 
669 
670 	maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx);
671 	if (maj_stat != GSS_S_COMPLETE)
672 	    errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
673 		     gssapi_err(maj_stat, min_stat, actual_mech));
674 
675 	/* server */
676 	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
677 						     &sctx,
678 						     1, /* version */
679 						     &ctx);
680 	if (maj_stat != GSS_S_COMPLETE)
681 	    errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
682 		     gssapi_err(maj_stat, min_stat, actual_mech));
683 	maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx);
684 	if (maj_stat != GSS_S_COMPLETE)
685 	    errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
686 		     gssapi_err(maj_stat, min_stat, actual_mech));
687 
688  	maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
689 							     sctx,
690 							     &time);
691 	if (maj_stat != GSS_S_COMPLETE)
692 	    errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
693 		     gssapi_err(maj_stat, min_stat, actual_mech));
694 
695 	if (time > now)
696 	    errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
697 		 "time authtime is before now: %ld %ld",
698 		 (long)time, (long)now);
699 
700  	maj_stat = gsskrb5_extract_service_keyblock(&min_stat,
701 						    sctx,
702 						    &keyblock);
703 	if (maj_stat != GSS_S_COMPLETE)
704 	    errx(1, "gsskrb5_export_service_keyblock failed: %s",
705 		     gssapi_err(maj_stat, min_stat, actual_mech));
706 
707 	krb5_free_keyblock(context, keyblock);
708 
709  	maj_stat = gsskrb5_get_subkey(&min_stat,
710 				      sctx,
711 				      &keyblock);
712 	if (maj_stat != GSS_S_COMPLETE
713 	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
714 	    errx(1, "gsskrb5_get_subkey server failed: %s",
715 		     gssapi_err(maj_stat, min_stat, actual_mech));
716 
717 	if (maj_stat != GSS_S_COMPLETE)
718 	    keyblock = NULL;
719 	else if (limit_enctype && keyblock->keytype != limit_enctype)
720 	    errx(1, "gsskrb5_get_subkey wrong enctype");
721 
722  	maj_stat = gsskrb5_get_subkey(&min_stat,
723 				      cctx,
724 				      &keyblock2);
725 	if (maj_stat != GSS_S_COMPLETE
726 	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
727 	    errx(1, "gsskrb5_get_subkey client failed: %s",
728 		     gssapi_err(maj_stat, min_stat, actual_mech));
729 
730 	if (maj_stat != GSS_S_COMPLETE)
731 	    keyblock2 = NULL;
732 	else if (limit_enctype && keyblock->keytype != limit_enctype)
733 	    errx(1, "gsskrb5_get_subkey wrong enctype");
734 
735 	if (keyblock || keyblock2) {
736 	    if (keyblock == NULL)
737 		errx(1, "server missing token keyblock");
738 	    if (keyblock2 == NULL)
739 		errx(1, "client missing token keyblock");
740 
741 	    if (keyblock->keytype != keyblock2->keytype)
742 		errx(1, "enctype mismatch");
743 	    if (keyblock->keyvalue.length != keyblock2->keyvalue.length)
744 		errx(1, "key length mismatch");
745 	    if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data,
746 		       keyblock2->keyvalue.length) != 0)
747 		errx(1, "key data mismatch");
748 	}
749 
750 	if (session_enctype_string) {
751 	    krb5_enctype enctype;
752 
753 	    ret = krb5_string_to_enctype(context,
754 					 session_enctype_string,
755 					 &enctype);
756 
757 	    if (ret)
758 		krb5_err(context, 1, ret, "krb5_string_to_enctype");
759 
760 	    if (enctype != keyblock->keytype)
761 		errx(1, "keytype is not the expected %d != %d",
762 		     (int)enctype, (int)keyblock2->keytype);
763 	}
764 
765 	if (keyblock)
766 	    krb5_free_keyblock(context, keyblock);
767 	if (keyblock2)
768 	    krb5_free_keyblock(context, keyblock2);
769 
770  	maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
771 						sctx,
772 						&keyblock);
773 	if (maj_stat != GSS_S_COMPLETE
774 	    && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
775 	    errx(1, "gsskrb5_get_initiator_subkey failed: %s",
776 		     gssapi_err(maj_stat, min_stat, actual_mech));
777 
778 	if (maj_stat == GSS_S_COMPLETE) {
779 
780 	    if (limit_enctype && keyblock->keytype != limit_enctype)
781 		errx(1, "gsskrb5_get_initiator_subkey wrong enctype");
782 	    krb5_free_keyblock(context, keyblock);
783 	}
784 
785  	maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
786 							       sctx,
787 							       128,
788 							       &authz_data);
789 	if (maj_stat == GSS_S_COMPLETE)
790 	    gss_release_buffer(&min_stat, &authz_data);
791 
792 
793 	memset(&out1, 0, sizeof(out1));
794 	memset(&out2, 0, sizeof(out2));
795 
796 	in.value = "foo";
797 	in.length = 3;
798 
799 	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
800 			  100, &out1);
801 	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,
802 			  100, &out2);
803 
804 	if (out1.length != out2.length)
805 	    errx(1, "prf len mismatch");
806 	if (memcmp(out1.value, out2.value, out1.length) != 0)
807 	    errx(1, "prf data mismatch");
808 
809 	gss_release_buffer(&min_stat, &out1);
810 
811 	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
812 			  100, &out1);
813 
814 	if (out1.length != out2.length)
815 	    errx(1, "prf len mismatch");
816 	if (memcmp(out1.value, out2.value, out1.length) != 0)
817 	    errx(1, "prf data mismatch");
818 
819 	gss_release_buffer(&min_stat, &out1);
820 	gss_release_buffer(&min_stat, &out2);
821 
822 	in.value = "bar";
823 	in.length = 3;
824 
825 	gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,
826 			  100, &out1);
827 	gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,
828 			  100, &out2);
829 
830 	if (out1.length != out2.length)
831 	    errx(1, "prf len mismatch");
832 	if (memcmp(out1.value, out2.value, out1.length) != 0)
833 	    errx(1, "prf data mismatch");
834 
835 	gss_release_buffer(&min_stat, &out1);
836 	gss_release_buffer(&min_stat, &out2);
837 
838 	wrapunwrap_flag = 1;
839 	getverifymic_flag = 1;
840     }
841 
842     if (wrapunwrap_flag) {
843 	wrapunwrap(cctx, sctx, 0, actual_mech);
844 	wrapunwrap(cctx, sctx, 1, actual_mech);
845 	wrapunwrap(sctx, cctx, 0, actual_mech);
846 	wrapunwrap(sctx, cctx, 1, actual_mech);
847     }
848 
849     if (iov_flag) {
850 	wrapunwrap_iov(cctx, sctx, 0, actual_mech);
851 	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
852 	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
853 	wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
854 	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
855 
856 	wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
857 	wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
858 	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
859 	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
860 
861 	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
862 	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
863 	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
864 
865 /* works */
866 	wrapunwrap_iov(cctx, sctx, 0, actual_mech);
867 	wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
868 
869 	wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
870 	wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
871 
872 	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY, actual_mech);
873 	wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
874 
875 	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech);
876 	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
877 
878 	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
879 	wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
880 
881 	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
882 	wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
883     }
884 
885     if (getverifymic_flag) {
886 	getverifymic(cctx, sctx, actual_mech);
887 	getverifymic(cctx, sctx, actual_mech);
888 	getverifymic(sctx, cctx, actual_mech);
889 	getverifymic(sctx, cctx, actual_mech);
890     }
891 
892 
893     gss_delete_sec_context(&min_stat, &cctx, NULL);
894     gss_delete_sec_context(&min_stat, &sctx, NULL);
895 
896     if (deleg_cred != GSS_C_NO_CREDENTIAL) {
897 	gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
898 	gss_buffer_desc cb;
899 
900 	if (verbose_flag)
901 	    printf("checking actual mech (%s) on delegated cred\n",
902 		   oid_to_string(actual_mech));
903 	loop(actual_mech, nameoid, argv[0], deleg_cred, &sctx, &cctx, &actual_mech2, &cred2);
904 
905 	gss_delete_sec_context(&min_stat, &cctx, NULL);
906 	gss_delete_sec_context(&min_stat, &sctx, NULL);
907 
908 	gss_release_cred(&min_stat, &cred2);
909 
910 	/* try again using SPNEGO */
911 	if (verbose_flag)
912 	    printf("checking spnego on delegated cred\n");
913 	loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], deleg_cred, &sctx, &cctx,
914 	     &actual_mech2, &cred2);
915 
916 	gss_delete_sec_context(&min_stat, &cctx, NULL);
917 	gss_delete_sec_context(&min_stat, &sctx, NULL);
918 
919 	gss_release_cred(&min_stat, &cred2);
920 
921 	/* check export/import */
922 	if (ei_flag) {
923 
924 	    maj_stat = gss_export_cred(&min_stat, deleg_cred, &cb);
925 	    if (maj_stat != GSS_S_COMPLETE)
926 		errx(1, "export failed: %s",
927 		     gssapi_err(maj_stat, min_stat, NULL));
928 
929 	    maj_stat = gss_import_cred(&min_stat, &cb, &cred2);
930 	    if (maj_stat != GSS_S_COMPLETE)
931 		errx(1, "import failed: %s",
932 		     gssapi_err(maj_stat, min_stat, NULL));
933 
934 	    gss_release_buffer(&min_stat, &cb);
935 	    gss_release_cred(&min_stat, &deleg_cred);
936 
937 	    if (verbose_flag)
938 		printf("checking actual mech (%s) on export/imported cred\n",
939 		       oid_to_string(actual_mech));
940 	    loop(actual_mech, nameoid, argv[0], cred2, &sctx, &cctx,
941 		 &actual_mech2, &deleg_cred);
942 
943 	    gss_release_cred(&min_stat, &deleg_cred);
944 
945 	    gss_delete_sec_context(&min_stat, &cctx, NULL);
946 	    gss_delete_sec_context(&min_stat, &sctx, NULL);
947 
948 	    /* try again using SPNEGO */
949 	    if (verbose_flag)
950 		printf("checking SPNEGO on export/imported cred\n");
951 	    loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], cred2, &sctx, &cctx,
952 		 &actual_mech2, &deleg_cred);
953 
954 	    gss_release_cred(&min_stat, &deleg_cred);
955 
956 	    gss_delete_sec_context(&min_stat, &cctx, NULL);
957 	    gss_delete_sec_context(&min_stat, &sctx, NULL);
958 
959 	    gss_release_cred(&min_stat, &cred2);
960 
961 	} else  {
962 	    gss_release_cred(&min_stat, &deleg_cred);
963 	}
964 
965     }
966 
967     empty_release();
968 
969     krb5_free_context(context);
970 
971     return 0;
972 }
973