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: releng/10.3/sys/kgssapi/gsstest.c 193066 2009-05-29 21:27:12Z jamie $"); 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 202193066Sjamiegsstest_1(struct thread *td) 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]; 230193066Sjamie memcpy(sbuf, "nfs@", 4); 231193066Sjamie getcredhostname(td->td_ucred, sbuf + 4, sizeof(sbuf) - 4); 232184588Sdfr name_desc.value = sbuf; 233184588Sdfr } 234184588Sdfr 235184588Sdfr name_desc.length = strlen((const char *) name_desc.value); 236184588Sdfr maj_stat = gss_import_name(&min_stat, &name_desc, 237184588Sdfr GSS_C_NT_HOSTBASED_SERVICE, &name); 238184588Sdfr if (GSS_ERROR(maj_stat)) { 239184588Sdfr printf("gss_import_name failed\n"); 240184588Sdfr report_error(mech, maj_stat, min_stat); 241184588Sdfr goto out; 242184588Sdfr } 243184588Sdfr 244184588Sdfr maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, 245184588Sdfr 0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_cred, 246184588Sdfr NULL, NULL); 247184588Sdfr if (GSS_ERROR(maj_stat)) { 248184588Sdfr printf("gss_acquire_cred (client) failed\n"); 249184588Sdfr report_error(mech, maj_stat, min_stat); 250184588Sdfr goto out; 251184588Sdfr } 252184588Sdfr 253184588Sdfr enctype[0] = (ETYPE_DES_CBC_CRC >> 24) & 0xff; 254184588Sdfr enctype[1] = (ETYPE_DES_CBC_CRC >> 16) & 0xff; 255184588Sdfr enctype[2] = (ETYPE_DES_CBC_CRC >> 8) & 0xff; 256184588Sdfr enctype[3] = ETYPE_DES_CBC_CRC & 0xff; 257184588Sdfr message_buf.length = sizeof(enctype); 258184588Sdfr message_buf.value = enctype; 259184588Sdfr maj_stat = gss_set_cred_option(&min_stat, &client_cred, 260184588Sdfr GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, &message_buf); 261184588Sdfr if (GSS_ERROR(maj_stat)) { 262184588Sdfr printf("gss_set_cred_option failed\n"); 263184588Sdfr report_error(mech, maj_stat, min_stat); 264184588Sdfr goto out; 265184588Sdfr } 266184588Sdfr 267184588Sdfr server_token.length = 0; 268184588Sdfr server_token.value = NULL; 269184588Sdfr while (!context_established) { 270184588Sdfr client_token.length = 0; 271184588Sdfr client_token.value = NULL; 272184588Sdfr maj_stat = gss_init_sec_context(&min_stat, 273184588Sdfr client_cred, 274184588Sdfr &client_context, 275184588Sdfr name, 276184588Sdfr mech, 277184588Sdfr GSS_C_MUTUAL_FLAG|GSS_C_CONF_FLAG|GSS_C_INTEG_FLAG, 278184588Sdfr 0, 279184588Sdfr GSS_C_NO_CHANNEL_BINDINGS, 280184588Sdfr &server_token, 281184588Sdfr &actual_mech, 282184588Sdfr &client_token, 283184588Sdfr NULL, 284184588Sdfr NULL); 285184588Sdfr if (server_token.length) 286184588Sdfr gss_release_buffer(&smin_stat, &server_token); 287184588Sdfr if (GSS_ERROR(maj_stat)) { 288184588Sdfr printf("gss_init_sec_context failed\n"); 289184588Sdfr report_error(mech, maj_stat, min_stat); 290184588Sdfr goto out; 291184588Sdfr } 292184588Sdfr 293184588Sdfr if (client_token.length != 0) { 294184588Sdfr if (!server_cred) { 295184588Sdfr gss_OID_set_desc oid_set; 296184588Sdfr oid_set.count = 1; 297184588Sdfr oid_set.elements = &krb5_desc; 298184588Sdfr smaj_stat = gss_acquire_cred(&smin_stat, 299184588Sdfr name, 0, &oid_set, GSS_C_ACCEPT, &server_cred, 300184588Sdfr NULL, NULL); 301184588Sdfr if (GSS_ERROR(smaj_stat)) { 302184588Sdfr printf("gss_acquire_cred (server) failed\n"); 303184588Sdfr report_error(mech_type, smaj_stat, smin_stat); 304184588Sdfr goto out; 305184588Sdfr } 306184588Sdfr } 307184588Sdfr smaj_stat = gss_accept_sec_context(&smin_stat, 308184588Sdfr &server_context, 309184588Sdfr server_cred, 310184588Sdfr &client_token, 311184588Sdfr GSS_C_NO_CHANNEL_BINDINGS, 312184588Sdfr &received_name, 313184588Sdfr &mech_type, 314184588Sdfr &server_token, 315184588Sdfr NULL, 316184588Sdfr NULL, 317184588Sdfr NULL); 318184588Sdfr if (GSS_ERROR(smaj_stat)) { 319184588Sdfr printf("gss_accept_sec_context failed\n"); 320184588Sdfr report_error(mech_type, smaj_stat, smin_stat); 321184588Sdfr goto out; 322184588Sdfr } 323184588Sdfr gss_release_buffer(&min_stat, &client_token); 324184588Sdfr } 325184588Sdfr if (GSS_ERROR(maj_stat)) { 326184588Sdfr if (client_context != GSS_C_NO_CONTEXT) 327184588Sdfr gss_delete_sec_context(&min_stat, 328184588Sdfr &client_context, 329184588Sdfr GSS_C_NO_BUFFER); 330184588Sdfr break; 331184588Sdfr } 332184588Sdfr 333184588Sdfr if (maj_stat == GSS_S_COMPLETE) { 334184588Sdfr context_established = 1; 335184588Sdfr } 336184588Sdfr } 337184588Sdfr 338184588Sdfr message_buf.length = strlen("Hello world"); 339184588Sdfr message_buf.value = (void *) "Hello world"; 340184588Sdfr 341184588Sdfr maj_stat = gss_get_mic(&min_stat, client_context, 342184588Sdfr GSS_C_QOP_DEFAULT, &message_buf, &client_token); 343184588Sdfr if (GSS_ERROR(maj_stat)) { 344184588Sdfr printf("gss_get_mic failed\n"); 345184588Sdfr report_error(mech_type, maj_stat, min_stat); 346184588Sdfr goto out; 347184588Sdfr } 348184588Sdfr maj_stat = gss_verify_mic(&min_stat, server_context, 349184588Sdfr &message_buf, &client_token, NULL); 350184588Sdfr if (GSS_ERROR(maj_stat)) { 351184588Sdfr printf("gss_verify_mic failed\n"); 352184588Sdfr report_error(mech_type, maj_stat, min_stat); 353184588Sdfr goto out; 354184588Sdfr } 355184588Sdfr gss_release_buffer(&min_stat, &client_token); 356184588Sdfr 357184588Sdfr maj_stat = gss_wrap(&min_stat, client_context, 358184588Sdfr TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, &client_token); 359184588Sdfr if (GSS_ERROR(maj_stat)) { 360184588Sdfr printf("gss_wrap failed\n"); 361184588Sdfr report_error(mech_type, maj_stat, min_stat); 362184588Sdfr goto out; 363184588Sdfr } 364184588Sdfr maj_stat = gss_unwrap(&min_stat, server_context, 365184588Sdfr &client_token, &server_token, NULL, NULL); 366184588Sdfr if (GSS_ERROR(maj_stat)) { 367184588Sdfr printf("gss_unwrap failed\n"); 368184588Sdfr report_error(mech_type, maj_stat, min_stat); 369184588Sdfr goto out; 370184588Sdfr } 371184588Sdfr 372184588Sdfr if (message_buf.length != server_token.length 373184588Sdfr || memcmp(message_buf.value, server_token.value, 374184588Sdfr message_buf.length)) 375184588Sdfr printf("unwrap result corrupt\n"); 376184588Sdfr 377184588Sdfr gss_release_buffer(&min_stat, &client_token); 378184588Sdfr gss_release_buffer(&min_stat, &server_token); 379184588Sdfr 380184588Sdfrout: 381184588Sdfr if (client_context) 382184588Sdfr gss_delete_sec_context(&min_stat, &client_context, 383184588Sdfr GSS_C_NO_BUFFER); 384184588Sdfr if (server_context) 385184588Sdfr gss_delete_sec_context(&min_stat, &server_context, 386184588Sdfr GSS_C_NO_BUFFER); 387184588Sdfr if (client_cred) 388184588Sdfr gss_release_cred(&min_stat, &client_cred); 389184588Sdfr if (server_cred) 390184588Sdfr gss_release_cred(&min_stat, &server_cred); 391184588Sdfr if (name) 392184588Sdfr gss_release_name(&min_stat, &name); 393184588Sdfr if (received_name) 394184588Sdfr gss_release_name(&min_stat, &received_name); 395184588Sdfr 396184588Sdfr return (0); 397184588Sdfr} 398184588Sdfr 399184588Sdfr/* 400184588Sdfr * Interoperability with userland. This takes several steps: 401184588Sdfr * 402184588Sdfr * 1. Accept an initiator token from userland, return acceptor 403184588Sdfr * token. Repeat this step until both userland and kernel return 404184588Sdfr * GSS_S_COMPLETE. 405184588Sdfr * 406184588Sdfr * 2. Receive a signed message from userland and verify the 407184588Sdfr * signature. Return a signed reply to userland for it to verify. 408184588Sdfr * 409184588Sdfr * 3. Receive a wrapped message from userland and unwrap it. Return a 410184588Sdfr * wrapped reply to userland. 411184588Sdfr */ 412184588Sdfrstatic int 413193066Sjamiegsstest_2(struct thread *td, int step, const gss_buffer_t input_token, 414184588Sdfr OM_uint32 *maj_stat_res, OM_uint32 *min_stat_res, gss_buffer_t output_token) 415184588Sdfr{ 416184588Sdfr OM_uint32 maj_stat, min_stat; 417184588Sdfr static int context_established = 0; 418184588Sdfr static gss_ctx_id_t server_context = GSS_C_NO_CONTEXT; 419184588Sdfr static gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL; 420184588Sdfr static gss_name_t name = GSS_C_NO_NAME; 421184588Sdfr gss_buffer_desc name_desc; 422184588Sdfr gss_buffer_desc message_buf; 423184588Sdfr gss_OID mech_type = GSS_C_NO_OID; 424184588Sdfr char enctype[sizeof(uint32_t)]; 425184588Sdfr int error = EINVAL; 426184588Sdfr 427184588Sdfr maj_stat = GSS_S_FAILURE; 428184588Sdfr min_stat = 0; 429184588Sdfr switch (step) { 430184588Sdfr 431184588Sdfr case 1: 432184588Sdfr if (server_context == GSS_C_NO_CONTEXT) { 433184588Sdfr static char sbuf[512]; 434193066Sjamie memcpy(sbuf, "nfs@", 4); 435193066Sjamie getcredhostname(td->td_ucred, sbuf + 4, 436193066Sjamie sizeof(sbuf) - 4); 437184588Sdfr name_desc.value = sbuf; 438184588Sdfr name_desc.length = strlen((const char *) 439184588Sdfr name_desc.value); 440184588Sdfr maj_stat = gss_import_name(&min_stat, &name_desc, 441184588Sdfr GSS_C_NT_HOSTBASED_SERVICE, &name); 442184588Sdfr if (GSS_ERROR(maj_stat)) { 443184588Sdfr printf("gss_import_name failed\n"); 444184588Sdfr report_error(mech_type, maj_stat, min_stat); 445184588Sdfr goto out; 446184588Sdfr } 447184588Sdfr 448184588Sdfr maj_stat = gss_acquire_cred(&min_stat, 449184588Sdfr name, 0, GSS_C_NO_OID_SET, GSS_C_ACCEPT, 450184588Sdfr &server_cred, NULL, NULL); 451184588Sdfr if (GSS_ERROR(maj_stat)) { 452184588Sdfr printf("gss_acquire_cred (server) failed\n"); 453184588Sdfr report_error(mech_type, maj_stat, min_stat); 454184588Sdfr goto out; 455184588Sdfr } 456184588Sdfr 457184588Sdfr enctype[0] = (ETYPE_DES_CBC_CRC >> 24) & 0xff; 458184588Sdfr enctype[1] = (ETYPE_DES_CBC_CRC >> 16) & 0xff; 459184588Sdfr enctype[2] = (ETYPE_DES_CBC_CRC >> 8) & 0xff; 460184588Sdfr enctype[3] = ETYPE_DES_CBC_CRC & 0xff; 461184588Sdfr message_buf.length = sizeof(enctype); 462184588Sdfr message_buf.value = enctype; 463184588Sdfr maj_stat = gss_set_cred_option(&min_stat, &server_cred, 464184588Sdfr GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, &message_buf); 465184588Sdfr if (GSS_ERROR(maj_stat)) { 466184588Sdfr printf("gss_set_cred_option failed\n"); 467184588Sdfr report_error(mech_type, maj_stat, min_stat); 468184588Sdfr goto out; 469184588Sdfr } 470184588Sdfr } 471184588Sdfr 472184588Sdfr maj_stat = gss_accept_sec_context(&min_stat, 473184588Sdfr &server_context, 474184588Sdfr server_cred, 475184588Sdfr input_token, 476184588Sdfr GSS_C_NO_CHANNEL_BINDINGS, 477184588Sdfr NULL, 478184588Sdfr &mech_type, 479184588Sdfr output_token, 480184588Sdfr NULL, 481184588Sdfr NULL, 482184588Sdfr NULL); 483184588Sdfr if (GSS_ERROR(maj_stat)) { 484184588Sdfr printf("gss_accept_sec_context failed\n"); 485184588Sdfr report_error(mech_type, maj_stat, min_stat); 486184588Sdfr goto out; 487184588Sdfr } 488184588Sdfr 489184588Sdfr if (maj_stat == GSS_S_COMPLETE) { 490184588Sdfr context_established = 1; 491184588Sdfr } 492184588Sdfr *maj_stat_res = maj_stat; 493184588Sdfr *min_stat_res = min_stat; 494184588Sdfr break; 495184588Sdfr 496184588Sdfr case 2: 497184588Sdfr message_buf.length = strlen("Hello world"); 498184588Sdfr message_buf.value = (void *) "Hello world"; 499184588Sdfr 500184588Sdfr maj_stat = gss_verify_mic(&min_stat, server_context, 501184588Sdfr &message_buf, input_token, NULL); 502184588Sdfr if (GSS_ERROR(maj_stat)) { 503184588Sdfr printf("gss_verify_mic failed\n"); 504184588Sdfr report_error(mech_type, maj_stat, min_stat); 505184588Sdfr goto out; 506184588Sdfr } 507184588Sdfr 508184588Sdfr maj_stat = gss_get_mic(&min_stat, server_context, 509184588Sdfr GSS_C_QOP_DEFAULT, &message_buf, output_token); 510184588Sdfr if (GSS_ERROR(maj_stat)) { 511184588Sdfr printf("gss_get_mic failed\n"); 512184588Sdfr report_error(mech_type, maj_stat, min_stat); 513184588Sdfr goto out; 514184588Sdfr } 515184588Sdfr break; 516184588Sdfr 517184588Sdfr case 3: 518184588Sdfr maj_stat = gss_unwrap(&min_stat, server_context, 519184588Sdfr input_token, &message_buf, NULL, NULL); 520184588Sdfr if (GSS_ERROR(maj_stat)) { 521184588Sdfr printf("gss_unwrap failed\n"); 522184588Sdfr report_error(mech_type, maj_stat, min_stat); 523184588Sdfr goto out; 524184588Sdfr } 525184588Sdfr gss_release_buffer(&min_stat, &message_buf); 526184588Sdfr 527184588Sdfr message_buf.length = strlen("Hello world"); 528184588Sdfr message_buf.value = (void *) "Hello world"; 529184588Sdfr maj_stat = gss_wrap(&min_stat, server_context, 530184588Sdfr TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, output_token); 531184588Sdfr if (GSS_ERROR(maj_stat)) { 532184588Sdfr printf("gss_wrap failed\n"); 533184588Sdfr report_error(mech_type, maj_stat, min_stat); 534184588Sdfr goto out; 535184588Sdfr } 536184588Sdfr break; 537184588Sdfr 538184588Sdfr case 4: 539184588Sdfr maj_stat = gss_unwrap(&min_stat, server_context, 540184588Sdfr input_token, &message_buf, NULL, NULL); 541184588Sdfr if (GSS_ERROR(maj_stat)) { 542184588Sdfr printf("gss_unwrap failed\n"); 543184588Sdfr report_error(mech_type, maj_stat, min_stat); 544184588Sdfr goto out; 545184588Sdfr } 546184588Sdfr gss_release_buffer(&min_stat, &message_buf); 547184588Sdfr 548184588Sdfr message_buf.length = strlen("Hello world"); 549184588Sdfr message_buf.value = (void *) "Hello world"; 550184588Sdfr maj_stat = gss_wrap(&min_stat, server_context, 551184588Sdfr FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL, output_token); 552184588Sdfr if (GSS_ERROR(maj_stat)) { 553184588Sdfr printf("gss_wrap failed\n"); 554184588Sdfr report_error(mech_type, maj_stat, min_stat); 555184588Sdfr goto out; 556184588Sdfr } 557184588Sdfr break; 558184588Sdfr 559184588Sdfr case 5: 560184588Sdfr error = 0; 561184588Sdfr goto out; 562184588Sdfr } 563184588Sdfr *maj_stat_res = maj_stat; 564184588Sdfr *min_stat_res = min_stat; 565184588Sdfr return (0); 566184588Sdfr 567184588Sdfrout: 568184588Sdfr *maj_stat_res = maj_stat; 569184588Sdfr *min_stat_res = min_stat; 570184588Sdfr if (server_context) 571184588Sdfr gss_delete_sec_context(&min_stat, &server_context, 572184588Sdfr GSS_C_NO_BUFFER); 573184588Sdfr if (server_cred) 574184588Sdfr gss_release_cred(&min_stat, &server_cred); 575184588Sdfr if (name) 576184588Sdfr gss_release_name(&min_stat, &name); 577184588Sdfr 578184588Sdfr return (error); 579184588Sdfr} 580184588Sdfr 581184588Sdfr/* 582184588Sdfr * Create an RPC client handle for the given (address,prog,vers) 583184588Sdfr * triple using UDP. 584184588Sdfr */ 585184588Sdfrstatic CLIENT * 586184588Sdfrgsstest_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers) 587184588Sdfr{ 588184588Sdfr struct thread *td = curthread; 589184588Sdfr const char* protofmly; 590184588Sdfr struct sockaddr_storage ss; 591184588Sdfr struct socket *so; 592184588Sdfr CLIENT *rpcb; 593184588Sdfr struct timeval timo; 594184588Sdfr RPCB parms; 595184588Sdfr char *uaddr; 596184588Sdfr enum clnt_stat stat = RPC_SUCCESS; 597184588Sdfr int rpcvers = RPCBVERS4; 598184588Sdfr bool_t do_tcp = FALSE; 599184588Sdfr struct portmap mapping; 600184588Sdfr u_short port = 0; 601184588Sdfr 602184588Sdfr /* 603184588Sdfr * First we need to contact the remote RPCBIND service to find 604184588Sdfr * the right port. 605184588Sdfr */ 606184588Sdfr memcpy(&ss, sa, sa->sa_len); 607184588Sdfr switch (ss.ss_family) { 608184588Sdfr case AF_INET: 609184588Sdfr ((struct sockaddr_in *)&ss)->sin_port = htons(111); 610184588Sdfr protofmly = "inet"; 611184588Sdfr socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td); 612184588Sdfr break; 613184588Sdfr 614184588Sdfr#ifdef INET6 615184588Sdfr case AF_INET6: 616184588Sdfr ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111); 617184588Sdfr protofmly = "inet6"; 618184588Sdfr socreate(AF_INET6, &so, SOCK_DGRAM, 0, td->td_ucred, td); 619184588Sdfr break; 620184588Sdfr#endif 621184588Sdfr 622184588Sdfr default: 623184588Sdfr /* 624184588Sdfr * Unsupported address family - fail. 625184588Sdfr */ 626184588Sdfr return (NULL); 627184588Sdfr } 628184588Sdfr 629184588Sdfr rpcb = clnt_dg_create(so, (struct sockaddr *)&ss, 630184588Sdfr RPCBPROG, rpcvers, 0, 0); 631184588Sdfr if (!rpcb) 632184588Sdfr return (NULL); 633184588Sdfr 634184588Sdfrtry_tcp: 635184588Sdfr parms.r_prog = prog; 636184588Sdfr parms.r_vers = vers; 637184588Sdfr if (do_tcp) 638184588Sdfr parms.r_netid = "tcp"; 639184588Sdfr else 640184588Sdfr parms.r_netid = "udp"; 641184588Sdfr parms.r_addr = ""; 642184588Sdfr parms.r_owner = ""; 643184588Sdfr 644184588Sdfr /* 645184588Sdfr * Use the default timeout. 646184588Sdfr */ 647184588Sdfr timo.tv_sec = 25; 648184588Sdfr timo.tv_usec = 0; 649184588Sdfragain: 650184588Sdfr switch (rpcvers) { 651184588Sdfr case RPCBVERS4: 652184588Sdfr case RPCBVERS: 653184588Sdfr /* 654184588Sdfr * Try RPCBIND 4 then 3. 655184588Sdfr */ 656184588Sdfr uaddr = NULL; 657184588Sdfr stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR, 658184588Sdfr (xdrproc_t) xdr_rpcb, &parms, 659184588Sdfr (xdrproc_t) xdr_wrapstring, &uaddr, timo); 660184588Sdfr if (stat == RPC_PROGVERSMISMATCH) { 661184588Sdfr if (rpcvers == RPCBVERS4) 662184588Sdfr rpcvers = RPCBVERS; 663184588Sdfr else if (rpcvers == RPCBVERS) 664184588Sdfr rpcvers = PMAPVERS; 665184588Sdfr CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers); 666184588Sdfr goto again; 667184588Sdfr } else if (stat == RPC_SUCCESS) { 668184588Sdfr /* 669184588Sdfr * We have a reply from the remote RPCBIND - turn it 670184588Sdfr * into an appropriate address and make a new client 671184588Sdfr * that can talk to the remote service. 672184588Sdfr * 673184588Sdfr * XXX fixup IPv6 scope ID. 674184588Sdfr */ 675184588Sdfr struct netbuf *a; 676184588Sdfr a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr); 677184588Sdfr xdr_free((xdrproc_t) xdr_wrapstring, &uaddr); 678184588Sdfr if (!a) { 679184588Sdfr CLNT_DESTROY(rpcb); 680184588Sdfr return (NULL); 681184588Sdfr } 682184588Sdfr memcpy(&ss, a->buf, a->len); 683184588Sdfr free(a->buf, M_RPC); 684184588Sdfr free(a, M_RPC); 685184588Sdfr } 686184588Sdfr break; 687184588Sdfr case PMAPVERS: 688184588Sdfr /* 689184588Sdfr * Try portmap. 690184588Sdfr */ 691184588Sdfr mapping.pm_prog = parms.r_prog; 692184588Sdfr mapping.pm_vers = parms.r_vers; 693184588Sdfr mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP; 694184588Sdfr mapping.pm_port = 0; 695184588Sdfr 696184588Sdfr stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT, 697184588Sdfr (xdrproc_t) xdr_portmap, &mapping, 698184588Sdfr (xdrproc_t) xdr_u_short, &port, timo); 699184588Sdfr 700184588Sdfr if (stat == RPC_SUCCESS) { 701184588Sdfr switch (ss.ss_family) { 702184588Sdfr case AF_INET: 703184588Sdfr ((struct sockaddr_in *)&ss)->sin_port = 704184588Sdfr htons(port); 705184588Sdfr break; 706184588Sdfr 707184588Sdfr#ifdef INET6 708184588Sdfr case AF_INET6: 709184588Sdfr ((struct sockaddr_in6 *)&ss)->sin6_port = 710184588Sdfr htons(port); 711184588Sdfr break; 712184588Sdfr#endif 713184588Sdfr } 714184588Sdfr } 715184588Sdfr break; 716184588Sdfr default: 717184588Sdfr panic("invalid rpcvers %d", rpcvers); 718184588Sdfr } 719184588Sdfr /* 720184588Sdfr * We may have a positive response from the portmapper, but 721184588Sdfr * the requested service was not found. Make sure we received 722184588Sdfr * a valid port. 723184588Sdfr */ 724184588Sdfr switch (ss.ss_family) { 725184588Sdfr case AF_INET: 726184588Sdfr port = ((struct sockaddr_in *)&ss)->sin_port; 727184588Sdfr break; 728184588Sdfr#ifdef INET6 729184588Sdfr case AF_INET6: 730184588Sdfr port = ((struct sockaddr_in6 *)&ss)->sin6_port; 731184588Sdfr break; 732184588Sdfr#endif 733184588Sdfr } 734184588Sdfr if (stat != RPC_SUCCESS || !port) { 735184588Sdfr /* 736184588Sdfr * If we were able to talk to rpcbind or portmap, but the udp 737184588Sdfr * variant wasn't available, ask about tcp. 738184588Sdfr * 739184588Sdfr * XXX - We could also check for a TCP portmapper, but 740184588Sdfr * if the host is running a portmapper at all, we should be able 741184588Sdfr * to hail it over UDP. 742184588Sdfr */ 743184588Sdfr if (stat == RPC_SUCCESS && !do_tcp) { 744184588Sdfr do_tcp = TRUE; 745184588Sdfr goto try_tcp; 746184588Sdfr } 747184588Sdfr 748184588Sdfr /* Otherwise, bad news. */ 749184588Sdfr printf("gsstest_get_rpc: failed to contact remote rpcbind, " 750184588Sdfr "stat = %d, port = %d\n", 751184588Sdfr (int) stat, port); 752184588Sdfr CLNT_DESTROY(rpcb); 753184588Sdfr return (NULL); 754184588Sdfr } 755184588Sdfr 756184588Sdfr if (do_tcp) { 757184588Sdfr /* 758184588Sdfr * Destroy the UDP client we used to speak to rpcbind and 759184588Sdfr * recreate as a TCP client. 760184588Sdfr */ 761184588Sdfr struct netconfig *nconf = NULL; 762184588Sdfr 763184588Sdfr CLNT_DESTROY(rpcb); 764184588Sdfr 765184588Sdfr switch (ss.ss_family) { 766184588Sdfr case AF_INET: 767184588Sdfr nconf = getnetconfigent("tcp"); 768184588Sdfr break; 769184588Sdfr#ifdef INET6 770184588Sdfr case AF_INET6: 771184588Sdfr nconf = getnetconfigent("tcp6"); 772184588Sdfr break; 773184588Sdfr#endif 774184588Sdfr } 775184588Sdfr 776184588Sdfr rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss, 777184588Sdfr prog, vers, 0, 0); 778184588Sdfr } else { 779184588Sdfr /* 780184588Sdfr * Re-use the client we used to speak to rpcbind. 781184588Sdfr */ 782184588Sdfr CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss); 783184588Sdfr CLNT_CONTROL(rpcb, CLSET_PROG, &prog); 784184588Sdfr CLNT_CONTROL(rpcb, CLSET_VERS, &vers); 785184588Sdfr } 786184588Sdfr 787184588Sdfr return (rpcb); 788184588Sdfr} 789184588Sdfr 790184588Sdfr/* 791184588Sdfr * RPCSEC_GSS client 792184588Sdfr */ 793184588Sdfrstatic int 794193066Sjamiegsstest_3(struct thread *td) 795184588Sdfr{ 796184588Sdfr struct sockaddr_in sin; 797184588Sdfr char service[128]; 798184588Sdfr CLIENT *client; 799184588Sdfr AUTH *auth; 800184588Sdfr rpc_gss_options_ret_t options_ret; 801184588Sdfr enum clnt_stat stat; 802184588Sdfr struct timeval tv; 803184588Sdfr rpc_gss_service_t svc; 804184588Sdfr int i; 805184588Sdfr 806184588Sdfr sin.sin_len = sizeof(sin); 807184588Sdfr sin.sin_family = AF_INET; 808184588Sdfr sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 809184588Sdfr sin.sin_port = 0; 810184588Sdfr 811184588Sdfr client = gsstest_get_rpc((struct sockaddr *) &sin, 123456, 1); 812184588Sdfr if (!client) { 813184588Sdfr uprintf("Can't connect to service\n"); 814184588Sdfr return(1); 815184588Sdfr } 816184588Sdfr 817193066Sjamie memcpy(service, "host@", 5); 818193066Sjamie getcredhostname(td->td_ucred, service + 5, sizeof(service) - 5); 819184588Sdfr 820184588Sdfr auth = rpc_gss_seccreate(client, curthread->td_ucred, 821184588Sdfr service, "kerberosv5", rpc_gss_svc_privacy, 822184588Sdfr NULL, NULL, &options_ret); 823184588Sdfr if (!auth) { 824184588Sdfr gss_OID oid; 825184588Sdfr uprintf("Can't authorize to service (mech=%s)\n", 826184588Sdfr options_ret.actual_mechanism); 827184588Sdfr oid = GSS_C_NO_OID; 828184588Sdfr rpc_gss_mech_to_oid(options_ret.actual_mechanism, &oid); 829184588Sdfr report_error(oid, options_ret.major_status, 830184588Sdfr options_ret.minor_status); 831184588Sdfr CLNT_DESTROY(client); 832184588Sdfr return (1); 833184588Sdfr } 834184588Sdfr 835184588Sdfr for (svc = rpc_gss_svc_none; svc <= rpc_gss_svc_privacy; svc++) { 836184588Sdfr const char *svc_names[] = { 837184588Sdfr "rpc_gss_svc_default", 838184588Sdfr "rpc_gss_svc_none", 839184588Sdfr "rpc_gss_svc_integrity", 840184588Sdfr "rpc_gss_svc_privacy" 841184588Sdfr }; 842184588Sdfr int num; 843184588Sdfr 844184588Sdfr rpc_gss_set_defaults(auth, svc, NULL); 845184588Sdfr 846184588Sdfr client->cl_auth = auth; 847184588Sdfr tv.tv_sec = 5; 848184588Sdfr tv.tv_usec = 0; 849184588Sdfr for (i = 42; i < 142; i++) { 850184588Sdfr num = i; 851184588Sdfr stat = CLNT_CALL(client, 1, 852184588Sdfr (xdrproc_t) xdr_int, (char *) &num, 853184588Sdfr (xdrproc_t) xdr_int, (char *) &num, tv); 854184588Sdfr if (stat == RPC_SUCCESS) { 855184588Sdfr if (num != i + 100) 856184588Sdfr uprintf("unexpected reply %d\n", num); 857184588Sdfr } else { 858184588Sdfr uprintf("call failed, stat=%d\n", (int) stat); 859184588Sdfr break; 860184588Sdfr } 861184588Sdfr } 862184588Sdfr if (i == 142) 863184588Sdfr uprintf("call succeeded with %s\n", svc_names[svc]); 864184588Sdfr } 865184588Sdfr 866184588Sdfr AUTH_DESTROY(auth); 867184588Sdfr CLNT_RELEASE(client); 868184588Sdfr 869184588Sdfr return (0); 870184588Sdfr} 871184588Sdfr 872184588Sdfr/* 873184588Sdfr * RPCSEC_GSS server 874184588Sdfr */ 875184588Sdfrstatic rpc_gss_principal_t server_acl = NULL; 876184588Sdfrstatic bool_t server_new_context(struct svc_req *req, gss_cred_id_t deleg, 877184588Sdfr gss_ctx_id_t gss_context, rpc_gss_lock_t *lock, void **cookie); 878184588Sdfrstatic void server_program_1(struct svc_req *rqstp, register SVCXPRT *transp); 879184588Sdfr 880184588Sdfrstatic int 881193066Sjamiegsstest_4(struct thread *td) 882184588Sdfr{ 883184588Sdfr SVCPOOL *pool; 884184588Sdfr char principal[128 + 5]; 885184588Sdfr const char **mechs; 886184588Sdfr static rpc_gss_callback_t cb; 887184588Sdfr 888193066Sjamie memcpy(principal, "host@", 5); 889193066Sjamie getcredhostname(td->td_ucred, principal + 5, sizeof(principal) - 5); 890184588Sdfr 891184588Sdfr mechs = rpc_gss_get_mechanisms(); 892184588Sdfr while (*mechs) { 893184588Sdfr if (!rpc_gss_set_svc_name(principal, *mechs, GSS_C_INDEFINITE, 894184588Sdfr 123456, 1)) { 895184588Sdfr rpc_gss_error_t e; 896184588Sdfr 897184588Sdfr rpc_gss_get_error(&e); 898184588Sdfr printf("setting name for %s for %s failed: %d, %d\n", 899184588Sdfr principal, *mechs, 900184588Sdfr e.rpc_gss_error, e.system_error); 901184588Sdfr } 902184588Sdfr mechs++; 903184588Sdfr } 904184588Sdfr 905184588Sdfr cb.program = 123456; 906184588Sdfr cb.version = 1; 907184588Sdfr cb.callback = server_new_context; 908184588Sdfr rpc_gss_set_callback(&cb); 909184588Sdfr 910184588Sdfr pool = svcpool_create("gsstest", NULL); 911184588Sdfr 912184588Sdfr svc_create(pool, server_program_1, 123456, 1, NULL); 913184588Sdfr svc_run(pool); 914184588Sdfr 915184588Sdfr rpc_gss_clear_svc_name(123456, 1); 916184588Sdfr rpc_gss_clear_callback(&cb); 917184588Sdfr 918184588Sdfr svcpool_destroy(pool); 919184588Sdfr 920184588Sdfr return (0); 921184588Sdfr} 922184588Sdfr 923184588Sdfrstatic void 924184588Sdfrserver_program_1(struct svc_req *rqstp, register SVCXPRT *transp) 925184588Sdfr{ 926184588Sdfr rpc_gss_rawcred_t *rcred; 927184588Sdfr rpc_gss_ucred_t *ucred; 928184588Sdfr int i, num; 929184588Sdfr 930184588Sdfr if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS) { 931184588Sdfr svcerr_weakauth(rqstp); 932184588Sdfr return; 933184588Sdfr } 934184588Sdfr 935184588Sdfr if (!rpc_gss_getcred(rqstp, &rcred, &ucred, NULL)) { 936184588Sdfr svcerr_systemerr(rqstp); 937184588Sdfr return; 938184588Sdfr } 939184588Sdfr 940184588Sdfr printf("svc=%d, mech=%s, uid=%d, gid=%d, gids={", 941184588Sdfr rcred->service, rcred->mechanism, ucred->uid, ucred->gid); 942184588Sdfr for (i = 0; i < ucred->gidlen; i++) { 943184588Sdfr if (i > 0) printf(","); 944184588Sdfr printf("%d", ucred->gidlist[i]); 945184588Sdfr } 946184588Sdfr printf("}\n"); 947184588Sdfr 948184588Sdfr switch (rqstp->rq_proc) { 949184588Sdfr case 0: 950184588Sdfr if (!svc_getargs(rqstp, (xdrproc_t) xdr_void, 0)) { 951184588Sdfr svcerr_decode(rqstp); 952184588Sdfr goto out; 953184588Sdfr } 954184588Sdfr if (!svc_sendreply(rqstp, (xdrproc_t) xdr_void, 0)) { 955184588Sdfr svcerr_systemerr(rqstp); 956184588Sdfr } 957184588Sdfr goto out; 958184588Sdfr 959184588Sdfr case 1: 960184588Sdfr if (!svc_getargs(rqstp, (xdrproc_t) xdr_int, 961184588Sdfr (char *) &num)) { 962184588Sdfr svcerr_decode(rqstp); 963184588Sdfr goto out; 964184588Sdfr } 965184588Sdfr num += 100; 966184588Sdfr if (!svc_sendreply(rqstp, (xdrproc_t) xdr_int, 967184588Sdfr (char *) &num)) { 968184588Sdfr svcerr_systemerr(rqstp); 969184588Sdfr } 970184588Sdfr goto out; 971184588Sdfr 972184588Sdfr default: 973184588Sdfr svcerr_noproc(rqstp); 974184588Sdfr goto out; 975184588Sdfr } 976184588Sdfr 977184588Sdfrout: 978184887Sdfr svc_freereq(rqstp); 979184588Sdfr return; 980184588Sdfr} 981184588Sdfr 982184588Sdfrstatic void 983184588Sdfrprint_principal(rpc_gss_principal_t principal) 984184588Sdfr{ 985184588Sdfr int i, len, n; 986184588Sdfr uint8_t *p; 987184588Sdfr 988184588Sdfr len = principal->len; 989184588Sdfr p = (uint8_t *) principal->name; 990184588Sdfr while (len > 0) { 991184588Sdfr n = len; 992184588Sdfr if (n > 16) 993184588Sdfr n = 16; 994184588Sdfr for (i = 0; i < n; i++) 995184588Sdfr printf("%02x ", p[i]); 996184588Sdfr for (; i < 16; i++) 997184588Sdfr printf(" "); 998184588Sdfr printf("|"); 999184588Sdfr for (i = 0; i < n; i++) 1000184588Sdfr printf("%c", isprint(p[i]) ? p[i] : '.'); 1001184588Sdfr printf("|\n"); 1002184588Sdfr len -= n; 1003184588Sdfr p += n; 1004184588Sdfr } 1005184588Sdfr} 1006184588Sdfr 1007184588Sdfrstatic bool_t 1008184588Sdfrserver_new_context(__unused struct svc_req *req, 1009184588Sdfr gss_cred_id_t deleg, 1010184588Sdfr __unused gss_ctx_id_t gss_context, 1011184588Sdfr rpc_gss_lock_t *lock, 1012184588Sdfr __unused void **cookie) 1013184588Sdfr{ 1014184588Sdfr rpc_gss_rawcred_t *rcred = lock->raw_cred; 1015184588Sdfr OM_uint32 junk; 1016184588Sdfr 1017184588Sdfr printf("new security context version=%d, mech=%s, qop=%s:\n", 1018184588Sdfr rcred->version, rcred->mechanism, rcred->qop); 1019184588Sdfr print_principal(rcred->client_principal); 1020184588Sdfr 1021184588Sdfr if (server_acl) { 1022184588Sdfr if (rcred->client_principal->len != server_acl->len 1023184588Sdfr || memcmp(rcred->client_principal->name, server_acl->name, 1024184588Sdfr server_acl->len)) { 1025184588Sdfr return (FALSE); 1026184588Sdfr } 1027184588Sdfr } 1028184588Sdfr gss_release_cred(&junk, &deleg); 1029184588Sdfr 1030184588Sdfr return (TRUE); 1031184588Sdfr} 1032184588Sdfr 1033184588Sdfr/* 1034184588Sdfr * Hook up a syscall for gssapi testing. 1035184588Sdfr */ 1036184588Sdfr 1037184588Sdfrstruct gsstest_args { 1038184588Sdfr int a_op; 1039184588Sdfr void *a_args; 1040184588Sdfr void *a_res; 1041184588Sdfr}; 1042184588Sdfr 1043184588Sdfrstruct gsstest_2_args { 1044184588Sdfr int step; /* test step number */ 1045184588Sdfr gss_buffer_desc input_token; /* token from userland */ 1046184588Sdfr gss_buffer_desc output_token; /* buffer to receive reply token */ 1047184588Sdfr}; 1048184588Sdfrstruct gsstest_2_res { 1049184588Sdfr OM_uint32 maj_stat; /* maj_stat from kernel */ 1050184588Sdfr OM_uint32 min_stat; /* min_stat from kernel */ 1051184588Sdfr gss_buffer_desc output_token; /* reply token (using space from gsstest_2_args.output) */ 1052184588Sdfr}; 1053184588Sdfr 1054184588Sdfrstatic int 1055184588Sdfrgsstest(struct thread *td, struct gsstest_args *uap) 1056184588Sdfr{ 1057184588Sdfr int error; 1058184588Sdfr 1059184588Sdfr switch (uap->a_op) { 1060184588Sdfr case 1: 1061193066Sjamie return (gsstest_1(td)); 1062184588Sdfr 1063184588Sdfr case 2: { 1064184588Sdfr struct gsstest_2_args args; 1065184588Sdfr struct gsstest_2_res res; 1066184588Sdfr gss_buffer_desc input_token, output_token; 1067184588Sdfr OM_uint32 junk; 1068184588Sdfr 1069184588Sdfr error = copyin(uap->a_args, &args, sizeof(args)); 1070184588Sdfr if (error) 1071184588Sdfr return (error); 1072184588Sdfr input_token.length = args.input_token.length; 1073184588Sdfr input_token.value = malloc(input_token.length, M_GSSAPI, 1074184588Sdfr M_WAITOK); 1075184588Sdfr error = copyin(args.input_token.value, input_token.value, 1076184588Sdfr input_token.length); 1077184588Sdfr if (error) { 1078184588Sdfr gss_release_buffer(&junk, &input_token); 1079184588Sdfr return (error); 1080184588Sdfr } 1081184588Sdfr output_token.length = 0; 1082184588Sdfr output_token.value = NULL; 1083193066Sjamie gsstest_2(td, args.step, &input_token, 1084184588Sdfr &res.maj_stat, &res.min_stat, &output_token); 1085184588Sdfr gss_release_buffer(&junk, &input_token); 1086184588Sdfr if (output_token.length > args.output_token.length) { 1087184588Sdfr gss_release_buffer(&junk, &output_token); 1088184588Sdfr return (EOVERFLOW); 1089184588Sdfr } 1090184588Sdfr res.output_token.length = output_token.length; 1091184588Sdfr res.output_token.value = args.output_token.value; 1092184588Sdfr error = copyout(output_token.value, res.output_token.value, 1093184588Sdfr output_token.length); 1094184588Sdfr gss_release_buffer(&junk, &output_token); 1095184588Sdfr if (error) 1096184588Sdfr return (error); 1097184588Sdfr 1098184588Sdfr return (copyout(&res, uap->a_res, sizeof(res))); 1099184588Sdfr 1100184588Sdfr break; 1101184588Sdfr } 1102184588Sdfr case 3: 1103193066Sjamie return (gsstest_3(td)); 1104184588Sdfr case 4: 1105193066Sjamie return (gsstest_4(td)); 1106184588Sdfr } 1107184588Sdfr 1108184588Sdfr return (EINVAL); 1109184588Sdfr} 1110184588Sdfr 1111184588Sdfr/* 1112184588Sdfr * The `sysent' for the new syscall 1113184588Sdfr */ 1114184588Sdfrstatic struct sysent gsstest_sysent = { 1115184588Sdfr 3, /* sy_narg */ 1116184588Sdfr (sy_call_t *) gsstest /* sy_call */ 1117184588Sdfr}; 1118184588Sdfr 1119184588Sdfr/* 1120184588Sdfr * The offset in sysent where the syscall is allocated. 1121184588Sdfr */ 1122184588Sdfrstatic int gsstest_offset = NO_SYSCALL; 1123184588Sdfr 1124184588Sdfr/* 1125184588Sdfr * The function called at load/unload. 1126184588Sdfr */ 1127184588Sdfr 1128184588Sdfr 1129184588Sdfrstatic int 1130184588Sdfrgsstest_load(struct module *module, int cmd, void *arg) 1131184588Sdfr{ 1132184588Sdfr int error = 0; 1133184588Sdfr 1134184588Sdfr switch (cmd) { 1135184588Sdfr case MOD_LOAD : 1136184588Sdfr break; 1137184588Sdfr case MOD_UNLOAD : 1138184588Sdfr break; 1139184588Sdfr default : 1140184588Sdfr error = EOPNOTSUPP; 1141184588Sdfr break; 1142184588Sdfr } 1143184588Sdfr return error; 1144184588Sdfr} 1145184588Sdfr 1146184588SdfrSYSCALL_MODULE(gsstest_syscall, &gsstest_offset, &gsstest_sysent, 1147184588Sdfr gsstest_load, NULL); 1148