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