1 /* 2 * Copyright (c) 2000-2001 Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD: src/sys/netsmb/smb_smb.c,v 1.1.2.3 2002/12/14 14:44:19 fjoe Exp $ 33 */ 34 /* 35 * various SMB requests. Most of the routines merely packs data into mbufs. 36 */ 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 #include <sys/proc.h> 42 #include <sys/lock.h> 43 #include <sys/sysctl.h> 44 #include <sys/socket.h> 45 #include <sys/uio.h> 46 47 #include <sys/iconv.h> 48 #include <machine/limits.h> 49 50 #include "smb.h" 51 #include "smb_subr.h" 52 #include "smb_rq.h" 53 #include "smb_conn.h" 54 #include "smb_tran.h" 55 56 #include "opt_netsmb.h" 57 58 struct smb_dialect { 59 int d_id; 60 const char * d_name; 61 }; 62 63 static struct smb_dialect smb_dialects[] = { 64 {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"}, 65 {SMB_DIALECT_COREPLUS, "MICROSOFT NETWORKS 1.03"}, 66 {SMB_DIALECT_LANMAN1_0, "MICROSOFT NETWORKS 3.0"}, 67 {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"}, 68 {SMB_DIALECT_LANMAN2_0, "LM1.2X002"}, 69 {SMB_DIALECT_LANMAN2_0, "Samba"}, 70 {SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"}, 71 {SMB_DIALECT_NTLM0_12, "NT LM 0.12"}, 72 {-1, NULL} 73 }; 74 75 #define SMB_DIALECT_MAX (NELEM(smb_dialects) - 2) 76 77 static int 78 smb_smb_nomux(struct smb_vc *vcp, struct smb_cred *scred, const char *name) 79 { 80 if (scred->scr_td == vcp->vc_iod->iod_td) 81 return 0; 82 SMBERROR("wrong function called(%s)\n", name); 83 return EINVAL; 84 } 85 86 int 87 smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) 88 { 89 struct smb_dialect *dp; 90 struct smb_sopt *sp = NULL; 91 struct smb_rq *rqp; 92 struct mbchain *mbp; 93 struct mdchain *mdp; 94 u_int8_t wc, stime[8], sblen; 95 u_int16_t dindex, tw, tw1, swlen, bc; 96 int error, maxqsz; 97 98 if (smb_smb_nomux(vcp, scred, __func__) != 0) 99 return EINVAL; 100 vcp->vc_hflags = 0; 101 vcp->vc_hflags2 = 0; 102 vcp->obj.co_flags &= ~(SMBV_ENCRYPT); 103 sp = &vcp->vc_sopt; 104 bzero(sp, sizeof(struct smb_sopt)); 105 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp); 106 if (error) 107 return error; 108 smb_rq_getrequest(rqp, &mbp); 109 smb_rq_wstart(rqp); 110 smb_rq_wend(rqp); 111 smb_rq_bstart(rqp); 112 for(dp = smb_dialects; dp->d_id != -1; dp++) { 113 mb_put_uint8(mbp, SMB_DT_DIALECT); 114 smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE); 115 } 116 smb_rq_bend(rqp); 117 error = smb_rq_simple(rqp); 118 SMBSDEBUG("%d\n", error); 119 if (error) 120 goto bad; 121 smb_rq_getreply(rqp, &mdp); 122 do { 123 error = md_get_uint8(mdp, &wc); 124 if (error) 125 break; 126 error = md_get_uint16le(mdp, &dindex); 127 if (error) 128 break; 129 if (dindex > 7) { 130 SMBERROR("Don't know how to talk with server %s (%d)\n", "xxx", dindex); 131 error = EBADRPC; 132 break; 133 } 134 dp = smb_dialects + dindex; 135 sp->sv_proto = dp->d_id; 136 SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc); 137 error = EBADRPC; 138 if (dp->d_id >= SMB_DIALECT_NTLM0_12) { 139 if (wc != 17) 140 break; 141 md_get_uint8(mdp, &sp->sv_sm); 142 md_get_uint16le(mdp, &sp->sv_maxmux); 143 md_get_uint16le(mdp, &sp->sv_maxvcs); 144 md_get_uint32le(mdp, &sp->sv_maxtx); 145 md_get_uint32le(mdp, &sp->sv_maxraw); 146 md_get_uint32le(mdp, &sp->sv_skey); 147 md_get_uint32le(mdp, &sp->sv_caps); 148 md_get_mem(mdp, stime, 8, MB_MSYSTEM); 149 md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); 150 md_get_uint8(mdp, &sblen); 151 if (sblen && (sp->sv_sm & SMB_SM_ENCRYPT)) { 152 if (sblen != SMB_MAXCHALLENGELEN) { 153 SMBERROR("Unexpected length of security blob (%d)\n", sblen); 154 break; 155 } 156 error = md_get_uint16(mdp, &bc); 157 if (error) 158 break; 159 if (sp->sv_caps & SMB_CAP_EXT_SECURITY) 160 md_get_mem(mdp, NULL, 16, MB_MSYSTEM); 161 error = md_get_mem(mdp, vcp->vc_ch, sblen, MB_MSYSTEM); 162 if (error) 163 break; 164 vcp->vc_chlen = sblen; 165 vcp->obj.co_flags |= SMBV_ENCRYPT; 166 } 167 if (sp->sv_sm & SMB_SM_SIGS_REQUIRE) 168 vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; 169 vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; 170 if (dp->d_id == SMB_DIALECT_NTLM0_12 && 171 sp->sv_maxtx < 4096 && 172 (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) { 173 vcp->obj.co_flags |= SMBV_WIN95; 174 SMBSDEBUG("Win95 detected\n"); 175 } 176 } else if (dp->d_id > SMB_DIALECT_CORE) { 177 md_get_uint16le(mdp, &tw); 178 sp->sv_sm = tw; 179 md_get_uint16le(mdp, &tw); 180 sp->sv_maxtx = tw; 181 md_get_uint16le(mdp, &sp->sv_maxmux); 182 md_get_uint16le(mdp, &sp->sv_maxvcs); 183 md_get_uint16le(mdp, &tw); /* rawmode */ 184 md_get_uint32le(mdp, &sp->sv_skey); 185 if (wc == 13) { /* >= LANMAN1 */ 186 md_get_uint16(mdp, &tw); /* time */ 187 md_get_uint16(mdp, &tw1); /* date */ 188 md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); 189 md_get_uint16le(mdp, &swlen); 190 if (swlen > SMB_MAXCHALLENGELEN) 191 break; 192 md_get_uint16(mdp, NULL); /* mbz */ 193 if (md_get_uint16(mdp, &bc) != 0) 194 break; 195 if (bc < swlen) 196 break; 197 if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) { 198 error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM); 199 if (error) 200 break; 201 vcp->vc_chlen = swlen; 202 vcp->obj.co_flags |= SMBV_ENCRYPT; 203 } 204 } 205 vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; 206 } else { /* an old CORE protocol */ 207 sp->sv_maxmux = 1; 208 } 209 error = 0; 210 } while (0); 211 if (error == 0) { 212 vcp->vc_maxvcs = sp->sv_maxvcs; 213 if (vcp->vc_maxvcs <= 1) { 214 if (vcp->vc_maxvcs == 0) 215 vcp->vc_maxvcs = 1; 216 } 217 if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff) 218 sp->sv_maxtx = 1024; 219 SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz); 220 vcp->vc_txmax = min(sp->sv_maxtx, maxqsz); 221 SMBSDEBUG("TZ = %d\n", sp->sv_tz); 222 SMBSDEBUG("CAPS = %x\n", sp->sv_caps); 223 SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux); 224 SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs); 225 SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw); 226 SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx); 227 } 228 bad: 229 smb_rq_done(rqp); 230 return error; 231 } 232 233 int 234 smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) 235 { 236 struct smb_rq *rqp; 237 struct mbchain *mbp; 238 /* u_int8_t wc; 239 u_int16_t tw, tw1;*/ 240 smb_uniptr unipp, ntencpass = NULL; 241 char *pp, *up, *pbuf, *encpass; 242 int error, plen, uniplen; 243 244 vcp->vc_smbuid = SMB_UID_UNKNOWN; 245 246 if (smb_smb_nomux(vcp, scred, __func__) != 0) 247 return EINVAL; 248 249 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp); 250 if (error) 251 return error; 252 pbuf = kmalloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); 253 encpass = kmalloc(24, M_SMBTEMP, M_WAITOK); 254 if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { 255 iconv_convstr(vcp->vc_toupper, pbuf, smb_vc_getpass(vcp)); 256 iconv_convstr(vcp->vc_toserver, pbuf, pbuf); 257 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { 258 uniplen = plen = 24; 259 smb_encrypt(pbuf, vcp->vc_ch, encpass); 260 ntencpass = kmalloc(uniplen, M_SMBTEMP, M_WAITOK); 261 iconv_convstr(vcp->vc_toserver, pbuf, smb_vc_getpass(vcp)); 262 smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass); 263 pp = encpass; 264 unipp = ntencpass; 265 } else { 266 plen = strlen(pbuf) + 1; 267 pp = pbuf; 268 uniplen = plen * 2; 269 ntencpass = kmalloc(uniplen, M_SMBTEMP, M_WAITOK); 270 smb_strtouni(ntencpass, smb_vc_getpass(vcp)); 271 plen--; 272 273 /* 274 * The uniplen is zeroed because Samba cannot deal 275 * with this 2nd cleartext password. This Samba 276 * "bug" is actually a workaround for problems in 277 * Microsoft clients. 278 */ 279 uniplen = 0/*-= 2*/; 280 unipp = ntencpass; 281 } 282 } else { 283 /* 284 * In the share security mode password will be used 285 * only in the tree authentication 286 */ 287 pp = ""; 288 plen = 1; 289 unipp = &smb_unieol; 290 uniplen = 0 /* sizeof(smb_unieol) */; 291 } 292 smb_rq_wstart(rqp); 293 mbp = &rqp->sr_rq; 294 up = vcp->vc_username; 295 mb_put_uint8(mbp, 0xff); 296 mb_put_uint8(mbp, 0); 297 mb_put_uint16le(mbp, 0); 298 mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx); 299 mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux); 300 mb_put_uint16le(mbp, vcp->vc_number); 301 mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey); 302 mb_put_uint16le(mbp, plen); 303 if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) { 304 mb_put_uint32le(mbp, 0); 305 smb_rq_wend(rqp); 306 smb_rq_bstart(rqp); 307 mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 308 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); 309 } else { 310 mb_put_uint16le(mbp, uniplen); 311 mb_put_uint32le(mbp, 0); /* reserved */ 312 mb_put_uint32le(mbp, vcp->obj.co_flags & SMBV_UNICODE ? 313 SMB_CAP_UNICODE : 0); 314 smb_rq_wend(rqp); 315 smb_rq_bstart(rqp); 316 mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 317 mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM); 318 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* AccountName */ 319 smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */ 320 smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE); /* Client's OS */ 321 smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE); /* Client name */ 322 } 323 smb_rq_bend(rqp); 324 if (ntencpass) 325 kfree(ntencpass, M_SMBTEMP); 326 if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) 327 smb_calcmackey(vcp); 328 error = smb_rq_simple(rqp); 329 SMBSDEBUG("%d\n", error); 330 if (error) { 331 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess) 332 error = EAUTH; 333 goto bad; 334 } 335 vcp->vc_smbuid = rqp->sr_rpuid; 336 bad: 337 kfree(encpass, M_SMBTEMP); 338 kfree(pbuf, M_SMBTEMP); 339 smb_rq_done(rqp); 340 return error; 341 } 342 343 int 344 smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred) 345 { 346 struct smb_rq *rqp; 347 struct mbchain *mbp; 348 int error; 349 350 if (vcp->vc_smbuid == SMB_UID_UNKNOWN) 351 return 0; 352 353 if (smb_smb_nomux(vcp, scred, __func__) != 0) 354 return EINVAL; 355 356 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp); 357 if (error) 358 return error; 359 mbp = &rqp->sr_rq; 360 smb_rq_wstart(rqp); 361 mb_put_uint8(mbp, 0xff); 362 mb_put_uint8(mbp, 0); 363 mb_put_uint16le(mbp, 0); 364 smb_rq_wend(rqp); 365 smb_rq_bstart(rqp); 366 smb_rq_bend(rqp); 367 error = smb_rq_simple(rqp); 368 SMBSDEBUG("%d\n", error); 369 smb_rq_done(rqp); 370 return error; 371 } 372 373 static char smb_any_share[] = "?????"; 374 375 static char * 376 smb_share_typename(int stype) 377 { 378 char *pp; 379 380 switch (stype) { 381 case SMB_ST_DISK: 382 pp = "A:"; 383 break; 384 case SMB_ST_PRINTER: 385 pp = smb_any_share; /* can't use LPT: here... */ 386 break; 387 case SMB_ST_PIPE: 388 pp = "IPC"; 389 break; 390 case SMB_ST_COMM: 391 pp = "COMM"; 392 break; 393 case SMB_ST_ANY: 394 default: 395 pp = smb_any_share; 396 break; 397 } 398 return pp; 399 } 400 401 int 402 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) 403 { 404 struct smb_vc *vcp; 405 struct smb_rq rq, *rqp = &rq; 406 struct mbchain *mbp; 407 char *pp, *pbuf, *encpass; 408 int error, plen, caseopt; 409 410 ssp->ss_tid = SMB_TID_UNKNOWN; 411 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp); 412 if (error) 413 return error; 414 vcp = rqp->sr_vc; 415 caseopt = SMB_CS_NONE; 416 if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { 417 plen = 1; 418 pp = ""; 419 pbuf = NULL; 420 encpass = NULL; 421 } else { 422 pbuf = kmalloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); 423 encpass = kmalloc(24, M_SMBTEMP, M_WAITOK); 424 iconv_convstr(vcp->vc_toupper, pbuf, smb_share_getpass(ssp)); 425 iconv_convstr(vcp->vc_toserver, pbuf, pbuf); 426 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { 427 plen = 24; 428 smb_encrypt(pbuf, vcp->vc_ch, encpass); 429 pp = encpass; 430 } else { 431 plen = strlen(pbuf) + 1; 432 pp = pbuf; 433 } 434 } 435 mbp = &rqp->sr_rq; 436 smb_rq_wstart(rqp); 437 mb_put_uint8(mbp, 0xff); 438 mb_put_uint8(mbp, 0); 439 mb_put_uint16le(mbp, 0); 440 mb_put_uint16le(mbp, 0); /* Flags */ 441 mb_put_uint16le(mbp, plen); 442 smb_rq_wend(rqp); 443 smb_rq_bstart(rqp); 444 mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 445 smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt); 446 pp = vcp->vc_srvname; 447 smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt); 448 smb_put_dmem(mbp, vcp, "\\", 1, caseopt); 449 pp = ssp->ss_name; 450 smb_put_dstring(mbp, vcp, pp, caseopt); 451 pp = smb_share_typename(ssp->ss_type); 452 smb_put_dstring(mbp, vcp, pp, caseopt); 453 smb_rq_bend(rqp); 454 error = smb_rq_simple(rqp); 455 SMBSDEBUG("%d\n", error); 456 if (error) 457 goto bad; 458 ssp->ss_tid = rqp->sr_rptid; 459 ssp->ss_vcgenid = vcp->vc_genid; 460 ssp->ss_flags |= SMBS_CONNECTED; 461 bad: 462 if (encpass) 463 kfree(encpass, M_SMBTEMP); 464 if (pbuf) 465 kfree(pbuf, M_SMBTEMP); 466 smb_rq_done(rqp); 467 return error; 468 } 469 470 int 471 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred) 472 { 473 struct smb_rq *rqp; 474 int error; 475 476 if (ssp->ss_tid == SMB_TID_UNKNOWN) 477 return 0; 478 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp); 479 if (error) 480 return error; 481 smb_rq_wstart(rqp); 482 smb_rq_wend(rqp); 483 smb_rq_bstart(rqp); 484 smb_rq_bend(rqp); 485 error = smb_rq_simple(rqp); 486 SMBSDEBUG("%d\n", error); 487 smb_rq_done(rqp); 488 ssp->ss_tid = SMB_TID_UNKNOWN; 489 return error; 490 } 491 492 static __inline int 493 smb_smb_read(struct smb_share *ssp, u_int16_t fid, 494 int *len, int *rresid, struct uio *uio, struct smb_cred *scred) 495 { 496 struct smb_rq *rqp; 497 struct mbchain *mbp; 498 struct mdchain *mdp; 499 u_int16_t resid, bc; 500 u_int8_t wc; 501 int error, rlen, blksz; 502 503 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp); 504 if (error) 505 return error; 506 507 blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; 508 rlen = *len = min(blksz, *len); 509 510 smb_rq_getrequest(rqp, &mbp); 511 smb_rq_wstart(rqp); 512 mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 513 mb_put_uint16le(mbp, rlen); 514 mb_put_uint32le(mbp, uio->uio_offset); 515 mb_put_uint16le(mbp, (unsigned short)szmin(uio->uio_resid, 0xffff)); 516 smb_rq_wend(rqp); 517 smb_rq_bstart(rqp); 518 smb_rq_bend(rqp); 519 do { 520 error = smb_rq_simple(rqp); 521 if (error) 522 break; 523 smb_rq_getreply(rqp, &mdp); 524 md_get_uint8(mdp, &wc); 525 if (wc != 5) { 526 error = EBADRPC; 527 break; 528 } 529 md_get_uint16le(mdp, &resid); 530 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); 531 md_get_uint16le(mdp, &bc); 532 md_get_uint8(mdp, NULL); /* ignore buffer type */ 533 md_get_uint16le(mdp, &resid); 534 if (resid == 0) { 535 *rresid = resid; 536 break; 537 } 538 error = md_get_uio(mdp, uio, resid); 539 if (error) 540 break; 541 *rresid = resid; 542 } while(0); 543 smb_rq_done(rqp); 544 return error; 545 } 546 547 int 548 smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio, 549 struct smb_cred *scred) 550 { 551 int len, resid; 552 int error = 0; 553 554 while (uio->uio_resid > 0) { 555 if (uio->uio_resid > INT_MAX) 556 len = INT_MAX; 557 else 558 len = (int)uio->uio_resid; 559 error = smb_smb_read(ssp, fid, &len, &resid, uio, scred); 560 if (error) 561 break; 562 if (resid < len) 563 break; 564 } 565 return error; 566 } 567 568 static __inline int 569 smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, 570 struct uio *uio, struct smb_cred *scred) 571 { 572 struct smb_rq *rqp; 573 struct mbchain *mbp; 574 struct mdchain *mdp; 575 u_int16_t resid; 576 u_int8_t wc; 577 int error, blksz; 578 579 /* write data must be real */ 580 KKASSERT(uio->uio_segflg != UIO_NOCOPY); 581 582 blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; 583 if (blksz > 0xffff) 584 blksz = 0xffff; 585 586 resid = *len = min(blksz, *len); 587 588 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp); 589 if (error) 590 return error; 591 smb_rq_getrequest(rqp, &mbp); 592 smb_rq_wstart(rqp); 593 mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 594 mb_put_uint16le(mbp, resid); 595 mb_put_uint32le(mbp, uio->uio_offset); 596 mb_put_uint16le(mbp, (unsigned short)szmin(uio->uio_resid, 0xffff)); 597 smb_rq_wend(rqp); 598 smb_rq_bstart(rqp); 599 mb_put_uint8(mbp, SMB_DT_DATA); 600 mb_put_uint16le(mbp, resid); 601 do { 602 error = mb_put_uio(mbp, uio, resid); 603 if (error) 604 break; 605 smb_rq_bend(rqp); 606 error = smb_rq_simple(rqp); 607 if (error) 608 break; 609 smb_rq_getreply(rqp, &mdp); 610 md_get_uint8(mdp, &wc); 611 if (wc != 1) { 612 error = EBADRPC; 613 break; 614 } 615 md_get_uint16le(mdp, &resid); 616 *rresid = resid; 617 } while(0); 618 smb_rq_done(rqp); 619 return error; 620 } 621 622 int 623 smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio, 624 struct smb_cred *scred) 625 { 626 int error = 0, len, resid; 627 struct uio olduio; 628 629 olduio = *uio; 630 while (uio->uio_resid > 0) { 631 if (uio->uio_resid > INT_MAX) 632 len = INT_MAX; 633 else 634 len = (int)uio->uio_resid; 635 error = smb_smb_write(ssp, fid, &len, &resid, uio, scred); 636 if (error) 637 break; 638 if (resid < len) { 639 error = EIO; 640 break; 641 } 642 } 643 if (error) { 644 /* 645 * Errors can happen on the copyin, the rpc, etc. So they 646 * imply resid is unreliable. The only safe thing is 647 * to pretend zero bytes made it. We needn't restore the 648 * iovs because callers don't depend on them in error 649 * paths - uio_resid and uio_offset are what matter. 650 */ 651 *uio = olduio; 652 } 653 return error; 654 } 655 656 int 657 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred) 658 { 659 struct smb_rq *rqp; 660 struct mbchain *mbp; 661 int error; 662 663 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp); 664 if (error) 665 return error; 666 mbp = &rqp->sr_rq; 667 smb_rq_wstart(rqp); 668 mb_put_uint16le(mbp, 1); 669 smb_rq_wend(rqp); 670 smb_rq_bstart(rqp); 671 mb_put_uint32le(mbp, 0); 672 smb_rq_bend(rqp); 673 error = smb_rq_simple(rqp); 674 SMBSDEBUG("%d\n", error); 675 smb_rq_done(rqp); 676 return error; 677 } 678