CVE-2017-2619 (Symlink race allows access outside share definition) https://www.samba.org/samba/history/samba-4.4.12.html
Here's a backport. Build / test reports on -stable would be appreciated. Index: Makefile =================================================================== RCS file: /d/cvs/ports/net/samba/Makefile,v retrieving revision 1.227.2.2 diff -u -p -r1.227.2.2 Makefile --- Makefile 18 Feb 2017 09:45:51 -0000 1.227.2.2 +++ Makefile 25 Mar 2017 16:18:48 -0000 @@ -15,7 +15,7 @@ PKGNAME-tevent = tevent-${TEVENT_V} PKGNAME-util = samba-util-${VERSION} PKGNAME-docs = samba-docs-${VERSION} -REVISION-main = 1 +REVISION-main = 2 REVISION-ldb = 0 REVISION-tevent = 0 Index: patches/patch-source3_smbd_dir_c =================================================================== RCS file: patches/patch-source3_smbd_dir_c diff -N patches/patch-source3_smbd_dir_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-source3_smbd_dir_c 25 Mar 2017 16:20:56 -0000 @@ -0,0 +1,206 @@ +$OpenBSD$ + +CVE-2017-2619 (Symlink race allows access outside share definition) + +--- source3/smbd/dir.c.orig Sat Mar 25 17:19:25 2017 ++++ source3/smbd/dir.c Sat Mar 25 17:19:50 2017 +@@ -1588,7 +1588,8 @@ static int smb_Dir_destructor(struct smb_Dir *dirp) + Open a directory. + ********************************************************************/ + +-struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn, ++static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx, ++ connection_struct *conn, + const char *name, + const char *mask, + uint32_t attr) +@@ -1600,27 +1601,21 @@ struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connectio + return NULL; + } + +- dirp->conn = conn; +- dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn)); +- +- dirp->dir_path = talloc_strdup(dirp, name); +- if (!dirp->dir_path) { +- errno = ENOMEM; ++ dirp->dir = SMB_VFS_OPENDIR(conn, name, mask, attr); ++ if (!dirp->dir) { ++ DEBUG(5,("OpenDir: Can't open %s. %s\n", name, ++ strerror(errno) )); + goto fail; + } + ++ dirp->conn = conn; ++ dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn)); ++ + if (sconn && !sconn->using_smb2) { + sconn->searches.dirhandles_open++; + } + talloc_set_destructor(dirp, smb_Dir_destructor); + +- dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr); +- if (!dirp->dir) { +- DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, +- strerror(errno) )); +- goto fail; +- } +- + return dirp; + + fail: +@@ -1628,6 +1623,76 @@ struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connectio + return NULL; + } + ++/**************************************************************************** ++ Open a directory handle by pathname, ensuring it's under the share path. ++****************************************************************************/ ++ ++static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx, ++ connection_struct *conn, ++ const char *name, ++ const char *wcard, ++ uint32_t attr) ++{ ++ struct smb_Dir *dir_hnd = NULL; ++ char *saved_dir = vfs_GetWd(ctx, conn); ++ NTSTATUS status; ++ ++ if (saved_dir == NULL) { ++ return NULL; ++ } ++ ++ if (vfs_ChDir(conn, name) == -1) { ++ goto out; ++ } ++ ++ /* ++ * Now the directory is pinned, use ++ * REALPATH to ensure we can access it. ++ */ ++ status = check_name(conn, "."); ++ if (!NT_STATUS_IS_OK(status)) { ++ goto out; ++ } ++ ++ dir_hnd = OpenDir_internal(ctx, ++ conn, ++ ".", ++ wcard, ++ attr); ++ ++ if (dir_hnd == NULL) { ++ goto out; ++ } ++ ++ /* ++ * OpenDir_internal only gets "." as the dir name. ++ * Store the real dir name here. ++ */ ++ ++ dir_hnd->dir_path = talloc_strdup(dir_hnd, name); ++ if (!dir_hnd->dir_path) { ++ errno = ENOMEM; ++ } ++ ++ out: ++ ++ vfs_ChDir(conn, saved_dir); ++ TALLOC_FREE(saved_dir); ++ return dir_hnd; ++} ++ ++struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn, ++ const char *name, ++ const char *mask, ++ uint32_t attr) ++{ ++ return open_dir_safely(mem_ctx, ++ conn, ++ name, ++ mask, ++ attr); ++} ++ + /******************************************************************* + Open a directory from an fsp. + ********************************************************************/ +@@ -1641,9 +1706,19 @@ static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx + struct smbd_server_connection *sconn = conn->sconn; + + if (!dirp) { +- return NULL; ++ goto fail; + } + ++ if (!fsp->is_directory) { ++ errno = EBADF; ++ goto fail; ++ } ++ ++ if (fsp->fh->fd == -1) { ++ errno = EBADF; ++ goto fail; ++ } ++ + dirp->conn = conn; + dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn)); + +@@ -1653,36 +1728,33 @@ static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx + goto fail; + } + +- if (sconn && !sconn->using_smb2) { +- sconn->searches.dirhandles_open++; +- } +- talloc_set_destructor(dirp, smb_Dir_destructor); +- +- if (fsp->is_directory && fsp->fh->fd != -1) { +- dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr); +- if (dirp->dir != NULL) { +- dirp->fsp = fsp; +- } else { +- DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned " +- "NULL (%s)\n", +- dirp->dir_path, +- strerror(errno))); +- if (errno != ENOSYS) { +- return NULL; +- } ++ dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr); ++ if (dirp->dir != NULL) { ++ dirp->fsp = fsp; ++ } else { ++ DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned " ++ "NULL (%s)\n", ++ dirp->dir_path, ++ strerror(errno))); ++ if (errno != ENOSYS) { ++ goto fail; + } + } + + if (dirp->dir == NULL) { +- /* FDOPENDIR didn't work. Use OPENDIR instead. */ +- dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr); ++ /* FDOPENDIR is not supported. Use OPENDIR instead. */ ++ TALLOC_FREE(dirp); ++ return open_dir_safely(mem_ctx, ++ conn, ++ fsp->fsp_name->base_name, ++ mask, ++ attr); + } + +- if (!dirp->dir) { +- DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path, +- strerror(errno) )); +- goto fail; ++ if (sconn && !sconn->using_smb2) { ++ sconn->searches.dirhandles_open++; + } ++ talloc_set_destructor(dirp, smb_Dir_destructor); + + return dirp; + Index: patches/patch-source3_smbd_open_c =================================================================== RCS file: patches/patch-source3_smbd_open_c diff -N patches/patch-source3_smbd_open_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-source3_smbd_open_c 25 Mar 2017 16:21:02 -0000 @@ -0,0 +1,338 @@ +$OpenBSD$ + +CVE-2017-2619 (Symlink race allows access outside share definition) + +--- source3/smbd/open.c.orig Sat Mar 25 17:19:25 2017 ++++ source3/smbd/open.c Sat Mar 25 17:19:50 2017 +@@ -345,6 +345,268 @@ static NTSTATUS check_base_file_access(struct connecti + } + + /**************************************************************************** ++ Handle differing symlink errno's ++****************************************************************************/ ++ ++static int link_errno_convert(int err) ++{ ++#if defined(ENOTSUP) && defined(OSF1) ++ /* handle special Tru64 errno */ ++ if (err == ENOTSUP) { ++ err = ELOOP; ++ } ++#endif /* ENOTSUP */ ++#ifdef EFTYPE ++ /* fix broken NetBSD errno */ ++ if (err == EFTYPE) { ++ err = ELOOP; ++ } ++#endif /* EFTYPE */ ++ /* fix broken FreeBSD errno */ ++ if (err == EMLINK) { ++ err = ELOOP; ++ } ++ return err; ++} ++ ++static int non_widelink_open(struct connection_struct *conn, ++ const char *conn_rootdir, ++ files_struct *fsp, ++ struct smb_filename *smb_fname, ++ int flags, ++ mode_t mode, ++ unsigned int link_depth); ++ ++/**************************************************************************** ++ Follow a symlink in userspace. ++****************************************************************************/ ++ ++static int process_symlink_open(struct connection_struct *conn, ++ const char *conn_rootdir, ++ files_struct *fsp, ++ struct smb_filename *smb_fname, ++ int flags, ++ mode_t mode, ++ unsigned int link_depth) ++{ ++ int fd = -1; ++ char *link_target = NULL; ++ int link_len = -1; ++ char *oldwd = NULL; ++ size_t rootdir_len = 0; ++ char *resolved_name = NULL; ++ bool matched = false; ++ int saved_errno = 0; ++ ++ /* ++ * Ensure we don't get stuck in a symlink loop. ++ */ ++ link_depth++; ++ if (link_depth >= 20) { ++ errno = ELOOP; ++ goto out; ++ } ++ ++ /* Allocate space for the link target. */ ++ link_target = talloc_array(talloc_tos(), char, PATH_MAX); ++ if (link_target == NULL) { ++ errno = ENOMEM; ++ goto out; ++ } ++ ++ /* Read the link target. */ ++ link_len = SMB_VFS_READLINK(conn, ++ smb_fname->base_name, ++ link_target, ++ PATH_MAX - 1); ++ if (link_len == -1) { ++ goto out; ++ } ++ ++ /* Ensure it's at least null terminated. */ ++ link_target[link_len] = '\0'; ++ ++ /* Convert to an absolute path. */ ++ resolved_name = SMB_VFS_REALPATH(conn, link_target); ++ if (resolved_name == NULL) { ++ goto out; ++ } ++ ++ /* ++ * We know conn_rootdir starts with '/' and ++ * does not end in '/'. FIXME ! Should we ++ * smb_assert this ? ++ */ ++ rootdir_len = strlen(conn_rootdir); ++ ++ matched = (strncmp(conn_rootdir, resolved_name, rootdir_len) == 0); ++ if (!matched) { ++ errno = EACCES; ++ goto out; ++ } ++ ++ /* ++ * Turn into a path relative to the share root. ++ */ ++ if (resolved_name[rootdir_len] == '\0') { ++ /* Link to the root of the share. */ ++ smb_fname->base_name = talloc_strdup(talloc_tos(), "."); ++ if (smb_fname->base_name == NULL) { ++ errno = ENOMEM; ++ goto out; ++ } ++ } else if (resolved_name[rootdir_len] == '/') { ++ smb_fname->base_name = &resolved_name[rootdir_len+1]; ++ } else { ++ errno = EACCES; ++ goto out; ++ } ++ ++ oldwd = vfs_GetWd(talloc_tos(), conn); ++ if (oldwd == NULL) { ++ goto out; ++ } ++ ++ /* Ensure we operate from the root of the share. */ ++ if (vfs_ChDir(conn, conn_rootdir) == -1) { ++ goto out; ++ } ++ ++ /* And do it all again.. */ ++ fd = non_widelink_open(conn, ++ conn_rootdir, ++ fsp, ++ smb_fname, ++ flags, ++ mode, ++ link_depth); ++ if (fd == -1) { ++ saved_errno = errno; ++ } ++ ++ out: ++ ++ SAFE_FREE(resolved_name); ++ TALLOC_FREE(link_target); ++ if (oldwd != NULL) { ++ int ret = vfs_ChDir(conn, oldwd); ++ if (ret == -1) { ++ smb_panic("unable to get back to old directory\n"); ++ } ++ TALLOC_FREE(oldwd); ++ } ++ if (saved_errno != 0) { ++ errno = saved_errno; ++ } ++ return fd; ++} ++ ++/**************************************************************************** ++ Non-widelink open. ++****************************************************************************/ ++ ++static int non_widelink_open(struct connection_struct *conn, ++ const char *conn_rootdir, ++ files_struct *fsp, ++ struct smb_filename *smb_fname, ++ int flags, ++ mode_t mode, ++ unsigned int link_depth) ++{ ++ NTSTATUS status; ++ int fd = -1; ++ struct smb_filename *smb_fname_rel = NULL; ++ int saved_errno = 0; ++ char *oldwd = NULL; ++ char *parent_dir = NULL; ++ const char *final_component = NULL; ++ ++ if (!parent_dirname(talloc_tos(), ++ smb_fname->base_name, ++ &parent_dir, ++ &final_component)) { ++ goto out; ++ } ++ ++ oldwd = vfs_GetWd(talloc_tos(), conn); ++ if (oldwd == NULL) { ++ goto out; ++ } ++ ++ /* Pin parent directory in place. */ ++ if (vfs_ChDir(conn, parent_dir) == -1) { ++ goto out; ++ } ++ ++ /* Ensure the relative path is below the share. */ ++ status = check_reduced_name(conn, final_component); ++ if (!NT_STATUS_IS_OK(status)) { ++ saved_errno = map_errno_from_nt_status(status); ++ goto out; ++ } ++ ++ smb_fname_rel = synthetic_smb_fname(talloc_tos(), ++ final_component, ++ smb_fname->stream_name, ++ &smb_fname->st); ++ ++ flags |= O_NOFOLLOW; ++ ++ { ++ struct smb_filename *tmp_name = fsp->fsp_name; ++ fsp->fsp_name = smb_fname_rel; ++ fd = SMB_VFS_OPEN(conn, smb_fname_rel, fsp, flags, mode); ++ fsp->fsp_name = tmp_name; ++ } ++ ++ if (fd == -1) { ++ saved_errno = link_errno_convert(errno); ++ if (saved_errno == ELOOP) { ++ if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) { ++ /* Never follow symlinks on posix open. */ ++ goto out; ++ } ++ if (!lp_follow_symlinks(SNUM(conn))) { ++ /* Explicitly no symlinks. */ ++ goto out; ++ } ++ /* ++ * We have a symlink. Follow in userspace ++ * to ensure it's under the share definition. ++ */ ++ fd = process_symlink_open(conn, ++ conn_rootdir, ++ fsp, ++ smb_fname_rel, ++ flags, ++ mode, ++ link_depth); ++ if (fd == -1) { ++ saved_errno = ++ link_errno_convert(errno); ++ } ++ } ++ } ++ ++ out: ++ ++ TALLOC_FREE(parent_dir); ++ TALLOC_FREE(smb_fname_rel); ++ ++ if (oldwd != NULL) { ++ int ret = vfs_ChDir(conn, oldwd); ++ if (ret == -1) { ++ smb_panic("unable to get back to old directory\n"); ++ } ++ TALLOC_FREE(oldwd); ++ } ++ if (saved_errno != 0) { ++ errno = saved_errno; ++ } ++ return fd; ++} ++ ++/**************************************************************************** + fd support routines - attempt to do a dos_open. + ****************************************************************************/ + +@@ -356,8 +618,7 @@ NTSTATUS fd_open(struct connection_struct *conn, + struct smb_filename *smb_fname = fsp->fsp_name; + NTSTATUS status = NT_STATUS_OK; + +-#ifdef O_NOFOLLOW +- /* ++ /* + * Never follow symlinks on a POSIX client. The + * client should be doing this. + */ +@@ -365,29 +626,31 @@ NTSTATUS fd_open(struct connection_struct *conn, + if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) || !lp_follow_symlinks(SNUM(conn))) { + flags |= O_NOFOLLOW; + } +-#endif + +- fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode); +- if (fsp->fh->fd == -1) { +- int posix_errno = errno; +-#ifdef O_NOFOLLOW +-#if defined(ENOTSUP) && defined(OSF1) +- /* handle special Tru64 errno */ +- if (errno == ENOTSUP) { +- posix_errno = ELOOP; ++ /* Ensure path is below share definition. */ ++ if (!lp_widelinks(SNUM(conn))) { ++ const char *conn_rootdir = SMB_VFS_CONNECTPATH(conn, ++ smb_fname->base_name); ++ if (conn_rootdir == NULL) { ++ return NT_STATUS_NO_MEMORY; + } +-#endif /* ENOTSUP */ +-#ifdef EFTYPE +- /* fix broken NetBSD errno */ +- if (errno == EFTYPE) { +- posix_errno = ELOOP; +- } +-#endif /* EFTYPE */ +- /* fix broken FreeBSD errno */ +- if (errno == EMLINK) { +- posix_errno = ELOOP; +- } +-#endif /* O_NOFOLLOW */ ++ /* ++ * Only follow symlinks within a share ++ * definition. ++ */ ++ fsp->fh->fd = non_widelink_open(conn, ++ conn_rootdir, ++ fsp, ++ smb_fname, ++ flags, ++ mode, ++ 0); ++ } else { ++ fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode); ++ } ++ ++ if (fsp->fh->fd == -1) { ++ int posix_errno = link_errno_convert(errno); + status = map_nt_error_from_unix(posix_errno); + if (errno == EMFILE) { + static time_t last_warned = 0L; Index: patches/patch-source3_smbd_smb2_query_directory_c =================================================================== RCS file: patches/patch-source3_smbd_smb2_query_directory_c diff -N patches/patch-source3_smbd_smb2_query_directory_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-source3_smbd_smb2_query_directory_c 25 Mar 2017 16:21:05 -0000 @@ -0,0 +1,38 @@ +$OpenBSD$ + +CVE-2017-2619 (Symlink race allows access outside share definition) + +--- source3/smbd/smb2_query_directory.c.orig Sat Mar 25 17:19:26 2017 ++++ source3/smbd/smb2_query_directory.c Sat Mar 25 17:19:50 2017 +@@ -24,6 +24,7 @@ + #include "../libcli/smb/smb_common.h" + #include "trans2.h" + #include "../lib/util/tevent_ntstatus.h" ++#include "system/filesys.h" + + static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +@@ -322,7 +323,23 @@ static struct tevent_req *smbd_smb2_query_directory_se + } + + if (in_flags & SMB2_CONTINUE_FLAG_REOPEN) { ++ int flags; ++ + dptr_CloseDir(fsp); ++ ++ /* ++ * dptr_CloseDir() will close and invalidate the fsp's file ++ * descriptor, we have to reopen it. ++ */ ++ ++ flags = O_RDONLY; ++#ifdef O_DIRECTORY ++ flags |= O_DIRECTORY; ++#endif ++ status = fd_open(conn, fsp, flags, 0); ++ if (tevent_req_nterror(req, status)) { ++ return tevent_req_post(req, ev); ++ } + } + + if (!smbreq->posix_pathnames) { Index: patches/patch-source4_torture_smb2_dir_c =================================================================== RCS file: patches/patch-source4_torture_smb2_dir_c diff -N patches/patch-source4_torture_smb2_dir_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-source4_torture_smb2_dir_c 25 Mar 2017 16:21:09 -0000 @@ -0,0 +1,50 @@ +$OpenBSD$ + +CVE-2017-2619 (Symlink race allows access outside share definition) + +--- source4/torture/smb2/dir.c.orig Sat Mar 25 17:19:28 2017 ++++ source4/torture/smb2/dir.c Sat Mar 25 17:19:50 2017 +@@ -674,7 +674,7 @@ bool fill_result(void *private_data, + return true; + } + +-enum continue_type {CONT_SINGLE, CONT_INDEX, CONT_RESTART}; ++enum continue_type {CONT_SINGLE, CONT_INDEX, CONT_RESTART, CONT_REOPEN}; + + static NTSTATUS multiple_smb2_search(struct smb2_tree *tree, + TALLOC_CTX *tctx, +@@ -700,6 +700,9 @@ static NTSTATUS multiple_smb2_search(struct smb2_tree + + /* The search should start from the beginning everytime */ + f.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART; ++ if (cont_type == CONT_REOPEN) { ++ f.in.continue_flags = SMB2_CONTINUE_FLAG_REOPEN; ++ } + + do { + status = smb2_find_level(tree, tree, &f, &count, &d); +@@ -803,18 +806,23 @@ static bool test_many_files(struct torture_context *tc + {"SMB2_FIND_BOTH_DIRECTORY_INFO", "SINGLE", SMB2_FIND_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_SINGLE}, + {"SMB2_FIND_BOTH_DIRECTORY_INFO", "INDEX", SMB2_FIND_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_INDEX}, + {"SMB2_FIND_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_RESTART}, ++ {"SMB2_FIND_BOTH_DIRECTORY_INFO", "REOPEN", SMB2_FIND_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO, CONT_REOPEN}, + {"SMB2_FIND_DIRECTORY_INFO", "SINGLE", SMB2_FIND_DIRECTORY_INFO, RAW_SEARCH_DATA_DIRECTORY_INFO, CONT_SINGLE}, + {"SMB2_FIND_DIRECTORY_INFO", "INDEX", SMB2_FIND_DIRECTORY_INFO, RAW_SEARCH_DATA_DIRECTORY_INFO, CONT_INDEX}, + {"SMB2_FIND_DIRECTORY_INFO", "RESTART", SMB2_FIND_DIRECTORY_INFO, RAW_SEARCH_DATA_DIRECTORY_INFO, CONT_RESTART}, ++ {"SMB2_FIND_DIRECTORY_INFO", "REOPEN", SMB2_FIND_DIRECTORY_INFO, RAW_SEARCH_DATA_DIRECTORY_INFO, CONT_REOPEN}, + {"SMB2_FIND_FULL_DIRECTORY_INFO", "SINGLE", SMB2_FIND_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, CONT_SINGLE}, + {"SMB2_FIND_FULL_DIRECTORY_INFO", "INDEX", SMB2_FIND_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, CONT_INDEX}, + {"SMB2_FIND_FULL_DIRECTORY_INFO", "RESTART", SMB2_FIND_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, CONT_RESTART}, ++ {"SMB2_FIND_FULL_DIRECTORY_INFO", "REOPEN", SMB2_FIND_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_FULL_DIRECTORY_INFO, CONT_REOPEN}, + {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "SINGLE", SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_SINGLE}, + {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "INDEX", SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_INDEX}, + {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_RESTART}, ++ {"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "REOPEN", SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_REOPEN}, + {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "SINGLE", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_SINGLE}, + {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "INDEX", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_INDEX}, +- {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_RESTART} ++ {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_RESTART}, ++ {"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "REOPEN", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_REOPEN}, + }; + + smb2_deltree(tree, DNAME); -- jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE