HEIMDAL: move code from source4/heimdal* to third_party/heimdal*
[samba.git] / third_party / heimdal / 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 #ifdef NOTYET
44 /*
45  * export/import of sec contexts on the initiator side
46  * don't work properly, yet.
47  */
48 #define DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT 1
49 #endif
50
51 static char *type_string;
52 static char *mech_string;
53 static char *mechs_string;
54 static char *ret_mech_string;
55 static char *localname_string;
56 static char *client_name;
57 static char *client_password;
58 static char *localname_string;
59 static int dns_canon_flag = -1;
60 static int mutual_auth_flag = 0;
61 static int dce_style_flag = 0;
62 static int wrapunwrap_flag = 0;
63 static int iov_flag = 0;
64 static int aead_flag = 0;
65 static int getverifymic_flag = 0;
66 static int deleg_flag = 0;
67 static int anon_flag = 0;
68 static int policy_deleg_flag = 0;
69 static int server_no_deleg_flag = 0;
70 static int ei_cred_flag = 0;
71 static int ei_ctx_flag = 0;
72 static char *client_ccache = NULL;
73 static char *client_keytab = NULL;
74 static char *gsskrb5_acceptor_identity = NULL;
75 static char *session_enctype_string = NULL;
76 static int client_time_offset = 0;
77 static int server_time_offset = 0;
78 static int max_loops = 0;
79 static char *limit_enctype_string = NULL;
80 static int token_split  = 0;
81 static int version_flag = 0;
82 static int verbose_flag = 0;
83 static int help_flag    = 0;
84 static char *i_channel_bindings = NULL;
85 static char *a_channel_bindings = NULL;
86
87 static krb5_context context;
88 static krb5_enctype limit_enctype = 0;
89
90 static gss_OID
91 string_to_oid(const char *name)
92 {
93     gss_OID oid = gss_name_to_oid(name);
94
95     if (oid == GSS_C_NO_OID)
96         errx(1, "name '%s' not known", name);
97
98     return oid;
99 }
100
101 static void
102 string_to_oids(gss_OID_set *oidsetp, char *names)
103 {
104     OM_uint32 maj_stat, min_stat;
105     char *name;
106     char *s;
107
108     if (names[0] == '\0') {
109         *oidsetp = GSS_C_NO_OID_SET;
110         return;
111     }
112
113     if (strcasecmp(names, "all") == 0) {
114         maj_stat = gss_indicate_mechs(&min_stat, oidsetp);
115         if (GSS_ERROR(maj_stat))
116             errx(1, "gss_indicate_mechs: %s",
117                  gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
118     } else {
119         maj_stat = gss_create_empty_oid_set(&min_stat, oidsetp);
120         if (GSS_ERROR(maj_stat))
121             errx(1, "gss_create_empty_oid_set: %s",
122                  gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
123
124         for (name = strtok_r(names, ", ", &s);
125              name != NULL;
126              name = strtok_r(NULL, ", ", &s)) {
127             gss_OID oid = string_to_oid(name);
128
129             maj_stat = gss_add_oid_set_member(&min_stat, oid, oidsetp);
130             if (GSS_ERROR(maj_stat))
131                 errx(1, "gss_add_oid_set_member: %s",
132                     gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
133         }
134     }
135 }
136
137 static void
138 loop(gss_OID mechoid,
139      gss_OID nameoid, const char *target,
140      gss_cred_id_t init_cred,
141      gss_ctx_id_t *sctx, gss_ctx_id_t *cctx,
142      gss_OID *actual_mech,
143      gss_cred_id_t *deleg_cred)
144 {
145     int server_done = 0, client_done = 0;
146     int num_loops = 0;
147     OM_uint32 maj_stat, min_stat;
148     gss_name_t gss_target_name, src_name = GSS_C_NO_NAME;
149     gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
150     gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
151 #ifdef DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT
152     gss_buffer_desc cctx_tok = GSS_C_EMPTY_BUFFER;
153 #endif
154     gss_buffer_desc sctx_tok = GSS_C_EMPTY_BUFFER;
155     OM_uint32 flags = 0, ret_cflags = 0, ret_sflags = 0;
156     gss_OID actual_mech_client = GSS_C_NO_OID;
157     gss_OID actual_mech_server = GSS_C_NO_OID;
158     struct gss_channel_bindings_struct i_channel_bindings_data = {0};
159     struct gss_channel_bindings_struct a_channel_bindings_data = {0};
160     gss_channel_bindings_t i_channel_bindings_p = GSS_C_NO_CHANNEL_BINDINGS;
161     gss_channel_bindings_t a_channel_bindings_p = GSS_C_NO_CHANNEL_BINDINGS;
162     size_t offset = 0;
163
164     *actual_mech = GSS_C_NO_OID;
165
166     flags |= GSS_C_REPLAY_FLAG;
167     flags |= GSS_C_INTEG_FLAG;
168     flags |= GSS_C_CONF_FLAG;
169
170     if (mutual_auth_flag)
171         flags |= GSS_C_MUTUAL_FLAG;
172     if (anon_flag)
173         flags |= GSS_C_ANON_FLAG;
174     if (dce_style_flag)
175         flags |= GSS_C_DCE_STYLE;
176     if (deleg_flag)
177         flags |= GSS_C_DELEG_FLAG;
178     if (policy_deleg_flag)
179         flags |= GSS_C_DELEG_POLICY_FLAG;
180
181     input_token.value = rk_UNCONST(target);
182     input_token.length = strlen(target);
183
184     maj_stat = gss_import_name(&min_stat,
185                                &input_token,
186                                nameoid,
187                                &gss_target_name);
188     if (GSS_ERROR(maj_stat))
189         err(1, "import name creds failed with: %d", maj_stat);
190
191     input_token.length = 0;
192     input_token.value = NULL;
193
194     if (i_channel_bindings) {
195         i_channel_bindings_data.application_data.length = strlen(i_channel_bindings);
196         i_channel_bindings_data.application_data.value = i_channel_bindings;
197         i_channel_bindings_p = &i_channel_bindings_data;
198     }
199     if (a_channel_bindings) {
200         a_channel_bindings_data.application_data.length = strlen(a_channel_bindings);
201         a_channel_bindings_data.application_data.value = a_channel_bindings;
202         a_channel_bindings_p = &a_channel_bindings_data;
203     }
204
205     /*
206      * This loop simulates both the initiator and acceptor sides of
207      * a GSS conversation.  We also simulate tokens that are broken
208      * into pieces before handed to gss_accept_sec_context().  Each
209      * iteration of the loop optionally calls gss_init_sec_context()
210      * then optionally calls gss_accept_sec_context().
211      */
212
213     while (!server_done || !client_done) {
214         num_loops++;
215         if (verbose_flag)
216             printf("loop #%d: input_token.length=%zu client_done=%d\n",
217                 num_loops, input_token.length, client_done);
218
219         /*
220          * First, we need to call gss_import_sec_context() if we are
221          * running through the loop the first time, or if we have been
222          * given a token (input_token) by gss_accept_sec_context().
223          * We aren't going to be called every time because when we are
224          * using split tokens, we may need to call gss_accept_sec_context()
225          * multiple times because it receives an entire token.
226          */
227         if ((num_loops == 1 || input_token.length > 0) && !client_done) {
228             gsskrb5_set_time_offset(client_time_offset);
229 #ifdef DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT
230             if (ei_ctx_flag && cctx_tok.length > 0) {
231                 maj_stat = gss_import_sec_context(&min_stat, &cctx_tok, cctx);
232                 if (maj_stat != GSS_S_COMPLETE)
233                     errx(1, "import client context failed: %s",
234                          gssapi_err(maj_stat, min_stat, NULL));
235                 gss_release_buffer(&min_stat, &cctx_tok);
236             }
237 #endif
238
239             maj_stat = gss_init_sec_context(&min_stat, init_cred, cctx,
240                                             gss_target_name, mechoid,
241                                             flags, 0, i_channel_bindings_p,
242                                             &input_token, &actual_mech_client,
243                                             &output_token, &ret_cflags, NULL);
244             if (GSS_ERROR(maj_stat))
245                 errx(1, "init_sec_context: %s",
246                      gssapi_err(maj_stat, min_stat, mechoid));
247             client_done = !(maj_stat & GSS_S_CONTINUE_NEEDED);
248
249             gss_release_buffer(&min_stat, &input_token);
250             input_token.length = 0;
251             input_token.value  = NULL;
252
253 #if DO_IMPORT_EXPORT_OF_CLIENT_CONTEXT
254             if (!client_done && ei_ctx_flag) {
255                 maj_stat = gss_export_sec_context(&min_stat, cctx, &cctx_tok);
256                 if (maj_stat != GSS_S_COMPLETE)
257                     errx(1, "export server context failed: %s",
258                          gssapi_err(maj_stat, min_stat, NULL));
259                 if (*cctx != GSS_C_NO_CONTEXT)
260                     errx(1, "export client context did not release it");
261             }
262 #endif
263
264             if (verbose_flag)
265                 printf("loop #%d: output_token.length=%zu\n", num_loops,
266                     output_token.length);
267
268             offset = 0;
269         }
270
271         /*
272          * We now call gss_accept_sec_context().  To support split
273          * tokens, we keep track of the offset into the token that
274          * we have used and keep handing in chunks until we're done.
275          */
276
277         if (offset < output_token.length && !server_done) {
278             gss_buffer_desc tmp;
279
280             gsskrb5_get_time_offset(&client_time_offset);
281             gsskrb5_set_time_offset(server_time_offset);
282
283             if (output_token.length && ((uint8_t *)output_token.value)[0] == 0x60) {
284                 tmp.length = output_token.length - offset;
285                 if (token_split && tmp.length > token_split)
286                     tmp.length = token_split;
287                 tmp.value  = (char *)output_token.value + offset;
288             } else
289                 tmp = output_token;
290
291             if (verbose_flag)
292                 printf("loop #%d: accept offset=%zu len=%zu\n", num_loops,
293                     offset, tmp.length);
294
295             if (ei_ctx_flag && sctx_tok.length > 0) {
296                 maj_stat = gss_import_sec_context(&min_stat, &sctx_tok, sctx);
297                 if (maj_stat != GSS_S_COMPLETE)
298                     errx(1, "import server context failed: %s",
299                          gssapi_err(maj_stat, min_stat, NULL));
300                 gss_release_buffer(&min_stat, &sctx_tok);
301             }
302
303             maj_stat = gss_accept_sec_context(&min_stat, sctx,
304                                               GSS_C_NO_CREDENTIAL, &tmp,
305                                               a_channel_bindings_p, &src_name,
306                                               &actual_mech_server,
307                                               &input_token, &ret_sflags,
308                                               NULL, deleg_cred);
309             if (GSS_ERROR(maj_stat))
310                 errx(1, "accept_sec_context: %s",
311                      gssapi_err(maj_stat, min_stat, actual_mech_server));
312             offset += tmp.length;
313             if (maj_stat & GSS_S_CONTINUE_NEEDED)
314                 gss_release_name(&min_stat, &src_name);
315             else
316                 server_done = 1;
317
318             if (ei_ctx_flag && !server_done) {
319                 maj_stat = gss_export_sec_context(&min_stat, sctx, &sctx_tok);
320                 if (maj_stat != GSS_S_COMPLETE)
321                     errx(1, "export server context failed: %s",
322                          gssapi_err(maj_stat, min_stat, NULL));
323                 if (*sctx != GSS_C_NO_CONTEXT)
324                     errx(1, "export server context did not release it");
325             }
326
327             gsskrb5_get_time_offset(&server_time_offset);
328
329             if (output_token.length == offset)
330                 gss_release_buffer(&min_stat, &output_token);
331         }
332         if (verbose_flag)
333             printf("loop #%d: end\n", num_loops);
334     }
335     if (output_token.length != 0)
336         gss_release_buffer(&min_stat, &output_token);
337     if (input_token.length != 0)
338         gss_release_buffer(&min_stat, &input_token);
339     gss_release_name(&min_stat, &gss_target_name);
340
341     if (deleg_flag || policy_deleg_flag) {
342         if (server_no_deleg_flag) {
343             if (*deleg_cred != GSS_C_NO_CREDENTIAL)
344                 errx(1, "got delegated cred but didn't expect one");
345         } else if (*deleg_cred == GSS_C_NO_CREDENTIAL)
346             errx(1, "asked for delegarated cred but did get one");
347     } else if (*deleg_cred != GSS_C_NO_CREDENTIAL)
348           errx(1, "got deleg_cred cred but didn't ask");
349
350     if (gss_oid_equal(actual_mech_server, actual_mech_client) == 0)
351         errx(1, "mech mismatch");
352     *actual_mech = actual_mech_server;
353
354     if (localname_string) {
355         gss_buffer_desc lname;
356
357         maj_stat = gss_localname(&min_stat, src_name, GSS_C_NO_OID, &lname);
358         if (maj_stat != GSS_S_COMPLETE)
359             errx(1, "localname: %s",
360                  gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
361         if (verbose_flag)
362             printf("localname: %.*s\n", (int)lname.length,
363                    (char *)lname.value);
364         if (lname.length != strlen(localname_string) ||
365             strncmp(localname_string, lname.value, lname.length) != 0)
366             errx(1, "localname: expected \"%s\", got \"%.*s\" (1)",
367                  localname_string, (int)lname.length, (char *)lname.value);
368         gss_release_buffer(&min_stat, &lname);
369         maj_stat = gss_localname(&min_stat, src_name, actual_mech_server,
370                                  &lname);
371         if (maj_stat != GSS_S_COMPLETE)
372             errx(1, "localname: %s",
373                  gssapi_err(maj_stat, min_stat, actual_mech_server));
374         if (lname.length != strlen(localname_string) ||
375             strncmp(localname_string, lname.value, lname.length) != 0)
376             errx(1, "localname: expected \"%s\", got \"%.*s\" (2)",
377                  localname_string, (int)lname.length, (char *)lname.value);
378         gss_release_buffer(&min_stat, &lname);
379
380         if (!gss_userok(src_name, localname_string))
381             errx(1, "localname is not userok");
382         if (gss_userok(src_name, "nosuchuser:no"))
383             errx(1, "gss_userok() appears broken");
384     }
385     if (verbose_flag) {
386         gss_buffer_desc iname;
387
388         maj_stat = gss_display_name(&min_stat, src_name, &iname, NULL);
389         if (maj_stat == GSS_S_COMPLETE) {
390             printf("client name: %.*s\n", (int)iname.length,
391                 (char *)iname.value);
392             gss_release_buffer(&min_stat, &iname);
393         } else
394             warnx("display_name: %s",
395                  gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
396     }
397     gss_release_name(&min_stat, &src_name);
398
399     if (max_loops && num_loops > max_loops)
400         errx(1, "num loops %d was lager then max loops %d",
401              num_loops, max_loops);
402
403     if (verbose_flag) {
404         printf("server time offset: %d\n", server_time_offset);
405         printf("client time offset: %d\n", client_time_offset);
406         printf("num loops %d\n", num_loops);
407         printf("cflags: ");
408         if (ret_cflags & GSS_C_DELEG_FLAG)
409             printf("deleg ");
410         if (ret_cflags & GSS_C_MUTUAL_FLAG)
411             printf("mutual ");
412         if (ret_cflags & GSS_C_REPLAY_FLAG)
413             printf("replay ");
414         if (ret_cflags & GSS_C_SEQUENCE_FLAG)
415             printf("sequence ");
416         if (ret_cflags & GSS_C_CONF_FLAG)
417             printf("conf ");
418         if (ret_cflags & GSS_C_INTEG_FLAG)
419             printf("integ ");
420         if (ret_cflags & GSS_C_ANON_FLAG)
421             printf("anon ");
422         if (ret_cflags & GSS_C_PROT_READY_FLAG)
423             printf("prot-ready ");
424         if (ret_cflags & GSS_C_TRANS_FLAG)
425             printf("trans ");
426         if (ret_cflags & GSS_C_DCE_STYLE)
427             printf("dce-style ");
428         if (ret_cflags & GSS_C_IDENTIFY_FLAG)
429             printf("identify " );
430         if (ret_cflags & GSS_C_EXTENDED_ERROR_FLAG)
431             printf("extended-error " );
432         if (ret_cflags & GSS_C_DELEG_POLICY_FLAG)
433             printf("deleg-policy " );
434         printf("\n");
435         printf("sflags: ");
436         if (ret_sflags & GSS_C_CHANNEL_BOUND_FLAG)
437             printf("channel-bound " );
438         printf("\n");
439     }
440 }
441
442 static void
443 wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
444 {
445     gss_buffer_desc input_token, output_token, output_token2;
446     OM_uint32 min_stat, maj_stat;
447     gss_qop_t qop_state;
448     int conf_state;
449
450     input_token.value = "foo";
451     input_token.length = 3;
452
453     maj_stat = gss_wrap(&min_stat, cctx, flags, 0, &input_token,
454                         &conf_state, &output_token);
455     if (maj_stat != GSS_S_COMPLETE)
456         errx(1, "gss_wrap failed: %s",
457              gssapi_err(maj_stat, min_stat, mechoid));
458
459     maj_stat = gss_unwrap(&min_stat, sctx, &output_token,
460                           &output_token2, &conf_state, &qop_state);
461     if (maj_stat != GSS_S_COMPLETE)
462         errx(1, "gss_unwrap failed: %s",
463              gssapi_err(maj_stat, min_stat, mechoid));
464
465     gss_release_buffer(&min_stat, &output_token);
466     gss_release_buffer(&min_stat, &output_token2);
467
468 #if 0 /* doesn't work for NTLM yet */
469     if (!!conf_state != !!flags)
470         errx(1, "conf_state mismatch");
471 #endif
472 }
473
474 #define USE_CONF                1
475 #define USE_HEADER_ONLY         2
476 #define USE_SIGN_ONLY           4
477 #define FORCE_IOV               8
478 /* NO_DATA comes from <netdb.h>; we don't use it here; we appropriate it */
479 #ifdef NO_DATA
480 #undef NO_DATA
481 #endif
482 #define NO_DATA                 16
483
484 static void
485 wrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
486 {
487     krb5_data token, header, trailer;
488     OM_uint32 min_stat, maj_stat;
489     gss_qop_t qop_state;
490     int conf_state, conf_state2;
491     gss_iov_buffer_desc iov[6];
492     unsigned char *p;
493     int iov_len;
494     char header_data[9] = "ABCheader";
495     char trailer_data[10] = "trailerXYZ";
496
497     char token_data[16] = "0123456789abcdef";
498
499     memset(&iov, 0, sizeof(iov));
500
501     if (flags & USE_SIGN_ONLY) {
502         header.data = header_data;
503         header.length = 9;
504         trailer.data = trailer_data;
505         trailer.length = 10;
506     } else {
507         header.data = NULL;
508         header.length = 0;
509         trailer.data = NULL;
510         trailer.length = 0;
511     }
512
513     token.data = token_data;
514     token.length = 16;
515
516     iov_len = sizeof(iov)/sizeof(iov[0]);
517
518     memset(iov, 0, sizeof(iov));
519
520     iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
521
522     if (header.length != 0) {
523         iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
524         iov[1].buffer.length = header.length;
525         iov[1].buffer.value = header.data;
526     } else {
527         iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
528         iov[1].buffer.length = 0;
529         iov[1].buffer.value = NULL;
530     }
531     iov[2].type = GSS_IOV_BUFFER_TYPE_DATA;
532     if (flags & NO_DATA) {
533         iov[2].buffer.length = 0;
534     } else {
535         iov[2].buffer.length = token.length;
536     }
537     iov[2].buffer.value = token.data;
538     if (trailer.length != 0) {
539         iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
540         iov[3].buffer.length = trailer.length;
541         iov[3].buffer.value = trailer.data;
542     } else {
543         iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
544         iov[3].buffer.length = 0;
545         iov[3].buffer.value = NULL;
546     }
547     if (dce_style_flag) {
548         iov[4].type = GSS_IOV_BUFFER_TYPE_EMPTY;
549     } else {
550         iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_FLAG_ALLOCATE;
551     }
552     iov[4].buffer.length = 0;
553     iov[4].buffer.value = 0;
554     if (dce_style_flag) {
555         iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
556     } else if (flags & USE_HEADER_ONLY) {
557         iov[5].type = GSS_IOV_BUFFER_TYPE_EMPTY;
558     } else {
559         iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
560     }
561     iov[5].buffer.length = 0;
562     iov[5].buffer.value = 0;
563
564     maj_stat = gss_wrap_iov(&min_stat, cctx, dce_style_flag || flags & USE_CONF, 0, &conf_state,
565                             iov, iov_len);
566     if (maj_stat != GSS_S_COMPLETE)
567         errx(1, "gss_wrap_iov failed");
568
569     token.length =
570         iov[0].buffer.length +
571         iov[1].buffer.length +
572         iov[2].buffer.length +
573         iov[3].buffer.length +
574         iov[4].buffer.length +
575         iov[5].buffer.length;
576     token.data = emalloc(token.length);
577
578     p = token.data;
579     memcpy(p, iov[0].buffer.value, iov[0].buffer.length);
580     p += iov[0].buffer.length;
581     memcpy(p, iov[1].buffer.value, iov[1].buffer.length);
582     p += iov[1].buffer.length;
583     memcpy(p, iov[2].buffer.value, iov[2].buffer.length);
584     p += iov[2].buffer.length;
585     memcpy(p, iov[3].buffer.value, iov[3].buffer.length);
586     p += iov[3].buffer.length;
587     memcpy(p, iov[4].buffer.value, iov[4].buffer.length);
588     p += iov[4].buffer.length;
589     memcpy(p, iov[5].buffer.value, iov[5].buffer.length);
590     p += iov[5].buffer.length;
591
592     assert(p - ((unsigned char *)token.data) == token.length);
593
594     if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) {
595         gss_buffer_desc input, output;
596
597         input.value = token.data;
598         input.length = token.length;
599
600         maj_stat = gss_unwrap(&min_stat, sctx, &input,
601                               &output, &conf_state2, &qop_state);
602
603         if (maj_stat != GSS_S_COMPLETE)
604             errx(1, "gss_unwrap from gss_wrap_iov failed: %s",
605                  gssapi_err(maj_stat, min_stat, mechoid));
606
607         gss_release_buffer(&min_stat, &output);
608     } else {
609         maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state,
610                                   iov, iov_len);
611
612         if (maj_stat != GSS_S_COMPLETE)
613             errx(1, "gss_unwrap_iov failed: %x %s", flags,
614                  gssapi_err(maj_stat, min_stat, mechoid));
615
616     }
617     if (conf_state2 != conf_state)
618         errx(1, "conf state wrong for iov: %x", flags);
619
620     gss_release_iov_buffer(&min_stat, iov, iov_len);
621
622     free(token.data);
623 }
624
625 static void
626 wrapunwrap_aead(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid)
627 {
628     gss_buffer_desc token, assoc, message = GSS_C_EMPTY_BUFFER;
629     gss_buffer_desc output;
630     OM_uint32 min_stat, maj_stat;
631     gss_qop_t qop_state;
632     int conf_state, conf_state2;
633     char assoc_data[9] = "ABCheader";
634     char token_data[16] = "0123456789abcdef";
635
636     if (flags & USE_SIGN_ONLY) {
637         assoc.value = assoc_data;
638         assoc.length = 9;
639     } else {
640         assoc.value = NULL;
641         assoc.length = 0;
642     }
643
644     token.value = token_data;
645     token.length = 16;
646
647     maj_stat = gss_wrap_aead(&min_stat, cctx, dce_style_flag || flags & USE_CONF,
648                              GSS_C_QOP_DEFAULT, &assoc, &token,
649                              &conf_state, &message);
650     if (maj_stat != GSS_S_COMPLETE)
651         errx(1, "gss_wrap_aead failed");
652
653     if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) {
654         maj_stat = gss_unwrap(&min_stat, sctx, &message,
655                               &output, &conf_state2, &qop_state);
656
657         if (maj_stat != GSS_S_COMPLETE)
658             errx(1, "gss_unwrap from gss_wrap_aead failed: %s",
659                  gssapi_err(maj_stat, min_stat, mechoid));
660     } else {
661         maj_stat = gss_unwrap_aead(&min_stat, sctx, &message, &assoc,
662                                    &output, &conf_state2, &qop_state);
663         if (maj_stat != GSS_S_COMPLETE)
664             errx(1, "gss_unwrap_aead failed: %x %s", flags,
665                  gssapi_err(maj_stat, min_stat, mechoid));
666     }
667
668     if (output.length != token.length)
669         errx(1, "plaintext length wrong for aead");
670     else if (memcmp(output.value, token.value, token.length) != 0)
671         errx(1, "plaintext wrong for aead");
672     if (conf_state2 != conf_state)
673         errx(1, "conf state wrong for aead: %x", flags);
674
675     gss_release_buffer(&min_stat, &message);
676     gss_release_buffer(&min_stat, &output);
677 }
678
679 static void
680 getverifymic(gss_ctx_id_t cctx, gss_ctx_id_t sctx, gss_OID mechoid)
681 {
682     gss_buffer_desc input_token, output_token;
683     OM_uint32 min_stat, maj_stat;
684     gss_qop_t qop_state;
685
686     input_token.value = "bar";
687     input_token.length = 3;
688
689     maj_stat = gss_get_mic(&min_stat, cctx, 0, &input_token,
690                            &output_token);
691     if (maj_stat != GSS_S_COMPLETE)
692         errx(1, "gss_get_mic failed: %s",
693              gssapi_err(maj_stat, min_stat, mechoid));
694
695     maj_stat = gss_verify_mic(&min_stat, sctx, &input_token,
696                               &output_token, &qop_state);
697     if (maj_stat != GSS_S_COMPLETE)
698         errx(1, "gss_verify_mic failed: %s",
699              gssapi_err(maj_stat, min_stat, mechoid));
700
701     gss_release_buffer(&min_stat, &output_token);
702 }
703
704 static void
705 empty_release(void)
706 {
707     gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
708     gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
709     gss_name_t name = GSS_C_NO_NAME;
710     gss_OID_set oidset = GSS_C_NO_OID_SET;
711     OM_uint32 junk;
712
713     gss_delete_sec_context(&junk, &ctx, NULL);
714     gss_release_cred(&junk, &cred);
715     gss_release_name(&junk, &name);
716     gss_release_oid_set(&junk, &oidset);
717 }
718
719 /*
720  *
721  */
722
723 static struct getargs args[] = {
724     {"name-type",0,     arg_string, &type_string,  "type of name", NULL },
725     {"mech-type",0,     arg_string, &mech_string,  "mech type (name)", NULL },
726     {"mech-types",0,    arg_string, &mechs_string, "mech types (names)", NULL },
727     {"ret-mech-type",0, arg_string, &ret_mech_string,
728      "type of return mech", NULL },
729     {"dns-canonicalize",0,arg_negative_flag, &dns_canon_flag,
730      "use dns to canonicalize", NULL },
731     {"mutual-auth",0,   arg_flag,       &mutual_auth_flag,"mutual auth", NULL },
732     {"client-ccache",0, arg_string,     &client_ccache, "client credentials cache", NULL },
733     {"client-keytab",0, arg_string,     &client_keytab, "client keytab", NULL },
734     {"client-name", 0,  arg_string,     &client_name, "client name", NULL },
735     {"client-password", 0,  arg_string, &client_password, "client password", NULL },
736     {"anonymous", 0,    arg_flag,       &anon_flag, "anonymous auth", NULL },
737     {"i-channel-bindings", 0, arg_string, &i_channel_bindings, "initiator channel binding data", NULL },
738     {"a-channel-bindings", 0, arg_string, &a_channel_bindings, "acceptor channel binding data", NULL },
739     {"limit-enctype",0, arg_string,     &limit_enctype_string, "enctype", NULL },
740     {"dce-style",0,     arg_flag,       &dce_style_flag, "dce-style", NULL },
741     {"wrapunwrap",0,    arg_flag,       &wrapunwrap_flag, "wrap/unwrap", NULL },
742     {"iov", 0,          arg_flag,       &iov_flag, "wrap/unwrap iov", NULL },
743     {"aead", 0,         arg_flag,       &aead_flag, "wrap/unwrap aead", NULL },
744     {"getverifymic",0,  arg_flag,       &getverifymic_flag,
745      "get and verify mic", NULL },
746     {"delegate",0,      arg_flag,       &deleg_flag, "delegate credential", NULL },
747     {"policy-delegate",0,       arg_flag,       &policy_deleg_flag, "policy delegate credential", NULL },
748     {"server-no-delegate",0,    arg_flag,       &server_no_deleg_flag,
749      "server should get a credential", NULL },
750     {"export-import-context",0, arg_flag,       &ei_ctx_flag, "test export/import context", NULL },
751     {"export-import-cred",0,    arg_flag,       &ei_cred_flag, "test export/import cred", NULL },
752     {"localname",0,     arg_string, &localname_string, "expected localname for client", "USERNAME"},
753     {"gsskrb5-acceptor-identity", 0, arg_string, &gsskrb5_acceptor_identity, "keytab", NULL },
754     {"session-enctype", 0, arg_string,  &session_enctype_string, "enctype", NULL },
755     {"client-time-offset",      0, arg_integer, &client_time_offset, "time", NULL },
756     {"server-time-offset",      0, arg_integer, &server_time_offset, "time", NULL },
757     {"max-loops",       0, arg_integer, &max_loops, "time", NULL },
758     {"token-split",     0, arg_integer, &token_split, "bytes", NULL },
759     {"version", 0,      arg_flag,       &version_flag, "print version", NULL },
760     {"verbose", 'v',    arg_flag,       &verbose_flag, "verbose", NULL },
761     {"help",    0,      arg_flag,       &help_flag,  NULL, NULL }
762 };
763
764 static void
765 usage (int ret)
766 {
767     arg_printusage (args, sizeof(args)/sizeof(*args),
768                     NULL, "service@host");
769     exit (ret);
770 }
771
772 int
773 main(int argc, char **argv)
774 {
775     int optidx = 0;
776     OM_uint32 min_stat, maj_stat;
777     gss_ctx_id_t cctx, sctx;
778     void *ctx;
779     gss_OID nameoid, mechoid, actual_mech, actual_mech2;
780     gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL, deleg_cred = GSS_C_NO_CREDENTIAL;
781     gss_name_t cname = GSS_C_NO_NAME;
782     gss_buffer_desc credential_data = GSS_C_EMPTY_BUFFER;
783     gss_OID_desc oids[7];
784     gss_OID_set_desc mechoid_descs;
785     gss_OID_set mechoids = GSS_C_NO_OID_SET;
786     gss_key_value_element_desc client_cred_elements[2];
787     gss_key_value_set_desc client_cred_store;
788     gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
789
790     setprogname(argv[0]);
791
792     if (krb5_init_context(&context))
793         errx(1, "krb5_init_context");
794
795     cctx = sctx = GSS_C_NO_CONTEXT;
796
797     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
798         usage(1);
799
800     if (help_flag)
801         usage (0);
802
803     if(version_flag){
804         print_version(NULL);
805         exit(0);
806     }
807
808     argc -= optidx;
809     argv += optidx;
810
811     if (argc != 1)
812         usage(1);
813
814     if (dns_canon_flag != -1)
815         gsskrb5_set_dns_canonicalize(dns_canon_flag);
816
817     if (type_string == NULL)
818         nameoid = GSS_C_NT_HOSTBASED_SERVICE;
819     else if (strcmp(type_string, "hostbased-service") == 0)
820         nameoid = GSS_C_NT_HOSTBASED_SERVICE;
821     else if (strcmp(type_string, "krb5-principal-name") == 0)
822         nameoid = GSS_KRB5_NT_PRINCIPAL_NAME;
823     else
824         errx(1, "%s not supported", type_string);
825
826     if (mech_string == NULL)
827         mechoid = GSS_KRB5_MECHANISM;
828     else
829         mechoid = string_to_oid(mech_string);
830
831     if (mechs_string == NULL) {
832         /*
833          * We ought to be able to use the OID set of the one mechanism
834          * OID given.  But there's some breakage that conspires to make
835          * that fail though it should succeed:
836          *
837          *  - the NTLM gss_acquire_cred() refuses to work with
838          *    desired_name == GSS_C_NO_NAME
839          *  - gss_acquire_cred() with desired_mechs == GSS_C_NO_OID_SET
840          *    does work here because we happen to have Kerberos
841          *    credentials in check-ntlm, and the subsequent
842          *    gss_init_sec_context() call finds no cred element for NTLM
843          *    but plows on anyways, surprisingly enough, and then the
844          *    NTLM gss_init_sec_context() just works.
845          *
846          * In summary, there's some breakage in gss_init_sec_context()
847          * and some breakage in NTLM that conspires against us here.
848          *
849          * We work around this in check-ntlm and check-spnego by adding
850          * --client-name=user1@${R} to the invocations of this test
851          * program that require it.
852          */
853         oids[0] = *mechoid;
854         mechoid_descs.elements = &oids[0];
855         mechoid_descs.count = 1;
856         mechoids = &mechoid_descs;
857     } else {
858         string_to_oids(&mechoids, mechs_string);
859     }
860
861     if (gsskrb5_acceptor_identity) {
862         /* XXX replace this with cred store, but test suites will need work */
863         maj_stat = gsskrb5_register_acceptor_identity(gsskrb5_acceptor_identity);
864         if (maj_stat)
865             errx(1, "gsskrb5_acceptor_identity: %s",
866                  gssapi_err(maj_stat, 0, GSS_C_NO_OID));
867     }
868
869     if (client_password && (client_ccache || client_keytab)) {
870         errx(1, "password option mutually exclusive with ccache or keytab option");
871     }
872
873     if (client_password) {
874         credential_data.value = client_password;
875         credential_data.length = strlen(client_password);
876     }
877
878     client_cred_store.count = 0;
879     client_cred_store.elements = client_cred_elements;
880
881     if (client_ccache) {
882         client_cred_store.elements[client_cred_store.count].key = "ccache";
883         client_cred_store.elements[client_cred_store.count].value = client_ccache;
884
885         client_cred_store.count++;
886     }
887
888     if (client_keytab) {
889         client_cred_store.elements[client_cred_store.count].key = "client_keytab";
890         client_cred_store.elements[client_cred_store.count].value = client_keytab;
891
892         client_cred_store.count++;
893     }
894
895     if (client_name) {
896         gss_buffer_desc cn;
897
898         cn.value = client_name;
899         cn.length = strlen(client_name);
900
901         maj_stat = gss_import_name(&min_stat, &cn, GSS_C_NT_USER_NAME, &cname);
902         if (maj_stat)
903             errx(1, "gss_import_name: %s",
904                  gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
905     }
906
907     if (client_password) {
908         maj_stat = gss_acquire_cred_with_password(&min_stat,
909                                                   cname,
910                                                   &credential_data,
911                                                   GSS_C_INDEFINITE,
912                                                   mechoids,
913                                                   GSS_C_INITIATE,
914                                                   &client_cred,
915                                                   &actual_mechs,
916                                                   NULL);
917         if (GSS_ERROR(maj_stat)) {
918             if (mechoids != GSS_C_NO_OID_SET && mechoids->count == 1)
919                 mechoid = &mechoids->elements[0];
920             else
921                 mechoid = GSS_C_NO_OID;
922             errx(1, "gss_acquire_cred_with_password: %s",
923                  gssapi_err(maj_stat, min_stat, mechoid));
924         }
925     } else {
926         maj_stat = gss_acquire_cred_from(&min_stat,
927                                          cname,
928                                          GSS_C_INDEFINITE,
929                                          mechoids,
930                                          GSS_C_INITIATE,
931                                          client_cred_store.count ? &client_cred_store
932                                                                  : GSS_C_NO_CRED_STORE,
933                                          &client_cred,
934                                          &actual_mechs,
935                                          NULL);
936         if (GSS_ERROR(maj_stat) && !anon_flag)
937             errx(1, "gss_acquire_cred: %s",
938                  gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
939     }
940
941     gss_release_name(&min_stat, &cname);
942
943     if (verbose_flag) {
944         size_t i;
945
946         printf("cred mechs:");
947         for (i = 0; i < actual_mechs->count; i++)
948             printf(" %s", gss_oid_to_name(&actual_mechs->elements[i]));
949         printf("\n");
950     }
951
952     if (gss_oid_equal(mechoid, GSS_SPNEGO_MECHANISM) && mechs_string) {
953         maj_stat = gss_set_neg_mechs(&min_stat, client_cred, mechoids);
954         if (GSS_ERROR(maj_stat))
955             errx(1, "gss_set_neg_mechs: %s",
956                  gssapi_err(maj_stat, min_stat, GSS_SPNEGO_MECHANISM));
957
958         mechoid_descs.elements = GSS_SPNEGO_MECHANISM;
959         mechoid_descs.count = 1;
960         mechoids = &mechoid_descs;
961     }
962
963     if (ei_cred_flag) {
964         gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
965         gss_buffer_desc cb;
966
967         maj_stat = gss_export_cred(&min_stat, client_cred, &cb);
968         if (maj_stat != GSS_S_COMPLETE)
969             errx(1, "export cred failed: %s",
970                  gssapi_err(maj_stat, min_stat, NULL));
971
972         maj_stat = gss_import_cred(&min_stat, &cb, &cred2);
973         if (maj_stat != GSS_S_COMPLETE)
974             errx(1, "import cred failed: %s",
975                  gssapi_err(maj_stat, min_stat, NULL));
976
977         gss_release_buffer(&min_stat, &cb);
978         gss_release_cred(&min_stat, &client_cred);
979         client_cred = cred2;
980     }
981
982     if (limit_enctype_string) {
983         krb5_error_code ret;
984
985         ret = krb5_string_to_enctype(context,
986                                      limit_enctype_string,
987                                      &limit_enctype);
988         if (ret)
989             krb5_err(context, 1, ret, "krb5_string_to_enctype");
990     }
991
992
993     if (limit_enctype) {
994         if (client_cred == NULL)
995             errx(1, "client_cred missing");
996
997         maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred,
998                                                    1, &limit_enctype);
999         if (maj_stat)
1000             errx(1, "gss_krb5_set_allowable_enctypes: %s",
1001                  gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
1002     }
1003
1004     loop(mechoid, nameoid, argv[0], client_cred,
1005          &sctx, &cctx, &actual_mech, &deleg_cred);
1006
1007     if (verbose_flag)
1008         printf("resulting mech: %s\n", gss_oid_to_name(actual_mech));
1009
1010     if (ret_mech_string) {
1011         gss_OID retoid;
1012
1013         retoid = string_to_oid(ret_mech_string);
1014
1015         if (gss_oid_equal(retoid, actual_mech) == 0)
1016             errx(1, "actual_mech mech is not the expected type %s",
1017                  ret_mech_string);
1018     }
1019
1020     /* XXX should be actual_mech */
1021     if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) {
1022         time_t sc_time;
1023         gss_buffer_desc authz_data;
1024         gss_buffer_desc in, out1, out2;
1025         krb5_keyblock *keyblock, *keyblock2;
1026         krb5_timestamp now;
1027         krb5_error_code ret;
1028
1029         ret = krb5_timeofday(context, &now);
1030         if (ret)
1031             errx(1, "krb5_timeofday failed");
1032
1033         /* client */
1034         maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
1035                                                      &cctx,
1036                                                      1, /* version */
1037                                                      &ctx);
1038         if (maj_stat != GSS_S_COMPLETE)
1039             errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
1040                  gssapi_err(maj_stat, min_stat, actual_mech));
1041
1042
1043         maj_stat = gss_krb5_free_lucid_sec_context(&maj_stat, ctx);
1044         if (maj_stat != GSS_S_COMPLETE)
1045             errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
1046                      gssapi_err(maj_stat, min_stat, actual_mech));
1047
1048         /* server */
1049         maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
1050                                                      &sctx,
1051                                                      1, /* version */
1052                                                      &ctx);
1053         if (maj_stat != GSS_S_COMPLETE)
1054             errx(1, "gss_krb5_export_lucid_sec_context failed: %s",
1055                      gssapi_err(maj_stat, min_stat, actual_mech));
1056         maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, ctx);
1057         if (maj_stat != GSS_S_COMPLETE)
1058             errx(1, "gss_krb5_free_lucid_sec_context failed: %s",
1059                      gssapi_err(maj_stat, min_stat, actual_mech));
1060
1061         maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
1062                                                              sctx,
1063                                                              &sc_time);
1064         if (maj_stat != GSS_S_COMPLETE)
1065             errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s",
1066                      gssapi_err(maj_stat, min_stat, actual_mech));
1067
1068         if (sc_time > now)
1069             errx(1, "gsskrb5_extract_authtime_from_sec_context failed: "
1070                  "time authtime is before now: %ld %ld",
1071                  (long)sc_time, (long)now);
1072
1073         maj_stat = gsskrb5_extract_service_keyblock(&min_stat,
1074                                                     sctx,
1075                                                     &keyblock);
1076         if (maj_stat != GSS_S_COMPLETE)
1077             errx(1, "gsskrb5_export_service_keyblock failed: %s",
1078                      gssapi_err(maj_stat, min_stat, actual_mech));
1079
1080         krb5_free_keyblock(context, keyblock);
1081
1082         maj_stat = gsskrb5_get_subkey(&min_stat,
1083                                       sctx,
1084                                       &keyblock);
1085         if (maj_stat != GSS_S_COMPLETE
1086             && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
1087             errx(1, "gsskrb5_get_subkey server failed: %s",
1088                      gssapi_err(maj_stat, min_stat, actual_mech));
1089
1090         if (maj_stat != GSS_S_COMPLETE)
1091             keyblock = NULL;
1092         else if (limit_enctype && keyblock->keytype != limit_enctype)
1093             errx(1, "gsskrb5_get_subkey wrong enctype");
1094
1095         maj_stat = gsskrb5_get_subkey(&min_stat,
1096                                       cctx,
1097                                       &keyblock2);
1098         if (maj_stat != GSS_S_COMPLETE
1099             && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
1100             errx(1, "gsskrb5_get_subkey client failed: %s",
1101                      gssapi_err(maj_stat, min_stat, actual_mech));
1102
1103         if (maj_stat != GSS_S_COMPLETE)
1104             keyblock2 = NULL;
1105         else if (limit_enctype && keyblock->keytype != limit_enctype)
1106             errx(1, "gsskrb5_get_subkey wrong enctype");
1107
1108         if (keyblock || keyblock2) {
1109             if (keyblock == NULL)
1110                 errx(1, "server missing token keyblock");
1111             if (keyblock2 == NULL)
1112                 errx(1, "client missing token keyblock");
1113
1114             if (keyblock->keytype != keyblock2->keytype)
1115                 errx(1, "enctype mismatch");
1116             if (keyblock->keyvalue.length != keyblock2->keyvalue.length)
1117                 errx(1, "key length mismatch");
1118             if (memcmp(keyblock->keyvalue.data, keyblock2->keyvalue.data,
1119                        keyblock2->keyvalue.length) != 0)
1120                 errx(1, "key data mismatch");
1121         }
1122
1123         if (session_enctype_string) {
1124             krb5_enctype enctype;
1125
1126             ret = krb5_string_to_enctype(context,
1127                                          session_enctype_string,
1128                                          &enctype);
1129
1130             if (ret)
1131                 krb5_err(context, 1, ret, "krb5_string_to_enctype");
1132
1133             if (enctype != keyblock->keytype)
1134                 errx(1, "keytype is not the expected %d != %d",
1135                      (int)enctype, (int)keyblock2->keytype);
1136         }
1137
1138         if (keyblock)
1139             krb5_free_keyblock(context, keyblock);
1140         if (keyblock2)
1141             krb5_free_keyblock(context, keyblock2);
1142
1143         maj_stat = gsskrb5_get_initiator_subkey(&min_stat,
1144                                                 sctx,
1145                                                 &keyblock);
1146         if (maj_stat != GSS_S_COMPLETE
1147             && (!(maj_stat == GSS_S_FAILURE && min_stat == GSS_KRB5_S_KG_NO_SUBKEY)))
1148             errx(1, "gsskrb5_get_initiator_subkey failed: %s",
1149                      gssapi_err(maj_stat, min_stat, actual_mech));
1150
1151         if (maj_stat == GSS_S_COMPLETE) {
1152
1153             if (limit_enctype && keyblock->keytype != limit_enctype)
1154                 errx(1, "gsskrb5_get_initiator_subkey wrong enctype");
1155             krb5_free_keyblock(context, keyblock);
1156         }
1157
1158         maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat,
1159                                                                sctx,
1160                                                                128,
1161                                                                &authz_data);
1162         if (maj_stat == GSS_S_COMPLETE)
1163             gss_release_buffer(&min_stat, &authz_data);
1164
1165
1166         memset(&out1, 0, sizeof(out1));
1167         memset(&out2, 0, sizeof(out2));
1168
1169         in.value = "foo";
1170         in.length = 3;
1171
1172         gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
1173                           100, &out1);
1174         gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_FULL, &in,
1175                           100, &out2);
1176
1177         if (out1.length != out2.length)
1178             errx(1, "prf len mismatch");
1179         if (memcmp(out1.value, out2.value, out1.length) != 0)
1180             errx(1, "prf data mismatch");
1181
1182         gss_release_buffer(&min_stat, &out1);
1183
1184         gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_FULL, &in,
1185                           100, &out1);
1186
1187         if (out1.length != out2.length)
1188             errx(1, "prf len mismatch");
1189         if (memcmp(out1.value, out2.value, out1.length) != 0)
1190             errx(1, "prf data mismatch");
1191
1192         gss_release_buffer(&min_stat, &out1);
1193         gss_release_buffer(&min_stat, &out2);
1194
1195         in.value = "bar";
1196         in.length = 3;
1197
1198         gss_pseudo_random(&min_stat, sctx, GSS_C_PRF_KEY_PARTIAL, &in,
1199                           100, &out1);
1200         gss_pseudo_random(&min_stat, cctx, GSS_C_PRF_KEY_PARTIAL, &in,
1201                           100, &out2);
1202
1203         if (out1.length != out2.length)
1204             errx(1, "prf len mismatch");
1205         if (memcmp(out1.value, out2.value, out1.length) != 0)
1206             errx(1, "prf data mismatch");
1207
1208         gss_release_buffer(&min_stat, &out1);
1209         gss_release_buffer(&min_stat, &out2);
1210
1211         wrapunwrap_flag = 1;
1212         getverifymic_flag = 1;
1213     }
1214
1215     if (ei_ctx_flag) {
1216         gss_buffer_desc ctx_token = GSS_C_EMPTY_BUFFER;
1217
1218         maj_stat = gss_export_sec_context(&min_stat, &cctx, &ctx_token);
1219         if (maj_stat != GSS_S_COMPLETE)
1220             errx(1, "export client context failed: %s",
1221                  gssapi_err(maj_stat, min_stat, NULL));
1222
1223         if (cctx != GSS_C_NO_CONTEXT)
1224             errx(1, "export client context did not release it");
1225
1226         maj_stat = gss_import_sec_context(&min_stat, &ctx_token, &cctx);
1227         if (maj_stat != GSS_S_COMPLETE)
1228             errx(1, "import client context failed: %s",
1229                  gssapi_err(maj_stat, min_stat, NULL));
1230
1231         gss_release_buffer(&min_stat, &ctx_token);
1232
1233         maj_stat = gss_export_sec_context(&min_stat, &sctx, &ctx_token);
1234         if (maj_stat != GSS_S_COMPLETE)
1235             errx(1, "export server context failed: %s",
1236                  gssapi_err(maj_stat, min_stat, NULL));
1237
1238         if (sctx != GSS_C_NO_CONTEXT)
1239             errx(1, "export server context did not release it");
1240
1241         maj_stat = gss_import_sec_context(&min_stat, &ctx_token, &sctx);
1242         if (maj_stat != GSS_S_COMPLETE)
1243             errx(1, "import server context failed: %s",
1244                  gssapi_err(maj_stat, min_stat, NULL));
1245
1246         gss_release_buffer(&min_stat, &ctx_token);
1247     }
1248
1249     if (wrapunwrap_flag) {
1250         wrapunwrap(cctx, sctx, 0, actual_mech);
1251         wrapunwrap(cctx, sctx, 1, actual_mech);
1252         wrapunwrap(sctx, cctx, 0, actual_mech);
1253         wrapunwrap(sctx, cctx, 1, actual_mech);
1254     }
1255
1256     if (iov_flag) {
1257         wrapunwrap_iov(cctx, sctx, 0, actual_mech);
1258         wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1259         wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
1260         wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
1261         wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
1262
1263         wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
1264         wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1265         wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1266         wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1267
1268         wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1269         wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1270         wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1271
1272 /* works */
1273         wrapunwrap_iov(cctx, sctx, 0, actual_mech);
1274         wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech);
1275
1276         wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech);
1277         wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1278
1279         wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY, actual_mech);
1280         wrapunwrap_iov(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1281
1282         wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech);
1283         wrapunwrap_iov(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1284
1285         wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY, actual_mech);
1286         wrapunwrap_iov(cctx, sctx, USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1287
1288         wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech);
1289         wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1290
1291         wrapunwrap_iov(cctx, sctx, NO_DATA, actual_mech);
1292         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1293         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY, actual_mech);
1294         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF, actual_mech);
1295         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY, actual_mech);
1296
1297         wrapunwrap_iov(cctx, sctx, NO_DATA|FORCE_IOV, actual_mech);
1298         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|FORCE_IOV, actual_mech);
1299         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1300         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1301
1302         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1303         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1304         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1305
1306  /* works */
1307         wrapunwrap_iov(cctx, sctx, NO_DATA, actual_mech);
1308         wrapunwrap_iov(cctx, sctx, NO_DATA|FORCE_IOV, actual_mech);
1309
1310         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF, actual_mech);
1311         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|FORCE_IOV, actual_mech);
1312
1313         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_SIGN_ONLY, actual_mech);
1314         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1315
1316         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_SIGN_ONLY, actual_mech);
1317         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1318
1319         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY, actual_mech);
1320         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1321
1322         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY, actual_mech);
1323         wrapunwrap_iov(cctx, sctx, NO_DATA|USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech);
1324     }
1325
1326     if (aead_flag) {
1327         wrapunwrap_aead(cctx, sctx, 0, actual_mech);
1328         wrapunwrap_aead(cctx, sctx, USE_CONF, actual_mech);
1329
1330         wrapunwrap_aead(cctx, sctx, FORCE_IOV, actual_mech);
1331         wrapunwrap_aead(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1332
1333         wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1334         wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1335
1336         wrapunwrap_aead(cctx, sctx, 0, actual_mech);
1337         wrapunwrap_aead(cctx, sctx, FORCE_IOV, actual_mech);
1338
1339         wrapunwrap_aead(cctx, sctx, USE_CONF, actual_mech);
1340         wrapunwrap_aead(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech);
1341
1342         wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY, actual_mech);
1343         wrapunwrap_aead(cctx, sctx, USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1344
1345         wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY, actual_mech);
1346         wrapunwrap_aead(cctx, sctx, USE_CONF|USE_SIGN_ONLY|FORCE_IOV, actual_mech);
1347     }
1348
1349     if (getverifymic_flag) {
1350         getverifymic(cctx, sctx, actual_mech);
1351         getverifymic(cctx, sctx, actual_mech);
1352         getverifymic(sctx, cctx, actual_mech);
1353         getverifymic(sctx, cctx, actual_mech);
1354     }
1355
1356     gss_delete_sec_context(&min_stat, &cctx, NULL);
1357     gss_delete_sec_context(&min_stat, &sctx, NULL);
1358
1359     if (deleg_cred != GSS_C_NO_CREDENTIAL) {
1360         gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
1361         gss_buffer_desc cb;
1362
1363         if (verbose_flag)
1364             printf("checking actual mech (%s) on delegated cred\n",
1365                    gss_oid_to_name(actual_mech));
1366         loop(actual_mech, nameoid, argv[0], deleg_cred, &sctx, &cctx, &actual_mech2, &cred2);
1367
1368         gss_delete_sec_context(&min_stat, &cctx, NULL);
1369         gss_delete_sec_context(&min_stat, &sctx, NULL);
1370
1371         gss_release_cred(&min_stat, &cred2);
1372
1373 #if 0
1374         /*
1375          * XXX We can't do this.  Delegated credentials only work with
1376          * the actual_mech.  We could gss_store_cred the delegated
1377          * credentials *then* gss_add/acquire_cred() with SPNEGO, then
1378          * we could try loop() with those credentials.
1379          */
1380         /* try again using SPNEGO */
1381         if (verbose_flag)
1382             printf("checking spnego on delegated cred\n");
1383         loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], deleg_cred, &sctx, &cctx,
1384              &actual_mech2, &cred2);
1385
1386         gss_delete_sec_context(&min_stat, &cctx, NULL);
1387         gss_delete_sec_context(&min_stat, &sctx, NULL);
1388
1389         gss_release_cred(&min_stat, &cred2);
1390 #endif
1391
1392         /* check export/import */
1393         if (ei_cred_flag) {
1394
1395             maj_stat = gss_export_cred(&min_stat, deleg_cred, &cb);
1396             if (maj_stat != GSS_S_COMPLETE)
1397                 errx(1, "export cred failed: %s",
1398                      gssapi_err(maj_stat, min_stat, NULL));
1399
1400             maj_stat = gss_import_cred(&min_stat, &cb, &cred2);
1401             if (maj_stat != GSS_S_COMPLETE)
1402                 errx(1, "import cred failed: %s",
1403                      gssapi_err(maj_stat, min_stat, NULL));
1404
1405             gss_release_buffer(&min_stat, &cb);
1406             gss_release_cred(&min_stat, &deleg_cred);
1407
1408             if (verbose_flag)
1409                 printf("checking actual mech (%s) on export/imported cred\n",
1410                        gss_oid_to_name(actual_mech));
1411             loop(actual_mech, nameoid, argv[0], cred2, &sctx, &cctx,
1412                  &actual_mech2, &deleg_cred);
1413
1414             gss_release_cred(&min_stat, &deleg_cred);
1415
1416             gss_delete_sec_context(&min_stat, &cctx, NULL);
1417             gss_delete_sec_context(&min_stat, &sctx, NULL);
1418
1419 #if 0
1420             /* XXX See above */
1421             /* try again using SPNEGO */
1422             if (verbose_flag)
1423                 printf("checking SPNEGO on export/imported cred\n");
1424             loop(GSS_SPNEGO_MECHANISM, nameoid, argv[0], cred2, &sctx, &cctx,
1425                  &actual_mech2, &deleg_cred);
1426
1427             gss_release_cred(&min_stat, &deleg_cred);
1428
1429             gss_delete_sec_context(&min_stat, &cctx, NULL);
1430             gss_delete_sec_context(&min_stat, &sctx, NULL);
1431 #endif
1432
1433             gss_release_cred(&min_stat, &cred2);
1434
1435         } else  {
1436             gss_release_cred(&min_stat, &deleg_cred);
1437         }
1438
1439     }
1440
1441     gss_release_cred(&min_stat, &client_cred);
1442     gss_release_oid_set(&min_stat, &actual_mechs);
1443     if (mechoids != GSS_C_NO_OID_SET && mechoids != &mechoid_descs)
1444         gss_release_oid_set(&min_stat, &mechoids);
1445     empty_release();
1446
1447     krb5_free_context(context);
1448
1449     return 0;
1450 }