xref: /onnv-gate/usr/src/lib/libsmbfs/smb/ssp.c (revision 11332:ed3411181494)
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
ssp_ctx_create_client(struct smb_ctx * ctx,struct mbdata * hint_mb)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
ssp_ctx_destroy(struct smb_ctx * ctx)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
ssp_ctx_next_token(struct smb_ctx * ctx,struct mbdata * caller_in,struct mbdata * caller_out)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