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