/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c
C | 2831 lines | 2119 code | 255 blank | 457 comment | 371 complexity | 3b8c9685fb05652d92bc904bc48edff4 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
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#include <netsmb/smb_osdep.h> 48 49#include <netsmb/smb.h> 50#include <netsmb/smb_conn.h> 51#include <netsmb/smb_subr.h> 52#include <netsmb/smb_rq.h> 53 54#include <smbfs/smbfs.h> 55#include <smbfs/smbfs_node.h> 56#include <smbfs/smbfs_subr.h> 57 58/* 59 * Jan 1 1980 as 64 bit NT time. 60 * (tenths of microseconds since 1601) 61 */ 62const uint64_t NT1980 = 11960035200ULL*10000000ULL; 63 64/* 65 * Local functions. 66 * Not static, to aid debugging. 67 */ 68 69int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, 70 struct smbfattr *fap, struct smb_cred *scrp); 71int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap, 72 struct smb_cred *scrp, uint16_t infolevel); 73 74int smbfs_smb_statfsLM1(struct smb_share *ssp, 75 statvfs64_t *sbp, struct smb_cred *scrp); 76int smbfs_smb_statfsLM2(struct smb_share *ssp, 77 statvfs64_t *sbp, struct smb_cred *scrp); 78 79int smbfs_smb_setfattrNT(struct smbnode *np, int fid, 80 uint32_t attr, struct timespec *mtime, struct timespec *atime, 81 struct smb_cred *scrp); 82 83int smbfs_smb_setftime1(struct smbnode *np, uint16_t fid, 84 struct timespec *mtime, struct timespec *atime, 85 struct smb_cred *scrp); 86 87int smbfs_smb_setpattr1(struct smbnode *np, 88 const char *name, int len, uint32_t attr, 89 struct timespec *mtime, struct smb_cred *scrp); 90 91 92/* 93 * Todo: locking over-the-wire 94 */ 95#ifdef APPLE 96 97static int 98smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid, 99 offset_t start, uint64_t len, int largelock, 100 struct smb_cred *scrp, uint32_t timeout) 101{ 102 struct smb_share *ssp = np->n_mount->smi_share; 103 struct smb_rq rq, *rqp = &rq; 104 struct mbchain *mbp; 105 uint8_t ltype = 0; 106 int error; 107 108 /* Shared lock for n_fid use below. */ 109 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); 110 111 /* After reconnect, n_fid is invalid */ 112 if (np->n_vcgenid != ssp->ss_vcgenid) 113 return (ESTALE); 114 115 if (op == SMB_LOCK_SHARED) 116 ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; 117 /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */ 118 if (largelock) 119 ltype |= SMB_LOCKING_ANDX_LARGE_FILES; 120 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp); 121 if (error) 122 return (error); 123 smb_rq_getrequest(rqp, &mbp); 124 smb_rq_wstart(rqp); 125 mb_put_uint8(mbp, 0xff); /* secondary command */ 126 mb_put_uint8(mbp, 0); /* MBZ */ 127 mb_put_uint16le(mbp, 0); 128 mb_put_uint16le(mbp, np->n_fid); 129 mb_put_uint8(mbp, ltype); /* locktype */ 130 mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ 131 mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */ 132 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); 133 mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); 134 smb_rq_wend(rqp); 135 smb_rq_bstart(rqp); 136 mb_put_uint16le(mbp, pid); 137 if (!largelock) { 138 mb_put_uint32le(mbp, start); 139 mb_put_uint32le(mbp, len); 140 } else { 141 mb_put_uint16le(mbp, 0); /* pad */ 142 mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */ 143 mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */ 144 mb_put_uint32le(mbp, len >> 32); /* LengthHigh */ 145 mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */ 146 } 147 smb_rq_bend(rqp); 148 /* 149 * Don't want to risk missing a successful 150 * unlock send or lock response, or we could 151 * lose track of an outstanding lock. 152 */ 153 if (op == SMB_LOCK_RELEASE) 154 rqp->sr_flags |= SMBR_NOINTR_SEND; 155 else 156 rqp->sr_flags |= SMBR_NOINTR_RECV; 157 158 error = smb_rq_simple(rqp); 159 smb_rq_done(rqp); 160 return (error); 161} 162 163int 164smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, 165 offset_t start, uint64_t len, int largelock, 166 struct smb_cred *scrp, uint32_t timeout) 167{ 168 struct smb_share *ssp = np->n_mount->smi_share; 169 170 if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0) 171 /* 172 * TODO: use LOCK_BYTE_RANGE here. 173 */ 174 return (EINVAL); 175 176 /* 177 * XXX: compute largelock via: 178 * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? 179 */ 180 return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len, 181 largelock, scrp, timeout)); 182} 183 184#endif /* APPLE */ 185 186/* 187 * Helper for smbfs_getattr 188 * Something like nfs_getattr_otw 189 */ 190int 191smbfs_smb_getfattr( 192 struct smbnode *np, 193 struct smbfattr *fap, 194 struct smb_cred *scrp) 195{ 196 int error; 197 198 /* 199 * This lock is necessary for FID-based calls. 200 * Lock may be writer (via open) or reader. 201 */ 202 ASSERT(np->r_lkserlock.count != 0); 203 204 /* 205 * Extended attribute directory or file. 206 */ 207 if (np->n_flag & N_XATTR) { 208 error = smbfs_xa_getfattr(np, fap, scrp); 209 return (error); 210 } 211 212 error = smbfs_smb_trans2_query(np, fap, scrp, 0); 213 if (error != EINVAL) 214 return (error); 215 216 /* fallback */ 217 error = smbfs_smb_query_info(np, NULL, 0, fap, scrp); 218 219 return (error); 220} 221 222/* 223 * Common function for QueryFileInfo, QueryPathInfo. 224 */ 225int 226smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap, 227 struct smb_cred *scrp, uint16_t infolevel) 228{ 229 struct smb_share *ssp = np->n_mount->smi_share; 230 struct smb_vc *vcp = SSTOVC(ssp); 231 struct smb_t2rq *t2p; 232 int error, svtz, timesok = 1; 233 struct mbchain *mbp; 234 struct mdchain *mdp; 235 uint16_t cmd, date, time, wattr; 236 uint64_t llongint, lsize; 237 uint32_t size, dattr; 238 239 /* 240 * Shared lock for n_fid use below. 241 * See smbfs_smb_getfattr() 242 */ 243 ASSERT(np->r_lkserlock.count != 0); 244 245 /* 246 * If we have a valid open FID, use it. 247 */ 248 if ((np->n_fidrefs > 0) && 249 (np->n_fid != SMB_FID_UNUSED) && 250 (np->n_vcgenid == ssp->ss_vcgenid)) 251 cmd = SMB_TRANS2_QUERY_FILE_INFORMATION; 252 else 253 cmd = SMB_TRANS2_QUERY_PATH_INFORMATION; 254 255top: 256 error = smb_t2_alloc(SSTOCP(ssp), cmd, 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 268 if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION) 269 mb_put_uint16le(mbp, np->n_fid); 270 271 mb_put_uint16le(mbp, infolevel); 272 273 if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) { 274 mb_put_uint32le(mbp, 0); 275 /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ 276 error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); 277 if (error) { 278 smb_t2_done(t2p); 279 return (error); 280 } 281 } 282 283 t2p->t2_maxpcount = 2; 284 t2p->t2_maxdcount = vcp->vc_txmax; 285 error = smb_t2_request(t2p); 286 if (error) { 287 smb_t2_done(t2p); 288 /* Invalid info level? Try fallback. */ 289 if (error == EINVAL && 290 infolevel == SMB_QFILEINFO_ALL_INFO) { 291 infolevel = SMB_QFILEINFO_STANDARD; 292 goto top; 293 } 294 return (error); 295 } 296 mdp = &t2p->t2_rdata; 297 svtz = vcp->vc_sopt.sv_tz; 298 switch (infolevel) { 299 case SMB_QFILEINFO_STANDARD: 300 md_get_uint16le(mdp, &date); 301 md_get_uint16le(mdp, &time); /* creation time */ 302 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime); 303 md_get_uint16le(mdp, &date); 304 md_get_uint16le(mdp, &time); /* access time */ 305 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); 306 md_get_uint16le(mdp, &date); 307 md_get_uint16le(mdp, &time); /* modify time */ 308 smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); 309 md_get_uint32le(mdp, &size); /* EOF position */ 310 fap->fa_size = size; 311 md_get_uint32le(mdp, &size); /* allocation size */ 312 fap->fa_allocsz = size; 313 error = md_get_uint16le(mdp, &wattr); 314 fap->fa_attr = wattr; 315 timesok = 1; 316 break; 317 case SMB_QFILEINFO_ALL_INFO: 318 timesok = 0; 319 /* creation time */ 320 md_get_uint64le(mdp, &llongint); 321 if (llongint) 322 timesok++; 323 smb_time_NT2local(llongint, &fap->fa_createtime); 324 325 /* last access time */ 326 md_get_uint64le(mdp, &llongint); 327 if (llongint) 328 timesok++; 329 smb_time_NT2local(llongint, &fap->fa_atime); 330 331 /* last write time */ 332 md_get_uint64le(mdp, &llongint); 333 if (llongint) 334 timesok++; 335 smb_time_NT2local(llongint, &fap->fa_mtime); 336 337 /* last change time */ 338 md_get_uint64le(mdp, &llongint); 339 if (llongint) 340 timesok++; 341 smb_time_NT2local(llongint, &fap->fa_ctime); 342 343 /* attributes */ 344 md_get_uint32le(mdp, &dattr); 345 fap->fa_attr = dattr; 346 347 /* 348 * 4-Byte alignment - discard 349 * Specs don't talk about this. 350 */ 351 md_get_uint32le(mdp, NULL); 352 /* allocation size */ 353 md_get_uint64le(mdp, &lsize); 354 fap->fa_allocsz = lsize; 355 /* File size */ 356 error = md_get_uint64le(mdp, &lsize); 357 fap->fa_size = lsize; 358 break; 359 default: 360 SMBVDEBUG("unexpected info level %d\n", infolevel); 361 error = EINVAL; 362 } 363 smb_t2_done(t2p); 364 /* 365 * if all times are zero (observed with FAT on NT4SP6) 366 * then fall back to older info level 367 */ 368 if (!timesok) { 369 if (infolevel == SMB_QFILEINFO_ALL_INFO) { 370 infolevel = SMB_QFILEINFO_STANDARD; 371 goto top; 372 } 373 error = EINVAL; 374 } 375 return (error); 376} 377 378/* 379 * Support functions for _qstreaminfo 380 * Moved to smbfs_xattr.c 381 */ 382 383int 384smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa, 385 struct smb_cred *scrp) 386{ 387 struct smb_t2rq *t2p; 388 struct mbchain *mbp; 389 struct mdchain *mdp; 390 int error; 391 uint32_t nlen; 392 393 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, 394 scrp, &t2p); 395 if (error) 396 return (error); 397 mbp = &t2p->t2_tparam; 398 mb_init(mbp); 399 mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO); 400 t2p->t2_maxpcount = 4; 401 t2p->t2_maxdcount = 4 * 3 + 512; 402 error = smb_t2_request(t2p); 403 if (error) 404 goto out; 405 406 mdp = &t2p->t2_rdata; 407 md_get_uint32le(mdp, &fsa->fsa_aflags); 408 md_get_uint32le(mdp, &fsa->fsa_maxname); 409 error = md_get_uint32le(mdp, &nlen); /* fs name length */ 410 if (error) 411 goto out; 412 413 /* 414 * Get the FS type name. 415 */ 416 bzero(fsa->fsa_tname, FSTYPSZ); 417 if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { 418 uint16_t tmpbuf[FSTYPSZ]; 419 size_t tmplen, outlen; 420 421 if (nlen > sizeof (tmpbuf)) 422 nlen = sizeof (tmpbuf); 423 error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM); 424 tmplen = nlen / 2; /* UCS-2 chars */ 425 outlen = FSTYPSZ - 1; 426 (void) uconv_u16tou8(tmpbuf, &tmplen, 427 (uchar_t *)fsa->fsa_tname, &outlen, 428 UCONV_IN_LITTLE_ENDIAN); 429 } else { 430 if (nlen > (FSTYPSZ - 1)) 431 nlen = FSTYPSZ - 1; 432 error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM); 433 } 434 435 /* 436 * If fs_name starts with FAT, we can't set dates before 1980 437 */ 438 if (0 == strncmp(fsa->fsa_tname, "FAT", 3)) { 439 SMB_SS_LOCK(ssp); 440 ssp->ss_flags |= SMBS_FST_FAT; 441 SMB_SS_UNLOCK(ssp); 442 } 443 444out: 445 smb_t2_done(t2p); 446 return (0); 447} 448 449int 450smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp, 451 struct smb_cred *scp) 452{ 453 int error; 454 455 if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) 456 error = smbfs_smb_statfsLM2(ssp, sbp, scp); 457 else 458 error = smbfs_smb_statfsLM1(ssp, sbp, scp); 459 460 return (error); 461} 462 463int 464smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp, 465 struct smb_cred *scrp) 466{ 467 struct smb_t2rq *t2p; 468 struct mbchain *mbp; 469 struct mdchain *mdp; 470 uint16_t bsize; 471 uint32_t units, bpu, funits; 472 uint64_t s, t, f; 473 int error; 474 475 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, 476 scrp, &t2p); 477 if (error) 478 return (error); 479 mbp = &t2p->t2_tparam; 480 mb_init(mbp); 481 mb_put_uint16le(mbp, SMB_QFS_ALLOCATION); 482 t2p->t2_maxpcount = 4; 483 t2p->t2_maxdcount = 4 * 4 + 2; 484 error = smb_t2_request(t2p); 485 if (error) 486 goto out; 487 488 mdp = &t2p->t2_rdata; 489 md_get_uint32le(mdp, NULL); /* fs id */ 490 md_get_uint32le(mdp, &bpu); 491 md_get_uint32le(mdp, &units); 492 md_get_uint32le(mdp, &funits); 493 error = md_get_uint16le(mdp, &bsize); 494 if (error) 495 goto out; 496 s = bsize; 497 s *= bpu; 498 t = units; 499 f = funits; 500 /* 501 * Don't allow over-large blocksizes as they determine 502 * Finder List-view size granularities. On the other 503 * hand, we mustn't let the block count overflow the 504 * 31 bits available. 505 */ 506 while (s > 16 * 1024) { 507 if (t > LONG_MAX) 508 break; 509 s /= 2; 510 t *= 2; 511 f *= 2; 512 } 513 while (t > LONG_MAX) { 514 t /= 2; 515 f /= 2; 516 s *= 2; 517 } 518 sbp->f_bsize = (ulong_t)s; /* file system block size */ 519 sbp->f_blocks = t; /* total data blocks in file system */ 520 sbp->f_bfree = f; /* free blocks in fs */ 521 sbp->f_bavail = f; /* free blocks avail to non-superuser */ 522 sbp->f_files = (-1); /* total file nodes in file system */ 523 sbp->f_ffree = (-1); /* free file nodes in fs */ 524 525out: 526 smb_t2_done(t2p); 527 return (0); 528} 529 530int 531smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp, 532 struct smb_cred *scrp) 533{ 534 struct smb_rq rq, *rqp = &rq; 535 struct mdchain *mdp; 536 uint16_t units, bpu, bsize, funits; 537 uint64_t s, t, f; 538 int error; 539 540 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, 541 scrp); 542 if (error) 543 return (error); 544 smb_rq_wstart(rqp); 545 smb_rq_wend(rqp); 546 smb_rq_bstart(rqp); 547 smb_rq_bend(rqp); 548 error = smb_rq_simple(rqp); 549 if (error) 550 goto out; 551 552 smb_rq_getreply(rqp, &mdp); 553 md_get_uint16le(mdp, &units); 554 md_get_uint16le(mdp, &bpu); 555 md_get_uint16le(mdp, &bsize); 556 error = md_get_uint16le(mdp, &funits); 557 if (error) 558 goto out; 559 s = bsize; 560 s *= bpu; 561 t = units; 562 f = funits; 563 /* 564 * Don't allow over-large blocksizes as they determine 565 * Finder List-view size granularities. On the other 566 * hand, we mustn't let the block count overflow the 567 * 31 bits available. 568 */ 569 while (s > 16 * 1024) { 570 if (t > LONG_MAX) 571 break; 572 s /= 2; 573 t *= 2; 574 f *= 2; 575 } 576 while (t > LONG_MAX) { 577 t /= 2; 578 f /= 2; 579 s *= 2; 580 } 581 sbp->f_bsize = (ulong_t)s; /* file system block size */ 582 sbp->f_blocks = t; /* total data blocks in file system */ 583 sbp->f_bfree = f; /* free blocks in fs */ 584 sbp->f_bavail = f; /* free blocks avail to non-superuser */ 585 sbp->f_files = (-1); /* total file nodes in file system */ 586 sbp->f_ffree = (-1); /* free file nodes in fs */ 587 588out: 589 smb_rq_done(rqp); 590 return (0); 591} 592 593int 594smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize, 595 struct smb_cred *scrp) 596{ 597 struct smb_t2rq *t2p; 598 struct smb_vc *vcp = SSTOVC(ssp); 599 struct mbchain *mbp; 600 int error; 601 602 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 603 scrp, &t2p); 604 if (error) 605 return (error); 606 mbp = &t2p->t2_tparam; 607 mb_init(mbp); 608 mb_put_uint16le(mbp, fid); 609 if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) 610 mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION); 611 else 612 mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO); 613 mb_put_uint16le(mbp, 0); /* pad */ 614 mbp = &t2p->t2_tdata; 615 mb_init(mbp); 616 mb_put_uint64le(mbp, newsize); 617 t2p->t2_maxpcount = 2; 618 t2p->t2_maxdcount = 0; 619 error = smb_t2_request(t2p); 620 smb_t2_done(t2p); 621 return (error); 622} 623 624/*ARGSUSED*/ 625int 626smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp, 627 const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite) 628{ 629 struct smb_t2rq *t2p; 630 struct smb_share *ssp = np->n_mount->smi_share; 631 struct smb_vc *vcp = SSTOVC(ssp); 632 struct mbchain *mbp; 633 int32_t *ucslenp; 634 int error, cerror; 635 uint16_t fid = 0; 636 637 /* Shared lock for n_fid use below. */ 638 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); 639 640 /* After reconnect, n_fid is invalid */ 641 if (np->n_vcgenid != ssp->ss_vcgenid) 642 return (ESTALE); 643 644 if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)) 645 return (ENOTSUP); 646 error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, 647 scrp, &t2p); 648 if (error) 649 return (error); 650 if (tdnp) { 651 error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp, 652 &fid); 653 if (error) 654 goto exit; 655 } 656 mbp = &t2p->t2_tparam; 657 mb_init(mbp); 658 mb_put_uint16le(mbp, np->n_fid); 659 mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION); 660 mb_put_uint16le(mbp, 0); /* reserved, nowadays */ 661 mbp = &t2p->t2_tdata; 662 mb_init(mbp); 663 mb_put_uint32le(mbp, overwrite); 664 mb_put_uint16le(mbp, fid); /* base for tname */ 665 mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */ 666 ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t)); 667 mbp->mb_count = 0; 668 error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE); 669 if (error) 670 goto exit; 671 mbp->mb_count--; /* don't count the null */ 672 *ucslenp = htolel(mbp->mb_count); 673 t2p->t2_maxpcount = 2; 674 t2p->t2_maxdcount = 0; 675 error = smb_t2_request(t2p); 676exit: 677 if (fid) { 678 cerror = smbfs_smb_tmpclose(tdnp, fid, scrp); 679 if (cerror) 680 SMBVDEBUG("error %d closing %s\n", 681 cerror, tdnp->n_rpath); 682 } 683 smb_t2_done(t2p); 684 return (error); 685} 686 687int 688smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp) 689{ 690 struct smb_share *ssp = np->n_mount->smi_share; 691 struct smb_rq rq, *rqp = &rq; 692 struct mbchain *mbp; 693 int error; 694 695 /* Shared lock for n_fid use below. */ 696 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); 697 698 if (!(np->n_flag & NFLUSHWIRE)) 699 return (0); 700 if (np->n_fidrefs == 0) 701 return (0); /* not open */ 702 703 /* After reconnect, n_fid is invalid */ 704 if (np->n_vcgenid != ssp->ss_vcgenid) 705 return (ESTALE); 706 707 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp); 708 if (error) 709 return (error); 710 smb_rq_getrequest(rqp, &mbp); 711 smb_rq_wstart(rqp); 712 mb_put_uint16le(mbp, np->n_fid); 713 smb_rq_wend(rqp); 714 smb_rq_bstart(rqp); 715 smb_rq_bend(rqp); 716 error = smb_rq_simple(rqp); 717 smb_rq_done(rqp); 718 if (!error) { 719 mutex_enter(&np->r_statelock); 720 np->n_flag &= ~NFLUSHWIRE; 721 mutex_exit(&np->r_statelock); 722 } 723 return (error); 724} 725 726int 727smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize, 728 struct smb_cred *scrp) 729{ 730 struct smb_share *ssp = np->n_mount->smi_share; 731 struct smb_rq rq, *rqp = &rq; 732 struct mbchain *mbp; 733 int error; 734 735 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 736 /* 737 * This call knows about 64-bit offsets. 738 */ 739 error = smbfs_smb_seteof(ssp, fid, newsize, scrp); 740 if (!error) { 741 mutex_enter(&np->r_statelock); 742 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); 743 mutex_exit(&np->r_statelock); 744 return (0); 745 } 746 } 747 748 /* 749 * OK, so fallback to SMB_COM_WRITE, but note: 750 * it only supports 32-bit file offsets. 751 */ 752 if (newsize > UINT32_MAX) 753 return (EFBIG); 754 755 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp); 756 if (error) 757 return (error); 758 smb_rq_getrequest(rqp, &mbp); 759 smb_rq_wstart(rqp); 760 mb_put_uint16le(mbp, fid); 761 mb_put_uint16le(mbp, 0); 762 mb_put_uint32le(mbp, newsize); 763 mb_put_uint16le(mbp, 0); 764 smb_rq_wend(rqp); 765 smb_rq_bstart(rqp); 766 mb_put_uint8(mbp, SMB_DT_DATA); 767 mb_put_uint16le(mbp, 0); 768 smb_rq_bend(rqp); 769 error = smb_rq_simple(rqp); 770 smb_rq_done(rqp); 771 mutex_enter(&np->r_statelock); 772 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); 773 mutex_exit(&np->r_statelock); 774 return (error); 775} 776 777/* 778 * Old method for getting file attributes. 779 */ 780int 781smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, 782 struct smbfattr *fap, struct smb_cred *scrp) 783{ 784 struct smb_rq rq, *rqp = &rq; 785 struct smb_share *ssp = np->n_mount->smi_share; 786 struct mbchain *mbp; 787 struct mdchain *mdp; 788 uint8_t wc; 789 int error; 790 uint16_t wattr; 791 uint32_t longint; 792 793 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp); 794 if (error) 795 return (error); 796 smb_rq_getrequest(rqp, &mbp); 797 smb_rq_wstart(rqp); 798 smb_rq_wend(rqp); 799 smb_rq_bstart(rqp); 800 mb_put_uint8(mbp, SMB_DT_ASCII); 801 802 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, 803 name, &nmlen, '\\'); 804 if (error) 805 goto out; 806 smb_rq_bend(rqp); 807 error = smb_rq_simple(rqp); 808 if (error) 809 goto out; 810 smb_rq_getreply(rqp, &mdp); 811 error = md_get_uint8(mdp, &wc); 812 if (error) 813 goto out; 814 if (wc != 10) { 815 error = EBADRPC; 816 goto out; 817 } 818 md_get_uint16le(mdp, &wattr); 819 fap->fa_attr = wattr; 820 /* 821 * Be careful using the time returned here, as 822 * with FAT on NT4SP6, at least, the time returned is low 823 * 32 bits of 100s of nanoseconds (since 1601) so it rolls 824 * over about every seven minutes! 825 */ 826 md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ 827 smb_time_server2local(longint, 828 SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime); 829 error = md_get_uint32le(mdp, &longint); 830 fap->fa_size = longint; 831 832out: 833 smb_rq_done(rqp); 834 return (error); 835} 836 837/* 838 * Set DOS file attributes. mtime should be NULL for dialects above lm10 839 */ 840int 841smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len, 842 uint32_t attr, struct timespec *mtime, 843 struct smb_cred *scrp) 844{ 845 struct smb_rq rq, *rqp = &rq; 846 struct smb_share *ssp = np->n_mount->smi_share; 847 struct mbchain *mbp; 848 long time; 849 int error, svtz; 850 851 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp); 852 if (error) 853 return (error); 854 svtz = SSTOVC(ssp)->vc_sopt.sv_tz; 855 smb_rq_getrequest(rqp, &mbp); 856 smb_rq_wstart(rqp); 857 mb_put_uint16le(mbp, (uint16_t)attr); 858 if (mtime) { 859 smb_time_local2server(mtime, svtz, &time); 860 } else 861 time = 0; 862 mb_put_uint32le(mbp, time); /* mtime */ 863 mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); 864 smb_rq_wend(rqp); 865 smb_rq_bstart(rqp); 866 mb_put_uint8(mbp, SMB_DT_ASCII); 867 868 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &len, '\\'); 869 if (error) 870 goto out; 871 mb_put_uint8(mbp, SMB_DT_ASCII); 872 if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { 873 mb_put_padbyte(mbp); 874 mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */ 875 } 876 mb_put_uint8(mbp, 0); 877 smb_rq_bend(rqp); 878 error = smb_rq_simple(rqp); 879 880out: 881 smb_rq_done(rqp); 882 return (error); 883} 884 885int 886smbfs_smb_hideit(struct smbnode *np, const char *name, int len, 887 struct smb_cred *scrp) 888{ 889 struct smbfattr fa; 890 int error; 891 uint32_t attr; 892 893 error = smbfs_smb_query_info(np, name, len, &fa, scrp); 894 attr = fa.fa_attr; 895 if (!error && !(attr & SMB_FA_HIDDEN)) { 896 attr |= SMB_FA_HIDDEN; 897 error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp); 898 } 899 return (error); 900} 901 902 903int 904smbfs_smb_unhideit(struct smbnode *np, const char *name, int len, 905 struct smb_cred *scrp) 906{ 907 struct smbfattr fa; 908 uint32_t attr; 909 int error; 910 911 error = smbfs_smb_query_info(np, name, len, &fa, scrp); 912 attr = fa.fa_attr; 913 if (!error && (attr & SMB_FA_HIDDEN)) { 914 attr &= ~SMB_FA_HIDDEN; 915 error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp); 916 } 917 return (error); 918} 919 920/* 921 * Set file attributes (optionally: DOS attr, atime, mtime) 922 * either by open FID or by path name (FID == -1). 923 */ 924int 925smbfs_smb_setfattr( 926 struct smbnode *np, 927 int fid, 928 uint32_t attr, 929 struct timespec *mtime, 930 struct timespec *atime, 931 struct smb_cred *scrp) 932{ 933 struct smb_share *ssp = np->n_mount->smi_share; 934 struct smb_vc *vcp = SSTOVC(ssp); 935 int error; 936 937 /* 938 * Normally can use the trans2 call. 939 */ 940 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 941 error = smbfs_smb_setfattrNT(np, fid, 942 attr, mtime, atime, scrp); 943 return (error); 944 } 945 946 /* 947 * Fall-back for older protocols. 948 */ 949 if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { 950 error = smbfs_smb_setftime1(np, fid, 951 mtime, atime, scrp); 952 return (error); 953 } 954 error = smbfs_smb_setpattr1(np, NULL, 0, 955 attr, mtime, scrp); 956 return (error); 957} 958 959/* 960 * Set file atime and mtime. Isn't supported by core dialect. 961 */ 962int 963smbfs_smb_setftime1( 964 struct smbnode *np, 965 uint16_t fid, 966 struct timespec *mtime, 967 struct timespec *atime, 968 struct smb_cred *scrp) 969{ 970 struct smb_rq rq, *rqp = &rq; 971 struct smb_share *ssp = np->n_mount->smi_share; 972 struct mbchain *mbp; 973 uint16_t date, time; 974 int error, tzoff; 975 976 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp); 977 if (error) 978 return (error); 979 980 tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; 981 smb_rq_getrequest(rqp, &mbp); 982 smb_rq_wstart(rqp); 983 mb_put_uint16le(mbp, fid); 984 mb_put_uint32le(mbp, 0); /* creation time */ 985 986 if (atime) 987 smb_time_unix2dos(atime, tzoff, &date, &time, NULL); 988 else 989 time = date = 0; 990 mb_put_uint16le(mbp, date); 991 mb_put_uint16le(mbp, time); 992 if (mtime) 993 smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); 994 else 995 time = date = 0; 996 mb_put_uint16le(mbp, date); 997 mb_put_uint16le(mbp, time); 998 smb_rq_wend(rqp); 999 smb_rq_bstart(rqp); 1000 smb_rq_bend(rqp); 1001 error = smb_rq_simple(rqp); 1002 SMBVDEBUG("%d\n", error); 1003 smb_rq_done(rqp); 1004 return (error); 1005} 1006 1007/* 1008 * Set DOS file attributes, either via open FID or by path name. 1009 * Looks like this call can be used only if CAP_NT_SMBS bit is on. 1010 * 1011 * When setting via path (fid == -1): 1012 * *BASIC_INFO works with Samba, but Win2K servers say it is an 1013 * invalid information level on a SET_PATH_INFO. Note Win2K does 1014 * support *BASIC_INFO on a SET_FILE_INFO, and they support the 1015 * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure. 1016 */ 1017int 1018smbfs_smb_setfattrNT( 1019 struct smbnode *np, 1020 int fid, /* if fid == -1, set by path */ 1021 uint32_t attr, 1022 struct timespec *mtime, 1023 struct timespec *atime, 1024 struct smb_cred *scrp) 1025{ 1026 struct smb_t2rq *t2p; 1027 struct smb_share *ssp = np->n_mount->smi_share; 1028 struct smb_vc *vcp = SSTOVC(ssp); 1029 struct mbchain *mbp; 1030 uint64_t tm; 1031 int error; 1032 uint16_t cmd, level; 1033 1034 if (fid == -1) { 1035 cmd = SMB_TRANS2_SET_PATH_INFORMATION; 1036 } else { 1037 if (fid > UINT16_MAX) 1038 return (EINVAL); 1039 cmd = SMB_TRANS2_SET_FILE_INFORMATION; 1040 } 1041 if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) 1042 level = SMB_SFILEINFO_BASIC_INFORMATION; 1043 else 1044 level = SMB_SFILEINFO_BASIC_INFO; 1045 1046 error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p); 1047 if (error) 1048 return (error); 1049 1050 mbp = &t2p->t2_tparam; 1051 mb_init(mbp); 1052 1053 if (cmd == SMB_TRANS2_SET_FILE_INFORMATION) 1054 mb_put_uint16le(mbp, fid); 1055 1056 mb_put_uint16le(mbp, level); 1057 mb_put_uint32le(mbp, 0); /* MBZ */ 1058 1059 if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) { 1060 error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); 1061 if (error != 0) 1062 goto out; 1063 } 1064 1065 /* FAT file systems don't support dates earlier than 1980. */ 1066 1067 mbp = &t2p->t2_tdata; 1068 mb_init(mbp); 1069 mb_put_uint64le(mbp, 0); /* creation time */ 1070 if (atime) { 1071 smb_time_local2NT(atime, &tm); 1072 if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && 1073 tm < NT1980) 1074 tm = NT1980; 1075 } else 1076 tm = 0; 1077 mb_put_uint64le(mbp, tm); /* access time */ 1078 if (mtime) { 1079 smb_time_local2NT(mtime, &tm); 1080 if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && 1081 tm < NT1980) 1082 tm = NT1980; 1083 } else 1084 tm = 0; 1085 mb_put_uint64le(mbp, tm); /* last write time */ 1086 mb_put_uint64le(mbp, 0); /* ctime (no change) */ 1087 mb_put_uint32le(mbp, attr); 1088 mb_put_uint32le(mbp, 0); /* padding */ 1089 t2p->t2_maxpcount = 2; 1090 t2p->t2_maxdcount = 0; 1091 error = smb_t2_request(t2p); 1092out: 1093 smb_t2_done(t2p); 1094 return (error); 1095} 1096 1097/* 1098 * Modern create/open of file or directory. 1099 * 1100 * If disp is ..._DISP_OPEN, or ...DISP_OPEN_IF, or... 1101 * then this is an open attempt, and: 1102 * If xattr then name is the stream to be opened at np, 1103 * Else np should be opened. 1104 * ...we won't touch *fidp, 1105 * ...we will set or clear *attrcacheupdated. 1106 * Else this is a creation attempt, and: 1107 * If xattr then name is the stream to create at np, 1108 * Else name is the thing to create under directory np. 1109 * ...we will return *fidp, 1110 * ...we won't touch *attrcacheupdated. 1111 * 1112 * Note, We use: disp = ...OPEN_IF, ...OVERWRITE_IF, etc. 1113 * now too, which may or may not create a new object. 1114 */ 1115int 1116smbfs_smb_ntcreatex( 1117 struct smbnode *np, 1118 const char *name, 1119 int nmlen, 1120 int xattr, /* is named stream? */ 1121 uint32_t req_acc, /* requested access */ 1122 uint32_t efa, /* ext. file attrs (DOS attr +) */ 1123 uint32_t share_acc, 1124 uint32_t disp, /* open disposition */ 1125 uint32_t createopt, /* NTCREATEX_OPTIONS_ */ 1126 struct smb_cred *scrp, 1127 uint16_t *fidp, 1128 uint32_t *cr_act_p, /* create action */ 1129 struct smbfattr *fap) /* optional */ 1130{ 1131 struct smb_rq rq, *rqp = &rq; 1132 struct smb_share *ssp = np->n_mount->smi_share; 1133 struct smb_vc *vcp = SSTOVC(ssp); 1134 struct mbchain *mbp; 1135 struct mdchain *mdp; 1136 struct smbfattr fa; 1137 uint8_t wc; 1138 uint32_t longint, createact; 1139 uint64_t llongint; 1140 int error; 1141 uint16_t fid, *namelenp; 1142 1143 bzero(&fa, sizeof (fa)); 1144 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp); 1145 if (error) 1146 return (error); 1147 smb_rq_getrequest(rqp, &mbp); 1148 smb_rq_wstart(rqp); 1149 mb_put_uint8(mbp, 0xff); /* secondary command */ 1150 mb_put_uint8(mbp, 0); /* MBZ */ 1151 mb_put_uint16le(mbp, 0); /* offset to next command (none) */ 1152 mb_put_uint8(mbp, 0); /* MBZ */ 1153 namelenp = (uint16_t *)mb_reserve(mbp, sizeof (uint16_t)); 1154 /* 1155 * XP to a W2K Server does not use NTCREATEX_FLAGS_OPEN_DIRECTORY 1156 * for creating nor for opening a directory. Samba ignores the bit. 1157 */ 1158 mb_put_uint32le(mbp, 0); /* NTCREATEX_FLAGS_* */ 1159 mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */ 1160 mb_put_uint32le(mbp, req_acc); 1161 mb_put_uint64le(mbp, 0); /* "initial allocation size" */ 1162 mb_put_uint32le(mbp, efa); 1163 mb_put_uint32le(mbp, share_acc); 1164 mb_put_uint32le(mbp, disp); 1165 mb_put_uint32le(mbp, createopt); 1166 mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */ 1167 mb_put_uint8(mbp, 0); /* security flags (?) */ 1168 smb_rq_wend(rqp); 1169 smb_rq_bstart(rqp); 1170 1171 if (name == NULL) 1172 nmlen = 0; 1173 error = smbfs_fullpath(mbp, vcp, np, name, &nmlen, 1174 xattr ? ':' : '\\'); 1175 if (error) 1176 goto done; 1177 *namelenp = htoles(nmlen); /* includes null */ 1178 smb_rq_bend(rqp); 1179 /* 1180 * Don't want to risk missing a successful 1181 * open response, or we could "leak" FIDs. 1182 */ 1183 rqp->sr_flags |= SMBR_NOINTR_RECV; 1184 error = smb_rq_simple_timed(rqp, smb_timo_open); 1185 if (error) 1186 goto done; 1187 smb_rq_getreply(rqp, &mdp); 1188 /* 1189 * spec says 26 for word count, but 34 words are defined 1190 * and observed from win2000 1191 */ 1192 error = md_get_uint8(mdp, &wc); 1193 if (error) 1194 goto done; 1195 if (wc != 26 && wc != 34 && wc != 42) { 1196 error = EBADRPC; 1197 goto done; 1198 } 1199 md_get_uint8(mdp, NULL); /* secondary cmd */ 1200 md_get_uint8(mdp, NULL); /* mbz */ 1201 md_get_uint16le(mdp, NULL); /* andxoffset */ 1202 md_get_uint8(mdp, NULL); /* oplock lvl granted */ 1203 md_get_uint16le(mdp, &fid); /* file ID */ 1204 md_get_uint32le(mdp, &createact); /* create_action */ 1205 1206 md_get_uint64le(mdp, &llongint); /* creation time */ 1207 smb_time_NT2local(llongint, &fa.fa_createtime); 1208 md_get_uint64le(mdp, &llongint); /* access time */ 1209 smb_time_NT2local(llongint, &fa.fa_atime); 1210 md_get_uint64le(mdp, &llongint); /* write time */ 1211 smb_time_NT2local(llongint, &fa.fa_mtime); 1212 md_get_uint64le(mdp, &llongint); /* change time */ 1213 smb_time_NT2local(llongint, &fa.fa_ctime); 1214 1215 md_get_uint32le(mdp, &longint); /* attributes */ 1216 fa.fa_attr = longint; 1217 1218 md_get_uint64le(mdp, &llongint); /* allocation size */ 1219 fa.fa_allocsz = llongint; 1220 1221 md_get_uint64le(mdp, &llongint); /* EOF position */ 1222 fa.fa_size = llongint; 1223 1224 error = md_get_uint16le(mdp, NULL); /* file type */ 1225 /* other stuff we don't care about */ 1226 1227done: 1228 smb_rq_done(rqp); 1229 if (error) 1230 return (error); 1231 1232 if (fidp) 1233 *fidp = fid; 1234 if (cr_act_p) 1235 *cr_act_p = createact; 1236 if (fap) 1237 *fap = fa; /* struct copy */ 1238 1239 return (0); 1240} 1241 1242static uint32_t 1243smb_mode2rights(int mode) 1244{ 1245 mode = mode & SMB_AM_OPENMODE; 1246 uint32_t rights = 1247 STD_RIGHT_SYNCHRONIZE_ACCESS | 1248 STD_RIGHT_READ_CONTROL_ACCESS; 1249 1250 if ((mode == SMB_AM_OPENREAD) || 1251 (mode == SMB_AM_OPENRW)) { 1252 rights |= 1253 SA_RIGHT_FILE_READ_ATTRIBUTES | 1254 SA_RIGHT_FILE_READ_DATA; 1255 } 1256 1257 if ((mode == SMB_AM_OPENWRITE) || 1258 (mode == SMB_AM_OPENRW)) { 1259 rights |= 1260 SA_RIGHT_FILE_WRITE_ATTRIBUTES | 1261 SA_RIGHT_FILE_APPEND_DATA | 1262 SA_RIGHT_FILE_WRITE_DATA; 1263 } 1264 1265 if (mode == SMB_AM_OPENEXEC) { 1266 rights |= 1267 SA_RIGHT_FILE_READ_ATTRIBUTES | 1268 SA_RIGHT_FILE_EXECUTE; 1269 } 1270 1271 return (rights); 1272} 1273 1274static int 1275smb_rights2mode(uint32_t rights) 1276{ 1277 int accmode = SMB_AM_OPENEXEC; /* our fallback */ 1278 1279 if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD | 1280 SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES | 1281 SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS | 1282 STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS)) 1283 accmode = SMB_AM_OPENWRITE; 1284 if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES | 1285 SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS)) 1286 accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD 1287 : SMB_AM_OPENRW; 1288 return (accmode); 1289} 1290 1291static int 1292smbfs_smb_oldopen( 1293 struct smbnode *np, 1294 const char *name, 1295 int nmlen, 1296 int xattr, 1297 int accmode, 1298 struct smb_cred *scrp, 1299 uint16_t *fidp, 1300 uint16_t *granted_mode_p, 1301 smbfattr_t *fap) 1302{ 1303 struct smb_rq rq, *rqp = &rq; 1304 struct smb_share *ssp = np->n_mount->smi_share; 1305 struct smb_vc *vcp = SSTOVC(ssp); 1306 struct mbchain *mbp; 1307 struct mdchain *mdp; 1308 struct smbfattr fa; 1309 uint8_t wc; 1310 uint16_t wattr; 1311 uint32_t longint; 1312 int error; 1313 1314 bzero(&fa, sizeof (fa)); 1315 1316 /* 1317 * XXX: move to callers... 1318 * 1319 * Use DENYNONE to give unixy semantics of permitting 1320 * everything not forbidden by permissions. Ie denial 1321 * is up to server with clients/openers needing to use 1322 * advisory locks for further control. 1323 */ 1324 accmode |= SMB_SM_DENYNONE; 1325 1326 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp); 1327 if (error) 1328 return (error); 1329 smb_rq_getrequest(rqp, &mbp); 1330 smb_rq_wstart(rqp); 1331 mb_put_uint16le(mbp, accmode); 1332 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY | 1333 SMB_FA_DIR); 1334 smb_rq_wend(rqp); 1335 smb_rq_bstart(rqp); 1336 mb_put_uint8(mbp, SMB_DT_ASCII); 1337 1338 error = smbfs_fullpath(mbp, vcp, np, name, &nmlen, 1339 xattr ? ':' : '\\'); 1340 if (error) 1341 goto done; 1342 smb_rq_bend(rqp); 1343 /* 1344 * Don't want to risk missing a successful 1345 * open response, or we could "leak" FIDs. 1346 */ 1347 rqp->sr_flags |= SMBR_NOINTR_RECV; 1348 error = smb_rq_simple_timed(rqp, smb_timo_open); 1349 if (error) 1350 goto done; 1351 smb_rq_getreply(rqp, &mdp); 1352 /* 1353 * 8/2002 a DAVE server returned wc of 15 so we ignore that. 1354 * (the actual packet length and data was correct) 1355 */ 1356 error = md_get_uint8(mdp, &wc); 1357 if (error) 1358 goto done; 1359 if (wc != 7 && wc != 15) { 1360 error = EBADRPC; 1361 goto done; 1362 } 1363 md_get_uint16le(mdp, fidp); 1364 md_get_uint16le(mdp, &wattr); 1365 fa.fa_attr = wattr; 1366 /* 1367 * Be careful using the time returned here, as 1368 * with FAT on NT4SP6, at least, the time returned is low 1369 * 32 bits of 100s of nanoseconds (since 1601) so it rolls 1370 * over about every seven minutes! 1371 */ 1372 md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ 1373 smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime); 1374 md_get_uint32le(mdp, &longint); 1375 fa.fa_size = longint; 1376 error = md_get_uint16le(mdp, granted_mode_p); 1377 1378done: 1379 smb_rq_done(rqp); 1380 if (error) 1381 return (error); 1382 1383 if (fap) 1384 *fap = fa; /* struct copy */ 1385 1386 return (0); 1387} 1388 1389int 1390smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, 1391 uint16_t *fidp) 1392{ 1393 struct smb_share *ssp = np->n_mount->smi_share; 1394 struct smb_vc *vcp = SSTOVC(ssp); 1395 int accmode, error; 1396 1397 /* Shared lock for n_fid use below. */ 1398 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); 1399 1400 /* Can we re-use n_fid? or must we open anew? */ 1401 mutex_enter(&np->r_statelock); 1402 if (np->n_fidrefs > 0 && 1403 np->n_vcgenid == ssp->ss_vcgenid && 1404 (rights & np->n_rights) == rights) { 1405 np->n_fidrefs++; 1406 *fidp = np->n_fid; 1407 mutex_exit(&np->r_statelock); 1408 return (0); 1409 } 1410 mutex_exit(&np->r_statelock); 1411 1412 /* re-open an existing file. */ 1413 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 1414 error = smbfs_smb_ntcreatex(np, 1415 NULL, 0, 0, /* name nmlen xattr */ 1416 rights, SMB_EFA_NORMAL, 1417 NTCREATEX_SHARE_ACCESS_ALL, 1418 NTCREATEX_DISP_OPEN, 1419 0, /* create options */ 1420 scrp, fidp, 1421 NULL, NULL); /* cr_act_p fa_p */ 1422 return (error); 1423 } 1424 1425 accmode = smb_rights2mode(rights); 1426 error = smbfs_smb_oldopen(np, 1427 NULL, 0, 0, /* name nmlen xattr */ 1428 accmode, scrp, 1429 fidp, 1430 NULL, /* granted mode p */ 1431 NULL); /* fa p */ 1432 1433 return (error); 1434} 1435 1436int 1437smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp) 1438{ 1439 struct smb_share *ssp = np->n_mount->smi_share; 1440 int error = 0; 1441 uint16_t oldfid = SMB_FID_UNUSED; 1442 1443 /* Shared lock for n_fid use below. */ 1444 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); 1445 1446 mutex_enter(&np->r_statelock); 1447 if (fid == np->n_fid) { 1448 ASSERT(np->n_fidrefs > 0); 1449 if (--np->n_fidrefs == 0) { 1450 /* 1451 * Don't expect to find the last reference 1452 * here in tmpclose. Hard to deal with as 1453 * we don't have r_lkserlock exclusive. 1454 * Will close oldfid below. 1455 */ 1456 oldfid = np->n_fid; 1457 np->n_fid = SMB_FID_UNUSED; 1458 } 1459 } else { 1460 /* Will close the passed fid. */ 1461 oldfid = fid; 1462 } 1463 mutex_exit(&np->r_statelock); 1464 1465 if (oldfid != SMB_FID_UNUSED) 1466 error = smbfs_smb_close(ssp, oldfid, NULL, scrp); 1467 1468 return (error); 1469} 1470 1471int 1472smbfs_smb_open( 1473 struct smbnode *np, 1474 const char *name, 1475 int nmlen, 1476 int xattr, 1477 uint32_t rights, 1478 struct smb_cred *scrp, 1479 uint16_t *fidp, 1480 uint32_t *rightsp, 1481 smbfattr_t *fap) 1482{ 1483 struct smb_share *ssp = np->n_mount->smi_share; 1484 struct smb_vc *vcp = SSTOVC(ssp); 1485 int accmode, error; 1486 uint16_t grantedmode; 1487 1488 /* open an existing file */ 1489 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 1490 error = smbfs_smb_ntcreatex(np, 1491 name, nmlen, xattr, 1492 rights, SMB_EFA_NORMAL, 1493 NTCREATEX_SHARE_ACCESS_ALL, 1494 NTCREATEX_DISP_OPEN, 1495 0, /* create options */ 1496 scrp, fidp, 1497 NULL, fap); /* cr_act_p fa_p */ 1498 if (error != 0) 1499 return (error); 1500 *rightsp = rights; 1501 return (0); 1502 } 1503 1504 accmode = smb_rights2mode(rights); 1505 error = smbfs_smb_oldopen(np, 1506 name, nmlen, xattr, accmode, scrp, 1507 fidp, &grantedmode, fap); 1508 if (error != 0) 1509 return (error); 1510 *rightsp = smb_mode2rights(grantedmode); 1511 (void) smbfs_smb_getfattr(np, fap, scrp); 1512 1513 return (0); 1514} 1515 1516int 1517smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime, 1518 struct smb_cred *scrp) 1519{ 1520 struct smb_rq rq, *rqp = &rq; 1521 struct mbchain *mbp; 1522 long time; 1523 int error; 1524 1525 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp); 1526 if (error) 1527 return (error); 1528 smb_rq_getrequest(rqp, &mbp); 1529 smb_rq_wstart(rqp); 1530 mb_put_uint16le(mbp, fid); 1531 if (mtime) { 1532 int sv_tz = SSTOVC(ssp)->vc_sopt.sv_tz; 1533 smb_time_local2server(mtime, sv_tz, &time); 1534 } else 1535 time = 0; 1536 mb_put_uint32le(mbp, time); 1537 smb_rq_wend(rqp); 1538 smb_rq_bstart(rqp); 1539 smb_rq_bend(rqp); 1540 1541 /* 1542 * We don't really care about the result here, but we 1543 * do need to make sure we send this out, or we could 1544 * "leak" open file handles on interrupt or timeout. 1545 * The NOINTR_SEND flag makes this request immune to 1546 * interrupt or timeout until the send is done. 1547 */ 1548 rqp->sr_flags |= SMBR_NOINTR_SEND; 1549 error = smb_rq_simple(rqp); 1550 smb_rq_done(rqp); 1551 /* 1552 * ENOTCONN isn't interesting - if the connection is closed, 1553 * so are all our FIDs - and EIO is also not interesting, 1554 * as it means a forced unmount was done. (was ENXIO) 1555 * Also ETIME, which means we sent the request but gave up 1556 * waiting before the response came back. 1557 * 1558 * Don't clog up the system log with warnings about these 1559 * uninteresting failures on closes. 1560 */ 1561 switch (error) { 1562 case ENOTCONN: 1563 case ENXIO: 1564 case EIO: 1565 case ETIME: 1566 error = 0; 1567 } 1568 return (error); 1569} 1570 1571static int 1572smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen, 1573 int xattr, struct smb_cred *scrp, uint16_t *fidp) 1574{ 1575 struct smb_rq rq, *rqp = &rq; 1576 struct smb_share *ssp = dnp->n_mount->smi_share; 1577 struct mbchain *mbp; 1578 struct mdchain *mdp; 1579 struct timespec ctime; 1580 uint8_t wc; 1581 long tm; 1582 int error; 1583 uint16_t attr = SMB_FA_ARCHIVE; 1584 1585 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp); 1586 if (error) 1587 return (error); 1588 smb_rq_getrequest(rqp, &mbp); 1589 smb_rq_wstart(rqp); 1590 if (name && *name == '.') 1591 attr |= SMB_FA_HIDDEN; 1592 mb_put_uint16le(mbp, attr); /* attributes */ 1593 gethrestime(&ctime); 1594 smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); 1595 mb_put_uint32le(mbp, tm); 1596 smb_rq_wend(rqp); 1597 smb_rq_bstart(rqp); 1598 mb_put_uint8(mbp, SMB_DT_ASCII); 1599 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &nmlen, 1600 xattr ? ':' : '\\'); 1601 if (error) 1602 goto out; 1603 smb_rq_bend(rqp); 1604 /* 1605 * Don't want to risk missing a successful 1606 * open response, or we could "leak" FIDs. 1607 */ 1608 rqp->sr_flags |= SMBR_NOINTR_RECV; 1609 error = smb_rq_simple_timed(rqp, smb_timo_open); 1610 if (error) 1611 goto out; 1612 1613 smb_rq_getreply(rqp, &mdp); 1614 md_get_uint8(mdp, &wc); 1615 if (wc != 1) { 1616 error = EBADRPC; 1617 goto out; 1618 } 1619 error = md_get_uint16le(mdp, fidp); 1620 1621out: 1622 smb_rq_done(rqp); 1623 return (error); 1624} 1625 1626int 1627smbfs_smb_create( 1628 struct smbnode *dnp, 1629 const char *name, 1630 int nmlen, 1631 int xattr, 1632 uint32_t disp, 1633 struct smb_cred *scrp, 1634 uint16_t *fidp) 1635{ 1636 struct smb_share *ssp = dnp->n_mount->smi_share; 1637 struct smb_vc *vcp = SSTOVC(ssp); 1638 uint32_t efa, rights; 1639 int error; 1640 1641 /* 1642 * At present the only access we might need is to WRITE data, 1643 * and that only if we are creating a "symlink". When/if the 1644 * access needed gets more complex it should made a parameter 1645 * and be set upstream. 1646 */ 1647 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 1648 rights = SA_RIGHT_FILE_WRITE_DATA; 1649 efa = SMB_EFA_NORMAL; 1650 if (!xattr && name && *name == '.') 1651 efa = SMB_EFA_HIDDEN; 1652 error = smbfs_smb_ntcreatex(dnp, 1653 name, nmlen, xattr, rights, efa, 1654 NTCREATEX_SHARE_ACCESS_ALL, 1655 disp, /* != NTCREATEX_DISP_OPEN */ 1656 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE, 1657 scrp, fidp, NULL, NULL); /* cr_act_p fa_p */ 1658 return (error); 1659 } 1660 1661 error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp); 1662 return (error); 1663} 1664 1665int 1666smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name, 1667 int nmlen, int xattr) 1668{ 1669 struct smb_rq rq, *rqp = &rq; 1670 struct smb_share *ssp = np->n_mount->smi_share; 1671 struct mbchain *mbp; 1672 int error; 1673 1674 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp); 1675 if (error) 1676 return (error); 1677 smb_rq_getrequest(rqp, &mbp); 1678 smb_rq_wstart(rqp); 1679 mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); 1680 smb_rq_wend(rqp); 1681 smb_rq_bstart(rqp); 1682 mb_put_uint8(mbp, SMB_DT_ASCII); 1683 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &nmlen, 1684 xattr ? ':' : '\\'); 1685 if (!error) { 1686 smb_rq_bend(rqp); 1687 error = smb_rq_simple(rqp); 1688 } 1689 smb_rq_done(rqp); 1690 return (error); 1691} 1692 1693int 1694smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, 1695 const char *tname, int tnmlen, struct smb_cred *scrp) 1696{ 1697 struct smb_rq rq, *rqp = &rq; 1698 struct smb_share *ssp = src->n_mount->smi_share; 1699 struct mbchain *mbp; 1700 int error; 1701 uint16_t fa; 1702 char sep; 1703 1704 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp); 1705 if (error) 1706 return (error); 1707 smb_rq_getrequest(rqp, &mbp); 1708 smb_rq_wstart(rqp); 1709 /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */ 1710 fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0; 1711 fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN; 1712 mb_put_uint16le(mbp, fa); 1713 smb_rq_wend(rqp); 1714 smb_rq_bstart(rqp); 1715 1716 /* 1717 * When we're not adding any component name, the 1718 * passed sep is ignored, so just pass sep=0. 1719 */ 1720 mb_put_uint8(mbp, SMB_DT_ASCII); 1721 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, 0); 1722 if (error) 1723 goto out; 1724 1725 /* 1726 * After XATTR directories, separator is ":" 1727 */ 1728 sep = (src->n_flag & N_XATTR) ? ':' : '\\'; 1729 mb_put_uint8(mbp, SMB_DT_ASCII); 1730 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, sep); 1731 if (error) 1732 goto out; 1733 1734 smb_rq_bend(rqp); 1735 error = smb_rq_simple(rqp); 1736out: 1737 smb_rq_done(rqp); 1738 return (error); 1739} 1740 1741int 1742smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, 1743 const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp) 1744{ 1745 struct smb_rq rq, *rqp = &rq; 1746 struct smb_share *ssp = src->n_mount->smi_share; 1747 struct mbchain *mbp; 1748 int error; 1749 1750 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp); 1751 if (error) 1752 return (error); 1753 smb_rq_getrequest(rqp, &mbp); 1754 smb_rq_wstart(rqp); 1755 mb_put_uint16le(mbp, SMB_TID_UNKNOWN); 1756 mb_put_uint16le(mbp, 0x20); /* delete target file */ 1757 mb_put_uint16le(mbp, flags); 1758 smb_rq_wend(rqp); 1759 smb_rq_bstart(rqp); 1760 mb_put_uint8(mbp, SMB_DT_ASCII); 1761 1762 error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\'); 1763 if (error) 1764 goto out; 1765 mb_put_uint8(mbp, SMB_DT_ASCII); 1766 error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, '\\'); 1767 if (error) 1768 goto out; 1769 smb_rq_bend(rqp); 1770 error = smb_rq_simple(rqp); 1771 1772out: 1773 smb_rq_done(rqp); 1774 return (error); 1775} 1776 1777static int 1778smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len, 1779 struct smb_cred *scrp) 1780{ 1781 struct smb_rq rq, *rqp = &rq; 1782 struct smb_share *ssp = dnp->n_mount->smi_share; 1783 struct mbchain *mbp; 1784 int error; 1785 1786 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp); 1787 if (error) 1788 return (error); 1789 smb_rq_getrequest(rqp, &mbp); 1790 smb_rq_wstart(rqp); 1791 smb_rq_wend(rqp); 1792 smb_rq_bstart(rqp); 1793 mb_put_uint8(mbp, SMB_DT_ASCII); 1794 error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &len, '\\'); 1795 if (!error) { 1796 smb_rq_bend(rqp); 1797 error = smb_rq_simple(rqp); 1798 } 1799 smb_rq_done(rqp); 1800 return (error); 1801} 1802 1803int 1804smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen, 1805 struct smb_cred *scrp) 1806{ 1807 struct smb_share *ssp = dnp->n_mount->smi_share; 1808 struct smb_vc *vcp = SSTOVC(ssp); 1809 uint32_t rights; 1810 uint16_t fid; 1811 int error; 1812 1813 /* 1814 * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but 1815 * just to be asking for something. The rights==0 case could 1816 * easily be broken on some old or unusual servers. 1817 */ 1818 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 1819 rights = SA_RIGHT_FILE_READ_DATA; 1820 error = smbfs_smb_ntcreatex(dnp, 1821 name, nmlen, 0, /* xattr */ 1822 rights, SMB_EFA_DIRECTORY, 1823 NTCREATEX_SHARE_ACCESS_ALL, 1824 NTCREATEX_DISP_CREATE, 1825 NTCREATEX_OPTIONS_DIRECTORY, 1826 scrp, &fid, NULL, NULL); /* cr_act_p fa_p */ 1827 if (error) 1828 return (error); 1829 (void) smbfs_smb_close(ssp, fid, NULL, scrp); 1830 return (0); 1831 } 1832 1833 error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp); 1834 return (error); 1835} 1836 1837int 1838smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp) 1839{ 1840 struct smb_rq rq, *rqp = &rq; 1841 struct smb_share *ssp = np->n_mount->smi_share; 1842 struct mbchain *mbp; 1843 int error; 1844 1845 error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp); 1846 if (error) 1847 return (error); 1848 smb_rq_getrequest(rqp, &mbp); 1849 smb_rq_wstart(rqp); 1850 smb_rq_wend(rqp); 1851 smb_rq_bstart(rqp); 1852 mb_put_uint8(mbp, SMB_DT_ASCII); 1853 error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, NULL, '\\'); 1854 if (!error) { 1855 smb_rq_bend(rqp); 1856 error = smb_rq_simple(rqp); 1857 } 1858 smb_rq_done(rqp); 1859 return (error); 1860} 1861 1862static int 1863smbfs_smb_search(struct smbfs_fctx *ctx) 1864{ 1865 struct smb_vc *vcp = SSTOVC(ctx->f_ssp); 1866 struct smb_rq *rqp; 1867 struct mbchain *mbp; 1868 struct mdchain *mdp; 1869 uint8_t wc, bt; 1870 uint16_t ec, dlen, bc; 1871 int len, maxent, error, iseof = 0; 1872 1873 maxent = min(ctx->f_left, 1874 (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN); 1875 if (ctx->f_rq) { 1876 smb_rq_done(ctx->f_rq); 1877 ctx->f_rq = NULL; 1878 } 1879 error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, 1880 ctx->f_scred, &rqp); 1881 if (error) 1882 return (error); 1883 ctx->f_rq = rqp; 1884 smb_rq_getrequest(rqp, &mbp); 1885 smb_rq_wstart(rqp); 1886 mb_put_uint16le(mbp, maxent); /* max entries to return */ 1887 mb_put_uint16le(mbp, ctx->f_attrmask); 1888 smb_rq_wend(rqp); 1889 smb_rq_bstart(rqp); 1890 mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ 1891 if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { 1892 len = ctx->f_wclen; 1893 error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, 1894 &len, '\\'); 1895 if (error) 1896 return (error); 1897 mb_put_uint8(mbp, SMB_DT_VARIABLE); 1898 mb_put_uint16le(mbp, 0); /* context length */ 1899 ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; 1900 } else { 1901 if (SMB_UNICODE_STRINGS(vcp)) { 1902 mb_put_padbyte(mbp); 1903 mb_put_uint8(mbp, 0); 1904 } 1905 mb_put_uint8(mbp, 0); 1906 mb_put_uint8(mbp, SMB_DT_VARIABLE); 1907 mb_put_uint16le(mbp, SMB_SKEYLEN); 1908 mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); 1909 } 1910 smb_rq_bend(rqp); 1911 error = smb_rq_simple(rqp); 1912 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { 1913 error = 0; 1914 iseof = 1; 1915 ctx->f_flags |= SMBFS_RDD_EOF; 1916 } else if (error) 1917 return (error); 1918 smb_rq_getreply(rqp, &mdp); 1919 error = md_get_uint8(mdp, &wc); 1920 if (error) 1921 return (error); 1922 if (wc != 1) 1923 return (iseof ? ENOENT : EBADRPC); 1924 md_get_uint16le(mdp, &ec); 1925 md_get_uint16le(mdp, &bc); 1926 md_get_uint8(mdp, &bt); 1927 error = md_get_uint16le(mdp, &dlen); 1928 if (error) 1929 return (error); 1930 if (ec == 0) 1931 return (ENOENT); 1932 ctx->f_ecnt = ec; 1933 if (bc < 3) 1934 return (EBADRPC); 1935 bc -= 3; 1936 if (bt != SMB_DT_VARIABLE) 1937 return (EBADRPC); 1938 if (dlen != bc || dlen % SMB_DENTRYLEN != 0) 1939 return (EBADRPC); 1940 return (0); 1941} 1942 1943 1944/*ARGSUSED*/ 1945static int 1946smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, 1947 const char *wildcard, int wclen, uint16_t attr) 1948{ 1949 1950 ctx->f_type = ft_LM1; 1951 ctx->f_attrmask = attr; 1952 if (wildcard) { 1953 if (wclen == 1 && wildcard[0] == '*') { 1954 ctx->f_wildcard = "*.*"; 1955 ctx->f_wclen = 3; 1956 } else { 1957 ctx->f_wildcard = wildcard; 1958 ctx->f_wclen = wclen; 1959 } 1960 } else { 1961 ctx->f_wildcard = NULL; 1962 ctx->f_wclen = 0; 1963 } 1964 ctx->f_name = (char *)ctx->f_fname; 1965 ctx->f_namesz = 0; 1966 return (0); 1967} 1968 1969static int 1970smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit) 1971{ 1972 struct mdchain *mdp; 1973 struct smb_rq *rqp; 1974 char *cp; 1975 uint8_t battr; 1976 uint16_t date, time; 1977 uint32_t size; 1978 int error; 1979 struct timespec ts; 1980 1981 if (ctx->f_ecnt == 0) { 1982 if (ctx->f_flags & SMBFS_RDD_EOF) 1983 return (ENOENT); 1984 ctx->f_left = ctx->f_limit = limit; 1985 gethrestime(&ts); 1986 error = smbfs_smb_search(ctx); 1987 if (error) 1988 return (error); 1989 } 1990 rqp = ctx->f_rq; 1991 smb_rq_getreply(rqp, &mdp); 1992 md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKE…
Large files files are truncated, but you can click here to view the full file