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 */