samba: fix some security problems

This fixes the following security problems:
* CVE-2015-7560
* CVE-2015-5370
* CVE-2016-2110
* CVE-2016-2111
* CVE-2016-2112
* CVE-2016-2115
* CVE-2016-2118

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>

SVN-Revision: 49175
This commit is contained in:
Hauke Mehrtens 2016-04-16 20:06:34 +00:00
parent 894aed060e
commit 1414f1647d
21 changed files with 20105 additions and 46 deletions

View file

@ -14,11 +14,9 @@ Reviewed-by: Volker Lendecke <vl@samba.org>
source3/smbd/vfs.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 6c56964..bd93b7f 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -982,6 +982,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
@@ -982,6 +982,7 @@ NTSTATUS check_reduced_name(connection_s
if (!allow_widelinks || !allow_symlinks) {
const char *conn_rootdir;
size_t rootdir_len;
@ -26,7 +24,7 @@ index 6c56964..bd93b7f 100644
conn_rootdir = SMB_VFS_CONNECTPATH(conn, fname);
if (conn_rootdir == NULL) {
@@ -992,8 +993,10 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
@@ -992,8 +993,10 @@ NTSTATUS check_reduced_name(connection_s
}
rootdir_len = strlen(conn_rootdir);
@ -39,5 +37,3 @@ index 6c56964..bd93b7f 100644
DEBUG(2, ("check_reduced_name: Bad access "
"attempt: %s is a symlink outside the "
"share path\n", fname));
--
2.5.0

View file

@ -12,11 +12,9 @@ Reviewed-by: Jeremy Allison <jra@samba.org>
source3/libsmb/clidfs.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c
index 23e1471..f153b6b 100644
--- a/source3/libsmb/clidfs.c
+++ b/source3/libsmb/clidfs.c
@@ -98,6 +98,11 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx,
@@ -98,6 +98,11 @@ static struct cli_state *do_connect(TALL
const char *username;
const char *password;
NTSTATUS status;
@ -28,7 +26,7 @@ index 23e1471..f153b6b 100644
/* make a copy so we don't modify the global string 'service' */
servicename = talloc_strdup(ctx,share);
@@ -132,7 +137,7 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx,
@@ -132,7 +137,7 @@ static struct cli_state *do_connect(TALL
zero_sockaddr(&ss);
/* have to open a new connection */
@ -37,26 +35,6 @@ index 23e1471..f153b6b 100644
if (c == NULL) {
d_printf("Connection to %s failed\n", server_n);
return NULL;
--
2.5.0
From 060adb0abdeda51b8b622c6020b5dea0c8dde1cf Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Wed, 30 Sep 2015 21:17:02 +0200
Subject: [PATCH 2/2] CVE-2015-5296: s3:libsmb: force signing when requiring
encryption in SMBC_server_internal()
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11536
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
---
source3/libsmb/libsmb_server.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c
index 45be660..167f2c9 100644
--- a/source3/libsmb/libsmb_server.c
+++ b/source3/libsmb/libsmb_server.c
@@ -258,6 +258,7 @@ SMBC_server_internal(TALLOC_CTX *ctx,
@ -108,5 +86,3 @@ index 45be660..167f2c9 100644
if (! NT_STATUS_IS_OK(nt_status)) {
DEBUG(1,("cli_full_connection failed! (%s)\n",
nt_errstr(nt_status)));
--
2.5.0

View file

@ -14,8 +14,6 @@ Reviewed-by: David Disseldorp <ddiss@samba.org>
source3/modules/vfs_shadow_copy2.c | 47 ++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index fedfb53..16c1ed7 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -21,6 +21,8 @@
@ -27,7 +25,7 @@ index fedfb53..16c1ed7 100644
#include "system/filesys.h"
#include "ntioctl.h"
@@ -764,6 +766,43 @@ static int shadow_copy2_mkdir(vfs_handle_struct *handle, const char *fname, mod
@@ -764,6 +766,43 @@ static int shadow_copy2_mkdir(vfs_handle
SHADOW2_NEXT(MKDIR, (handle, name, mode), int, -1);
}
@ -71,7 +69,7 @@ index fedfb53..16c1ed7 100644
static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
{
SHADOW2_NEXT(RMDIR, (handle, name), int, -1);
@@ -877,6 +916,7 @@ static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle,
@@ -877,6 +916,7 @@ static int shadow_copy2_get_shadow_copy2
SMB_STRUCT_DIRENT *d;
TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
char *snapshot;
@ -79,7 +77,7 @@ index fedfb53..16c1ed7 100644
snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
if (snapdir == NULL) {
@@ -886,6 +926,13 @@ static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle,
@@ -886,6 +926,13 @@ static int shadow_copy2_get_shadow_copy2
talloc_free(tmp_ctx);
return -1;
}
@ -93,5 +91,3 @@ index fedfb53..16c1ed7 100644
p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
--
2.5.0

View file

@ -0,0 +1,172 @@
From eb27f9b7bf9c1dc902d9545eecf805831bd4e46c Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 5 Jan 2016 11:18:12 -0800
Subject: [PATCH 1/8] 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: Michael Adam <obnox@samba.org>
---
source3/smbd/trans2.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -51,6 +51,34 @@ static char *store_file_unix_basic_info2
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_fname(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;
+}
+
/********************************************************************
Roundup a value to the nearest allocation roundup size boundary.
Only do this for Windows clients.
@@ -181,12 +209,22 @@ NTSTATUS get_ea_names_from_file(TALLOC_C
char **names, **tmp;
size_t num_names;
ssize_t sizeret = -1;
+ NTSTATUS status;
+
+ if (pnames) {
+ *pnames = NULL;
+ }
+ *pnum_names = 0;
if (!lp_ea_support(SNUM(conn))) {
- if (pnames) {
- *pnames = NULL;
- }
- *pnum_names = 0;
+ 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;
}
@@ -236,10 +274,6 @@ NTSTATUS get_ea_names_from_file(TALLOC_C
if (sizeret == 0) {
TALLOC_FREE(names);
- if (pnames) {
- *pnames = NULL;
- }
- *pnum_names = 0;
return NT_STATUS_OK;
}
@@ -550,6 +584,7 @@ NTSTATUS set_ea(connection_struct *conn,
const struct smb_filename *smb_fname, struct ea_list *ea_list)
{
char *fname = NULL;
+ NTSTATUS status;
if (!lp_ea_support(SNUM(conn))) {
return NT_STATUS_EAS_NOT_SUPPORTED;
@@ -559,6 +594,12 @@ NTSTATUS set_ea(connection_struct *conn,
return NT_STATUS_ACCESS_DENIED;
}
+ status = refuse_symlink(conn, fsp, smb_fname->base_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+
/* For now setting EAs on streams isn't supported. */
fname = smb_fname->base_name;
@@ -4931,6 +4972,13 @@ NTSTATUS smbd_do_qfilepathinfo(connectio
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);
} else {
@@ -6452,6 +6500,7 @@ static NTSTATUS smb_set_posix_acl(connec
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;
@@ -6479,6 +6528,11 @@ static NTSTATUS smb_set_posix_acl(connec
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,
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -877,6 +877,12 @@ NTSTATUS set_sd(files_struct *fsp, struc
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;
}
@@ -1925,6 +1931,12 @@ NTSTATUS smbd_do_query_security_desc(con
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)));
+ 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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,255 @@
From 202d69267c8550b850438877fb51c3d2c992949d Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Tue, 1 Dec 2015 08:46:45 +0100
Subject: [PATCH 01/10] CVE-2016-2110: s3:ntlmssp: set and use
ntlmssp_state->allow_lm_key
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11644
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Günther Deschner <gd@samba.org>
---
source3/libsmb/ntlmssp.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/source3/libsmb/ntlmssp.c
+++ b/source3/libsmb/ntlmssp.c
@@ -176,17 +176,19 @@ void ntlmssp_want_feature_list(struct nt
* also add NTLMSSP_NEGOTIATE_SEAL here. JRA.
*/
if (in_list("NTLMSSP_FEATURE_SESSION_KEY", feature_list, True)) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
}
if (in_list("NTLMSSP_FEATURE_SIGN", feature_list, True)) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
}
if(in_list("NTLMSSP_FEATURE_SEAL", feature_list, True)) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL;
}
if (in_list("NTLMSSP_FEATURE_CCACHE", feature_list, true)) {
ntlmssp_state->use_ccache = true;
}
+
+ ntlmssp_state->neg_flags |= ntlmssp_state->required_flags;
}
/**
@@ -199,17 +201,20 @@ void ntlmssp_want_feature(struct ntlmssp
{
/* As per JRA's comment above */
if (feature & NTLMSSP_FEATURE_SESSION_KEY) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
}
if (feature & NTLMSSP_FEATURE_SIGN) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
}
if (feature & NTLMSSP_FEATURE_SEAL) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_SEAL;
}
if (feature & NTLMSSP_FEATURE_CCACHE) {
ntlmssp_state->use_ccache = true;
}
+
+ ntlmssp_state->neg_flags |= ntlmssp_state->required_flags;
}
/**
@@ -387,7 +392,12 @@ static NTSTATUS ntlmssp_client_initial(s
}
if (ntlmssp_state->use_ntlmv2) {
- ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+ ntlmssp_state->required_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+ ntlmssp_state->allow_lm_key = false;
+ }
+
+ if (ntlmssp_state->allow_lm_key) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
}
/* generate the ntlmssp negotiate packet */
@@ -422,6 +432,86 @@ static NTSTATUS ntlmssp_client_initial(s
return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
+static NTSTATUS ntlmssp3_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
+ uint32_t flags)
+{
+ uint32_t missing_flags = ntlmssp_state->required_flags;
+
+ if (flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
+ ntlmssp_state->unicode = true;
+ } else {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
+ ntlmssp_state->unicode = false;
+ }
+
+ /*
+ * NTLMSSP_NEGOTIATE_NTLM2 (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)
+ * has priority over NTLMSSP_NEGOTIATE_LM_KEY
+ */
+ if (!(flags & NTLMSSP_NEGOTIATE_NTLM2)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+ }
+
+ if (!(flags & NTLMSSP_NEGOTIATE_LM_KEY)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+ }
+
+ if (!(flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+ }
+
+ if (!(flags & NTLMSSP_NEGOTIATE_128)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
+ }
+
+ if (!(flags & NTLMSSP_NEGOTIATE_56)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56;
+ }
+
+ if (!(flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH;
+ }
+
+ if (!(flags & NTLMSSP_NEGOTIATE_SIGN)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
+ }
+
+ if (!(flags & NTLMSSP_NEGOTIATE_SEAL)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SEAL;
+ }
+
+ if ((flags & NTLMSSP_REQUEST_TARGET)) {
+ ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET;
+ }
+
+ missing_flags &= ~ntlmssp_state->neg_flags;
+ if (missing_flags != 0) {
+ NTSTATUS status = NT_STATUS_RPC_SEC_PKG_ERROR;
+ DEBUG(1, ("%s: Got challenge flags[0x%08x] "
+ "- possible downgrade detected! "
+ "missing_flags[0x%08x] - %s\n",
+ __func__,
+ (unsigned)flags,
+ (unsigned)missing_flags,
+ nt_errstr(status)));
+ debug_ntlmssp_flags(missing_flags);
+ DEBUGADD(4, ("neg_flags[0x%08x]\n",
+ (unsigned)ntlmssp_state->neg_flags));
+ debug_ntlmssp_flags(ntlmssp_state->neg_flags);
+
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
/**
* Next state function for the Challenge Packet. Generate an auth packet.
*
@@ -448,6 +538,26 @@ static NTSTATUS ntlmssp_client_challenge
DATA_BLOB encrypted_session_key = data_blob_null;
NTSTATUS nt_status = NT_STATUS_OK;
+ if (!msrpc_parse(ntlmssp_state, &reply, "CdBd",
+ "NTLMSSP",
+ &ntlmssp_command,
+ &server_domain_blob,
+ &chal_flags)) {
+ DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
+ dump_data(2, reply.data, reply.length);
+
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ data_blob_free(&server_domain_blob);
+
+ DEBUG(3, ("Got challenge flags:\n"));
+ debug_ntlmssp_flags(chal_flags);
+
+ nt_status = ntlmssp3_handle_neg_flags(ntlmssp_state, chal_flags);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
if (ntlmssp_state->use_ccache) {
struct wbcCredentialCacheParams params;
struct wbcCredentialCacheInfo *info = NULL;
@@ -498,17 +608,6 @@ static NTSTATUS ntlmssp_client_challenge
noccache:
- if (!msrpc_parse(ntlmssp_state, &reply, "CdBd",
- "NTLMSSP",
- &ntlmssp_command,
- &server_domain_blob,
- &chal_flags)) {
- DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
- dump_data(2, reply.data, reply.length);
-
- return NT_STATUS_INVALID_PARAMETER;
- }
-
if (DEBUGLEVEL >= 10) {
struct CHALLENGE_MESSAGE *challenge = talloc(
talloc_tos(), struct CHALLENGE_MESSAGE);
@@ -525,13 +624,6 @@ noccache:
}
}
- data_blob_free(&server_domain_blob);
-
- DEBUG(3, ("Got challenge flags:\n"));
- debug_ntlmssp_flags(chal_flags);
-
- ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth());
-
if (ntlmssp_state->unicode) {
if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) {
chal_parse_string = "CdUdbddB";
@@ -769,6 +861,7 @@ NTSTATUS ntlmssp_client_start(TALLOC_CTX
ntlmssp_state->unicode = True;
ntlmssp_state->use_ntlmv2 = use_ntlmv2;
+ ntlmssp_state->allow_lm_key = lp_client_lanman_auth();
ntlmssp_state->expected_state = NTLMSSP_INITIAL;
@@ -780,6 +873,10 @@ NTSTATUS ntlmssp_client_start(TALLOC_CTX
NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_REQUEST_TARGET;
+ if (ntlmssp_state->use_ntlmv2) {
+ ntlmssp_state->allow_lm_key = false;
+ }
+
ntlmssp_state->client.netbios_name = talloc_strdup(ntlmssp_state, netbios_name);
if (!ntlmssp_state->client.netbios_name) {
talloc_free(ntlmssp_state);
--- a/libcli/auth/ntlmssp.h
+++ b/libcli/auth/ntlmssp.h
@@ -83,6 +83,7 @@ struct ntlmssp_state
DATA_BLOB nt_resp;
DATA_BLOB session_key;
+ uint32_t required_flags;
uint32_t neg_flags; /* the current state of negotiation with the NTLMSSP partner */
/**

View file

@ -0,0 +1,681 @@
From ee105156fa151ebfd34b8febc2928e144b3b7b0e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
Date: Sat, 26 Sep 2015 01:29:10 +0200
Subject: [PATCH 01/15] CVE-2016-2111: s3:rpc_server/netlogon: always go
through netr_creds_server_step_check()
The ensures we apply the "server schannel = yes" restrictions.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11749
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Guenther Deschner <gd@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
source3/rpc_server/netlogon/srv_netlog_nt.c | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -1508,6 +1508,7 @@ static NTSTATUS _netr_LogonSamLogon_base
case NetlogonNetworkTransitiveInformation:
{
const char *wksname = nt_workstation;
+ const char *workgroup = lp_workgroup();
status = make_auth_context_fixed(talloc_tos(), &auth_context,
logon->network->challenge);
@@ -1532,6 +1533,14 @@ static NTSTATUS _netr_LogonSamLogon_base
logon->network->nt.length)) {
status = NT_STATUS_NO_MEMORY;
}
+
+ if (NT_STATUS_IS_OK(status)) {
+ status = NTLMv2_RESPONSE_verify_netlogon_creds(
+ user_info->client.account_name,
+ user_info->client.domain_name,
+ user_info->password.response.nt,
+ creds, workgroup);
+ }
break;
}
case NetlogonInteractiveInformation:
@@ -1636,6 +1645,14 @@ static NTSTATUS _netr_LogonSamLogon_base
r->out.validation->sam3);
break;
case 6:
+ /* Only allow this if the pipe is protected. */
+ if (p->auth.auth_level < DCERPC_AUTH_LEVEL_PRIVACY) {
+ DEBUG(0,("netr_Validation6: client %s not using privacy for netlogon\n",
+ get_remote_machine_name()));
+ status = NT_STATUS_INVALID_PARAMETER;
+ break;
+ }
+
status = serverinfo_to_SamInfo6(server_info, pipe_session_key, 16,
r->out.validation->sam6);
break;
@@ -2271,11 +2288,13 @@ NTSTATUS _netr_GetForestTrustInformation
/* TODO: check server name */
- status = schannel_check_creds_state(p->mem_ctx, lp_private_dir(),
- r->in.computer_name,
- r->in.credential,
- r->out.return_authenticator,
- &creds);
+ become_root();
+ status = netr_creds_server_step_check(p, p->mem_ctx,
+ r->in.computer_name,
+ r->in.credential,
+ r->out.return_authenticator,
+ &creds);
+ unbecome_root();
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -2371,11 +2390,13 @@ NTSTATUS _netr_ServerGetTrustInfo(struct
/* TODO: check server name */
- status = schannel_check_creds_state(p->mem_ctx, lp_private_dir(),
- r->in.computer_name,
- r->in.credential,
- r->out.return_authenticator,
- &creds);
+ become_root();
+ status = netr_creds_server_step_check(p, p->mem_ctx,
+ r->in.computer_name,
+ r->in.credential,
+ r->out.return_authenticator,
+ &creds);
+ unbecome_root();
if (!NT_STATUS_IS_OK(status)) {
return status;
}
--- a/source4/torture/rpc/samba3rpc.c
+++ b/source4/torture/rpc/samba3rpc.c
@@ -1122,8 +1122,8 @@ static bool schan(struct torture_context
generate_random_buffer(chal.data, chal.length);
names_blob = NTLMv2_generate_names_blob(
mem_ctx,
- cli_credentials_get_workstation(user_creds),
- cli_credentials_get_domain(user_creds));
+ cli_credentials_get_workstation(wks_creds),
+ cli_credentials_get_domain(wks_creds));
status = cli_credentials_get_ntlm_response(
user_creds, mem_ctx, &flags, chal, names_blob,
&lm_resp, &nt_resp, NULL, NULL);
--- a/libcli/auth/proto.h
+++ b/libcli/auth/proto.h
@@ -139,6 +139,11 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ct
const DATA_BLOB *names_blob,
DATA_BLOB *lm_response, DATA_BLOB *nt_response,
DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ;
+NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
+ const char *account_domain,
+ const DATA_BLOB response,
+ const struct netlogon_creds_CredentialState *creds,
+ const char *workgroup);
/***********************************************************
encode a password buffer with a unicode password. The buffer
--- a/libcli/auth/smbencrypt.c
+++ b/libcli/auth/smbencrypt.c
@@ -26,7 +26,7 @@
#include "../libcli/auth/msrpc_parse.h"
#include "../lib/crypto/crypto.h"
#include "../libcli/auth/libcli_auth.h"
-#include "../librpc/gen_ndr/ntlmssp.h"
+#include "../librpc/gen_ndr/ndr_ntlmssp.h"
void SMBencrypt_hash(const uint8_t lm_hash[16], const uint8_t *c8, uint8_t p24[24])
{
@@ -522,6 +522,146 @@ bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ct
lm_response, nt_response, lm_session_key, user_session_key);
}
+NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
+ const char *account_domain,
+ const DATA_BLOB response,
+ const struct netlogon_creds_CredentialState *creds,
+ const char *workgroup)
+{
+ TALLOC_CTX *frame = NULL;
+ /* RespType + HiRespType */
+ static const char *magic = "\x01\x01";
+ int cmp;
+ struct NTLMv2_RESPONSE v2_resp;
+ enum ndr_err_code err;
+ const struct AV_PAIR *av_nb_cn = NULL;
+ const struct AV_PAIR *av_nb_dn = NULL;
+
+ if (response.length < 48) {
+ /*
+ * NTLMv2_RESPONSE has at least 48 bytes.
+ */
+ return NT_STATUS_OK;
+ }
+
+ cmp = memcmp(response.data + 16, magic, 2);
+ if (cmp != 0) {
+ /*
+ * It doesn't look like a valid NTLMv2_RESPONSE
+ */
+ return NT_STATUS_OK;
+ }
+
+ frame = talloc_stackframe();
+
+ err = ndr_pull_struct_blob(&response, frame, &v2_resp,
+ (ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ NTSTATUS status;
+ status = ndr_map_error2ntstatus(err);
+ DEBUG(2,("Failed to parse NTLMv2_RESPONSE "
+ "length %u - %s - %s\n",
+ (unsigned)response.length,
+ ndr_map_error2string(err),
+ nt_errstr(status)));
+ dump_data(2, response.data, response.length);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &v2_resp);
+ }
+
+ /*
+ * Make sure the netbios computer name in the
+ * NTLMv2_RESPONSE matches the computer name
+ * in the secure channel credentials for workstation
+ * trusts.
+ *
+ * And the netbios domain name matches our
+ * workgroup.
+ *
+ * This prevents workstations from requesting
+ * the session key of NTLMSSP sessions of clients
+ * to other hosts.
+ */
+ if (creds->secure_channel_type == SEC_CHAN_WKSTA) {
+ av_nb_cn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
+ MsvAvNbComputerName);
+ av_nb_dn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
+ MsvAvNbDomainName);
+ }
+
+ if (av_nb_cn != NULL) {
+ const char *v = NULL;
+ char *a = NULL;
+ size_t len;
+
+ v = av_nb_cn->Value.AvNbComputerName;
+
+ a = talloc_strdup(frame, creds->account_name);
+ if (a == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ len = strlen(a);
+ if (len > 0 && a[len - 1] == '$') {
+ a[len - 1] = '\0';
+ }
+
+#ifdef SAMBA4_INTERNAL_HEIMDAL /* smbtorture4 for make test */
+ cmp = strcasecmp_m(a, v);
+#else /* smbd */
+ cmp = StrCaseCmp(a, v);
+#endif
+ if (cmp != 0) {
+ DEBUG(2,("%s: NTLMv2_RESPONSE with "
+ "NbComputerName[%s] rejected "
+ "for user[%s\\%s] "
+ "against SEC_CHAN_WKSTA[%s/%s] "
+ "in workgroup[%s]\n",
+ __func__, v,
+ account_domain,
+ account_name,
+ creds->computer_name,
+ creds->account_name,
+ workgroup));
+ TALLOC_FREE(frame);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+ if (av_nb_dn != NULL) {
+ const char *v = NULL;
+
+ v = av_nb_dn->Value.AvNbDomainName;
+
+#ifdef SAMBA4_INTERNAL_HEIMDAL /* smbtorture4 for make test */
+ cmp = strcasecmp_m(workgroup, v);
+#else /* smbd */
+ cmp = StrCaseCmp(workgroup, v);
+#endif
+ if (cmp != 0) {
+ DEBUG(2,("%s: NTLMv2_RESPONSE with "
+ "NbDomainName[%s] rejected "
+ "for user[%s\\%s] "
+ "against SEC_CHAN_WKSTA[%s/%s] "
+ "in workgroup[%s]\n",
+ __func__, v,
+ account_domain,
+ account_name,
+ creds->computer_name,
+ creds->account_name,
+ workgroup));
+ TALLOC_FREE(frame);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
/***********************************************************
encode a password buffer with a unicode password. The buffer
is filled with random data to make it harder to attack.
--- a/libcli/auth/wscript_build
+++ b/libcli/auth/wscript_build
@@ -19,7 +19,7 @@ bld.SAMBA_SUBSYSTEM('MSRPC_PARSE',
bld.SAMBA_SUBSYSTEM('LIBCLI_AUTH',
source='credentials.c session.c smbencrypt.c smbdes.c',
- public_deps='MSRPC_PARSE',
+ public_deps='MSRPC_PARSE NDR_NTLMSSP',
public_headers='credentials.h:domain_credentials.h'
)
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -783,6 +783,7 @@ GROUPDB_OBJ = groupdb/mapping.o groupdb/
PROFILE_OBJ = profile/profile.o
PROFILES_OBJ = utils/profiles.o \
$(LIBSMB_ERR_OBJ) \
+ $(LIBNDR_NTLMSSP_OBJ) \
$(PARAM_OBJ) \
$(LIB_OBJ) $(LIB_DUMMY_OBJ) \
$(POPT_LIB_OBJ) \
@@ -995,10 +996,10 @@ SWAT_OBJ = $(SWAT_OBJ1) $(PARAM_OBJ) $(P
STATUS_OBJ = utils/status.o utils/status_profile.o \
$(LOCKING_OBJ) $(PARAM_OBJ) \
$(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
- $(LIBSMB_ERR_OBJ) $(FNAME_UTIL_OBJ)
+ $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(FNAME_UTIL_OBJ)
SMBCONTROL_OBJ = utils/smbcontrol.o $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
- $(LIBSMB_ERR_OBJ) $(POPT_LIB_OBJ) $(PRINTBASE_OBJ)
+ $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(POPT_LIB_OBJ) $(PRINTBASE_OBJ)
SMBTREE_OBJ = utils/smbtree.o $(PARAM_OBJ) \
$(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_OBJ) \
@@ -1012,11 +1013,11 @@ SMBTREE_OBJ = utils/smbtree.o $(PARAM_OB
TESTPARM_OBJ = utils/testparm.o \
$(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \
- $(LIBSMB_ERR_OBJ)
+ $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
SMBTA_UTIL_OBJ = utils/smbta-util.o $(PARAM_OBJ) $(POPT_LIB_OBJ) \
$(LIB_NONSMBD_OBJ) \
- $(LIBSMB_ERR_OBJ) $(FNAME_UTIL_OBJ)
+ $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(FNAME_UTIL_OBJ)
TEST_LP_LOAD_OBJ = param/test_lp_load.o \
$(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
@@ -1146,6 +1147,7 @@ SMBCONFTORT_OBJ = $(SMBCONFTORT_OBJ0) \
$(LIB_NONSMBD_OBJ) \
$(PARAM_OBJ) \
$(LIBSMB_ERR_OBJ) \
+ $(LIBNDR_NTLMSSP_OBJ) \
$(POPT_LIB_OBJ)
PTHREADPOOLTEST_OBJ = lib/pthreadpool/pthreadpool.o \
@@ -1229,7 +1231,7 @@ CUPS_OBJ = client/smbspool.o $(PARAM_OBJ
$(LIBNDR_GEN_OBJ0)
NMBLOOKUP_OBJ = utils/nmblookup.o $(PARAM_OBJ) $(LIBNMB_OBJ) \
- $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ)
+ $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
SMBTORTURE_OBJ1 = torture/torture.o torture/nbio.o torture/scanner.o torture/utable.o \
torture/denytest.o torture/mangle_test.o \
@@ -1253,6 +1255,7 @@ MASKTEST_OBJ = torture/masktest.o $(PARA
$(LIBNDR_GEN_OBJ0)
MSGTEST_OBJ = torture/msgtest.o $(PARAM_OBJ) $(LIBSMB_ERR_OBJ) \
+ $(LIBNDR_NTLMSSP_OBJ) \
$(LIB_NONSMBD_OBJ) \
$(LIBNDR_GEN_OBJ0)
@@ -1269,7 +1272,7 @@ PDBTEST_OBJ = torture/pdbtest.o $(PARAM_
VFSTEST_OBJ = torture/cmd_vfs.o torture/vfstest.o $(SMBD_OBJ_BASE) $(READLINE_OBJ)
-SMBICONV_OBJ = $(PARAM_OBJ) torture/smbiconv.o $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ)
+SMBICONV_OBJ = $(PARAM_OBJ) torture/smbiconv.o $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
LOG2PCAP_OBJ = utils/log2pcaphex.o
@@ -1297,17 +1300,17 @@ SMBCQUOTAS_OBJ = utils/smbcquotas.o $(LI
EVTLOGADM_OBJ0 = utils/eventlogadm.o
EVTLOGADM_OBJ = $(EVTLOGADM_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
- $(LIBSMB_ERR_OBJ) $(LIB_EVENTLOG_OBJ) \
+ $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(LIB_EVENTLOG_OBJ) \
librpc/gen_ndr/ndr_eventlog.o \
librpc/gen_ndr/ndr_lsa.o
SHARESEC_OBJ0 = utils/sharesec.o
SHARESEC_OBJ = $(SHARESEC_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
- $(LIBSMB_ERR_OBJ) \
+ $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) \
$(POPT_LIB_OBJ)
TALLOCTORT_OBJ = @tallocdir@/testsuite.o @tallocdir@/testsuite_main.o \
- $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ)
+ $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ)
REPLACETORT_OBJ = @libreplacedir@/test/testsuite.o \
@libreplacedir@/test/getifaddrs.o \
@@ -1323,7 +1326,7 @@ SMBFILTER_OBJ = utils/smbfilter.o $(PARA
$(LIBNDR_GEN_OBJ0)
WINBIND_WINS_NSS_OBJ = ../nsswitch/wins.o $(PARAM_OBJ) \
- $(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNMB_OBJ)
+ $(LIB_NONSMBD_OBJ) $(LIBSMB_ERR_OBJ) $(LIBNDR_NTLMSSP_OBJ) $(LIBNMB_OBJ)
PAM_SMBPASS_OBJ_0 = pam_smbpass/pam_smb_auth.o pam_smbpass/pam_smb_passwd.o \
pam_smbpass/pam_smb_acct.o pam_smbpass/support.o ../lib/util/asn1.o
@@ -1531,12 +1534,14 @@ RPC_OPEN_TCP_OBJ = torture/rpc_open_tcp.
DBWRAP_TOOL_OBJ = utils/dbwrap_tool.o \
$(PARAM_OBJ) \
$(LIB_NONSMBD_OBJ) \
- $(LIBSMB_ERR_OBJ)
+ $(LIBSMB_ERR_OBJ) \
+ $(LIBNDR_NTLMSSP_OBJ)
DBWRAP_TORTURE_OBJ = utils/dbwrap_torture.o \
$(PARAM_OBJ) \
$(LIB_NONSMBD_OBJ) \
$(LIBSMB_ERR_OBJ) \
+ $(LIBNDR_NTLMSSP_OBJ) \
$(POPT_LIB_OBJ)
SPLIT_TOKENS_OBJ = utils/split_tokens.o \
--- a/source4/torture/raw/samba3misc.c
+++ b/source4/torture/raw/samba3misc.c
@@ -340,6 +340,7 @@ bool torture_samba3_badpath(struct tortu
bool ret = true;
TALLOC_CTX *mem_ctx;
bool nt_status_support;
+ bool client_ntlmv2_auth;
if (!(mem_ctx = talloc_init("torture_samba3_badpath"))) {
d_printf("talloc_init failed\n");
@@ -347,20 +348,17 @@ bool torture_samba3_badpath(struct tortu
}
nt_status_support = lpcfg_nt_status_support(torture->lp_ctx);
+ client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(torture->lp_ctx);
- if (!lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "yes")) {
- printf("Could not set 'nt status support = yes'\n");
- goto fail;
- }
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "yes"), ret, fail, "Could not set 'nt status support = yes'\n");
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "yes"), ret, fail, "Could not set 'client ntlmv2 auth = yes'\n");
if (!torture_open_connection(&cli_nt, torture, 0)) {
goto fail;
}
- if (!lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "no")) {
- printf("Could not set 'nt status support = yes'\n");
- goto fail;
- }
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support", "no"), ret, fail, "Could not set 'nt status support = no'\n");
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth", "no"), ret, fail, "Could not set 'client ntlmv2 auth = no'\n");
if (!torture_open_connection(&cli_dos, torture, 1)) {
goto fail;
@@ -373,6 +371,12 @@ bool torture_samba3_badpath(struct tortu
}
smbcli_deltree(cli_nt->tree, dirname);
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "nt status support",
+ nt_status_support ? "yes":"no"),
+ ret, fail, "Could not set 'nt status support' back to where it was\n");
+ torture_assert_goto(torture, lpcfg_set_cmdline(torture->lp_ctx, "client ntlmv2 auth",
+ client_ntlmv2_auth ? "yes":"no"),
+ ret, fail, "Could not set 'client ntlmv2 auth' back to where it was\n");
status = smbcli_mkdir(cli_nt->tree, dirname);
if (!NT_STATUS_IS_OK(status)) {
--- a/source4/torture/basic/base.c
+++ b/source4/torture/basic/base.c
@@ -1476,6 +1476,7 @@ static bool torture_chkpath_test(struct
static bool torture_samba3_errorpaths(struct torture_context *tctx)
{
bool nt_status_support;
+ bool client_ntlmv2_auth;
struct smbcli_state *cli_nt = NULL, *cli_dos = NULL;
bool result = false;
int fnum;
@@ -1485,18 +1486,27 @@ static bool torture_samba3_errorpaths(st
NTSTATUS status;
nt_status_support = lpcfg_nt_status_support(tctx->lp_ctx);
+ client_ntlmv2_auth = lpcfg_client_ntlmv2_auth(tctx->lp_ctx);
if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "yes")) {
torture_comment(tctx, "Could not set 'nt status support = yes'\n");
goto fail;
}
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "yes")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = yes'\n");
+ goto fail;
+ }
if (!torture_open_connection(&cli_nt, tctx, 0)) {
goto fail;
}
if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support", "no")) {
- torture_comment(tctx, "Could not set 'nt status support = yes'\n");
+ torture_result(tctx, TORTURE_FAIL, "Could not set 'nt status support = no'\n");
+ goto fail;
+ }
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth", "no")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not set 'client ntlmv2 auth = no'\n");
goto fail;
}
@@ -1506,7 +1516,12 @@ static bool torture_samba3_errorpaths(st
if (!lpcfg_set_cmdline(tctx->lp_ctx, "nt status support",
nt_status_support ? "yes":"no")) {
- torture_comment(tctx, "Could not reset 'nt status support = yes'");
+ torture_result(tctx, TORTURE_FAIL, "Could not reset 'nt status support'");
+ goto fail;
+ }
+ if (!lpcfg_set_cmdline(tctx->lp_ctx, "client ntlmv2 auth",
+ client_ntlmv2_auth ? "yes":"no")) {
+ torture_result(tctx, TORTURE_FAIL, "Could not reset 'client ntlmv2 auth'");
goto fail;
}
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -2077,6 +2077,17 @@ NTSTATUS cli_session_setup(struct cli_st
NTSTATUS status;
/* otherwise do a NT1 style session setup */
+ if (lp_client_ntlmv2_auth() && lp_client_use_spnego()) {
+ /*
+ * Don't send an NTLMv2 response without NTLMSSP
+ * if we want to use spnego support
+ */
+ DEBUG(1, ("Server does not support EXTENDED_SECURITY "
+ " but 'client use spnego = yes"
+ " and 'client ntlmv2 auth = yes'\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
status = cli_session_setup_nt1(cli, user, pass, passlen,
ntpass, ntpasslen, workgroup);
if (!NT_STATUS_IS_OK(status)) {
--- a/docs-xml/smbdotconf/protocol/clientusespnego.xml
+++ b/docs-xml/smbdotconf/protocol/clientusespnego.xml
@@ -9,6 +9,11 @@
supporting servers (including WindowsXP, Windows2000 and Samba
3.0) to agree upon an authentication
mechanism. This enables Kerberos authentication in particular.</para>
+
+ <para>When <smbconfoption name="client NTLMv2 auth"/> is also set to
+ <constant>yes</constant> extended security (SPNEGO) is required
+ in order to use NTLMv2 only within NTLMSSP. This behavior was
+ introduced with the patches for CVE-2016-2111.</para>
</description>
<value type="default">yes</value>
--- a/docs-xml/smbdotconf/security/clientntlmv2auth.xml
+++ b/docs-xml/smbdotconf/security/clientntlmv2auth.xml
@@ -28,6 +28,11 @@
NTLMv2 by default, and some sites (particularly those following
'best practice' security polices) only allow NTLMv2 responses, and
not the weaker LM or NTLM.</para>
+
+ <para>When <smbconfoption name="client use spnego"/> is also set to
+ <constant>yes</constant> extended security (SPNEGO) is required
+ in order to use NTLMv2 only within NTLMSSP. This behavior was
+ introduced with the patches for CVE-2016-2111.</para>
</description>
<value type="default">yes</value>
</samba:parameter>
--- /dev/null
+++ b/docs-xml/smbdotconf/security/rawntlmv2auth.xml
@@ -0,0 +1,19 @@
+<samba:parameter name="raw NTLMv2 auth"
+ context="G"
+ type="boolean"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>This parameter determines whether or not <citerefentry><refentrytitle>smbd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> will allow SMB1 clients without
+ extended security (without SPNEGO) to use NTLMv2 authentication.</para>
+
+ <para>If this option, <command moreinfo="none">lanman auth</command>
+ and <command moreinfo="none">ntlm auth</command> are all disabled,
+ then only clients with SPNEGO support will be permitted.
+ That means NTLMv2 is only supported within NTLMSSP.</para>
+</description>
+
+<related>lanman auth</related>
+<related>ntlm auth</related>
+<value type="default">no</value>
+</samba:parameter>
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1489,6 +1489,7 @@ bool lp_map_untrusted_to_domain(void);
int lp_restrict_anonymous(void);
bool lp_lanman_auth(void);
bool lp_ntlm_auth(void);
+bool lp_raw_ntlmv2_auth(void);
bool lp_client_plaintext_auth(void);
bool lp_client_lanman_auth(void);
bool lp_client_ntlmv2_auth(void);
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -336,6 +336,7 @@ struct global {
bool bAllowTrustedDomains;
bool bLanmanAuth;
bool bNTLMAuth;
+ bool bRawNTLMv2Auth;
bool bUseSpnego;
bool bClientLanManAuth;
bool bClientNTLMv2Auth;
@@ -1383,6 +1384,15 @@ static struct parm_struct parm_table[] =
.flags = FLAG_ADVANCED,
},
{
+ .label = "raw NTLMv2 auth",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bRawNTLMv2Auth,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
.label = "client NTLMv2 auth",
.type = P_BOOL,
.p_class = P_GLOBAL,
@@ -5337,6 +5347,7 @@ static void init_globals(bool reinit_glo
Globals.bClientPlaintextAuth = False; /* Do NOT use a plaintext password even if is requested by the server */
Globals.bLanmanAuth = False; /* Do NOT use the LanMan hash, even if it is supplied */
Globals.bNTLMAuth = True; /* Do use NTLMv1 if it is supplied by the client (otherwise NTLMv2) */
+ Globals.bRawNTLMv2Auth = false; /* Allow NTLMv2 without NTLMSSP */
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 */
@@ -5819,6 +5830,7 @@ FN_GLOBAL_BOOL(lp_map_untrusted_to_domai
FN_GLOBAL_INTEGER(lp_restrict_anonymous, &Globals.restrict_anonymous)
FN_GLOBAL_BOOL(lp_lanman_auth, &Globals.bLanmanAuth)
FN_GLOBAL_BOOL(lp_ntlm_auth, &Globals.bNTLMAuth)
+FN_GLOBAL_BOOL(lp_raw_ntlmv2_auth, &Globals.bRawNTLMv2Auth)
FN_GLOBAL_BOOL(lp_client_plaintext_auth, &Globals.bClientPlaintextAuth)
FN_GLOBAL_BOOL(lp_client_lanman_auth, &Globals.bClientLanManAuth)
FN_GLOBAL_BOOL(lp_client_ntlmv2_auth, &Globals.bClientNTLMv2Auth)
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -30,6 +30,7 @@
#include "../lib/util/util_pw.h"
#include "lib/winbind_util.h"
#include "passdb.h"
+#include "../lib/tsocket/tsocket.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
@@ -367,6 +368,19 @@ NTSTATUS make_user_info_for_reply_enc(st
const char *client_domain,
DATA_BLOB lm_resp, DATA_BLOB nt_resp)
{
+ bool allow_raw = lp_raw_ntlmv2_auth();
+
+ if (!allow_raw && nt_resp.length >= 48) {
+ /*
+ * NTLMv2_RESPONSE has at least 48 bytes
+ * and should only be supported via NTLMSSP.
+ */
+ DEBUG(2,("Rejecting raw NTLMv2 authentication with "
+ "user [%s\\%s]\n",
+ client_domain, smb_name));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
return make_user_info_map(user_info, smb_name,
client_domain,
get_remote_machine_name(),
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -127,6 +127,7 @@ sub setup_dc($$)
domain master = yes
domain logons = yes
lanman auth = yes
+ raw NTLMv2 auth = yes
";
my $vars = $self->provision($path,
@@ -230,6 +231,7 @@ sub setup_secserver($$$)
my $secserver_options = "
security = server
password server = $s3dcvars->{SERVER_IP}
+ client ntlmv2 auth = no
";
my $ret = $self->provision($prefix,

View file

@ -0,0 +1,129 @@
From 126e3e992bed7174d60ee19212db9b717647ab2e Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@cryptomilk.org>
Date: Wed, 30 Mar 2016 16:55:44 +0200
Subject: [PATCH 1/3] CVE-2016-2112: s3:ntlmssp: Implement missing
ntlmssp_have_feature()
Signed-off-by: Andreas Schneider <asn@samba.org>
---
source3/include/proto.h | 1 +
source3/libsmb/ntlmssp.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1260,6 +1260,7 @@ NTSTATUS ntlmssp_set_password(struct ntl
NTSTATUS ntlmssp_set_domain(struct ntlmssp_state *ntlmssp_state, const char *domain) ;
void ntlmssp_want_feature_list(struct ntlmssp_state *ntlmssp_state, char *feature_list);
void ntlmssp_want_feature(struct ntlmssp_state *ntlmssp_state, uint32_t feature);
+bool ntlmssp_have_feature(struct ntlmssp_state *ntlmssp_state, uint32_t feature);
NTSTATUS ntlmssp_update(struct ntlmssp_state *ntlmssp_state,
const DATA_BLOB in, DATA_BLOB *out) ;
NTSTATUS ntlmssp_server_start(TALLOC_CTX *mem_ctx,
--- a/source3/libsmb/ntlmssp.c
+++ b/source3/libsmb/ntlmssp.c
@@ -162,6 +162,36 @@ NTSTATUS ntlmssp_set_domain(struct ntlms
return NT_STATUS_OK;
}
+bool ntlmssp_have_feature(struct ntlmssp_state *ntlmssp_state,
+ uint32_t feature)
+{
+ if (feature & NTLMSSP_FEATURE_SIGN) {
+ if (ntlmssp_state->session_key.length == 0) {
+ return false;
+ }
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
+ return true;
+ }
+ }
+
+ if (feature & NTLMSSP_FEATURE_SEAL) {
+ if (ntlmssp_state->session_key.length == 0) {
+ return false;
+ }
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
+ return true;
+ }
+ }
+
+ if (feature & NTLMSSP_FEATURE_SESSION_KEY) {
+ if (ntlmssp_state->session_key.length > 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/**
* Request features for the NTLMSSP negotiation
*
--- a/source3/libads/sasl.c
+++ b/source3/libads/sasl.c
@@ -261,6 +261,37 @@ static ADS_STATUS ads_sasl_spnego_ntlmss
/* we have a reference conter on ntlmssp_state, if we are signing
then the state will be kept by the signing engine */
+ if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
+ bool ok;
+
+ ok = ntlmssp_have_feature(ntlmssp_state,
+ NTLMSSP_FEATURE_SEAL);
+ if (!ok) {
+ DEBUG(0,("The ntlmssp feature sealing request, but unavailable\n"));
+ TALLOC_FREE(ntlmssp_state);
+ return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
+ }
+
+ ok = ntlmssp_have_feature(ntlmssp_state,
+ NTLMSSP_FEATURE_SIGN);
+ if (!ok) {
+ DEBUG(0,("The ntlmssp feature signing request, but unavailable\n"));
+ TALLOC_FREE(ntlmssp_state);
+ return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
+ }
+
+ } else if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
+ bool ok;
+
+ ok = ntlmssp_have_feature(ntlmssp_state,
+ NTLMSSP_FEATURE_SIGN);
+ if (!ok) {
+ DEBUG(0,("The gensec feature signing request, but unavailable\n"));
+ TALLOC_FREE(ntlmssp_state);
+ return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
+ }
+ }
+
if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
--- a/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml
+++ b/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml
@@ -34,11 +34,9 @@
</para>
<para>
- The default value is <emphasis>plain</emphasis> which is not irritable
- to KRB5 clock skew errors. That implies synchronizing the time
- with the KDC in the case of using <emphasis>sign</emphasis> or
- <emphasis>seal</emphasis>.
+ The default value is <emphasis>sign</emphasis>. That implies synchronizing the time
+ with the KDC in the case of using <emphasis>Kerberos</emphasis>.
</para>
</description>
-<value type="default">plain</value>
+<value type="default">sign</value>
</samba:parameter>
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -5392,6 +5392,8 @@ static void init_globals(bool reinit_glo
Globals.ldap_debug_level = 0;
Globals.ldap_debug_threshold = 10;
+ Globals.client_ldap_sasl_wrapping = ADS_AUTH_SASL_SIGN;
+
/* This is what we tell the afs client. in reality we set the token
* to never expire, though, when this runs out the afs client will
* forget the token. Set to 0 to get NEVERDATE.*/

View file

@ -0,0 +1,256 @@
From 513bd34e4523e49e742487be32a7239111486a12 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Sat, 27 Feb 2016 03:43:58 +0100
Subject: [PATCH 1/4] CVE-2016-2115: docs-xml: add "client ipc signing" option
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11756
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
---
docs-xml/smbdotconf/security/clientipcsigning.xml | 23 +++++++++++++++++++++++
docs-xml/smbdotconf/security/clientsigning.xml | 3 +++
source3/include/proto.h | 1 +
source3/param/loadparm.c | 12 ++++++++++++
4 files changed, 39 insertions(+)
create mode 100644 docs-xml/smbdotconf/security/clientipcsigning.xml
--- /dev/null
+++ b/docs-xml/smbdotconf/security/clientipcsigning.xml
@@ -0,0 +1,23 @@
+<samba:parameter name="client ipc signing"
+ context="G"
+ type="enum"
+ enumlist="enum_smb_signing_vals"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>This controls whether the client is allowed or required to use SMB signing for IPC$
+ connections as DCERPC transport inside of winbind. Possible values
+ are <emphasis>auto</emphasis>, <emphasis>mandatory</emphasis>
+ and <emphasis>disabled</emphasis>.
+ </para>
+
+ <para>When set to auto, SMB signing is offered, but not enforced and if set
+ to disabled, SMB signing is not offered either.</para>
+
+ <para>Connections from winbindd to Active Directory Domain Controllers
+ always enforce signing.</para>
+</description>
+
+<related>client signing</related>
+
+<value type="default">mandatory</value>
+</samba:parameter>
--- a/docs-xml/smbdotconf/security/clientsigning.xml
+++ b/docs-xml/smbdotconf/security/clientsigning.xml
@@ -12,6 +12,9 @@
<para>When set to auto, SMB signing is offered, but not enforced.
When set to mandatory, SMB signing is required and if set
to disabled, SMB signing is not offered either.
+
+ <para>IPC$ connections for DCERPC e.g. in winbindd, are handled by the
+ <smbconfoption name="client ipc signing"/> option.</para>
</para>
</description>
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1690,9 +1690,11 @@ int lp_winbind_cache_time(void);
int lp_winbind_reconnect_delay(void);
int lp_winbind_max_clients(void);
const char **lp_winbind_nss_info(void);
+bool lp_winbind_sealed_pipes(void);
int lp_algorithmic_rid_base(void);
int lp_name_cache_timeout(void);
int lp_client_signing(void);
+int lp_client_ipc_signing(void);
int lp_server_signing(void);
int lp_client_ldap_sasl_wrapping(void);
char *lp_parm_talloc_string(int snum, const char *type, const char *option, const char *def);
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -215,6 +215,7 @@ struct global {
int winbind_expand_groups;
bool bWinbindRefreshTickets;
bool bWinbindOfflineLogon;
+ bool bWinbindSealedPipes;
bool bWinbindNormalizeNames;
bool bWinbindRpcOnly;
bool bCreateKrb5Conf;
@@ -366,6 +367,7 @@ struct global {
int restrict_anonymous;
int name_cache_timeout;
int client_signing;
+ int client_ipc_signing;
int server_signing;
int client_ldap_sasl_wrapping;
int iUsershareMaxShares;
@@ -2319,6 +2321,15 @@ static struct parm_struct parm_table[] =
.flags = FLAG_ADVANCED,
},
{
+ .label = "client ipc signing",
+ .type = P_ENUM,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.client_ipc_signing,
+ .special = NULL,
+ .enum_list = enum_smb_signing_vals,
+ .flags = FLAG_ADVANCED,
+ },
+ {
.label = "server signing",
.type = P_ENUM,
.p_class = P_GLOBAL,
@@ -4765,6 +4776,15 @@ static struct parm_struct parm_table[] =
.flags = FLAG_ADVANCED,
},
{
+ .label = "winbind sealed pipes",
+ .type = P_BOOL,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.bWinbindSealedPipes,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
+ {
.label = "winbind normalize names",
.type = P_BOOL,
.p_class = P_GLOBAL,
@@ -5458,6 +5478,7 @@ static void init_globals(bool reinit_glo
Globals.szWinbindNssInfo = str_list_make_v3(NULL, "template", NULL);
Globals.bWinbindRefreshTickets = False;
Globals.bWinbindOfflineLogon = False;
+ Globals.bWinbindSealedPipes = True;
Globals.iIdmapCacheTime = 86400 * 7; /* a week by default */
Globals.iIdmapNegativeCacheTime = 120; /* 2 minutes by default */
@@ -5470,6 +5491,7 @@ static void init_globals(bool reinit_glo
Globals.bClientUseSpnego = True;
Globals.client_signing = Auto;
+ Globals.client_ipc_signing = Required;
Globals.server_signing = False;
Globals.bDeferSharingViolations = True;
@@ -5736,6 +5758,7 @@ FN_GLOBAL_BOOL(lp_winbind_nested_groups,
FN_GLOBAL_INTEGER(lp_winbind_expand_groups, &Globals.winbind_expand_groups)
FN_GLOBAL_BOOL(lp_winbind_refresh_tickets, &Globals.bWinbindRefreshTickets)
FN_GLOBAL_BOOL(lp_winbind_offline_logon, &Globals.bWinbindOfflineLogon)
+FN_GLOBAL_BOOL(lp_winbind_sealed_pipes, &Globals.bWinbindSealedPipes)
FN_GLOBAL_BOOL(lp_winbind_normalize_names, &Globals.bWinbindNormalizeNames)
FN_GLOBAL_BOOL(lp_winbind_rpc_only, &Globals.bWinbindRpcOnly)
FN_GLOBAL_BOOL(lp_create_krb5_conf, &Globals.bCreateKrb5Conf)
@@ -6071,6 +6094,7 @@ FN_GLOBAL_LIST(lp_winbind_nss_info, &Glo
FN_GLOBAL_INTEGER(lp_algorithmic_rid_base, &Globals.AlgorithmicRidBase)
FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing)
+FN_GLOBAL_INTEGER(lp_client_ipc_signing, &Globals.client_ipc_signing)
FN_GLOBAL_INTEGER(lp_server_signing, &Globals.server_signing)
FN_GLOBAL_INTEGER(lp_client_ldap_sasl_wrapping, &Globals.client_ldap_sasl_wrapping)
@@ -9700,6 +9724,20 @@ static bool lp_load_ex(const char *pszFn
lp_do_parameter(GLOBAL_SECTION_SNUM, "wins server", "127.0.0.1");
}
+ if (!lp_is_in_client()) {
+ switch (lp_client_ipc_signing()) {
+ case Required:
+ lp_set_cmdline("client signing", "mandatory");
+ break;
+ case Auto:
+ lp_set_cmdline("client signing", "auto");
+ break;
+ case False:
+ lp_set_cmdline("client signing", "disabled");
+ break;
+ }
+ }
+
init_iconv();
bAllowIncludeRegistry = true;
--- a/source3/rpc_server/spoolss/srv_spoolss_nt.c
+++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c
@@ -2480,7 +2480,7 @@ static bool spoolss_connect_to_client(st
"", /* username */
"", /* domain */
"", /* password */
- 0, lp_client_signing());
+ 0, False);
if ( !NT_STATUS_IS_OK( ret ) ) {
DEBUG(2,("spoolss_connect_to_client: connection to [%s] failed!\n",
--- /dev/null
+++ b/docs-xml/smbdotconf/winbind/winbindsealedpipes.xml
@@ -0,0 +1,15 @@
+<samba:parameter name="winbind sealed pipes"
+ context="G"
+ type="boolean"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>This option controls whether any requests from winbindd to domain controllers
+ pipe will be sealed. Disabling sealing can be useful for debugging
+ purposes.</para>
+
+ <para>The behavior can be controlled per netbios domain
+ by using 'winbind sealed pipes:NETBIOSDOMAIN = no' as option.</para>
+</description>
+
+<value type="default">yes</value>
+</samba:parameter>
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -2384,6 +2384,15 @@ NTSTATUS cm_connect_sam(struct winbindd_
TALLOC_FREE(conn->samr_pipe);
anonymous:
+ if (lp_winbind_sealed_pipes() && (IS_DC || domain->primary)) {
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ DEBUG(1, ("Unwilling to make SAMR connection to domain %s "
+ "without connection level security, "
+ "must set 'winbind sealed pipes = false' "
+ "to proceed: %s\n",
+ domain->name, nt_errstr(status)));
+ goto done;
+ }
/* Finally fall back to anonymous. */
status = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr.syntax_id,
@@ -2610,6 +2619,16 @@ NTSTATUS cm_connect_lsa(struct winbindd_
anonymous:
+ if (lp_winbind_sealed_pipes() && (IS_DC || domain->primary)) {
+ result = NT_STATUS_DOWNGRADE_DETECTED;
+ DEBUG(1, ("Unwilling to make LSA connection to domain %s "
+ "without connection level security, "
+ "must set 'winbind sealed pipes = false' "
+ "to proceed: %s\n",
+ domain->name, nt_errstr(result)));
+ goto done;
+ }
+
result = cli_rpc_pipe_open_noauth(conn->cli,
&ndr_table_lsarpc.syntax_id,
&conn->lsa_pipe);
@@ -2749,7 +2768,18 @@ NTSTATUS cm_connect_netlogon(struct winb
no_schannel:
if ((lp_client_schannel() == False) ||
- ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
+ ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
+ if (lp_winbind_sealed_pipes() && (IS_DC || domain->primary)) {
+ result = NT_STATUS_DOWNGRADE_DETECTED;
+ DEBUG(1, ("Unwilling to make connection to domain %s "
+ "without connection level security, "
+ "must set 'winbind sealed pipes = false' "
+ "to proceed: %s\n",
+ domain->name, nt_errstr(result)));
+ TALLOC_FREE(netlogon_pipe);
+ invalidate_cm_connection(conn);
+ return result;
+ }
/*
* NetSamLogonEx only works for schannel
*/

View file

@ -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;
}

View file

@ -36,7 +36,7 @@
BIN_PROGS1 = bin/smbclient@EXEEXT@ bin/net@EXEEXT@ bin/smbspool@EXEEXT@ \
bin/testparm@EXEEXT@ bin/smbstatus@EXEEXT@ bin/smbget@EXEEXT@ \
@@ -1777,6 +1777,42 @@ bin/.dummy:
@@ -1799,6 +1799,42 @@ bin/.dummy:
dir=bin $(MAKEDIR); fi
@: >> $@ || : > $@ # what a fancy emoticon!

View file

@ -1,6 +1,6 @@
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -1019,7 +1019,7 @@ TEST_LP_LOAD_OBJ = param/test_lp_load.o
@@ -1025,7 +1025,7 @@ TEST_LP_LOAD_OBJ = param/test_lp_load.o
PASSWD_UTIL_OBJ = utils/passwd_util.o
@ -9,7 +9,7 @@
$(PARAM_OBJ) $(LIBSMB_OBJ) $(PASSDB_OBJ) \
$(GROUPDB_OBJ) $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) \
$(POPT_LIB_OBJ) $(SMBLDAP_OBJ) \
@@ -1791,7 +1791,7 @@ nmbd/nmbd_multicall.o: nmbd/nmbd.c nmbd/
@@ -1813,7 +1813,7 @@ nmbd/nmbd_multicall.o: nmbd/nmbd.c nmbd/
echo "$(COMPILE_CC_PATH)" 1>&2;\
$(COMPILE_CC_PATH) >/dev/null 2>&1
@ -18,7 +18,7 @@
@echo Compiling $<.c
@$(COMPILE_CC_PATH) -Dmain=smbpasswd_main && exit 0;\
echo "The following command failed:" 1>&2;\
@@ -1800,7 +1800,7 @@ utils/smbpasswd_multicall.o: utils/smbpa
@@ -1822,7 +1822,7 @@ utils/smbpasswd_multicall.o: utils/smbpa
SMBD_MULTI_O = $(patsubst smbd/server.o,smbd/server_multicall.o,$(SMBD_OBJ))
NMBD_MULTI_O = $(patsubst nmbd/nmbd.o,nmbd/nmbd_multicall.o,$(filter-out $(LIB_DUMMY_OBJ),$(NMBD_OBJ)))

View file

@ -24,3 +24,18 @@
epmapper_commands,
shutdown_commands,
test_commands,
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -433,10 +433,12 @@ static bool check_bind_req(struct pipes_
if (ok) {
context_fns->allow_connect = true;
}
+#ifdef DEVELOPER
ok = ndr_syntax_id_equal(abstract, &ndr_table_rpcecho.syntax_id);
if (ok) {
context_fns->allow_connect = true;
}
+#endif
/*
* every interface can be modified to allow "connect" auth_level by
* using a parametric option like:

View file

@ -71,7 +71,7 @@
#endif
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -2904,12 +2904,14 @@ NTSTATUS cli_rpc_pipe_open_noauth_transp
@@ -3391,12 +3391,14 @@ NTSTATUS cli_rpc_pipe_open_noauth_transp
status = rpc_pipe_bind(result, auth);
if (!NT_STATUS_IS_OK(status)) {
int lvl = 0;

View file

@ -183,3 +183,31 @@
/*
* Force a log file check.
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -421,10 +421,12 @@ static bool check_bind_req(struct pipes_
if (ok) {
context_fns->allow_connect = false;
}
+#ifdef NETLOGON_SUPPORT
ok = ndr_syntax_id_equal(abstract, &ndr_table_netlogon.syntax_id);
if (ok) {
context_fns->allow_connect = false;
}
+#endif
/*
* for the epmapper and echo interfaces we allow "connect"
* auth_level by default.
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -2221,6 +2221,10 @@ static void rpc_pipe_bind_step_two_trigg
struct schannel_state);
struct tevent_req *subreq;
+#ifndef NETLOGON_SUPPORT
+ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return;
+#endif
if (schannel_auth == NULL ||
!ndr_syntax_id_equal(&state->cli->abstract_syntax,
&ndr_table_netlogon.syntax_id)) {

View file

@ -142,3 +142,21 @@
if (!str1 || !str2 || !UserName || !p) {
return False;
}
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -409,6 +409,7 @@ static bool check_bind_req(struct pipes_
context_fns->syntax = *abstract;
context_fns->allow_connect = lp_allow_dcerpc_auth_level_connect();
+#ifdef SAMR_SUPPORT
/*
* for the samr and the lsarpc interfaces we don't allow "connect"
* auth_level by default.
@@ -417,6 +418,7 @@ static bool check_bind_req(struct pipes_
if (ok) {
context_fns->allow_connect = false;
}
+#endif
ok = ndr_syntax_id_equal(abstract, &ndr_table_lsarpc.syntax_id);
if (ok) {
context_fns->allow_connect = false;

View file

@ -71,3 +71,18 @@
}
size_t num_pipe_handles(struct pipes_struct *p)
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -419,10 +419,12 @@ static bool check_bind_req(struct pipes_
context_fns->allow_connect = false;
}
#endif
+#ifdef LSA_SUPPORT
ok = ndr_syntax_id_equal(abstract, &ndr_table_lsarpc.syntax_id);
if (ok) {
context_fns->allow_connect = false;
}
+#endif
#ifdef NETLOGON_SUPPORT
ok = ndr_syntax_id_equal(abstract, &ndr_table_netlogon.syntax_id);
if (ok) {

View file

@ -65,7 +65,7 @@
}
--- a/librpc/ndr/libndr.h
+++ b/librpc/ndr/libndr.h
@@ -604,4 +604,20 @@ _PUBLIC_ enum ndr_err_code ndr_push_enum
@@ -663,4 +663,20 @@ _PUBLIC_ enum ndr_err_code ndr_push_enum
_PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b);
@ -251,3 +251,87 @@
print " return;";
print " }";
print "";
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -445,7 +445,6 @@ static NTSTATUS cli_pipe_validate_curren
rpccli_pipe_txt(talloc_tos(), cli),
pkt->ptype, expected_pkt_type,
nt_errstr(ret)));
- NDR_PRINT_DEBUG(ncacn_packet, pkt);
return ret;
}
@@ -466,7 +465,6 @@ static NTSTATUS cli_pipe_validate_curren
rpccli_pipe_txt(talloc_tos(), cli),
pkt->ptype, expected_pkt_type,
nt_errstr(ret)));
- NDR_PRINT_DEBUG(ncacn_packet, pkt);
return ret;
}
@@ -486,7 +484,6 @@ static NTSTATUS cli_pipe_validate_curren
rpccli_pipe_txt(talloc_tos(), cli),
pkt->ptype, expected_pkt_type,
nt_errstr(ret)));
- NDR_PRINT_DEBUG(ncacn_packet, pkt);
return ret;
}
@@ -508,7 +505,6 @@ static NTSTATUS cli_pipe_validate_curren
rpccli_pipe_txt(talloc_tos(), cli),
pkt->ptype, expected_pkt_type,
nt_errstr(ret)));
- NDR_PRINT_DEBUG(ncacn_packet, pkt);
return ret;
}
@@ -526,7 +522,6 @@ static NTSTATUS cli_pipe_validate_curren
rpccli_pipe_txt(talloc_tos(), cli),
pkt->ptype, expected_pkt_type,
nt_errstr(ret)));
- NDR_PRINT_DEBUG(ncacn_packet, pkt);
return ret;
}
@@ -570,7 +565,6 @@ static NTSTATUS cli_pipe_validate_curren
rpccli_pipe_txt(talloc_tos(), cli),
pkt->ptype, expected_pkt_type,
nt_errstr(ret)));
- NDR_PRINT_DEBUG(ncacn_packet, pkt);
return ret;
}
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -991,7 +991,6 @@ static bool api_pipe_bind_req(struct pip
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("api_pipe_bind_req: invalid pdu: %s\n",
nt_errstr(status)));
- NDR_PRINT_DEBUG(ncacn_packet, pkt);
goto err_exit;
}
@@ -1325,7 +1324,6 @@ bool api_pipe_bind_auth3(struct pipes_st
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("api_pipe_bind_auth3: invalid pdu: %s\n",
nt_errstr(status)));
- NDR_PRINT_DEBUG(ncacn_packet, pkt);
goto err;
}
@@ -1483,7 +1481,6 @@ static bool api_pipe_alter_context(struc
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("api_pipe_alter_context: invalid pdu: %s\n",
nt_errstr(status)));
- NDR_PRINT_DEBUG(ncacn_packet, pkt);
goto err_exit;
}
@@ -2057,7 +2054,6 @@ static bool process_request_pdu(struct p
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("process_request_pdu: invalid pdu: %s\n",
nt_errstr(status)));
- NDR_PRINT_DEBUG(ncacn_packet, pkt);
set_incoming_fault(p);
return false;
}

View file

@ -8844,7 +8844,7 @@
+done
--- a/librpc/ndr/libndr.h
+++ b/librpc/ndr/libndr.h
@@ -603,6 +603,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_enum
@@ -662,6 +662,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_enum
_PUBLIC_ enum ndr_err_code ndr_push_enum_uint1632(struct ndr_push *ndr, int ndr_flags, uint16_t v);
_PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b);