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 * $Id: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $ 33 */ 34 35 /* 36 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/time.h> 43 #include <sys/vnode.h> 44 #include <sys/cmn_err.h> 45 46 #ifdef APPLE 47 #include <sys/smb_apple.h> 48 #include <sys/utfconv.h> 49 #else 50 #include <netsmb/smb_osdep.h> 51 #endif 52 53 #include <netsmb/smb.h> 54 #include <netsmb/smb_conn.h> 55 #include <netsmb/smb_subr.h> 56 #include <netsmb/smb_rq.h> 57 58 #include <smbfs/smbfs.h> 59 #include <smbfs/smbfs_node.h> 60 #include <smbfs/smbfs_subr.h> 61 62 /* 63 * Local functions. 64 * Not static, to aid debugging. 65 */ 66 67 int smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap, 68 struct smb_cred *scrp, short infolevel); 69 int smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap, 70 struct smb_cred *scrp, short infolevel); 71 int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, 72 struct smbfattr *fap, struct smb_cred *scrp); 73 74 int smbfs_smb_statfsLM1(struct smb_share *ssp, 75 statvfs64_t *sbp, struct smb_cred *scrp); 76 int smbfs_smb_statfsLM2(struct smb_share *ssp, 77 statvfs64_t *sbp, struct smb_cred *scrp); 78 79 int smbfs_smb_setftime1(struct smbnode *np, uint16_t fid, 80 struct timespec *mtime, struct timespec *atime, 81 struct smb_cred *scrp); 82 int smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid, 83 uint32_t attr, struct timespec *mtime, struct timespec *atime, 84 struct smb_cred *scrp); 85 86 int smbfs_smb_setpattr1(struct smbnode *np, 87 const char *name, int len, uint32_t attr, 88 struct timespec *mtime, struct smb_cred *scrp); 89 int smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr, 90 struct timespec *mtime, struct timespec *atime, 91 struct smb_cred *scrp); 92 int smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr, 93 struct timespec *mtime, struct timespec *atime, 94 struct smb_cred *scrp); 95 96 97 /* 98 * Todo: locking over-the-wire 99 */ 100 #ifdef APPLE 101 102 static int 103 smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid, 104 offset_t start, uint64_t len, int largelock, 105 struct smb_cred *scrp, uint32_t timeout) 106 { 107 struct smb_share *ssp = np->n_mount->smi_share; 108 struct smb_rq rq, *rqp = &rq; 109 struct mbchain *mbp; 110 uint8_t ltype = 0; 111 int error; 112 113 /* Shared lock for n_fid use below. */ 114 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); 115 116 if (op == SMB_LOCK_SHARED) 117 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; 118 if (largelock) 119 ltype |= SMB_LOCKING_ANDX_LARGE_FILES; 120 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp); 121 if (error) 122 return (error); 123 smb_rq_getrequest(rqp, &mbp); 124 smb_rq_wstart(rqp); 125 mb_put_uint8(mbp, 0xff); /* secondary command */ 126 mb_put_uint8(mbp, 0); /* MBZ */ 127 mb_put_uint16le(mbp, 0); 128 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 129 mb_put_uint8(mbp, ltype); /* locktype */ 130 mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ 131 mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */ 132 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); 133 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); 134 smb_rq_wend(rqp); 135 smb_rq_bstart(rqp); 136 mb_put_uint16le(mbp, pid); 137 if (!largelock) { 138 mb_put_uint32le(mbp, start); 139 mb_put_uint32le(mbp, len); 140 } else { 141 mb_put_uint16le(mbp, 0); /* pad */ 142 mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */ 143 mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */ 144 mb_put_uint32le(mbp, len >> 32); /* LengthHigh */ 145 mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */ 146 } 147 smb_rq_bend(rqp); 148 /* 149 * Don't want to risk missing a successful 150 * unlock send or lock response, or we could 151 * lose track of an outstanding lock. 152 */ 153 if (op == SMB_LOCK_RELEASE) 154 rqp->sr_flags |= SMBR_NOINTR_SEND; 155 else 156 rqp->sr_flags |= SMBR_NOINTR_RECV; 157 158 error = smb_rq_simple(rqp); 159 smb_rq_done(rqp); 160 return (error); 161 } 162 163 int 164 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, 165 offset_t start, uint64_t len, int largelock, 166 struct smb_cred *scrp, uint32_t timeout) 167 { 168 struct smb_share *ssp = np->n_mount->smi_share; 169 170 if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0) 171 /* 172 * TODO: use LOCK_BYTE_RANGE here. 173 */ 174 return (EINVAL); 175 else 176 return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len, 177 largelock, scrp, timeout)); 178 } 179 180 #endif /* APPLE */ 181 182 /* 183 * Helper for smbfs_getattr 184 * Something like nfs_getattr_otw 185 */ 186 int 187 smbfs_smb_getfattr( 188 struct smbnode *np, 189 struct smbfattr *fap, 190 struct smb_cred *scrp) 191 { 192 int error; 193 194 /* 195 * This lock is really only necessary for qfileinfo, 196 * but hopefully we use that most of the time. 197 * Lock may be writer (via open) or reader. 198 */ 199 ASSERT(np->r_lkserlock.count != 0); 200 201 /* 202 * Extended attribute directory or file. 203 */ 204 if (np->n_flag & N_XATTR) { 205 error = smbfs_xa_getfattr(np, fap, scrp); 206 return (error); 207 } 208 209 if (np->n_fidrefs) 210 error = smbfs_smb_qfileinfo(np, fap, scrp, 0); 211 else 212 error = smbfs_smb_qpathinfo(np, fap, scrp, 0); 213 214 if (error == EINVAL) { 215 /* fallback */ 216 error = smbfs_smb_query_info(np, NULL, 0, fap, scrp); 217 } 218 219 /* 220 * Note directory size is not provided by 221 * windows servers (they leave it as zero) 222 */ 223 if ((fap->fa_attr & SMB_FA_DIR) && 224 (fap->fa_size < DEV_BSIZE)) 225 fap->fa_size = DEV_BSIZE; 226 227 return (error); 228 } 229 230 231 /* 232 * Nearly identical to smbfs_smb_qfileinfo (below). 233 * Please keep them in sync. 234 */ 235 int 236 smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap, 237 struct smb_cred *scrp, short infolevel) 238 { 239 struct smb_share *ssp = np->n_mount->smi_share; 240 struct smb_vc *vcp = SSTOVC(ssp); 241 struct smb_t2rq *t2p; 242 int error, svtz, timesok = 1; 243 struct mbchain *mbp; 244 struct mdchain *mdp; 245 uint16_t date, time, wattr; 246 uint64_t llongint, lsize; 247 uint32_t size, dattr; 248 249 top: 250 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION, 251 scrp, &t2p); 252 if (error) 253 return (error); 254 mbp = &t2p->t2_tparam; 255 mb_init(mbp); 256 if (!infolevel) { 257 if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) 258 infolevel = SMB_QFILEINFO_STANDARD; 259 else 260 infolevel = SMB_QFILEINFO_ALL_INFO; 261 } 262 mb_put_uint16le(mbp, infolevel); 263 mb_put_uint32le(mbp, 0); 264 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ 265 error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); 266 if (error) { 267 smb_t2_done(t2p); 268 return (error); 269 } 270 t2p->t2_maxpcount = 2; 271 t2p->t2_maxdcount = vcp->vc_txmax; 272 error = smb_t2_request(t2p); 273 if (error) { 274 smb_t2_done(t2p); 275 /* Invalid info level? Try fallback. */ 276 if (error == EINVAL && 277 infolevel == SMB_QFILEINFO_ALL_INFO) { 278 infolevel = SMB_QFILEINFO_STANDARD; 279 goto top; 280 } 281 return (error); 282 } 283 mdp = &t2p->t2_rdata; 284 svtz = vcp->vc_sopt.sv_tz; 285 switch (infolevel) { 286 case SMB_QFILEINFO_STANDARD: 287 timesok = 0; 288 md_get_uint16le(mdp, NULL); 289 md_get_uint16le(mdp, NULL); /* creation time */ 290 md_get_uint16le(mdp, &date); 291 md_get_uint16le(mdp, &time); /* access time */ 292 if (date || time) { 293 timesok++; 294 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); 295 } 296 md_get_uint16le(mdp, &date); 297 md_get_uint16le(mdp, &time); /* modify time */ 298 if (date || time) { 299 timesok++; 300 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); 301 } 302 md_get_uint32le(mdp, &size); 303 fap->fa_size = size; 304 md_get_uint32(mdp, NULL); /* allocation size */ 305 md_get_uint16le(mdp, &wattr); 306 fap->fa_attr = wattr; 307 break; 308 case SMB_QFILEINFO_ALL_INFO: 309 timesok = 0; 310 /* creation time (discard) */ 311 md_get_uint64(mdp, NULL); 312 /* last access time */ 313 md_get_uint64le(mdp, &llongint); 314 if (llongint) { 315 timesok++; 316 smb_time_NT2local(llongint, svtz, &fap->fa_atime); 317 } 318 /* last write time */ 319 md_get_uint64le(mdp, &llongint); 320 if (llongint) { 321 timesok++; 322 smb_time_NT2local(llongint, svtz, &fap->fa_mtime); 323 } 324 /* last change time */ 325 md_get_uint64le(mdp, &llongint); 326 if (llongint) { 327 timesok++; 328 smb_time_NT2local(llongint, svtz, &fap->fa_ctime); 329 } 330 /* attributes */ 331 md_get_uint32le(mdp, &dattr); 332 fap->fa_attr = dattr; 333 /* 334 * 4-Byte alignment - discard 335 * Specs doesn't talk about this. 336 */ 337 md_get_uint32le(mdp, NULL); 338 /* allocation size (discard) */ 339 md_get_uint64le(mdp, NULL); 340 /* File size */ 341 md_get_uint64le(mdp, &lsize); 342 fap->fa_size = lsize; 343 break; 344 default: 345 SMBVDEBUG("unexpected info level %d\n", infolevel); 346 error = EINVAL; 347 } 348 smb_t2_done(t2p); 349 /* 350 * if all times are zero (observed with FAT on NT4SP6) 351 * then fall back to older info level 352 */ 353 if (!timesok) { 354 if (infolevel == SMB_QFILEINFO_ALL_INFO) { 355 infolevel = SMB_QFILEINFO_STANDARD; 356 goto top; 357 } 358 error = EINVAL; 359 } 360 return (error); 361 } 362 363 /* 364 * Nearly identical to smbfs_smb_qpathinfo (above). 365 * Please keep them in sync. 366 */ 367 int 368 smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap, 369 struct smb_cred *scrp, short infolevel) 370 { 371 struct smb_share *ssp = np->n_mount->smi_share; 372 struct smb_vc *vcp = SSTOVC(ssp); 373 struct smb_t2rq *t2p; 374 int error, svtz, timesok = 1; 375 struct mbchain *mbp; 376 struct mdchain *mdp; 377 uint16_t date, time, wattr; 378 uint64_t llongint, lsize; 379 uint32_t size, dattr; 380 381 /* 382 * Shared lock for n_fid use below. 383 * See smbfs_smb_getfattr() 384 */ 385 ASSERT(np->r_lkserlock.count != 0); 386 387 if (np->n_fid == SMB_FID_UNUSED) 388 return (EBADF); 389 390 top: 391 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FILE_INFORMATION, 392 scrp, &t2p); 393 if (error) 394 return (error); 395 mbp = &t2p->t2_tparam; 396 mb_init(mbp); 397 if (!infolevel) { 398 if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) 399 infolevel = SMB_QFILEINFO_STANDARD; 400 else 401 infolevel = SMB_QFILEINFO_ALL_INFO; 402 } 403 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 404 mb_put_uint16le(mbp, infolevel); 405 t2p->t2_maxpcount = 2; 406 t2p->t2_maxdcount = vcp->vc_txmax; 407 error = smb_t2_request(t2p); 408 if (error) { 409 smb_t2_done(t2p); 410 /* Invalid info level? Try fallback. */ 411 if (error == EINVAL && 412 infolevel == SMB_QFILEINFO_ALL_INFO) { 413 infolevel = SMB_QFILEINFO_STANDARD; 414 goto top; 415 } 416 return (error); 417 } 418 mdp = &t2p->t2_rdata; 419 svtz = vcp->vc_sopt.sv_tz; 420 switch (infolevel) { 421 case SMB_QFILEINFO_STANDARD: 422 timesok = 0; 423 md_get_uint16le(mdp, NULL); 424 md_get_uint16le(mdp, NULL); /* creation time */ 425 md_get_uint16le(mdp, &date); 426 md_get_uint16le(mdp, &time); /* access time */ 427 if (date || time) { 428 timesok++; 429 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); 430 } 431 md_get_uint16le(mdp, &date); 432 md_get_uint16le(mdp, &time); /* modify time */ 433 if (date || time) { 434 timesok++; 435 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); 436 } 437 md_get_uint32le(mdp, &size); 438 fap->fa_size = size; 439 md_get_uint32(mdp, NULL); /* allocation size */ 440 md_get_uint16le(mdp, &wattr); 441 fap->fa_attr = wattr; 442 break; 443 case SMB_QFILEINFO_ALL_INFO: 444 timesok = 0; 445 /* creation time (discard) */ 446 md_get_uint64(mdp, NULL); 447 /* last access time */ 448 md_get_uint64le(mdp, &llongint); 449 if (llongint) { 450 timesok++; 451 smb_time_NT2local(llongint, svtz, &fap->fa_atime); 452 } 453 /* last write time */ 454 md_get_uint64le(mdp, &llongint); 455 if (llongint) { 456 timesok++; 457 smb_time_NT2local(llongint, svtz, &fap->fa_mtime); 458 } 459 /* last change time */ 460 md_get_uint64le(mdp, &llongint); 461 if (llongint) { 462 timesok++; 463 smb_time_NT2local(llongint, svtz, &fap->fa_ctime); 464 } 465 /* attributes */ 466 md_get_uint32le(mdp, &dattr); 467 fap->fa_attr = dattr; 468 /* 469 * 4-Byte alignment - discard 470 * Specs doesn't talk about this. 471 */ 472 md_get_uint32le(mdp, NULL); 473 /* allocation size (discard) */ 474 md_get_uint64le(mdp, NULL); 475 /* File size */ 476 md_get_uint64le(mdp, &lsize); 477 fap->fa_size = lsize; 478 break; 479 default: 480 SMBVDEBUG("unexpected info level %d\n", infolevel); 481 error = EINVAL; 482 } 483 smb_t2_done(t2p); 484 /* 485 * if all times are zero (observed with FAT on NT4SP6) 486 * then fall back to older info level 487 */ 488 if (!timesok) { 489 if (infolevel == SMB_QFILEINFO_ALL_INFO) { 490 infolevel = SMB_QFILEINFO_STANDARD; 491 goto top; 492 } 493 error = EINVAL; 494 } 495 return (error); 496 } 497 498 /* 499 * Support functions for _qstreaminfo 500 * See smbfs_xattr.c 501 */ 502 503 int 504 smbfs_smb_qfsattr(struct smb_share *ssp, uint32_t *attrp, 505 struct smb_cred *scrp) 506 { 507 struct smb_t2rq *t2p; 508 struct mbchain *mbp; 509 struct mdchain *mdp; 510 uint32_t nlen; 511 int error; 512 char *fs_name; /* will malloc whatever the size is */ 513 struct smbfs_fctx ctx; 514 515 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, 516 scrp, &t2p); 517 if (error) 518 return (error); 519 mbp = &t2p->t2_tparam; 520 mb_init(mbp); 521 mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO); 522 t2p->t2_maxpcount = 4; 523 t2p->t2_maxdcount = 4 * 3 + 512; 524 error = smb_t2_request(t2p); 525 if (error) { 526 smb_t2_done(t2p); 527 return (error); 528 } 529 mdp = &t2p->t2_rdata; 530 md_get_uint32le(mdp, attrp); 531 md_get_uint32le(mdp, &ssp->ss_maxfilenamelen); 532 md_get_uint32le(mdp, &nlen); /* fs name length */ 533 if (ssp->ss_fsname == NULL && nlen) { 534 ctx.f_ssp = ssp; 535 ctx.f_name = kmem_alloc(nlen, KM_SLEEP); 536 ctx.f_namesz = nlen; 537 md_get_mem(mdp, ctx.f_name, nlen, MB_MSYSTEM); 538 ctx.f_nmlen = nlen; 539 smbfs_fname_tolocal(&ctx); 540 fs_name = kmem_alloc(ctx.f_nmlen+1, KM_SLEEP); 541 bcopy(ctx.f_name, fs_name, ctx.f_nmlen); 542 fs_name[ctx.f_nmlen] = '\0'; 543 ssp->ss_fsname = fs_name; 544 kmem_free(ctx.f_name, ctx.f_namesz); 545 /* 546 * If fs_name isn't NTFS they probably require resume keys. 547 * This is another example of the client trying to fix a server 548 * bug. This code uses the logic created by PR-3983209. See 549 * long block comment in smbfs_smb_findnextLM2. 550 */ 551 if (strcmp(fs_name, "NTFS")) { 552 SMB_SS_LOCK(ssp); 553 ssp->ss_flags |= SMBS_RESUMEKEYS; 554 SMB_SS_UNLOCK(ssp); 555 } 556 SMBVDEBUG("(fyi) share '%s', attr 0x%x, maxfilename %d\n", 557 ssp->ss_fsname, *attrp, ssp->ss_maxfilenamelen); 558 } 559 smb_t2_done(t2p); 560 return (0); 561 } 562 563 int 564 smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp, 565 struct smb_cred *scp) 566 { 567 int error; 568 569 if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) 570 error = smbfs_smb_statfsLM2(ssp, sbp, scp); 571 else 572 error = smbfs_smb_statfsLM1(ssp, sbp, scp); 573 574 return (error); 575 } 576 577 int 578 smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp, 579 struct smb_cred *scrp) 580 { 581 struct smb_t2rq *t2p; 582 struct mbchain *mbp; 583 struct mdchain *mdp; 584 uint16_t bsize; 585 uint32_t units, bpu, funits; 586 uint64_t s, t, f; 587 int error; 588 589 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, 590 scrp, &t2p); 591 if (error) 592 return (error); 593 mbp = &t2p->t2_tparam; 594 mb_init(mbp); 595 mb_put_uint16le(mbp, SMB_QFS_ALLOCATION); 596 t2p->t2_maxpcount = 4; 597 t2p->t2_maxdcount = 4 * 4 + 2; 598 error = smb_t2_request(t2p); 599 if (error) { 600 smb_t2_done(t2p); 601 return (error); 602 } 603 mdp = &t2p->t2_rdata; 604 md_get_uint32(mdp, NULL); /* fs id */ 605 md_get_uint32le(mdp, &bpu); 606 md_get_uint32le(mdp, &units); 607 md_get_uint32le(mdp, &funits); 608 md_get_uint16le(mdp, &bsize); 609 s = bsize; 610 s *= bpu; 611 t = units; 612 f = funits; 613 /* 614 * Don't allow over-large blocksizes as they determine 615 * Finder List-view size granularities. On the other 616 * hand, we mustn't let the block count overflow the 617 * 31 bits available. 618 */ 619 while (s > 16 * 1024) { 620 if (t > LONG_MAX) 621 break; 622 s /= 2; 623 t *= 2; 624 f *= 2; 625 } 626 while (t > LONG_MAX) { 627 t /= 2; 628 f /= 2; 629 s *= 2; 630 } 631 sbp->f_bsize = (ulong_t)s; /* file system block size */ 632 sbp->f_blocks = t; /* total data blocks in file system */ 633 sbp->f_bfree = f; /* free blocks in fs */ 634 sbp->f_bavail = f; /* free blocks avail to non-superuser */ 635 sbp->f_files = (-1); /* total file nodes in file system */ 636 sbp->f_ffree = (-1); /* free file nodes in fs */ 637 smb_t2_done(t2p); 638 return (0); 639 } 640 641 int 642 smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp, 643 struct smb_cred *scrp) 644 { 645 struct smb_rq rq, *rqp = &rq; 646 struct mdchain *mdp; 647 uint16_t units, bpu, bsize, funits; 648 uint64_t s, t, f; 649 int error; 650 651 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, 652 scrp); 653 if (error) 654 return (error); 655 smb_rq_wstart(rqp); 656 smb_rq_wend(rqp); 657 smb_rq_bstart(rqp); 658 smb_rq_bend(rqp); 659 error = smb_rq_simple(rqp); 660 if (error) { 661 smb_rq_done(rqp); 662 return (error); 663 } 664 smb_rq_getreply(rqp, &mdp); 665 md_get_uint16le(mdp, &units); 666 md_get_uint16le(mdp, &bpu); 667 md_get_uint16le(mdp, &bsize); 668 md_get_uint16le(mdp, &funits); 669 s = bsize; 670 s *= bpu; 671 t = units; 672 f = funits; 673 /* 674 * Don't allow over-large blocksizes as they determine 675 * Finder List-view size granularities. On the other 676 * hand, we mustn't let the block count overflow the 677 * 31 bits available. 678 */ 679 while (s > 16 * 1024) { 680 if (t > LONG_MAX) 681 break; 682 s /= 2; 683 t *= 2; 684 f *= 2; 685 } 686 while (t > LONG_MAX) { 687 t /= 2; 688 f /= 2; 689 s *= 2; 690 } 691 sbp->f_bsize = (ulong_t)s; /* file system block size */ 692 sbp->f_blocks = t; /* total data blocks in file system */ 693 sbp->f_bfree = f; /* free blocks in fs */ 694 sbp->f_bavail = f; /* free blocks avail to non-superuser */ 695 sbp->f_files = (-1); /* total file nodes in file system */ 696 sbp->f_ffree = (-1); /* free file nodes in fs */ 697 smb_rq_done(rqp); 698 return (0); 699 } 700 701 int 702 smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize, 703 struct smb_cred *scrp) 704 { 705 struct smb_t2rq *t2p; 706 struct smb_vc *vcp = SSTOVC(ssp); 707 struct mbchain *mbp; 708 int error; 709 710 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 711 scrp, &t2p); 712 if (error) 713 return (error); 714 mbp = &t2p->t2_tparam; 715 mb_init(mbp); 716 mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); 717 if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) 718 mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION); 719 else 720 mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO); 721 mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */ 722 mbp = &t2p->t2_tdata; 723 mb_init(mbp); 724 mb_put_uint64le(mbp, newsize); 725 mb_put_uint32le(mbp, 0); /* padding */ 726 mb_put_uint16le(mbp, 0); 727 t2p->t2_maxpcount = 2; 728 t2p->t2_maxdcount = 0; 729 error = smb_t2_request(t2p); 730 smb_t2_done(t2p); 731 return (error); 732 } 733 734 /*ARGSUSED*/ 735 int 736 smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp, 737 const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite) 738 { 739 struct smb_t2rq *t2p; 740 struct smb_share *ssp = np->n_mount->smi_share; 741 struct smb_vc *vcp = SSTOVC(ssp); 742 struct mbchain *mbp; 743 int32_t *ucslenp; 744 int error, cerror; 745 uint16_t fid = 0; 746 747 /* Shared lock for n_fid use below. */ 748 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); 749 750 if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)) 751 return (ENOTSUP); 752 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 753 scrp, &t2p); 754 if (error) 755 return (error); 756 if (tdnp) { 757 error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp, 758 &fid); 759 if (error) 760 goto exit; 761 } 762 mbp = &t2p->t2_tparam; 763 mb_init(mbp); 764 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 765 mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION); 766 mb_put_uint16le(mbp, 0); /* reserved, nowadays */ 767 mbp = &t2p->t2_tdata; 768 mb_init(mbp); 769 mb_put_uint32le(mbp, overwrite); 770 mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); /* base for tname */ 771 mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */ 772 ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t)); 773 mbp->mb_count = 0; 774 error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE); 775 if (error) 776 goto exit; 777 mbp->mb_count--; /* don't count the null */ 778 *ucslenp = htolel(mbp->mb_count); 779 t2p->t2_maxpcount = 2; 780 t2p->t2_maxdcount = 0; 781 error = smb_t2_request(t2p); 782 exit: 783 if (fid) { 784 cerror = smbfs_smb_tmpclose(tdnp, fid, scrp); 785 if (cerror) 786 SMBERROR("error %d closing fid %d\n", cerror, fid); 787 } 788 smb_t2_done(t2p); 789 return (error); 790 } 791 792 int 793 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp) 794 { 795 struct smb_share *ssp = np->n_mount->smi_share; 796 struct smb_rq rq, *rqp = &rq; 797 struct mbchain *mbp; 798 int error; 799 800 /* Shared lock for n_fid use below. */ 801 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); 802 803 if (!(np->n_flag & NFLUSHWIRE)) 804 return (0); 805 if (np->n_fidrefs == 0) 806 return (0); /* not open */ 807 808 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp); 809 if (error) 810 return (error); 811 smb_rq_getrequest(rqp, &mbp); 812 smb_rq_wstart(rqp); 813 mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM); 814 smb_rq_wend(rqp); 815 smb_rq_bstart(rqp); 816 smb_rq_bend(rqp); 817 error = smb_rq_simple(rqp); 818 smb_rq_done(rqp); 819 if (!error) { 820 mutex_enter(&np->r_statelock); 821 np->n_flag &= ~NFLUSHWIRE; 822 mutex_exit(&np->r_statelock); 823 } 824 return (error); 825 } 826 827 int 828 smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize, 829 struct smb_cred *scrp) 830 { 831 struct smb_share *ssp = np->n_mount->smi_share; 832 struct smb_rq rq, *rqp = &rq; 833 struct mbchain *mbp; 834 int error; 835 836 /* 837 * This call knows about 64-bit offsets. 838 */ 839 error = smbfs_smb_seteof(ssp, fid, newsize, scrp); 840 if (!error) { 841 mutex_enter(&np->r_statelock); 842 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); 843 mutex_exit(&np->r_statelock); 844 return (0); 845 } 846 847 /* 848 * If we have SMB_CAP_LARGE_FILES, the above 849 * should have worked. XXX: Don't fallback? 850 * XXX: Or fallback on specific errors? 851 */ 852 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) { 853 SMBVDEBUG("Have CAP_LARGE but _seteof error=%d\n", error); 854 } 855 856 /* 857 * OK, so fallback to SMB_COM_WRITE, but note: 858 * it only supports 32-bit file offsets. 859 */ 860 if (newsize > UINT32_MAX) 861 return (EFBIG); 862 863 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp); 864 if (error) 865 return (error); 866 smb_rq_getrequest(rqp, &mbp); 867 smb_rq_wstart(rqp); 868 mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); 869 mb_put_uint16le(mbp, 0); 870 mb_put_uint32le(mbp, newsize); 871 mb_put_uint16le(mbp, 0); 872 smb_rq_wend(rqp); 873 smb_rq_bstart(rqp); 874 mb_put_uint8(mbp, SMB_DT_DATA); 875 mb_put_uint16le(mbp, 0); 876 smb_rq_bend(rqp); 877 error = smb_rq_simple(rqp); 878 smb_rq_done(rqp); 879 mutex_enter(&np->r_statelock); 880 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); 881 mutex_exit(&np->r_statelock); 882 return (error); 883 } 884 885 int 886 smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, 887 struct smbfattr *fap, struct smb_cred *scrp) 888 { 889 struct smb_rq rq, *rqp = &rq; 890 struct smb_share *ssp = np->n_mount->smi_share; 891 struct mbchain *mbp; 892 struct mdchain *mdp; 893 uint8_t wc; 894 int error; 895 uint16_t wattr; 896 uint32_t longint; 897 898 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp); 899 if (error) 900 return (error); 901 smb_rq_getrequest(rqp, &mbp); 902 smb_rq_wstart(rqp); 903 smb_rq_wend(rqp); 904 smb_rq_bstart(rqp); 905 mb_put_uint8(mbp, SMB_DT_ASCII); 906 do { 907 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, 908 name, &nmlen, '\\'); 909 if (error) 910 break; 911 smb_rq_bend(rqp); 912 error = smb_rq_simple(rqp); 913 if (error) 914 break; 915 smb_rq_getreply(rqp, &mdp); 916 if (md_get_uint8(mdp, &wc) != 0 || wc != 10) { 917 error = EBADRPC; 918 break; 919 } 920 md_get_uint16le(mdp, &wattr); 921 fap->fa_attr = wattr; 922 /* 923 * Be careful using the time returned here, as 924 * with FAT on NT4SP6, at least, the time returned is low 925 * 32 bits of 100s of nanoseconds (since 1601) so it rolls 926 * over about every seven minutes! 927 */ 928 md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ 929 if (longint) /* avoid bogus zero returns */ 930 smb_time_server2local(longint, 931 SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime); 932 md_get_uint32le(mdp, &longint); 933 fap->fa_size = longint; 934 /*LINTED*/ 935 } while (0); 936 smb_rq_done(rqp); 937 return (error); 938 } 939 940 int 941 smbfs_smb_setpattr(struct smbnode *np, uint32_t attr, 942 struct timespec *mtime, struct timespec *atime, 943 struct smb_cred *scrp) 944 { 945 struct smb_share *ssp = np->n_mount->smi_share; 946 struct smb_vc *vcp = SSTOVC(ssp); 947 int error; 948 949 /* 950 * This is the logic that was in smbfs_vnops.c 951 */ 952 if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) && 953 (vcp->vc_flags & SMBV_NT4) == 0) { 954 /* 955 * NT4 doesn't understand "NT" style SMBs; 956 * for NT4 we use the old SET_PATH_INFO 957 * XXX Actually, I think the issue is that 958 * NT requires an open handle for this. 959 */ 960 error = smbfs_smb_setpattrNT(np, 961 attr, mtime, atime, scrp); 962 if (error != EBADRPC) 963 return (error); 964 965 /* NT4 response, remember */ 966 SMB_VC_LOCK(vcp); 967 vcp->vc_flags |= SMBV_NT4; 968 SMB_VC_UNLOCK(vcp); 969 } 970 971 if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { 972 error = smbfs_smb_setpattr2(np, 973 attr, mtime, atime, scrp); 974 } else { 975 error = smbfs_smb_setpattr1(np, NULL, 0, 976 attr, mtime, scrp); 977 } 978 979 return (error); 980 } 981 982 /* 983 * Set DOS file attributes. mtime should be NULL for dialects above lm10 984 */ 985 int 986 smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len, 987 uint32_t attr, struct timespec *mtime, 988 struct smb_cred *scrp) 989 { 990 struct smb_rq rq, *rqp = &rq; 991 struct smb_share *ssp = np->n_mount->smi_share; 992 struct mbchain *mbp; 993 long time; 994 int error, svtz; 995 996 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp); 997 if (error) 998 return (error); 999 svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 1000 smb_rq_getrequest(rqp, &mbp); 1001 smb_rq_wstart(rqp); 1002 mb_put_uint16le(mbp, (uint16_t)attr); 1003 if (mtime) { 1004 smb_time_local2server(mtime, svtz, &time); 1005 } else 1006 time = 0; 1007 mb_put_uint32le(mbp, time); /* mtime */ 1008 mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); 1009 smb_rq_wend(rqp); 1010 smb_rq_bstart(rqp); 1011 mb_put_uint8(mbp, SMB_DT_ASCII); 1012 do { 1013 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &len, '\\'); 1014 if (error) 1015 break; 1016 mb_put_uint8(mbp, SMB_DT_ASCII); 1017 if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { 1018 mb_put_padbyte(mbp); 1019 mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */ 1020 } 1021 mb_put_uint8(mbp, 0); 1022 smb_rq_bend(rqp); 1023 error = smb_rq_simple(rqp); 1024 if (error) 1025 break; 1026 /*LINTED*/ 1027 } while (0); 1028 smb_rq_done(rqp); 1029 return (error); 1030 } 1031 1032 int 1033 smbfs_smb_hideit(struct smbnode *np, const char *name, int len, 1034 struct smb_cred *scrp) 1035 { 1036 struct smbfattr fa; 1037 int error; 1038 uint32_t attr; 1039 1040 error = smbfs_smb_query_info(np, name, len, &fa, scrp); 1041 attr = fa.fa_attr; 1042 if (!error && !(attr & SMB_FA_HIDDEN)) { 1043 attr |= SMB_FA_HIDDEN; 1044 error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp); 1045 } 1046 return (error); 1047 } 1048 1049 1050 int 1051 smbfs_smb_unhideit(struct smbnode *np, const char *name, int len, 1052 struct smb_cred *scrp) 1053 { 1054 struct smbfattr fa; 1055 uint32_t attr; 1056 int error; 1057 1058 error = smbfs_smb_query_info(np, name, len, &fa, scrp); 1059 attr = fa.fa_attr; 1060 if (!error && (attr & SMB_FA_HIDDEN)) { 1061 attr &= ~SMB_FA_HIDDEN; 1062 error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp); 1063 } 1064 return (error); 1065 } 1066 1067 /* 1068 * Note, win95 doesn't support this call. 1069 */ 1070 int 1071 smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr, 1072 struct timespec *mtime, struct timespec *atime, 1073 struct smb_cred *scrp) 1074 { 1075 struct smb_t2rq *t2p; 1076 struct smb_share *ssp = np->n_mount->smi_share; 1077 struct smb_vc *vcp = SSTOVC(ssp); 1078 struct mbchain *mbp; 1079 uint16_t date, time; 1080 int error, tzoff; 1081 1082 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 1083 scrp, &t2p); 1084 if (error) 1085 return (error); 1086 mbp = &t2p->t2_tparam; 1087 mb_init(mbp); 1088 mb_put_uint16le(mbp, SMB_SFILEINFO_STANDARD); 1089 mb_put_uint32le(mbp, 0); /* MBZ */ 1090 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 1091 error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); 1092 if (error) { 1093 smb_t2_done(t2p); 1094 return (error); 1095 } 1096 tzoff = vcp->vc_sopt.sv_tz; 1097 mbp = &t2p->t2_tdata; 1098 mb_init(mbp); 1099 mb_put_uint32le(mbp, 0); /* creation time */ 1100 if (atime) 1101 smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 1102 else 1103 time = date = 0; 1104 mb_put_uint16le(mbp, date); 1105 mb_put_uint16le(mbp, time); 1106 if (mtime) 1107 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 1108 else 1109 time = date = 0; 1110 mb_put_uint16le(mbp, date); 1111 mb_put_uint16le(mbp, time); 1112 mb_put_uint32le(mbp, 0); /* file size */ 1113 mb_put_uint32le(mbp, 0); /* allocation unit size */ 1114 mb_put_uint16le(mbp, attr); /* DOS attr */ 1115 mb_put_uint32le(mbp, 0); /* EA size */ 1116 t2p->t2_maxpcount = 5 * 2; 1117 t2p->t2_maxdcount = vcp->vc_txmax; 1118 error = smb_t2_request(t2p); 1119 smb_t2_done(t2p); 1120 return (error); 1121 } 1122 1123 /* 1124 * *BASIC_INFO works with Samba, but Win2K servers say it is an 1125 * invalid information level on a SET_PATH_INFO. Note Win2K does 1126 * support *BASIC_INFO on a SET_FILE_INFO, and they support the 1127 * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure. 1128 */ 1129 int 1130 smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr, 1131 struct timespec *mtime, struct timespec *atime, 1132 struct smb_cred *scrp) 1133 { 1134 struct smb_t2rq *t2p; 1135 struct smb_share *ssp = np->n_mount->smi_share; 1136 struct smb_vc *vcp = SSTOVC(ssp); 1137 struct mbchain *mbp; 1138 uint64_t tm; 1139 int error, tzoff; 1140 /* 64 bit value for Jan 1 1980 */ 1141 PRIVSYM uint64_t DIFF1980TO1601 = 11960035200ULL*10000000ULL; 1142 1143 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, 1144 scrp, &t2p); 1145 if (error) 1146 return (error); 1147 mbp = &t2p->t2_tparam; 1148 mb_init(mbp); 1149 if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) 1150 mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION); 1151 else 1152 mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO); 1153 mb_put_uint32le(mbp, 0); /* MBZ */ 1154 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ 1155 error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); 1156 if (error) { 1157 smb_t2_done(t2p); 1158 return (error); 1159 } 1160 tzoff = vcp->vc_sopt.sv_tz; 1161 1162 /* do we know it won't support dates < 1980? */ 1163 if (!(ssp->ss_flags & SMBS_1980)) { 1164 mbp = &t2p->t2_tdata; 1165 mb_init(mbp); 1166 mb_put_uint64le(mbp, 0); /* creation time */ 1167 if (atime) { 1168 smb_time_local2NT(atime, tzoff, &tm); 1169 } else 1170 tm = 0; 1171 mb_put_uint64le(mbp, tm); /* access time */ 1172 if (mtime) { 1173 smb_time_local2NT(mtime, tzoff, &tm); 1174 } else 1175 tm = 0; 1176 mb_put_uint64le(mbp, tm); /* last write time */ 1177 mb_put_uint64le(mbp, tm); /* change time */ 1178 mb_put_uint32le(mbp, attr); /* attr */ 1179 mb_put_uint32le(mbp, 0); /* undocumented padding */ 1180 t2p->t2_maxpcount = 24; 1181 t2p->t2_maxdcount = 56; 1182 error = smb_t2_request(t2p); 1183 } 1184 /* 1185 * "invalid argument" error probably means it's a 1186 * FAT drive that doesn't accept dates earlier 1187 * than 1980, so adjust dates and retry. If the 1188 * 1980 flag is on we fell thru the if {} above 1189 */ 1190 if ((ssp->ss_flags & SMBS_1980) || (error == EINVAL)) { 1191 mbp = &t2p->t2_tdata; 1192 mb_init(mbp); 1193 mb_put_uint64le(mbp, 0); /* creation time */ 1194 if (atime) { 1195 smb_time_local2NT(atime, tzoff, &tm); 1196 if (tm < DIFF1980TO1601) 1197 tm = DIFF1980TO1601; 1198 } else 1199 tm = 0; 1200 mb_put_uint64le(mbp, tm); /* access time */ 1201 if (mtime) { 1202 smb_time_local2NT(mtime, tzoff, &tm); 1203 if (tm < DIFF1980TO1601) 1204 tm = DIFF1980TO1601; 1205 } else 1206 tm = 0; 1207 mb_put_uint64le(mbp, tm); /* last write time */ 1208 mb_put_uint64le(mbp, tm); /* change time */ 1209 mb_put_uint32le(mbp, attr); /* attr */ 1210 mb_put_uint32le(mbp, 0); /* undocumented padding */ 1211 t2p->t2_maxpcount = 24; 1212 t2p->t2_maxdcount = 56; 1213 error = smb_t2_request(t2p); 1214 1215 /* if this worked set flag to do the right thing next time */ 1216 if (!(error)) { 1217 SMB_SS_LOCK(ssp); 1218 ssp->ss_flags |= SMBS_1980; 1219 SMB_SS_UNLOCK(ssp); 1220 } 1221 } 1222 smb_t2_done(t2p); 1223 return (error); 1224 } 1225 1226 int 1227 smbfs_smb_setfattr(struct smbnode *np, uint16_t fid, 1228 uint32_t attr, struct timespec *mtime, 1229 struct timespec *atime, struct smb_cred *scrp) 1230 { 1231 struct smb_share *ssp = np->n_mount->smi_share; 1232 struct smb_vc *vcp = SSTOVC(ssp); 1233 int error; 1234 1235 /* 1236 * This is the logic that was in smbfs_vnops.c 1237 * Might not be quite right for older dialects. 1238 * (XXX: What about the DOS attributes?) 1239 */ 1240 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) 1241 error = smbfs_smb_setfattrNT(np, fid, 1242 np->n_dosattr, mtime, atime, scrp); 1243 else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) 1244 error = smbfs_smb_setftime1(np, fid, 1245 mtime, atime, scrp); 1246 else 1247 error = smbfs_smb_setpattr1(np, NULL, 0, 1248 attr, mtime, scrp); 1249 1250 return (error); 1251 } 1252 1253 /* 1254 * Set file atime and mtime. Isn't supported by core dialect. 1255 */ 1256 int 1257 smbfs_smb_setftime1( 1258 struct smbnode *np, 1259 uint16_t fid, 1260 struct timespec *mtime, 1261 struct timespec *atime, 1262 struct smb_cred *scrp) 1263 { 1264 struct smb_rq rq, *rqp = &rq; 1265 struct smb_share *ssp = np->n_mount->smi_share; 1266 struct mbchain *mbp; 1267 uint16_t date, time; 1268 int error, tzoff; 1269 1270 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp); 1271 if (error) 1272 return (error); 1273 tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; 1274 smb_rq_getrequest(rqp, &mbp); 1275 smb_rq_wstart(rqp); 1276 mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); 1277 mb_put_uint32le(mbp, 0); /* creation time */ 1278 1279 if (atime) 1280 smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 1281 else 1282 time = date = 0; 1283 mb_put_uint16le(mbp, date); 1284 mb_put_uint16le(mbp, time); 1285 if (mtime) 1286 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 1287 else 1288 time = date = 0; 1289 mb_put_uint16le(mbp, date); 1290 mb_put_uint16le(mbp, time); 1291 smb_rq_wend(rqp); 1292 smb_rq_bstart(rqp); 1293 smb_rq_bend(rqp); 1294 error = smb_rq_simple(rqp); 1295 SMBVDEBUG("%d\n", error); 1296 smb_rq_done(rqp); 1297 return (error); 1298 } 1299 1300 /* 1301 * Set DOS file attributes. 1302 * Looks like this call can be used only if CAP_NT_SMBS bit is on. 1303 */ 1304 int 1305 smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid, 1306 uint32_t attr, struct timespec *mtime, 1307 struct timespec *atime, struct smb_cred *scrp) 1308 { 1309 struct smb_t2rq *t2p; 1310 struct smb_share *ssp = np->n_mount->smi_share; 1311 struct smb_vc *vcp = SSTOVC(ssp); 1312 struct mbchain *mbp; 1313 uint64_t tm; 1314 int error, svtz; 1315 1316 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 1317 scrp, &t2p); 1318 if (error) 1319 return (error); 1320 svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 1321 mbp = &t2p->t2_tparam; 1322 mb_init(mbp); 1323 mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); 1324 if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) 1325 mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION); 1326 else 1327 mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO); 1328 mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */ 1329 mbp = &t2p->t2_tdata; 1330 mb_init(mbp); 1331 mb_put_uint64le(mbp, 0); /* creation time */ 1332 if (atime) { 1333 smb_time_local2NT(atime, svtz, &tm); 1334 } else 1335 tm = 0; 1336 mb_put_uint64le(mbp, tm); /* access time */ 1337 if (mtime) { 1338 smb_time_local2NT(mtime, svtz, &tm); 1339 } else 1340 tm = 0; 1341 mb_put_uint64le(mbp, tm); /* last write time */ 1342 mb_put_uint64le(mbp, tm); /* change time */ 1343 mb_put_uint32le(mbp, attr); 1344 mb_put_uint32le(mbp, 0); /* padding */ 1345 t2p->t2_maxpcount = 2; 1346 t2p->t2_maxdcount = 0; 1347 error = smb_t2_request(t2p); 1348 smb_t2_done(t2p); 1349 return (error); 1350 } 1351 1352 /* 1353 * Modern create/open of file or directory. 1354 * 1355 * If disp is ..._DISP_OPEN, or ...DISP_OPEN_IF, or... 1356 * then this is an open attempt, and: 1357 * If xattr then name is the stream to be opened at np, 1358 * Else np should be opened. 1359 * ...we won't touch *fidp, 1360 * ...we will set or clear *attrcacheupdated. 1361 * Else this is a creation attempt, and: 1362 * If xattr then name is the stream to create at np, 1363 * Else name is the thing to create under directory np. 1364 * ...we will return *fidp, 1365 * ...we won't touch *attrcacheupdated. 1366 * 1367 * Note, We use: disp = ...OPEN_IF, ...OVERWRITE_IF, etc. 1368 * now too, which may or may not create a new object. 1369 */ 1370 int 1371 smbfs_smb_ntcreatex(struct smbnode *np, uint32_t rights, 1372 struct smb_cred *scrp, enum vtype vt, 1373 int *attrcacheupdated, uint16_t *fidp, 1374 const char *name, int nmlen, uint32_t disp, int xattr, 1375 len_t *sizep, uint32_t *rightsp) 1376 { 1377 struct smb_rq rq, *rqp = &rq; 1378 struct smb_share *ssp = np->n_mount->smi_share; 1379 struct smb_vc *vcp = SSTOVC(ssp); 1380 struct mbchain *mbp; 1381 struct mdchain *mdp; 1382 struct smbfattr fap; 1383 uint8_t wc; 1384 uint32_t longint, createact, createopt, efa; 1385 uint64_t llongint; 1386 int error; 1387 uint16_t fid, *namelenp; 1388 1389 /* 1390 * Set the File attributes and Create options. 1391 * WinXP uses EFA_NORMAL in all of these cases. 1392 */ 1393 createopt = (vt == VDIR) ? 1394 NTCREATEX_OPTIONS_DIRECTORY : 1395 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE; 1396 efa = SMB_EFA_NORMAL; 1397 if (disp != NTCREATEX_DISP_OPEN && !xattr) { 1398 if (name && *name == '.') 1399 efa = SMB_EFA_HIDDEN; 1400 } 1401 1402 gethrestime(&fap.fa_reqtime); 1403 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp); 1404 if (error) 1405 return (error); 1406 smb_rq_getrequest(rqp, &mbp); 1407 smb_rq_wstart(rqp); 1408 mb_put_uint8(mbp, 0xff); /* secondary command */ 1409 mb_put_uint8(mbp, 0); /* MBZ */ 1410 mb_put_uint16le(mbp, 0); /* offset to next command (none) */ 1411 mb_put_uint8(mbp, 0); /* MBZ */ 1412 namelenp = (uint16_t *)mb_reserve(mbp, sizeof (uint16_t)); 1413 /* 1414 * XP to a W2K Server does not use NTCREATEX_FLAGS_OPEN_DIRECTORY 1415 * for creating nor for opening a directory. Samba ignores the bit. 1416 */ 1417 #if 0 /* causes sharing violation when making dir on W2K! */ 1418 mb_put_uint32le(mbp, vt == VDIR ? NTCREATEX_FLAGS_OPEN_DIRECTORY : 0); 1419 #else 1420 mb_put_uint32le(mbp, 0); /* NTCREATEX_FLAGS_* */ 1421 #endif 1422 mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */ 1423 mb_put_uint32le(mbp, rights); 1424 mb_put_uint64le(mbp, 0); /* "initial allocation size" */ 1425 mb_put_uint32le(mbp, efa); 1426 mb_put_uint32le(mbp, NTCREATEX_SHARE_ACCESS_ALL); 1427 mb_put_uint32le(mbp, disp); 1428 mb_put_uint32le(mbp, createopt); 1429 mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */ 1430 mb_put_uint8(mbp, 0); /* security flags (?) */ 1431 smb_rq_wend(rqp); 1432 smb_rq_bstart(rqp); 1433 do { 1434 if (name == NULL) 1435 nmlen = 0; 1436 error = smbfs_fullpath(mbp, vcp, np, name, &nmlen, 1437 xattr ? ':' : '\\'); 1438 if (error) 1439 break; 1440 *namelenp = htoles(nmlen); /* includes null */ 1441 smb_rq_bend(rqp); 1442 /* 1443 * Don't want to risk missing a successful 1444 * open response, or we could "leak" FIDs. 1445 */ 1446 rqp->sr_flags |= SMBR_NOINTR_RECV; 1447 error = smb_rq_simple_timed(rqp, smb_timo_open); 1448 if (error) 1449 break; 1450 smb_rq_getreply(rqp, &mdp); 1451 /* 1452 * spec says 26 for word count, but 34 words are defined 1453 * and observed from win2000 1454 */ 1455 if (md_get_uint8(mdp, &wc) != 0 || 1456 (wc != 26 && wc != 34 && wc != 42)) { 1457 error = EBADRPC; 1458 break; 1459 } 1460 md_get_uint8(mdp, NULL); /* secondary cmd */ 1461 md_get_uint8(mdp, NULL); /* mbz */ 1462 md_get_uint16le(mdp, NULL); /* andxoffset */ 1463 md_get_uint8(mdp, NULL); /* oplock lvl granted */ 1464 md_get_uint16(mdp, &fid); /* yes, leaving it LE */ 1465 md_get_uint32le(mdp, &createact); /* create_action */ 1466 md_get_uint64le(mdp, &llongint); /* creation time */ 1467 md_get_uint64le(mdp, &llongint); /* access time */ 1468 if (llongint) /* avoid bogus 0 time (on FAT roots) */ 1469 smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz, 1470 &fap.fa_atime); 1471 md_get_uint64le(mdp, &llongint); /* write time */ 1472 if (llongint) /* avoid bogus 0 time (on FAT roots) */ 1473 smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz, 1474 &fap.fa_mtime); 1475 md_get_uint64le(mdp, &llongint); /* change time */ 1476 if (llongint) /* avoid bogus 0 time (on FAT roots) */ 1477 smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz, 1478 &fap.fa_ctime); 1479 md_get_uint32le(mdp, &longint); /* attributes */ 1480 fap.fa_attr = longint; 1481 md_get_uint64le(mdp, NULL); /* allocation size */ 1482 md_get_uint64le(mdp, &llongint); /* EOF */ 1483 fap.fa_size = llongint; 1484 if (sizep) 1485 *sizep = fap.fa_size; 1486 md_get_uint16le(mdp, NULL); /* file type */ 1487 md_get_uint16le(mdp, NULL); /* device state */ 1488 md_get_uint8(mdp, NULL); /* directory (boolean) */ 1489 /*LINTED*/ 1490 } while (0); 1491 smb_rq_done(rqp); 1492 if (error) 1493 return (error); 1494 if (fidp) 1495 *fidp = fid; 1496 if (rightsp) 1497 *rightsp = rights; 1498 /* 1499 * Is it possible that we have cached attributes? 1500 * Assume "not cached" if we created the object. 1501 */ 1502 if (createact == NTCREATEX_ACTION_CREATED || xattr) 1503 goto uncached; 1504 if (attrcacheupdated) 1505 *attrcacheupdated = 0; 1506 /* 1507 * Update the cached attributes if they are still valid 1508 * in the cache and if nothing has changed. 1509 */ 1510 if (np->r_vnode == NULL) 1511 goto uncached; 1512 if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0) 1513 goto uncached; /* the cached attributes are not valid */ 1514 if (fap.fa_size != np->n_size) 1515 goto uncached; /* the size is different */ 1516 if (fap.fa_attr != np->n_dosattr) 1517 goto uncached; /* the attrs are different */ 1518 /* 1519 * fap.fa_mtime is in two second increments while np->n_mtime 1520 * may be in one second increments, so comparing the times is 1521 * somewhat sloppy. 1522 * 1523 * XXX: true fap.fa_mtime resolution must depend upon server's 1524 * local filesystem and is thus indeterminate... XXX ...TBD how that 1525 * affects this code... note wire resolution here is 100ns versus 1526 * 1sec down in smbfs_smb_oldopen(SMB_COM_OPEN) 1527 */ 1528 if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec && 1529 fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 && 1530 fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1) 1531 goto uncached; /* the mod time is different */ 1532 1533 fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */ 1534 smbfs_attr_cacheenter(np->r_vnode, &fap); 1535 if (attrcacheupdated) 1536 *attrcacheupdated = 1; 1537 uncached: 1538 return (0); 1539 } 1540 1541 static uint32_t 1542 smb_mode2rights(int mode) 1543 { 1544 mode = mode & SMB_AM_OPENMODE; 1545 1546 switch (mode) { 1547 case SMB_AM_OPENREAD: 1548 return (GENERIC_RIGHT_READ_ACCESS); 1549 case SMB_AM_OPENWRITE: 1550 return (GENERIC_RIGHT_WRITE_ACCESS); 1551 case SMB_AM_OPENRW: 1552 return (GENERIC_RIGHT_ALL_ACCESS); 1553 case SMB_AM_OPENEXEC: 1554 return (GENERIC_RIGHT_EXECUTE_ACCESS); 1555 } 1556 return (0); 1557 } 1558 1559 static int 1560 smb_rights2mode(uint32_t rights) 1561 { 1562 int accmode = SMB_AM_OPENEXEC; /* our fallback */ 1563 1564 if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD | 1565 SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES | 1566 SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS | 1567 STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS | 1568 GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_WRITE_ACCESS)) 1569 accmode = SMB_AM_OPENWRITE; 1570 if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES | 1571 SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS | 1572 GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_READ_ACCESS)) 1573 accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD 1574 : SMB_AM_OPENRW; 1575 return (accmode); 1576 } 1577 1578 static int 1579 smbfs_smb_oldopen(struct smbnode *np, int accmode, struct smb_cred *scrp, 1580 int *attrcacheupdated, uint16_t *fidp, const char *name, 1581 int nmlen, int xattr, len_t *sizep, uint32_t *rightsp) 1582 { 1583 struct smb_rq rq, *rqp = &rq; 1584 struct smb_share *ssp = np->n_mount->smi_share; 1585 struct smb_vc *vcp = SSTOVC(ssp); 1586 struct mbchain *mbp; 1587 struct mdchain *mdp; 1588 struct smbfattr fap; 1589 uint8_t wc; 1590 uint16_t fid, wattr, grantedmode; 1591 uint32_t longint; 1592 int error; 1593 1594 /* 1595 * Use DENYNONE to give unixy semantics of permitting 1596 * everything not forbidden by permissions. Ie denial 1597 * is up to server with clients/openers needing to use 1598 * advisory locks for further control. 1599 */ 1600 accmode |= SMB_SM_DENYNONE; 1601 1602 gethrestime(&fap.fa_reqtime); 1603 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp); 1604 if (error) 1605 return (error); 1606 smb_rq_getrequest(rqp, &mbp); 1607 smb_rq_wstart(rqp); 1608 mb_put_uint16le(mbp, accmode); 1609 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY | 1610 SMB_FA_DIR); 1611 smb_rq_wend(rqp); 1612 smb_rq_bstart(rqp); 1613 mb_put_uint8(mbp, SMB_DT_ASCII); 1614 do { 1615 error = smbfs_fullpath(mbp, vcp, np, name, &nmlen, 1616 xattr ? ':' : '\\'); 1617 if (error) 1618 break; 1619 smb_rq_bend(rqp); 1620 /* 1621 * Don't want to risk missing a successful 1622 * open response, or we could "leak" FIDs. 1623 */ 1624 rqp->sr_flags |= SMBR_NOINTR_RECV; 1625 error = smb_rq_simple_timed(rqp, smb_timo_open); 1626 if (error) 1627 break; 1628 smb_rq_getreply(rqp, &mdp); 1629 /* 1630 * 8/2002 a DAVE server returned wc of 15 so we ignore that. 1631 * (the actual packet length and data was correct) 1632 */ 1633 if (md_get_uint8(mdp, &wc) != 0 || (wc != 7 && wc != 15)) { 1634 error = EBADRPC; 1635 break; 1636 } 1637 md_get_uint16(mdp, &fid); /* yes, we leave it LE */ 1638 md_get_uint16le(mdp, &wattr); 1639 fap.fa_attr = wattr; 1640 /* 1641 * Be careful using the time returned here, as 1642 * with FAT on NT4SP6, at least, the time returned is low 1643 * 32 bits of 100s of nanoseconds (since 1601) so it rolls 1644 * over about every seven minutes! 1645 */ 1646 md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ 1647 if (longint) /* avoid bogus zero returns */ 1648 smb_time_server2local(longint, vcp->vc_sopt.sv_tz, 1649 &fap.fa_mtime); 1650 md_get_uint32le(mdp, &longint); 1651 fap.fa_size = longint; 1652 if (sizep) 1653 *sizep = fap.fa_size; 1654 md_get_uint16le(mdp, &grantedmode); 1655 /*LINTED*/ 1656 } while (0); 1657 smb_rq_done(rqp); 1658 if (error) 1659 return (error); 1660 if (fidp) 1661 *fidp = fid; 1662 if (xattr) 1663 goto uncached; 1664 if (rightsp) 1665 *rightsp = smb_mode2rights(grantedmode); 1666 if (attrcacheupdated) 1667 *attrcacheupdated = 0; 1668 /* 1669 * Update the cached attributes if they are still valid 1670 * in the cache and if nothing has changed. 1671 * Note that this won't ever update if the file size is 1672 * greater than the 32-bits returned by SMB_COM_OPEN. 1673 * For 64-bit file sizes, SMB_COM_NT_CREATE_ANDX must 1674 * be used instead of SMB_COM_OPEN. 1675 */ 1676 if (np->r_vnode == NULL) 1677 goto uncached; 1678 if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0) 1679 goto uncached; /* the cached attributes are not valid */ 1680 if (fap.fa_size != np->n_size) 1681 goto uncached; /* the size is different */ 1682 if (fap.fa_attr != np->n_dosattr) 1683 goto uncached; /* the attrs are different */ 1684 /* 1685 * fap.fa_mtime is in two second increments while np->n_mtime 1686 * may be in one second increments, so comparing the times is 1687 * somewhat sloppy. 1688 */ 1689 if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec && 1690 fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 && 1691 fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1) 1692 goto uncached; /* the mod time is different */ 1693 1694 fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */ 1695 smbfs_attr_cacheenter(np->r_vnode, &fap); 1696 if (attrcacheupdated) 1697 *attrcacheupdated = 1; 1698 uncached: 1699 return (0); 1700 } 1701 1702 int 1703 smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, 1704 uint16_t *fidp) 1705 { 1706 struct smb_vc *vcp = SSTOVC(np->n_mount->smi_share); 1707 enum vtype vt = VREG; 1708 int error; 1709 1710 /* Shared lock for n_fid use below. */ 1711 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); 1712 1713 mutex_enter(&np->r_statelock); 1714 if (np->n_fidrefs && (rights & np->n_rights) == rights) { 1715 np->n_fidrefs++; 1716 *fidp = np->n_fid; 1717 mutex_exit(&np->r_statelock); 1718 return (0); 1719 } 1720 mutex_exit(&np->r_statelock); 1721 1722 if (!(vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { 1723 int mode = smb_rights2mode(rights); 1724 error = smbfs_smb_oldopen(np, mode, scrp, 1725 NULL, fidp, NULL, 0, 0, NULL, NULL); 1726 } else { 1727 if (SMBTOV(np)) 1728 vt = SMBTOV(np)->v_type; 1729 error = smbfs_smb_ntcreatex(np, rights, scrp, vt, 1730 NULL, fidp, NULL, 0, NTCREATEX_DISP_OPEN, 0, 1731 NULL, NULL); 1732 } 1733 1734 if (*fidp == np->n_fid) { 1735 /* 1736 * Oh no, the server gave us the same FID again? 1737 * This will cause us to close np->n_fid early! 1738 */ 1739 SMBVDEBUG("duplicate fid: 0x%x\n", *fidp); 1740 } 1741 1742 return (error); 1743 } 1744 1745 int 1746 smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp) 1747 { 1748 struct smb_share *ssp = np->n_mount->smi_share; 1749 int error = 0; 1750 uint16_t oldfid = SMB_FID_UNUSED; 1751 1752 /* Shared lock for n_fid use below. */ 1753 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); 1754 1755 mutex_enter(&np->r_statelock); 1756 if (fid == np->n_fid) { 1757 ASSERT(np->n_fidrefs > 0); 1758 if (--np->n_fidrefs == 0) { 1759 /* 1760 * Don't expect to find the last reference 1761 * here in tmpclose. Hard to deal with as 1762 * we don't have r_lkserlock exclusive. 1763 * Will close oldfid below. 1764 */ 1765 oldfid = np->n_fid; 1766 np->n_fid = SMB_FID_UNUSED; 1767 } 1768 } else { 1769 /* Will close the passed fid. */ 1770 oldfid = fid; 1771 } 1772 mutex_exit(&np->r_statelock); 1773 1774 if (oldfid != SMB_FID_UNUSED) 1775 error = smbfs_smb_close(ssp, oldfid, NULL, scrp); 1776 1777 return (error); 1778 } 1779 1780 int 1781 smbfs_smb_open(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, 1782 int *attrcacheupdated, uint16_t *fidp, const char *name, 1783 int nmlen, int xattr, len_t *sizep, uint32_t *rightsp) 1784 { 1785 int error; 1786 struct smb_share *ssp = np->n_mount->smi_share; 1787 struct smb_vc *vcp = SSTOVC(ssp); 1788 enum vtype vt = VREG; 1789 1790 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 1791 if (SMBTOV(np)) 1792 vt = SMBTOV(np)->v_type; 1793 error = smbfs_smb_ntcreatex(np, rights, scrp, vt, 1794 attrcacheupdated, fidp, name, nmlen, 1795 NTCREATEX_DISP_OPEN, xattr, sizep, rightsp); 1796 } else { 1797 error = smbfs_smb_oldopen(np, smb_rights2mode(rights), scrp, 1798 attrcacheupdated, fidp, name, nmlen, xattr, sizep, rightsp); 1799 } 1800 #if 0 /* let caller do this */ 1801 if (!error && !name) 1802 np->n_fidrefs++; 1803 #endif 1804 return (error); 1805 } 1806 1807 int 1808 smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime, 1809 struct smb_cred *scrp) 1810 { 1811 struct smb_rq rq, *rqp = &rq; 1812 struct mbchain *mbp; 1813 long time; 1814 int error; 1815 1816 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp); 1817 if (error) 1818 return (error); 1819 smb_rq_getrequest(rqp, &mbp); 1820 smb_rq_wstart(rqp); 1821 mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM); 1822 if (mtime) { 1823 smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); 1824 } else 1825 time = 0; 1826 mb_put_uint32le(mbp, time); 1827 smb_rq_wend(rqp); 1828 smb_rq_bstart(rqp); 1829 smb_rq_bend(rqp); 1830 1831 /* 1832 * We don't really care about the result here, but we 1833 * do need to make sure we send this out, or we could 1834 * "leak" open file handles on interrupt or timeout. 1835 * The NOINTR_SEND flag makes this request immune to 1836 * interrupt or timeout until the send is done. 1837 */ 1838 rqp->sr_flags |= SMBR_NOINTR_SEND; 1839 error = smb_rq_simple(rqp); 1840 smb_rq_done(rqp); 1841 /* 1842 * ENOTCONN isn't interesting - if the connection is closed, 1843 * so are all our FIDs - and EIO is also not interesting, 1844 * as it means a forced unmount was done. (was ENXIO) 1845 * Also ETIME, which means we sent the request but gave up 1846 * waiting before the response came back. 1847 * 1848 * Don't clog up the system log with warnings about these 1849 * uninteresting failures on closes. 1850 */ 1851 switch (error) { 1852 case ENOTCONN: 1853 case ENXIO: 1854 case EIO: 1855 case ETIME: 1856 error = 0; 1857 } 1858 return (error); 1859 } 1860 1861 static int 1862 smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen, 1863 struct smb_cred *scrp, uint16_t *fidp, int xattr) 1864 { 1865 struct smb_rq rq, *rqp = &rq; 1866 struct smb_share *ssp = dnp->n_mount->smi_share; 1867 struct mbchain *mbp; 1868 struct mdchain *mdp; 1869 struct timespec ctime; 1870 uint8_t wc; 1871 long tm; 1872 int error; 1873 uint16_t attr = SMB_FA_ARCHIVE; 1874 1875 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp); 1876 if (error) 1877 return (error); 1878 smb_rq_getrequest(rqp, &mbp); 1879 smb_rq_wstart(rqp); 1880 if (name && *name == '.') 1881 attr |= SMB_FA_HIDDEN; 1882 mb_put_uint16le(mbp, attr); /* attributes */ 1883 gethrestime(&ctime); 1884 smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); 1885 mb_put_uint32le(mbp, tm); 1886 smb_rq_wend(rqp); 1887 smb_rq_bstart(rqp); 1888 mb_put_uint8(mbp, SMB_DT_ASCII); 1889 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &nmlen, 1890 xattr ? ':' : '\\'); 1891 if (!error) { 1892 smb_rq_bend(rqp); 1893 /* 1894 * Don't want to risk missing a successful 1895 * open response, or we could "leak" FIDs. 1896 */ 1897 rqp->sr_flags |= SMBR_NOINTR_RECV; 1898 error = smb_rq_simple_timed(rqp, smb_timo_open); 1899 if (!error) { 1900 smb_rq_getreply(rqp, &mdp); 1901 md_get_uint8(mdp, &wc); 1902 if (wc == 1) 1903 md_get_uint16(mdp, fidp); 1904 else 1905 error = EBADRPC; 1906 } 1907 } 1908 smb_rq_done(rqp); 1909 return (error); 1910 } 1911 1912 int 1913 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, 1914 struct smb_cred *scrp, uint16_t *fidp, uint32_t disp, int xattr) 1915 { 1916 struct smb_vc *vcp = SSTOVC(dnp->n_mount->smi_share); 1917 1918 /* 1919 * At present the only access we might need is to WRITE data, 1920 * and that only if we are creating a "symlink". When/if the 1921 * access needed gets more complex it should made a parameter 1922 * and be set upstream. 1923 */ 1924 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 1925 return (smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_WRITE_DATA, 1926 scrp, VREG, NULL, fidp, name, nmlen, disp, xattr, 1927 NULL, NULL)); 1928 } else 1929 return (smbfs_smb_oldcreate(dnp, name, nmlen, scrp, fidp, 1930 xattr)); 1931 } 1932 1933 int 1934 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name, 1935 int nmlen, int xattr) 1936 { 1937 struct smb_rq rq, *rqp = &rq; 1938 struct smb_share *ssp = np->n_mount->smi_share; 1939 struct mbchain *mbp; 1940 int error; 1941 1942 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp); 1943 if (error) 1944 return (error); 1945 smb_rq_getrequest(rqp, &mbp); 1946 smb_rq_wstart(rqp); 1947 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 1948 smb_rq_wend(rqp); 1949 smb_rq_bstart(rqp); 1950 mb_put_uint8(mbp, SMB_DT_ASCII); 1951 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &nmlen, 1952 xattr ? ':' : '\\'); 1953 if (!error) { 1954 smb_rq_bend(rqp); 1955 error = smb_rq_simple(rqp); 1956 } 1957 smb_rq_done(rqp); 1958 return (error); 1959 } 1960 1961 int 1962 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, 1963 const char *tname, int tnmlen, struct smb_cred *scrp) 1964 { 1965 struct smb_rq rq, *rqp = &rq; 1966 struct smb_share *ssp = src->n_mount->smi_share; 1967 struct mbchain *mbp; 1968 int error; 1969 uint16_t fa; 1970 char sep; 1971 1972 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp); 1973 if (error) 1974 return (error); 1975 smb_rq_getrequest(rqp, &mbp); 1976 smb_rq_wstart(rqp); 1977 /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */ 1978 fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0; 1979 fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN; 1980 mb_put_uint16le(mbp, fa); 1981 smb_rq_wend(rqp); 1982 smb_rq_bstart(rqp); 1983 1984 /* 1985 * When we're not adding any component name, the 1986 * passed sep is ignored, so just pass sep=0. 1987 */ 1988 mb_put_uint8(mbp, SMB_DT_ASCII); 1989 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, 0); 1990 if (error) 1991 goto out; 1992 1993 /* 1994 * After XATTR directories, separator is ":" 1995 */ 1996 sep = (src->n_flag & N_XATTR) ? ':' : '\\'; 1997 mb_put_uint8(mbp, SMB_DT_ASCII); 1998 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, sep); 1999 if (error) 2000 goto out; 2001 2002 smb_rq_bend(rqp); 2003 error = smb_rq_simple(rqp); 2004 out: 2005 smb_rq_done(rqp); 2006 return (error); 2007 } 2008 2009 int 2010 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, 2011 const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp) 2012 { 2013 struct smb_rq rq, *rqp = &rq; 2014 struct smb_share *ssp = src->n_mount->smi_share; 2015 struct mbchain *mbp; 2016 int error; 2017 2018 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp); 2019 if (error) 2020 return (error); 2021 smb_rq_getrequest(rqp, &mbp); 2022 smb_rq_wstart(rqp); 2023 mb_put_uint16le(mbp, SMB_TID_UNKNOWN); 2024 mb_put_uint16le(mbp, 0x20); /* delete target file */ 2025 mb_put_uint16le(mbp, flags); 2026 smb_rq_wend(rqp); 2027 smb_rq_bstart(rqp); 2028 mb_put_uint8(mbp, SMB_DT_ASCII); 2029 do { 2030 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\'); 2031 if (error) 2032 break; 2033 mb_put_uint8(mbp, SMB_DT_ASCII); 2034 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, 2035 '\\'); 2036 if (error) 2037 break; 2038 smb_rq_bend(rqp); 2039 error = smb_rq_simple(rqp); 2040 /*LINTED*/ 2041 } while (0); 2042 smb_rq_done(rqp); 2043 return (error); 2044 } 2045 2046 static int 2047 smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len, 2048 struct smb_cred *scrp) 2049 { 2050 struct smb_rq rq, *rqp = &rq; 2051 struct smb_share *ssp = dnp->n_mount->smi_share; 2052 struct mbchain *mbp; 2053 int error; 2054 2055 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp); 2056 if (error) 2057 return (error); 2058 smb_rq_getrequest(rqp, &mbp); 2059 smb_rq_wstart(rqp); 2060 smb_rq_wend(rqp); 2061 smb_rq_bstart(rqp); 2062 mb_put_uint8(mbp, SMB_DT_ASCII); 2063 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &len, '\\'); 2064 if (!error) { 2065 smb_rq_bend(rqp); 2066 error = smb_rq_simple(rqp); 2067 } 2068 smb_rq_done(rqp); 2069 return (error); 2070 } 2071 2072 int 2073 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, 2074 struct smb_cred *scrp) 2075 { 2076 struct smb_share *ssp = dnp->n_mount->smi_share; 2077 uint16_t fid; 2078 int error; 2079 2080 /* 2081 * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but 2082 * just to be asking for something. The rights==0 case could 2083 * easily be broken on some old or unusual servers. 2084 */ 2085 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 2086 error = smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_READ_DATA, 2087 scrp, VDIR, NULL, &fid, name, len, 2088 NTCREATEX_DISP_CREATE, 0, NULL, NULL); 2089 if (error) 2090 return (error); 2091 error = smbfs_smb_close(ssp, fid, NULL, scrp); 2092 if (error) 2093 SMBERROR("error %d closing fid %d\n", error, fid); 2094 return (0); 2095 } else 2096 return (smbfs_smb_oldmkdir(dnp, name, len, scrp)); 2097 } 2098 2099 int 2100 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp) 2101 { 2102 struct smb_rq rq, *rqp = &rq; 2103 struct smb_share *ssp = np->n_mount->smi_share; 2104 struct mbchain *mbp; 2105 int error; 2106 2107 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp); 2108 if (error) 2109 return (error); 2110 smb_rq_getrequest(rqp, &mbp); 2111 smb_rq_wstart(rqp); 2112 smb_rq_wend(rqp); 2113 smb_rq_bstart(rqp); 2114 mb_put_uint8(mbp, SMB_DT_ASCII); 2115 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, NULL, '\\'); 2116 if (!error) { 2117 smb_rq_bend(rqp); 2118 error = smb_rq_simple(rqp); 2119 } 2120 smb_rq_done(rqp); 2121 return (error); 2122 } 2123 2124 static int 2125 smbfs_smb_search(struct smbfs_fctx *ctx) 2126 { 2127 struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 2128 struct smb_rq *rqp; 2129 struct mbchain *mbp; 2130 struct mdchain *mdp; 2131 uint8_t wc, bt; 2132 uint16_t ec, dlen, bc; 2133 int len, maxent, error, iseof = 0; 2134 2135 maxent = min(ctx->f_left, 2136 (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN); 2137 if (ctx->f_rq) { 2138 smb_rq_done(ctx->f_rq); 2139 ctx->f_rq = NULL; 2140 } 2141 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, 2142 ctx->f_scred, &rqp); 2143 if (error) 2144 return (error); 2145 ctx->f_rq = rqp; 2146 smb_rq_getrequest(rqp, &mbp); 2147 smb_rq_wstart(rqp); 2148 mb_put_uint16le(mbp, maxent); /* max entries to return */ 2149 mb_put_uint16le(mbp, ctx->f_attrmask); 2150 smb_rq_wend(rqp); 2151 smb_rq_bstart(rqp); 2152 mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ 2153 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 2154 len = ctx->f_wclen; 2155 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, 2156 &len, '\\'); 2157 if (error) 2158 return (error); 2159 mb_put_uint8(mbp, SMB_DT_VARIABLE); 2160 mb_put_uint16le(mbp, 0); /* context length */ 2161 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 2162 } else { 2163 if (SMB_UNICODE_STRINGS(vcp)) { 2164 mb_put_padbyte(mbp); 2165 mb_put_uint8(mbp, 0); 2166 } 2167 mb_put_uint8(mbp, 0); 2168 mb_put_uint8(mbp, SMB_DT_VARIABLE); 2169 mb_put_uint16le(mbp, SMB_SKEYLEN); 2170 mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 2171 } 2172 smb_rq_bend(rqp); 2173 error = smb_rq_simple(rqp); 2174 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { 2175 error = 0; 2176 iseof = 1; 2177 ctx->f_flags |= SMBFS_RDD_EOF; 2178 } else if (error) 2179 return (error); 2180 smb_rq_getreply(rqp, &mdp); 2181 md_get_uint8(mdp, &wc); 2182 if (wc != 1) 2183 return (iseof ? ENOENT : EBADRPC); 2184 md_get_uint16le(mdp, &ec); 2185 if (ec == 0) 2186 return (ENOENT); 2187 ctx->f_ecnt = ec; 2188 md_get_uint16le(mdp, &bc); 2189 if (bc < 3) 2190 return (EBADRPC); 2191 bc -= 3; 2192 md_get_uint8(mdp, &bt); 2193 if (bt != SMB_DT_VARIABLE) 2194 return (EBADRPC); 2195 md_get_uint16le(mdp, &dlen); 2196 if (dlen != bc || dlen % SMB_DENTRYLEN != 0) 2197 return (EBADRPC); 2198 return (0); 2199 } 2200 2201 2202 /*ARGSUSED*/ 2203 static int 2204 smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, 2205 const char *wildcard, int wclen, uint16_t attr) 2206 { 2207 2208 ctx->f_type = ft_LM1; 2209 ctx->f_attrmask = attr; 2210 if (wildcard) { 2211 if (wclen == 1 && wildcard[0] == '*') { 2212 ctx->f_wildcard = "*.*"; 2213 ctx->f_wclen = 3; 2214 } else { 2215 ctx->f_wildcard = wildcard; 2216 ctx->f_wclen = wclen; 2217 } 2218 } else { 2219 ctx->f_wildcard = NULL; 2220 ctx->f_wclen = 0; 2221 } 2222 ctx->f_name = (char *)ctx->f_fname; 2223 ctx->f_namesz = 0; 2224 return (0); 2225 } 2226 2227 static int 2228 smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit) 2229 { 2230 struct mdchain *mdp; 2231 struct smb_rq *rqp; 2232 char *cp; 2233 uint8_t battr; 2234 uint16_t date, time; 2235 uint32_t size; 2236 int error; 2237 struct timespec ts; 2238 2239 if (ctx->f_ecnt == 0) { 2240 if (ctx->f_flags & SMBFS_RDD_EOF) 2241 return (ENOENT); 2242 ctx->f_left = ctx->f_limit = limit; 2243 gethrestime(&ts); 2244 error = smbfs_smb_search(ctx); 2245 if (error) 2246 return (error); 2247 ctx->f_attr.fa_reqtime = ts; 2248 } 2249 rqp = ctx->f_rq; 2250 smb_rq_getreply(rqp, &mdp); 2251 md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 2252 md_get_uint8(mdp, &battr); 2253 md_get_uint16le(mdp, &time); 2254 md_get_uint16le(mdp, &date); 2255 md_get_uint32le(mdp, &size); 2256 cp = ctx->f_name; 2257 md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM); 2258 cp[sizeof (ctx->f_fname) - 1] = 0; 2259 cp += strlen(cp) - 1; 2260 while (*cp == ' ' && cp >= ctx->f_name) 2261 *cp-- = 0; 2262 ctx->f_attr.fa_attr = battr; 2263 smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz, 2264 &ctx->f_attr.fa_mtime); 2265 ctx->f_attr.fa_size = size; 2266 ctx->f_nmlen = strlen(ctx->f_name); 2267 ctx->f_ecnt--; 2268 ctx->f_left--; 2269 return (0); 2270 } 2271 2272 static int 2273 smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx) 2274 { 2275 if (ctx->f_rq) 2276 smb_rq_done(ctx->f_rq); 2277 return (0); 2278 } 2279 2280 /* 2281 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect 2282 */ 2283 static int 2284 smbfs_smb_trans2find2(struct smbfs_fctx *ctx) 2285 { 2286 struct smb_t2rq *t2p; 2287 struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 2288 struct mbchain *mbp; 2289 struct mdchain *mdp; 2290 uint16_t tw, flags; 2291 int len, error; 2292 2293 if (ctx->f_t2) { 2294 smb_t2_done(ctx->f_t2); 2295 ctx->f_t2 = NULL; 2296 } 2297 ctx->f_flags &= ~SMBFS_RDD_GOTRNAME; 2298 flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS; 2299 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { 2300 flags |= FIND2_CLOSE_AFTER_REQUEST; 2301 ctx->f_flags |= SMBFS_RDD_NOCLOSE; 2302 } 2303 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 2304 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, 2305 ctx->f_scred, &t2p); 2306 if (error) 2307 return (error); 2308 ctx->f_t2 = t2p; 2309 mbp = &t2p->t2_tparam; 2310 mb_init(mbp); 2311 mb_put_uint16le(mbp, ctx->f_attrmask); 2312 mb_put_uint16le(mbp, ctx->f_limit); 2313 mb_put_uint16le(mbp, flags); 2314 mb_put_uint16le(mbp, ctx->f_infolevel); 2315 mb_put_uint32le(mbp, 0); 2316 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs? hah! */ 2317 len = ctx->f_wclen; 2318 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, 2319 &len, '\\'); 2320 if (error) 2321 return (error); 2322 } else { 2323 error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, 2324 ctx->f_scred, &t2p); 2325 if (error) 2326 return (error); 2327 ctx->f_t2 = t2p; 2328 mbp = &t2p->t2_tparam; 2329 mb_init(mbp); 2330 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 2331 mb_put_uint16le(mbp, ctx->f_limit); 2332 mb_put_uint16le(mbp, ctx->f_infolevel); 2333 if (ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS) { 2334 mb_put_uint32le(mbp, ctx->f_rkey); 2335 } else 2336 mb_put_uint32le(mbp, 0); 2337 mb_put_uint16le(mbp, flags); 2338 if (ctx->f_rname) { 2339 /* resume file name */ 2340 mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen, 2341 MB_MSYSTEM); 2342 } 2343 /* Add trailing null - 1 byte if ASCII, 2 if Unicode */ 2344 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) 2345 mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */ 2346 mb_put_uint8(mbp, 0); 2347 #if 0 2348 struct timespec ts; 2349 ts.tv_sec = 0; 2350 ts.tv_nsec = 200 * 1000 * 1000; /* 200ms */ 2351 if (vcp->vc_flags & SMBC_WIN95) { 2352 /* 2353 * some implementations suggests to sleep here 2354 * for 200ms, due to the bug in the Win95. 2355 * I've didn't notice any problem, but put code 2356 * for it. 2357 */ 2358 msleep(&flags, 0, PVFS, "fix95", &ts); 2359 } 2360 #endif 2361 } 2362 t2p->t2_maxpcount = 5 * 2; 2363 t2p->t2_maxdcount = vcp->vc_txmax; 2364 error = smb_t2_request(t2p); 2365 if (error) 2366 return (error); 2367 mdp = &t2p->t2_rparam; 2368 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 2369 if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0) 2370 return (error); 2371 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 2372 } 2373 if ((error = md_get_uint16le(mdp, &tw)) != 0) 2374 return (error); 2375 ctx->f_ecnt = tw; /* search count - # entries returned */ 2376 if ((error = md_get_uint16le(mdp, &tw)) != 0) 2377 return (error); 2378 /* 2379 * tw now is the "end of search" flag. against an XP server tw 2380 * comes back zero when the prior find_next returned exactly 2381 * the number of entries requested. in which case we'd try again 2382 * but the search has in fact been closed so an EBADF results. our 2383 * circumvention is to check here for a zero search count. 2384 */ 2385 if (tw || ctx->f_ecnt == 0) 2386 ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; 2387 if ((error = md_get_uint16le(mdp, &tw)) != 0) 2388 return (error); 2389 if ((error = md_get_uint16le(mdp, &tw)) != 0) 2390 return (error); 2391 if (ctx->f_ecnt == 0) 2392 return (ENOENT); 2393 ctx->f_rnameofs = tw; 2394 mdp = &t2p->t2_rdata; 2395 if (mdp->md_top == NULL) { 2396 SMBVDEBUG("ecnt = %d, but data is NULL\n", ctx->f_ecnt); 2397 return (ENOENT); 2398 } 2399 #ifdef APPLE 2400 if (mdp->md_top->m_len == 0) { 2401 printf("bug: ecnt = %d, but m_len = 0 and m_next = %p " 2402 "(please report)\n", ctx->f_ecnt, mbp->mb_top->m_next); 2403 return (ENOENT); 2404 } 2405 #endif 2406 ctx->f_eofs = 0; 2407 return (0); 2408 } 2409 2410 static int 2411 smbfs_smb_findclose2(struct smbfs_fctx *ctx) 2412 { 2413 struct smb_rq rq, *rqp = &rq; 2414 struct mbchain *mbp; 2415 int error; 2416 2417 error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, 2418 ctx->f_scred); 2419 if (error) 2420 return (error); 2421 smb_rq_getrequest(rqp, &mbp); 2422 smb_rq_wstart(rqp); 2423 mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM); 2424 smb_rq_wend(rqp); 2425 smb_rq_bstart(rqp); 2426 smb_rq_bend(rqp); 2427 /* Ditto comments at _smb_close */ 2428 rqp->sr_flags |= SMBR_NOINTR_SEND; 2429 error = smb_rq_simple(rqp); 2430 smb_rq_done(rqp); 2431 return (error); 2432 } 2433 2434 /*ARGSUSED*/ 2435 static int 2436 smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, 2437 const char *wildcard, int wclen, uint16_t attr) 2438 { 2439 2440 ctx->f_type = ft_LM2; 2441 ctx->f_namesz = SMB_MAXFNAMELEN; 2442 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) 2443 ctx->f_namesz *= 2; 2444 ctx->f_name = kmem_zalloc(ctx->f_namesz, KM_SLEEP); 2445 ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) 2446 < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD : 2447 SMB_FIND_BOTH_DIRECTORY_INFO; 2448 ctx->f_attrmask = attr; 2449 ctx->f_wildcard = wildcard; 2450 ctx->f_wclen = wclen; 2451 return (0); 2452 } 2453 2454 static int 2455 smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit) 2456 { 2457 struct mdchain *mdp; 2458 struct smb_t2rq *t2p; 2459 char *cp; 2460 uint8_t tb; 2461 uint16_t date, time, wattr; 2462 uint32_t size, next, dattr, resumekey = 0; 2463 uint64_t llongint; 2464 int error, svtz, cnt, fxsz, nmlen, recsz, otw; 2465 struct timespec ts; 2466 2467 again: 2468 otw = 0; /* nothing sent Over The Wire (yet) */ 2469 if (ctx->f_ecnt == 0) { 2470 if (ctx->f_flags & SMBFS_RDD_EOF) 2471 return (ENOENT); 2472 ctx->f_left = ctx->f_limit = limit; 2473 gethrestime(&ts); 2474 error = smbfs_smb_trans2find2(ctx); 2475 if (error) 2476 return (error); 2477 ctx->f_attr.fa_reqtime = ts; 2478 ctx->f_otws++; 2479 otw = 1; 2480 } 2481 t2p = ctx->f_t2; 2482 mdp = &t2p->t2_rdata; 2483 svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; 2484 switch (ctx->f_infolevel) { 2485 case SMB_FIND_STANDARD: 2486 next = 0; 2487 fxsz = 0; 2488 md_get_uint16le(mdp, &date); 2489 md_get_uint16le(mdp, &time); /* creation time */ 2490 md_get_uint16le(mdp, &date); 2491 md_get_uint16le(mdp, &time); /* access time */ 2492 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); 2493 md_get_uint16le(mdp, &date); 2494 md_get_uint16le(mdp, &time); /* modify time */ 2495 smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); 2496 md_get_uint32le(mdp, &size); 2497 ctx->f_attr.fa_size = size; 2498 md_get_uint32(mdp, NULL); /* allocation size */ 2499 md_get_uint16le(mdp, &wattr); 2500 ctx->f_attr.fa_attr = wattr; 2501 md_get_uint8(mdp, &tb); 2502 size = nmlen = tb; 2503 fxsz = 23; 2504 recsz = next = 24 + nmlen; /* docs misses zero byte @end */ 2505 break; 2506 case SMB_FIND_DIRECTORY_INFO: 2507 case SMB_FIND_BOTH_DIRECTORY_INFO: 2508 md_get_uint32le(mdp, &next); 2509 md_get_uint32le(mdp, &resumekey); /* file index (resume key) */ 2510 md_get_uint64(mdp, NULL); /* creation time */ 2511 md_get_uint64le(mdp, &llongint); 2512 smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_atime); 2513 md_get_uint64le(mdp, &llongint); 2514 smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_mtime); 2515 md_get_uint64le(mdp, &llongint); 2516 smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_ctime); 2517 md_get_uint64le(mdp, &llongint); /* file size */ 2518 ctx->f_attr.fa_size = llongint; 2519 md_get_uint64(mdp, NULL); /* real size (should use) */ 2520 /* freebsd bug: fa_attr endian bug */ 2521 md_get_uint32le(mdp, &dattr); /* extended file attributes */ 2522 ctx->f_attr.fa_attr = dattr; 2523 md_get_uint32le(mdp, &size); /* name len */ 2524 fxsz = 64; /* size ofinfo up to filename */ 2525 if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) { 2526 /* 2527 * Skip EaSize(4 bytes), a byte of ShortNameLength, 2528 * a reserved byte, and ShortName(8.3 means 24 bytes, 2529 * as Leach defined it to always be Unicode) 2530 */ 2531 md_get_mem(mdp, NULL, 30, MB_MSYSTEM); 2532 fxsz += 30; 2533 } 2534 recsz = next ? next : fxsz + size; 2535 break; 2536 default: 2537 SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel); 2538 return (EINVAL); 2539 } 2540 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) 2541 nmlen = min(size, SMB_MAXFNAMELEN * 2); 2542 else 2543 nmlen = min(size, SMB_MAXFNAMELEN); 2544 if (ctx->f_name) 2545 kmem_free(ctx->f_name, ctx->f_namesz); 2546 cp = ctx->f_name = kmem_alloc(nmlen, KM_SLEEP); 2547 ctx->f_namesz = nmlen; 2548 error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM); 2549 if (error) 2550 return (error); 2551 if (next) { 2552 cnt = next - nmlen - fxsz; 2553 if (cnt > 0) 2554 md_get_mem(mdp, NULL, cnt, MB_MSYSTEM); 2555 else if (cnt < 0) { 2556 SMBVDEBUG("out of sync\n"); 2557 return (EBADRPC); 2558 } 2559 } 2560 /* Don't count any trailing null in the name. */ 2561 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { 2562 if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0) 2563 nmlen -= 2; 2564 } else { 2565 if (nmlen && cp[nmlen - 1] == 0) 2566 nmlen--; 2567 } 2568 if (nmlen == 0) 2569 return (EBADRPC); 2570 2571 /* 2572 * Ref radar 3983209. On a find-next we expect a server will 2573 * 1) if the continue bit is set, use the server's idea of current loc, 2574 * 2) else if the resume key is non-zero, use that location, 2575 * 3) else if the resume name is set, use that location, 2576 * 4) else use the server's idea of current location. 2577 * 2578 * Current NetApps don't do that. If we send no continue bit, a zero 2579 * resume key, and a resume name, the NetApp ignores the resume name 2580 * and acts on the (zero) resume key, sending back the start of the 2581 * directory again. Panther doesn't expose the netapp bug; Panther used 2582 * the continue bit, but that was changed for 2866172. Win2000 as a 2583 * client also relies upon the resume name, but they request a very 2584 * large number of files, so the bug would be seen only with very 2585 * large directories. 2586 * 2587 * Our fix is to notice if the second OTW op (the first find-next) 2588 * returns, in the first filename, the same filename we got back 2589 * at the start of the first OTW (the find-first). In that case 2590 * we've detected the server bug and set SMBS_RESUMEKEYS, causing us 2591 * to send non-zero resume keys henceforth. 2592 * 2593 * Caveat: if there's a netapp so old it doesn't negotiate NTLM 0.12 2594 * then we get no resume keys so f_rkey stays zero and this "fix" 2595 * changes nothing. 2596 * 2597 * Note due to a similar problem (4051871) we also set SMBS_RESUMEKEYS 2598 * for FAT volumes, at mount time. 2599 */ 2600 if (otw && !(ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS)) { 2601 if (ctx->f_otws == 1) { 2602 ctx->f_firstnmlen = nmlen; 2603 ctx->f_firstnm = kmem_alloc(nmlen, KM_SLEEP); 2604 bcopy(ctx->f_name, ctx->f_firstnm, nmlen); 2605 } else if (ctx->f_otws == 2 && nmlen == ctx->f_firstnmlen && 2606 !(bcmp(ctx->f_name, ctx->f_firstnm, nmlen) == 0)) { 2607 struct smb_share *ssp = ctx->f_ssp; 2608 SMBERROR( 2609 "server resume_name bug seen; using resume keys\n"); 2610 SMB_SS_LOCK(ssp); 2611 ssp->ss_flags |= SMBS_RESUMEKEYS; 2612 SMB_SS_UNLOCK(ssp); 2613 ctx->f_ecnt = 0; 2614 goto again; /* must redo last otw op! */ 2615 } 2616 } 2617 ctx->f_rkey = resumekey; 2618 2619 next = ctx->f_eofs + recsz; 2620 if (ctx->f_rnameofs && 2621 (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 && 2622 (ctx->f_rnameofs >= ctx->f_eofs && 2623 ctx->f_rnameofs < (int)next)) { 2624 /* 2625 * Server needs a resume filename. 2626 */ 2627 if (ctx->f_rnamelen != nmlen) { 2628 if (ctx->f_rname) 2629 kmem_free(ctx->f_rname, ctx->f_rnamelen); 2630 ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP); 2631 ctx->f_rnamelen = nmlen; 2632 } 2633 bcopy(ctx->f_name, ctx->f_rname, nmlen); 2634 ctx->f_flags |= SMBFS_RDD_GOTRNAME; 2635 } 2636 ctx->f_nmlen = nmlen; 2637 ctx->f_eofs = next; 2638 ctx->f_ecnt--; 2639 ctx->f_left--; 2640 2641 smbfs_fname_tolocal(ctx); 2642 return (0); 2643 } 2644 2645 static int 2646 smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx) 2647 { 2648 int error = 0; 2649 if (ctx->f_name) 2650 kmem_free(ctx->f_name, ctx->f_namesz); 2651 if (ctx->f_t2) 2652 smb_t2_done(ctx->f_t2); 2653 if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) 2654 error = smbfs_smb_findclose2(ctx); 2655 return (error); 2656 } 2657 2658 int 2659 smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen, 2660 int attr, struct smb_cred *scrp, 2661 struct smbfs_fctx **ctxpp) 2662 { 2663 struct smbfs_fctx *ctx; 2664 int error; 2665 2666 ctx = kmem_alloc(sizeof (*ctx), KM_SLEEP); 2667 if (ctx == NULL) 2668 return (ENOMEM); 2669 bzero(ctx, sizeof (*ctx)); 2670 2671 ctx->f_flags = SMBFS_RDD_FINDFIRST; 2672 ctx->f_dnp = dnp; 2673 ctx->f_scred = scrp; 2674 ctx->f_ssp = dnp->n_mount->smi_share; 2675 2676 if (dnp->n_flag & N_XATTR) { 2677 error = smbfs_xa_findopen(ctx, dnp, wild, wlen); 2678 goto out; 2679 } 2680 2681 if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || 2682 (dnp->n_mount->smi_args.flags & SMBFS_MOUNT_NO_LONG)) { 2683 error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr); 2684 } else { 2685 error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr); 2686 } 2687 2688 out: 2689 if (error) 2690 (void) smbfs_smb_findclose(ctx, scrp); 2691 else 2692 *ctxpp = ctx; 2693 return (error); 2694 } 2695 2696 int 2697 smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp) 2698 { 2699 int error; 2700 2701 /* 2702 * Note: "limit" (maxcount) needs to fit in a short! 2703 * 2704 * smb_lookup always uses 1, which is OK (no wildcards). 2705 * Otherwise, this is smbfs_readdir, and we want to force 2706 * limit to be in the range 3 to 1000. The low limit (3) 2707 * is so we can always give the caller one "real" entry 2708 * (something other than "." or "..") The high limit is 2709 * just tuning. WinNT used 512, Win2k 1366. We use 1000. 2710 * 2711 * XXX: Move the [skip . ..] gunk to our caller (readdir). 2712 */ 2713 if ((ctx->f_flags & SMBFS_RDD_FINDSINGLE) == 0) { 2714 if (limit < 3) 2715 limit = 3; 2716 if (limit > 1000) 2717 limit = 1000; 2718 } 2719 2720 ctx->f_scred = scrp; 2721 for (;;) { 2722 bzero(&ctx->f_attr, sizeof (ctx->f_attr)); 2723 switch (ctx->f_type) { 2724 case ft_LM1: 2725 error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit); 2726 break; 2727 case ft_LM2: 2728 error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit); 2729 break; 2730 case ft_XA: 2731 error = smbfs_xa_findnext(ctx, (uint16_t)limit); 2732 break; 2733 default: 2734 ASSERT(0); 2735 error = EINVAL; 2736 break; 2737 } 2738 if (error) 2739 return (error); 2740 /* 2741 * Skip "." or ".." - easy now that ctx->f_name 2742 * has already been converted to utf-8 format. 2743 */ 2744 if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || 2745 (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && 2746 ctx->f_name[1] == '.')) 2747 continue; 2748 break; 2749 } 2750 2751 /* 2752 * Moved the smbfs_fname_tolocal(ctx) call into 2753 * the ..._findnext functions above. 2754 */ 2755 2756 ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, 2757 ctx->f_nmlen); 2758 return (0); 2759 } 2760 2761 2762 int 2763 smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp) 2764 { 2765 int error; 2766 2767 ctx->f_scred = scrp; 2768 switch (ctx->f_type) { 2769 case ft_LM1: 2770 error = smbfs_smb_findcloseLM1(ctx); 2771 break; 2772 case ft_LM2: 2773 error = smbfs_smb_findcloseLM2(ctx); 2774 break; 2775 case ft_XA: 2776 error = smbfs_xa_findclose(ctx); 2777 break; 2778 } 2779 if (ctx->f_rname) 2780 kmem_free(ctx->f_rname, ctx->f_rnamelen); 2781 if (ctx->f_firstnm) 2782 kmem_free(ctx->f_firstnm, ctx->f_firstnmlen); 2783 kmem_free(ctx, sizeof (*ctx)); 2784 return (error); 2785 } 2786 2787 2788 int 2789 smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp, 2790 struct smbfattr *fap, struct smb_cred *scrp) 2791 { 2792 struct smbfs_fctx *ctx; 2793 int error, intr; 2794 const char *name = (namep ? *namep : NULL); 2795 int nmlen = (nmlenp ? *nmlenp : 0); 2796 2797 /* This is no longer called with a null dnp */ 2798 ASSERT(dnp); 2799 2800 /* 2801 * Should not get here with "" anymore. 2802 */ 2803 if (!name || !nmlen) { 2804 DEBUG_ENTER("smbfs_smb_lookup: name is NULL"); 2805 return (EINVAL); 2806 } 2807 2808 /* 2809 * Should not get here with "." or ".." anymore. 2810 */ 2811 if ((nmlen == 1 && name[0] == '.') || 2812 (nmlen == 2 && name[0] == '.' && name[1] == '.')) { 2813 DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'"); 2814 return (EINVAL); 2815 } 2816 2817 /* 2818 * Shared lock for n_fid use (smb_flush). 2819 */ 2820 intr = dnp->n_mount->smi_flags & SMI_INT; 2821 if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr)) 2822 return (EINTR); 2823 2824 /* 2825 * This hides a server bug observable in Win98: 2826 * size changes may not show until a CLOSE or a FLUSH op 2827 * XXX: Make this conditional on !NTSMBs 2828 */ 2829 error = smbfs_smb_flush(dnp, scrp); 2830 if (error) 2831 goto out; 2832 error = smbfs_smb_findopen(dnp, name, nmlen, 2833 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx); 2834 if (error) 2835 goto out; 2836 ctx->f_flags |= SMBFS_RDD_FINDSINGLE; 2837 error = smbfs_smb_findnext(ctx, 1, scrp); 2838 if (error == 0) { 2839 *fap = ctx->f_attr; 2840 if (name == NULL) 2841 fap->fa_ino = dnp->n_ino; 2842 if (namep) 2843 *namep = (const char *)smbfs_name_alloc( 2844 ctx->f_name, ctx->f_nmlen); 2845 if (nmlenp) 2846 *nmlenp = ctx->f_nmlen; 2847 } 2848 (void) smbfs_smb_findclose(ctx, scrp); 2849 2850 out: 2851 smbfs_rw_exit(&dnp->r_lkserlock); 2852 return (error); 2853 } 2854 2855 /* 2856 * OTW function to Get a security descriptor (SD). 2857 * 2858 * Note: On success, this fills in mdp->md_top, 2859 * which the caller should free. 2860 */ 2861 int 2862 smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid, 2863 struct smb_cred *scrp, uint32_t selector, 2864 mblk_t **res, uint32_t *reslen) 2865 { 2866 struct smb_ntrq *ntp; 2867 struct mbchain *mbp; 2868 struct mdchain *mdp; 2869 int error, len; 2870 2871 error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC, 2872 scrp, &ntp); 2873 if (error) 2874 return (error); 2875 2876 /* Parameters part */ 2877 mbp = &ntp->nt_tparam; 2878 mb_init(mbp); 2879 mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); 2880 mb_put_uint16le(mbp, 0); /* reserved */ 2881 mb_put_uint32le(mbp, selector); 2882 /* Data part (none) */ 2883 2884 /* Max. returned parameters and data. */ 2885 ntp->nt_maxpcount = 4; 2886 ntp->nt_maxdcount = *reslen; 2887 2888 error = smb_nt_request(ntp); 2889 if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) 2890 goto done; 2891 *res = NULL; 2892 2893 /* 2894 * if there's more data than we said we could receive, here 2895 * is where we pick up the length of it 2896 */ 2897 mdp = &ntp->nt_rparam; 2898 md_get_uint32le(mdp, reslen); 2899 if (error) 2900 goto done; 2901 2902 /* 2903 * get the data part. 2904 */ 2905 mdp = &ntp->nt_rdata; 2906 if (mdp->md_top == NULL) { 2907 SMBVDEBUG("null md_top? fid 0x%x\n", letohs(fid)); 2908 error = EBADRPC; 2909 goto done; 2910 } 2911 2912 /* 2913 * The returned parameter SD_length should match 2914 * the length of the returned data. Unfortunately, 2915 * we have to work around server bugs here. 2916 */ 2917 len = m_fixhdr(mdp->md_top); 2918 if (len != *reslen) { 2919 SMBVDEBUG("len %d *reslen %d fid 0x%x\n", 2920 len, *reslen, letohs(fid)); 2921 } 2922 2923 /* 2924 * Actual data provided is < returned SD_length. 2925 * 2926 * The following "if (len < *reslen)" handles a Windows bug 2927 * observed when the underlying filesystem is FAT32. In that 2928 * case a 32 byte security descriptor comes back (S-1-1-0, ie 2929 * "Everyone") but the Parameter Block claims 44 is the length 2930 * of the security descriptor. (The Data Block length 2931 * claimed is 32. This server bug was reported against NT 2932 * first and I've personally observed it with W2K. 2933 */ 2934 if (len < *reslen) 2935 *reslen = len; 2936 2937 /* 2938 * Actual data provided is > returned SD_length. 2939 * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0) 2940 * Narrow work-around for returned SD_length==0. 2941 */ 2942 if (len > *reslen) { 2943 /* 2944 * Increase *reslen, but carefully. 2945 */ 2946 if (*reslen == 0 && len <= ntp->nt_maxdcount) 2947 *reslen = len; 2948 } 2949 error = md_get_mbuf(mdp, len, res); 2950 2951 done: 2952 if (error == 0 && *res == NULL) { 2953 ASSERT(*res); 2954 error = EBADRPC; 2955 } 2956 2957 smb_nt_done(ntp); 2958 return (error); 2959 } 2960 2961 #ifdef APPLE 2962 /* 2963 * Wrapper for _getsd() compatible with darwin code. 2964 */ 2965 int 2966 smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp, 2967 uint32_t selector, struct ntsecdesc **res) 2968 { 2969 int error; 2970 uint32_t len, olen; 2971 struct mdchain *mdp, md_store; 2972 struct mbuf *m; 2973 2974 bzero(mdp, sizeof (*mdp)); 2975 len = 500; /* "overlarge" values => server errors */ 2976 again: 2977 olen = len; 2978 error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len); 2979 /* 2980 * Server may give us an error indicating that we 2981 * need a larger data buffer to receive the SD, 2982 * and the size we'll need. Use the given size, 2983 * but only after a sanity check. 2984 * 2985 * XXX: Check for specific error values here? 2986 * XXX: also ... && len <= MAX_RAW_SD_SIZE 2987 */ 2988 if (error && len > olen) 2989 goto again; 2990 2991 if (error) 2992 return (error); 2993 2994 mdp = &md_store; 2995 md_initm(mdp, m); 2996 MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK); 2997 error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM); 2998 md_done(mdp); 2999 3000 return (error); 3001 } 3002 #endif /* APPLE */ 3003 3004 /* 3005 * OTW function to Set a security descriptor (SD). 3006 * Caller data are carried in an mbchain_t. 3007 * 3008 * Note: This normally consumes mbp->mb_top, and clears 3009 * that pointer when it does. 3010 */ 3011 int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid, 3012 struct smb_cred *scrp, uint32_t selector, mblk_t **mp) 3013 { 3014 struct smb_ntrq *ntp; 3015 struct mbchain *mbp; 3016 int error; 3017 3018 error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC, 3019 scrp, &ntp); 3020 if (error) 3021 return (error); 3022 3023 /* Parameters part */ 3024 mbp = &ntp->nt_tparam; 3025 mb_init(mbp); 3026 mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); 3027 mb_put_uint16le(mbp, 0); /* reserved */ 3028 mb_put_uint32le(mbp, selector); 3029 3030 /* Data part */ 3031 mbp = &ntp->nt_tdata; 3032 mb_initm(mbp, *mp); 3033 *mp = NULL; /* consumed */ 3034 3035 /* No returned parameters or data. */ 3036 ntp->nt_maxpcount = 0; 3037 ntp->nt_maxdcount = 0; 3038 3039 error = smb_nt_request(ntp); 3040 smb_nt_done(ntp); 3041 3042 return (error); 3043 } 3044 3045 #ifdef APPLE 3046 /* 3047 * This function builds the SD given the various parts. 3048 */ 3049 int 3050 smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp, 3051 uint32_t selector, uint16_t flags, struct ntsid *owner, 3052 struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl) 3053 { 3054 struct mbchain *mbp, mb_store; 3055 struct ntsecdesc ntsd; 3056 int error, off; 3057 3058 /* 3059 * Build the SD as its own mbuf chain and pass it to 3060 * smbfs_smb_setsec_m() 3061 */ 3062 mbp = &mb_store; 3063 mb_init(mbp); 3064 bzero(&ntsd, sizeof (ntsd)); 3065 wset_sdrevision(&ntsd); 3066 /* 3067 * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN) 3068 * We set here only those bits we can be sure must be set. The rest 3069 * are up to the caller. In particular, the caller may intentionally 3070 * set an acl PRESENT bit while giving us a null pointer for the 3071 * acl - that sets a null acl, giving access to everyone. Note also 3072 * that the AUTO_INHERITED bits should probably always be set unless 3073 * the server is NT. 3074 */ 3075 flags |= SD_SELF_RELATIVE; 3076 off = sizeof (ntsd); 3077 if (owner) { 3078 wset_sdowneroff(&ntsd, off); 3079 off += sidlen(owner); 3080 } 3081 if (group) { 3082 wset_sdgroupoff(&ntsd, off); 3083 off += sidlen(group); 3084 } 3085 if (sacl) { 3086 flags |= SD_SACL_PRESENT; 3087 wset_sdsacloff(&ntsd, off); 3088 off += acllen(sacl); 3089 } 3090 if (dacl) { 3091 flags |= SD_DACL_PRESENT; 3092 wset_sddacloff(&ntsd, off); 3093 } 3094 wset_sdflags(&ntsd, flags); 3095 mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM); 3096 if (owner) 3097 mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM); 3098 if (group) 3099 mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM); 3100 if (sacl) 3101 mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM); 3102 if (dacl) 3103 mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM); 3104 3105 /* 3106 * Just pass the mbuf to _setsec_m 3107 * It will clear mb_top if consumed. 3108 */ 3109 error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top); 3110 mb_done(mbp); 3111 3112 return (error); 3113 } 3114 3115 #endif /* APPLE */ 3116