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$"); 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 7175374Sbp#define SMB_DIALECT_MAX (sizeof(smb_dialects) / sizeof(struct smb_dialect) - 2) 7275374Sbp 73103395Sbpstatic u_int32_t 74103395Sbpsmb_vc_maxread(struct smb_vc *vcp) 75103395Sbp{ 76103395Sbp /* 77103395Sbp * Specs say up to 64k data bytes, but Windows traffic 78103395Sbp * uses 60k... no doubt for some good reason. 79124087Stjr * 80124087Stjr * Don't exceed the server's buffer size if signatures 81124087Stjr * are enabled otherwise Windows 2003 chokes. Allow space 82124087Stjr * for the SMB header & a little bit extra. 83103395Sbp */ 84124087Stjr if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) && 85124087Stjr (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) 86103395Sbp return (60*1024); 87103395Sbp else 88124087Stjr return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64); 89103395Sbp} 90103395Sbp 91103395Sbpstatic u_int32_t 92103395Sbpsmb_vc_maxwrite(struct smb_vc *vcp) 93103395Sbp{ 94103395Sbp /* 95124087Stjr * See comment above. 96103395Sbp */ 97124087Stjr if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) && 98124087Stjr (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) 99103395Sbp return (60*1024); 100103395Sbp else 101124087Stjr return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64); 102103395Sbp} 103103395Sbp 10475374Sbpstatic int 10575374Sbpsmb_smb_nomux(struct smb_vc *vcp, struct smb_cred *scred, const char *name) 10675374Sbp{ 10787192Sbp if (scred->scr_td->td_proc == vcp->vc_iod->iod_p) 10875374Sbp return 0; 10975374Sbp SMBERROR("wrong function called(%s)\n", name); 11075374Sbp return EINVAL; 11175374Sbp} 11275374Sbp 11375374Sbpint 11475374Sbpsmb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) 11575374Sbp{ 11675374Sbp struct smb_dialect *dp; 11775374Sbp struct smb_sopt *sp = NULL; 11875374Sbp struct smb_rq *rqp; 11975374Sbp struct mbchain *mbp; 12075374Sbp struct mdchain *mdp; 12175374Sbp u_int8_t wc, stime[8], sblen; 12275374Sbp u_int16_t dindex, tw, tw1, swlen, bc; 12375374Sbp int error, maxqsz; 124227650Skevlo int unicode = SMB_UNICODE_STRINGS(vcp); 125227650Skevlo void * servercharset = vcp->vc_toserver; 126227650Skevlo void * localcharset = vcp->vc_tolocal; 12775374Sbp 12887599Sobrien if (smb_smb_nomux(vcp, scred, __func__) != 0) 12975374Sbp return EINVAL; 130227650Skevlo /* Disable Unicode for SMB_COM_NEGOTIATE requests */ 131227650Skevlo if (unicode) { 132227650Skevlo vcp->vc_toserver = vcp->vc_cp_toserver; 133227650Skevlo vcp->vc_tolocal = vcp->vc_cp_tolocal; 134227650Skevlo } 13575374Sbp vcp->vc_hflags = 0; 13675374Sbp vcp->vc_hflags2 = 0; 13775374Sbp vcp->obj.co_flags &= ~(SMBV_ENCRYPT); 13875374Sbp sp = &vcp->vc_sopt; 13975374Sbp bzero(sp, sizeof(struct smb_sopt)); 14075374Sbp error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp); 14175374Sbp if (error) 14275374Sbp return error; 14375374Sbp smb_rq_getrequest(rqp, &mbp); 14475374Sbp smb_rq_wstart(rqp); 14575374Sbp smb_rq_wend(rqp); 14675374Sbp smb_rq_bstart(rqp); 14775374Sbp for(dp = smb_dialects; dp->d_id != -1; dp++) { 14875374Sbp mb_put_uint8(mbp, SMB_DT_DIALECT); 14975374Sbp smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE); 15075374Sbp } 15175374Sbp smb_rq_bend(rqp); 15275374Sbp error = smb_rq_simple(rqp); 15375374Sbp SMBSDEBUG("%d\n", error); 15475374Sbp if (error) 15575374Sbp goto bad; 15675374Sbp smb_rq_getreply(rqp, &mdp); 15775374Sbp do { 15875374Sbp error = md_get_uint8(mdp, &wc); 15975374Sbp if (error) 16075374Sbp break; 16175374Sbp error = md_get_uint16le(mdp, &dindex); 16275374Sbp if (error) 16375374Sbp break; 16475374Sbp if (dindex > 7) { 16575374Sbp SMBERROR("Don't know how to talk with server %s (%d)\n", "xxx", dindex); 16675374Sbp error = EBADRPC; 16775374Sbp break; 16875374Sbp } 16975374Sbp dp = smb_dialects + dindex; 17075374Sbp sp->sv_proto = dp->d_id; 17175374Sbp SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc); 17275374Sbp error = EBADRPC; 17375374Sbp if (dp->d_id >= SMB_DIALECT_NTLM0_12) { 17475374Sbp if (wc != 17) 17575374Sbp break; 17675374Sbp md_get_uint8(mdp, &sp->sv_sm); 17775374Sbp md_get_uint16le(mdp, &sp->sv_maxmux); 17875374Sbp md_get_uint16le(mdp, &sp->sv_maxvcs); 17975374Sbp md_get_uint32le(mdp, &sp->sv_maxtx); 18075374Sbp md_get_uint32le(mdp, &sp->sv_maxraw); 18175374Sbp md_get_uint32le(mdp, &sp->sv_skey); 18275374Sbp md_get_uint32le(mdp, &sp->sv_caps); 18375374Sbp md_get_mem(mdp, stime, 8, MB_MSYSTEM); 18475374Sbp md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); 18575374Sbp md_get_uint8(mdp, &sblen); 18675374Sbp if (sblen && (sp->sv_sm & SMB_SM_ENCRYPT)) { 18775374Sbp if (sblen != SMB_MAXCHALLENGELEN) { 18875374Sbp SMBERROR("Unexpected length of security blob (%d)\n", sblen); 18975374Sbp break; 19075374Sbp } 191227650Skevlo error = md_get_uint16le(mdp, &bc); 19275374Sbp if (error) 19375374Sbp break; 19475374Sbp if (sp->sv_caps & SMB_CAP_EXT_SECURITY) 19575374Sbp md_get_mem(mdp, NULL, 16, MB_MSYSTEM); 19675374Sbp error = md_get_mem(mdp, vcp->vc_ch, sblen, MB_MSYSTEM); 19775374Sbp if (error) 19875374Sbp break; 19975374Sbp vcp->vc_chlen = sblen; 20075374Sbp vcp->obj.co_flags |= SMBV_ENCRYPT; 20175374Sbp } 202124087Stjr if (sp->sv_sm & SMB_SM_SIGS_REQUIRE) 203124087Stjr vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; 204227650Skevlo if (vcp->vc_ucs_toserver && 205227650Skevlo sp->sv_caps & SMB_CAP_UNICODE) { 206227650Skevlo /* 207227650Skevlo * They do Unicode. 208227650Skevlo */ 209227650Skevlo vcp->obj.co_flags |= SMBV_UNICODE; 210227650Skevlo } 21175374Sbp vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; 21275374Sbp if (dp->d_id == SMB_DIALECT_NTLM0_12 && 21375374Sbp sp->sv_maxtx < 4096 && 21475374Sbp (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) { 21575374Sbp vcp->obj.co_flags |= SMBV_WIN95; 21675374Sbp SMBSDEBUG("Win95 detected\n"); 21775374Sbp } 218227650Skevlo error = 0; 219227650Skevlo break; 220227650Skevlo } 221227650Skevlo vcp->vc_hflags2 &= ~(SMB_FLAGS2_EXT_SEC|SMB_FLAGS2_DFS| 222227650Skevlo SMB_FLAGS2_ERR_STATUS|SMB_FLAGS2_UNICODE); 223227650Skevlo unicode = 0; 224227650Skevlo if (dp->d_id > SMB_DIALECT_CORE) { 22575374Sbp md_get_uint16le(mdp, &tw); 22675374Sbp sp->sv_sm = tw; 22775374Sbp md_get_uint16le(mdp, &tw); 22875374Sbp sp->sv_maxtx = tw; 22975374Sbp md_get_uint16le(mdp, &sp->sv_maxmux); 23075374Sbp md_get_uint16le(mdp, &sp->sv_maxvcs); 23175374Sbp md_get_uint16le(mdp, &tw); /* rawmode */ 23275374Sbp md_get_uint32le(mdp, &sp->sv_skey); 23375374Sbp if (wc == 13) { /* >= LANMAN1 */ 23475374Sbp md_get_uint16(mdp, &tw); /* time */ 23575374Sbp md_get_uint16(mdp, &tw1); /* date */ 23675374Sbp md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); 23775374Sbp md_get_uint16le(mdp, &swlen); 23875374Sbp if (swlen > SMB_MAXCHALLENGELEN) 23975374Sbp break; 24075374Sbp md_get_uint16(mdp, NULL); /* mbz */ 241227650Skevlo if (md_get_uint16le(mdp, &bc) != 0) 24275374Sbp break; 24375374Sbp if (bc < swlen) 24475374Sbp break; 24575374Sbp if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) { 24675374Sbp error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM); 24775374Sbp if (error) 24875374Sbp break; 24975374Sbp vcp->vc_chlen = swlen; 25075374Sbp vcp->obj.co_flags |= SMBV_ENCRYPT; 25175374Sbp } 25275374Sbp } 25375374Sbp vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; 25475374Sbp } else { /* an old CORE protocol */ 25575374Sbp sp->sv_maxmux = 1; 25675374Sbp } 25775374Sbp error = 0; 25875374Sbp } while (0); 25975374Sbp if (error == 0) { 26075374Sbp vcp->vc_maxvcs = sp->sv_maxvcs; 26175374Sbp if (vcp->vc_maxvcs <= 1) { 26275374Sbp if (vcp->vc_maxvcs == 0) 26375374Sbp vcp->vc_maxvcs = 1; 26475374Sbp } 26575374Sbp if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff) 26675374Sbp sp->sv_maxtx = 1024; 267103395Sbp else 268103395Sbp sp->sv_maxtx = min(sp->sv_maxtx, 269103395Sbp 63*1024 + SMB_HDRLEN + 16); 270103395Sbp SMB_TRAN_GETPARAM(vcp, SMBTP_RCVSZ, &maxqsz); 271103395Sbp vcp->vc_rxmax = min(smb_vc_maxread(vcp), maxqsz - 1024); 27275374Sbp SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz); 273103395Sbp vcp->vc_wxmax = min(smb_vc_maxwrite(vcp), maxqsz - 1024); 27475374Sbp vcp->vc_txmax = min(sp->sv_maxtx, maxqsz); 27575374Sbp SMBSDEBUG("TZ = %d\n", sp->sv_tz); 27675374Sbp SMBSDEBUG("CAPS = %x\n", sp->sv_caps); 27775374Sbp SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux); 27875374Sbp SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs); 27975374Sbp SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw); 28075374Sbp SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx); 28175374Sbp } 28275374Sbpbad: 283227650Skevlo /* Restore Unicode conversion state */ 284227650Skevlo if (unicode) { 285227650Skevlo vcp->vc_toserver = servercharset; 286227650Skevlo vcp->vc_tolocal = localcharset; 287227650Skevlo vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE; 288227650Skevlo } 28975374Sbp smb_rq_done(rqp); 29075374Sbp return error; 29175374Sbp} 29275374Sbp 29375374Sbpint 29475374Sbpsmb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) 29575374Sbp{ 29675374Sbp struct smb_rq *rqp; 29775374Sbp struct mbchain *mbp; 29875374Sbp/* u_int8_t wc; 29975374Sbp u_int16_t tw, tw1;*/ 30075374Sbp smb_uniptr unipp, ntencpass = NULL; 30175374Sbp char *pp, *up, *pbuf, *encpass; 302103396Sbp int error, plen, uniplen, ulen, upper; 303227650Skevlo u_int32_t caps = 0; 30475374Sbp 305103396Sbp upper = 0; 306103396Sbp 307227650Skevlo if (vcp->obj.co_flags & SMBV_UNICODE) 308227650Skevlo caps |= SMB_CAP_UNICODE; 309227650Skevlo 310103396Sbpagain: 311103396Sbp 31275374Sbp vcp->vc_smbuid = SMB_UID_UNKNOWN; 31375374Sbp 31487599Sobrien if (smb_smb_nomux(vcp, scred, __func__) != 0) 31575374Sbp return EINVAL; 31675374Sbp 31775374Sbp error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp); 31875374Sbp if (error) 31975374Sbp return error; 320111119Simp pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); 321111119Simp encpass = malloc(24, M_SMBTEMP, M_WAITOK); 32275374Sbp if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { 323103396Sbp /* 324103396Sbp * We try w/o uppercasing first so Samba mixed case 325103396Sbp * passwords work. If that fails we come back and try 326103396Sbp * uppercasing to satisfy OS/2 and Windows for Workgroups. 327103396Sbp */ 328103396Sbp if (upper++) { 329103396Sbp iconv_convstr(vcp->vc_toupper, pbuf, 330103396Sbp smb_vc_getpass(vcp)/*, SMB_MAXPASSWORDLEN*/); 331103396Sbp } else { 332103396Sbp strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN); 333103396Sbp pbuf[SMB_MAXPASSWORDLEN] = '\0'; 334103396Sbp } 335103396Sbp if (!SMB_UNICODE_STRINGS(vcp)) 336103396Sbp iconv_convstr(vcp->vc_toserver, pbuf, pbuf/*, 337103396Sbp SMB_MAXPASSWORDLEN*/); 338103396Sbp 33975374Sbp if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { 34075374Sbp uniplen = plen = 24; 34175374Sbp smb_encrypt(pbuf, vcp->vc_ch, encpass); 342111119Simp ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK); 343103396Sbp if (SMB_UNICODE_STRINGS(vcp)) { 344103396Sbp strncpy(pbuf, smb_vc_getpass(vcp), 345103396Sbp SMB_MAXPASSWORDLEN); 346103396Sbp pbuf[SMB_MAXPASSWORDLEN] = '\0'; 347103396Sbp } else 348103396Sbp iconv_convstr(vcp->vc_toserver, pbuf, 349103396Sbp smb_vc_getpass(vcp)/*, 350103396Sbp SMB_MAXPASSWORDLEN*/); 35175374Sbp smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass); 35275374Sbp pp = encpass; 35375374Sbp unipp = ntencpass; 35475374Sbp } else { 35575374Sbp plen = strlen(pbuf) + 1; 35675374Sbp pp = pbuf; 35775374Sbp uniplen = plen * 2; 358111119Simp ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK); 35975374Sbp smb_strtouni(ntencpass, smb_vc_getpass(vcp)); 36075374Sbp plen--; 36191022Sbp 36291022Sbp /* 36391022Sbp * The uniplen is zeroed because Samba cannot deal 36491022Sbp * with this 2nd cleartext password. This Samba 36591022Sbp * "bug" is actually a workaround for problems in 36691022Sbp * Microsoft clients. 36791022Sbp */ 36875374Sbp uniplen = 0/*-= 2*/; 36975374Sbp unipp = ntencpass; 37075374Sbp } 37175374Sbp } else { 37275374Sbp /* 37375374Sbp * In the share security mode password will be used 37475374Sbp * only in the tree authentication 37575374Sbp */ 37675374Sbp pp = ""; 37775374Sbp plen = 1; 37875374Sbp unipp = &smb_unieol; 379107666Sfjoe uniplen = 0 /* sizeof(smb_unieol) */; 38075374Sbp } 38175374Sbp smb_rq_wstart(rqp); 38275374Sbp mbp = &rqp->sr_rq; 38375374Sbp up = vcp->vc_username; 38475374Sbp ulen = strlen(up) + 1; 385103396Sbp /* 386103396Sbp * If userid is null we are attempting anonymous browse login 387103396Sbp * so passwords must be zero length. 388103396Sbp */ 389103396Sbp if (ulen == 1) 390103396Sbp plen = uniplen = 0; 39175374Sbp mb_put_uint8(mbp, 0xff); 39275374Sbp mb_put_uint8(mbp, 0); 39375374Sbp mb_put_uint16le(mbp, 0); 39475374Sbp mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx); 39575374Sbp mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux); 39675374Sbp mb_put_uint16le(mbp, vcp->vc_number); 39775374Sbp mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey); 39875374Sbp mb_put_uint16le(mbp, plen); 39975374Sbp if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) { 40075374Sbp mb_put_uint32le(mbp, 0); 40175374Sbp smb_rq_wend(rqp); 40275374Sbp smb_rq_bstart(rqp); 40375374Sbp mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 40475374Sbp smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); 40575374Sbp } else { 40675374Sbp mb_put_uint16le(mbp, uniplen); 40775374Sbp mb_put_uint32le(mbp, 0); /* reserved */ 408227650Skevlo mb_put_uint32le(mbp, caps); 40975374Sbp smb_rq_wend(rqp); 41075374Sbp smb_rq_bstart(rqp); 41175374Sbp mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 41275374Sbp mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM); 41375374Sbp smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* AccountName */ 41475374Sbp smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */ 41575374Sbp smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE); /* Client's OS */ 41675374Sbp smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE); /* Client name */ 41775374Sbp } 41875374Sbp smb_rq_bend(rqp); 41975374Sbp if (ntencpass) 42075374Sbp free(ntencpass, M_SMBTEMP); 421124087Stjr if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) 422124087Stjr smb_calcmackey(vcp); 42375374Sbp error = smb_rq_simple(rqp); 42475374Sbp SMBSDEBUG("%d\n", error); 42575374Sbp if (error) { 42675374Sbp if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess) 42775374Sbp error = EAUTH; 42875374Sbp goto bad; 42975374Sbp } 43075374Sbp vcp->vc_smbuid = rqp->sr_rpuid; 43175374Sbpbad: 43275374Sbp free(encpass, M_SMBTEMP); 43375374Sbp free(pbuf, M_SMBTEMP); 43475374Sbp smb_rq_done(rqp); 435103396Sbp if (error && upper == 1 && vcp->vc_sopt.sv_sm & SMB_SM_USER) 436103396Sbp goto again; 43775374Sbp return error; 43875374Sbp} 43975374Sbp 44075374Sbpint 44175374Sbpsmb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred) 44275374Sbp{ 44375374Sbp struct smb_rq *rqp; 44475374Sbp struct mbchain *mbp; 44575374Sbp int error; 44675374Sbp 44775374Sbp if (vcp->vc_smbuid == SMB_UID_UNKNOWN) 44875374Sbp return 0; 44975374Sbp 45087599Sobrien if (smb_smb_nomux(vcp, scred, __func__) != 0) 45175374Sbp return EINVAL; 45275374Sbp 45375374Sbp error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp); 45475374Sbp if (error) 45575374Sbp return error; 45675374Sbp mbp = &rqp->sr_rq; 45775374Sbp smb_rq_wstart(rqp); 45875374Sbp mb_put_uint8(mbp, 0xff); 45975374Sbp mb_put_uint8(mbp, 0); 46075374Sbp mb_put_uint16le(mbp, 0); 46175374Sbp smb_rq_wend(rqp); 46275374Sbp smb_rq_bstart(rqp); 46375374Sbp smb_rq_bend(rqp); 46475374Sbp error = smb_rq_simple(rqp); 46575374Sbp SMBSDEBUG("%d\n", error); 46675374Sbp smb_rq_done(rqp); 46775374Sbp return error; 46875374Sbp} 46975374Sbp 47075374Sbpstatic char smb_any_share[] = "?????"; 47175374Sbp 47275374Sbpstatic char * 47375374Sbpsmb_share_typename(int stype) 47475374Sbp{ 47575374Sbp char *pp; 47675374Sbp 47775374Sbp switch (stype) { 47875374Sbp case SMB_ST_DISK: 47975374Sbp pp = "A:"; 48075374Sbp break; 48175374Sbp case SMB_ST_PRINTER: 48275374Sbp pp = smb_any_share; /* can't use LPT: here... */ 48375374Sbp break; 48475374Sbp case SMB_ST_PIPE: 48575374Sbp pp = "IPC"; 48675374Sbp break; 48775374Sbp case SMB_ST_COMM: 48875374Sbp pp = "COMM"; 48975374Sbp break; 49075374Sbp case SMB_ST_ANY: 49175374Sbp default: 49275374Sbp pp = smb_any_share; 49375374Sbp break; 49475374Sbp } 49575374Sbp return pp; 49675374Sbp} 49775374Sbp 49875374Sbpint 49975374Sbpsmb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) 50075374Sbp{ 50175374Sbp struct smb_vc *vcp; 50275374Sbp struct smb_rq rq, *rqp = &rq; 50375374Sbp struct mbchain *mbp; 50475374Sbp char *pp, *pbuf, *encpass; 505103396Sbp int error, plen, caseopt, upper; 50675374Sbp 507103396Sbp upper = 0; 508103396Sbp 509103396Sbpagain: 510103396Sbp /* Disable Unicode for SMB_COM_TREE_CONNECT_ANDX requests */ 511103396Sbp if (SSTOVC(ssp)->vc_hflags2 & SMB_FLAGS2_UNICODE) { 512103396Sbp vcp = SSTOVC(ssp); 513227650Skevlo vcp->vc_toserver = vcp->vc_cp_toserver; 514227650Skevlo vcp->vc_tolocal = vcp->vc_cp_tolocal; 515103396Sbp vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE; 516103396Sbp } 517103396Sbp 51875374Sbp ssp->ss_tid = SMB_TID_UNKNOWN; 51975374Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp); 52075374Sbp if (error) 52175374Sbp return error; 52275374Sbp vcp = rqp->sr_vc; 52375374Sbp caseopt = SMB_CS_NONE; 52475374Sbp if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { 52575374Sbp plen = 1; 52675374Sbp pp = ""; 52775374Sbp pbuf = NULL; 52875374Sbp encpass = NULL; 52975374Sbp } else { 530111119Simp pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); 531111119Simp encpass = malloc(24, M_SMBTEMP, M_WAITOK); 532103396Sbp /* 533103396Sbp * We try w/o uppercasing first so Samba mixed case 534103396Sbp * passwords work. If that fails we come back and try 535103396Sbp * uppercasing to satisfy OS/2 and Windows for Workgroups. 536103396Sbp */ 537103396Sbp if (upper++) { 538103396Sbp iconv_convstr(vcp->vc_toupper, pbuf, 539103396Sbp smb_share_getpass(ssp)/*, 540103396Sbp SMB_MAXPASSWORDLEN*/); 541103396Sbp } else { 542103396Sbp strncpy(pbuf, smb_share_getpass(ssp), 543103396Sbp SMB_MAXPASSWORDLEN); 544103396Sbp pbuf[SMB_MAXPASSWORDLEN] = '\0'; 545103396Sbp } 54675374Sbp if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { 54775374Sbp plen = 24; 54875374Sbp smb_encrypt(pbuf, vcp->vc_ch, encpass); 54975374Sbp pp = encpass; 55075374Sbp } else { 55175374Sbp plen = strlen(pbuf) + 1; 55275374Sbp pp = pbuf; 55375374Sbp } 55475374Sbp } 55575374Sbp mbp = &rqp->sr_rq; 55675374Sbp smb_rq_wstart(rqp); 55775374Sbp mb_put_uint8(mbp, 0xff); 55875374Sbp mb_put_uint8(mbp, 0); 55975374Sbp mb_put_uint16le(mbp, 0); 56075374Sbp mb_put_uint16le(mbp, 0); /* Flags */ 56175374Sbp mb_put_uint16le(mbp, plen); 56275374Sbp smb_rq_wend(rqp); 56375374Sbp smb_rq_bstart(rqp); 56475374Sbp mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 56575374Sbp smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt); 56675374Sbp pp = vcp->vc_srvname; 56775374Sbp smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt); 56875374Sbp smb_put_dmem(mbp, vcp, "\\", 1, caseopt); 56975374Sbp pp = ssp->ss_name; 57075374Sbp smb_put_dstring(mbp, vcp, pp, caseopt); 57175374Sbp pp = smb_share_typename(ssp->ss_type); 57275374Sbp smb_put_dstring(mbp, vcp, pp, caseopt); 57375374Sbp smb_rq_bend(rqp); 57475374Sbp error = smb_rq_simple(rqp); 57575374Sbp SMBSDEBUG("%d\n", error); 57675374Sbp if (error) 57775374Sbp goto bad; 57875374Sbp ssp->ss_tid = rqp->sr_rptid; 57975374Sbp ssp->ss_vcgenid = vcp->vc_genid; 58075374Sbp ssp->ss_flags |= SMBS_CONNECTED; 581227650Skevlo /* 582227650Skevlo * If the server can speak Unicode then switch 583227650Skevlo * our converters to do Unicode <--> Local 584227650Skevlo */ 585227650Skevlo if (vcp->obj.co_flags & SMBV_UNICODE) { 586227650Skevlo vcp->vc_toserver = vcp->vc_ucs_toserver; 587227650Skevlo vcp->vc_tolocal = vcp->vc_ucs_tolocal; 588227650Skevlo vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE; 589227650Skevlo } 59075374Sbpbad: 59175374Sbp if (encpass) 59275374Sbp free(encpass, M_SMBTEMP); 59375374Sbp if (pbuf) 59475374Sbp free(pbuf, M_SMBTEMP); 59575374Sbp smb_rq_done(rqp); 596103396Sbp if (error && upper == 1) 597103396Sbp goto again; 59875374Sbp return error; 59975374Sbp} 60075374Sbp 60175374Sbpint 60275374Sbpsmb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred) 60375374Sbp{ 60475374Sbp struct smb_rq *rqp; 60575374Sbp struct mbchain *mbp; 60675374Sbp int error; 60775374Sbp 60875374Sbp if (ssp->ss_tid == SMB_TID_UNKNOWN) 60975374Sbp return 0; 61075374Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp); 61175374Sbp if (error) 61275374Sbp return error; 61375374Sbp mbp = &rqp->sr_rq; 61475374Sbp smb_rq_wstart(rqp); 61575374Sbp smb_rq_wend(rqp); 61675374Sbp smb_rq_bstart(rqp); 61775374Sbp smb_rq_bend(rqp); 61875374Sbp error = smb_rq_simple(rqp); 61975374Sbp SMBSDEBUG("%d\n", error); 62075374Sbp smb_rq_done(rqp); 62175374Sbp ssp->ss_tid = SMB_TID_UNKNOWN; 62275374Sbp return error; 62375374Sbp} 62475374Sbp 62575374Sbpstatic __inline int 626103395Sbpsmb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, 627103395Sbp struct uio *uio, struct smb_cred *scred) 628103395Sbp{ 629103395Sbp struct smb_rq *rqp; 630103395Sbp struct mbchain *mbp; 631103395Sbp struct mdchain *mdp; 632103395Sbp u_int8_t wc; 633103395Sbp int error; 634103395Sbp u_int16_t residhi, residlo, off, doff; 635103395Sbp u_int32_t resid; 636103395Sbp 637103395Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp); 638103395Sbp if (error) 639103395Sbp return error; 640103395Sbp smb_rq_getrequest(rqp, &mbp); 641103395Sbp smb_rq_wstart(rqp); 642103395Sbp mb_put_uint8(mbp, 0xff); /* no secondary command */ 643103395Sbp mb_put_uint8(mbp, 0); /* MBZ */ 644103395Sbp mb_put_uint16le(mbp, 0); /* offset to secondary */ 645103395Sbp mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 646103395Sbp mb_put_uint32le(mbp, uio->uio_offset); 647103395Sbp *len = min(SSTOVC(ssp)->vc_rxmax, *len); 648103395Sbp mb_put_uint16le(mbp, *len); /* MaxCount */ 649103395Sbp mb_put_uint16le(mbp, *len); /* MinCount (only indicates blocking) */ 650103395Sbp mb_put_uint32le(mbp, (unsigned)*len >> 16); /* MaxCountHigh */ 651103395Sbp mb_put_uint16le(mbp, *len); /* Remaining ("obsolete") */ 652103395Sbp mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */ 653103395Sbp smb_rq_wend(rqp); 654103395Sbp smb_rq_bstart(rqp); 655103395Sbp smb_rq_bend(rqp); 656103395Sbp do { 657103395Sbp error = smb_rq_simple(rqp); 658103395Sbp if (error) 659103395Sbp break; 660103395Sbp smb_rq_getreply(rqp, &mdp); 661103395Sbp off = SMB_HDRLEN; 662103395Sbp md_get_uint8(mdp, &wc); 663103395Sbp off++; 664103395Sbp if (wc != 12) { 665103395Sbp error = EBADRPC; 666103395Sbp break; 667103395Sbp } 668103395Sbp md_get_uint8(mdp, NULL); 669103395Sbp off++; 670103395Sbp md_get_uint8(mdp, NULL); 671103395Sbp off++; 672103395Sbp md_get_uint16le(mdp, NULL); 673103395Sbp off += 2; 674103395Sbp md_get_uint16le(mdp, NULL); 675103395Sbp off += 2; 676103395Sbp md_get_uint16le(mdp, NULL); /* data compaction mode */ 677103395Sbp off += 2; 678103395Sbp md_get_uint16le(mdp, NULL); 679103395Sbp off += 2; 680103395Sbp md_get_uint16le(mdp, &residlo); 681103395Sbp off += 2; 682103395Sbp md_get_uint16le(mdp, &doff); /* data offset */ 683103395Sbp off += 2; 684103395Sbp md_get_uint16le(mdp, &residhi); 685103395Sbp off += 2; 686103395Sbp resid = (residhi << 16) | residlo; 687103395Sbp md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); 688103395Sbp off += 4*2; 689103395Sbp md_get_uint16le(mdp, NULL); /* ByteCount */ 690103395Sbp off += 2; 691103395Sbp if (doff > off) /* pad byte(s)? */ 692103395Sbp md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); 693103395Sbp if (resid == 0) { 694103395Sbp *rresid = resid; 695103395Sbp break; 696103395Sbp } 697103395Sbp error = md_get_uio(mdp, uio, resid); 698103395Sbp if (error) 699103395Sbp break; 700103395Sbp *rresid = resid; 701103395Sbp } while(0); 702103395Sbp smb_rq_done(rqp); 703103395Sbp return (error); 704103395Sbp} 705103395Sbp 706103395Sbpstatic __inline int 707103395Sbpsmb_smb_writex(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, 708103395Sbp struct uio *uio, struct smb_cred *scred) 709103395Sbp{ 710103395Sbp struct smb_rq *rqp; 711103395Sbp struct mbchain *mbp; 712103395Sbp struct mdchain *mdp; 713103395Sbp int error; 714103395Sbp u_int8_t wc; 715103395Sbp u_int16_t resid; 716103395Sbp 717103395Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp); 718103395Sbp if (error) 719103395Sbp return (error); 720103395Sbp smb_rq_getrequest(rqp, &mbp); 721103395Sbp smb_rq_wstart(rqp); 722103395Sbp mb_put_uint8(mbp, 0xff); /* no secondary command */ 723103395Sbp mb_put_uint8(mbp, 0); /* MBZ */ 724103395Sbp mb_put_uint16le(mbp, 0); /* offset to secondary */ 725103395Sbp mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 726103395Sbp mb_put_uint32le(mbp, uio->uio_offset); 727103395Sbp mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ 728103395Sbp mb_put_uint16le(mbp, 0); /* !write-thru */ 729103395Sbp mb_put_uint16le(mbp, 0); 730103395Sbp *len = min(SSTOVC(ssp)->vc_wxmax, *len); 731103395Sbp mb_put_uint16le(mbp, (unsigned)*len >> 16); 732103395Sbp mb_put_uint16le(mbp, *len); 733103395Sbp mb_put_uint16le(mbp, 64); /* data offset from header start */ 734103395Sbp mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */ 735103395Sbp smb_rq_wend(rqp); 736103395Sbp smb_rq_bstart(rqp); 737103395Sbp do { 738103395Sbp mb_put_uint8(mbp, 0xee); /* mimic xp pad byte! */ 739103395Sbp error = mb_put_uio(mbp, uio, *len); 740103395Sbp if (error) 741103395Sbp break; 742103395Sbp smb_rq_bend(rqp); 743103395Sbp error = smb_rq_simple(rqp); 744103395Sbp if (error) 745103395Sbp break; 746103395Sbp smb_rq_getreply(rqp, &mdp); 747103395Sbp md_get_uint8(mdp, &wc); 748103395Sbp if (wc != 6) { 749103395Sbp error = EBADRPC; 750103395Sbp break; 751103395Sbp } 752103395Sbp md_get_uint8(mdp, NULL); 753103395Sbp md_get_uint8(mdp, NULL); 754103395Sbp md_get_uint16le(mdp, NULL); 755103395Sbp md_get_uint16le(mdp, &resid); 756103395Sbp *rresid = resid; 757103395Sbp } while(0); 758103395Sbp 759103395Sbp smb_rq_done(rqp); 760103395Sbp return (error); 761103395Sbp} 762103395Sbp 763103395Sbpstatic __inline int 76475374Sbpsmb_smb_read(struct smb_share *ssp, u_int16_t fid, 76575374Sbp int *len, int *rresid, struct uio *uio, struct smb_cred *scred) 76675374Sbp{ 76775374Sbp struct smb_rq *rqp; 76875374Sbp struct mbchain *mbp; 76975374Sbp struct mdchain *mdp; 77075374Sbp u_int16_t resid, bc; 77175374Sbp u_int8_t wc; 77275374Sbp int error, rlen, blksz; 77375374Sbp 774103395Sbp if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) 775103395Sbp return (smb_smb_readx(ssp, fid, len, rresid, uio, scred)); 776103395Sbp 77775374Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp); 77875374Sbp if (error) 77975374Sbp return error; 78075374Sbp 78175374Sbp blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; 78275374Sbp rlen = *len = min(blksz, *len); 78375374Sbp 78475374Sbp smb_rq_getrequest(rqp, &mbp); 78575374Sbp smb_rq_wstart(rqp); 78675374Sbp mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 78775374Sbp mb_put_uint16le(mbp, rlen); 78875374Sbp mb_put_uint32le(mbp, uio->uio_offset); 78975374Sbp mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff)); 79075374Sbp smb_rq_wend(rqp); 79175374Sbp smb_rq_bstart(rqp); 79275374Sbp smb_rq_bend(rqp); 79375374Sbp do { 79475374Sbp error = smb_rq_simple(rqp); 79575374Sbp if (error) 79675374Sbp break; 79775374Sbp smb_rq_getreply(rqp, &mdp); 79875374Sbp md_get_uint8(mdp, &wc); 79975374Sbp if (wc != 5) { 80075374Sbp error = EBADRPC; 80175374Sbp break; 80275374Sbp } 80375374Sbp md_get_uint16le(mdp, &resid); 80475374Sbp md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); 80575374Sbp md_get_uint16le(mdp, &bc); 80675374Sbp md_get_uint8(mdp, NULL); /* ignore buffer type */ 80775374Sbp md_get_uint16le(mdp, &resid); 80875374Sbp if (resid == 0) { 80975374Sbp *rresid = resid; 81075374Sbp break; 81175374Sbp } 81275374Sbp error = md_get_uio(mdp, uio, resid); 81375374Sbp if (error) 81475374Sbp break; 81575374Sbp *rresid = resid; 81675374Sbp } while(0); 81775374Sbp smb_rq_done(rqp); 81875374Sbp return error; 81975374Sbp} 82075374Sbp 82175374Sbpint 82275374Sbpsmb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio, 82375374Sbp struct smb_cred *scred) 82475374Sbp{ 82575374Sbp int tsize, len, resid; 82675374Sbp int error = 0; 82775374Sbp 82875374Sbp tsize = uio->uio_resid; 82975374Sbp while (tsize > 0) { 830170804Smjacob resid = 0; 83175374Sbp len = tsize; 83275374Sbp error = smb_smb_read(ssp, fid, &len, &resid, uio, scred); 83375374Sbp if (error) 83475374Sbp break; 83575374Sbp tsize -= resid; 83675374Sbp if (resid < len) 83775374Sbp break; 83875374Sbp } 83975374Sbp return error; 84075374Sbp} 84175374Sbp 84275374Sbpstatic __inline int 84375374Sbpsmb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, 84475374Sbp struct uio *uio, struct smb_cred *scred) 84575374Sbp{ 84675374Sbp struct smb_rq *rqp; 84775374Sbp struct mbchain *mbp; 84875374Sbp struct mdchain *mdp; 84975374Sbp u_int16_t resid; 85075374Sbp u_int8_t wc; 85175374Sbp int error, blksz; 85275374Sbp 853103395Sbp if (*len && SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) 854103395Sbp return (smb_smb_writex(ssp, fid, len, rresid, uio, scred)); 855103395Sbp 85675374Sbp blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; 85775374Sbp if (blksz > 0xffff) 85875374Sbp blksz = 0xffff; 85975374Sbp 86075374Sbp resid = *len = min(blksz, *len); 86175374Sbp 86275374Sbp error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); 86375374Sbp if (error) 86475374Sbp return error; 86575374Sbp smb_rq_getrequest(rqp, &mbp); 86675374Sbp smb_rq_wstart(rqp); 86775374Sbp mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 86875374Sbp mb_put_uint16le(mbp, resid); 86975374Sbp mb_put_uint32le(mbp, uio->uio_offset); 87075374Sbp mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff)); 87175374Sbp smb_rq_wend(rqp); 87275374Sbp smb_rq_bstart(rqp); 87375374Sbp mb_put_uint8(mbp, SMB_DT_DATA); 87475374Sbp mb_put_uint16le(mbp, resid); 87575374Sbp do { 87675374Sbp error = mb_put_uio(mbp, uio, resid); 87775374Sbp if (error) 87875374Sbp break; 87975374Sbp smb_rq_bend(rqp); 88075374Sbp error = smb_rq_simple(rqp); 88175374Sbp if (error) 88275374Sbp break; 88375374Sbp smb_rq_getreply(rqp, &mdp); 88475374Sbp md_get_uint8(mdp, &wc); 88575374Sbp if (wc != 1) { 88675374Sbp error = EBADRPC; 88775374Sbp break; 88875374Sbp } 88975374Sbp md_get_uint16le(mdp, &resid); 89075374Sbp *rresid = resid; 89175374Sbp } while(0); 89275374Sbp smb_rq_done(rqp); 89375374Sbp return error; 89475374Sbp} 89575374Sbp 89675374Sbpint 89775374Sbpsmb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio, 89875374Sbp struct smb_cred *scred) 89975374Sbp{ 90075374Sbp int error = 0, len, tsize, resid; 90175374Sbp struct uio olduio; 90275374Sbp 90375374Sbp tsize = uio->uio_resid; 90475374Sbp olduio = *uio; 90575374Sbp while (tsize > 0) { 906170804Smjacob resid = 0; 90775374Sbp len = tsize; 90875374Sbp error = smb_smb_write(ssp, fid, &len, &resid, uio, scred); 90975374Sbp if (error) 91075374Sbp break; 91175374Sbp if (resid < len) { 91275374Sbp error = EIO; 91375374Sbp break; 91475374Sbp } 91575374Sbp tsize -= resid; 91675374Sbp } 91775374Sbp if (error) { 91891023Sbp /* 91991023Sbp * Errors can happen on the copyin, the rpc, etc. So they 92091023Sbp * imply resid is unreliable. The only safe thing is 92191023Sbp * to pretend zero bytes made it. We needn't restore the 92291023Sbp * iovs because callers don't depend on them in error 92391023Sbp * paths - uio_resid and uio_offset are what matter. 92491023Sbp */ 92575374Sbp *uio = olduio; 92675374Sbp } 92775374Sbp return error; 92875374Sbp} 92975374Sbp 93075374Sbpint 93175374Sbpsmb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred) 93275374Sbp{ 93375374Sbp struct smb_rq *rqp; 93475374Sbp struct mbchain *mbp; 93575374Sbp int error; 93675374Sbp 93775374Sbp error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp); 93875374Sbp if (error) 93975374Sbp return error; 94075374Sbp mbp = &rqp->sr_rq; 94175374Sbp smb_rq_wstart(rqp); 94275374Sbp mb_put_uint16le(mbp, 1); 94375374Sbp smb_rq_wend(rqp); 94475374Sbp smb_rq_bstart(rqp); 94575374Sbp mb_put_uint32le(mbp, 0); 94675374Sbp smb_rq_bend(rqp); 94775374Sbp error = smb_rq_simple(rqp); 94875374Sbp SMBSDEBUG("%d\n", error); 94975374Sbp smb_rq_done(rqp); 95075374Sbp return error; 95175374Sbp} 952