samba: fix some security problems
[openwrt.git] / package / network / services / samba36 / patches / 027-CVE-2016-2118-v3-6.patch
diff --git a/package/network/services/samba36/patches/027-CVE-2016-2118-v3-6.patch b/package/network/services/samba36/patches/027-CVE-2016-2118-v3-6.patch
new file mode 100644 (file)
index 0000000..06c1b0b
--- /dev/null
@@ -0,0 +1,308 @@
+From d68424b5ef92f5810760f90e9eeb664572a61e4e Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze@samba.org>
+Date: Tue, 15 Dec 2015 14:49:36 +0100
+Subject: [PATCH 01/10] CVE-2016-2118: s3: rpcclient: change the default auth
+ level from DCERPC_AUTH_LEVEL_CONNECT to DCERPC_AUTH_LEVEL_INTEGRITY
+
+ncacn_ip_tcp:server should get the same protection as ncacn_np:server
+if authentication and smb signing is used.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=11616
+
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+
+(cherry picked from commit dab41dee8a4fb27dbf3913b0e44a4cc726e3ac98)
+---
+ source3/rpcclient/rpcclient.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/source3/rpcclient/rpcclient.c
++++ b/source3/rpcclient/rpcclient.c
+@@ -1062,10 +1062,9 @@ out_free:
+               }
+       }
+       if (pipe_default_auth_type != DCERPC_AUTH_TYPE_NONE) {
+-              /* If neither Integrity or Privacy are requested then
+-               * Use just Connect level */
++              /* If nothing is requested then default to integrity */
+               if (pipe_default_auth_level == DCERPC_AUTH_LEVEL_NONE) {
+-                      pipe_default_auth_level = DCERPC_AUTH_LEVEL_CONNECT;
++                      pipe_default_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+               }
+       }
+--- a/source4/librpc/rpc/dcerpc_util.c
++++ b/source4/librpc/rpc/dcerpc_util.c
+@@ -593,15 +593,15 @@ struct composite_context *dcerpc_pipe_au
+       /* Perform an authenticated DCE-RPC bind
+        */
+-      if (!(conn->flags & (DCERPC_SIGN|DCERPC_SEAL))) {
++      if (!(conn->flags & (DCERPC_CONNECT|DCERPC_SEAL))) {
+               /*
+                 we are doing an authenticated connection,
+-                but not using sign or seal. We must force
+-                the CONNECT dcerpc auth type as a NONE auth
+-                type doesn't allow authentication
+-                information to be passed.
++                which needs to use [connect], [sign] or [seal].
++                If nothing is specified, we default to [sign] now.
++                This give roughly the same protection as
++                ncacn_np with smb signing.
+               */
+-              conn->flags |= DCERPC_CONNECT;
++              conn->flags |= DCERPC_SIGN;
+       }
+       if (s->binding->flags & DCERPC_AUTH_SPNEGO) {
+--- /dev/null
++++ b/docs-xml/smbdotconf/security/allowdcerpcauthlevelconnect.xml
+@@ -0,0 +1,22 @@
++<samba:parameter name="allow dcerpc auth level connect"
++                 context="G"
++                 type="boolean"
++                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
++<description>
++      <para>This option controls whether DCERPC services are allowed to
++      be used with DCERPC_AUTH_LEVEL_CONNECT, which provides authentication,
++      but no per message integrity nor privacy protection.</para>
++
++      <para>The behavior can be controlled per interface name (e.g. lsarpc, netlogon, samr, srvsvc,
++      winreg, wkssvc ...) by using 'allow dcerpc auth level connect:interface = no' as option.</para>
++
++      <para>This option yields precedence to the implentation specific restrictions.
++      E.g. the drsuapi and backupkey protocols require DCERPC_AUTH_LEVEL_PRIVACY.
++      While others like samr and lsarpc have a hardcoded default of <constant>no</constant>.
++      </para>
++</description>
++
++<value type="default">no</value>
++<value type="example">yes</value>
++
++</samba:parameter>
+--- a/source3/include/proto.h
++++ b/source3/include/proto.h
+@@ -1821,6 +1821,7 @@ char* lp_perfcount_module(void);
+ void lp_set_passdb_backend(const char *backend);
+ void widelinks_warning(int snum);
+ char *lp_ncalrpc_dir(void);
++bool lp_allow_dcerpc_auth_level_connect(void);
+ /* The following definitions come from param/loadparm_server_role.c  */
+--- a/source3/param/loadparm.c
++++ b/source3/param/loadparm.c
+@@ -355,6 +355,7 @@ struct global {
+       bool bUseMmap;
+       bool bHostnameLookups;
+       bool bUnixExtensions;
++      bool bAllowDcerpcAuthLevelConnect;
+       bool bDisableNetbios;
+       char * szDedicatedKeytabFile;
+       int  iKerberosMethod;
+@@ -2303,6 +2304,15 @@ static struct parm_struct parm_table[] =
+               .flags          = FLAG_ADVANCED,
+       },
+       {
++              .label          = "allow dcerpc auth level connect",
++              .type           = P_BOOL,
++              .p_class        = P_GLOBAL,
++              .ptr            = &Globals.bAllowDcerpcAuthLevelConnect,
++              .special        = NULL,
++              .enum_list      = NULL,
++              .flags          = FLAG_ADVANCED,
++      },
++      {
+               .label          = "use spnego",
+               .type           = P_BOOL,
+               .p_class        = P_GLOBAL,
+@@ -5371,6 +5381,8 @@ static void init_globals(bool reinit_glo
+       Globals.bClientNTLMv2Auth = True; /* Client should always use use NTLMv2, as we can't tell that the server supports it, but most modern servers do */
+       /* Note, that we will also use NTLM2 session security (which is different), if it is available */
++      Globals.bAllowDcerpcAuthLevelConnect = false; /* we don't allow this by default */
++
+       Globals.map_to_guest = 0;       /* By Default, "Never" */
+       Globals.oplock_break_wait_time = 0;     /* By Default, 0 msecs. */
+       Globals.enhanced_browsing = true;
+@@ -5745,6 +5757,7 @@ FN_GLOBAL_INTEGER(lp_username_map_cache_
+ FN_GLOBAL_STRING(lp_check_password_script, &Globals.szCheckPasswordScript)
++FN_GLOBAL_BOOL(lp_allow_dcerpc_auth_level_connect, &Globals.bAllowDcerpcAuthLevelConnect)
+ FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook)
+ FN_GLOBAL_CONST_STRING(lp_template_homedir, &Globals.szTemplateHomedir)
+ FN_GLOBAL_CONST_STRING(lp_template_shell, &Globals.szTemplateShell)
+--- a/source3/include/ntdomain.h
++++ b/source3/include/ntdomain.h
+@@ -89,6 +89,10 @@ typedef struct pipe_rpc_fns {
+       uint32 context_id;
+       struct ndr_syntax_id syntax;
++      /*
++       * shall we allow "connect" auth level for this interface ?
++       */
++      bool allow_connect;
+ } PIPE_RPC_FNS;
+ /*
+--- a/source3/rpc_server/srv_pipe.c
++++ b/source3/rpc_server/srv_pipe.c
+@@ -44,6 +44,11 @@
+ #include "rpc_server/srv_pipe.h"
+ #include "../librpc/gen_ndr/ndr_dcerpc.h"
+ #include "../librpc/ndr/ndr_dcerpc.h"
++#include "../librpc/gen_ndr/ndr_samr.h"
++#include "../librpc/gen_ndr/ndr_lsa.h"
++#include "../librpc/gen_ndr/ndr_netlogon.h"
++#include "../librpc/gen_ndr/ndr_epmapper.h"
++#include "../librpc/gen_ndr/ndr_echo.h"
+ #undef DBGC_CLASS
+ #define DBGC_CLASS DBGC_RPC_SRV
+@@ -340,6 +345,8 @@ static bool check_bind_req(struct pipes_
+                          uint32 context_id)
+ {
+       struct pipe_rpc_fns *context_fns;
++      const char *interface_name = NULL;
++      bool ok;
+       DEBUG(3,("check_bind_req for %s\n",
+                get_pipe_name_from_syntax(talloc_tos(), abstract)));
+@@ -390,12 +397,57 @@ static bool check_bind_req(struct pipes_
+               return False;
+       }
++      interface_name = get_pipe_name_from_syntax(talloc_tos(),
++                                                 abstract);
++
++      SMB_ASSERT(interface_name != NULL);
++
+       context_fns->next = context_fns->prev = NULL;
+       context_fns->n_cmds = rpc_srv_get_pipe_num_cmds(abstract);
+       context_fns->cmds = rpc_srv_get_pipe_cmds(abstract);
+       context_fns->context_id = context_id;
+       context_fns->syntax = *abstract;
++      context_fns->allow_connect = lp_allow_dcerpc_auth_level_connect();
++      /*
++       * for the samr and the lsarpc interfaces we don't allow "connect"
++       * auth_level by default.
++       */
++      ok = ndr_syntax_id_equal(abstract, &ndr_table_samr.syntax_id);
++      if (ok) {
++              context_fns->allow_connect = false;
++      }
++      ok = ndr_syntax_id_equal(abstract, &ndr_table_lsarpc.syntax_id);
++      if (ok) {
++              context_fns->allow_connect = false;
++      }
++      ok = ndr_syntax_id_equal(abstract, &ndr_table_netlogon.syntax_id);
++      if (ok) {
++              context_fns->allow_connect = false;
++      }
++      /*
++       * for the epmapper and echo interfaces we allow "connect"
++       * auth_level by default.
++       */
++      ok = ndr_syntax_id_equal(abstract, &ndr_table_epmapper.syntax_id);
++      if (ok) {
++              context_fns->allow_connect = true;
++      }
++      ok = ndr_syntax_id_equal(abstract, &ndr_table_rpcecho.syntax_id);
++      if (ok) {
++              context_fns->allow_connect = true;
++      }
++      /*
++       * every interface can be modified to allow "connect" auth_level by
++       * using a parametric option like:
++       * allow dcerpc auth level connect:<interface>
++       * e.g.
++       * allow dcerpc auth level connect:samr = yes
++       */
++      context_fns->allow_connect = lp_parm_bool(-1,
++              "allow dcerpc auth level connect",
++              interface_name, context_fns->allow_connect);
++
+       /* add to the list of open contexts */
+       DLIST_ADD( p->contexts, context_fns );
+@@ -1736,6 +1788,7 @@ static bool api_pipe_request(struct pipe
+       TALLOC_CTX *frame = talloc_stackframe();
+       bool ret = False;
+       PIPE_RPC_FNS *pipe_fns;
++      const char *interface_name = NULL;
+       if (!p->pipe_bound) {
+               DEBUG(1, ("Pipe not bound!\n"));
+@@ -1757,8 +1810,36 @@ static bool api_pipe_request(struct pipe
+               return false;
+       }
++      interface_name = get_pipe_name_from_syntax(talloc_tos(),
++                                                 &pipe_fns->syntax);
++
++      SMB_ASSERT(interface_name != NULL);
++
+       DEBUG(5, ("Requested \\PIPE\\%s\n",
+-                get_pipe_name_from_syntax(talloc_tos(), &pipe_fns->syntax)));
++                interface_name));
++
++      switch (p->auth.auth_level) {
++      case DCERPC_AUTH_LEVEL_NONE:
++      case DCERPC_AUTH_LEVEL_INTEGRITY:
++      case DCERPC_AUTH_LEVEL_PRIVACY:
++              break;
++      default:
++              if (!pipe_fns->allow_connect) {
++                      DEBUG(1, ("%s: restrict auth_level_connect access "
++                                "to [%s] with auth[type=0x%x,level=0x%x] "
++                                "on [%s] from [%s]\n",
++                                __func__, interface_name,
++                                p->auth.auth_type,
++                                p->auth.auth_level,
++                                derpc_transport_string_by_transport(p->transport),
++                                p->client_id->name));
++
++                      setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED));
++                      TALLOC_FREE(frame);
++                      return true;
++              }
++              break;
++      }
+       if (!srv_pipe_check_verification_trailer(p, pkt, pipe_fns)) {
+               DEBUG(1, ("srv_pipe_check_verification_trailer: failed\n"));
+--- a/source3/selftest/knownfail
++++ b/source3/selftest/knownfail
+@@ -18,3 +18,5 @@ samba3.posix_s3.nbt.dgram.*netlogon2
+ samba3.*rap.sam.*.useradd # Not provided by Samba 3
+ samba3.*rap.sam.*.userdelete # Not provided by Samba 3
+ samba3.*rap.basic.*.netsessiongetinfo # Not provided by Samba 3
++samba3.blackbox.rpcclient.over.ncacn_np.with.*connect.* # we don't allow auth_level_connect anymore
++samba3.posix_s3.rpc.lsa.lookupsids.*ncacn_ip_tcp.*connect.* # we don't allow auth_level_connect anymore
+--- a/source3/selftest/tests.py
++++ b/source3/selftest/tests.py
+@@ -201,6 +201,8 @@ if sub.returncode == 0:
+             plansmbtorturetestsuite(t, "s3dc", '//$SERVER_IP/tmpguest -U$USERNAME%$PASSWORD')
+         elif t == "raw.samba3posixtimedlock":
+             plansmbtorturetestsuite(t, "s3dc", '//$SERVER_IP/tmpguest -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/dc/share')
++        elif t == "rpc.samr.passwords.validate":
++            plansmbtorturetestsuite(t, "s3dc", 'ncacn_np:$SERVER_IP[seal] -U$USERNAME%$PASSWORD', 'over ncacn_np ')
+         else:
+             plansmbtorturetestsuite(t, "s3dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
+--- a/source3/rpc_server/samr/srv_samr_nt.c
++++ b/source3/rpc_server/samr/srv_samr_nt.c
+@@ -6628,6 +6628,11 @@ NTSTATUS _samr_ValidatePassword(struct p
+       struct samr_GetDomPwInfo pw;
+       struct samr_PwInfo dom_pw_info;
++      if (p->auth.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
++              p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
++              return NT_STATUS_ACCESS_DENIED;
++      }
++
+       if (r->in.level < 1 || r->in.level > 3) {
+               return NT_STATUS_INVALID_INFO_CLASS;
+       }