Print this page
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-4797 MS-Office crash while saving a file on a Nexenta smb share
Revert "NEX-4324 Should not include $DATA when enumerating streams"
This reverts commits c72f3674cf6d0db6a44cd40c1ed626e79f20a537
and 2db2cee12b7a06b6651924ff35cf8bfc42a3b32f.
NEX-4324 Should not include $DATA when enumerating streams (lint)
NEX-4324 Should not include $DATA when enumerating streams
Reviewed by: Daniel Borek <daniel.borek@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
re #14152 Race between ipmi_submit_driver_request() and kcs_loop() (sync with illumos fix 3902)
SMB-46 File handle leaks exposed by mtime fixes (rm 7815)
re #7815 SMB server delivers old modification time...
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 - * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 + * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
25 25 */
26 26
27 27 #include <smbsrv/smb_kproto.h>
28 28 #include <smbsrv/smb_vops.h>
29 29 #include <smbsrv/smb_fsops.h>
30 30
31 31 /*
32 32 * Trans2 Query File/Path Information Levels:
33 33 *
34 34 * SMB_INFO_STANDARD
35 35 * SMB_INFO_QUERY_EA_SIZE
36 36 * SMB_INFO_QUERY_EAS_FROM_LIST
37 37 * SMB_INFO_QUERY_ALL_EAS - not valid for pipes
38 38 * SMB_INFO_IS_NAME_VALID - only valid when query is by path
39 39 *
40 40 * SMB_QUERY_FILE_BASIC_INFO
41 41 * SMB_QUERY_FILE_STANDARD_INFO
42 42 * SMB_QUERY_FILE_EA_INFO
43 43 * SMB_QUERY_FILE_NAME_INFO
44 44 * SMB_QUERY_FILE_ALL_INFO
45 45 * SMB_QUERY_FILE_ALT_NAME_INFO - not valid for pipes
46 46 * SMB_QUERY_FILE_STREAM_INFO - not valid for pipes
47 47 * SMB_QUERY_FILE_COMPRESSION_INFO - not valid for pipes
48 48 *
49 49 * Supported Passthrough levels:
50 50 * SMB_FILE_BASIC_INFORMATION
51 51 * SMB_FILE_STANDARD_INFORMATION
52 52 * SMB_FILE_INTERNAL_INFORMATION
53 53 * SMB_FILE_EA_INFORMATION
54 54 * SMB_FILE_ACCESS_INFORMATION - not yet supported when query by path
55 55 * SMB_FILE_NAME_INFORMATION
56 56 * SMB_FILE_ALL_INFORMATION
57 57 * SMB_FILE_ALT_NAME_INFORMATION - not valid for pipes
58 58 * SMB_FILE_STREAM_INFORMATION - not valid for pipes
59 59 * SMB_FILE_COMPRESSION_INFORMATION - not valid for pipes
60 60 * SMB_FILE_NETWORK_OPEN_INFORMATION - not valid for pipes
61 61 * SMB_FILE_ATTR_TAG_INFORMATION - not valid for pipes
62 62 *
63 63 * Internal levels representing non trans2 requests
64 64 * SMB_QUERY_INFORMATION
65 65 * SMB_QUERY_INFORMATION2
66 66 */
67 67
68 68 /*
69 69 * SMB_STREAM_ENCODE_FIXED_SIZE:
70 70 * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
71 71 */
72 72 #define SMB_STREAM_ENCODE_FIXED_SZ 24
73 73
74 74 /* See smb_queryinfo_t in smb_ktypes.h */
75 75 #define qi_mtime qi_attr.sa_vattr.va_mtime
76 76 #define qi_ctime qi_attr.sa_vattr.va_ctime
77 77 #define qi_atime qi_attr.sa_vattr.va_atime
78 78 #define qi_crtime qi_attr.sa_crtime
79 79
80 80 static int smb_query_by_fid(smb_request_t *, smb_xa_t *, uint16_t);
81 81 static int smb_query_by_path(smb_request_t *, smb_xa_t *, uint16_t);
82 82
83 83 static int smb_query_fileinfo(smb_request_t *, smb_node_t *,
84 84 uint16_t, smb_queryinfo_t *);
85 85 static int smb_query_pipeinfo(smb_request_t *, smb_opipe_t *,
86 86 uint16_t, smb_queryinfo_t *);
87 87 static boolean_t smb_query_pipe_valid_infolev(smb_request_t *, uint16_t);
88 88
89 89 static int smb_query_encode_response(smb_request_t *, smb_xa_t *,
90 90 uint16_t, smb_queryinfo_t *);
91 91 static boolean_t smb_stream_fits(smb_request_t *, mbuf_chain_t *,
92 92 char *, uint32_t);
93 93 static int smb_query_pathname(smb_request_t *, smb_node_t *, boolean_t,
94 94 smb_queryinfo_t *);
95 95
96 96 int smb_query_passthru;
97 97
98 98 /*
99 99 * smb_com_trans2_query_file_information
100 100 */
101 101 smb_sdrc_t
102 102 smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
103 103 {
104 104 uint16_t infolev;
105 105
106 106 if (smb_mbc_decodef(&xa->req_param_mb, "ww",
107 107 &sr->smb_fid, &infolev) != 0)
108 108 return (SDRC_ERROR);
109 109
110 110 if (smb_query_by_fid(sr, xa, infolev) != 0)
111 111 return (SDRC_ERROR);
112 112
113 113 return (SDRC_SUCCESS);
114 114 }
115 115
116 116 /*
117 117 * smb_com_trans2_query_path_information
118 118 */
119 119 smb_sdrc_t
120 120 smb_com_trans2_query_path_information(smb_request_t *sr, smb_xa_t *xa)
121 121 {
122 122 uint16_t infolev;
123 123 smb_fqi_t *fqi = &sr->arg.dirop.fqi;
124 124
125 125 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
126 126 smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
127 127 ERRDOS, ERROR_INVALID_FUNCTION);
128 128 return (SDRC_ERROR);
129 129 }
130 130
131 131 if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u",
132 132 sr, &infolev, &fqi->fq_path.pn_path) != 0)
133 133 return (SDRC_ERROR);
134 134
135 135 if (smb_query_by_path(sr, xa, infolev) != 0)
136 136 return (SDRC_ERROR);
137 137
138 138 return (SDRC_SUCCESS);
139 139 }
140 140
141 141 /*
|
↓ open down ↓ |
107 lines elided |
↑ open up ↑ |
142 142 * smb_com_query_information (aka getattr)
143 143 */
144 144 smb_sdrc_t
145 145 smb_pre_query_information(smb_request_t *sr)
146 146 {
147 147 int rc;
148 148 smb_fqi_t *fqi = &sr->arg.dirop.fqi;
149 149
150 150 rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
151 151
152 - DTRACE_SMB_2(op__QueryInformation__start, smb_request_t *, sr,
153 - smb_fqi_t *, fqi);
152 + DTRACE_SMB_START(op__QueryInformation, smb_request_t *, sr);
154 153
155 154 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
156 155 }
157 156
158 157 void
159 158 smb_post_query_information(smb_request_t *sr)
160 159 {
161 - DTRACE_SMB_1(op__QueryInformation__done, smb_request_t *, sr);
160 + DTRACE_SMB_DONE(op__QueryInformation, smb_request_t *, sr);
162 161 }
163 162
164 163 smb_sdrc_t
165 164 smb_com_query_information(smb_request_t *sr)
166 165 {
167 166 uint16_t infolev = SMB_QUERY_INFORMATION;
168 167
169 168 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
170 169 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
171 170 ERRDOS, ERROR_ACCESS_DENIED);
172 171 return (SDRC_ERROR);
173 172 }
174 173
175 174 if (smb_query_by_path(sr, NULL, infolev) != 0)
176 175 return (SDRC_ERROR);
177 176
178 177 return (SDRC_SUCCESS);
179 178 }
|
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
180 179
181 180 /*
182 181 * smb_com_query_information2 (aka getattre)
183 182 */
184 183 smb_sdrc_t
185 184 smb_pre_query_information2(smb_request_t *sr)
186 185 {
187 186 int rc;
188 187 rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
189 188
190 - DTRACE_SMB_1(op__QueryInformation2__start, smb_request_t *, sr);
189 + DTRACE_SMB_START(op__QueryInformation2, smb_request_t *, sr);
191 190
192 191 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
193 192 }
194 193
195 194 void
196 195 smb_post_query_information2(smb_request_t *sr)
197 196 {
198 - DTRACE_SMB_1(op__QueryInformation2__done, smb_request_t *, sr);
197 + DTRACE_SMB_DONE(op__QueryInformation2, smb_request_t *, sr);
199 198 }
200 199
201 200 smb_sdrc_t
202 201 smb_com_query_information2(smb_request_t *sr)
203 202 {
204 203 uint16_t infolev = SMB_QUERY_INFORMATION2;
205 204
206 205 if (smb_query_by_fid(sr, NULL, infolev) != 0)
207 206 return (SDRC_ERROR);
208 207
209 208 return (SDRC_SUCCESS);
210 209 }
211 210
212 211 /*
213 212 * smb_query_by_fid
214 213 *
215 214 * Common code for querying file information by open file (or pipe) id.
216 215 * Use the id to identify the node / pipe object and request the
217 216 * smb_queryinfo_t data for that object.
218 217 */
219 218 static int
220 219 smb_query_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
221 220 {
222 221 int rc;
223 222 smb_queryinfo_t *qinfo;
224 223 smb_node_t *node;
225 224 smb_opipe_t *opipe;
226 225
227 226 smbsr_lookup_file(sr);
228 227
229 228 if (sr->fid_ofile == NULL) {
230 229 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
231 230 return (-1);
232 231 }
233 232
234 233 if (infolev == SMB_INFO_IS_NAME_VALID) {
235 234 smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
236 235 smbsr_release_file(sr);
237 236 return (-1);
238 237 }
239 238
240 239 if ((sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE) &&
241 240 (!smb_query_pipe_valid_infolev(sr, infolev))) {
242 241 smbsr_release_file(sr);
243 242 return (-1);
244 243 }
245 244
246 245 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
247 246 qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP);
248 247
249 248 switch (sr->fid_ofile->f_ftype) {
250 249 case SMB_FTYPE_DISK:
251 250 node = sr->fid_ofile->f_node;
252 251 rc = smb_query_fileinfo(sr, node, infolev, qinfo);
253 252 break;
254 253 case SMB_FTYPE_MESG_PIPE:
255 254 opipe = sr->fid_ofile->f_pipe;
256 255 rc = smb_query_pipeinfo(sr, opipe, infolev, qinfo);
257 256 break;
258 257 default:
259 258 smbsr_error(sr, 0, ERRDOS, ERRbadfile);
260 259 rc = -1;
261 260 break;
262 261 }
263 262
264 263 if (rc == 0)
265 264 rc = smb_query_encode_response(sr, xa, infolev, qinfo);
266 265
267 266 kmem_free(qinfo, sizeof (smb_queryinfo_t));
268 267 smbsr_release_file(sr);
269 268 return (rc);
270 269 }
271 270
272 271 /*
273 272 * smb_query_by_path
274 273 *
275 274 * Common code for querying file information by file name.
276 275 * Use the file name to identify the node object and request the
277 276 * smb_queryinfo_t data for that node.
278 277 *
279 278 * Path should be set in sr->arg.dirop.fqi.fq_path prior to
280 279 * calling smb_query_by_path.
281 280 *
282 281 * Querying attributes on a named pipe by name is an error and
283 282 * is handled in the calling functions so that they can return
284 283 * the appropriate error status code (which differs by caller).
285 284 */
286 285 static int
287 286 smb_query_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
288 287 {
289 288 smb_queryinfo_t *qinfo;
290 289 smb_node_t *node, *dnode;
291 290 smb_pathname_t *pn;
292 291 int rc;
293 292
294 293 /*
295 294 * The function smb_query_fileinfo is used here and in
296 295 * smb_query_by_fid. That common function needs this
297 296 * one to call it with a NULL fid_ofile, so check here.
298 297 * Note: smb_query_by_fid enforces the opposite.
299 298 *
300 299 * In theory we could ASSERT this, but whether we have
301 300 * fid_ofile set here depends on what sequence of SMB
302 301 * commands the client has sent in this message, so
303 302 * let's be cautious and handle it as an error.
304 303 */
305 304 if (sr->fid_ofile != NULL)
306 305 return (-1);
307 306
308 307
309 308 /* VALID, but not yet supported */
310 309 if (infolev == SMB_FILE_ACCESS_INFORMATION) {
311 310 smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
312 311 return (-1);
313 312 }
314 313
315 314 pn = &sr->arg.dirop.fqi.fq_path;
316 315 smb_pathname_init(sr, pn, pn->pn_path);
317 316 if (!smb_pathname_validate(sr, pn))
318 317 return (-1);
319 318
320 319 qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP);
321 320
322 321 rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
|
↓ open down ↓ |
114 lines elided |
↑ open up ↑ |
323 322 sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode,
324 323 qinfo->qi_name);
325 324
326 325 if (rc == 0) {
327 326 rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
328 327 sr->tid_tree->t_snode, dnode, qinfo->qi_name, &node);
329 328 smb_node_release(dnode);
330 329 }
331 330
332 331 if (rc != 0) {
333 - if (rc == ENOENT)
334 - smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
335 - ERRDOS, ERROR_FILE_NOT_FOUND);
336 - else
337 - smbsr_errno(sr, rc);
332 + smbsr_errno(sr, rc);
338 333
339 334 kmem_free(qinfo, sizeof (smb_queryinfo_t));
340 335 return (-1);
341 336 }
342 337
343 338 if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) {
344 339 smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
345 340 kmem_free(qinfo, sizeof (smb_queryinfo_t));
346 341 smb_node_release(node);
347 342 return (-1);
348 343 }
349 344
350 345 rc = smb_query_fileinfo(sr, node, infolev, qinfo);
351 346 if (rc != 0) {
352 347 kmem_free(qinfo, sizeof (smb_queryinfo_t));
353 348 smb_node_release(node);
354 349 return (rc);
355 350 }
356 351
357 352 /* If delete_on_close - NT_STATUS_DELETE_PENDING */
358 353 if (qinfo->qi_delete_on_close) {
359 354 smbsr_error(sr, NT_STATUS_DELETE_PENDING,
360 355 ERRDOS, ERROR_ACCESS_DENIED);
361 356 kmem_free(qinfo, sizeof (smb_queryinfo_t));
362 357 smb_node_release(node);
363 358 return (-1);
364 359 }
365 360
366 361 rc = smb_query_encode_response(sr, xa, infolev, qinfo);
367 362 kmem_free(qinfo, sizeof (smb_queryinfo_t));
368 363 smb_node_release(node);
369 364 return (rc);
370 365 }
371 366
372 367 /*
373 368 * smb_size32
374 369 * Some responses only support 32 bit file sizes. If the file size
375 370 * exceeds UINT_MAX (32 bit) we return UINT_MAX in the response.
376 371 */
377 372 static uint32_t
378 373 smb_size32(u_offset_t size)
379 374 {
380 375 return ((size > UINT_MAX) ? UINT_MAX : (uint32_t)size);
381 376 }
382 377
383 378 /*
384 379 * smb_query_encode_response
385 380 *
386 381 * Encode the data from smb_queryinfo_t into client response
387 382 */
388 383 int
389 384 smb_query_encode_response(smb_request_t *sr, smb_xa_t *xa,
390 385 uint16_t infolev, smb_queryinfo_t *qinfo)
391 386 {
392 387 uint16_t dattr;
393 388 u_offset_t datasz, allocsz;
394 389 uint32_t status;
395 390
396 391 dattr = qinfo->qi_attr.sa_dosattr & FILE_ATTRIBUTE_MASK;
397 392 datasz = qinfo->qi_attr.sa_vattr.va_size;
398 393 allocsz = qinfo->qi_attr.sa_allocsz;
399 394
400 395 switch (infolev) {
401 396 case SMB_QUERY_INFORMATION:
402 397 (void) smbsr_encode_result(sr, 10, 0, "bwll10.w",
403 398 10,
404 399 dattr,
405 400 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
406 401 smb_size32(datasz),
407 402 0);
408 403 break;
409 404
410 405 case SMB_QUERY_INFORMATION2:
411 406 (void) smbsr_encode_result(sr, 11, 0, "byyyllww",
412 407 11,
413 408 smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
414 409 smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
415 410 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
416 411 smb_size32(datasz), smb_size32(allocsz), dattr, 0);
417 412 break;
418 413
419 414 case SMB_FILE_ACCESS_INFORMATION:
420 415 ASSERT(sr->fid_ofile);
421 416 (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
422 417 sr->fid_ofile->f_granted_access);
423 418 break;
424 419
425 420 case SMB_INFO_STANDARD:
426 421 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
427 422 (void) smb_mbc_encodef(&xa->rep_data_mb,
428 423 ((sr->session->native_os == NATIVE_OS_WIN95) ?
429 424 "YYYllw" : "yyyllw"),
430 425 smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
431 426 smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
432 427 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
433 428 smb_size32(datasz), smb_size32(allocsz), dattr);
434 429 break;
435 430
436 431 case SMB_INFO_QUERY_EA_SIZE:
437 432 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
438 433 (void) smb_mbc_encodef(&xa->rep_data_mb,
439 434 ((sr->session->native_os == NATIVE_OS_WIN95) ?
440 435 "YYYllwl" : "yyyllwl"),
441 436 smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
442 437 smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
443 438 smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
444 439 smb_size32(datasz), smb_size32(allocsz), dattr, 0);
445 440 break;
446 441
447 442 case SMB_INFO_QUERY_ALL_EAS:
448 443 case SMB_INFO_QUERY_EAS_FROM_LIST:
449 444 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
450 445 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
451 446 break;
452 447
453 448 case SMB_INFO_IS_NAME_VALID:
454 449 break;
455 450
456 451 case SMB_QUERY_FILE_BASIC_INFO:
457 452 case SMB_FILE_BASIC_INFORMATION:
458 453 /*
459 454 * NT includes 6 bytes (spec says 4) at the end of this
460 455 * response, which are required by NetBench 5.01.
461 456 */
462 457 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
463 458 (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.",
464 459 &qinfo->qi_crtime,
465 460 &qinfo->qi_atime,
466 461 &qinfo->qi_mtime,
467 462 &qinfo->qi_ctime,
468 463 dattr);
469 464 break;
470 465
471 466 case SMB_QUERY_FILE_STANDARD_INFO:
472 467 case SMB_FILE_STANDARD_INFORMATION:
473 468 /* 2-byte pad at end */
474 469 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
475 470 (void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
476 471 (uint64_t)allocsz,
477 472 (uint64_t)datasz,
478 473 qinfo->qi_attr.sa_vattr.va_nlink,
479 474 qinfo->qi_delete_on_close,
480 475 qinfo->qi_isdir);
481 476 break;
482 477
483 478 case SMB_QUERY_FILE_EA_INFO:
484 479 case SMB_FILE_EA_INFORMATION:
485 480 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
486 481 (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
487 482 break;
488 483
489 484 case SMB_QUERY_FILE_NAME_INFO:
490 485 case SMB_FILE_NAME_INFORMATION:
491 486 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
492 487 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
493 488 qinfo->qi_namelen, qinfo->qi_name);
494 489 break;
495 490
496 491 case SMB_QUERY_FILE_ALL_INFO:
497 492 case SMB_FILE_ALL_INFORMATION:
498 493 /*
499 494 * There is a 6-byte pad between Attributes and AllocationSize,
500 495 * and a 2-byte pad after the Directory field.
501 496 */
502 497 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
503 498 (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
504 499 &qinfo->qi_crtime,
505 500 &qinfo->qi_atime,
506 501 &qinfo->qi_mtime,
507 502 &qinfo->qi_ctime,
508 503 dattr,
509 504 (uint64_t)allocsz,
510 505 (uint64_t)datasz,
511 506 qinfo->qi_attr.sa_vattr.va_nlink,
512 507 qinfo->qi_delete_on_close,
513 508 qinfo->qi_isdir,
514 509 0);
515 510
516 511 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu",
517 512 sr, qinfo->qi_namelen, qinfo->qi_name);
518 513 break;
519 514
520 515 case SMB_QUERY_FILE_ALT_NAME_INFO:
521 516 case SMB_FILE_ALT_NAME_INFORMATION:
522 517 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
523 518 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
524 519 smb_wcequiv_strlen(qinfo->qi_shortname),
525 520 qinfo->qi_shortname);
526 521 break;
527 522
528 523 case SMB_QUERY_FILE_STREAM_INFO:
529 524 case SMB_FILE_STREAM_INFORMATION:
530 525 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
531 526 status = smb_query_stream_info(sr, &xa->rep_data_mb, qinfo);
532 527 if (status)
533 528 smbsr_status(sr, status, 0, 0);
534 529 break;
535 530
536 531 case SMB_QUERY_FILE_COMPRESSION_INFO:
537 532 case SMB_FILE_COMPRESSION_INFORMATION:
538 533 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
539 534 (void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.",
540 535 datasz, 0, 0, 0, 0);
541 536 break;
542 537
543 538 case SMB_FILE_INTERNAL_INFORMATION:
544 539 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
545 540 (void) smb_mbc_encodef(&xa->rep_data_mb, "q",
546 541 qinfo->qi_attr.sa_vattr.va_nodeid);
547 542 break;
548 543
549 544 case SMB_FILE_NETWORK_OPEN_INFORMATION:
550 545 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
551 546 (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTqql4.",
552 547 &qinfo->qi_crtime,
553 548 &qinfo->qi_atime,
554 549 &qinfo->qi_mtime,
555 550 &qinfo->qi_ctime,
556 551 (uint64_t)allocsz,
557 552 (uint64_t)datasz,
558 553 (uint32_t)dattr);
559 554 break;
560 555
561 556 case SMB_FILE_ATTR_TAG_INFORMATION:
562 557 /*
563 558 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
564 559 * second dword should be the reparse tag. Otherwise
565 560 * the tag value should be set to zero.
566 561 * We don't support reparse points, so we set the tag
567 562 * to zero.
568 563 */
569 564 (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
570 565 (void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
571 566 (uint32_t)dattr, 0);
572 567 break;
573 568
574 569 default:
575 570 if ((infolev > 1000) && smb_query_passthru)
576 571 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
577 572 ERRDOS, ERROR_NOT_SUPPORTED);
578 573 else
579 574 smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL);
580 575 return (-1);
581 576 }
582 577
583 578 return (0);
584 579 }
585 580
586 581 /*
587 582 * smb_encode_stream_info
588 583 *
589 584 * This function encodes the streams information.
590 585 * The following rules about how have been derived from observed NT
591 586 * behaviour.
592 587 *
593 588 * If the target is a file:
594 589 * 1. If there are no named streams, the response should still contain
595 590 * an entry for the unnamed stream.
596 591 * 2. If there are named streams, the response should contain an entry
597 592 * for the unnamed stream followed by the entries for the named
598 593 * streams.
599 594 *
600 595 * If the target is a directory:
601 596 * 1. If there are no streams, the response is complete. Directories
602 597 * do not report the unnamed stream.
603 598 * 2. If there are streams, the response should contain entries for
604 599 * those streams but there should not be an entry for the unnamed
605 600 * stream.
606 601 *
607 602 * Note that the stream name lengths exclude the null terminator but
608 603 * the field lengths (i.e. next offset calculations) need to include
609 604 * the null terminator and be padded to a multiple of 8 bytes. The
610 605 * last entry does not seem to need any padding.
611 606 *
612 607 * If an error is encountered when trying to read the stream entries
613 608 * (smb_odir_read_streaminfo) it is treated as if there are no [more]
614 609 * entries. The entries that have been read so far are returned and
615 610 * no error is reported.
616 611 *
617 612 * If the response buffer is not large enough to return all of the
618 613 * named stream entries, the entries that do fit are returned and
619 614 * a warning code is set (NT_STATUS_BUFFER_OVERFLOW). The next_offset
620 615 * value in the last returned entry must be 0.
621 616 */
622 617 uint32_t
623 618 smb_query_stream_info(smb_request_t *sr, mbuf_chain_t *mbc,
624 619 smb_queryinfo_t *qinfo)
625 620 {
626 621 char *stream_name;
627 622 uint32_t next_offset;
628 623 uint32_t stream_nlen;
629 624 uint32_t pad;
630 625 u_offset_t datasz, allocsz;
631 626 smb_streaminfo_t *sinfo, *sinfo_next;
632 627 int rc = 0;
633 628 boolean_t done = B_FALSE;
634 629 boolean_t eos = B_FALSE;
635 630 smb_odir_t *od = NULL;
636 631 uint32_t status = 0;
637 632
638 633 smb_node_t *fnode = qinfo->qi_node;
639 634 smb_attr_t *attr = &qinfo->qi_attr;
640 635
641 636 ASSERT(fnode);
642 637 if (SMB_IS_STREAM(fnode)) {
643 638 fnode = fnode->n_unode;
644 639 ASSERT(fnode);
645 640 }
646 641 ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
647 642 ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
|
↓ open down ↓ |
300 lines elided |
↑ open up ↑ |
648 643
649 644 sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
650 645 sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
651 646 datasz = attr->sa_vattr.va_size;
652 647 allocsz = attr->sa_allocsz;
653 648
654 649 status = smb_odir_openat(sr, fnode, &od);
655 650 switch (status) {
656 651 case 0:
657 652 break;
653 + case NT_STATUS_OBJECT_NAME_NOT_FOUND:
658 654 case NT_STATUS_NO_SUCH_FILE:
659 655 case NT_STATUS_NOT_SUPPORTED:
660 656 /* No streams. */
657 + status = 0;
661 658 done = B_TRUE;
662 659 break;
663 660 default:
664 661 return (status);
665 662 }
666 663
667 664 if (!done) {
668 665 rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos);
669 666 if ((rc != 0) || (eos))
670 667 done = B_TRUE;
671 668 }
672 669
673 670 /* If not a directory, encode an entry for the unnamed stream. */
674 671 if (qinfo->qi_isdir == 0) {
675 672 stream_name = "::$DATA";
676 673 stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
677 674 next_offset = SMB_STREAM_ENCODE_FIXED_SZ + stream_nlen +
678 675 smb_ascii_or_unicode_null_len(sr);
679 676
680 677 /* Can unnamed stream fit in response buffer? */
681 678 if (MBC_ROOM_FOR(mbc, next_offset) == 0) {
682 679 done = B_TRUE;
683 680 status = NT_STATUS_BUFFER_OVERFLOW;
684 681 } else {
685 682 /* Can first named stream fit in rsp buffer? */
686 683 if (!done && !smb_stream_fits(sr, mbc, sinfo->si_name,
687 684 next_offset)) {
688 685 done = B_TRUE;
689 686 status = NT_STATUS_BUFFER_OVERFLOW;
690 687 }
691 688
692 689 if (done)
693 690 next_offset = 0;
694 691
695 692 (void) smb_mbc_encodef(mbc, "%llqqu", sr,
696 693 next_offset, stream_nlen, datasz, allocsz,
697 694 stream_name);
698 695 }
699 696 }
700 697
701 698 /*
702 699 * If there is no next entry, or there is not enough space in
703 700 * the response buffer for the next entry, the next_offset and
704 701 * padding are 0.
705 702 */
706 703 while (!done) {
707 704 stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name);
708 705 sinfo_next->si_name[0] = 0;
709 706
710 707 rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos);
711 708 if ((rc != 0) || (eos)) {
712 709 done = B_TRUE;
713 710 } else {
714 711 next_offset = SMB_STREAM_ENCODE_FIXED_SZ +
715 712 stream_nlen +
716 713 smb_ascii_or_unicode_null_len(sr);
717 714 pad = smb_pad_align(next_offset, 8);
718 715 next_offset += pad;
719 716
720 717 /* Can next named stream fit in response buffer? */
721 718 if (!smb_stream_fits(sr, mbc, sinfo_next->si_name,
722 719 next_offset)) {
723 720 done = B_TRUE;
724 721 status = NT_STATUS_BUFFER_OVERFLOW;
725 722 }
726 723 }
727 724
728 725 if (done) {
729 726 next_offset = 0;
730 727 pad = 0;
731 728 }
732 729
733 730 (void) smb_mbc_encodef(mbc, "%llqqu#.",
734 731 sr, next_offset, stream_nlen,
735 732 sinfo->si_size, sinfo->si_alloc_size,
736 733 sinfo->si_name, pad);
737 734
738 735 (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t));
739 736 }
740 737
741 738 kmem_free(sinfo, sizeof (smb_streaminfo_t));
742 739 kmem_free(sinfo_next, sizeof (smb_streaminfo_t));
743 740 if (od) {
744 741 smb_odir_close(od);
745 742 smb_odir_release(od);
746 743 }
747 744
748 745 return (status);
749 746 }
750 747
751 748 /*
752 749 * smb_stream_fits
753 750 *
754 751 * Check if the named stream entry can fit in the response buffer.
755 752 *
756 753 * Required space =
757 754 * offset (size of current entry)
758 755 * + SMB_STREAM_ENCODE_FIXED_SIZE
759 756 * + length of encoded stream name
760 757 * + length of null terminator
761 758 * + alignment padding
762 759 */
763 760 static boolean_t
764 761 smb_stream_fits(smb_request_t *sr, mbuf_chain_t *mbc,
765 762 char *name, uint32_t offset)
766 763 {
767 764 uint32_t len, pad;
768 765
769 766 len = SMB_STREAM_ENCODE_FIXED_SZ +
770 767 smb_ascii_or_unicode_strlen(sr, name) +
771 768 smb_ascii_or_unicode_null_len(sr);
772 769 pad = smb_pad_align(len, 8);
773 770 len += pad;
774 771
775 772 return (MBC_ROOM_FOR(mbc, offset + len) != 0);
776 773 }
777 774
778 775 /*
779 776 * smb_query_fileinfo
780 777 *
781 778 * Populate smb_queryinfo_t structure for SMB_FTYPE_DISK
782 779 * (This should become an smb_ofile / smb_node function.)
783 780 */
784 781 int
785 782 smb_query_fileinfo(smb_request_t *sr, smb_node_t *node, uint16_t infolev,
786 783 smb_queryinfo_t *qinfo)
787 784 {
788 785 int rc = 0;
789 786
790 787 /* If shortname required but not supported -> OBJECT_NAME_NOT_FOUND */
791 788 if ((infolev == SMB_QUERY_FILE_ALT_NAME_INFO) ||
792 789 (infolev == SMB_FILE_ALT_NAME_INFORMATION)) {
793 790 if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_SHORTNAMES)) {
794 791 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
795 792 ERRDOS, ERROR_FILE_NOT_FOUND);
796 793 return (-1);
797 794 }
798 795 }
799 796
800 797 (void) bzero(qinfo, sizeof (smb_queryinfo_t));
801 798
802 799 /* See: smb_query_encode_response */
803 800 qinfo->qi_attr.sa_mask = SMB_AT_ALL;
804 801 rc = smb_node_getattr(sr, node, sr->user_cr, sr->fid_ofile,
805 802 &qinfo->qi_attr);
806 803 if (rc != 0) {
807 804 smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
808 805 ERRDOS, ERROR_INTERNAL_ERROR);
809 806 return (-1);
810 807 }
811 808
812 809 qinfo->qi_node = node;
813 810 qinfo->qi_delete_on_close =
814 811 (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
815 812 qinfo->qi_isdir = smb_node_is_dir(node);
816 813
817 814 /*
818 815 * The number of links reported should be the number of
819 816 * non-deleted links. Thus if delete_on_close is set,
820 817 * decrement the link count.
821 818 */
822 819 if (qinfo->qi_delete_on_close &&
823 820 qinfo->qi_attr.sa_vattr.va_nlink > 0) {
824 821 --(qinfo->qi_attr.sa_vattr.va_nlink);
825 822 }
826 823
827 824 /*
828 825 * populate name, namelen and shortname ONLY for the information
829 826 * levels that require these fields
830 827 */
831 828 switch (infolev) {
832 829 case SMB_QUERY_FILE_ALL_INFO:
833 830 case SMB_FILE_ALL_INFORMATION:
834 831 rc = smb_query_pathname(sr, node, B_TRUE, qinfo);
835 832 break;
836 833 case SMB_QUERY_FILE_NAME_INFO:
837 834 case SMB_FILE_NAME_INFORMATION:
838 835 rc = smb_query_pathname(sr, node, B_FALSE, qinfo);
839 836 break;
840 837 case SMB_QUERY_FILE_ALT_NAME_INFO:
841 838 case SMB_FILE_ALT_NAME_INFORMATION:
842 839 smb_query_shortname(node, qinfo);
843 840 break;
844 841 default:
845 842 break;
846 843 }
847 844
848 845 if (rc != 0) {
849 846 smbsr_errno(sr, rc);
850 847 return (-1);
851 848 }
852 849 return (0);
853 850 }
854 851
855 852 /*
856 853 * smb_query_pathname
857 854 *
858 855 * Determine the absolute pathname of 'node' within the share.
859 856 * For some levels (e.g. ALL_INFO) the pathname should include the
860 857 * sharename for others (e.g. NAME_INFO) the pathname should be
861 858 * relative to the share.
862 859 * For example if the node represents file "test1.txt" in directory
863 860 * "dir1" on share "share1"
864 861 * - if include_share is TRUE the pathname would be: \share1\dir1\test1.txt
865 862 * - if include_share is FALSE the pathname would be: \dir1\test1.txt
866 863 *
867 864 * For some reason NT will not show the security tab in the root
868 865 * directory of a mapped drive unless the filename length is greater
869 866 * than one. So if the length is 1 we set it to 2 to persuade NT to
870 867 * show the tab. It should be safe because of the null terminator.
871 868 */
872 869 static int
873 870 smb_query_pathname(smb_request_t *sr, smb_node_t *node, boolean_t include_share,
874 871 smb_queryinfo_t *qinfo)
875 872 {
876 873 smb_tree_t *tree = sr->tid_tree;
877 874 char *buf = qinfo->qi_name;
878 875 size_t buflen = MAXPATHLEN;
879 876 size_t len;
880 877 int rc;
881 878
882 879 if (include_share) {
883 880 len = snprintf(buf, buflen, "\\%s", tree->t_sharename);
884 881 if (len == (buflen - 1))
885 882 return (ENAMETOOLONG);
886 883
887 884 buf += len;
888 885 buflen -= len;
889 886 }
890 887
891 888 if (node == tree->t_snode) {
892 889 if (!include_share)
893 890 (void) strlcpy(buf, "\\", buflen);
894 891 return (0);
895 892 }
896 893
897 894 rc = smb_node_getshrpath(node, tree, buf, buflen);
898 895 if (rc == 0) {
899 896 qinfo->qi_namelen =
900 897 smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
901 898 if (qinfo->qi_namelen == 1)
902 899 qinfo->qi_namelen = 2;
903 900 }
904 901 return (rc);
905 902 }
906 903
907 904 /*
908 905 * smb_query_shortname
909 906 *
910 907 * If the node is a named stream, use its associated
911 908 * unnamed stream name to determine the shortname.
912 909 * If a shortname is required (smb_needs_mangle()), generate it
913 910 * using smb_mangle(), otherwise, convert the original name to
914 911 * upper-case and return it as the alternative name.
915 912 */
916 913 void
917 914 smb_query_shortname(smb_node_t *node, smb_queryinfo_t *qinfo)
918 915 {
919 916 char *namep;
920 917
921 918 if (SMB_IS_STREAM(node))
922 919 namep = node->n_unode->od_name;
923 920 else
924 921 namep = node->od_name;
925 922
926 923 if (smb_needs_mangled(namep)) {
927 924 smb_mangle(namep, qinfo->qi_attr.sa_vattr.va_nodeid,
928 925 qinfo->qi_shortname, SMB_SHORTNAMELEN);
929 926 } else {
930 927 (void) strlcpy(qinfo->qi_shortname, namep, SMB_SHORTNAMELEN);
931 928 (void) smb_strupr(qinfo->qi_shortname);
932 929 }
933 930 }
934 931
935 932 /*
936 933 * smb_query_pipeinfo
937 934 *
938 935 * Populate smb_queryinfo_t structure for SMB_FTYPE_MESG_PIPE
939 936 * (This should become an smb_opipe function.)
940 937 */
941 938 static int
942 939 smb_query_pipeinfo(smb_request_t *sr, smb_opipe_t *opipe, uint16_t infolev,
943 940 smb_queryinfo_t *qinfo)
944 941 {
945 942 char *namep = opipe->p_name;
946 943
947 944 (void) bzero(qinfo, sizeof (smb_queryinfo_t));
948 945 qinfo->qi_node = NULL;
949 946 qinfo->qi_attr.sa_vattr.va_nlink = 1;
950 947 qinfo->qi_delete_on_close = 1;
951 948 qinfo->qi_isdir = 0;
952 949
953 950 if ((infolev == SMB_INFO_STANDARD) ||
954 951 (infolev == SMB_INFO_QUERY_EA_SIZE) ||
955 952 (infolev == SMB_QUERY_INFORMATION2)) {
956 953 qinfo->qi_attr.sa_dosattr = 0;
957 954 } else {
958 955 qinfo->qi_attr.sa_dosattr = FILE_ATTRIBUTE_NORMAL;
959 956 }
960 957
961 958 /* If the leading \ is missing from the pipe name, add it. */
962 959 if (*namep != '\\')
963 960 (void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep);
964 961 else
965 962 (void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN);
966 963
967 964 qinfo->qi_namelen=
968 965 smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
969 966
970 967 return (0);
971 968 }
972 969
973 970 /*
974 971 * smb_query_pipe_valid_infolev
975 972 *
976 973 * If the infolev is not valid for a message pipe, the error
977 974 * information is set in sr and B_FALSE is returned.
978 975 * Otherwise, returns B_TRUE.
979 976 */
980 977 static boolean_t
981 978 smb_query_pipe_valid_infolev(smb_request_t *sr, uint16_t infolev)
982 979 {
983 980 switch (infolev) {
984 981 case SMB_INFO_QUERY_ALL_EAS:
985 982 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
986 983 ERRDOS, ERROR_ACCESS_DENIED);
987 984 return (B_FALSE);
988 985
989 986 case SMB_QUERY_FILE_ALT_NAME_INFO:
990 987 case SMB_FILE_ALT_NAME_INFORMATION:
991 988 case SMB_QUERY_FILE_STREAM_INFO:
992 989 case SMB_FILE_STREAM_INFORMATION:
993 990 case SMB_QUERY_FILE_COMPRESSION_INFO:
994 991 case SMB_FILE_COMPRESSION_INFORMATION:
995 992 case SMB_FILE_NETWORK_OPEN_INFORMATION:
996 993 case SMB_FILE_ATTR_TAG_INFORMATION:
997 994 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
998 995 ERRDOS, ERROR_INVALID_PARAMETER);
999 996 return (B_FALSE);
1000 997 }
1001 998
1002 999 return (B_TRUE);
1003 1000 }
|
↓ open down ↓ |
333 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX