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