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