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 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 /*
28 * This module provides functions for TRANS2_FIND_FIRST2 and
29 * TRANS2_FIND_NEXT2 requests. The requests allow the client to search
30 * for the file(s) which match the file specification. The search is
31 * started with TRANS2_FIND_FIRST2 and can be continued if necessary with
32 * TRANS2_FIND_NEXT2. There are numerous levels of information which may be
33 * obtained for the returned files, the desired level is specified in the
34 * InformationLevel field of the requests.
35 *
36 * InformationLevel Name Value
37 * ================================= ================
38 *
39 * SMB_INFO_STANDARD 1
40 * SMB_INFO_QUERY_EA_SIZE 2
41 * SMB_INFO_QUERY_EAS_FROM_LIST 3
42 * SMB_FIND_FILE_DIRECTORY_INFO 0x101
43 * SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
44 * SMB_FIND_FILE_NAMES_INFO 0x103
45 * SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
46 * SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO 0x105
47 * SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO 0x106
48 *
49 * The following sections detail the data returned for each
50 * InformationLevel. The requested information is placed in the Data
51 * portion of the transaction response. Note: a client which does not
52 * support long names can only request SMB_INFO_STANDARD.
53 *
54 * A four-byte resume key precedes each data item (described below) if bit
55 * 2 in the Flags field is set, i.e. if the request indicates the server
56 * should return resume keys. Note: it is not always the case. If the
57 * data item already includes the resume key, the resume key should not be
58 * added again.
59 *
60 * 4.3.4.1 SMB_INFO_STANDARD
61 *
62 * Response Field Description
63 * ================================ ==================================
64 *
65 * SMB_DATE CreationDate; Date when file was created
66 * SMB_TIME CreationTime; Time when file was created
67 * SMB_DATE LastAccessDate; Date of last file access
68 * SMB_TIME LastAccessTime; Time of last file access
69 * SMB_DATE LastWriteDate; Date of last write to the file
70 * SMB_TIME LastWriteTime; Time of last write to the file
71 * ULONG DataSize; File Size
72 * ULONG AllocationSize; Size of filesystem allocation unit
73 * USHORT Attributes; File Attributes
74 * UCHAR FileNameLength; Length of filename in bytes
75 * STRING FileName; Name of found file
76 *
77 * 4.3.4.2 SMB_INFO_QUERY_EA_SIZE
78 *
79 * Response Field Description
80 * ================================= ==================================
81 *
82 * SMB_DATE CreationDate; Date when file was created
83 * SMB_TIME CreationTime; Time when file was created
84 * SMB_DATE LastAccessDate; Date of last file access
85 * SMB_TIME LastAccessTime; Time of last file access
86 * SMB_DATE LastWriteDate; Date of last write to the file
87 * SMB_TIME LastWriteTime; Time of last write to the file
88 * ULONG DataSize; File Size
89 * ULONG AllocationSize; Size of filesystem allocation unit
90 * USHORT Attributes; File Attributes
91 * ULONG EaSize; Size of file's EA information
92 * UCHAR FileNameLength; Length of filename in bytes
93 * STRING FileName; Name of found file
94 *
95 * 4.3.4.3 SMB_INFO_QUERY_EAS_FROM_LIST
96 *
97 * This request returns the same information as SMB_INFO_QUERY_EA_SIZE, but
98 * only for files which have an EA list which match the EA information in
99 * the Data part of the request.
100 *
101 * 4.3.4.4 SMB_FIND_FILE_DIRECTORY_INFO
102 *
103 * Response Field Description
104 * ================================= ==================================
105 *
106 * ULONG NextEntryOffset; Offset from this structure to
107 * beginning of next one
108 * ULONG FileIndex;
109 * LARGE_INTEGER CreationTime; file creation time
110 * LARGE_INTEGER LastAccessTime; last access time
111 * LARGE_INTEGER LastWriteTime; last write time
112 * LARGE_INTEGER ChangeTime; last attribute change time
113 * LARGE_INTEGER EndOfFile; file size
114 * LARGE_INTEGER AllocationSize; size of filesystem allocation information
115 * ULONG ExtFileAttributes; Extended file attributes
116 * (see section 3.11)
117 * ULONG FileNameLength; Length of filename in bytes
118 * STRING FileName; Name of the file
119 *
120 * 4.3.4.5 SMB_FIND_FILE_FULL_DIRECTORY_INFO
121 *
122 * Response Field Description
123 * ================================= ==================================
124 *
125 * ULONG NextEntryOffset; Offset from this structure to
126 * beginning of next one
127 * ULONG FileIndex;
128 * LARGE_INTEGER CreationTime; file creation time
129 * LARGE_INTEGER LastAccessTime; last access time
130 * LARGE_INTEGER LastWriteTime; last write time
131 * LARGE_INTEGER ChangeTime; last attribute change time
132 * LARGE_INTEGER EndOfFile; file size
133 * LARGE_INTEGER AllocationSize; size of filesystem allocation information
134 * ULONG ExtFileAttributes; Extended file attributes
135 * (see section 3.11)
136 * ULONG FileNameLength; Length of filename in bytes
137 * ULONG EaSize; Size of file's extended attributes
138 * STRING FileName; Name of the file
139 *
140 *
141 * SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO
142 *
143 * This is the same as SMB_FIND_FILE_FULL_DIRECTORY_INFO but with
144 * FileId inserted after EaSize. FileId is preceded by a 4 byte
145 * alignment padding.
146 *
147 * Response Field Description
148 * ================================= ==================================
149 * ...
150 * ULONG EaSize; Size of file's extended attributes
151 * UCHAR Reserved[4]
152 * LARGE_INTEGER FileId Internal file system unique id.
153 * STRING FileName; Name of the file
154 *
155 * 4.3.4.6 SMB_FIND_FILE_BOTH_DIRECTORY_INFO
156 *
157 * Response Field Description
158 * ================================= ==================================
159 *
160 * ULONG NextEntryOffset; Offset from this structure to
161 * beginning of next one
162 * ULONG FileIndex;
163 * LARGE_INTEGER CreationTime; file creation time
164 * LARGE_INTEGER LastAccessTime; last access time
165 * LARGE_INTEGER LastWriteTime; last write time
166 * LARGE_INTEGER ChangeTime; last attribute change time
167 * LARGE_INTEGER EndOfFile; file size
168 * LARGE_INTEGER AllocationSize; size of filesystem allocation information
169 * ULONG ExtFileAttributes; Extended file attributes
170 * (see section 3.11)
171 * ULONG FileNameLength; Length of FileName in bytes
172 * ULONG EaSize; Size of file's extended attributes
173 * UCHAR ShortNameLength; Length of file's short name in bytes
174 * UCHAR Reserved
175 * WCHAR ShortName[12]; File's 8.3 conformant name in Unicode
176 * STRING FileName; Files full length name
177 *
178 *
179 * SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO
180 *
181 * This is the same as SMB_FIND_FILE_BOTH_DIRECTORY_INFO but with
182 * FileId inserted after ShortName. FileId is preceded by a 2 byte
183 * alignment pad.
184 *
185 * Response Field Description
186 * ================================= ==================================
187 * ...
188 * WCHAR ShortName[12]; File's 8.3 conformant name in Unicode
189 * UCHAR Reserved[2]
190 * LARGE_INTEGER FileId Internal file system unique id.
191 * STRING FileName; Files full length name
192 *
193 * 4.3.4.7 SMB_FIND_FILE_NAMES_INFO
194 *
195 * Response Field Description
196 * ================================= ==================================
197 *
198 * ULONG NextEntryOffset; Offset from this structure to
199 * beginning of next one
200 * ULONG FileIndex;
201 * ULONG FileNameLength; Length of FileName in bytes
202 * STRING FileName; Files full length name
203 */
204
205 #include <smbsrv/smb_kproto.h>
206 #include <smbsrv/msgbuf.h>
207 #include <smbsrv/smb_fsops.h>
208
209 typedef struct smb_find_args {
210 uint16_t fa_infolev;
211 uint16_t fa_maxcount;
212 uint16_t fa_fflag;
213 uint32_t fa_maxdata;
214 } smb_find_args_t;
215
216 static int smb_trans2_find_entries(smb_request_t *, smb_xa_t *,
217 smb_odir_t *, smb_find_args_t *, boolean_t *);
218 static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t);
219 static int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *,
220 smb_fileinfo_t *, smb_find_args_t *);
221
222 /*
223 * Tunable parameter to limit the maximum
224 * number of entries to be returned.
225 */
226 uint16_t smb_trans2_find_max = 128;
227
228 /*
229 * smb_com_trans2_find_first2
230 *
231 * Client Request Value
232 * ============================ ==================================
233 *
234 * UCHAR WordCount 15
235 * UCHAR TotalDataCount Total size of extended attribute list
236 * UCHAR SetupCount 1
237 * UCHAR Setup[0] TRANS2_FIND_FIRST2
238 *
239 * Parameter Block Encoding Description
240 * ============================ ==================================
241 * USHORT SearchAttributes;
242 * USHORT SearchCount; Maximum number of entries to return
243 * USHORT Flags; Additional information:
244 * Bit 0 - close search after this request
245 * Bit 1 - close search if end of search
246 * reached
247 * Bit 2 - return resume keys for each
248 * entry found
249 * Bit 3 - continue search from previous
250 * ending place
251 * Bit 4 - find with backup intent
252 * USHORT InformationLevel; See below
253 * ULONG SearchStorageType;
254 * STRING FileName; Pattern for the search
255 * UCHAR Data[ TotalDataCount ] FEAList if InformationLevel is
256 * QUERY_EAS_FROM_LIST
257 *
258 * Response Parameter Block Description
259 * ============================ ==================================
260 *
261 * USHORT Sid; Search handle
262 * USHORT SearchCount; Number of entries returned
263 * USHORT EndOfSearch; Was last entry returned?
264 * USHORT EaErrorOffset; Offset into EA list if EA error
265 * USHORT LastNameOffset; Offset into data to file name of last
266 * entry, if server needs it to resume
267 * search; else 0
268 * UCHAR Data[ TotalDataCount ] Level dependent info about the matches
269 * found in the search
270 */
271 smb_sdrc_t
smb_com_trans2_find_first2(smb_request_t * sr,smb_xa_t * xa)272 smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa)
273 {
274 int count;
275 uint16_t sattr, odid;
276 smb_pathname_t *pn;
277 smb_odir_t *od;
278 smb_find_args_t args;
279 boolean_t eos;
280 uint32_t odir_flags = 0;
281
282 bzero(&args, sizeof (smb_find_args_t));
283
284 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
285 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
286 ERRDOS, ERROR_ACCESS_DENIED);
287 return (SDRC_ERROR);
288 }
289
290 pn = &sr->arg.dirop.fqi.fq_path;
291
292 if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr,
293 &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev,
294 &pn->pn_path) != 0) {
295 return (SDRC_ERROR);
296 }
297
298 smb_pathname_init(sr, pn, pn->pn_path);
299 if (!smb_pathname_validate(sr, pn))
300 return (-1);
301
302 if (smb_is_stream_name(pn->pn_path)) {
303 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
304 ERRDOS, ERROR_INVALID_NAME);
305 return (SDRC_ERROR);
306 }
307
308 if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) {
309 sr->user_cr = smb_user_getprivcred(sr->uid_user);
310 odir_flags = SMB_ODIR_OPENF_BACKUP_INTENT;
311 }
312
313 args.fa_maxdata =
314 smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
315 if (args.fa_maxdata == 0)
316 return (SDRC_ERROR);
317
318 odid = smb_odir_open(sr, pn->pn_path, sattr, odir_flags);
319 if (odid == 0) {
320 if (sr->smb_error.status == NT_STATUS_OBJECT_PATH_NOT_FOUND) {
321 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
322 ERRDOS, ERROR_FILE_NOT_FOUND);
323 }
324 return (SDRC_ERROR);
325 }
326
327 od = smb_tree_lookup_odir(sr->tid_tree, odid);
328 if (od == NULL)
329 return (SDRC_ERROR);
330 count = smb_trans2_find_entries(sr, xa, od, &args, &eos);
331
332 if (count == -1) {
333 smb_odir_close(od);
334 smb_odir_release(od);
335 return (SDRC_ERROR);
336 }
337
338 if (count == 0) {
339 smb_odir_close(od);
340 smb_odir_release(od);
341 smbsr_errno(sr, ENOENT);
342 return (SDRC_ERROR);
343 }
344
345 if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
346 (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
347 smb_odir_close(od);
348 } /* else leave odir open for trans2_find_next2 */
349
350 smb_odir_release(od);
351
352 (void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww",
353 odid, count, (eos) ? 1 : 0, 0, 0);
354
355 return (SDRC_SUCCESS);
356 }
357
358 /*
359 * smb_com_trans2_find_next2
360 *
361 * Client Request Value
362 * ================================== =================================
363 *
364 * WordCount 15
365 * SetupCount 1
366 * Setup[0] TRANS2_FIND_NEXT2
367 *
368 * Parameter Block Encoding Description
369 * ================================== =================================
370 *
371 * USHORT Sid; Search handle
372 * USHORT SearchCount; Maximum number of entries to
373 * return
374 * USHORT InformationLevel; Levels described in
375 * TRANS2_FIND_FIRST2 request
376 * ULONG ResumeKey; Value returned by previous find2
377 * call
378 * USHORT Flags; Additional information: bit set-
379 * 0 - close search after this
380 * request
381 * 1 - close search if end of search
382 * reached
383 * 2 - return resume keys for each
384 * entry found
385 * 3 - resume/continue from previous
386 * ending place
387 * 4 - find with backup intent
388 * STRING FileName; Resume file name
389 *
390 * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2
391 * call. If Bit3 of Flags is set, then FileName may be the NULL string,
392 * since the search is continued from the previous TRANS2_FIND request.
393 * Otherwise, FileName must not be more than 256 characters long.
394 *
395 * Response Field Description
396 * ================================== =================================
397 *
398 * USHORT SearchCount; Number of entries returned
399 * USHORT EndOfSearch; Was last entry returned?
400 * USHORT EaErrorOffset; Offset into EA list if EA error
401 * USHORT LastNameOffset; Offset into data to file name of
402 * last entry, if server needs it to
403 * resume search; else 0
404 * UCHAR Data[TotalDataCount] Level dependent info about the
405 * matches found in the search
406 *
407 *
408 * The last parameter in the request is a filename, which is a
409 * null-terminated unicode string.
410 *
411 * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr,
412 * &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname)
413 *
414 * The filename parameter is not currently decoded because we
415 * expect a 2-byte null but Mac OS 10 clients send a 1-byte null,
416 * which leads to a decode error.
417 * Thus, we do not support resume by filename. We treat a request
418 * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST.
419 */
420 smb_sdrc_t
smb_com_trans2_find_next2(smb_request_t * sr,smb_xa_t * xa)421 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa)
422 {
423 int count;
424 uint16_t odid;
425 uint32_t cookie;
426 smb_odir_t *od;
427 smb_find_args_t args;
428 boolean_t eos;
429 smb_odir_resume_t odir_resume;
430
431 bzero(&args, sizeof (smb_find_args_t));
432
433 if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlw", sr, &odid,
434 &args.fa_maxcount, &args.fa_infolev, &cookie, &args.fa_fflag)
435 != 0) {
436 return (SDRC_ERROR);
437 }
438
439 /* continuation by filename not supported */
440 if ((args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) || (cookie == 0)) {
441 odir_resume.or_type = SMB_ODIR_RESUME_IDX;
442 odir_resume.or_idx = 0;
443 } else {
444 odir_resume.or_type = SMB_ODIR_RESUME_COOKIE;
445 odir_resume.or_cookie = cookie;
446 }
447
448 if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT)
449 sr->user_cr = smb_user_getprivcred(sr->uid_user);
450
451 args.fa_maxdata =
452 smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
453 if (args.fa_maxdata == 0)
454 return (SDRC_ERROR);
455
456 od = smb_tree_lookup_odir(sr->tid_tree, odid);
457 if (od == NULL) {
458 smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
459 ERRDOS, ERROR_INVALID_HANDLE);
460 return (SDRC_ERROR);
461 }
462 smb_odir_resume_at(od, &odir_resume);
463 count = smb_trans2_find_entries(sr, xa, od, &args, &eos);
464
465 if (count == -1) {
466 smb_odir_close(od);
467 smb_odir_release(od);
468 return (SDRC_ERROR);
469 }
470
471 if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
472 (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
473 smb_odir_close(od);
474 } /* else leave odir open for trans2_find_next2 */
475
476 smb_odir_release(od);
477 (void) smb_mbc_encodef(&xa->rep_param_mb, "wwww",
478 count, (eos) ? 1 : 0, 0, 0);
479
480 return (SDRC_SUCCESS);
481 }
482
483
484 /*
485 * smb_trans2_find_entries
486 *
487 * Find and encode up to args->fa_maxcount directory entries.
488 * For compatibilty with Windows, if args->fa_maxcount is zero treat it as 1.
489 *
490 * Returns:
491 * count - count of entries encoded
492 * *eos = B_TRUE if no more directory entries
493 * -1 - error
494 */
495 static int
smb_trans2_find_entries(smb_request_t * sr,smb_xa_t * xa,smb_odir_t * od,smb_find_args_t * args,boolean_t * eos)496 smb_trans2_find_entries(smb_request_t *sr, smb_xa_t *xa, smb_odir_t *od,
497 smb_find_args_t *args, boolean_t *eos)
498 {
499 int rc;
500 uint16_t count, maxcount;
501 uint32_t cookie;
502 smb_fileinfo_t fileinfo;
503
504 if ((maxcount = args->fa_maxcount) == 0)
505 maxcount = 1;
506
507 if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
508 maxcount = smb_trans2_find_max;
509
510 count = 0;
511 while (count < maxcount) {
512 if (smb_odir_read_fileinfo(sr, od, &fileinfo, eos) != 0)
513 return (-1);
514 if (*eos == B_TRUE)
515 break;
516
517 rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args);
518 if (rc == -1)
519 return (-1);
520 if (rc == 1)
521 break;
522
523 cookie = fileinfo.fi_cookie;
524 ++count;
525 }
526
527 /* save the last cookie returned to client */
528 if (count != 0)
529 smb_odir_save_cookie(od, 0, cookie);
530
531 /*
532 * If all retrieved entries have been successfully encoded
533 * and eos has not already been detected, check if there are
534 * any more entries. eos will be set if there are no more.
535 */
536 if ((rc == 0) && (!*eos))
537 (void) smb_odir_read_fileinfo(sr, od, &fileinfo, eos);
538
539 return (count);
540 }
541
542 /*
543 * smb_trans2_find_get_maxdata
544 *
545 * Calculate the minimum response space required for the specified
546 * information level.
547 *
548 * A non-zero return value provides the minimum space required.
549 * A return value of zero indicates an unknown information level.
550 */
551 static int
smb_trans2_find_get_maxdata(smb_request_t * sr,uint16_t infolev,uint16_t fflag)552 smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag)
553 {
554 int maxdata;
555
556 maxdata = smb_ascii_or_unicode_null_len(sr);
557
558 switch (infolev) {
559 case SMB_INFO_STANDARD :
560 if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
561 maxdata += sizeof (int32_t);
562 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 1;
563 break;
564
565 case SMB_INFO_QUERY_EA_SIZE:
566 if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
567 maxdata += sizeof (int32_t);
568 maxdata += 2 + 2 + 2 + 4 + 4 + 2 + 4 + 1;
569 break;
570
571 case SMB_FIND_FILE_DIRECTORY_INFO:
572 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4;
573 break;
574
575 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
576 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4;
577 break;
578
579 case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
580 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 8;
581 break;
582
583 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
584 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24;
585 break;
586
587 case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
588 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24
589 + 2 + 8;
590 break;
591
592 case SMB_FIND_FILE_NAMES_INFO:
593 maxdata += 4 + 4 + 4;
594 break;
595
596 case SMB_MAC_FIND_BOTH_HFS_INFO:
597 maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 1 + 1 + 2 +
598 4 + 32 + 4 + 1 + 1 + 24 + 4;
599 break;
600
601 default:
602 maxdata = 0;
603 smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
604 ERRDOS, ERROR_INVALID_LEVEL);
605 }
606
607 return (maxdata);
608 }
609
610 /*
611 * smb_trans2_mbc_encode
612 *
613 * This function encodes the mbc for one directory entry.
614 *
615 * The function returns -1 when the max data requested by client
616 * is reached. If the entry is valid and successful encoded, 0
617 * will be returned; otherwise, 1 will be returned.
618 *
619 * We always null terminate the filename. The space for the null
620 * is included in the maxdata calculation and is therefore included
621 * in the next_entry_offset. namelen is the unterminated length of
622 * the filename. For levels except STANDARD and EA_SIZE, if the
623 * filename is ascii the name length returned to the client should
624 * include the null terminator. Otherwise the length returned to
625 * the client should not include the terminator.
626 *
627 * Returns: 0 - data successfully encoded
628 * 1 - client request's maxdata limit reached
629 * -1 - error
630 */
631 static int
smb_trans2_find_mbc_encode(smb_request_t * sr,smb_xa_t * xa,smb_fileinfo_t * fileinfo,smb_find_args_t * args)632 smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
633 smb_fileinfo_t *fileinfo, smb_find_args_t *args)
634 {
635 int namelen, shortlen, buflen;
636 uint32_t next_entry_offset;
637 uint32_t dsize32, asize32;
638 uint32_t mb_flags = 0;
639 char buf83[26];
640 char *tmpbuf;
641 smb_msgbuf_t mb;
642
643 namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name);
644 if (namelen == -1)
645 return (-1);
646
647 next_entry_offset = args->fa_maxdata + namelen;
648
649 if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0)
650 return (1);
651
652 /*
653 * If ascii the filename length returned to the client should
654 * include the null terminator for levels except STANDARD and
655 * EASIZE.
656 */
657 if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
658 if ((args->fa_infolev != SMB_INFO_STANDARD) &&
659 (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE))
660 namelen += 1;
661 }
662
663 mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0;
664 dsize32 = (fileinfo->fi_size > UINT_MAX) ?
665 UINT_MAX : (uint32_t)fileinfo->fi_size;
666 asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ?
667 UINT_MAX : (uint32_t)fileinfo->fi_alloc_size;
668
669 switch (args->fa_infolev) {
670 case SMB_INFO_STANDARD:
671 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
672 (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
673 fileinfo->fi_cookie);
674
675 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr,
676 smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
677 smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
678 smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
679 dsize32,
680 asize32,
681 fileinfo->fi_dosattr,
682 namelen,
683 fileinfo->fi_name);
684 break;
685
686 case SMB_INFO_QUERY_EA_SIZE:
687 if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
688 (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
689 fileinfo->fi_cookie);
690
691 /*
692 * Unicode filename should NOT be aligned. Encode ('u')
693 * into a temporary buffer, then encode buffer as a
694 * byte stream ('#c').
695 * Regardless of whether unicode or ascii, a single
696 * termination byte is used.
697 */
698 buflen = namelen + sizeof (smb_wchar_t);
699 tmpbuf = kmem_zalloc(buflen, KM_SLEEP);
700 smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen, mb_flags);
701 if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_name) < 0) {
702 smb_msgbuf_term(&mb);
703 kmem_free(tmpbuf, buflen);
704 return (-1);
705 }
706 tmpbuf[namelen] = '\0';
707
708 (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr,
709 smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
710 smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
711 smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
712 dsize32,
713 asize32,
714 fileinfo->fi_dosattr,
715 0L, /* EA Size */
716 namelen,
717 namelen + 1,
718 tmpbuf);
719
720 smb_msgbuf_term(&mb);
721 kmem_free(tmpbuf, buflen);
722 break;
723
724 case SMB_FIND_FILE_DIRECTORY_INFO:
725 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqllu", sr,
726 next_entry_offset,
727 fileinfo->fi_cookie,
728 &fileinfo->fi_crtime,
729 &fileinfo->fi_atime,
730 &fileinfo->fi_mtime,
731 &fileinfo->fi_ctime,
732 fileinfo->fi_size,
733 fileinfo->fi_alloc_size,
734 fileinfo->fi_dosattr,
735 namelen,
736 fileinfo->fi_name);
737 break;
738
739 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
740 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllu", sr,
741 next_entry_offset,
742 fileinfo->fi_cookie,
743 &fileinfo->fi_crtime,
744 &fileinfo->fi_atime,
745 &fileinfo->fi_mtime,
746 &fileinfo->fi_ctime,
747 fileinfo->fi_size,
748 fileinfo->fi_alloc_size,
749 fileinfo->fi_dosattr,
750 namelen,
751 0L,
752 fileinfo->fi_name);
753 break;
754
755 case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
756 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.qu", sr,
757 next_entry_offset,
758 fileinfo->fi_cookie,
759 &fileinfo->fi_crtime,
760 &fileinfo->fi_atime,
761 &fileinfo->fi_mtime,
762 &fileinfo->fi_ctime,
763 fileinfo->fi_size,
764 fileinfo->fi_alloc_size,
765 fileinfo->fi_dosattr,
766 namelen,
767 0L,
768 fileinfo->fi_nodeid,
769 fileinfo->fi_name);
770 break;
771
772 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
773 bzero(buf83, sizeof (buf83));
774 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
775 mb_flags);
776 if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) {
777 smb_msgbuf_term(&mb);
778 return (-1);
779 }
780 shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname);
781
782 (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24cu",
783 sr,
784 next_entry_offset,
785 fileinfo->fi_cookie,
786 &fileinfo->fi_crtime,
787 &fileinfo->fi_atime,
788 &fileinfo->fi_mtime,
789 &fileinfo->fi_ctime,
790 fileinfo->fi_size,
791 fileinfo->fi_alloc_size,
792 fileinfo->fi_dosattr,
793 namelen,
794 0L,
795 shortlen,
796 buf83,
797 fileinfo->fi_name);
798
799 smb_msgbuf_term(&mb);
800 break;
801
802 case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
803 bzero(buf83, sizeof (buf83));
804 smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
805 mb_flags);
806 if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) {
807 smb_msgbuf_term(&mb);
808 return (-1);
809 }
810 shortlen = smb_ascii_or_unicode_strlen(sr,
811 fileinfo->fi_shortname);
812
813 (void) smb_mbc_encodef(&xa->rep_data_mb,
814 "%llTTTTqqlllb.24c2.qu",
815 sr,
816 next_entry_offset,
817 fileinfo->fi_cookie,
818 &fileinfo->fi_crtime,
819 &fileinfo->fi_atime,
820 &fileinfo->fi_mtime,
821 &fileinfo->fi_ctime,
822 fileinfo->fi_size,
823 fileinfo->fi_alloc_size,
824 fileinfo->fi_dosattr,
825 namelen,
826 0L,
827 shortlen,
828 buf83,
829 fileinfo->fi_nodeid,
830 fileinfo->fi_name);
831
832 smb_msgbuf_term(&mb);
833 break;
834
835 case SMB_FIND_FILE_NAMES_INFO:
836 (void) smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr,
837 next_entry_offset,
838 fileinfo->fi_cookie,
839 namelen,
840 fileinfo->fi_name);
841 break;
842 }
843
844 return (0);
845 }
846
847 /*
848 * Close a search started by a Trans2FindFirst2 request.
849 */
850 smb_sdrc_t
smb_pre_find_close2(smb_request_t * sr)851 smb_pre_find_close2(smb_request_t *sr)
852 {
853 DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr);
854 return (SDRC_SUCCESS);
855 }
856
857 void
smb_post_find_close2(smb_request_t * sr)858 smb_post_find_close2(smb_request_t *sr)
859 {
860 DTRACE_SMB_1(op__FindClose2__done, smb_request_t *, sr);
861 }
862
863 smb_sdrc_t
smb_com_find_close2(smb_request_t * sr)864 smb_com_find_close2(smb_request_t *sr)
865 {
866 uint16_t odid;
867 smb_odir_t *od;
868
869 if (smbsr_decode_vwv(sr, "w", &odid) != 0)
870 return (SDRC_ERROR);
871
872 od = smb_tree_lookup_odir(sr->tid_tree, odid);
873 if (od == NULL) {
874 smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
875 ERRDOS, ERROR_INVALID_HANDLE);
876 return (SDRC_ERROR);
877 }
878
879 smb_odir_close(od);
880 smb_odir_release(od);
881
882 if (smbsr_encode_empty_result(sr))
883 return (SDRC_ERROR);
884
885 return (SDRC_SUCCESS);
886 }
887