1 /*- 2 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3 * Authors: Doug Rabson <dfr@rabson.org> 4 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 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 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #include <sys/types.h> 31 #include <sys/syscall.h> 32 #include <sys/module.h> 33 34 #include <stdio.h> 35 #include <string.h> 36 #include <err.h> 37 #include <unistd.h> 38 #include <stdlib.h> 39 40 #include <krb5.h> 41 #include <gssapi/gssapi.h> 42 #include <gssapi/gssapi_krb5.h> 43 44 struct gsstest_2_args { 45 int step; /* test step number */ 46 gss_buffer_desc input_token; /* token from userland */ 47 gss_buffer_desc output_token; /* buffer to receive reply token */ 48 }; 49 struct gsstest_2_res { 50 OM_uint32 maj_stat; /* maj_stat from kernel */ 51 OM_uint32 min_stat; /* min_stat from kernel */ 52 gss_buffer_desc output_token; /* reply token (using space from gsstest_2_args.output) */ 53 }; 54 55 static void 56 report_error(gss_OID mech, OM_uint32 maj, OM_uint32 min) 57 { 58 OM_uint32 maj_stat, min_stat; 59 OM_uint32 message_context; 60 gss_buffer_desc buf; 61 62 printf("major_stat=%d, minor_stat=%d\n", maj, min); 63 message_context = 0; 64 do { 65 maj_stat = gss_display_status(&min_stat, maj, 66 GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buf); 67 printf("%.*s\n", (int)buf.length, (char *) buf.value); 68 gss_release_buffer(&min_stat, &buf); 69 } while (message_context); 70 if (mech) { 71 message_context = 0; 72 do { 73 maj_stat = gss_display_status(&min_stat, min, 74 GSS_C_MECH_CODE, mech, &message_context, &buf); 75 printf("%.*s\n", (int)buf.length, (char *) buf.value); 76 gss_release_buffer(&min_stat, &buf); 77 } while (message_context); 78 } 79 } 80 81 int 82 main(int argc, char **argv) 83 { 84 struct module_stat stat; 85 int mod; 86 int syscall_num; 87 88 stat.version = sizeof(stat); 89 mod = modfind("gsstest_syscall"); 90 if (mod < 0) { 91 fprintf(stderr, "%s: kernel support not present\n", argv[0]); 92 exit(1); 93 } 94 modstat(mod, &stat); 95 syscall_num = stat.data.intval; 96 97 switch (atoi(argv[1])) { 98 case 1: 99 syscall(syscall_num, 1, NULL, NULL); 100 break; 101 102 case 2: { 103 struct gsstest_2_args args; 104 struct gsstest_2_res res; 105 char hostname[512]; 106 char token_buffer[8192]; 107 OM_uint32 maj_stat, min_stat; 108 gss_ctx_id_t client_context = GSS_C_NO_CONTEXT; 109 gss_cred_id_t client_cred; 110 gss_OID mech_type = GSS_C_NO_OID; 111 gss_buffer_desc name_buf, message_buf; 112 gss_name_t name; 113 int32_t enctypes[] = { 114 ETYPE_DES_CBC_CRC, 115 ETYPE_ARCFOUR_HMAC_MD5, 116 ETYPE_ARCFOUR_HMAC_MD5_56, 117 ETYPE_AES256_CTS_HMAC_SHA1_96, 118 ETYPE_AES128_CTS_HMAC_SHA1_96, 119 ETYPE_DES3_CBC_SHA1, 120 }; 121 int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]); 122 int established; 123 int i; 124 125 for (i = 0; i < num_enctypes; i++) { 126 printf("testing etype %d\n", enctypes[i]); 127 args.output_token.length = sizeof(token_buffer); 128 args.output_token.value = token_buffer; 129 130 gethostname(hostname, sizeof(hostname)); 131 snprintf(token_buffer, sizeof(token_buffer), 132 "nfs@%s", hostname); 133 name_buf.length = strlen(token_buffer); 134 name_buf.value = token_buffer; 135 maj_stat = gss_import_name(&min_stat, &name_buf, 136 GSS_C_NT_HOSTBASED_SERVICE, &name); 137 if (GSS_ERROR(maj_stat)) { 138 printf("gss_import_name failed\n"); 139 report_error(mech_type, maj_stat, min_stat); 140 goto out; 141 } 142 143 maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, 144 0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_cred, 145 NULL, NULL); 146 if (GSS_ERROR(maj_stat)) { 147 printf("gss_acquire_cred (client) failed\n"); 148 report_error(mech_type, maj_stat, min_stat); 149 goto out; 150 } 151 152 maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, 153 client_cred, 1, &enctypes[i]); 154 if (GSS_ERROR(maj_stat)) { 155 printf("gss_krb5_set_allowable_enctypes failed\n"); 156 report_error(mech_type, maj_stat, min_stat); 157 goto out; 158 } 159 160 res.output_token.length = 0; 161 res.output_token.value = 0; 162 established = 0; 163 while (!established) { 164 maj_stat = gss_init_sec_context(&min_stat, 165 client_cred, 166 &client_context, 167 name, 168 GSS_C_NO_OID, 169 (GSS_C_MUTUAL_FLAG 170 |GSS_C_CONF_FLAG 171 |GSS_C_INTEG_FLAG 172 |GSS_C_SEQUENCE_FLAG 173 |GSS_C_REPLAY_FLAG), 174 0, 175 GSS_C_NO_CHANNEL_BINDINGS, 176 &res.output_token, 177 &mech_type, 178 &args.input_token, 179 NULL, 180 NULL); 181 if (GSS_ERROR(maj_stat)) { 182 printf("gss_init_sec_context failed\n"); 183 report_error(mech_type, maj_stat, min_stat); 184 goto out; 185 } 186 if (args.input_token.length) { 187 args.step = 1; 188 syscall(syscall_num, 2, &args, &res); 189 gss_release_buffer(&min_stat, 190 &args.input_token); 191 if (res.maj_stat != GSS_S_COMPLETE 192 && res.maj_stat != GSS_S_CONTINUE_NEEDED) { 193 printf("gss_accept_sec_context (kernel) failed\n"); 194 report_error(mech_type, res.maj_stat, 195 res.min_stat); 196 goto out; 197 } 198 } 199 if (maj_stat == GSS_S_COMPLETE) 200 established = 1; 201 } 202 203 message_buf.value = "Hello world"; 204 message_buf.length = strlen((char *) message_buf.value); 205 206 maj_stat = gss_get_mic(&min_stat, client_context, 207 GSS_C_QOP_DEFAULT, &message_buf, &args.input_token); 208 if (GSS_ERROR(maj_stat)) { 209 printf("gss_get_mic failed\n"); 210 report_error(mech_type, maj_stat, min_stat); 211 goto out; 212 } 213 214 args.step = 2; 215 syscall(syscall_num, 2, &args, &res); 216 gss_release_buffer(&min_stat, &args.input_token); 217 if (GSS_ERROR(res.maj_stat)) { 218 printf("kernel gss_verify_mic failed\n"); 219 report_error(mech_type, res.maj_stat, res.min_stat); 220 goto out; 221 } 222 223 maj_stat = gss_verify_mic(&min_stat, client_context, 224 &message_buf, &res.output_token, NULL); 225 if (GSS_ERROR(maj_stat)) { 226 printf("gss_verify_mic failed\n"); 227 report_error(mech_type, maj_stat, min_stat); 228 goto out; 229 } 230 231 maj_stat = gss_wrap(&min_stat, client_context, 232 TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, 233 &args.input_token); 234 if (GSS_ERROR(maj_stat)) { 235 printf("gss_wrap failed\n"); 236 report_error(mech_type, maj_stat, min_stat); 237 goto out; 238 } 239 240 args.step = 3; 241 syscall(syscall_num, 2, &args, &res); 242 gss_release_buffer(&min_stat, &args.input_token); 243 if (GSS_ERROR(res.maj_stat)) { 244 printf("kernel gss_unwrap failed\n"); 245 report_error(mech_type, res.maj_stat, res.min_stat); 246 goto out; 247 } 248 249 maj_stat = gss_unwrap(&min_stat, client_context, 250 &res.output_token, &message_buf, NULL, NULL); 251 if (GSS_ERROR(maj_stat)) { 252 printf("gss_unwrap failed\n"); 253 report_error(mech_type, maj_stat, min_stat); 254 goto out; 255 } 256 gss_release_buffer(&min_stat, &message_buf); 257 258 maj_stat = gss_wrap(&min_stat, client_context, 259 FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL, 260 &args.input_token); 261 if (GSS_ERROR(maj_stat)) { 262 printf("gss_wrap failed\n"); 263 report_error(mech_type, maj_stat, min_stat); 264 goto out; 265 } 266 267 args.step = 4; 268 syscall(syscall_num, 2, &args, &res); 269 gss_release_buffer(&min_stat, &args.input_token); 270 if (GSS_ERROR(res.maj_stat)) { 271 printf("kernel gss_unwrap failed\n"); 272 report_error(mech_type, res.maj_stat, res.min_stat); 273 goto out; 274 } 275 276 maj_stat = gss_unwrap(&min_stat, client_context, 277 &res.output_token, &message_buf, NULL, NULL); 278 if (GSS_ERROR(maj_stat)) { 279 printf("gss_unwrap failed\n"); 280 report_error(mech_type, maj_stat, min_stat); 281 goto out; 282 } 283 gss_release_buffer(&min_stat, &message_buf); 284 285 args.step = 5; 286 syscall(syscall_num, 2, &args, &res); 287 288 gss_release_name(&min_stat, &name); 289 gss_release_cred(&min_stat, &client_cred); 290 gss_delete_sec_context(&min_stat, &client_context, 291 GSS_C_NO_BUFFER); 292 } 293 294 break; 295 } 296 case 3: 297 syscall(syscall_num, 3, NULL, NULL); 298 break; 299 case 4: 300 syscall(syscall_num, 4, NULL, NULL); 301 break; 302 } 303 return (0); 304 305 out: 306 return (1); 307 } 308