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