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