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