1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 2009 by the Massachusetts Institute of Technology. 4 * All Rights Reserved. 5 * 6 * Export of this software from the United States of America may 7 * require a specific license from the United States Government. 8 * It is the responsibility of any person or organization contemplating 9 * export to obtain such a license before exporting. 10 * 11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 12 * distribute this software and its documentation for any purpose and 13 * without fee is hereby granted, provided that the above copyright 14 * notice appear in all copies and that both that copyright notice and 15 * this permission notice appear in supporting documentation, and that 16 * the name of M.I.T. not be used in advertising or publicity pertaining 17 * to distribution of the software without specific, written prior 18 * permission. Furthermore if you modify this software you must label 19 * your software as modified software and not distribute it in such a 20 * fashion that it might be confused with the original M.I.T. software. 21 * M.I.T. makes no representations about the suitability of 22 * this software for any purpose. It is provided "as is" without express 23 * or implied warranty. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 30 #include "common.h" 31 32 /* 33 * Test program for protocol transition (S4U2Self) and constrained delegation 34 * (S4U2Proxy) 35 * 36 * Note: because of name canonicalization, the following tips may help 37 * when configuring with Active Directory: 38 * 39 * - Create a computer account FOO$ 40 * - Set the UPN to host/foo.domain (no suffix); this is necessary to 41 * be able to send an AS-REQ as this principal, otherwise you would 42 * need to use the canonical name (FOO$), which will cause principal 43 * comparison errors in gss_accept_sec_context(). 44 * - Add a SPN of host/foo.domain 45 * - Configure the computer account to support constrained delegation with 46 * protocol transition (Trust this computer for delegation to specified 47 * services only / Use any authentication protocol) 48 * - Add host/foo.domain to the keytab (possibly easiest to do this 49 * with ktadd) 50 * 51 * For S4U2Proxy to work the TGT must be forwardable too. 52 * 53 * Usage eg: 54 * 55 * kinit -k -t test.keytab -f 'host/test.win.mit.edu@WIN.MIT.EDU' 56 * ./t_s4u p:delegtest@WIN.MIT.EDU p:HOST/WIN-EQ7E4AA2WR8.win.mit.edu@WIN.MIT.EDU test.keytab 57 */ 58 59 static int use_spnego = 0; 60 61 static void 62 test_prf(gss_ctx_id_t initiatorContext, gss_ctx_id_t acceptorContext, 63 int flags) 64 { 65 gss_buffer_desc constant; 66 OM_uint32 major, minor; 67 unsigned int i; 68 gss_buffer_desc initiatorPrf; 69 gss_buffer_desc acceptorPrf; 70 71 constant.value = "gss prf test"; 72 constant.length = strlen((char *)constant.value); 73 74 initiatorPrf.value = NULL; 75 acceptorPrf.value = NULL; 76 77 major = gss_pseudo_random(&minor, initiatorContext, flags, &constant, 19, 78 &initiatorPrf); 79 check_gsserr("gss_pseudo_random", major, minor); 80 81 printf("%s\n", flags == GSS_C_PRF_KEY_FULL ? 82 "PRF_KEY_FULL" : "PRF_KEY_PARTIAL"); 83 84 printf("Initiator PRF: "); 85 for (i = 0; i < initiatorPrf.length; i++) 86 printf("%02x ", ((char *)initiatorPrf.value)[i] & 0xFF); 87 printf("\n"); 88 89 major = gss_pseudo_random(&minor, acceptorContext, flags, &constant, 19, 90 &acceptorPrf); 91 check_gsserr("gss_pseudo_random", major, minor); 92 93 printf("Acceptor PRF: "); 94 for (i = 0; i < acceptorPrf.length; i++) 95 printf("%02x ", ((char *)acceptorPrf.value)[i] & 0xFF); 96 printf("\n"); 97 98 if (acceptorPrf.length != initiatorPrf.length || 99 memcmp(acceptorPrf.value, initiatorPrf.value, initiatorPrf.length)) { 100 fprintf(stderr, "Initiator and acceptor PRF output does not match\n"); 101 exit(1); 102 } 103 104 (void)gss_release_buffer(&minor, &initiatorPrf); 105 (void)gss_release_buffer(&minor, &acceptorPrf); 106 } 107 108 static void 109 init_accept_sec_context(gss_cred_id_t claimant_cred_handle, 110 gss_cred_id_t verifier_cred_handle, 111 gss_cred_id_t *deleg_cred_handle) 112 { 113 OM_uint32 major, minor, flags; 114 gss_name_t source_name = GSS_C_NO_NAME, target_name = GSS_C_NO_NAME; 115 gss_ctx_id_t initiator_context, acceptor_context; 116 gss_OID mech; 117 118 *deleg_cred_handle = GSS_C_NO_CREDENTIAL; 119 120 major = gss_inquire_cred(&minor, verifier_cred_handle, &target_name, NULL, 121 NULL, NULL); 122 check_gsserr("gss_inquire_cred", major, minor); 123 display_canon_name("Target name", target_name, &mech_krb5); 124 125 mech = use_spnego ? &mech_spnego : &mech_krb5; 126 display_oid("Target mech", mech); 127 128 flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG; 129 establish_contexts(mech, claimant_cred_handle, verifier_cred_handle, 130 target_name, flags, &initiator_context, 131 &acceptor_context, &source_name, NULL, 132 deleg_cred_handle); 133 134 test_prf(initiator_context, acceptor_context, GSS_C_PRF_KEY_FULL); 135 test_prf(initiator_context, acceptor_context, GSS_C_PRF_KEY_PARTIAL); 136 137 (void)gss_release_name(&minor, &source_name); 138 (void)gss_delete_sec_context(&minor, &acceptor_context, NULL); 139 (void)gss_delete_sec_context(&minor, &initiator_context, NULL); 140 } 141 142 static void 143 get_default_cred(const char *keytab_name, gss_OID_set mechs, 144 gss_cred_id_t *impersonator_cred_handle) 145 { 146 OM_uint32 major = GSS_S_FAILURE, minor; 147 krb5_error_code ret; 148 krb5_context context = NULL; 149 krb5_keytab keytab = NULL; 150 krb5_principal keytab_principal = NULL; 151 krb5_ccache ccache = NULL; 152 153 if (keytab_name != NULL) { 154 ret = krb5_init_context(&context); 155 check_k5err(context, "krb5_init_context", ret); 156 157 ret = krb5_kt_resolve(context, keytab_name, &keytab); 158 check_k5err(context, "krb5_kt_resolve", ret); 159 160 ret = krb5_cc_default(context, &ccache); 161 check_k5err(context, "krb5_cc_default", ret); 162 163 ret = krb5_cc_get_principal(context, ccache, &keytab_principal); 164 check_k5err(context, "krb5_cc_get_principal", ret); 165 166 major = gss_krb5_import_cred(&minor, ccache, keytab_principal, keytab, 167 impersonator_cred_handle); 168 check_gsserr("gss_krb5_import_cred", major, minor); 169 170 krb5_free_principal(context, keytab_principal); 171 krb5_cc_close(context, ccache); 172 krb5_kt_close(context, keytab); 173 krb5_free_context(context); 174 } else { 175 major = gss_acquire_cred(&minor, GSS_C_NO_NAME, GSS_C_INDEFINITE, 176 mechs, GSS_C_BOTH, impersonator_cred_handle, 177 NULL, NULL); 178 check_gsserr("gss_acquire_cred", major, minor); 179 } 180 } 181 182 int 183 main(int argc, char *argv[]) 184 { 185 OM_uint32 minor, major; 186 gss_cred_id_t impersonator_cred_handle = GSS_C_NO_CREDENTIAL; 187 gss_cred_id_t user_cred_handle = GSS_C_NO_CREDENTIAL; 188 gss_cred_id_t delegated_cred_handle = GSS_C_NO_CREDENTIAL; 189 gss_name_t user = GSS_C_NO_NAME, target = GSS_C_NO_NAME; 190 gss_OID_set mechs, actual_mechs = GSS_C_NO_OID_SET; 191 uid_t uid; 192 193 if (argc < 2 || argc > 5) { 194 fprintf(stderr, "Usage: %s [--spnego] [user] " 195 "[proxy-target] [keytab]\n", argv[0]); 196 fprintf(stderr, " proxy-target and keytab are optional\n"); 197 exit(1); 198 } 199 200 if (strcmp(argv[1], "--spnego") == 0) { 201 use_spnego++; 202 argc--; 203 argv++; 204 } 205 206 user = import_name(argv[1]); 207 208 major = gss_pname_to_uid(&minor, user, NULL, &uid); 209 check_gsserr("gss_pname_to_uid(user)", major, minor); 210 211 if (argc > 2 && strcmp(argv[2], "-") != 0) 212 target = import_name(argv[2]); 213 214 mechs = use_spnego ? &mechset_spnego : &mechset_krb5; 215 216 get_default_cred((argc > 3) ? argv[3] : NULL, mechs, 217 &impersonator_cred_handle); 218 219 printf("Protocol transition tests follow\n"); 220 printf("-----------------------------------\n\n"); 221 222 /* get S4U2Self cred */ 223 major = gss_acquire_cred_impersonate_name(&minor, impersonator_cred_handle, 224 user, GSS_C_INDEFINITE, mechs, 225 GSS_C_INITIATE, 226 &user_cred_handle, &actual_mechs, 227 NULL); 228 check_gsserr("gss_acquire_cred_impersonate_name", major, minor); 229 230 /* Try to store it in default ccache */ 231 major = gss_store_cred(&minor, user_cred_handle, GSS_C_INITIATE, 232 &mechs->elements[0], 1, 1, NULL, NULL); 233 check_gsserr("gss_store_cred", major, minor); 234 235 init_accept_sec_context(user_cred_handle, impersonator_cred_handle, 236 &delegated_cred_handle); 237 238 printf("\n"); 239 240 (void)gss_release_name(&minor, &user); 241 (void)gss_release_name(&minor, &target); 242 (void)gss_release_cred(&minor, &delegated_cred_handle); 243 (void)gss_release_cred(&minor, &impersonator_cred_handle); 244 (void)gss_release_cred(&minor, &user_cred_handle); 245 (void)gss_release_oid_set(&minor, &actual_mechs); 246 return 0; 247 } 248