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