39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43#include <sys/malloc.h> 44#include <sys/proc.h> 45#include <sys/lock.h> 46#include <sys/sysctl.h> 47#include <sys/socket.h> 48#include <sys/uio.h> 49 50#include <sys/iconv.h> 51 52#include <netsmb/smb.h> 53#include <netsmb/smb_subr.h> 54#include <netsmb/smb_rq.h> 55#include <netsmb/smb_conn.h> 56#include <netsmb/smb_tran.h> 57 58#include "opt_netsmb.h" 59 60struct smb_dialect { 61 int d_id; 62 const char * d_name; 63}; 64 65static struct smb_dialect smb_dialects[] = { 66 {SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"}, 67 {SMB_DIALECT_COREPLUS, "MICROSOFT NETWORKS 1.03"}, 68 {SMB_DIALECT_LANMAN1_0, "MICROSOFT NETWORKS 3.0"}, 69 {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"}, 70 {SMB_DIALECT_LANMAN2_0, "LM1.2X002"}, 71 {SMB_DIALECT_LANMAN2_0, "Samba"}, 72 {SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"}, 73 {SMB_DIALECT_NTLM0_12, "NT LM 0.12"}, 74 {-1, NULL} 75}; 76 77#define SMB_DIALECT_MAX (sizeof(smb_dialects) / sizeof(struct smb_dialect) - 2) 78 79static u_int32_t 80smb_vc_maxread(struct smb_vc *vcp) 81{ 82 /* 83 * Specs say up to 64k data bytes, but Windows traffic 84 * uses 60k... no doubt for some good reason. 85 * 86 * Don't exceed the server's buffer size if signatures 87 * are enabled otherwise Windows 2003 chokes. Allow space 88 * for the SMB header & a little bit extra. 89 */ 90 if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) && 91 (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) 92 return (60*1024); 93 else 94 return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64); 95} 96 97static u_int32_t 98smb_vc_maxwrite(struct smb_vc *vcp) 99{ 100 /* 101 * See comment above. 102 */ 103 if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) && 104 (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) 105 return (60*1024); 106 else 107 return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64); 108} 109 110static int 111smb_smb_nomux(struct smb_vc *vcp, struct smb_cred *scred, const char *name) 112{ 113 if (scred->scr_td->td_proc == vcp->vc_iod->iod_p) 114 return 0; 115 SMBERROR("wrong function called(%s)\n", name); 116 return EINVAL; 117} 118 119int 120smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) 121{ 122 struct smb_dialect *dp; 123 struct smb_sopt *sp = NULL; 124 struct smb_rq *rqp; 125 struct mbchain *mbp; 126 struct mdchain *mdp; 127 u_int8_t wc, stime[8], sblen; 128 u_int16_t dindex, tw, tw1, swlen, bc; 129 int error, maxqsz; 130 131 if (smb_smb_nomux(vcp, scred, __func__) != 0) 132 return EINVAL; 133 vcp->vc_hflags = 0; 134 vcp->vc_hflags2 = 0; 135 vcp->obj.co_flags &= ~(SMBV_ENCRYPT); 136 sp = &vcp->vc_sopt; 137 bzero(sp, sizeof(struct smb_sopt)); 138 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp); 139 if (error) 140 return error; 141 smb_rq_getrequest(rqp, &mbp); 142 smb_rq_wstart(rqp); 143 smb_rq_wend(rqp); 144 smb_rq_bstart(rqp); 145 for(dp = smb_dialects; dp->d_id != -1; dp++) { 146 mb_put_uint8(mbp, SMB_DT_DIALECT); 147 smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE); 148 } 149 smb_rq_bend(rqp); 150 error = smb_rq_simple(rqp); 151 SMBSDEBUG("%d\n", error); 152 if (error) 153 goto bad; 154 smb_rq_getreply(rqp, &mdp); 155 do { 156 error = md_get_uint8(mdp, &wc); 157 if (error) 158 break; 159 error = md_get_uint16le(mdp, &dindex); 160 if (error) 161 break; 162 if (dindex > 7) { 163 SMBERROR("Don't know how to talk with server %s (%d)\n", "xxx", dindex); 164 error = EBADRPC; 165 break; 166 } 167 dp = smb_dialects + dindex; 168 sp->sv_proto = dp->d_id; 169 SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc); 170 error = EBADRPC; 171 if (dp->d_id >= SMB_DIALECT_NTLM0_12) { 172 if (wc != 17) 173 break; 174 md_get_uint8(mdp, &sp->sv_sm); 175 md_get_uint16le(mdp, &sp->sv_maxmux); 176 md_get_uint16le(mdp, &sp->sv_maxvcs); 177 md_get_uint32le(mdp, &sp->sv_maxtx); 178 md_get_uint32le(mdp, &sp->sv_maxraw); 179 md_get_uint32le(mdp, &sp->sv_skey); 180 md_get_uint32le(mdp, &sp->sv_caps); 181 md_get_mem(mdp, stime, 8, MB_MSYSTEM); 182 md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); 183 md_get_uint8(mdp, &sblen); 184 if (sblen && (sp->sv_sm & SMB_SM_ENCRYPT)) { 185 if (sblen != SMB_MAXCHALLENGELEN) { 186 SMBERROR("Unexpected length of security blob (%d)\n", sblen); 187 break; 188 } 189 error = md_get_uint16(mdp, &bc); 190 if (error) 191 break; 192 if (sp->sv_caps & SMB_CAP_EXT_SECURITY) 193 md_get_mem(mdp, NULL, 16, MB_MSYSTEM); 194 error = md_get_mem(mdp, vcp->vc_ch, sblen, MB_MSYSTEM); 195 if (error) 196 break; 197 vcp->vc_chlen = sblen; 198 vcp->obj.co_flags |= SMBV_ENCRYPT; 199 } 200 if (sp->sv_sm & SMB_SM_SIGS_REQUIRE) 201 vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; 202 vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; 203 if (dp->d_id == SMB_DIALECT_NTLM0_12 && 204 sp->sv_maxtx < 4096 && 205 (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) { 206 vcp->obj.co_flags |= SMBV_WIN95; 207 SMBSDEBUG("Win95 detected\n"); 208 } 209 } else if (dp->d_id > SMB_DIALECT_CORE) { 210 md_get_uint16le(mdp, &tw); 211 sp->sv_sm = tw; 212 md_get_uint16le(mdp, &tw); 213 sp->sv_maxtx = tw; 214 md_get_uint16le(mdp, &sp->sv_maxmux); 215 md_get_uint16le(mdp, &sp->sv_maxvcs); 216 md_get_uint16le(mdp, &tw); /* rawmode */ 217 md_get_uint32le(mdp, &sp->sv_skey); 218 if (wc == 13) { /* >= LANMAN1 */ 219 md_get_uint16(mdp, &tw); /* time */ 220 md_get_uint16(mdp, &tw1); /* date */ 221 md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz); 222 md_get_uint16le(mdp, &swlen); 223 if (swlen > SMB_MAXCHALLENGELEN) 224 break; 225 md_get_uint16(mdp, NULL); /* mbz */ 226 if (md_get_uint16(mdp, &bc) != 0) 227 break; 228 if (bc < swlen) 229 break; 230 if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) { 231 error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM); 232 if (error) 233 break; 234 vcp->vc_chlen = swlen; 235 vcp->obj.co_flags |= SMBV_ENCRYPT; 236 } 237 } 238 vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; 239 } else { /* an old CORE protocol */ 240 sp->sv_maxmux = 1; 241 } 242 error = 0; 243 } while (0); 244 if (error == 0) { 245 vcp->vc_maxvcs = sp->sv_maxvcs; 246 if (vcp->vc_maxvcs <= 1) { 247 if (vcp->vc_maxvcs == 0) 248 vcp->vc_maxvcs = 1; 249 } 250 if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff) 251 sp->sv_maxtx = 1024; 252 else 253 sp->sv_maxtx = min(sp->sv_maxtx, 254 63*1024 + SMB_HDRLEN + 16); 255 SMB_TRAN_GETPARAM(vcp, SMBTP_RCVSZ, &maxqsz); 256 vcp->vc_rxmax = min(smb_vc_maxread(vcp), maxqsz - 1024); 257 SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz); 258 vcp->vc_wxmax = min(smb_vc_maxwrite(vcp), maxqsz - 1024); 259 vcp->vc_txmax = min(sp->sv_maxtx, maxqsz); 260 SMBSDEBUG("TZ = %d\n", sp->sv_tz); 261 SMBSDEBUG("CAPS = %x\n", sp->sv_caps); 262 SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux); 263 SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs); 264 SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw); 265 SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx); 266 } 267bad: 268 smb_rq_done(rqp); 269 return error; 270} 271 272int 273smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) 274{ 275 struct smb_rq *rqp; 276 struct mbchain *mbp; 277/* u_int8_t wc; 278 u_int16_t tw, tw1;*/ 279 smb_uniptr unipp, ntencpass = NULL; 280 char *pp, *up, *pbuf, *encpass; 281 int error, plen, uniplen, ulen, upper; 282 283 upper = 0; 284 285again: 286 287 vcp->vc_smbuid = SMB_UID_UNKNOWN; 288 289 if (smb_smb_nomux(vcp, scred, __func__) != 0) 290 return EINVAL; 291 292 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp); 293 if (error) 294 return error; 295 pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); 296 encpass = malloc(24, M_SMBTEMP, M_WAITOK); 297 if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { 298 /* 299 * We try w/o uppercasing first so Samba mixed case 300 * passwords work. If that fails we come back and try 301 * uppercasing to satisfy OS/2 and Windows for Workgroups. 302 */ 303 if (upper++) { 304 iconv_convstr(vcp->vc_toupper, pbuf, 305 smb_vc_getpass(vcp)/*, SMB_MAXPASSWORDLEN*/); 306 } else { 307 strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN); 308 pbuf[SMB_MAXPASSWORDLEN] = '\0'; 309 } 310 if (!SMB_UNICODE_STRINGS(vcp)) 311 iconv_convstr(vcp->vc_toserver, pbuf, pbuf/*, 312 SMB_MAXPASSWORDLEN*/); 313 314 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { 315 uniplen = plen = 24; 316 smb_encrypt(pbuf, vcp->vc_ch, encpass); 317 ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK); 318 if (SMB_UNICODE_STRINGS(vcp)) { 319 strncpy(pbuf, smb_vc_getpass(vcp), 320 SMB_MAXPASSWORDLEN); 321 pbuf[SMB_MAXPASSWORDLEN] = '\0'; 322 } else 323 iconv_convstr(vcp->vc_toserver, pbuf, 324 smb_vc_getpass(vcp)/*, 325 SMB_MAXPASSWORDLEN*/); 326 smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass); 327 pp = encpass; 328 unipp = ntencpass; 329 } else { 330 plen = strlen(pbuf) + 1; 331 pp = pbuf; 332 uniplen = plen * 2; 333 ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK); 334 smb_strtouni(ntencpass, smb_vc_getpass(vcp)); 335 plen--; 336 337 /* 338 * The uniplen is zeroed because Samba cannot deal 339 * with this 2nd cleartext password. This Samba 340 * "bug" is actually a workaround for problems in 341 * Microsoft clients. 342 */ 343 uniplen = 0/*-= 2*/; 344 unipp = ntencpass; 345 } 346 } else { 347 /* 348 * In the share security mode password will be used 349 * only in the tree authentication 350 */ 351 pp = ""; 352 plen = 1; 353 unipp = &smb_unieol; 354 uniplen = 0 /* sizeof(smb_unieol) */; 355 } 356 smb_rq_wstart(rqp); 357 mbp = &rqp->sr_rq; 358 up = vcp->vc_username; 359 ulen = strlen(up) + 1; 360 /* 361 * If userid is null we are attempting anonymous browse login 362 * so passwords must be zero length. 363 */ 364 if (ulen == 1) 365 plen = uniplen = 0; 366 mb_put_uint8(mbp, 0xff); 367 mb_put_uint8(mbp, 0); 368 mb_put_uint16le(mbp, 0); 369 mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx); 370 mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux); 371 mb_put_uint16le(mbp, vcp->vc_number); 372 mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey); 373 mb_put_uint16le(mbp, plen); 374 if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) { 375 mb_put_uint32le(mbp, 0); 376 smb_rq_wend(rqp); 377 smb_rq_bstart(rqp); 378 mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 379 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); 380 } else { 381 mb_put_uint16le(mbp, uniplen); 382 mb_put_uint32le(mbp, 0); /* reserved */ 383 mb_put_uint32le(mbp, vcp->obj.co_flags & SMBV_UNICODE ? 384 SMB_CAP_UNICODE : 0); 385 smb_rq_wend(rqp); 386 smb_rq_bstart(rqp); 387 mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 388 mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM); 389 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* AccountName */ 390 smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */ 391 smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE); /* Client's OS */ 392 smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE); /* Client name */ 393 } 394 smb_rq_bend(rqp); 395 if (ntencpass) 396 free(ntencpass, M_SMBTEMP); 397 if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) 398 smb_calcmackey(vcp); 399 error = smb_rq_simple(rqp); 400 SMBSDEBUG("%d\n", error); 401 if (error) { 402 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess) 403 error = EAUTH; 404 goto bad; 405 } 406 vcp->vc_smbuid = rqp->sr_rpuid; 407bad: 408 free(encpass, M_SMBTEMP); 409 free(pbuf, M_SMBTEMP); 410 smb_rq_done(rqp); 411 if (error && upper == 1 && vcp->vc_sopt.sv_sm & SMB_SM_USER) 412 goto again; 413 return error; 414} 415 416int 417smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred) 418{ 419 struct smb_rq *rqp; 420 struct mbchain *mbp; 421 int error; 422 423 if (vcp->vc_smbuid == SMB_UID_UNKNOWN) 424 return 0; 425 426 if (smb_smb_nomux(vcp, scred, __func__) != 0) 427 return EINVAL; 428 429 error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp); 430 if (error) 431 return error; 432 mbp = &rqp->sr_rq; 433 smb_rq_wstart(rqp); 434 mb_put_uint8(mbp, 0xff); 435 mb_put_uint8(mbp, 0); 436 mb_put_uint16le(mbp, 0); 437 smb_rq_wend(rqp); 438 smb_rq_bstart(rqp); 439 smb_rq_bend(rqp); 440 error = smb_rq_simple(rqp); 441 SMBSDEBUG("%d\n", error); 442 smb_rq_done(rqp); 443 return error; 444} 445 446static char smb_any_share[] = "?????"; 447 448static char * 449smb_share_typename(int stype) 450{ 451 char *pp; 452 453 switch (stype) { 454 case SMB_ST_DISK: 455 pp = "A:"; 456 break; 457 case SMB_ST_PRINTER: 458 pp = smb_any_share; /* can't use LPT: here... */ 459 break; 460 case SMB_ST_PIPE: 461 pp = "IPC"; 462 break; 463 case SMB_ST_COMM: 464 pp = "COMM"; 465 break; 466 case SMB_ST_ANY: 467 default: 468 pp = smb_any_share; 469 break; 470 } 471 return pp; 472} 473 474int 475smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) 476{ 477 struct smb_vc *vcp; 478 struct smb_rq rq, *rqp = &rq; 479 struct mbchain *mbp; 480 char *pp, *pbuf, *encpass; 481 int error, plen, caseopt, upper; 482 483 upper = 0; 484 485again: 486 487#if 0 488 /* Disable Unicode for SMB_COM_TREE_CONNECT_ANDX requests */ 489 if (SSTOVC(ssp)->vc_hflags2 & SMB_FLAGS2_UNICODE) { 490 vcp = SSTOVC(ssp); 491 if (vcp->vc_toserver) { 492 iconv_close(vcp->vc_toserver); 493 /* Use NULL until UTF-8 -> ASCII works */ 494 vcp->vc_toserver = NULL; 495 } 496 if (vcp->vc_tolocal) { 497 iconv_close(vcp->vc_tolocal); 498 /* Use NULL until ASCII -> UTF-8 works*/ 499 vcp->vc_tolocal = NULL; 500 } 501 vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE; 502 } 503#endif 504 505 ssp->ss_tid = SMB_TID_UNKNOWN; 506 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp); 507 if (error) 508 return error; 509 vcp = rqp->sr_vc; 510 caseopt = SMB_CS_NONE; 511 if (vcp->vc_sopt.sv_sm & SMB_SM_USER) { 512 plen = 1; 513 pp = ""; 514 pbuf = NULL; 515 encpass = NULL; 516 } else { 517 pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK); 518 encpass = malloc(24, M_SMBTEMP, M_WAITOK); 519 /* 520 * We try w/o uppercasing first so Samba mixed case 521 * passwords work. If that fails we come back and try 522 * uppercasing to satisfy OS/2 and Windows for Workgroups. 523 */ 524 if (upper++) { 525 iconv_convstr(vcp->vc_toupper, pbuf, 526 smb_share_getpass(ssp)/*, 527 SMB_MAXPASSWORDLEN*/); 528 } else { 529 strncpy(pbuf, smb_share_getpass(ssp), 530 SMB_MAXPASSWORDLEN); 531 pbuf[SMB_MAXPASSWORDLEN] = '\0'; 532 } 533 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) { 534 plen = 24; 535 smb_encrypt(pbuf, vcp->vc_ch, encpass); 536 pp = encpass; 537 } else { 538 plen = strlen(pbuf) + 1; 539 pp = pbuf; 540 } 541 } 542 mbp = &rqp->sr_rq; 543 smb_rq_wstart(rqp); 544 mb_put_uint8(mbp, 0xff); 545 mb_put_uint8(mbp, 0); 546 mb_put_uint16le(mbp, 0); 547 mb_put_uint16le(mbp, 0); /* Flags */ 548 mb_put_uint16le(mbp, plen); 549 smb_rq_wend(rqp); 550 smb_rq_bstart(rqp); 551 mb_put_mem(mbp, pp, plen, MB_MSYSTEM); 552 smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt); 553 pp = vcp->vc_srvname; 554 smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt); 555 smb_put_dmem(mbp, vcp, "\\", 1, caseopt); 556 pp = ssp->ss_name; 557 smb_put_dstring(mbp, vcp, pp, caseopt); 558 pp = smb_share_typename(ssp->ss_type); 559 smb_put_dstring(mbp, vcp, pp, caseopt); 560 smb_rq_bend(rqp); 561 error = smb_rq_simple(rqp); 562 SMBSDEBUG("%d\n", error); 563 if (error) 564 goto bad; 565 ssp->ss_tid = rqp->sr_rptid; 566 ssp->ss_vcgenid = vcp->vc_genid; 567 ssp->ss_flags |= SMBS_CONNECTED; 568bad: 569 if (encpass) 570 free(encpass, M_SMBTEMP); 571 if (pbuf) 572 free(pbuf, M_SMBTEMP); 573 smb_rq_done(rqp); 574 if (error && upper == 1) 575 goto again; 576 return error; 577} 578 579int 580smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred) 581{ 582 struct smb_rq *rqp; 583 struct mbchain *mbp; 584 int error; 585 586 if (ssp->ss_tid == SMB_TID_UNKNOWN) 587 return 0; 588 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp); 589 if (error) 590 return error; 591 mbp = &rqp->sr_rq; 592 smb_rq_wstart(rqp); 593 smb_rq_wend(rqp); 594 smb_rq_bstart(rqp); 595 smb_rq_bend(rqp); 596 error = smb_rq_simple(rqp); 597 SMBSDEBUG("%d\n", error); 598 smb_rq_done(rqp); 599 ssp->ss_tid = SMB_TID_UNKNOWN; 600 return error; 601} 602 603static __inline int 604smb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, 605 struct uio *uio, struct smb_cred *scred) 606{ 607 struct smb_rq *rqp; 608 struct mbchain *mbp; 609 struct mdchain *mdp; 610 u_int8_t wc; 611 int error; 612 u_int16_t residhi, residlo, off, doff; 613 u_int32_t resid; 614 615 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp); 616 if (error) 617 return error; 618 smb_rq_getrequest(rqp, &mbp); 619 smb_rq_wstart(rqp); 620 mb_put_uint8(mbp, 0xff); /* no secondary command */ 621 mb_put_uint8(mbp, 0); /* MBZ */ 622 mb_put_uint16le(mbp, 0); /* offset to secondary */ 623 mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 624 mb_put_uint32le(mbp, uio->uio_offset); 625 *len = min(SSTOVC(ssp)->vc_rxmax, *len); 626 mb_put_uint16le(mbp, *len); /* MaxCount */ 627 mb_put_uint16le(mbp, *len); /* MinCount (only indicates blocking) */ 628 mb_put_uint32le(mbp, (unsigned)*len >> 16); /* MaxCountHigh */ 629 mb_put_uint16le(mbp, *len); /* Remaining ("obsolete") */ 630 mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */ 631 smb_rq_wend(rqp); 632 smb_rq_bstart(rqp); 633 smb_rq_bend(rqp); 634 do { 635 error = smb_rq_simple(rqp); 636 if (error) 637 break; 638 smb_rq_getreply(rqp, &mdp); 639 off = SMB_HDRLEN; 640 md_get_uint8(mdp, &wc); 641 off++; 642 if (wc != 12) { 643 error = EBADRPC; 644 break; 645 } 646 md_get_uint8(mdp, NULL); 647 off++; 648 md_get_uint8(mdp, NULL); 649 off++; 650 md_get_uint16le(mdp, NULL); 651 off += 2; 652 md_get_uint16le(mdp, NULL); 653 off += 2; 654 md_get_uint16le(mdp, NULL); /* data compaction mode */ 655 off += 2; 656 md_get_uint16le(mdp, NULL); 657 off += 2; 658 md_get_uint16le(mdp, &residlo); 659 off += 2; 660 md_get_uint16le(mdp, &doff); /* data offset */ 661 off += 2; 662 md_get_uint16le(mdp, &residhi); 663 off += 2; 664 resid = (residhi << 16) | residlo; 665 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); 666 off += 4*2; 667 md_get_uint16le(mdp, NULL); /* ByteCount */ 668 off += 2; 669 if (doff > off) /* pad byte(s)? */ 670 md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); 671 if (resid == 0) { 672 *rresid = resid; 673 break; 674 } 675 error = md_get_uio(mdp, uio, resid); 676 if (error) 677 break; 678 *rresid = resid; 679 } while(0); 680 smb_rq_done(rqp); 681 return (error); 682} 683 684static __inline int 685smb_smb_writex(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid, 686 struct uio *uio, struct smb_cred *scred) 687{ 688 struct smb_rq *rqp; 689 struct mbchain *mbp; 690 struct mdchain *mdp; 691 int error; 692 u_int8_t wc; 693 u_int16_t resid; 694 695 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp); 696 if (error) 697 return (error); 698 smb_rq_getrequest(rqp, &mbp); 699 smb_rq_wstart(rqp); 700 mb_put_uint8(mbp, 0xff); /* no secondary command */ 701 mb_put_uint8(mbp, 0); /* MBZ */ 702 mb_put_uint16le(mbp, 0); /* offset to secondary */ 703 mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 704 mb_put_uint32le(mbp, uio->uio_offset); 705 mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ 706 mb_put_uint16le(mbp, 0); /* !write-thru */ 707 mb_put_uint16le(mbp, 0); 708 *len = min(SSTOVC(ssp)->vc_wxmax, *len); 709 mb_put_uint16le(mbp, (unsigned)*len >> 16); 710 mb_put_uint16le(mbp, *len); 711 mb_put_uint16le(mbp, 64); /* data offset from header start */ 712 mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */ 713 smb_rq_wend(rqp); 714 smb_rq_bstart(rqp); 715 do { 716 mb_put_uint8(mbp, 0xee); /* mimic xp pad byte! */ 717 error = mb_put_uio(mbp, uio, *len); 718 if (error) 719 break; 720 smb_rq_bend(rqp); 721 error = smb_rq_simple(rqp); 722 if (error) 723 break; 724 smb_rq_getreply(rqp, &mdp); 725 md_get_uint8(mdp, &wc); 726 if (wc != 6) { 727 error = EBADRPC; 728 break; 729 } 730 md_get_uint8(mdp, NULL); 731 md_get_uint8(mdp, NULL); 732 md_get_uint16le(mdp, NULL); 733 md_get_uint16le(mdp, &resid); 734 *rresid = resid; 735 } while(0); 736 737 smb_rq_done(rqp); 738 return (error); 739} 740 741static __inline int 742smb_smb_read(struct smb_share *ssp, u_int16_t fid, 743 int *len, int *rresid, struct uio *uio, struct smb_cred *scred) 744{ 745 struct smb_rq *rqp; 746 struct mbchain *mbp; 747 struct mdchain *mdp; 748 u_int16_t resid, bc; 749 u_int8_t wc; 750 int error, rlen, blksz; 751 752 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) 753 return (smb_smb_readx(ssp, fid, len, rresid, uio, scred)); 754 755 error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp); 756 if (error) 757 return error; 758 759 blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16; 760 rlen = *len = min(blksz, *len); 761 762 smb_rq_getrequest(rqp, &mbp); 763 smb_rq_wstart(rqp); 764 mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM); 765 mb_put_uint16le(mbp, rlen); 766 mb_put_uint32le(mbp, uio->uio_offset); 767 mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff)); 768 smb_rq_wend(rqp); 769 smb_rq_bstart(rqp); 770 smb_rq_bend(rqp); 771 do { 772 error = smb_rq_simple(rqp); 773 if (error) 774 break; 775 smb_rq_getreply(rqp, &mdp); 776 md_get_uint8(mdp, &wc); 777 if (wc != 5) { 778 error = EBADRPC; 779 break; 780 } 781 md_get_uint16le(mdp, &resid); 782 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); 783 md_get_uint16le(mdp, &bc); 784 md_get_uint8(mdp, NULL); /* ignore buffer type */ 785 md_get_uint16le(mdp, &resid); 786 if (resid == 0) { 787 *rresid = resid; 788 break; 789 } 790 error = md_get_uio(mdp, uio, resid); 791 if (error) 792 break; 793 *rresid = resid; 794 } while(0); 795 smb_rq_done(rqp); 796 return error; 797} 798 799int 800smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio, 801 struct smb_cred *scred) 802{ 803 int tsize, len, resid; 804 int error = 0; 805 806 tsize = uio->uio_resid; 807 while (tsize > 0) {
|