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  *   |          |
 
 
 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
 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;
 
 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
 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
 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);
 
 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
 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
 
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
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) {
 
 | 
 
 
   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 2018 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  *   |          |
 
 
 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 static void smb_odir_delete(void *);
 268 
 269 
 270 /*
 271  * smb_odir_openpath
 272  *
 273  * Create an odir representing the directory specified in pathname.
 274  *
 275  * Returns:
 276  *    NT Status
 277  */
 278 uint32_t
 279 smb_odir_openpath(smb_request_t *sr, char *path, uint16_t sattr,
 280         uint32_t flags, smb_odir_t **odp)
 281 {
 282         int             rc;
 283         smb_tree_t      *tree;
 284         smb_node_t      *dnode;
 285         char            pattern[MAXNAMELEN];
 286         uint16_t        odid;
 287         cred_t          *cr;
 
 429         case SMB_ODIR_STATE_CLOSING:
 430         case SMB_ODIR_STATE_CLOSED:
 431         default:
 432                 mutex_exit(&od->d_mutex);
 433                 return (B_FALSE);
 434         }
 435 
 436         mutex_exit(&od->d_mutex);
 437         return (B_TRUE);
 438 }
 439 
 440 /*
 441  * If the odir is in SMB_ODIR_STATE_CLOSING and this release results in
 442  * a refcnt of 0, change the state to SMB_ODIR_STATE_CLOSED and post the
 443  * object for deletion.  Object deletion is deferred to avoid modifying
 444  * a list while an iteration may be in progress.
 445  */
 446 void
 447 smb_odir_release(smb_odir_t *od)
 448 {
 449         smb_tree_t *tree = od->d_tree;
 450 
 451         SMB_ODIR_VALID(od);
 452 
 453         mutex_enter(&od->d_mutex);
 454         ASSERT(od->d_refcnt > 0);
 455 
 456         switch (od->d_state) {
 457         case SMB_ODIR_STATE_OPEN:
 458                 break;
 459         case SMB_ODIR_STATE_IN_USE:
 460                 od->d_refcnt--;
 461                 if (od->d_refcnt == 0)
 462                         od->d_state = SMB_ODIR_STATE_OPEN;
 463                 break;
 464         case SMB_ODIR_STATE_CLOSING:
 465                 od->d_refcnt--;
 466                 if (od->d_refcnt == 0) {
 467                         od->d_state = SMB_ODIR_STATE_CLOSED;
 468                         smb_llist_post(&tree->t_odir_list, od,
 469                             smb_odir_delete);
 470                 }
 471                 break;
 472         case SMB_ODIR_STATE_CLOSED:
 473         default:
 474                 break;
 475         }
 476 
 477         mutex_exit(&od->d_mutex);
 478 }
 479 
 480 /*
 481  * smb_odir_close
 482  */
 483 void
 484 smb_odir_close(smb_odir_t *od)
 485 {
 486         ASSERT(od);
 487         ASSERT(od->d_magic == SMB_ODIR_MAGIC);
 488 
 489         mutex_enter(&od->d_mutex);
 
 976         (void) strlcpy(od->d_pattern, pattern, sizeof (od->d_pattern));
 977         if (smb_contains_wildcards(od->d_pattern))
 978                 od->d_flags |= SMB_ODIR_FLAG_WILDCARDS;
 979         else
 980                 od->d_flags &= ~SMB_ODIR_FLAG_WILDCARDS;
 981 
 982         /* Internal smb_odir_resume_at */
 983         od->d_offset = 0;
 984         od->d_bufptr = NULL;
 985         od->d_eof = B_FALSE;
 986 
 987         mutex_exit(&od->d_mutex);
 988 }
 989 
 990 /*
 991  * Delete an odir.
 992  *
 993  * Remove the odir from the tree list before freeing resources
 994  * associated with the odir.
 995  */
 996 static void
 997 smb_odir_delete(void *arg)
 998 {
 999         smb_tree_t      *tree;
1000         smb_odir_t      *od = (smb_odir_t *)arg;
1001 
1002         SMB_ODIR_VALID(od);
1003         ASSERT(od->d_refcnt == 0);
1004         ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED);
1005 
1006         tree = od->d_tree;
1007         smb_llist_enter(&tree->t_odir_list, RW_WRITER);
1008         smb_llist_remove(&tree->t_odir_list, od);
1009         if (od->d_odid != 0)
1010                 smb_idpool_free(&tree->t_odid_pool, od->d_odid);
1011         atomic_dec_32(&tree->t_session->s_dir_cnt);
1012         smb_llist_exit(&tree->t_odir_list);
1013 
1014         /*
1015          * This ofile is no longer on t_odir_list, however...
1016          *
1017          * This is called via smb_llist_post, which means it may run
1018          * BEFORE smb_odir_release drops d_mutex (if another thread
1019          * flushes the delete queue before we do).  Synchronize.
1020          */
1021         mutex_enter(&od->d_mutex);
1022         mutex_exit(&od->d_mutex);
1023 
1024         od->d_magic = 0;
1025         smb_node_release(od->d_dnode);
1026         smb_user_release(od->d_user);
1027         mutex_destroy(&od->d_mutex);
1028         kmem_cache_free(smb_cache_odir, od);
1029 }
1030 
1031 /*
1032  * smb_odir_next_odirent
1033  *
1034  * Find the next directory entry in d_buf. If d_bufptr is NULL (buffer
1035  * is empty or we've reached the end of it), read the next set of
1036  * entries from the file system (vop_readdir).
1037  *
1038  * File systems which support VFSFT_EDIRENT_FLAGS will return the
1039  * directory entries as a buffer of edirent_t structure. Others will
1040  * return a buffer of dirent64_t structures.  For simplicity translate
 
1042  * The ed_name/d_name in d_buf is NULL terminated by the file system.
1043  *
1044  * Some file systems can have directories larger than SMB_MAXDIRSIZE.
1045  * If the odirent offset >= SMB_MAXDIRSIZE return ENOENT and set d_eof
1046  * to true to stop subsequent calls to smb_vop_readdir.
1047  *
1048  * Returns:
1049  *      0 - success. odirent is populated with the next directory entry
1050  * ENOENT - no more directory entries
1051  *  errno - error
1052  */
1053 static int
1054 smb_odir_next_odirent(smb_odir_t *od, smb_odirent_t *odirent)
1055 {
1056         int             rc;
1057         int             reclen;
1058         int             eof;
1059         dirent64_t      *dp;
1060         edirent_t       *edp;
1061         char            *np;
1062         uint32_t        rddir_flags = 0;
1063 
1064         ASSERT(MUTEX_HELD(&od->d_mutex));
1065 
1066         bzero(odirent, sizeof (smb_odirent_t));
1067 
1068         if (od->d_flags & SMB_ODIR_FLAG_ABE)
1069                 rddir_flags |= SMB_ABE;
1070         if (od->d_flags & SMB_ODIR_FLAG_EDIRENT)
1071                 rddir_flags |= SMB_EDIRENT;
1072 
1073         if (od->d_bufptr != NULL) {
1074                 if (od->d_flags & SMB_ODIR_FLAG_EDIRENT)
1075                         reclen = od->d_edp->ed_reclen;
1076                 else
1077                         reclen = od->d_dp->d_reclen;
1078 
1079                 if (reclen == 0) {
1080                         od->d_bufptr = NULL;
1081                 } else {
1082                         od->d_bufptr += reclen;
1083                         if (od->d_bufptr >= od->d_buf + od->d_bufsize)
1084                                 od->d_bufptr = NULL;
1085                 }
1086         }
1087 
1088         if (od->d_bufptr == NULL) {
1089                 if (od->d_eof)
1090                         return (ENOENT);
1091 
1092                 od->d_bufsize = sizeof (od->d_buf);
1093 
1094                 rc = smb_vop_readdir(od->d_dnode->vp, od->d_offset,
1095                     od->d_buf, &od->d_bufsize, &eof, rddir_flags, od->d_cred);
1096 
1097                 if ((rc == 0) && (od->d_bufsize == 0))
1098                         rc = ENOENT;
1099 
1100                 if (rc != 0) {
1101                         od->d_bufptr = NULL;
1102                         od->d_bufsize = 0;
1103                         return (rc);
1104                 }
1105 
1106                 od->d_eof = (eof != 0);
1107                 od->d_bufptr = od->d_buf;
1108         }
1109 
1110         if (od->d_flags & SMB_ODIR_FLAG_EDIRENT)
1111                 od->d_offset = od->d_edp->ed_off;
1112         else
1113                 od->d_offset = od->d_dp->d_off;
1114 
1115         if (od->d_offset >= SMB_MAXDIRSIZE) {
 
 |