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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 /*
27 * General Structures Layout
28 * -------------------------
29 *
30 * This is a simplified diagram showing the relationship between most of the
31 * main structures.
32 *
33 * +-------------------+
34 * | SMB_INFO |
35 * +-------------------+
36 * |
37 * |
38 * v
39 * +-------------------+ +-------------------+ +-------------------+
40 * | SESSION |<----->| SESSION |......| SESSION |
41 * +-------------------+ +-------------------+ +-------------------+
42 * | |
43 * | |
44 * | v
45 * | +-------------------+ +-------------------+ +-------------------+
46 * | | USER |<--->| USER |...| USER |
47 * | +-------------------+ +-------------------+ +-------------------+
48 * |
49 * |
50 * v
51 * +-------------------+ +-------------------+ +-------------------+
52 * | TREE |<----->| TREE |......| TREE |
53 * +-------------------+ +-------------------+ +-------------------+
54 * | |
55 * | |
56 * | v
57 * | +-------+ +-------+ +-------+
58 * | | OFILE |<----->| OFILE |......| OFILE |
59 * | +-------+ +-------+ +-------+
60 * |
61 * |
62 * v
63 * +-------+ +------+ +------+
64 * | ODIR |<----->| ODIR |......| ODIR |
65 * +-------+ +------+ +------+
66 *
67 *
68 * Odir State Machine
69 * ------------------
70 *
71 * +-------------------------+
72 * | SMB_ODIR_STATE_OPEN |<----------- open / creation
73 * +-------------------------+
74 * | ^
75 * | (first) | (last)
76 * | lookup | release
77 * v |
78 * +-------------------------+
79 * | SMB_ODIR_STATE_IN_USE |----
80 * +-------------------------+ | lookup / release / read
81 * | ^-------
82 * | close
83 * |
84 * v
85 * +-------------------------+
86 * | SMB_ODIR_STATE_CLOSING |----
87 * +-------------------------+ | close / release / read
88 * | ^-------
89 * | (last) release
90 * |
91 * v
92 * +-------------------------+
93 * | SMB_ODIR_STATE_CLOSED |----------> deletion
94 * +-------------------------+
95 *
96 *
97 * SMB_ODIR_STATE_OPEN
98 * - the odir exists in the list of odirs of its tree
99 * - lookup is valid in this state. It will place a hold on the odir
100 * by incrementing the reference count and the odir will transition
101 * to SMB_ODIR_STATE_IN_USE
102 * - read/close/release not valid in this state
103 *
104 * SMB_ODIR_STATE_IN_USE
105 * - the odir exists in the list of odirs of its tree.
106 * - lookup is valid in this state. It will place a hold on the odir
107 * by incrementing the reference count.
108 * - if the last hold is released the odir will transition
109 * back to SMB_ODIR_STATE_OPEN
110 * - if a close is received the odir will transition to
111 * SMB_ODIR_STATE_CLOSING.
112 *
113 * SMB_ODIR_STATE_CLOSING
114 * - the odir exists in the list of odirs of its tree.
115 * - lookup will fail in this state.
116 * - when the last hold is released the odir will transition
117 * to SMB_ODIR_STATE_CLOSED.
118 *
119 * SMB_ODIR_STATE_CLOSED
120 * - the odir exists in the list of odirs of its tree.
121 * - there are no users of the odir (refcnt == 0)
122 * - the odir is being removed from the tree's list and deleted.
123 * - lookup will fail in this state.
124 * - read/close/release not valid in this state
125 *
126 * Comments
127 * --------
128 * The state machine of the odir structures is controlled by 3 elements:
129 * - The list of odirs of the tree it belongs to.
130 * - The mutex embedded in the structure itself.
131 * - The reference count.
132 *
133 * There's a mutex embedded in the odir structure used to protect its fields
134 * and there's a lock embedded in the list of odirs of a tree. To
135 * increment or to decrement the reference count the mutex must be entered.
136 * To insert the odir into the list of odirs of the tree and to remove
137 * the odir from it, the lock must be entered in RW_WRITER mode.
138 *
139 * In order to avoid deadlocks, when both (mutex and lock of the odir
140 * list) have to be entered, the lock must be entered first.
141 *
142 *
143 * Odir Interface
144 * ---------------
145 * odid = smb_odir_open(pathname)
146 * Create an odir representing the directory specified in pathname and
147 * add it into the tree's list of odirs.
148 * Return an identifier (odid) uniquely identifying the created odir.
149 *
150 * smb_odir_openat(smb_node_t *unode)
151 * Create an odir representing the extended attribute directory
152 * associated with the file (or directory) represented by unode
153 * and add it into the tree's list of odirs.
154 * Return an identifier (odid) uniquely identifying the created odir.
155 *
156 * smb_odir_t *odir = smb_tree_lookup_odir(..., odid)
157 * Find the odir corresponding to the specified odid in the tree's
158 * list of odirs. Place a hold on the odir.
159 *
160 * smb_odir_read(..., smb_odirent_t *odirent)
161 * Find the next directory entry in the odir and return it in odirent.
162 *
163 * smb_odir_read_fileinfo(..., smb_fileinfo_t *)
164 * Find the next directory entry in the odir. Return the details of
165 * the directory entry in smb_fileinfo_t. (See odir internals below)
166 *
167 * smb_odir_read_streaminfo(..., smb_streaminfo_t *)
168 * Find the next named stream entry in the odir. Return the details of
169 * the named stream in smb_streaminfo_t.
170 *
171 * smb_odir_close(smb_odir_t *odir)
172 * Close the odir.
173 * The caller of close must have a hold on the odir being closed.
174 * The hold should be released after closing.
175 *
176 * smb_odir_release(smb_odir_t *odir)
177 * Release the hold on the odir, obtained by lookup.
178 *
179 *
180 * Odir Internals
181 * --------------
182 * The odir object represent an open directory search. Each read operation
183 * provides the caller with a structure containing information pertaining
184 * to the next directory entry that matches the search criteria, namely
185 * the filename or match pattern and, in the case of smb_odir_read_fileinfo(),
186 * the search attributes.
187 *
188 * The odir maintains a buffer (d_buf) of directory entries read from
189 * the filesystem via a vop_readdir. The buffer is populated when a read
190 * request (smb_odir_next_odirent) finds that the buffer is empty or that
191 * the end of the buffer has been reached, and also when a new client request
192 * (find next) begins.
193 *
194 * The data in d_buf (that which is returned from the file system) can
195 * be in one of two formats. If the file system supports extended directory
196 * entries we request that the data be returned as edirent_t structures. If
197 * it does not the data will be returned as dirent64_t structures. For
198 * convenience, when the next directory entry is read from d_buf by
199 * smb_odir_next_odirent it is translated into an smb_odirent_t.
200 *
201 * smb_odir_read_fileinfo
202 * The processing required to obtain the information to populate the caller's
203 * smb_fileinfo_t differs depending upon whether the directory search is for a
204 * single specified filename or for multiple files matching a search pattern.
205 * Thus smb_odir_read_fileinfo uses two static functions:
206 * smb_odir_single_fileinfo - obtains the smb_fileinfo_t info for the single
207 * filename as specified in smb_odir_open request.
208 * smb_odir_wildcard_fileinfo - obtains the smb_fileinfo_t info for the filename
209 * returned from the smb_odir_next_odirent. This is called in a loop until
210 * an entry matching the search criteria is found or no more entries exist.
211 *
212 * If a directory entry is a VLNK, the name returned in the smb_fileinfo_t
213 * is the name of the directory entry but the attributes are the attribites
214 * of the file that is the target of the link. If the link target cannot
215 * be found the attributes returned are the attributes of the link itself.
216 *
217 * smb_odir_read_streaminfo
218 * In order for an odir to provide information about stream files it
219 * must be opened with smb_odir_openat(). smb_odir_read_streaminfo() can
220 * then be used to obtain the name and size of named stream files.
221 *
222 * Resuming a Search
223 * -----------------
224 * A directory search often consists of multiple client requests: an initial
225 * find_first request followed by zero or more find_next requests and a
226 * find_close request.
227 * The find_first request will open and lookup the odir, read its desired
228 * number of entries from the odir, then release the odir and return.
229 * A find_next request will lookup the odir and read its desired number of
230 * entries from the odir, then release the odir and return.
231 * At the end of the search the find_close request will close the odir.
232 *
233 * In order to be able to resume a directory search (find_next) the odir
234 * provides the capability for the caller to save one or more resume points
235 * (cookies) at the end of a request, and to specify which resume point
236 * (cookie) to restart from at the beginning of the next search.
237 * smb_odir_save_cookie(..., cookie)
238 * smb_odir_resume_at(smb_odir_resume_t *resume)
239 * A search can be resumed at a specified resume point (cookie), the resume
240 * point (cookie) stored at a specified index in the d_cookies array, or
241 * a specified filename. The latter (specified filename) is not yet supported.
242 *
243 * See smb_search, smb_find, smb_find_unique, and smb_trans2_find for details
244 */
245
246 #include <smbsrv/smb_kproto.h>
247 #include <smbsrv/smb_fsops.h>
248 #include <smbsrv/smb_share.h>
249 #include <sys/extdirent.h>
250
251 /* static functions */
252 static uint16_t smb_odir_create(smb_request_t *, smb_node_t *,
253 char *, uint16_t, cred_t *);
254 static int smb_odir_single_fileinfo(smb_request_t *, smb_odir_t *,
255 smb_fileinfo_t *);
256 static int smb_odir_wildcard_fileinfo(smb_request_t *, smb_odir_t *,
257 smb_odirent_t *, smb_fileinfo_t *);
258 static int smb_odir_next_odirent(smb_odir_t *, smb_odirent_t *);
259 static boolean_t smb_odir_lookup_link(smb_request_t *, smb_odir_t *,
260 char *, smb_node_t **);
261 static boolean_t smb_odir_match_name(smb_odir_t *, smb_odirent_t *);
262
263
264 /*
265 * smb_odir_open
266 *
267 * Create an odir representing the directory specified in pathname.
268 *
269 * Returns:
270 * odid - Unique identifier of newly created odir.
271 * 0 - error, error details set in sr.
272 */
273 uint16_t
smb_odir_open(smb_request_t * sr,char * path,uint16_t sattr,uint32_t flags)274 smb_odir_open(smb_request_t *sr, char *path, uint16_t sattr, uint32_t flags)
275 {
276 int rc;
277 smb_tree_t *tree;
278 smb_node_t *dnode;
279 char pattern[MAXNAMELEN];
280 uint16_t odid;
281 cred_t *cr;
282
283 ASSERT(sr);
284 ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
285 ASSERT(sr->tid_tree);
286 ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC);
287
288 tree = sr->tid_tree;
289
290 if (sr->session->dialect < NT_LM_0_12)
291 smb_convert_wildcards(path);
292
293 rc = smb_pathname_reduce(sr, sr->user_cr, path,
294 tree->t_snode, tree->t_snode, &dnode, pattern);
295 if (rc != 0) {
296 smbsr_errno(sr, rc);
297 return (0);
298 }
299
300 if (!smb_node_is_dir(dnode)) {
301 smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND,
302 ERRDOS, ERROR_PATH_NOT_FOUND);
303 smb_node_release(dnode);
304 return (0);
305 }
306
307 if (smb_fsop_access(sr, sr->user_cr, dnode, FILE_LIST_DIRECTORY) != 0) {
308 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
309 ERRDOS, ERROR_ACCESS_DENIED);
310 smb_node_release(dnode);
311 return (0);
312 }
313
314 if (flags & SMB_ODIR_OPENF_BACKUP_INTENT)
315 cr = smb_user_getprivcred(sr->uid_user);
316 else
317 cr = sr->uid_user->u_cred;
318
319 odid = smb_odir_create(sr, dnode, pattern, sattr, cr);
320 smb_node_release(dnode);
321 return (odid);
322 }
323
324 /*
325 * smb_odir_openat
326 *
327 * Create an odir representing the extended attribute directory
328 * associated with the file (or directory) represented by unode.
329 *
330 * Returns:
331 * odid - Unique identifier of newly created odir.
332 * 0 - error, error details set in sr.
333 */
334 uint16_t
smb_odir_openat(smb_request_t * sr,smb_node_t * unode)335 smb_odir_openat(smb_request_t *sr, smb_node_t *unode)
336 {
337 int rc;
338 vnode_t *xattr_dvp;
339 uint16_t odid;
340 cred_t *cr;
341 char pattern[SMB_STREAM_PREFIX_LEN + 2];
342
343 smb_node_t *xattr_dnode;
344
345 ASSERT(sr);
346 ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
347 ASSERT(unode);
348 ASSERT(unode->n_magic == SMB_NODE_MAGIC);
349
350 if (SMB_TREE_CONTAINS_NODE(sr, unode) == 0 ||
351 SMB_TREE_HAS_ACCESS(sr, ACE_LIST_DIRECTORY) == 0) {
352 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
353 ERRDOS, ERROR_ACCESS_DENIED);
354 return (0);
355 }
356 cr = zone_kcred();
357
358 /* find the xattrdir vnode */
359 rc = smb_vop_lookup_xattrdir(unode->vp, &xattr_dvp, LOOKUP_XATTR, cr);
360 if (rc != 0) {
361 smbsr_errno(sr, rc);
362 return (0);
363 }
364
365 /* lookup the xattrdir's smb_node */
366 xattr_dnode = smb_node_lookup(sr, NULL, cr, xattr_dvp, XATTR_DIR,
367 unode, NULL);
368 VN_RELE(xattr_dvp);
369 if (xattr_dnode == NULL) {
370 smbsr_error(sr, NT_STATUS_NO_MEMORY,
371 ERRDOS, ERROR_NOT_ENOUGH_MEMORY);
372 return (0);
373 }
374
375 (void) snprintf(pattern, sizeof (pattern), "%s*", SMB_STREAM_PREFIX);
376 odid = smb_odir_create(sr, xattr_dnode, pattern, SMB_SEARCH_ATTRIBUTES,
377 cr);
378 smb_node_release(xattr_dnode);
379 return (odid);
380 }
381
382 /*
383 * smb_odir_hold
384 *
385 * A hold will only be granted if the odir is open or in_use.
386 */
387 boolean_t
smb_odir_hold(smb_odir_t * od)388 smb_odir_hold(smb_odir_t *od)
389 {
390 ASSERT(od);
391 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
392
393 mutex_enter(&od->d_mutex);
394
395 switch (od->d_state) {
396 case SMB_ODIR_STATE_OPEN:
397 od->d_refcnt++;
398 od->d_state = SMB_ODIR_STATE_IN_USE;
399 break;
400 case SMB_ODIR_STATE_IN_USE:
401 od->d_refcnt++;
402 break;
403 case SMB_ODIR_STATE_CLOSING:
404 case SMB_ODIR_STATE_CLOSED:
405 default:
406 mutex_exit(&od->d_mutex);
407 return (B_FALSE);
408 }
409
410 mutex_exit(&od->d_mutex);
411 return (B_TRUE);
412 }
413
414 /*
415 * If the odir is in SMB_ODIR_STATE_CLOSING and this release results in
416 * a refcnt of 0, change the state to SMB_ODIR_STATE_CLOSED and post the
417 * object for deletion. Object deletion is deferred to avoid modifying
418 * a list while an iteration may be in progress.
419 */
420 void
smb_odir_release(smb_odir_t * od)421 smb_odir_release(smb_odir_t *od)
422 {
423 SMB_ODIR_VALID(od);
424
425 mutex_enter(&od->d_mutex);
426 ASSERT(od->d_refcnt > 0);
427
428 switch (od->d_state) {
429 case SMB_ODIR_STATE_OPEN:
430 break;
431 case SMB_ODIR_STATE_IN_USE:
432 od->d_refcnt--;
433 if (od->d_refcnt == 0)
434 od->d_state = SMB_ODIR_STATE_OPEN;
435 break;
436 case SMB_ODIR_STATE_CLOSING:
437 od->d_refcnt--;
438 if (od->d_refcnt == 0) {
439 od->d_state = SMB_ODIR_STATE_CLOSED;
440 smb_tree_post_odir(od->d_tree, od);
441 }
442 break;
443 case SMB_ODIR_STATE_CLOSED:
444 default:
445 break;
446 }
447
448 mutex_exit(&od->d_mutex);
449 }
450
451 /*
452 * smb_odir_close
453 */
454 void
smb_odir_close(smb_odir_t * od)455 smb_odir_close(smb_odir_t *od)
456 {
457 ASSERT(od);
458 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
459
460 mutex_enter(&od->d_mutex);
461 ASSERT(od->d_refcnt > 0);
462 switch (od->d_state) {
463 case SMB_ODIR_STATE_OPEN:
464 break;
465 case SMB_ODIR_STATE_IN_USE:
466 od->d_state = SMB_ODIR_STATE_CLOSING;
467 break;
468 case SMB_ODIR_STATE_CLOSING:
469 case SMB_ODIR_STATE_CLOSED:
470 default:
471 break;
472 }
473 mutex_exit(&od->d_mutex);
474 }
475
476 /*
477 * smb_odir_read
478 *
479 * Find the next directory entry matching the search pattern.
480 * No search attribute matching is performed.
481 *
482 * Returns:
483 * 0 - success.
484 * - If a matching entry was found eof will be B_FALSE and
485 * odirent will be populated.
486 * - If there are no matching entries eof will be B_TRUE.
487 * -1 - error, error details set in sr.
488 */
489 int
smb_odir_read(smb_request_t * sr,smb_odir_t * od,smb_odirent_t * odirent,boolean_t * eof)490 smb_odir_read(smb_request_t *sr, smb_odir_t *od,
491 smb_odirent_t *odirent, boolean_t *eof)
492 {
493 int rc;
494
495 ASSERT(sr);
496 ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
497 ASSERT(od);
498 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
499 ASSERT(odirent);
500
501 mutex_enter(&od->d_mutex);
502 ASSERT(od->d_refcnt > 0);
503
504 switch (od->d_state) {
505 case SMB_ODIR_STATE_IN_USE:
506 case SMB_ODIR_STATE_CLOSING:
507 break;
508 case SMB_ODIR_STATE_OPEN:
509 case SMB_ODIR_STATE_CLOSED:
510 default:
511 mutex_exit(&od->d_mutex);
512 return (-1);
513 }
514
515 for (;;) {
516 if ((rc = smb_odir_next_odirent(od, odirent)) != 0)
517 break;
518 if (smb_odir_match_name(od, odirent))
519 break;
520 }
521
522 mutex_exit(&od->d_mutex);
523
524 switch (rc) {
525 case 0:
526 *eof = B_FALSE;
527 return (0);
528 case ENOENT:
529 *eof = B_TRUE;
530 return (0);
531 default:
532 smbsr_errno(sr, rc);
533 return (-1);
534 }
535 }
536
537 /*
538 * smb_odir_read_fileinfo
539 *
540 * Find the next directory entry matching the search pattern
541 * and attributes: od->d_pattern and od->d_sattr.
542 *
543 * If the search pattern specifies a single filename call
544 * smb_odir_single_fileinfo to get the file attributes and
545 * populate the caller's smb_fileinfo_t.
546 *
547 * If the search pattern contains wildcards call smb_odir_next_odirent
548 * to get the next directory entry then. Repeat until a matching
549 * filename is found. Call smb_odir_wildcard_fileinfo to get the
550 * file attributes and populate the caller's smb_fileinfo_t.
551 * This is repeated until a file matching the search criteria is found.
552 *
553 * Returns:
554 * 0 - success.
555 * - If a matching entry was found eof will be B_FALSE and
556 * fileinfo will be populated.
557 * - If there are no matching entries eof will be B_TRUE.
558 * -1 - error, error details set in sr.
559 */
560 int
smb_odir_read_fileinfo(smb_request_t * sr,smb_odir_t * od,smb_fileinfo_t * fileinfo,uint16_t * eof)561 smb_odir_read_fileinfo(smb_request_t *sr, smb_odir_t *od,
562 smb_fileinfo_t *fileinfo, uint16_t *eof)
563 {
564 int rc, errnum;
565 smb_odirent_t *odirent;
566
567 ASSERT(sr);
568 ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
569 ASSERT(od);
570 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
571 ASSERT(fileinfo);
572
573 mutex_enter(&od->d_mutex);
574 ASSERT(od->d_refcnt > 0);
575
576 switch (od->d_state) {
577 case SMB_ODIR_STATE_IN_USE:
578 case SMB_ODIR_STATE_CLOSING:
579 break;
580 case SMB_ODIR_STATE_OPEN:
581 case SMB_ODIR_STATE_CLOSED:
582 default:
583 mutex_exit(&od->d_mutex);
584 return (-1);
585 }
586
587 if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) {
588 if (od->d_eof)
589 rc = ENOENT;
590 else
591 rc = smb_odir_single_fileinfo(sr, od, fileinfo);
592 od->d_eof = B_TRUE;
593 } else {
594 odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
595 for (;;) {
596 bzero(fileinfo, sizeof (smb_fileinfo_t));
597 if ((rc = smb_odir_next_odirent(od, odirent)) != 0)
598 break;
599
600 /* skip non utf8 filename */
601 if (u8_validate(odirent->od_name,
602 strlen(odirent->od_name), NULL,
603 U8_VALIDATE_ENTIRE, &errnum) < 0)
604 continue;
605
606 if (!smb_odir_match_name(od, odirent))
607 continue;
608
609 rc = smb_odir_wildcard_fileinfo(sr, od, odirent,
610 fileinfo);
611 if (rc == 0)
612 break;
613 }
614 kmem_free(odirent, sizeof (smb_odirent_t));
615 }
616 mutex_exit(&od->d_mutex);
617
618 switch (rc) {
619 case 0:
620 *eof = 0;
621 return (0);
622 case ENOENT:
623 *eof = 1; /* per. FindFirst, FindNext spec. */
624 return (0);
625 default:
626 smbsr_errno(sr, rc);
627 return (-1);
628 }
629 }
630
631 /*
632 * smb_odir_read_streaminfo
633 *
634 * Find the next directory entry whose name begins with SMB_STREAM_PREFIX,
635 * and thus represents an NTFS named stream.
636 * No search attribute matching is performed.
637 * No case conflict name mangling is required for NTFS named stream names.
638 *
639 * Returns:
640 * 0 - success.
641 * - If a matching entry was found eof will be B_FALSE and
642 * sinfo will be populated.
643 * - If there are no matching entries eof will be B_TRUE.
644 * -1 - error, error details set in sr.
645 */
646 int
smb_odir_read_streaminfo(smb_request_t * sr,smb_odir_t * od,smb_streaminfo_t * sinfo,boolean_t * eof)647 smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od,
648 smb_streaminfo_t *sinfo, boolean_t *eof)
649 {
650 int rc;
651 smb_odirent_t *odirent;
652 smb_node_t *fnode;
653 smb_attr_t attr;
654
655 ASSERT(sr);
656 ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
657 ASSERT(od);
658 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
659 ASSERT(sinfo);
660
661 mutex_enter(&od->d_mutex);
662 ASSERT(od->d_refcnt > 0);
663
664 switch (od->d_state) {
665 case SMB_ODIR_STATE_IN_USE:
666 case SMB_ODIR_STATE_CLOSING:
667 break;
668 case SMB_ODIR_STATE_OPEN:
669 case SMB_ODIR_STATE_CLOSED:
670 default:
671 mutex_exit(&od->d_mutex);
672 return (-1);
673 }
674
675 /* Check that odir represents an xattr directory */
676 if (!(od->d_flags & SMB_ODIR_FLAG_XATTR)) {
677 *eof = B_TRUE;
678 mutex_exit(&od->d_mutex);
679 return (0);
680 }
681
682 odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
683 bzero(&attr, sizeof (attr));
684
685 for (;;) {
686 bzero(sinfo, sizeof (smb_streaminfo_t));
687 if ((rc = smb_odir_next_odirent(od, odirent)) != 0)
688 break;
689
690 if (strncmp(odirent->od_name, SMB_STREAM_PREFIX,
691 SMB_STREAM_PREFIX_LEN)) {
692 continue;
693 }
694
695 rc = smb_fsop_lookup(sr, od->d_cred, 0, od->d_tree->t_snode,
696 od->d_dnode, odirent->od_name, &fnode);
697 if (rc == 0) {
698 attr.sa_mask = SMB_AT_SIZE | SMB_AT_ALLOCSZ;
699 rc = smb_node_getattr(sr, fnode, od->d_cred,
700 NULL, &attr);
701 smb_node_release(fnode);
702 }
703
704 if (rc == 0) {
705 (void) strlcpy(sinfo->si_name,
706 odirent->od_name + SMB_STREAM_PREFIX_LEN,
707 sizeof (sinfo->si_name));
708 sinfo->si_size = attr.sa_vattr.va_size;
709 sinfo->si_alloc_size = attr.sa_allocsz;
710 break;
711 }
712 }
713 mutex_exit(&od->d_mutex);
714
715 kmem_free(odirent, sizeof (smb_odirent_t));
716
717 switch (rc) {
718 case 0:
719 *eof = B_FALSE;
720 return (0);
721 case ENOENT:
722 *eof = B_TRUE;
723 return (0);
724 default:
725 smbsr_errno(sr, rc);
726 return (-1);
727 }
728 }
729
730 /*
731 * smb_odir_save_cookie
732 *
733 * Callers can save up to SMB_MAX_SEARCH cookies in the odir
734 * to be used as resume points for a 'find next' request.
735 */
736 void
smb_odir_save_cookie(smb_odir_t * od,int idx,uint32_t cookie)737 smb_odir_save_cookie(smb_odir_t *od, int idx, uint32_t cookie)
738 {
739 ASSERT(od);
740 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
741 ASSERT(idx >= 0 && idx < SMB_MAX_SEARCH);
742
743 mutex_enter(&od->d_mutex);
744 od->d_cookies[idx] = cookie;
745 mutex_exit(&od->d_mutex);
746 }
747
748 /*
749 * smb_odir_save_fname
750 *
751 * Save a filename / offset pair, which are basically a
752 * one entry cache. See smb_com_trans2_find_next2.
753 */
754 void
smb_odir_save_fname(smb_odir_t * od,uint32_t cookie,const char * fname)755 smb_odir_save_fname(smb_odir_t *od, uint32_t cookie, const char *fname)
756 {
757 ASSERT(od);
758 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
759
760 mutex_enter(&od->d_mutex);
761
762 od->d_last_cookie = cookie;
763 bzero(od->d_last_name, MAXNAMELEN);
764 if (fname != NULL)
765 (void) strlcpy(od->d_last_name, fname, MAXNAMELEN);
766
767 mutex_exit(&od->d_mutex);
768 }
769
770 /*
771 * smb_odir_resume_at
772 *
773 * If SMB_ODIR_FLAG_WILDCARDS is not set the search is for a single
774 * file and should not be resumed.
775 *
776 * Wildcard searching can be resumed from:
777 * - the cookie saved at a specified index (SMBsearch, SMBfind).
778 * - a specified cookie (SMB_trans2_find)
779 * - a specified filename (SMB_trans2_find) - NOT SUPPORTED.
780 * Defaults to continuing from where the last search ended.
781 *
782 * Continuation from where the last search ended (SMB_trans2_find)
783 * is implemented by saving the last cookie at a specific index (0)
784 * smb_odir_resume_at indicates a new request, so reset od->d_bufptr
785 * and d_eof to force a vop_readdir.
786 */
787 void
smb_odir_resume_at(smb_odir_t * od,smb_odir_resume_t * resume)788 smb_odir_resume_at(smb_odir_t *od, smb_odir_resume_t *resume)
789 {
790 ASSERT(od);
791 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
792 ASSERT(resume);
793
794 mutex_enter(&od->d_mutex);
795
796 if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) {
797 od->d_eof = B_TRUE;
798 mutex_exit(&od->d_mutex);
799 return;
800 }
801
802 switch (resume->or_type) {
803
804 default:
805 case SMB_ODIR_RESUME_CONT:
806 /* Continue where we left off. */
807 break;
808
809 case SMB_ODIR_RESUME_IDX:
810 /*
811 * This is used only by the (ancient) SMB_SEARCH.
812 * Modern clients use trans2 FindFirst, FindNext.
813 */
814 ASSERT(resume->or_idx >= 0);
815 ASSERT(resume->or_idx < SMB_MAX_SEARCH);
816
817 if ((resume->or_idx < 0) ||
818 (resume->or_idx >= SMB_MAX_SEARCH)) {
819 resume->or_idx = 0;
820 }
821 od->d_offset = od->d_cookies[resume->or_idx];
822 break;
823
824 case SMB_ODIR_RESUME_COOKIE:
825 od->d_offset = resume->or_cookie;
826 break;
827
828 case SMB_ODIR_RESUME_FNAME:
829 /*
830 * If the name matches the last one saved,
831 * use the offset that was saved with it in
832 * the odir. Otherwise use the cookie value
833 * in the resume data from the client.
834 */
835 if (strcmp(resume->or_fname, od->d_last_name) &&
836 od->d_last_cookie != 0) {
837 od->d_offset = od->d_last_cookie;
838 } else if (resume->or_cookie != 0) {
839 od->d_offset = resume->or_cookie;
840 } /* else continue where we left off */
841 break;
842 }
843
844 /* Force a vop_readdir to refresh d_buf */
845 od->d_bufptr = NULL;
846 od->d_eof = B_FALSE;
847
848 mutex_exit(&od->d_mutex);
849 }
850
851
852 /* *** static functions *** */
853
854 /*
855 * smb_odir_create
856 * Allocate and populate an odir obect and add it to the tree's list.
857 */
858 static uint16_t
smb_odir_create(smb_request_t * sr,smb_node_t * dnode,char * pattern,uint16_t sattr,cred_t * cr)859 smb_odir_create(smb_request_t *sr, smb_node_t *dnode,
860 char *pattern, uint16_t sattr, cred_t *cr)
861 {
862 smb_odir_t *od;
863 smb_tree_t *tree;
864 uint16_t odid;
865
866 ASSERT(sr);
867 ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
868 ASSERT(sr->tid_tree);
869 ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC);
870 ASSERT(dnode);
871 ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
872
873 tree = sr->tid_tree;
874
875 if (smb_idpool_alloc(&tree->t_odid_pool, &odid)) {
876 smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
877 ERRDOS, ERROR_TOO_MANY_OPEN_FILES);
878 return (0);
879 }
880
881 od = kmem_cache_alloc(smb_cache_odir, KM_SLEEP);
882 bzero(od, sizeof (smb_odir_t));
883
884 mutex_init(&od->d_mutex, NULL, MUTEX_DEFAULT, NULL);
885 od->d_refcnt = 0;
886 od->d_state = SMB_ODIR_STATE_OPEN;
887 od->d_magic = SMB_ODIR_MAGIC;
888 od->d_opened_by_pid = sr->smb_pid;
889 od->d_session = tree->t_session;
890 od->d_cred = cr;
891 /*
892 * grab a ref for od->d_user
893 * released in smb_odir_delete()
894 */
895 smb_user_hold_internal(sr->uid_user);
896 od->d_user = sr->uid_user;
897 od->d_tree = tree;
898 od->d_dnode = dnode;
899 smb_node_ref(dnode);
900 od->d_odid = odid;
901 od->d_sattr = sattr;
902 (void) strlcpy(od->d_pattern, pattern, sizeof (od->d_pattern));
903 od->d_flags = 0;
904 if (smb_contains_wildcards(od->d_pattern))
905 od->d_flags |= SMB_ODIR_FLAG_WILDCARDS;
906 if (vfs_has_feature(dnode->vp->v_vfsp, VFSFT_DIRENTFLAGS))
907 od->d_flags |= SMB_ODIR_FLAG_EDIRENT;
908 if (smb_tree_has_feature(tree, SMB_TREE_CASEINSENSITIVE))
909 od->d_flags |= SMB_ODIR_FLAG_IGNORE_CASE;
910 if (smb_tree_has_feature(tree, SMB_TREE_SHORTNAMES))
911 od->d_flags |= SMB_ODIR_FLAG_SHORTNAMES;
912 if (SMB_TREE_SUPPORTS_CATIA(sr))
913 od->d_flags |= SMB_ODIR_FLAG_CATIA;
914 if (SMB_TREE_SUPPORTS_ABE(sr))
915 od->d_flags |= SMB_ODIR_FLAG_ABE;
916 if (dnode->flags & NODE_XATTR_DIR)
917 od->d_flags |= SMB_ODIR_FLAG_XATTR;
918 od->d_eof = B_FALSE;
919
920 smb_llist_enter(&tree->t_odir_list, RW_WRITER);
921 smb_llist_insert_tail(&tree->t_odir_list, od);
922 smb_llist_exit(&tree->t_odir_list);
923
924 atomic_inc_32(&tree->t_session->s_dir_cnt);
925 return (odid);
926 }
927
928 /*
929 * Delete an odir.
930 *
931 * Remove the odir from the tree list before freeing resources
932 * associated with the odir.
933 */
934 void
smb_odir_delete(void * arg)935 smb_odir_delete(void *arg)
936 {
937 smb_tree_t *tree;
938 smb_odir_t *od = (smb_odir_t *)arg;
939
940 SMB_ODIR_VALID(od);
941 ASSERT(od->d_refcnt == 0);
942 ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED);
943
944 tree = od->d_tree;
945 smb_llist_enter(&tree->t_odir_list, RW_WRITER);
946 smb_llist_remove(&tree->t_odir_list, od);
947 smb_idpool_free(&tree->t_odid_pool, od->d_odid);
948 atomic_dec_32(&tree->t_session->s_dir_cnt);
949 smb_llist_exit(&tree->t_odir_list);
950
951 mutex_enter(&od->d_mutex);
952 mutex_exit(&od->d_mutex);
953
954 od->d_magic = 0;
955 smb_node_release(od->d_dnode);
956 smb_user_release(od->d_user);
957 mutex_destroy(&od->d_mutex);
958 kmem_cache_free(smb_cache_odir, od);
959 }
960
961 /*
962 * smb_odir_next_odirent
963 *
964 * Find the next directory entry in d_buf. If d_bufptr is NULL (buffer
965 * is empty or we've reached the end of it), read the next set of
966 * entries from the file system (vop_readdir).
967 *
968 * File systems which support VFSFT_EDIRENT_FLAGS will return the
969 * directory entries as a buffer of edirent_t structure. Others will
970 * return a buffer of dirent64_t structures. For simplicity translate
971 * the data into an smb_odirent_t structure.
972 * The ed_name/d_name in d_buf is NULL terminated by the file system.
973 *
974 * Some file systems can have directories larger than SMB_MAXDIRSIZE.
975 * If the odirent offset >= SMB_MAXDIRSIZE return ENOENT and set d_eof
976 * to true to stop subsequent calls to smb_vop_readdir.
977 *
978 * Returns:
979 * 0 - success. odirent is populated with the next directory entry
980 * ENOENT - no more directory entries
981 * errno - error
982 */
983 static int
smb_odir_next_odirent(smb_odir_t * od,smb_odirent_t * odirent)984 smb_odir_next_odirent(smb_odir_t *od, smb_odirent_t *odirent)
985 {
986 int rc;
987 int reclen;
988 int eof;
989 dirent64_t *dp;
990 edirent_t *edp;
991 char *np;
992 uint32_t abe_flag = 0;
993
994 ASSERT(MUTEX_HELD(&od->d_mutex));
995
996 bzero(odirent, sizeof (smb_odirent_t));
997
998 if (od->d_bufptr != NULL) {
999 if (od->d_flags & SMB_ODIR_FLAG_EDIRENT)
1000 reclen = od->d_edp->ed_reclen;
1001 else
1002 reclen = od->d_dp->d_reclen;
1003
1004 if (reclen == 0) {
1005 od->d_bufptr = NULL;
1006 } else {
1007 od->d_bufptr += reclen;
1008 if (od->d_bufptr >= od->d_buf + od->d_bufsize)
1009 od->d_bufptr = NULL;
1010 }
1011 }
1012
1013 if (od->d_bufptr == NULL) {
1014 if (od->d_eof)
1015 return (ENOENT);
1016
1017 od->d_bufsize = sizeof (od->d_buf);
1018
1019 if (od->d_flags & SMB_ODIR_FLAG_ABE)
1020 abe_flag = SMB_ABE;
1021
1022 rc = smb_vop_readdir(od->d_dnode->vp, od->d_offset,
1023 od->d_buf, &od->d_bufsize, &eof, abe_flag, od->d_cred);
1024
1025 if ((rc == 0) && (od->d_bufsize == 0))
1026 rc = ENOENT;
1027
1028 if (rc != 0) {
1029 od->d_bufptr = NULL;
1030 od->d_bufsize = 0;
1031 return (rc);
1032 }
1033
1034 od->d_eof = (eof != 0);
1035 od->d_bufptr = od->d_buf;
1036 }
1037
1038 if (od->d_flags & SMB_ODIR_FLAG_EDIRENT)
1039 od->d_offset = od->d_edp->ed_off;
1040 else
1041 od->d_offset = od->d_dp->d_off;
1042
1043 if (od->d_offset >= SMB_MAXDIRSIZE) {
1044 od->d_bufptr = NULL;
1045 od->d_bufsize = 0;
1046 od->d_eof = B_TRUE;
1047 return (ENOENT);
1048 }
1049
1050 if (od->d_flags & SMB_ODIR_FLAG_EDIRENT) {
1051 edp = od->d_edp;
1052 odirent->od_ino = edp->ed_ino;
1053 odirent->od_eflags = edp->ed_eflags;
1054 np = edp->ed_name;
1055 } else {
1056 dp = od->d_dp;
1057 odirent->od_ino = dp->d_ino;
1058 odirent->od_eflags = 0;
1059 np = dp->d_name;
1060 }
1061
1062 if ((od->d_flags & SMB_ODIR_FLAG_CATIA) &&
1063 ((od->d_flags & SMB_ODIR_FLAG_XATTR) == 0)) {
1064 smb_vop_catia_v4tov5(np, odirent->od_name,
1065 sizeof (odirent->od_name));
1066 } else {
1067 (void) strlcpy(odirent->od_name, np,
1068 sizeof (odirent->od_name));
1069 }
1070
1071 return (0);
1072 }
1073
1074 /*
1075 * smb_odir_single_fileinfo
1076 *
1077 * Lookup the file identified by od->d_pattern.
1078 *
1079 * If the looked up file is a link, we attempt to lookup the link target
1080 * to use its attributes in place of those of the files's.
1081 * If we fail to lookup the target of the link we use the original
1082 * file's attributes.
1083 * Check if the attributes match the search attributes.
1084 *
1085 * Returns: 0 - success
1086 * ENOENT - no match
1087 * errno - error
1088 */
1089 static int
smb_odir_single_fileinfo(smb_request_t * sr,smb_odir_t * od,smb_fileinfo_t * fileinfo)1090 smb_odir_single_fileinfo(smb_request_t *sr, smb_odir_t *od,
1091 smb_fileinfo_t *fileinfo)
1092 {
1093 int rc;
1094 smb_node_t *fnode, *tgt_node;
1095 smb_attr_t attr;
1096 ino64_t fid;
1097 char *name;
1098 boolean_t case_conflict = B_FALSE;
1099 int lookup_flags, flags = 0;
1100 vnode_t *vp;
1101
1102 ASSERT(sr);
1103 ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1104 ASSERT(od);
1105 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1106
1107 ASSERT(MUTEX_HELD(&od->d_mutex));
1108 bzero(fileinfo, sizeof (smb_fileinfo_t));
1109
1110 rc = smb_fsop_lookup(sr, od->d_cred, 0, od->d_tree->t_snode,
1111 od->d_dnode, od->d_pattern, &fnode);
1112 if (rc != 0)
1113 return (rc);
1114
1115 /*
1116 * If case sensitive, do a case insensitive smb_vop_lookup to
1117 * check for case conflict
1118 */
1119 if (od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) {
1120 lookup_flags = SMB_IGNORE_CASE;
1121 if (od->d_flags & SMB_ODIR_FLAG_CATIA)
1122 lookup_flags |= SMB_CATIA;
1123
1124 rc = smb_vop_lookup(od->d_dnode->vp, fnode->od_name, &vp,
1125 NULL, lookup_flags, &flags, od->d_tree->t_snode->vp,
1126 NULL, od->d_cred);
1127 if (rc != 0)
1128 return (rc);
1129 VN_RELE(vp);
1130
1131 if (flags & ED_CASE_CONFLICT)
1132 case_conflict = B_TRUE;
1133 }
1134
1135 bzero(&attr, sizeof (attr));
1136 attr.sa_mask = SMB_AT_ALL;
1137 rc = smb_node_getattr(sr, fnode, zone_kcred(), NULL, &attr);
1138 if (rc != 0) {
1139 smb_node_release(fnode);
1140 return (rc);
1141 }
1142
1143
1144 /* follow link to get target node & attr */
1145 if (smb_node_is_symlink(fnode) &&
1146 smb_odir_lookup_link(sr, od, fnode->od_name, &tgt_node)) {
1147 smb_node_release(fnode);
1148 fnode = tgt_node;
1149 attr.sa_mask = SMB_AT_ALL;
1150 rc = smb_node_getattr(sr, fnode, zone_kcred(), NULL, &attr);
1151 if (rc != 0) {
1152 smb_node_release(fnode);
1153 return (rc);
1154 }
1155 }
1156
1157 /* check search attributes */
1158 if (!smb_sattr_check(attr.sa_dosattr, od->d_sattr)) {
1159 smb_node_release(fnode);
1160 return (ENOENT);
1161 }
1162
1163 name = fnode->od_name;
1164 if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) {
1165 fid = attr.sa_vattr.va_nodeid;
1166 if (case_conflict || smb_needs_mangled(name)) {
1167 smb_mangle(name, fid, fileinfo->fi_shortname,
1168 SMB_SHORTNAMELEN);
1169 }
1170 if (case_conflict)
1171 name = fileinfo->fi_shortname;
1172 }
1173
1174 (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name));
1175
1176 fileinfo->fi_dosattr = attr.sa_dosattr;
1177 fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid;
1178 fileinfo->fi_size = attr.sa_vattr.va_size;
1179 fileinfo->fi_alloc_size = attr.sa_allocsz;
1180 fileinfo->fi_atime = attr.sa_vattr.va_atime;
1181 fileinfo->fi_mtime = attr.sa_vattr.va_mtime;
1182 fileinfo->fi_ctime = attr.sa_vattr.va_ctime;
1183 if (attr.sa_crtime.tv_sec)
1184 fileinfo->fi_crtime = attr.sa_crtime;
1185 else
1186 fileinfo->fi_crtime = attr.sa_vattr.va_mtime;
1187
1188 smb_node_release(fnode);
1189 return (0);
1190 }
1191
1192 /*
1193 * smb_odir_wildcard_fileinfo
1194 *
1195 * odirent contains a directory entry, obtained from a vop_readdir.
1196 * If a case conflict is identified the filename is mangled and the
1197 * shortname is used as 'name', in place of odirent->od_name.
1198 *
1199 * If the looked up file is a link, we attempt to lookup the link target
1200 * to use its attributes in place of those of the files's.
1201 * If we fail to lookup the target of the link we use the original
1202 * file's attributes.
1203 * Check if the attributes match the search attributes.
1204 *
1205 * Although some file systems can have directories larger than
1206 * SMB_MAXDIRSIZE smb_odir_next_odirent ensures that no offset larger
1207 * than SMB_MAXDIRSIZE is returned. It is therefore safe to use the
1208 * offset as the cookie (uint32_t).
1209 *
1210 * Returns: 0 - success
1211 * ENOENT - no match, proceed to next entry
1212 * errno - error
1213 */
1214 static int
smb_odir_wildcard_fileinfo(smb_request_t * sr,smb_odir_t * od,smb_odirent_t * odirent,smb_fileinfo_t * fileinfo)1215 smb_odir_wildcard_fileinfo(smb_request_t *sr, smb_odir_t *od,
1216 smb_odirent_t *odirent, smb_fileinfo_t *fileinfo)
1217 {
1218 int rc;
1219 cred_t *cr;
1220 smb_node_t *fnode, *tgt_node;
1221 smb_attr_t attr;
1222 char *name;
1223 boolean_t case_conflict;
1224
1225 ASSERT(sr);
1226 ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1227 ASSERT(od);
1228 ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1229
1230 ASSERT(MUTEX_HELD(&od->d_mutex));
1231 bzero(fileinfo, sizeof (smb_fileinfo_t));
1232
1233 rc = smb_fsop_lookup(sr, od->d_cred, SMB_CASE_SENSITIVE,
1234 od->d_tree->t_snode, od->d_dnode, odirent->od_name, &fnode);
1235 if (rc != 0)
1236 return (rc);
1237
1238 /* follow link to get target node & attr */
1239 if (smb_node_is_symlink(fnode) &&
1240 smb_odir_lookup_link(sr, od, odirent->od_name, &tgt_node)) {
1241 smb_node_release(fnode);
1242 fnode = tgt_node;
1243 }
1244
1245 /* skip system files */
1246 if (smb_node_is_system(fnode)) {
1247 smb_node_release(fnode);
1248 return (ENOENT);
1249 }
1250
1251 /*
1252 * Windows directory listings return not only names, but
1253 * also some attributes. In Unix, you need some access to
1254 * get those attributes. Which credential should we use to
1255 * get those? If we're doing Access Based Enumeration (ABE)
1256 * we want this getattr to fail, which will cause the caller
1257 * to skip this entry. If we're NOT doing ABE, we normally
1258 * want to show all the directory entries (including their
1259 * attributes) so we want this getattr to succeed!
1260 */
1261 if (smb_tree_has_feature(od->d_tree, SMB_TREE_ABE))
1262 cr = od->d_cred;
1263 else
1264 cr = zone_kcred();
1265
1266 bzero(&attr, sizeof (attr));
1267 attr.sa_mask = SMB_AT_ALL;
1268 rc = smb_node_getattr(NULL, fnode, cr, NULL, &attr);
1269 if (rc != 0) {
1270 smb_node_release(fnode);
1271 return (rc);
1272 }
1273
1274 /* check search attributes */
1275 if (!smb_sattr_check(attr.sa_dosattr, od->d_sattr)) {
1276 smb_node_release(fnode);
1277 return (ENOENT);
1278 }
1279
1280 name = odirent->od_name;
1281 if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) {
1282 case_conflict = ((od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) &&
1283 (odirent->od_eflags & ED_CASE_CONFLICT));
1284 if (case_conflict || smb_needs_mangled(name)) {
1285 smb_mangle(name, odirent->od_ino,
1286 fileinfo->fi_shortname, SMB_SHORTNAMELEN);
1287 }
1288 if (case_conflict)
1289 name = fileinfo->fi_shortname;
1290 }
1291
1292 (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name));
1293
1294 fileinfo->fi_cookie = (uint32_t)od->d_offset;
1295 fileinfo->fi_dosattr = attr.sa_dosattr;
1296 fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid;
1297 fileinfo->fi_size = attr.sa_vattr.va_size;
1298 fileinfo->fi_alloc_size = attr.sa_allocsz;
1299 fileinfo->fi_atime = attr.sa_vattr.va_atime;
1300 fileinfo->fi_mtime = attr.sa_vattr.va_mtime;
1301 fileinfo->fi_ctime = attr.sa_vattr.va_ctime;
1302 if (attr.sa_crtime.tv_sec)
1303 fileinfo->fi_crtime = attr.sa_crtime;
1304 else
1305 fileinfo->fi_crtime = attr.sa_vattr.va_mtime;
1306
1307 smb_node_release(fnode);
1308 return (0);
1309 }
1310
1311 /*
1312 * smb_odir_lookup_link
1313 *
1314 * If the file is a symlink we lookup the object to which the
1315 * symlink refers so that we can return its attributes.
1316 * This can cause a problem if a symlink in a sub-directory
1317 * points to a parent directory (some UNIX GUI's create a symlink
1318 * in $HOME/.desktop that points to the user's home directory).
1319 * Some Windows applications (e.g. virus scanning) loop/hang
1320 * trying to follow this recursive path and there is little
1321 * we can do because the path is constructed on the client.
1322 * smb_dirsymlink_enable allows an end-user to disable
1323 * symlinks to directories. Symlinks to other object types
1324 * should be unaffected.
1325 *
1326 * Returns: B_TRUE - followed link. tgt_node and tgt_attr set
1327 * B_FALSE - link not followed
1328 */
1329 static boolean_t
smb_odir_lookup_link(smb_request_t * sr,smb_odir_t * od,char * fname,smb_node_t ** tgt_node)1330 smb_odir_lookup_link(smb_request_t *sr, smb_odir_t *od,
1331 char *fname, smb_node_t **tgt_node)
1332 {
1333 int rc;
1334 uint32_t flags = SMB_FOLLOW_LINKS | SMB_CASE_SENSITIVE;
1335
1336 rc = smb_fsop_lookup(sr, od->d_cred, flags,
1337 od->d_tree->t_snode, od->d_dnode, fname, tgt_node);
1338 if (rc != 0) {
1339 *tgt_node = NULL;
1340 return (B_FALSE);
1341 }
1342
1343 if (smb_node_is_dir(*tgt_node) && (!smb_dirsymlink_enable)) {
1344 smb_node_release(*tgt_node);
1345 *tgt_node = NULL;
1346 return (B_FALSE);
1347 }
1348
1349 return (B_TRUE);
1350 }
1351
1352 /*
1353 * smb_odir_match_name
1354 *
1355 * Check if the directory entry name matches the search pattern:
1356 * - Don't match reserved dos filenames.
1357 * - Check if odirent->od_name matches od->d_pattern.
1358 * - If shortnames are supported, generate the shortname from
1359 * odirent->od_name and check if it matches od->d_pattern.
1360 */
1361 static boolean_t
smb_odir_match_name(smb_odir_t * od,smb_odirent_t * odirent)1362 smb_odir_match_name(smb_odir_t *od, smb_odirent_t *odirent)
1363 {
1364 char *name = odirent->od_name;
1365 char shortname[SMB_SHORTNAMELEN];
1366 ino64_t ino = odirent->od_ino;
1367 boolean_t ci = (od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) != 0;
1368
1369 if (smb_is_reserved_dos_name(name))
1370 return (B_FALSE);
1371
1372 if (smb_match(od->d_pattern, name, ci))
1373 return (B_TRUE);
1374
1375 if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) {
1376 smb_mangle(name, ino, shortname, SMB_SHORTNAMELEN);
1377 if (smb_match(od->d_pattern, shortname, ci))
1378 return (B_TRUE);
1379 }
1380
1381 return (B_FALSE);
1382 }
1383