Blob Blame History Raw
From a91cf9a5648184d39aa87e06d484b3d533aeefdb Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 5 Jan 2016 11:18:12 -0800
Subject: [PATCH 01/12] CVE-2015-7560: s3: smbd: Add refuse_symlink() function
 that can be used to prevent operations on a symlink.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 source3/smbd/trans2.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 41e1bb1..b9865fd 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -54,6 +54,34 @@ static char *store_file_unix_basic_info2(connection_struct *conn,
 				files_struct *fsp,
 				const SMB_STRUCT_STAT *psbuf);
 
+/****************************************************************************
+ Check if an open file handle or pathname is a symlink.
+****************************************************************************/
+
+static NTSTATUS refuse_symlink(connection_struct *conn,
+			const files_struct *fsp,
+			const char *name)
+{
+	SMB_STRUCT_STAT sbuf;
+	const SMB_STRUCT_STAT *pst = NULL;
+
+	if (fsp) {
+		pst = &fsp->fsp_name->st;
+	} else {
+		int ret = vfs_stat_smb_basename(conn,
+				name,
+				&sbuf);
+		if (ret == -1) {
+			return map_nt_error_from_unix(errno);
+		}
+		pst = &sbuf;
+	}
+	if (S_ISLNK(pst->st_ex_mode)) {
+		return NT_STATUS_ACCESS_DENIED;
+	}
+	return NT_STATUS_OK;
+}
+
 /********************************************************************
  The canonical "check access" based on object handle or path function.
 ********************************************************************/
-- 
1.9.1


From cd950ca41df5076c8622cdf9be0e0db165b992f1 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 5 Jan 2016 10:38:28 -0800
Subject: [PATCH 02/12] CVE-2015-7560: s3: smbd: Refuse to get an ACL from a
 POSIX file handle on a symlink.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 source3/smbd/nttrans.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 4423a44..8113909 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -1905,6 +1905,13 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
+	if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
+		DEBUG(10, ("ACL get on symlink %s denied.\n",
+			fsp_str_dbg(fsp)));
+		TALLOC_FREE(frame);
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
 	if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|
 			SECINFO_GROUP|SECINFO_SACL)) {
 		/* Don't return SECINFO_LABEL if anything else was
-- 
1.9.1


From b95ded07aec97c31c69f49f691d5f90fdee40f92 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 5 Jan 2016 10:52:50 -0800
Subject: [PATCH 03/12] CVE-2015-7560: s3: smbd: Refuse to set an ACL from a
 POSIX file handle on a symlink.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 source3/smbd/nttrans.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 8113909..372d420 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -875,6 +875,12 @@ NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd,
 		return NT_STATUS_OK;
 	}
 
+	if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
+		DEBUG(10, ("ACL set on symlink %s denied.\n",
+			fsp_str_dbg(fsp)));
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
 	if (psd->owner_sid == NULL) {
 		security_info_sent &= ~SECINFO_OWNER;
 	}
-- 
1.9.1


From 35abb608ce57efea1bc197b7d65f9347f9533f23 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 5 Jan 2016 11:22:12 -0800
Subject: [PATCH 04/12] CVE-2015-7560: s3: smbd: Refuse to set a POSIX ACL on a
 symlink.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 source3/smbd/trans2.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index b9865fd..a5eeda8 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -6745,6 +6745,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
 	uint16 num_def_acls;
 	bool valid_file_acls = True;
 	bool valid_def_acls = True;
+	NTSTATUS status;
 
 	if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
 		return NT_STATUS_INVALID_PARAMETER;
@@ -6772,6 +6773,11 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
+	status = refuse_symlink(conn, fsp, smb_fname->base_name);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
 	DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
 		smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
 		(unsigned int)num_file_acls,
-- 
1.9.1


From 95c3bf9102440cf299312acc0d0a89afebf0474e Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 5 Jan 2016 11:24:36 -0800
Subject: [PATCH 05/12] CVE-2015-7560: s3: smbd: Refuse to get a POSIX ACL on a
 symlink.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 source3/smbd/trans2.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index a5eeda8..8ea49f1e 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -5248,6 +5248,13 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 				uint16 num_file_acls = 0;
 				uint16 num_def_acls = 0;
 
+				status = refuse_symlink(conn,
+						fsp,
+						smb_fname->base_name);
+				if (!NT_STATUS_IS_OK(status)) {
+					return status;
+				}
+
 				if (fsp && fsp->fh->fd != -1) {
 					file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
 						talloc_tos());
-- 
1.9.1


From c7ea0914d3b4a3deaf31a742c6edf4c6e7a91939 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 5 Jan 2016 11:05:48 -0800
Subject: [PATCH 06/12] CVE-2015-7560: s3: smbd: Set return values early,
 allows removal of code duplication.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 source3/smbd/trans2.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 8ea49f1e..35a0ba2 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -238,11 +238,12 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
 	size_t num_names;
 	ssize_t sizeret = -1;
 
+	if (pnames) {
+		*pnames = NULL;
+	}
+	*pnum_names = 0;
+
 	if (!lp_ea_support(SNUM(conn))) {
-		if (pnames) {
-			*pnames = NULL;
-		}
-		*pnum_names = 0;
 		return NT_STATUS_OK;
 	}
 
@@ -292,10 +293,6 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
 
 	if (sizeret == 0) {
 		TALLOC_FREE(names);
-		if (pnames) {
-			*pnames = NULL;
-		}
-		*pnum_names = 0;
 		return NT_STATUS_OK;
 	}
 
-- 
1.9.1


From 142a3050ec9875501b4f5693792d133bc5c3331a Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 5 Jan 2016 11:29:38 -0800
Subject: [PATCH 07/12] CVE-2015-7560: s3: smbd: Silently return no EA's
 available on a symlink.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 source3/smbd/trans2.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 35a0ba2..29e28bd 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -237,6 +237,7 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
 	char **names, **tmp;
 	size_t num_names;
 	ssize_t sizeret = -1;
+	NTSTATUS status;
 
 	if (pnames) {
 		*pnames = NULL;
@@ -247,6 +248,14 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
 		return NT_STATUS_OK;
 	}
 
+	status = refuse_symlink(conn, fsp, fname);
+	if (!NT_STATUS_IS_OK(status)) {
+		/*
+		 * Just return no EA's on a symlink.
+		 */
+		return NT_STATUS_OK;
+	}
+
 	/*
 	 * TALLOC the result early to get the talloc hierarchy right.
 	 */
-- 
1.9.1


From 08cf63d886b2f59f94a749089b73599330cee0e7 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 5 Jan 2016 11:33:48 -0800
Subject: [PATCH 08/12] CVE-2015-7560: s3: smbd: Refuse to set EA's on a
 symlink.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 source3/smbd/trans2.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 29e28bd..aaaa5f4 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -659,6 +659,11 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
 		return NT_STATUS_EAS_NOT_SUPPORTED;
 	}
 
+	status = refuse_symlink(conn, fsp, smb_fname->base_name);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
 	status = check_access(conn, fsp, smb_fname, FILE_WRITE_EA);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
-- 
1.9.1


From 259fec336cee663044d7e107a3dfce6264f20e84 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 6 Jan 2016 17:17:24 -0800
Subject: [PATCH 09/12] CVE-2015-7560: s3: libsmb: Rename cli_posix_getfaclXX()
 functions to cli_posix_getacl() as they operate on pathnames.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 source3/client/client.c  |  2 +-
 source3/libsmb/clifile.c | 30 +++++++++++++++---------------
 source3/libsmb/proto.h   |  6 +++---
 3 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/source3/client/client.c b/source3/client/client.c
index 67cc359..a8e5338 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -3376,7 +3376,7 @@ static int cmd_getfacl(void)
 		return 1;
 	}
 
-	status = cli_posix_getfacl(targetcli, targetname, ctx, &rb_size, &retbuf);
+	status = cli_posix_getacl(targetcli, targetname, ctx, &rb_size, &retbuf);
 	if (!NT_STATUS_IS_OK(status)) {
 		d_printf("%s getfacl file %s\n",
 			 nt_errstr(status), src);
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index 61cb8b5..ff646e4 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -590,25 +590,25 @@ NTSTATUS cli_posix_hardlink(struct cli_state *cli,
 }
 
 /****************************************************************************
- Do a POSIX getfacl (UNIX extensions).
+ Do a POSIX getacl - pathname based ACL get (UNIX extensions).
 ****************************************************************************/
 
-struct getfacl_state {
+struct getacl_state {
 	uint32_t num_data;
 	uint8_t *data;
 };
 
-static void cli_posix_getfacl_done(struct tevent_req *subreq);
+static void cli_posix_getacl_done(struct tevent_req *subreq);
 
-struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
+struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
 					struct tevent_context *ev,
 					struct cli_state *cli,
 					const char *fname)
 {
 	struct tevent_req *req = NULL, *subreq = NULL;
-	struct getfacl_state *state = NULL;
+	struct getacl_state *state = NULL;
 
-	req = tevent_req_create(mem_ctx, &state, struct getfacl_state);
+	req = tevent_req_create(mem_ctx, &state, struct getacl_state);
 	if (req == NULL) {
 		return NULL;
 	}
@@ -617,16 +617,16 @@ struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
-	tevent_req_set_callback(subreq, cli_posix_getfacl_done, req);
+	tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
 	return req;
 }
 
-static void cli_posix_getfacl_done(struct tevent_req *subreq)
+static void cli_posix_getacl_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
 		subreq, struct tevent_req);
-	struct getfacl_state *state = tevent_req_data(
-		req, struct getfacl_state);
+	struct getacl_state *state = tevent_req_data(
+		req, struct getacl_state);
 	NTSTATUS status;
 
 	status = cli_qpathinfo_recv(subreq, state, &state->data,
@@ -638,12 +638,12 @@ static void cli_posix_getfacl_done(struct tevent_req *subreq)
 	tevent_req_done(req);
 }
 
-NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
+NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
 				TALLOC_CTX *mem_ctx,
 				size_t *prb_size,
 				char **retbuf)
 {
-	struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
+	struct getacl_state *state = tevent_req_data(req, struct getacl_state);
 	NTSTATUS status;
 
 	if (tevent_req_is_nterror(req, &status)) {
@@ -654,7 +654,7 @@ NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
 	return NT_STATUS_OK;
 }
 
-NTSTATUS cli_posix_getfacl(struct cli_state *cli,
+NTSTATUS cli_posix_getacl(struct cli_state *cli,
 			const char *fname,
 			TALLOC_CTX *mem_ctx,
 			size_t *prb_size,
@@ -679,7 +679,7 @@ NTSTATUS cli_posix_getfacl(struct cli_state *cli,
 		goto fail;
 	}
 
-	req = cli_posix_getfacl_send(frame,
+	req = cli_posix_getacl_send(frame,
 				ev,
 				cli,
 				fname);
@@ -693,7 +693,7 @@ NTSTATUS cli_posix_getfacl(struct cli_state *cli,
 		goto fail;
 	}
 
-	status = cli_posix_getfacl_recv(req, mem_ctx, prb_size, retbuf);
+	status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
 
  fail:
 	TALLOC_FREE(frame);
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index 2efb208..f5f35e0 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -256,15 +256,15 @@ NTSTATUS cli_posix_hardlink(struct cli_state *cli,
 			const char *newname);
 uint32_t unix_perms_to_wire(mode_t perms);
 mode_t wire_perms_to_unix(uint32_t perms);
-struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
+struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
 					struct tevent_context *ev,
 					struct cli_state *cli,
 					const char *fname);
-NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
+NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
 				TALLOC_CTX *mem_ctx,
 				size_t *prb_size,
 				char **retbuf);
-NTSTATUS cli_posix_getfacl(struct cli_state *cli,
+NTSTATUS cli_posix_getacl(struct cli_state *cli,
 			const char *fname,
 			TALLOC_CTX *mem_ctx,
 			size_t *prb_size,
-- 
1.9.1


From d9054880d4bdbcb05c677e494906a26d62afa3a1 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Wed, 6 Jan 2016 17:02:52 -0800
Subject: [PATCH 10/12] CVE-2015-7560: s3: libsmb: Add SMB1-only POSIX
 cli_posix_setacl() functions. Needed for tests.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 source3/libsmb/clifile.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++
 source3/libsmb/proto.h   |  11 ++++++
 2 files changed, 111 insertions(+)

diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index ff646e4..e4480c6 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -701,6 +701,106 @@ NTSTATUS cli_posix_getacl(struct cli_state *cli,
 }
 
 /****************************************************************************
+ Do a POSIX setacl - pathname based ACL set (UNIX extensions).
+****************************************************************************/
+
+struct setacl_state {
+	uint8_t *data;
+};
+
+static void cli_posix_setacl_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct cli_state *cli,
+					const char *fname,
+					const void *data,
+					size_t num_data)
+{
+	struct tevent_req *req = NULL, *subreq = NULL;
+	struct setacl_state *state = NULL;
+
+	req = tevent_req_create(mem_ctx, &state, struct setacl_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->data = talloc_memdup(state, data, num_data);
+	if (tevent_req_nomem(state->data, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	subreq = cli_setpathinfo_send(state,
+				ev,
+				cli,
+				SMB_SET_POSIX_ACL,
+				fname,
+				state->data,
+				num_data);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
+	return req;
+}
+
+static void cli_posix_setacl_done(struct tevent_req *subreq)
+{
+	NTSTATUS status = cli_setpathinfo_recv(subreq);
+	tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_posix_setacl(struct cli_state *cli,
+			const char *fname,
+			const void *acl_buf,
+			size_t acl_buf_size)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct tevent_context *ev = NULL;
+	struct tevent_req *req = NULL;
+	NTSTATUS status = NT_STATUS_OK;
+
+	if (smbXcli_conn_has_async_calls(cli->conn)) {
+		/*
+		 * Can't use sync call while an async call is in flight
+		 */
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto fail;
+	}
+
+	ev = samba_tevent_context_init(frame);
+	if (ev == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto fail;
+	}
+
+	req = cli_posix_setacl_send(frame,
+				ev,
+				cli,
+				fname,
+				acl_buf,
+				acl_buf_size);
+	if (req == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto fail;
+	}
+
+	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+		goto fail;
+	}
+
+	status = cli_posix_setacl_recv(req);
+
+ fail:
+	TALLOC_FREE(frame);
+	return status;
+}
+
+/****************************************************************************
  Stat a file (UNIX extensions).
 ****************************************************************************/
 
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index f5f35e0..08dda96 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -269,6 +269,17 @@ NTSTATUS cli_posix_getacl(struct cli_state *cli,
 			TALLOC_CTX *mem_ctx,
 			size_t *prb_size,
 			char **retbuf);
+struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct cli_state *cli,
+					const char *fname,
+					const void *acl_buf,
+					size_t acl_buf_size);
+NTSTATUS cli_posix_setacl_recv(struct tevent_req *req);
+NTSTATUS cli_posix_setacl(struct cli_state *cli,
+			const char *fname,
+			const void *acl_buf,
+			size_t acl_buf_size);
 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
 					struct tevent_context *ev,
 					struct cli_state *cli,
-- 
1.9.1


From 5de774189a4e7be050c67d06f450a498d90d4368 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 7 Jan 2016 12:58:34 -0800
Subject: [PATCH 11/12] CVE-2015-7560: s3: torture3: Add new POSIX-SYMLINK-ACL
 test.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 selftest/knownfail        |   1 +
 source3/selftest/tests.py |   2 +-
 source3/torture/torture.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 200 insertions(+), 1 deletion(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index fd41263..6696ba3 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -16,6 +16,7 @@
 ^samba3.smbtorture_s3.plain\(dc\).UID-REGRESSION-TEST # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain\(dc\).SHORTNAME-TEST # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain\(dc\).POSIX-APPEND # Fails against the s4 ntvfs server
+^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).POSIX-SYMLINK-ACL # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain\(dc\).NTTRANS-FSCTL # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain\(dc\).SMB2-NEGPROT # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain\(dc\).BAD-NBT-SESSION # Fails against the s4 ntvfs server
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index 7279927..e66ddbc 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -78,7 +78,7 @@ tests = ["RW1", "RW2", "RW3"]
 for t in tests:
     plantestsuite("samba3.smbtorture_s3.vfs_aio_fork(simpleserver).%s" % t, "simpleserver", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER_IP/vfs_aio_fork', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"])
 
-posix_tests = ["POSIX", "POSIX-APPEND"]
+posix_tests = ["POSIX", "POSIX-APPEND", "POSIX-SYMLINK-ACL"]
 
 for t in posix_tests:
     plantestsuite("samba3.smbtorture_s3.plain(s3dc).%s" % t, "s3dc", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER_IP/posix_share', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"])
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 0b37e5c..6c0ab17 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -5820,6 +5820,203 @@ static bool run_simple_posix_open_test(int dummy)
 	return correct;
 }
 
+/*
+ Test POSIX and Windows ACLs are rejected on symlinks.
+ */
+static bool run_acl_symlink_test(int dummy)
+{
+	static struct cli_state *cli;
+	const char *fname = "posix_file";
+	const char *sname = "posix_symlink";
+	uint16_t fnum = (uint16_t)-1;
+	bool correct = false;
+	NTSTATUS status;
+	char *posix_acl = NULL;
+	size_t posix_acl_len = 0;
+	char *posix_acl_sym = NULL;
+	size_t posix_acl_len_sym = 0;
+	struct security_descriptor *sd = NULL;
+	struct security_descriptor *sd_sym = NULL;
+	TALLOC_CTX *frame = NULL;
+
+	frame = talloc_stackframe();
+
+	printf("Starting acl symlink test\n");
+
+	if (!torture_open_connection(&cli, 0)) {
+		TALLOC_FREE(frame);
+		return false;
+	}
+
+	smbXcli_conn_set_sockopt(cli->conn, sockops);
+
+	status = torture_setup_unix_extensions(cli);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(frame);
+		return false;
+	}
+
+	cli_setatr(cli, fname, 0, 0);
+	cli_posix_unlink(cli, fname);
+	cli_setatr(cli, sname, 0, 0);
+	cli_posix_unlink(cli, sname);
+
+	status = cli_ntcreate(cli,
+			fname,
+			0,
+			READ_CONTROL_ACCESS,
+			0,
+			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+			FILE_CREATE,
+			0x0,
+			0x0,
+			&fnum,
+			NULL);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_ntcreate of %s failed (%s)\n",
+			fname,
+			nt_errstr(status));
+		goto out;
+	}
+
+	/* Get the Windows ACL on the file. */
+	status = cli_query_secdesc(cli,
+				fnum,
+				frame,
+				&sd);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_query_secdesc failed (%s)\n",
+			nt_errstr(status));
+		goto out;
+	}
+
+	/* Get the POSIX ACL on the file. */
+	status = cli_posix_getacl(cli,
+				fname,
+				frame,
+				&posix_acl_len,
+				&posix_acl);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_posix_getacl failed (%s)\n",
+			nt_errstr(status));
+		goto out;
+	}
+
+	status = cli_close(cli, fnum);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("close failed (%s)\n", nt_errstr(status));
+		goto out;
+	}
+	fnum = (uint16_t)-1;
+
+	/* Now create a symlink. */
+	status = cli_posix_symlink(cli, fname, sname);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_posix_symlink of %s -> %s failed (%s)\n",
+			sname,
+			fname,
+			nt_errstr(status));
+		goto out;
+	}
+
+	/* Open a handle on the symlink. */
+	status = cli_ntcreate(cli,
+			sname,
+			0,
+			READ_CONTROL_ACCESS|SEC_STD_WRITE_DAC,
+			0,
+			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+			FILE_OPEN,
+			0x0,
+			0x0,
+			&fnum,
+			NULL);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_posix_open of %s failed (%s)\n",
+			sname,
+			nt_errstr(status));
+		goto out;
+	}
+
+	/* Get the Windows ACL on the symlink handle. Should fail */
+	status = cli_query_secdesc(cli,
+				fnum,
+				frame,
+				&sd_sym);
+
+	if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+		printf("cli_query_secdesc on a symlink gave %s. "
+			"Should be NT_STATUS_ACCESS_DENIED.\n",
+			nt_errstr(status));
+		goto out;
+	}
+
+	/* Get the POSIX ACL on the symlink pathname. Should fail. */
+	status = cli_posix_getacl(cli,
+				sname,
+				frame,
+				&posix_acl_len_sym,
+				&posix_acl_sym);
+
+	if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+		printf("cli_posix_getacl on a symlink gave %s. "
+			"Should be NT_STATUS_ACCESS_DENIED.\n",
+			nt_errstr(status));
+		goto out;
+	}
+
+	/* Set the Windows ACL on the symlink handle. Should fail */
+	status = cli_set_security_descriptor(cli,
+				fnum,
+				SECINFO_DACL,
+				sd);
+
+	if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+		printf("cli_query_secdesc on a symlink gave %s. "
+			"Should be NT_STATUS_ACCESS_DENIED.\n",
+			nt_errstr(status));
+		goto out;
+	}
+
+	/* Set the POSIX ACL on the symlink pathname. Should fail. */
+	status = cli_posix_setacl(cli,
+				sname,
+				posix_acl,
+				posix_acl_len);
+
+	if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+		printf("cli_posix_getacl on a symlink gave %s. "
+			"Should be NT_STATUS_ACCESS_DENIED.\n",
+			nt_errstr(status));
+		goto out;
+	}
+
+	printf("ACL symlink test passed\n");
+	correct = true;
+
+  out:
+
+	if (fnum != (uint16_t)-1) {
+		cli_close(cli, fnum);
+		fnum = (uint16_t)-1;
+	}
+
+	cli_setatr(cli, sname, 0, 0);
+	cli_posix_unlink(cli, sname);
+	cli_setatr(cli, fname, 0, 0);
+	cli_posix_unlink(cli, fname);
+
+	if (!torture_close_connection(cli)) {
+		correct = false;
+	}
+
+	TALLOC_FREE(frame);
+	return correct;
+}
+
 
 static uint32 open_attrs_table[] = {
 		FILE_ATTRIBUTE_NORMAL,
@@ -9647,6 +9844,7 @@ static struct {
 	{"OPEN", run_opentest, 0},
 	{"POSIX", run_simple_posix_open_test, 0},
 	{"POSIX-APPEND", run_posix_append, 0},
+	{"POSIX-SYMLINK-ACL", run_acl_symlink_test, 0},
 	{"CASE-INSENSITIVE-CREATE", run_case_insensitive_create, 0},
 	{"ASYNC-ECHO", run_async_echo, 0},
 	{ "UID-REGRESSION-TEST", run_uid_regression_test, 0},
-- 
1.9.1


From 6149e7297d9279df3b535e72eabbede7bd235925 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Thu, 7 Jan 2016 14:26:35 -0800
Subject: [PATCH 12/12] CVE-2015-7560: s3: torture3: Add new POSIX-SYMLINK-EA
 test.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
---
 selftest/knownfail        |   1 +
 source3/selftest/tests.py |   2 +-
 source3/torture/torture.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 181 insertions(+), 1 deletion(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index 6696ba3..c919a6a 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -17,6 +17,7 @@
 ^samba3.smbtorture_s3.plain\(dc\).SHORTNAME-TEST # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain\(dc\).POSIX-APPEND # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).POSIX-SYMLINK-ACL # Fails against the s4 ntvfs server
+^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).POSIX-SYMLINK-EA # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain\(dc\).NTTRANS-FSCTL # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain\(dc\).SMB2-NEGPROT # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain\(dc\).BAD-NBT-SESSION # Fails against the s4 ntvfs server
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index e66ddbc..830753c 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -78,7 +78,7 @@ tests = ["RW1", "RW2", "RW3"]
 for t in tests:
     plantestsuite("samba3.smbtorture_s3.vfs_aio_fork(simpleserver).%s" % t, "simpleserver", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER_IP/vfs_aio_fork', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"])
 
-posix_tests = ["POSIX", "POSIX-APPEND", "POSIX-SYMLINK-ACL"]
+posix_tests = ["POSIX", "POSIX-APPEND", "POSIX-SYMLINK-ACL", "POSIX-SYMLINK-EA"]
 
 for t in posix_tests:
     plantestsuite("samba3.smbtorture_s3.plain(s3dc).%s" % t, "s3dc", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER_IP/posix_share', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"])
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 6c0ab17..34c1a37 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -6017,6 +6017,183 @@ static bool run_acl_symlink_test(int dummy)
 	return correct;
 }
 
+/*
+  Test setting EA's are rejected on symlinks.
+ */
+static bool run_ea_symlink_test(int dummy)
+{
+	static struct cli_state *cli;
+	const char *fname = "posix_file_ea";
+	const char *sname = "posix_symlink_ea";
+	const char *ea_name = "testea_name";
+	const char *ea_value = "testea_value";
+	uint16_t fnum = (uint16_t)-1;
+	bool correct = false;
+	NTSTATUS status;
+	size_t i, num_eas;
+	struct ea_struct *eas = NULL;
+	TALLOC_CTX *frame = NULL;
+
+	frame = talloc_stackframe();
+
+	printf("Starting EA symlink test\n");
+
+	if (!torture_open_connection(&cli, 0)) {
+		TALLOC_FREE(frame);
+		return false;
+	}
+
+	smbXcli_conn_set_sockopt(cli->conn, sockops);
+
+	status = torture_setup_unix_extensions(cli);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(frame);
+		return false;
+	}
+
+	cli_setatr(cli, fname, 0, 0);
+	cli_posix_unlink(cli, fname);
+	cli_setatr(cli, sname, 0, 0);
+	cli_posix_unlink(cli, sname);
+
+	status = cli_ntcreate(cli,
+			fname,
+			0,
+			READ_CONTROL_ACCESS,
+			0,
+			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+			FILE_CREATE,
+			0x0,
+			0x0,
+			&fnum,
+			NULL);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_ntcreate of %s failed (%s)\n",
+			fname,
+			nt_errstr(status));
+		goto out;
+	}
+
+	status = cli_close(cli, fnum);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("close failed (%s)\n",
+			nt_errstr(status));
+		goto out;
+	}
+	fnum = (uint16_t)-1;
+
+	/* Set an EA on the path. */
+	status = cli_set_ea_path(cli,
+				fname,
+				ea_name,
+				ea_value,
+				strlen(ea_value)+1);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_set_ea_path failed (%s)\n",
+			nt_errstr(status));
+		goto out;
+	}
+
+	/* Now create a symlink. */
+	status = cli_posix_symlink(cli, fname, sname);
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_posix_symlink of %s -> %s failed (%s)\n",
+			sname,
+			fname,
+			nt_errstr(status));
+		goto out;
+	}
+
+	/* Get the EA list on the path. Should return value set. */
+	status = cli_get_ea_list_path(cli,
+				fname,
+				frame,
+				&num_eas,
+				&eas);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_get_ea_list_path failed (%s)\n",
+			nt_errstr(status));
+		goto out;
+	}
+
+	/* Ensure the EA we set is there. */
+	for (i=0; i<num_eas; i++) {
+		if (strcmp(eas[i].name, ea_name) == 0 &&
+				eas[i].value.length == strlen(ea_value)+1 &&
+				memcmp(eas[i].value.data,
+					ea_value,
+					eas[i].value.length) == 0) {
+			break;
+		}
+	}
+
+	if (i == num_eas) {
+		printf("Didn't find EA on pathname %s\n",
+			fname);
+		goto out;
+	}
+
+	num_eas = 0;
+	TALLOC_FREE(eas);
+
+	/* Get the EA list on the symlink. Should return empty list. */
+	status = cli_get_ea_list_path(cli,
+				sname,
+				frame,
+				&num_eas,
+				&eas);
+
+	if (!NT_STATUS_IS_OK(status)) {
+		printf("cli_get_ea_list_path failed (%s)\n",
+			nt_errstr(status));
+		goto out;
+	}
+
+	if (num_eas != 0) {
+		printf("cli_get_ea_list_path failed (%s)\n",
+			nt_errstr(status));
+		goto out;
+	}
+
+	/* Set an EA on the symlink. Should fail. */
+	status = cli_set_ea_path(cli,
+				sname,
+				ea_name,
+				ea_value,
+				strlen(ea_value)+1);
+
+	if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+		printf("cli_set_ea_path on a symlink gave %s. "
+			"Should be NT_STATUS_ACCESS_DENIED.\n",
+			nt_errstr(status));
+		goto out;
+	}
+
+	printf("EA symlink test passed\n");
+	correct = true;
+
+  out:
+
+	if (fnum != (uint16_t)-1) {
+		cli_close(cli, fnum);
+		fnum = (uint16_t)-1;
+	}
+
+	cli_setatr(cli, sname, 0, 0);
+	cli_posix_unlink(cli, sname);
+	cli_setatr(cli, fname, 0, 0);
+	cli_posix_unlink(cli, fname);
+
+	if (!torture_close_connection(cli)) {
+		correct = false;
+	}
+
+	TALLOC_FREE(frame);
+	return correct;
+}
 
 static uint32 open_attrs_table[] = {
 		FILE_ATTRIBUTE_NORMAL,
@@ -9845,6 +10022,8 @@ static struct {
 	{"POSIX", run_simple_posix_open_test, 0},
 	{"POSIX-APPEND", run_posix_append, 0},
 	{"POSIX-SYMLINK-ACL", run_acl_symlink_test, 0},
+	{"POSIX-SYMLINK-ACL", run_acl_symlink_test, 0},
+	{"POSIX-SYMLINK-EA", run_ea_symlink_test, 0},
 	{"CASE-INSENSITIVE-CREATE", run_case_insensitive_create, 0},
 	{"ASYNC-ECHO", run_async_echo, 0},
 	{ "UID-REGRESSION-TEST", run_uid_regression_test, 0},
-- 
1.9.1