1*10023SGordon.Ross@Sun.COM /* 2*10023SGordon.Ross@Sun.COM * CDDL HEADER START 3*10023SGordon.Ross@Sun.COM * 4*10023SGordon.Ross@Sun.COM * The contents of this file are subject to the terms of the 5*10023SGordon.Ross@Sun.COM * Common Development and Distribution License (the "License"). 6*10023SGordon.Ross@Sun.COM * You may not use this file except in compliance with the License. 7*10023SGordon.Ross@Sun.COM * 8*10023SGordon.Ross@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10023SGordon.Ross@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*10023SGordon.Ross@Sun.COM * See the License for the specific language governing permissions 11*10023SGordon.Ross@Sun.COM * and limitations under the License. 12*10023SGordon.Ross@Sun.COM * 13*10023SGordon.Ross@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*10023SGordon.Ross@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10023SGordon.Ross@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*10023SGordon.Ross@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*10023SGordon.Ross@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*10023SGordon.Ross@Sun.COM * 19*10023SGordon.Ross@Sun.COM * CDDL HEADER END 20*10023SGordon.Ross@Sun.COM */ 21*10023SGordon.Ross@Sun.COM 22*10023SGordon.Ross@Sun.COM /* 23*10023SGordon.Ross@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*10023SGordon.Ross@Sun.COM * Use is subject to license terms. 25*10023SGordon.Ross@Sun.COM */ 26*10023SGordon.Ross@Sun.COM 27*10023SGordon.Ross@Sun.COM /* 28*10023SGordon.Ross@Sun.COM * Security Provider glue 29*10023SGordon.Ross@Sun.COM * 30*10023SGordon.Ross@Sun.COM * Modeled after SSPI for now, only because we're currently 31*10023SGordon.Ross@Sun.COM * using the Microsoft sample spnego code. 32*10023SGordon.Ross@Sun.COM * 33*10023SGordon.Ross@Sun.COM * ToDo: Port all of this to GSS-API plugins. 34*10023SGordon.Ross@Sun.COM */ 35*10023SGordon.Ross@Sun.COM 36*10023SGordon.Ross@Sun.COM #include <errno.h> 37*10023SGordon.Ross@Sun.COM #include <stdio.h> 38*10023SGordon.Ross@Sun.COM #include <stdlib.h> 39*10023SGordon.Ross@Sun.COM #include <unistd.h> 40*10023SGordon.Ross@Sun.COM #include <strings.h> 41*10023SGordon.Ross@Sun.COM #include <netdb.h> 42*10023SGordon.Ross@Sun.COM #include <libintl.h> 43*10023SGordon.Ross@Sun.COM #include <xti.h> 44*10023SGordon.Ross@Sun.COM #include <assert.h> 45*10023SGordon.Ross@Sun.COM 46*10023SGordon.Ross@Sun.COM #include <sys/types.h> 47*10023SGordon.Ross@Sun.COM #include <sys/time.h> 48*10023SGordon.Ross@Sun.COM #include <sys/byteorder.h> 49*10023SGordon.Ross@Sun.COM #include <sys/socket.h> 50*10023SGordon.Ross@Sun.COM #include <sys/fcntl.h> 51*10023SGordon.Ross@Sun.COM 52*10023SGordon.Ross@Sun.COM #include <netinet/in.h> 53*10023SGordon.Ross@Sun.COM #include <netinet/tcp.h> 54*10023SGordon.Ross@Sun.COM #include <arpa/inet.h> 55*10023SGordon.Ross@Sun.COM 56*10023SGordon.Ross@Sun.COM #include <netsmb/smb_lib.h> 57*10023SGordon.Ross@Sun.COM #include <netsmb/mchain.h> 58*10023SGordon.Ross@Sun.COM 59*10023SGordon.Ross@Sun.COM #include "private.h" 60*10023SGordon.Ross@Sun.COM #include "charsets.h" 61*10023SGordon.Ross@Sun.COM #include "spnego.h" 62*10023SGordon.Ross@Sun.COM #include "derparse.h" 63*10023SGordon.Ross@Sun.COM #include "ssp.h" 64*10023SGordon.Ross@Sun.COM 65*10023SGordon.Ross@Sun.COM 66*10023SGordon.Ross@Sun.COM /* 67*10023SGordon.Ross@Sun.COM * ssp_ctx_create_client 68*10023SGordon.Ross@Sun.COM * 69*10023SGordon.Ross@Sun.COM * This is the first function called for SMB "extended security". 70*10023SGordon.Ross@Sun.COM * Here we select a security support provider (SSP), or mechanism, 71*10023SGordon.Ross@Sun.COM * and build the security context used throughout authentication. 72*10023SGordon.Ross@Sun.COM * 73*10023SGordon.Ross@Sun.COM * Note that we receive a "hint" in the SMB Negotiate response 74*10023SGordon.Ross@Sun.COM * that contains the list of mechanisms supported by the server. 75*10023SGordon.Ross@Sun.COM * We use this to help us select a mechanism. 76*10023SGordon.Ross@Sun.COM * 77*10023SGordon.Ross@Sun.COM * With SSPI this would call: 78*10023SGordon.Ross@Sun.COM * ssp->InitSecurityInterface() 79*10023SGordon.Ross@Sun.COM * ssp->AcquireCredentialsHandle() 80*10023SGordon.Ross@Sun.COM * ssp->InitializeSecurityContext() 81*10023SGordon.Ross@Sun.COM * With GSS-API this will become: 82*10023SGordon.Ross@Sun.COM * gss_import_name(... service_principal_name) 83*10023SGordon.Ross@Sun.COM * gss_init_sec_context(), etc. 84*10023SGordon.Ross@Sun.COM */ 85*10023SGordon.Ross@Sun.COM int 86*10023SGordon.Ross@Sun.COM ssp_ctx_create_client(struct smb_ctx *ctx, struct mbdata *hint_mb) 87*10023SGordon.Ross@Sun.COM { 88*10023SGordon.Ross@Sun.COM struct ssp_ctx *sp; 89*10023SGordon.Ross@Sun.COM mbuf_t *m; 90*10023SGordon.Ross@Sun.COM SPNEGO_MECH_OID oid; 91*10023SGordon.Ross@Sun.COM int indx, rc; 92*10023SGordon.Ross@Sun.COM int err = ENOTSUP; /* in case nothing matches */ 93*10023SGordon.Ross@Sun.COM 94*10023SGordon.Ross@Sun.COM sp = malloc(sizeof (*sp)); 95*10023SGordon.Ross@Sun.COM if (sp == NULL) 96*10023SGordon.Ross@Sun.COM return (ENOMEM); 97*10023SGordon.Ross@Sun.COM bzero(sp, sizeof (*sp)); 98*10023SGordon.Ross@Sun.COM ctx->ct_ssp_ctx = sp; 99*10023SGordon.Ross@Sun.COM sp->smb_ctx = ctx; 100*10023SGordon.Ross@Sun.COM 101*10023SGordon.Ross@Sun.COM /* 102*10023SGordon.Ross@Sun.COM * Parse the SPNEGO "hint" to get the server's list of 103*10023SGordon.Ross@Sun.COM * supported mechanisms. If the "hint" is empty, 104*10023SGordon.Ross@Sun.COM * assume NTLMSSP. (Or could use "raw NTLMSSP") 105*10023SGordon.Ross@Sun.COM */ 106*10023SGordon.Ross@Sun.COM m = hint_mb->mb_top; 107*10023SGordon.Ross@Sun.COM if (m == NULL) 108*10023SGordon.Ross@Sun.COM goto use_ntlm; 109*10023SGordon.Ross@Sun.COM rc = spnegoInitFromBinary((uchar_t *)m->m_data, m->m_len, 110*10023SGordon.Ross@Sun.COM &sp->sp_hint); 111*10023SGordon.Ross@Sun.COM if (rc) { 112*10023SGordon.Ross@Sun.COM DPRINT("parse hint, rc %d", rc); 113*10023SGordon.Ross@Sun.COM goto use_ntlm; 114*10023SGordon.Ross@Sun.COM } 115*10023SGordon.Ross@Sun.COM 116*10023SGordon.Ross@Sun.COM /* 117*10023SGordon.Ross@Sun.COM * Did the server offer Kerberos? 118*10023SGordon.Ross@Sun.COM * Either spec. OID or legacy is OK, 119*10023SGordon.Ross@Sun.COM * but have to remember what we got. 120*10023SGordon.Ross@Sun.COM */ 121*10023SGordon.Ross@Sun.COM oid = spnego_mech_oid_NotUsed; 122*10023SGordon.Ross@Sun.COM if (0 == spnegoIsMechTypeAvailable(sp->sp_hint, 123*10023SGordon.Ross@Sun.COM spnego_mech_oid_Kerberos_V5, &indx)) 124*10023SGordon.Ross@Sun.COM oid = spnego_mech_oid_Kerberos_V5; 125*10023SGordon.Ross@Sun.COM else if (0 == spnegoIsMechTypeAvailable(sp->sp_hint, 126*10023SGordon.Ross@Sun.COM spnego_mech_oid_Kerberos_V5_Legacy, &indx)) 127*10023SGordon.Ross@Sun.COM oid = spnego_mech_oid_Kerberos_V5_Legacy; 128*10023SGordon.Ross@Sun.COM if (oid != spnego_mech_oid_NotUsed) { 129*10023SGordon.Ross@Sun.COM /* 130*10023SGordon.Ross@Sun.COM * Yes! Server offers Kerberos. 131*10023SGordon.Ross@Sun.COM * Try to init our krb5 mechanism. 132*10023SGordon.Ross@Sun.COM * It will fail if the calling user 133*10023SGordon.Ross@Sun.COM * does not have krb5 credentials. 134*10023SGordon.Ross@Sun.COM */ 135*10023SGordon.Ross@Sun.COM sp->sp_mech = oid; 136*10023SGordon.Ross@Sun.COM err = krb5ssp_init_client(sp); 137*10023SGordon.Ross@Sun.COM if (err == 0) { 138*10023SGordon.Ross@Sun.COM DPRINT("using Kerberos"); 139*10023SGordon.Ross@Sun.COM return (0); 140*10023SGordon.Ross@Sun.COM } 141*10023SGordon.Ross@Sun.COM /* else fall back to NTLMSSP */ 142*10023SGordon.Ross@Sun.COM } 143*10023SGordon.Ross@Sun.COM 144*10023SGordon.Ross@Sun.COM /* 145*10023SGordon.Ross@Sun.COM * Did the server offer NTLMSSP? 146*10023SGordon.Ross@Sun.COM */ 147*10023SGordon.Ross@Sun.COM if (0 == spnegoIsMechTypeAvailable(sp->sp_hint, 148*10023SGordon.Ross@Sun.COM spnego_mech_oid_NTLMSSP, &indx)) { 149*10023SGordon.Ross@Sun.COM /* 150*10023SGordon.Ross@Sun.COM * OK, we'll use NTLMSSP 151*10023SGordon.Ross@Sun.COM */ 152*10023SGordon.Ross@Sun.COM use_ntlm: 153*10023SGordon.Ross@Sun.COM sp->sp_mech = spnego_mech_oid_NTLMSSP; 154*10023SGordon.Ross@Sun.COM err = ntlmssp_init_client(sp); 155*10023SGordon.Ross@Sun.COM if (err == 0) { 156*10023SGordon.Ross@Sun.COM DPRINT("using NTLMSSP"); 157*10023SGordon.Ross@Sun.COM return (0); 158*10023SGordon.Ross@Sun.COM } 159*10023SGordon.Ross@Sun.COM } 160*10023SGordon.Ross@Sun.COM 161*10023SGordon.Ross@Sun.COM /* No supported mechanisms! */ 162*10023SGordon.Ross@Sun.COM return (err); 163*10023SGordon.Ross@Sun.COM } 164*10023SGordon.Ross@Sun.COM 165*10023SGordon.Ross@Sun.COM 166*10023SGordon.Ross@Sun.COM /* 167*10023SGordon.Ross@Sun.COM * ssp_ctx_destroy 168*10023SGordon.Ross@Sun.COM * 169*10023SGordon.Ross@Sun.COM * Dispatch to the mechanism-specific destroy. 170*10023SGordon.Ross@Sun.COM */ 171*10023SGordon.Ross@Sun.COM void 172*10023SGordon.Ross@Sun.COM ssp_ctx_destroy(struct smb_ctx *ctx) 173*10023SGordon.Ross@Sun.COM { 174*10023SGordon.Ross@Sun.COM ssp_ctx_t *sp; 175*10023SGordon.Ross@Sun.COM 176*10023SGordon.Ross@Sun.COM sp = ctx->ct_ssp_ctx; 177*10023SGordon.Ross@Sun.COM ctx->ct_ssp_ctx = NULL; 178*10023SGordon.Ross@Sun.COM 179*10023SGordon.Ross@Sun.COM if (sp == NULL) 180*10023SGordon.Ross@Sun.COM return; 181*10023SGordon.Ross@Sun.COM 182*10023SGordon.Ross@Sun.COM if (sp->sp_destroy != NULL) 183*10023SGordon.Ross@Sun.COM (sp->sp_destroy)(sp); 184*10023SGordon.Ross@Sun.COM 185*10023SGordon.Ross@Sun.COM if (sp->sp_hint != NULL) 186*10023SGordon.Ross@Sun.COM spnegoFreeData(sp->sp_hint); 187*10023SGordon.Ross@Sun.COM 188*10023SGordon.Ross@Sun.COM free(sp); 189*10023SGordon.Ross@Sun.COM } 190*10023SGordon.Ross@Sun.COM 191*10023SGordon.Ross@Sun.COM 192*10023SGordon.Ross@Sun.COM /* 193*10023SGordon.Ross@Sun.COM * ssp_ctx_next_token 194*10023SGordon.Ross@Sun.COM * 195*10023SGordon.Ross@Sun.COM * This is the function called to generate the next token to send, 196*10023SGordon.Ross@Sun.COM * given a token just received, using the selected back-end method. 197*10023SGordon.Ross@Sun.COM * The back-end method is called a security service provider (SSP). 198*10023SGordon.Ross@Sun.COM * 199*10023SGordon.Ross@Sun.COM * This is also called to generate the first token to send 200*10023SGordon.Ross@Sun.COM * (when called with caller_in == NULL) and to handle the last 201*10023SGordon.Ross@Sun.COM * token received (when called with caller_out == NULL). 202*10023SGordon.Ross@Sun.COM * See caller: smb_ssnsetup_spnego 203*10023SGordon.Ross@Sun.COM * 204*10023SGordon.Ross@Sun.COM * Note that if the back-end SSP "next token" function ever 205*10023SGordon.Ross@Sun.COM * returns an error, the conversation ends, and there are 206*10023SGordon.Ross@Sun.COM * no further calls to this function for this context. 207*10023SGordon.Ross@Sun.COM * 208*10023SGordon.Ross@Sun.COM * General outline of this funcion: 209*10023SGordon.Ross@Sun.COM * if (caller_in) 210*10023SGordon.Ross@Sun.COM * Unwrap caller_in spnego blob, 211*10023SGordon.Ross@Sun.COM * store payload in body_in 212*10023SGordon.Ross@Sun.COM * Call back-end SSP "next token" method (body_in, body_out) 213*10023SGordon.Ross@Sun.COM * if (caller_out) 214*10023SGordon.Ross@Sun.COM * Wrap returned body_out in spnego, 215*10023SGordon.Ross@Sun.COM * store in caller_out 216*10023SGordon.Ross@Sun.COM * 217*10023SGordon.Ross@Sun.COM * With SSPI this would call: 218*10023SGordon.Ross@Sun.COM * ssp->InitializeSecurityContext() 219*10023SGordon.Ross@Sun.COM * With GSS-API this will become: 220*10023SGordon.Ross@Sun.COM * gss_init_sec_context() 221*10023SGordon.Ross@Sun.COM */ 222*10023SGordon.Ross@Sun.COM int 223*10023SGordon.Ross@Sun.COM ssp_ctx_next_token(struct smb_ctx *ctx, 224*10023SGordon.Ross@Sun.COM struct mbdata *caller_in, 225*10023SGordon.Ross@Sun.COM struct mbdata *caller_out) 226*10023SGordon.Ross@Sun.COM { 227*10023SGordon.Ross@Sun.COM struct mbdata body_in, body_out; 228*10023SGordon.Ross@Sun.COM SPNEGO_TOKEN_HANDLE stok_in, stok_out; 229*10023SGordon.Ross@Sun.COM SPNEGO_NEGRESULT result; 230*10023SGordon.Ross@Sun.COM ssp_ctx_t *sp; 231*10023SGordon.Ross@Sun.COM struct mbuf *m; 232*10023SGordon.Ross@Sun.COM ulong_t toklen; 233*10023SGordon.Ross@Sun.COM int err, rc; 234*10023SGordon.Ross@Sun.COM 235*10023SGordon.Ross@Sun.COM bzero(&body_in, sizeof (body_in)); 236*10023SGordon.Ross@Sun.COM bzero(&body_out, sizeof (body_out)); 237*10023SGordon.Ross@Sun.COM stok_out = stok_in = NULL; 238*10023SGordon.Ross@Sun.COM sp = ctx->ct_ssp_ctx; 239*10023SGordon.Ross@Sun.COM 240*10023SGordon.Ross@Sun.COM /* 241*10023SGordon.Ross@Sun.COM * If we have an spnego input token, parse it, 242*10023SGordon.Ross@Sun.COM * extract the payload for the back-end SSP. 243*10023SGordon.Ross@Sun.COM */ 244*10023SGordon.Ross@Sun.COM if (caller_in != NULL) { 245*10023SGordon.Ross@Sun.COM 246*10023SGordon.Ross@Sun.COM /* 247*10023SGordon.Ross@Sun.COM * Let the spnego code parse it. 248*10023SGordon.Ross@Sun.COM */ 249*10023SGordon.Ross@Sun.COM m = caller_in->mb_top; 250*10023SGordon.Ross@Sun.COM rc = spnegoInitFromBinary((uchar_t *)m->m_data, 251*10023SGordon.Ross@Sun.COM m->m_len, &stok_in); 252*10023SGordon.Ross@Sun.COM if (rc) { 253*10023SGordon.Ross@Sun.COM DPRINT("parse reply, rc %d", rc); 254*10023SGordon.Ross@Sun.COM err = EBADRPC; 255*10023SGordon.Ross@Sun.COM goto out; 256*10023SGordon.Ross@Sun.COM } 257*10023SGordon.Ross@Sun.COM /* Note: Allocated stok_in */ 258*10023SGordon.Ross@Sun.COM 259*10023SGordon.Ross@Sun.COM /* 260*10023SGordon.Ross@Sun.COM * Now get the payload. Two calls: 261*10023SGordon.Ross@Sun.COM * first gets the size, 2nd the data. 262*10023SGordon.Ross@Sun.COM * 263*10023SGordon.Ross@Sun.COM * Expect SPNEGO_E_BUFFER_TOO_SMALL here, 264*10023SGordon.Ross@Sun.COM * but if the payload is missing, we'll 265*10023SGordon.Ross@Sun.COM * get SPNEGO_E_ELEMENT_UNAVAILABLE. 266*10023SGordon.Ross@Sun.COM */ 267*10023SGordon.Ross@Sun.COM rc = spnegoGetMechToken(stok_in, NULL, &toklen); 268*10023SGordon.Ross@Sun.COM switch (rc) { 269*10023SGordon.Ross@Sun.COM case SPNEGO_E_ELEMENT_UNAVAILABLE: 270*10023SGordon.Ross@Sun.COM toklen = 0; 271*10023SGordon.Ross@Sun.COM break; 272*10023SGordon.Ross@Sun.COM case SPNEGO_E_BUFFER_TOO_SMALL: 273*10023SGordon.Ross@Sun.COM /* have toklen */ 274*10023SGordon.Ross@Sun.COM break; 275*10023SGordon.Ross@Sun.COM default: 276*10023SGordon.Ross@Sun.COM DPRINT("GetMechTok1, rc %d", rc); 277*10023SGordon.Ross@Sun.COM err = EBADRPC; 278*10023SGordon.Ross@Sun.COM goto out; 279*10023SGordon.Ross@Sun.COM } 280*10023SGordon.Ross@Sun.COM err = mb_init(&body_in, (size_t)toklen); 281*10023SGordon.Ross@Sun.COM if (err) 282*10023SGordon.Ross@Sun.COM goto out; 283*10023SGordon.Ross@Sun.COM m = body_in.mb_top; 284*10023SGordon.Ross@Sun.COM if (toklen > 0) { 285*10023SGordon.Ross@Sun.COM rc = spnegoGetMechToken(stok_in, 286*10023SGordon.Ross@Sun.COM (uchar_t *)m->m_data, &toklen); 287*10023SGordon.Ross@Sun.COM if (rc) { 288*10023SGordon.Ross@Sun.COM DPRINT("GetMechTok2, rc %d", rc); 289*10023SGordon.Ross@Sun.COM err = EBADRPC; 290*10023SGordon.Ross@Sun.COM goto out; 291*10023SGordon.Ross@Sun.COM } 292*10023SGordon.Ross@Sun.COM body_in.mb_count = m->m_len = (size_t)toklen; 293*10023SGordon.Ross@Sun.COM } 294*10023SGordon.Ross@Sun.COM } 295*10023SGordon.Ross@Sun.COM 296*10023SGordon.Ross@Sun.COM /* 297*10023SGordon.Ross@Sun.COM * Call the back-end security provider (SSP) to 298*10023SGordon.Ross@Sun.COM * handle the received token (if present) and 299*10023SGordon.Ross@Sun.COM * generate an output token (if requested). 300*10023SGordon.Ross@Sun.COM */ 301*10023SGordon.Ross@Sun.COM err = sp->sp_nexttok(sp, 302*10023SGordon.Ross@Sun.COM caller_in ? &body_in : NULL, 303*10023SGordon.Ross@Sun.COM caller_out ? &body_out : NULL); 304*10023SGordon.Ross@Sun.COM if (err) 305*10023SGordon.Ross@Sun.COM goto out; 306*10023SGordon.Ross@Sun.COM 307*10023SGordon.Ross@Sun.COM /* 308*10023SGordon.Ross@Sun.COM * Wrap the outgoing body if requested, 309*10023SGordon.Ross@Sun.COM * either negTokenInit on first call, or 310*10023SGordon.Ross@Sun.COM * negTokenTarg on subsequent calls. 311*10023SGordon.Ross@Sun.COM */ 312*10023SGordon.Ross@Sun.COM if (caller_out != NULL) { 313*10023SGordon.Ross@Sun.COM m = body_out.mb_top; 314*10023SGordon.Ross@Sun.COM 315*10023SGordon.Ross@Sun.COM if (caller_in == NULL) { 316*10023SGordon.Ross@Sun.COM /* 317*10023SGordon.Ross@Sun.COM * This is the first call, so create a 318*10023SGordon.Ross@Sun.COM * negTokenInit. 319*10023SGordon.Ross@Sun.COM */ 320*10023SGordon.Ross@Sun.COM rc = spnegoCreateNegTokenInit( 321*10023SGordon.Ross@Sun.COM sp->sp_mech, 0, 322*10023SGordon.Ross@Sun.COM (uchar_t *)m->m_data, m->m_len, 323*10023SGordon.Ross@Sun.COM NULL, 0, &stok_out); 324*10023SGordon.Ross@Sun.COM /* Note: allocated stok_out */ 325*10023SGordon.Ross@Sun.COM } else { 326*10023SGordon.Ross@Sun.COM /* 327*10023SGordon.Ross@Sun.COM * Note: must pass spnego_mech_oid_NotUsed, 328*10023SGordon.Ross@Sun.COM * instead of sp->sp_mech so that the spnego 329*10023SGordon.Ross@Sun.COM * code will not marshal a mech OID list. 330*10023SGordon.Ross@Sun.COM * The mechanism is determined at this point, 331*10023SGordon.Ross@Sun.COM * and some servers won't parse an unexpected 332*10023SGordon.Ross@Sun.COM * mech. OID list in a negTokenTarg 333*10023SGordon.Ross@Sun.COM */ 334*10023SGordon.Ross@Sun.COM rc = spnegoCreateNegTokenTarg( 335*10023SGordon.Ross@Sun.COM spnego_mech_oid_NotUsed, 336*10023SGordon.Ross@Sun.COM spnego_negresult_NotUsed, 337*10023SGordon.Ross@Sun.COM (uchar_t *)m->m_data, m->m_len, 338*10023SGordon.Ross@Sun.COM NULL, 0, &stok_out); 339*10023SGordon.Ross@Sun.COM /* Note: allocated stok_out */ 340*10023SGordon.Ross@Sun.COM } 341*10023SGordon.Ross@Sun.COM if (rc) { 342*10023SGordon.Ross@Sun.COM DPRINT("CreateNegTokenX, rc 0x%x", rc); 343*10023SGordon.Ross@Sun.COM err = EBADRPC; 344*10023SGordon.Ross@Sun.COM goto out; 345*10023SGordon.Ross@Sun.COM } 346*10023SGordon.Ross@Sun.COM 347*10023SGordon.Ross@Sun.COM /* 348*10023SGordon.Ross@Sun.COM * Copy binary from stok_out to caller_out 349*10023SGordon.Ross@Sun.COM * Two calls: get the size, get the data. 350*10023SGordon.Ross@Sun.COM */ 351*10023SGordon.Ross@Sun.COM rc = spnegoTokenGetBinary(stok_out, NULL, &toklen); 352*10023SGordon.Ross@Sun.COM if (rc != SPNEGO_E_BUFFER_TOO_SMALL) { 353*10023SGordon.Ross@Sun.COM DPRINT("GetBinary1, rc 0x%x", rc); 354*10023SGordon.Ross@Sun.COM err = EBADRPC; 355*10023SGordon.Ross@Sun.COM goto out; 356*10023SGordon.Ross@Sun.COM } 357*10023SGordon.Ross@Sun.COM err = mb_init(caller_out, (size_t)toklen); 358*10023SGordon.Ross@Sun.COM if (err) 359*10023SGordon.Ross@Sun.COM goto out; 360*10023SGordon.Ross@Sun.COM m = caller_out->mb_top; 361*10023SGordon.Ross@Sun.COM rc = spnegoTokenGetBinary(stok_out, 362*10023SGordon.Ross@Sun.COM (uchar_t *)m->m_data, &toklen); 363*10023SGordon.Ross@Sun.COM if (rc) { 364*10023SGordon.Ross@Sun.COM DPRINT("GetBinary2, rc 0x%x", rc); 365*10023SGordon.Ross@Sun.COM err = EBADRPC; 366*10023SGordon.Ross@Sun.COM goto out; 367*10023SGordon.Ross@Sun.COM } 368*10023SGordon.Ross@Sun.COM caller_out->mb_count = m->m_len = (size_t)toklen; 369*10023SGordon.Ross@Sun.COM } else { 370*10023SGordon.Ross@Sun.COM /* 371*10023SGordon.Ross@Sun.COM * caller_out == NULL, so this is the "final" call. 372*10023SGordon.Ross@Sun.COM * Get final SPNEGO result from the INPUT token. 373*10023SGordon.Ross@Sun.COM */ 374*10023SGordon.Ross@Sun.COM rc = spnegoGetNegotiationResult(stok_in, &result); 375*10023SGordon.Ross@Sun.COM if (rc) { 376*10023SGordon.Ross@Sun.COM DPRINT("rc 0x%x", rc); 377*10023SGordon.Ross@Sun.COM err = EBADRPC; 378*10023SGordon.Ross@Sun.COM goto out; 379*10023SGordon.Ross@Sun.COM } 380*10023SGordon.Ross@Sun.COM DPRINT("spnego result: 0x%x", result); 381*10023SGordon.Ross@Sun.COM if (result != spnego_negresult_success) { 382*10023SGordon.Ross@Sun.COM err = EAUTH; 383*10023SGordon.Ross@Sun.COM goto out; 384*10023SGordon.Ross@Sun.COM } 385*10023SGordon.Ross@Sun.COM } 386*10023SGordon.Ross@Sun.COM err = 0; 387*10023SGordon.Ross@Sun.COM 388*10023SGordon.Ross@Sun.COM out: 389*10023SGordon.Ross@Sun.COM mb_done(&body_in); 390*10023SGordon.Ross@Sun.COM mb_done(&body_out); 391*10023SGordon.Ross@Sun.COM spnegoFreeData(stok_in); 392*10023SGordon.Ross@Sun.COM spnegoFreeData(stok_out); 393*10023SGordon.Ross@Sun.COM 394*10023SGordon.Ross@Sun.COM return (err); 395*10023SGordon.Ross@Sun.COM } 396