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)
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
+++ new/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
1 1 /*
2 2 * Copyright (c) 2000-2001, Boris Popov
3 3 * All rights reserved.
4 4 *
5 5 * Redistribution and use in source and binary forms, with or without
6 6 * modification, are permitted provided that the following conditions
7 7 * are met:
8 8 * 1. Redistributions of source code must retain the above copyright
9 9 * notice, this list of conditions and the following disclaimer.
10 10 * 2. Redistributions in binary form must reproduce the above copyright
11 11 * notice, this list of conditions and the following disclaimer in the
12 12 * documentation and/or other materials provided with the distribution.
13 13 * 3. All advertising materials mentioning features or use of this software
14 14 * must display the following acknowledgement:
15 15 * This product includes software developed by Boris Popov.
16 16 * 4. Neither the name of the author nor the names of any co-contributors
17 17 * may be used to endorse or promote products derived from this software
18 18 * without specific prior written permission.
19 19 *
20 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
26 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 30 * SUCH DAMAGE.
31 31 *
32 32 * $Id: smbfs_subr.c,v 1.18 2005/02/02 00:22:23 lindak Exp $
33 33 */
34 34
35 35 /*
36 - * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
37 36 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
38 37 * Use is subject to license terms.
38 + *
39 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
39 40 */
40 41
41 42 #include <sys/param.h>
42 43 #include <sys/systm.h>
43 44 #include <sys/time.h>
44 45 #include <sys/vnode.h>
45 46 #include <sys/sunddi.h>
46 47
47 48 #include <netsmb/smb_osdep.h>
48 49
49 50 #include <netsmb/smb.h>
51 +#include <netsmb/smb2.h>
50 52 #include <netsmb/smb_conn.h>
51 53 #include <netsmb/smb_subr.h>
52 54 #include <netsmb/smb_rq.h>
53 55
54 56 #include <smbfs/smbfs.h>
55 57 #include <smbfs/smbfs_node.h>
56 58 #include <smbfs/smbfs_subr.h>
57 59
58 60 /*
59 61 * In the Darwin code, this function used to compute the full path
60 62 * by following the chain of n_parent pointers back to the root.
61 63 * In the Solaris port we found the n_parent pointers inconvenient
62 64 * because they hold parent nodes busy. We now keep the full path
63 65 * in every node, so this function need only marshall the directory
64 66 * path, and (if provided) the separator and last component name.
65 67 *
|
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
66 68 * Note that this logic must match that in smbfs_getino
67 69 */
68 70 int
69 71 smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
70 72 const char *name, int nmlen, u_int8_t sep)
71 73 {
72 74 int caseopt = SMB_CS_NONE;
73 75 int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0;
74 76 int error;
75 77
76 - if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
77 - caseopt |= SMB_CS_UPPER;
78 -
79 - if (unicode) {
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) {
80 83 error = mb_put_padbyte(mbp);
81 84 if (error)
82 85 return (error);
83 86 }
84 87
85 88 error = smb_put_dmem(mbp, vcp,
86 89 dnp->n_rpath, dnp->n_rplen,
87 90 caseopt, NULL);
88 91 if (name) {
89 92 /*
90 93 * Special case at share root:
91 94 * Don't put another slash.
92 95 */
93 96 if (dnp->n_rplen <= 1 && sep == '\\')
94 97 sep = 0;
95 98 /*
96 99 * More special cases, now for XATTR:
97 100 * Our "faked up" XATTR directories use a
98 101 * full path name ending with ":" so as to
99 102 * avoid conflicts with any real paths.
100 103 * (It is not a valid CIFS path name.)
101 104 * Therefore, when we're composing a full
102 105 * path name from an XATTR directory, we
103 106 * need to _ommit_ the ":" separator and
104 107 * instead copy the one from the "fake"
105 108 * parent node's path name.
106 109 */
107 110 if (dnp->n_flag & N_XATTR)
108 111 sep = 0;
109 112
110 113 if (sep) {
111 114 /* Put the separator */
112 115 if (unicode)
113 116 error = mb_put_uint16le(mbp, sep);
114 117 else
|
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
115 118 error = mb_put_uint8(mbp, sep);
116 119 if (error)
117 120 return (error);
118 121 }
119 122 /* Put the name */
120 123 error = smb_put_dmem(mbp, vcp,
121 124 name, nmlen, caseopt, NULL);
122 125 if (error)
123 126 return (error);
124 127 }
125 - /* Put NULL termination. */
126 - if (unicode)
127 - error = mb_put_uint16le(mbp, 0);
128 - else
129 - error = mb_put_uint8(mbp, 0);
130 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 +
131 137 return (error);
132 138 }
133 139
134 140 /*
135 141 * Convert a Unicode directory entry to UTF-8
136 142 */
137 143 void
138 144 smbfs_fname_tolocal(struct smbfs_fctx *ctx)
139 145 {
140 146 uchar_t tmpbuf[SMB_MAXFNAMELEN+1];
141 147 struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
142 148 uchar_t *dst;
143 149 const ushort_t *src;
144 150 size_t inlen, outlen;
145 151 int flags;
146 152
147 153 if (ctx->f_nmlen == 0)
148 154 return;
149 155
150 156 if (!SMB_UNICODE_STRINGS(vcp))
151 157 return;
152 158
153 159 if (ctx->f_namesz < sizeof (tmpbuf)) {
154 160 ASSERT(0);
155 161 goto errout;
156 162 }
157 163
158 164 /*
159 165 * In-place conversions are not supported,
160 166 * so convert into tmpbuf and copy.
161 167 */
162 168 dst = tmpbuf;
163 169 outlen = SMB_MAXFNAMELEN;
164 170 /*LINTED*/
165 171 src = (const ushort_t *)ctx->f_name;
166 172 inlen = ctx->f_nmlen / 2; /* number of UCS-2 characters */
167 173 flags = UCONV_IN_LITTLE_ENDIAN;
168 174
169 175 if (uconv_u16tou8(src, &inlen, dst, &outlen, flags) != 0)
170 176 goto errout;
171 177
172 178 ASSERT(outlen < sizeof (tmpbuf));
173 179 tmpbuf[outlen] = '\0';
174 180 bcopy(tmpbuf, ctx->f_name, outlen + 1);
|
↓ open down ↓ |
34 lines elided |
↑ open up ↑ |
175 181 ctx->f_nmlen = (int)outlen;
176 182 return;
177 183
178 184 errout:
179 185 /*
180 186 * Conversion failed, but our caller does not
181 187 * deal with errors here, so just put a "?".
182 188 * Don't expect to ever see this.
183 189 */
184 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);
185 459 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX