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 28 #include <sys/types.h> 29 #include <sys/syscall.h> 30 #include <sys/module.h> 31 32 #include <stdio.h> 33 #include <string.h> 34 #include <err.h> 35 #include <unistd.h> 36 #include <stdlib.h> 37 38 #include <krb5.h> 39 #include <gssapi/gssapi.h> 40 #include <gssapi/gssapi_krb5.h> 41 42 struct gsstest_2_args { 43 int step; /* test step number */ 44 gss_buffer_desc input_token; /* token from userland */ 45 gss_buffer_desc output_token; /* buffer to receive reply token */ 46 }; 47 struct gsstest_2_res { 48 OM_uint32 maj_stat; /* maj_stat from kernel */ 49 OM_uint32 min_stat; /* min_stat from kernel */ 50 gss_buffer_desc output_token; /* reply token (using space from gsstest_2_args.output) */ 51 }; 52 53 static void 54 report_error(gss_OID mech, OM_uint32 maj, OM_uint32 min) 55 { 56 OM_uint32 maj_stat, min_stat; 57 OM_uint32 message_context; 58 gss_buffer_desc buf; 59 60 printf("major_stat=%d, minor_stat=%d\n", maj, min); 61 message_context = 0; 62 do { 63 maj_stat = gss_display_status(&min_stat, maj, 64 GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buf); 65 printf("%.*s\n", (int)buf.length, (char *) buf.value); 66 gss_release_buffer(&min_stat, &buf); 67 } while (message_context); 68 if (mech) { 69 message_context = 0; 70 do { 71 maj_stat = gss_display_status(&min_stat, min, 72 GSS_C_MECH_CODE, mech, &message_context, &buf); 73 printf("%.*s\n", (int)buf.length, (char *) buf.value); 74 gss_release_buffer(&min_stat, &buf); 75 } while (message_context); 76 } 77 } 78 79 int 80 main(int argc, char **argv) 81 { 82 struct module_stat stat; 83 int mod; 84 int syscall_num; 85 86 stat.version = sizeof(stat); 87 mod = modfind("gsstest_syscall"); 88 if (mod < 0) { 89 fprintf(stderr, "%s: kernel support not present\n", argv[0]); 90 exit(1); 91 } 92 modstat(mod, &stat); 93 syscall_num = stat.data.intval; 94 95 switch (atoi(argv[1])) { 96 case 1: 97 syscall(syscall_num, 1, NULL, NULL); 98 break; 99 100 case 2: { 101 struct gsstest_2_args args; 102 struct gsstest_2_res res; 103 char hostname[512]; 104 char token_buffer[8192]; 105 OM_uint32 maj_stat, min_stat; 106 gss_ctx_id_t client_context = GSS_C_NO_CONTEXT; 107 gss_cred_id_t client_cred; 108 gss_OID mech_type = GSS_C_NO_OID; 109 gss_buffer_desc name_buf, message_buf; 110 gss_name_t name; 111 int32_t enctypes[] = { 112 ETYPE_DES_CBC_CRC, 113 ETYPE_ARCFOUR_HMAC_MD5, 114 ETYPE_ARCFOUR_HMAC_MD5_56, 115 ETYPE_AES256_CTS_HMAC_SHA1_96, 116 ETYPE_AES128_CTS_HMAC_SHA1_96, 117 ETYPE_DES3_CBC_SHA1, 118 }; 119 int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]); 120 int established; 121 int i; 122 123 for (i = 0; i < num_enctypes; i++) { 124 printf("testing etype %d\n", enctypes[i]); 125 args.output_token.length = sizeof(token_buffer); 126 args.output_token.value = token_buffer; 127 128 gethostname(hostname, sizeof(hostname)); 129 snprintf(token_buffer, sizeof(token_buffer), 130 "nfs@%s", hostname); 131 name_buf.length = strlen(token_buffer); 132 name_buf.value = token_buffer; 133 maj_stat = gss_import_name(&min_stat, &name_buf, 134 GSS_C_NT_HOSTBASED_SERVICE, &name); 135 if (GSS_ERROR(maj_stat)) { 136 printf("gss_import_name failed\n"); 137 report_error(mech_type, maj_stat, min_stat); 138 goto out; 139 } 140 141 maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, 142 0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_cred, 143 NULL, NULL); 144 if (GSS_ERROR(maj_stat)) { 145 printf("gss_acquire_cred (client) failed\n"); 146 report_error(mech_type, maj_stat, min_stat); 147 goto out; 148 } 149 150 maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, 151 client_cred, 1, &enctypes[i]); 152 if (GSS_ERROR(maj_stat)) { 153 printf("gss_krb5_set_allowable_enctypes failed\n"); 154 report_error(mech_type, maj_stat, min_stat); 155 goto out; 156 } 157 158 res.output_token.length = 0; 159 res.output_token.value = 0; 160 established = 0; 161 while (!established) { 162 maj_stat = gss_init_sec_context(&min_stat, 163 client_cred, 164 &client_context, 165 name, 166 GSS_C_NO_OID, 167 (GSS_C_MUTUAL_FLAG 168 |GSS_C_CONF_FLAG 169 |GSS_C_INTEG_FLAG 170 |GSS_C_SEQUENCE_FLAG 171 |GSS_C_REPLAY_FLAG), 172 0, 173 GSS_C_NO_CHANNEL_BINDINGS, 174 &res.output_token, 175 &mech_type, 176 &args.input_token, 177 NULL, 178 NULL); 179 if (GSS_ERROR(maj_stat)) { 180 printf("gss_init_sec_context failed\n"); 181 report_error(mech_type, maj_stat, min_stat); 182 goto out; 183 } 184 if (args.input_token.length) { 185 args.step = 1; 186 syscall(syscall_num, 2, &args, &res); 187 gss_release_buffer(&min_stat, 188 &args.input_token); 189 if (res.maj_stat != GSS_S_COMPLETE 190 && res.maj_stat != GSS_S_CONTINUE_NEEDED) { 191 printf("gss_accept_sec_context (kernel) failed\n"); 192 report_error(mech_type, res.maj_stat, 193 res.min_stat); 194 goto out; 195 } 196 } 197 if (maj_stat == GSS_S_COMPLETE) 198 established = 1; 199 } 200 201 message_buf.value = "Hello world"; 202 message_buf.length = strlen((char *) message_buf.value); 203 204 maj_stat = gss_get_mic(&min_stat, client_context, 205 GSS_C_QOP_DEFAULT, &message_buf, &args.input_token); 206 if (GSS_ERROR(maj_stat)) { 207 printf("gss_get_mic failed\n"); 208 report_error(mech_type, maj_stat, min_stat); 209 goto out; 210 } 211 212 args.step = 2; 213 syscall(syscall_num, 2, &args, &res); 214 gss_release_buffer(&min_stat, &args.input_token); 215 if (GSS_ERROR(res.maj_stat)) { 216 printf("kernel gss_verify_mic failed\n"); 217 report_error(mech_type, res.maj_stat, res.min_stat); 218 goto out; 219 } 220 221 maj_stat = gss_verify_mic(&min_stat, client_context, 222 &message_buf, &res.output_token, NULL); 223 if (GSS_ERROR(maj_stat)) { 224 printf("gss_verify_mic failed\n"); 225 report_error(mech_type, maj_stat, min_stat); 226 goto out; 227 } 228 229 maj_stat = gss_wrap(&min_stat, client_context, 230 TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, 231 &args.input_token); 232 if (GSS_ERROR(maj_stat)) { 233 printf("gss_wrap failed\n"); 234 report_error(mech_type, maj_stat, min_stat); 235 goto out; 236 } 237 238 args.step = 3; 239 syscall(syscall_num, 2, &args, &res); 240 gss_release_buffer(&min_stat, &args.input_token); 241 if (GSS_ERROR(res.maj_stat)) { 242 printf("kernel gss_unwrap failed\n"); 243 report_error(mech_type, res.maj_stat, res.min_stat); 244 goto out; 245 } 246 247 maj_stat = gss_unwrap(&min_stat, client_context, 248 &res.output_token, &message_buf, NULL, NULL); 249 if (GSS_ERROR(maj_stat)) { 250 printf("gss_unwrap failed\n"); 251 report_error(mech_type, maj_stat, min_stat); 252 goto out; 253 } 254 gss_release_buffer(&min_stat, &message_buf); 255 256 maj_stat = gss_wrap(&min_stat, client_context, 257 FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL, 258 &args.input_token); 259 if (GSS_ERROR(maj_stat)) { 260 printf("gss_wrap failed\n"); 261 report_error(mech_type, maj_stat, min_stat); 262 goto out; 263 } 264 265 args.step = 4; 266 syscall(syscall_num, 2, &args, &res); 267 gss_release_buffer(&min_stat, &args.input_token); 268 if (GSS_ERROR(res.maj_stat)) { 269 printf("kernel gss_unwrap failed\n"); 270 report_error(mech_type, res.maj_stat, res.min_stat); 271 goto out; 272 } 273 274 maj_stat = gss_unwrap(&min_stat, client_context, 275 &res.output_token, &message_buf, NULL, NULL); 276 if (GSS_ERROR(maj_stat)) { 277 printf("gss_unwrap failed\n"); 278 report_error(mech_type, maj_stat, min_stat); 279 goto out; 280 } 281 gss_release_buffer(&min_stat, &message_buf); 282 283 args.step = 5; 284 syscall(syscall_num, 2, &args, &res); 285 286 gss_release_name(&min_stat, &name); 287 gss_release_cred(&min_stat, &client_cred); 288 gss_delete_sec_context(&min_stat, &client_context, 289 GSS_C_NO_BUFFER); 290 } 291 292 break; 293 } 294 case 3: 295 syscall(syscall_num, 3, NULL, NULL); 296 break; 297 case 4: 298 syscall(syscall_num, 4, NULL, NULL); 299 break; 300 } 301 return (0); 302 303 out: 304 return (1); 305 } 306