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