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