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