/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* tests/gssapi/common.c - Common utility functions for GSSAPI test programs */ /* * Copyright (C) 2012 by the Massachusetts Institute of Technology. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "common.h" gss_OID_desc mech_krb5 = { 9, "\052\206\110\206\367\022\001\002\002" }; gss_OID_desc mech_spnego = { 6, "\053\006\001\005\005\002" }; gss_OID_desc mech_iakerb = { 6, "\053\006\001\005\002\005" }; gss_OID_set_desc mechset_krb5 = { 1, &mech_krb5 }; gss_OID_set_desc mechset_spnego = { 1, &mech_spnego }; gss_OID_set_desc mechset_iakerb = { 1, &mech_iakerb }; static void display_status(const char *msg, OM_uint32 code, int type) { OM_uint32 min_stat, msg_ctx = 0; gss_buffer_desc buf; do { (void)gss_display_status(&min_stat, code, type, GSS_C_NULL_OID, &msg_ctx, &buf); fprintf(stderr, "%s: %.*s\n", msg, (int)buf.length, (char *)buf.value); (void)gss_release_buffer(&min_stat, &buf); } while (msg_ctx != 0); } void check_gsserr(const char *msg, OM_uint32 major, OM_uint32 minor) { if (GSS_ERROR(major)) { display_status(msg, major, GSS_C_GSS_CODE); display_status(msg, minor, GSS_C_MECH_CODE); exit(1); } } void check_k5err(krb5_context context, const char *msg, krb5_error_code code) { const char *errmsg; if (code) { errmsg = krb5_get_error_message(context, code); printf("%s: %s\n", msg, errmsg); krb5_free_error_message(context, errmsg); exit(1); } } void errout(const char *msg) { fprintf(stderr, "%s\n", msg); exit(1); } gss_name_t import_name(const char *str) { OM_uint32 major, minor; gss_name_t name; gss_buffer_desc buf; gss_OID nametype = NULL; if (*str == 'u') nametype = GSS_C_NT_USER_NAME; else if (*str == 'p') nametype = (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME; else if (*str == 'h') nametype = GSS_C_NT_HOSTBASED_SERVICE; if (nametype == NULL || str[1] != ':') errout("names must begin with u: or p: or h:"); buf.value = (char *)str + 2; buf.length = strlen(str) - 2; major = gss_import_name(&minor, &buf, nametype, &name); check_gsserr("gss_import_name", major, minor); return name; } void establish_contexts(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred, gss_name_t tname, OM_uint32 flags, gss_ctx_id_t *ictx, gss_ctx_id_t *actx, gss_name_t *src_name, gss_OID *amech, gss_cred_id_t *deleg_cred) { OM_uint32 minor, imaj, amaj; gss_buffer_desc itok, atok; *ictx = *actx = GSS_C_NO_CONTEXT; imaj = amaj = GSS_S_CONTINUE_NEEDED; itok.value = atok.value = NULL; itok.length = atok.length = 0; for (;;) { (void)gss_release_buffer(&minor, &itok); imaj = gss_init_sec_context(&minor, icred, ictx, tname, imech, flags, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &atok, NULL, &itok, NULL, NULL); check_gsserr("gss_init_sec_context", imaj, minor); if (amaj == GSS_S_COMPLETE) break; (void)gss_release_buffer(&minor, &atok); amaj = gss_accept_sec_context(&minor, actx, acred, &itok, GSS_C_NO_CHANNEL_BINDINGS, src_name, amech, &atok, NULL, NULL, deleg_cred); check_gsserr("gss_accept_sec_context", amaj, minor); (void)gss_release_buffer(&minor, &itok); if (imaj == GSS_S_COMPLETE) break; } if (imaj != GSS_S_COMPLETE || amaj != GSS_S_COMPLETE) errout("One side wants to continue after the other is done"); (void)gss_release_buffer(&minor, &itok); (void)gss_release_buffer(&minor, &atok); } void export_import_cred(gss_cred_id_t *cred) { OM_uint32 major, minor; gss_buffer_desc buf; major = gss_export_cred(&minor, *cred, &buf); check_gsserr("gss_export_cred", major, minor); (void)gss_release_cred(&minor, cred); major = gss_import_cred(&minor, &buf, cred); check_gsserr("gss_import_cred", major, minor); (void)gss_release_buffer(&minor, &buf); } void display_canon_name(const char *tag, gss_name_t name, gss_OID mech) { gss_name_t canon; OM_uint32 major, minor; gss_buffer_desc buf; major = gss_canonicalize_name(&minor, name, mech, &canon); check_gsserr("gss_canonicalize_name", major, minor); major = gss_display_name(&minor, canon, &buf, NULL); check_gsserr("gss_display_name", major, minor); printf("%s:\t%.*s\n", tag, (int)buf.length, (char *)buf.value); (void)gss_release_name(&minor, &canon); (void)gss_release_buffer(&minor, &buf); } void display_oid(const char *tag, gss_OID oid) { OM_uint32 major, minor; gss_buffer_desc buf; major = gss_oid_to_str(&minor, oid, &buf); check_gsserr("gss_oid_to_str", major, minor); if (tag != NULL) printf("%s:\t", tag); printf("%.*s\n", (int)buf.length, (char *)buf.value); (void)gss_release_buffer(&minor, &buf); } static void dump_attribute(gss_name_t name, gss_buffer_t attribute, int noisy) { OM_uint32 major, minor; gss_buffer_desc value; gss_buffer_desc display_value; int authenticated = 0; int complete = 0; int more = -1; unsigned int i; while (more != 0) { value.value = NULL; display_value.value = NULL; major = gss_get_name_attribute(&minor, name, attribute, &authenticated, &complete, &value, &display_value, &more); check_gsserr("gss_get_name_attribute", major, minor); printf("Attribute %.*s %s %s\n\n%.*s\n", (int)attribute->length, (char *)attribute->value, authenticated ? "Authenticated" : "", complete ? "Complete" : "", (int)display_value.length, (char *)display_value.value); if (noisy) { for (i = 0; i < value.length; i++) { if ((i % 32) == 0) printf("\n"); printf("%02x", ((char *)value.value)[i] & 0xFF); } printf("\n\n"); } (void)gss_release_buffer(&minor, &value); (void)gss_release_buffer(&minor, &display_value); } } void enumerate_attributes(gss_name_t name, int noisy) { OM_uint32 major, minor; int is_mechname; gss_OID mech = GSS_C_NO_OID; gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; size_t i; major = gss_inquire_name(&minor, name, &is_mechname, &mech, &attrs); check_gsserr("gss_inquire_name", major, minor); if (attrs != GSS_C_NO_BUFFER_SET) { for (i = 0; i < attrs->count; i++) dump_attribute(name, &attrs->elements[i], noisy); } (void)gss_release_buffer_set(&minor, &attrs); } void print_hex(FILE *fp, gss_buffer_t buf) { size_t i; const unsigned char *bytes = buf->value; for (i = 0; i < buf->length; i++) printf("%02X", bytes[i]); printf("\n"); }