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