1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Functions supporting Solaris Extended Attributes,
  29  * used to provide access to CIFS "named streams".
  30  */
  31 
  32 #include <sys/systm.h>
  33 #include <sys/inttypes.h>
  34 #include <sys/cred.h>
  35 #include <sys/vnode.h>
  36 #include <sys/vfs.h>
  37 #include <sys/filio.h>
  38 #include <sys/uio.h>
  39 #include <sys/dirent.h>
  40 #include <sys/errno.h>
  41 #include <sys/sysmacros.h>
  42 #include <sys/kmem.h>
  43 #include <sys/stat.h>
  44 #include <sys/cmn_err.h>
  45 #include <sys/u8_textprep.h>
  46 
  47 #include <netsmb/smb_osdep.h>
  48 
  49 #include <netsmb/smb.h>
  50 #include <netsmb/smb2.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 #include <fs/fs_subr.h>
  60 
  61 /*
  62  * Solaris wants there to be a directory node to contain
  63  * all the extended attributes.  The SMB protocol does not
  64  * really support a directory here, and uses very different
  65  * operations to list attributes, etc. so we "fake up" an
  66  * smbnode here to represent the attributes directory.
  67  *
  68  * We need to give this (fake) directory a unique identity,
  69  * and since we're using the full remote pathname as the
  70  * unique identity of all nodes, the easiest thing to do
  71  * here is append a colon (:) to the given pathname.
  72  *
  73  * There are several places where smbfs_fullpath and its
  74  * callers must decide what separator to use when building
  75  * a remote path name, and the rule is now as follows:
  76  * 1: When no XATTR involved, use "\\" as the separator.
  77  * 2: Traversal into the (fake) XATTR dir adds one ":"
  78  * 3: Children of the XATTR dir add nothing (sep=0)
  79  * The result should be _one_ colon before the attr name.
  80  */
  81 
  82 /* ARGSUSED */
  83 int
  84 smbfs_get_xattrdir(vnode_t *pvp, vnode_t **vpp, cred_t *cr, int flags)
  85 {
  86         vnode_t *xvp;
  87         smbnode_t *pnp, *xnp;
  88 
  89         pnp = VTOSMB(pvp);
  90 
  91         /*
  92          * We don't allow recursive extended attributes
  93          * (xattr under xattr dir.) so the "parent" node
  94          * (pnp) must NOT be an XATTR directory or file.
  95          */
  96         if (pnp->n_flag & N_XATTR)
  97                 return (EINVAL);
  98 
  99         xnp = smbfs_node_findcreate(pnp->n_mount,
 100             pnp->n_rpath, pnp->n_rplen, NULL, 0, ':',
 101             &smbfs_fattr0); /* force create */
 102         ASSERT(xnp != NULL);
 103         xvp = SMBTOV(xnp);
 104         /* Note: xvp has a VN_HOLD, which our caller expects. */
 105 
 106         /* If it's a new node, initialize. */
 107         if (xvp->v_type == VNON) {
 108 
 109                 mutex_enter(&xvp->v_lock);
 110                 xvp->v_type = VDIR;
 111                 xvp->v_flag |= V_XATTRDIR;
 112                 mutex_exit(&xvp->v_lock);
 113 
 114                 mutex_enter(&xnp->r_statelock);
 115                 xnp->n_flag |= N_XATTR;
 116                 mutex_exit(&xnp->r_statelock);
 117         }
 118 
 119         /* Success! */
 120         *vpp = xvp;
 121         return (0);
 122 }
 123 
 124 /*
 125  * Find the parent of an XATTR directory or file,
 126  * by trimming off the ":attrname" part of rpath.
 127  * Called on XATTR files to get the XATTR dir, and
 128  * called on the XATTR dir to get the real object
 129  * under which the (faked up) XATTR dir lives.
 130  */
 131 int
 132 smbfs_xa_parent(vnode_t *vp, vnode_t **vpp)
 133 {
 134         smbnode_t *np = VTOSMB(vp);
 135         smbnode_t *pnp;
 136         int rplen;
 137 
 138         *vpp = NULL;
 139 
 140         if ((np->n_flag & N_XATTR) == 0)
 141                 return (EINVAL);
 142 
 143         if (vp->v_flag & V_XATTRDIR) {
 144                 /*
 145                  * Want the parent of the XATTR directory.
 146                  * That's easy: just remove trailing ":"
 147                  */
 148                 rplen = np->n_rplen - 1;
 149                 if (rplen < 1) {
 150                         SMBVDEBUG("rplen < 1?");
 151                         return (ENOENT);
 152                 }
 153                 if (np->n_rpath[rplen] != ':') {
 154                         SMBVDEBUG("last is not colon");
 155                         return (ENOENT);
 156                 }
 157         } else {
 158                 /*
 159                  * Want the XATTR directory given
 160                  * one of its XATTR files (children).
 161                  * Find the ":" and trim after it.
 162                  */
 163                 for (rplen = 1; rplen < np->n_rplen; rplen++)
 164                         if (np->n_rpath[rplen] == ':')
 165                                 break;
 166                 /* Should have found ":stream_name" */
 167                 if (rplen >= np->n_rplen) {
 168                         SMBVDEBUG("colon not found");
 169                         return (ENOENT);
 170                 }
 171                 rplen++; /* keep the ":" */
 172                 if (rplen >= np->n_rplen) {
 173                         SMBVDEBUG("no stream name");
 174                         return (ENOENT);
 175                 }
 176         }
 177 
 178         pnp = smbfs_node_findcreate(np->n_mount,
 179             np->n_rpath, rplen, NULL, 0, 0,
 180             &smbfs_fattr0); /* force create */
 181         ASSERT(pnp != NULL);
 182         /* Note: have VN_HOLD from smbfs_node_findcreate */
 183         *vpp = SMBTOV(pnp);
 184         return (0);
 185 }
 186 
 187 /*
 188  * This is called by smbfs_pathconf to find out
 189  * if some file has any extended attributes.
 190  * There's no short-cut way to find out, so we
 191  * just list the attributes the usual way and
 192  * check for an empty result.
 193  *
 194  * Returns 1: (exists) or 0: (none found)
 195  */
 196 int
 197 smbfs_xa_exists(vnode_t *vp, cred_t *cr)
 198 {
 199         smbnode_t *xnp;
 200         vnode_t *xvp;
 201         struct smb_cred scred;
 202         struct smbfs_fctx ctx;
 203         int error, rc = 0;
 204 
 205         /* Get the xattr dir */
 206         error = smbfs_get_xattrdir(vp, &xvp, cr, LOOKUP_XATTR);
 207         if (error)
 208                 return (0);
 209         /* NB: have VN_HOLD on xpv */
 210         xnp = VTOSMB(xvp);
 211 
 212         smb_credinit(&scred, cr);
 213 
 214         bzero(&ctx, sizeof (ctx));
 215         ctx.f_flags = SMBFS_RDD_FINDFIRST;
 216         ctx.f_dnp = xnp;
 217         ctx.f_scred = &scred;
 218         ctx.f_ssp = xnp->n_mount->smi_share;
 219 
 220         error = smbfs_xa_findopen(&ctx, xnp, "*", 1);
 221         if (error)
 222                 goto out;
 223 
 224         error = smbfs_xa_findnext(&ctx, 1);
 225         if (error)
 226                 goto out;
 227 
 228         /* Have at least one named stream. */
 229         SMBVDEBUG("ctx.f_name: %s\n", ctx.f_name);
 230         rc = 1;
 231 
 232 out:
 233         /* NB: Always call findclose, error or not. */
 234         (void) smbfs_xa_findclose(&ctx);
 235         smb_credrele(&scred);
 236         VN_RELE(xvp);
 237         return (rc);
 238 }
 239 
 240 
 241 /*
 242  * This is called to get attributes (size, etc.) of either
 243  * the "faked up" XATTR directory or a named stream.
 244  */
 245 int
 246 smbfs_xa_getfattr(struct smbnode *xnp, struct smbfattr *fap,
 247         struct smb_cred *scrp)
 248 {
 249         vnode_t *xvp;   /* xattr */
 250         vnode_t *pvp;   /* parent */
 251         smbnode_t *pnp; /* parent */
 252         int error, nlen;
 253         const char *name, *sname;
 254 
 255         xvp = SMBTOV(xnp);
 256 
 257         /*
 258          * Simulate smbfs_smb_getfattr() for a named stream.
 259          * OK to leave a,c,m times zero (expected w/ XATTR).
 260          * The XATTR directory is easy (all fake).
 261          */
 262         if (xvp->v_flag & V_XATTRDIR) {
 263                 fap->fa_attr = SMB_FA_DIR;
 264                 fap->fa_size = DEV_BSIZE;
 265                 return (0);
 266         }
 267 
 268         /*
 269          * Do a lookup in the XATTR directory,
 270          * using the stream name (last part)
 271          * from the xattr node.
 272          */
 273         error = smbfs_xa_parent(xvp, &pvp);
 274         if (error)
 275                 return (error);
 276         /* Note: pvp has a VN_HOLD */
 277         pnp = VTOSMB(pvp);
 278 
 279         /* Get stream name (ptr and length) */
 280         ASSERT(xnp->n_rplen > pnp->n_rplen);
 281         nlen = xnp->n_rplen - pnp->n_rplen;
 282         name = xnp->n_rpath + pnp->n_rplen;
 283         sname = name;
 284 
 285         /* Note: this can allocate a new "name" */
 286         error = smbfs_smb_lookup(pnp, &name, &nlen, fap, scrp);
 287         if (error == 0 && name != sname)
 288                 smbfs_name_free(name, nlen);
 289 
 290         VN_RELE(pvp);
 291 
 292         return (error);
 293 }
 294 
 295 /*
 296  * Actually go OtW to get the list of "streams".
 297  *
 298  * This is called on the XATTR directory, so we
 299  * have to get the (real) parent object first.
 300  */
 301 static int
 302 smbfs_xa_get_streaminfo(struct smbfs_fctx *ctx)
 303 {
 304         vnode_t *pvp;   /* parent */
 305         smbnode_t *pnp;
 306         smbnode_t *dnp = ctx->f_dnp;
 307         struct mdchain *mdp;
 308         int error;
 309 
 310         error = smbfs_xa_parent(SMBTOV(dnp), &pvp);
 311         if (error)
 312                 return (error);
 313         ASSERT(pvp);
 314         /* Note: pvp has a VN_HOLD */
 315         pnp = VTOSMB(pvp);
 316 
 317         /*
 318          * Get stream info into f_mdchain
 319          */
 320         mdp = &ctx->f_mdchain;
 321         md_done(mdp);
 322 
 323         if (SSTOVC(ctx->f_ssp)->vc_flags & SMBV_SMB2) {
 324                 error = smbfs_smb2_get_streaminfo(pnp, mdp, ctx->f_scred);
 325         } else {
 326                 error = smbfs_smb1_get_streaminfo(pnp, mdp, ctx->f_scred);
 327         }
 328         if (error)
 329                 goto out;
 330 
 331         /*
 332          * Have stream info in ctx->f_mdchain
 333          * Initialize buffer length, position.
 334          */
 335         ctx->f_left = m_fixhdr(mdp->md_top);
 336         ctx->f_eofs = 0;
 337 
 338         /*
 339          * After one successful call, we're at EOF.
 340          */
 341         ctx->f_flags |= SMBFS_RDD_EOF;
 342 
 343 out:
 344         VN_RELE(pvp);
 345         return (error);
 346 }
 347 
 348 /*
 349  * Get a buffer of directory entries (if we don't already have
 350  * some remaining in the current buffer) then decode one.
 351  */
 352 int
 353 smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
 354         const char *wildcard, int wclen)
 355 {
 356 
 357         ASSERT(dnp->n_flag & N_XATTR);
 358 
 359         ctx->f_type = ft_XA;
 360         ctx->f_namesz = SMB_MAXFNAMELEN + 1;
 361         ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
 362         ctx->f_infolevel = FileStreamInformation;
 363         ctx->f_wildcard = wildcard;
 364         ctx->f_wclen = wclen;
 365 
 366         return (0);
 367 }
 368 
 369 
 370 /*
 371  * Get the next name in an XATTR directory
 372  */
 373 /* ARGSUSED */
 374 int
 375 smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit)
 376 {
 377         int error;
 378 
 379         /*
 380          * If we've scanned to the end of the current buffer
 381          * try to read anohther buffer of dir entries.
 382          * Treat anything less than 8 bytes as an "empty"
 383          * buffer to ensure we can read something.
 384          * (There may be up to 8 bytes of padding.)
 385          */
 386 again:
 387         if ((ctx->f_eofs + 8) > ctx->f_left) {
 388                 /* Scanned the whole buffer. */
 389                 if (ctx->f_flags & SMBFS_RDD_EOF)
 390                         return (ENOENT);
 391                 ctx->f_limit = limit;
 392                 error = smbfs_xa_get_streaminfo(ctx);
 393                 if (error)
 394                         return (error);
 395                 ctx->f_otws++;
 396         }
 397 
 398         /*
 399          * Decode one entry, advance f_eofs
 400          */
 401         error = smbfs_decode_dirent(ctx);
 402         if (error)
 403                 return (error);
 404         SMBVDEBUG("name: %s\n", ctx->f_name);
 405 
 406         /*
 407          * Chop off the trailing ":$DATA"
 408          * The 6 here is strlen(":$DATA")
 409          */
 410         if (ctx->f_nmlen >= 6) {
 411                 char *p = ctx->f_name + ctx->f_nmlen - 6;
 412                 if (strncmp(p, ":$DATA", 6) == 0) {
 413                         *p = '\0'; /* Chop! */
 414                         ctx->f_nmlen -= 6;
 415                 }
 416         }
 417 
 418         /*
 419          * The Chop above will typically leave
 420          * an empty name in the first slot,
 421          * which we will skip here.
 422          */
 423         if (ctx->f_nmlen == 0)
 424                 goto again;
 425 
 426         /*
 427          * When called by lookup, we'll have the "single" flag,
 428          * and a name with no wildcards.  We need to filter here
 429          * because smbfs_xa_get_streaminfo() gets ALL the names
 430          * (not just those matching our pattern).
 431          */
 432         if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
 433                 if (ctx->f_wclen != ctx->f_nmlen)
 434                         goto again;
 435                 if (u8_strcmp(ctx->f_wildcard, ctx->f_name,
 436                     ctx->f_nmlen, U8_STRCMP_CI_LOWER,
 437                     U8_UNICODE_LATEST, &error) || error)
 438                         goto again;
 439         }
 440 
 441         return (0);
 442 }
 443 
 444 /*
 445  * Find first/next/close for XATTR directories.
 446  * NB: also used by smbfs_smb_lookup
 447  */
 448 
 449 int
 450 smbfs_xa_findclose(struct smbfs_fctx *ctx)
 451 {
 452 
 453         if (ctx->f_name)
 454                 kmem_free(ctx->f_name, ctx->f_namesz);
 455 
 456         return (0);
 457 }