1*10023SGordon.Ross@Sun.COM /* 2*10023SGordon.Ross@Sun.COM * Copyright (c) 2000-2001 Boris Popov 3*10023SGordon.Ross@Sun.COM * All rights reserved. 4*10023SGordon.Ross@Sun.COM * 5*10023SGordon.Ross@Sun.COM * Redistribution and use in source and binary forms, with or without 6*10023SGordon.Ross@Sun.COM * modification, are permitted provided that the following conditions 7*10023SGordon.Ross@Sun.COM * are met: 8*10023SGordon.Ross@Sun.COM * 1. Redistributions of source code must retain the above copyright 9*10023SGordon.Ross@Sun.COM * notice, this list of conditions and the following disclaimer. 10*10023SGordon.Ross@Sun.COM * 2. Redistributions in binary form must reproduce the above copyright 11*10023SGordon.Ross@Sun.COM * notice, this list of conditions and the following disclaimer in the 12*10023SGordon.Ross@Sun.COM * documentation and/or other materials provided with the distribution. 13*10023SGordon.Ross@Sun.COM * 3. All advertising materials mentioning features or use of this software 14*10023SGordon.Ross@Sun.COM * must display the following acknowledgement: 15*10023SGordon.Ross@Sun.COM * This product includes software developed by Boris Popov. 16*10023SGordon.Ross@Sun.COM * 4. Neither the name of the author nor the names of any co-contributors 17*10023SGordon.Ross@Sun.COM * may be used to endorse or promote products derived from this software 18*10023SGordon.Ross@Sun.COM * without specific prior written permission. 19*10023SGordon.Ross@Sun.COM * 20*10023SGordon.Ross@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21*10023SGordon.Ross@Sun.COM * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22*10023SGordon.Ross@Sun.COM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23*10023SGordon.Ross@Sun.COM * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24*10023SGordon.Ross@Sun.COM * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25*10023SGordon.Ross@Sun.COM * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26*10023SGordon.Ross@Sun.COM * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27*10023SGordon.Ross@Sun.COM * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28*10023SGordon.Ross@Sun.COM * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29*10023SGordon.Ross@Sun.COM * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30*10023SGordon.Ross@Sun.COM * SUCH DAMAGE. 31*10023SGordon.Ross@Sun.COM */ 32*10023SGordon.Ross@Sun.COM 33*10023SGordon.Ross@Sun.COM /* 34*10023SGordon.Ross@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 35*10023SGordon.Ross@Sun.COM * Use is subject to license terms. 36*10023SGordon.Ross@Sun.COM */ 37*10023SGordon.Ross@Sun.COM 38*10023SGordon.Ross@Sun.COM /* 39*10023SGordon.Ross@Sun.COM * SMB Session Setup, and related. 40*10023SGordon.Ross@Sun.COM * Copied from the driver: smb_smb.c 41*10023SGordon.Ross@Sun.COM */ 42*10023SGordon.Ross@Sun.COM 43*10023SGordon.Ross@Sun.COM #include <errno.h> 44*10023SGordon.Ross@Sun.COM #include <stdio.h> 45*10023SGordon.Ross@Sun.COM #include <stdlib.h> 46*10023SGordon.Ross@Sun.COM #include <unistd.h> 47*10023SGordon.Ross@Sun.COM #include <strings.h> 48*10023SGordon.Ross@Sun.COM #include <netdb.h> 49*10023SGordon.Ross@Sun.COM #include <libintl.h> 50*10023SGordon.Ross@Sun.COM #include <xti.h> 51*10023SGordon.Ross@Sun.COM #include <assert.h> 52*10023SGordon.Ross@Sun.COM 53*10023SGordon.Ross@Sun.COM #include <sys/types.h> 54*10023SGordon.Ross@Sun.COM #include <sys/time.h> 55*10023SGordon.Ross@Sun.COM #include <sys/byteorder.h> 56*10023SGordon.Ross@Sun.COM #include <sys/socket.h> 57*10023SGordon.Ross@Sun.COM #include <sys/fcntl.h> 58*10023SGordon.Ross@Sun.COM 59*10023SGordon.Ross@Sun.COM #include <netinet/in.h> 60*10023SGordon.Ross@Sun.COM #include <netinet/tcp.h> 61*10023SGordon.Ross@Sun.COM #include <arpa/inet.h> 62*10023SGordon.Ross@Sun.COM 63*10023SGordon.Ross@Sun.COM #include <netsmb/mchain.h> 64*10023SGordon.Ross@Sun.COM #include <netsmb/netbios.h> 65*10023SGordon.Ross@Sun.COM #include <netsmb/smb_dev.h> 66*10023SGordon.Ross@Sun.COM #include <netsmb/smb.h> 67*10023SGordon.Ross@Sun.COM 68*10023SGordon.Ross@Sun.COM #include <netsmb/smb_lib.h> 69*10023SGordon.Ross@Sun.COM #include <netsmb/nb_lib.h> 70*10023SGordon.Ross@Sun.COM 71*10023SGordon.Ross@Sun.COM #include "private.h" 72*10023SGordon.Ross@Sun.COM #include "charsets.h" 73*10023SGordon.Ross@Sun.COM #include "ntlm.h" 74*10023SGordon.Ross@Sun.COM #include "smb_crypt.h" 75*10023SGordon.Ross@Sun.COM 76*10023SGordon.Ross@Sun.COM /* 77*10023SGordon.Ross@Sun.COM * When we have a _real_ ntstatus.h, eliminate this. 78*10023SGordon.Ross@Sun.COM * XXX: Current smb.h defines it without the high bits. 79*10023SGordon.Ross@Sun.COM */ 80*10023SGordon.Ross@Sun.COM #define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 81*10023SGordon.Ross@Sun.COM 82*10023SGordon.Ross@Sun.COM static int 83*10023SGordon.Ross@Sun.COM smb__ssnsetup(struct smb_ctx *ctx, 84*10023SGordon.Ross@Sun.COM struct mbdata *mbc1, struct mbdata *mbc2, 85*10023SGordon.Ross@Sun.COM uint32_t *statusp, uint16_t *actionp); 86*10023SGordon.Ross@Sun.COM 87*10023SGordon.Ross@Sun.COM /* 88*10023SGordon.Ross@Sun.COM * Session Setup: NULL session (anonymous) 89*10023SGordon.Ross@Sun.COM */ 90*10023SGordon.Ross@Sun.COM int 91*10023SGordon.Ross@Sun.COM smb_ssnsetup_null(struct smb_ctx *ctx) 92*10023SGordon.Ross@Sun.COM { 93*10023SGordon.Ross@Sun.COM int err; 94*10023SGordon.Ross@Sun.COM uint32_t ntstatus; 95*10023SGordon.Ross@Sun.COM uint16_t action = 0; 96*10023SGordon.Ross@Sun.COM 97*10023SGordon.Ross@Sun.COM if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) { 98*10023SGordon.Ross@Sun.COM /* Should not get here with... */ 99*10023SGordon.Ross@Sun.COM err = EINVAL; 100*10023SGordon.Ross@Sun.COM goto out; 101*10023SGordon.Ross@Sun.COM } 102*10023SGordon.Ross@Sun.COM 103*10023SGordon.Ross@Sun.COM err = smb__ssnsetup(ctx, NULL, NULL, &ntstatus, &action); 104*10023SGordon.Ross@Sun.COM if (err) 105*10023SGordon.Ross@Sun.COM goto out; 106*10023SGordon.Ross@Sun.COM 107*10023SGordon.Ross@Sun.COM DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); 108*10023SGordon.Ross@Sun.COM if (ntstatus != 0) 109*10023SGordon.Ross@Sun.COM err = EAUTH; 110*10023SGordon.Ross@Sun.COM 111*10023SGordon.Ross@Sun.COM out: 112*10023SGordon.Ross@Sun.COM return (err); 113*10023SGordon.Ross@Sun.COM } 114*10023SGordon.Ross@Sun.COM 115*10023SGordon.Ross@Sun.COM 116*10023SGordon.Ross@Sun.COM /* 117*10023SGordon.Ross@Sun.COM * SMB Session Setup, using NTLMv1 (and maybe LMv1) 118*10023SGordon.Ross@Sun.COM */ 119*10023SGordon.Ross@Sun.COM int 120*10023SGordon.Ross@Sun.COM smb_ssnsetup_ntlm1(struct smb_ctx *ctx) 121*10023SGordon.Ross@Sun.COM { 122*10023SGordon.Ross@Sun.COM struct mbdata lm_mbc, nt_mbc; 123*10023SGordon.Ross@Sun.COM int err; 124*10023SGordon.Ross@Sun.COM uint32_t ntstatus; 125*10023SGordon.Ross@Sun.COM uint16_t action = 0; 126*10023SGordon.Ross@Sun.COM 127*10023SGordon.Ross@Sun.COM if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) { 128*10023SGordon.Ross@Sun.COM /* Should not get here with... */ 129*10023SGordon.Ross@Sun.COM err = EINVAL; 130*10023SGordon.Ross@Sun.COM goto out; 131*10023SGordon.Ross@Sun.COM } 132*10023SGordon.Ross@Sun.COM 133*10023SGordon.Ross@Sun.COM /* Make mb_done calls at out safe. */ 134*10023SGordon.Ross@Sun.COM bzero(&lm_mbc, sizeof (lm_mbc)); 135*10023SGordon.Ross@Sun.COM bzero(&nt_mbc, sizeof (nt_mbc)); 136*10023SGordon.Ross@Sun.COM 137*10023SGordon.Ross@Sun.COM /* Put the LM,NTLM responses (as mbdata). */ 138*10023SGordon.Ross@Sun.COM err = ntlm_put_v1_responses(ctx, &lm_mbc, &nt_mbc); 139*10023SGordon.Ross@Sun.COM if (err) 140*10023SGordon.Ross@Sun.COM goto out; 141*10023SGordon.Ross@Sun.COM 142*10023SGordon.Ross@Sun.COM /* 143*10023SGordon.Ross@Sun.COM * If we negotiated signing, compute the MAC key 144*10023SGordon.Ross@Sun.COM * and start signing messages, but only on the 145*10023SGordon.Ross@Sun.COM * first non-null session login. 146*10023SGordon.Ross@Sun.COM */ 147*10023SGordon.Ross@Sun.COM if ((ctx->ct_vcflags & SMBV_WILL_SIGN) && 148*10023SGordon.Ross@Sun.COM (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) { 149*10023SGordon.Ross@Sun.COM struct mbuf *m = nt_mbc.mb_top; 150*10023SGordon.Ross@Sun.COM char *p; 151*10023SGordon.Ross@Sun.COM 152*10023SGordon.Ross@Sun.COM /* 153*10023SGordon.Ross@Sun.COM * MAC_key = concat(session_key, nt_response) 154*10023SGordon.Ross@Sun.COM */ 155*10023SGordon.Ross@Sun.COM ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len; 156*10023SGordon.Ross@Sun.COM ctx->ct_mackey = malloc(ctx->ct_mackeylen); 157*10023SGordon.Ross@Sun.COM if (ctx->ct_mackey == NULL) { 158*10023SGordon.Ross@Sun.COM ctx->ct_mackeylen = 0; 159*10023SGordon.Ross@Sun.COM err = ENOMEM; 160*10023SGordon.Ross@Sun.COM goto out; 161*10023SGordon.Ross@Sun.COM } 162*10023SGordon.Ross@Sun.COM p = ctx->ct_mackey; 163*10023SGordon.Ross@Sun.COM memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ); 164*10023SGordon.Ross@Sun.COM memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len); 165*10023SGordon.Ross@Sun.COM 166*10023SGordon.Ross@Sun.COM /* OK, start signing! */ 167*10023SGordon.Ross@Sun.COM ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; 168*10023SGordon.Ross@Sun.COM } 169*10023SGordon.Ross@Sun.COM 170*10023SGordon.Ross@Sun.COM err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action); 171*10023SGordon.Ross@Sun.COM if (err) 172*10023SGordon.Ross@Sun.COM goto out; 173*10023SGordon.Ross@Sun.COM 174*10023SGordon.Ross@Sun.COM DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); 175*10023SGordon.Ross@Sun.COM if (ntstatus != 0) 176*10023SGordon.Ross@Sun.COM err = EAUTH; 177*10023SGordon.Ross@Sun.COM 178*10023SGordon.Ross@Sun.COM out: 179*10023SGordon.Ross@Sun.COM mb_done(&lm_mbc); 180*10023SGordon.Ross@Sun.COM mb_done(&nt_mbc); 181*10023SGordon.Ross@Sun.COM 182*10023SGordon.Ross@Sun.COM return (err); 183*10023SGordon.Ross@Sun.COM } 184*10023SGordon.Ross@Sun.COM 185*10023SGordon.Ross@Sun.COM /* 186*10023SGordon.Ross@Sun.COM * SMB Session Setup, using NTLMv2 (and LMv2) 187*10023SGordon.Ross@Sun.COM */ 188*10023SGordon.Ross@Sun.COM int 189*10023SGordon.Ross@Sun.COM smb_ssnsetup_ntlm2(struct smb_ctx *ctx) 190*10023SGordon.Ross@Sun.COM { 191*10023SGordon.Ross@Sun.COM struct mbdata lm_mbc, nt_mbc, ti_mbc; 192*10023SGordon.Ross@Sun.COM int err; 193*10023SGordon.Ross@Sun.COM uint32_t ntstatus; 194*10023SGordon.Ross@Sun.COM uint16_t action = 0; 195*10023SGordon.Ross@Sun.COM 196*10023SGordon.Ross@Sun.COM if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) { 197*10023SGordon.Ross@Sun.COM /* Should not get here with... */ 198*10023SGordon.Ross@Sun.COM err = EINVAL; 199*10023SGordon.Ross@Sun.COM goto out; 200*10023SGordon.Ross@Sun.COM } 201*10023SGordon.Ross@Sun.COM 202*10023SGordon.Ross@Sun.COM /* Make mb_done calls at out safe. */ 203*10023SGordon.Ross@Sun.COM bzero(&lm_mbc, sizeof (lm_mbc)); 204*10023SGordon.Ross@Sun.COM bzero(&nt_mbc, sizeof (nt_mbc)); 205*10023SGordon.Ross@Sun.COM bzero(&ti_mbc, sizeof (ti_mbc)); 206*10023SGordon.Ross@Sun.COM 207*10023SGordon.Ross@Sun.COM /* Build the NTLMv2 "target info" blob (as mbdata) */ 208*10023SGordon.Ross@Sun.COM err = ntlm_build_target_info(ctx, NULL, &ti_mbc); 209*10023SGordon.Ross@Sun.COM if (err) 210*10023SGordon.Ross@Sun.COM goto out; 211*10023SGordon.Ross@Sun.COM 212*10023SGordon.Ross@Sun.COM /* Put the LMv2, NTLMv2 responses (as mbdata). */ 213*10023SGordon.Ross@Sun.COM err = ntlm_put_v2_responses(ctx, &ti_mbc, &lm_mbc, &nt_mbc); 214*10023SGordon.Ross@Sun.COM if (err) 215*10023SGordon.Ross@Sun.COM goto out; 216*10023SGordon.Ross@Sun.COM 217*10023SGordon.Ross@Sun.COM /* 218*10023SGordon.Ross@Sun.COM * If we negotiated signing, compute the MAC key 219*10023SGordon.Ross@Sun.COM * and start signing messages, but only on the 220*10023SGordon.Ross@Sun.COM * first non-null session login. 221*10023SGordon.Ross@Sun.COM */ 222*10023SGordon.Ross@Sun.COM if ((ctx->ct_vcflags & SMBV_WILL_SIGN) && 223*10023SGordon.Ross@Sun.COM (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) { 224*10023SGordon.Ross@Sun.COM struct mbuf *m = nt_mbc.mb_top; 225*10023SGordon.Ross@Sun.COM char *p; 226*10023SGordon.Ross@Sun.COM 227*10023SGordon.Ross@Sun.COM /* 228*10023SGordon.Ross@Sun.COM * MAC_key = concat(session_key, nt_response) 229*10023SGordon.Ross@Sun.COM */ 230*10023SGordon.Ross@Sun.COM ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len; 231*10023SGordon.Ross@Sun.COM ctx->ct_mackey = malloc(ctx->ct_mackeylen); 232*10023SGordon.Ross@Sun.COM if (ctx->ct_mackey == NULL) { 233*10023SGordon.Ross@Sun.COM ctx->ct_mackeylen = 0; 234*10023SGordon.Ross@Sun.COM err = ENOMEM; 235*10023SGordon.Ross@Sun.COM goto out; 236*10023SGordon.Ross@Sun.COM } 237*10023SGordon.Ross@Sun.COM p = ctx->ct_mackey; 238*10023SGordon.Ross@Sun.COM memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ); 239*10023SGordon.Ross@Sun.COM memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len); 240*10023SGordon.Ross@Sun.COM 241*10023SGordon.Ross@Sun.COM /* OK, start signing! */ 242*10023SGordon.Ross@Sun.COM ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; 243*10023SGordon.Ross@Sun.COM } 244*10023SGordon.Ross@Sun.COM 245*10023SGordon.Ross@Sun.COM err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action); 246*10023SGordon.Ross@Sun.COM if (err) 247*10023SGordon.Ross@Sun.COM goto out; 248*10023SGordon.Ross@Sun.COM 249*10023SGordon.Ross@Sun.COM DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); 250*10023SGordon.Ross@Sun.COM if (ntstatus != 0) 251*10023SGordon.Ross@Sun.COM err = EAUTH; 252*10023SGordon.Ross@Sun.COM 253*10023SGordon.Ross@Sun.COM out: 254*10023SGordon.Ross@Sun.COM mb_done(&ti_mbc); 255*10023SGordon.Ross@Sun.COM mb_done(&lm_mbc); 256*10023SGordon.Ross@Sun.COM mb_done(&nt_mbc); 257*10023SGordon.Ross@Sun.COM 258*10023SGordon.Ross@Sun.COM return (err); 259*10023SGordon.Ross@Sun.COM } 260*10023SGordon.Ross@Sun.COM 261*10023SGordon.Ross@Sun.COM int 262*10023SGordon.Ross@Sun.COM smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb) 263*10023SGordon.Ross@Sun.COM { 264*10023SGordon.Ross@Sun.COM struct mbdata send_mb, recv_mb; 265*10023SGordon.Ross@Sun.COM int err; 266*10023SGordon.Ross@Sun.COM uint32_t ntstatus; 267*10023SGordon.Ross@Sun.COM uint16_t action = 0; 268*10023SGordon.Ross@Sun.COM 269*10023SGordon.Ross@Sun.COM err = ssp_ctx_create_client(ctx, hint_mb); 270*10023SGordon.Ross@Sun.COM if (err) 271*10023SGordon.Ross@Sun.COM goto out; 272*10023SGordon.Ross@Sun.COM 273*10023SGordon.Ross@Sun.COM bzero(&send_mb, sizeof (send_mb)); 274*10023SGordon.Ross@Sun.COM bzero(&recv_mb, sizeof (recv_mb)); 275*10023SGordon.Ross@Sun.COM 276*10023SGordon.Ross@Sun.COM /* NULL input indicates first call. */ 277*10023SGordon.Ross@Sun.COM err = ssp_ctx_next_token(ctx, NULL, &send_mb); 278*10023SGordon.Ross@Sun.COM if (err) 279*10023SGordon.Ross@Sun.COM goto out; 280*10023SGordon.Ross@Sun.COM 281*10023SGordon.Ross@Sun.COM for (;;) { 282*10023SGordon.Ross@Sun.COM err = smb__ssnsetup(ctx, &send_mb, &recv_mb, 283*10023SGordon.Ross@Sun.COM &ntstatus, &action); 284*10023SGordon.Ross@Sun.COM if (err) 285*10023SGordon.Ross@Sun.COM goto out; 286*10023SGordon.Ross@Sun.COM if (ntstatus == 0) 287*10023SGordon.Ross@Sun.COM break; /* normal loop termination */ 288*10023SGordon.Ross@Sun.COM if (ntstatus != STATUS_MORE_PROCESSING_REQUIRED) { 289*10023SGordon.Ross@Sun.COM err = EAUTH; 290*10023SGordon.Ross@Sun.COM break; 291*10023SGordon.Ross@Sun.COM } 292*10023SGordon.Ross@Sun.COM 293*10023SGordon.Ross@Sun.COM /* middle calls get both in, out */ 294*10023SGordon.Ross@Sun.COM err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb); 295*10023SGordon.Ross@Sun.COM if (err) 296*10023SGordon.Ross@Sun.COM goto out; 297*10023SGordon.Ross@Sun.COM } 298*10023SGordon.Ross@Sun.COM DPRINT("status 0x%x action 0x%x", ntstatus, (int)action); 299*10023SGordon.Ross@Sun.COM 300*10023SGordon.Ross@Sun.COM /* NULL output indicates last call. */ 301*10023SGordon.Ross@Sun.COM (void) ssp_ctx_next_token(ctx, &recv_mb, NULL); 302*10023SGordon.Ross@Sun.COM 303*10023SGordon.Ross@Sun.COM out: 304*10023SGordon.Ross@Sun.COM ssp_ctx_destroy(ctx); 305*10023SGordon.Ross@Sun.COM 306*10023SGordon.Ross@Sun.COM return (err); 307*10023SGordon.Ross@Sun.COM } 308*10023SGordon.Ross@Sun.COM 309*10023SGordon.Ross@Sun.COM /* 310*10023SGordon.Ross@Sun.COM * Session Setup function used for all the forms we support. 311*10023SGordon.Ross@Sun.COM * To allow this sharing, the crypto stuff is computed by 312*10023SGordon.Ross@Sun.COM * callers and passed in as mbdata chains. Also, the args 313*10023SGordon.Ross@Sun.COM * have different meanings for extended security vs. old. 314*10023SGordon.Ross@Sun.COM * Some may be used as either IN or OUT parameters. 315*10023SGordon.Ross@Sun.COM * 316*10023SGordon.Ross@Sun.COM * For NTLM (v1, v2), all parameters are inputs 317*10023SGordon.Ross@Sun.COM * mbc1: [in] LM password hash 318*10023SGordon.Ross@Sun.COM * mbc2: [in] NT password hash 319*10023SGordon.Ross@Sun.COM * For Extended security (spnego) 320*10023SGordon.Ross@Sun.COM * mbc1: [in] outgoing blob data 321*10023SGordon.Ross@Sun.COM * mbc2: [out] received blob data 322*10023SGordon.Ross@Sun.COM * For both forms, these are optional: 323*10023SGordon.Ross@Sun.COM * statusp: [out] NT status 324*10023SGordon.Ross@Sun.COM * actionp: [out] Logon Action (i.e. SMB_ACT_GUEST) 325*10023SGordon.Ross@Sun.COM */ 326*10023SGordon.Ross@Sun.COM static int 327*10023SGordon.Ross@Sun.COM smb__ssnsetup(struct smb_ctx *ctx, 328*10023SGordon.Ross@Sun.COM struct mbdata *mbc1, struct mbdata *mbc2, 329*10023SGordon.Ross@Sun.COM uint32_t *statusp, uint16_t *actionp) 330*10023SGordon.Ross@Sun.COM { 331*10023SGordon.Ross@Sun.COM static const char NativeOS[] = "Solaris"; 332*10023SGordon.Ross@Sun.COM static const char LanMan[] = "NETSMB"; 333*10023SGordon.Ross@Sun.COM struct smb_sopt *sv = &ctx->ct_sopt; 334*10023SGordon.Ross@Sun.COM struct smb_iods *is = &ctx->ct_iods; 335*10023SGordon.Ross@Sun.COM struct smb_rq *rqp = NULL; 336*10023SGordon.Ross@Sun.COM struct mbdata *mbp; 337*10023SGordon.Ross@Sun.COM struct mbuf *m; 338*10023SGordon.Ross@Sun.COM int err, uc; 339*10023SGordon.Ross@Sun.COM uint32_t caps; 340*10023SGordon.Ross@Sun.COM uint16_t bc, len1, len2, sblen; 341*10023SGordon.Ross@Sun.COM uint8_t wc; 342*10023SGordon.Ross@Sun.COM 343*10023SGordon.Ross@Sun.COM /* 344*10023SGordon.Ross@Sun.COM * Some of the "capability" bits we offer will be copied 345*10023SGordon.Ross@Sun.COM * from those offered by the server, with a mask applied. 346*10023SGordon.Ross@Sun.COM * This is the mask of capabilies copied from the server. 347*10023SGordon.Ross@Sun.COM * Some others get special handling below. 348*10023SGordon.Ross@Sun.COM */ 349*10023SGordon.Ross@Sun.COM static const uint32_t caps_mask = 350*10023SGordon.Ross@Sun.COM SMB_CAP_UNICODE | 351*10023SGordon.Ross@Sun.COM SMB_CAP_LARGE_FILES | 352*10023SGordon.Ross@Sun.COM SMB_CAP_NT_SMBS | 353*10023SGordon.Ross@Sun.COM SMB_CAP_STATUS32 | 354*10023SGordon.Ross@Sun.COM SMB_CAP_EXT_SECURITY; 355*10023SGordon.Ross@Sun.COM 356*10023SGordon.Ross@Sun.COM caps = ctx->ct_sopt.sv_caps & caps_mask; 357*10023SGordon.Ross@Sun.COM uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE; 358*10023SGordon.Ross@Sun.COM 359*10023SGordon.Ross@Sun.COM err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp); 360*10023SGordon.Ross@Sun.COM if (err) 361*10023SGordon.Ross@Sun.COM goto out; 362*10023SGordon.Ross@Sun.COM 363*10023SGordon.Ross@Sun.COM /* 364*10023SGordon.Ross@Sun.COM * Build the SMB request. 365*10023SGordon.Ross@Sun.COM */ 366*10023SGordon.Ross@Sun.COM mbp = &rqp->rq_rq; 367*10023SGordon.Ross@Sun.COM smb_rq_wstart(rqp); 368*10023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, 0xff); /* 0: AndXCommand */ 369*10023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, 0); /* 1: AndXOffset */ 370*10023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, sv->sv_maxtx); /* 2: MaxBufferSize */ 371*10023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */ 372*10023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, 1); /* 4: VcNumber */ 373*10023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, sv->sv_skey); /* 5,6: Session Key */ 374*10023SGordon.Ross@Sun.COM 375*10023SGordon.Ross@Sun.COM if (caps & SMB_CAP_EXT_SECURITY) { 376*10023SGordon.Ross@Sun.COM len1 = mbc1 ? mbc1->mb_count : 0; 377*10023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, len1); /* 7: Sec. Blob Len */ 378*10023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, 0); /* 8,9: reserved */ 379*10023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, caps); /* 10,11: Capabilities */ 380*10023SGordon.Ross@Sun.COM smb_rq_wend(rqp); /* 12: Byte Count */ 381*10023SGordon.Ross@Sun.COM smb_rq_bstart(rqp); 382*10023SGordon.Ross@Sun.COM if (mbc1 && mbc1->mb_top) { 383*10023SGordon.Ross@Sun.COM mb_put_mbuf(mbp, mbc1->mb_top); /* sec. blob */ 384*10023SGordon.Ross@Sun.COM mbc1->mb_top = NULL; /* consumed */ 385*10023SGordon.Ross@Sun.COM } 386*10023SGordon.Ross@Sun.COM /* mbc2 is required below */ 387*10023SGordon.Ross@Sun.COM if (mbc2 == NULL) { 388*10023SGordon.Ross@Sun.COM err = EINVAL; 389*10023SGordon.Ross@Sun.COM goto out; 390*10023SGordon.Ross@Sun.COM } 391*10023SGordon.Ross@Sun.COM } else { 392*10023SGordon.Ross@Sun.COM len1 = mbc1 ? mbc1->mb_count : 0; 393*10023SGordon.Ross@Sun.COM len2 = mbc2 ? mbc2->mb_count : 0; 394*10023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, len1); /* 7: LM pass. len */ 395*10023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, len2); /* 8: NT pass. len */ 396*10023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, 0); /* 9,10: reserved */ 397*10023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, caps); /* 11,12: Capabilities */ 398*10023SGordon.Ross@Sun.COM smb_rq_wend(rqp); /* 13: Byte Count */ 399*10023SGordon.Ross@Sun.COM smb_rq_bstart(rqp); 400*10023SGordon.Ross@Sun.COM if (mbc1 && mbc1->mb_top) { 401*10023SGordon.Ross@Sun.COM mb_put_mbuf(mbp, mbc1->mb_top); /* LM password */ 402*10023SGordon.Ross@Sun.COM mbc1->mb_top = NULL; /* consumed */ 403*10023SGordon.Ross@Sun.COM } 404*10023SGordon.Ross@Sun.COM if (mbc2 && mbc2->mb_top) { 405*10023SGordon.Ross@Sun.COM mb_put_mbuf(mbp, mbc2->mb_top); /* NT password */ 406*10023SGordon.Ross@Sun.COM mbc2->mb_top = NULL; /* consumed */ 407*10023SGordon.Ross@Sun.COM } 408*10023SGordon.Ross@Sun.COM mb_put_dstring(mbp, ctx->ct_user, uc); 409*10023SGordon.Ross@Sun.COM mb_put_dstring(mbp, ctx->ct_domain, uc); 410*10023SGordon.Ross@Sun.COM } 411*10023SGordon.Ross@Sun.COM mb_put_dstring(mbp, NativeOS, uc); 412*10023SGordon.Ross@Sun.COM mb_put_dstring(mbp, LanMan, uc); 413*10023SGordon.Ross@Sun.COM smb_rq_bend(rqp); 414*10023SGordon.Ross@Sun.COM 415*10023SGordon.Ross@Sun.COM err = smb_rq_internal(ctx, rqp); 416*10023SGordon.Ross@Sun.COM if (err) 417*10023SGordon.Ross@Sun.COM goto out; 418*10023SGordon.Ross@Sun.COM 419*10023SGordon.Ross@Sun.COM if (statusp) 420*10023SGordon.Ross@Sun.COM *statusp = rqp->rq_status; 421*10023SGordon.Ross@Sun.COM 422*10023SGordon.Ross@Sun.COM /* 423*10023SGordon.Ross@Sun.COM * If we have a real error, the response probably has 424*10023SGordon.Ross@Sun.COM * no more data, so don't try to parse any more. 425*10023SGordon.Ross@Sun.COM * Note: err=0, means rq_status is valid. 426*10023SGordon.Ross@Sun.COM */ 427*10023SGordon.Ross@Sun.COM if (rqp->rq_status != 0 && 428*10023SGordon.Ross@Sun.COM rqp->rq_status != STATUS_MORE_PROCESSING_REQUIRED) { 429*10023SGordon.Ross@Sun.COM goto out; 430*10023SGordon.Ross@Sun.COM } 431*10023SGordon.Ross@Sun.COM 432*10023SGordon.Ross@Sun.COM /* 433*10023SGordon.Ross@Sun.COM * Parse the reply 434*10023SGordon.Ross@Sun.COM */ 435*10023SGordon.Ross@Sun.COM uc = rqp->rq_hflags2 & SMB_FLAGS2_UNICODE; 436*10023SGordon.Ross@Sun.COM is->is_smbuid = rqp->rq_uid; 437*10023SGordon.Ross@Sun.COM mbp = &rqp->rq_rp; 438*10023SGordon.Ross@Sun.COM 439*10023SGordon.Ross@Sun.COM err = mb_get_uint8(mbp, &wc); 440*10023SGordon.Ross@Sun.COM if (err) 441*10023SGordon.Ross@Sun.COM goto out; 442*10023SGordon.Ross@Sun.COM 443*10023SGordon.Ross@Sun.COM err = EBADRPC; /* for any problems in this section */ 444*10023SGordon.Ross@Sun.COM if (caps & SMB_CAP_EXT_SECURITY) { 445*10023SGordon.Ross@Sun.COM if (wc != 4) 446*10023SGordon.Ross@Sun.COM goto out; 447*10023SGordon.Ross@Sun.COM mb_get_uint16le(mbp, NULL); /* secondary cmd */ 448*10023SGordon.Ross@Sun.COM mb_get_uint16le(mbp, NULL); /* andxoffset */ 449*10023SGordon.Ross@Sun.COM mb_get_uint16le(mbp, actionp); /* action */ 450*10023SGordon.Ross@Sun.COM mb_get_uint16le(mbp, &sblen); /* sec. blob len */ 451*10023SGordon.Ross@Sun.COM mb_get_uint16le(mbp, &bc); /* byte count */ 452*10023SGordon.Ross@Sun.COM /* 453*10023SGordon.Ross@Sun.COM * Get the security blob, after 454*10023SGordon.Ross@Sun.COM * sanity-checking the length. 455*10023SGordon.Ross@Sun.COM */ 456*10023SGordon.Ross@Sun.COM if (sblen == 0 || bc < sblen) 457*10023SGordon.Ross@Sun.COM goto out; 458*10023SGordon.Ross@Sun.COM err = mb_get_mbuf(mbp, sblen, &m); 459*10023SGordon.Ross@Sun.COM if (err) 460*10023SGordon.Ross@Sun.COM goto out; 461*10023SGordon.Ross@Sun.COM mb_initm(mbc2, m); 462*10023SGordon.Ross@Sun.COM mbc2->mb_count = sblen; 463*10023SGordon.Ross@Sun.COM } else { 464*10023SGordon.Ross@Sun.COM if (wc != 3) 465*10023SGordon.Ross@Sun.COM goto out; 466*10023SGordon.Ross@Sun.COM mb_get_uint16le(mbp, NULL); /* secondary cmd */ 467*10023SGordon.Ross@Sun.COM mb_get_uint16le(mbp, NULL); /* andxoffset */ 468*10023SGordon.Ross@Sun.COM mb_get_uint16le(mbp, actionp); /* action */ 469*10023SGordon.Ross@Sun.COM err = mb_get_uint16le(mbp, &bc); /* byte count */ 470*10023SGordon.Ross@Sun.COM if (err) 471*10023SGordon.Ross@Sun.COM goto out; 472*10023SGordon.Ross@Sun.COM } 473*10023SGordon.Ross@Sun.COM 474*10023SGordon.Ross@Sun.COM /* 475*10023SGordon.Ross@Sun.COM * Native OS, LANMGR, & Domain follow here. 476*10023SGordon.Ross@Sun.COM * Parse these strings and store for later. 477*10023SGordon.Ross@Sun.COM * If unicode, they should be aligned. 478*10023SGordon.Ross@Sun.COM * 479*10023SGordon.Ross@Sun.COM * Note that with Extended security, we may use 480*10023SGordon.Ross@Sun.COM * multiple calls to this function. Only parse 481*10023SGordon.Ross@Sun.COM * these strings on the last one (status == 0). 482*10023SGordon.Ross@Sun.COM * Ditto for the CAP_LARGE work-around. 483*10023SGordon.Ross@Sun.COM */ 484*10023SGordon.Ross@Sun.COM if (rqp->rq_status != 0) 485*10023SGordon.Ross@Sun.COM goto out; 486*10023SGordon.Ross@Sun.COM 487*10023SGordon.Ross@Sun.COM /* Ignore any parsing errors for these strings. */ 488*10023SGordon.Ross@Sun.COM err = mb_get_string(mbp, &ctx->ct_srv_OS, uc); 489*10023SGordon.Ross@Sun.COM DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS); 490*10023SGordon.Ross@Sun.COM err = mb_get_string(mbp, &ctx->ct_srv_LM, uc); 491*10023SGordon.Ross@Sun.COM DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM); 492*10023SGordon.Ross@Sun.COM /* 493*10023SGordon.Ross@Sun.COM * There's sometimes a server domain folloing 494*10023SGordon.Ross@Sun.COM * at this point, but we don't need it. 495*10023SGordon.Ross@Sun.COM */ 496*10023SGordon.Ross@Sun.COM 497*10023SGordon.Ross@Sun.COM /* Success! (See Ignore any ... above) */ 498*10023SGordon.Ross@Sun.COM err = 0; 499*10023SGordon.Ross@Sun.COM 500*10023SGordon.Ross@Sun.COM /* 501*10023SGordon.Ross@Sun.COM * Windows systems don't suport CAP_LARGE_READX,WRITEX 502*10023SGordon.Ross@Sun.COM * when signing is enabled, so adjust sv_caps. 503*10023SGordon.Ross@Sun.COM */ 504*10023SGordon.Ross@Sun.COM if (ctx->ct_srv_OS && 505*10023SGordon.Ross@Sun.COM 0 == strncmp(ctx->ct_srv_OS, "Windows ", 8)) { 506*10023SGordon.Ross@Sun.COM DPRINT("Server is Windows"); 507*10023SGordon.Ross@Sun.COM if (ctx->ct_vcflags & SMBV_WILL_SIGN) { 508*10023SGordon.Ross@Sun.COM DPRINT("disable CAP_LARGE_(r/w)"); 509*10023SGordon.Ross@Sun.COM ctx->ct_sopt.sv_caps &= 510*10023SGordon.Ross@Sun.COM ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX); 511*10023SGordon.Ross@Sun.COM } 512*10023SGordon.Ross@Sun.COM } 513*10023SGordon.Ross@Sun.COM 514*10023SGordon.Ross@Sun.COM out: 515*10023SGordon.Ross@Sun.COM if (rqp) 516*10023SGordon.Ross@Sun.COM smb_rq_done(rqp); 517*10023SGordon.Ross@Sun.COM 518*10023SGordon.Ross@Sun.COM return (err); 519*10023SGordon.Ross@Sun.COM } 520