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