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