1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-08 05:57:51 +03:00

samba: tag release samba-4.9.15

-----BEGIN PGP SIGNATURE-----
 
 iF0EABECAB0WIQRS+8C4bZVLCEMyTNxvM5FbZWi36gUCXbF/SAAKCRBvM5FbZWi3
 6mCPAKCcjT2k6f0OcFruA8Wvvinz5OYXFQCfSBRw+WmI1bDVeGyfaHEb2PbQJDw=
 =kmPe
 -----END PGP SIGNATURE-----

Merge tag 'samba-4.9.15' into v4-9-test

samba: tag release samba-4.9.15
Signed-off-by: Karolin Seeger <kseeger@samba.org>
This commit is contained in:
Karolin Seeger 2019-11-26 13:03:54 +01:00
commit 2927573cfe
9 changed files with 247 additions and 17 deletions

View File

@ -1,3 +1,77 @@
==============================
Release Notes for Samba 4.9.15
October 29, 2019
==============================
This is a security release in order to address the following defects:
o CVE-2019-10218: Client code can return filenames containing path separators.
o CVE-2019-14833: Samba AD DC check password script does not receive the full
password.
o CVE-2019-14847: User with "get changes" permission can crash AD DC LDAP server
via dirsync.
=======
Details
=======
o CVE-2019-10218:
Malicious servers can cause Samba client code to return filenames containing
path separators to calling code.
o CVE-2019-14833:
When the password contains multi-byte (non-ASCII) characters, the check
password script does not receive the full password string.
o CVE-2019-14847:
Users with the "get changes" extended access right can crash the AD DC LDAP
server by requesting an attribute using the range= syntax.
For more details and workarounds, please refer to the security advisories.
Changes since 4.9.14:
---------------------
o Jeremy Allison <jra@samba.org>
* BUG 14071: CVE-2019-10218 - s3: libsmb: Protect SMB1 and SMB2 client code
from evil server returned names.
o Andrew Bartlett <abartlet@samba.org>
* BUG 12438: CVE-2019-14833: Use utf8 characters in the unacceptable
password.
* BUG 14040: CVE-2019-14847 dsdb: Correct behaviour of ranged_results when
combined with dirsync.
o Björn Baumbach <bb@sernet.de>
* BUG 12438: CVE-2019-14833 dsdb: Send full password to check password
script.
#######################################
Reporting bugs & Development Discussion
#######################################
Please discuss this release on the samba-technical mailing list or by
joining the #samba-technical IRC channel on irc.freenode.net.
If you do report problems then please try to send high quality
feedback. If you don't provide vital information to help us track down
the problem then you will probably be ignored. All bug reports should
be filed under the "Samba 4.1 and newer" product in the project's Bugzilla
database (https://bugzilla.samba.org/).
======================================================================
== Our Code, Our Bugs, Our Responsibility.
== The Samba Team
======================================================================
Release notes for older releases follow:
----------------------------------------
==============================
Release Notes for Samba 4.9.14
October 22, 2019
@ -77,8 +151,8 @@ database (https://bugzilla.samba.org/).
======================================================================
Release notes for older releases follow:
----------------------------------------
----------------------------------------------------------------------
==============================
Release Notes for Samba 4.9.13

View File

@ -1986,7 +1986,7 @@ sub provision_chgdcpass($$)
my $extra_provision_options = undef;
# This environment disallows the use of this password
# (and also removes the default AD complexity checks)
my $unacceptable_password = "widk3Dsle32jxdBdskldsk55klASKQ";
my $unacceptable_password = "Paßßword-widk3Dsle32jxdBdskldsk55klASKQ";
push (@{$extra_provision_options}, "--dns-backend=BIND9_DLZ");
my $ret = $self->provision($prefix,
"domain controller",

View File

@ -1017,6 +1017,13 @@ NTSTATUS cli_smb2_list(struct cli_state *cli,
goto fail;
}
/* Protect against server attack. */
status = is_bad_finfo_name(cli, finfo);
if (!NT_STATUS_IS_OK(status)) {
smbXcli_conn_disconnect(cli->conn, status);
goto fail;
}
if (dir_check_ftype((uint32_t)finfo->mode,
(uint32_t)attribute)) {
/*

View File

@ -24,6 +24,66 @@
#include "trans2.h"
#include "../libcli/smb/smbXcli_base.h"
/****************************************************************************
Check if a returned directory name is safe.
****************************************************************************/
static NTSTATUS is_bad_name(bool windows_names, const char *name)
{
const char *bad_name_p = NULL;
bad_name_p = strchr(name, '/');
if (bad_name_p != NULL) {
/*
* Windows and POSIX names can't have '/'.
* Server is attacking us.
*/
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
if (windows_names) {
bad_name_p = strchr(name, '\\');
if (bad_name_p != NULL) {
/*
* Windows names can't have '\\'.
* Server is attacking us.
*/
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
}
return NT_STATUS_OK;
}
/****************************************************************************
Check if a returned directory name is safe. Disconnect if server is
sending bad names.
****************************************************************************/
NTSTATUS is_bad_finfo_name(const struct cli_state *cli,
const struct file_info *finfo)
{
NTSTATUS status = NT_STATUS_OK;
bool windows_names = true;
if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
windows_names = false;
}
if (finfo->name != NULL) {
status = is_bad_name(windows_names, finfo->name);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("bad finfo->name\n");
return status;
}
}
if (finfo->short_name != NULL) {
status = is_bad_name(windows_names, finfo->short_name);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("bad finfo->short_name\n");
return status;
}
}
return NT_STATUS_OK;
}
/****************************************************************************
Calculate a safe next_entry_offset.
****************************************************************************/
@ -492,6 +552,13 @@ static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
TALLOC_FREE(finfo);
return NT_STATUS_NO_MEMORY;
}
status = is_bad_finfo_name(state->cli, finfo);
if (!NT_STATUS_IS_OK(status)) {
smbXcli_conn_disconnect(state->cli->conn, status);
TALLOC_FREE(finfo);
return status;
}
}
*pfinfo = finfo;
return NT_STATUS_OK;
@ -727,6 +794,14 @@ static void cli_list_trans_done(struct tevent_req *subreq)
ff_eos = true;
break;
}
status = is_bad_finfo_name(state->cli, finfo);
if (!NT_STATUS_IS_OK(status)) {
smbXcli_conn_disconnect(state->cli->conn, status);
tevent_req_nterror(req, status);
return;
}
if (!state->first && (state->mask[0] != '\0') &&
strcsequal(finfo->name, state->mask)) {
DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has "

View File

@ -722,6 +722,9 @@ NTSTATUS cli_posix_whoami(struct cli_state *cli,
/* The following definitions come from libsmb/clilist.c */
NTSTATUS is_bad_finfo_name(const struct cli_state *cli,
const struct file_info *finfo);
NTSTATUS cli_list_old(struct cli_state *cli,const char *Mask,uint16_t attribute,
NTSTATUS (*fn)(const char *, struct file_info *,
const char *, void *), void *state);

View File

@ -2088,21 +2088,36 @@ enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx,
const uint32_t pwdProperties,
const uint32_t minPwdLength)
{
const char *utf8_pw = (const char *)utf8_blob->data;
size_t utf8_len = strlen_m(utf8_pw);
char *password_script = NULL;
const char *utf8_pw = (const char *)utf8_blob->data;
/*
* This looks strange because it is.
*
* The check for the number of characters in the password
* should clearly not be against the byte length, or else a
* single UTF8 character would count for more than one.
*
* We have chosen to use the number of 16-bit units that the
* password encodes to as the measure of length. This is not
* the same as the number of codepoints, if a password
* contains a character beyond the Basic Multilingual Plane
* (above 65535) it will count for more than one "character".
*/
size_t password_characters_roughly = strlen_m(utf8_pw);
/* checks if the "minPwdLength" property is satisfied */
if (minPwdLength > utf8_len) {
if (minPwdLength > password_characters_roughly) {
return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
}
/* checks the password complexity */
/* We might not be asked to check the password complexity */
if (!(pwdProperties & DOMAIN_PASSWORD_COMPLEX)) {
return SAMR_VALIDATION_STATUS_SUCCESS;
}
if (utf8_len == 0) {
if (password_characters_roughly == 0) {
return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
}
@ -2110,6 +2125,7 @@ enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx,
if (password_script != NULL && *password_script != '\0') {
int check_ret = 0;
int error = 0;
ssize_t nwritten = 0;
struct tevent_context *event_ctx = NULL;
struct tevent_req *req = NULL;
struct samba_runcmd_state *run_cmd = NULL;
@ -2134,7 +2150,12 @@ enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx,
tevent_timeval_current_ofs(10, 0),
100, 100, cmd, NULL);
run_cmd = tevent_req_data(req, struct samba_runcmd_state);
if (write(run_cmd->fd_stdin, utf8_pw, utf8_len) != utf8_len) {
nwritten = write(run_cmd->fd_stdin,
utf8_blob->data,
utf8_blob->length);
if (nwritten != utf8_blob->length) {
close(run_cmd->fd_stdin);
run_cmd->fd_stdin = -1;
TALLOC_FREE(password_script);
TALLOC_FREE(event_ctx);
return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;

View File

@ -343,6 +343,10 @@ skip:
attr = dsdb_attribute_by_lDAPDisplayName(dsc->schema,
el->name);
if (attr == NULL) {
continue;
}
keep = false;
if (attr->linkID & 1) {
@ -994,7 +998,7 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req
}
/*
* check if there's an extended dn control
* check if there's a dirsync control
*/
control = ldb_request_get_control(req, LDB_CONTROL_DIRSYNC_OID);
if (control == NULL) {
@ -1323,11 +1327,12 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req
}
/*
* Remove our control from the list of controls
* Mark dirsync control as uncritical (done)
*
* We need this so ranged_results knows how to behave with
* dirsync
*/
if (!ldb_save_controls(control, req, NULL)) {
return ldb_operr(ldb);
}
control->critical = false;
dsc->schema = dsdb_get_schema(ldb, dsc);
/*
* At the begining we make the hypothesis that we will return a complete

View File

@ -35,14 +35,14 @@
struct rr_context {
struct ldb_module *module;
struct ldb_request *req;
bool dirsync_in_use;
};
static struct rr_context *rr_init_context(struct ldb_module *module,
struct ldb_request *req)
{
struct rr_context *ac;
ac = talloc_zero(req, struct rr_context);
struct ldb_control *dirsync_control = NULL;
struct rr_context *ac = talloc_zero(req, struct rr_context);
if (ac == NULL) {
ldb_set_errstring(ldb_module_get_ctx(module), "Out of Memory");
return NULL;
@ -51,6 +51,16 @@ static struct rr_context *rr_init_context(struct ldb_module *module,
ac->module = module;
ac->req = req;
/*
* check if there's a dirsync control (as there is an
* interaction between these modules)
*/
dirsync_control = ldb_request_get_control(req,
LDB_CONTROL_DIRSYNC_OID);
if (dirsync_control != NULL) {
ac->dirsync_in_use = true;
}
return ac;
}
@ -82,6 +92,15 @@ static int rr_search_callback(struct ldb_request *req, struct ldb_reply *ares)
ares->response, ares->error);
}
if (ac->dirsync_in_use) {
/*
* We return full attribute values when mixed with
* dirsync
*/
return ldb_module_send_entry(ac->req,
ares->message,
ares->controls);
}
/* LDB_REPLY_ENTRY */
temp_ctx = talloc_new(ac->req);

View File

@ -28,6 +28,7 @@ from samba.tests.subunitrun import TestProgram, SubunitOptions
import samba.getopt as options
import base64
import ldb
from ldb import LdbError, SCOPE_BASE
from ldb import Message, MessageElement, Dn
from ldb import FLAG_MOD_ADD, FLAG_MOD_DELETE
@ -590,6 +591,31 @@ class SimpleDirsyncTests(DirsyncBaseTests):
class ExtendedDirsyncTests(SimpleDirsyncTests):
def test_dirsync_linkedattributes_range(self):
self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass)
res = self.ldb_admin.search(self.base_dn,
attrs=["member;range=1-1"],
expression="(name=Administrators)",
controls=["dirsync:1:0:0"])
self.assertTrue(len(res) > 0)
self.assertTrue(res[0].get("member;range=1-1") is None)
self.assertTrue(res[0].get("member") is not None)
self.assertTrue(len(res[0].get("member")) > 0)
def test_dirsync_linkedattributes_range_user(self):
self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass)
try:
res = self.ldb_simple.search(self.base_dn,
attrs=["member;range=1-1"],
expression="(name=Administrators)",
controls=["dirsync:1:0:0"])
except LdbError as e:
(num, _) = e.args
self.assertEquals(num, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS)
else:
self.fail()
def test_dirsync_linkedattributes(self):
flag_incr_linked = 2147483648
self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass)