1From d68424b5ef92f5810760f90e9eeb664572a61e4e Mon Sep 17 00:00:00 2001
2From: Stefan Metzmacher <metze@samba.org>
3Date: Tue, 15 Dec 2015 14:49:36 +0100
4Subject: [PATCH 01/10] CVE-2016-2118: s3: rpcclient: change the default auth
5 level from DCERPC_AUTH_LEVEL_CONNECT to DCERPC_AUTH_LEVEL_INTEGRITY
6
7ncacn_ip_tcp:server should get the same protection as ncacn_np:server
8if authentication and smb signing is used.
9
10BUG: https://bugzilla.samba.org/show_bug.cgi?id=11616
11
12Signed-off-by: Stefan Metzmacher <metze@samba.org>
13
14(cherry picked from commit dab41dee8a4fb27dbf3913b0e44a4cc726e3ac98)
15---
16 source3/rpcclient/rpcclient.c | 5 ++---
17 1 file changed, 2 insertions(+), 3 deletions(-)
18
19--- a/source3/rpcclient/rpcclient.c
20+++ b/source3/rpcclient/rpcclient.c
21@@ -1062,10 +1062,9 @@ out_free:
22 		}
23 	}
24 	if (pipe_default_auth_type != DCERPC_AUTH_TYPE_NONE) {
25-		/* If neither Integrity or Privacy are requested then
26-		 * Use just Connect level */
27+		/* If nothing is requested then default to integrity */
28 		if (pipe_default_auth_level == DCERPC_AUTH_LEVEL_NONE) {
29-			pipe_default_auth_level = DCERPC_AUTH_LEVEL_CONNECT;
30+			pipe_default_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
31 		}
32 	}
33 
34--- a/source4/librpc/rpc/dcerpc_util.c
35+++ b/source4/librpc/rpc/dcerpc_util.c
36@@ -593,15 +593,15 @@ struct composite_context *dcerpc_pipe_au
37 
38 	/* Perform an authenticated DCE-RPC bind
39 	 */
40-	if (!(conn->flags & (DCERPC_SIGN|DCERPC_SEAL))) {
41+	if (!(conn->flags & (DCERPC_CONNECT|DCERPC_SEAL))) {
42 		/*
43 		  we are doing an authenticated connection,
44-		  but not using sign or seal. We must force
45-		  the CONNECT dcerpc auth type as a NONE auth
46-		  type doesn't allow authentication
47-		  information to be passed.
48+		  which needs to use [connect], [sign] or [seal].
49+		  If nothing is specified, we default to [sign] now.
50+		  This give roughly the same protection as
51+		  ncacn_np with smb signing.
52 		*/
53-		conn->flags |= DCERPC_CONNECT;
54+		conn->flags |= DCERPC_SIGN;
55 	}
56 
57 	if (s->binding->flags & DCERPC_AUTH_SPNEGO) {
58--- /dev/null
59+++ b/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml
60@@ -0,0 +1,22 @@
61+<samba:parameter name="allow dcerpc auth level connect"
62+                 context="G"
63+                 type="boolean"
64+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
65+<description>
66+	<para>This option controls whether DCERPC services are allowed to
67+	be used with DCERPC_AUTH_LEVEL_CONNECT, which provides authentication,
68+	but no per message integrity nor privacy protection.</para>
69+
70+	<para>The behavior can be controlled per interface name (e.g. lsarpc, netlogon, samr, srvsvc,
71+	winreg, wkssvc ...) by using 'allow dcerpc auth level connect:interface = no' as option.</para>
72+
73+	<para>This option yields precedence to the implentation specific restrictions.
74+	E.g. the drsuapi and backupkey protocols require DCERPC_AUTH_LEVEL_PRIVACY.
75+	While others like samr and lsarpc have a hardcoded default of <constant>no</constant>.
76+	</para>
77+</description>
78+
79+<value type="default">no</value>
80+<value type="example">yes</value>
81+
82+</samba:parameter>
83--- a/source3/include/proto.h
84+++ b/source3/include/proto.h
85@@ -1821,6 +1821,7 @@ char* lp_perfcount_module(void);
86 void lp_set_passdb_backend(const char *backend);
87 void widelinks_warning(int snum);
88 char *lp_ncalrpc_dir(void);
89+bool lp_allow_dcerpc_auth_level_connect(void);
90 
91 /* The following definitions come from param/loadparm_server_role.c  */
92 
93--- a/source3/param/loadparm.c
94+++ b/source3/param/loadparm.c
95@@ -355,6 +355,7 @@ struct global {
96 	bool bUseMmap;
97 	bool bHostnameLookups;
98 	bool bUnixExtensions;
99+	bool bAllowDcerpcAuthLevelConnect;
100 	bool bDisableNetbios;
101 	char * szDedicatedKeytabFile;
102 	int  iKerberosMethod;
103@@ -2303,6 +2304,15 @@ static struct parm_struct parm_table[] =
104 		.flags		= FLAG_ADVANCED,
105 	},
106 	{
107+		.label		= "allow dcerpc auth level connect",
108+		.type		= P_BOOL,
109+		.p_class	= P_GLOBAL,
110+		.ptr		= &Globals.bAllowDcerpcAuthLevelConnect,
111+		.special	= NULL,
112+		.enum_list	= NULL,
113+		.flags		= FLAG_ADVANCED,
114+	},
115+	{
116 		.label		= "use spnego",
117 		.type		= P_BOOL,
118 		.p_class	= P_GLOBAL,
119@@ -5371,6 +5381,8 @@ static void init_globals(bool reinit_glo
120 	Globals.bClientNTLMv2Auth = True; /* Client should always use use NTLMv2, as we can't tell that the server supports it, but most modern servers do */
121 	/* Note, that we will also use NTLM2 session security (which is different), if it is available */
122 
123+	Globals.bAllowDcerpcAuthLevelConnect = false; /* we don't allow this by default */
124+
125 	Globals.map_to_guest = 0;	/* By Default, "Never" */
126 	Globals.oplock_break_wait_time = 0;	/* By Default, 0 msecs. */
127 	Globals.enhanced_browsing = true;
128@@ -5745,6 +5757,7 @@ FN_GLOBAL_INTEGER(lp_username_map_cache_
129 
130 FN_GLOBAL_STRING(lp_check_password_script, &Globals.szCheckPasswordScript)
131 
132+FN_GLOBAL_BOOL(lp_allow_dcerpc_auth_level_connect, &Globals.bAllowDcerpcAuthLevelConnect)
133 FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook)
134 FN_GLOBAL_CONST_STRING(lp_template_homedir, &Globals.szTemplateHomedir)
135 FN_GLOBAL_CONST_STRING(lp_template_shell, &Globals.szTemplateShell)
136--- a/source3/include/ntdomain.h
137+++ b/source3/include/ntdomain.h
138@@ -89,6 +89,10 @@ typedef struct pipe_rpc_fns {
139 	uint32 context_id;
140 	struct ndr_syntax_id syntax;
141 
142+	/*
143+	 * shall we allow "connect" auth level for this interface ?
144+	 */
145+	bool allow_connect;
146 } PIPE_RPC_FNS;
147 
148 /*
149--- a/source3/rpc_server/srv_pipe.c
150+++ b/source3/rpc_server/srv_pipe.c
151@@ -44,6 +44,11 @@
152 #include "rpc_server/srv_pipe.h"
153 #include "../librpc/gen_ndr/ndr_dcerpc.h"
154 #include "../librpc/ndr/ndr_dcerpc.h"
155+#include "../librpc/gen_ndr/ndr_samr.h"
156+#include "../librpc/gen_ndr/ndr_lsa.h"
157+#include "../librpc/gen_ndr/ndr_netlogon.h"
158+#include "../librpc/gen_ndr/ndr_epmapper.h"
159+#include "../librpc/gen_ndr/ndr_echo.h"
160 
161 #undef DBGC_CLASS
162 #define DBGC_CLASS DBGC_RPC_SRV
163@@ -340,6 +345,8 @@ static bool check_bind_req(struct pipes_
164 			   uint32 context_id)
165 {
166 	struct pipe_rpc_fns *context_fns;
167+	const char *interface_name = NULL;
168+	bool ok;
169 
170 	DEBUG(3,("check_bind_req for %s\n",
171 		 get_pipe_name_from_syntax(talloc_tos(), abstract)));
172@@ -390,12 +397,57 @@ static bool check_bind_req(struct pipes_
173 		return False;
174 	}
175 
176+	interface_name = get_pipe_name_from_syntax(talloc_tos(),
177+						   abstract);
178+
179+	SMB_ASSERT(interface_name != NULL);
180+
181 	context_fns->next = context_fns->prev = NULL;
182 	context_fns->n_cmds = rpc_srv_get_pipe_num_cmds(abstract);
183 	context_fns->cmds = rpc_srv_get_pipe_cmds(abstract);
184 	context_fns->context_id = context_id;
185 	context_fns->syntax = *abstract;
186 
187+	context_fns->allow_connect = lp_allow_dcerpc_auth_level_connect();
188+	/*
189+	 * for the samr and the lsarpc interfaces we don't allow "connect"
190+	 * auth_level by default.
191+	 */
192+	ok = ndr_syntax_id_equal(abstract, &ndr_table_samr.syntax_id);
193+	if (ok) {
194+		context_fns->allow_connect = false;
195+	}
196+	ok = ndr_syntax_id_equal(abstract, &ndr_table_lsarpc.syntax_id);
197+	if (ok) {
198+		context_fns->allow_connect = false;
199+	}
200+	ok = ndr_syntax_id_equal(abstract, &ndr_table_netlogon.syntax_id);
201+	if (ok) {
202+		context_fns->allow_connect = false;
203+	}
204+	/*
205+	 * for the epmapper and echo interfaces we allow "connect"
206+	 * auth_level by default.
207+	 */
208+	ok = ndr_syntax_id_equal(abstract, &ndr_table_epmapper.syntax_id);
209+	if (ok) {
210+		context_fns->allow_connect = true;
211+	}
212+	ok = ndr_syntax_id_equal(abstract, &ndr_table_rpcecho.syntax_id);
213+	if (ok) {
214+		context_fns->allow_connect = true;
215+	}
216+	/*
217+	 * every interface can be modified to allow "connect" auth_level by
218+	 * using a parametric option like:
219+	 * allow dcerpc auth level connect:<interface>
220+	 * e.g.
221+	 * allow dcerpc auth level connect:samr = yes
222+	 */
223+	context_fns->allow_connect = lp_parm_bool(-1,
224+		"allow dcerpc auth level connect",
225+		interface_name, context_fns->allow_connect);
226+
227 	/* add to the list of open contexts */
228 
229 	DLIST_ADD( p->contexts, context_fns );
230@@ -1736,6 +1788,7 @@ static bool api_pipe_request(struct pipe
231 	TALLOC_CTX *frame = talloc_stackframe();
232 	bool ret = False;
233 	PIPE_RPC_FNS *pipe_fns;
234+	const char *interface_name = NULL;
235 
236 	if (!p->pipe_bound) {
237 		DEBUG(1, ("Pipe not bound!\n"));
238@@ -1757,8 +1810,36 @@ static bool api_pipe_request(struct pipe
239 		return false;
240 	}
241 
242+	interface_name = get_pipe_name_from_syntax(talloc_tos(),
243+						   &pipe_fns->syntax);
244+
245+	SMB_ASSERT(interface_name != NULL);
246+
247 	DEBUG(5, ("Requested \\PIPE\\%s\n",
248-		  get_pipe_name_from_syntax(talloc_tos(), &pipe_fns->syntax)));
249+		  interface_name));
250+
251+	switch (p->auth.auth_level) {
252+	case DCERPC_AUTH_LEVEL_NONE:
253+	case DCERPC_AUTH_LEVEL_INTEGRITY:
254+	case DCERPC_AUTH_LEVEL_PRIVACY:
255+		break;
256+	default:
257+		if (!pipe_fns->allow_connect) {
258+			DEBUG(1, ("%s: restrict auth_level_connect access "
259+				  "to [%s] with auth[type=0x%x,level=0x%x] "
260+				  "on [%s] from [%s]\n",
261+				  __func__, interface_name,
262+				  p->auth.auth_type,
263+				  p->auth.auth_level,
264+				  derpc_transport_string_by_transport(p->transport),
265+				  p->client_id->name));
266+
267+			setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED));
268+			TALLOC_FREE(frame);
269+			return true;
270+		}
271+		break;
272+	}
273 
274 	if (!srv_pipe_check_verification_trailer(p, pkt, pipe_fns)) {
275 		DEBUG(1, ("srv_pipe_check_verification_trailer: failed\n"));
276--- a/source3/selftest/knownfail
277+++ b/source3/selftest/knownfail
278@@ -18,3 +18,5 @@ samba3.posix_s3.nbt.dgram.*netlogon2
279 samba3.*rap.sam.*.useradd # Not provided by Samba 3
280 samba3.*rap.sam.*.userdelete # Not provided by Samba 3
281 samba3.*rap.basic.*.netsessiongetinfo # Not provided by Samba 3
282+samba3.blackbox.rpcclient.over.ncacn_np.with.*connect.* # we don't allow auth_level_connect anymore
283+samba3.posix_s3.rpc.lsa.lookupsids.*ncacn_ip_tcp.*connect.* # we don't allow auth_level_connect anymore
284--- a/source3/selftest/tests.py
285+++ b/source3/selftest/tests.py
286@@ -201,6 +201,8 @@ if sub.returncode == 0:
287             plansmbtorturetestsuite(t, "s3dc", '//$SERVER_IP/tmpguest -U$USERNAME%$PASSWORD')
288         elif t == "raw.samba3posixtimedlock":
289             plansmbtorturetestsuite(t, "s3dc", '//$SERVER_IP/tmpguest -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/dc/share')
290+        elif t == "rpc.samr.passwords.validate":
291+            plansmbtorturetestsuite(t, "s3dc", 'ncacn_np:$SERVER_IP[seal] -U$USERNAME%$PASSWORD', 'over ncacn_np ')
292         else:
293             plansmbtorturetestsuite(t, "s3dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
294 
295--- a/source3/rpc_server/samr/srv_samr_nt.c
296+++ b/source3/rpc_server/samr/srv_samr_nt.c
297@@ -6628,6 +6628,11 @@ NTSTATUS _samr_ValidatePassword(struct p
298 	struct samr_GetDomPwInfo pw;
299 	struct samr_PwInfo dom_pw_info;
300 
301+	if (p->auth.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
302+		p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
303+		return NT_STATUS_ACCESS_DENIED;
304+	}
305+
306 	if (r->in.level < 1 || r->in.level > 3) {
307 		return NT_STATUS_INVALID_INFO_CLASS;
308 	}
309