gsstest.c revision 184887
1184588Sdfr/*- 2184588Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3184588Sdfr * Authors: Doug Rabson <dfr@rabson.org> 4184588Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5184588Sdfr * 6184588Sdfr * Redistribution and use in source and binary forms, with or without 7184588Sdfr * modification, are permitted provided that the following conditions 8184588Sdfr * are met: 9184588Sdfr * 1. Redistributions of source code must retain the above copyright 10184588Sdfr * notice, this list of conditions and the following disclaimer. 11184588Sdfr * 2. Redistributions in binary form must reproduce the above copyright 12184588Sdfr * notice, this list of conditions and the following disclaimer in the 13184588Sdfr * documentation and/or other materials provided with the distribution. 14184588Sdfr * 15184588Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16184588Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17184588Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18184588Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19184588Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20184588Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21184588Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22184588Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23184588Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24184588Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25184588Sdfr * SUCH DAMAGE. 26184588Sdfr */ 27184588Sdfr 28184588Sdfr#include <sys/cdefs.h> 29184588Sdfr__FBSDID("$FreeBSD: head/sys/kgssapi/gsstest.c 184887 2008-11-12 15:31:05Z dfr $"); 30184588Sdfr 31184588Sdfr#include <sys/ctype.h> 32184588Sdfr#include <sys/param.h> 33184588Sdfr#include <sys/kernel.h> 34184588Sdfr#include <sys/kobj.h> 35184588Sdfr#include <sys/malloc.h> 36184588Sdfr#include <sys/module.h> 37184588Sdfr#include <sys/proc.h> 38184588Sdfr#include <sys/socketvar.h> 39184588Sdfr#include <sys/sysent.h> 40184588Sdfr#include <sys/sysproto.h> 41184588Sdfr 42184588Sdfr#include <kgssapi/gssapi.h> 43184588Sdfr#include <kgssapi/gssapi_impl.h> 44184588Sdfr#include <rpc/rpc.h> 45184588Sdfr#include <rpc/rpc_com.h> 46184588Sdfr#include <rpc/rpcb_prot.h> 47184588Sdfr#include <rpc/rpcsec_gss.h> 48184588Sdfr 49184588Sdfrstatic void 50184588Sdfrreport_error(gss_OID mech, OM_uint32 maj, OM_uint32 min) 51184588Sdfr{ 52184588Sdfr OM_uint32 maj_stat, min_stat; 53184588Sdfr OM_uint32 message_context; 54184588Sdfr gss_buffer_desc buf; 55184588Sdfr 56184588Sdfr uprintf("major_stat=%d, minor_stat=%d\n", maj, min); 57184588Sdfr message_context = 0; 58184588Sdfr do { 59184588Sdfr maj_stat = gss_display_status(&min_stat, maj, 60184588Sdfr GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buf); 61184588Sdfr if (GSS_ERROR(maj_stat)) 62184588Sdfr break; 63184588Sdfr uprintf("%.*s\n", (int)buf.length, (char *) buf.value); 64184588Sdfr gss_release_buffer(&min_stat, &buf); 65184588Sdfr } while (message_context); 66184588Sdfr if (mech && min) { 67184588Sdfr message_context = 0; 68184588Sdfr do { 69184588Sdfr maj_stat = gss_display_status(&min_stat, min, 70184588Sdfr GSS_C_MECH_CODE, mech, &message_context, &buf); 71184588Sdfr if (GSS_ERROR(maj_stat)) 72184588Sdfr break; 73184588Sdfr uprintf("%.*s\n", (int)buf.length, (char *) buf.value); 74184588Sdfr gss_release_buffer(&min_stat, &buf); 75184588Sdfr } while (message_context); 76184588Sdfr } 77184588Sdfr} 78184588Sdfr 79184588Sdfr#if 0 80184588Sdfrstatic void 81184588Sdfrsend_token_to_peer(const gss_buffer_t token) 82184588Sdfr{ 83184588Sdfr const uint8_t *p; 84184588Sdfr size_t i; 85184588Sdfr 86184588Sdfr printf("send token:\n"); 87184588Sdfr printf("%d ", (int) token->length); 88184588Sdfr p = (const uint8_t *) token->value; 89184588Sdfr for (i = 0; i < token->length; i++) 90184588Sdfr printf("%02x", *p++); 91184588Sdfr printf("\n"); 92184588Sdfr} 93184588Sdfr 94184588Sdfrstatic void 95184588Sdfrreceive_token_from_peer(gss_buffer_t token) 96184588Sdfr{ 97184588Sdfr char line[8192]; 98184588Sdfr char *p; 99184588Sdfr uint8_t *q; 100184588Sdfr int len, val; 101184588Sdfr 102184588Sdfr printf("receive token:\n"); 103184588Sdfr fgets(line, sizeof(line), stdin); 104184588Sdfr if (line[strlen(line) - 1] != '\n') { 105184588Sdfr printf("token truncated\n"); 106184588Sdfr exit(1); 107184588Sdfr } 108184588Sdfr p = line; 109184588Sdfr if (sscanf(line, "%d ", &len) != 1) { 110184588Sdfr printf("bad token\n"); 111184588Sdfr exit(1); 112184588Sdfr } 113184588Sdfr p = strchr(p, ' ') + 1; 114184588Sdfr token->length = len; 115184588Sdfr token->value = malloc(len); 116184588Sdfr q = (uint8_t *) token->value; 117184588Sdfr while (len) { 118184588Sdfr if (sscanf(p, "%02x", &val) != 1) { 119184588Sdfr printf("bad token\n"); 120184588Sdfr exit(1); 121184588Sdfr } 122184588Sdfr *q++ = val; 123184588Sdfr p += 2; 124184588Sdfr len--; 125184588Sdfr } 126184588Sdfr} 127184588Sdfr#endif 128184588Sdfr 129184588Sdfr#if 0 130184588Sdfrvoid 131184588Sdfrserver(int argc, char** argv) 132184588Sdfr{ 133184588Sdfr OM_uint32 maj_stat, min_stat; 134184588Sdfr gss_buffer_desc input_token, output_token; 135184588Sdfr gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT; 136184588Sdfr gss_name_t client_name; 137184588Sdfr gss_OID mech_type; 138184588Sdfr 139184588Sdfr if (argc != 1) 140184588Sdfr usage(); 141184588Sdfr 142184588Sdfr do { 143184588Sdfr receive_token_from_peer(&input_token); 144184588Sdfr maj_stat = gss_accept_sec_context(&min_stat, 145184588Sdfr &context_hdl, 146184588Sdfr GSS_C_NO_CREDENTIAL, 147184588Sdfr &input_token, 148184588Sdfr GSS_C_NO_CHANNEL_BINDINGS, 149184588Sdfr &client_name, 150184588Sdfr &mech_type, 151184588Sdfr &output_token, 152184588Sdfr NULL, 153184588Sdfr NULL, 154184588Sdfr NULL); 155184588Sdfr if (GSS_ERROR(maj_stat)) { 156184588Sdfr report_error(mech_type, maj_stat, min_stat); 157184588Sdfr } 158184588Sdfr if (output_token.length != 0) { 159184588Sdfr send_token_to_peer(&output_token); 160184588Sdfr gss_release_buffer(&min_stat, &output_token); 161184588Sdfr } 162184588Sdfr if (GSS_ERROR(maj_stat)) { 163184588Sdfr if (context_hdl != GSS_C_NO_CONTEXT) 164184588Sdfr gss_delete_sec_context(&min_stat, 165184588Sdfr &context_hdl, 166184588Sdfr GSS_C_NO_BUFFER); 167184588Sdfr break; 168184588Sdfr } 169184588Sdfr } while (maj_stat & GSS_S_CONTINUE_NEEDED); 170184588Sdfr 171184588Sdfr if (client_name) { 172184588Sdfr gss_buffer_desc name_desc; 173184588Sdfr char buf[512]; 174184588Sdfr 175184588Sdfr gss_display_name(&min_stat, client_name, &name_desc, NULL); 176184588Sdfr memcpy(buf, name_desc.value, name_desc.length); 177184588Sdfr buf[name_desc.length] = 0; 178184588Sdfr gss_release_buffer(&min_stat, &name_desc); 179184588Sdfr printf("client name is %s\n", buf); 180184588Sdfr } 181184588Sdfr 182184588Sdfr receive_token_from_peer(&input_token); 183184588Sdfr gss_unwrap(&min_stat, context_hdl, &input_token, &output_token, 184184588Sdfr NULL, NULL); 185184588Sdfr printf("%.*s\n", (int)output_token.length, (char *) output_token.value); 186184588Sdfr gss_release_buffer(&min_stat, &output_token); 187184588Sdfr} 188184588Sdfr#endif 189184588Sdfr 190184588Sdfr/* 1.2.752.43.13.14 */ 191184588Sdfrstatic gss_OID_desc gss_krb5_set_allowable_enctypes_x_desc = 192184588Sdfr{6, (void *) "\x2a\x85\x70\x2b\x0d\x0e"}; 193184588Sdfr 194184588Sdfrgss_OID GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X = &gss_krb5_set_allowable_enctypes_x_desc; 195184588Sdfr#define ETYPE_DES_CBC_CRC 1 196184588Sdfr 197184588Sdfr/* 198184588Sdfr * Create an initiator context and acceptor context in the kernel and 199184588Sdfr * use them to exchange signed and sealed messages. 200184588Sdfr */ 201184588Sdfrstatic int 202184588Sdfrgsstest_1(void) 203184588Sdfr{ 204184588Sdfr OM_uint32 maj_stat, min_stat; 205184588Sdfr OM_uint32 smaj_stat, smin_stat; 206184588Sdfr int context_established = 0; 207184588Sdfr gss_ctx_id_t client_context = GSS_C_NO_CONTEXT; 208184588Sdfr gss_ctx_id_t server_context = GSS_C_NO_CONTEXT; 209184588Sdfr gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL; 210184588Sdfr gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL; 211184588Sdfr gss_name_t name = GSS_C_NO_NAME; 212184588Sdfr gss_name_t received_name = GSS_C_NO_NAME; 213184588Sdfr gss_buffer_desc name_desc; 214184588Sdfr gss_buffer_desc client_token, server_token, message_buf; 215184588Sdfr gss_OID mech, actual_mech, mech_type; 216184588Sdfr static gss_OID_desc krb5_desc = 217184588Sdfr {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}; 218184588Sdfr#if 0 219184588Sdfr static gss_OID_desc spnego_desc = 220184588Sdfr {6, (void *)"\x2b\x06\x01\x05\x05\x02"}; 221184588Sdfr static gss_OID_desc ntlm_desc = 222184588Sdfr {10, (void *)"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"}; 223184588Sdfr#endif 224184588Sdfr char enctype[sizeof(uint32_t)]; 225184588Sdfr 226184588Sdfr mech = GSS_C_NO_OID; 227184588Sdfr 228184588Sdfr { 229184588Sdfr static char sbuf[512]; 230184588Sdfr snprintf(sbuf, sizeof(sbuf), "nfs@%s", hostname); 231184588Sdfr name_desc.value = sbuf; 232184588Sdfr } 233184588Sdfr 234184588Sdfr name_desc.length = strlen((const char *) name_desc.value); 235184588Sdfr maj_stat = gss_import_name(&min_stat, &name_desc, 236184588Sdfr GSS_C_NT_HOSTBASED_SERVICE, &name); 237184588Sdfr if (GSS_ERROR(maj_stat)) { 238184588Sdfr printf("gss_import_name failed\n"); 239184588Sdfr report_error(mech, maj_stat, min_stat); 240184588Sdfr goto out; 241184588Sdfr } 242184588Sdfr 243184588Sdfr maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, 244184588Sdfr 0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_cred, 245184588Sdfr NULL, NULL); 246184588Sdfr if (GSS_ERROR(maj_stat)) { 247184588Sdfr printf("gss_acquire_cred (client) failed\n"); 248184588Sdfr report_error(mech, maj_stat, min_stat); 249184588Sdfr goto out; 250184588Sdfr } 251184588Sdfr 252184588Sdfr enctype[0] = (ETYPE_DES_CBC_CRC >> 24) & 0xff; 253184588Sdfr enctype[1] = (ETYPE_DES_CBC_CRC >> 16) & 0xff; 254184588Sdfr enctype[2] = (ETYPE_DES_CBC_CRC >> 8) & 0xff; 255184588Sdfr enctype[3] = ETYPE_DES_CBC_CRC & 0xff; 256184588Sdfr message_buf.length = sizeof(enctype); 257184588Sdfr message_buf.value = enctype; 258184588Sdfr maj_stat = gss_set_cred_option(&min_stat, &client_cred, 259184588Sdfr GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, &message_buf); 260184588Sdfr if (GSS_ERROR(maj_stat)) { 261184588Sdfr printf("gss_set_cred_option failed\n"); 262184588Sdfr report_error(mech, maj_stat, min_stat); 263184588Sdfr goto out; 264184588Sdfr } 265184588Sdfr 266184588Sdfr server_token.length = 0; 267184588Sdfr server_token.value = NULL; 268184588Sdfr while (!context_established) { 269184588Sdfr client_token.length = 0; 270184588Sdfr client_token.value = NULL; 271184588Sdfr maj_stat = gss_init_sec_context(&min_stat, 272184588Sdfr client_cred, 273184588Sdfr &client_context, 274184588Sdfr name, 275184588Sdfr mech, 276184588Sdfr GSS_C_MUTUAL_FLAG|GSS_C_CONF_FLAG|GSS_C_INTEG_FLAG, 277184588Sdfr 0, 278184588Sdfr GSS_C_NO_CHANNEL_BINDINGS, 279184588Sdfr &server_token, 280184588Sdfr &actual_mech, 281184588Sdfr &client_token, 282184588Sdfr NULL, 283184588Sdfr NULL); 284184588Sdfr if (server_token.length) 285184588Sdfr gss_release_buffer(&smin_stat, &server_token); 286184588Sdfr if (GSS_ERROR(maj_stat)) { 287184588Sdfr printf("gss_init_sec_context failed\n"); 288184588Sdfr report_error(mech, maj_stat, min_stat); 289184588Sdfr goto out; 290184588Sdfr } 291184588Sdfr 292184588Sdfr if (client_token.length != 0) { 293184588Sdfr if (!server_cred) { 294184588Sdfr gss_OID_set_desc oid_set; 295184588Sdfr oid_set.count = 1; 296184588Sdfr oid_set.elements = &krb5_desc; 297184588Sdfr smaj_stat = gss_acquire_cred(&smin_stat, 298184588Sdfr name, 0, &oid_set, GSS_C_ACCEPT, &server_cred, 299184588Sdfr NULL, NULL); 300184588Sdfr if (GSS_ERROR(smaj_stat)) { 301184588Sdfr printf("gss_acquire_cred (server) failed\n"); 302184588Sdfr report_error(mech_type, smaj_stat, smin_stat); 303184588Sdfr goto out; 304184588Sdfr } 305184588Sdfr } 306184588Sdfr smaj_stat = gss_accept_sec_context(&smin_stat, 307184588Sdfr &server_context, 308184588Sdfr server_cred, 309184588Sdfr &client_token, 310184588Sdfr GSS_C_NO_CHANNEL_BINDINGS, 311184588Sdfr &received_name, 312184588Sdfr &mech_type, 313184588Sdfr &server_token, 314184588Sdfr NULL, 315184588Sdfr NULL, 316184588Sdfr NULL); 317184588Sdfr if (GSS_ERROR(smaj_stat)) { 318184588Sdfr printf("gss_accept_sec_context failed\n"); 319184588Sdfr report_error(mech_type, smaj_stat, smin_stat); 320184588Sdfr goto out; 321184588Sdfr } 322184588Sdfr gss_release_buffer(&min_stat, &client_token); 323184588Sdfr } 324184588Sdfr if (GSS_ERROR(maj_stat)) { 325184588Sdfr if (client_context != GSS_C_NO_CONTEXT) 326184588Sdfr gss_delete_sec_context(&min_stat, 327184588Sdfr &client_context, 328184588Sdfr GSS_C_NO_BUFFER); 329184588Sdfr break; 330184588Sdfr } 331184588Sdfr 332184588Sdfr if (maj_stat == GSS_S_COMPLETE) { 333184588Sdfr context_established = 1; 334184588Sdfr } 335184588Sdfr } 336184588Sdfr 337184588Sdfr message_buf.length = strlen("Hello world"); 338184588Sdfr message_buf.value = (void *) "Hello world"; 339184588Sdfr 340184588Sdfr maj_stat = gss_get_mic(&min_stat, client_context, 341184588Sdfr GSS_C_QOP_DEFAULT, &message_buf, &client_token); 342184588Sdfr if (GSS_ERROR(maj_stat)) { 343184588Sdfr printf("gss_get_mic failed\n"); 344184588Sdfr report_error(mech_type, maj_stat, min_stat); 345184588Sdfr goto out; 346184588Sdfr } 347184588Sdfr maj_stat = gss_verify_mic(&min_stat, server_context, 348184588Sdfr &message_buf, &client_token, NULL); 349184588Sdfr if (GSS_ERROR(maj_stat)) { 350184588Sdfr printf("gss_verify_mic failed\n"); 351184588Sdfr report_error(mech_type, maj_stat, min_stat); 352184588Sdfr goto out; 353184588Sdfr } 354184588Sdfr gss_release_buffer(&min_stat, &client_token); 355184588Sdfr 356184588Sdfr maj_stat = gss_wrap(&min_stat, client_context, 357184588Sdfr TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, &client_token); 358184588Sdfr if (GSS_ERROR(maj_stat)) { 359184588Sdfr printf("gss_wrap failed\n"); 360184588Sdfr report_error(mech_type, maj_stat, min_stat); 361184588Sdfr goto out; 362184588Sdfr } 363184588Sdfr maj_stat = gss_unwrap(&min_stat, server_context, 364184588Sdfr &client_token, &server_token, NULL, NULL); 365184588Sdfr if (GSS_ERROR(maj_stat)) { 366184588Sdfr printf("gss_unwrap failed\n"); 367184588Sdfr report_error(mech_type, maj_stat, min_stat); 368184588Sdfr goto out; 369184588Sdfr } 370184588Sdfr 371184588Sdfr if (message_buf.length != server_token.length 372184588Sdfr || memcmp(message_buf.value, server_token.value, 373184588Sdfr message_buf.length)) 374184588Sdfr printf("unwrap result corrupt\n"); 375184588Sdfr 376184588Sdfr gss_release_buffer(&min_stat, &client_token); 377184588Sdfr gss_release_buffer(&min_stat, &server_token); 378184588Sdfr 379184588Sdfrout: 380184588Sdfr if (client_context) 381184588Sdfr gss_delete_sec_context(&min_stat, &client_context, 382184588Sdfr GSS_C_NO_BUFFER); 383184588Sdfr if (server_context) 384184588Sdfr gss_delete_sec_context(&min_stat, &server_context, 385184588Sdfr GSS_C_NO_BUFFER); 386184588Sdfr if (client_cred) 387184588Sdfr gss_release_cred(&min_stat, &client_cred); 388184588Sdfr if (server_cred) 389184588Sdfr gss_release_cred(&min_stat, &server_cred); 390184588Sdfr if (name) 391184588Sdfr gss_release_name(&min_stat, &name); 392184588Sdfr if (received_name) 393184588Sdfr gss_release_name(&min_stat, &received_name); 394184588Sdfr 395184588Sdfr return (0); 396184588Sdfr} 397184588Sdfr 398184588Sdfr/* 399184588Sdfr * Interoperability with userland. This takes several steps: 400184588Sdfr * 401184588Sdfr * 1. Accept an initiator token from userland, return acceptor 402184588Sdfr * token. Repeat this step until both userland and kernel return 403184588Sdfr * GSS_S_COMPLETE. 404184588Sdfr * 405184588Sdfr * 2. Receive a signed message from userland and verify the 406184588Sdfr * signature. Return a signed reply to userland for it to verify. 407184588Sdfr * 408184588Sdfr * 3. Receive a wrapped message from userland and unwrap it. Return a 409184588Sdfr * wrapped reply to userland. 410184588Sdfr */ 411184588Sdfrstatic int 412184588Sdfrgsstest_2(int step, const gss_buffer_t input_token, 413184588Sdfr OM_uint32 *maj_stat_res, OM_uint32 *min_stat_res, gss_buffer_t output_token) 414184588Sdfr{ 415184588Sdfr OM_uint32 maj_stat, min_stat; 416184588Sdfr static int context_established = 0; 417184588Sdfr static gss_ctx_id_t server_context = GSS_C_NO_CONTEXT; 418184588Sdfr static gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL; 419184588Sdfr static gss_name_t name = GSS_C_NO_NAME; 420184588Sdfr gss_buffer_desc name_desc; 421184588Sdfr gss_buffer_desc message_buf; 422184588Sdfr gss_OID mech_type = GSS_C_NO_OID; 423184588Sdfr char enctype[sizeof(uint32_t)]; 424184588Sdfr int error = EINVAL; 425184588Sdfr 426184588Sdfr maj_stat = GSS_S_FAILURE; 427184588Sdfr min_stat = 0; 428184588Sdfr switch (step) { 429184588Sdfr 430184588Sdfr case 1: 431184588Sdfr if (server_context == GSS_C_NO_CONTEXT) { 432184588Sdfr static char sbuf[512]; 433184588Sdfr snprintf(sbuf, sizeof(sbuf), "nfs@%s", hostname); 434184588Sdfr name_desc.value = sbuf; 435184588Sdfr name_desc.length = strlen((const char *) 436184588Sdfr name_desc.value); 437184588Sdfr maj_stat = gss_import_name(&min_stat, &name_desc, 438184588Sdfr GSS_C_NT_HOSTBASED_SERVICE, &name); 439184588Sdfr if (GSS_ERROR(maj_stat)) { 440184588Sdfr printf("gss_import_name failed\n"); 441184588Sdfr report_error(mech_type, maj_stat, min_stat); 442184588Sdfr goto out; 443184588Sdfr } 444184588Sdfr 445184588Sdfr maj_stat = gss_acquire_cred(&min_stat, 446184588Sdfr name, 0, GSS_C_NO_OID_SET, GSS_C_ACCEPT, 447184588Sdfr &server_cred, NULL, NULL); 448184588Sdfr if (GSS_ERROR(maj_stat)) { 449184588Sdfr printf("gss_acquire_cred (server) failed\n"); 450184588Sdfr report_error(mech_type, maj_stat, min_stat); 451184588Sdfr goto out; 452184588Sdfr } 453184588Sdfr 454184588Sdfr enctype[0] = (ETYPE_DES_CBC_CRC >> 24) & 0xff; 455184588Sdfr enctype[1] = (ETYPE_DES_CBC_CRC >> 16) & 0xff; 456184588Sdfr enctype[2] = (ETYPE_DES_CBC_CRC >> 8) & 0xff; 457184588Sdfr enctype[3] = ETYPE_DES_CBC_CRC & 0xff; 458184588Sdfr message_buf.length = sizeof(enctype); 459184588Sdfr message_buf.value = enctype; 460184588Sdfr maj_stat = gss_set_cred_option(&min_stat, &server_cred, 461184588Sdfr GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, &message_buf); 462184588Sdfr if (GSS_ERROR(maj_stat)) { 463184588Sdfr printf("gss_set_cred_option failed\n"); 464184588Sdfr report_error(mech_type, maj_stat, min_stat); 465184588Sdfr goto out; 466184588Sdfr } 467184588Sdfr } 468184588Sdfr 469184588Sdfr maj_stat = gss_accept_sec_context(&min_stat, 470184588Sdfr &server_context, 471184588Sdfr server_cred, 472184588Sdfr input_token, 473184588Sdfr GSS_C_NO_CHANNEL_BINDINGS, 474184588Sdfr NULL, 475184588Sdfr &mech_type, 476184588Sdfr output_token, 477184588Sdfr NULL, 478184588Sdfr NULL, 479184588Sdfr NULL); 480184588Sdfr if (GSS_ERROR(maj_stat)) { 481184588Sdfr printf("gss_accept_sec_context failed\n"); 482184588Sdfr report_error(mech_type, maj_stat, min_stat); 483184588Sdfr goto out; 484184588Sdfr } 485184588Sdfr 486184588Sdfr if (maj_stat == GSS_S_COMPLETE) { 487184588Sdfr context_established = 1; 488184588Sdfr } 489184588Sdfr *maj_stat_res = maj_stat; 490184588Sdfr *min_stat_res = min_stat; 491184588Sdfr break; 492184588Sdfr 493184588Sdfr case 2: 494184588Sdfr message_buf.length = strlen("Hello world"); 495184588Sdfr message_buf.value = (void *) "Hello world"; 496184588Sdfr 497184588Sdfr maj_stat = gss_verify_mic(&min_stat, server_context, 498184588Sdfr &message_buf, input_token, NULL); 499184588Sdfr if (GSS_ERROR(maj_stat)) { 500184588Sdfr printf("gss_verify_mic failed\n"); 501184588Sdfr report_error(mech_type, maj_stat, min_stat); 502184588Sdfr goto out; 503184588Sdfr } 504184588Sdfr 505184588Sdfr maj_stat = gss_get_mic(&min_stat, server_context, 506184588Sdfr GSS_C_QOP_DEFAULT, &message_buf, output_token); 507184588Sdfr if (GSS_ERROR(maj_stat)) { 508184588Sdfr printf("gss_get_mic failed\n"); 509184588Sdfr report_error(mech_type, maj_stat, min_stat); 510184588Sdfr goto out; 511184588Sdfr } 512184588Sdfr break; 513184588Sdfr 514184588Sdfr case 3: 515184588Sdfr maj_stat = gss_unwrap(&min_stat, server_context, 516184588Sdfr input_token, &message_buf, NULL, NULL); 517184588Sdfr if (GSS_ERROR(maj_stat)) { 518184588Sdfr printf("gss_unwrap failed\n"); 519184588Sdfr report_error(mech_type, maj_stat, min_stat); 520184588Sdfr goto out; 521184588Sdfr } 522184588Sdfr gss_release_buffer(&min_stat, &message_buf); 523184588Sdfr 524184588Sdfr message_buf.length = strlen("Hello world"); 525184588Sdfr message_buf.value = (void *) "Hello world"; 526184588Sdfr maj_stat = gss_wrap(&min_stat, server_context, 527184588Sdfr TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, output_token); 528184588Sdfr if (GSS_ERROR(maj_stat)) { 529184588Sdfr printf("gss_wrap failed\n"); 530184588Sdfr report_error(mech_type, maj_stat, min_stat); 531184588Sdfr goto out; 532184588Sdfr } 533184588Sdfr break; 534184588Sdfr 535184588Sdfr case 4: 536184588Sdfr maj_stat = gss_unwrap(&min_stat, server_context, 537184588Sdfr input_token, &message_buf, NULL, NULL); 538184588Sdfr if (GSS_ERROR(maj_stat)) { 539184588Sdfr printf("gss_unwrap failed\n"); 540184588Sdfr report_error(mech_type, maj_stat, min_stat); 541184588Sdfr goto out; 542184588Sdfr } 543184588Sdfr gss_release_buffer(&min_stat, &message_buf); 544184588Sdfr 545184588Sdfr message_buf.length = strlen("Hello world"); 546184588Sdfr message_buf.value = (void *) "Hello world"; 547184588Sdfr maj_stat = gss_wrap(&min_stat, server_context, 548184588Sdfr FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL, output_token); 549184588Sdfr if (GSS_ERROR(maj_stat)) { 550184588Sdfr printf("gss_wrap failed\n"); 551184588Sdfr report_error(mech_type, maj_stat, min_stat); 552184588Sdfr goto out; 553184588Sdfr } 554184588Sdfr break; 555184588Sdfr 556184588Sdfr case 5: 557184588Sdfr error = 0; 558184588Sdfr goto out; 559184588Sdfr } 560184588Sdfr *maj_stat_res = maj_stat; 561184588Sdfr *min_stat_res = min_stat; 562184588Sdfr return (0); 563184588Sdfr 564184588Sdfrout: 565184588Sdfr *maj_stat_res = maj_stat; 566184588Sdfr *min_stat_res = min_stat; 567184588Sdfr if (server_context) 568184588Sdfr gss_delete_sec_context(&min_stat, &server_context, 569184588Sdfr GSS_C_NO_BUFFER); 570184588Sdfr if (server_cred) 571184588Sdfr gss_release_cred(&min_stat, &server_cred); 572184588Sdfr if (name) 573184588Sdfr gss_release_name(&min_stat, &name); 574184588Sdfr 575184588Sdfr return (error); 576184588Sdfr} 577184588Sdfr 578184588Sdfr/* 579184588Sdfr * Create an RPC client handle for the given (address,prog,vers) 580184588Sdfr * triple using UDP. 581184588Sdfr */ 582184588Sdfrstatic CLIENT * 583184588Sdfrgsstest_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers) 584184588Sdfr{ 585184588Sdfr struct thread *td = curthread; 586184588Sdfr const char* protofmly; 587184588Sdfr struct sockaddr_storage ss; 588184588Sdfr struct socket *so; 589184588Sdfr CLIENT *rpcb; 590184588Sdfr struct timeval timo; 591184588Sdfr RPCB parms; 592184588Sdfr char *uaddr; 593184588Sdfr enum clnt_stat stat = RPC_SUCCESS; 594184588Sdfr int rpcvers = RPCBVERS4; 595184588Sdfr bool_t do_tcp = FALSE; 596184588Sdfr struct portmap mapping; 597184588Sdfr u_short port = 0; 598184588Sdfr 599184588Sdfr /* 600184588Sdfr * First we need to contact the remote RPCBIND service to find 601184588Sdfr * the right port. 602184588Sdfr */ 603184588Sdfr memcpy(&ss, sa, sa->sa_len); 604184588Sdfr switch (ss.ss_family) { 605184588Sdfr case AF_INET: 606184588Sdfr ((struct sockaddr_in *)&ss)->sin_port = htons(111); 607184588Sdfr protofmly = "inet"; 608184588Sdfr socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td); 609184588Sdfr break; 610184588Sdfr 611184588Sdfr#ifdef INET6 612184588Sdfr case AF_INET6: 613184588Sdfr ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111); 614184588Sdfr protofmly = "inet6"; 615184588Sdfr socreate(AF_INET6, &so, SOCK_DGRAM, 0, td->td_ucred, td); 616184588Sdfr break; 617184588Sdfr#endif 618184588Sdfr 619184588Sdfr default: 620184588Sdfr /* 621184588Sdfr * Unsupported address family - fail. 622184588Sdfr */ 623184588Sdfr return (NULL); 624184588Sdfr } 625184588Sdfr 626184588Sdfr rpcb = clnt_dg_create(so, (struct sockaddr *)&ss, 627184588Sdfr RPCBPROG, rpcvers, 0, 0); 628184588Sdfr if (!rpcb) 629184588Sdfr return (NULL); 630184588Sdfr 631184588Sdfrtry_tcp: 632184588Sdfr parms.r_prog = prog; 633184588Sdfr parms.r_vers = vers; 634184588Sdfr if (do_tcp) 635184588Sdfr parms.r_netid = "tcp"; 636184588Sdfr else 637184588Sdfr parms.r_netid = "udp"; 638184588Sdfr parms.r_addr = ""; 639184588Sdfr parms.r_owner = ""; 640184588Sdfr 641184588Sdfr /* 642184588Sdfr * Use the default timeout. 643184588Sdfr */ 644184588Sdfr timo.tv_sec = 25; 645184588Sdfr timo.tv_usec = 0; 646184588Sdfragain: 647184588Sdfr switch (rpcvers) { 648184588Sdfr case RPCBVERS4: 649184588Sdfr case RPCBVERS: 650184588Sdfr /* 651184588Sdfr * Try RPCBIND 4 then 3. 652184588Sdfr */ 653184588Sdfr uaddr = NULL; 654184588Sdfr stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR, 655184588Sdfr (xdrproc_t) xdr_rpcb, &parms, 656184588Sdfr (xdrproc_t) xdr_wrapstring, &uaddr, timo); 657184588Sdfr if (stat == RPC_PROGVERSMISMATCH) { 658184588Sdfr if (rpcvers == RPCBVERS4) 659184588Sdfr rpcvers = RPCBVERS; 660184588Sdfr else if (rpcvers == RPCBVERS) 661184588Sdfr rpcvers = PMAPVERS; 662184588Sdfr CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers); 663184588Sdfr goto again; 664184588Sdfr } else if (stat == RPC_SUCCESS) { 665184588Sdfr /* 666184588Sdfr * We have a reply from the remote RPCBIND - turn it 667184588Sdfr * into an appropriate address and make a new client 668184588Sdfr * that can talk to the remote service. 669184588Sdfr * 670184588Sdfr * XXX fixup IPv6 scope ID. 671184588Sdfr */ 672184588Sdfr struct netbuf *a; 673184588Sdfr a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr); 674184588Sdfr xdr_free((xdrproc_t) xdr_wrapstring, &uaddr); 675184588Sdfr if (!a) { 676184588Sdfr CLNT_DESTROY(rpcb); 677184588Sdfr return (NULL); 678184588Sdfr } 679184588Sdfr memcpy(&ss, a->buf, a->len); 680184588Sdfr free(a->buf, M_RPC); 681184588Sdfr free(a, M_RPC); 682184588Sdfr } 683184588Sdfr break; 684184588Sdfr case PMAPVERS: 685184588Sdfr /* 686184588Sdfr * Try portmap. 687184588Sdfr */ 688184588Sdfr mapping.pm_prog = parms.r_prog; 689184588Sdfr mapping.pm_vers = parms.r_vers; 690184588Sdfr mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP; 691184588Sdfr mapping.pm_port = 0; 692184588Sdfr 693184588Sdfr stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT, 694184588Sdfr (xdrproc_t) xdr_portmap, &mapping, 695184588Sdfr (xdrproc_t) xdr_u_short, &port, timo); 696184588Sdfr 697184588Sdfr if (stat == RPC_SUCCESS) { 698184588Sdfr switch (ss.ss_family) { 699184588Sdfr case AF_INET: 700184588Sdfr ((struct sockaddr_in *)&ss)->sin_port = 701184588Sdfr htons(port); 702184588Sdfr break; 703184588Sdfr 704184588Sdfr#ifdef INET6 705184588Sdfr case AF_INET6: 706184588Sdfr ((struct sockaddr_in6 *)&ss)->sin6_port = 707184588Sdfr htons(port); 708184588Sdfr break; 709184588Sdfr#endif 710184588Sdfr } 711184588Sdfr } 712184588Sdfr break; 713184588Sdfr default: 714184588Sdfr panic("invalid rpcvers %d", rpcvers); 715184588Sdfr } 716184588Sdfr /* 717184588Sdfr * We may have a positive response from the portmapper, but 718184588Sdfr * the requested service was not found. Make sure we received 719184588Sdfr * a valid port. 720184588Sdfr */ 721184588Sdfr switch (ss.ss_family) { 722184588Sdfr case AF_INET: 723184588Sdfr port = ((struct sockaddr_in *)&ss)->sin_port; 724184588Sdfr break; 725184588Sdfr#ifdef INET6 726184588Sdfr case AF_INET6: 727184588Sdfr port = ((struct sockaddr_in6 *)&ss)->sin6_port; 728184588Sdfr break; 729184588Sdfr#endif 730184588Sdfr } 731184588Sdfr if (stat != RPC_SUCCESS || !port) { 732184588Sdfr /* 733184588Sdfr * If we were able to talk to rpcbind or portmap, but the udp 734184588Sdfr * variant wasn't available, ask about tcp. 735184588Sdfr * 736184588Sdfr * XXX - We could also check for a TCP portmapper, but 737184588Sdfr * if the host is running a portmapper at all, we should be able 738184588Sdfr * to hail it over UDP. 739184588Sdfr */ 740184588Sdfr if (stat == RPC_SUCCESS && !do_tcp) { 741184588Sdfr do_tcp = TRUE; 742184588Sdfr goto try_tcp; 743184588Sdfr } 744184588Sdfr 745184588Sdfr /* Otherwise, bad news. */ 746184588Sdfr printf("gsstest_get_rpc: failed to contact remote rpcbind, " 747184588Sdfr "stat = %d, port = %d\n", 748184588Sdfr (int) stat, port); 749184588Sdfr CLNT_DESTROY(rpcb); 750184588Sdfr return (NULL); 751184588Sdfr } 752184588Sdfr 753184588Sdfr if (do_tcp) { 754184588Sdfr /* 755184588Sdfr * Destroy the UDP client we used to speak to rpcbind and 756184588Sdfr * recreate as a TCP client. 757184588Sdfr */ 758184588Sdfr struct netconfig *nconf = NULL; 759184588Sdfr 760184588Sdfr CLNT_DESTROY(rpcb); 761184588Sdfr 762184588Sdfr switch (ss.ss_family) { 763184588Sdfr case AF_INET: 764184588Sdfr nconf = getnetconfigent("tcp"); 765184588Sdfr break; 766184588Sdfr#ifdef INET6 767184588Sdfr case AF_INET6: 768184588Sdfr nconf = getnetconfigent("tcp6"); 769184588Sdfr break; 770184588Sdfr#endif 771184588Sdfr } 772184588Sdfr 773184588Sdfr rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss, 774184588Sdfr prog, vers, 0, 0); 775184588Sdfr } else { 776184588Sdfr /* 777184588Sdfr * Re-use the client we used to speak to rpcbind. 778184588Sdfr */ 779184588Sdfr CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss); 780184588Sdfr CLNT_CONTROL(rpcb, CLSET_PROG, &prog); 781184588Sdfr CLNT_CONTROL(rpcb, CLSET_VERS, &vers); 782184588Sdfr } 783184588Sdfr 784184588Sdfr return (rpcb); 785184588Sdfr} 786184588Sdfr 787184588Sdfr/* 788184588Sdfr * RPCSEC_GSS client 789184588Sdfr */ 790184588Sdfrstatic int 791184588Sdfrgsstest_3(void) 792184588Sdfr{ 793184588Sdfr struct sockaddr_in sin; 794184588Sdfr char service[128]; 795184588Sdfr CLIENT *client; 796184588Sdfr AUTH *auth; 797184588Sdfr rpc_gss_options_ret_t options_ret; 798184588Sdfr enum clnt_stat stat; 799184588Sdfr struct timeval tv; 800184588Sdfr rpc_gss_service_t svc; 801184588Sdfr int i; 802184588Sdfr 803184588Sdfr sin.sin_len = sizeof(sin); 804184588Sdfr sin.sin_family = AF_INET; 805184588Sdfr sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 806184588Sdfr sin.sin_port = 0; 807184588Sdfr 808184588Sdfr client = gsstest_get_rpc((struct sockaddr *) &sin, 123456, 1); 809184588Sdfr if (!client) { 810184588Sdfr uprintf("Can't connect to service\n"); 811184588Sdfr return(1); 812184588Sdfr } 813184588Sdfr 814184588Sdfr snprintf(service, sizeof(service), "host@%s", hostname); 815184588Sdfr 816184588Sdfr auth = rpc_gss_seccreate(client, curthread->td_ucred, 817184588Sdfr service, "kerberosv5", rpc_gss_svc_privacy, 818184588Sdfr NULL, NULL, &options_ret); 819184588Sdfr if (!auth) { 820184588Sdfr gss_OID oid; 821184588Sdfr uprintf("Can't authorize to service (mech=%s)\n", 822184588Sdfr options_ret.actual_mechanism); 823184588Sdfr oid = GSS_C_NO_OID; 824184588Sdfr rpc_gss_mech_to_oid(options_ret.actual_mechanism, &oid); 825184588Sdfr report_error(oid, options_ret.major_status, 826184588Sdfr options_ret.minor_status); 827184588Sdfr CLNT_DESTROY(client); 828184588Sdfr return (1); 829184588Sdfr } 830184588Sdfr 831184588Sdfr for (svc = rpc_gss_svc_none; svc <= rpc_gss_svc_privacy; svc++) { 832184588Sdfr const char *svc_names[] = { 833184588Sdfr "rpc_gss_svc_default", 834184588Sdfr "rpc_gss_svc_none", 835184588Sdfr "rpc_gss_svc_integrity", 836184588Sdfr "rpc_gss_svc_privacy" 837184588Sdfr }; 838184588Sdfr int num; 839184588Sdfr 840184588Sdfr rpc_gss_set_defaults(auth, svc, NULL); 841184588Sdfr 842184588Sdfr client->cl_auth = auth; 843184588Sdfr tv.tv_sec = 5; 844184588Sdfr tv.tv_usec = 0; 845184588Sdfr for (i = 42; i < 142; i++) { 846184588Sdfr num = i; 847184588Sdfr stat = CLNT_CALL(client, 1, 848184588Sdfr (xdrproc_t) xdr_int, (char *) &num, 849184588Sdfr (xdrproc_t) xdr_int, (char *) &num, tv); 850184588Sdfr if (stat == RPC_SUCCESS) { 851184588Sdfr if (num != i + 100) 852184588Sdfr uprintf("unexpected reply %d\n", num); 853184588Sdfr } else { 854184588Sdfr uprintf("call failed, stat=%d\n", (int) stat); 855184588Sdfr break; 856184588Sdfr } 857184588Sdfr } 858184588Sdfr if (i == 142) 859184588Sdfr uprintf("call succeeded with %s\n", svc_names[svc]); 860184588Sdfr } 861184588Sdfr 862184588Sdfr AUTH_DESTROY(auth); 863184588Sdfr CLNT_RELEASE(client); 864184588Sdfr 865184588Sdfr return (0); 866184588Sdfr} 867184588Sdfr 868184588Sdfr/* 869184588Sdfr * RPCSEC_GSS server 870184588Sdfr */ 871184588Sdfrstatic rpc_gss_principal_t server_acl = NULL; 872184588Sdfrstatic bool_t server_new_context(struct svc_req *req, gss_cred_id_t deleg, 873184588Sdfr gss_ctx_id_t gss_context, rpc_gss_lock_t *lock, void **cookie); 874184588Sdfrstatic void server_program_1(struct svc_req *rqstp, register SVCXPRT *transp); 875184588Sdfr 876184588Sdfrstatic int 877184588Sdfrgsstest_4(void) 878184588Sdfr{ 879184588Sdfr SVCPOOL *pool; 880184588Sdfr char principal[128 + 5]; 881184588Sdfr const char **mechs; 882184588Sdfr static rpc_gss_callback_t cb; 883184588Sdfr 884184588Sdfr snprintf(principal, sizeof(principal), "host@%s", hostname); 885184588Sdfr 886184588Sdfr mechs = rpc_gss_get_mechanisms(); 887184588Sdfr while (*mechs) { 888184588Sdfr if (!rpc_gss_set_svc_name(principal, *mechs, GSS_C_INDEFINITE, 889184588Sdfr 123456, 1)) { 890184588Sdfr rpc_gss_error_t e; 891184588Sdfr 892184588Sdfr rpc_gss_get_error(&e); 893184588Sdfr printf("setting name for %s for %s failed: %d, %d\n", 894184588Sdfr principal, *mechs, 895184588Sdfr e.rpc_gss_error, e.system_error); 896184588Sdfr } 897184588Sdfr mechs++; 898184588Sdfr } 899184588Sdfr 900184588Sdfr cb.program = 123456; 901184588Sdfr cb.version = 1; 902184588Sdfr cb.callback = server_new_context; 903184588Sdfr rpc_gss_set_callback(&cb); 904184588Sdfr 905184588Sdfr pool = svcpool_create("gsstest", NULL); 906184588Sdfr 907184588Sdfr svc_create(pool, server_program_1, 123456, 1, NULL); 908184588Sdfr svc_run(pool); 909184588Sdfr 910184588Sdfr rpc_gss_clear_svc_name(123456, 1); 911184588Sdfr rpc_gss_clear_callback(&cb); 912184588Sdfr 913184588Sdfr svcpool_destroy(pool); 914184588Sdfr 915184588Sdfr return (0); 916184588Sdfr} 917184588Sdfr 918184588Sdfrstatic void 919184588Sdfrserver_program_1(struct svc_req *rqstp, register SVCXPRT *transp) 920184588Sdfr{ 921184588Sdfr rpc_gss_rawcred_t *rcred; 922184588Sdfr rpc_gss_ucred_t *ucred; 923184588Sdfr int i, num; 924184588Sdfr 925184588Sdfr if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS) { 926184588Sdfr svcerr_weakauth(rqstp); 927184588Sdfr return; 928184588Sdfr } 929184588Sdfr 930184588Sdfr if (!rpc_gss_getcred(rqstp, &rcred, &ucred, NULL)) { 931184588Sdfr svcerr_systemerr(rqstp); 932184588Sdfr return; 933184588Sdfr } 934184588Sdfr 935184588Sdfr printf("svc=%d, mech=%s, uid=%d, gid=%d, gids={", 936184588Sdfr rcred->service, rcred->mechanism, ucred->uid, ucred->gid); 937184588Sdfr for (i = 0; i < ucred->gidlen; i++) { 938184588Sdfr if (i > 0) printf(","); 939184588Sdfr printf("%d", ucred->gidlist[i]); 940184588Sdfr } 941184588Sdfr printf("}\n"); 942184588Sdfr 943184588Sdfr switch (rqstp->rq_proc) { 944184588Sdfr case 0: 945184588Sdfr if (!svc_getargs(rqstp, (xdrproc_t) xdr_void, 0)) { 946184588Sdfr svcerr_decode(rqstp); 947184588Sdfr goto out; 948184588Sdfr } 949184588Sdfr if (!svc_sendreply(rqstp, (xdrproc_t) xdr_void, 0)) { 950184588Sdfr svcerr_systemerr(rqstp); 951184588Sdfr } 952184588Sdfr goto out; 953184588Sdfr 954184588Sdfr case 1: 955184588Sdfr if (!svc_getargs(rqstp, (xdrproc_t) xdr_int, 956184588Sdfr (char *) &num)) { 957184588Sdfr svcerr_decode(rqstp); 958184588Sdfr goto out; 959184588Sdfr } 960184588Sdfr num += 100; 961184588Sdfr if (!svc_sendreply(rqstp, (xdrproc_t) xdr_int, 962184588Sdfr (char *) &num)) { 963184588Sdfr svcerr_systemerr(rqstp); 964184588Sdfr } 965184588Sdfr goto out; 966184588Sdfr 967184588Sdfr default: 968184588Sdfr svcerr_noproc(rqstp); 969184588Sdfr goto out; 970184588Sdfr } 971184588Sdfr 972184588Sdfrout: 973184887Sdfr svc_freereq(rqstp); 974184588Sdfr return; 975184588Sdfr} 976184588Sdfr 977184588Sdfrstatic void 978184588Sdfrprint_principal(rpc_gss_principal_t principal) 979184588Sdfr{ 980184588Sdfr int i, len, n; 981184588Sdfr uint8_t *p; 982184588Sdfr 983184588Sdfr len = principal->len; 984184588Sdfr p = (uint8_t *) principal->name; 985184588Sdfr while (len > 0) { 986184588Sdfr n = len; 987184588Sdfr if (n > 16) 988184588Sdfr n = 16; 989184588Sdfr for (i = 0; i < n; i++) 990184588Sdfr printf("%02x ", p[i]); 991184588Sdfr for (; i < 16; i++) 992184588Sdfr printf(" "); 993184588Sdfr printf("|"); 994184588Sdfr for (i = 0; i < n; i++) 995184588Sdfr printf("%c", isprint(p[i]) ? p[i] : '.'); 996184588Sdfr printf("|\n"); 997184588Sdfr len -= n; 998184588Sdfr p += n; 999184588Sdfr } 1000184588Sdfr} 1001184588Sdfr 1002184588Sdfrstatic bool_t 1003184588Sdfrserver_new_context(__unused struct svc_req *req, 1004184588Sdfr gss_cred_id_t deleg, 1005184588Sdfr __unused gss_ctx_id_t gss_context, 1006184588Sdfr rpc_gss_lock_t *lock, 1007184588Sdfr __unused void **cookie) 1008184588Sdfr{ 1009184588Sdfr rpc_gss_rawcred_t *rcred = lock->raw_cred; 1010184588Sdfr OM_uint32 junk; 1011184588Sdfr 1012184588Sdfr printf("new security context version=%d, mech=%s, qop=%s:\n", 1013184588Sdfr rcred->version, rcred->mechanism, rcred->qop); 1014184588Sdfr print_principal(rcred->client_principal); 1015184588Sdfr 1016184588Sdfr if (server_acl) { 1017184588Sdfr if (rcred->client_principal->len != server_acl->len 1018184588Sdfr || memcmp(rcred->client_principal->name, server_acl->name, 1019184588Sdfr server_acl->len)) { 1020184588Sdfr return (FALSE); 1021184588Sdfr } 1022184588Sdfr } 1023184588Sdfr gss_release_cred(&junk, &deleg); 1024184588Sdfr 1025184588Sdfr return (TRUE); 1026184588Sdfr} 1027184588Sdfr 1028184588Sdfr/* 1029184588Sdfr * Hook up a syscall for gssapi testing. 1030184588Sdfr */ 1031184588Sdfr 1032184588Sdfrstruct gsstest_args { 1033184588Sdfr int a_op; 1034184588Sdfr void *a_args; 1035184588Sdfr void *a_res; 1036184588Sdfr}; 1037184588Sdfr 1038184588Sdfrstruct gsstest_2_args { 1039184588Sdfr int step; /* test step number */ 1040184588Sdfr gss_buffer_desc input_token; /* token from userland */ 1041184588Sdfr gss_buffer_desc output_token; /* buffer to receive reply token */ 1042184588Sdfr}; 1043184588Sdfrstruct gsstest_2_res { 1044184588Sdfr OM_uint32 maj_stat; /* maj_stat from kernel */ 1045184588Sdfr OM_uint32 min_stat; /* min_stat from kernel */ 1046184588Sdfr gss_buffer_desc output_token; /* reply token (using space from gsstest_2_args.output) */ 1047184588Sdfr}; 1048184588Sdfr 1049184588Sdfrstatic int 1050184588Sdfrgsstest(struct thread *td, struct gsstest_args *uap) 1051184588Sdfr{ 1052184588Sdfr int error; 1053184588Sdfr 1054184588Sdfr switch (uap->a_op) { 1055184588Sdfr case 1: 1056184588Sdfr return (gsstest_1()); 1057184588Sdfr 1058184588Sdfr case 2: { 1059184588Sdfr struct gsstest_2_args args; 1060184588Sdfr struct gsstest_2_res res; 1061184588Sdfr gss_buffer_desc input_token, output_token; 1062184588Sdfr OM_uint32 junk; 1063184588Sdfr 1064184588Sdfr error = copyin(uap->a_args, &args, sizeof(args)); 1065184588Sdfr if (error) 1066184588Sdfr return (error); 1067184588Sdfr input_token.length = args.input_token.length; 1068184588Sdfr input_token.value = malloc(input_token.length, M_GSSAPI, 1069184588Sdfr M_WAITOK); 1070184588Sdfr error = copyin(args.input_token.value, input_token.value, 1071184588Sdfr input_token.length); 1072184588Sdfr if (error) { 1073184588Sdfr gss_release_buffer(&junk, &input_token); 1074184588Sdfr return (error); 1075184588Sdfr } 1076184588Sdfr output_token.length = 0; 1077184588Sdfr output_token.value = NULL; 1078184588Sdfr gsstest_2(args.step, &input_token, 1079184588Sdfr &res.maj_stat, &res.min_stat, &output_token); 1080184588Sdfr gss_release_buffer(&junk, &input_token); 1081184588Sdfr if (output_token.length > args.output_token.length) { 1082184588Sdfr gss_release_buffer(&junk, &output_token); 1083184588Sdfr return (EOVERFLOW); 1084184588Sdfr } 1085184588Sdfr res.output_token.length = output_token.length; 1086184588Sdfr res.output_token.value = args.output_token.value; 1087184588Sdfr error = copyout(output_token.value, res.output_token.value, 1088184588Sdfr output_token.length); 1089184588Sdfr gss_release_buffer(&junk, &output_token); 1090184588Sdfr if (error) 1091184588Sdfr return (error); 1092184588Sdfr 1093184588Sdfr return (copyout(&res, uap->a_res, sizeof(res))); 1094184588Sdfr 1095184588Sdfr break; 1096184588Sdfr } 1097184588Sdfr case 3: 1098184588Sdfr return (gsstest_3()); 1099184588Sdfr case 4: 1100184588Sdfr return (gsstest_4()); 1101184588Sdfr } 1102184588Sdfr 1103184588Sdfr return (EINVAL); 1104184588Sdfr} 1105184588Sdfr 1106184588Sdfr/* 1107184588Sdfr * The `sysent' for the new syscall 1108184588Sdfr */ 1109184588Sdfrstatic struct sysent gsstest_sysent = { 1110184588Sdfr 3, /* sy_narg */ 1111184588Sdfr (sy_call_t *) gsstest /* sy_call */ 1112184588Sdfr}; 1113184588Sdfr 1114184588Sdfr/* 1115184588Sdfr * The offset in sysent where the syscall is allocated. 1116184588Sdfr */ 1117184588Sdfrstatic int gsstest_offset = NO_SYSCALL; 1118184588Sdfr 1119184588Sdfr/* 1120184588Sdfr * The function called at load/unload. 1121184588Sdfr */ 1122184588Sdfr 1123184588Sdfr 1124184588Sdfrstatic int 1125184588Sdfrgsstest_load(struct module *module, int cmd, void *arg) 1126184588Sdfr{ 1127184588Sdfr int error = 0; 1128184588Sdfr 1129184588Sdfr switch (cmd) { 1130184588Sdfr case MOD_LOAD : 1131184588Sdfr break; 1132184588Sdfr case MOD_UNLOAD : 1133184588Sdfr break; 1134184588Sdfr default : 1135184588Sdfr error = EOPNOTSUPP; 1136184588Sdfr break; 1137184588Sdfr } 1138184588Sdfr return error; 1139184588Sdfr} 1140184588Sdfr 1141184588SdfrSYSCALL_MODULE(gsstest_syscall, &gsstest_offset, &gsstest_sysent, 1142184588Sdfr gsstest_load, NULL); 1143