1 /* -*- mode: c; indent-tabs-mode: nil -*- */ 2 /* tests/gssapi/t_s4u2proxy_deleg.c - Test S4U2Proxy after krb5 auth */ 3 /* 4 * Copyright 2011 by the Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 #include "common.h" 32 33 /* 34 * Usage: ./t_s4u2proxy_krb5 [--spnego] client_cache storage_cache 35 * [accname|-] service1 service2 36 * 37 * This program performs a regular Kerberos or SPNEGO authentication from the 38 * default principal of client_cache to service1. If that authentication 39 * yields delegated credentials, the program stores those credentials in 40 * sorage_ccache and uses that cache to perform a second authentication to 41 * service2 using S4U2Proxy. 42 * 43 * The default keytab must contain keys for service1 and service2. The default 44 * ccache must contain a TGT for service1. This program assumes that krb5 or 45 * SPNEGO authentication requires only one token exchange. 46 */ 47 48 int 49 main(int argc, char *argv[]) 50 { 51 const char *client_ccname, *storage_ccname, *accname, *service1, *service2; 52 krb5_context context = NULL; 53 krb5_error_code ret; 54 krb5_boolean use_spnego = FALSE; 55 krb5_ccache storage_ccache = NULL; 56 krb5_principal client_princ = NULL; 57 OM_uint32 minor, major, flags; 58 gss_buffer_desc buf = GSS_C_EMPTY_BUFFER; 59 gss_OID mech; 60 gss_OID_set mechs; 61 gss_name_t acceptor_name = GSS_C_NO_NAME, client_name = GSS_C_NO_NAME; 62 gss_name_t service1_name = GSS_C_NO_NAME, service2_name = GSS_C_NO_NAME; 63 gss_cred_id_t service1_cred = GSS_C_NO_CREDENTIAL; 64 gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL; 65 gss_ctx_id_t initiator_context, acceptor_context; 66 67 /* Parse arguments. */ 68 if (argc >= 2 && strcmp(argv[1], "--spnego") == 0) { 69 use_spnego = TRUE; 70 argc--; 71 argv++; 72 } 73 if (argc != 6) { 74 fprintf(stderr, "./t_s4u2proxy_krb5 [--spnego] client_ccache " 75 "storage_ccache [accname|-] service1 service2\n"); 76 return 1; 77 } 78 client_ccname = argv[1]; 79 storage_ccname = argv[2]; 80 accname = argv[3]; 81 service1 = argv[4]; 82 service2 = argv[5]; 83 84 mech = use_spnego ? &mech_spnego : &mech_krb5; 85 mechs = use_spnego ? &mechset_spnego : &mechset_krb5; 86 ret = krb5_init_context(&context); 87 check_k5err(context, "krb5_init_context", ret); 88 89 /* Get GSS_C_BOTH acceptor credentials, using the default ccache. */ 90 acceptor_name = GSS_C_NO_NAME; 91 if (strcmp(accname, "-") != 0) 92 acceptor_name = import_name(service1); 93 major = gss_acquire_cred(&minor, acceptor_name, GSS_C_INDEFINITE, 94 mechs, GSS_C_BOTH, &service1_cred, NULL, NULL); 95 check_gsserr("gss_acquire_cred(service1)", major, minor); 96 97 /* Establish contexts using the client ccache. */ 98 service1_name = import_name(service1); 99 major = gss_krb5_ccache_name(&minor, client_ccname, NULL); 100 check_gsserr("gss_krb5_ccache_name(1)", major, minor); 101 flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG; 102 establish_contexts(mech, GSS_C_NO_CREDENTIAL, service1_cred, service1_name, 103 flags, &initiator_context, &acceptor_context, 104 &client_name, NULL, &deleg_cred); 105 106 /* Display and remember the client principal. */ 107 major = gss_display_name(&minor, client_name, &buf, NULL); 108 check_gsserr("gss_display_name(1)", major, minor); 109 printf("auth1: %.*s\n", (int)buf.length, (char *)buf.value); 110 /* Assumes buffer is null-terminated, which in our implementation it is. */ 111 ret = krb5_parse_name(context, buf.value, &client_princ); 112 check_k5err(context, "krb5_parse_name", ret); 113 (void)gss_release_buffer(&minor, &buf); 114 115 if (deleg_cred == GSS_C_NO_CREDENTIAL) { 116 printf("no credential delegated.\n"); 117 goto cleanup; 118 } 119 120 /* Take the opportunity to test cred export/import on the synthesized 121 * S4U2Proxy delegated cred. */ 122 export_import_cred(&deleg_cred); 123 124 /* Store the delegated credentials. */ 125 ret = krb5_cc_resolve(context, storage_ccname, &storage_ccache); 126 check_k5err(context, "krb5_cc_resolve", ret); 127 ret = krb5_cc_initialize(context, storage_ccache, client_princ); 128 check_k5err(context, "krb5_cc_initialize", ret); 129 major = gss_krb5_copy_ccache(&minor, deleg_cred, storage_ccache); 130 check_gsserr("gss_krb5_copy_ccache", major, minor); 131 ret = krb5_cc_close(context, storage_ccache); 132 check_k5err(context, "krb5_cc_close", ret); 133 134 (void)gss_delete_sec_context(&minor, &initiator_context, GSS_C_NO_BUFFER); 135 (void)gss_delete_sec_context(&minor, &acceptor_context, GSS_C_NO_BUFFER); 136 (void)gss_release_name(&minor, &client_name); 137 (void)gss_release_cred(&minor, &deleg_cred); 138 139 /* Establish contexts using the storage ccache. */ 140 service2_name = import_name(service2); 141 major = gss_krb5_ccache_name(&minor, storage_ccname, NULL); 142 check_gsserr("gss_krb5_ccache_name(2)", major, minor); 143 establish_contexts(mech, GSS_C_NO_CREDENTIAL, GSS_C_NO_CREDENTIAL, 144 service2_name, flags, &initiator_context, 145 &acceptor_context, &client_name, NULL, &deleg_cred); 146 147 major = gss_display_name(&minor, client_name, &buf, NULL); 148 check_gsserr("gss_display_name(2)", major, minor); 149 printf("auth2: %.*s\n", (int)buf.length, (char *)buf.value); 150 (void)gss_release_buffer(&minor, &buf); 151 152 cleanup: 153 (void)gss_release_name(&minor, &acceptor_name); 154 (void)gss_release_name(&minor, &client_name); 155 (void)gss_release_name(&minor, &service1_name); 156 (void)gss_release_name(&minor, &service2_name); 157 (void)gss_release_cred(&minor, &service1_cred); 158 (void)gss_release_cred(&minor, &deleg_cred); 159 (void)gss_delete_sec_context(&minor, &initiator_context, GSS_C_NO_BUFFER); 160 (void)gss_delete_sec_context(&minor, &acceptor_context, GSS_C_NO_BUFFER); 161 krb5_free_principal(context, client_princ); 162 krb5_free_context(context); 163 return 0; 164 } 165