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