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