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 */
25
26 /*
27 * Functions supporting Solaris Extended Attributes,
28 * used to provide access to CIFS "named streams".
29 */
30
31 #include <sys/systm.h>
32 #include <sys/cred.h>
33 #include <sys/vnode.h>
34 #include <sys/vfs.h>
35 #include <sys/filio.h>
36 #include <sys/uio.h>
37 #include <sys/dirent.h>
38 #include <sys/errno.h>
39 #include <sys/sysmacros.h>
40 #include <sys/kmem.h>
41 #include <sys/stat.h>
42 #include <sys/cmn_err.h>
43 #include <sys/u8_textprep.h>
44
45 #include <netsmb/smb_osdep.h>
46 #include <netsmb/smb.h>
47 #include <netsmb/smb_conn.h>
48 #include <netsmb/smb_subr.h>
49 #include <netsmb/smb_rq.h>
50
51 #include <smbfs/smbfs.h>
52 #include <smbfs/smbfs_node.h>
53 #include <smbfs/smbfs_subr.h>
54
55 #include <fs/fs_subr.h>
56
57 /*
58 * Solaris wants there to be a directory node to contain
59 * all the extended attributes. The SMB protocol does not
60 * really support a directory here, and uses very different
61 * operations to list attributes, etc. so we "fake up" an
62 * smbnode here to represent the attributes directory.
63 *
64 * We need to give this (fake) directory a unique identity,
65 * and since we're using the full remote pathname as the
66 * unique identity of all nodes, the easiest thing to do
272 /* Note: pvp has a VN_HOLD */
273 pnp = VTOSMB(pvp);
274
275 /* Get stream name (ptr and length) */
276 ASSERT(xnp->n_rplen > pnp->n_rplen);
277 nlen = xnp->n_rplen - pnp->n_rplen;
278 name = xnp->n_rpath + pnp->n_rplen;
279 sname = name;
280
281 /* Note: this can allocate a new "name" */
282 error = smbfs_smb_lookup(pnp, &name, &nlen, fap, scrp);
283 if (error == 0 && name != sname)
284 smbfs_name_free(name, nlen);
285
286 VN_RELE(pvp);
287
288 return (error);
289 }
290
291 /*
292 * Fetch the entire attribute list here in findopen.
293 * Will parse the results in findnext.
294 *
295 * This is called on the XATTR directory, so we
296 * have to get the (real) parent object first.
297 */
298 /* ARGSUSED */
299 int
300 smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
301 const char *wildcard, int wclen)
302 {
303 vnode_t *pvp; /* parent */
304 smbnode_t *pnp;
305 struct smb_t2rq *t2p;
306 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
307 struct mbchain *mbp;
308 int error;
309
310 ASSERT(dnp->n_flag & N_XATTR);
311
312 ctx->f_type = ft_XA;
313 ctx->f_namesz = SMB_MAXFNAMELEN + 1;
314 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
315 ctx->f_namesz *= 2;
316 ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
317
318 error = smbfs_xa_parent(SMBTOV(dnp), &pvp);
319 if (error)
320 return (error);
321 ASSERT(pvp);
322 /* Note: pvp has a VN_HOLD */
323 pnp = VTOSMB(pvp);
324
325 if (ctx->f_t2) {
326 smb_t2_done(ctx->f_t2);
327 ctx->f_t2 = NULL;
328 }
329
330 error = smb_t2_alloc(SSTOCP(ctx->f_ssp),
331 SMB_TRANS2_QUERY_PATH_INFORMATION,
332 ctx->f_scred, &t2p);
333 if (error)
334 goto out;
335 ctx->f_t2 = t2p;
336
337 mbp = &t2p->t2_tparam;
338 (void) mb_init(mbp);
339 (void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
340 (void) mb_put_uint32le(mbp, 0);
341 error = smbfs_fullpath(mbp, vcp, pnp, NULL, NULL, 0);
342 if (error)
343 goto out;
344 t2p->t2_maxpcount = 2;
345 t2p->t2_maxdcount = INT16_MAX;
346 error = smb_t2_request(t2p);
347 if (error) {
348 if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER)
349 error = ENOTSUP;
350 }
351 /*
352 * No returned parameters to parse.
353 * Returned data are in t2_rdata,
354 * which we'll parse in _findnext.
355 * However, save the wildcard.
356 */
357 ctx->f_wildcard = wildcard;
358 ctx->f_wclen = wclen;
359
360 out:
361 VN_RELE(pvp);
362 return (error);
363 }
364
365 /*
366 * Get the next name in an XATTR directory into f_name
367 */
368 /* ARGSUSED */
369 int
370 smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit)
371 {
372 struct mdchain *mdp;
373 struct smb_t2rq *t2p;
374 uint32_t size, next;
375 uint64_t llongint;
376 int error, skip, used, nmlen;
377
378 t2p = ctx->f_t2;
379 mdp = &t2p->t2_rdata;
380
381 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
382 ASSERT(ctx->f_wildcard);
383 SMBVDEBUG("wildcard: %s\n", ctx->f_wildcard);
384 }
385
386 again:
387 if (ctx->f_flags & SMBFS_RDD_EOF)
388 return (ENOENT);
389
390 /* Parse FILE_STREAM_INFORMATION */
391 if ((error = md_get_uint32le(mdp, &next)) != 0) /* offset to */
392 return (ENOENT);
393 if ((error = md_get_uint32le(mdp, &size)) != 0) /* name len */
394 return (ENOENT);
395 (void) md_get_uint64le(mdp, &llongint); /* file size */
396 ctx->f_attr.fa_size = llongint;
397 (void) md_get_uint64le(mdp, NULL); /* alloc. size */
398 used = 4 + 4 + 8 + 8; /* how much we consumed */
399
400 /*
401 * Copy the string, but skip the first char (":")
402 * Watch out for zero-length strings here.
403 */
404 if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
405 if (size >= 2) {
406 size -= 2; used += 2;
407 (void) md_get_uint16le(mdp, NULL);
408 }
409 nmlen = min(size, SMB_MAXFNAMELEN * 2);
410 } else {
411 if (size >= 1) {
412 size -= 1; used += 1;
413 (void) md_get_uint8(mdp, NULL);
414 }
415 nmlen = min(size, SMB_MAXFNAMELEN);
416 }
417
418 ASSERT(nmlen < ctx->f_namesz);
419 ctx->f_nmlen = nmlen;
420 error = md_get_mem(mdp, ctx->f_name, nmlen, MB_MSYSTEM);
421 if (error)
422 return (error);
423 used += nmlen;
424
425 /*
426 * Convert UCS-2 to UTF-8
427 */
428 smbfs_fname_tolocal(ctx);
429 if (nmlen)
430 SMBVDEBUG("name: %s\n", ctx->f_name);
431 else
432 SMBVDEBUG("null name!\n");
433
434 /*
435 * Skip padding until next offset
436 */
437 if (next > used) {
438 skip = next - used;
439 (void) md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
440 }
441 if (next == 0)
442 ctx->f_flags |= SMBFS_RDD_EOF;
443
444 /*
445 * Chop off the trailing ":$DATA"
446 * The 6 here is strlen(":$DATA")
447 */
448 if (ctx->f_nmlen >= 6) {
449 char *p = ctx->f_name + ctx->f_nmlen - 6;
450 if (strncmp(p, ":$DATA", 6) == 0) {
451 *p = '\0'; /* Chop! */
452 ctx->f_nmlen -= 6;
453 }
454 }
455
456 /*
457 * The Chop above will typically leave
458 * an empty name in the first slot,
459 * which we will skip here.
460 */
461 if (ctx->f_nmlen == 0)
462 goto again;
463
464 /*
465 * If this is a lookup of a specific name,
466 * skip past any non-matching names.
467 */
468 if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
469 if (ctx->f_wclen != ctx->f_nmlen)
470 goto again;
471 if (u8_strcmp(ctx->f_wildcard, ctx->f_name,
472 ctx->f_nmlen, U8_STRCMP_CI_LOWER,
473 U8_UNICODE_LATEST, &error) || error)
474 goto again;
475 }
476
477 return (0);
478 }
479
480 /*
481 * Find first/next/close for XATTR directories.
482 * NB: also used by smbfs_smb_lookup
483 */
484
485 int
486 smbfs_xa_findclose(struct smbfs_fctx *ctx)
487 {
488
489 if (ctx->f_name)
490 kmem_free(ctx->f_name, ctx->f_namesz);
491 if (ctx->f_t2)
492 smb_t2_done(ctx->f_t2);
493
494 return (0);
495 }
|
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
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 }
|