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