110023SGordon.Ross@Sun.COM /* 210023SGordon.Ross@Sun.COM * Copyright (c) 2000-2001 Boris Popov 310023SGordon.Ross@Sun.COM * All rights reserved. 410023SGordon.Ross@Sun.COM * 510023SGordon.Ross@Sun.COM * Redistribution and use in source and binary forms, with or without 610023SGordon.Ross@Sun.COM * modification, are permitted provided that the following conditions 710023SGordon.Ross@Sun.COM * are met: 810023SGordon.Ross@Sun.COM * 1. Redistributions of source code must retain the above copyright 910023SGordon.Ross@Sun.COM * notice, this list of conditions and the following disclaimer. 1010023SGordon.Ross@Sun.COM * 2. Redistributions in binary form must reproduce the above copyright 1110023SGordon.Ross@Sun.COM * notice, this list of conditions and the following disclaimer in the 1210023SGordon.Ross@Sun.COM * documentation and/or other materials provided with the distribution. 1310023SGordon.Ross@Sun.COM * 3. All advertising materials mentioning features or use of this software 1410023SGordon.Ross@Sun.COM * must display the following acknowledgement: 1510023SGordon.Ross@Sun.COM * This product includes software developed by Boris Popov. 1610023SGordon.Ross@Sun.COM * 4. Neither the name of the author nor the names of any co-contributors 1710023SGordon.Ross@Sun.COM * may be used to endorse or promote products derived from this software 1810023SGordon.Ross@Sun.COM * without specific prior written permission. 1910023SGordon.Ross@Sun.COM * 2010023SGordon.Ross@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2110023SGordon.Ross@Sun.COM * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2210023SGordon.Ross@Sun.COM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2310023SGordon.Ross@Sun.COM * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2410023SGordon.Ross@Sun.COM * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2510023SGordon.Ross@Sun.COM * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2610023SGordon.Ross@Sun.COM * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2710023SGordon.Ross@Sun.COM * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2810023SGordon.Ross@Sun.COM * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2910023SGordon.Ross@Sun.COM * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3010023SGordon.Ross@Sun.COM * SUCH DAMAGE. 3110023SGordon.Ross@Sun.COM */ 3210023SGordon.Ross@Sun.COM 3310023SGordon.Ross@Sun.COM /* 3410023SGordon.Ross@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3510023SGordon.Ross@Sun.COM * Use is subject to license terms. 3610023SGordon.Ross@Sun.COM */ 3710023SGordon.Ross@Sun.COM 3810023SGordon.Ross@Sun.COM /* 3910023SGordon.Ross@Sun.COM * SMB Session Setup, and related. 4010023SGordon.Ross@Sun.COM * Copied from the driver: smb_smb.c 4110023SGordon.Ross@Sun.COM */ 4210023SGordon.Ross@Sun.COM 4310023SGordon.Ross@Sun.COM #include <errno.h> 4410023SGordon.Ross@Sun.COM #include <stdio.h> 4510023SGordon.Ross@Sun.COM #include <stdlib.h> 4610023SGordon.Ross@Sun.COM #include <unistd.h> 4710023SGordon.Ross@Sun.COM #include <strings.h> 4810023SGordon.Ross@Sun.COM #include <netdb.h> 4910023SGordon.Ross@Sun.COM #include <libintl.h> 5010023SGordon.Ross@Sun.COM #include <xti.h> 5110023SGordon.Ross@Sun.COM #include <assert.h> 5210023SGordon.Ross@Sun.COM 5310023SGordon.Ross@Sun.COM #include <sys/types.h> 5410023SGordon.Ross@Sun.COM #include <sys/time.h> 5510023SGordon.Ross@Sun.COM #include <sys/byteorder.h> 5610023SGordon.Ross@Sun.COM #include <sys/socket.h> 5710023SGordon.Ross@Sun.COM #include <sys/fcntl.h> 5810023SGordon.Ross@Sun.COM 5910023SGordon.Ross@Sun.COM #include <netinet/in.h> 6010023SGordon.Ross@Sun.COM #include <netinet/tcp.h> 6110023SGordon.Ross@Sun.COM #include <arpa/inet.h> 6210023SGordon.Ross@Sun.COM 6310023SGordon.Ross@Sun.COM #include <netsmb/mchain.h> 6410023SGordon.Ross@Sun.COM #include <netsmb/netbios.h> 6510023SGordon.Ross@Sun.COM #include <netsmb/smb_dev.h> 6610023SGordon.Ross@Sun.COM #include <netsmb/smb.h> 6710023SGordon.Ross@Sun.COM 6810023SGordon.Ross@Sun.COM #include <netsmb/smb_lib.h> 6910023SGordon.Ross@Sun.COM #include <netsmb/nb_lib.h> 7010023SGordon.Ross@Sun.COM 7110023SGordon.Ross@Sun.COM #include "private.h" 7210023SGordon.Ross@Sun.COM #include "charsets.h" 7310023SGordon.Ross@Sun.COM #include "ntlm.h" 7410023SGordon.Ross@Sun.COM #include "smb_crypt.h" 7510023SGordon.Ross@Sun.COM 7610023SGordon.Ross@Sun.COM /* 7710023SGordon.Ross@Sun.COM * When we have a _real_ ntstatus.h, eliminate this. 7810023SGordon.Ross@Sun.COM * XXX: Current smb.h defines it without the high bits. 7910023SGordon.Ross@Sun.COM */ 8010023SGordon.Ross@Sun.COM #define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 8110023SGordon.Ross@Sun.COM 8210023SGordon.Ross@Sun.COM static int 8310023SGordon.Ross@Sun.COM smb__ssnsetup(struct smb_ctx *ctx, 8410023SGordon.Ross@Sun.COM struct mbdata *mbc1, struct mbdata *mbc2, 8510023SGordon.Ross@Sun.COM uint32_t *statusp, uint16_t *actionp); 8610023SGordon.Ross@Sun.COM 8710023SGordon.Ross@Sun.COM /* 8810023SGordon.Ross@Sun.COM * Session Setup: NULL session (anonymous) 8910023SGordon.Ross@Sun.COM */ 9010023SGordon.Ross@Sun.COM int 9110023SGordon.Ross@Sun.COM smb_ssnsetup_null(struct smb_ctx *ctx) 9210023SGordon.Ross@Sun.COM { 9310023SGordon.Ross@Sun.COM int err; 9410023SGordon.Ross@Sun.COM uint32_t ntstatus; 9510023SGordon.Ross@Sun.COM uint16_t action = 0; 9610023SGordon.Ross@Sun.COM 9710023SGordon.Ross@Sun.COM if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) { 9810023SGordon.Ross@Sun.COM /* Should not get here with... */ 9910023SGordon.Ross@Sun.COM err = EINVAL; 10010023SGordon.Ross@Sun.COM goto out; 10110023SGordon.Ross@Sun.COM } 10210023SGordon.Ross@Sun.COM 10310023SGordon.Ross@Sun.COM err = smb__ssnsetup(ctx, NULL, NULL, &ntstatus, &action); 10410023SGordon.Ross@Sun.COM if (err) 10510023SGordon.Ross@Sun.COM goto out; 10610023SGordon.Ross@Sun.COM 10710023SGordon.Ross@Sun.COM DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); 10810023SGordon.Ross@Sun.COM if (ntstatus != 0) 10910023SGordon.Ross@Sun.COM err = EAUTH; 11010023SGordon.Ross@Sun.COM 11110023SGordon.Ross@Sun.COM out: 11210023SGordon.Ross@Sun.COM return (err); 11310023SGordon.Ross@Sun.COM } 11410023SGordon.Ross@Sun.COM 11510023SGordon.Ross@Sun.COM 11610023SGordon.Ross@Sun.COM /* 11710023SGordon.Ross@Sun.COM * SMB Session Setup, using NTLMv1 (and maybe LMv1) 11810023SGordon.Ross@Sun.COM */ 11910023SGordon.Ross@Sun.COM int 12010023SGordon.Ross@Sun.COM smb_ssnsetup_ntlm1(struct smb_ctx *ctx) 12110023SGordon.Ross@Sun.COM { 12210023SGordon.Ross@Sun.COM struct mbdata lm_mbc, nt_mbc; 12310023SGordon.Ross@Sun.COM int err; 12410023SGordon.Ross@Sun.COM uint32_t ntstatus; 12510023SGordon.Ross@Sun.COM uint16_t action = 0; 12610023SGordon.Ross@Sun.COM 12710023SGordon.Ross@Sun.COM if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) { 12810023SGordon.Ross@Sun.COM /* Should not get here with... */ 12910023SGordon.Ross@Sun.COM err = EINVAL; 13010023SGordon.Ross@Sun.COM goto out; 13110023SGordon.Ross@Sun.COM } 13210023SGordon.Ross@Sun.COM 13310023SGordon.Ross@Sun.COM /* Make mb_done calls at out safe. */ 13410023SGordon.Ross@Sun.COM bzero(&lm_mbc, sizeof (lm_mbc)); 13510023SGordon.Ross@Sun.COM bzero(&nt_mbc, sizeof (nt_mbc)); 13610023SGordon.Ross@Sun.COM 13710023SGordon.Ross@Sun.COM /* Put the LM,NTLM responses (as mbdata). */ 13810023SGordon.Ross@Sun.COM err = ntlm_put_v1_responses(ctx, &lm_mbc, &nt_mbc); 13910023SGordon.Ross@Sun.COM if (err) 14010023SGordon.Ross@Sun.COM goto out; 14110023SGordon.Ross@Sun.COM 14210023SGordon.Ross@Sun.COM /* 14310023SGordon.Ross@Sun.COM * If we negotiated signing, compute the MAC key 14410023SGordon.Ross@Sun.COM * and start signing messages, but only on the 14510023SGordon.Ross@Sun.COM * first non-null session login. 14610023SGordon.Ross@Sun.COM */ 14710023SGordon.Ross@Sun.COM if ((ctx->ct_vcflags & SMBV_WILL_SIGN) && 14810023SGordon.Ross@Sun.COM (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) { 14910023SGordon.Ross@Sun.COM struct mbuf *m = nt_mbc.mb_top; 15010023SGordon.Ross@Sun.COM char *p; 15110023SGordon.Ross@Sun.COM 15210023SGordon.Ross@Sun.COM /* 15310023SGordon.Ross@Sun.COM * MAC_key = concat(session_key, nt_response) 15410023SGordon.Ross@Sun.COM */ 15510023SGordon.Ross@Sun.COM ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len; 15610023SGordon.Ross@Sun.COM ctx->ct_mackey = malloc(ctx->ct_mackeylen); 15710023SGordon.Ross@Sun.COM if (ctx->ct_mackey == NULL) { 15810023SGordon.Ross@Sun.COM ctx->ct_mackeylen = 0; 15910023SGordon.Ross@Sun.COM err = ENOMEM; 16010023SGordon.Ross@Sun.COM goto out; 16110023SGordon.Ross@Sun.COM } 16210023SGordon.Ross@Sun.COM p = ctx->ct_mackey; 16310023SGordon.Ross@Sun.COM memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ); 16410023SGordon.Ross@Sun.COM memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len); 16510023SGordon.Ross@Sun.COM 16610023SGordon.Ross@Sun.COM /* OK, start signing! */ 16710023SGordon.Ross@Sun.COM ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; 16810023SGordon.Ross@Sun.COM } 16910023SGordon.Ross@Sun.COM 17010023SGordon.Ross@Sun.COM err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action); 17110023SGordon.Ross@Sun.COM if (err) 17210023SGordon.Ross@Sun.COM goto out; 17310023SGordon.Ross@Sun.COM 17410023SGordon.Ross@Sun.COM DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); 17510023SGordon.Ross@Sun.COM if (ntstatus != 0) 17610023SGordon.Ross@Sun.COM err = EAUTH; 17710023SGordon.Ross@Sun.COM 17810023SGordon.Ross@Sun.COM out: 17910023SGordon.Ross@Sun.COM mb_done(&lm_mbc); 18010023SGordon.Ross@Sun.COM mb_done(&nt_mbc); 18110023SGordon.Ross@Sun.COM 18210023SGordon.Ross@Sun.COM return (err); 18310023SGordon.Ross@Sun.COM } 18410023SGordon.Ross@Sun.COM 18510023SGordon.Ross@Sun.COM /* 18610023SGordon.Ross@Sun.COM * SMB Session Setup, using NTLMv2 (and LMv2) 18710023SGordon.Ross@Sun.COM */ 18810023SGordon.Ross@Sun.COM int 18910023SGordon.Ross@Sun.COM smb_ssnsetup_ntlm2(struct smb_ctx *ctx) 19010023SGordon.Ross@Sun.COM { 19110023SGordon.Ross@Sun.COM struct mbdata lm_mbc, nt_mbc, ti_mbc; 19210023SGordon.Ross@Sun.COM int err; 19310023SGordon.Ross@Sun.COM uint32_t ntstatus; 19410023SGordon.Ross@Sun.COM uint16_t action = 0; 19510023SGordon.Ross@Sun.COM 19610023SGordon.Ross@Sun.COM if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) { 19710023SGordon.Ross@Sun.COM /* Should not get here with... */ 19810023SGordon.Ross@Sun.COM err = EINVAL; 19910023SGordon.Ross@Sun.COM goto out; 20010023SGordon.Ross@Sun.COM } 20110023SGordon.Ross@Sun.COM 20210023SGordon.Ross@Sun.COM /* Make mb_done calls at out safe. */ 20310023SGordon.Ross@Sun.COM bzero(&lm_mbc, sizeof (lm_mbc)); 20410023SGordon.Ross@Sun.COM bzero(&nt_mbc, sizeof (nt_mbc)); 20510023SGordon.Ross@Sun.COM bzero(&ti_mbc, sizeof (ti_mbc)); 20610023SGordon.Ross@Sun.COM 20710023SGordon.Ross@Sun.COM /* Build the NTLMv2 "target info" blob (as mbdata) */ 20810023SGordon.Ross@Sun.COM err = ntlm_build_target_info(ctx, NULL, &ti_mbc); 20910023SGordon.Ross@Sun.COM if (err) 21010023SGordon.Ross@Sun.COM goto out; 21110023SGordon.Ross@Sun.COM 21210023SGordon.Ross@Sun.COM /* Put the LMv2, NTLMv2 responses (as mbdata). */ 21310023SGordon.Ross@Sun.COM err = ntlm_put_v2_responses(ctx, &ti_mbc, &lm_mbc, &nt_mbc); 21410023SGordon.Ross@Sun.COM if (err) 21510023SGordon.Ross@Sun.COM goto out; 21610023SGordon.Ross@Sun.COM 21710023SGordon.Ross@Sun.COM /* 21810023SGordon.Ross@Sun.COM * If we negotiated signing, compute the MAC key 21910023SGordon.Ross@Sun.COM * and start signing messages, but only on the 22010023SGordon.Ross@Sun.COM * first non-null session login. 22110023SGordon.Ross@Sun.COM */ 22210023SGordon.Ross@Sun.COM if ((ctx->ct_vcflags & SMBV_WILL_SIGN) && 22310023SGordon.Ross@Sun.COM (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) { 22410023SGordon.Ross@Sun.COM struct mbuf *m = nt_mbc.mb_top; 22510023SGordon.Ross@Sun.COM char *p; 22610023SGordon.Ross@Sun.COM 22710023SGordon.Ross@Sun.COM /* 22810023SGordon.Ross@Sun.COM * MAC_key = concat(session_key, nt_response) 22910023SGordon.Ross@Sun.COM */ 23010023SGordon.Ross@Sun.COM ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len; 23110023SGordon.Ross@Sun.COM ctx->ct_mackey = malloc(ctx->ct_mackeylen); 23210023SGordon.Ross@Sun.COM if (ctx->ct_mackey == NULL) { 23310023SGordon.Ross@Sun.COM ctx->ct_mackeylen = 0; 23410023SGordon.Ross@Sun.COM err = ENOMEM; 23510023SGordon.Ross@Sun.COM goto out; 23610023SGordon.Ross@Sun.COM } 23710023SGordon.Ross@Sun.COM p = ctx->ct_mackey; 23810023SGordon.Ross@Sun.COM memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ); 23910023SGordon.Ross@Sun.COM memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len); 24010023SGordon.Ross@Sun.COM 24110023SGordon.Ross@Sun.COM /* OK, start signing! */ 24210023SGordon.Ross@Sun.COM ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; 24310023SGordon.Ross@Sun.COM } 24410023SGordon.Ross@Sun.COM 24510023SGordon.Ross@Sun.COM err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action); 24610023SGordon.Ross@Sun.COM if (err) 24710023SGordon.Ross@Sun.COM goto out; 24810023SGordon.Ross@Sun.COM 24910023SGordon.Ross@Sun.COM DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); 25010023SGordon.Ross@Sun.COM if (ntstatus != 0) 25110023SGordon.Ross@Sun.COM err = EAUTH; 25210023SGordon.Ross@Sun.COM 25310023SGordon.Ross@Sun.COM out: 25410023SGordon.Ross@Sun.COM mb_done(&ti_mbc); 25510023SGordon.Ross@Sun.COM mb_done(&lm_mbc); 25610023SGordon.Ross@Sun.COM mb_done(&nt_mbc); 25710023SGordon.Ross@Sun.COM 25810023SGordon.Ross@Sun.COM return (err); 25910023SGordon.Ross@Sun.COM } 26010023SGordon.Ross@Sun.COM 26110023SGordon.Ross@Sun.COM int 26210023SGordon.Ross@Sun.COM smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb) 26310023SGordon.Ross@Sun.COM { 26410023SGordon.Ross@Sun.COM struct mbdata send_mb, recv_mb; 26510023SGordon.Ross@Sun.COM int err; 26610023SGordon.Ross@Sun.COM uint32_t ntstatus; 26710023SGordon.Ross@Sun.COM uint16_t action = 0; 26810023SGordon.Ross@Sun.COM 26910023SGordon.Ross@Sun.COM err = ssp_ctx_create_client(ctx, hint_mb); 27010023SGordon.Ross@Sun.COM if (err) 27110023SGordon.Ross@Sun.COM goto out; 27210023SGordon.Ross@Sun.COM 27310023SGordon.Ross@Sun.COM bzero(&send_mb, sizeof (send_mb)); 27410023SGordon.Ross@Sun.COM bzero(&recv_mb, sizeof (recv_mb)); 27510023SGordon.Ross@Sun.COM 27610023SGordon.Ross@Sun.COM /* NULL input indicates first call. */ 27710023SGordon.Ross@Sun.COM err = ssp_ctx_next_token(ctx, NULL, &send_mb); 27810023SGordon.Ross@Sun.COM if (err) 27910023SGordon.Ross@Sun.COM goto out; 28010023SGordon.Ross@Sun.COM 28110023SGordon.Ross@Sun.COM for (;;) { 28210023SGordon.Ross@Sun.COM err = smb__ssnsetup(ctx, &send_mb, &recv_mb, 28310023SGordon.Ross@Sun.COM &ntstatus, &action); 28410023SGordon.Ross@Sun.COM if (err) 28510023SGordon.Ross@Sun.COM goto out; 28610023SGordon.Ross@Sun.COM if (ntstatus == 0) 28710023SGordon.Ross@Sun.COM break; /* normal loop termination */ 28810023SGordon.Ross@Sun.COM if (ntstatus != STATUS_MORE_PROCESSING_REQUIRED) { 28910023SGordon.Ross@Sun.COM err = EAUTH; 29010023SGordon.Ross@Sun.COM break; 29110023SGordon.Ross@Sun.COM } 29210023SGordon.Ross@Sun.COM 29310023SGordon.Ross@Sun.COM /* middle calls get both in, out */ 29410023SGordon.Ross@Sun.COM err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb); 29510023SGordon.Ross@Sun.COM if (err) 29610023SGordon.Ross@Sun.COM goto out; 29710023SGordon.Ross@Sun.COM } 29810023SGordon.Ross@Sun.COM DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); 29910023SGordon.Ross@Sun.COM 30010023SGordon.Ross@Sun.COM /* NULL output indicates last call. */ 30110023SGordon.Ross@Sun.COM (void) ssp_ctx_next_token(ctx, &recv_mb, NULL); 30210023SGordon.Ross@Sun.COM 30310023SGordon.Ross@Sun.COM out: 30410023SGordon.Ross@Sun.COM ssp_ctx_destroy(ctx); 30510023SGordon.Ross@Sun.COM 30610023SGordon.Ross@Sun.COM return (err); 30710023SGordon.Ross@Sun.COM } 30810023SGordon.Ross@Sun.COM 30910023SGordon.Ross@Sun.COM /* 31010023SGordon.Ross@Sun.COM * Session Setup function used for all the forms we support. 31110023SGordon.Ross@Sun.COM * To allow this sharing, the crypto stuff is computed by 31210023SGordon.Ross@Sun.COM * callers and passed in as mbdata chains. Also, the args 31310023SGordon.Ross@Sun.COM * have different meanings for extended security vs. old. 31410023SGordon.Ross@Sun.COM * Some may be used as either IN or OUT parameters. 31510023SGordon.Ross@Sun.COM * 31610023SGordon.Ross@Sun.COM * For NTLM (v1, v2), all parameters are inputs 31710023SGordon.Ross@Sun.COM * mbc1: [in] LM password hash 31810023SGordon.Ross@Sun.COM * mbc2: [in] NT password hash 31910023SGordon.Ross@Sun.COM * For Extended security (spnego) 32010023SGordon.Ross@Sun.COM * mbc1: [in] outgoing blob data 32110023SGordon.Ross@Sun.COM * mbc2: [out] received blob data 32210023SGordon.Ross@Sun.COM * For both forms, these are optional: 32310023SGordon.Ross@Sun.COM * statusp: [out] NT status 32410023SGordon.Ross@Sun.COM * actionp: [out] Logon Action (i.e. SMB_ACT_GUEST) 32510023SGordon.Ross@Sun.COM */ 32610023SGordon.Ross@Sun.COM static int 32710023SGordon.Ross@Sun.COM smb__ssnsetup(struct smb_ctx *ctx, 32810023SGordon.Ross@Sun.COM struct mbdata *mbc1, struct mbdata *mbc2, 32910023SGordon.Ross@Sun.COM uint32_t *statusp, uint16_t *actionp) 33010023SGordon.Ross@Sun.COM { 33110023SGordon.Ross@Sun.COM static const char NativeOS[] = "Solaris"; 33210023SGordon.Ross@Sun.COM static const char LanMan[] = "NETSMB"; 33310023SGordon.Ross@Sun.COM struct smb_sopt *sv = &ctx->ct_sopt; 33410023SGordon.Ross@Sun.COM struct smb_iods *is = &ctx->ct_iods; 33510023SGordon.Ross@Sun.COM struct smb_rq *rqp = NULL; 33610023SGordon.Ross@Sun.COM struct mbdata *mbp; 33710023SGordon.Ross@Sun.COM struct mbuf *m; 33810023SGordon.Ross@Sun.COM int err, uc; 33910023SGordon.Ross@Sun.COM uint32_t caps; 34010023SGordon.Ross@Sun.COM uint16_t bc, len1, len2, sblen; 34110023SGordon.Ross@Sun.COM uint8_t wc; 34210023SGordon.Ross@Sun.COM 34310023SGordon.Ross@Sun.COM /* 34410023SGordon.Ross@Sun.COM * Some of the "capability" bits we offer will be copied 34510023SGordon.Ross@Sun.COM * from those offered by the server, with a mask applied. 34610023SGordon.Ross@Sun.COM * This is the mask of capabilies copied from the server. 34710023SGordon.Ross@Sun.COM * Some others get special handling below. 34810023SGordon.Ross@Sun.COM */ 34910023SGordon.Ross@Sun.COM static const uint32_t caps_mask = 35010023SGordon.Ross@Sun.COM SMB_CAP_UNICODE | 35110023SGordon.Ross@Sun.COM SMB_CAP_LARGE_FILES | 35210023SGordon.Ross@Sun.COM SMB_CAP_NT_SMBS | 35310023SGordon.Ross@Sun.COM SMB_CAP_STATUS32 | 35410023SGordon.Ross@Sun.COM SMB_CAP_EXT_SECURITY; 35510023SGordon.Ross@Sun.COM 35610023SGordon.Ross@Sun.COM caps = ctx->ct_sopt.sv_caps & caps_mask; 35710023SGordon.Ross@Sun.COM uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE; 35810023SGordon.Ross@Sun.COM 35910023SGordon.Ross@Sun.COM err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp); 36010023SGordon.Ross@Sun.COM if (err) 36110023SGordon.Ross@Sun.COM goto out; 36210023SGordon.Ross@Sun.COM 36310023SGordon.Ross@Sun.COM /* 36410023SGordon.Ross@Sun.COM * Build the SMB request. 36510023SGordon.Ross@Sun.COM */ 36610023SGordon.Ross@Sun.COM mbp = &rqp->rq_rq; 36710023SGordon.Ross@Sun.COM smb_rq_wstart(rqp); 36810023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */ 36910023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, 0); /* 1: AndXOffset */ 37010023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */ 37110023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */ 37210023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, 1); /* 4: VcNumber */ 37310023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */ 37410023SGordon.Ross@Sun.COM 37510023SGordon.Ross@Sun.COM if (caps & SMB_CAP_EXT_SECURITY) { 37610023SGordon.Ross@Sun.COM len1 = mbc1 ? mbc1->mb_count : 0; 37710023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, len1); /* 7: Sec. Blob Len */ 37810023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, 0); /* 8,9: reserved */ 37910023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */ 38010023SGordon.Ross@Sun.COM smb_rq_wend(rqp); /* 12: Byte Count */ 38110023SGordon.Ross@Sun.COM smb_rq_bstart(rqp); 38210023SGordon.Ross@Sun.COM if (mbc1 && mbc1->mb_top) { 38310023SGordon.Ross@Sun.COM mb_put_mbuf(mbp, mbc1->mb_top); /* sec. blob */ 38410023SGordon.Ross@Sun.COM mbc1->mb_top = NULL; /* consumed */ 38510023SGordon.Ross@Sun.COM } 38610023SGordon.Ross@Sun.COM /* mbc2 is required below */ 38710023SGordon.Ross@Sun.COM if (mbc2 == NULL) { 38810023SGordon.Ross@Sun.COM err = EINVAL; 38910023SGordon.Ross@Sun.COM goto out; 39010023SGordon.Ross@Sun.COM } 39110023SGordon.Ross@Sun.COM } else { 39210023SGordon.Ross@Sun.COM len1 = mbc1 ? mbc1->mb_count : 0; 39310023SGordon.Ross@Sun.COM len2 = mbc2 ? mbc2->mb_count : 0; 39410023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, len1); /* 7: LM pass. len */ 39510023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, len2); /* 8: NT pass. len */ 39610023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, 0); /* 9,10: reserved */ 39710023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, caps); /* 11,12: Capabilities */ 39810023SGordon.Ross@Sun.COM smb_rq_wend(rqp); /* 13: Byte Count */ 39910023SGordon.Ross@Sun.COM smb_rq_bstart(rqp); 40010023SGordon.Ross@Sun.COM if (mbc1 && mbc1->mb_top) { 40110023SGordon.Ross@Sun.COM mb_put_mbuf(mbp, mbc1->mb_top); /* LM password */ 40210023SGordon.Ross@Sun.COM mbc1->mb_top = NULL; /* consumed */ 40310023SGordon.Ross@Sun.COM } 40410023SGordon.Ross@Sun.COM if (mbc2 && mbc2->mb_top) { 40510023SGordon.Ross@Sun.COM mb_put_mbuf(mbp, mbc2->mb_top); /* NT password */ 40610023SGordon.Ross@Sun.COM mbc2->mb_top = NULL; /* consumed */ 40710023SGordon.Ross@Sun.COM } 408*11332SGordon.Ross@Sun.COM mb_put_string(mbp, ctx->ct_user, uc); 409*11332SGordon.Ross@Sun.COM mb_put_string(mbp, ctx->ct_domain, uc); 41010023SGordon.Ross@Sun.COM } 411*11332SGordon.Ross@Sun.COM mb_put_string(mbp, NativeOS, uc); 412*11332SGordon.Ross@Sun.COM mb_put_string(mbp, LanMan, uc); 41310023SGordon.Ross@Sun.COM smb_rq_bend(rqp); 41410023SGordon.Ross@Sun.COM 41510023SGordon.Ross@Sun.COM err = smb_rq_internal(ctx, rqp); 41610023SGordon.Ross@Sun.COM if (err) 41710023SGordon.Ross@Sun.COM goto out; 41810023SGordon.Ross@Sun.COM 41910023SGordon.Ross@Sun.COM if (statusp) 42010023SGordon.Ross@Sun.COM *statusp = rqp->rq_status; 42110023SGordon.Ross@Sun.COM 42210023SGordon.Ross@Sun.COM /* 42310023SGordon.Ross@Sun.COM * If we have a real error, the response probably has 42410023SGordon.Ross@Sun.COM * no more data, so don't try to parse any more. 42510023SGordon.Ross@Sun.COM * Note: err=0, means rq_status is valid. 42610023SGordon.Ross@Sun.COM */ 42710023SGordon.Ross@Sun.COM if (rqp->rq_status != 0 && 42810023SGordon.Ross@Sun.COM rqp->rq_status != STATUS_MORE_PROCESSING_REQUIRED) { 42910023SGordon.Ross@Sun.COM goto out; 43010023SGordon.Ross@Sun.COM } 43110023SGordon.Ross@Sun.COM 43210023SGordon.Ross@Sun.COM /* 43310023SGordon.Ross@Sun.COM * Parse the reply 43410023SGordon.Ross@Sun.COM */ 43510023SGordon.Ross@Sun.COM uc = rqp->rq_hflags2 & SMB_FLAGS2_UNICODE; 43610023SGordon.Ross@Sun.COM is->is_smbuid = rqp->rq_uid; 43710023SGordon.Ross@Sun.COM mbp = &rqp->rq_rp; 43810023SGordon.Ross@Sun.COM 439*11332SGordon.Ross@Sun.COM err = md_get_uint8(mbp, &wc); 44010023SGordon.Ross@Sun.COM if (err) 44110023SGordon.Ross@Sun.COM goto out; 44210023SGordon.Ross@Sun.COM 44310023SGordon.Ross@Sun.COM err = EBADRPC; /* for any problems in this section */ 44410023SGordon.Ross@Sun.COM if (caps & SMB_CAP_EXT_SECURITY) { 44510023SGordon.Ross@Sun.COM if (wc != 4) 44610023SGordon.Ross@Sun.COM goto out; 447*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, NULL); /* secondary cmd */ 448*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, NULL); /* andxoffset */ 449*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, actionp); /* action */ 450*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, &sblen); /* sec. blob len */ 451*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, &bc); /* byte count */ 45210023SGordon.Ross@Sun.COM /* 45310023SGordon.Ross@Sun.COM * Get the security blob, after 45410023SGordon.Ross@Sun.COM * sanity-checking the length. 45510023SGordon.Ross@Sun.COM */ 45610023SGordon.Ross@Sun.COM if (sblen == 0 || bc < sblen) 45710023SGordon.Ross@Sun.COM goto out; 458*11332SGordon.Ross@Sun.COM err = md_get_mbuf(mbp, sblen, &m); 45910023SGordon.Ross@Sun.COM if (err) 46010023SGordon.Ross@Sun.COM goto out; 46110023SGordon.Ross@Sun.COM mb_initm(mbc2, m); 46210023SGordon.Ross@Sun.COM mbc2->mb_count = sblen; 46310023SGordon.Ross@Sun.COM } else { 46410023SGordon.Ross@Sun.COM if (wc != 3) 46510023SGordon.Ross@Sun.COM goto out; 466*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, NULL); /* secondary cmd */ 467*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, NULL); /* andxoffset */ 468*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, actionp); /* action */ 469*11332SGordon.Ross@Sun.COM err = md_get_uint16le(mbp, &bc); /* byte count */ 47010023SGordon.Ross@Sun.COM if (err) 47110023SGordon.Ross@Sun.COM goto out; 47210023SGordon.Ross@Sun.COM } 47310023SGordon.Ross@Sun.COM 47410023SGordon.Ross@Sun.COM /* 47510023SGordon.Ross@Sun.COM * Native OS, LANMGR, & Domain follow here. 47610023SGordon.Ross@Sun.COM * Parse these strings and store for later. 47710023SGordon.Ross@Sun.COM * If unicode, they should be aligned. 47810023SGordon.Ross@Sun.COM * 47910023SGordon.Ross@Sun.COM * Note that with Extended security, we may use 48010023SGordon.Ross@Sun.COM * multiple calls to this function. Only parse 48110023SGordon.Ross@Sun.COM * these strings on the last one (status == 0). 48210023SGordon.Ross@Sun.COM * Ditto for the CAP_LARGE work-around. 48310023SGordon.Ross@Sun.COM */ 48410023SGordon.Ross@Sun.COM if (rqp->rq_status != 0) 48510023SGordon.Ross@Sun.COM goto out; 48610023SGordon.Ross@Sun.COM 48710023SGordon.Ross@Sun.COM /* Ignore any parsing errors for these strings. */ 488*11332SGordon.Ross@Sun.COM err = md_get_string(mbp, &ctx->ct_srv_OS, uc); 48910023SGordon.Ross@Sun.COM DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS); 490*11332SGordon.Ross@Sun.COM err = md_get_string(mbp, &ctx->ct_srv_LM, uc); 49110023SGordon.Ross@Sun.COM DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM); 49210023SGordon.Ross@Sun.COM /* 49310023SGordon.Ross@Sun.COM * There's sometimes a server domain folloing 49410023SGordon.Ross@Sun.COM * at this point, but we don't need it. 49510023SGordon.Ross@Sun.COM */ 49610023SGordon.Ross@Sun.COM 49710023SGordon.Ross@Sun.COM /* Success! (See Ignore any ... above) */ 49810023SGordon.Ross@Sun.COM err = 0; 49910023SGordon.Ross@Sun.COM 50010023SGordon.Ross@Sun.COM /* 50110023SGordon.Ross@Sun.COM * Windows systems don't suport CAP_LARGE_READX,WRITEX 50210023SGordon.Ross@Sun.COM * when signing is enabled, so adjust sv_caps. 50310023SGordon.Ross@Sun.COM */ 50410023SGordon.Ross@Sun.COM if (ctx->ct_srv_OS && 50510023SGordon.Ross@Sun.COM 0 == strncmp(ctx->ct_srv_OS, "Windows ", 8)) { 50610023SGordon.Ross@Sun.COM DPRINT("Server is Windows"); 50710023SGordon.Ross@Sun.COM if (ctx->ct_vcflags & SMBV_WILL_SIGN) { 50810023SGordon.Ross@Sun.COM DPRINT("disable CAP_LARGE_(r/w)"); 50910023SGordon.Ross@Sun.COM ctx->ct_sopt.sv_caps &= 51010023SGordon.Ross@Sun.COM ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX); 51110023SGordon.Ross@Sun.COM } 51210023SGordon.Ross@Sun.COM } 51310023SGordon.Ross@Sun.COM 51410023SGordon.Ross@Sun.COM out: 51510023SGordon.Ross@Sun.COM if (rqp) 51610023SGordon.Ross@Sun.COM smb_rq_done(rqp); 51710023SGordon.Ross@Sun.COM 51810023SGordon.Ross@Sun.COM return (err); 51910023SGordon.Ross@Sun.COM } 520