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_subr.c,v 1.18 2005/02/02 00:22:23 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 
  47 #include <netsmb/smb_osdep.h>
  48 
  49 #include <netsmb/smb.h>
  50 #include <netsmb/smb_conn.h>
  51 #include <netsmb/smb_subr.h>
  52 #include <netsmb/smb_rq.h>
  53 
  54 #include <smbfs/smbfs.h>
  55 #include <smbfs/smbfs_node.h>
  56 #include <smbfs/smbfs_subr.h>
  57 
  58 /*
  59  * In the Darwin code, this function used to compute the full path
  60  * by following the chain of n_parent pointers back to the root.
  61  * In the Solaris port we found the n_parent pointers inconvenient
  62  * because they hold parent nodes busy.  We now keep the full path
  63  * in every node, so this function need only marshall the directory
  64  * path, and (if provided) the separator and last component name.
  65  *
  66  * Note that this logic must match that in smbfs_getino
  67  */
  68 int
  69 smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
  70         const char *name, int nmlen, u_int8_t sep)
  71 {
  72         int caseopt = SMB_CS_NONE;
  73         int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0;
  74         int error;
  75 
  76         if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
  77                 caseopt |= SMB_CS_UPPER;
  78 
  79         if (unicode) {
  80                 error = mb_put_padbyte(mbp);
  81                 if (error)
  82                         return (error);
  83         }
  84 
  85         error = smb_put_dmem(mbp, vcp,
  86             dnp->n_rpath, dnp->n_rplen,
  87             caseopt, NULL);
  88         if (name) {
  89                 /*
  90                  * Special case at share root:
  91                  * Don't put another slash.
  92                  */
  93                 if (dnp->n_rplen <= 1 && sep == '\\')
  94                         sep = 0;
  95                 /*
  96                  * More special cases, now for XATTR:
  97                  * Our "faked up" XATTR directories use a
  98                  * full path name ending with ":" so as to
  99                  * avoid conflicts with any real paths.
 
 105                  * parent node's path name.
 106                  */
 107                 if (dnp->n_flag & N_XATTR)
 108                         sep = 0;
 109 
 110                 if (sep) {
 111                         /* Put the separator */
 112                         if (unicode)
 113                                 error = mb_put_uint16le(mbp, sep);
 114                         else
 115                                 error = mb_put_uint8(mbp, sep);
 116                         if (error)
 117                                 return (error);
 118                 }
 119                 /* Put the name */
 120                 error = smb_put_dmem(mbp, vcp,
 121                     name, nmlen, caseopt, NULL);
 122                 if (error)
 123                         return (error);
 124         }
 125         /* Put NULL termination. */
 126         if (unicode)
 127                 error = mb_put_uint16le(mbp, 0);
 128         else
 129                 error = mb_put_uint8(mbp, 0);
 130 
 131         return (error);
 132 }
 133 
 134 /*
 135  * Convert a Unicode directory entry to UTF-8
 136  */
 137 void
 138 smbfs_fname_tolocal(struct smbfs_fctx *ctx)
 139 {
 140         uchar_t tmpbuf[SMB_MAXFNAMELEN+1];
 141         struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
 142         uchar_t *dst;
 143         const ushort_t *src;
 144         size_t inlen, outlen;
 145         int flags;
 146 
 147         if (ctx->f_nmlen == 0)
 148                 return;
 149 
 
 165         src = (const ushort_t *)ctx->f_name;
 166         inlen = ctx->f_nmlen / 2;    /* number of UCS-2 characters */
 167         flags = UCONV_IN_LITTLE_ENDIAN;
 168 
 169         if (uconv_u16tou8(src, &inlen, dst, &outlen, flags) != 0)
 170                 goto errout;
 171 
 172         ASSERT(outlen < sizeof (tmpbuf));
 173         tmpbuf[outlen] = '\0';
 174         bcopy(tmpbuf, ctx->f_name, outlen + 1);
 175         ctx->f_nmlen = (int)outlen;
 176         return;
 177 
 178 errout:
 179         /*
 180          * Conversion failed, but our caller does not
 181          * deal with errors here, so just put a "?".
 182          * Don't expect to ever see this.
 183          */
 184         (void) strlcpy(ctx->f_name, "?", ctx->f_namesz);
 185 }
  | 
 
 
  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_subr.c,v 1.18 2005/02/02 00:22:23 lindak Exp $
  33  */
  34 
  35 /*
  36  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  37  * Use is subject to license terms.
  38  *
  39  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  40  */
  41 
  42 #include <sys/param.h>
  43 #include <sys/systm.h>
  44 #include <sys/time.h>
  45 #include <sys/vnode.h>
  46 #include <sys/sunddi.h>
  47 
  48 #include <netsmb/smb_osdep.h>
  49 
  50 #include <netsmb/smb.h>
  51 #include <netsmb/smb2.h>
  52 #include <netsmb/smb_conn.h>
  53 #include <netsmb/smb_subr.h>
  54 #include <netsmb/smb_rq.h>
  55 
  56 #include <smbfs/smbfs.h>
  57 #include <smbfs/smbfs_node.h>
  58 #include <smbfs/smbfs_subr.h>
  59 
  60 /*
  61  * In the Darwin code, this function used to compute the full path
  62  * by following the chain of n_parent pointers back to the root.
  63  * In the Solaris port we found the n_parent pointers inconvenient
  64  * because they hold parent nodes busy.  We now keep the full path
  65  * in every node, so this function need only marshall the directory
  66  * path, and (if provided) the separator and last component name.
  67  *
  68  * Note that this logic must match that in smbfs_getino
  69  */
  70 int
  71 smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
  72         const char *name, int nmlen, u_int8_t sep)
  73 {
  74         int caseopt = SMB_CS_NONE;
  75         int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0;
  76         int error;
  77 
  78         /*
  79          * SMB1 may need an alignment pad before (not SMB2)
  80          */
  81         if (((vcp)->vc_flags & SMBV_SMB2) == 0 &&
  82             ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0) {
  83                 error = mb_put_padbyte(mbp);
  84                 if (error)
  85                         return (error);
  86         }
  87 
  88         error = smb_put_dmem(mbp, vcp,
  89             dnp->n_rpath, dnp->n_rplen,
  90             caseopt, NULL);
  91         if (name) {
  92                 /*
  93                  * Special case at share root:
  94                  * Don't put another slash.
  95                  */
  96                 if (dnp->n_rplen <= 1 && sep == '\\')
  97                         sep = 0;
  98                 /*
  99                  * More special cases, now for XATTR:
 100                  * Our "faked up" XATTR directories use a
 101                  * full path name ending with ":" so as to
 102                  * avoid conflicts with any real paths.
 
 108                  * parent node's path name.
 109                  */
 110                 if (dnp->n_flag & N_XATTR)
 111                         sep = 0;
 112 
 113                 if (sep) {
 114                         /* Put the separator */
 115                         if (unicode)
 116                                 error = mb_put_uint16le(mbp, sep);
 117                         else
 118                                 error = mb_put_uint8(mbp, sep);
 119                         if (error)
 120                                 return (error);
 121                 }
 122                 /* Put the name */
 123                 error = smb_put_dmem(mbp, vcp,
 124                     name, nmlen, caseopt, NULL);
 125                 if (error)
 126                         return (error);
 127         }
 128 
 129         /* SMB1 wants NULL termination. */
 130         if (((vcp)->vc_flags & SMBV_SMB2) == 0) {
 131                 if (unicode)
 132                         error = mb_put_uint16le(mbp, 0);
 133                 else
 134                         error = mb_put_uint8(mbp, 0);
 135         }
 136 
 137         return (error);
 138 }
 139 
 140 /*
 141  * Convert a Unicode directory entry to UTF-8
 142  */
 143 void
 144 smbfs_fname_tolocal(struct smbfs_fctx *ctx)
 145 {
 146         uchar_t tmpbuf[SMB_MAXFNAMELEN+1];
 147         struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
 148         uchar_t *dst;
 149         const ushort_t *src;
 150         size_t inlen, outlen;
 151         int flags;
 152 
 153         if (ctx->f_nmlen == 0)
 154                 return;
 155 
 
 171         src = (const ushort_t *)ctx->f_name;
 172         inlen = ctx->f_nmlen / 2;    /* number of UCS-2 characters */
 173         flags = UCONV_IN_LITTLE_ENDIAN;
 174 
 175         if (uconv_u16tou8(src, &inlen, dst, &outlen, flags) != 0)
 176                 goto errout;
 177 
 178         ASSERT(outlen < sizeof (tmpbuf));
 179         tmpbuf[outlen] = '\0';
 180         bcopy(tmpbuf, ctx->f_name, outlen + 1);
 181         ctx->f_nmlen = (int)outlen;
 182         return;
 183 
 184 errout:
 185         /*
 186          * Conversion failed, but our caller does not
 187          * deal with errors here, so just put a "?".
 188          * Don't expect to ever see this.
 189          */
 190         (void) strlcpy(ctx->f_name, "?", ctx->f_namesz);
 191 }
 192 
 193 /*
 194  * Decode a directory entry from OtW form into ctx->f_attr
 195  *
 196  * Caller already put some (wire-format) directory entries
 197  * into ctx->f_mdchain and we expect to find one.
 198  *
 199  * Advancing correctly through the buffer can be tricky if one
 200  * tries to add up the size of an entry as you go (which is how
 201  * the darwin code this is derived from did it).  The easiest way
 202  * to correctly advance the position is to get a whole dirent
 203  * into another mdchain (entry_mdc) based on NextEntryOffset,
 204  * and then scan the data from that mdchain.  On the last entry,
 205  * we don't know the entire length, so just scan directly from
 206  * what remains of the multi-entry buffer instead of trying to
 207  * figure out the length to copy into a separate mdchain.
 208  */
 209 int
 210 smbfs_decode_dirent(struct smbfs_fctx *ctx)
 211 {
 212         struct mdchain entry_mdc;
 213         struct mdchain *mdp = &ctx->f_mdchain;
 214         size_t nmlen;
 215         uint64_t llongint;
 216         uint32_t nmsize, dattr;
 217         uint32_t nextoff = 0;
 218         int error;
 219 
 220         /* In case we error out... */
 221         ctx->f_nmlen = 0;
 222         ctx->f_rkey = (uint32_t)-1;
 223         bzero(&entry_mdc, sizeof (entry_mdc));
 224 
 225         /*
 226          * Setup mdp to point to an mbchain holding
 227          * what should be a single directory entry.
 228          */
 229         error = md_get_uint32le(mdp, &nextoff);
 230         if (error != 0)
 231                 goto errout;
 232         if (nextoff >= 4) {
 233                 /*
 234                  * More entries follow.  Make a new mbchain
 235                  * holding just this one entry, then advance.
 236                  */
 237                 mblk_t *m = NULL;
 238                 error = md_get_mbuf(mdp, nextoff - 4, &m);
 239                 if (error != 0)
 240                         goto errout;
 241                 md_initm(&entry_mdc, m);
 242                 mdp = &entry_mdc;
 243                 ctx->f_eofs += nextoff;
 244         } else {
 245                 /* Scan directly from ctx->f_mdchain */
 246                 ctx->f_eofs = ctx->f_left;
 247         }
 248 
 249         /*
 250          * Decode the fixed-size parts
 251          */
 252         switch (ctx->f_infolevel) {
 253         case FileFullDirectoryInformation:
 254         case SMB_FIND_FULL_DIRECTORY_INFO:
 255                 md_get_uint32le(mdp, &ctx->f_rkey);      /* resume key (idx) */
 256                 md_get_uint64le(mdp, &llongint);    /* creation time */
 257                 smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
 258                 md_get_uint64le(mdp, &llongint);
 259                 smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
 260                 md_get_uint64le(mdp, &llongint);
 261                 smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
 262                 md_get_uint64le(mdp, &llongint);
 263                 smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
 264                 md_get_uint64le(mdp, &llongint);    /* file size */
 265                 ctx->f_attr.fa_size = llongint;
 266                 md_get_uint64le(mdp, &llongint);    /* alloc. size */
 267                 ctx->f_attr.fa_allocsz = llongint;
 268                 md_get_uint32le(mdp, &dattr);       /* ext. file attributes */
 269                 ctx->f_attr.fa_attr = dattr;
 270                 error = md_get_uint32le(mdp, &nmsize);      /* name size (otw) */
 271                 if (error)
 272                         goto errout;
 273                 md_get_uint32le(mdp, NULL);     /* Ea size */
 274                 break;
 275 
 276         case FileStreamInformation:
 277                 error = md_get_uint32le(mdp, &nmsize);      /* name size (otw) */
 278                 md_get_uint64le(mdp, &llongint);    /* file size */
 279                 ctx->f_attr.fa_size = llongint;
 280                 md_get_uint64le(mdp, &llongint);    /* alloc. size */
 281                 ctx->f_attr.fa_allocsz = llongint;
 282                 /*
 283                  * Stream names start with a ':' that we want to skip.
 284                  * This is the easiest place to take care of that.
 285                  * Always unicode here.
 286                  */
 287                 if (nmsize >= 2) {
 288                         struct mdchain save_mdc;
 289                         uint16_t wch;
 290                         save_mdc = *mdp;
 291                         md_get_uint16le(mdp, &wch);
 292                         if (wch == ':') {
 293                                 /* OK, we skipped the ':' */
 294                                 nmsize -= 2;
 295                         } else {
 296                                 SMBVDEBUG("No leading : in stream?\n");
 297                                 /* restore position */
 298                                 *mdp = save_mdc;
 299                         }
 300                 }
 301                 break;
 302 
 303         default:
 304                 SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
 305                 error = EINVAL;
 306                 goto errout;
 307         }
 308 
 309         /*
 310          * Get the filename, and convert to utf-8
 311          * Allocated f_name in findopen
 312          */
 313         nmlen = ctx->f_namesz;
 314         error = smb_get_dstring(mdp, SSTOVC(ctx->f_ssp),
 315             ctx->f_name, &nmlen, nmsize);
 316         if (error != 0)
 317                 goto errout;
 318         ctx->f_nmlen = (int)nmlen;
 319         md_done(&entry_mdc);
 320         return (0);
 321 
 322 errout:
 323         /*
 324          * Something bad has happened and we ran out of data
 325          * before we could parse all f_ecnt entries expected.
 326          * Give up on the current buffer.
 327          */
 328         SMBVDEBUG("ran out of data\n");
 329         ctx->f_eofs = ctx->f_left;
 330         md_done(&entry_mdc);
 331         return (error);
 332 }
 333 
 334 /*
 335  * Decode FileAllInformation
 336  *
 337  * The data is a concatenation of:
 338  *      FileBasicInformation
 339  *      FileStandardInformation
 340  *      FileInternalInformation
 341  *      FileEaInformation
 342  *      FilePositionInformation
 343  *      FileModeInformation
 344  *      FileAlignmentInformation
 345  *      FileNameInformation
 346  */
 347 /*ARGSUSED*/
 348 int
 349 smbfs_decode_file_all_info(struct smb_share *ssp,
 350         struct mdchain *mdp, struct smbfattr *fap)
 351 {
 352         uint64_t llongint, lsize;
 353         uint32_t dattr;
 354         int error;
 355 
 356         /*
 357          * This part is: FileBasicInformation
 358          */
 359 
 360         /* creation time */
 361         md_get_uint64le(mdp, &llongint);
 362         smb_time_NT2local(llongint, &fap->fa_createtime);
 363 
 364         /* last access time */
 365         md_get_uint64le(mdp, &llongint);
 366         smb_time_NT2local(llongint, &fap->fa_atime);
 367 
 368         /* last write time */
 369         md_get_uint64le(mdp, &llongint);
 370         smb_time_NT2local(llongint, &fap->fa_mtime);
 371 
 372         /* last change time */
 373         md_get_uint64le(mdp, &llongint);
 374         smb_time_NT2local(llongint, &fap->fa_ctime);
 375 
 376         /* attributes */
 377         md_get_uint32le(mdp, &dattr);
 378         fap->fa_attr = dattr;
 379 
 380         /* reserved */
 381         md_get_uint32le(mdp, NULL);
 382 
 383         /*
 384          * This part is: FileStandardInformation
 385          */
 386 
 387         /* allocation size */
 388         md_get_uint64le(mdp, &lsize);
 389         fap->fa_allocsz = lsize;
 390 
 391         /* File size */
 392         error = md_get_uint64le(mdp, &lsize);
 393         fap->fa_size = lsize;
 394 
 395         /*
 396          * There's more after this but we don't need it:
 397          * Remainder of FileStandardInformation
 398          *      NumLlinks, DeletOnClose, IsDir, reserved.
 399          * Then:
 400          *      FileInternalInformation
 401          *      FileEaInformation
 402          *      FilePositionInformation
 403          *      FileModeInformation
 404          *      FileAlignmentInformation
 405          *      FileNameInformation
 406          */
 407 
 408         return (error);
 409 }
 410 
 411 /*
 412  * Decode FileFsAttributeInformation
 413  *
 414  *    ULONG FileSystemAttributes;
 415  *    LONG MaximumComponentNameLength;
 416  *    ULONG FileSystemNameLength;
 417  *    WCHAR FileSystemName[1];
 418  */
 419 int
 420 smbfs_decode_fs_attr_info(struct smb_share *ssp,
 421         struct mdchain *mdp, struct smb_fs_attr_info *fsa)
 422 {
 423         struct smb_vc *vcp = SSTOVC(ssp);
 424         uint32_t nlen;
 425         int error;
 426 
 427         md_get_uint32le(mdp, &fsa->fsa_aflags);
 428         md_get_uint32le(mdp, &fsa->fsa_maxname);
 429         error = md_get_uint32le(mdp, &nlen);        /* fs name length */
 430         if (error)
 431                 goto out;
 432 
 433         /*
 434          * Get the FS type name.
 435          */
 436         bzero(fsa->fsa_tname, FSTYPSZ);
 437         if (SMB_UNICODE_STRINGS(vcp)) {
 438                 uint16_t tmpbuf[FSTYPSZ];
 439                 size_t tmplen, outlen;
 440 
 441                 if (nlen > sizeof (tmpbuf))
 442                         nlen = sizeof (tmpbuf);
 443                 error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
 444                 if (error != 0)
 445                         goto out;
 446                 tmplen = nlen / 2;      /* UCS-2 chars */
 447                 outlen = FSTYPSZ - 1;
 448                 error = uconv_u16tou8(tmpbuf, &tmplen,
 449                     (uchar_t *)fsa->fsa_tname, &outlen,
 450                     UCONV_IN_LITTLE_ENDIAN);
 451         } else {
 452                 if (nlen > (FSTYPSZ - 1))
 453                         nlen = FSTYPSZ - 1;
 454                 error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
 455         }
 456 
 457 out:
 458         return (error);
 459 }
 |