1 From a398754c9bb1639f762979765de6c540c714b5cb Mon Sep 17 00:00:00 2001
2 From: Jeremy Allison <jra@samba.org>
3 Date: Mon, 20 Mar 2017 11:32:19 -0700
4 Subject: [PATCH 01/15] CVE-2017-2619: s3/smbd: re-open directory after
7 dptr_CloseDir() will close and invalidate the fsp's file descriptor, we
10 Bug: https://bugzilla.samba.org/show_bug.cgi?id=12496
12 Signed-off-by: Ralph Bohme <slow@samba.org>
13 Signed-off-by: Jeremy Allison <jra@samba.org>
15 source3/smbd/open.c | 2 +-
16 source3/smbd/proto.h | 2 ++
17 source3/smbd/smb2_find.c | 17 +++++++++++++++++
18 3 files changed, 20 insertions(+), 1 deletion(-)
20 diff --git a/source3/smbd/open.c b/source3/smbd/open.c
21 index 441b8cd4362..35eee0a1485 100644
22 --- a/source3/smbd/open.c
23 +++ b/source3/smbd/open.c
24 @@ -197,7 +197,7 @@ static NTSTATUS check_base_file_access(struct connection_struct *conn,
25 fd support routines - attempt to do a dos_open.
26 ****************************************************************************/
28 -static NTSTATUS fd_open(struct connection_struct *conn,
29 +NTSTATUS fd_open(struct connection_struct *conn,
33 diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
34 index f5fad2bbb50..594edfa1e98 100644
35 --- a/source3/smbd/proto.h
36 +++ b/source3/smbd/proto.h
37 @@ -603,6 +603,8 @@ NTSTATUS smb1_file_se_access_check(connection_struct *conn,
38 const struct security_token *token,
39 uint32_t access_desired,
40 uint32_t *access_granted);
41 +NTSTATUS fd_open(struct connection_struct *conn, files_struct *fsp,
42 + int flags, mode_t mode);
43 NTSTATUS fd_close(files_struct *fsp);
44 void change_file_owner_to_parent(connection_struct *conn,
45 const char *inherit_from_dir,
46 diff --git a/source3/smbd/smb2_find.c b/source3/smbd/smb2_find.c
47 index 6fe6545c128..9dd3176497b 100644
48 --- a/source3/smbd/smb2_find.c
49 +++ b/source3/smbd/smb2_find.c
51 #include "../libcli/smb/smb_common.h"
53 #include "../lib/util/tevent_ntstatus.h"
54 +#include "system/filesys.h"
56 static struct tevent_req *smbd_smb2_find_send(TALLOC_CTX *mem_ctx,
57 struct tevent_context *ev,
58 @@ -301,7 +302,23 @@ static struct tevent_req *smbd_smb2_find_send(TALLOC_CTX *mem_ctx,
61 if (in_flags & SMB2_CONTINUE_FLAG_REOPEN) {
67 + * dptr_CloseDir() will close and invalidate the fsp's file
68 + * descriptor, we have to reopen it.
73 + flags |= O_DIRECTORY;
75 + status = fd_open(conn, fsp, flags, 0);
76 + if (tevent_req_nterror(req, status)) {
77 + return tevent_req_post(req, ev);
81 wcard_has_wild = ms_has_wild(in_file_name);
86 From a35fa98b99aa60132eb2c083d6393c28905e2045 Mon Sep 17 00:00:00 2001
87 From: Jeremy Allison <jra@samba.org>
88 Date: Tue, 28 Feb 2017 09:24:07 -0800
89 Subject: [PATCH 02/15] s3: vfs: dirsort doesn't handle opendir of "."
92 Needs to store $cwd path for correct sorting.
94 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12499
96 Signed-off-by: Jeremy Allison <jra@samba.org>
98 source3/modules/vfs_dirsort.c | 4 ++++
99 1 file changed, 4 insertions(+)
101 diff --git a/source3/modules/vfs_dirsort.c b/source3/modules/vfs_dirsort.c
102 index 66582e67890..dbcf0b16ed3 100644
103 --- a/source3/modules/vfs_dirsort.c
104 +++ b/source3/modules/vfs_dirsort.c
105 @@ -153,6 +153,10 @@ static SMB_STRUCT_DIR *dirsort_opendir(vfs_handle_struct *handle,
109 + if (ISDOT(data->smb_fname->base_name)) {
110 + data->smb_fname->base_name = vfs_GetWd(data, handle->conn);
113 /* Open the underlying directory and count the number of entries */
114 data->source_directory = SMB_VFS_NEXT_OPENDIR(handle, fname, mask,
120 From 23d2849d724a0f5bdf51dc7d7db438ed9fb4c2a9 Mon Sep 17 00:00:00 2001
121 From: Jeremy Allison <jra@samba.org>
122 Date: Mon, 13 Mar 2017 13:44:42 -0700
123 Subject: [PATCH 03/15] s3: VFS: vfs_streams_xattr.c: Make streams_xattr_open()
124 store the same path as streams_xattr_recheck().
126 If the open is changing directories, fsp->fsp_name->base_name
127 will be the full path from the share root, whilst
128 smb_fname will be relative to the $cwd.
130 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12546
132 Back-ported from a24ba3e4083200ec9885363efc5769f43183fb6b
134 Signed-off-by: Jeremy Allison <jra@samba.org>
136 source3/modules/vfs_streams_xattr.c | 9 ++++++++-
137 1 file changed, 8 insertions(+), 1 deletion(-)
139 diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
140 index 731c813f4d7..be46f8dc1e6 100644
141 --- a/source3/modules/vfs_streams_xattr.c
142 +++ b/source3/modules/vfs_streams_xattr.c
143 @@ -511,8 +511,15 @@ static int streams_xattr_open(vfs_handle_struct *handle,
145 sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
148 + * sio->base needs to be a copy of fsp->fsp_name->base_name,
149 + * making it identical to streams_xattr_recheck(). If the
150 + * open is changing directories, fsp->fsp_name->base_name
151 + * will be the full path from the share root, whilst
152 + * smb_fname will be relative to the $cwd.
154 sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
155 - smb_fname->base_name);
156 + fsp->fsp_name->base_name);
157 sio->fsp_name_ptr = fsp->fsp_name;
158 sio->handle = handle;
164 From 91935aaf77c70e3e2436af1d6e4a538d29fd4276 Mon Sep 17 00:00:00 2001
165 From: Jeremy Allison <jra@samba.org>
166 Date: Mon, 13 Mar 2017 13:54:04 -0700
167 Subject: [PATCH 04/15] vfs_streams_xattr: use fsp, not base_fsp
169 The base_fsp's fd is always -1 as it's closed after being openend in
170 create_file_unixpath().
172 Additionally in streams_xattr_open force using of SMB_VFS_FSETXATTR() by
173 sticking the just created fd into the fsp (and removing it afterwards).
175 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12591
177 Back-ported from 021189e32ba507832b5e821e5cda8a2889225955.
179 Signed-off-by: Jeremy Allison <jra@samba.org>
181 source3/modules/vfs_streams_xattr.c | 205 +++++++++++++++++-------------------
182 1 file changed, 99 insertions(+), 106 deletions(-)
184 diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
185 index be46f8dc1e6..a4ab84bba71 100644
186 --- a/source3/modules/vfs_streams_xattr.c
187 +++ b/source3/modules/vfs_streams_xattr.c
188 @@ -229,7 +229,7 @@ static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
192 - sbuf->st_ex_size = get_xattr_size(handle->conn, fsp->base_fsp,
193 + sbuf->st_ex_size = get_xattr_size(handle->conn, fsp,
194 io->base, io->xattr_name);
195 if (sbuf->st_ex_size == -1) {
197 @@ -364,6 +364,7 @@ static int streams_xattr_open(vfs_handle_struct *handle,
198 char *xattr_name = NULL;
203 DEBUG(10, ("streams_xattr_open called for %s\n",
204 smb_fname_str_dbg(smb_fname)));
205 @@ -375,133 +376,125 @@ static int streams_xattr_open(vfs_handle_struct *handle,
206 /* If the default stream is requested, just open the base file. */
207 if (is_ntfs_default_stream_smb_fname(smb_fname)) {
208 char *tmp_stream_name;
211 tmp_stream_name = smb_fname->stream_name;
212 smb_fname->stream_name = NULL;
214 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
216 - smb_fname->stream_name = tmp_stream_name;
220 + smb_fname->stream_name = tmp_stream_name;
222 - status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
224 - if (!NT_STATUS_IS_OK(status)) {
225 - errno = map_errno_from_nt_status(status);
231 - /* Create an smb_filename with stream_name == NULL. */
232 - status = create_synthetic_smb_fname(talloc_tos(),
233 - smb_fname->base_name,
236 - if (!NT_STATUS_IS_OK(status)) {
237 - errno = map_errno_from_nt_status(status);
240 + status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
242 + if (!NT_STATUS_IS_OK(status)) {
243 + errno = map_errno_from_nt_status(status);
248 - * We use baseflags to turn off nasty side-effects when opening the
252 - baseflags &= ~O_TRUNC;
253 - baseflags &= ~O_EXCL;
254 - baseflags &= ~O_CREAT;
255 + /* Create an smb_filename with stream_name == NULL. */
256 + status = create_synthetic_smb_fname(talloc_tos(),
257 + smb_fname->base_name,
260 + if (!NT_STATUS_IS_OK(status)) {
261 + errno = map_errno_from_nt_status(status);
265 - hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp,
268 + * We use baseflags to turn off nasty side-effects when opening the
272 + baseflags &= ~O_TRUNC;
273 + baseflags &= ~O_EXCL;
274 + baseflags &= ~O_CREAT;
276 - TALLOC_FREE(smb_fname_base);
277 + hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp,
280 - /* It is legit to open a stream on a directory, but the base
281 - * fd has to be read-only.
283 - if ((hostfd == -1) && (errno == EISDIR)) {
284 - baseflags &= ~O_ACCMODE;
285 - baseflags |= O_RDONLY;
286 - hostfd = SMB_VFS_OPEN(handle->conn, smb_fname, fsp, baseflags,
289 + TALLOC_FREE(smb_fname_base);
291 - if (hostfd == -1) {
294 + /* It is legit to open a stream on a directory, but the base
295 + * fd has to be read-only.
297 + if ((hostfd == -1) && (errno == EISDIR)) {
298 + baseflags &= ~O_ACCMODE;
299 + baseflags |= O_RDONLY;
300 + hostfd = SMB_VFS_OPEN(handle->conn, smb_fname, fsp, baseflags,
304 - status = get_ea_value(talloc_tos(), handle->conn, NULL,
305 - smb_fname->base_name, xattr_name, &ea);
306 + if (hostfd == -1) {
310 - DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status)));
311 + status = get_ea_value(talloc_tos(), handle->conn, NULL,
312 + smb_fname->base_name, xattr_name, &ea);
314 - if (!NT_STATUS_IS_OK(status)
315 - && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
317 - * The base file is not there. This is an error even if we got
318 - * O_CREAT, the higher levels should have created the base
321 - DEBUG(10, ("streams_xattr_open: base file %s not around, "
322 - "returning ENOENT\n", smb_fname->base_name));
326 + DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status)));
328 - if (!NT_STATUS_IS_OK(status)) {
330 - * The attribute does not exist
332 + if (!NT_STATUS_IS_OK(status)
333 + && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
335 + * The base file is not there. This is an error even if we got
336 + * O_CREAT, the higher levels should have created the base
339 + DEBUG(10, ("streams_xattr_open: base file %s not around, "
340 + "returning ENOENT\n", smb_fname->base_name));
345 - if (flags & O_CREAT) {
346 + if (!NT_STATUS_IS_OK(status)) {
348 - * Darn, xattrs need at least 1 byte
349 + * The attribute does not exist
353 - DEBUG(10, ("creating attribute %s on file %s\n",
354 - xattr_name, smb_fname->base_name));
355 + if (flags & O_CREAT) {
357 + * Darn, xattrs need at least 1 byte
361 + DEBUG(10, ("creating attribute %s on file %s\n",
362 + xattr_name, smb_fname->base_name));
364 + fsp->fh->fd = hostfd;
365 + ret = SMB_VFS_FSETXATTR(fsp, xattr_name,
366 + &null, sizeof(null),
367 + flags & O_EXCL ? XATTR_CREATE : 0);
375 + if (flags & O_TRUNC) {
377 if (fsp->base_fsp->fh->fd != -1) {
378 - if (SMB_VFS_FSETXATTR(
379 - fsp->base_fsp, xattr_name,
380 - &null, sizeof(null),
381 - flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
382 + if (SMB_VFS_FSETXATTR(
383 + fsp->base_fsp, xattr_name,
384 + &null, sizeof(null),
385 + flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
389 - if (SMB_VFS_SETXATTR(
390 - handle->conn, smb_fname->base_name,
391 - xattr_name, &null, sizeof(null),
392 - flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
393 + if (SMB_VFS_SETXATTR(
394 + handle->conn, smb_fname->base_name,
395 + xattr_name, &null, sizeof(null),
396 + flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
403 - if (flags & O_TRUNC) {
405 - if (fsp->base_fsp->fh->fd != -1) {
406 - if (SMB_VFS_FSETXATTR(
407 - fsp->base_fsp, xattr_name,
408 - &null, sizeof(null),
409 - flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
413 - if (SMB_VFS_SETXATTR(
414 - handle->conn, smb_fname->base_name,
415 - xattr_name, &null, sizeof(null),
416 - flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
422 - sio = (struct stream_io *)VFS_ADD_FSP_EXTENSION(handle, fsp,
423 + sio = (struct stream_io *)VFS_ADD_FSP_EXTENSION(handle, fsp,
427 @@ -868,7 +861,7 @@ static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
431 - status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
432 + status = get_ea_value(talloc_tos(), handle->conn, fsp,
433 sio->base, sio->xattr_name, &ea);
434 if (!NT_STATUS_IS_OK(status)) {
436 @@ -892,13 +885,13 @@ static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
438 memcpy(ea.value.data + offset, data, n);
440 - if (fsp->base_fsp->fh->fd != -1) {
441 - ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
442 + if (fsp->fh->fd != -1) {
443 + ret = SMB_VFS_FSETXATTR(fsp,
445 ea.value.data, ea.value.length, 0);
447 ret = SMB_VFS_SETXATTR(fsp->conn,
448 - fsp->base_fsp->fsp_name->base_name,
449 + fsp->fsp_name->base_name,
451 ea.value.data, ea.value.length, 0);
453 @@ -932,7 +925,7 @@ static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
457 - status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
458 + status = get_ea_value(talloc_tos(), handle->conn, fsp,
459 sio->base, sio->xattr_name, &ea);
460 if (!NT_STATUS_IS_OK(status)) {
462 @@ -977,7 +970,7 @@ static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
466 - status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
467 + status = get_ea_value(talloc_tos(), handle->conn, fsp,
468 sio->base, sio->xattr_name, &ea);
469 if (!NT_STATUS_IS_OK(status)) {
471 @@ -1002,13 +995,13 @@ static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
472 ea.value.length = offset + 1;
473 ea.value.data[offset] = 0;
475 - if (fsp->base_fsp->fh->fd != -1) {
476 - ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
477 + if (fsp->fh->fd != -1) {
478 + ret = SMB_VFS_FSETXATTR(fsp,
480 ea.value.data, ea.value.length, 0);
482 ret = SMB_VFS_SETXATTR(fsp->conn,
483 - fsp->base_fsp->fsp_name->base_name,
484 + fsp->fsp_name->base_name,
486 ea.value.data, ea.value.length, 0);
492 From 3f3c731faaa59f4d3ce7e49c12795c40e048d29f Mon Sep 17 00:00:00 2001
493 From: Jeremy Allison <jra@samba.org>
494 Date: Mon, 19 Dec 2016 11:55:56 -0800
495 Subject: [PATCH 05/15] s3: smbd: Create wrapper function for OpenDir in
496 preparation for making robust.
500 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496
502 Signed-off-by: Jeremy Allison <jra@samba.org>
504 source3/smbd/dir.c | 15 ++++++++++++++-
505 1 file changed, 14 insertions(+), 1 deletion(-)
507 diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
508 index 18ecf066824..ebe2641f813 100644
509 --- a/source3/smbd/dir.c
510 +++ b/source3/smbd/dir.c
511 @@ -1367,7 +1367,8 @@ static int smb_Dir_destructor(struct smb_Dir *dirp)
513 ********************************************************************/
515 -struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
516 +static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
517 + connection_struct *conn,
521 @@ -1407,6 +1408,18 @@ struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
525 +struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
530 + return OpenDir_internal(mem_ctx,
537 /*******************************************************************
538 Open a directory from an fsp.
539 ********************************************************************/
544 From 7efeb067c1586e0f1cfbb775b1efcb3b92005140 Mon Sep 17 00:00:00 2001
545 From: Jeremy Allison <jra@samba.org>
546 Date: Mon, 19 Dec 2016 16:25:26 -0800
547 Subject: [PATCH 06/15] s3: smbd: Opendir_internal() early return if
548 SMB_VFS_OPENDIR failed.
552 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496
554 Signed-off-by: Jeremy Allison <jra@samba.org>
556 source3/smbd/dir.c | 14 +++++++-------
557 1 file changed, 7 insertions(+), 7 deletions(-)
559 diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
560 index ebe2641f813..65327dd0dd1 100644
561 --- a/source3/smbd/dir.c
562 +++ b/source3/smbd/dir.c
563 @@ -1380,6 +1380,13 @@ static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
567 + dirp->dir = SMB_VFS_OPENDIR(conn, name, mask, attr);
569 + DEBUG(5,("OpenDir: Can't open %s. %s\n", name,
570 + strerror(errno) ));
575 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
577 @@ -1394,13 +1401,6 @@ static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
579 talloc_set_destructor(dirp, smb_Dir_destructor);
581 - dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
583 - DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
584 - strerror(errno) ));
595 From 49d22a0c51ef1f78f0488a7c35131887704e987b Mon Sep 17 00:00:00 2001
596 From: Jeremy Allison <jra@samba.org>
597 Date: Mon, 19 Dec 2016 16:35:00 -0800
598 Subject: [PATCH 07/15] s3: smbd: Create and use open_dir_safely(). Use from
601 Hardens OpenDir against TOC/TOU races.
605 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496
607 Signed-off-by: Jeremy Allison <jra@samba.org>
609 source3/smbd/dir.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++------
610 1 file changed, 59 insertions(+), 7 deletions(-)
612 diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
613 index 65327dd0dd1..2d168c3ba9f 100644
614 --- a/source3/smbd/dir.c
615 +++ b/source3/smbd/dir.c
616 @@ -1390,12 +1390,6 @@ static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
618 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
620 - dirp->dir_path = talloc_strdup(dirp, name);
621 - if (!dirp->dir_path) {
626 if (sconn && !sconn->using_smb2) {
627 sconn->searches.dirhandles_open++;
629 @@ -1408,12 +1402,70 @@ static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
633 +/****************************************************************************
634 + Open a directory handle by pathname, ensuring it's under the share path.
635 +****************************************************************************/
637 +static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
638 + connection_struct *conn,
643 + struct smb_Dir *dir_hnd = NULL;
644 + char *saved_dir = vfs_GetWd(ctx, conn);
647 + if (saved_dir == NULL) {
651 + if (vfs_ChDir(conn, name) == -1) {
656 + * Now the directory is pinned, use
657 + * REALPATH to ensure we can access it.
659 + status = check_name(conn, ".");
660 + if (!NT_STATUS_IS_OK(status)) {
664 + dir_hnd = OpenDir_internal(ctx,
670 + if (dir_hnd == NULL) {
675 + * OpenDir_internal only gets "." as the dir name.
676 + * Store the real dir name here.
679 + dir_hnd->dir_path = talloc_strdup(dir_hnd, name);
680 + if (!dir_hnd->dir_path) {
686 + vfs_ChDir(conn, saved_dir);
687 + TALLOC_FREE(saved_dir);
691 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
696 - return OpenDir_internal(mem_ctx,
697 + return open_dir_safely(mem_ctx,
705 From 6426ae1f9ef53158a6fbe1912dfec40d834115fe Mon Sep 17 00:00:00 2001
706 From: Jeremy Allison <jra@samba.org>
707 Date: Mon, 19 Dec 2016 12:13:20 -0800
708 Subject: [PATCH 08/15] s3: smbd: OpenDir_fsp() use early returns.
712 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496
714 Signed-off-by: Jeremy Allison <jra@samba.org>
716 source3/smbd/dir.c | 34 +++++++++++++++++++++-------------
717 1 file changed, 21 insertions(+), 13 deletions(-)
719 diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
720 index 2d168c3ba9f..6aed4a6da46 100644
721 --- a/source3/smbd/dir.c
722 +++ b/source3/smbd/dir.c
723 @@ -1485,7 +1485,17 @@ static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
724 struct smbd_server_connection *sconn = conn->sconn;
731 + if (!fsp->is_directory) {
736 + if (fsp->fh->fd == -1) {
742 @@ -1502,18 +1512,16 @@ static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
744 talloc_set_destructor(dirp, smb_Dir_destructor);
746 - if (fsp->is_directory && fsp->fh->fd != -1) {
747 - dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
748 - if (dirp->dir != NULL) {
751 - DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
755 - if (errno != ENOSYS) {
758 + dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
759 + if (dirp->dir != NULL) {
762 + DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
766 + if (errno != ENOSYS) {
775 From f6581858ce665b880c5fea465ec61b1b0c504d89 Mon Sep 17 00:00:00 2001
776 From: Jeremy Allison <jra@samba.org>
777 Date: Mon, 19 Dec 2016 12:15:59 -0800
778 Subject: [PATCH 09/15] s3: smbd: OpenDir_fsp() - Fix memory leak on error.
782 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496
784 Signed-off-by: Jeremy Allison <jra@samba.org>
786 source3/smbd/dir.c | 2 +-
787 1 file changed, 1 insertion(+), 1 deletion(-)
789 diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
790 index 6aed4a6da46..efd1a73aab6 100644
791 --- a/source3/smbd/dir.c
792 +++ b/source3/smbd/dir.c
793 @@ -1521,7 +1521,7 @@ static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
796 if (errno != ENOSYS) {
806 From bacba6987e58d44886d04b1dd5e36f7781dcd9b0 Mon Sep 17 00:00:00 2001
807 From: Jeremy Allison <jra@samba.org>
808 Date: Mon, 19 Dec 2016 12:32:07 -0800
809 Subject: [PATCH 10/15] s3: smbd: Move the reference counting and destructor
810 setup to just before retuning success.
814 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496
816 Signed-off-by: Jeremy Allison <jra@samba.org>
818 source3/smbd/dir.c | 10 +++++-----
819 1 file changed, 5 insertions(+), 5 deletions(-)
821 diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
822 index efd1a73aab6..5eca128c033 100644
823 --- a/source3/smbd/dir.c
824 +++ b/source3/smbd/dir.c
825 @@ -1507,11 +1507,6 @@ static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
829 - if (sconn && !sconn->using_smb2) {
830 - sconn->searches.dirhandles_open++;
832 - talloc_set_destructor(dirp, smb_Dir_destructor);
834 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
835 if (dirp->dir != NULL) {
837 @@ -1536,6 +1531,11 @@ static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
841 + if (sconn && !sconn->using_smb2) {
842 + sconn->searches.dirhandles_open++;
844 + talloc_set_destructor(dirp, smb_Dir_destructor);
853 From 34b3d05b55f5c40de76ba65d6b028818518a519f Mon Sep 17 00:00:00 2001
854 From: Jeremy Allison <jra@samba.org>
855 Date: Mon, 19 Dec 2016 12:35:32 -0800
856 Subject: [PATCH 11/15] s3: smbd: Correctly fallback to open_dir_safely if
857 FDOPENDIR not supported on system.
861 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496
863 Signed-off-by: Jeremy Allison <jra@samba.org>
865 source3/smbd/dir.c | 15 +++++++--------
866 1 file changed, 7 insertions(+), 8 deletions(-)
868 diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
869 index 5eca128c033..7690cb18c1a 100644
870 --- a/source3/smbd/dir.c
871 +++ b/source3/smbd/dir.c
872 @@ -1521,14 +1521,13 @@ static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
875 if (dirp->dir == NULL) {
876 - /* FDOPENDIR didn't work. Use OPENDIR instead. */
877 - dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
881 - DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
882 - strerror(errno) ));
884 + /* FDOPENDIR is not supported. Use OPENDIR instead. */
886 + return open_dir_safely(mem_ctx,
888 + fsp->fsp_name->base_name,
893 if (sconn && !sconn->using_smb2) {
898 From 84bc8b232a4495bff270b7800833ef6785937576 Mon Sep 17 00:00:00 2001
899 From: Jeremy Allison <jra@samba.org>
900 Date: Thu, 15 Dec 2016 12:52:13 -0800
901 Subject: [PATCH 12/15] s3: smbd: Remove O_NOFOLLOW guards. We insist on
906 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496
908 Signed-off-by: Jeremy Allison <jra@samba.org>
910 source3/smbd/open.c | 4 +---
911 1 file changed, 1 insertion(+), 3 deletions(-)
913 diff --git a/source3/smbd/open.c b/source3/smbd/open.c
914 index 35eee0a1485..8417f8aca4a 100644
915 --- a/source3/smbd/open.c
916 +++ b/source3/smbd/open.c
917 @@ -205,8 +205,7 @@ NTSTATUS fd_open(struct connection_struct *conn,
918 struct smb_filename *smb_fname = fsp->fsp_name;
919 NTSTATUS status = NT_STATUS_OK;
924 * Never follow symlinks on a POSIX client. The
925 * client should be doing this.
927 @@ -214,7 +213,6 @@ NTSTATUS fd_open(struct connection_struct *conn,
928 if (fsp->posix_open || !lp_symlinks(SNUM(conn))) {
933 fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
934 if (fsp->fh->fd == -1) {
939 From af0c5a266ae65ad2a638fe48a7ad7d77417f97d7 Mon Sep 17 00:00:00 2001
940 From: Jeremy Allison <jra@samba.org>
941 Date: Thu, 15 Dec 2016 12:56:08 -0800
942 Subject: [PATCH 13/15] s3: smbd: Move special handling of symlink errno's into
947 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496
949 Signed-off-by: Jeremy Allison <jra@samba.org>
951 source3/smbd/open.c | 30 ++++++++++++++++++++++++++++--
952 1 file changed, 28 insertions(+), 2 deletions(-)
954 diff --git a/source3/smbd/open.c b/source3/smbd/open.c
955 index 8417f8aca4a..e727e89e9d8 100644
956 --- a/source3/smbd/open.c
957 +++ b/source3/smbd/open.c
958 @@ -194,6 +194,31 @@ static NTSTATUS check_base_file_access(struct connection_struct *conn,
961 /****************************************************************************
962 + Handle differing symlink errno's
963 +****************************************************************************/
965 +static int link_errno_convert(int err)
967 +#if defined(ENOTSUP) && defined(OSF1)
968 + /* handle special Tru64 errno */
969 + if (err == ENOTSUP) {
972 +#endif /* ENOTSUP */
974 + /* fix broken NetBSD errno */
975 + if (err == EFTYPE) {
979 + /* fix broken FreeBSD errno */
980 + if (err == EMLINK) {
986 +/****************************************************************************
987 fd support routines - attempt to do a dos_open.
988 ****************************************************************************/
990 @@ -216,8 +241,9 @@ NTSTATUS fd_open(struct connection_struct *conn,
992 fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
993 if (fsp->fh->fd == -1) {
994 - status = map_nt_error_from_unix(errno);
995 - if (errno == EMFILE) {
996 + int posix_errno = link_errno_convert(errno);
997 + status = map_nt_error_from_unix(posix_errno);
998 + if (posix_errno == EMFILE) {
999 static time_t last_warned = 0L;
1001 if (time((time_t *) NULL) > last_warned) {
1006 From c3bc4ff0367d7a3ebfd64db6defddea0bc3a5f4a Mon Sep 17 00:00:00 2001
1007 From: Jeremy Allison <jra@samba.org>
1008 Date: Thu, 15 Dec 2016 13:04:46 -0800
1009 Subject: [PATCH 14/15] s3: smbd: Add the core functions to prevent symlink
1014 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496
1016 Signed-off-by: Jeremy Allison <jra@samba.org>
1018 source3/smbd/open.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1019 1 file changed, 242 insertions(+)
1021 diff --git a/source3/smbd/open.c b/source3/smbd/open.c
1022 index e727e89e9d8..0998adc416a 100644
1023 --- a/source3/smbd/open.c
1024 +++ b/source3/smbd/open.c
1025 @@ -218,6 +218,248 @@ static int link_errno_convert(int err)
1029 +static int non_widelink_open(struct connection_struct *conn,
1030 + const char *conn_rootdir,
1031 + files_struct *fsp,
1032 + struct smb_filename *smb_fname,
1035 + unsigned int link_depth);
1037 +/****************************************************************************
1038 + Follow a symlink in userspace.
1039 +****************************************************************************/
1041 +static int process_symlink_open(struct connection_struct *conn,
1042 + const char *conn_rootdir,
1043 + files_struct *fsp,
1044 + struct smb_filename *smb_fname,
1047 + unsigned int link_depth)
1050 + char *link_target = NULL;
1051 + int link_len = -1;
1052 + char *oldwd = NULL;
1053 + size_t rootdir_len = 0;
1054 + char *resolved_name = NULL;
1055 + bool matched = false;
1056 + int saved_errno = 0;
1059 + * Ensure we don't get stuck in a symlink loop.
1062 + if (link_depth >= 20) {
1067 + /* Allocate space for the link target. */
1068 + link_target = talloc_array(talloc_tos(), char, PATH_MAX);
1069 + if (link_target == NULL) {
1074 + /* Read the link target. */
1075 + link_len = SMB_VFS_READLINK(conn,
1076 + smb_fname->base_name,
1079 + if (link_len == -1) {
1083 + /* Ensure it's at least null terminated. */
1084 + link_target[link_len] = '\0';
1086 + /* Convert to an absolute path. */
1087 + resolved_name = SMB_VFS_REALPATH(conn, link_target);
1088 + if (resolved_name == NULL) {
1093 + * We know conn_rootdir starts with '/' and
1094 + * does not end in '/'. FIXME ! Should we
1095 + * smb_assert this ?
1097 + rootdir_len = strlen(conn_rootdir);
1099 + matched = (strncmp(conn_rootdir, resolved_name, rootdir_len) == 0);
1106 + * Turn into a path relative to the share root.
1108 + if (resolved_name[rootdir_len] == '\0') {
1109 + /* Link to the root of the share. */
1110 + smb_fname->base_name = talloc_strdup(talloc_tos(), ".");
1111 + if (smb_fname->base_name == NULL) {
1115 + } else if (resolved_name[rootdir_len] == '/') {
1116 + smb_fname->base_name = &resolved_name[rootdir_len+1];
1122 + oldwd = vfs_GetWd(talloc_tos(), conn);
1123 + if (oldwd == NULL) {
1127 + /* Ensure we operate from the root of the share. */
1128 + if (vfs_ChDir(conn, conn_rootdir) == -1) {
1132 + /* And do it all again.. */
1133 + fd = non_widelink_open(conn,
1141 + saved_errno = errno;
1146 + SAFE_FREE(resolved_name);
1147 + TALLOC_FREE(link_target);
1148 + if (oldwd != NULL) {
1149 + int ret = vfs_ChDir(conn, oldwd);
1151 + smb_panic("unable to get back to old directory\n");
1153 + TALLOC_FREE(oldwd);
1155 + if (saved_errno != 0) {
1156 + errno = saved_errno;
1161 +/****************************************************************************
1162 + Non-widelink open.
1163 +****************************************************************************/
1165 +static int non_widelink_open(struct connection_struct *conn,
1166 + const char *conn_rootdir,
1167 + files_struct *fsp,
1168 + struct smb_filename *smb_fname,
1171 + unsigned int link_depth)
1175 + struct smb_filename *smb_fname_rel = NULL;
1176 + int saved_errno = 0;
1177 + char *oldwd = NULL;
1178 + char *parent_dir = NULL;
1179 + const char *final_component = NULL;
1181 + if (!parent_dirname(talloc_tos(),
1182 + smb_fname->base_name,
1184 + &final_component)) {
1188 + oldwd = vfs_GetWd(talloc_tos(), conn);
1189 + if (oldwd == NULL) {
1193 + /* Pin parent directory in place. */
1194 + if (vfs_ChDir(conn, parent_dir) == -1) {
1198 + /* Ensure the relative path is below the share. */
1199 + status = check_reduced_name(conn, final_component);
1200 + if (!NT_STATUS_IS_OK(status)) {
1201 + saved_errno = map_errno_from_nt_status(status);
1205 + status = create_synthetic_smb_fname(talloc_tos(),
1207 + smb_fname->stream_name,
1210 + if (!NT_STATUS_IS_OK(status)) {
1211 + saved_errno = map_errno_from_nt_status(status);
1215 + flags |= O_NOFOLLOW;
1218 + struct smb_filename *tmp_name = fsp->fsp_name;
1219 + fsp->fsp_name = smb_fname_rel;
1220 + fd = SMB_VFS_OPEN(conn, smb_fname_rel, fsp, flags, mode);
1221 + fsp->fsp_name = tmp_name;
1225 + saved_errno = link_errno_convert(errno);
1226 + if (saved_errno == ELOOP) {
1227 + if (fsp->posix_open) {
1228 + /* Never follow symlinks on posix open. */
1231 + if (!lp_symlinks(SNUM(conn))) {
1232 + /* Explicitly no symlinks. */
1236 + * We have a symlink. Follow in userspace
1237 + * to ensure it's under the share definition.
1239 + fd = process_symlink_open(conn,
1248 + link_errno_convert(errno);
1255 + TALLOC_FREE(parent_dir);
1256 + TALLOC_FREE(smb_fname_rel);
1258 + if (oldwd != NULL) {
1259 + int ret = vfs_ChDir(conn, oldwd);
1261 + smb_panic("unable to get back to old directory\n");
1263 + TALLOC_FREE(oldwd);
1265 + if (saved_errno != 0) {
1266 + errno = saved_errno;
1271 /****************************************************************************
1272 fd support routines - attempt to do a dos_open.
1273 ****************************************************************************/
1278 From 6a88d1cf3deb54a784f50c8eba3b9a24a65c1b34 Mon Sep 17 00:00:00 2001
1279 From: Jeremy Allison <jra@samba.org>
1280 Date: Thu, 15 Dec 2016 13:06:31 -0800
1281 Subject: [PATCH 15/15] s3: smbd: Use the new non_widelink_open() function.
1285 BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496
1287 Signed-off-by: Jeremy Allison <jra@samba.org>
1289 source3/smbd/open.c | 23 ++++++++++++++++++++++-
1290 1 file changed, 22 insertions(+), 1 deletion(-)
1292 diff --git a/source3/smbd/open.c b/source3/smbd/open.c
1293 index 0998adc416a..65ca14ec8b8 100644
1294 --- a/source3/smbd/open.c
1295 +++ b/source3/smbd/open.c
1296 @@ -481,7 +481,28 @@ NTSTATUS fd_open(struct connection_struct *conn,
1297 flags |= O_NOFOLLOW;
1300 - fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
1301 + /* Ensure path is below share definition. */
1302 + if (!lp_widelinks(SNUM(conn))) {
1303 + const char *conn_rootdir = SMB_VFS_CONNECTPATH(conn,
1304 + smb_fname->base_name);
1305 + if (conn_rootdir == NULL) {
1306 + return NT_STATUS_NO_MEMORY;
1309 + * Only follow symlinks within a share
1312 + fsp->fh->fd = non_widelink_open(conn,
1320 + fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
1323 if (fsp->fh->fd == -1) {
1324 int posix_errno = link_errno_convert(errno);
1325 status = map_nt_error_from_unix(posix_errno);