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 } 458