1139823Simp/*- 275374Sbp * Copyright (c) 2000-2001 Boris Popov 375374Sbp * All rights reserved. 475374Sbp * 575374Sbp * Redistribution and use in source and binary forms, with or without 675374Sbp * modification, are permitted provided that the following conditions 775374Sbp * are met: 875374Sbp * 1. Redistributions of source code must retain the above copyright 975374Sbp * notice, this list of conditions and the following disclaimer. 1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright 1175374Sbp * notice, this list of conditions and the following disclaimer in the 1275374Sbp * documentation and/or other materials provided with the distribution. 1375374Sbp * 1475374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1575374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1675374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1775374Sbp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1875374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1975374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2075374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2175374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2275374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2375374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2475374Sbp * SUCH DAMAGE. 2575374Sbp */ 26116189Sobrien 2775374Sbp/* 2875374Sbp * various SMB requests. Most of the routines merely packs data into mbufs. 2975374Sbp */ 30116189Sobrien 31116189Sobrien#include <sys/cdefs.h> 32116189Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/netsmb/smb_smb.c 298375 2016-04-20 21:13:24Z pfg $"); 33116189Sobrien 3475374Sbp#include <sys/param.h> 3575374Sbp#include <sys/systm.h> 3675374Sbp#include <sys/kernel.h> 3775374Sbp#include <sys/malloc.h> 3875374Sbp#include <sys/proc.h> 3975374Sbp#include <sys/lock.h> 4075374Sbp#include <sys/sysctl.h> 4175374Sbp#include <sys/socket.h> 4275374Sbp#include <sys/uio.h> 4375374Sbp 4475374Sbp#include <sys/iconv.h> 4575374Sbp 4675374Sbp#include <netsmb/smb.h> 4775374Sbp#include <netsmb/smb_subr.h> 4875374Sbp#include <netsmb/smb_rq.h> 4975374Sbp#include <netsmb/smb_conn.h> 5075374Sbp#include <netsmb/smb_tran.h> 5175374Sbp 52124087Stjr#include "opt_netsmb.h" 53124087Stjr 5475374Sbpstruct smb_dialect { 5575374Sbp int d_id; 5675374Sbp const char * d_name; 5775374Sbp}; 5875374Sbp 5975374Sbpstatic struct smb_dialect smb_dialects[] = { 6075374Sbp {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"}, 6175374Sbp {SMB_DIALECT_COREPLUS, "MICROSOFT NETWORKS 1.03"}, 6275374Sbp {SMB_DIALECT_LANMAN1_0, "MICROSOFT NETWORKS 3.0"}, 6375374Sbp {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"}, 6475374Sbp {SMB_DIALECT_LANMAN2_0, "LM1.2X002"}, 6575374Sbp {SMB_DIALECT_LANMAN2_0, "Samba"}, 6675374Sbp {SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"}, 6775374Sbp {SMB_DIALECT_NTLM0_12, "NT LM 0.12"}, 6875374Sbp {-1, NULL} 6975374Sbp}; 7075374Sbp 71103395Sbpstatic u_int32_t 72103395Sbpsmb_vc_maxread(struct smb_vc *vcp) 73103395Sbp{ 74103395Sbp /* 75103395Sbp * Specs say up to 64k data bytes, but Windows traffic 76103395Sbp * uses 60k... no doubt for some good reason. 77124087Stjr * 78124087Stjr * Don't exceed the server's buffer size if signatures 79124087Stjr * are enabled otherwise Windows 2003 chokes. Allow space 80124087Stjr * for the SMB header & a little bit extra. 81103395Sbp */ 82124087Stjr if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) && 83124087Stjr (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) 84103395Sbp return (60*1024); 85103395Sbp else 86124087Stjr return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64); 87103395Sbp} 88103395Sbp 89103395Sbpstatic u_int32_t 90103395Sbpsmb_vc_maxwrite(struct smb_vc *vcp) 91103395Sbp{ 92103395Sbp /* 93124087Stjr * See comment above. 94103395Sbp */ 95124087Stjr if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) && 96124087Stjr (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) 97103395Sbp return (60*1024); 98103395Sbp else 99124087Stjr return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64); 100103395Sbp} 101103395Sbp 10275374Sbpstatic int 10375374Sbpsmb_smb_nomux(struct smb_vc *vcp, struct smb_cred *scred, const char *name) 10475374Sbp{ 10587192Sbp if (scred->scr_td->td_proc == vcp->vc_iod->iod_p) 10675374Sbp return 0; 10775374Sbp SMBERROR("wrong function called(%s)\n", name); 10875374Sbp return EINVAL; 10975374Sbp} 11075374Sbp 11175374Sbpint 11275374Sbpsmb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) 11375374Sbp{ 11475374Sbp struct smb_dialect *dp; 11575374Sbp struct smb_sopt *sp = NULL; 11675374Sbp struct smb_rq *rqp; 11775374Sbp struct mbchain *mbp; 11875374Sbp struct mdchain *mdp; 11975374Sbp u_int8_t wc, stime[8], sblen; 12075374Sbp u_int16_t dindex, tw, tw1, swlen, bc; 12175374Sbp int error, maxqsz; 122227650Skevlo int unicode = SMB_UNICODE_STRINGS(vcp); 123227650Skevlo void * servercharset = vcp->vc_toserver; 124227650Skevlo void * localcharset = vcp->vc_tolocal; 12575374Sbp 12687599Sobrien if (smb_smb_nomux(vcp, scred, __func__) != 0) 12775374Sbp return EINVAL; 128227650Skevlo /* Disable Unicode for SMB_COM_NEGOTIATE requests */ 129227650Skevlo if (unicode) { 130227650Skevlo vcp->vc_toserver = vcp->vc_cp_toserver; 131227650Skevlo vcp->vc_tolocal = vcp->vc_cp_tolocal; 132227650Skevlo } 13375374Sbp vcp->vc_hflags = 0; 13475374Sbp vcp->vc_hflags2 = 0; 13575374Sbp vcp->obj.co_flags &= ~(SMBV_ENCRYPT); 13675374Sbp sp = &vcp->vc_sopt; 13775374Sbp bzero(sp, sizeof(struct smb_sopt)); 13875374Sbp error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp); 13975374Sbp if (error) 14075374Sbp return error; 14175374Sbp smb_rq_getrequest(rqp, &mbp); 14275374Sbp smb_rq_wstart(rqp); 14375374Sbp smb_rq_wend(rqp); 14475374Sbp smb_rq_bstart(rqp); 14575374Sbp for(dp = smb_dialects; dp->d_id != -1; dp++) { 14675374Sbp mb_put_uint8(mbp, SMB_DT_DIALECT); 14775374Sbp smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE); 14875374Sbp } 14975374Sbp smb_rq_bend(rqp); 15075374Sbp error = smb_rq_simple(rqp); 15175374Sbp SMBSDEBUG("%d\n", error); 15275374Sbp if (error) 15375374Sbp goto bad; 15475374Sbp smb_rq_getreply(rqp, &mdp); 15575374Sbp do { 15675374Sbp error = md_get_uint8(mdp, &wc); 15775374Sbp if (error) 15875374Sbp break; 15975374Sbp error = md_get_uint16le(mdp, &dindex); 16075374Sbp if (error) 16175374Sbp break; 16275374Sbp if (dindex > 7) { 16375374Sbp SMBERROR("Don't know how to talk with server %s (%d)\n", "xxx", dindex); 16475374Sbp error = EBADRPC; 16575374Sbp break; 16675374Sbp } 16775374Sbp dp = smb_dialects + dindex; 16875374Sbp sp->sv_proto = dp->d_id; 16975374Sbp SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc); 17075374Sbp error = EBADRPC; 17175374Sbp if (dp->d_id >= SMB_DIALECT_NTLM0_12) { 17275374Sbp if (wc != 17) 17375374Sbp break; 17475374Sbp md_get_uint8(mdp, &sp->sv_sm); 17575374Sbp md_get_uint16le(mdp, &sp->sv_maxmux); 17675374Sbp md_get_uint16le(mdp, &sp->sv_maxvcs); 17775374Sbp md_get_uint32le(mdp, &sp->sv_maxtx); 17875374Sbp md_get_uint32le(mdp, &sp->sv_maxraw); 17975374Sbp md_get_uint32le(mdp, &sp->sv_skey); 18075374Sbp md_get_uint32le(mdp, &sp->sv_caps); 18175374Sbp md_get_mem(mdp, stime, 8, MB_MSYSTEM); 18275374Sbp md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); 18375374Sbp md_get_uint8(mdp, &sblen); 18475374Sbp if (sblen && (sp->sv_sm & SMB_SM_ENCRYPT)) { 18575374Sbp if (sblen != SMB_MAXCHALLENGELEN) { 18675374Sbp SMBERROR("Unexpected length of security blob (%d)\n", sblen); 18775374Sbp break; 18875374Sbp } 189227650Skevlo error = md_get_uint16le(mdp, &bc); 19075374Sbp if (error) 19175374Sbp break; 19275374Sbp if (sp->sv_caps & SMB_CAP_EXT_SECURITY) 19375374Sbp md_get_mem(mdp, NULL, 16, MB_MSYSTEM); 19475374Sbp error = md_get_mem(mdp, vcp->vc_ch, sblen, MB_MSYSTEM); 19575374Sbp if (error) 19675374Sbp break; 19775374Sbp vcp->vc_chlen = sblen; 19875374Sbp vcp->obj.co_flags |= SMBV_ENCRYPT; 19975374Sbp } 200124087Stjr if (sp->sv_sm & SMB_SM_SIGS_REQUIRE) 201124087Stjr vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; 202227650Skevlo if (vcp->vc_ucs_toserver && 203227650Skevlo sp->sv_caps & SMB_CAP_UNICODE) { 204227650Skevlo /* 205227650Skevlo * They do Unicode. 206227650Skevlo */ 207227650Skevlo vcp->obj.co_flags |= SMBV_UNICODE; 208227650Skevlo } 20975374Sbp vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; 21075374Sbp if (dp->d_id == SMB_DIALECT_NTLM0_12 && 21175374Sbp sp->sv_maxtx < 4096 && 21275374Sbp (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) { 21375374Sbp vcp->obj.co_flags |= SMBV_WIN95; 21475374Sbp SMBSDEBUG("Win95 detected\n"); 21575374Sbp } 216227650Skevlo error = 0; 217227650Skevlo break; 218227650Skevlo } 219227650Skevlo vcp->vc_hflags2 &= ~(SMB_FLAGS2_EXT_SEC|SMB_FLAGS2_DFS| 220227650Skevlo SMB_FLAGS2_ERR_STATUS|SMB_FLAGS2_UNICODE); 221227650Skevlo unicode = 0; 222227650Skevlo if (dp->d_id > SMB_DIALECT_CORE) { 22375374Sbp md_get_uint16le(mdp, &tw); 22475374Sbp sp->sv_sm = tw; 22575374Sbp md_get_uint16le(mdp, &tw); 22675374Sbp sp->sv_maxtx = tw; 22775374Sbp md_get_uint16le(mdp, &sp->sv_maxmux); 22875374Sbp md_get_uint16le(mdp, &sp->sv_maxvcs); 22975374Sbp md_get_uint16le(mdp, &tw); /* rawmode */ 23075374Sbp md_get_uint32le(mdp, &sp->sv_skey); 23175374Sbp if (wc == 13) { /* >= LANMAN1 */ 23275374Sbp md_get_uint16(mdp, &tw); /* time */ 23375374Sbp md_get_uint16(mdp, &tw1); /* date */ 23475374Sbp md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); 23575374Sbp md_get_uint16le(mdp, &swlen); 23675374Sbp if (swlen > SMB_MAXCHALLENGELEN) 23775374Sbp break; 23875374Sbp md_get_uint16(mdp, NULL); /* mbz */ 239227650Skevlo if (md_get_uint16le(mdp, &bc) != 0) 24075374Sbp break; 24175374Sbp if (bc < swlen) 24275374Sbp break; 24375374Sbp if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) { 24475374Sbp error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM); 24575374Sbp if (error) 24675374Sbp break; 24775374Sbp vcp->vc_chlen = swlen; 24875374Sbp vcp->obj.co_flags |= SMBV_ENCRYPT; 24975374Sbp } 25075374Sbp } 25175374Sbp vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; 25275374Sbp } else { /* an old CORE protocol */ 25375374Sbp sp->sv_maxmux = 1; 25475374Sbp } 25575374Sbp error = 0; 25675374Sbp } while (0); 25775374Sbp if (error == 0) { 25875374Sbp vcp->vc_maxvcs = sp->sv_maxvcs; 25975374Sbp if (vcp->vc_maxvcs <= 1) { 26075374Sbp if (vcp->vc_maxvcs == 0) 26175374Sbp vcp->vc_maxvcs = 1; 26275374Sbp } 26375374Sbp if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff) 26475374Sbp sp->sv_maxtx = 1024; 265103395Sbp else 266103395Sbp sp->sv_maxtx = min(sp->sv_maxtx, 267103395Sbp 63*1024 + SMB_HDRLEN + 16); 268103395Sbp SMB_TRAN_GETPARAM(vcp, SMBTP_RCVSZ, &maxqsz); 269103395Sbp vcp->vc_rxmax = min(smb_vc_maxread(vcp), maxqsz - 1024); 27075374Sbp SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz); 271103395Sbp vcp->vc_wxmax = min(smb_vc_maxwrite(vcp), maxqsz - 1024); 27275374Sbp vcp->vc_txmax = min(sp->sv_maxtx, maxqsz); 27375374Sbp SMBSDEBUG("TZ = %d\n", sp->sv_tz); 27475374Sbp SMBSDEBUG("CAPS = %x\n", sp->sv_caps); 27575374Sbp SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux); 27675374Sbp SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs); 27775374Sbp SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw); 27875374Sbp SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx); 27975374Sbp } 28075374Sbpbad: 281227650Skevlo /* Restore Unicode conversion state */ 282227650Skevlo if (unicode) { 283227650Skevlo vcp->vc_toserver = servercharset; 284227650Skevlo vcp->vc_tolocal = localcharset; 285227650Skevlo vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE; 286227650Skevlo } 28775374Sbp smb_rq_done(rqp); 28875374Sbp return error; 28975374Sbp} 29075374Sbp 29175374Sbpint 29275374Sbpsmb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) 29375374Sbp{ 29475374Sbp struct smb_rq *rqp; 29575374Sbp struct mbchain *mbp; 29675374Sbp/* u_int8_t wc; 29775374Sbp u_int16_t tw, tw1;*/ 29875374Sbp smb_uniptr unipp, ntencpass = NULL; 29975374Sbp char *pp, *up, *pbuf, *encpass; 300103396Sbp int error, plen, uniplen, ulen, upper; 301227650Skevlo u_int32_t caps = 0; 30275374Sbp 303103396Sbp upper = 0; 304103396Sbp 305227650Skevlo if (vcp->obj.co_flags & SMBV_UNICODE) 306227650Skevlo caps |= SMB_CAP_UNICODE; 307227650Skevlo 308103396Sbpagain: 309103396Sbp 31075374Sbp vcp->vc_smbuid = SMB_UID_UNKNOWN; 31175374Sbp 31287599Sobrien if (smb_smb_nomux(vcp, scred, __func__) != 0) 31375374Sbp return EINVAL; 31475374Sbp 31575374Sbp error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp); 31675374Sbp if (error) 31775374Sbp return error; 318111119Simp pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); 319111119Simp encpass = malloc(24, M_SMBTEMP, M_WAITOK); 32075374Sbp if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { 321103396Sbp /* 322103396Sbp * We try w/o uppercasing first so Samba mixed case 323103396Sbp * passwords work. If that fails we come back and try 324103396Sbp * uppercasing to satisfy OS/2 and Windows for Workgroups. 325103396Sbp */ 326103396Sbp if (upper++) { 327103396Sbp iconv_convstr(vcp->vc_toupper, pbuf, 328103396Sbp smb_vc_getpass(vcp)/*, SMB_MAXPASSWORDLEN*/); 329103396Sbp } else { 330103396Sbp strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN); 331103396Sbp pbuf[SMB_MAXPASSWORDLEN] = '\0'; 332103396Sbp } 333103396Sbp if (!SMB_UNICODE_STRINGS(vcp)) 334103396Sbp iconv_convstr(vcp->vc_toserver, pbuf, pbuf/*, 335103396Sbp SMB_MAXPASSWORDLEN*/); 336103396Sbp 33775374Sbp if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { 33875374Sbp uniplen = plen = 24; 33975374Sbp smb_encrypt(pbuf, vcp->vc_ch, encpass); 340111119Simp ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK); 341103396Sbp if (SMB_UNICODE_STRINGS(vcp)) { 342103396Sbp strncpy(pbuf, smb_vc_getpass(vcp), 343103396Sbp SMB_MAXPASSWORDLEN); 344103396Sbp pbuf[SMB_MAXPASSWORDLEN] = '\0'; 345103396Sbp } else 346103396Sbp iconv_convstr(vcp->vc_toserver, pbuf, 347103396Sbp smb_vc_getpass(vcp)/*, 348103396Sbp SMB_MAXPASSWORDLEN*/); 34975374Sbp smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass); 35075374Sbp pp = encpass; 35175374Sbp unipp = ntencpass; 35275374Sbp } else { 35375374Sbp plen = strlen(pbuf) + 1; 35475374Sbp pp = pbuf; 35575374Sbp uniplen = plen * 2; 356111119Simp ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK); 35775374Sbp smb_strtouni(ntencpass, smb_vc_getpass(vcp)); 35875374Sbp plen--; 35991022Sbp 36091022Sbp /* 36191022Sbp * The uniplen is zeroed because Samba cannot deal 36291022Sbp * with this 2nd cleartext password. This Samba 36391022Sbp * "bug" is actually a workaround for problems in 36491022Sbp * Microsoft clients. 36591022Sbp */ 36675374Sbp uniplen = 0/*-= 2*/; 36775374Sbp unipp = ntencpass; 36875374Sbp } 36975374Sbp } else { 37075374Sbp /* 37175374Sbp * In the share security mode password will be used 37275374Sbp * only in the tree authentication 37375374Sbp */ 37475374Sbp pp = ""; 37575374Sbp plen = 1; 37675374Sbp unipp = &smb_unieol; 377107666Sfjoe uniplen = 0 /* sizeof(smb_unieol) */; 37875374Sbp } 37975374Sbp smb_rq_wstart(rqp); 38075374Sbp mbp = &rqp->sr_rq; 38175374Sbp up = vcp->vc_username; 38275374Sbp ulen = strlen(up) + 1; 383103396Sbp /* 384103396Sbp * If userid is null we are attempting anonymous browse login 385103396Sbp * so passwords must be zero length. 386103396Sbp */ 387103396Sbp if (ulen == 1) 388103396Sbp plen = uniplen = 0; 38975374Sbp mb_put_uint8(mbp, 0xff); 39075374Sbp mb_put_uint8(mbp, 0); 39175374Sbp mb_put_uint16le(mbp, 0); 39275374Sbp mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx); 39375374Sbp mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux); 39475374Sbp mb_put_uint16le(mbp, vcp->vc_number); 39575374Sbp mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey); 39675374Sbp mb_put_uint16le(mbp, plen); 39775374Sbp if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) { 39875374Sbp mb_put_uint32le(mbp, 0); 39975374Sbp smb_rq_wend(rqp); 40075374Sbp smb_rq_bstart(rqp); 40175374Sbp mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 40275374Sbp smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); 40375374Sbp } else { 40475374Sbp mb_put_uint16le(mbp, uniplen); 40575374Sbp mb_put_uint32le(mbp, 0); /* reserved */ 406227650Skevlo mb_put_uint32le(mbp, caps); 40775374Sbp smb_rq_wend(rqp); 40875374Sbp smb_rq_bstart(rqp); 40975374Sbp mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 41075374Sbp mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM); 41175374Sbp smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* AccountName */ 41275374Sbp smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */ 41375374Sbp smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE); /* Client's OS */ 41475374Sbp smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE); /* Client name */ 41575374Sbp } 41675374Sbp smb_rq_bend(rqp); 41775374Sbp if (ntencpass) 41875374Sbp free(ntencpass, M_SMBTEMP); 419124087Stjr if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) 420124087Stjr smb_calcmackey(vcp); 42175374Sbp error = smb_rq_simple(rqp); 42275374Sbp SMBSDEBUG("%d\n", error); 42375374Sbp if (error) { 42475374Sbp if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess) 42575374Sbp error = EAUTH; 42675374Sbp goto bad; 42775374Sbp } 42875374Sbp vcp->vc_smbuid = rqp->sr_rpuid; 42975374Sbpbad: 43075374Sbp free(encpass, M_SMBTEMP); 43175374Sbp free(pbuf, M_SMBTEMP); 43275374Sbp smb_rq_done(rqp); 433103396Sbp if (error && upper == 1 && vcp->vc_sopt.sv_sm & SMB_SM_USER) 434103396Sbp goto again; 43575374Sbp return error; 43675374Sbp} 43775374Sbp 43875374Sbpint 43975374Sbpsmb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred) 44075374Sbp{ 44175374Sbp struct smb_rq *rqp; 44275374Sbp struct mbchain *mbp; 44375374Sbp int error; 44475374Sbp 44575374Sbp if (vcp->vc_smbuid == SMB_UID_UNKNOWN) 44675374Sbp return 0; 44775374Sbp 44887599Sobrien if (smb_smb_nomux(vcp, scred, __func__) != 0) 44975374Sbp return EINVAL; 45075374Sbp 45175374Sbp error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp); 45275374Sbp if (error) 45375374Sbp return error; 45475374Sbp mbp = &rqp->sr_rq; 45575374Sbp smb_rq_wstart(rqp); 45675374Sbp mb_put_uint8(mbp, 0xff); 45775374Sbp mb_put_uint8(mbp, 0); 45875374Sbp mb_put_uint16le(mbp, 0); 45975374Sbp smb_rq_wend(rqp); 46075374Sbp smb_rq_bstart(rqp); 46175374Sbp smb_rq_bend(rqp); 46275374Sbp error = smb_rq_simple(rqp); 46375374Sbp SMBSDEBUG("%d\n", error); 46475374Sbp smb_rq_done(rqp); 46575374Sbp return error; 46675374Sbp} 46775374Sbp 46875374Sbpstatic char smb_any_share[] = "?????"; 46975374Sbp 47075374Sbpstatic char * 47175374Sbpsmb_share_typename(int stype) 47275374Sbp{ 47375374Sbp char *pp; 47475374Sbp 47575374Sbp switch (stype) { 47675374Sbp case SMB_ST_DISK: 47775374Sbp pp = "A:"; 47875374Sbp break; 47975374Sbp case SMB_ST_PRINTER: 48075374Sbp pp = smb_any_share; /* can't use LPT: here... */ 48175374Sbp break; 48275374Sbp case SMB_ST_PIPE: 48375374Sbp pp = "IPC"; 48475374Sbp break; 48575374Sbp case SMB_ST_COMM: 48675374Sbp pp = "COMM"; 48775374Sbp break; 48875374Sbp case SMB_ST_ANY: 48975374Sbp default: 49075374Sbp pp = smb_any_share; 49175374Sbp break; 49275374Sbp } 49375374Sbp return pp; 49475374Sbp} 49575374Sbp 49675374Sbpint 49775374Sbpsmb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) 49875374Sbp{ 49975374Sbp struct smb_vc *vcp; 50075374Sbp struct smb_rq rq, *rqp = &rq; 50175374Sbp struct mbchain *mbp; 50275374Sbp char *pp, *pbuf, *encpass; 503103396Sbp int error, plen, caseopt, upper; 50475374Sbp 505103396Sbp upper = 0; 506103396Sbp 507103396Sbpagain: 508103396Sbp /* Disable Unicode for SMB_COM_TREE_CONNECT_ANDX requests */ 509103396Sbp if (SSTOVC(ssp)->vc_hflags2 & SMB_FLAGS2_UNICODE) { 510103396Sbp vcp = SSTOVC(ssp); 511227650Skevlo vcp->vc_toserver = vcp->vc_cp_toserver; 512227650Skevlo vcp->vc_tolocal = vcp->vc_cp_tolocal; 513103396Sbp vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE; 514103396Sbp } 515103396Sbp 51675374Sbp ssp->ss_tid = SMB_TID_UNKNOWN; 51775374Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp); 51875374Sbp if (error) 51975374Sbp return error; 52075374Sbp vcp = rqp->sr_vc; 52175374Sbp caseopt = SMB_CS_NONE; 52275374Sbp if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { 52375374Sbp plen = 1; 52475374Sbp pp = ""; 52575374Sbp pbuf = NULL; 52675374Sbp encpass = NULL; 52775374Sbp } else { 528111119Simp pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); 529111119Simp encpass = malloc(24, M_SMBTEMP, M_WAITOK); 530103396Sbp /* 531103396Sbp * We try w/o uppercasing first so Samba mixed case 532103396Sbp * passwords work. If that fails we come back and try 533103396Sbp * uppercasing to satisfy OS/2 and Windows for Workgroups. 534103396Sbp */ 535103396Sbp if (upper++) { 536103396Sbp iconv_convstr(vcp->vc_toupper, pbuf, 537103396Sbp smb_share_getpass(ssp)/*, 538103396Sbp SMB_MAXPASSWORDLEN*/); 539103396Sbp } else { 540103396Sbp strncpy(pbuf, smb_share_getpass(ssp), 541103396Sbp SMB_MAXPASSWORDLEN); 542103396Sbp pbuf[SMB_MAXPASSWORDLEN] = '\0'; 543103396Sbp } 54475374Sbp if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { 54575374Sbp plen = 24; 54675374Sbp smb_encrypt(pbuf, vcp->vc_ch, encpass); 54775374Sbp pp = encpass; 54875374Sbp } else { 54975374Sbp plen = strlen(pbuf) + 1; 55075374Sbp pp = pbuf; 55175374Sbp } 55275374Sbp } 55375374Sbp mbp = &rqp->sr_rq; 55475374Sbp smb_rq_wstart(rqp); 55575374Sbp mb_put_uint8(mbp, 0xff); 55675374Sbp mb_put_uint8(mbp, 0); 55775374Sbp mb_put_uint16le(mbp, 0); 55875374Sbp mb_put_uint16le(mbp, 0); /* Flags */ 55975374Sbp mb_put_uint16le(mbp, plen); 56075374Sbp smb_rq_wend(rqp); 56175374Sbp smb_rq_bstart(rqp); 56275374Sbp mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 56375374Sbp smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt); 56475374Sbp pp = vcp->vc_srvname; 56575374Sbp smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt); 56675374Sbp smb_put_dmem(mbp, vcp, "\\", 1, caseopt); 56775374Sbp pp = ssp->ss_name; 56875374Sbp smb_put_dstring(mbp, vcp, pp, caseopt); 56975374Sbp pp = smb_share_typename(ssp->ss_type); 57075374Sbp smb_put_dstring(mbp, vcp, pp, caseopt); 57175374Sbp smb_rq_bend(rqp); 57275374Sbp error = smb_rq_simple(rqp); 57375374Sbp SMBSDEBUG("%d\n", error); 57475374Sbp if (error) 57575374Sbp goto bad; 57675374Sbp ssp->ss_tid = rqp->sr_rptid; 57775374Sbp ssp->ss_vcgenid = vcp->vc_genid; 57875374Sbp ssp->ss_flags |= SMBS_CONNECTED; 579227650Skevlo /* 580227650Skevlo * If the server can speak Unicode then switch 581227650Skevlo * our converters to do Unicode <--> Local 582227650Skevlo */ 583227650Skevlo if (vcp->obj.co_flags & SMBV_UNICODE) { 584227650Skevlo vcp->vc_toserver = vcp->vc_ucs_toserver; 585227650Skevlo vcp->vc_tolocal = vcp->vc_ucs_tolocal; 586227650Skevlo vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE; 587227650Skevlo } 58875374Sbpbad: 58975374Sbp if (encpass) 59075374Sbp free(encpass, M_SMBTEMP); 59175374Sbp if (pbuf) 59275374Sbp free(pbuf, M_SMBTEMP); 59375374Sbp smb_rq_done(rqp); 594103396Sbp if (error && upper == 1) 595103396Sbp goto again; 59675374Sbp return error; 59775374Sbp} 59875374Sbp 59975374Sbpint 60075374Sbpsmb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred) 60175374Sbp{ 60275374Sbp struct smb_rq *rqp; 60375374Sbp struct mbchain *mbp; 60475374Sbp int error; 60575374Sbp 60675374Sbp if (ssp->ss_tid == SMB_TID_UNKNOWN) 60775374Sbp return 0; 60875374Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp); 60975374Sbp if (error) 61075374Sbp return error; 61175374Sbp mbp = &rqp->sr_rq; 61275374Sbp smb_rq_wstart(rqp); 61375374Sbp smb_rq_wend(rqp); 61475374Sbp smb_rq_bstart(rqp); 61575374Sbp smb_rq_bend(rqp); 61675374Sbp error = smb_rq_simple(rqp); 61775374Sbp SMBSDEBUG("%d\n", error); 61875374Sbp smb_rq_done(rqp); 61975374Sbp ssp->ss_tid = SMB_TID_UNKNOWN; 62075374Sbp return error; 62175374Sbp} 62275374Sbp 62375374Sbpstatic __inline int 624103395Sbpsmb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, 625103395Sbp struct uio *uio, struct smb_cred *scred) 626103395Sbp{ 627103395Sbp struct smb_rq *rqp; 628103395Sbp struct mbchain *mbp; 629103395Sbp struct mdchain *mdp; 630103395Sbp u_int8_t wc; 631103395Sbp int error; 632103395Sbp u_int16_t residhi, residlo, off, doff; 633103395Sbp u_int32_t resid; 634103395Sbp 635103395Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp); 636103395Sbp if (error) 637103395Sbp return error; 638103395Sbp smb_rq_getrequest(rqp, &mbp); 639103395Sbp smb_rq_wstart(rqp); 640103395Sbp mb_put_uint8(mbp, 0xff); /* no secondary command */ 641103395Sbp mb_put_uint8(mbp, 0); /* MBZ */ 642103395Sbp mb_put_uint16le(mbp, 0); /* offset to secondary */ 643103395Sbp mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 644103395Sbp mb_put_uint32le(mbp, uio->uio_offset); 645103395Sbp *len = min(SSTOVC(ssp)->vc_rxmax, *len); 646103395Sbp mb_put_uint16le(mbp, *len); /* MaxCount */ 647103395Sbp mb_put_uint16le(mbp, *len); /* MinCount (only indicates blocking) */ 648103395Sbp mb_put_uint32le(mbp, (unsigned)*len >> 16); /* MaxCountHigh */ 649103395Sbp mb_put_uint16le(mbp, *len); /* Remaining ("obsolete") */ 650103395Sbp mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */ 651103395Sbp smb_rq_wend(rqp); 652103395Sbp smb_rq_bstart(rqp); 653103395Sbp smb_rq_bend(rqp); 654103395Sbp do { 655103395Sbp error = smb_rq_simple(rqp); 656103395Sbp if (error) 657103395Sbp break; 658103395Sbp smb_rq_getreply(rqp, &mdp); 659103395Sbp off = SMB_HDRLEN; 660103395Sbp md_get_uint8(mdp, &wc); 661103395Sbp off++; 662103395Sbp if (wc != 12) { 663103395Sbp error = EBADRPC; 664103395Sbp break; 665103395Sbp } 666103395Sbp md_get_uint8(mdp, NULL); 667103395Sbp off++; 668103395Sbp md_get_uint8(mdp, NULL); 669103395Sbp off++; 670103395Sbp md_get_uint16le(mdp, NULL); 671103395Sbp off += 2; 672103395Sbp md_get_uint16le(mdp, NULL); 673103395Sbp off += 2; 674103395Sbp md_get_uint16le(mdp, NULL); /* data compaction mode */ 675103395Sbp off += 2; 676103395Sbp md_get_uint16le(mdp, NULL); 677103395Sbp off += 2; 678103395Sbp md_get_uint16le(mdp, &residlo); 679103395Sbp off += 2; 680103395Sbp md_get_uint16le(mdp, &doff); /* data offset */ 681103395Sbp off += 2; 682103395Sbp md_get_uint16le(mdp, &residhi); 683103395Sbp off += 2; 684103395Sbp resid = (residhi << 16) | residlo; 685103395Sbp md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); 686103395Sbp off += 4*2; 687103395Sbp md_get_uint16le(mdp, NULL); /* ByteCount */ 688103395Sbp off += 2; 689103395Sbp if (doff > off) /* pad byte(s)? */ 690103395Sbp md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); 691103395Sbp if (resid == 0) { 692103395Sbp *rresid = resid; 693103395Sbp break; 694103395Sbp } 695103395Sbp error = md_get_uio(mdp, uio, resid); 696103395Sbp if (error) 697103395Sbp break; 698103395Sbp *rresid = resid; 699103395Sbp } while(0); 700103395Sbp smb_rq_done(rqp); 701103395Sbp return (error); 702103395Sbp} 703103395Sbp 704103395Sbpstatic __inline int 705103395Sbpsmb_smb_writex(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, 706103395Sbp struct uio *uio, struct smb_cred *scred) 707103395Sbp{ 708103395Sbp struct smb_rq *rqp; 709103395Sbp struct mbchain *mbp; 710103395Sbp struct mdchain *mdp; 711103395Sbp int error; 712103395Sbp u_int8_t wc; 713103395Sbp u_int16_t resid; 714103395Sbp 715103395Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp); 716103395Sbp if (error) 717103395Sbp return (error); 718103395Sbp smb_rq_getrequest(rqp, &mbp); 719103395Sbp smb_rq_wstart(rqp); 720103395Sbp mb_put_uint8(mbp, 0xff); /* no secondary command */ 721103395Sbp mb_put_uint8(mbp, 0); /* MBZ */ 722103395Sbp mb_put_uint16le(mbp, 0); /* offset to secondary */ 723103395Sbp mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 724103395Sbp mb_put_uint32le(mbp, uio->uio_offset); 725103395Sbp mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ 726103395Sbp mb_put_uint16le(mbp, 0); /* !write-thru */ 727103395Sbp mb_put_uint16le(mbp, 0); 728103395Sbp *len = min(SSTOVC(ssp)->vc_wxmax, *len); 729103395Sbp mb_put_uint16le(mbp, (unsigned)*len >> 16); 730103395Sbp mb_put_uint16le(mbp, *len); 731103395Sbp mb_put_uint16le(mbp, 64); /* data offset from header start */ 732103395Sbp mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */ 733103395Sbp smb_rq_wend(rqp); 734103395Sbp smb_rq_bstart(rqp); 735103395Sbp do { 736103395Sbp mb_put_uint8(mbp, 0xee); /* mimic xp pad byte! */ 737103395Sbp error = mb_put_uio(mbp, uio, *len); 738103395Sbp if (error) 739103395Sbp break; 740103395Sbp smb_rq_bend(rqp); 741103395Sbp error = smb_rq_simple(rqp); 742103395Sbp if (error) 743103395Sbp break; 744103395Sbp smb_rq_getreply(rqp, &mdp); 745103395Sbp md_get_uint8(mdp, &wc); 746103395Sbp if (wc != 6) { 747103395Sbp error = EBADRPC; 748103395Sbp break; 749103395Sbp } 750103395Sbp md_get_uint8(mdp, NULL); 751103395Sbp md_get_uint8(mdp, NULL); 752103395Sbp md_get_uint16le(mdp, NULL); 753103395Sbp md_get_uint16le(mdp, &resid); 754103395Sbp *rresid = resid; 755103395Sbp } while(0); 756103395Sbp 757103395Sbp smb_rq_done(rqp); 758103395Sbp return (error); 759103395Sbp} 760103395Sbp 761103395Sbpstatic __inline int 76275374Sbpsmb_smb_read(struct smb_share *ssp, u_int16_t fid, 76375374Sbp int *len, int *rresid, struct uio *uio, struct smb_cred *scred) 76475374Sbp{ 76575374Sbp struct smb_rq *rqp; 76675374Sbp struct mbchain *mbp; 76775374Sbp struct mdchain *mdp; 76875374Sbp u_int16_t resid, bc; 76975374Sbp u_int8_t wc; 77075374Sbp int error, rlen, blksz; 77175374Sbp 772103395Sbp if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) 773103395Sbp return (smb_smb_readx(ssp, fid, len, rresid, uio, scred)); 774103395Sbp 77575374Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp); 77675374Sbp if (error) 77775374Sbp return error; 77875374Sbp 77975374Sbp blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; 78075374Sbp rlen = *len = min(blksz, *len); 78175374Sbp 78275374Sbp smb_rq_getrequest(rqp, &mbp); 78375374Sbp smb_rq_wstart(rqp); 78475374Sbp mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 78575374Sbp mb_put_uint16le(mbp, rlen); 78675374Sbp mb_put_uint32le(mbp, uio->uio_offset); 78775374Sbp mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff)); 78875374Sbp smb_rq_wend(rqp); 78975374Sbp smb_rq_bstart(rqp); 79075374Sbp smb_rq_bend(rqp); 79175374Sbp do { 79275374Sbp error = smb_rq_simple(rqp); 79375374Sbp if (error) 79475374Sbp break; 79575374Sbp smb_rq_getreply(rqp, &mdp); 79675374Sbp md_get_uint8(mdp, &wc); 79775374Sbp if (wc != 5) { 79875374Sbp error = EBADRPC; 79975374Sbp break; 80075374Sbp } 80175374Sbp md_get_uint16le(mdp, &resid); 80275374Sbp md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); 80375374Sbp md_get_uint16le(mdp, &bc); 80475374Sbp md_get_uint8(mdp, NULL); /* ignore buffer type */ 80575374Sbp md_get_uint16le(mdp, &resid); 80675374Sbp if (resid == 0) { 80775374Sbp *rresid = resid; 80875374Sbp break; 80975374Sbp } 81075374Sbp error = md_get_uio(mdp, uio, resid); 81175374Sbp if (error) 81275374Sbp break; 81375374Sbp *rresid = resid; 81475374Sbp } while(0); 81575374Sbp smb_rq_done(rqp); 81675374Sbp return error; 81775374Sbp} 81875374Sbp 81975374Sbpint 82075374Sbpsmb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio, 82175374Sbp struct smb_cred *scred) 82275374Sbp{ 82375374Sbp int tsize, len, resid; 82475374Sbp int error = 0; 82575374Sbp 82675374Sbp tsize = uio->uio_resid; 82775374Sbp while (tsize > 0) { 828170804Smjacob resid = 0; 82975374Sbp len = tsize; 83075374Sbp error = smb_smb_read(ssp, fid, &len, &resid, uio, scred); 83175374Sbp if (error) 83275374Sbp break; 83375374Sbp tsize -= resid; 83475374Sbp if (resid < len) 83575374Sbp break; 83675374Sbp } 83775374Sbp return error; 83875374Sbp} 83975374Sbp 84075374Sbpstatic __inline int 84175374Sbpsmb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, 84275374Sbp struct uio *uio, struct smb_cred *scred) 84375374Sbp{ 84475374Sbp struct smb_rq *rqp; 84575374Sbp struct mbchain *mbp; 84675374Sbp struct mdchain *mdp; 84775374Sbp u_int16_t resid; 84875374Sbp u_int8_t wc; 84975374Sbp int error, blksz; 85075374Sbp 851103395Sbp if (*len && SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) 852103395Sbp return (smb_smb_writex(ssp, fid, len, rresid, uio, scred)); 853103395Sbp 85475374Sbp blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; 85575374Sbp if (blksz > 0xffff) 85675374Sbp blksz = 0xffff; 85775374Sbp 85875374Sbp resid = *len = min(blksz, *len); 85975374Sbp 86075374Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); 86175374Sbp if (error) 86275374Sbp return error; 86375374Sbp smb_rq_getrequest(rqp, &mbp); 86475374Sbp smb_rq_wstart(rqp); 86575374Sbp mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 86675374Sbp mb_put_uint16le(mbp, resid); 86775374Sbp mb_put_uint32le(mbp, uio->uio_offset); 86875374Sbp mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff)); 86975374Sbp smb_rq_wend(rqp); 87075374Sbp smb_rq_bstart(rqp); 87175374Sbp mb_put_uint8(mbp, SMB_DT_DATA); 87275374Sbp mb_put_uint16le(mbp, resid); 87375374Sbp do { 87475374Sbp error = mb_put_uio(mbp, uio, resid); 87575374Sbp if (error) 87675374Sbp break; 87775374Sbp smb_rq_bend(rqp); 87875374Sbp error = smb_rq_simple(rqp); 87975374Sbp if (error) 88075374Sbp break; 88175374Sbp smb_rq_getreply(rqp, &mdp); 88275374Sbp md_get_uint8(mdp, &wc); 88375374Sbp if (wc != 1) { 88475374Sbp error = EBADRPC; 88575374Sbp break; 88675374Sbp } 88775374Sbp md_get_uint16le(mdp, &resid); 88875374Sbp *rresid = resid; 88975374Sbp } while(0); 89075374Sbp smb_rq_done(rqp); 89175374Sbp return error; 89275374Sbp} 89375374Sbp 89475374Sbpint 89575374Sbpsmb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio, 89675374Sbp struct smb_cred *scred) 89775374Sbp{ 89875374Sbp int error = 0, len, tsize, resid; 89975374Sbp struct uio olduio; 90075374Sbp 90175374Sbp tsize = uio->uio_resid; 90275374Sbp olduio = *uio; 90375374Sbp while (tsize > 0) { 904170804Smjacob resid = 0; 90575374Sbp len = tsize; 90675374Sbp error = smb_smb_write(ssp, fid, &len, &resid, uio, scred); 90775374Sbp if (error) 90875374Sbp break; 90975374Sbp if (resid < len) { 91075374Sbp error = EIO; 91175374Sbp break; 91275374Sbp } 91375374Sbp tsize -= resid; 91475374Sbp } 91575374Sbp if (error) { 91691023Sbp /* 91791023Sbp * Errors can happen on the copyin, the rpc, etc. So they 91891023Sbp * imply resid is unreliable. The only safe thing is 91991023Sbp * to pretend zero bytes made it. We needn't restore the 92091023Sbp * iovs because callers don't depend on them in error 92191023Sbp * paths - uio_resid and uio_offset are what matter. 92291023Sbp */ 92375374Sbp *uio = olduio; 92475374Sbp } 92575374Sbp return error; 92675374Sbp} 92775374Sbp 92875374Sbpint 92975374Sbpsmb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred) 93075374Sbp{ 93175374Sbp struct smb_rq *rqp; 93275374Sbp struct mbchain *mbp; 93375374Sbp int error; 93475374Sbp 93575374Sbp error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp); 93675374Sbp if (error) 93775374Sbp return error; 93875374Sbp mbp = &rqp->sr_rq; 93975374Sbp smb_rq_wstart(rqp); 94075374Sbp mb_put_uint16le(mbp, 1); 94175374Sbp smb_rq_wend(rqp); 94275374Sbp smb_rq_bstart(rqp); 94375374Sbp mb_put_uint32le(mbp, 0); 94475374Sbp smb_rq_bend(rqp); 94575374Sbp error = smb_rq_simple(rqp); 94675374Sbp SMBSDEBUG("%d\n", error); 94775374Sbp smb_rq_done(rqp); 94875374Sbp return error; 94975374Sbp} 950