110023SGordon.Ross@Sun.COM /* 210023SGordon.Ross@Sun.COM * CDDL HEADER START 310023SGordon.Ross@Sun.COM * 410023SGordon.Ross@Sun.COM * The contents of this file are subject to the terms of the 510023SGordon.Ross@Sun.COM * Common Development and Distribution License (the "License"). 610023SGordon.Ross@Sun.COM * You may not use this file except in compliance with the License. 710023SGordon.Ross@Sun.COM * 810023SGordon.Ross@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 910023SGordon.Ross@Sun.COM * or http://www.opensolaris.org/os/licensing. 1010023SGordon.Ross@Sun.COM * See the License for the specific language governing permissions 1110023SGordon.Ross@Sun.COM * and limitations under the License. 1210023SGordon.Ross@Sun.COM * 1310023SGordon.Ross@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1410023SGordon.Ross@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1510023SGordon.Ross@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1610023SGordon.Ross@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1710023SGordon.Ross@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1810023SGordon.Ross@Sun.COM * 1910023SGordon.Ross@Sun.COM * CDDL HEADER END 2010023SGordon.Ross@Sun.COM */ 2110023SGordon.Ross@Sun.COM 2210023SGordon.Ross@Sun.COM /* 2310023SGordon.Ross@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2410023SGordon.Ross@Sun.COM * Use is subject to license terms. 2510023SGordon.Ross@Sun.COM */ 2610023SGordon.Ross@Sun.COM 2710023SGordon.Ross@Sun.COM /* 2810023SGordon.Ross@Sun.COM * Security Provider glue 2910023SGordon.Ross@Sun.COM * 3010023SGordon.Ross@Sun.COM * Modeled after SSPI for now, only because we're currently 3110023SGordon.Ross@Sun.COM * using the Microsoft sample spnego code. 3210023SGordon.Ross@Sun.COM * 3310023SGordon.Ross@Sun.COM * ToDo: Port all of this to GSS-API plugins. 3410023SGordon.Ross@Sun.COM */ 3510023SGordon.Ross@Sun.COM 3610023SGordon.Ross@Sun.COM #include <errno.h> 3710023SGordon.Ross@Sun.COM #include <stdio.h> 3810023SGordon.Ross@Sun.COM #include <stdlib.h> 3910023SGordon.Ross@Sun.COM #include <unistd.h> 4010023SGordon.Ross@Sun.COM #include <strings.h> 4110023SGordon.Ross@Sun.COM #include <netdb.h> 4210023SGordon.Ross@Sun.COM #include <libintl.h> 4310023SGordon.Ross@Sun.COM #include <xti.h> 4410023SGordon.Ross@Sun.COM #include <assert.h> 4510023SGordon.Ross@Sun.COM 4610023SGordon.Ross@Sun.COM #include <sys/types.h> 4710023SGordon.Ross@Sun.COM #include <sys/time.h> 4810023SGordon.Ross@Sun.COM #include <sys/byteorder.h> 4910023SGordon.Ross@Sun.COM #include <sys/socket.h> 5010023SGordon.Ross@Sun.COM #include <sys/fcntl.h> 5110023SGordon.Ross@Sun.COM 5210023SGordon.Ross@Sun.COM #include <netinet/in.h> 5310023SGordon.Ross@Sun.COM #include <netinet/tcp.h> 5410023SGordon.Ross@Sun.COM #include <arpa/inet.h> 5510023SGordon.Ross@Sun.COM 5610023SGordon.Ross@Sun.COM #include <netsmb/smb_lib.h> 5710023SGordon.Ross@Sun.COM #include <netsmb/mchain.h> 5810023SGordon.Ross@Sun.COM 5910023SGordon.Ross@Sun.COM #include "private.h" 6010023SGordon.Ross@Sun.COM #include "charsets.h" 6110023SGordon.Ross@Sun.COM #include "spnego.h" 6210023SGordon.Ross@Sun.COM #include "derparse.h" 6310023SGordon.Ross@Sun.COM #include "ssp.h" 6410023SGordon.Ross@Sun.COM 6510023SGordon.Ross@Sun.COM 6610023SGordon.Ross@Sun.COM /* 6710023SGordon.Ross@Sun.COM * ssp_ctx_create_client 6810023SGordon.Ross@Sun.COM * 6910023SGordon.Ross@Sun.COM * This is the first function called for SMB "extended security". 7010023SGordon.Ross@Sun.COM * Here we select a security support provider (SSP), or mechanism, 7110023SGordon.Ross@Sun.COM * and build the security context used throughout authentication. 7210023SGordon.Ross@Sun.COM * 7310023SGordon.Ross@Sun.COM * Note that we receive a "hint" in the SMB Negotiate response 7410023SGordon.Ross@Sun.COM * that contains the list of mechanisms supported by the server. 7510023SGordon.Ross@Sun.COM * We use this to help us select a mechanism. 7610023SGordon.Ross@Sun.COM * 7710023SGordon.Ross@Sun.COM * With SSPI this would call: 7810023SGordon.Ross@Sun.COM * ssp->InitSecurityInterface() 7910023SGordon.Ross@Sun.COM * ssp->AcquireCredentialsHandle() 8010023SGordon.Ross@Sun.COM * ssp->InitializeSecurityContext() 8110023SGordon.Ross@Sun.COM * With GSS-API this will become: 8210023SGordon.Ross@Sun.COM * gss_import_name(... service_principal_name) 8310023SGordon.Ross@Sun.COM * gss_init_sec_context(), etc. 8410023SGordon.Ross@Sun.COM */ 8510023SGordon.Ross@Sun.COM int 8610023SGordon.Ross@Sun.COM ssp_ctx_create_client(struct smb_ctx *ctx, struct mbdata *hint_mb) 8710023SGordon.Ross@Sun.COM { 8810023SGordon.Ross@Sun.COM struct ssp_ctx *sp; 8910023SGordon.Ross@Sun.COM mbuf_t *m; 9010023SGordon.Ross@Sun.COM SPNEGO_MECH_OID oid; 9110023SGordon.Ross@Sun.COM int indx, rc; 9210023SGordon.Ross@Sun.COM int err = ENOTSUP; /* in case nothing matches */ 9310023SGordon.Ross@Sun.COM 9410023SGordon.Ross@Sun.COM sp = malloc(sizeof (*sp)); 9510023SGordon.Ross@Sun.COM if (sp == NULL) 9610023SGordon.Ross@Sun.COM return (ENOMEM); 9710023SGordon.Ross@Sun.COM bzero(sp, sizeof (*sp)); 9810023SGordon.Ross@Sun.COM ctx->ct_ssp_ctx = sp; 9910023SGordon.Ross@Sun.COM sp->smb_ctx = ctx; 10010023SGordon.Ross@Sun.COM 10110023SGordon.Ross@Sun.COM /* 10210023SGordon.Ross@Sun.COM * Parse the SPNEGO "hint" to get the server's list of 10310023SGordon.Ross@Sun.COM * supported mechanisms. If the "hint" is empty, 10410023SGordon.Ross@Sun.COM * assume NTLMSSP. (Or could use "raw NTLMSSP") 10510023SGordon.Ross@Sun.COM */ 10610023SGordon.Ross@Sun.COM m = hint_mb->mb_top; 10710023SGordon.Ross@Sun.COM if (m == NULL) 10810023SGordon.Ross@Sun.COM goto use_ntlm; 10910023SGordon.Ross@Sun.COM rc = spnegoInitFromBinary((uchar_t *)m->m_data, m->m_len, 11010023SGordon.Ross@Sun.COM &sp->sp_hint); 11110023SGordon.Ross@Sun.COM if (rc) { 11210023SGordon.Ross@Sun.COM DPRINT("parse hint, rc %d", rc); 11310023SGordon.Ross@Sun.COM goto use_ntlm; 11410023SGordon.Ross@Sun.COM } 11510023SGordon.Ross@Sun.COM 11610023SGordon.Ross@Sun.COM /* 11710023SGordon.Ross@Sun.COM * Did the server offer Kerberos? 11810023SGordon.Ross@Sun.COM * Either spec. OID or legacy is OK, 11910023SGordon.Ross@Sun.COM * but have to remember what we got. 12010023SGordon.Ross@Sun.COM */ 12110023SGordon.Ross@Sun.COM oid = spnego_mech_oid_NotUsed; 12210023SGordon.Ross@Sun.COM if (0 == spnegoIsMechTypeAvailable(sp->sp_hint, 12310023SGordon.Ross@Sun.COM spnego_mech_oid_Kerberos_V5, &indx)) 12410023SGordon.Ross@Sun.COM oid = spnego_mech_oid_Kerberos_V5; 12510023SGordon.Ross@Sun.COM else if (0 == spnegoIsMechTypeAvailable(sp->sp_hint, 12610023SGordon.Ross@Sun.COM spnego_mech_oid_Kerberos_V5_Legacy, &indx)) 12710023SGordon.Ross@Sun.COM oid = spnego_mech_oid_Kerberos_V5_Legacy; 12810023SGordon.Ross@Sun.COM if (oid != spnego_mech_oid_NotUsed) { 12910023SGordon.Ross@Sun.COM /* 13010023SGordon.Ross@Sun.COM * Yes! Server offers Kerberos. 13110023SGordon.Ross@Sun.COM * Try to init our krb5 mechanism. 13210023SGordon.Ross@Sun.COM * It will fail if the calling user 13310023SGordon.Ross@Sun.COM * does not have krb5 credentials. 13410023SGordon.Ross@Sun.COM */ 13510023SGordon.Ross@Sun.COM sp->sp_mech = oid; 13610023SGordon.Ross@Sun.COM err = krb5ssp_init_client(sp); 13710023SGordon.Ross@Sun.COM if (err == 0) { 13810023SGordon.Ross@Sun.COM DPRINT("using Kerberos"); 13910023SGordon.Ross@Sun.COM return (0); 14010023SGordon.Ross@Sun.COM } 14110023SGordon.Ross@Sun.COM /* else fall back to NTLMSSP */ 14210023SGordon.Ross@Sun.COM } 14310023SGordon.Ross@Sun.COM 14410023SGordon.Ross@Sun.COM /* 14510023SGordon.Ross@Sun.COM * Did the server offer NTLMSSP? 14610023SGordon.Ross@Sun.COM */ 14710023SGordon.Ross@Sun.COM if (0 == spnegoIsMechTypeAvailable(sp->sp_hint, 14810023SGordon.Ross@Sun.COM spnego_mech_oid_NTLMSSP, &indx)) { 14910023SGordon.Ross@Sun.COM /* 15010023SGordon.Ross@Sun.COM * OK, we'll use NTLMSSP 15110023SGordon.Ross@Sun.COM */ 15210023SGordon.Ross@Sun.COM use_ntlm: 15310023SGordon.Ross@Sun.COM sp->sp_mech = spnego_mech_oid_NTLMSSP; 15410023SGordon.Ross@Sun.COM err = ntlmssp_init_client(sp); 15510023SGordon.Ross@Sun.COM if (err == 0) { 15610023SGordon.Ross@Sun.COM DPRINT("using NTLMSSP"); 15710023SGordon.Ross@Sun.COM return (0); 15810023SGordon.Ross@Sun.COM } 15910023SGordon.Ross@Sun.COM } 16010023SGordon.Ross@Sun.COM 16110023SGordon.Ross@Sun.COM /* No supported mechanisms! */ 16210023SGordon.Ross@Sun.COM return (err); 16310023SGordon.Ross@Sun.COM } 16410023SGordon.Ross@Sun.COM 16510023SGordon.Ross@Sun.COM 16610023SGordon.Ross@Sun.COM /* 16710023SGordon.Ross@Sun.COM * ssp_ctx_destroy 16810023SGordon.Ross@Sun.COM * 16910023SGordon.Ross@Sun.COM * Dispatch to the mechanism-specific destroy. 17010023SGordon.Ross@Sun.COM */ 17110023SGordon.Ross@Sun.COM void 17210023SGordon.Ross@Sun.COM ssp_ctx_destroy(struct smb_ctx *ctx) 17310023SGordon.Ross@Sun.COM { 17410023SGordon.Ross@Sun.COM ssp_ctx_t *sp; 17510023SGordon.Ross@Sun.COM 17610023SGordon.Ross@Sun.COM sp = ctx->ct_ssp_ctx; 17710023SGordon.Ross@Sun.COM ctx->ct_ssp_ctx = NULL; 17810023SGordon.Ross@Sun.COM 17910023SGordon.Ross@Sun.COM if (sp == NULL) 18010023SGordon.Ross@Sun.COM return; 18110023SGordon.Ross@Sun.COM 18210023SGordon.Ross@Sun.COM if (sp->sp_destroy != NULL) 18310023SGordon.Ross@Sun.COM (sp->sp_destroy)(sp); 18410023SGordon.Ross@Sun.COM 18510023SGordon.Ross@Sun.COM if (sp->sp_hint != NULL) 18610023SGordon.Ross@Sun.COM spnegoFreeData(sp->sp_hint); 18710023SGordon.Ross@Sun.COM 18810023SGordon.Ross@Sun.COM free(sp); 18910023SGordon.Ross@Sun.COM } 19010023SGordon.Ross@Sun.COM 19110023SGordon.Ross@Sun.COM 19210023SGordon.Ross@Sun.COM /* 19310023SGordon.Ross@Sun.COM * ssp_ctx_next_token 19410023SGordon.Ross@Sun.COM * 19510023SGordon.Ross@Sun.COM * This is the function called to generate the next token to send, 19610023SGordon.Ross@Sun.COM * given a token just received, using the selected back-end method. 19710023SGordon.Ross@Sun.COM * The back-end method is called a security service provider (SSP). 19810023SGordon.Ross@Sun.COM * 19910023SGordon.Ross@Sun.COM * This is also called to generate the first token to send 20010023SGordon.Ross@Sun.COM * (when called with caller_in == NULL) and to handle the last 20110023SGordon.Ross@Sun.COM * token received (when called with caller_out == NULL). 20210023SGordon.Ross@Sun.COM * See caller: smb_ssnsetup_spnego 20310023SGordon.Ross@Sun.COM * 20410023SGordon.Ross@Sun.COM * Note that if the back-end SSP "next token" function ever 20510023SGordon.Ross@Sun.COM * returns an error, the conversation ends, and there are 20610023SGordon.Ross@Sun.COM * no further calls to this function for this context. 20710023SGordon.Ross@Sun.COM * 20810023SGordon.Ross@Sun.COM * General outline of this funcion: 20910023SGordon.Ross@Sun.COM * if (caller_in) 21010023SGordon.Ross@Sun.COM * Unwrap caller_in spnego blob, 21110023SGordon.Ross@Sun.COM * store payload in body_in 21210023SGordon.Ross@Sun.COM * Call back-end SSP "next token" method (body_in, body_out) 21310023SGordon.Ross@Sun.COM * if (caller_out) 21410023SGordon.Ross@Sun.COM * Wrap returned body_out in spnego, 21510023SGordon.Ross@Sun.COM * store in caller_out 21610023SGordon.Ross@Sun.COM * 21710023SGordon.Ross@Sun.COM * With SSPI this would call: 21810023SGordon.Ross@Sun.COM * ssp->InitializeSecurityContext() 21910023SGordon.Ross@Sun.COM * With GSS-API this will become: 22010023SGordon.Ross@Sun.COM * gss_init_sec_context() 22110023SGordon.Ross@Sun.COM */ 22210023SGordon.Ross@Sun.COM int 22310023SGordon.Ross@Sun.COM ssp_ctx_next_token(struct smb_ctx *ctx, 22410023SGordon.Ross@Sun.COM struct mbdata *caller_in, 22510023SGordon.Ross@Sun.COM struct mbdata *caller_out) 22610023SGordon.Ross@Sun.COM { 22710023SGordon.Ross@Sun.COM struct mbdata body_in, body_out; 22810023SGordon.Ross@Sun.COM SPNEGO_TOKEN_HANDLE stok_in, stok_out; 22910023SGordon.Ross@Sun.COM SPNEGO_NEGRESULT result; 23010023SGordon.Ross@Sun.COM ssp_ctx_t *sp; 23110023SGordon.Ross@Sun.COM struct mbuf *m; 23210023SGordon.Ross@Sun.COM ulong_t toklen; 23310023SGordon.Ross@Sun.COM int err, rc; 23410023SGordon.Ross@Sun.COM 23510023SGordon.Ross@Sun.COM bzero(&body_in, sizeof (body_in)); 23610023SGordon.Ross@Sun.COM bzero(&body_out, sizeof (body_out)); 23710023SGordon.Ross@Sun.COM stok_out = stok_in = NULL; 23810023SGordon.Ross@Sun.COM sp = ctx->ct_ssp_ctx; 23910023SGordon.Ross@Sun.COM 24010023SGordon.Ross@Sun.COM /* 24110023SGordon.Ross@Sun.COM * If we have an spnego input token, parse it, 24210023SGordon.Ross@Sun.COM * extract the payload for the back-end SSP. 24310023SGordon.Ross@Sun.COM */ 24410023SGordon.Ross@Sun.COM if (caller_in != NULL) { 24510023SGordon.Ross@Sun.COM 24610023SGordon.Ross@Sun.COM /* 24710023SGordon.Ross@Sun.COM * Let the spnego code parse it. 24810023SGordon.Ross@Sun.COM */ 24910023SGordon.Ross@Sun.COM m = caller_in->mb_top; 25010023SGordon.Ross@Sun.COM rc = spnegoInitFromBinary((uchar_t *)m->m_data, 25110023SGordon.Ross@Sun.COM m->m_len, &stok_in); 25210023SGordon.Ross@Sun.COM if (rc) { 25310023SGordon.Ross@Sun.COM DPRINT("parse reply, rc %d", rc); 25410023SGordon.Ross@Sun.COM err = EBADRPC; 25510023SGordon.Ross@Sun.COM goto out; 25610023SGordon.Ross@Sun.COM } 25710023SGordon.Ross@Sun.COM /* Note: Allocated stok_in */ 25810023SGordon.Ross@Sun.COM 25910023SGordon.Ross@Sun.COM /* 26010023SGordon.Ross@Sun.COM * Now get the payload. Two calls: 26110023SGordon.Ross@Sun.COM * first gets the size, 2nd the data. 26210023SGordon.Ross@Sun.COM * 26310023SGordon.Ross@Sun.COM * Expect SPNEGO_E_BUFFER_TOO_SMALL here, 26410023SGordon.Ross@Sun.COM * but if the payload is missing, we'll 26510023SGordon.Ross@Sun.COM * get SPNEGO_E_ELEMENT_UNAVAILABLE. 26610023SGordon.Ross@Sun.COM */ 26710023SGordon.Ross@Sun.COM rc = spnegoGetMechToken(stok_in, NULL, &toklen); 26810023SGordon.Ross@Sun.COM switch (rc) { 26910023SGordon.Ross@Sun.COM case SPNEGO_E_ELEMENT_UNAVAILABLE: 27010023SGordon.Ross@Sun.COM toklen = 0; 27110023SGordon.Ross@Sun.COM break; 27210023SGordon.Ross@Sun.COM case SPNEGO_E_BUFFER_TOO_SMALL: 27310023SGordon.Ross@Sun.COM /* have toklen */ 27410023SGordon.Ross@Sun.COM break; 27510023SGordon.Ross@Sun.COM default: 27610023SGordon.Ross@Sun.COM DPRINT("GetMechTok1, rc %d", rc); 27710023SGordon.Ross@Sun.COM err = EBADRPC; 27810023SGordon.Ross@Sun.COM goto out; 27910023SGordon.Ross@Sun.COM } 280*11332SGordon.Ross@Sun.COM err = mb_init_sz(&body_in, (size_t)toklen); 28110023SGordon.Ross@Sun.COM if (err) 28210023SGordon.Ross@Sun.COM goto out; 28310023SGordon.Ross@Sun.COM m = body_in.mb_top; 28410023SGordon.Ross@Sun.COM if (toklen > 0) { 28510023SGordon.Ross@Sun.COM rc = spnegoGetMechToken(stok_in, 28610023SGordon.Ross@Sun.COM (uchar_t *)m->m_data, &toklen); 28710023SGordon.Ross@Sun.COM if (rc) { 28810023SGordon.Ross@Sun.COM DPRINT("GetMechTok2, rc %d", rc); 28910023SGordon.Ross@Sun.COM err = EBADRPC; 29010023SGordon.Ross@Sun.COM goto out; 29110023SGordon.Ross@Sun.COM } 29210023SGordon.Ross@Sun.COM body_in.mb_count = m->m_len = (size_t)toklen; 29310023SGordon.Ross@Sun.COM } 29410023SGordon.Ross@Sun.COM } 29510023SGordon.Ross@Sun.COM 29610023SGordon.Ross@Sun.COM /* 29710023SGordon.Ross@Sun.COM * Call the back-end security provider (SSP) to 29810023SGordon.Ross@Sun.COM * handle the received token (if present) and 29910023SGordon.Ross@Sun.COM * generate an output token (if requested). 30010023SGordon.Ross@Sun.COM */ 30110023SGordon.Ross@Sun.COM err = sp->sp_nexttok(sp, 30210023SGordon.Ross@Sun.COM caller_in ? &body_in : NULL, 30310023SGordon.Ross@Sun.COM caller_out ? &body_out : NULL); 30410023SGordon.Ross@Sun.COM if (err) 30510023SGordon.Ross@Sun.COM goto out; 30610023SGordon.Ross@Sun.COM 30710023SGordon.Ross@Sun.COM /* 30810023SGordon.Ross@Sun.COM * Wrap the outgoing body if requested, 30910023SGordon.Ross@Sun.COM * either negTokenInit on first call, or 31010023SGordon.Ross@Sun.COM * negTokenTarg on subsequent calls. 31110023SGordon.Ross@Sun.COM */ 31210023SGordon.Ross@Sun.COM if (caller_out != NULL) { 31310023SGordon.Ross@Sun.COM m = body_out.mb_top; 31410023SGordon.Ross@Sun.COM 31510023SGordon.Ross@Sun.COM if (caller_in == NULL) { 31610023SGordon.Ross@Sun.COM /* 31710023SGordon.Ross@Sun.COM * This is the first call, so create a 31810023SGordon.Ross@Sun.COM * negTokenInit. 31910023SGordon.Ross@Sun.COM */ 32010023SGordon.Ross@Sun.COM rc = spnegoCreateNegTokenInit( 32110023SGordon.Ross@Sun.COM sp->sp_mech, 0, 32210023SGordon.Ross@Sun.COM (uchar_t *)m->m_data, m->m_len, 32310023SGordon.Ross@Sun.COM NULL, 0, &stok_out); 32410023SGordon.Ross@Sun.COM /* Note: allocated stok_out */ 32510023SGordon.Ross@Sun.COM } else { 32610023SGordon.Ross@Sun.COM /* 32710023SGordon.Ross@Sun.COM * Note: must pass spnego_mech_oid_NotUsed, 32810023SGordon.Ross@Sun.COM * instead of sp->sp_mech so that the spnego 32910023SGordon.Ross@Sun.COM * code will not marshal a mech OID list. 33010023SGordon.Ross@Sun.COM * The mechanism is determined at this point, 33110023SGordon.Ross@Sun.COM * and some servers won't parse an unexpected 33210023SGordon.Ross@Sun.COM * mech. OID list in a negTokenTarg 33310023SGordon.Ross@Sun.COM */ 33410023SGordon.Ross@Sun.COM rc = spnegoCreateNegTokenTarg( 33510023SGordon.Ross@Sun.COM spnego_mech_oid_NotUsed, 33610023SGordon.Ross@Sun.COM spnego_negresult_NotUsed, 33710023SGordon.Ross@Sun.COM (uchar_t *)m->m_data, m->m_len, 33810023SGordon.Ross@Sun.COM NULL, 0, &stok_out); 33910023SGordon.Ross@Sun.COM /* Note: allocated stok_out */ 34010023SGordon.Ross@Sun.COM } 34110023SGordon.Ross@Sun.COM if (rc) { 34210023SGordon.Ross@Sun.COM DPRINT("CreateNegTokenX, rc 0x%x", rc); 34310023SGordon.Ross@Sun.COM err = EBADRPC; 34410023SGordon.Ross@Sun.COM goto out; 34510023SGordon.Ross@Sun.COM } 34610023SGordon.Ross@Sun.COM 34710023SGordon.Ross@Sun.COM /* 34810023SGordon.Ross@Sun.COM * Copy binary from stok_out to caller_out 34910023SGordon.Ross@Sun.COM * Two calls: get the size, get the data. 35010023SGordon.Ross@Sun.COM */ 35110023SGordon.Ross@Sun.COM rc = spnegoTokenGetBinary(stok_out, NULL, &toklen); 35210023SGordon.Ross@Sun.COM if (rc != SPNEGO_E_BUFFER_TOO_SMALL) { 35310023SGordon.Ross@Sun.COM DPRINT("GetBinary1, rc 0x%x", rc); 35410023SGordon.Ross@Sun.COM err = EBADRPC; 35510023SGordon.Ross@Sun.COM goto out; 35610023SGordon.Ross@Sun.COM } 357*11332SGordon.Ross@Sun.COM err = mb_init_sz(caller_out, (size_t)toklen); 35810023SGordon.Ross@Sun.COM if (err) 35910023SGordon.Ross@Sun.COM goto out; 36010023SGordon.Ross@Sun.COM m = caller_out->mb_top; 36110023SGordon.Ross@Sun.COM rc = spnegoTokenGetBinary(stok_out, 36210023SGordon.Ross@Sun.COM (uchar_t *)m->m_data, &toklen); 36310023SGordon.Ross@Sun.COM if (rc) { 36410023SGordon.Ross@Sun.COM DPRINT("GetBinary2, rc 0x%x", rc); 36510023SGordon.Ross@Sun.COM err = EBADRPC; 36610023SGordon.Ross@Sun.COM goto out; 36710023SGordon.Ross@Sun.COM } 36810023SGordon.Ross@Sun.COM caller_out->mb_count = m->m_len = (size_t)toklen; 36910023SGordon.Ross@Sun.COM } else { 37010023SGordon.Ross@Sun.COM /* 37110023SGordon.Ross@Sun.COM * caller_out == NULL, so this is the "final" call. 37210023SGordon.Ross@Sun.COM * Get final SPNEGO result from the INPUT token. 37310023SGordon.Ross@Sun.COM */ 37410023SGordon.Ross@Sun.COM rc = spnegoGetNegotiationResult(stok_in, &result); 37510023SGordon.Ross@Sun.COM if (rc) { 37610023SGordon.Ross@Sun.COM DPRINT("rc 0x%x", rc); 37710023SGordon.Ross@Sun.COM err = EBADRPC; 37810023SGordon.Ross@Sun.COM goto out; 37910023SGordon.Ross@Sun.COM } 38010023SGordon.Ross@Sun.COM DPRINT("spnego result: 0x%x", result); 38110023SGordon.Ross@Sun.COM if (result != spnego_negresult_success) { 38210023SGordon.Ross@Sun.COM err = EAUTH; 38310023SGordon.Ross@Sun.COM goto out; 38410023SGordon.Ross@Sun.COM } 38510023SGordon.Ross@Sun.COM } 38610023SGordon.Ross@Sun.COM err = 0; 38710023SGordon.Ross@Sun.COM 38810023SGordon.Ross@Sun.COM out: 38910023SGordon.Ross@Sun.COM mb_done(&body_in); 39010023SGordon.Ross@Sun.COM mb_done(&body_out); 39110023SGordon.Ross@Sun.COM spnegoFreeData(stok_in); 39210023SGordon.Ross@Sun.COM spnegoFreeData(stok_out); 39310023SGordon.Ross@Sun.COM 39410023SGordon.Ross@Sun.COM return (err); 39510023SGordon.Ross@Sun.COM } 396