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