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