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