Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • lts-team/packages/samba
  • thctlo/samba-lintianfix
  • arnaudr/samba
  • jrwren/samba
  • paride/samba
  • athos/samba
  • henrich/samba
  • cnotin/samba
  • mimi89999/samba
  • samba-team/samba
  • ahasenack/samba
  • jrtc27/samba
  • noel/samba
13 results
Show changes
Commits on Source (61)
Showing
with 779 additions and 60 deletions
......@@ -146,8 +146,7 @@ include:
- ccache -z -M 500M
- ccache -s
# We are already running .gitlab-ci directives from this repo, remove additional checks that break our CI
- git config --global --add safe.directory `pwd`
- git config --global --add safe.directory /builds/samba-team/devel/samba/.git
- git config --global --add safe.directory '*'
after_script:
- mount
- df -h
......
......@@ -27,7 +27,7 @@ SAMBA_COPYRIGHT_STRING="Copyright Andrew Tridgell and the Samba Team 1992-2024"
########################################################
SAMBA_VERSION_MAJOR=4
SAMBA_VERSION_MINOR=20
SAMBA_VERSION_RELEASE=2
SAMBA_VERSION_RELEASE=3
########################################################
# If a official release has a serious bug #
......
==============================
Release Notes for Samba 4.20.3
August 02, 2024
==============================
This is the latest stable release of the Samba 4.20 release series.
LDAP TLS/SASL channel binding support
-------------------------------------
The ldap server supports SASL binds with
kerberos or NTLMSSP over TLS connections
now (either ldaps or starttls).
Setups where 'ldap server require strong auth = allow_sasl_over_tls'
was required before, can now most likely move to the
default of 'ldap server require strong auth = yes'.
If SASL binds without correct tls channel bindings are required
'ldap server require strong auth = allow_sasl_without_tls_channel_bindings'
should be used now, as 'allow_sasl_over_tls' will generate a
warning in every start of 'samba', as well as '[samba-tool ]testparm'.
This is similar to LdapEnforceChannelBinding under
HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters
on Windows.
All client tools using ldaps also include the correct
channel bindings now.
smb.conf changes
================
Parameter Name Description Default
-------------- ----------- -------
ldap server require strong auth new values
Changes since 4.20.2
--------------------
o Andreas Schneider <asn@samba.org>
* BUG 15683: Running samba-bgqd a a standalone systemd service does not work.
o Andrew Bartlett <abartlet@samba.org>
* BUG 15655: When claims enabled with heimdal kerberos, unable to log on to a
Windows computer when user account need to change their own password.
o Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
* BUG 15671: Invalid client warning about command line passwords.
* BUG 15672: Version string is truncated in manpages.
* BUG 15673: --version-* options are still not ergonomic, and they reject
tilde characters.
* BUG 15674: cmdline_burn does not always burn secrets.
* BUG 15685: Samba does not parse SDDL found in defaultSecurityDescriptor in
AD_DS_Classes_Windows_Server_v1903.ldf.
o Jo Sutton <josutton@catalyst.net.nz>
* BUG 15655: When claims enabled with heimdal kerberos, unable to log on to a
Windows computer when user account need to change their own password.
o Pavel Filipenský <pfilipensky@samba.org>
* BUG 15660: The images don\'t build after the git security release and
CentOS 8 Stream is EOL.
o Ralph Boehme <slow@samba.org>
* BUG 15676: Fix clock skew error message and memory cache clock skew
recovery.
o Stefan Metzmacher <metze@samba.org>
* BUG 15603: Heimdal ignores _gsskrb5_decapsulate errors in
init_sec_context/repl_mutual.
* BUG 15621: s4:ldap_server: does not support tls channel bindings
for sasl binds.
o Xavi Hernandez <xhernandez@redhat.com>
* BUG 15678: CTDB socket output queues may suffer unbounded delays under some
special conditions.
#######################################
Reporting bugs & Development Discussion
#######################################
Please discuss this release on the samba-technical mailing list or by
joining the #samba-technical:matrix.org matrix room, or
#samba-technical IRC channel on irc.libera.chat.
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.20.2
June 19, 2024
......@@ -79,8 +182,7 @@ database (https://bugzilla.samba.org/).
======================================================================
Release notes for older releases follow:
----------------------------------------
----------------------------------------------------------------------
==============================
Release Notes for Samba 4.20.1
May 08, 2024
......@@ -404,6 +506,7 @@ smb.conf changes
Parameter Name Description Default
-------------- ----------- -------
ldap server require strong auth new values (4.20.3)
acl claims evaluation new AD DC only
smb3 unix extensions Per share -
smb3 share cap:ASYMMETRIC new no
......
......@@ -854,3 +854,66 @@ _PUBLIC_ const char *gensec_get_target_principal(struct gensec_security *gensec_
return NULL;
}
static int gensec_channel_bindings_destructor(struct gensec_channel_bindings *cb)
{
data_blob_clear_free(&cb->initiator_address);
data_blob_clear_free(&cb->acceptor_address);
data_blob_clear_free(&cb->application_data);
*cb = (struct gensec_channel_bindings) { .initiator_addrtype = 0, };
return 0;
}
_PUBLIC_ NTSTATUS gensec_set_channel_bindings(struct gensec_security *gensec_security,
uint32_t initiator_addrtype,
const DATA_BLOB *initiator_address,
uint32_t acceptor_addrtype,
const DATA_BLOB *acceptor_address,
const DATA_BLOB *application_data)
{
struct gensec_channel_bindings *cb = NULL;
if (gensec_security->subcontext) {
return NT_STATUS_INTERNAL_ERROR;
}
if (gensec_security->channel_bindings != NULL) {
return NT_STATUS_ALREADY_REGISTERED;
}
cb = talloc_zero(gensec_security, struct gensec_channel_bindings);
if (cb == NULL) {
return NT_STATUS_NO_MEMORY;
}
talloc_set_destructor(cb, gensec_channel_bindings_destructor);
cb->initiator_addrtype = initiator_addrtype;
if (initiator_address != NULL) {
cb->initiator_address = data_blob_dup_talloc(cb,
*initiator_address);
if (cb->initiator_address.length != initiator_address->length) {
TALLOC_FREE(cb);
return NT_STATUS_NO_MEMORY;
}
}
cb->acceptor_addrtype = acceptor_addrtype;
if (acceptor_address != NULL) {
cb->acceptor_address = data_blob_dup_talloc(cb,
*acceptor_address);
if (cb->acceptor_address.length != acceptor_address->length) {
TALLOC_FREE(cb);
return NT_STATUS_NO_MEMORY;
}
}
if (application_data != NULL) {
cb->application_data = data_blob_dup_talloc(cb,
*application_data);
if (cb->application_data.length != application_data->length) {
TALLOC_FREE(cb);
return NT_STATUS_NO_MEMORY;
}
}
gensec_security->channel_bindings = cb;
return NT_STATUS_OK;
}
......@@ -70,6 +70,7 @@ struct gensec_target {
#define GENSEC_FEATURE_NO_AUTHZ_LOG 0x00000800
#define GENSEC_FEATURE_SMB_TRANSPORT 0x00001000
#define GENSEC_FEATURE_LDAPS_TRANSPORT 0x00002000
#define GENSEC_FEATURE_CB_OPTIONAL 0x00004000
#define GENSEC_EXPIRE_TIME_INFINITY (NTTIME)0x8000000000000000LL
......@@ -313,6 +314,13 @@ bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism
NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal);
const char *gensec_get_target_principal(struct gensec_security *gensec_security);
NTSTATUS gensec_set_channel_bindings(struct gensec_security *gensec_security,
uint32_t initiator_addrtype,
const DATA_BLOB *initiator_address,
uint32_t acceptor_addrtype,
const DATA_BLOB *acceptor_address,
const DATA_BLOB *application_data);
NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx,
struct gensec_security *gensec_security,
struct smb_krb5_context *smb_krb5_context,
......
......@@ -95,6 +95,23 @@ struct gensec_security_ops_wrapper {
const char *oid;
};
/*
* typedef struct gss_channel_bindings_struct {
* OM_uint32 initiator_addrtype;
* gss_buffer_desc initiator_address;
* OM_uint32 acceptor_addrtype;
* gss_buffer_desc acceptor_address;
* gss_buffer_desc application_data;
* } *gss_channel_bindings_t;
*/
struct gensec_channel_bindings {
uint32_t initiator_addrtype;
DATA_BLOB initiator_address;
uint32_t acceptor_addrtype;
DATA_BLOB acceptor_address;
DATA_BLOB application_data;
};
struct gensec_security {
const struct gensec_security_ops *ops;
void *private_data;
......@@ -106,6 +123,7 @@ struct gensec_security {
uint32_t max_update_size;
uint8_t dcerpc_auth_level;
struct tsocket_address *local_addr, *remote_addr;
struct gensec_channel_bindings *channel_bindings;
struct gensec_settings *settings;
/* When we are a server, this may be filled in to provide an
......
......@@ -732,6 +732,7 @@ _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
(*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
(*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
(*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
(*gensec_security)->channel_bindings = talloc_reference(*gensec_security, parent->channel_bindings);
talloc_set_destructor((*gensec_security), gensec_security_destructor);
return NT_STATUS_OK;
......
......@@ -599,6 +599,8 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
SingleHost->Value.AvSingleHost.remaining = data_blob_null;
}
if (!(gensec_security->want_features & GENSEC_FEATURE_CB_OPTIONAL)
|| gensec_security->channel_bindings != NULL)
{
struct AV_PAIR *ChannelBindings = NULL;
......@@ -607,13 +609,12 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security,
count++;
*eol = *ChannelBindings;
/*
* gensec doesn't support channel bindings yet,
* but we want to match Windows on the wire
*/
ChannelBindings->AvId = MsvChannelBindings;
memset(ChannelBindings->Value.ChannelBindings, 0,
sizeof(ChannelBindings->Value.ChannelBindings));
nt_status = ntlmssp_hash_channel_bindings(gensec_security,
ChannelBindings->Value.ChannelBindings);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
}
service = gensec_get_target_service(gensec_security);
......
......@@ -56,6 +56,8 @@ void debug_ntlmssp_flags(uint32_t neg_flags);
NTSTATUS ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
uint32_t neg_flags, const char *name);
const DATA_BLOB ntlmssp_version_blob(void);
NTSTATUS ntlmssp_hash_channel_bindings(struct gensec_security *gensec_security,
uint8_t cb_hash[16]);
/* The following definitions come from auth/ntlmssp_server.c */
......
......@@ -386,6 +386,9 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
DATA_BLOB version_blob = data_blob_null;
const unsigned int mic_len = NTLMSSP_MIC_SIZE;
DATA_BLOB mic_blob = data_blob_null;
const uint8_t zero_channel_bindings[16] = { 0, };
const uint8_t *client_channel_bindings = zero_channel_bindings;
uint8_t server_channel_bindings[16] = { 0, };
const char *parse_string;
bool ok;
struct timeval endtime;
......@@ -523,6 +526,7 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
uint32_t i = 0;
uint32_t count = 0;
const struct AV_PAIR *flags = NULL;
const struct AV_PAIR *cb = NULL;
const struct AV_PAIR *eol = NULL;
uint32_t av_flags = 0;
......@@ -598,6 +602,12 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
ntlmssp_state->new_spnego = true;
}
cb = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
MsvChannelBindings);
if (cb != NULL) {
client_channel_bindings = cb->Value.ChannelBindings;
}
count = ntlmssp_state->server.av_pair_list.count;
if (v2_resp.Challenge.AvPairs.count < count) {
return NT_STATUS_INVALID_PARAMETER;
......@@ -700,6 +710,43 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
}
}
if (gensec_security->channel_bindings != NULL) {
nt_status = ntlmssp_hash_channel_bindings(gensec_security,
server_channel_bindings);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
ok = mem_equal_const_time(client_channel_bindings,
server_channel_bindings,
16);
if (!ok && gensec_security->want_features & GENSEC_FEATURE_CB_OPTIONAL) {
/*
* Unlike kerberos, explicit 16 zeros in
* MsvChannelBindings are not enough to
* pass the optional check.
*
* So we only let it through without explicit
* MsvChannelBindings.
*/
ok = (client_channel_bindings == zero_channel_bindings);
}
if (!ok) {
DBG_WARNING("Invalid channel bindings for "
"user=[%s] domain=[%s] workstation=[%s]\n",
ntlmssp_state->user,
ntlmssp_state->domain,
ntlmssp_state->client.netbios_name);
dump_data(DBGLVL_WARNING,
client_channel_bindings,
16);
dump_data(DBGLVL_WARNING,
server_channel_bindings,
16);
return NT_STATUS_BAD_BINDINGS;
}
}
nttime_to_timeval(&endtime, ntlmssp_state->server.challenge_endtime);
expired = timeval_expired(&endtime);
if (expired) {
......
......@@ -22,9 +22,15 @@
*/
#include "includes.h"
#include "auth/gensec/gensec.h"
#include "auth/gensec/gensec_internal.h"
#include "../auth/ntlmssp/ntlmssp.h"
#include "../auth/ntlmssp/ntlmssp_private.h"
#include "lib/crypto/gnutls_helpers.h"
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
......@@ -218,3 +224,95 @@ const DATA_BLOB ntlmssp_version_blob(void)
return data_blob_const(version_buffer, ARRAY_SIZE(version_buffer));
}
NTSTATUS ntlmssp_hash_channel_bindings(struct gensec_security *gensec_security,
uint8_t cb_hash[16])
{
const struct gensec_channel_bindings *cb =
gensec_security->channel_bindings;
gnutls_hash_hd_t hash_hnd = NULL;
uint8_t uint32buf[4];
int rc;
if (cb == NULL) {
memset(cb_hash, 0, 16);
return NT_STATUS_OK;
}
GNUTLS_FIPS140_SET_LAX_MODE();
rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
if (rc < 0) {
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
SIVAL(uint32buf, 0, cb->initiator_addrtype);
rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf));
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
SIVAL(uint32buf, 0, cb->initiator_address.length);
rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf));
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
if (cb->initiator_address.length > 0) {
rc = gnutls_hash(hash_hnd,
cb->initiator_address.data,
cb->initiator_address.length);
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
}
SIVAL(uint32buf, 0, cb->acceptor_addrtype);
rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf));
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
SIVAL(uint32buf, 0, cb->acceptor_address.length);
rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf));
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
if (cb->acceptor_address.length > 0) {
rc = gnutls_hash(hash_hnd,
cb->acceptor_address.data,
cb->acceptor_address.length);
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
}
SIVAL(uint32buf, 0, cb->application_data.length);
rc = gnutls_hash(hash_hnd, uint32buf, sizeof(uint32buf));
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
if (cb->application_data.length > 0) {
rc = gnutls_hash(hash_hnd,
cb->application_data.data,
cb->application_data.length);
if (rc < 0) {
gnutls_hash_deinit(hash_hnd, NULL);
GNUTLS_FIPS140_SET_STRICT_MODE();
return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
}
}
gnutls_hash_deinit(hash_hnd, cb_hash);
GNUTLS_FIPS140_SET_STRICT_MODE();
return NT_STATUS_OK;
}
......@@ -286,7 +286,7 @@ def abi_build_vscript(task):
f.close()
def VSCRIPT_MAP_PRIVATE(bld, libname, orig_vscript, version, private_vscript):
version = version.replace("-", "_").replace("+","_").upper()
version = re.sub(r'\W', '_', version).upper()
t = bld.SAMBA_GENERATOR(private_vscript,
rule=abi_build_vscript,
source=orig_vscript,
......@@ -314,8 +314,8 @@ def ABI_VSCRIPT(bld, libname, abi_directory, version, vscript, abi_match=None, p
libname = os.path.basename(libname)
version = os.path.basename(version)
libname = libname.replace("-", "_").replace("+","_").upper()
version = version.replace("-", "_").replace("+","_").upper()
libname = re.sub(r'\W', '_', libname).upper()
version = re.sub(r'\W', '_', version).upper()
t = bld.SAMBA_GENERATOR(vscript,
rule=abi_build_vscript,
......
......@@ -272,7 +272,7 @@ static void queue_dead(struct tevent_context *ev, struct tevent_immediate *im,
/*
called when an incoming connection is writeable
*/
static void queue_io_write(struct ctdb_queue *queue)
static bool queue_io_write(struct ctdb_queue *queue)
{
while (queue->out_queue) {
struct ctdb_queue_pkt *pkt = queue->out_queue;
......@@ -294,14 +294,14 @@ static void queue_io_write(struct ctdb_queue *queue)
queue->fd = -1;
tevent_schedule_immediate(queue->im, queue->ctdb->ev,
queue_dead, queue);
return;
return false;
}
if (n <= 0) return;
if (n <= 0) return true;
if (n != pkt->length) {
pkt->length -= n;
pkt->data += n;
return;
return true;
}
DLIST_REMOVE(queue->out_queue, pkt);
......@@ -310,6 +310,8 @@ static void queue_io_write(struct ctdb_queue *queue)
}
TEVENT_FD_NOT_WRITEABLE(queue->fde);
return true;
}
/*
......@@ -320,10 +322,13 @@ static void queue_io_handler(struct tevent_context *ev, struct tevent_fd *fde,
{
struct ctdb_queue *queue = talloc_get_type(private_data, struct ctdb_queue);
if (flags & TEVENT_FD_WRITE) {
if (!queue_io_write(queue)) {
return;
}
}
if (flags & TEVENT_FD_READ) {
queue_io_read(queue);
} else {
queue_io_write(queue);
}
}
......
......@@ -7,20 +7,44 @@
<para>
The <smbconfoption name="ldap server require strong auth"/> defines whether
the ldap server requires ldap traffic to be signed or signed and encrypted (sealed).
Possible values are <emphasis>no</emphasis>, <emphasis>allow_sasl_over_tls</emphasis>
Possible values are <emphasis>no</emphasis>,
<emphasis>allow_sasl_without_tls_channel_bindings</emphasis>
and <emphasis>yes</emphasis>.
</para>
<para>Windows has <emphasis>LdapEnforceChannelBinding</emphasis> under
<emphasis>HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters\</emphasis>.
</para>
<para>A value of <emphasis>no</emphasis> allows simple and sasl binds over
all transports.</para>
all transports. This matches LdapEnforceChannelBinding=0.</para>
<para>A value of <emphasis>allow_sasl_without_tls_channel_bindings</emphasis>
allows simple and sasl binds (without sign or seal) over TLS encrypted connections.
Missing tls channel bindings are ignored, so only use this if a value of
<emphasis>yes</emphasis> is not possible.
Unencrypted connections only allow sasl binds with sign or seal.
This matches LdapEnforceChannelBinding=1.
</para>
<para>A value of <emphasis>allow_sasl_over_tls</emphasis> allows simple and sasl binds
(without sign or seal) over TLS encrypted connections. Unencrypted connections only
allow sasl binds with sign or seal.</para>
<para>Before support for tls channel bindings existed in Samba,
a value of <emphasis>allow_sasl_over_tls</emphasis> was possible in order
to allow sasl binds without tls channel bindings. This now misleading
as a value of <emphasis>yes</emphasis> will now allow sasl binds
with tls channel bindings. Configurations should be changed to
<emphasis>yes</emphasis> instead or
<emphasis>allow_sasl_without_tls_channel_bindings</emphasis>
if really required. Currently <emphasis>allow_sasl_over_tls</emphasis>
is just an alias of <emphasis>allow_sasl_without_tls_channel_bindings</emphasis>,
but it will be removed in future versions.
</para>
<para>A value of <emphasis>yes</emphasis> allows only simple binds
over TLS encrypted connections. Unencrypted connections only
allow sasl binds with sign or seal.</para>
and sasl binds with correct tls channel bindings
over TLS encrypted connections. sasl binds without tls channel bindings
are not allowed. Unencrypted connections only
allow sasl binds with sign or seal. This matches LdapEnforceChannelBinding=2.
</para>
</description>
<value type="default">yes</value>
</samba:parameter>
......@@ -11,6 +11,9 @@
<xsl:param name="use.id.as.filename" select="1"/>
<xsl:param name="man.endnotes.are.numbered" select="0"/>
<!-- make room for long version numbers -->
<xsl:param name="man.th.extra2.max.length">40</xsl:param>
<!--
Our ulink stylesheet omits @url part if content was specified
-->
......
......@@ -135,63 +135,230 @@ void samba_cmdline_set_machine_account_fn(
cli_credentials_set_machine_account_fn = fn;
}
/*
* Are the strings p and option equal from the point of view of option
* parsing, meaning is the next character '\0' or '='.
*/
static bool strneq_cmdline_exact(const char *p, const char *option, size_t len)
{
if (strncmp(p, option, len) == 0) {
if (p[len] == 0 || p[len] == '=') {
return true;
}
}
return false;
}
/*
* Return true if the argument to the option should be redacted.
*
* The option name is presumed to contain the substring "pass". It is checked
* against a list of options that specify secrets. If it is there, the value
* should be redacted and we return early.
*
* Otherwise, it is checked against a list of known safe options. If it is
* there, we return false.
*
* If the option is not in either list, we assume it might be secret and
* redact the argument, but warn loadly about it. The hope is that developers
* will see what they're doing and add the option to the appropriate list.
*
* If true is returned, *ulen will be set to the apparent length of the
* option. It is set to zero if false is returned (we don't need it in that
* case).
*/
static bool is_password_option(const char *p, size_t *ulen)
{
size_t i, len;
static const char *must_burn[] = {
"--password",
"--newpassword",
"--password2",
"--adminpass",
"--dnspass",
"--machinepass",
"--krbtgtpass",
"--fixed-password",
};
static const char *allowed[] = {
"--bad-password-count-reset",
"--badpassword-frequency",
"--change-user-password",
"--force-initialized-passwords",
"--machine-pass", /* distinct from --machinepass */
"--managed-password-interval",
"--no-pass",
"--no-pass2",
"--no-passthrough",
"--no-password",
"--passcmd",
"--passwd",
"--passwd_path",
"--password-file",
"--password-from-stdin",
"--random-password",
"--smbpasswd-style",
"--strip-passed-output",
"--with-smbpasswd-file",
};
char *equals = NULL;
*ulen = 0;
for (i = 0; i < ARRAY_SIZE(must_burn); i++) {
bool secret;
len = strlen(must_burn[i]);
secret = strneq_cmdline_exact(p, must_burn[i], len);
if (secret) {
*ulen = len;
return true;
}
}
for (i = 0; i < ARRAY_SIZE(allowed); i++) {
bool safe;
len = strlen(allowed[i]);
safe = strneq_cmdline_exact(p, allowed[i], len);
if (safe) {
return false;
}
}
/*
* We have found a suspicious option, and we need to work out where to
* burn it from. It could be
*
* --secret-password=cow -> password after '='
* --secret-password -> password is in next argument.
*
* but we also have the possibility of
*
* --cow=secret-password
*
* that is, the 'pass' in this option string is not in the option but
* the argument to it, which should not be burnt.
*/
equals = strchr(p, '=');
if (equals == NULL) {
*ulen = strlen(p);
} else {
char *pass = (strstr(p, "pass"));
if (pass > equals) {
/* this is --foo=pass, not --pass=foo */
return false;
}
*ulen = equals - p;
}
/*
* This message will be seen with Python tools when an option
* is misspelt, but not with C tools, because in C burning
* happens after the command line is parsed, while in Python
* it happens before (on a copy of argv).
*
* In either case it will appear for a newly added option, and
* we hope developers will notice it before pushing.
*/
DBG_ERR("\nNote for developers: if '%*s' is not misspelt, it should be "
"added to the appropriate list in is_password_option().\n\n",
(int)(*ulen), p);
return true;
}
bool samba_cmdline_burn(int argc, char *argv[])
{
bool burnt = false;
bool found = false;
bool is_user = false;
char *p = NULL;
int i;
size_t ulen = 0;
for (i = 0; i < argc; i++) {
bool found = false;
bool is_user = false;
size_t ulen = 0;
char *p = NULL;
p = argv[i];
if (p == NULL) {
return false;
return burnt;
}
/*
* Take care that this list must be in longest-match
* first order
*/
if (strncmp(p, "-U", 2) == 0) {
/*
* Note: this won't catch combinations of
* short options like
* `samba-tool -NUAdministrator%...`, which is
* not possible in general outside of the
* actual parser (consider for example
* `-NHUroot%password`, which parses as
* `-N -H 'Uroot%password'`). We don't know
* here which short options might take
* arguments.
*
* This is an argument for embedding redaction
* inside the parser (e.g. by adding a flag to
* the option definitions), but we decided not
* to do that in order to share cmdline_burn().
*/
ulen = 2;
found = true;
is_user = true;
} else if (strncmp(p, "--user", 6) == 0) {
} else if (strneq_cmdline_exact(p, "--user", 6)) {
ulen = 6;
found = true;
is_user = true;
} else if (strncmp(p, "--password2", 11) == 0) {
ulen = 11;
found = true;
} else if (strncmp(p, "--password", 10) == 0) {
} else if (strneq_cmdline_exact(p, "--username", 10)) {
ulen = 10;
found = true;
} else if (strncmp(p, "--newpassword", 13) == 0) {
ulen = 13;
found = true;
is_user = true;
} else if (strncmp(p, "--", 2) == 0 && strstr(p, "pass")) {
/*
* We have many secret options like --password,
* --adminpass, --newpassword, and we could easily
* add more, so we will use an allowlist to let the
* safe ones through (of which there are also many).
*/
found = is_password_option(p, &ulen);
}
if (found) {
char *q = NULL;
if (strlen(p) == ulen) {
continue;
/*
* The option string has no '=', so
* its argument will come in the NEXT
* argv member. If there is one, we
* can just step forward and take it,
* setting ulen to 0.
*
* {"--password=secret"} --> {"--password"}
* {"--password", "secret"} --> {"--password", ""}
* {"-Uadmin%secret"} --> {"-Uadmin"}
* {"-U", "admin%secret"} --> {"-U", "admin"}
*/
i++;
if (i == argc) {
/*
* this looks like an invalid
* command line, but that's
* for the caller to decide.
*/
return burnt;
}
p = argv[i];
if (p == NULL) {
return burnt;
}
ulen = 0;
}
if (is_user) {
q = strchr_m(p, '%');
if (q != NULL) {
p = q;
char *q = strchr_m(p, '%');
if (q == NULL) {
/* -U without '%' has no secret */
continue;
}
p = q;
} else {
p += ulen;
}
memset_s(p, strlen(p), '\0', strlen(p));
found = false;
is_user = false;
burnt = true;
}
}
......
......@@ -24,6 +24,7 @@
#include <cmocka.h>
#include <time.h>
#include <sys/time.h>
#include "replace.h"
#include "lib/cmdline/cmdline.h"
......@@ -61,20 +62,59 @@ static void torture_cmdline_sanity_check_bad(void **state)
static void torture_cmdline_burn(void **state)
{
/* arg1 would require -U' Administrator%secret' */
char arg1[] = "-U Administrator%secret";
char arg2[] = "--user=Administrator%secret";
char arg3[] = "--user=Administrator%super%secret";
char arg4[] = "--password=super%secret";
char arg2[] = "--no-no-no-not-secret=not%secret";
char arg3[] = "--user=Administrator%secret";
char arg4[] = "--user=Administrator%super%secret";
char arg5[] = "--password=super%secret";
char arg6[] = "--no-no-no-not-secret=not%secret";
char arg7[] = "-U";
char arg8[] = "fish%chips";
char arg9[] = "--password";
char arg10[] = "fish%chips";
char arg11[] = "--password2";
char arg12[] = "fish%chips";
char arg13[] = "--username=Admonisher % secretest";
/*
* The next two are not used in samba (--client-password
* appears in a Heimdal script that won't use lib/cmdline even
* if built) and are burnt by virtue of not being in the allow
* list.
*/
char arg14[] = "--client-password=bean stew";
char arg15[] = "--enpassant="; /* like --enpassant='', no effect on affect next arg */
char arg16[] = "bean";
char arg17[] = "--bean=password";
char arg18[] = "--name";
char arg19[] = "Compass Alompass";
char *argv[] = { arg1, arg2, arg3, arg4, NULL };
int argc = 4;
char *argv[] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17,
arg18, arg19, NULL };
int argc = ARRAY_SIZE(argv) - 1;
samba_cmdline_burn(argc, argv);
assert_string_equal(arg1, "-U Administrator");
assert_string_equal(arg2, "--user=Administrator");
assert_string_equal(arg2, "--no-no-no-not-secret=not%secret");
assert_string_equal(arg3, "--user=Administrator");
assert_string_equal(arg4, "--password");
assert_string_equal(arg4, "--user=Administrator");
assert_string_equal(arg5, "--password");
assert_string_equal(arg6, "--no-no-no-not-secret=not%secret");
assert_string_equal(arg7, "-U");
assert_string_equal(arg8, "fish");
assert_string_equal(arg9, "--password");
assert_string_equal(arg10, "");
assert_string_equal(arg11, "--password2");
assert_string_equal(arg12, "");
assert_string_equal(arg13, "--username=Admonisher ");
assert_string_equal(arg14, "--client-password");
assert_string_equal(arg15, "--enpassant");
assert_string_equal(arg16, "bean");
assert_string_equal(arg17, "--bean=password");
assert_string_equal(arg18, "--name");
assert_string_equal(arg19, "Compass Alompass");
}
int main(int argc, char *argv[])
......
......@@ -233,4 +233,10 @@ NTSTATUS samba_gnutls_sp800_108_derive_key(
uint8_t *KO,
size_t KO_len);
#ifndef HAVE_GNUTLS_CB_TLS_SERVER_END_POINT
int legacy_gnutls_server_end_point_cb(gnutls_session_t session,
bool is_server,
gnutls_datum_t * cb);
#endif /* HAVE_GNUTLS_CB_TLS_SERVER_END_POINT */
#endif /* _GNUTLS_HELPERS_H */
/*
* Copyright (C) 2002-2016 Free Software Foundation, Inc.
* Copyright (C) 2014-2016 Nikos Mavrogiannopoulos
* Copyright (C) 2015-2018 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GnuTLS.
*
* The GnuTLS is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>
*
*/
#include "replace.h"
#include "gnutls_helpers.h"
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
int legacy_gnutls_server_end_point_cb(gnutls_session_t session,
bool is_server,
gnutls_datum_t * cb)
{
/*
* copied from the logic in gnutls_session_channel_binding()
* introduced by gnutls commit (as LGPL 2.1+):
*
* commit 9ebee00c793e40e3e8c797c645577c9e025b9f1e
* Author: Ruslan N. Marchenko <me@ruff.mobi>
* Date: Sat May 1 23:05:54 2021 +0200
*
* Add tls-server-end-point tls channel binding implementation.
* ...
*/
const gnutls_datum_t *ders = NULL;
unsigned int num_certs = 1;
int ret;
size_t rlen;
gnutls_x509_crt_t cert;
gnutls_digest_algorithm_t algo;
/* Only X509 certificates are supported for this binding type */
ret = gnutls_certificate_type_get(session);
if (ret != GNUTLS_CRT_X509) {
return GNUTLS_E_UNIMPLEMENTED_FEATURE;
}
if (is_server) {
ders = gnutls_certificate_get_ours(session);
} else {
ders = gnutls_certificate_get_peers(session, &num_certs);
}
/* Previous check indicated we have x509 but you never know */
if (!ders || num_certs == 0) {
return GNUTLS_E_UNIMPLEMENTED_FEATURE;
}
ret = gnutls_x509_crt_list_import(&cert,
&num_certs,
ders,
GNUTLS_X509_FMT_DER,
0);
/* Again, this is not supposed to happen (normally) */
if (ret < 0 || num_certs == 0) {
return GNUTLS_E_CHANNEL_BINDING_NOT_AVAILABLE;
}
/* Obtain signature algorithm used by certificate */
ret = gnutls_x509_crt_get_signature_algorithm(cert);
if (ret < 0 || ret == GNUTLS_SIGN_UNKNOWN) {
gnutls_x509_crt_deinit(cert);
return GNUTLS_E_UNIMPLEMENTED_FEATURE;
}
/* obtain hash function from signature and normalize it */
algo = gnutls_sign_get_hash_algorithm(ret);
switch (algo) {
case GNUTLS_DIG_MD5:
case GNUTLS_DIG_SHA1:
algo = GNUTLS_DIG_SHA256;
break;
case GNUTLS_DIG_UNKNOWN:
case GNUTLS_DIG_NULL:
case GNUTLS_DIG_MD5_SHA1:
/* double hashing not supported either */
gnutls_x509_crt_deinit(cert);
return GNUTLS_E_UNIMPLEMENTED_FEATURE;
default:
break;
}
/* preallocate 512 bits buffer as maximum supported digest */
rlen = 64;
cb->data = gnutls_malloc(rlen);
if (cb->data == NULL) {
gnutls_x509_crt_deinit(cert);
return GNUTLS_E_MEMORY_ERROR;
}
ret = gnutls_x509_crt_get_fingerprint(cert,
algo,
cb->data,
&rlen);
if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
cb->data = gnutls_realloc(cb->data, cb->size);
if (cb->data == NULL) {
gnutls_x509_crt_deinit(cert);
return GNUTLS_E_MEMORY_ERROR;
}
ret = gnutls_x509_crt_get_fingerprint(cert,
algo,
cb->data,
&rlen);
}
cb->size = rlen;
gnutls_x509_crt_deinit(cert);
return ret;
}
......@@ -2,6 +2,10 @@
def build(bld):
legacy_gnutls_helpers = ''
if not bld.CONFIG_SET('HAVE_GNUTLS_CB_TLS_SERVER_END_POINT'):
legacy_gnutls_helpers += ' gnutls_server_end_point_cb.c'
bld.SAMBA_SUBSYSTEM("GNUTLS_HELPERS",
source='''
gnutls_error.c
......@@ -9,7 +13,7 @@ def build(bld):
gnutls_arcfour_confounded_md5.c
gnutls_weak_crypto.c
gnutls_sp800_108.c
''',
''' + legacy_gnutls_helpers,
deps="gnutls samba-errors")
bld.SAMBA_SUBSYSTEM('LIBCRYPTO',
......