diff -Nru samba-4.13.3+dfsg/auth/auth_util.c samba-4.13.14+dfsg/auth/auth_util.c
--- samba-4.13.3+dfsg/auth/auth_util.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/auth/auth_util.c 2021-11-08 11:29:14.000000000 +0000
@@ -26,26 +26,28 @@
struct auth_session_info *copy_session_info(TALLOC_CTX *mem_ctx,
const struct auth_session_info *src)
{
+ TALLOC_CTX *frame = talloc_stackframe();
struct auth_session_info *dst;
DATA_BLOB blob;
enum ndr_err_code ndr_err;
ndr_err = ndr_push_struct_blob(
&blob,
- talloc_tos(),
+ frame,
src,
(ndr_push_flags_fn_t)ndr_push_auth_session_info);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
DBG_ERR("copy_session_info(): ndr_push_auth_session_info "
"failed: %s\n",
ndr_errstr(ndr_err));
+ TALLOC_FREE(frame);
return NULL;
}
dst = talloc(mem_ctx, struct auth_session_info);
if (dst == NULL) {
DBG_ERR("talloc failed\n");
- TALLOC_FREE(blob.data);
+ TALLOC_FREE(frame);
return NULL;
}
@@ -54,15 +56,16 @@
dst,
dst,
(ndr_pull_flags_fn_t)ndr_pull_auth_session_info);
- TALLOC_FREE(blob.data);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
DBG_ERR("copy_session_info(): ndr_pull_auth_session_info "
"failed: %s\n",
ndr_errstr(ndr_err));
TALLOC_FREE(dst);
+ TALLOC_FREE(frame);
return NULL;
}
+ TALLOC_FREE(frame);
return dst;
}
diff -Nru samba-4.13.3+dfsg/auth/credentials/credentials_krb5.c samba-4.13.14+dfsg/auth/credentials/credentials_krb5.c
--- samba-4.13.3+dfsg/auth/credentials/credentials_krb5.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/auth/credentials/credentials_krb5.c 2021-10-29 06:17:36.000000000 +0000
@@ -1199,12 +1199,12 @@
break;
}
- ret = smb_krb5_salt_principal(realm,
- username, /* sAMAccountName */
- upn, /* userPrincipalName */
- uac_flags,
- mem_ctx,
- &salt_principal);
+ ret = smb_krb5_salt_principal_str(realm,
+ username, /* sAMAccountName */
+ upn, /* userPrincipalName */
+ uac_flags,
+ mem_ctx,
+ &salt_principal);
if (ret) {
talloc_free(mem_ctx);
return ret;
diff -Nru samba-4.13.3+dfsg/auth/credentials/pycredentials.c samba-4.13.14+dfsg/auth/credentials/pycredentials.c
--- samba-4.13.3+dfsg/auth/credentials/pycredentials.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/auth/credentials/pycredentials.c 2021-09-22 06:59:39.000000000 +0000
@@ -603,8 +603,6 @@
static PyObject *py_creds_set_forced_sasl_mech(PyObject *self, PyObject *args)
{
char *newval;
- enum credentials_obtained obt = CRED_SPECIFIED;
- int _obt = obt;
struct cli_credentials *creds = PyCredentials_AsCliCredentials(self);
if (creds == NULL) {
PyErr_Format(PyExc_TypeError, "Credentials expected");
@@ -614,7 +612,6 @@
if (!PyArg_ParseTuple(args, "s", &newval)) {
return NULL;
}
- obt = _obt;
cli_credentials_set_forced_sasl_mech(creds, newval);
Py_RETURN_NONE;
@@ -766,6 +763,7 @@
if (!PyArg_ParseTuple(args, "s|iO", &newval, &_obt, &py_lp_ctx))
return NULL;
+ obt = _obt;
mem_ctx = talloc_new(NULL);
if (mem_ctx == NULL) {
@@ -781,7 +779,7 @@
ret = cli_credentials_set_ccache(creds,
lp_ctx,
- newval, CRED_SPECIFIED,
+ newval, obt,
&error_string);
if (ret != 0) {
@@ -1223,7 +1221,7 @@
PyTypeObject PyCredentials = {
.tp_name = "credentials.Credentials",
.tp_new = py_creds_new,
- .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_methods = py_creds_methods,
};
diff -Nru samba-4.13.3+dfsg/auth/credentials/tests/bind.py samba-4.13.14+dfsg/auth/credentials/tests/bind.py
--- samba-4.13.3+dfsg/auth/credentials/tests/bind.py 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/auth/credentials/tests/bind.py 2021-11-08 11:29:14.000000000 +0000
@@ -90,7 +90,8 @@
# this test to detect when the LDAP DN is being double-parsed
# but must be in the user@realm style to allow the account to
# be created
- self.ldb.add_ldif("""
+ try:
+ self.ldb.add_ldif("""
dn: """ + self.virtual_user_dn + """
cn: frednurk@""" + self.realm + """
displayName: Fred Nurk
@@ -103,13 +104,21 @@
objectClass: top
objectClass: user
""")
+ except LdbError as e:
+ (num, msg) = e.args
+ self.fail(f"Failed to create e-mail user: {msg}")
+
self.addCleanup(delete_force, self.ldb, self.virtual_user_dn)
- self.ldb.modify_ldif("""
+ try:
+ self.ldb.modify_ldif("""
dn: """ + self.virtual_user_dn + """
changetype: modify
replace: unicodePwd
unicodePwd:: """ + base64.b64encode(u"\"P@ssw0rd\"".encode('utf-16-le')).decode('utf8') + """
""")
+ except LdbError as e:
+ (num, msg) = e.args
+ self.fail(f"Failed to set password on e-mail user: {msg}")
self.ldb.enable_account('distinguishedName=%s' % self.virtual_user_dn)
diff -Nru samba-4.13.3+dfsg/auth/gensec/gensec_util.c samba-4.13.14+dfsg/auth/gensec/gensec_util.c
--- samba-4.13.3+dfsg/auth/gensec/gensec_util.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/auth/gensec/gensec_util.c 2021-11-08 11:29:14.000000000 +0000
@@ -25,6 +25,8 @@
#include "auth/gensec/gensec_internal.h"
#include "auth/common_auth.h"
#include "../lib/util/asn1.h"
+#include "param/param.h"
+#include "libds/common/roles.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
@@ -46,10 +48,27 @@
session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS;
if (!pac_blob) {
- if (gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) {
- DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n",
- principal_string));
- return NT_STATUS_ACCESS_DENIED;
+ enum server_role server_role =
+ lpcfg_server_role(gensec_security->settings->lp_ctx);
+
+ /*
+ * For any domain setup (DC or member) we require having
+ * a PAC, as the service ticket comes from an AD DC,
+ * which will always provide a PAC, unless
+ * UF_NO_AUTH_DATA_REQUIRED is configured for our
+ * account, but that's just an invalid configuration,
+ * the admin configured for us!
+ *
+ * As a legacy case, we still allow kerberos tickets from an MIT
+ * realm, but only in standalone mode. In that mode we'll only
+ * ever accept a kerberos authentication with a keytab file
+ * being explicitly configured via the 'keytab method' option.
+ */
+ if (server_role != ROLE_STANDALONE) {
+ DBG_WARNING("Unable to find PAC in ticket from %s, "
+ "failing to allow access\n",
+ principal_string);
+ return NT_STATUS_NO_IMPERSONATION_TOKEN;
}
DBG_NOTICE("Unable to find PAC for %s, resorting to local "
"user lookup\n", principal_string);
diff -Nru samba-4.13.3+dfsg/auth/ntlmssp/ntlmssp_server.c samba-4.13.14+dfsg/auth/ntlmssp/ntlmssp_server.c
--- samba-4.13.3+dfsg/auth/ntlmssp/ntlmssp_server.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/auth/ntlmssp/ntlmssp_server.c 2021-11-08 11:29:14.000000000 +0000
@@ -799,7 +799,7 @@
struct gensec_security *gensec_security = state->gensec_security;
struct gensec_ntlmssp_context *gensec_ntlmssp = state->gensec_ntlmssp;
struct auth4_context *auth_context = gensec_security->auth_context;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
NTSTATUS status;
status = auth_context->check_ntlm_password_recv(subreq,
diff -Nru samba-4.13.3+dfsg/bootstrap/config.py samba-4.13.14+dfsg/bootstrap/config.py
--- samba-4.13.3+dfsg/bootstrap/config.py 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/bootstrap/config.py 2021-08-09 07:20:55.000000000 +0000
@@ -232,8 +232,10 @@
yum install -y epel-release
yum -v repolist all
-yum config-manager --set-enabled PowerTools -y
-yum config-manager --set-enabled Devel -y
+yum config-manager --set-enabled PowerTools -y || \
+ yum config-manager --set-enabled powertools -y
+yum config-manager --set-enabled Devel -y || \
+ yum config-manager --set-enabled devel -y
yum update -y
yum install -y \
diff -Nru samba-4.13.3+dfsg/bootstrap/generated-dists/centos8/bootstrap.sh samba-4.13.14+dfsg/bootstrap/generated-dists/centos8/bootstrap.sh
--- samba-4.13.3+dfsg/bootstrap/generated-dists/centos8/bootstrap.sh 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/bootstrap/generated-dists/centos8/bootstrap.sh 2021-08-09 07:20:55.000000000 +0000
@@ -12,8 +12,10 @@
yum install -y epel-release
yum -v repolist all
-yum config-manager --set-enabled PowerTools -y
-yum config-manager --set-enabled Devel -y
+yum config-manager --set-enabled PowerTools -y || \
+ yum config-manager --set-enabled powertools -y
+yum config-manager --set-enabled Devel -y || \
+ yum config-manager --set-enabled devel -y
yum update -y
yum install -y \
diff -Nru samba-4.13.3+dfsg/bootstrap/sha1sum.txt samba-4.13.14+dfsg/bootstrap/sha1sum.txt
--- samba-4.13.3+dfsg/bootstrap/sha1sum.txt 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/bootstrap/sha1sum.txt 2021-08-09 07:20:55.000000000 +0000
@@ -1 +1 @@
-1275dc52ac8c1de5981f267df88b85b6f87e299a
+b5b78cacae2fa6cec91925170bc6d4e3774cac9b
diff -Nru samba-4.13.3+dfsg/buildtools/wafsamba/samba_dist.py samba-4.13.14+dfsg/buildtools/wafsamba/samba_dist.py
--- samba-4.13.3+dfsg/buildtools/wafsamba/samba_dist.py 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/buildtools/wafsamba/samba_dist.py 2021-10-29 06:17:36.000000000 +0000
@@ -109,7 +109,7 @@
"""
repo = path
while repo != "/":
- if os.path.isdir(os.path.join(repo, ".git")):
+ if os.path.exists(os.path.join(repo, ".git")):
ls_files_cmd = [ 'git', 'ls-files', '--full-name',
os.path.relpath(path, repo) ]
cwd = None
diff -Nru samba-4.13.3+dfsg/buildtools/wafsamba/samba_third_party.py samba-4.13.14+dfsg/buildtools/wafsamba/samba_third_party.py
--- samba-4.13.3+dfsg/buildtools/wafsamba/samba_third_party.py 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/buildtools/wafsamba/samba_third_party.py 2021-08-06 12:19:57.000000000 +0000
@@ -24,7 +24,7 @@
@conf
def CHECK_SOCKET_WRAPPER(conf):
- return conf.CHECK_BUNDLED_SYSTEM_PKG('socket_wrapper', minversion='1.2.5')
+ return conf.CHECK_BUNDLED_SYSTEM_PKG('socket_wrapper', minversion='1.3.3')
Build.BuildContext.CHECK_SOCKET_WRAPPER = CHECK_SOCKET_WRAPPER
@conf
diff -Nru samba-4.13.3+dfsg/configure samba-4.13.14+dfsg/configure
--- samba-4.13.3+dfsg/configure 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/configure 2021-09-07 07:01:16.000000000 +0000
@@ -13,5 +13,5 @@
unset LD_PRELOAD
cd . || exit 1
-$PYTHON $WAF configure "$@" || exit 1
+$PYTHON $WAF configure $@ || exit 1
cd $PREVPATH
diff -Nru samba-4.13.3+dfsg/ctdb/client/client_control_sync.c samba-4.13.14+dfsg/ctdb/client/client_control_sync.c
--- samba-4.13.3+dfsg/ctdb/client/client_control_sync.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/client/client_control_sync.c 2021-09-22 06:59:39.000000000 +0000
@@ -2718,3 +2718,71 @@
return 0;
}
+
+int ctdb_ctrl_disable_node(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ctdb_client_context *client,
+ int destnode,
+ struct timeval timeout)
+{
+ struct ctdb_req_control request;
+ struct ctdb_reply_control *reply;
+ int ret;
+
+ ctdb_req_control_disable_node(&request);
+ ret = ctdb_client_control(mem_ctx,
+ ev,
+ client,
+ destnode,
+ timeout,
+ &request,
+ &reply);
+ if (ret != 0) {
+ D_ERR("Control DISABLE_NODE failed to node %u, ret=%d\n",
+ destnode,
+ ret);
+ return ret;
+ }
+
+ ret = ctdb_reply_control_disable_node(reply);
+ if (ret != 0) {
+ D_ERR("Control DISABLE_NODE failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int ctdb_ctrl_enable_node(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ctdb_client_context *client,
+ int destnode,
+ struct timeval timeout)
+{
+ struct ctdb_req_control request;
+ struct ctdb_reply_control *reply;
+ int ret;
+
+ ctdb_req_control_enable_node(&request);
+ ret = ctdb_client_control(mem_ctx,
+ ev,
+ client,
+ destnode,
+ timeout,
+ &request,
+ &reply);
+ if (ret != 0) {
+ D_ERR("Control ENABLE_NODE failed to node %u, ret=%d\n",
+ destnode,
+ ret);
+ return ret;
+ }
+
+ ret = ctdb_reply_control_enable_node(reply);
+ if (ret != 0) {
+ D_ERR("Control ENABLE_NODE failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
diff -Nru samba-4.13.3+dfsg/ctdb/client/client_sync.h samba-4.13.14+dfsg/ctdb/client/client_sync.h
--- samba-4.13.3+dfsg/ctdb/client/client_sync.h 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/client/client_sync.h 2021-09-22 06:59:39.000000000 +0000
@@ -491,6 +491,18 @@
int destnode, struct timeval timeout,
uint64_t tunnel_id);
+int ctdb_ctrl_disable_node(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ctdb_client_context *client,
+ int destnode,
+ struct timeval timeout);
+
+int ctdb_ctrl_enable_node(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct ctdb_client_context *client,
+ int destnode,
+ struct timeval timeout);
+
/* from client/client_message_sync.c */
int ctdb_message_recd_update_ip(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
diff -Nru samba-4.13.3+dfsg/ctdb/common/run_proc.c samba-4.13.14+dfsg/ctdb/common/run_proc.c
--- samba-4.13.3+dfsg/ctdb/common/run_proc.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/common/run_proc.c 2021-08-06 12:19:57.000000000 +0000
@@ -426,7 +426,7 @@
state->result = state->proc->result;
if (state->proc->output != NULL) {
- state->output = talloc_steal(state, state->proc->output);
+ state->output = talloc_move(state, &state->proc->output);
}
talloc_steal(state, state->proc);
@@ -464,7 +464,7 @@
state->result.err = ETIMEDOUT;
if (state->proc->output != NULL) {
- state->output = talloc_steal(state, state->proc->output);
+ state->output = talloc_move(state, &state->proc->output);
}
state->pid = state->proc->pid;
@@ -495,7 +495,7 @@
}
if (output != NULL) {
- *output = talloc_steal(mem_ctx, state->output);
+ *output = talloc_move(mem_ctx, &state->output);
}
return true;
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdb.1 samba-4.13.14+dfsg/ctdb/doc/ctdb.1
--- samba-4.13.3+dfsg/ctdb/doc/ctdb.1 2020-12-15 07:54:01.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdb.1 2021-11-08 11:49:13.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ctdb
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CTDB" "1" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB" "1" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdb.7 samba-4.13.14+dfsg/ctdb/doc/ctdb.7
--- samba-4.13.3+dfsg/ctdb/doc/ctdb.7 2020-12-15 07:54:04.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdb.7 2021-11-08 11:49:16.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ctdb
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CTDB" "7" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB" "7" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdb.conf.5 samba-4.13.14+dfsg/ctdb/doc/ctdb.conf.5
--- samba-4.13.3+dfsg/ctdb/doc/ctdb.conf.5 2020-12-15 07:54:03.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdb.conf.5 2021-11-08 11:49:15.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ctdb.conf
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CTDB\&.CONF" "5" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\&.CONF" "5" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdbd.1 samba-4.13.14+dfsg/ctdb/doc/ctdbd.1
--- samba-4.13.3+dfsg/ctdb/doc/ctdbd.1 2020-12-15 07:54:01.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdbd.1 2021-11-08 11:49:14.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ctdbd
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CTDBD" "1" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDBD" "1" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdb_diagnostics.1 samba-4.13.14+dfsg/ctdb/doc/ctdb_diagnostics.1
--- samba-4.13.3+dfsg/ctdb/doc/ctdb_diagnostics.1 2020-12-15 07:54:02.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdb_diagnostics.1 2021-11-08 11:49:14.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ctdb_diagnostics
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CTDB_DIAGNOSTICS" "1" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB_DIAGNOSTICS" "1" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdbd_wrapper.1 samba-4.13.14+dfsg/ctdb/doc/ctdbd_wrapper.1
--- samba-4.13.3+dfsg/ctdb/doc/ctdbd_wrapper.1 2020-12-15 07:54:03.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdbd_wrapper.1 2021-11-08 11:49:15.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ctdbd_wrapper
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CTDBD_WRAPPER" "1" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDBD_WRAPPER" "1" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdb-etcd.7 samba-4.13.14+dfsg/ctdb/doc/ctdb-etcd.7
--- samba-4.13.3+dfsg/ctdb/doc/ctdb-etcd.7 2020-12-15 07:54:05.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdb-etcd.7 2021-11-08 11:49:17.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ctdb-etcd
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CTDB\-ETCD" "7" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\-ETCD" "7" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdb_mutex_ceph_rados_helper.7 samba-4.13.14+dfsg/ctdb/doc/ctdb_mutex_ceph_rados_helper.7
--- samba-4.13.3+dfsg/ctdb/doc/ctdb_mutex_ceph_rados_helper.7 2020-12-15 07:54:06.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdb_mutex_ceph_rados_helper.7 2021-11-08 11:49:17.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: Ceph RADOS Mutex
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CEPH RADOS MUTEX" "7" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CEPH RADOS MUTEX" "7" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdb-script.options.5 samba-4.13.14+dfsg/ctdb/doc/ctdb-script.options.5
--- samba-4.13.3+dfsg/ctdb/doc/ctdb-script.options.5 2020-12-15 07:54:04.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdb-script.options.5 2021-11-08 11:49:16.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ctdb-script.options
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CTDB\-SCRIPT\&.OPTIO" "5" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\-SCRIPT\&.OPTIO" "5" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdb-statistics.7 samba-4.13.14+dfsg/ctdb/doc/ctdb-statistics.7
--- samba-4.13.3+dfsg/ctdb/doc/ctdb-statistics.7 2020-12-15 07:54:05.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdb-statistics.7 2021-11-08 11:49:17.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ctdb-statistics
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CTDB\-STATISTICS" "7" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\-STATISTICS" "7" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdb.sysconfig.5 samba-4.13.14+dfsg/ctdb/doc/ctdb.sysconfig.5
--- samba-4.13.3+dfsg/ctdb/doc/ctdb.sysconfig.5 2020-12-15 07:54:04.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdb.sysconfig.5 2021-11-08 11:49:16.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ctdb.sysconfig
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CTDB\&.SYSCONFIG" "5" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\&.SYSCONFIG" "5" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ctdb-tunables.7 samba-4.13.14+dfsg/ctdb/doc/ctdb-tunables.7
--- samba-4.13.3+dfsg/ctdb/doc/ctdb-tunables.7 2020-12-15 07:54:05.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ctdb-tunables.7 2021-11-08 11:49:17.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ctdb-tunables
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "CTDB\-TUNABLES" "7" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "CTDB\-TUNABLES" "7" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ltdbtool.1 samba-4.13.14+dfsg/ctdb/doc/ltdbtool.1
--- samba-4.13.3+dfsg/ctdb/doc/ltdbtool.1 2020-12-15 07:54:02.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ltdbtool.1 2021-11-08 11:49:14.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ltdbtool
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "LTDBTOOL" "1" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "LTDBTOOL" "1" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/onnode.1 samba-4.13.14+dfsg/ctdb/doc/onnode.1
--- samba-4.13.3+dfsg/ctdb/doc/onnode.1 2020-12-15 07:54:03.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/onnode.1 2021-11-08 11:49:15.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: onnode
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "ONNODE" "1" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "ONNODE" "1" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/doc/ping_pong.1 samba-4.13.14+dfsg/ctdb/doc/ping_pong.1
--- samba-4.13.3+dfsg/ctdb/doc/ping_pong.1 2020-12-15 07:54:02.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/doc/ping_pong.1 2021-11-08 11:49:14.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ping_pong
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: CTDB - clustered TDB database
.\" Source: ctdb
.\" Language: English
.\"
-.TH "PING_PONG" "1" "12/15/2020" "ctdb" "CTDB \- clustered TDB database"
+.TH "PING_PONG" "1" "11/08/2021" "ctdb" "CTDB \- clustered TDB database"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/ctdb/include/ctdb_private.h samba-4.13.14+dfsg/ctdb/include/ctdb_private.h
--- samba-4.13.3+dfsg/ctdb/include/ctdb_private.h 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/include/ctdb_private.h 2021-09-22 06:59:39.000000000 +0000
@@ -565,6 +565,8 @@
void daemon_tunnel_handler(uint64_t tunnel_id, TDB_DATA data,
void *private_data);
+struct ctdb_node *ctdb_find_node(struct ctdb_context *ctdb, uint32_t pnn);
+
int ctdb_start_daemon(struct ctdb_context *ctdb,
bool interactive,
bool test_mode_enabled);
diff -Nru samba-4.13.3+dfsg/ctdb/protocol/protocol_api.h samba-4.13.14+dfsg/ctdb/protocol/protocol_api.h
--- samba-4.13.3+dfsg/ctdb/protocol/protocol_api.h 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/protocol/protocol_api.h 2021-09-22 06:59:39.000000000 +0000
@@ -615,6 +615,12 @@
struct ctdb_echo_data *echo_data);
int ctdb_reply_control_echo_data(struct ctdb_reply_control *reply);
+void ctdb_req_control_disable_node(struct ctdb_req_control *request);
+int ctdb_reply_control_disable_node(struct ctdb_reply_control *reply);
+
+void ctdb_req_control_enable_node(struct ctdb_req_control *request);
+int ctdb_reply_control_enable_node(struct ctdb_reply_control *reply);
+
/* From protocol/protocol_debug.c */
void ctdb_packet_print(uint8_t *buf, size_t buflen, FILE *fp);
diff -Nru samba-4.13.3+dfsg/ctdb/protocol/protocol_client.c samba-4.13.14+dfsg/ctdb/protocol/protocol_client.c
--- samba-4.13.3+dfsg/ctdb/protocol/protocol_client.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/protocol/protocol_client.c 2021-09-22 06:59:39.000000000 +0000
@@ -2409,3 +2409,39 @@
return reply->status;
}
+
+/* CTDB_CONTROL_DISABLE_NODE */
+
+void ctdb_req_control_disable_node(struct ctdb_req_control *request)
+{
+ request->opcode = CTDB_CONTROL_DISABLE_NODE;
+ request->pad = 0;
+ request->srvid = 0;
+ request->client_id = 0;
+ request->flags = 0;
+
+ request->rdata.opcode = CTDB_CONTROL_DISABLE_NODE;
+}
+
+int ctdb_reply_control_disable_node(struct ctdb_reply_control *reply)
+{
+ return ctdb_reply_control_generic(reply, CTDB_CONTROL_DISABLE_NODE);
+}
+
+/* CTDB_CONTROL_ENABLE_NODE */
+
+void ctdb_req_control_enable_node(struct ctdb_req_control *request)
+{
+ request->opcode = CTDB_CONTROL_ENABLE_NODE;
+ request->pad = 0;
+ request->srvid = 0;
+ request->client_id = 0;
+ request->flags = 0;
+
+ request->rdata.opcode = CTDB_CONTROL_ENABLE_NODE;
+}
+
+int ctdb_reply_control_enable_node(struct ctdb_reply_control *reply)
+{
+ return ctdb_reply_control_generic(reply, CTDB_CONTROL_ENABLE_NODE);
+}
diff -Nru samba-4.13.3+dfsg/ctdb/protocol/protocol_control.c samba-4.13.14+dfsg/ctdb/protocol/protocol_control.c
--- samba-4.13.3+dfsg/ctdb/protocol/protocol_control.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/protocol/protocol_control.c 2021-09-22 06:59:39.000000000 +0000
@@ -419,6 +419,12 @@
case CTDB_CONTROL_ECHO_DATA:
len = ctdb_echo_data_len(cd->data.echo_data);
break;
+
+ case CTDB_CONTROL_DISABLE_NODE:
+ break;
+
+ case CTDB_CONTROL_ENABLE_NODE:
+ break;
}
return len;
@@ -1418,6 +1424,12 @@
case CTDB_CONTROL_ECHO_DATA:
len = ctdb_echo_data_len(cd->data.echo_data);
break;
+
+ case CTDB_CONTROL_DISABLE_NODE:
+ break;
+
+ case CTDB_CONTROL_ENABLE_NODE:
+ break;
}
return len;
diff -Nru samba-4.13.3+dfsg/ctdb/protocol/protocol_debug.c samba-4.13.14+dfsg/ctdb/protocol/protocol_debug.c
--- samba-4.13.3+dfsg/ctdb/protocol/protocol_debug.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/protocol/protocol_debug.c 2021-09-22 06:59:39.000000000 +0000
@@ -245,6 +245,8 @@
{ CTDB_CONTROL_VACUUM_FETCH, "VACUUM_FETCH" },
{ CTDB_CONTROL_DB_VACUUM, "DB_VACUUM" },
{ CTDB_CONTROL_ECHO_DATA, "ECHO_DATA" },
+ { CTDB_CONTROL_DISABLE_NODE, "DISABLE_NODE" },
+ { CTDB_CONTROL_ENABLE_NODE, "ENABLE_NODE" },
{ MAP_END, "" },
};
diff -Nru samba-4.13.3+dfsg/ctdb/protocol/protocol.h samba-4.13.14+dfsg/ctdb/protocol/protocol.h
--- samba-4.13.3+dfsg/ctdb/protocol/protocol.h 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/protocol/protocol.h 2021-09-22 06:59:39.000000000 +0000
@@ -137,7 +137,7 @@
/* SRVID to inform clients that an IP address has been taken over */
#define CTDB_SRVID_TAKE_IP 0xF301000000000000LL
-/* SRVID to inform recovery daemon of the node flags */
+/* SRVID to inform recovery daemon of the node flags - OBSOLETE */
#define CTDB_SRVID_SET_NODE_FLAGS 0xF400000000000000LL
/* SRVID to inform recovery daemon to update public ip assignment */
@@ -376,6 +376,8 @@
CTDB_CONTROL_VACUUM_FETCH = 154,
CTDB_CONTROL_DB_VACUUM = 155,
CTDB_CONTROL_ECHO_DATA = 156,
+ CTDB_CONTROL_DISABLE_NODE = 157,
+ CTDB_CONTROL_ENABLE_NODE = 158,
};
#define MAX_COUNT_BUCKETS 16
diff -Nru samba-4.13.3+dfsg/ctdb/server/ctdb_control.c samba-4.13.14+dfsg/ctdb/server/ctdb_control.c
--- samba-4.13.3+dfsg/ctdb/server/ctdb_control.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/server/ctdb_control.c 2021-09-22 06:59:39.000000000 +0000
@@ -173,6 +173,40 @@
TALLOC_FREE(state);
}
+static int ctdb_control_disable_node(struct ctdb_context *ctdb)
+{
+ struct ctdb_node *node;
+
+ node = ctdb_find_node(ctdb, CTDB_CURRENT_NODE);
+ if (node == NULL) {
+ /* Can't happen */
+ DBG_ERR("Unable to find current node\n");
+ return -1;
+ }
+
+ D_ERR("Disable node\n");
+ node->flags |= NODE_FLAGS_PERMANENTLY_DISABLED;
+
+ return 0;
+}
+
+static int ctdb_control_enable_node(struct ctdb_context *ctdb)
+{
+ struct ctdb_node *node;
+
+ node = ctdb_find_node(ctdb, CTDB_CURRENT_NODE);
+ if (node == NULL) {
+ /* Can't happen */
+ DBG_ERR("Unable to find current node\n");
+ return -1;
+ }
+
+ D_ERR("Enable node\n");
+ node->flags &= ~NODE_FLAGS_PERMANENTLY_DISABLED;
+
+ return 0;
+}
+
/*
process a control request
*/
@@ -828,6 +862,14 @@
return ctdb_control_echo_data(ctdb, c, indata, async_reply);
}
+ case CTDB_CONTROL_DISABLE_NODE:
+ CHECK_CONTROL_DATA_SIZE(0);
+ return ctdb_control_disable_node(ctdb);
+
+ case CTDB_CONTROL_ENABLE_NODE:
+ CHECK_CONTROL_DATA_SIZE(0);
+ return ctdb_control_enable_node(ctdb);
+
default:
DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
return -1;
diff -Nru samba-4.13.3+dfsg/ctdb/server/ctdb_daemon.c samba-4.13.14+dfsg/ctdb/server/ctdb_daemon.c
--- samba-4.13.3+dfsg/ctdb/server/ctdb_daemon.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/server/ctdb_daemon.c 2021-09-22 06:59:39.000000000 +0000
@@ -1225,28 +1225,51 @@
return -1;
}
-static void initialise_node_flags (struct ctdb_context *ctdb)
+struct ctdb_node *ctdb_find_node(struct ctdb_context *ctdb, uint32_t pnn)
{
+ struct ctdb_node *node = NULL;
unsigned int i;
+ if (pnn == CTDB_CURRENT_NODE) {
+ pnn = ctdb->pnn;
+ }
+
/* Always found: PNN correctly set just before this is called */
for (i = 0; i < ctdb->num_nodes; i++) {
- if (ctdb->pnn == ctdb->nodes[i]->pnn) {
- break;
+ node = ctdb->nodes[i];
+ if (pnn == node->pnn) {
+ return node;
}
}
- ctdb->nodes[i]->flags &= ~NODE_FLAGS_DISCONNECTED;
+ return NULL;
+}
+
+static void initialise_node_flags (struct ctdb_context *ctdb)
+{
+ struct ctdb_node *node = NULL;
+
+ node = ctdb_find_node(ctdb, CTDB_CURRENT_NODE);
+ /*
+ * PNN correctly set just before this is called so always
+ * found but keep static analysers happy...
+ */
+ if (node == NULL) {
+ DBG_ERR("Unable to find current node\n");
+ return;
+ }
+
+ node->flags &= ~NODE_FLAGS_DISCONNECTED;
/* do we start out in DISABLED mode? */
if (ctdb->start_as_disabled != 0) {
D_ERR("This node is configured to start in DISABLED state\n");
- ctdb->nodes[i]->flags |= NODE_FLAGS_DISABLED;
+ node->flags |= NODE_FLAGS_PERMANENTLY_DISABLED;
}
/* do we start out in STOPPED mode? */
if (ctdb->start_as_stopped != 0) {
D_ERR("This node is configured to start in STOPPED state\n");
- ctdb->nodes[i]->flags |= NODE_FLAGS_STOPPED;
+ node->flags |= NODE_FLAGS_STOPPED;
}
}
diff -Nru samba-4.13.3+dfsg/ctdb/server/ctdb_monitor.c samba-4.13.14+dfsg/ctdb/server/ctdb_monitor.c
--- samba-4.13.3+dfsg/ctdb/server/ctdb_monitor.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/server/ctdb_monitor.c 2021-09-22 06:59:39.000000000 +0000
@@ -455,52 +455,55 @@
struct ctdb_node *node;
uint32_t old_flags;
- if (c->pnn >= ctdb->num_nodes) {
- DEBUG(DEBUG_ERR,(__location__ " Node %d is invalid, num_nodes :%d\n", c->pnn, ctdb->num_nodes));
- return -1;
+ /*
+ * Don't let other nodes override the current node's flags.
+ * The recovery master fetches flags from this node so there's
+ * no need to push them back. Doing so is racy.
+ */
+ if (c->pnn == ctdb->pnn) {
+ DBG_DEBUG("Ignoring flag changes for current node\n");
+ return 0;
}
- node = ctdb->nodes[c->pnn];
- old_flags = node->flags;
- if (c->pnn != ctdb->pnn) {
- c->old_flags = node->flags;
+ node = ctdb_find_node(ctdb, c->pnn);
+ if (node == NULL) {
+ DBG_ERR("Node %u is invalid\n", c->pnn);
+ return -1;
}
- node->flags = c->new_flags & ~NODE_FLAGS_DISCONNECTED;
- node->flags |= (c->old_flags & NODE_FLAGS_DISCONNECTED);
- /* we don't let other nodes modify our STOPPED status */
- if (c->pnn == ctdb->pnn) {
- node->flags &= ~NODE_FLAGS_STOPPED;
- if (old_flags & NODE_FLAGS_STOPPED) {
- node->flags |= NODE_FLAGS_STOPPED;
- }
+ if (node->flags & NODE_FLAGS_DISCONNECTED) {
+ DBG_DEBUG("Ignoring flag changes for disconnected node\n");
+ return 0;
}
- /* we don't let other nodes modify our BANNED status */
- if (c->pnn == ctdb->pnn) {
- node->flags &= ~NODE_FLAGS_BANNED;
- if (old_flags & NODE_FLAGS_BANNED) {
- node->flags |= NODE_FLAGS_BANNED;
- }
- }
+ /*
+ * Remember the old flags. We don't care what some other node
+ * thought the old flags were - that's irrelevant.
+ */
+ old_flags = node->flags;
+
+ /*
+ * This node tracks nodes it is connected to, so don't let
+ * another node override this
+ */
+ node->flags =
+ (old_flags & NODE_FLAGS_DISCONNECTED) |
+ (c->new_flags & ~NODE_FLAGS_DISCONNECTED);
- if (node->flags == c->old_flags) {
- DEBUG(DEBUG_INFO, ("Control modflags on node %u - Unchanged - flags 0x%x\n", c->pnn, node->flags));
+ if (node->flags == old_flags) {
return 0;
}
- DEBUG(DEBUG_INFO, ("Control modflags on node %u - flags now 0x%x\n", c->pnn, node->flags));
+ D_NOTICE("Node %u has changed flags - 0x%x -> 0x%x\n",
+ c->pnn,
+ old_flags,
+ node->flags);
if (node->flags == 0 && ctdb->runstate <= CTDB_RUNSTATE_STARTUP) {
- DEBUG(DEBUG_ERR, (__location__ " Node %u became healthy - force recovery for startup\n",
- c->pnn));
+ DBG_ERR("Node %u became healthy - force recovery for startup\n",
+ c->pnn);
ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE;
}
- /* tell the recovery daemon something has changed */
- c->new_flags = node->flags;
- ctdb_daemon_send_message(ctdb, ctdb->pnn,
- CTDB_SRVID_SET_NODE_FLAGS, indata);
-
return 0;
}
diff -Nru samba-4.13.3+dfsg/ctdb/server/ctdb_recoverd.c samba-4.13.14+dfsg/ctdb/server/ctdb_recoverd.c
--- samba-4.13.3+dfsg/ctdb/server/ctdb_recoverd.c 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/server/ctdb_recoverd.c 2021-09-22 06:59:39.000000000 +0000
@@ -553,40 +553,73 @@
for (j=0; jnum; j++) {
struct ctdb_node_map_old *remote_nodemap=NULL;
uint32_t local_flags = nodemap->nodes[j].flags;
+ uint32_t remote_pnn = nodemap->nodes[j].pnn;
uint32_t remote_flags;
+ unsigned int i;
int ret;
if (local_flags & NODE_FLAGS_DISCONNECTED) {
continue;
}
- if (nodemap->nodes[j].pnn == ctdb->pnn) {
- continue;
+ if (remote_pnn == ctdb->pnn) {
+ /*
+ * No remote nodemap for this node since this
+ * is the local nodemap. However, still need
+ * to check this against the remote nodes and
+ * push it if they are out-of-date.
+ */
+ goto compare_remotes;
}
remote_nodemap = remote_nodemaps[j];
remote_flags = remote_nodemap->nodes[j].flags;
if (local_flags != remote_flags) {
- ret = update_flags_on_all_nodes(rec,
- nodemap->nodes[j].pnn,
- remote_flags);
- if (ret != 0) {
- DBG_ERR(
- "Unable to update flags on remote nodes\n");
- talloc_free(mem_ctx);
- return -1;
- }
-
/*
* Update the local copy of the flags in the
* recovery daemon.
*/
D_NOTICE("Remote node %u had flags 0x%x, "
"local had 0x%x - updating local\n",
- nodemap->nodes[j].pnn,
+ remote_pnn,
remote_flags,
local_flags);
nodemap->nodes[j].flags = remote_flags;
+ local_flags = remote_flags;
+ goto push;
+ }
+
+compare_remotes:
+ for (i = 0; i < nodemap->num; i++) {
+ if (i == j) {
+ continue;
+ }
+ if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+ continue;
+ }
+ if (nodemap->nodes[i].pnn == ctdb->pnn) {
+ continue;
+ }
+
+ remote_nodemap = remote_nodemaps[i];
+ remote_flags = remote_nodemap->nodes[j].flags;
+
+ if (local_flags != remote_flags) {
+ goto push;
+ }
+ }
+
+ continue;
+
+push:
+ D_NOTICE("Pushing updated flags for node %u (0x%x)\n",
+ remote_pnn,
+ local_flags);
+ ret = update_flags_on_all_nodes(rec, remote_pnn, local_flags);
+ if (ret != 0) {
+ DBG_ERR("Unable to update flags on remote nodes\n");
+ talloc_free(mem_ctx);
+ return -1;
}
}
talloc_free(mem_ctx);
@@ -1748,54 +1781,21 @@
}
-
-/*
- handler for when a node changes its flags
-*/
-static void monitor_handler(uint64_t srvid, TDB_DATA data, void *private_data)
+static void srvid_not_implemented(uint64_t srvid,
+ TDB_DATA data,
+ void *private_data)
{
- struct ctdb_recoverd *rec = talloc_get_type(
- private_data, struct ctdb_recoverd);
- struct ctdb_context *ctdb = rec->ctdb;
- int ret;
- struct ctdb_node_flag_change *c = (struct ctdb_node_flag_change *)data.dptr;
- struct ctdb_node_map_old *nodemap=NULL;
- TALLOC_CTX *tmp_ctx;
- unsigned int i;
+ const char *s;
- if (data.dsize != sizeof(*c)) {
- DEBUG(DEBUG_ERR,(__location__ "Invalid data in ctdb_node_flag_change\n"));
- return;
- }
-
- tmp_ctx = talloc_new(ctdb);
- CTDB_NO_MEMORY_VOID(ctdb, tmp_ctx);
-
- ret = ctdb_ctrl_getnodemap(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
- if (ret != 0) {
- DEBUG(DEBUG_ERR,(__location__ "ctdb_ctrl_getnodemap failed in monitor_handler\n"));
- talloc_free(tmp_ctx);
- return;
- }
-
-
- for (i=0;inum;i++) {
- if (nodemap->nodes[i].pnn == c->pnn) break;
- }
-
- if (i == nodemap->num) {
- DEBUG(DEBUG_CRIT,(__location__ "Flag change for non-existant node %u\n", c->pnn));
- talloc_free(tmp_ctx);
- return;
- }
-
- if (c->old_flags != c->new_flags) {
- DEBUG(DEBUG_NOTICE,("Node %u has changed flags - now 0x%x was 0x%x\n", c->pnn, c->new_flags, c->old_flags));
+ switch (srvid) {
+ case CTDB_SRVID_SET_NODE_FLAGS:
+ s = "CTDB_SRVID_SET_NODE_FLAGS";
+ break;
+ default:
+ s = "UNKNOWN";
}
- nodemap->nodes[i].flags = c->new_flags;
-
- talloc_free(tmp_ctx);
+ D_WARNING("SRVID %s (0x%" PRIx64 ") is obsolete\n", s, srvid);
}
/*
@@ -2963,8 +2963,10 @@
/* register a message port for recovery elections */
ctdb_client_set_message_handler(ctdb, CTDB_SRVID_ELECTION, election_handler, rec);
- /* when nodes are disabled/enabled */
- ctdb_client_set_message_handler(ctdb, CTDB_SRVID_SET_NODE_FLAGS, monitor_handler, rec);
+ ctdb_client_set_message_handler(ctdb,
+ CTDB_SRVID_SET_NODE_FLAGS,
+ srvid_not_implemented,
+ rec);
/* when we are asked to puch out a flag change */
ctdb_client_set_message_handler(ctdb, CTDB_SRVID_PUSH_NODE_FLAGS, push_flags_handler, rec);
diff -Nru samba-4.13.3+dfsg/ctdb/server/ctdb_server.c samba-4.13.14+dfsg/ctdb/server/ctdb_server.c
--- samba-4.13.3+dfsg/ctdb/server/ctdb_server.c 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/server/ctdb_server.c 2021-09-22 06:59:39.000000000 +0000
@@ -337,7 +337,6 @@
node->ctdb->num_connected++;
node->dead_count = 0;
node->flags &= ~NODE_FLAGS_DISCONNECTED;
- node->flags |= NODE_FLAGS_UNHEALTHY;
DEBUG(DEBUG_ERR,
("%s: connected to %s - %u connected\n",
node->ctdb->name, node->name, node->ctdb->num_connected));
diff -Nru samba-4.13.3+dfsg/ctdb/tests/src/fake_ctdbd.c samba-4.13.14+dfsg/ctdb/tests/src/fake_ctdbd.c
--- samba-4.13.3+dfsg/ctdb/tests/src/fake_ctdbd.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/tests/src/fake_ctdbd.c 2021-09-22 06:59:39.000000000 +0000
@@ -3513,6 +3513,52 @@
client_send_control(req, header, &reply);
}
+static void control_disable_node(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct ctdb_req_header *header,
+ struct ctdb_req_control *request)
+{
+ struct client_state *state = tevent_req_data(
+ req, struct client_state);
+ struct ctdbd_context *ctdb = state->ctdb;
+ struct ctdb_reply_control reply;
+
+ reply.rdata.opcode = request->opcode;
+
+ DEBUG(DEBUG_INFO, ("Disabling node\n"));
+ ctdb->node_map->node[header->destnode].flags |=
+ NODE_FLAGS_PERMANENTLY_DISABLED;
+
+ reply.status = 0;
+ reply.errmsg = NULL;
+
+ client_send_control(req, header, &reply);
+ return;
+}
+
+static void control_enable_node(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct ctdb_req_header *header,
+ struct ctdb_req_control *request)
+{
+ struct client_state *state = tevent_req_data(
+ req, struct client_state);
+ struct ctdbd_context *ctdb = state->ctdb;
+ struct ctdb_reply_control reply;
+
+ reply.rdata.opcode = request->opcode;
+
+ DEBUG(DEBUG_INFO, ("Enable node\n"));
+ ctdb->node_map->node[header->destnode].flags &=
+ ~NODE_FLAGS_PERMANENTLY_DISABLED;
+
+ reply.status = 0;
+ reply.errmsg = NULL;
+
+ client_send_control(req, header, &reply);
+ return;
+}
+
static bool fake_control_failure(TALLOC_CTX *mem_ctx,
struct tevent_req *req,
struct ctdb_req_header *header,
@@ -4205,6 +4251,14 @@
control_check_pid_srvid(mem_ctx, req, &header, &request);
break;
+ case CTDB_CONTROL_DISABLE_NODE:
+ control_disable_node(mem_ctx, req, &header, &request);
+ break;
+
+ case CTDB_CONTROL_ENABLE_NODE:
+ control_enable_node(mem_ctx, req, &header, &request);
+ break;
+
default:
if (! (request.flags & CTDB_CTRL_FLAG_NOREPLY)) {
control_error(mem_ctx, req, &header, &request);
diff -Nru samba-4.13.3+dfsg/ctdb/tests/src/protocol_common_ctdb.c samba-4.13.14+dfsg/ctdb/tests/src/protocol_common_ctdb.c
--- samba-4.13.3+dfsg/ctdb/tests/src/protocol_common_ctdb.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/tests/src/protocol_common_ctdb.c 2021-09-22 06:59:39.000000000 +0000
@@ -606,6 +606,12 @@
assert(cd->data.echo_data != NULL);
fill_ctdb_echo_data(mem_ctx, cd->data.echo_data);
break;
+
+ case CTDB_CONTROL_DISABLE_NODE:
+ break;
+
+ case CTDB_CONTROL_ENABLE_NODE:
+ break;
}
}
@@ -1004,6 +1010,12 @@
case CTDB_CONTROL_ECHO_DATA:
verify_ctdb_echo_data(cd->data.echo_data, cd2->data.echo_data);
break;
+
+ case CTDB_CONTROL_DISABLE_NODE:
+ break;
+
+ case CTDB_CONTROL_ENABLE_NODE:
+ break;
}
}
@@ -1409,6 +1421,12 @@
assert(cd->data.echo_data != NULL);
fill_ctdb_echo_data(mem_ctx, cd->data.echo_data);
break;
+
+ case CTDB_CONTROL_DISABLE_NODE:
+ break;
+
+ case CTDB_CONTROL_ENABLE_NODE:
+ break;
}
}
@@ -1753,6 +1771,12 @@
case CTDB_CONTROL_ECHO_DATA:
verify_ctdb_echo_data(cd->data.echo_data, cd2->data.echo_data);
break;
+
+ case CTDB_CONTROL_DISABLE_NODE:
+ break;
+
+ case CTDB_CONTROL_ENABLE_NODE:
+ break;
}
}
diff -Nru samba-4.13.3+dfsg/ctdb/tests/src/protocol_ctdb_test.c samba-4.13.14+dfsg/ctdb/tests/src/protocol_ctdb_test.c
--- samba-4.13.3+dfsg/ctdb/tests/src/protocol_ctdb_test.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/tests/src/protocol_ctdb_test.c 2021-09-22 06:59:39.000000000 +0000
@@ -284,7 +284,7 @@
PROTOCOL_CTDB4_TEST(struct ctdb_reply_dmaster, ctdb_reply_dmaster,
CTDB_REPLY_DMASTER);
-#define NUM_CONTROLS 157
+#define NUM_CONTROLS 159
PROTOCOL_CTDB2_TEST(struct ctdb_req_control_data, ctdb_req_control_data);
PROTOCOL_CTDB2_TEST(struct ctdb_reply_control_data, ctdb_reply_control_data);
diff -Nru samba-4.13.3+dfsg/ctdb/tests/src/run_event_test.c samba-4.13.14+dfsg/ctdb/tests/src/run_event_test.c
--- samba-4.13.3+dfsg/ctdb/tests/src/run_event_test.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/tests/src/run_event_test.c 2021-08-06 12:19:57.000000000 +0000
@@ -52,6 +52,19 @@
return arg_str;
}
+static void run_done(struct tevent_req *req)
+{
+ struct run_event_script_list **script_list =
+ tevent_req_callback_data_void(req);
+ bool status;
+ int ret;
+
+ status = run_event_recv(req, &ret, NULL, script_list);
+ if (!status) {
+ fprintf(stderr, "run_event_recv() failed, ret=%d\n", ret);
+ }
+}
+
static void do_run(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
struct run_event_context *run_ctx,
int argc, const char **argv)
@@ -61,8 +74,8 @@
struct run_event_script_list *script_list = NULL;
char *arg_str;
unsigned int i;
- int ret, t;
- bool status;
+ int t;
+ bool wait_for_signal = false;
if (argc < 5) {
usage(argv[0]);
@@ -86,17 +99,13 @@
timeout,
false);
if (req == NULL) {
- fprintf(stderr, "run_proc_send() failed\n");
+ fprintf(stderr, "run_event_send() failed\n");
return;
}
- tevent_req_poll(req, ev);
+ tevent_req_set_callback(req, run_done, &script_list);
- status = run_event_recv(req, &ret, mem_ctx, &script_list);
- if (! status) {
- fprintf(stderr, "run_proc_recv() failed, ret=%d\n", ret);
- return;
- }
+ tevent_req_poll(req, ev);
if (script_list == NULL || script_list->num_scripts == 0) {
printf("No event scripts found\n");
@@ -106,9 +115,30 @@
printf("Event %s completed with result=%d\n",
argv[4], script_list->summary);
for (i=0; inum_scripts; i++) {
- printf("%s result=%d\n", script_list->script[i].name,
- script_list->script[i].summary);
+ struct run_event_script *s = &script_list->script[i];
+ printf("%s result=%d\n", s->name, s->summary);
+
+ if (s->summary == -ETIMEDOUT) {
+ wait_for_signal = true;
+ }
+ }
+
+ TALLOC_FREE(script_list);
+ TALLOC_FREE(req);
+
+ if (!wait_for_signal) {
+ return;
}
+
+ req = tevent_wakeup_send(
+ ev, ev, tevent_timeval_current_ofs(10, 0));
+ if (req == NULL) {
+ fprintf(stderr, "Could not wait for signal\n");
+ return;
+ }
+
+ tevent_req_poll(req, ev);
+ TALLOC_FREE(req);
}
static void do_list(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
diff -Nru samba-4.13.3+dfsg/ctdb/tests/UNIT/cunit/protocol_test_101.sh samba-4.13.14+dfsg/ctdb/tests/UNIT/cunit/protocol_test_101.sh
--- samba-4.13.3+dfsg/ctdb/tests/UNIT/cunit/protocol_test_101.sh 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/tests/UNIT/cunit/protocol_test_101.sh 2021-09-22 06:59:39.000000000 +0000
@@ -2,7 +2,7 @@
. "${TEST_SCRIPTS_DIR}/unit.sh"
-last_control=156
+last_control=158
generate_control_output ()
{
diff -Nru samba-4.13.3+dfsg/ctdb/tests/UNIT/cunit/run_event_001.sh samba-4.13.14+dfsg/ctdb/tests/UNIT/cunit/run_event_001.sh
--- samba-4.13.3+dfsg/ctdb/tests/UNIT/cunit/run_event_001.sh 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/ctdb/tests/UNIT/cunit/run_event_001.sh 2021-08-06 12:19:57.000000000 +0000
@@ -113,7 +113,9 @@
cat > "$scriptdir/22.bar.script" <node[destnode].flags;
- flag_change.new_flags = flag_change.old_flags | set;
- flag_change.new_flags &= ~clear;
-
- count = list_of_connected_nodes(nodemap, -1, mem_ctx, &pnn_list);
- if (count == -1) {
- return ENOMEM;
- }
-
- ctdb_req_control_modify_flags(&request, &flag_change);
- ret = ctdb_client_control_multi(mem_ctx, ev, client, pnn_list, count,
- tevent_timeval_zero(), &request,
- NULL, NULL);
- return ret;
-}
-
struct ipreallocate_state {
int status;
bool done;
@@ -2694,13 +2660,13 @@
return 0;
}
- ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
- ctdb->cmd_pnn, TIMEOUT(),
- NODE_FLAGS_PERMANENTLY_DISABLED, 0);
+ ret = ctdb_ctrl_disable_node(mem_ctx,
+ ctdb->ev,
+ ctdb->client,
+ ctdb->cmd_pnn,
+ TIMEOUT());
if (ret != 0) {
- fprintf(stderr,
- "Failed to set DISABLED flag on node %u\n",
- ctdb->cmd_pnn);
+ fprintf(stderr, "Failed to disable node %u\n", ctdb->cmd_pnn);
return ret;
}
@@ -2723,12 +2689,13 @@
return 0;
}
- ret = ctdb_ctrl_modflags(mem_ctx, ctdb->ev, ctdb->client,
- ctdb->cmd_pnn, TIMEOUT(),
- 0, NODE_FLAGS_PERMANENTLY_DISABLED);
+ ret = ctdb_ctrl_enable_node(mem_ctx,
+ ctdb->ev,
+ ctdb->client,
+ ctdb->cmd_pnn,
+ TIMEOUT());
if (ret != 0) {
- fprintf(stderr, "Failed to reset DISABLED flag on node %u\n",
- ctdb->cmd_pnn);
+ fprintf(stderr, "Failed to enable node %u\n", ctdb->cmd_pnn);
return ret;
}
diff -Nru samba-4.13.3+dfsg/debian/changelog samba-4.13.14+dfsg/debian/changelog
--- samba-4.13.3+dfsg/debian/changelog 2021-04-29 10:48:54.000000000 +0000
+++ samba-4.13.14+dfsg/debian/changelog 2021-11-09 19:52:07.000000000 +0000
@@ -1,3 +1,19 @@
+samba (2:4.13.14+dfsg-0ubuntu0.21.04.1) hirsute-security; urgency=medium
+
+ * Update to 4.13.14 as a security update (LP: #1950363)
+ - debian/patches/CVE-2021-20254.patch: removed, included in new
+ version.
+ - debian/control: bump ldb Build-Depends to 2.2.3.
+ - debian/samba-libs.install: removed libsmbd-conn.so.0, added
+ libdcerpc-pkt-auth.so.0.
+ - debian/libwbclient0.symbols: added new symbol.
+ - debian/patches/trusted_domain_regression_fix.patch: fix regression
+ introduced in 4.13.14.
+ - CVE-2016-2124, CVE-2020-25717, CVE-2020-25718, CVE-2020-25719,
+ CVE-2020-25721, CVE-2020-25722, CVE-2021-3738, CVE-2021-23192
+
+ -- Marc Deslauriers Tue, 09 Nov 2021 14:52:07 -0500
+
samba (2:4.13.3+dfsg-1ubuntu2.1) hirsute-security; urgency=medium
* SECURITY UPDATE: wrong group entries via negative idmap cache entries
diff -Nru samba-4.13.3+dfsg/debian/control samba-4.13.14+dfsg/debian/control
--- samba-4.13.3+dfsg/debian/control 2021-01-13 20:44:04.000000000 +0000
+++ samba-4.13.14+dfsg/debian/control 2021-11-09 19:52:07.000000000 +0000
@@ -32,7 +32,7 @@
libicu-dev,
libjansson-dev,
libldap2-dev,
- libldb-dev (>= 2:2.2.0~),
+ libldb-dev (>= 2:2.2.3~),
libncurses5-dev,
libpam0g-dev,
libparse-yapp-perl,
@@ -53,8 +53,8 @@
python3-dev,
python3-dnspython,
python3-etcd,
- python3-ldb (>= 2:2.2.0~),
- python3-ldb-dev (>= 2:2.2.0~),
+ python3-ldb (>= 2:2.2.3~),
+ python3-ldb-dev (>= 2:2.2.3~),
python3-talloc-dev (>= 2.3.1~),
python3-tdb (>= 1.4.3~),
python3-testtools,
diff -Nru samba-4.13.3+dfsg/debian/libwbclient0.symbols samba-4.13.14+dfsg/debian/libwbclient0.symbols
--- samba-4.13.3+dfsg/debian/libwbclient0.symbols 2021-01-13 19:26:09.000000000 +0000
+++ samba-4.13.14+dfsg/debian/libwbclient0.symbols 2021-11-01 11:33:25.000000000 +0000
@@ -81,6 +81,7 @@
data_path@SAMBA_UTIL_0.0.1 2:4.11.0
directory_create_or_exist@SAMBA_UTIL_0.0.1 2:4.11.0
directory_create_or_exist_strict@SAMBA_UTIL_0.0.1 2:4.11.0
+ directory_create_or_exists_recursive@SAMBA_UTIL_0.0.1 2:4.13.4
directory_exist@SAMBA_UTIL_0.0.1 2:4.11.0
display_set_stderr@SAMBA_UTIL_0.0.1 2:4.11.0
dump_data@SAMBA_UTIL_0.0.1 2:4.11.0
diff -Nru samba-4.13.3+dfsg/debian/patches/CVE-2021-20254.patch samba-4.13.14+dfsg/debian/patches/CVE-2021-20254.patch
--- samba-4.13.3+dfsg/debian/patches/CVE-2021-20254.patch 2021-04-29 10:48:48.000000000 +0000
+++ samba-4.13.14+dfsg/debian/patches/CVE-2021-20254.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,235 +0,0 @@
-From c5f31dbc3b8b86335769b9c84a0d09765cc33259 Mon Sep 17 00:00:00 2001
-From: Volker Lendecke
-Date: Sat, 20 Feb 2021 15:50:12 +0100
-Subject: [PATCH] CVE-2021-20254 passdb: Simplify sids_to_unixids()
-
-Best reviewed with "git show -b", there's a "continue" statement that
-changes subsequent indentation.
-
-Decouple lookup status of ids from ID_TYPE_NOT_SPECIFIED
-
-Bug: https://bugzilla.samba.org/show_bug.cgi?id=14571
-
-Signed-off-by: Volker Lendecke
-Reviewed-by: Jeremy Allison
-
-(backported from patch from master)
-[backport by npower@samba.org as master commit
- 493f5d6b078e0b0f80d1ef25043e2834cb4fcb87 and
- 58e9b62222ad62c81cdf11d704859a227cb2902b creates conflicts
- due to rename of WBC_ID_TYPE_* -> ID_TYPE_*]
----
- source3/passdb/lookup_sid.c | 123 +++++++++++++++++++++++++++++-------
- 1 file changed, 101 insertions(+), 22 deletions(-)
-
-diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c
-index 82c47b3145b..4b3aa7e435d 100644
---- a/source3/passdb/lookup_sid.c
-+++ b/source3/passdb/lookup_sid.c
-@@ -29,6 +29,7 @@
- #include "../libcli/security/security.h"
- #include "lib/winbind_util.h"
- #include "../librpc/gen_ndr/idmap.h"
-+#include "lib/util/bitmap.h"
-
- static bool lookup_unix_user_name(const char *name, struct dom_sid *sid)
- {
-@@ -1247,7 +1248,9 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids,
- {
- struct wbcDomainSid *wbc_sids = NULL;
- struct wbcUnixId *wbc_ids = NULL;
-+ struct bitmap *found = NULL;
- uint32_t i, num_not_cached;
-+ uint32_t wbc_ids_size = 0;
- wbcErr err;
- bool ret = false;
-
-@@ -1255,6 +1258,20 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids,
- if (wbc_sids == NULL) {
- return false;
- }
-+ found = bitmap_talloc(wbc_sids, num_sids);
-+ if (found == NULL) {
-+ goto fail;
-+ }
-+
-+ /*
-+ * We go through the requested SID array three times.
-+ * First time to look for global_sid_Unix_Users
-+ * and global_sid_Unix_Groups SIDS, and to look
-+ * for mappings cached in the idmap_cache.
-+ *
-+ * Use bitmap_set() to mark an ids[] array entry as
-+ * being mapped.
-+ */
-
- num_not_cached = 0;
-
-@@ -1266,17 +1283,20 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids,
- &sids[i], &rid)) {
- ids[i].type = ID_TYPE_UID;
- ids[i].id = rid;
-+ bitmap_set(found, i);
- continue;
- }
- if (sid_peek_check_rid(&global_sid_Unix_Groups,
- &sids[i], &rid)) {
- ids[i].type = ID_TYPE_GID;
- ids[i].id = rid;
-+ bitmap_set(found, i);
- continue;
- }
- if (idmap_cache_find_sid2unixid(&sids[i], &ids[i], &expired)
- && !expired)
- {
-+ bitmap_set(found, i);
- continue;
- }
- ids[i].type = ID_TYPE_NOT_SPECIFIED;
-@@ -1287,62 +1307,121 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids,
- if (num_not_cached == 0) {
- goto done;
- }
-- wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, num_not_cached);
-+
-+ /*
-+ * For the ones that we couldn't map in the loop above, query winbindd
-+ * via wbcSidsToUnixIds().
-+ */
-+
-+ wbc_ids_size = num_not_cached;
-+ wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, wbc_ids_size);
- if (wbc_ids == NULL) {
- goto fail;
- }
-- for (i=0; i id is a union anyway */
-- ids[i].type = (enum id_type)wbc_ids[num_not_cached].type;
-- ids[i].id = wbc_ids[num_not_cached].id.gid;
-- break;
-- }
-- num_not_cached += 1;
-+ if (bitmap_query(found, i)) {
-+ continue;
- }
-+
-+ SMB_ASSERT(num_not_cached < wbc_ids_size);
-+
-+ switch (wbc_ids[num_not_cached].type) {
-+ case WBC_ID_TYPE_UID:
-+ ids[i].type = ID_TYPE_UID;
-+ ids[i].id = wbc_ids[num_not_cached].id.uid;
-+ bitmap_set(found, i);
-+ break;
-+ case WBC_ID_TYPE_GID:
-+ ids[i].type = ID_TYPE_GID;
-+ ids[i].id = wbc_ids[num_not_cached].id.gid;
-+ bitmap_set(found, i);
-+ break;
-+ case WBC_ID_TYPE_BOTH:
-+ ids[i].type = ID_TYPE_BOTH;
-+ ids[i].id = wbc_ids[num_not_cached].id.uid;
-+ bitmap_set(found, i);
-+ break;
-+ case WBC_ID_TYPE_NOT_SPECIFIED:
-+ /*
-+ * wbcSidsToUnixIds() wasn't able to map this
-+ * so we still need to check legacy_sid_to_XXX()
-+ * below. Don't mark the bitmap entry
-+ * as being found so the final loop knows
-+ * to try and map this entry.
-+ */
-+ ids[i].type = ID_TYPE_NOT_SPECIFIED;
-+ ids[i].id = (uint32_t)-1;
-+ break;
-+ default:
-+ /*
-+ * A successful return from wbcSidsToUnixIds()
-+ * cannot return anything other than the values
-+ * checked for above. Ensure this is so.
-+ */
-+ smb_panic(__location__);
-+ break;
-+ }
-+ num_not_cached += 1;
- }
-
-+ /*
-+ * Third and final time through the SID array,
-+ * try legacy_sid_to_gid()/legacy_sid_to_uid()
-+ * for entries we haven't already been able to
-+ * map.
-+ *
-+ * Use bitmap_set() to mark an ids[] array entry as
-+ * being mapped.
-+ */
-+
- for (i=0; i
+Date: Tue, 9 Nov 2021 20:50:20 +0100
+Subject: [PATCH] s3:winbindd: fix "allow trusted domains = no" regression
+
+add_trusted_domain() should only reject domains
+based on is_allowed_domain(), which now also
+checks "allow trusted domains = no", if we don't
+have an explicit trust to the domain (SEC_CHAN_NULL).
+
+We use at least SEC_CHAN_LOCAL for local domains like
+BUILTIN.
+
+Signed-off-by: Stefan Metzmacher
+---
+ source3/winbindd/winbindd_util.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/source3/winbindd/winbindd_util.c
++++ b/source3/winbindd/winbindd_util.c
+@@ -131,7 +131,7 @@ static NTSTATUS add_trusted_domain(const
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+- if (!is_allowed_domain(domain_name)) {
++ if (secure_channel_type == SEC_CHAN_NULL && !is_allowed_domain(domain_name)) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
diff -Nru samba-4.13.3+dfsg/debian/samba-libs.install samba-4.13.14+dfsg/debian/samba-libs.install
--- samba-4.13.3+dfsg/debian/samba-libs.install 2021-01-13 19:26:09.000000000 +0000
+++ samba-4.13.14+dfsg/debian/samba-libs.install 2021-11-09 19:52:07.000000000 +0000
@@ -50,6 +50,7 @@
usr/lib/*/samba/libcom_err-samba4.so.0.25
usr/lib/*/samba/libcommon-auth.so.0
usr/lib/*/samba/libdbwrap.so.*
+usr/lib/*/samba/libdcerpc-pkt-auth.so.0
usr/lib/*/samba/libdcerpc-samba.so.*
usr/lib/*/samba/libdcerpc-samba4.so.*
usr/lib/*/samba/libdfs-server-ad.so.0
@@ -116,7 +117,6 @@
usr/lib/*/samba/libsmb-transport.so.0
usr/lib/*/samba/libsmbclient-raw.so.0*
usr/lib/*/samba/libsmbd-base.so.0
-usr/lib/*/samba/libsmbd-conn.so.0
usr/lib/*/samba/libsmbd-shim.so.0
usr/lib/*/samba/libsmbldaphelper.so.*
usr/lib/*/samba/libsmbpasswdparser.so.*
diff -Nru samba-4.13.3+dfsg/docs/manpages/cifsdd.8 samba-4.13.14+dfsg/docs/manpages/cifsdd.8
--- samba-4.13.3+dfsg/docs/manpages/cifsdd.8 2020-12-15 07:54:07.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/cifsdd.8 2021-11-08 11:49:19.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: cifsdd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "CIFSDD" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "CIFSDD" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/dbwrap_tool.1 samba-4.13.14+dfsg/docs/manpages/dbwrap_tool.1
--- samba-4.13.3+dfsg/docs/manpages/dbwrap_tool.1 2020-12-15 07:54:07.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/dbwrap_tool.1 2021-11-08 11:49:19.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: dbwrap_tool
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "DBWRAP_TOOL" "1" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "DBWRAP_TOOL" "1" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -301,7 +301,7 @@
Use with caution!
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsmbd\fR(8),
diff -Nru samba-4.13.3+dfsg/docs/manpages/eventlogadm.8 samba-4.13.14+dfsg/docs/manpages/eventlogadm.8
--- samba-4.13.3+dfsg/docs/manpages/eventlogadm.8 2020-12-15 07:54:08.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/eventlogadm.8 2021-11-08 11:49:19.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: eventlogadm
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "EVENTLOGADM" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "EVENTLOGADM" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -339,7 +339,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/findsmb.1 samba-4.13.14+dfsg/docs/manpages/findsmb.1
--- samba-4.13.3+dfsg/docs/manpages/findsmb.1 2020-12-15 07:54:08.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/findsmb.1 2021-11-08 11:49:19.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: findsmb
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "FINDSMB" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "FINDSMB" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -119,7 +119,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBnmbd\fR(8),
diff -Nru samba-4.13.3+dfsg/docs/manpages/idmap_ad.8 samba-4.13.14+dfsg/docs/manpages/idmap_ad.8
--- samba-4.13.3+dfsg/docs/manpages/idmap_ad.8 2020-12-15 07:54:08.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/idmap_ad.8 2021-11-08 11:49:19.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: idmap_ad
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "IDMAP_AD" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "IDMAP_AD" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/idmap_autorid.8 samba-4.13.14+dfsg/docs/manpages/idmap_autorid.8
--- samba-4.13.3+dfsg/docs/manpages/idmap_autorid.8 2020-12-15 07:54:08.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/idmap_autorid.8 2021-11-08 11:49:19.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: idmap_autorid
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "IDMAP_AUTORID" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "IDMAP_AUTORID" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/idmap_hash.8 samba-4.13.14+dfsg/docs/manpages/idmap_hash.8
--- samba-4.13.3+dfsg/docs/manpages/idmap_hash.8 2020-12-15 07:54:09.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/idmap_hash.8 2021-11-08 11:49:19.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: idmap_hash
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "IDMAP_HASH" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "IDMAP_HASH" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/idmap_ldap.8 samba-4.13.14+dfsg/docs/manpages/idmap_ldap.8
--- samba-4.13.3+dfsg/docs/manpages/idmap_ldap.8 2020-12-15 07:54:09.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/idmap_ldap.8 2021-11-08 11:49:20.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: idmap_ldap
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "IDMAP_LDAP" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "IDMAP_LDAP" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/idmap_nss.8 samba-4.13.14+dfsg/docs/manpages/idmap_nss.8
--- samba-4.13.3+dfsg/docs/manpages/idmap_nss.8 2020-12-15 07:54:09.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/idmap_nss.8 2021-11-08 11:49:20.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: idmap_nss
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "IDMAP_NSS" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "IDMAP_NSS" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/idmap_rfc2307.8 samba-4.13.14+dfsg/docs/manpages/idmap_rfc2307.8
--- samba-4.13.3+dfsg/docs/manpages/idmap_rfc2307.8 2020-12-15 07:54:09.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/idmap_rfc2307.8 2021-11-08 11:49:20.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: idmap_rfc2307
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "IDMAP_RFC2307" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "IDMAP_RFC2307" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/idmap_rid.8 samba-4.13.14+dfsg/docs/manpages/idmap_rid.8
--- samba-4.13.3+dfsg/docs/manpages/idmap_rid.8 2020-12-15 07:54:09.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/idmap_rid.8 2021-11-08 11:49:20.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: idmap_rid
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "IDMAP_RID" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "IDMAP_RID" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/idmap_script.8 samba-4.13.14+dfsg/docs/manpages/idmap_script.8
--- samba-4.13.3+dfsg/docs/manpages/idmap_script.8 2020-12-15 07:54:10.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/idmap_script.8 2021-11-08 11:49:20.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: idmap_script
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "IDMAP_SCRIPT" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "IDMAP_SCRIPT" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/idmap_tdb2.8 samba-4.13.14+dfsg/docs/manpages/idmap_tdb2.8
--- samba-4.13.3+dfsg/docs/manpages/idmap_tdb2.8 2020-12-15 07:54:10.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/idmap_tdb2.8 2021-11-08 11:49:21.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: idmap_tdb2
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "IDMAP_TDB2" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "IDMAP_TDB2" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/idmap_tdb.8 samba-4.13.14+dfsg/docs/manpages/idmap_tdb.8
--- samba-4.13.3+dfsg/docs/manpages/idmap_tdb.8 2020-12-15 07:54:10.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/idmap_tdb.8 2021-11-08 11:49:20.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: idmap_tdb
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "IDMAP_TDB" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "IDMAP_TDB" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/libsmbclient.7 samba-4.13.14+dfsg/docs/manpages/libsmbclient.7
--- samba-4.13.3+dfsg/docs/manpages/libsmbclient.7 2020-12-15 07:54:10.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/libsmbclient.7 2021-11-08 11:49:21.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: libsmbclient
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: 7
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "LIBSMBCLIENT" "7" "12/15/2020" "Samba 4\&.13\&.3" "7"
+.TH "LIBSMBCLIENT" "7" "11/08/2021" "Samba 4\&.13\&.14" "7"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -86,7 +86,7 @@
Watch this space for future updates\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/lmhosts.5 samba-4.13.14+dfsg/docs/manpages/lmhosts.5
--- samba-4.13.3+dfsg/docs/manpages/lmhosts.5 2020-12-15 07:54:10.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/lmhosts.5 2021-11-08 11:49:21.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: lmhosts
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: File Formats and Conventions
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "LMHOSTS" "5" "12/15/2020" "Samba 4\&.13\&.3" "File Formats and Conventions"
+.TH "LMHOSTS" "5" "11/08/2021" "Samba 4\&.13\&.14" "File Formats and Conventions"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -112,7 +112,7 @@
/usr/local/samba/lib\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsmbclient\fR(1),
diff -Nru samba-4.13.3+dfsg/docs/manpages/log2pcap.1 samba-4.13.14+dfsg/docs/manpages/log2pcap.1
--- samba-4.13.3+dfsg/docs/manpages/log2pcap.1 2020-12-15 07:54:11.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/log2pcap.1 2021-11-08 11:49:21.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: log2pcap
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "LOG2PCAP" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "LOG2PCAP" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -107,7 +107,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "BUGS"
.PP
Only SMB data is extracted from the samba logs, no LDAP, NetBIOS lookup or other data\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/mdfind.1 samba-4.13.14+dfsg/docs/manpages/mdfind.1
--- samba-4.13.3+dfsg/docs/manpages/mdfind.1 2020-12-15 07:54:11.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/mdfind.1 2021-11-08 11:49:21.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: mdfind
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "MDFIND" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "MDFIND" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -158,7 +158,7 @@
https://developer\&.apple\&.com/library/archive/documentation/Carbon/Conceptual/SpotlightQuery/Concepts/Introduction\&.html
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/mvxattr.1 samba-4.13.14+dfsg/docs/manpages/mvxattr.1
--- samba-4.13.3+dfsg/docs/manpages/mvxattr.1 2020-12-15 07:54:11.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/mvxattr.1 2021-11-08 11:49:21.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: mvxattr
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "MVXATTR" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "MVXATTR" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -76,7 +76,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/net.8 samba-4.13.14+dfsg/docs/manpages/net.8
--- samba-4.13.3+dfsg/docs/manpages/net.8 2020-12-15 07:54:11.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/net.8 2021-11-08 11:49:22.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: net
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "NET" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "NET" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/nmbd.8 samba-4.13.14+dfsg/docs/manpages/nmbd.8
--- samba-4.13.3+dfsg/docs/manpages/nmbd.8 2020-12-15 07:54:12.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/nmbd.8 2021-11-08 11:49:22.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: nmbd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "NMBD" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "NMBD" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -284,7 +284,7 @@
(SIGUSR[1|2] signals are no longer used since Samba 2\&.2)\&. This is to allow transient problems to be diagnosed, whilst still running at a normally low log level\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBinetd\fR(8),
diff -Nru samba-4.13.3+dfsg/docs/manpages/nmblookup.1 samba-4.13.14+dfsg/docs/manpages/nmblookup.1
--- samba-4.13.3+dfsg/docs/manpages/nmblookup.1 2020-12-15 07:54:12.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/nmblookup.1 2021-11-08 11:49:22.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: nmblookup
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "NMBLOOKUP" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "NMBLOOKUP" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -214,7 +214,7 @@
would query the WINS server samba\&.org for the domain master browser (1B name type) for the IRIX workgroup\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBnmbd\fR(8),
diff -Nru samba-4.13.3+dfsg/docs/manpages/ntlm_auth.1 samba-4.13.14+dfsg/docs/manpages/ntlm_auth.1
--- samba-4.13.3+dfsg/docs/manpages/ntlm_auth.1 2020-12-15 07:54:12.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/ntlm_auth.1 2021-11-08 11:49:22.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: ntlm_auth
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "NTLM_AUTH" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "NTLM_AUTH" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -421,7 +421,7 @@
the Microsoft Knowledge Base article #239869 and follow instructions described there\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/pam_winbind.8 samba-4.13.14+dfsg/docs/manpages/pam_winbind.8
--- samba-4.13.3+dfsg/docs/manpages/pam_winbind.8 2020-12-15 07:54:12.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/pam_winbind.8 2021-11-08 11:49:22.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: pam_winbind
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: 8
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "PAM_WINBIND" "8" "12/15/2020" "Samba 4\&.13\&.3" "8"
+.TH "PAM_WINBIND" "8" "11/08/2021" "Samba 4\&.13\&.14" "8"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -210,7 +210,7 @@
\fBsmb.conf\fR(5)
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of Samba\&.
+This man page is part of version 4\&.13\&.14 of Samba\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/pam_winbind.conf.5 samba-4.13.14+dfsg/docs/manpages/pam_winbind.conf.5
--- samba-4.13.3+dfsg/docs/manpages/pam_winbind.conf.5 2020-12-15 07:54:12.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/pam_winbind.conf.5 2021-11-08 11:49:22.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: pam_winbind.conf
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: 5
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "PAM_WINBIND\&.CONF" "5" "12/15/2020" "Samba 4\&.13\&.3" "5"
+.TH "PAM_WINBIND\&.CONF" "5" "11/08/2021" "Samba 4\&.13\&.14" "5"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -148,7 +148,7 @@
\fBsmb.conf\fR(5)
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of Samba\&.
+This man page is part of version 4\&.13\&.14 of Samba\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/pdbedit.8 samba-4.13.14+dfsg/docs/manpages/pdbedit.8
--- samba-4.13.3+dfsg/docs/manpages/pdbedit.8 2020-12-15 07:54:13.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/pdbedit.8 2021-11-08 11:49:23.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: pdbedit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "PDBEDIT" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "PDBEDIT" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -619,7 +619,7 @@
This command may be used only by root\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsmbpasswd\fR(5),
diff -Nru samba-4.13.3+dfsg/docs/manpages/profiles.1 samba-4.13.14+dfsg/docs/manpages/profiles.1
--- samba-4.13.3+dfsg/docs/manpages/profiles.1 2020-12-15 07:54:13.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/profiles.1 2021-11-08 11:49:23.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: profiles
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "PROFILES" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "PROFILES" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -112,7 +112,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/rpcclient.1 samba-4.13.14+dfsg/docs/manpages/rpcclient.1
--- samba-4.13.3+dfsg/docs/manpages/rpcclient.1 2020-12-15 07:54:13.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/rpcclient.1 2021-11-08 11:49:23.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: rpcclient
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "RPCCLIENT" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "RPCCLIENT" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -1127,7 +1127,7 @@
that are incompatible for some commands or services\&. Additionally, the developers are sending reports to Microsoft, and problems found or reported to Microsoft are fixed in Service Packs, which may result in incompatibilities\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/samba.7 samba-4.13.14+dfsg/docs/manpages/samba.7
--- samba-4.13.3+dfsg/docs/manpages/samba.7 2020-12-15 07:54:14.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/samba.7 2021-11-08 11:49:23.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: samba
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: Miscellanea
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SAMBA" "7" "12/15/2020" "Samba 4\&.13\&.3" "Miscellanea"
+.TH "SAMBA" "7" "11/08/2021" "Samba 4\&.13\&.14" "Miscellanea"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -238,7 +238,7 @@
you can find a lot of information in the archives and you can subscribe to the samba list and ask for help or discuss things\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "CONTRIBUTIONS"
.PP
If you wish to contribute to the Samba project, then I suggest you join the Samba mailing list at
diff -Nru samba-4.13.3+dfsg/docs/manpages/samba.8 samba-4.13.14+dfsg/docs/manpages/samba.8
--- samba-4.13.3+dfsg/docs/manpages/samba.8 2020-12-15 07:54:14.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/samba.8 2021-11-08 11:49:24.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: samba
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SAMBA" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "SAMBA" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -241,7 +241,7 @@
Most messages are reasonably self\-explanatory\&. Unfortunately, at the time this man page was created, there are too many diagnostics available in the source code to warrant describing each and every diagnostic\&. At this stage your best bet is still to grep the source code and inspect the conditions that gave rise to the diagnostics you are seeing\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBhosts_access\fR(5)
diff -Nru samba-4.13.3+dfsg/docs/manpages/samba_downgrade_db.8 samba-4.13.14+dfsg/docs/manpages/samba_downgrade_db.8
--- samba-4.13.3+dfsg/docs/manpages/samba_downgrade_db.8 2020-12-15 07:54:14.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/samba_downgrade_db.8 2021-11-08 11:49:24.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: samba_downgrade_db
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SAMBA_DOWNGRADE_DB" "8" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "SAMBA_DOWNGRADE_DB" "8" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -42,7 +42,7 @@
\fIbefore\fR
the Samba packages can be safely downgraded\&.
.PP
-This tool downgrades a Samba sam\&.ldb database from the format used in version 4\&.13\&.3 to that of version 4\&.7\&. The v4\&.7 database format can safely be read by any version of Samba\&. If necessary, later versions of Samba will repack and reconfigure a v4\&.7\-format database when the samba executable is first started\&.
+This tool downgrades a Samba sam\&.ldb database from the format used in version 4\&.13\&.14 to that of version 4\&.7\&. The v4\&.7 database format can safely be read by any version of Samba\&. If necessary, later versions of Samba will repack and reconfigure a v4\&.7\-format database when the samba executable is first started\&.
.PP
Note that all Samba services must be stopped on the DC before running this tool\&. Once the tool has run, do not restart samba or modify the database before the Samba software package has been downgraded\&.
.SH "OPTIONS"
@@ -58,7 +58,7 @@
.RE
.SH "VERSION"
.PP
-This man page is complete for version 4\&.13\&.3 of the Samba suite\&.
+This man page is complete for version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/samba-regedit.8 samba-4.13.14+dfsg/docs/manpages/samba-regedit.8
--- samba-4.13.3+dfsg/docs/manpages/samba-regedit.8 2020-12-15 07:54:13.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/samba-regedit.8 2021-11-08 11:49:23.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: samba-regedit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SAMBA\-REGEDIT" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "SAMBA\-REGEDIT" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -207,7 +207,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsmbd\fR(8),
diff -Nru samba-4.13.3+dfsg/docs/manpages/samba-tool.8 samba-4.13.14+dfsg/docs/manpages/samba-tool.8
--- samba-4.13.3+dfsg/docs/manpages/samba-tool.8 2020-12-15 07:54:14.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/samba-tool.8 2021-11-08 11:49:23.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: samba-tool
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SAMBA\-TOOL" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "SAMBA\-TOOL" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -893,7 +893,7 @@
Gives usage information\&.
.SH "VERSION"
.PP
-This man page is complete for version 4\&.13\&.3 of the Samba suite\&.
+This man page is complete for version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/sharesec.1 samba-4.13.14+dfsg/docs/manpages/sharesec.1
--- samba-4.13.3+dfsg/docs/manpages/sharesec.1 2020-12-15 07:54:14.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/sharesec.1 2021-11-08 11:49:24.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: sharesec
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SHARESEC" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "SHARESEC" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -337,7 +337,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbcacls.1 samba-4.13.14+dfsg/docs/manpages/smbcacls.1
--- samba-4.13.3+dfsg/docs/manpages/smbcacls.1 2020-12-15 07:54:16.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbcacls.1 2021-11-08 11:49:26.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbcacls
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBCACLS" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "SMBCACLS" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -496,7 +496,7 @@
couldn\*(Aqt connect to the specified server, or there was an error getting or setting the ACLs, an exit status of 1 is returned\&. If there was an error parsing any command line arguments, an exit status of 2 is returned\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbclient.1 samba-4.13.14+dfsg/docs/manpages/smbclient.1
--- samba-4.13.3+dfsg/docs/manpages/smbclient.1 2020-12-15 07:54:17.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbclient.1 2021-11-08 11:49:26.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbclient
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBCLIENT" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "SMBCLIENT" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -1165,7 +1165,7 @@
The number and nature of diagnostics available depends on the debug level used by the client\&. If you have problems, set the debug level to 3 and peruse the log files\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/smb.conf.5 samba-4.13.14+dfsg/docs/manpages/smb.conf.5
--- samba-4.13.3+dfsg/docs/manpages/smb.conf.5 2020-12-15 07:54:16.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smb.conf.5 2021-11-08 11:49:26.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smb.conf
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: File Formats and Conventions
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMB\&.CONF" "5" "12/15/2020" "Samba 4\&.13\&.3" "File Formats and Conventions"
+.TH "SMB\&.CONF" "5" "11/08/2021" "Samba 4\&.13\&.14" "File Formats and Conventions"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -1522,11 +1522,17 @@
When enabled, this option causes Samba (acting as an Active Directory Domain Controller) to stream authentication events across the internal message bus\&. Scripts built using Samba\*(Aqs python bindings can listen to these events by registering as the service
auth_event\&.
.sp
-This should be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around)\&. Additionally Samba must be compiled with the jansson support for this option to be effective\&.
+This is
+\fInot\fR
+needed for the audit logging described in
+\m[blue]\fBlog level\fR\m[]\&.
+.sp
+Instead, this should instead be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around)\&.
.sp
The authentication events are also logged via the normal logging methods when the
\m[blue]\fBlog level\fR\m[]
-is set appropriately\&.
+is set appropriately, say to
+auth_json_audit:3\&.
.sp
Default:
\fI\fIauth event notification\fR\fR\fI = \fR\fIno\fR\fI \fR
@@ -3513,11 +3519,17 @@
When enabled, this option causes Samba (acting as an Active Directory Domain Controller) to stream Samba database events across the internal message bus\&. Scripts built using Samba\*(Aqs python bindings can listen to these events by registering as the service
dsdb_event\&.
.sp
-This should be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around)\&.
+This is
+\fInot\fR
+needed for the audit logging described in
+\m[blue]\fBlog level\fR\m[]\&.
+.sp
+Instead, this should instead be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around)\&.
.sp
The Samba database events are also logged via the normal logging methods when the
\m[blue]\fBlog level\fR\m[]
-is set appropriately\&.
+is set appropriately, say to
+dsdb_json_audit:5\&.
.sp
Default:
\fI\fIdsdb event notification\fR\fR\fI = \fR\fIno\fR\fI \fR
@@ -3529,11 +3541,17 @@
When enabled, this option causes Samba (acting as an Active Directory Domain Controller) to stream group membership change events across the internal message bus\&. Scripts built using Samba\*(Aqs python bindings can listen to these events by registering as the service
dsdb_group_event\&.
.sp
-This should be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around)\&.
+This is
+\fInot\fR
+needed for the audit logging described in
+\m[blue]\fBlog level\fR\m[]\&.
+.sp
+Instead, this should instead be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around)\&.
.sp
-The group events are also logged via the normal logging methods when the
+The Samba database events are also logged via the normal logging methods when the
\m[blue]\fBlog level\fR\m[]
-is set appropriately\&.
+is set appropriately, say to
+dsdb_group_json_audit:5\&.
.sp
Default:
\fI\fIdsdb group change notification\fR\fR\fI = \fR\fIno\fR\fI \fR
@@ -3545,11 +3563,17 @@
When enabled, this option causes Samba (acting as an Active Directory Domain Controller) to stream password change and reset events across the internal message bus\&. Scripts built using Samba\*(Aqs python bindings can listen to these events by registering as the service
password_event\&.
.sp
-This should be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around)\&.
+This is
+\fInot\fR
+needed for the audit logging described in
+\m[blue]\fBlog level\fR\m[]\&.
+.sp
+Instead, this should instead be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around)\&.
.sp
-The password events are also logged via the normal logging methods when the
+The Samba database events are also logged via the normal logging methods when the
\m[blue]\fBlog level\fR\m[]
-is set appropriately\&.
+is set appropriately, say to
+dsdb_password_json_audit:5\&.
.sp
Default:
\fI\fIdsdb password event notification\fR\fR\fI = \fR\fIno\fR\fI \fR
@@ -4635,6 +4659,10 @@
Defines the available matching uid and gid range for which the backend is authoritative\&. For allocating backends, this also defines the start and the end of the range for allocating new unique IDs\&.
.sp
winbind uses this parameter to find the backend that is authoritative for a unix ID to SID mapping, so it must be set for each individually configured domain and for the default configuration\&. The configured ranges must be mutually disjoint\&.
+.sp
+Note that the low value interacts with the
+\m[blue]\fBmin domain uid\fR\m[]
+option!
.RE
.PP
read only = yes|no
@@ -6152,28 +6180,6 @@
.sp -1
.IP \(bu 2.3
.\}
-\fIsmb2\fR
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-\fIsmb2_credits\fR
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
\fIrpc_parse\fR
.RE
.sp
@@ -6416,6 +6422,39 @@
.sp -1
.IP \(bu 2.3
.\}
+\fIdrs_repl\fR
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fIsmb2\fR
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fIsmb2_credits\fR
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
\fIdsdb_audit\fR
.RE
.sp
@@ -6474,6 +6513,28 @@
\fIdsdb_transaction_json_audit\fR
.RE
.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fIdsdb_group_audit\fR
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fIdsdb_group_json_audit\fR
+.RE
+.sp
.RE
To configure the logging for specific classes to go into a different file then
\m[blue]\fBlog file\fR\m[], you can append
@@ -6481,11 +6542,17 @@
to the class, eg
\fIlog level = 1 full_audit:1@/var/log/audit\&.log\fR\&.
.sp
-Authentication and authorization audit information is logged under the auth_audit, and if Samba was not compiled with \-\-without\-json, a JSON representation is logged under auth_json_audit\&.
+Authentication and authorization audit information is logged under the
+\fIauth_audit\fR, and if Samba was not compiled with \-\-without\-json, a JSON representation is logged under
+\fIauth_json_audit\fR\&.
.sp
Support is comprehensive for all authentication and authorisation of user accounts in the Samba Active Directory Domain Controller, as well as the implicit authentication in password changes\&. In the file server, NTLM authentication, SMB and RPC authorization is covered\&.
.sp
-Log levels for auth_audit and auth_audit_json are:
+Log levels for
+\fIauth_audit\fR
+and
+\fIauth_audit_json\fR
+are:
.RS
.sp
.RS 4
@@ -6533,12 +6600,137 @@
.RE
.sp
.RE
-Changes to the sam\&.ldb database are logged under the dsdb_audit and a JSON representation is logged under dsdb_json_audit\&.
+Changes to the AD DC
+sam\&.ldb
+database are logged under the
+\fIdsdb_audit\fR
+and a JSON representation is logged under
+\fIdsdb_json_audit\fR\&.
+.sp
+Group membership changes to the AD DC
+sam\&.ldb
+database are logged under the
+\fIdsdb_group_audit\fR
+and a JSON representation is logged under
+\fIdsdb_group_json_audit\fR\&.
+.sp
+Log levels for
+\fIdsdb_audit\fR,
+\fIdsdb_json_audit\fR,
+\fIdsdb_group_audit\fR,
+\fIdsdb_group_json_audit\fR
+and
+\fIdsdb_json_audit\fR
+are:
+.RS
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+5: Database modifications
+.RE
.sp
-Password changes and Password resets are logged under dsdb_password_audit and a JSON representation is logged under the dsdb_password_json_audit\&.
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+5: Replicated updates from another DC
+.RE
.sp
-Transaction rollbacks and prepare commit failures are logged under the dsdb_transaction_audit and a JSON representation is logged under the password_json_audit\&. Logging the transaction details allows the identification of password and sam\&.ldb operations that have been rolled back\&.
+.RE
+Password changes and Password resets in the AD DC are logged under
+\fIdsdb_password_audit\fR
+and a JSON representation is logged under the
+\fIdsdb_password_json_audit\fR\&. Password changes will also appears as authentication events via
+\fIauth_audit\fR
+and
+\fIauth_audit_json\fR\&.
+.sp
+Log levels for
+\fIdsdb_password_audit\fR
+and
+\fIdsdb_password_json_audit\fR
+are:
+.RS
.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+5: Successful password changes and resets
+.RE
+.sp
+.RE
+Transaction rollbacks and prepare commit failures are logged under the
+\fIdsdb_transaction_audit\fR
+and a JSON representation is logged under the
+\fIdsdb_transaction_json_audit\fR\&.
+.sp
+Log levels for
+\fIdsdb_transaction_audit\fR
+and
+\fIdsdb_transaction_json\fR
+are:
+.RS
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+5: Transaction failure (rollback)
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+10: Transaction success (commit)
+.RE
+.sp
+.RE
+Transaction roll\-backs are possible in Samba, and whilst they rarely reflect anything more than the failure of an individual operation (say due to the add of a conflicting record), they are possible\&. Audit logs are already generated and sent to the system logs before the transaction is complete\&. Logging the transaction details allows the identification of password and
+sam\&.ldb
+operations that have been rolled back, and so have not actually persisted\&.
+.if n \{\
+.sp
+.\}
+.RS 4
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBWarning\fR
+.ps -1
+.br
+Changes to
+sam\&.ldb
+made locally by the
+root
+user with direct access to the database are not logged to the system logs, but to the administrator\*(Aqs own console\&. While less than ideal, any user able to make such modifications could disable the audit logging in any case\&.
+.sp .5v
+.RE
Default:
\fI\fIlog level\fR\fR\fI = \fR\fI0\fR\fI \fR
.sp
@@ -7670,6 +7862,18 @@
\fI\fImessage command\fR\fR\fI = \fR\fIcsh \-c \*(Aqxedit %s; rm %s\*(Aq &\fR\fI \fR
.RE
+min domain uid (G)
+.PP
+.RS 4
+The integer parameter specifies the minimum uid allowed when mapping a local account to a domain account\&.
+.sp
+Note that this option interacts with the configured
+\fIidmap ranges\fR!
+.sp
+Default:
+\fI\fImin domain uid\fR\fR\fI = \fR\fI1000\fR\fI \fR
+.RE
+
min print space (S)
.PP
.RS 4
@@ -10493,6 +10697,10 @@
This mode of operation runs Samba as an active directory domain controller, providing domain logon services to Windows and Samba clients of the domain\&. This role requires special configuration, see the
Samba4 HOWTO
.sp
+\fISERVER ROLE = IPA DOMAIN CONTROLLER\fR
+.sp
+This mode of operation runs Samba in a hybrid mode for IPA domain controller, providing forest trust to Active Directory\&. This role requires special configuration performed by IPA installers and should not be used manually by any administrator\&.
+.sp
Default:
\fI\fIserver role\fR\fR\fI = \fR\fIAUTO\fR\fI \fR
.sp
@@ -13622,7 +13830,7 @@
special sections make life for an administrator easy, but the various combinations of default attributes can be tricky\&. Take extreme care when designing these sections\&. In particular, ensure that the permissions on spool directories are correct\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsamba\fR(7),
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbcontrol.1 samba-4.13.14+dfsg/docs/manpages/smbcontrol.1
--- samba-4.13.3+dfsg/docs/manpages/smbcontrol.1 2020-12-15 07:54:17.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbcontrol.1 2021-11-08 11:49:26.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbcontrol
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBCONTROL" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "SMBCONTROL" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -316,7 +316,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBnmbd\fR(8)
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbcquotas.1 samba-4.13.14+dfsg/docs/manpages/smbcquotas.1
--- samba-4.13.3+dfsg/docs/manpages/smbcquotas.1 2020-12-15 07:54:17.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbcquotas.1 2021-11-08 11:49:26.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbcquotas
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBCQUOTAS" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "SMBCQUOTAS" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -247,7 +247,7 @@
couldn\*(Aqt connect to the specified server, or when there was an error getting or setting the quota(s), an exit status of 1 is returned\&. If there was an error parsing any command line arguments, an exit status of 2 is returned\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbd.8 samba-4.13.14+dfsg/docs/manpages/smbd.8
--- samba-4.13.3+dfsg/docs/manpages/smbd.8 2020-12-15 07:54:17.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbd.8 2021-11-08 11:49:27.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBD" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "SMBD" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -256,7 +256,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "DIAGNOSTICS"
.PP
Most diagnostics issued by the server are logged in a specified log file\&. The log file name is specified at compile time, but may be overridden on the command line\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbget.1 samba-4.13.14+dfsg/docs/manpages/smbget.1
--- samba-4.13.3+dfsg/docs/manpages/smbget.1 2020-12-15 07:54:17.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbget.1 2021-11-08 11:49:27.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbget
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBGET" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "SMBGET" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -189,7 +189,7 @@
Permission denied is returned in some cases where the cause of the error is unknown (such as an illegally formatted smb:// url or trying to get a directory without \-R turned on)\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbgetrc.5 samba-4.13.14+dfsg/docs/manpages/smbgetrc.5
--- samba-4.13.3+dfsg/docs/manpages/smbgetrc.5 2020-12-15 07:54:18.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbgetrc.5 2021-11-08 11:49:27.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbgetrc
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: File Formats and Conventions
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBGETRC" "5" "12/15/2020" "Samba 4\&.13\&.3" "File Formats and Conventions"
+.TH "SMBGETRC" "5" "11/08/2021" "Samba 4\&.13\&.14" "File Formats and Conventions"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -87,7 +87,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsmbget\fR(1)
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbpasswd.5 samba-4.13.14+dfsg/docs/manpages/smbpasswd.5
--- samba-4.13.3+dfsg/docs/manpages/smbpasswd.5 2020-12-15 07:54:18.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbpasswd.5 2021-11-08 11:49:27.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbpasswd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: File Formats and Conventions
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBPASSWD" "5" "12/15/2020" "Samba 4\&.13\&.3" "File Formats and Conventions"
+.TH "SMBPASSWD" "5" "11/08/2021" "Samba 4\&.13\&.14" "File Formats and Conventions"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -165,7 +165,7 @@
All other colon separated fields are ignored at this time\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsmbpasswd\fR(8),
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbpasswd.8 samba-4.13.14+dfsg/docs/manpages/smbpasswd.8
--- samba-4.13.3+dfsg/docs/manpages/smbpasswd.8 2020-12-15 07:54:18.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbpasswd.8 2021-11-08 11:49:27.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbpasswd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBPASSWD" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "SMBPASSWD" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -314,7 +314,7 @@
In addition, the smbpasswd command is only useful if Samba has been set up to use encrypted passwords\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsmbpasswd\fR(5),
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbspool.8 samba-4.13.14+dfsg/docs/manpages/smbspool.8
--- samba-4.13.3+dfsg/docs/manpages/smbspool.8 2020-12-15 07:54:18.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbspool.8 2021-11-08 11:49:27.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbspool
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBSPOOL" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "SMBSPOOL" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -173,7 +173,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsmbd\fR(8)
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbspool_krb5_wrapper.8 samba-4.13.14+dfsg/docs/manpages/smbspool_krb5_wrapper.8
--- samba-4.13.3+dfsg/docs/manpages/smbspool_krb5_wrapper.8 2020-12-15 07:54:18.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbspool_krb5_wrapper.8 2021-11-08 11:49:27.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbspool_krb5_wrapper
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBSPOOL_KRB5_WRAPPE" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "SMBSPOOL_KRB5_WRAPPE" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbstatus.1 samba-4.13.14+dfsg/docs/manpages/smbstatus.1
--- samba-4.13.3+dfsg/docs/manpages/smbstatus.1 2020-12-15 07:54:19.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbstatus.1 2021-11-08 11:49:28.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbstatus
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBSTATUS" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "SMBSTATUS" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -154,7 +154,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsmbd\fR(8)
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbtar.1 samba-4.13.14+dfsg/docs/manpages/smbtar.1
--- samba-4.13.3+dfsg/docs/manpages/smbtar.1 2020-12-15 07:54:19.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbtar.1 2021-11-08 11:49:28.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbtar
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBTAR" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "SMBTAR" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -145,7 +145,7 @@
command\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsmbd\fR(8),
diff -Nru samba-4.13.3+dfsg/docs/manpages/smbtree.1 samba-4.13.14+dfsg/docs/manpages/smbtree.1
--- samba-4.13.3+dfsg/docs/manpages/smbtree.1 2020-12-15 07:54:19.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/smbtree.1 2021-11-08 11:49:28.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: smbtree
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "SMBTREE" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "SMBTREE" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -186,7 +186,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/testparm.1 samba-4.13.14+dfsg/docs/manpages/testparm.1
--- samba-4.13.3+dfsg/docs/manpages/testparm.1 2020-12-15 07:54:19.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/testparm.1 2021-11-08 11:49:28.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: testparm
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "TESTPARM" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "TESTPARM" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -169,7 +169,7 @@
The program will issue a message saying whether the configuration file loaded OK or not\&. This message may be preceded by errors and warnings if the file did not load\&. If the file was loaded OK, the program then dumps all known service details to stdout\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBsmb.conf\fR(5),
diff -Nru samba-4.13.3+dfsg/docs/manpages/traffic_learner.7 samba-4.13.14+dfsg/docs/manpages/traffic_learner.7
--- samba-4.13.3+dfsg/docs/manpages/traffic_learner.7 2020-12-15 07:54:20.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/traffic_learner.7 2021-11-08 11:49:28.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: traffic_learner
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "TRAFFIC_LEARNER" "7" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "TRAFFIC_LEARNER" "7" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -115,7 +115,7 @@
The other special packet is "\-", which represents the limit of the conversation\&. In the example, this indicates that one observed conversation ended after this particular ngram\&. This special opcode is also used at the beginning of conversations, which are indicated by the ngram "\-\et\-"\&.
.SH "VERSION"
.PP
-This man page is complete for version 4\&.13\&.3 of the Samba suite\&.
+This man page is complete for version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBtraffic_replay\fR(7)\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/traffic_replay.7 samba-4.13.14+dfsg/docs/manpages/traffic_replay.7
--- samba-4.13.3+dfsg/docs/manpages/traffic_replay.7 2020-12-15 07:54:20.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/traffic_replay.7 2021-11-08 11:49:28.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: traffic_replay
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "TRAFFIC_REPLAY" "7" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "TRAFFIC_REPLAY" "7" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -355,7 +355,7 @@
The users created by the test will have names like STGU\-0\-xyz\&. The groups generated have names like STGG\-0\-xyz\&.
.SH "VERSION"
.PP
-This man page is complete for version 4\&.13\&.3 of the Samba suite\&.
+This man page is complete for version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBtraffic_learner\fR(7)\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_acl_tdb.8 samba-4.13.14+dfsg/docs/manpages/vfs_acl_tdb.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_acl_tdb.8 2020-12-15 07:54:20.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_acl_tdb.8 2021-11-08 11:49:29.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_acl_tdb
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_ACL_TDB" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_ACL_TDB" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_acl_xattr.8 samba-4.13.14+dfsg/docs/manpages/vfs_acl_xattr.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_acl_xattr.8 2020-12-15 07:54:20.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_acl_xattr.8 2021-11-08 11:49:29.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_acl_xattr
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_ACL_XATTR" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_ACL_XATTR" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_aio_fork.8 samba-4.13.14+dfsg/docs/manpages/vfs_aio_fork.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_aio_fork.8 2020-12-15 07:54:20.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_aio_fork.8 2021-11-08 11:49:29.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_aio_fork
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_AIO_FORK" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_AIO_FORK" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -62,7 +62,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_aio_pthread.8 samba-4.13.14+dfsg/docs/manpages/vfs_aio_pthread.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_aio_pthread.8 2020-12-15 07:54:21.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_aio_pthread.8 2021-11-08 11:49:29.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_aio_pthread
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_AIO_PTHREAD" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_AIO_PTHREAD" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -75,7 +75,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_audit.8 samba-4.13.14+dfsg/docs/manpages/vfs_audit.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_audit.8 2020-12-15 07:54:21.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_audit.8 2021-11-08 11:49:29.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_audit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_AUDIT" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_AUDIT" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -112,7 +112,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_btrfs.8 samba-4.13.14+dfsg/docs/manpages/vfs_btrfs.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_btrfs.8 2020-12-15 07:54:21.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_btrfs.8 2021-11-08 11:49:29.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_btrfs
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_BTRFS" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_BTRFS" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -104,7 +104,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_cacheprime.8 samba-4.13.14+dfsg/docs/manpages/vfs_cacheprime.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_cacheprime.8 2020-12-15 07:54:21.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_cacheprime.8 2021-11-08 11:49:30.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_cacheprime
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_CACHEPRIME" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_CACHEPRIME" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -115,7 +115,7 @@
is not a substitute for a general\-purpose readahead mechanism\&. It is intended for use only in very specific environments where disk operations must be aligned and sized to known values (as much as that is possible)\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_cap.8 samba-4.13.14+dfsg/docs/manpages/vfs_cap.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_cap.8 2020-12-15 07:54:21.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_cap.8 2021-11-08 11:49:30.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_cap
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_CAP" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_CAP" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -63,7 +63,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_catia.8 samba-4.13.14+dfsg/docs/manpages/vfs_catia.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_catia.8 2020-12-15 07:54:22.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_catia.8 2021-11-08 11:49:30.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_catia
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_CATIA" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_CATIA" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_ceph.8 samba-4.13.14+dfsg/docs/manpages/vfs_ceph.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_ceph.8 2020-12-15 07:54:22.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_ceph.8 2021-11-08 11:49:30.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_ceph
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_CEPH" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_CEPH" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -109,7 +109,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_ceph_snapshots.8 samba-4.13.14+dfsg/docs/manpages/vfs_ceph_snapshots.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_ceph_snapshots.8 2020-12-15 07:54:22.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_ceph_snapshots.8 2021-11-08 11:49:30.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_ceph_snapshots
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_CEPH_SNAPSHOTS" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_CEPH_SNAPSHOTS" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -107,7 +107,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_commit.8 samba-4.13.14+dfsg/docs/manpages/vfs_commit.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_commit.8 2020-12-15 07:54:22.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_commit.8 2021-11-08 11:49:30.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_commit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_COMMIT" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_COMMIT" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -116,7 +116,7 @@
may reduce performance\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_crossrename.8 samba-4.13.14+dfsg/docs/manpages/vfs_crossrename.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_crossrename.8 2020-12-15 07:54:22.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_crossrename.8 2021-11-08 11:49:30.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_crossrename
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_CROSSRENAME" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_CROSSRENAME" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -89,7 +89,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_default_quota.8 samba-4.13.14+dfsg/docs/manpages/vfs_default_quota.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_default_quota.8 2020-12-15 07:54:23.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_default_quota.8 2021-11-08 11:49:31.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_default_quota
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_DEFAULT_QUOTA" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_DEFAULT_QUOTA" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -86,7 +86,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_dirsort.8 samba-4.13.14+dfsg/docs/manpages/vfs_dirsort.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_dirsort.8 2020-12-15 07:54:23.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_dirsort.8 2021-11-08 11:49:31.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_dirsort
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_DIRSORT" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_DIRSORT" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -59,7 +59,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_extd_audit.8 samba-4.13.14+dfsg/docs/manpages/vfs_extd_audit.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_extd_audit.8 2020-12-15 07:54:23.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_extd_audit.8 2021-11-08 11:49:31.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_extd_audit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_EXTD_AUDIT" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_EXTD_AUDIT" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -55,7 +55,7 @@
This module is stackable\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_fake_perms.8 samba-4.13.14+dfsg/docs/manpages/vfs_fake_perms.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_fake_perms.8 2020-12-15 07:54:23.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_fake_perms.8 2021-11-08 11:49:31.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_fake_perms
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_FAKE_PERMS" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_FAKE_PERMS" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -58,7 +58,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_fileid.8 samba-4.13.14+dfsg/docs/manpages/vfs_fileid.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_fileid.8 2020-12-15 07:54:24.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_fileid.8 2021-11-08 11:49:31.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_fileid
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_FILEID" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_FILEID" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -142,7 +142,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_fruit.8 samba-4.13.14+dfsg/docs/manpages/vfs_fruit.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_fruit.8 2020-12-15 07:54:24.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_fruit.8 2021-11-08 11:49:31.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_fruit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_FRUIT" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_FRUIT" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_full_audit.8 samba-4.13.14+dfsg/docs/manpages/vfs_full_audit.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_full_audit.8 2020-12-15 07:54:24.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_full_audit.8 2021-11-08 11:49:32.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_full_audit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_FULL_AUDIT" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_FULL_AUDIT" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -517,7 +517,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_glusterfs.8 samba-4.13.14+dfsg/docs/manpages/vfs_glusterfs.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_glusterfs.8 2020-12-15 07:54:24.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_glusterfs.8 2021-11-08 11:49:32.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_glusterfs
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_GLUSTERFS" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_GLUSTERFS" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -129,7 +129,7 @@
With GlusterFS versions >= 9, we silently bypass write\-behind translator during initial connect and failure is avoided\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_glusterfs_fuse.8 samba-4.13.14+dfsg/docs/manpages/vfs_glusterfs_fuse.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_glusterfs_fuse.8 2020-12-15 07:54:24.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_glusterfs_fuse.8 2021-11-08 11:49:32.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_glusterfs_fuse
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_GLUSTERFS_FUSE" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_GLUSTERFS_FUSE" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -78,7 +78,7 @@
This module does currently have no further options\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_gpfs.8 samba-4.13.14+dfsg/docs/manpages/vfs_gpfs.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_gpfs.8 2020-12-15 07:54:25.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_gpfs.8 2021-11-08 11:49:32.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_gpfs
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_GPFS" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_GPFS" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -660,7 +660,7 @@
in gpfs versions newer than 3\&.2\&.1 PTF8\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_io_uring.8 samba-4.13.14+dfsg/docs/manpages/vfs_io_uring.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_io_uring.8 2020-12-15 07:54:25.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_io_uring.8 2021-11-08 11:49:32.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_io_uring
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_IO_URING" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_IO_URING" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -78,7 +78,7 @@
\fBio_uring_setup\fR(2)\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_linux_xfs_sgid.8 samba-4.13.14+dfsg/docs/manpages/vfs_linux_xfs_sgid.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_linux_xfs_sgid.8 2020-12-15 07:54:25.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_linux_xfs_sgid.8 2021-11-08 11:49:32.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_syncops
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_SYNCOPS" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_SYNCOPS" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -64,7 +64,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_media_harmony.8 samba-4.13.14+dfsg/docs/manpages/vfs_media_harmony.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_media_harmony.8 2020-12-15 07:54:25.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_media_harmony.8 2021-11-08 11:49:32.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_media_harmony
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_MEDIA_HARMONY" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_MEDIA_HARMONY" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -138,7 +138,7 @@
is designed to work with Avid editing applications that look in the Avid MediaFiles or OMFI MediaFiles directories for media\&. It is not designed to work as expected in all circumstances for general use\&. For example: It is possible to open a client\-specific file such as msmMMOB\&.mdb_192\&.168\&.1\&.10_userx even though it doesn\*(Aqt show up in a directory listing\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_nfs4acl_xattr.8 samba-4.13.14+dfsg/docs/manpages/vfs_nfs4acl_xattr.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_nfs4acl_xattr.8 2020-12-15 07:54:25.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_nfs4acl_xattr.8 2021-11-08 11:49:33.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_nfs4acl_xattr
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_NFS4ACL_XATTR" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_NFS4ACL_XATTR" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_offline.8 samba-4.13.14+dfsg/docs/manpages/vfs_offline.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_offline.8 2020-12-15 07:54:26.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_offline.8 2021-11-08 11:49:33.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_offline
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_OFFLINE" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_OFFLINE" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -59,7 +59,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_prealloc.8 samba-4.13.14+dfsg/docs/manpages/vfs_prealloc.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_prealloc.8 2020-12-15 07:54:26.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_prealloc.8 2021-11-08 11:49:33.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_prealloc
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_PREALLOC" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_PREALLOC" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -112,7 +112,7 @@
is not supported on all platforms and filesystems\&. Currently only XFS filesystems on Linux and IRIX are supported\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_preopen.8 samba-4.13.14+dfsg/docs/manpages/vfs_preopen.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_preopen.8 2020-12-15 07:54:26.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_preopen.8 2021-11-08 11:49:33.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_preopen
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_PREOPEN" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_PREOPEN" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -67,7 +67,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_readahead.8 samba-4.13.14+dfsg/docs/manpages/vfs_readahead.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_readahead.8 2020-12-15 07:54:26.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_readahead.8 2021-11-08 11:49:33.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_readahead
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_READAHEAD" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_READAHEAD" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -115,7 +115,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_readonly.8 samba-4.13.14+dfsg/docs/manpages/vfs_readonly.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_readonly.8 2020-12-15 07:54:26.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_readonly.8 2021-11-08 11:49:33.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_readonly
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_READONLY" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_READONLY" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -81,7 +81,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_recycle.8 samba-4.13.14+dfsg/docs/manpages/vfs_recycle.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_recycle.8 2020-12-15 07:54:27.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_recycle.8 2021-11-08 11:49:34.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_recycle
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_RECYCLE" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_RECYCLE" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -136,7 +136,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_shadow_copy2.8 samba-4.13.14+dfsg/docs/manpages/vfs_shadow_copy2.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_shadow_copy2.8 2020-12-15 07:54:27.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_shadow_copy2.8 2021-11-08 11:49:34.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_shadow_copy2
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_SHADOW_COPY2" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_SHADOW_COPY2" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -519,7 +519,7 @@
is designed to be an end\-user tool only\&. It does not replace or enhance your backup and archival solutions and should in no way be considered as such\&. Additionally, if you need version control, implement a version control system\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_shadow_copy.8 samba-4.13.14+dfsg/docs/manpages/vfs_shadow_copy.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_shadow_copy.8 2020-12-15 07:54:27.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_shadow_copy.8 2021-11-08 11:49:34.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_shadow_copy
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_SHADOW_COPY" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_SHADOW_COPY" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -167,7 +167,7 @@
is designed to be an end\-user tool only\&. It does not replace or enhance your backup and archival solutions and should in no way be considered as such\&. Additionally, if you need version control, implement a version control system\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_shell_snap.8 samba-4.13.14+dfsg/docs/manpages/vfs_shell_snap.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_shell_snap.8 2020-12-15 07:54:27.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_shell_snap.8 2021-11-08 11:49:34.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_shell_snap
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_SHELL_SNAP" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_SHELL_SNAP" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -215,7 +215,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_snapper.8 samba-4.13.14+dfsg/docs/manpages/vfs_snapper.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_snapper.8 2020-12-15 07:54:28.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_snapper.8 2021-11-08 11:49:34.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_snapper
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_SNAPPER" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_SNAPPER" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -85,7 +85,7 @@
The DiskShadow\&.exe FSRVP client initially authenticates as the Active Directory computer account\&. This account must therefore be granted the same permissions as the user account issuing the snapshot creation and deletion requests\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_streams_depot.8 samba-4.13.14+dfsg/docs/manpages/vfs_streams_depot.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_streams_depot.8 2020-12-15 07:54:28.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_streams_depot.8 2021-11-08 11:49:34.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_streams_depot
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_STREAMS_DEPOT" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_STREAMS_DEPOT" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_streams_xattr.8 samba-4.13.14+dfsg/docs/manpages/vfs_streams_xattr.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_streams_xattr.8 2020-12-15 07:54:28.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_streams_xattr.8 2021-11-08 11:49:35.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_streams_xattr
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_STREAMS_XATTR" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_STREAMS_XATTR" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_syncops.8 samba-4.13.14+dfsg/docs/manpages/vfs_syncops.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_syncops.8 2020-12-15 07:54:28.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_syncops.8 2021-11-08 11:49:35.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_syncops
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_SYNCOPS" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_SYNCOPS" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -76,7 +76,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfstest.1 samba-4.13.14+dfsg/docs/manpages/vfstest.1
--- samba-4.13.3+dfsg/docs/manpages/vfstest.1 2020-12-15 07:54:30.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfstest.1 2021-11-08 11:49:36.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfstest
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFSTEST" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "VFSTEST" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -783,7 +783,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_time_audit.8 samba-4.13.14+dfsg/docs/manpages/vfs_time_audit.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_time_audit.8 2020-12-15 07:54:28.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_time_audit.8 2021-11-08 11:49:35.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_time_audit
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_TIME_AUDIT" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_TIME_AUDIT" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -72,7 +72,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_tsmsm.8 samba-4.13.14+dfsg/docs/manpages/vfs_tsmsm.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_tsmsm.8 2020-12-15 07:54:29.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_tsmsm.8 2021-11-08 11:49:35.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_tsmsm
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_TSMSM" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_TSMSM" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -83,7 +83,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_unityed_media.8 samba-4.13.14+dfsg/docs/manpages/vfs_unityed_media.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_unityed_media.8 2020-12-15 07:54:29.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_unityed_media.8 2021-11-08 11:49:35.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_unityed_media
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_UNITYED_MEDIA" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_UNITYED_MEDIA" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -111,7 +111,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_virusfilter.8 samba-4.13.14+dfsg/docs/manpages/vfs_virusfilter.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_virusfilter.8 2020-12-15 07:54:29.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_virusfilter.8 2021-11-08 11:49:35.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_virusfilter
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
.\" Source: Samba 4.8
.\" Language: English
.\"
-.TH "VFS_VIRUSFILTER" "8" "12/15/2020" "Samba 4\&.8" "System Administration tools"
+.TH "VFS_VIRUSFILTER" "8" "11/08/2021" "Samba 4\&.8" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_widelinks.8 samba-4.13.14+dfsg/docs/manpages/vfs_widelinks.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_widelinks.8 2020-12-15 07:54:29.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_widelinks.8 2021-11-08 11:49:36.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_widelinks
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_WIDELINKS" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_WIDELINKS" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -53,7 +53,7 @@
No examples listed\&. This module is implicitly loaded by smbd as needed\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_worm.8 samba-4.13.14+dfsg/docs/manpages/vfs_worm.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_worm.8 2020-12-15 07:54:29.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_worm.8 2021-11-08 11:49:36.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_worm
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_WORM" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_WORM" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -68,7 +68,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_xattr_tdb.8 samba-4.13.14+dfsg/docs/manpages/vfs_xattr_tdb.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_xattr_tdb.8 2020-12-15 07:54:30.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_xattr_tdb.8 2021-11-08 11:49:36.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_xattr_tdb
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_XATTR_TDB" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_XATTR_TDB" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff -Nru samba-4.13.3+dfsg/docs/manpages/vfs_zfsacl.8 samba-4.13.14+dfsg/docs/manpages/vfs_zfsacl.8
--- samba-4.13.3+dfsg/docs/manpages/vfs_zfsacl.8 2020-12-15 07:54:30.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/vfs_zfsacl.8 2021-11-08 11:49:36.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: vfs_zfsacl
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "VFS_ZFSACL" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "VFS_ZFSACL" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -308,7 +308,7 @@
.\}
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/wbinfo.1 samba-4.13.14+dfsg/docs/manpages/wbinfo.1
--- samba-4.13.3+dfsg/docs/manpages/wbinfo.1 2020-12-15 07:54:30.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/wbinfo.1 2021-11-08 11:49:36.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: wbinfo
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "WBINFO" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "WBINFO" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -467,7 +467,7 @@
will always return failure\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
\fBwinbindd\fR(8)
diff -Nru samba-4.13.3+dfsg/docs/manpages/winbindd.8 samba-4.13.14+dfsg/docs/manpages/winbindd.8
--- samba-4.13.3+dfsg/docs/manpages/winbindd.8 2020-12-15 07:54:31.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/winbindd.8 2021-11-08 11:49:37.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: winbindd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: System Administration tools
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "WINBINDD" "8" "12/15/2020" "Samba 4\&.13\&.3" "System Administration tools"
+.TH "WINBINDD" "8" "11/08/2021" "Samba 4\&.13\&.14" "System Administration tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -583,7 +583,7 @@
.RE
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "SEE ALSO"
.PP
nsswitch\&.conf(5),
diff -Nru samba-4.13.3+dfsg/docs/manpages/winbind_krb5_localauth.8 samba-4.13.14+dfsg/docs/manpages/winbind_krb5_localauth.8
--- samba-4.13.3+dfsg/docs/manpages/winbind_krb5_localauth.8 2020-12-15 07:54:30.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/winbind_krb5_localauth.8 2021-11-08 11:49:36.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: winbind_krb5_localauth
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: 8
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "WINBIND_KRB5_LOCALAU" "8" "12/15/2020" "Samba 4\&.13\&.3" "8"
+.TH "WINBIND_KRB5_LOCALAU" "8" "11/08/2021" "Samba 4\&.13\&.14" "8"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -66,7 +66,7 @@
.sp
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/winbind_krb5_locator.8 samba-4.13.14+dfsg/docs/manpages/winbind_krb5_locator.8
--- samba-4.13.3+dfsg/docs/manpages/winbind_krb5_locator.8 2020-12-15 07:54:31.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/winbind_krb5_locator.8 2021-11-08 11:49:37.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: winbind_krb5_locator
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: 8
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "WINBIND_KRB5_LOCATOR" "8" "12/15/2020" "Samba 4\&.13\&.3" "8"
+.TH "WINBIND_KRB5_LOCATOR" "8" "11/08/2021" "Samba 4\&.13\&.14" "8"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -57,7 +57,7 @@
/etc/krb5\&.conf\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs/manpages/winexe.1 samba-4.13.14+dfsg/docs/manpages/winexe.1
--- samba-4.13.3+dfsg/docs/manpages/winexe.1 2020-12-15 07:54:31.000000000 +0000
+++ samba-4.13.14+dfsg/docs/manpages/winexe.1 2021-11-08 11:49:37.000000000 +0000
@@ -2,12 +2,12 @@
.\" Title: winexe
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1
-.\" Date: 12/15/2020
+.\" Date: 11/08/2021
.\" Manual: User Commands
-.\" Source: Samba 4.13.3
+.\" Source: Samba 4.13.14
.\" Language: English
.\"
-.TH "WINEXE" "1" "12/15/2020" "Samba 4\&.13\&.3" "User Commands"
+.TH "WINEXE" "1" "11/08/2021" "Samba 4\&.13\&.14" "User Commands"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -224,7 +224,7 @@
The winexe program returns 0 if the operation succeeded, or 1 if the operation failed\&.
.SH "VERSION"
.PP
-This man page is part of version 4\&.13\&.3 of the Samba suite\&.
+This man page is part of version 4\&.13\&.14 of the Samba suite\&.
.SH "AUTHOR"
.PP
The original Samba software and related utilities were created by Andrew Tridgell\&. Samba is now developed by the Samba Team as an Open Source project similar to the way the Linux kernel is developed\&.
diff -Nru samba-4.13.3+dfsg/docs-xml/smbdotconf/logging/loglevel.xml samba-4.13.14+dfsg/docs-xml/smbdotconf/logging/loglevel.xml
--- samba-4.13.3+dfsg/docs-xml/smbdotconf/logging/loglevel.xml 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/docs-xml/smbdotconf/logging/loglevel.xml 2021-08-09 07:17:53.000000000 +0000
@@ -24,8 +24,6 @@
printdrivers
lanman
smb
- smb2
- smb2_credits
rpc_parse
rpc_srv
rpc_cli
@@ -41,19 +39,24 @@
msdfs
dmapi
registry
- scavenger
- dns
- ldb
- tevent
- auth_audit
- auth_json_audit
- kerberos
- dsdb_audit
- dsdb_json_audit
- dsdb_password_audit
- dsdb_password_json_audit
- dsdb_transaction_audit
- dsdb_transaction_json_audit
+ scavenger
+ dns
+ ldb
+ tevent
+ auth_audit
+ auth_json_audit
+ kerberos
+ drs_repl
+ smb2
+ smb2_credits
+ dsdb_audit
+ dsdb_json_audit
+ dsdb_password_audit
+ dsdb_password_json_audit
+ dsdb_transaction_audit
+ dsdb_transaction_json_audit
+ dsdb_group_audit
+ dsdb_group_json_audit
To configure the logging for specific classes to go into a different
@@ -62,9 +65,9 @@
full_audit:1@/var/log/audit.log.
Authentication and authorization audit information is logged
- under the auth_audit, and if Samba was not compiled with
+ under the auth_audit, and if Samba was not compiled with
--without-json, a JSON representation is logged under
- auth_json_audit.
+ auth_json_audit.
Support is comprehensive for all authentication and authorisation
of user accounts in the Samba Active Directory Domain Controller,
@@ -72,7 +75,8 @@
the file server, NTLM authentication, SMB and RPC authorization is
covered.
- Log levels for auth_audit and auth_audit_json are:
+ Log levels for auth_audit and
+ auth_audit_json are:
2: Authentication Failure
3: Authentication Success
@@ -80,21 +84,69 @@
5: Anonymous Authentication and Authorization Success
- Changes to the sam.ldb database are logged
- under the dsdb_audit and a JSON representation is logged under
- dsdb_json_audit.
-
- Password changes and Password resets are logged under
- dsdb_password_audit and a JSON representation is logged under the
- dsdb_password_json_audit.
+ Changes to the AD DC sam.ldb
+ database are logged under the dsdb_audit
+ and a JSON representation is logged under
+ dsdb_json_audit.
+
+ Group membership changes to the AD DC sam.ldb database are logged under the
+ dsdb_group_audit and a JSON representation
+ is logged under
+ dsdb_group_json_audit.
+
+ Log levels for dsdb_audit,
+ dsdb_json_audit,
+ dsdb_group_audit,
+ dsdb_group_json_audit and
+ dsdb_json_audit are:
+
+ 5: Database modifications
+ 5: Replicated updates from another DC
+
+
+ Password changes and Password resets in the AD DC are logged
+ under dsdb_password_audit and a JSON
+ representation is logged under the
+ dsdb_password_json_audit. Password changes
+ will also appears as authentication events via
+ auth_audit and
+ auth_audit_json.
+
+ Log levels for dsdb_password_audit and
+ dsdb_password_json_audit are:
+
+ 5: Successful password changes and resets
+
Transaction rollbacks and prepare commit failures are logged under
- the dsdb_transaction_audit and a JSON representation is logged under the
- password_json_audit. Logging the transaction details allows the
- identification of password and sam.ldb operations that have been rolled
- back.
+ the dsdb_transaction_audit and a JSON representation is logged under the
+ dsdb_transaction_json_audit.
+ Log levels for dsdb_transaction_audit and
+ dsdb_transaction_json are:
+
+
+ 5: Transaction failure (rollback)
+ 10: Transaction success (commit)
+
+ Transaction roll-backs are possible in Samba, and whilst
+ they rarely reflect anything more than the failure of an
+ individual operation (say due to the add of a conflicting record),
+ they are possible. Audit logs are already generated and sent to
+ the system logs before the transaction is complete. Logging the
+ transaction details allows the identification of password and
+ sam.ldb operations that have
+ been rolled back, and so have not actually persisted.
+
+ Changes to sam.ldb made locally by the root user with direct access to the
+ database are not logged to the system logs, but to the
+ administrator's own console. While less than ideal, any user able
+ to make such modifications could disable the audit logging in any
+ case.
0
3 passdb:5 auth:10 winbind:2
diff -Nru samba-4.13.3+dfsg/docs-xml/smbdotconf/logon/autheventnotification.xml samba-4.13.14+dfsg/docs-xml/smbdotconf/logon/autheventnotification.xml
--- samba-4.13.3+dfsg/docs-xml/smbdotconf/logon/autheventnotification.xml 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/docs-xml/smbdotconf/logon/autheventnotification.xml 2021-08-06 12:19:57.000000000 +0000
@@ -10,16 +10,19 @@
registering as the service
auth_event.
- This should be considered a developer option (it assists
- in the Samba testsuite) rather than a facility for external
- auditing, as message delivery is not guaranteed (a feature
- that the testsuite works around). Additionally Samba must be
- compiled with the jansson support for this option to be
- effective.
+ This is not needed for the audit
+ logging described in .
+
+ Instead, this should instead be considered a developer
+ option (it assists in the Samba testsuite) rather than a
+ facility for external auditing, as message delivery is not
+ guaranteed (a feature that the testsuite works around).
The authentication events are also logged via the normal
logging methods when the is
- set appropriately.
+ set appropriately, say to
+ auth_json_audit:3.
+
no
diff -Nru samba-4.13.3+dfsg/docs-xml/smbdotconf/misc/dsdbeventnotification.xml samba-4.13.14+dfsg/docs-xml/smbdotconf/misc/dsdbeventnotification.xml
--- samba-4.13.3+dfsg/docs-xml/smbdotconf/misc/dsdbeventnotification.xml 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/docs-xml/smbdotconf/misc/dsdbeventnotification.xml 2021-08-06 12:19:57.000000000 +0000
@@ -10,14 +10,18 @@
registering as the service
dsdb_event.
- This should be considered a developer option (it assists
- in the Samba testsuite) rather than a facility for external
- auditing, as message delivery is not guaranteed (a feature
- that the testsuite works around).
+ This is not needed for the audit
+ logging described in .
+
+ Instead, this should instead be considered a developer
+ option (it assists in the Samba testsuite) rather than a
+ facility for external auditing, as message delivery is not
+ guaranteed (a feature that the testsuite works around).
The Samba database events are also logged via the normal
logging methods when the is
- set appropriately.
+ set appropriately, say to
+ dsdb_json_audit:5.
diff -Nru samba-4.13.3+dfsg/docs-xml/smbdotconf/misc/dsdbgroupchangenotification.xml samba-4.13.14+dfsg/docs-xml/smbdotconf/misc/dsdbgroupchangenotification.xml
--- samba-4.13.3+dfsg/docs-xml/smbdotconf/misc/dsdbgroupchangenotification.xml 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/docs-xml/smbdotconf/misc/dsdbgroupchangenotification.xml 2021-08-06 12:19:57.000000000 +0000
@@ -10,14 +10,18 @@
registering as the service
dsdb_group_event.
- This should be considered a developer option (it assists
- in the Samba testsuite) rather than a facility for external
- auditing, as message delivery is not guaranteed (a feature
- that the testsuite works around).
+ This is not needed for the audit
+ logging described in .
- The group events are also logged via the normal
+ Instead, this should instead be considered a developer
+ option (it assists in the Samba testsuite) rather than a
+ facility for external auditing, as message delivery is not
+ guaranteed (a feature that the testsuite works around).
+
+ The Samba database events are also logged via the normal
logging methods when the is
- set appropriately.
+ set appropriately, say to
+ dsdb_group_json_audit:5.
diff -Nru samba-4.13.3+dfsg/docs-xml/smbdotconf/misc/dsdbpasswordeventnotification.xml samba-4.13.14+dfsg/docs-xml/smbdotconf/misc/dsdbpasswordeventnotification.xml
--- samba-4.13.3+dfsg/docs-xml/smbdotconf/misc/dsdbpasswordeventnotification.xml 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/docs-xml/smbdotconf/misc/dsdbpasswordeventnotification.xml 2021-08-06 12:19:57.000000000 +0000
@@ -10,14 +10,18 @@
events by registering as the service
password_event.
- This should be considered a developer option (it assists
- in the Samba testsuite) rather than a facility for external
- auditing, as message delivery is not guaranteed (a feature
- that the testsuite works around).
+ This is not needed for the audit
+ logging described in .
- The password events are also logged via the normal
+ Instead, this should instead be considered a developer
+ option (it assists in the Samba testsuite) rather than a
+ facility for external auditing, as message delivery is not
+ guaranteed (a feature that the testsuite works around).
+
+ The Samba database events are also logged via the normal
logging methods when the is
- set appropriately.
+ set appropriately, say to
+ dsdb_password_json_audit:5.
diff -Nru samba-4.13.3+dfsg/docs-xml/smbdotconf/security/mindomainuid.xml samba-4.13.14+dfsg/docs-xml/smbdotconf/security/mindomainuid.xml
--- samba-4.13.3+dfsg/docs-xml/smbdotconf/security/mindomainuid.xml 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/docs-xml/smbdotconf/security/mindomainuid.xml 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,17 @@
+
+
+
+ The integer parameter specifies the minimum uid allowed when mapping a
+ local account to a domain account.
+
+
+
+ Note that this option interacts with the configured idmap ranges!
+
+
+
+1000
+
diff -Nru samba-4.13.3+dfsg/docs-xml/smbdotconf/security/serverrole.xml samba-4.13.14+dfsg/docs-xml/smbdotconf/security/serverrole.xml
--- samba-4.13.3+dfsg/docs-xml/smbdotconf/security/serverrole.xml 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/docs-xml/smbdotconf/security/serverrole.xml 2021-11-08 11:29:14.000000000 +0000
@@ -78,6 +78,13 @@
url="http://wiki.samba.org/index.php/Samba4/HOWTO">Samba4
HOWTO
+ SERVER ROLE = IPA DOMAIN CONTROLLER
+
+ This mode of operation runs Samba in a hybrid mode for IPA
+ domain controller, providing forest trust to Active Directory.
+ This role requires special configuration performed by IPA installers
+ and should not be used manually by any administrator.
+
security
diff -Nru samba-4.13.3+dfsg/docs-xml/smbdotconf/winbind/idmapconfig.xml samba-4.13.14+dfsg/docs-xml/smbdotconf/winbind/idmapconfig.xml
--- samba-4.13.3+dfsg/docs-xml/smbdotconf/winbind/idmapconfig.xml 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/docs-xml/smbdotconf/winbind/idmapconfig.xml 2021-11-08 11:29:14.000000000 +0000
@@ -80,6 +80,9 @@
authoritative for a unix ID to SID mapping, so it must be set
for each individually configured domain and for the default
configuration. The configured ranges must be mutually disjoint.
+
+
+ Note that the low value interacts with the option!
@@ -115,4 +118,5 @@
+min domain uid
diff -Nru samba-4.13.3+dfsg/.gitlab-ci.yml samba-4.13.14+dfsg/.gitlab-ci.yml
--- samba-4.13.3+dfsg/.gitlab-ci.yml 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/.gitlab-ci.yml 2021-08-09 07:20:55.000000000 +0000
@@ -23,7 +23,7 @@
# Set this to the contents of bootstrap/sha1sum.txt
# which is generated by bootstrap/template.py --render
#
- SAMBA_CI_CONTAINER_TAG: 1275dc52ac8c1de5981f267df88b85b6f87e299a
+ SAMBA_CI_CONTAINER_TAG: b5b78cacae2fa6cec91925170bc6d4e3774cac9b
#
# We use the ubuntu1804 image as default as
# it matches what we have on sn-devel-184.
diff -Nru samba-4.13.3+dfsg/GPG_AA99442FB680B620_replaces_6F33915B6568B7EA.txt samba-4.13.14+dfsg/GPG_AA99442FB680B620_replaces_6F33915B6568B7EA.txt
--- samba-4.13.3+dfsg/GPG_AA99442FB680B620_replaces_6F33915B6568B7EA.txt 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/GPG_AA99442FB680B620_replaces_6F33915B6568B7EA.txt 2021-08-06 12:19:57.000000000 +0000
@@ -0,0 +1,27 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+The GPG release key for Samba releases changed from:
+
+pub dsa1024/6F33915B6568B7EA 2007-02-04 [SC] [expires: 2021-02-05]
+ Key fingerprint = 52FB C0B8 6D95 4B08 4332 4CDC 6F33 915B 6568 B7EA
+uid [ full ] Samba Distribution Verification Key
+sub elg2048/9C6ED163DA6DFB44 2007-02-04 [E] [expires: 2021-02-05]
+
+to the following new key:
+
+pub rsa4096/AA99442FB680B620 2020-12-21 [SC] [expires: 2022-12-21]
+ Key fingerprint = 81F5 E283 2BD2 545A 1897 B713 AA99 442F B680 B620
+uid [ultimate] Samba Distribution Verification Key
+sub rsa4096/97EF9386FBFD4002 2020-12-21 [E] [expires: 2022-12-21]
+
+Starting from Jan 21th 2021, all Samba releases will be signed with the new key.
+
+This document is signed with the old key.
+
+-----BEGIN PGP SIGNATURE-----
+
+iF0EARECAB0WIQRS+8C4bZVLCEMyTNxvM5FbZWi36gUCYAltCQAKCRBvM5FbZWi3
+6ofOAJ491tFEr36jLkf158ueIrDw9zNVtgCbBV3PgocOX5VH57s1NQdBOof+ihw=
+=wf56
+-----END PGP SIGNATURE-----
diff -Nru samba-4.13.3+dfsg/lib/krb5_wrap/krb5_samba.c samba-4.13.14+dfsg/lib/krb5_wrap/krb5_samba.c
--- samba-4.13.3+dfsg/lib/krb5_wrap/krb5_samba.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/krb5_wrap/krb5_samba.c 2021-10-29 06:17:36.000000000 +0000
@@ -456,19 +456,20 @@
*
* @see smb_krb5_salt_principal2data
*/
-int smb_krb5_salt_principal(const char *realm,
+int smb_krb5_salt_principal(krb5_context krb5_ctx,
+ const char *realm,
const char *sAMAccountName,
const char *userPrincipalName,
uint32_t uac_flags,
- TALLOC_CTX *mem_ctx,
- char **_salt_principal)
+ krb5_principal *salt_princ)
{
TALLOC_CTX *frame = talloc_stackframe();
char *upper_realm = NULL;
const char *principal = NULL;
int principal_len = 0;
+ krb5_error_code krb5_ret;
- *_salt_principal = NULL;
+ *salt_princ = NULL;
if (sAMAccountName == NULL) {
TALLOC_FREE(frame);
@@ -512,7 +513,6 @@
*/
if (uac_flags & UF_TRUST_ACCOUNT_MASK) {
int computer_len = 0;
- char *tmp = NULL;
computer_len = strlen(sAMAccountName);
if (sAMAccountName[computer_len-1] == '$') {
@@ -520,60 +520,186 @@
}
if (uac_flags & UF_INTERDOMAIN_TRUST_ACCOUNT) {
- principal = talloc_asprintf(frame, "krbtgt/%*.*s",
- computer_len, computer_len,
- sAMAccountName);
- if (principal == NULL) {
+ const char *krbtgt = "krbtgt";
+ krb5_ret = krb5_build_principal_ext(krb5_ctx,
+ salt_princ,
+ strlen(upper_realm),
+ upper_realm,
+ strlen(krbtgt),
+ krbtgt,
+ computer_len,
+ sAMAccountName,
+ 0);
+ if (krb5_ret != 0) {
TALLOC_FREE(frame);
- return ENOMEM;
+ return krb5_ret;
}
} else {
-
- tmp = talloc_asprintf(frame, "host/%*.*s.%s",
- computer_len, computer_len,
- sAMAccountName, realm);
+ const char *host = "host";
+ char *tmp = NULL;
+ char *tmp_lower = NULL;
+
+ tmp = talloc_asprintf(frame, "%*.*s.%s",
+ computer_len,
+ computer_len,
+ sAMAccountName,
+ realm);
if (tmp == NULL) {
TALLOC_FREE(frame);
return ENOMEM;
}
- principal = strlower_talloc(frame, tmp);
- TALLOC_FREE(tmp);
- if (principal == NULL) {
+ tmp_lower = strlower_talloc(frame, tmp);
+ if (tmp_lower == NULL) {
TALLOC_FREE(frame);
return ENOMEM;
}
- }
- principal_len = strlen(principal);
+ krb5_ret = krb5_build_principal_ext(krb5_ctx,
+ salt_princ,
+ strlen(upper_realm),
+ upper_realm,
+ strlen(host),
+ host,
+ strlen(tmp_lower),
+ tmp_lower,
+ 0);
+ if (krb5_ret != 0) {
+ TALLOC_FREE(frame);
+ return krb5_ret;
+ }
+ }
} else if (userPrincipalName != NULL) {
- char *p;
+ /*
+ * We parse the name not only to allow an easy
+ * replacement of the realm (no matter the realm in
+ * the UPN, the salt comes from the upper-case real
+ * realm, but also to correctly provide a salt when
+ * the UPN is host/foo.bar
+ *
+ * This can fail for a UPN of the form foo@bar@REALM
+ * (which is accepted by windows) however.
+ */
+ krb5_ret = krb5_parse_name(krb5_ctx,
+ userPrincipalName,
+ salt_princ);
+
+ if (krb5_ret != 0) {
+ TALLOC_FREE(frame);
+ return krb5_ret;
+ }
- principal = userPrincipalName;
- p = strchr(principal, '@');
- if (p != NULL) {
- principal_len = PTR_DIFF(p, principal);
- } else {
- principal_len = strlen(principal);
+ /*
+ * No matter what realm (including none) in the UPN,
+ * the realm is replaced with our upper-case realm
+ */
+ krb5_ret = smb_krb5_principal_set_realm(krb5_ctx,
+ *salt_princ,
+ upper_realm);
+ if (krb5_ret != 0) {
+ krb5_free_principal(krb5_ctx, *salt_princ);
+ TALLOC_FREE(frame);
+ return krb5_ret;
}
} else {
principal = sAMAccountName;
principal_len = strlen(principal);
- }
- *_salt_principal = talloc_asprintf(mem_ctx, "%*.*s@%s",
- principal_len, principal_len,
- principal, upper_realm);
- if (*_salt_principal == NULL) {
- TALLOC_FREE(frame);
- return ENOMEM;
+ krb5_ret = krb5_build_principal_ext(krb5_ctx,
+ salt_princ,
+ strlen(upper_realm),
+ upper_realm,
+ principal_len,
+ principal,
+ 0);
+ if (krb5_ret != 0) {
+ TALLOC_FREE(frame);
+ return krb5_ret;
+ }
}
TALLOC_FREE(frame);
return 0;
}
+/**
+ * @brief This constructs the salt principal used by active directory
+ *
+ * Most Kerberos encryption types require a salt in order to
+ * calculate the long term private key for user/computer object
+ * based on a password.
+ *
+ * The returned _salt_principal is a string in forms like this:
+ * - host/somehost.example.com@EXAMPLE.COM
+ * - SomeAccount@EXAMPLE.COM
+ * - SomePrincipal@EXAMPLE.COM
+ *
+ * This is not the form that's used as salt, it's just
+ * the human readable form. It needs to be converted by
+ * smb_krb5_salt_principal2data().
+ *
+ * @param[in] realm The realm the user/computer is added too.
+ *
+ * @param[in] sAMAccountName The sAMAccountName attribute of the object.
+ *
+ * @param[in] userPrincipalName The userPrincipalName attribute of the object
+ * or NULL is not available.
+ *
+ * @param[in] uac_flags UF_ACCOUNT_TYPE_MASKed userAccountControl field
+ *
+ * @param[in] mem_ctx The TALLOC_CTX to allocate _salt_principal.
+ *
+ * @param[out] _salt_principal The resulting principal as string.
+ *
+ * @retval 0 Success; otherwise - Kerberos error codes
+ *
+ * @see smb_krb5_salt_principal2data
+ */
+int smb_krb5_salt_principal_str(const char *realm,
+ const char *sAMAccountName,
+ const char *userPrincipalName,
+ uint32_t uac_flags,
+ TALLOC_CTX *mem_ctx,
+ char **_salt_principal_str)
+{
+ krb5_principal salt_principal = NULL;
+ char *salt_principal_malloc;
+ krb5_context krb5_ctx;
+ krb5_error_code krb5_ret
+ = smb_krb5_init_context_common(&krb5_ctx);
+ if (krb5_ret != 0) {
+ DBG_ERR("kerberos init context failed (%s)\n",
+ error_message(krb5_ret));
+ return krb5_ret;
+ }
+
+ krb5_ret = smb_krb5_salt_principal(krb5_ctx,
+ realm,
+ sAMAccountName,
+ userPrincipalName,
+ uac_flags,
+ &salt_principal);
+
+ krb5_ret = krb5_unparse_name(krb5_ctx, salt_principal,
+ &salt_principal_malloc);
+ if (krb5_ret != 0) {
+ krb5_free_principal(krb5_ctx, salt_principal);
+ DBG_ERR("kerberos unparse of salt principal failed (%s)\n",
+ error_message(krb5_ret));
+ return krb5_ret;
+ }
+ krb5_free_principal(krb5_ctx, salt_principal);
+ *_salt_principal_str
+ = talloc_strdup(mem_ctx, salt_principal_malloc);
+ krb5_free_unparsed_name(krb5_ctx, salt_principal_malloc);
+
+ if (*_salt_principal_str == NULL) {
+ return ENOMEM;
+ }
+ return 0;
+}
+
/**
* @brief Converts the salt principal string into the salt data blob
*
diff -Nru samba-4.13.3+dfsg/lib/krb5_wrap/krb5_samba.h samba-4.13.14+dfsg/lib/krb5_wrap/krb5_samba.h
--- samba-4.13.3+dfsg/lib/krb5_wrap/krb5_samba.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/krb5_wrap/krb5_samba.h 2021-10-29 06:17:36.000000000 +0000
@@ -350,12 +350,19 @@
int smb_krb5_get_pw_salt(krb5_context context,
krb5_const_principal host_princ,
krb5_data *psalt);
-int smb_krb5_salt_principal(const char *realm,
+int smb_krb5_salt_principal(krb5_context krb5_ctx,
+ const char *realm,
const char *sAMAccountName,
const char *userPrincipalName,
uint32_t uac_flags,
- TALLOC_CTX *mem_ctx,
- char **_salt_principal);
+ krb5_principal *salt_princ);
+
+int smb_krb5_salt_principal_str(const char *realm,
+ const char *sAMAccountName,
+ const char *userPrincipalName,
+ uint32_t uac_flags,
+ TALLOC_CTX *mem_ctx,
+ char **_salt_principal);
int smb_krb5_salt_principal2data(krb5_context context,
const char *salt_principal,
TALLOC_CTX *mem_ctx,
diff -Nru samba-4.13.3+dfsg/lib/ldb/ABI/ldb-2.2.1.sigs samba-4.13.14+dfsg/lib/ldb/ABI/ldb-2.2.1.sigs
--- samba-4.13.3+dfsg/lib/ldb/ABI/ldb-2.2.1.sigs 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/ABI/ldb-2.2.1.sigs 2021-08-09 07:20:55.000000000 +0000
@@ -0,0 +1,283 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff -Nru samba-4.13.3+dfsg/lib/ldb/ABI/ldb-2.2.2.sigs samba-4.13.14+dfsg/lib/ldb/ABI/ldb-2.2.2.sigs
--- samba-4.13.3+dfsg/lib/ldb/ABI/ldb-2.2.2.sigs 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/ABI/ldb-2.2.2.sigs 2021-10-29 06:17:36.000000000 +0000
@@ -0,0 +1,283 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff -Nru samba-4.13.3+dfsg/lib/ldb/ABI/ldb-2.2.3.sigs samba-4.13.14+dfsg/lib/ldb/ABI/ldb-2.2.3.sigs
--- samba-4.13.3+dfsg/lib/ldb/ABI/ldb-2.2.3.sigs 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/ABI/ldb-2.2.3.sigs 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,283 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_copy: const char **(TALLOC_CTX *, const char **)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_options_get: const char **(struct ldb_context *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff -Nru samba-4.13.3+dfsg/lib/ldb/ABI/pyldb-util-2.2.1.sigs samba-4.13.14+dfsg/lib/ldb/ABI/pyldb-util-2.2.1.sigs
--- samba-4.13.3+dfsg/lib/ldb/ABI/pyldb-util-2.2.1.sigs 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/ABI/pyldb-util-2.2.1.sigs 2021-08-09 07:20:55.000000000 +0000
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff -Nru samba-4.13.3+dfsg/lib/ldb/ABI/pyldb-util-2.2.2.sigs samba-4.13.14+dfsg/lib/ldb/ABI/pyldb-util-2.2.2.sigs
--- samba-4.13.3+dfsg/lib/ldb/ABI/pyldb-util-2.2.2.sigs 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/ABI/pyldb-util-2.2.2.sigs 2021-10-29 06:17:36.000000000 +0000
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff -Nru samba-4.13.3+dfsg/lib/ldb/ABI/pyldb-util-2.2.3.sigs samba-4.13.14+dfsg/lib/ldb/ABI/pyldb-util-2.2.3.sigs
--- samba-4.13.3+dfsg/lib/ldb/ABI/pyldb-util-2.2.3.sigs 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/ABI/pyldb-util-2.2.3.sigs 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,3 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
+pyldb_check_type: bool (PyObject *, const char *)
diff -Nru samba-4.13.3+dfsg/lib/ldb/common/attrib_handlers.c samba-4.13.14+dfsg/lib/ldb/common/attrib_handlers.c
--- samba-4.13.3+dfsg/lib/ldb/common/attrib_handlers.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/common/attrib_handlers.c 2021-11-08 11:29:14.000000000 +0000
@@ -54,8 +54,8 @@
int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
- char *s, *t;
- size_t l;
+ char *s, *t, *start;
+ bool in_space;
if (!in || !out || !(in->data)) {
return -1;
@@ -67,40 +67,37 @@
return -1;
}
- s = (char *)(out->data);
-
- /* remove trailing spaces if any */
- l = strlen(s);
- while (l > 0 && s[l - 1] == ' ') l--;
- s[l] = '\0';
-
- /* remove leading spaces if any */
- if (*s == ' ') {
- for (t = s; *s == ' '; s++) ;
-
- /* remove leading spaces by moving down the string */
- memmove(t, s, l);
-
- s = t;
+ start = (char *)(out->data);
+ in_space = true;
+ t = start;
+ for (s = start; *s != '\0'; s++) {
+ if (*s == ' ') {
+ if (in_space) {
+ /*
+ * We already have one (or this is the start)
+ * and we don't want to add more
+ */
+ continue;
+ }
+ in_space = true;
+ } else {
+ in_space = false;
+ }
+ *t = *s;
+ t++;
}
- /* check middle spaces */
- while ((t = strchr(s, ' ')) != NULL) {
- for (s = t; *s == ' '; s++) ;
-
- if ((s - t) > 1) {
- l = strlen(s);
-
- /* remove all spaces but one by moving down the string */
- memmove(t + 1, s, l);
- }
+ if (in_space && t != start) {
+ /* the loop will have left a single trailing space */
+ t--;
}
+ *t = '\0';
- out->length = strlen((char *)out->data);
+ out->length = t - start;
return 0;
}
-/* length limited conversion of a ldb_val to a int32_t */
+/* length limited conversion of a ldb_val to an int64_t */
static int val_to_int64(const struct ldb_val *in, int64_t *v)
{
char *end;
@@ -113,8 +110,6 @@
strncpy(buf, (char *)in->data, in->length);
buf[in->length] = 0;
- /* We've to use "strtoll" here to have the intended overflows.
- * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
*v = (int64_t) strtoll(buf, &end, 0);
if (*end != 0) {
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
@@ -337,8 +332,8 @@
if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
break;
if (*s1 == ' ') {
- while (n1 && s1[0] == s1[1]) { s1++; n1--; }
- while (n2 && s2[0] == s2[1]) { s2++; n2--; }
+ while (n1 > 1 && s1[0] == s1[1]) { s1++; n1--; }
+ while (n2 > 1 && s2[0] == s2[1]) { s2++; n2--; }
}
s1++; s2++;
n1--; n2--;
diff -Nru samba-4.13.3+dfsg/lib/ldb/common/ldb_controls.c samba-4.13.14+dfsg/lib/ldb/common/ldb_controls.c
--- samba-4.13.3+dfsg/lib/ldb/common/ldb_controls.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/common/ldb_controls.c 2021-11-08 11:29:14.000000000 +0000
@@ -286,6 +286,9 @@
if (strcmp(control->oid, LDB_CONTROL_PAGED_RESULTS_OID) == 0) {
struct ldb_paged_control *rep_control = talloc_get_type(control->data, struct ldb_paged_control);
char *cookie;
+ if (rep_control == NULL) {
+ return NULL;
+ }
cookie = ldb_base64_encode(mem_ctx, rep_control->cookie, rep_control->cookie_len);
if (cookie == NULL) {
@@ -312,6 +315,10 @@
char *cookie;
+ if (rep_control == NULL) {
+ return NULL;
+ }
+
cookie = ldb_base64_encode(mem_ctx,
(char *)rep_control->contextId,
rep_control->ctxid_len);
@@ -334,6 +341,9 @@
struct ldb_sort_resp_control *rep_control = talloc_get_type(control->data,
struct ldb_sort_resp_control);
+ if (rep_control == NULL) {
+ return NULL;
+ }
res = talloc_asprintf(mem_ctx, "%s:%d:%d:%s",
LDB_CONTROL_SORT_RESP_NAME,
control->critical,
@@ -347,6 +357,9 @@
struct ldb_asq_control *rep_control = talloc_get_type(control->data,
struct ldb_asq_control);
+ if (rep_control == NULL) {
+ return NULL;
+ }
res = talloc_asprintf(mem_ctx, "%s:%d:%d",
LDB_CONTROL_SORT_RESP_NAME,
control->critical,
@@ -360,6 +373,9 @@
struct ldb_dirsync_control *rep_control = talloc_get_type(control->data,
struct ldb_dirsync_control);
+ if (rep_control == NULL) {
+ return NULL;
+ }
cookie = ldb_base64_encode(mem_ctx, rep_control->cookie,
rep_control->cookie_len);
if (cookie == NULL) {
@@ -380,6 +396,9 @@
struct ldb_dirsync_control *rep_control = talloc_get_type(control->data,
struct ldb_dirsync_control);
+ if (rep_control == NULL) {
+ return NULL;
+ }
cookie = ldb_base64_encode(mem_ctx, rep_control->cookie,
rep_control->cookie_len);
if (cookie == NULL) {
@@ -399,6 +418,9 @@
if (strcmp(control->oid, LDB_CONTROL_VERIFY_NAME_OID) == 0) {
struct ldb_verify_name_control *rep_control = talloc_get_type(control->data, struct ldb_verify_name_control);
+ if (rep_control == NULL) {
+ return NULL;
+ }
if (rep_control->gc != NULL) {
res = talloc_asprintf(mem_ctx, "%s:%d:%d:%s",
LDB_CONTROL_VERIFY_NAME_NAME,
diff -Nru samba-4.13.3+dfsg/lib/ldb/common/ldb_dn.c samba-4.13.14+dfsg/lib/ldb/common/ldb_dn.c
--- samba-4.13.3+dfsg/lib/ldb/common/ldb_dn.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/common/ldb_dn.c 2021-08-06 12:19:57.000000000 +0000
@@ -570,6 +570,7 @@
/* trim back */
d -= (p - t);
l -= (p - t);
+ t = NULL;
}
in_attr = true;
diff -Nru samba-4.13.3+dfsg/lib/ldb/common/ldb_match.c samba-4.13.14+dfsg/lib/ldb/common/ldb_match.c
--- samba-4.13.3+dfsg/lib/ldb/common/ldb_match.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/common/ldb_match.c 2021-11-08 11:29:14.000000000 +0000
@@ -295,8 +295,9 @@
uint8_t *p;
chunk = tree->u.substring.chunks[c];
- if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch;
-
+ if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) {
+ goto mismatch;
+ }
/*
* Empty strings are returned as length 0. Ensure
* we can cope with this.
@@ -304,56 +305,43 @@
if (cnk.length == 0) {
goto mismatch;
}
- /*
- * Values might be binary blobs. Don't use string
- * search, but memory search instead.
- */
- p = memmem((const void *)val.data,val.length,
- (const void *)cnk.data, cnk.length);
- if (p == NULL) goto mismatch;
-
- /*
- * At this point we know cnk.length <= val.length as
- * otherwise there could be no match
- */
-
- if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
- uint8_t *g;
- uint8_t *end = val.data + val.length;
- do { /* greedy */
-
- /*
- * haystack is a valid pointer in val
- * because the memmem() can only
- * succeed if the needle (cnk.length)
- * is <= haystacklen
- *
- * p will be a pointer at least
- * cnk.length from the end of haystack
- */
- uint8_t *haystack
- = p + cnk.length;
- size_t haystacklen
- = end - (haystack);
+ if (cnk.length > val.length) {
+ goto mismatch;
+ }
- g = memmem(haystack,
- haystacklen,
- (const uint8_t *)cnk.data,
- cnk.length);
- if (g) {
- p = g;
- }
- } while(g);
+ if ( (tree->u.substring.chunks[c + 1]) == NULL &&
+ (! tree->u.substring.end_with_wildcard) ) {
+ /*
+ * The last bit, after all the asterisks, must match
+ * exactly the last bit of the string.
+ */
+ int cmp;
+ p = val.data + val.length - cnk.length;
+ cmp = memcmp(p,
+ cnk.data,
+ cnk.length);
+ if (cmp != 0) {
+ goto mismatch;
+ }
+ } else {
+ /*
+ * Values might be binary blobs. Don't use string
+ * search, but memory search instead.
+ */
+ p = memmem((const void *)val.data, val.length,
+ (const void *)cnk.data, cnk.length);
+ if (p == NULL) {
+ goto mismatch;
+ }
+ /* move val to the end of the match */
+ p += cnk.length;
+ val.length -= (p - val.data);
+ val.data = p;
}
- val.length = val.length - (p - (uint8_t *)(val.data)) - cnk.length;
- val.data = (uint8_t *)(p + cnk.length);
c++;
- talloc_free(cnk.data);
- cnk.data = NULL;
+ TALLOC_FREE(cnk.data);
}
- /* last chunk may not have reached end of string */
- if ( (! tree->u.substring.end_with_wildcard) && (val.length != 0) ) goto mismatch;
talloc_free(save_p);
*matched = true;
return LDB_SUCCESS;
diff -Nru samba-4.13.3+dfsg/lib/ldb/common/ldb_modules.c samba-4.13.14+dfsg/lib/ldb/common/ldb_modules.c
--- samba-4.13.3+dfsg/lib/ldb/common/ldb_modules.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/common/ldb_modules.c 2021-11-08 11:29:14.000000000 +0000
@@ -173,11 +173,15 @@
/*
Return the ldb module form of a database.
- The URL can either be one of the following forms
- ldb://path
- ldapi://path
+ The URL looks something like this:
+ tdb://PATH
+ ldb://PATH
+ mdb://PATH
+ ldapi://PATH
+ PATH (unadorned PATH defaults to tdb://)
- flags is made up of LDB_FLG_*
+ for a complete list of backends (including possibly unmaintained ones) grep
+ for calls to ldb_register_backend().
the options are passed uninterpreted to the backend, and are
backend specific.
diff -Nru samba-4.13.3+dfsg/lib/ldb/common/ldb_msg.c samba-4.13.14+dfsg/lib/ldb/common/ldb_msg.c
--- samba-4.13.3+dfsg/lib/ldb/common/ldb_msg.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/common/ldb_msg.c 2021-11-08 11:29:14.000000000 +0000
@@ -876,8 +876,10 @@
msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
if (msg2 == NULL) return NULL;
- msg2->dn = ldb_dn_copy(msg2, msg2->dn);
- if (msg2->dn == NULL) goto failed;
+ if (msg2->dn != NULL) {
+ msg2->dn = ldb_dn_copy(msg2, msg2->dn);
+ if (msg2->dn == NULL) goto failed;
+ }
for (i=0;inum_elements;i++) {
struct ldb_message_element *el = &msg2->elements[i];
@@ -1270,6 +1272,7 @@
if (r != 17) {
talloc_free(ts);
+ errno = EOVERFLOW;
return NULL;
}
diff -Nru samba-4.13.3+dfsg/lib/ldb/common/ldb_parse.c samba-4.13.14+dfsg/lib/ldb/common/ldb_parse.c
--- samba-4.13.3+dfsg/lib/ldb/common/ldb_parse.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/common/ldb_parse.c 2021-11-08 11:29:14.000000000 +0000
@@ -53,26 +53,6 @@
*/
#define LDB_MAX_PARSE_TREE_DEPTH 128
-static int ldb_parse_hex2char(const char *x)
-{
- if (isxdigit(x[0]) && isxdigit(x[1])) {
- const char h1 = x[0], h2 = x[1];
- int c = 0;
-
- if (h1 >= 'a') c = h1 - (int)'a' + 10;
- else if (h1 >= 'A') c = h1 - (int)'A' + 10;
- else if (h1 >= '0') c = h1 - (int)'0';
- c = c << 4;
- if (h2 >= 'a') c += h2 - (int)'a' + 10;
- else if (h2 >= 'A') c += h2 - (int)'A' + 10;
- else if (h2 >= '0') c += h2 - (int)'0';
-
- return c;
- }
-
- return -1;
-}
-
/*
a filter is defined by:
::= '(' ')'
@@ -101,10 +81,11 @@
for (i=j=0;idata->critical = true;
} else {
@@ -839,7 +843,7 @@
"S.get_component_value(num) -> string\n"
"get the attribute value of the specified component as a binary string" },
{ "set_component", (PyCFunction)py_ldb_dn_set_component, METH_VARARGS,
- "S.get_component_value(num, name, value) -> None\n"
+ "S.set_component(num, name, value) -> None\n"
"set the attribute name and value of the specified component" },
{ "get_rdn_name", (PyCFunction)py_ldb_dn_get_rdn_name, METH_NOARGS,
"S.get_rdn_name() -> string\n"
@@ -1804,6 +1808,7 @@
struct ldb_message *diff;
struct ldb_context *ldb;
PyObject *py_ret;
+ TALLOC_CTX *mem_ctx = NULL;
if (!PyArg_ParseTuple(args, "OO", &py_msg_old, &py_msg_new))
return NULL;
@@ -1818,19 +1823,32 @@
return NULL;
}
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
- ldb_ret = ldb_msg_difference(ldb, ldb,
+ ldb_ret = ldb_msg_difference(ldb, mem_ctx,
pyldb_Message_AsMessage(py_msg_old),
pyldb_Message_AsMessage(py_msg_new),
&diff);
if (ldb_ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
PyErr_SetString(PyExc_RuntimeError, "Failed to generate the Ldb Message diff");
return NULL;
}
+ diff = ldb_msg_copy(mem_ctx, diff);
+ if (diff == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
py_ret = PyLdbMessage_FromMessage(diff);
- talloc_unlink(ldb, diff);
+ talloc_free(mem_ctx);
return py_ret;
}
@@ -3415,33 +3433,41 @@
return obj;
}
-static PyObject *py_ldb_msg_getitem_helper(PyLdbMessageObject *self, PyObject *py_name)
+static int py_ldb_msg_contains(PyLdbMessageObject *self, PyObject *py_name)
{
- struct ldb_message_element *el;
- const char *name;
+ struct ldb_message_element *el = NULL;
+ const char *name = NULL;
struct ldb_message *msg = pyldb_Message_AsMessage(self);
name = PyUnicode_AsUTF8(py_name);
if (name == NULL) {
- PyErr_SetNone(PyExc_TypeError);
- return NULL;
+ return -1;
}
- if (!ldb_attr_cmp(name, "dn"))
- return pyldb_Dn_FromDn(msg->dn);
- el = ldb_msg_find_element(msg, name);
- if (el == NULL) {
- return NULL;
+ if (!ldb_attr_cmp(name, "dn")) {
+ return 1;
}
- return (PyObject *)PyLdbMessageElement_FromMessageElement(el, msg->elements);
+ el = ldb_msg_find_element(msg, name);
+ return el != NULL ? 1 : 0;
}
static PyObject *py_ldb_msg_getitem(PyLdbMessageObject *self, PyObject *py_name)
{
- PyObject *ret = py_ldb_msg_getitem_helper(self, py_name);
- if (ret == NULL) {
+ struct ldb_message_element *el = NULL;
+ const char *name = NULL;
+ struct ldb_message *msg = pyldb_Message_AsMessage(self);
+ name = PyUnicode_AsUTF8(py_name);
+ if (name == NULL) {
+ return NULL;
+ }
+ if (!ldb_attr_cmp(name, "dn")) {
+ return pyldb_Dn_FromDn(msg->dn);
+ }
+ el = ldb_msg_find_element(msg, name);
+ if (el == NULL) {
PyErr_SetString(PyExc_KeyError, "No such element");
return NULL;
}
- return ret;
+
+ return PyLdbMessageElement_FromMessageElement(el, msg->elements);
}
static PyObject *py_ldb_msg_get(PyLdbMessageObject *self, PyObject *args, PyObject *kwargs)
@@ -3509,13 +3535,13 @@
PyObject *value = NULL;
PyObject *py_el = PyLdbMessageElement_FromMessageElement(&msg->elements[i], msg->elements);
int res = 0;
- Py_CLEAR(py_el);
value = Py_BuildValue("(sO)", msg->elements[i].name, py_el);
+ Py_CLEAR(py_el);
if (value == NULL ) {
Py_CLEAR(l);
return NULL;
}
- res = PyList_SetItem(l, 0, value);
+ res = PyList_SetItem(l, j, value);
if (res == -1) {
Py_CLEAR(l);
return NULL;
@@ -3651,6 +3677,10 @@
return pyldb_Message_AsMessage(self)->num_elements;
}
+static PySequenceMethods py_ldb_msg_sequence = {
+ .sq_contains = (objobjproc)py_ldb_msg_contains,
+};
+
static PyMappingMethods py_ldb_msg_mapping = {
.mp_length = (lenfunc)py_ldb_msg_length,
.mp_subscript = (binaryfunc)py_ldb_msg_getitem,
@@ -3727,6 +3757,10 @@
static int py_ldb_msg_set_dn(PyLdbMessageObject *self, PyObject *value, void *closure)
{
struct ldb_message *msg = pyldb_Message_AsMessage(self);
+ if (value == NULL) {
+ PyErr_SetString(PyExc_AttributeError, "cannot delete dn");
+ return -1;
+ }
if (!pyldb_Dn_Check(value)) {
PyErr_SetString(PyExc_TypeError, "expected dn");
return -1;
@@ -3824,6 +3858,7 @@
.tp_name = "ldb.Message",
.tp_methods = py_ldb_msg_methods,
.tp_getset = py_ldb_msg_getset,
+ .tp_as_sequence = &py_ldb_msg_sequence,
.tp_as_mapping = &py_ldb_msg_mapping,
.tp_basicsize = sizeof(PyLdbMessageObject),
.tp_dealloc = (destructor)py_ldb_msg_dealloc,
@@ -4192,6 +4227,13 @@
if (!PyArg_ParseTuple(args, "l", &t_val))
return NULL;
tresult = ldb_timestring(NULL, (time_t) t_val);
+ if (tresult == NULL) {
+ /*
+ * Most likely EOVERFLOW from gmtime()
+ */
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
ret = PyUnicode_FromString(tresult);
talloc_free(tresult);
return ret;
@@ -4272,7 +4314,7 @@
"S.string_to_time(string) -> int\n\n"
"Parse a LDAP time string into a UNIX timestamp." },
{ "valid_attr_name", py_valid_attr_name, METH_VARARGS,
- "S.valid_attr_name(name) -> bool\n\nn"
+ "S.valid_attr_name(name) -> bool\n\n"
"Check whether the supplied name is a valid attribute name." },
{ "binary_encode", py_binary_encode, METH_VARARGS,
"S.binary_encode(string) -> string\n\n"
diff -Nru samba-4.13.3+dfsg/lib/ldb/tests/ldb_match_test.c samba-4.13.14+dfsg/lib/ldb/tests/ldb_match_test.c
--- samba-4.13.3+dfsg/lib/ldb/tests/ldb_match_test.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/tests/ldb_match_test.c 2021-11-08 11:29:14.000000000 +0000
@@ -91,6 +91,33 @@
return 0;
}
+static void escape_string(uint8_t *buf, size_t buflen,
+ const uint8_t *s, size_t len)
+{
+ size_t i;
+ size_t j = 0;
+ for (i = 0; i < len; i++) {
+ if (j == buflen - 1) {
+ goto fin;
+ }
+ if (s[i] >= 0x20) {
+ buf[j] = s[i];
+ j++;
+ } else {
+ if (j >= buflen - 4) {
+ goto fin;
+ }
+ /* utf-8 control char representation */
+ buf[j] = 0xE2;
+ buf[j + 1] = 0x90;
+ buf[j + 2] = 0x80 + s[i];
+ j+= 3;
+ }
+ }
+fin:
+ buf[j] = 0;
+}
+
/*
* The wild card pattern "attribute=*" is parsed as an LDB_OP_PRESENT operation
@@ -122,23 +149,116 @@
* Test basic wild card matching
*
*/
+struct wildcard_test {
+ uint8_t *val;
+ size_t val_size;
+ const char *search;
+ bool should_match;
+ bool fold;
+};
+
+/*
+ * Q: Why this macro rather than plain struct values?
+ * A: So we can get the size of the const char[] value while it is still a
+ * true array, not a pointer.
+ *
+ * Q: but why not just use strlen?
+ * A: so values can contain '\0', which we supposedly allow.
+ */
+
+#define TEST_ENTRY(val, search, should_match, fold) \
+ { \
+ (uint8_t*)discard_const(val), \
+ sizeof(val) - 1, \
+ search, \
+ should_match, \
+ fold \
+ }
+
static void test_wildcard_match(void **state)
{
struct ldbtest_ctx *ctx = *state;
- bool matched = false;
-
- uint8_t value[] = "The value.......end";
- struct ldb_val val = {
- .data = value,
- .length = (sizeof(value))
+ size_t failed = 0;
+ size_t i;
+ struct wildcard_test tests[] = {
+ TEST_ENTRY(" 1 0", "1*0*", true, true),
+ TEST_ENTRY(" 1 0", "1 *0", true, true),
+ TEST_ENTRY(" 1 0", "*1 0", true, true),
+ TEST_ENTRY("1 0", "*1 0", true, true),
+ TEST_ENTRY("The value.......end", "*end", true, true),
+ TEST_ENTRY("The value.......end", "*fend", false, true),
+ TEST_ENTRY("The value.......end", "*eel", false, true),
+ TEST_ENTRY("The value.......end", "*d", true, true),
+ TEST_ENTRY("The value.......end", "*D*", true, true),
+ TEST_ENTRY("The value.......end", "*e*d*", true, true),
+ TEST_ENTRY("end", "*e*d*", true, true),
+ TEST_ENTRY("end", " *e*d*", true, true),
+ TEST_ENTRY("1.0..0.0.0.0.0.0.0aAaaaAAAAAAA", "*a", true, true),
+ TEST_ENTRY("1.0.0.0.0.0.0.0.0.0.0aaaa", "*aaaaa", false, true),
+ TEST_ENTRY("1.0.0.0.0.0.0.0.0.0.0", "*0.0", true, true),
+ TEST_ENTRY("1.0.0.0.0.0.0.0.0.0", "1*0*0*0*0*0*0*0*0*0", true,
+ true),
+ TEST_ENTRY("1.0.0.0.0.0.0.0.0", "1*0*0*0*0*0*0*0*0*0", false,
+ true),
+ TEST_ENTRY("1.0.0.0.000.0.0.0.0", "1*0*0*0*0*0*0*0*0*0", true,
+ true),
+ TEST_ENTRY("1\n0\r0\t000.0.0.0.0", "1*0*0*0*0*0*0*0*0", true,
+ true),
+ /*
+ * We allow NUL bytes and redundant spaces in non-casefolding
+ * syntaxes.
+ */
+ TEST_ENTRY(" 1 0", "*1 0", true, false),
+ TEST_ENTRY(" 1 0", "*1 0", true, false),
+ TEST_ENTRY("1 0", "*1 0", false, false),
+ TEST_ENTRY("1\x00 x", "1*x", true, false),
+ TEST_ENTRY("1\x00 x", "*x", true, false),
+ TEST_ENTRY("1\x00 x", "*x*", true, false),
+ TEST_ENTRY("1\x00 x", "* *", true, false),
+ TEST_ENTRY("1\x00 x", "1*", true, false),
+ TEST_ENTRY("1\x00 b* x", "1*b*", true, false),
+ TEST_ENTRY("1.0..0.0.0.0.0.0.0aAaaaAAAAAAA", "*a", false, false),
};
- struct ldb_parse_tree *tree = ldb_parse_tree(ctx, "objectClass=*end");
- assert_non_null(tree);
- ldb_wildcard_compare(ctx->ldb, tree, val, &matched);
- assert_true(matched);
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ bool matched;
+ int ret;
+ struct ldb_val val = {
+ .data = (uint8_t *)tests[i].val,
+ .length = tests[i].val_size
+ };
+ const char *attr = tests[i].fold ? "objectclass" : "birthLocation";
+ const char *s = talloc_asprintf(ctx, "%s=%s",
+ attr, tests[i].search);
+ struct ldb_parse_tree *tree = ldb_parse_tree(ctx, s);
+ assert_non_null(tree);
+ ret = ldb_wildcard_compare(ctx->ldb, tree, val, &matched);
+ if (ret != LDB_SUCCESS) {
+ uint8_t buf[100];
+ escape_string(buf, sizeof(buf),
+ tests[i].val, tests[i].val_size);
+ print_error("%zu val: «%s», search «%s» FAILED with %d\n",
+ i, buf, tests[i].search, ret);
+ failed++;
+ }
+ if (matched != tests[i].should_match) {
+ uint8_t buf[100];
+ escape_string(buf, sizeof(buf),
+ tests[i].val, tests[i].val_size);
+ print_error("%zu val: «%s», search «%s» should %s\n",
+ i, buf, tests[i].search,
+ matched ? "not match" : "match");
+ failed++;
+ }
+ }
+ if (failed != 0) {
+ fail_msg("wrong results for %zu/%zu wildcard searches\n",
+ failed, ARRAY_SIZE(tests));
+ }
}
+#undef TEST_ENTRY
+
/*
* ldb_handler_copy and ldb_val_dup over allocate by one and add a trailing '\0'
diff -Nru samba-4.13.3+dfsg/lib/ldb/tests/python/api.py samba-4.13.14+dfsg/lib/ldb/tests/python/api.py
--- samba-4.13.3+dfsg/lib/ldb/tests/python/api.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/tests/python/api.py 2021-11-08 11:29:14.000000000 +0000
@@ -5,10 +5,12 @@
import os
from unittest import TestCase
import sys
+sys.path.insert(0, "bin/python")
import gc
import time
import ldb
import shutil
+import errno
PY3 = sys.version_info > (3, 0)
@@ -42,10 +44,27 @@
self.assertEqual("19700101000000.0Z", ldb.timestring(0))
self.assertEqual("20071119191012.0Z", ldb.timestring(1195499412))
+ self.assertEqual("00000101000000.0Z", ldb.timestring(-62167219200))
+ self.assertEqual("99991231235959.0Z", ldb.timestring(253402300799))
+
+ # should result with OSError EOVERFLOW from gmtime()
+ with self.assertRaises(OSError) as err:
+ ldb.timestring(-62167219201)
+ self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+ with self.assertRaises(OSError) as err:
+ ldb.timestring(253402300800)
+ self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+ with self.assertRaises(OSError) as err:
+ ldb.timestring(0x7fffffffffffffff)
+ self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+
def test_string_to_time(self):
self.assertEqual(0, ldb.string_to_time("19700101000000.0Z"))
self.assertEqual(1195499412, ldb.string_to_time("20071119191012.0Z"))
+ self.assertEqual(-62167219200, ldb.string_to_time("00000101000000.0Z"))
+ self.assertEqual(253402300799, ldb.string_to_time("99991231235959.0Z"))
+
def test_binary_encode(self):
encoded = ldb.binary_encode(b'test\\x')
decoded = ldb.binary_decode(encoded)
@@ -3056,6 +3075,12 @@
def test_notpresent(self):
self.assertRaises(KeyError, lambda: self.msg["foo"])
+ def test_invalid(self):
+ try:
+ self.assertRaises(TypeError, lambda: self.msg[42])
+ except KeyError:
+ self.fail()
+
def test_del(self):
del self.msg["foo"]
@@ -3171,6 +3196,29 @@
def test_get_unknown_text(self):
self.assertEqual(None, self.msg.text.get("lalalala"))
+ def test_contains(self):
+ self.msg['foo'] = ['bar']
+ self.assertIn('foo', self.msg)
+
+ self.msg['Foo'] = ['bar']
+ self.assertIn('Foo', self.msg)
+
+ def test_contains_case(self):
+ self.msg['foo'] = ['bar']
+ self.assertIn('Foo', self.msg)
+
+ self.msg['Foo'] = ['bar']
+ self.assertIn('foo', self.msg)
+
+ def test_contains_dn(self):
+ self.assertIn('dn', self.msg)
+
+ def test_contains_dn_case(self):
+ self.assertIn('DN', self.msg)
+
+ def test_contains_invalid(self):
+ self.assertRaises(TypeError, lambda: None in self.msg)
+
def test_msg_diff(self):
l = ldb.Ldb()
msgs = l.parse_ldif("dn: foo=bar\nfoo: bar\nbaz: do\n\ndn: foo=bar\nfoo: bar\nbaz: dont\n")
diff -Nru samba-4.13.3+dfsg/lib/ldb/tests/python/crash.py samba-4.13.14+dfsg/lib/ldb/tests/python/crash.py
--- samba-4.13.3+dfsg/lib/ldb/tests/python/crash.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/tests/python/crash.py 2021-08-06 12:19:57.000000000 +0000
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+#
+# Tests for crashing functions
+
+import os
+from unittest import TestCase
+import os
+import sys
+import traceback
+
+import ldb
+
+
+def segfault_detector(f):
+ def wrapper(*args, **kwargs):
+ pid = os.fork()
+ if pid == 0:
+ # child, crashing?
+ try:
+ f(*args, **kwargs)
+ except Exception as e:
+ traceback.print_exc()
+ sys.stderr.flush()
+ sys.stdout.flush()
+ os._exit(0)
+
+ # parent, waiting
+ pid2, status = os.waitpid(pid, 0)
+ if os.WIFSIGNALED(status):
+ signal = os.WTERMSIG(status)
+ raise AssertionError("Failed with signal %d" % signal)
+
+ return wrapper
+
+
+class LdbDnCrashTests(TestCase):
+ @segfault_detector
+ def test_ldb_dn_explode_crash(self):
+ for i in range(106, 150):
+ dn = ldb.Dn(ldb.Ldb(), "a=b%s,c= " % (' ' * i))
+ dn.validate()
+
+if __name__ == '__main__':
+ import unittest
+ unittest.TestProgram()
diff -Nru samba-4.13.3+dfsg/lib/ldb/tools/cmdline.c samba-4.13.14+dfsg/lib/ldb/tools/cmdline.c
--- samba-4.13.3+dfsg/lib/ldb/tools/cmdline.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/tools/cmdline.c 2021-11-08 11:29:14.000000000 +0000
@@ -34,32 +34,232 @@
static struct poptOption builtin_popt_options[] = {
POPT_AUTOHELP
- { "url", 'H', POPT_ARG_STRING, &options.url, 0, "database URL", "URL" },
- { "basedn", 'b', POPT_ARG_STRING, &options.basedn, 0, "base DN", "DN" },
- { "editor", 'e', POPT_ARG_STRING, &options.editor, 0, "external editor", "PROGRAM" },
- { "scope", 's', POPT_ARG_STRING, NULL, 's', "search scope", "SCOPE" },
- { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "increase verbosity", NULL },
- { "trace", 0, POPT_ARG_NONE, &options.tracing, 0, "enable tracing", NULL },
- { "interactive", 'i', POPT_ARG_NONE, &options.interactive, 0, "input from stdin", NULL },
- { "recursive", 'r', POPT_ARG_NONE, &options.recursive, 0, "recursive delete", NULL },
- { "modules-path", 0, POPT_ARG_STRING, &options.modules_path, 0, "modules path", "PATH" },
- { "num-searches", 0, POPT_ARG_INT, &options.num_searches, 0, "number of test searches", NULL },
- { "num-records", 0, POPT_ARG_INT, &options.num_records, 0, "number of test records", NULL },
- { "all", 'a', POPT_ARG_NONE, &options.all_records, 0, "(|(objectClass=*)(distinguishedName=*))", NULL },
- { "nosync", 0, POPT_ARG_NONE, &options.nosync, 0, "non-synchronous transactions", NULL },
- { "sorted", 'S', POPT_ARG_NONE, &options.sorted, 0, "sort attributes", NULL },
- { NULL, 'o', POPT_ARG_STRING, NULL, 'o', "ldb_connect option", "OPTION" },
- { "controls", 0, POPT_ARG_STRING, NULL, 'c', "controls", NULL },
- { "show-binary", 0, POPT_ARG_NONE, &options.show_binary, 0, "display binary LDIF", NULL },
- { "paged", 0, POPT_ARG_NONE, NULL, 'P', "use a paged search", NULL },
- { "show-deleted", 0, POPT_ARG_NONE, NULL, 'D', "show deleted objects", NULL },
- { "show-recycled", 0, POPT_ARG_NONE, NULL, 'R', "show recycled objects", NULL },
- { "show-deactivated-link", 0, POPT_ARG_NONE, NULL, 'd', "show deactivated links", NULL },
- { "reveal", 0, POPT_ARG_NONE, NULL, 'r', "reveal ldb internals", NULL },
- { "relax", 0, POPT_ARG_NONE, NULL, CMDLINE_RELAX, "pass relax control", NULL },
- { "cross-ncs", 0, POPT_ARG_NONE, NULL, 'N', "search across NC boundaries", NULL },
- { "extended-dn", 0, POPT_ARG_NONE, NULL, 'E', "show extended DNs", NULL },
- {0}
+ {
+ .longName = "url",
+ .shortName = 'H',
+ .argInfo = POPT_ARG_STRING,
+ .arg = &options.url,
+ .val = 0,
+ .descrip = "database URL",
+ .argDescrip = "URL"
+ },
+ {
+ .longName = "basedn",
+ .shortName = 'b',
+ .argInfo = POPT_ARG_STRING,
+ .arg = &options.basedn,
+ .val = 0,
+ .descrip = "base DN",
+ .argDescrip = "DN"
+ },
+ {
+ .longName = "editor",
+ .shortName = 'e',
+ .argInfo = POPT_ARG_STRING,
+ .arg = &options.editor,
+ .val = 0,
+ .descrip = "external editor",
+ .argDescrip = "PROGRAM"
+ },
+ {
+ .longName = "scope",
+ .shortName = 's',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 's',
+ .descrip = "search scope",
+ .argDescrip = "SCOPE"
+ },
+ {
+ .longName = "verbose",
+ .shortName = 'v',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'v',
+ .descrip = "increase verbosity",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "trace",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.tracing,
+ .val = 0,
+ .descrip = "enable tracing",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "interactive",
+ .shortName = 'i',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.interactive,
+ .val = 0,
+ .descrip = "input from stdin",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "recursive",
+ .shortName = 'r',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.recursive,
+ .val = 0,
+ .descrip = "recursive delete",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "modules-path",
+ .shortName = 0,
+ .argInfo = POPT_ARG_STRING,
+ .arg = &options.modules_path,
+ .val = 0,
+ .descrip = "modules path",
+ .argDescrip = "PATH"
+ },
+ {
+ .longName = "num-searches",
+ .shortName = 0,
+ .argInfo = POPT_ARG_INT,
+ .arg = &options.num_searches,
+ .val = 0,
+ .descrip = "number of test searches",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "num-records",
+ .shortName = 0,
+ .argInfo = POPT_ARG_INT,
+ .arg = &options.num_records,
+ .val = 0,
+ .descrip = "number of test records",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "all",
+ .shortName = 'a',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.all_records,
+ .val = 0,
+ .descrip = "(|(objectClass=*)(distinguishedName=*))",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "nosync",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.nosync,
+ .val = 0,
+ .descrip = "non-synchronous transactions",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "sorted",
+ .shortName = 'S',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.sorted,
+ .val = 0,
+ .descrip = "sort attributes",
+ .argDescrip = NULL
+ },
+ {
+ .longName = NULL,
+ .shortName = 'o',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'o',
+ .descrip = "ldb_connect option",
+ .argDescrip = "OPTION"
+ },
+ {
+ .longName = "controls",
+ .shortName = 0,
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'c',
+ .descrip = "controls",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "show-binary",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = &options.show_binary,
+ .val = 0,
+ .descrip = "display binary LDIF",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "paged",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'P',
+ .descrip = "use a paged search",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "show-deleted",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'D',
+ .descrip = "show deleted objects",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "show-recycled",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'R',
+ .descrip = "show recycled objects",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "show-deactivated-link",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'd',
+ .descrip = "show deactivated links",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "reveal",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'r',
+ .descrip = "reveal ldb internals",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "relax",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = CMDLINE_RELAX,
+ .descrip = "pass relax control",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "cross-ncs",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'N',
+ .descrip = "search across NC boundaries",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "extended-dn",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = 'E',
+ .descrip = "show extended DNs",
+ .argDescrip = NULL
+ },
+ POPT_TABLEEND
};
void ldb_cmdline_help(struct ldb_context *ldb, const char *cmdname, FILE *f)
diff -Nru samba-4.13.3+dfsg/lib/ldb/wscript samba-4.13.14+dfsg/lib/ldb/wscript
--- samba-4.13.3+dfsg/lib/ldb/wscript 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb/wscript 2021-11-08 11:29:14.000000000 +0000
@@ -1,7 +1,8 @@
#!/usr/bin/env python
APPNAME = 'ldb'
-VERSION = '2.2.0'
+# For Samba 4.13.x
+VERSION = '2.2.3'
import sys, os
@@ -614,6 +615,7 @@
os.mkdir(tmp_dir)
pyret = samba_utils.RUN_PYTHON_TESTS(
['tests/python/api.py',
+ 'tests/python/crash.py',
'tests/python/index.py',
'tests/python/repack.py'],
extra_env={'SELFTEST_PREFIX': test_prefix})
diff -Nru samba-4.13.3+dfsg/lib/ldb-samba/samba_extensions.c samba-4.13.14+dfsg/lib/ldb-samba/samba_extensions.c
--- samba-4.13.3+dfsg/lib/ldb-samba/samba_extensions.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/ldb-samba/samba_extensions.c 2021-11-08 11:29:14.000000000 +0000
@@ -34,15 +34,32 @@
#include "popt.h"
+static bool is_popt_table_end(const struct poptOption *o)
+{
+ if (o->longName == NULL &&
+ o->shortName =='\0' &&
+ o->arg == NULL) {
+ return true;
+ }
+
+ return false;
+}
/*
work out the length of a popt array
*/
-static unsigned calculate_popt_array_length(struct poptOption *opts)
+static size_t calculate_popt_array_length(struct poptOption *opts)
{
- unsigned i;
- struct poptOption zero_opt = { 0 };
- for (i=0; memcmp(&zero_opt, &opts[i], sizeof(zero_opt)) != 0; i++) ;
+ size_t i = 0;
+
+ for (i = 0; i < UINT32_MAX; i++) {
+ struct poptOption *o = &(opts[i]);
+
+ if (is_popt_table_end(o)) {
+ break;
+ }
+ }
+
return i;
}
@@ -61,7 +78,7 @@
{
switch (t) {
case LDB_MODULE_HOOK_CMDLINE_OPTIONS: {
- unsigned len1, len2;
+ size_t len1, len2;
struct poptOption **popt_options = ldb_module_popt_options(ldb);
struct poptOption *new_array;
diff -Nru samba-4.13.3+dfsg/lib/param/loadparm.c samba-4.13.14+dfsg/lib/param/loadparm.c
--- samba-4.13.3+dfsg/lib/param/loadparm.c 2020-12-15 07:53:45.000000000 +0000
+++ samba-4.13.14+dfsg/lib/param/loadparm.c 2021-11-08 11:29:14.000000000 +0000
@@ -3079,6 +3079,10 @@
lpcfg_do_global_parameter(
lp_ctx, "ldap max search request size", "256000");
+ lpcfg_do_global_parameter(lp_ctx,
+ "min domain uid",
+ "1000");
+
for (i = 0; parm_table[i].label; i++) {
if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) {
lp_ctx->flags[i] |= FLAG_DEFAULT;
diff -Nru samba-4.13.3+dfsg/lib/param/loadparm_server_role.c samba-4.13.14+dfsg/lib/param/loadparm_server_role.c
--- samba-4.13.3+dfsg/lib/param/loadparm_server_role.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/param/loadparm_server_role.c 2021-11-08 11:29:14.000000000 +0000
@@ -42,6 +42,7 @@
{ ROLE_DOMAIN_BDC, "ROLE_DOMAIN_BDC" },
{ ROLE_DOMAIN_PDC, "ROLE_DOMAIN_PDC" },
{ ROLE_ACTIVE_DIRECTORY_DC, "ROLE_ACTIVE_DIRECTORY_DC" },
+ { ROLE_IPA_DC, "ROLE_IPA_DC"},
{ 0, NULL }
};
@@ -140,6 +141,7 @@
case ROLE_DOMAIN_PDC:
case ROLE_DOMAIN_BDC:
case ROLE_ACTIVE_DIRECTORY_DC:
+ case ROLE_IPA_DC:
if (security == SEC_USER) {
valid = true;
}
diff -Nru samba-4.13.3+dfsg/lib/param/param_table.c samba-4.13.14+dfsg/lib/param/param_table.c
--- samba-4.13.3+dfsg/lib/param/param_table.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/param/param_table.c 2021-11-08 11:29:14.000000000 +0000
@@ -111,6 +111,7 @@
{ROLE_ACTIVE_DIRECTORY_DC, "active directory domain controller"},
{ROLE_ACTIVE_DIRECTORY_DC, "domain controller"},
{ROLE_ACTIVE_DIRECTORY_DC, "dc"},
+ {ROLE_IPA_DC, "IPA primary domain controller"},
{-1, NULL}
};
diff -Nru samba-4.13.3+dfsg/lib/param/util.c samba-4.13.14+dfsg/lib/param/util.c
--- samba-4.13.3+dfsg/lib/param/util.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/param/util.c 2021-11-08 11:29:14.000000000 +0000
@@ -255,6 +255,7 @@
case ROLE_DOMAIN_BDC:
case ROLE_DOMAIN_PDC:
case ROLE_ACTIVE_DIRECTORY_DC:
+ case ROLE_IPA_DC:
return lpcfg_workgroup(lp_ctx);
default:
return lpcfg_netbios_name(lp_ctx);
diff -Nru samba-4.13.3+dfsg/lib/replace/replace.h samba-4.13.14+dfsg/lib/replace/replace.h
--- samba-4.13.3+dfsg/lib/replace/replace.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/replace/replace.h 2021-11-08 11:29:14.000000000 +0000
@@ -977,6 +977,22 @@
bool socket_wrapper_enabled(void);
bool uid_wrapper_enabled(void);
+static inline bool _hexcharval(char c, uint8_t *val)
+{
+ if ((c >= '0') && (c <= '9')) { *val = c - '0'; return true; }
+ if ((c >= 'a') && (c <= 'f')) { *val = c - 'a' + 10; return true; }
+ if ((c >= 'A') && (c <= 'F')) { *val = c - 'A' + 10; return true; }
+ return false;
+}
+
+static inline bool hex_byte(const char *in, uint8_t *out)
+{
+ uint8_t hi=0, lo=0;
+ bool ok = _hexcharval(in[0], &hi) && _hexcharval(in[1], &lo);
+ *out = (hi<<4)+lo;
+ return ok;
+}
+
/* Needed for Solaris atomic_add_XX functions. */
#if defined(HAVE_SYS_ATOMIC_H)
#include
diff -Nru samba-4.13.3+dfsg/lib/talloc/pytalloc.c samba-4.13.14+dfsg/lib/talloc/pytalloc.c
--- samba-4.13.3+dfsg/lib/talloc/pytalloc.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/talloc/pytalloc.c 2021-09-22 06:59:39.000000000 +0000
@@ -37,7 +37,7 @@
} else {
talloc_report_full(pytalloc_get_mem_ctx(py_obj), stdout);
}
- return Py_None;
+ Py_RETURN_NONE;
}
/* enable null tracking */
@@ -45,7 +45,7 @@
PyObject *Py_UNUSED(ignored))
{
talloc_enable_null_tracking();
- return Py_None;
+ Py_RETURN_NONE;
}
/* return the number of talloc blocks */
diff -Nru samba-4.13.3+dfsg/lib/tdb/pytdb.c samba-4.13.14+dfsg/lib/tdb/pytdb.c
--- samba-4.13.3+dfsg/lib/tdb/pytdb.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/tdb/pytdb.c 2021-10-29 06:17:36.000000000 +0000
@@ -577,7 +577,7 @@
{ "add_flags", (PyCFunction)obj_add_flags, METH_VARARGS, "S.add_flags(flags) -> None" },
{ "remove_flags", (PyCFunction)obj_remove_flags, METH_VARARGS, "S.remove_flags(flags) -> None" },
#if PY_MAJOR_VERSION >= 3
- { "keys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" },
+ { "keys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.keys() -> iterator" },
#else
{ "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" },
#endif
diff -Nru samba-4.13.3+dfsg/lib/tevent/pytevent.c samba-4.13.14+dfsg/lib/tevent/pytevent.c
--- samba-4.13.3+dfsg/lib/tevent/pytevent.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/tevent/pytevent.c 2021-10-29 06:17:36.000000000 +0000
@@ -573,7 +573,7 @@
{ "add_timer", (PyCFunction)py_tevent_context_add_timer,
METH_VARARGS, "S.add_timer(next_event, handler) -> timer" },
{ "add_timer_offset", (PyCFunction)py_tevent_context_add_timer_offset,
- METH_VARARGS, "S.add_timer(offset_seconds, handler) -> timer" },
+ METH_VARARGS, "S.add_timer_offset(offset_seconds, handler) -> timer" },
{ "add_fd", (PyCFunction)py_tevent_context_add_fd,
METH_VARARGS, "S.add_fd(fd, flags, handler) -> fd" },
{0},
diff -Nru samba-4.13.3+dfsg/lib/util/memcache.c samba-4.13.14+dfsg/lib/util/memcache.c
--- samba-4.13.3+dfsg/lib/util/memcache.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/util/memcache.c 2021-08-06 12:19:57.000000000 +0000
@@ -223,14 +223,25 @@
TALLOC_FREE(e);
}
-static void memcache_trim(struct memcache *cache)
+static void memcache_trim(struct memcache *cache, struct memcache_element *e)
{
+ struct memcache_element *tail = NULL;
+
if (cache->max_size == 0) {
return;
}
- while ((cache->size > cache->max_size) && DLIST_TAIL(cache->mru)) {
- memcache_delete_element(cache, DLIST_TAIL(cache->mru));
+ for (tail = DLIST_TAIL(cache->mru);
+ (cache->size > cache->max_size) && (tail != NULL);
+ tail = DLIST_TAIL(cache->mru))
+ {
+ if (tail == e) {
+ tail = DLIST_PREV(tail);
+ if (tail == NULL) {
+ break;
+ }
+ }
+ memcache_delete_element(cache, tail);
}
}
@@ -351,7 +362,7 @@
memcpy(&mtv, cache_value.data, sizeof(mtv));
cache->size += mtv.len;
}
- memcache_trim(cache);
+ memcache_trim(cache, e);
}
void memcache_add_talloc(struct memcache *cache, enum memcache_number n,
diff -Nru samba-4.13.3+dfsg/lib/util/samba_util.h samba-4.13.14+dfsg/lib/util/samba_util.h
--- samba-4.13.3+dfsg/lib/util/samba_util.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/lib/util/samba_util.h 2021-08-09 07:20:55.000000000 +0000
@@ -478,6 +478,20 @@
*/
_PUBLIC_ bool directory_create_or_exist(const char *dname, mode_t dir_perms);
+/**
+ * @brief Try to create a specified directory and the parent directory if they
+ * don't exist.
+ *
+ * @param[in] dname The directory path to create.
+ *
+ * @param[in] dir_perms The permission of the directories.
+ *
+ * @return true on success, false otherwise.
+ */
+_PUBLIC_ bool directory_create_or_exists_recursive(
+ const char *dname,
+ mode_t dir_perms);
+
_PUBLIC_ bool directory_create_or_exist_strict(const char *dname,
uid_t uid,
mode_t dir_perms);
diff -Nru samba-4.13.3+dfsg/lib/util/tests/test_memcache.c samba-4.13.14+dfsg/lib/util/tests/test_memcache.c
--- samba-4.13.3+dfsg/lib/util/tests/test_memcache.c 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/lib/util/tests/test_memcache.c 2021-08-06 12:19:57.000000000 +0000
@@ -0,0 +1,161 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2021 Andreas Schneider
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "lib/replace/replace.h"
+#include "lib/util/talloc_stack.h"
+#include "lib/util/memcache.h"
+
+static int setup_talloc_context(void **state)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ *state = frame;
+ return 0;
+}
+
+static int teardown_talloc_context(void **state)
+{
+ TALLOC_CTX *frame = *state;
+ TALLOC_FREE(frame);
+ return 0;
+}
+
+static void torture_memcache_init(void **state)
+{
+ TALLOC_CTX *mem_ctx = *state;
+ struct memcache *cache = NULL;
+
+ cache = memcache_init(mem_ctx, 0);
+ assert_non_null(cache);
+
+ TALLOC_FREE(cache);
+
+ cache = memcache_init(mem_ctx, 10);
+ assert_non_null(cache);
+
+ TALLOC_FREE(cache);
+}
+
+static void torture_memcache_add_lookup_delete(void **state)
+{
+ TALLOC_CTX *mem_ctx = *state;
+ struct memcache *cache = NULL;
+ DATA_BLOB key1, key2;
+ char *path1 = NULL, *path2 = NULL;
+
+ cache = memcache_init(mem_ctx, 0);
+ assert_non_null(cache);
+
+ key1 = data_blob_const("key1", 4);
+ path1 = talloc_strdup(mem_ctx, "/tmp/one");
+ assert_non_null(path1);
+
+ key2 = data_blob_const("key2", 4);
+ path2 = talloc_strdup(mem_ctx, "/tmp/two");
+ assert_non_null(path1);
+
+ memcache_add_talloc(cache, GETWD_CACHE, key1, &path1);
+ assert_null(path1);
+
+ memcache_add_talloc(cache, GETWD_CACHE, key2, &path2);
+ assert_null(path2);
+
+ path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1);
+ assert_non_null(path1);
+ assert_string_equal(path1, "/tmp/one");
+
+ path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2);
+ assert_non_null(path2);
+ assert_string_equal(path2, "/tmp/two");
+
+ memcache_delete(cache, GETWD_CACHE, key1);
+ path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1);
+ assert_null(path1);
+
+ memcache_flush(cache, GETWD_CACHE);
+ path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2);
+ assert_null(path2);
+
+ TALLOC_FREE(path1);
+ TALLOC_FREE(path2);
+ TALLOC_FREE(cache);
+}
+
+static void torture_memcache_add_oversize(void **state)
+{
+ TALLOC_CTX *mem_ctx = *state;
+ struct memcache *cache = NULL;
+ DATA_BLOB key1, key2;
+ char *path1 = NULL, *path2 = NULL;
+
+ cache = memcache_init(mem_ctx, 10);
+ assert_non_null(cache);
+
+ key1 = data_blob_const("key1", 4);
+ path1 = talloc_strdup(mem_ctx, "/tmp/one");
+ assert_non_null(path1);
+
+ key2 = data_blob_const("key2", 4);
+ path2 = talloc_strdup(mem_ctx, "/tmp/two");
+ assert_non_null(path1);
+
+ memcache_add_talloc(cache, GETWD_CACHE, key1, &path1);
+ assert_null(path1);
+
+ memcache_add_talloc(cache, GETWD_CACHE, key2, &path2);
+ assert_null(path2);
+
+ path1 = memcache_lookup_talloc(cache, GETWD_CACHE, key1);
+ assert_null(path1);
+
+ path2 = memcache_lookup_talloc(cache, GETWD_CACHE, key2);
+ assert_non_null(path2);
+ assert_string_equal(path2, "/tmp/two");
+
+ TALLOC_FREE(path1);
+ TALLOC_FREE(path2);
+ TALLOC_FREE(cache);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_memcache_init),
+ cmocka_unit_test(torture_memcache_add_lookup_delete),
+ cmocka_unit_test(torture_memcache_add_oversize),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests,
+ setup_talloc_context,
+ teardown_talloc_context);
+
+ return rc;
+}
diff -Nru samba-4.13.3+dfsg/lib/util/tests/test_util.c samba-4.13.14+dfsg/lib/util/tests/test_util.c
--- samba-4.13.3+dfsg/lib/util/tests/test_util.c 2020-08-28 09:32:54.000000000 +0000
+++ samba-4.13.14+dfsg/lib/util/tests/test_util.c 2021-08-09 07:20:55.000000000 +0000
@@ -4,6 +4,7 @@
* Unit test for util.c
*
* Copyright (C) Christof Schmitt 2020
+ * Copyright (C) Andreas Schneider 2020
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,13 +20,22 @@
* along with this program; if not, see .
*/
-#include "lib/util/util.c"
+#include
+#include
+#include
+#include
#include
+#include "lib/replace/replace.h"
+#include "system/dir.h"
+
+#include "lib/util/util.c"
+
struct test_paths {
char testdir[PATH_MAX];
char none[PATH_MAX];
char dir[PATH_MAX];
+ char dir_recursive[PATH_MAX];
mode_t dir_mode;
char file[PATH_MAX];
mode_t file_mode;
@@ -59,6 +69,12 @@
ret = mkdir(paths->dir, paths->dir_mode);
assert_return_code(ret, errno);
+ strlcpy(paths->dir_recursive, testdir, sizeof(paths->dir));
+ strlcat(paths->dir_recursive, "/dir_recursive", sizeof(paths->dir));
+ paths->dir_mode = 0750;
+ ret = mkdir(paths->dir_recursive, paths->dir_mode);
+ assert_return_code(ret, errno);
+
strlcpy(paths->file, testdir, sizeof(paths->file));
strlcat(paths->file, "/file", sizeof(paths->file));
paths->file_mode = 0640;
@@ -89,15 +105,78 @@
return 0;
}
-static int group_teardown(void **state)
+static int torture_rmdirs(const char *path)
{
- struct test_paths *paths = *state;
- int ret;
+ DIR *d;
+ struct dirent *dp;
+ struct stat sb;
+ char *fname;
+
+ if ((d = opendir(path)) != NULL) {
+ while(stat(path, &sb) == 0) {
+ /* if we can remove the directory we're done */
+ if (rmdir(path) == 0) {
+ break;
+ }
+ switch (errno) {
+ case ENOTEMPTY:
+ case EEXIST:
+ case EBADF:
+ break; /* continue */
+ default:
+ closedir(d);
+ return 0;
+ }
+
+ while ((dp = readdir(d)) != NULL) {
+ size_t len;
+ /* skip '.' and '..' */
+ if (dp->d_name[0] == '.' &&
+ (dp->d_name[1] == '\0' ||
+ (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) {
+ continue;
+ }
+
+ len = strlen(path) + strlen(dp->d_name) + 2;
+ fname = malloc(len);
+ if (fname == NULL) {
+ closedir(d);
+ return -1;
+ }
+ snprintf(fname, len, "%s/%s", path, dp->d_name);
+
+ /* stat the file */
+ if (lstat(fname, &sb) != -1) {
+ if (S_ISDIR(sb.st_mode) && !S_ISLNK(sb.st_mode)) {
+ if (rmdir(fname) < 0) { /* can't be deleted */
+ if (errno == EACCES) {
+ closedir(d);
+ SAFE_FREE(fname);
+ return -1;
+ }
+ torture_rmdirs(fname);
+ }
+ } else {
+ unlink(fname);
+ }
+ } /* lstat */
+ SAFE_FREE(fname);
+ } /* readdir */
+
+ rewinddir(d);
+ }
+ } else {
+ return -1;
+ }
+ closedir(d);
return 0;
+}
- ret = rmdir(paths->dir);
- assert_return_code(ret, errno);
+static int group_teardown(void **state)
+{
+ struct test_paths *paths = *state;
+ int ret;
ret = unlink(paths->file);
assert_return_code(ret, errno);
@@ -111,7 +190,7 @@
ret = unlink(paths->symlink_file);
assert_return_code(ret, errno);
- ret = unlink(paths->testdir);
+ ret = torture_rmdirs(paths->testdir);
assert_return_code(ret, errno);
free(paths);
@@ -217,6 +296,30 @@
assert_true(S_ISLNK(sbuf.st_mode));
}
+static void test_directory_create_or_exists_recursive(void **state)
+{
+ struct test_paths *paths = *state;
+ char recursive_testdir[PATH_MAX] = {0};
+ struct stat sbuf = {0};
+ bool ok;
+ int ret;
+
+ ret = snprintf(recursive_testdir,
+ sizeof(recursive_testdir),
+ "%s/wurst/brot",
+ paths->dir_recursive);
+ assert_int_not_equal(ret, -1);
+
+ ok = directory_create_or_exists_recursive(recursive_testdir,
+ 0700);
+ assert_true(ok);
+
+ ret = lstat(recursive_testdir, &sbuf);
+ assert_return_code(ret, errno);
+ assert_int_equal(sbuf.st_mode & 0777, 0700);
+ assert_true(S_ISDIR(sbuf.st_mode));
+}
+
int main(int argc, char **argv)
{
const struct CMUnitTest tests[] = {
@@ -226,6 +329,7 @@
cmocka_unit_test(test_directory_create_or_exists_symlink_none),
cmocka_unit_test(test_directory_create_or_exists_symlink_dir),
cmocka_unit_test(test_directory_create_or_exists_symlink_file),
+ cmocka_unit_test(test_directory_create_or_exists_recursive),
};
cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
diff -Nru samba-4.13.3+dfsg/lib/util/util.c samba-4.13.14+dfsg/lib/util/util.c
--- samba-4.13.3+dfsg/lib/util/util.c 2020-08-28 09:32:54.000000000 +0000
+++ samba-4.13.14+dfsg/lib/util/util.c 2021-08-09 07:20:55.000000000 +0000
@@ -35,6 +35,7 @@
#include "debug.h"
#include "samba_util.h"
#include "lib/util/select.h"
+#include
#ifdef HAVE_SYS_PRCTL_H
#include
@@ -398,6 +399,45 @@
return true;
}
+_PUBLIC_ bool directory_create_or_exists_recursive(
+ const char *dname,
+ mode_t dir_perms)
+{
+ bool ok;
+
+ ok = directory_create_or_exist(dname, dir_perms);
+ if (!ok) {
+ if (!directory_exist(dname)) {
+ char tmp[PATH_MAX] = {0};
+ char *parent = NULL;
+ size_t n;
+
+ /* Use the null context */
+ n = strlcpy(tmp, dname, sizeof(tmp));
+ if (n < strlen(dname)) {
+ DBG_ERR("Path too long!\n");
+ return false;
+ }
+
+ parent = dirname(tmp);
+ if (parent == NULL) {
+ DBG_ERR("Failed to create dirname!\n");
+ return false;
+ }
+
+ ok = directory_create_or_exists_recursive(parent,
+ dir_perms);
+ if (!ok) {
+ return false;
+ }
+
+ ok = directory_create_or_exist(dname, dir_perms);
+ }
+ }
+
+ return ok;
+}
+
/**
* @brief Try to create a specified directory if it doesn't exist.
*
diff -Nru samba-4.13.3+dfsg/lib/util/wscript_build samba-4.13.14+dfsg/lib/util/wscript_build
--- samba-4.13.3+dfsg/lib/util/wscript_build 2020-08-28 09:32:54.000000000 +0000
+++ samba-4.13.14+dfsg/lib/util/wscript_build 2021-08-09 07:20:55.000000000 +0000
@@ -310,4 +310,10 @@
source='tests/test_util.c',
deps='cmocka replace talloc samba-util',
local_include=False,
- for_selftest=True);
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_memcache',
+ source='tests/test_memcache.c',
+ deps='cmocka replace talloc samba-util',
+ local_include=False,
+ for_selftest=True)
diff -Nru samba-4.13.3+dfsg/libcli/auth/wscript_build samba-4.13.14+dfsg/libcli/auth/wscript_build
--- samba-4.13.3+dfsg/libcli/auth/wscript_build 2020-09-22 13:43:27.000000000 +0000
+++ samba-4.13.14+dfsg/libcli/auth/wscript_build 2021-11-08 11:29:14.000000000 +0000
@@ -30,7 +30,15 @@
bld.SAMBA_SUBSYSTEM('NETLOGON_CREDS_CLI',
source='netlogon_creds_cli.c',
- deps='dbwrap util_tdb tevent-util samba-hostconfig RPC_NDR_NETLOGON NDR_NETLOGON'
+ deps='''
+ dbwrap
+ util_tdb
+ tevent-util
+ samba-hostconfig
+ gensec
+ RPC_NDR_NETLOGON
+ NDR_NETLOGON
+ '''
)
bld.SAMBA_SUBSYSTEM('PAM_ERRORS',
diff -Nru samba-4.13.3+dfsg/libcli/netlogon/netlogon.c samba-4.13.14+dfsg/libcli/netlogon/netlogon.c
--- samba-4.13.3+dfsg/libcli/netlogon/netlogon.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/libcli/netlogon/netlogon.c 2021-11-08 11:29:14.000000000 +0000
@@ -93,7 +93,7 @@
if (ndr->offset < ndr->data_size) {
TALLOC_FREE(ndr);
/*
- * We need to handle a bug in FreeIPA (at least <= 4.1.2).
+ * We need to handle a bug in IPA (at least <= 4.1.2).
*
* They include the ip address information without setting
* NETLOGON_NT_VERSION_5EX_WITH_IP, while using
diff -Nru samba-4.13.3+dfsg/libcli/smb/smb2cli_ioctl.c samba-4.13.14+dfsg/libcli/smb/smb2cli_ioctl.c
--- samba-4.13.3+dfsg/libcli/smb/smb2cli_ioctl.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/libcli/smb/smb2cli_ioctl.c 2021-09-07 07:01:16.000000000 +0000
@@ -169,15 +169,19 @@
tevent_req_data(req,
struct smb2cli_ioctl_state);
NTSTATUS status;
+ NTSTATUS error;
struct iovec *iov;
uint8_t *fixed;
- uint8_t *dyn;
- size_t dyn_len;
+ DATA_BLOB dyn_buffer = data_blob_null;
uint32_t dyn_ofs = SMB2_HDR_BODY + 0x30;
+ uint32_t input_min_offset;
uint32_t input_buffer_offset;
uint32_t input_buffer_length;
+ uint32_t input_next_offset;
+ uint32_t output_min_offset;
uint32_t output_buffer_offset;
uint32_t output_buffer_length;
+ uint32_t output_next_offset;
static const struct smb2cli_req_expected_response expected[] = {
{
.status = NT_STATUS_OK,
@@ -247,92 +251,44 @@
state->recv_iov = iov;
fixed = (uint8_t *)iov[1].iov_base;
- dyn = (uint8_t *)iov[2].iov_base;
- dyn_len = iov[2].iov_len;
+ dyn_buffer = data_blob_const((uint8_t *)iov[2].iov_base,
+ iov[2].iov_len);
input_buffer_offset = IVAL(fixed, 0x18);
input_buffer_length = IVAL(fixed, 0x1C);
output_buffer_offset = IVAL(fixed, 0x20);
output_buffer_length = IVAL(fixed, 0x24);
- if ((input_buffer_offset > 0) && (input_buffer_length > 0)) {
- uint32_t ofs;
-
- if (input_buffer_offset != dyn_ofs) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- ofs = input_buffer_length;
- ofs = NDR_ROUND(ofs, 8);
-
- if (state->max_input_length == 0) {
- /*
- * If max_input_length is 0 we ignore
- * the input_buffer_length, because
- * Windows 2008 echos the DCERPC request
- * from the requested input_buffer
- * to the response input_buffer.
- */
- input_buffer_length = 0;
- }
-
- if (input_buffer_length > dyn_len) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- if (input_buffer_length > state->max_input_length) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- state->out_input_buffer.data = dyn;
- state->out_input_buffer.length = input_buffer_length;
-
- if (ofs > dyn_len) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- dyn_ofs += ofs;
- dyn += ofs;
- dyn_len -= ofs;
+ input_min_offset = dyn_ofs;
+ input_next_offset = dyn_ofs;
+ error = smb2cli_parse_dyn_buffer(dyn_ofs,
+ dyn_buffer,
+ input_min_offset,
+ input_buffer_offset,
+ input_buffer_length,
+ state->max_input_length,
+ &input_next_offset,
+ &state->out_input_buffer);
+ if (tevent_req_nterror(req, error)) {
+ return;
}
- if ((output_buffer_offset > 0) && (output_buffer_length > 0)) {
- if (output_buffer_offset != dyn_ofs) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- if (state->max_output_length == 0) {
- /*
- * We do the same logic as for
- * max_input_length.
- */
- output_buffer_length = 0;
- }
-
- if (output_buffer_length > dyn_len) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- if (output_buffer_length > state->max_output_length) {
- tevent_req_nterror(
- req, NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
-
- state->out_output_buffer.data = dyn;
- state->out_output_buffer.length = output_buffer_length;
+ /*
+ * If output data is returned, the output offset MUST be set to
+ * InputOffset + InputCount rounded up to a multiple of 8.
+ */
+ output_min_offset = NDR_ROUND(input_next_offset, 8);
+ output_next_offset = 0; /* this variable is completely ignored */
+ error = smb2cli_parse_dyn_buffer(dyn_ofs,
+ dyn_buffer,
+ output_min_offset,
+ output_buffer_offset,
+ output_buffer_length,
+ state->max_output_length,
+ &output_next_offset,
+ &state->out_output_buffer);
+ if (tevent_req_nterror(req, error)) {
+ return;
}
state->out_valid = true;
diff -Nru samba-4.13.3+dfsg/libcli/smb/smb2cli_read.c samba-4.13.14+dfsg/libcli/smb/smb2cli_read.c
--- samba-4.13.3+dfsg/libcli/smb/smb2cli_read.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/libcli/smb/smb2cli_read.c 2021-09-07 07:01:16.000000000 +0000
@@ -90,8 +90,13 @@
tevent_req_data(req,
struct smb2cli_read_state);
NTSTATUS status;
+ NTSTATUS error;
struct iovec *iov;
+ const uint8_t dyn_ofs = SMB2_HDR_BODY + 0x10;
+ DATA_BLOB dyn_buffer = data_blob_null;
uint8_t data_offset;
+ DATA_BLOB data_buffer = data_blob_null;
+ uint32_t next_offset = 0; /* this variable is completely ignored */
static const struct smb2cli_req_expected_response expected[] = {
{
.status = STATUS_BUFFER_OVERFLOW,
@@ -117,14 +122,23 @@
data_offset = CVAL(iov[1].iov_base, 2);
state->data_length = IVAL(iov[1].iov_base, 4);
- if ((data_offset != SMB2_HDR_BODY + 16) ||
- (state->data_length > iov[2].iov_len)) {
- tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ dyn_buffer = data_blob_const((uint8_t *)iov[2].iov_base,
+ iov[2].iov_len);
+
+ error = smb2cli_parse_dyn_buffer(dyn_ofs,
+ dyn_buffer,
+ dyn_ofs, /* min_offset */
+ data_offset,
+ state->data_length,
+ dyn_buffer.length, /* max_length */
+ &next_offset,
+ &data_buffer);
+ if (tevent_req_nterror(req, error)) {
return;
}
state->recv_iov = iov;
- state->data = (uint8_t *)iov[2].iov_base;
+ state->data = data_buffer.data;
state->out_valid = true;
diff -Nru samba-4.13.3+dfsg/libcli/smb/smb2_signing.c samba-4.13.14+dfsg/libcli/smb/smb2_signing.c
--- samba-4.13.3+dfsg/libcli/smb/smb2_signing.c 2020-12-15 07:53:45.000000000 +0000
+++ samba-4.13.14+dfsg/libcli/smb/smb2_signing.c 2021-08-09 07:20:55.000000000 +0000
@@ -189,13 +189,8 @@
static const uint8_t zero_sig[16] = { 0, };
int i;
- if (count < 2) {
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (vector[0].iov_len != SMB2_HDR_BODY) {
- return NT_STATUS_INVALID_PARAMETER;
- }
+ SMB_ASSERT(count >= 2);
+ SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
hdr = (const uint8_t *)vector[0].iov_base;
diff -Nru samba-4.13.3+dfsg/libcli/smb/smb_constants.h samba-4.13.14+dfsg/libcli/smb/smb_constants.h
--- samba-4.13.3+dfsg/libcli/smb/smb_constants.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/libcli/smb/smb_constants.h 2021-09-07 07:01:16.000000000 +0000
@@ -589,6 +589,10 @@
#define FSCTL_SMBTORTURE 0x83840000
#define FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT \
(FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0000 | FSCTL_METHOD_NEITHER)
+#define FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8 \
+ (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0010 | FSCTL_METHOD_NEITHER)
+#define FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8 \
+ (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0020 | FSCTL_METHOD_NEITHER)
/*
* A few values from [MS-FSCC] 2.1.2.1 Reparse Tags
diff -Nru samba-4.13.3+dfsg/libcli/smb/smbXcli_base.c samba-4.13.14+dfsg/libcli/smb/smbXcli_base.c
--- samba-4.13.3+dfsg/libcli/smb/smbXcli_base.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/libcli/smb/smbXcli_base.c 2021-09-07 07:01:16.000000000 +0000
@@ -5420,6 +5420,18 @@
&state->out_input_buffer,
&state->out_output_buffer);
TALLOC_FREE(subreq);
+
+ /*
+ * This response must be signed correctly for
+ * these "normal" error codes to be processed.
+ * If the packet wasn't signed correctly we will get
+ * NT_STATUS_ACCESS_DENIED or NT_STATUS_HMAC_NOT_SUPPORTED,
+ * or NT_STATUS_INVALID_NETWORK_RESPONSE
+ * from smb2_signing_check_pdu().
+ *
+ * We must never ignore the above errors here.
+ */
+
if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED)) {
/*
* The response was signed, but not supported
@@ -5465,6 +5477,19 @@
tevent_req_done(req);
return;
}
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /*
+ * The response was signed, but not supported
+ *
+ * This might be returned by NetApp Ontap 7.3.7 SMB server
+ * implementations.
+ *
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14607
+ *
+ */
+ tevent_req_done(req);
+ return;
+ }
if (tevent_req_nterror(req, status)) {
return;
}
@@ -6639,3 +6664,94 @@
{
return conn->smb2.mid;
}
+
+NTSTATUS smb2cli_parse_dyn_buffer(uint32_t dyn_offset,
+ const DATA_BLOB dyn_buffer,
+ uint32_t min_offset,
+ uint32_t buffer_offset,
+ uint32_t buffer_length,
+ uint32_t max_length,
+ uint32_t *next_offset,
+ DATA_BLOB *buffer)
+{
+ uint32_t offset;
+ bool oob;
+
+ *buffer = data_blob_null;
+ *next_offset = dyn_offset;
+
+ if (buffer_offset == 0) {
+ /*
+ * If the offset is 0, we better ignore
+ * the buffer_length field.
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (buffer_length == 0) {
+ /*
+ * If the length is 0, we better ignore
+ * the buffer_offset field.
+ */
+ return NT_STATUS_OK;
+ }
+
+ if ((buffer_offset % 8) != 0) {
+ /*
+ * The offset needs to be 8 byte aligned.
+ */
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * We used to enforce buffer_offset to be
+ * an exact match of the expected minimum,
+ * but the NetApp Ontap 7.3.7 SMB server
+ * gets the padding wrong and aligns the
+ * input_buffer_offset by a value of 8.
+ *
+ * So we just enforce that the offset is
+ * not lower than the expected value.
+ */
+ SMB_ASSERT(min_offset >= dyn_offset);
+ if (buffer_offset < min_offset) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * Make [input|output]_buffer_offset relative to "dyn_buffer"
+ */
+ offset = buffer_offset - dyn_offset;
+ oob = smb_buffer_oob(dyn_buffer.length, offset, buffer_length);
+ if (oob) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * Give the caller a hint what we consumed,
+ * the caller may need to add possible padding.
+ */
+ *next_offset = buffer_offset + buffer_length;
+
+ if (max_length == 0) {
+ /*
+ * If max_input_length is 0 we ignore the
+ * input_buffer_length, because Windows 2008 echos the
+ * DCERPC request from the requested input_buffer to
+ * the response input_buffer.
+ *
+ * We just use the same logic also for max_output_length...
+ */
+ buffer_length = 0;
+ }
+
+ if (buffer_length > max_length) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *buffer = (DATA_BLOB) {
+ .data = dyn_buffer.data + offset,
+ .length = buffer_length,
+ };
+ return NT_STATUS_OK;
+}
diff -Nru samba-4.13.3+dfsg/libcli/smb/smbXcli_base.h samba-4.13.14+dfsg/libcli/smb/smbXcli_base.h
--- samba-4.13.3+dfsg/libcli/smb/smbXcli_base.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/libcli/smb/smbXcli_base.h 2021-09-07 07:01:16.000000000 +0000
@@ -390,6 +390,15 @@
void smb2cli_conn_set_mid(struct smbXcli_conn *conn, uint64_t mid);
uint64_t smb2cli_conn_get_mid(struct smbXcli_conn *conn);
+NTSTATUS smb2cli_parse_dyn_buffer(uint32_t dyn_offset,
+ const DATA_BLOB dyn_buffer,
+ uint32_t min_offset,
+ uint32_t buffer_offset,
+ uint32_t buffer_length,
+ uint32_t max_length,
+ uint32_t *next_offset,
+ DATA_BLOB *buffer);
+
struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct smbXcli_conn *conn,
diff -Nru samba-4.13.3+dfsg/libds/common/flag_mapping.c samba-4.13.14+dfsg/libds/common/flag_mapping.c
--- samba-4.13.3+dfsg/libds/common/flag_mapping.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/libds/common/flag_mapping.c 2021-11-08 11:29:14.000000000 +0000
@@ -164,3 +164,53 @@
return prim_group_rid;
}
+
+#define FLAG(x) { .name = #x, .uf = x }
+struct {
+ const char *name;
+ uint32_t uf;
+} user_account_control_name_map[] = {
+ FLAG(UF_SCRIPT),
+ FLAG(UF_ACCOUNTDISABLE),
+ FLAG(UF_00000004),
+ FLAG(UF_HOMEDIR_REQUIRED),
+ FLAG(UF_LOCKOUT),
+ FLAG(UF_PASSWD_NOTREQD),
+ FLAG(UF_PASSWD_CANT_CHANGE),
+ FLAG(UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED),
+
+ FLAG(UF_TEMP_DUPLICATE_ACCOUNT),
+ FLAG(UF_NORMAL_ACCOUNT),
+ FLAG(UF_00000400),
+ FLAG(UF_INTERDOMAIN_TRUST_ACCOUNT),
+
+ FLAG(UF_WORKSTATION_TRUST_ACCOUNT),
+ FLAG(UF_SERVER_TRUST_ACCOUNT),
+ FLAG(UF_00004000),
+ FLAG(UF_00008000),
+
+ FLAG(UF_DONT_EXPIRE_PASSWD),
+ FLAG(UF_MNS_LOGON_ACCOUNT),
+ FLAG(UF_SMARTCARD_REQUIRED),
+ FLAG(UF_TRUSTED_FOR_DELEGATION),
+
+ FLAG(UF_NOT_DELEGATED),
+ FLAG(UF_USE_DES_KEY_ONLY),
+ FLAG(UF_DONT_REQUIRE_PREAUTH),
+ FLAG(UF_PASSWORD_EXPIRED),
+ FLAG(UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION),
+ FLAG(UF_NO_AUTH_DATA_REQUIRED),
+ FLAG(UF_PARTIAL_SECRETS_ACCOUNT),
+ FLAG(UF_USE_AES_KEYS)
+};
+
+const char *dsdb_user_account_control_flag_bit_to_string(uint32_t uf)
+{
+ int i;
+ for (i=0; i < ARRAY_SIZE(user_account_control_name_map); i++) {
+ if (uf == user_account_control_name_map[i].uf) {
+ return user_account_control_name_map[i].name;
+ }
+ }
+ return NULL;
+}
diff -Nru samba-4.13.3+dfsg/libds/common/flag_mapping.h samba-4.13.14+dfsg/libds/common/flag_mapping.h
--- samba-4.13.3+dfsg/libds/common/flag_mapping.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/libds/common/flag_mapping.h 2021-11-08 11:29:14.000000000 +0000
@@ -31,5 +31,6 @@
uint32_t ds_gtype2atype(uint32_t gtype);
enum lsa_SidType ds_atype_map(uint32_t atype);
uint32_t ds_uf2prim_group_rid(uint32_t uf);
+const char *dsdb_user_account_control_flag_bit_to_string(uint32_t uf);
#endif /* __LIBDS_COMMON_FLAG_MAPPING_H__ */
diff -Nru samba-4.13.3+dfsg/libds/common/flags.h samba-4.13.14+dfsg/libds/common/flags.h
--- samba-4.13.3+dfsg/libds/common/flags.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/libds/common/flags.h 2021-11-08 11:29:14.000000000 +0000
@@ -18,6 +18,8 @@
along with this program. If not, see .
*/
+/* Please keep this list in sync with the flag_mapping.c and pydsdb.c */
+
/* User flags for "userAccountControl" */
#define UF_SCRIPT 0x00000001 /* NT or Lan Manager Login script must be executed */
#define UF_ACCOUNTDISABLE 0x00000002
@@ -53,6 +55,9 @@
#define UF_PARTIAL_SECRETS_ACCOUNT 0x04000000
#define UF_USE_AES_KEYS 0x08000000
+/* Please keep this list in sync with the flag_mapping.c and pydsdb.c */
+
+
#define UF_TRUST_ACCOUNT_MASK (\
UF_INTERDOMAIN_TRUST_ACCOUNT |\
UF_WORKSTATION_TRUST_ACCOUNT |\
diff -Nru samba-4.13.3+dfsg/libds/common/roles.h samba-4.13.14+dfsg/libds/common/roles.h
--- samba-4.13.3+dfsg/libds/common/roles.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/libds/common/roles.h 2021-11-08 11:29:14.000000000 +0000
@@ -33,6 +33,7 @@
/* not in samr.idl */
ROLE_ACTIVE_DIRECTORY_DC = 4,
+ ROLE_IPA_DC = 5,
/* To determine the role automatically, this is not a valid role */
ROLE_AUTO = 100
diff -Nru samba-4.13.3+dfsg/libgpo/pygpo.c samba-4.13.14+dfsg/libgpo/pygpo.c
--- samba-4.13.3+dfsg/libgpo/pygpo.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/libgpo/pygpo.c 2021-09-22 06:59:39.000000000 +0000
@@ -41,7 +41,7 @@
if (gpo_ptr->ATTR) \
return PyUnicode_FromString(gpo_ptr->ATTR); \
else \
- return Py_None; \
+ Py_RETURN_NONE; \
}
GPO_getter(ds_path)
GPO_getter(file_sys_path)
diff -Nru samba-4.13.3+dfsg/librpc/idl/idmap.idl samba-4.13.14+dfsg/librpc/idl/idmap.idl
--- samba-4.13.3+dfsg/librpc/idl/idmap.idl 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/idl/idmap.idl 2021-11-08 11:29:14.000000000 +0000
@@ -11,7 +11,18 @@
ID_TYPE_NOT_SPECIFIED,
ID_TYPE_UID,
ID_TYPE_GID,
- ID_TYPE_BOTH
+ ID_TYPE_BOTH,
+ /*
+ * This are internal between winbindd
+ * parent and child.
+ *
+ * It means the idmap backend/child requires a valid type_hint
+ * for wbint_Sids2UnixIDs():
+ *
+ * - ID_TYPE_UID or ID_TYPE_GID means the user/group exists
+ * - ID_TYPE_BOTH means that only the domain exist
+ */
+ ID_TYPE_WB_REQUIRE_TYPE
} id_type;
typedef [public] struct {
@@ -23,7 +34,15 @@
ID_UNKNOWN,
ID_MAPPED,
ID_UNMAPPED,
- ID_EXPIRED
+ ID_EXPIRED,
+ /*
+ * This means the idmap backend requires a valid type_hint
+ * in order to map a sid to a unix id.
+ *
+ * - ID_TYPE_UID or ID_TYPE_GID means the user/group exists
+ * - ID_TYPE_BOTH means that only the domain exist
+ */
+ ID_REQUIRE_TYPE
} id_mapping;
typedef [public] struct {
diff -Nru samba-4.13.3+dfsg/librpc/idl/krb5ccache.idl samba-4.13.14+dfsg/librpc/idl/krb5ccache.idl
--- samba-4.13.3+dfsg/librpc/idl/krb5ccache.idl 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/idl/krb5ccache.idl 2021-09-22 06:59:39.000000000 +0000
@@ -0,0 +1,115 @@
+/*
+ krb5 credentials cache (version 3 or 4)
+ specification: https://web.mit.edu/kerberos/krb5-devel/doc/formats/ccache_file_format.html
+*/
+
+#include "idl_types.h"
+
+[
+ uuid("1702b695-99ca-4f32-93e4-1e1c4d5ddb53"),
+ version(0.0),
+ pointer_default(unique),
+ helpstring("KRB5 credentials cache")
+]
+interface krb5ccache
+{
+ typedef struct {
+ uint32 name_type;
+ uint32 component_count;
+ [flag(STR_SIZE4|STR_NOTERM|STR_UTF8)] string realm;
+ [flag(STR_SIZE4|STR_NOTERM|STR_UTF8)] string components[component_count];
+ } PRINCIPAL;
+
+ typedef struct {
+ uint16 enctype;
+ DATA_BLOB data;
+ } KEYBLOCK;
+
+ typedef struct {
+ uint16 addrtype;
+ DATA_BLOB data;
+ } ADDRESS;
+
+ typedef struct {
+ uint32 count;
+ ADDRESS data[count];
+ } ADDRESSES;
+
+ typedef struct {
+ uint16 ad_type;
+ DATA_BLOB data;
+ } AUTHDATUM;
+
+ typedef struct {
+ uint32 count;
+ AUTHDATUM data[count];
+ } AUTHDATA;
+
+ typedef struct {
+ PRINCIPAL client;
+ PRINCIPAL server;
+ KEYBLOCK keyblock;
+ uint32 authtime;
+ uint32 starttime;
+ uint32 endtime;
+ uint32 renew_till;
+ uint8 is_skey;
+ uint32 ticket_flags;
+ ADDRESSES addresses;
+ AUTHDATA authdata;
+ DATA_BLOB ticket;
+ DATA_BLOB second_ticket;
+ } CREDENTIAL;
+
+ typedef struct {
+ [value(0)] int32 kdc_sec_offset;
+ [value(0)] int32 kdc_usec_offset;
+ } DELTATIME_TAG;
+
+ typedef [nodiscriminant] union {
+ [case(1)] DELTATIME_TAG deltatime_tag;
+ } FIELD;
+
+ typedef struct {
+ [value(1)] uint16 tag;
+ [subcontext(2),switch_is(tag)] FIELD field;
+ } V4TAG;
+
+ typedef struct {
+ V4TAG tag;
+ /*
+ * We should allow for more than one tag to be properly parsed, but that
+ * would require manual parsing.
+ */
+ [flag(NDR_REMAINING)] DATA_BLOB further_tags;
+ } V4TAGS;
+
+ typedef struct {
+ [subcontext(2)] V4TAGS v4tags;
+ } V4HEADER;
+
+ typedef [nodiscriminant] union {
+ /*
+ * We don't attempt to support file format versions 1 and 2 as they
+ * assume native CPU byte order, which makes no sense in PIDL.
+ */
+ [case(3)] ;
+ [case(4)] V4HEADER v4header;
+ } OPTIONAL_HEADER;
+
+ /* Public structures. */
+
+ typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+ [value(5)] uint8 pvno;
+ [value(4)] uint8 version;
+ [switch_is(version)] OPTIONAL_HEADER optional_header;
+ PRINCIPAL principal;
+ CREDENTIAL cred;
+ [flag(NDR_REMAINING)] DATA_BLOB further_creds;
+ } CCACHE;
+
+ typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+ CREDENTIAL cred;
+ [flag(NDR_REMAINING)] DATA_BLOB further_creds;
+ } MULTIPLE_CREDENTIALS;
+}
diff -Nru samba-4.13.3+dfsg/librpc/idl/krb5pac.idl samba-4.13.14+dfsg/librpc/idl/krb5pac.idl
--- samba-4.13.3+dfsg/librpc/idl/krb5pac.idl 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/idl/krb5pac.idl 2021-11-08 11:29:14.000000000 +0000
@@ -86,17 +86,45 @@
} PAC_CONSTRAINED_DELEGATION;
typedef [bitmap32bit] bitmap {
- PAC_UPN_DNS_FLAG_CONSTRUCTED = 0x00000001
+ PAC_UPN_DNS_FLAG_CONSTRUCTED = 0x00000001,
+ PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID = 0x00000002
} PAC_UPN_DNS_FLAGS;
typedef struct {
+ [value(2*strlen_m(samaccountname))] uint16 samaccountname_size;
+ [relative_short,subcontext(0),subcontext_size(samaccountname_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *samaccountname;
+ [value(ndr_size_dom_sid(objectsid, ndr->flags))] uint16 objectsid_size;
+ [relative_short,subcontext(0),subcontext_size(objectsid_size)] dom_sid *objectsid;
+ } PAC_UPN_DNS_INFO_SAM_NAME_AND_SID;
+
+ typedef [nodiscriminant] union {
+ [case(PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID)] PAC_UPN_DNS_INFO_SAM_NAME_AND_SID sam_name_and_sid;
+ [default];
+ } PAC_UPN_DNS_INFO_EX;
+
+ typedef struct {
[value(2*strlen_m(upn_name))] uint16 upn_name_size;
[relative_short,subcontext(0),subcontext_size(upn_name_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *upn_name;
[value(2*strlen_m(dns_domain_name))] uint16 dns_domain_name_size;
[relative_short,subcontext(0),subcontext_size(dns_domain_name_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *dns_domain_name;
PAC_UPN_DNS_FLAGS flags;
+ [switch_is(flags & PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID)] PAC_UPN_DNS_INFO_EX ex;
} PAC_UPN_DNS_INFO;
+ typedef [bitmap32bit] bitmap {
+ PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED = 0x00000001,
+ PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY = 0x00000002
+ } PAC_ATTRIBUTE_INFO_FLAGS;
+
+ typedef struct {
+ uint32 flags_length; /* length in bits */
+ PAC_ATTRIBUTE_INFO_FLAGS flags;
+ } PAC_ATTRIBUTES_INFO;
+
+ typedef struct {
+ dom_sid sid;
+ } PAC_REQUESTER_SID;
+
typedef [public] struct {
PAC_LOGON_INFO *info;
} PAC_LOGON_INFO_CTR;
@@ -112,7 +140,13 @@
PAC_TYPE_KDC_CHECKSUM = 7,
PAC_TYPE_LOGON_NAME = 10,
PAC_TYPE_CONSTRAINED_DELEGATION = 11,
- PAC_TYPE_UPN_DNS_INFO = 12
+ PAC_TYPE_UPN_DNS_INFO = 12,
+ PAC_TYPE_CLIENT_CLAIMS_INFO = 13,
+ PAC_TYPE_DEVICE_INFO = 14,
+ PAC_TYPE_DEVICE_CLAIMS_INFO = 15,
+ PAC_TYPE_TICKET_CHECKSUM = 16,
+ PAC_TYPE_ATTRIBUTES_INFO = 17,
+ PAC_TYPE_REQUESTER_SID = 18
} PAC_TYPE;
typedef struct {
@@ -128,6 +162,9 @@
[case(PAC_TYPE_CONSTRAINED_DELEGATION)][subcontext(0xFFFFFC01)]
PAC_CONSTRAINED_DELEGATION_CTR constrained_delegation;
[case(PAC_TYPE_UPN_DNS_INFO)] PAC_UPN_DNS_INFO upn_dns_info;
+ [case(PAC_TYPE_TICKET_CHECKSUM)] PAC_SIGNATURE_DATA ticket_checksum;
+ [case(PAC_TYPE_ATTRIBUTES_INFO)] PAC_ATTRIBUTES_INFO attributes_info;
+ [case(PAC_TYPE_REQUESTER_SID)] PAC_REQUESTER_SID requester_sid;
/* when new PAC info types are added they are supposed to be done
in such a way that they are backwards compatible with existing
servers. This makes it safe to just use a [default] for
@@ -137,7 +174,7 @@
typedef [public,nopush,nopull] struct {
PAC_TYPE type;
- [value(_ndr_size_PAC_INFO(info, type, 0))] uint32 _ndr_size;
+ [value(_ndr_size_PAC_INFO(info, type, LIBNDR_FLAG_ALIGN8))] uint32 _ndr_size;
/*
* We need to have two subcontexts to get the padding right,
* the outer subcontext uses NDR_ROUND(_ndr_size, 8), while
diff -Nru samba-4.13.3+dfsg/librpc/idl/security.idl samba-4.13.14+dfsg/librpc/idl/security.idl
--- samba-4.13.3+dfsg/librpc/idl/security.idl 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/idl/security.idl 2021-10-29 06:17:36.000000000 +0000
@@ -292,6 +292,9 @@
const string SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY = "S-1-18-1";
const string SID_SERVICE_ASSERTED_IDENTITY = "S-1-18-2";
+ const string SID_COMPOUNDED_AUTHENTICATION = "S-1-5-21-0-0-0-496";
+ const string SID_CLAIMS_VALID = "S-1-5-21-0-0-0-497";
+
/*
* http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
*/
diff -Nru samba-4.13.3+dfsg/librpc/idl/winbind.idl samba-4.13.14+dfsg/librpc/idl/winbind.idl
--- samba-4.13.3+dfsg/librpc/idl/winbind.idl 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/idl/winbind.idl 2021-11-08 11:29:14.000000000 +0000
@@ -40,7 +40,7 @@
);
typedef struct {
- id_type type;
+ id_type type_hint;
uint32 domain_index;
uint32 rid;
unixid xid;
diff -Nru samba-4.13.3+dfsg/librpc/idl/wscript_build samba-4.13.14+dfsg/librpc/idl/wscript_build
--- samba-4.13.3+dfsg/librpc/idl/wscript_build 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/idl/wscript_build 2021-09-22 06:59:39.000000000 +0000
@@ -147,6 +147,7 @@
drsblobs.idl
idmap.idl
krb5pac.idl
+ krb5ccache.idl
messaging.idl
misc.idl
nbt.idl
diff -Nru samba-4.13.3+dfsg/librpc/ndr/ndr_krb5pac.c samba-4.13.14+dfsg/librpc/ndr/ndr_krb5pac.c
--- samba-4.13.3+dfsg/librpc/ndr/ndr_krb5pac.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/ndr/ndr_krb5pac.c 2021-11-08 11:29:14.000000000 +0000
@@ -41,7 +41,7 @@
if (ndr_flags & NDR_SCALARS) {
NDR_CHECK(ndr_push_align(ndr, 4));
NDR_CHECK(ndr_push_PAC_TYPE(ndr, NDR_SCALARS, r->type));
- NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, _ndr_size_PAC_INFO(r->info,r->type,0)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, _ndr_size_PAC_INFO(r->info,r->type,LIBNDR_FLAG_ALIGN8)));
{
uint32_t _flags_save_PAC_INFO = ndr->flags;
ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
@@ -59,7 +59,7 @@
{
struct ndr_push *_ndr_info_pad;
struct ndr_push *_ndr_info;
- size_t _ndr_size = _ndr_size_PAC_INFO(r->info, r->type, 0);
+ size_t _ndr_size = _ndr_size_PAC_INFO(r->info, r->type, LIBNDR_FLAG_ALIGN8);
NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info_pad, 0, NDR_ROUND(_ndr_size, 8)));
NDR_CHECK(ndr_push_subcontext_start(_ndr_info_pad, &_ndr_info, 0, _ndr_size));
NDR_CHECK(ndr_push_set_switch_value(_ndr_info, r->info, r->type));
diff -Nru samba-4.13.3+dfsg/librpc/rpc/dcerpc_pkt_auth.c samba-4.13.14+dfsg/librpc/rpc/dcerpc_pkt_auth.c
--- samba-4.13.3+dfsg/librpc/rpc/dcerpc_pkt_auth.c 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/rpc/dcerpc_pkt_auth.c 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,500 @@
+/*
+ Unix SMB/CIFS implementation.
+ raw dcerpc operations
+
+ Copyright (C) Andrew Tridgell 2003-2005
+ Copyright (C) Jelmer Vernooij 2004-2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include
+#include "lib/util/talloc_stack.h"
+#include "lib/util/debug.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/samba_util.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_util.h"
+#include "librpc/rpc/dcerpc_pkt_auth.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "rpc_common.h"
+#include "lib/util/bitmap.h"
+#include "auth/gensec/gensec.h"
+#include "lib/util/mkdir_p.h"
+#include "lib/crypto/gnutls_helpers.h"
+#include
+
+NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
+ struct gensec_security *gensec,
+ bool check_pkt_auth_fields,
+ TALLOC_CTX *mem_ctx,
+ enum dcerpc_pkt_type ptype,
+ uint8_t required_flags,
+ uint8_t optional_flags,
+ uint8_t payload_offset,
+ DATA_BLOB *payload_and_verifier,
+ DATA_BLOB *raw_packet,
+ const struct ncacn_packet *pkt)
+{
+ NTSTATUS status;
+ struct dcerpc_auth auth;
+ uint32_t auth_length;
+
+ if (auth_state == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ status = dcerpc_verify_ncacn_packet_header(pkt, ptype,
+ payload_and_verifier->length,
+ required_flags, optional_flags);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ switch (auth_state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ break;
+
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ if (pkt->auth_length != 0) {
+ break;
+ }
+ return NT_STATUS_OK;
+ case DCERPC_AUTH_LEVEL_NONE:
+ if (pkt->auth_length != 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ return NT_STATUS_OK;
+
+ default:
+ return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
+ }
+
+ if (pkt->auth_length == 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (gensec == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
+ payload_and_verifier,
+ &auth, &auth_length, false);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (payload_and_verifier->length < auth_length) {
+ /*
+ * should be checked in dcerpc_pull_auth_trailer()
+ */
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ payload_and_verifier->length -= auth_length;
+
+ if (payload_and_verifier->length < auth.auth_pad_length) {
+ /*
+ * should be checked in dcerpc_pull_auth_trailer()
+ */
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (check_pkt_auth_fields) {
+ if (auth.auth_type != auth_state->auth_type) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (auth.auth_level != auth_state->auth_level) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (auth.auth_context_id != auth_state->auth_context_id) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ /* check signature or unseal the packet */
+ switch (auth_state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ status = gensec_unseal_packet(gensec,
+ raw_packet->data + payload_offset,
+ payload_and_verifier->length,
+ raw_packet->data,
+ raw_packet->length -
+ auth.credentials.length,
+ &auth.credentials);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_RPC_SEC_PKG_ERROR;
+ }
+ memcpy(payload_and_verifier->data,
+ raw_packet->data + payload_offset,
+ payload_and_verifier->length);
+ break;
+
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ status = gensec_check_packet(gensec,
+ payload_and_verifier->data,
+ payload_and_verifier->length,
+ raw_packet->data,
+ raw_packet->length -
+ auth.credentials.length,
+ &auth.credentials);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_RPC_SEC_PKG_ERROR;
+ }
+ break;
+
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ /* for now we ignore possible signatures here */
+ break;
+
+ default:
+ return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
+ }
+
+ /*
+ * remove the indicated amount of padding
+ *
+ * A possible overflow is checked above.
+ */
+ payload_and_verifier->length -= auth.auth_pad_length;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
+ struct gensec_security *gensec,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *raw_packet,
+ size_t sig_size,
+ uint8_t payload_offset,
+ const DATA_BLOB *payload,
+ const struct ncacn_packet *pkt)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ struct ndr_push *ndr = NULL;
+ uint32_t payload_length;
+ uint32_t whole_length;
+ DATA_BLOB blob = data_blob_null;
+ DATA_BLOB sig = data_blob_null;
+ struct dcerpc_auth _out_auth_info;
+ struct dcerpc_auth *out_auth_info = NULL;
+
+ *raw_packet = data_blob_null;
+
+ if (auth_state == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ switch (auth_state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ if (sig_size == 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (gensec == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ _out_auth_info = (struct dcerpc_auth) {
+ .auth_type = auth_state->auth_type,
+ .auth_level = auth_state->auth_level,
+ .auth_context_id = auth_state->auth_context_id,
+ };
+ out_auth_info = &_out_auth_info;
+ break;
+
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ /*
+ * TODO: let the gensec mech decide if it wants to generate a
+ * signature that might be needed for schannel...
+ */
+ if (sig_size != 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (gensec == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ break;
+
+ case DCERPC_AUTH_LEVEL_NONE:
+ if (sig_size != 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ break;
+
+ default:
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ ndr = ndr_push_init_ctx(frame);
+ if (ndr == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ if (out_auth_info != NULL) {
+ /*
+ * pad to 16 byte multiple in the payload portion of the
+ * packet. This matches what w2k3 does. Note that we can't use
+ * ndr_push_align() as that is relative to the start of the
+ * whole packet, whereas w2k8 wants it relative to the start
+ * of the stub.
+ */
+ out_auth_info->auth_pad_length =
+ DCERPC_AUTH_PAD_LENGTH(payload->length);
+ ndr_err = ndr_push_zero(ndr, out_auth_info->auth_pad_length);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ payload_length = payload->length +
+ out_auth_info->auth_pad_length;
+
+ ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
+ out_auth_info);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ whole_length = ndr->offset;
+
+ ndr_err = ndr_push_zero(ndr, sig_size);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ } else {
+ payload_length = payload->length;
+ whole_length = ndr->offset;
+ }
+
+ /* extract the whole packet as a blob */
+ blob = ndr_push_blob(ndr);
+
+ /*
+ * Setup the frag and auth length in the packet buffer.
+ * This is needed if the GENSEC mech does AEAD signing
+ * of the packet headers. The signature itself will be
+ * appended later.
+ */
+ dcerpc_set_frag_length(&blob, blob.length);
+ dcerpc_set_auth_length(&blob, sig_size);
+
+ /* sign or seal the packet */
+ switch (auth_state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ status = gensec_seal_packet(gensec,
+ frame,
+ blob.data + payload_offset,
+ payload_length,
+ blob.data,
+ whole_length,
+ &sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+ break;
+
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ status = gensec_sign_packet(gensec,
+ frame,
+ blob.data + payload_offset,
+ payload_length,
+ blob.data,
+ whole_length,
+ &sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+ break;
+
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ case DCERPC_AUTH_LEVEL_NONE:
+ break;
+
+ default:
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (sig.length != sig_size) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_RPC_SEC_PKG_ERROR;
+ }
+
+ if (sig_size != 0) {
+ memcpy(blob.data + whole_length, sig.data, sig_size);
+ }
+
+ *raw_packet = blob;
+ talloc_steal(mem_ctx, raw_packet->data);
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+#ifdef DEVELOPER
+
+/*
+ * Save valid, well-formed DCE/RPC stubs to use as a seed for
+ * ndr_fuzz_X
+ */
+void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX *mem_ctx,
+ DATA_BLOB raw_blob,
+ const char *dump_dir,
+ const char *iface_name,
+ int flags,
+ int opnum,
+ bool ndr64)
+{
+ char *fname = NULL;
+ const char *sub_dir = NULL;
+ TALLOC_CTX *temp_ctx = talloc_new(mem_ctx);
+ DATA_BLOB blob;
+ int ret, rc;
+ uint8_t digest[20];
+ DATA_BLOB digest_blob;
+ char *digest_hex;
+ uint16_t fuzz_flags = 0;
+
+ /*
+ * We want to save the 'stub' in a per-pipe subdirectory, with
+ * the ndr_fuzz_X header 4 byte header. For the sake of
+ * convenience (this is a developer only function), we mkdir
+ * -p the sub-directories when they are needed.
+ */
+
+ if (dump_dir == NULL) {
+ return;
+ }
+
+ temp_ctx = talloc_stackframe();
+
+ sub_dir = talloc_asprintf(temp_ctx, "%s/%s",
+ dump_dir,
+ iface_name);
+ if (sub_dir == NULL) {
+ talloc_free(temp_ctx);
+ return;
+ }
+ ret = mkdir_p(sub_dir, 0755);
+ if (ret && errno != EEXIST) {
+ DBG_ERR("could not create %s\n", sub_dir);
+ talloc_free(temp_ctx);
+ return;
+ }
+
+ blob.length = raw_blob.length + 4;
+ blob.data = talloc_array(sub_dir,
+ uint8_t,
+ blob.length);
+ if (blob.data == NULL) {
+ DBG_ERR("could not allocate for fuzz seeds! (%s)\n",
+ iface_name);
+ talloc_free(temp_ctx);
+ return;
+ }
+
+ if (ndr64) {
+ fuzz_flags = 4;
+ }
+ if (flags & NDR_IN) {
+ fuzz_flags |= 1;
+ } else if (flags & NDR_OUT) {
+ fuzz_flags |= 2;
+ }
+
+ SSVAL(blob.data, 0, fuzz_flags);
+ SSVAL(blob.data, 2, opnum);
+
+ memcpy(&blob.data[4],
+ raw_blob.data,
+ raw_blob.length);
+
+ /*
+ * This matches how oss-fuzz names the corpus input files, due
+ * to a preference from libFuzzer
+ */
+ rc = gnutls_hash_fast(GNUTLS_DIG_SHA1,
+ blob.data,
+ blob.length,
+ digest);
+ if (rc < 0) {
+ /*
+ * This prints a better error message, eg if SHA1 is
+ * disabled
+ */
+ NTSTATUS status = gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HASH_NOT_SUPPORTED);
+ DBG_ERR("Failed to generate SHA1 to save fuzz seed: %s",
+ nt_errstr(status));
+ talloc_free(temp_ctx);
+ return;
+ }
+
+ digest_blob.data = digest;
+ digest_blob.length = sizeof(digest);
+ digest_hex = data_blob_hex_string_lower(temp_ctx, &digest_blob);
+
+ fname = talloc_asprintf(temp_ctx, "%s/%s",
+ sub_dir,
+ digest_hex);
+ if (fname == NULL) {
+ talloc_free(temp_ctx);
+ return;
+ }
+
+ /*
+ * If this fails, it is most likely because that file already
+ * exists. This is fine, it means we already have this
+ * sample
+ */
+ file_save(fname,
+ blob.data,
+ blob.length);
+
+ talloc_free(temp_ctx);
+}
+
+#endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */
diff -Nru samba-4.13.3+dfsg/librpc/rpc/dcerpc_pkt_auth.h samba-4.13.14+dfsg/librpc/rpc/dcerpc_pkt_auth.h
--- samba-4.13.3+dfsg/librpc/rpc/dcerpc_pkt_auth.h 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/rpc/dcerpc_pkt_auth.h 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,59 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2010-2011
+ Copyright (C) Andrew Tridgell 2010-2011
+ Copyright (C) Simo Sorce 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef __LIBRPC_RPC_DCERPC_PKT_AUTH_H__
+#define __LIBRPC_RPC_DCERPC_PKT_AUTH_H__
+
+#include "replace.h"
+#include
+#include "lib/util/data_blob.h"
+#include "libcli/util/ntstatus.h"
+#include "librpc/rpc/rpc_common.h"
+#include "librpc/gen_ndr/dcerpc.h"
+
+NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
+ struct gensec_security *gensec,
+ bool check_pkt_auth_fields,
+ TALLOC_CTX *mem_ctx,
+ enum dcerpc_pkt_type ptype,
+ uint8_t required_flags,
+ uint8_t optional_flags,
+ uint8_t payload_offset,
+ DATA_BLOB *payload_and_verifier,
+ DATA_BLOB *raw_packet,
+ const struct ncacn_packet *pkt);
+NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
+ struct gensec_security *gensec,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *raw_packet,
+ size_t sig_size,
+ uint8_t payload_offset,
+ const DATA_BLOB *payload,
+ const struct ncacn_packet *pkt);
+struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream);
+NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct ncacn_packet **pkt,
+ DATA_BLOB *buffer);
+
+#endif
diff -Nru samba-4.13.3+dfsg/librpc/rpc/dcerpc_util.c samba-4.13.14+dfsg/librpc/rpc/dcerpc_util.c
--- samba-4.13.3+dfsg/librpc/rpc/dcerpc_util.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/rpc/dcerpc_util.c 2021-11-08 11:29:14.000000000 +0000
@@ -25,13 +25,10 @@
#include "lib/tsocket/tsocket.h"
#include "lib/util/tevent_ntstatus.h"
#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_util.h"
#include "librpc/gen_ndr/ndr_dcerpc.h"
#include "rpc_common.h"
#include "lib/util/bitmap.h"
-#include "auth/gensec/gensec.h"
-#include "lib/util/mkdir_p.h"
-#include "lib/crypto/gnutls_helpers.h"
-#include
/* we need to be able to get/set the fragment length without doing a full
decode */
@@ -483,340 +480,6 @@
return NT_STATUS_OK;
}
-NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
- struct gensec_security *gensec,
- TALLOC_CTX *mem_ctx,
- enum dcerpc_pkt_type ptype,
- uint8_t required_flags,
- uint8_t optional_flags,
- uint8_t payload_offset,
- DATA_BLOB *payload_and_verifier,
- DATA_BLOB *raw_packet,
- const struct ncacn_packet *pkt)
-{
- NTSTATUS status;
- struct dcerpc_auth auth;
- uint32_t auth_length;
-
- if (auth_state == NULL) {
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- status = dcerpc_verify_ncacn_packet_header(pkt, ptype,
- payload_and_verifier->length,
- required_flags, optional_flags);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- switch (auth_state->auth_level) {
- case DCERPC_AUTH_LEVEL_PRIVACY:
- case DCERPC_AUTH_LEVEL_INTEGRITY:
- case DCERPC_AUTH_LEVEL_PACKET:
- break;
-
- case DCERPC_AUTH_LEVEL_CONNECT:
- if (pkt->auth_length != 0) {
- break;
- }
- return NT_STATUS_OK;
- case DCERPC_AUTH_LEVEL_NONE:
- if (pkt->auth_length != 0) {
- return NT_STATUS_ACCESS_DENIED;
- }
- return NT_STATUS_OK;
-
- default:
- return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
- }
-
- if (pkt->auth_length == 0) {
- return NT_STATUS_RPC_PROTOCOL_ERROR;
- }
-
- if (gensec == NULL) {
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
- payload_and_verifier,
- &auth, &auth_length, false);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- if (payload_and_verifier->length < auth_length) {
- /*
- * should be checked in dcerpc_pull_auth_trailer()
- */
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- payload_and_verifier->length -= auth_length;
-
- if (payload_and_verifier->length < auth.auth_pad_length) {
- /*
- * should be checked in dcerpc_pull_auth_trailer()
- */
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- if (auth.auth_type != auth_state->auth_type) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
- if (auth.auth_level != auth_state->auth_level) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
- if (auth.auth_context_id != auth_state->auth_context_id) {
- return NT_STATUS_ACCESS_DENIED;
- }
-
- /* check signature or unseal the packet */
- switch (auth_state->auth_level) {
- case DCERPC_AUTH_LEVEL_PRIVACY:
- status = gensec_unseal_packet(gensec,
- raw_packet->data + payload_offset,
- payload_and_verifier->length,
- raw_packet->data,
- raw_packet->length -
- auth.credentials.length,
- &auth.credentials);
- if (!NT_STATUS_IS_OK(status)) {
- return NT_STATUS_RPC_SEC_PKG_ERROR;
- }
- memcpy(payload_and_verifier->data,
- raw_packet->data + payload_offset,
- payload_and_verifier->length);
- break;
-
- case DCERPC_AUTH_LEVEL_INTEGRITY:
- case DCERPC_AUTH_LEVEL_PACKET:
- status = gensec_check_packet(gensec,
- payload_and_verifier->data,
- payload_and_verifier->length,
- raw_packet->data,
- raw_packet->length -
- auth.credentials.length,
- &auth.credentials);
- if (!NT_STATUS_IS_OK(status)) {
- return NT_STATUS_RPC_SEC_PKG_ERROR;
- }
- break;
-
- case DCERPC_AUTH_LEVEL_CONNECT:
- /* for now we ignore possible signatures here */
- break;
-
- default:
- return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
- }
-
- /*
- * remove the indicated amount of padding
- *
- * A possible overflow is checked above.
- */
- payload_and_verifier->length -= auth.auth_pad_length;
-
- return NT_STATUS_OK;
-}
-
-NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
- struct gensec_security *gensec,
- TALLOC_CTX *mem_ctx,
- DATA_BLOB *raw_packet,
- size_t sig_size,
- uint8_t payload_offset,
- const DATA_BLOB *payload,
- const struct ncacn_packet *pkt)
-{
- TALLOC_CTX *frame = talloc_stackframe();
- NTSTATUS status;
- enum ndr_err_code ndr_err;
- struct ndr_push *ndr = NULL;
- uint32_t payload_length;
- uint32_t whole_length;
- DATA_BLOB blob = data_blob_null;
- DATA_BLOB sig = data_blob_null;
- struct dcerpc_auth _out_auth_info;
- struct dcerpc_auth *out_auth_info = NULL;
-
- *raw_packet = data_blob_null;
-
- if (auth_state == NULL) {
- TALLOC_FREE(frame);
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- switch (auth_state->auth_level) {
- case DCERPC_AUTH_LEVEL_PRIVACY:
- case DCERPC_AUTH_LEVEL_INTEGRITY:
- case DCERPC_AUTH_LEVEL_PACKET:
- if (sig_size == 0) {
- TALLOC_FREE(frame);
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- if (gensec == NULL) {
- TALLOC_FREE(frame);
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- _out_auth_info = (struct dcerpc_auth) {
- .auth_type = auth_state->auth_type,
- .auth_level = auth_state->auth_level,
- .auth_context_id = auth_state->auth_context_id,
- };
- out_auth_info = &_out_auth_info;
- break;
-
- case DCERPC_AUTH_LEVEL_CONNECT:
- /*
- * TODO: let the gensec mech decide if it wants to generate a
- * signature that might be needed for schannel...
- */
- if (sig_size != 0) {
- TALLOC_FREE(frame);
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- if (gensec == NULL) {
- TALLOC_FREE(frame);
- return NT_STATUS_INTERNAL_ERROR;
- }
- break;
-
- case DCERPC_AUTH_LEVEL_NONE:
- if (sig_size != 0) {
- TALLOC_FREE(frame);
- return NT_STATUS_INTERNAL_ERROR;
- }
- break;
-
- default:
- TALLOC_FREE(frame);
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- ndr = ndr_push_init_ctx(frame);
- if (ndr == NULL) {
- TALLOC_FREE(frame);
- return NT_STATUS_NO_MEMORY;
- }
-
- ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- TALLOC_FREE(frame);
- return ndr_map_error2ntstatus(ndr_err);
- }
-
- if (out_auth_info != NULL) {
- /*
- * pad to 16 byte multiple in the payload portion of the
- * packet. This matches what w2k3 does. Note that we can't use
- * ndr_push_align() as that is relative to the start of the
- * whole packet, whereas w2k8 wants it relative to the start
- * of the stub.
- */
- out_auth_info->auth_pad_length =
- DCERPC_AUTH_PAD_LENGTH(payload->length);
- ndr_err = ndr_push_zero(ndr, out_auth_info->auth_pad_length);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- TALLOC_FREE(frame);
- return ndr_map_error2ntstatus(ndr_err);
- }
-
- payload_length = payload->length +
- out_auth_info->auth_pad_length;
-
- ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
- out_auth_info);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- TALLOC_FREE(frame);
- return ndr_map_error2ntstatus(ndr_err);
- }
-
- whole_length = ndr->offset;
-
- ndr_err = ndr_push_zero(ndr, sig_size);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- TALLOC_FREE(frame);
- return ndr_map_error2ntstatus(ndr_err);
- }
- } else {
- payload_length = payload->length;
- whole_length = ndr->offset;
- }
-
- /* extract the whole packet as a blob */
- blob = ndr_push_blob(ndr);
-
- /*
- * Setup the frag and auth length in the packet buffer.
- * This is needed if the GENSEC mech does AEAD signing
- * of the packet headers. The signature itself will be
- * appended later.
- */
- dcerpc_set_frag_length(&blob, blob.length);
- dcerpc_set_auth_length(&blob, sig_size);
-
- /* sign or seal the packet */
- switch (auth_state->auth_level) {
- case DCERPC_AUTH_LEVEL_PRIVACY:
- status = gensec_seal_packet(gensec,
- frame,
- blob.data + payload_offset,
- payload_length,
- blob.data,
- whole_length,
- &sig);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(frame);
- return status;
- }
- break;
-
- case DCERPC_AUTH_LEVEL_INTEGRITY:
- case DCERPC_AUTH_LEVEL_PACKET:
- status = gensec_sign_packet(gensec,
- frame,
- blob.data + payload_offset,
- payload_length,
- blob.data,
- whole_length,
- &sig);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(frame);
- return status;
- }
- break;
-
- case DCERPC_AUTH_LEVEL_CONNECT:
- case DCERPC_AUTH_LEVEL_NONE:
- break;
-
- default:
- TALLOC_FREE(frame);
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- if (sig.length != sig_size) {
- TALLOC_FREE(frame);
- return NT_STATUS_RPC_SEC_PKG_ERROR;
- }
-
- if (sig_size != 0) {
- memcpy(blob.data + whole_length, sig.data, sig_size);
- }
-
- *raw_packet = blob;
- talloc_steal(mem_ctx, raw_packet->data);
- TALLOC_FREE(frame);
- return NT_STATUS_OK;
-}
-
struct dcerpc_read_ncacn_packet_state {
#if 0
struct {
@@ -1471,129 +1134,3 @@
free(name);
}
}
-
-
-#ifdef DEVELOPER
-
-/*
- * Save valid, well-formed DCE/RPC stubs to use as a seed for
- * ndr_fuzz_X
- */
-void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX *mem_ctx,
- DATA_BLOB raw_blob,
- const char *dump_dir,
- const char *iface_name,
- int flags,
- int opnum,
- bool ndr64)
-{
- char *fname = NULL;
- const char *sub_dir = NULL;
- TALLOC_CTX *temp_ctx = talloc_new(mem_ctx);
- DATA_BLOB blob;
- int ret, rc;
- uint8_t digest[20];
- DATA_BLOB digest_blob;
- char *digest_hex;
- uint16_t fuzz_flags = 0;
-
- /*
- * We want to save the 'stub' in a per-pipe subdirectory, with
- * the ndr_fuzz_X header 4 byte header. For the sake of
- * convenience (this is a developer only function), we mkdir
- * -p the sub-directories when they are needed.
- */
-
- if (dump_dir == NULL) {
- return;
- }
-
- temp_ctx = talloc_stackframe();
-
- sub_dir = talloc_asprintf(temp_ctx, "%s/%s",
- dump_dir,
- iface_name);
- if (sub_dir == NULL) {
- talloc_free(temp_ctx);
- return;
- }
- ret = mkdir_p(sub_dir, 0755);
- if (ret && errno != EEXIST) {
- DBG_ERR("could not create %s\n", sub_dir);
- talloc_free(temp_ctx);
- return;
- }
-
- blob.length = raw_blob.length + 4;
- blob.data = talloc_array(sub_dir,
- uint8_t,
- blob.length);
- if (blob.data == NULL) {
- DBG_ERR("could not allocate for fuzz seeds! (%s)\n",
- iface_name);
- talloc_free(temp_ctx);
- return;
- }
-
- if (ndr64) {
- fuzz_flags = 4;
- }
- if (flags & NDR_IN) {
- fuzz_flags |= 1;
- } else if (flags & NDR_OUT) {
- fuzz_flags |= 2;
- }
-
- SSVAL(blob.data, 0, fuzz_flags);
- SSVAL(blob.data, 2, opnum);
-
- memcpy(&blob.data[4],
- raw_blob.data,
- raw_blob.length);
-
- /*
- * This matches how oss-fuzz names the corpus input files, due
- * to a preference from libFuzzer
- */
- rc = gnutls_hash_fast(GNUTLS_DIG_SHA1,
- blob.data,
- blob.length,
- digest);
- if (rc < 0) {
- /*
- * This prints a better error message, eg if SHA1 is
- * disabled
- */
- NTSTATUS status = gnutls_error_to_ntstatus(rc,
- NT_STATUS_HASH_NOT_SUPPORTED);
- DBG_ERR("Failed to generate SHA1 to save fuzz seed: %s",
- nt_errstr(status));
- talloc_free(temp_ctx);
- return;
- }
-
- digest_blob.data = digest;
- digest_blob.length = sizeof(digest);
- digest_hex = data_blob_hex_string_lower(temp_ctx, &digest_blob);
-
- fname = talloc_asprintf(temp_ctx, "%s/%s",
- sub_dir,
- digest_hex);
- if (fname == NULL) {
- talloc_free(temp_ctx);
- return;
- }
-
- /*
- * If this fails, it is most likely because that file already
- * exists. This is fine, it means we already have this
- * sample
- */
- file_save(fname,
- blob.data,
- blob.length);
-
- talloc_free(temp_ctx);
-}
-
-#endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */
diff -Nru samba-4.13.3+dfsg/librpc/rpc/dcerpc_util.h samba-4.13.14+dfsg/librpc/rpc/dcerpc_util.h
--- samba-4.13.3+dfsg/librpc/rpc/dcerpc_util.h 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/rpc/dcerpc_util.h 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2010-2011
+ Copyright (C) Andrew Tridgell 2010-2011
+ Copyright (C) Simo Sorce 2010
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef __LIBRPC_RPC_DCERPC_UTIL_H__
+#define __LIBRPC_RPC_DCERPC_UTIL_H__
+
+#include "replace.h"
+#include
+#include "lib/util/data_blob.h"
+#include "librpc/rpc/rpc_common.h"
+#include "librpc/gen_ndr/dcerpc.h"
+
+void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v);
+uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob);
+void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v);
+uint16_t dcerpc_get_auth_length(const DATA_BLOB *blob);
+uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob);
+uint8_t dcerpc_get_auth_type(const DATA_BLOB *blob);
+uint8_t dcerpc_get_auth_level(const DATA_BLOB *blob);
+uint32_t dcerpc_get_auth_context_id(const DATA_BLOB *blob);
+const char *dcerpc_default_transport_endpoint(TALLOC_CTX *mem_ctx,
+ enum dcerpc_transport_t transport,
+ const struct ndr_interface_table *table);
+
+NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ struct ncacn_packet *r);
+
+/**
+* @brief Pull a dcerpc_auth structure, taking account of any auth
+* padding in the blob. For request/response packets we pass
+* the whole data blob, so auth_data_only must be set to false
+* as the blob contains data+pad+auth and no just pad+auth.
+*
+* @param pkt - The ncacn_packet strcuture
+* @param mem_ctx - The mem_ctx used to allocate dcerpc_auth elements
+* @param pkt_trailer - The packet trailer data, usually the trailing
+* auth_info blob, but in the request/response case
+* this is the stub_and_verifier blob.
+* @param auth - A preallocated dcerpc_auth *empty* structure
+* @param auth_length - The length of the auth trail, sum of auth header
+* lenght and pkt->auth_length
+* @param auth_data_only - Whether the pkt_trailer includes only the auth_blob
+* (+ padding) or also other data.
+*
+* @return - A NTSTATUS error code.
+*/
+NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *pkt_trailer,
+ struct dcerpc_auth *auth,
+ uint32_t *auth_length,
+ bool auth_data_only);
+NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
+ enum dcerpc_pkt_type ptype,
+ size_t max_auth_info,
+ uint8_t required_flags,
+ uint8_t optional_flags);
+struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream);
+NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct ncacn_packet **pkt,
+ DATA_BLOB *buffer);
+
+#endif
diff -Nru samba-4.13.3+dfsg/librpc/rpc/dcesrv_auth.c samba-4.13.14+dfsg/librpc/rpc/dcesrv_auth.c
--- samba-4.13.3+dfsg/librpc/rpc/dcesrv_auth.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/rpc/dcesrv_auth.c 2021-11-08 11:29:14.000000000 +0000
@@ -23,6 +23,8 @@
#include "includes.h"
#include "librpc/rpc/dcesrv_core.h"
#include "librpc/rpc/dcesrv_core_proto.h"
+#include "librpc/rpc/dcerpc_util.h"
+#include "librpc/rpc/dcerpc_pkt_auth.h"
#include "librpc/gen_ndr/ndr_dcerpc.h"
#include "auth/credentials/credentials.h"
#include "auth/gensec/gensec.h"
@@ -436,6 +438,10 @@
return false;
}
+ if (auth->auth_invalid) {
+ return false;
+ }
+
/* We can't work without an existing gensec state */
if (auth->gensec_security == NULL) {
return false;
@@ -522,6 +528,10 @@
return false;
}
+ if (auth->auth_invalid) {
+ return false;
+ }
+
if (call->in_auth_info.auth_type != auth->auth_type) {
return false;
}
@@ -588,6 +598,7 @@
.auth_level = auth->auth_level,
.auth_context_id = auth->auth_context_id,
};
+ bool check_pkt_auth_fields;
NTSTATUS status;
if (!auth->auth_started) {
@@ -603,8 +614,27 @@
return false;
}
+ if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
+ /*
+ * The caller most likely checked this
+ * already, but we better double check.
+ */
+ check_pkt_auth_fields = true;
+ } else {
+ /*
+ * The caller already found first fragment
+ * and is passing the auth_state of it.
+ * A server is supposed to use the
+ * setting of the first fragment and
+ * completely ignore the values
+ * on the remaining fragments
+ */
+ check_pkt_auth_fields = false;
+ }
+
status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
auth->gensec_security,
+ check_pkt_auth_fields,
call,
pkt->ptype,
required_flags,
diff -Nru samba-4.13.3+dfsg/librpc/rpc/dcesrv_core.c samba-4.13.14+dfsg/librpc/rpc/dcesrv_core.c
--- samba-4.13.3+dfsg/librpc/rpc/dcesrv_core.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/rpc/dcesrv_core.c 2021-11-08 11:29:14.000000000 +0000
@@ -24,6 +24,7 @@
#include "includes.h"
#include "librpc/rpc/dcesrv_core.h"
#include "librpc/rpc/dcesrv_core_proto.h"
+#include "librpc/rpc/dcerpc_util.h"
#include "librpc/gen_ndr/auth.h"
#include "auth/gensec/gensec.h"
#include "lib/util/dlinklist.h"
@@ -702,19 +703,41 @@
return NT_STATUS_OK;
}
-static NTSTATUS dcesrv_fault_disconnect(struct dcesrv_call_state *call,
- uint32_t fault_code)
-{
+static NTSTATUS _dcesrv_fault_disconnect_flags(struct dcesrv_call_state *call,
+ uint32_t fault_code,
+ uint8_t extra_flags,
+ const char *func,
+ const char *location)
+{
+ const char *reason = NULL;
+
+ reason = talloc_asprintf(call, "%s:%s: fault=%u (%s) flags=0x%x",
+ func, location,
+ fault_code,
+ dcerpc_errstr(call, fault_code),
+ extra_flags);
+ if (reason == NULL) {
+ reason = location;
+ }
+
/*
* We add the call to the pending_call_list
* in order to defer the termination.
*/
- dcesrv_call_disconnect_after(call, "dcesrv_fault_disconnect");
- return dcesrv_fault_with_flags(call, fault_code,
- DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
+ dcesrv_call_disconnect_after(call, reason);
+
+ return dcesrv_fault_with_flags(call, fault_code, extra_flags);
}
+#define dcesrv_fault_disconnect(call, fault_code) \
+ _dcesrv_fault_disconnect_flags(call, fault_code, \
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE, \
+ __func__, __location__)
+#define dcesrv_fault_disconnect0(call, fault_code) \
+ _dcesrv_fault_disconnect_flags(call, fault_code, 0, \
+ __func__, __location__)
+
static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
{
DLIST_REMOVE(c->conn->contexts, c);
@@ -1780,6 +1803,10 @@
struct ndr_pull *pull;
NTSTATUS status;
+ if (auth->auth_invalid) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
if (!auth->auth_finished) {
return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
}
@@ -1943,6 +1970,7 @@
enum dcerpc_AuthType auth_type = 0;
enum dcerpc_AuthLevel auth_level = 0;
uint32_t auth_context_id = 0;
+ bool auth_invalid = false;
call = talloc_zero(dce_conn, struct dcesrv_call_state);
if (!call) {
@@ -1974,12 +2002,16 @@
if (call->auth_state == NULL) {
struct dcesrv_auth *a = NULL;
+ bool check_type_level = true;
auth_type = dcerpc_get_auth_type(&blob);
auth_level = dcerpc_get_auth_level(&blob);
auth_context_id = dcerpc_get_auth_context_id(&blob);
if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
+ if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
+ check_type_level = false;
+ }
dce_conn->default_auth_level_connect = NULL;
if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
dce_conn->got_explicit_auth_level_connect = true;
@@ -1989,14 +2021,19 @@
for (a = dce_conn->auth_states; a != NULL; a = a->next) {
num_auth_ctx++;
- if (a->auth_type != auth_type) {
+ if (a->auth_context_id != auth_context_id) {
continue;
}
- if (a->auth_finished && a->auth_level != auth_level) {
- continue;
+
+ if (a->auth_type != auth_type) {
+ auth_invalid = true;
}
- if (a->auth_context_id != auth_context_id) {
- continue;
+ if (a->auth_level != auth_level) {
+ auth_invalid = true;
+ }
+
+ if (check_type_level && auth_invalid) {
+ a->auth_invalid = true;
}
DLIST_PROMOTE(dce_conn->auth_states, a);
@@ -2023,6 +2060,7 @@
/*
* This can never be valid.
*/
+ auth_invalid = true;
a->auth_invalid = true;
}
call->auth_state = a;
@@ -2075,10 +2113,7 @@
* Note that we don't check against the negotiated
* max_recv_frag, but a hard coded value.
*/
- dcesrv_call_disconnect_after(call,
- "dcesrv_auth_request - frag_length too large");
- return dcesrv_fault(call,
- DCERPC_NCA_S_PROTO_ERROR);
+ return dcesrv_fault_disconnect0(call, DCERPC_NCA_S_PROTO_ERROR);
}
if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
@@ -2088,15 +2123,24 @@
* if DCERPC_PFC_FLAG_CONC_MPX was negotiated.
*/
if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
- dcesrv_call_disconnect_after(call,
- "dcesrv_auth_request - "
- "existing pending call without CONN_MPX");
- return dcesrv_fault(call,
+ return dcesrv_fault_disconnect0(call,
DCERPC_NCA_S_PROTO_ERROR);
}
}
/* only one request is possible in the fragmented list */
if (dce_conn->incoming_fragmented_call_list != NULL) {
+ call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
+
+ existing = dcesrv_find_fragmented_call(dce_conn,
+ call->pkt.call_id);
+ if (existing != NULL && call->auth_state != existing->auth_state) {
+ call->context = dcesrv_find_context(call->conn,
+ call->pkt.u.request.context_id);
+
+ if (call->pkt.auth_length != 0 && existing->context == call->context) {
+ call->fault_code = DCERPC_FAULT_SEC_PKG_ERROR;
+ }
+ }
if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
/*
* Without DCERPC_PFC_FLAG_CONC_MPX
@@ -2106,14 +2150,14 @@
* This is important to get the
* call_id and context_id right.
*/
+ dce_conn->incoming_fragmented_call_list->fault_code = call->fault_code;
TALLOC_FREE(call);
call = dce_conn->incoming_fragmented_call_list;
}
- dcesrv_call_disconnect_after(call,
- "dcesrv_auth_request - "
- "existing fragmented call");
- return dcesrv_fault(call,
- DCERPC_NCA_S_PROTO_ERROR);
+ if (existing != NULL) {
+ call->context = existing->context;
+ }
+ return dcesrv_fault_disconnect0(call, call->fault_code);
}
if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_PENDING_CANCEL) {
return dcesrv_fault_disconnect(call,
@@ -2126,20 +2170,43 @@
DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
}
} else {
- const struct dcerpc_request *nr = &call->pkt.u.request;
- const struct dcerpc_request *er = NULL;
int cmp;
existing = dcesrv_find_fragmented_call(dce_conn,
call->pkt.call_id);
if (existing == NULL) {
- dcesrv_call_disconnect_after(call,
- "dcesrv_auth_request - "
- "no existing fragmented call");
- return dcesrv_fault(call,
+ if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
+ /*
+ * Without DCERPC_PFC_FLAG_CONC_MPX
+ * we need to return the FAULT on the
+ * already existing call.
+ *
+ * This is important to get the
+ * call_id and context_id right.
+ */
+ if (dce_conn->incoming_fragmented_call_list != NULL) {
+ TALLOC_FREE(call);
+ call = dce_conn->incoming_fragmented_call_list;
+ }
+ return dcesrv_fault_disconnect0(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+ if (dce_conn->incoming_fragmented_call_list != NULL) {
+ return dcesrv_fault_disconnect0(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+ call->context = dcesrv_find_context(call->conn,
+ call->pkt.u.request.context_id);
+ if (call->context == NULL) {
+ return dcesrv_fault_with_flags(call, DCERPC_NCA_S_UNKNOWN_IF,
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
+ }
+ if (auth_invalid) {
+ return dcesrv_fault_disconnect0(call,
+ DCERPC_FAULT_ACCESS_DENIED);
+ }
+ return dcesrv_fault_disconnect0(call,
DCERPC_NCA_S_PROTO_ERROR);
}
- er = &existing->pkt.u.request;
if (call->pkt.ptype != existing->pkt.ptype) {
/* trying to play silly buggers are we? */
@@ -2152,14 +2219,8 @@
return dcesrv_fault_disconnect(existing,
DCERPC_NCA_S_PROTO_ERROR);
}
- if (nr->context_id != er->context_id) {
- return dcesrv_fault_disconnect(existing,
- DCERPC_NCA_S_PROTO_ERROR);
- }
- if (nr->opnum != er->opnum) {
- return dcesrv_fault_disconnect(existing,
- DCERPC_NCA_S_PROTO_ERROR);
- }
+ call->auth_state = existing->auth_state;
+ call->context = existing->context;
}
}
@@ -2189,12 +2250,10 @@
* here, because we don't want to set
* DCERPC_PFC_FLAG_DID_NOT_EXECUTE
*/
- dcesrv_call_disconnect_after(call,
- "dcesrv_auth_request - failed");
if (call->fault_code == 0) {
call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
}
- return dcesrv_fault(call, call->fault_code);
+ return dcesrv_fault_disconnect0(call, call->fault_code);
}
}
@@ -2211,20 +2270,17 @@
*/
available = dce_conn->max_total_request_size;
if (er->stub_and_verifier.length > available) {
- dcesrv_call_disconnect_after(existing,
- "dcesrv_auth_request - existing payload too large");
- return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED);
+ return dcesrv_fault_disconnect0(existing,
+ DCERPC_FAULT_ACCESS_DENIED);
}
available -= er->stub_and_verifier.length;
if (nr->alloc_hint > available) {
- dcesrv_call_disconnect_after(existing,
- "dcesrv_auth_request - alloc hint too large");
- return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED);
+ return dcesrv_fault_disconnect0(existing,
+ DCERPC_FAULT_ACCESS_DENIED);
}
if (nr->stub_and_verifier.length > available) {
- dcesrv_call_disconnect_after(existing,
- "dcesrv_auth_request - new payload too large");
- return dcesrv_fault(existing, DCERPC_FAULT_ACCESS_DENIED);
+ return dcesrv_fault_disconnect0(existing,
+ DCERPC_FAULT_ACCESS_DENIED);
}
alloc_hint = er->stub_and_verifier.length + nr->alloc_hint;
/* allocate at least 1 byte */
@@ -2263,9 +2319,8 @@
* Up to 4 MByte are allowed by all fragments
*/
if (call->pkt.u.request.alloc_hint > dce_conn->max_total_request_size) {
- dcesrv_call_disconnect_after(call,
- "dcesrv_auth_request - initial alloc hint too large");
- return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
+ return dcesrv_fault_disconnect0(call,
+ DCERPC_FAULT_ACCESS_DENIED);
}
dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
return NT_STATUS_OK;
diff -Nru samba-4.13.3+dfsg/librpc/rpc/dcesrv_reply.c samba-4.13.14+dfsg/librpc/rpc/dcesrv_reply.c
--- samba-4.13.3+dfsg/librpc/rpc/dcesrv_reply.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/rpc/dcesrv_reply.c 2021-11-08 11:29:14.000000000 +0000
@@ -23,6 +23,7 @@
#include "includes.h"
#include "librpc/rpc/dcesrv_core.h"
#include "librpc/rpc/dcesrv_core_proto.h"
+#include "librpc/rpc/dcerpc_util.h"
#include "auth/gensec/gensec.h"
#include "lib/util/dlinklist.h"
#include "param/param.h"
diff -Nru samba-4.13.3+dfsg/librpc/rpc/rpc_common.h samba-4.13.14+dfsg/librpc/rpc/rpc_common.h
--- samba-4.13.3+dfsg/librpc/rpc/rpc_common.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/rpc/rpc_common.h 2021-11-08 11:29:14.000000000 +0000
@@ -163,80 +163,6 @@
enum dcerpc_transport_t dcerpc_transport_by_name(const char *name);
enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower);
-/* The following definitions come from ../librpc/rpc/dcerpc_util.c */
-
-void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v);
-uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob);
-void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v);
-uint16_t dcerpc_get_auth_length(const DATA_BLOB *blob);
-uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob);
-uint8_t dcerpc_get_auth_type(const DATA_BLOB *blob);
-uint8_t dcerpc_get_auth_level(const DATA_BLOB *blob);
-uint32_t dcerpc_get_auth_context_id(const DATA_BLOB *blob);
-const char *dcerpc_default_transport_endpoint(TALLOC_CTX *mem_ctx,
- enum dcerpc_transport_t transport,
- const struct ndr_interface_table *table);
-
-NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
- const DATA_BLOB *blob,
- struct ncacn_packet *r);
-
-/**
-* @brief Pull a dcerpc_auth structure, taking account of any auth
-* padding in the blob. For request/response packets we pass
-* the whole data blob, so auth_data_only must be set to false
-* as the blob contains data+pad+auth and no just pad+auth.
-*
-* @param pkt - The ncacn_packet strcuture
-* @param mem_ctx - The mem_ctx used to allocate dcerpc_auth elements
-* @param pkt_trailer - The packet trailer data, usually the trailing
-* auth_info blob, but in the request/response case
-* this is the stub_and_verifier blob.
-* @param auth - A preallocated dcerpc_auth *empty* structure
-* @param auth_length - The length of the auth trail, sum of auth header
-* lenght and pkt->auth_length
-* @param auth_data_only - Whether the pkt_trailer includes only the auth_blob
-* (+ padding) or also other data.
-*
-* @return - A NTSTATUS error code.
-*/
-NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
- TALLOC_CTX *mem_ctx,
- const DATA_BLOB *pkt_trailer,
- struct dcerpc_auth *auth,
- uint32_t *auth_length,
- bool auth_data_only);
-NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
- enum dcerpc_pkt_type ptype,
- size_t max_auth_info,
- uint8_t required_flags,
- uint8_t optional_flags);
-NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
- struct gensec_security *gensec,
- TALLOC_CTX *mem_ctx,
- enum dcerpc_pkt_type ptype,
- uint8_t required_flags,
- uint8_t optional_flags,
- uint8_t payload_offset,
- DATA_BLOB *payload_and_verifier,
- DATA_BLOB *raw_packet,
- const struct ncacn_packet *pkt);
-NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
- struct gensec_security *gensec,
- TALLOC_CTX *mem_ctx,
- DATA_BLOB *raw_packet,
- size_t sig_size,
- uint8_t payload_offset,
- const DATA_BLOB *payload,
- const struct ncacn_packet *pkt);
-struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct tstream_context *stream);
-NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx,
- struct ncacn_packet **pkt,
- DATA_BLOB *buffer);
-
/* The following definitions come from ../librpc/rpc/binding_handle.c */
struct dcerpc_binding_handle_ops {
diff -Nru samba-4.13.3+dfsg/librpc/wscript_build samba-4.13.14+dfsg/librpc/wscript_build
--- samba-4.13.3+dfsg/librpc/wscript_build 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/librpc/wscript_build 2021-11-08 11:29:14.000000000 +0000
@@ -374,6 +374,11 @@
vnum='0.0.1'
)
+bld.SAMBA_SUBSYSTEM('NDR_KRB5CCACHE',
+ source='gen_ndr/ndr_krb5ccache.c',
+ deps='ndr NDR_COMPRESSION NDR_SECURITY ndr-standard asn1util'
+ )
+
bld.SAMBA_LIBRARY('ndr-standard',
source='',
vnum='0.0.1',
@@ -616,7 +621,8 @@
source=[],
deps='''NDR_DRSBLOBS NDR_DRSUAPI NDR_IDMAP NDR_NTLMSSP NDR_NEGOEX NDR_SCHANNEL NDR_MGMT
NDR_DNSSERVER NDR_EPMAPPER NDR_XATTR NDR_UNIXINFO NDR_NAMED_PIPE_AUTH NDR_DCOM
- NDR_NTPRINTING NDR_FSRVP NDR_WITNESS NDR_MDSSVC NDR_OPEN_FILES NDR_SMBXSRV''',
+ NDR_NTPRINTING NDR_FSRVP NDR_WITNESS NDR_MDSSVC NDR_OPEN_FILES NDR_SMBXSRV
+ NDR_KRB5CCACHE''',
private_library=True,
grouping_library=True
)
@@ -649,12 +655,24 @@
)
bld.SAMBA_LIBRARY('dcerpc-binding',
- source='rpc/dcerpc_error.c rpc/binding.c rpc/dcerpc_util.c rpc/binding_handle.c',
- deps='ndr tevent NDR_DCERPC LIBTSOCKET tevent-util gensec',
+ source='''
+ rpc/dcerpc_error.c
+ rpc/binding.c
+ rpc/dcerpc_util.c
+ rpc/binding_handle.c
+ ''',
+ deps='ndr tevent NDR_DCERPC LIBTSOCKET tevent-util',
pc_files=[],
public_headers='rpc/rpc_common.h',
vnum='0.0.1')
+bld.SAMBA_LIBRARY('dcerpc-pkt-auth',
+ private_library=True,
+ source='''
+ rpc/dcerpc_pkt_auth.c
+ ''',
+ deps='dcerpc-binding gensec')
+
bld.SAMBA_LIBRARY('dcerpc-server-core',
source='''
rpc/dcesrv_core.c
@@ -663,7 +681,14 @@
rpc/dcesrv_reply.c
rpc/dcesrv_handles.c
''',
- deps='ndr dcerpc-binding samba-util-core gnutls GNUTLS_HELPERS',
+ deps='''
+ ndr
+ dcerpc-binding
+ samba-util-core
+ gnutls
+ GNUTLS_HELPERS
+ dcerpc-pkt-auth
+ ''',
pc_files=[],
public_headers='rpc/dcesrv_core.h',
autoproto='rpc/dcesrv_core_proto.h',
diff -Nru samba-4.13.3+dfsg/Makefile samba-4.13.14+dfsg/Makefile
--- samba-4.13.3+dfsg/Makefile 2020-07-09 09:33:55.000000000 +0000
+++ samba-4.13.14+dfsg/Makefile 2021-08-06 12:19:57.000000000 +0000
@@ -15,6 +15,9 @@
test:
$(WAF) test $(TEST_OPTIONS)
+testonly:
+ $(WAF) testonly $(TEST_OPTIONS)
+
perftest:
$(WAF) test --perf-test $(TEST_OPTIONS)
diff -Nru samba-4.13.3+dfsg/pidl/lib/Parse/Pidl/Samba4/NDR/ServerCompat.pm samba-4.13.14+dfsg/pidl/lib/Parse/Pidl/Samba4/NDR/ServerCompat.pm
--- samba-4.13.3+dfsg/pidl/lib/Parse/Pidl/Samba4/NDR/ServerCompat.pm 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/pidl/lib/Parse/Pidl/Samba4/NDR/ServerCompat.pm 2021-08-06 12:19:57.000000000 +0000
@@ -299,6 +299,7 @@
$self->pidl("/* Update pipes struct opnum */");
$self->pidl("p->opnum = opnum;");
$self->pidl("p->dce_call = dce_call;");
+ $self->pidl("p->mem_ctx = mem_ctx;");
$self->pidl("/* Update pipes struct session info */");
$self->pidl("pipe_session_info = p->session_info;");
$self->pidl("p->session_info = dce_call->auth_state->session_info;");
@@ -344,6 +345,7 @@
$self->pidl("");
$self->pidl("p->dce_call = NULL;");
+ $self->pidl("p->mem_ctx = NULL;");
$self->pidl("/* Restore session info */");
$self->pidl("p->session_info = pipe_session_info;");
$self->pidl("p->auth.auth_type = 0;");
diff -Nru samba-4.13.3+dfsg/python/samba/common.py samba-4.13.14+dfsg/python/samba/common.py
--- samba-4.13.3+dfsg/python/samba/common.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/common.py 2021-10-29 06:17:36.000000000 +0000
@@ -16,13 +16,6 @@
# along with this program. If not, see .
#
-
-import ldb
-from samba import dsdb
-from samba.ndr import ndr_pack
-from samba.dcerpc import misc
-import binascii
-
from samba.compat import PY3
@@ -74,75 +67,3 @@
return str(ivalue)
-class dsdb_Dn(object):
- '''a class for binary DN'''
-
- def __init__(self, samdb, dnstring, syntax_oid=None):
- '''create a dsdb_Dn'''
- if syntax_oid is None:
- # auto-detect based on string
- if dnstring.startswith("B:"):
- syntax_oid = dsdb.DSDB_SYNTAX_BINARY_DN
- elif dnstring.startswith("S:"):
- syntax_oid = dsdb.DSDB_SYNTAX_STRING_DN
- else:
- syntax_oid = dsdb.DSDB_SYNTAX_OR_NAME
- if syntax_oid in [dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_STRING_DN]:
- # it is a binary DN
- colons = dnstring.split(':')
- if len(colons) < 4:
- raise RuntimeError("Invalid DN %s" % dnstring)
- prefix_len = 4 + len(colons[1]) + int(colons[1])
- self.prefix = dnstring[0:prefix_len]
- self.binary = self.prefix[3 + len(colons[1]):-1]
- self.dnstring = dnstring[prefix_len:]
- else:
- self.dnstring = dnstring
- self.prefix = ''
- self.binary = ''
- self.dn = ldb.Dn(samdb, self.dnstring)
-
- def __str__(self):
- return self.prefix + str(self.dn.extended_str(mode=1))
-
- def __cmp__(self, other):
- ''' compare dsdb_Dn values similar to parsed_dn_compare()'''
- dn1 = self
- dn2 = other
- guid1 = dn1.dn.get_extended_component("GUID")
- guid2 = dn2.dn.get_extended_component("GUID")
-
- v = cmp(guid1, guid2)
- if v != 0:
- return v
- v = cmp(dn1.binary, dn2.binary)
- return v
-
- # In Python3, __cmp__ is replaced by these 6 methods
- def __eq__(self, other):
- return self.__cmp__(other) == 0
-
- def __ne__(self, other):
- return self.__cmp__(other) != 0
-
- def __lt__(self, other):
- return self.__cmp__(other) < 0
-
- def __le__(self, other):
- return self.__cmp__(other) <= 0
-
- def __gt__(self, other):
- return self.__cmp__(other) > 0
-
- def __ge__(self, other):
- return self.__cmp__(other) >= 0
-
- def get_binary_integer(self):
- '''return binary part of a dsdb_Dn as an integer, or None'''
- if self.prefix == '':
- return None
- return int(self.binary, 16)
-
- def get_bytes(self):
- '''return binary as a byte string'''
- return binascii.unhexlify(self.binary)
diff -Nru samba-4.13.3+dfsg/python/samba/dbchecker.py samba-4.13.14+dfsg/python/samba/dbchecker.py
--- samba-4.13.3+dfsg/python/samba/dbchecker.py 2020-08-14 08:48:07.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/dbchecker.py 2021-10-29 06:17:36.000000000 +0000
@@ -28,7 +28,7 @@
from samba.dcerpc import drsuapi
from samba.ndr import ndr_unpack, ndr_pack
from samba.dcerpc import drsblobs
-from samba.common import dsdb_Dn
+from samba.samdb import dsdb_Dn
from samba.dcerpc import security
from samba.descriptor import get_wellknown_sds, get_diff_sds
from samba.auth import system_session, admin_session
@@ -1819,6 +1819,11 @@
# old static provision dumps
return False
+ if dn in self.deleted_objects_containers:
+ # The Deleted Objects container will look like an expired
+ # tombstone
+ return False
+
repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, repl_val)
isDeleted = self.find_repl_attid(repl, drsuapi.DRSUAPI_ATTID_isDeleted)
@@ -1832,7 +1837,25 @@
if delta <= tombstone_delta:
return False
- self.report("SKIPING: object %s is an expired tombstone" % dn)
+ expunge_time = delete_time + tombstone_delta
+
+ delta_days = delta / (24 * 60 * 60)
+
+ if delta_days <= 2:
+ self.report("SKIPPING additional checks on object "
+ "%s which very recently "
+ "became an expired tombstone (normal)" % dn)
+ self.report("INFO: it is expected this will be expunged "
+ "by the next daily task some time after %s, "
+ "%d hours ago"
+ % (time.ctime(expunge_time), delta // (60 * 60)))
+ else:
+ self.report("SKIPPING: object %s is an expired tombstone" % dn)
+ self.report("INFO: it was expected this object would have "
+ "been expunged soon after"
+ "%s, %d days ago"
+ % (time.ctime(expunge_time), delta_days))
+
self.report("isDeleted: attid=0x%08x version=%d invocation=%s usn=%s (local=%s) at %s" % (
isDeleted.attid,
isDeleted.version,
diff -Nru samba-4.13.3+dfsg/python/samba/__init__.py samba-4.13.14+dfsg/python/samba/__init__.py
--- samba-4.13.3+dfsg/python/samba/__init__.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/__init__.py 2021-10-29 06:17:36.000000000 +0000
@@ -218,7 +218,8 @@
:param ldif_path: Path to LDIF file.
"""
- self.add_ldif(open(ldif_path, 'r').read())
+ with open(ldif_path, 'r') as ldif_file:
+ self.add_ldif(ldif_file.read())
def add_ldif(self, ldif, controls=None):
"""Add data based on a LDIF string.
@@ -280,10 +281,11 @@
:param file_name: File to be read (typically from setup directory)
param subst_vars: Optional variables to subsitute in the file.
"""
- data = open(file_name, 'r', encoding="utf-8").read()
- if subst_vars is not None:
- data = substitute_var(data, subst_vars)
- check_all_substituted(data)
+ with open(file_name, 'r', encoding="utf-8") as data_file:
+ data = data_file.read()
+ if subst_vars is not None:
+ data = substitute_var(data, subst_vars)
+ check_all_substituted(data)
return data
diff -Nru samba-4.13.3+dfsg/python/samba/join.py samba-4.13.14+dfsg/python/samba/join.py
--- samba-4.13.3+dfsg/python/samba/join.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/join.py 2021-10-29 06:17:36.000000000 +0000
@@ -258,8 +258,9 @@
ctx.del_noerror(res[0].dn, recursive=True)
- if "msDS-Krbtgtlink" in res[0]:
- new_krbtgt_dn = res[0]["msDS-Krbtgtlink"][0]
+ krbtgt_dn = res[0].get('msDS-KrbTgtLink', idx=0)
+ if krbtgt_dn is not None:
+ ctx.new_krbtgt_dn = krbtgt_dn
ctx.del_noerror(ctx.new_krbtgt_dn)
res = ctx.samdb.search(base=ctx.samdb.get_default_basedn(),
@@ -338,7 +339,7 @@
attrs=["msDS-krbTgtLink", "userAccountControl", "serverReferenceBL", "rIDSetReferences"])
if len(res) == 0:
raise Exception("Could not find domain member account '%s' to promote to a DC, use 'samba-tool domain join' instead'" % ctx.samname)
- if "msDS-krbTgtLink" in res[0] or "serverReferenceBL" in res[0] or "rIDSetReferences" in res[0]:
+ if "msDS-KrbTgtLink" in res[0] or "serverReferenceBL" in res[0] or "rIDSetReferences" in res[0]:
raise Exception("Account '%s' appears to be an active DC, use 'samba-tool domain join' if you must re-create this account" % ctx.samname)
if (int(res[0]["userAccountControl"][0]) & (samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT |
samba.dsdb.UF_SERVER_TRUST_ACCOUNT) == 0):
diff -Nru samba-4.13.3+dfsg/python/samba/kcc/kcc_utils.py samba-4.13.14+dfsg/python/samba/kcc/kcc_utils.py
--- samba-4.13.3+dfsg/python/samba/kcc/kcc_utils.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/kcc/kcc_utils.py 2021-10-29 06:17:36.000000000 +0000
@@ -30,7 +30,7 @@
drsuapi,
misc,
)
-from samba.common import dsdb_Dn
+from samba.samdb import dsdb_Dn
from samba.ndr import ndr_unpack, ndr_pack
from collections import Counter
diff -Nru samba-4.13.3+dfsg/python/samba/kcc/ldif_import_export.py samba-4.13.14+dfsg/python/samba/kcc/ldif_import_export.py
--- samba-4.13.3+dfsg/python/samba/kcc/ldif_import_export.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/kcc/ldif_import_export.py 2021-10-29 06:17:36.000000000 +0000
@@ -23,8 +23,7 @@
from samba import Ldb, ldb, read_and_sub_file
from samba.auth import system_session
-from samba.samdb import SamDB
-from samba.common import dsdb_Dn
+from samba.samdb import SamDB, dsdb_Dn
class LdifError(Exception):
diff -Nru samba-4.13.3+dfsg/python/samba/ms_schema.py samba-4.13.14+dfsg/python/samba/ms_schema.py
--- samba-4.13.3+dfsg/python/samba/ms_schema.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/ms_schema.py 2021-10-29 06:17:36.000000000 +0000
@@ -296,9 +296,9 @@
out = []
from io import open
- f = open(filename, "r", encoding='latin-1')
- for entry in __read_raw_entries(f):
- out.append(__write_ldif_one(__transform_entry(entry, objectClass)))
+ with open(filename, "r", encoding='latin-1') as f:
+ for entry in __read_raw_entries(f):
+ out.append(__write_ldif_one(__transform_entry(entry, objectClass)))
return "\n\n".join(out)
diff -Nru samba-4.13.3+dfsg/python/samba/netcmd/domain_backup.py samba-4.13.14+dfsg/python/samba/netcmd/domain_backup.py
--- samba-4.13.3+dfsg/python/samba/netcmd/domain_backup.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/netcmd/domain_backup.py 2021-08-09 07:20:55.000000000 +0000
@@ -27,6 +27,7 @@
import samba.getopt as options
from samba.samdb import SamDB, get_default_backend_store
import ldb
+from ldb import LdbError
from samba.samba3 import libsmb_samba_internal as libsmb
from samba.samba3 import param as s3param
from samba.ntacls import backup_online, backup_restore, backup_offline
@@ -60,53 +61,50 @@
# This ensures that the restored DC's SID won't clash with any other RIDs
# already in use in the domain
def get_sid_for_restore(samdb, logger):
- # Find the DN of the RID set of the server
- res = samdb.search(base=ldb.Dn(samdb, samdb.get_serverName()),
- scope=ldb.SCOPE_BASE, attrs=["serverReference"])
- server_ref_dn = ldb.Dn(samdb, str(res[0]['serverReference'][0]))
- res = samdb.search(base=server_ref_dn,
- scope=ldb.SCOPE_BASE,
- attrs=['rIDSetReferences'])
- rid_set_dn = ldb.Dn(samdb, str(res[0]['rIDSetReferences'][0]))
-
- # Get the alloc pools and next RID of the RID set
- res = samdb.search(base=rid_set_dn,
- scope=ldb.SCOPE_SUBTREE,
- expression="(rIDNextRID=*)",
- attrs=['rIDAllocationPool',
- 'rIDPreviousAllocationPool',
- 'rIDNextRID'])
-
- # Decode the bounds of the RID allocation pools
+ # Allocate a new RID without modifying the database. This should be safe,
+ # because we acquire the RID master role after creating an account using
+ # this RID during the restore process. Acquiring the RID master role
+ # creates a new RID pool which we will fetch RIDs from, so we shouldn't get
+ # duplicates.
try:
- rid = int(res[0].get('rIDNextRID')[0])
- except IndexError:
- logger.info("The RID pool for this DC is not initalized "
- "(e.g. it may be a fairly new DC).")
- logger.info("To initialize it, create a temporary user on this DC "
- "(you can delete it later).")
- raise CommandError("Cannot create backup - "
- "please initialize this DC's RID pool first.")
-
- def split_val(num):
- high = (0xFFFFFFFF00000000 & int(num)) >> 32
- low = 0x00000000FFFFFFFF & int(num)
- return low, high
- pool_l, pool_h = split_val(res[0].get('rIDPreviousAllocationPool')[0])
- npool_l, npool_h = split_val(res[0].get('rIDAllocationPool')[0])
-
- # Calculate next RID based on pool bounds
- if rid == npool_h:
- raise CommandError('Out of RIDs, finished AllocPool')
- if rid == pool_h:
- if pool_h == npool_h:
- raise CommandError('Out of RIDs, finished PrevAllocPool.')
- rid = npool_l
- else:
- rid += 1
+ rid = samdb.next_free_rid()
+ except LdbError as err:
+ logger.info("A SID could not be allocated for restoring the domain. "
+ "Either no RID Set was found on this DC, "
+ "or the RID Set was not usable.")
+ logger.info("To initialise this DC's RID pools, obtain a RID Set from "
+ "this domain's RID master, or run samba-tool dbcheck "
+ "to fix the existing RID Set.")
+ raise CommandError("Cannot create backup", err)
# Construct full SID
sid = dom_sid(samdb.get_domain_sid())
+ sid_for_restore = str(sid) + '-' + str(rid)
+
+ # Confirm the SID is not already in use
+ try:
+ res = samdb.search(scope=ldb.SCOPE_BASE,
+ base='' % sid_for_restore,
+ attrs=[],
+ controls=['show_deleted:1',
+ 'show_recycled:1'])
+ if len(res) != 1:
+ # This case makes no sense, but neither does a corrupt RID set
+ raise CommandError("Cannot create backup - "
+ "this DC's RID pool is corrupt, "
+ "the next SID (%s) appears to be in use." %
+ sid_for_restore)
+ raise CommandError("Cannot create backup - "
+ "this DC's RID pool is corrupt, "
+ "the next SID %s points to existing object %s. "
+ "Please run samba-tool dbcheck on the source DC." %
+ (sid_for_restore, res[0].dn))
+ except ldb.LdbError as e:
+ (enum, emsg) = e.args
+ if enum != ldb.ERR_NO_SUCH_OBJECT:
+ # We want NO_SUCH_OBJECT, anything else is a serious issue
+ raise
+
return str(sid) + '-' + str(rid)
@@ -278,7 +276,8 @@
shutil.rmtree(paths.sysvol)
# Edit the downloaded sam.ldb to mark it as a backup
- samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp)
+ samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp,
+ flags=ldb.FLG_DONT_CREATE_DB)
time_str = get_timestamp()
add_backup_marker(samdb, "backupDate", time_str)
add_backup_marker(samdb, "sidForRestore", new_sid)
@@ -502,7 +501,8 @@
# open a DB connection to the restored DB
private_dir = os.path.join(targetdir, 'private')
samdb_path = os.path.join(private_dir, 'sam.ldb')
- samdb = SamDB(url=samdb_path, session_info=system_session(), lp=lp)
+ samdb = SamDB(url=samdb_path, session_info=system_session(), lp=lp,
+ flags=ldb.FLG_DONT_CREATE_DB)
backup_type = self.get_backup_type(samdb)
if site is None:
@@ -550,7 +550,50 @@
attrs=['sidForRestore'])
sid = res[0].get('sidForRestore')[0]
logger.info('Creating account with SID: ' + str(sid))
- ctx.join_add_objects(specified_sid=dom_sid(str(sid)))
+ try:
+ ctx.join_add_objects(specified_sid=dom_sid(str(sid)))
+ except LdbError as e:
+ (enum, emsg) = e.args
+ if enum != ldb.ERR_CONSTRAINT_VIOLATION:
+ raise
+
+ dup_res = []
+ try:
+ dup_res = samdb.search(base=ldb.Dn(samdb, "" % sid),
+ scope=ldb.SCOPE_BASE,
+ attrs=['objectGUID'],
+ controls=["show_deleted:0",
+ "show_recycled:0"])
+ except LdbError as dup_e:
+ (dup_enum, _) = dup_e.args
+ if dup_enum != ldb.ERR_NO_SUCH_OBJECT:
+ raise
+
+ if (len(dup_res) != 1):
+ raise
+
+ objectguid = samdb.schema_format_value("objectGUID",
+ dup_res[0]["objectGUID"][0])
+ objectguid = objectguid.decode('utf-8')
+ logger.error("The RID Pool on the source DC for the backup in %s "
+ "may be corrupt "
+ "or in conflict with SIDs already allocated "
+ "in the domain. " % backup_file)
+ logger.error("Running 'samba-tool dbcheck' on the source "
+ "DC (and obtaining a new backup) may correct the issue.")
+ logger.error("Alternatively please obtain a new backup "
+ "against a different DC.")
+ logger.error("The SID we wish to use (%s) is recorded in "
+ "@SAMBA_DSDB as the sidForRestore attribute."
+ % sid)
+
+ raise CommandError("Domain restore failed because there "
+ "is already an existing object (%s) "
+ "with SID %s and objectGUID %s. "
+ "This conflicts with "
+ "the new DC account we want to add "
+ "for the restored domain. " % (
+ dup_res[0].dn, sid, objectguid))
m = ldb.Message()
m.dn = ldb.Dn(samdb, '@ROOTDSE')
@@ -568,7 +611,8 @@
host_ip, host_ip6, site)
secrets_path = os.path.join(private_dir, 'secrets.ldb')
- secrets_ldb = Ldb(secrets_path, session_info=system_session(), lp=lp)
+ secrets_ldb = Ldb(secrets_path, session_info=system_session(), lp=lp,
+ flags=ldb.FLG_DONT_CREATE_DB)
secretsdb_self_join(secrets_ldb, domain=ctx.domain_name,
realm=ctx.realm, dnsdomain=ctx.dnsdomain,
netbiosname=ctx.myname, domainsid=ctx.domsid,
@@ -860,7 +904,8 @@
# connect to the local DB (making sure we use the new/renamed config)
lp.load(paths.smbconf)
- samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp)
+ samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp,
+ flags=ldb.FLG_DONT_CREATE_DB)
# Edit the cloned sam.ldb to mark it as a backup
time_str = get_timestamp()
@@ -948,7 +993,8 @@
# on the secrets.ldb file before backing up that file and secrets.tdb
def backup_secrets(self, private_dir, lp, logger):
secrets_path = os.path.join(private_dir, 'secrets')
- secrets_obj = Ldb(secrets_path + '.ldb', lp=lp)
+ secrets_obj = Ldb(secrets_path + '.ldb', lp=lp,
+ flags=ldb.FLG_DONT_CREATE_DB)
logger.info('Starting transaction on ' + secrets_path)
secrets_obj.transaction_start()
self.offline_tdb_copy(secrets_path + '.ldb')
@@ -973,7 +1019,7 @@
else:
logger.info('Starting transaction on ' + sam_ldb_path)
copy_function = self.offline_tdb_copy
- sam_obj = Ldb(sam_ldb_path, lp=lp)
+ sam_obj = Ldb(sam_ldb_path, lp=lp, flags=ldb.FLG_DONT_CREATE_DB)
sam_obj.transaction_start()
logger.info(' backing up ' + sam_ldb_path)
@@ -1025,9 +1071,14 @@
check_targetdir(logger, targetdir)
- samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp)
+ samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp,
+ flags=ldb.FLG_RDONLY)
sid = get_sid_for_restore(samdb, logger)
+ # Iterating over the directories in this specific order ensures that
+ # when the private directory contains hardlinks that are also contained
+ # in other directories to be backed up (such as in paths.binddns_dir),
+ # the hardlinks in the private directory take precedence.
backup_dirs = [paths.private_dir, paths.state_dir,
os.path.dirname(paths.smbconf)] # etc dir
logger.info('running backup on dirs: {0}'.format(' '.join(backup_dirs)))
@@ -1040,22 +1091,31 @@
continue
if working_dir.endswith('.sock') or '.sock/' in working_dir:
continue
+ # The BIND DNS database can be regenerated, so it doesn't need
+ # to be backed up.
+ if working_dir.startswith(os.path.join(paths.binddns_dir, 'dns')):
+ continue
for filename in filenames:
- if filename in all_files:
+ full_path = os.path.join(working_dir, filename)
+
+ # Ignore files that have already been added. This prevents
+ # duplicates if one backup dir is a subdirectory of another,
+ # or if backup dirs contain hardlinks.
+ if any(os.path.samefile(full_path, file) for file in all_files):
continue
# Assume existing backup files are from a previous backup.
# Delete and ignore.
if filename.endswith(self.backup_ext):
- os.remove(os.path.join(working_dir, filename))
+ os.remove(full_path)
continue
# Sock files are autogenerated at runtime, ignore.
if filename.endswith('.sock'):
continue
- all_files.append(os.path.join(working_dir, filename))
+ all_files.append(full_path)
# Backup secrets, sam.ldb and their downstream files
self.backup_secrets(paths.private_dir, lp, logger)
@@ -1067,7 +1127,8 @@
# Writing to a .bak file only works because the DN being
# written to happens to be top level.
samdb = SamDB(url=paths.samdb + self.backup_ext,
- session_info=system_session(), lp=lp)
+ session_info=system_session(), lp=lp,
+ flags=ldb.FLG_DONT_CREATE_DB)
time_str = get_timestamp()
add_backup_marker(samdb, "backupDate", time_str)
add_backup_marker(samdb, "sidForRestore", sid)
@@ -1079,7 +1140,7 @@
if not os.path.exists(path + self.backup_ext):
if path.endswith('.ldb'):
logger.info('Starting transaction on solo db: ' + path)
- ldb_obj = Ldb(path, lp=lp)
+ ldb_obj = Ldb(path, lp=lp, flags=ldb.FLG_DONT_CREATE_DB)
ldb_obj.transaction_start()
logger.info(' running tdbbackup on the same file')
self.offline_tdb_copy(path)
diff -Nru samba-4.13.3+dfsg/python/samba/netcmd/spn.py samba-4.13.14+dfsg/python/samba/netcmd/spn.py
--- samba-4.13.3+dfsg/python/samba/netcmd/spn.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/netcmd/spn.py 2021-11-08 11:29:14.000000000 +0000
@@ -18,7 +18,6 @@
import samba.getopt as options
import ldb
-from samba import provision
from samba.samdb import SamDB
from samba.auth import system_session
from samba.netcmd.common import _get_user_realm_domain
@@ -40,14 +39,20 @@
"credopts": options.CredentialsOptions,
"versionopts": options.VersionOptions,
}
+ takes_options = [
+ Option("-H", "--URL", help="LDB URL for database or target server",
+ type=str, metavar="URL", dest="H"),
+ ]
takes_args = ["user"]
- def run(self, user, credopts=None, sambaopts=None, versionopts=None):
+ def run(self, user, H=None,
+ credopts=None,
+ sambaopts=None,
+ versionopts=None):
lp = sambaopts.get_loadparm()
creds = credopts.get_credentials(lp)
- paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
- sam = SamDB(paths.samdb, session_info=system_session(),
+ sam = SamDB(H, session_info=system_session(),
credentials=creds, lp=lp)
# TODO once I understand how, use the domain info to naildown
# to the correct domain
@@ -82,22 +87,23 @@
"versionopts": options.VersionOptions,
}
takes_options = [
- Option("--force", help="Force the addition of the spn"
- " even it exists already", action="store_true"),
- ]
+ Option("-H", "--URL", help="LDB URL for database or target server",
+ type=str, metavar="URL", dest="H"),
+ ]
takes_args = ["name", "user"]
- def run(self, name, user, force=False, credopts=None, sambaopts=None,
+ def run(self, name, user, H=None,
+ credopts=None,
+ sambaopts=None,
versionopts=None):
lp = sambaopts.get_loadparm()
creds = credopts.get_credentials(lp)
- paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
- sam = SamDB(paths.samdb, session_info=system_session(),
+ sam = SamDB(H, session_info=system_session(),
credentials=creds, lp=lp)
res = sam.search(
expression="servicePrincipalName=%s" % ldb.binary_encode(name),
scope=ldb.SCOPE_SUBTREE)
- if len(res) != 0 and not force:
+ if len(res) != 0:
raise CommandError("Service principal %s already"
" affected to another user" % name)
@@ -141,15 +147,18 @@
"credopts": options.CredentialsOptions,
"versionopts": options.VersionOptions,
}
+ takes_options = [
+ Option("-H", "--URL", help="LDB URL for database or target server",
+ type=str, metavar="URL", dest="H"),
+ ]
takes_args = ["name", "user?"]
- def run(self, name, user=None, credopts=None, sambaopts=None,
+ def run(self, name, user=None, H=None, credopts=None, sambaopts=None,
versionopts=None):
lp = sambaopts.get_loadparm()
creds = credopts.get_credentials(lp)
- paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
- sam = SamDB(paths.samdb, session_info=system_session(),
+ sam = SamDB(H, session_info=system_session(),
credentials=creds, lp=lp)
res = sam.search(
expression="servicePrincipalName=%s" % ldb.binary_encode(name),
diff -Nru samba-4.13.3+dfsg/python/samba/netcmd/user.py samba-4.13.14+dfsg/python/samba/netcmd/user.py
--- samba-4.13.3+dfsg/python/samba/netcmd/user.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/netcmd/user.py 2021-09-22 06:59:39.000000000 +0000
@@ -3001,14 +3001,8 @@
if unix_home is None:
# obtain nETBIOS Domain Name
- filter = "(&(objectClass=crossRef)(nETBIOSName=*))"
- searchdn = ("CN=Partitions,CN=Configuration," + domaindn)
- try:
- res = samdb.search(searchdn,
- scope=ldb.SCOPE_SUBTREE,
- expression=filter)
- unix_domain = res[0]["nETBIOSName"][0]
- except IndexError:
+ unix_domain = samdb.domain_netbios_name()
+ if unix_domain is None:
raise CommandError('Unable to find Unix domain')
unix_home = "/home/{0}/{1}".format(unix_domain, username)
diff -Nru samba-4.13.3+dfsg/python/samba/samdb.py samba-4.13.14+dfsg/python/samba/samdb.py
--- samba-4.13.3+dfsg/python/samba/samdb.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/samdb.py 2021-10-29 06:17:36.000000000 +0000
@@ -35,7 +35,9 @@
from samba.compat import text_type
from samba.compat import binary_type
from samba.compat import get_bytes
+from samba.common import cmp
from samba.dcerpc import security
+import binascii
__docformat__ = "restructuredText"
@@ -928,6 +930,21 @@
domain_dn = self.get_default_basedn()
return domain_dn.canonical_str().split('/')[0]
+ def domain_netbios_name(self):
+ """return the NetBIOS name of the domain root"""
+ domain_dn = self.get_default_basedn()
+ dns_name = self.domain_dns_name()
+ filter = "(&(objectClass=crossRef)(nETBIOSName=*)(ncName=%s)(dnsroot=%s))" % (domain_dn, dns_name)
+ partitions_dn = self.get_partitions_dn()
+ res = self.search(partitions_dn,
+ scope=ldb.SCOPE_ONELEVEL,
+ expression=filter)
+ try:
+ netbios_domain = res[0]["nETBIOSName"][0].decode()
+ except IndexError:
+ return None
+ return netbios_domain
+
def forest_dns_name(self):
"""return the DNS name of the forest root"""
forest_dn = self.get_root_basedn()
@@ -1285,6 +1302,111 @@
'''return a new RID from the RID Pool on this DSA'''
return dsdb._dsdb_allocate_rid(self)
+ def next_free_rid(self):
+ '''return the next free RID from the RID Pool on this DSA.
+
+ :note: This function is not intended for general use, and care must be
+ taken if it is used to generate objectSIDs. The returned RID is not
+ formally reserved for use, creating the possibility of duplicate
+ objectSIDs.
+ '''
+ rid, _ = self.free_rid_bounds()
+ return rid
+
+ def free_rid_bounds(self):
+ '''return the low and high bounds (inclusive) of RIDs that are
+ available for use in this DSA's current RID pool.
+
+ :note: This function is not intended for general use, and care must be
+ taken if it is used to generate objectSIDs. The returned range of
+ RIDs is not formally reserved for use, creating the possibility of
+ duplicate objectSIDs.
+ '''
+ # Get DN of this server's RID Set
+ server_name_dn = ldb.Dn(self, self.get_serverName())
+ res = self.search(base=server_name_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=["serverReference"])
+ try:
+ server_ref = res[0]["serverReference"]
+ except KeyError:
+ raise ldb.LdbError(
+ ldb.ERR_NO_SUCH_ATTRIBUTE,
+ "No RID Set DN - "
+ "Cannot find attribute serverReference of %s "
+ "to calculate reference dn" % server_name_dn) from None
+ server_ref_dn = ldb.Dn(self, server_ref[0].decode("utf-8"))
+
+ res = self.search(base=server_ref_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=["rIDSetReferences"])
+ try:
+ rid_set_refs = res[0]["rIDSetReferences"]
+ except KeyError:
+ raise ldb.LdbError(
+ ldb.ERR_NO_SUCH_ATTRIBUTE,
+ "No RID Set DN - "
+ "Cannot find attribute rIDSetReferences of %s "
+ "to calculate reference dn" % server_ref_dn) from None
+ rid_set_dn = ldb.Dn(self, rid_set_refs[0].decode("utf-8"))
+
+ # Get the alloc pools and next RID of this RID Set
+ res = self.search(base=rid_set_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=["rIDAllocationPool",
+ "rIDPreviousAllocationPool",
+ "rIDNextRID"])
+
+ uint32_max = 2**32 - 1
+ uint64_max = 2**64 - 1
+
+ try:
+ alloc_pool = int(res[0]["rIDAllocationPool"][0])
+ except KeyError:
+ alloc_pool = uint64_max
+ if alloc_pool == uint64_max:
+ raise ldb.LdbError(ldb.ERR_OPERATIONS_ERROR,
+ "Bad RID Set %s" % rid_set_dn)
+
+ try:
+ prev_pool = int(res[0]["rIDPreviousAllocationPool"][0])
+ except KeyError:
+ prev_pool = uint64_max
+ try:
+ next_rid = int(res[0]["rIDNextRID"][0])
+ except KeyError:
+ next_rid = uint32_max
+
+ # If we never used a pool, set up our first pool
+ if prev_pool == uint64_max or next_rid == uint32_max:
+ prev_pool = alloc_pool
+ next_rid = prev_pool & uint32_max
+
+ next_rid += 1
+
+ # Now check if our current pool is still usable
+ prev_pool_lo = prev_pool & uint32_max
+ prev_pool_hi = prev_pool >> 32
+ if next_rid > prev_pool_hi:
+ # We need a new pool, check if we already have a new one
+ # Otherwise we return an error code.
+ if alloc_pool == prev_pool:
+ raise ldb.LdbError(ldb.ERR_OPERATIONS_ERROR,
+ "RID pools out of RIDs")
+
+ # Now use the new pool
+ prev_pool = alloc_pool
+ prev_pool_lo = prev_pool & uint32_max
+ prev_pool_hi = prev_pool >> 32
+ next_rid = prev_pool_lo
+
+ if next_rid < prev_pool_lo or next_rid > prev_pool_hi:
+ raise ldb.LdbError(ldb.ERR_OPERATIONS_ERROR,
+ "Bad RID chosen %d from range %d-%d" %
+ (next_rid, prev_pool_lo, prev_pool_hi))
+
+ return next_rid, prev_pool_hi
+
def normalize_dn_in_domain(self, dn):
'''return a new DN expanded by adding the domain DN
@@ -1302,3 +1424,76 @@
if not full_dn.is_child_of(domain_dn):
full_dn.add_base(domain_dn)
return full_dn
+
+class dsdb_Dn(object):
+ '''a class for binary DN'''
+
+ def __init__(self, samdb, dnstring, syntax_oid=None):
+ '''create a dsdb_Dn'''
+ if syntax_oid is None:
+ # auto-detect based on string
+ if dnstring.startswith("B:"):
+ syntax_oid = dsdb.DSDB_SYNTAX_BINARY_DN
+ elif dnstring.startswith("S:"):
+ syntax_oid = dsdb.DSDB_SYNTAX_STRING_DN
+ else:
+ syntax_oid = dsdb.DSDB_SYNTAX_OR_NAME
+ if syntax_oid in [dsdb.DSDB_SYNTAX_BINARY_DN, dsdb.DSDB_SYNTAX_STRING_DN]:
+ # it is a binary DN
+ colons = dnstring.split(':')
+ if len(colons) < 4:
+ raise RuntimeError("Invalid DN %s" % dnstring)
+ prefix_len = 4 + len(colons[1]) + int(colons[1])
+ self.prefix = dnstring[0:prefix_len]
+ self.binary = self.prefix[3 + len(colons[1]):-1]
+ self.dnstring = dnstring[prefix_len:]
+ else:
+ self.dnstring = dnstring
+ self.prefix = ''
+ self.binary = ''
+ self.dn = ldb.Dn(samdb, self.dnstring)
+
+ def __str__(self):
+ return self.prefix + str(self.dn.extended_str(mode=1))
+
+ def __cmp__(self, other):
+ ''' compare dsdb_Dn values similar to parsed_dn_compare()'''
+ dn1 = self
+ dn2 = other
+ guid1 = dn1.dn.get_extended_component("GUID")
+ guid2 = dn2.dn.get_extended_component("GUID")
+
+ v = cmp(guid1, guid2)
+ if v != 0:
+ return v
+ v = cmp(dn1.binary, dn2.binary)
+ return v
+
+ # In Python3, __cmp__ is replaced by these 6 methods
+ def __eq__(self, other):
+ return self.__cmp__(other) == 0
+
+ def __ne__(self, other):
+ return self.__cmp__(other) != 0
+
+ def __lt__(self, other):
+ return self.__cmp__(other) < 0
+
+ def __le__(self, other):
+ return self.__cmp__(other) <= 0
+
+ def __gt__(self, other):
+ return self.__cmp__(other) > 0
+
+ def __ge__(self, other):
+ return self.__cmp__(other) >= 0
+
+ def get_binary_integer(self):
+ '''return binary part of a dsdb_Dn as an integer, or None'''
+ if self.prefix == '':
+ return None
+ return int(self.binary, 16)
+
+ def get_bytes(self):
+ '''return binary as a byte string'''
+ return binascii.unhexlify(self.binary)
diff -Nru samba-4.13.3+dfsg/python/samba/schema.py samba-4.13.14+dfsg/python/samba/schema.py
--- samba-4.13.3+dfsg/python/samba/schema.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/schema.py 2021-10-29 06:17:36.000000000 +0000
@@ -110,8 +110,13 @@
setup_path('ad-schema/%s' % Schema.base_schemas[base_schema][0]),
setup_path('ad-schema/%s' % Schema.base_schemas[base_schema][1]))
+ def read_file(file):
+ with open(file, 'rb') as data_file:
+ return data_file.read()
+
if files is not None:
- self.schema_data = "".join(get_string(open(file, 'rb').read()) for file in files)
+ self.schema_data = "".join(get_string(read_file(file))
+ for file in files)
self.schema_data = substitute_var(self.schema_data,
{"SCHEMADN": schemadn})
@@ -130,7 +135,7 @@
if override_prefixmap is not None:
self.prefixmap_data = override_prefixmap
else:
- self.prefixmap_data = open(setup_path("prefixMap.txt"), 'rb').read()
+ self.prefixmap_data = read_file(setup_path("prefixMap.txt"))
if additional_prefixmap is not None:
self.prefixmap_data += "".join("%s\n" % map for map in additional_prefixmap)
diff -Nru samba-4.13.3+dfsg/python/samba/tests/blackbox/ndrdump.py samba-4.13.14+dfsg/python/samba/tests/blackbox/ndrdump.py
--- samba-4.13.3+dfsg/python/samba/tests/blackbox/ndrdump.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/blackbox/ndrdump.py 2021-11-08 11:29:14.000000000 +0000
@@ -25,13 +25,7 @@
import re
from samba.tests import BlackboxTestCase, BlackboxProcessError
-for p in ["../../../../../source4/librpc/tests",
- "../../../../../librpc/tests"]:
- data_path_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), p))
- print(data_path_dir)
- if os.path.exists(data_path_dir):
- break
-
+data_path_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../../../source4/librpc/tests"))
class NdrDumpTests(BlackboxTestCase):
"""Blackbox tests for ndrdump."""
@@ -96,6 +90,41 @@
expected.encode('utf-8'))
self.assertTrue(actual.endswith(b"dump OK\n"))
+ def test_ndrdump_upn_dns_info_ex(self):
+ with open(self.data_path(
+ 'krb5pac_upn_dns_info_ex.txt')) as f:
+ expected = f.read()
+ data_path = self.data_path(
+ 'krb5pac_upn_dns_info_ex.b64.txt')
+
+ try:
+ actual = self.check_output(
+ 'ndrdump --debug-stdout -d0 krb5pac PAC_DATA struct '
+ '--validate --base64-input ' + data_path)
+ except BlackboxProcessError as e:
+ self.fail(e)
+
+ self.assertEqual(actual, expected.encode('utf-8'))
+
+ def test_ndrdump_upn_dns_info_ex_not_supported(self):
+ with open(self.data_path(
+ 'krb5pac_upn_dns_info_ex_not_supported.txt')) as f:
+ expected = f.read()
+ data_path = self.data_path(
+ 'krb5pac_upn_dns_info_ex_not_supported.b64.txt')
+
+ try:
+ # This PAC has been edited to remove the
+ # PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID bit, so that we can
+ # simulate older versions of Samba parsing this structure.
+ actual = self.check_output(
+ 'ndrdump --debug-stdout -d0 krb5pac PAC_DATA struct '
+ '--validate --base64-input ' + data_path)
+ except BlackboxProcessError as e:
+ self.fail(e)
+
+ self.assertEqual(actual, expected.encode('utf-8'))
+
def test_ndrdump_with_binary_struct_number(self):
expected = '''pull returned Success
GUID : 33323130-3534-3736-3839-616263646566
@@ -323,6 +352,43 @@
except BlackboxProcessError as e:
self.fail(e)
# check_output will return bytes
+ # convert expected to bytes for python 3
+ self.assertEqual(actual, expected.encode('utf-8'))
+
+ def test_ndrdump_Krb5ccache(self):
+ expected = open(self.data_path("../../../source3/selftest/"
+ "ktest-krb5_ccache-2.txt")).read()
+ try:
+ # Specify -d1 to match the generated output file, because ndrdump
+ # only outputs some additional info if this parameter is specified,
+ # and the --configfile parameter gives us an empty smb.conf to avoid
+ # extraneous output.
+ actual = self.check_output(
+ "ndrdump krb5ccache CCACHE struct "
+ "--configfile /dev/null -d1 --validate " +
+ self.data_path("../../../source3/selftest/"
+ "ktest-krb5_ccache-2"))
+ except BlackboxProcessError as e:
+ self.fail(e)
+ # check_output will return bytes
+ # convert expected to bytes for python 3
+ self.assertEqual(actual, expected.encode('utf-8'))
+
+ expected = open(self.data_path("../../../source3/selftest/"
+ "ktest-krb5_ccache-3.txt")).read()
+ try:
+ # Specify -d1 to match the generated output file, because ndrdump
+ # only outputs some additional info if this parameter is specified,
+ # and the --configfile parameter gives us an empty smb.conf to avoid
+ # extraneous output.
+ actual = self.check_output(
+ "ndrdump krb5ccache CCACHE struct "
+ "--configfile /dev/null -d1 --validate " +
+ self.data_path("../../../source3/selftest/"
+ "ktest-krb5_ccache-3"))
+ except BlackboxProcessError as e:
+ self.fail(e)
+ # check_output will return bytes
# convert expected to bytes for python 3
self.assertEqual(actual, expected.encode('utf-8'))
diff -Nru samba-4.13.3+dfsg/python/samba/tests/common.py samba-4.13.14+dfsg/python/samba/tests/common.py
--- samba-4.13.3+dfsg/python/samba/tests/common.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/common.py 2021-10-29 06:17:36.000000000 +0000
@@ -20,8 +20,8 @@
import samba
import os
import samba.tests
-from samba.common import normalise_int32, dsdb_Dn
-from samba.samdb import SamDB
+from samba.common import normalise_int32
+from samba.samdb import SamDB, dsdb_Dn
class CommonTests(samba.tests.TestCaseInTempDir):
diff -Nru samba-4.13.3+dfsg/python/samba/tests/dcerpc/lsa.py samba-4.13.14+dfsg/python/samba/tests/dcerpc/lsa.py
--- samba-4.13.3+dfsg/python/samba/tests/dcerpc/lsa.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/dcerpc/lsa.py 2021-09-22 06:59:39.000000000 +0000
@@ -0,0 +1,333 @@
+# -*- coding: utf-8 -*-
+#
+# Unix SMB/CIFS implementation.
+# Copyright © Andrew Bartlett 2021
+# Copyright (C) Catalyst IT Ltd. 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+"""Tests for samba.dcerpc.sam."""
+
+from samba.dcerpc import samr, security, lsa
+from samba.credentials import Credentials
+from samba.tests import TestCase
+from samba.dcerpc.security import dom_sid
+from samba import NTSTATUSError
+from samba.ntstatus import NT_STATUS_ACCESS_DENIED
+import samba.tests
+
+class LsaTests(TestCase):
+
+ def setUp(self):
+ self.lp = self.get_loadparm()
+ self.server = samba.tests.env_get_var_value('SERVER')
+
+ def test_lsa_LookupSids3_multiple(self):
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.SidArray()
+ sid = lsa.SidPtr()
+ # Need a set
+ x = dom_sid("S-1-5-7")
+ sid.sid = x
+ sids.sids = [sid]
+ sids.num_sids = 1
+ names = lsa.TransNameArray2()
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+
+ # We want to run LookupSids3 multiple times on the same
+ # connection as we have code to re-use the sam.ldb and we need
+ # to check things work for the second request.
+ (domains, names, count) = c.LookupSids3(sids, names, level, count, lookup_options, client_revision)
+ self.assertEqual(count, 1)
+ self.assertEqual(names.count, 1)
+ self.assertEqual(names.names[0].name.string,
+ "ANONYMOUS LOGON")
+ (domains2, names2, count2) = c.LookupSids3(sids, names, level, count, lookup_options, client_revision)
+ self.assertEqual(count2, 1)
+ self.assertEqual(names2.count, 1)
+ self.assertEqual(names2.names[0].name.string,
+ "ANONYMOUS LOGON")
+
+ # Just looking for any exceptions in the last couple of loops
+ c.LookupSids3(sids, names, level, count, lookup_options, client_revision)
+ c.LookupSids3(sids, names, level, count, lookup_options, client_revision)
+
+ def test_lsa_LookupSids3_multiple_conns(self):
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.SidArray()
+ sid = lsa.SidPtr()
+ # Need a set
+ x = dom_sid("S-1-5-7")
+ sid.sid = x
+ sids.sids = [sid]
+ sids.num_sids = 1
+ names = lsa.TransNameArray2()
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+
+ # We want to run LookupSids3, and then again on a new
+ # connection to show that we don't have an issue with the DB
+ # being tied to the wrong connection.
+ (domains, names, count) = c.LookupSids3(sids,
+ names,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+ self.assertEqual(count, 1)
+ self.assertEqual(names.count, 1)
+ self.assertEqual(names.names[0].name.string,
+ "ANONYMOUS LOGON")
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ (domains, names, count) = c.LookupSids3(sids,
+ names,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+ self.assertEqual(count, 1)
+ self.assertEqual(names.count, 1)
+ self.assertEqual(names.names[0].name.string,
+ "ANONYMOUS LOGON")
+
+
+ def test_lsa_LookupNames4_LookupSids3_multiple(self):
+ """
+ Test by going back and forward between real DB lookups
+ name->sid->name to ensure the sam.ldb handle is fine once
+ shared
+ """
+
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c_normal = lsa.lsarpc(
+ "ncacn_np:%s[seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ username, domain = c_normal.GetUserName(None, None, None)
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.TransSidArray3()
+ names = [username]
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+ (domains, sids, count) = c.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+
+ # Another lookup on the same connection, will re-used the
+ # server-side implicit state handle on the connection
+ (domains, sids, count) = c.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+
+ self.assertEqual(count, 1)
+ self.assertEqual(sids.count, 1)
+
+ # Now look the SIDs back up
+ names = lsa.TransNameArray2()
+ sid = lsa.SidPtr()
+ sid.sid = sids.sids[0].sid
+ lookup_sids = lsa.SidArray()
+ lookup_sids.sids = [sid]
+ lookup_sids.num_sids = 1
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 1
+ lookup_options = 0
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+
+ (domains, names, count) = c.LookupSids3(lookup_sids,
+ names,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+ self.assertEqual(count, 1)
+ self.assertEqual(names.count, 1)
+ self.assertEqual(names.names[0].name.string,
+ username.string)
+
+ # And once more just to be sure, just checking for a fault
+ sids = lsa.TransSidArray3()
+ names = [username]
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+ (domains, sids, count) = c.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+
+
+ def test_lsa_LookupNames4_multiple_conns(self):
+ """
+ Test by going back and forward between real DB lookups
+ name->sid->name to ensure the sam.ldb handle is fine once
+ shared
+ """
+
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c_normal = lsa.lsarpc(
+ "ncacn_np:%s[seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ username, domain = c_normal.GetUserName(None, None, None)
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.TransSidArray3()
+ names = [username]
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+ (domains, sids, count) = c.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[schannel,seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.TransSidArray3()
+ names = [username]
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+ (domains, sids, count) = c.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+
+ def test_lsa_LookupNames4_without_schannel(self):
+
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c_normal = lsa.lsarpc(
+ "ncacn_np:%s[seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ username, domain = c_normal.GetUserName(None, None, None)
+
+ sids = lsa.TransSidArray3()
+ names = [username]
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+
+ with self.assertRaises(NTSTATUSError) as e:
+ c_normal.LookupNames4(names,
+ sids,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+ if (e.exception.args[0] != NT_STATUS_ACCESS_DENIED):
+ raise AssertionError("LookupNames4 without schannel must fail with ACCESS_DENIED")
+
+ def test_lsa_LookupSids3_without_schannel(self):
+ machine_creds = Credentials()
+ machine_creds.guess(self.lp)
+ machine_creds.set_machine_account()
+
+ c = lsa.lsarpc(
+ "ncacn_ip_tcp:%s[seal]" % self.server,
+ self.lp,
+ machine_creds)
+
+ sids = lsa.SidArray()
+ sid = lsa.SidPtr()
+ # Need a set
+ x = dom_sid("S-1-5-7")
+ sid.sid = x
+ sids.sids = [sid]
+ sids.num_sids = 1
+ names = lsa.TransNameArray2()
+ level = lsa.LSA_LOOKUP_NAMES_ALL
+ count = 0
+ lookup_options = lsa.LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES
+ client_revision = lsa.LSA_CLIENT_REVISION_2
+
+ with self.assertRaises(NTSTATUSError) as e:
+ c.LookupSids3(sids,
+ names,
+ level,
+ count,
+ lookup_options,
+ client_revision)
+ if (e.exception.args[0] != NT_STATUS_ACCESS_DENIED):
+ raise AssertionError("LookupSids3 without schannel must fail with ACCESS_DENIED")
diff -Nru samba-4.13.3+dfsg/python/samba/tests/dcerpc/raw_protocol.py samba-4.13.14+dfsg/python/samba/tests/dcerpc/raw_protocol.py
--- samba-4.13.3+dfsg/python/samba/tests/dcerpc/raw_protocol.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/dcerpc/raw_protocol.py 2021-11-08 11:29:14.000000000 +0000
@@ -66,7 +66,7 @@
pfc_flags=rep_pfc_flags, auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -87,7 +87,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -109,7 +109,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -129,7 +129,7 @@
pfc_flags=rep_pfc_flags, auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertEqual(rep.u.secondary_address, "")
self.assertPadding(rep.u._pad1, 2)
@@ -150,7 +150,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -397,7 +397,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -470,7 +470,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -490,7 +490,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -522,7 +522,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -542,7 +542,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 1)
@@ -563,7 +563,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, ctx1.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -590,7 +590,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -610,7 +610,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 1)
@@ -631,7 +631,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -647,7 +647,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 1)
@@ -706,7 +706,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -733,7 +733,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -766,7 +766,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -795,7 +795,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -827,7 +827,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -856,7 +856,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 1)
@@ -877,7 +877,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, ctx1a.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -903,7 +903,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -929,7 +929,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 1)
@@ -948,7 +948,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -967,7 +967,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 1)
@@ -986,7 +986,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1005,7 +1005,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 1)
@@ -1024,7 +1024,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1050,7 +1050,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 2)
@@ -1074,7 +1074,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1086,7 +1086,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 2)
@@ -1110,7 +1110,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1123,7 +1123,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1135,7 +1135,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 2)
@@ -1159,7 +1159,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1172,7 +1172,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1198,7 +1198,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 2)
@@ -1222,7 +1222,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1234,7 +1234,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 0)
self.assertPadding(rep.u._pad1, 2)
self.assertEqual(rep.u.num_results, 2)
@@ -1258,7 +1258,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1283,7 +1283,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -1319,7 +1319,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -1353,7 +1353,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -1425,7 +1425,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -1460,7 +1460,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -1495,7 +1495,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -1618,7 +1618,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -1639,7 +1639,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1659,7 +1659,7 @@
# We get a fault back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -1684,6 +1684,1279 @@
def test_auth_none_packet_request(self):
return self._test_auth_none_level_request(dcerpc.DCERPC_AUTH_LEVEL_PACKET)
+ def test_ntlmssp_multi_auth_first1_lastSame2(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_SEC_PKG_ERROR
+ auth_context_2nd = 2
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastNext2(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 2
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastSame111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = None
+ auth_context_2nd = 1
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastNext111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_lastNext111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastSameNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_lastSameNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastNextNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_lastNextNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastSameNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_lastSameNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_lastNextNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_lastNextNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_last(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def _test_generic_auth_first_2nd(self,
+ auth_type,
+ pfc_flags_2nd,
+ expected_fault,
+ auth_context_2nd=2,
+ skip_first=False,
+ expected_call_id=None,
+ expected_context_id=None,
+ conc_mpx=False,
+ not_executed=False,
+ forced_call_id=None,
+ forced_context_id=None,
+ forced_opnum=None,
+ forced_auth_context_id=None,
+ forced_auth_type=None,
+ forced_auth_level=None):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ auth_level1 = dcerpc.DCERPC_AUTH_LEVEL_INTEGRITY
+ auth_context_id1=1
+ auth_level2 = dcerpc.DCERPC_AUTH_LEVEL_PACKET
+ auth_context_id2=2
+
+ creds = self.get_user_creds()
+
+ abstract = samba.dcerpc.mgmt.abstract_syntax()
+ transfer = base.transfer_syntax_ndr()
+
+ tsf1_list = [transfer]
+ ctx = samba.dcerpc.dcerpc.ctx_list()
+ ctx.context_id = 1
+ ctx.num_transfer_syntaxes = len(tsf1_list)
+ ctx.abstract_syntax = abstract
+ ctx.transfer_syntaxes = tsf1_list
+
+ auth_context1 = self.get_auth_context_creds(creds=creds,
+ auth_type=auth_type,
+ auth_level=auth_level1,
+ auth_context_id=auth_context_id1,
+ hdr_signing=False)
+ auth_context2 = self.get_auth_context_creds(creds=creds,
+ auth_type=auth_type,
+ auth_level=auth_level2,
+ auth_context_id=auth_context_id2,
+ hdr_signing=False)
+
+ bind_pfc_flags = dcerpc.DCERPC_PFC_FLAG_FIRST | dcerpc.DCERPC_PFC_FLAG_LAST
+ if conc_mpx:
+ bind_pfc_flags |= dcerpc.DCERPC_PFC_FLAG_CONC_MPX
+
+ ack0 = self.do_generic_bind(call_id=0,
+ ctx=ctx,
+ pfc_flags=bind_pfc_flags)
+
+ ack1 = self.do_generic_bind(call_id=1,
+ ctx=ctx,
+ auth_context=auth_context1,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+ if auth_context_2nd == 2:
+ ack2 = self.do_generic_bind(call_id=2,
+ ctx=ctx,
+ auth_context=auth_context2,
+ assoc_group_id = ack0.u.assoc_group_id,
+ start_with_alter=True)
+
+ ndr_print = self.do_ndr_print
+ hexdump = self.do_hexdump
+ inq_if_ids = samba.dcerpc.mgmt.inq_if_ids()
+ io = inq_if_ids
+ if ndr_print:
+ sys.stderr.write("in: %s" % samba.ndr.ndr_print_in(io))
+ stub_in = samba.ndr.ndr_pack_in(io)
+ stub_in += b'\xfe'*45 # add some padding in order to have some payload
+ if hexdump:
+ sys.stderr.write("stub_in: %d\n%s" % (len(stub_in), self.hexdump(stub_in)))
+
+ call_id = 3
+ context_id = ctx.context_id
+ opnum = io.opnum()
+
+ if not skip_first:
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
+ stub_in_tmp = stub_in[0:16]
+ req = self.generate_request_auth(call_id=call_id,
+ context_id=context_id,
+ pfc_flags=pfc_flags,
+ opnum=opnum,
+ alloc_hint=len(stub_in),
+ stub=stub_in_tmp,
+ auth_context=auth_context1)
+ self.send_pdu(req, ndr_print=ndr_print, hexdump=hexdump)
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+
+ # context_id, opnum and auth header values are completely ignored
+ if auth_context_2nd == 1:
+ auth_context_copy = auth_context1.copy()
+ elif auth_context_2nd == 2:
+ auth_context_copy = auth_context2.copy()
+ else:
+ auth_context_copy = None
+
+ expected_pfc_flags = dcerpc.DCERPC_PFC_FLAG_FIRST | dcerpc.DCERPC_PFC_FLAG_LAST
+ if expected_context_id is None:
+ expected_context_id = context_id
+ if expected_call_id is None:
+ expected_call_id = call_id
+ if not_executed:
+ expected_pfc_flags |= dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE
+
+ if forced_call_id is not None:
+ call_id = forced_call_id
+ if forced_context_id is not None:
+ context_id = forced_context_id
+ if forced_opnum is not None:
+ opnum = forced_opnum
+ if forced_auth_context_id is not None:
+ auth_context_copy["auth_context_id"] = forced_auth_context_id
+ if forced_auth_type is not None:
+ auth_context_copy["auth_type"] = forced_auth_type
+ if forced_auth_level is not None:
+ auth_context_copy["auth_level"] = forced_auth_level
+
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
+ stub_in_tmp = stub_in[16:-1]
+ req = self.generate_request_auth(call_id=call_id,
+ context_id=context_id,
+ pfc_flags=pfc_flags_2nd,
+ opnum=opnum,
+ alloc_hint=len(stub_in_tmp),
+ stub=stub_in_tmp,
+ auth_context=auth_context_copy)
+ self.send_pdu(req, ndr_print=ndr_print, hexdump=hexdump)
+ if expected_fault is None:
+ self.do_single_request(call_id=3, ctx=ctx, io=io, send_req=False, auth_context=auth_context1)
+ return
+ rep = self.recv_pdu()
+ self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, expected_call_id,
+ pfc_flags=expected_pfc_flags,
+ auth_length=0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, expected_context_id)
+ self.assertEqual(rep.u.cancel_count, 0)
+ self.assertEqual(rep.u.flags, 0)
+ self.assertEqual(rep.u.status, expected_fault)
+ self.assertEqual(rep.u.reserved, 0)
+ self.assertEqual(len(rep.u.error_and_verifier), 0)
+
+ if not_executed:
+ # still alive
+ rep = self.recv_pdu(timeout=0.01)
+ self.assertIsNone(rep)
+ self.assertIsConnected()
+ return
+
+ # wait for a disconnect
+ rep = self.recv_pdu()
+ self.assertIsNone(rep)
+ self.assertNotConnected()
+
+ def _test_generic_auth_first_last(self,
+ auth_type,
+ expected_fault,
+ auth_context_2nd=2,
+ expected_call_id=None,
+ expected_context_id=None,
+ conc_mpx=False,
+ not_executed=False,
+ forced_call_id=None,
+ forced_context_id=None,
+ forced_opnum=None,
+ forced_auth_context_id=None,
+ forced_auth_type=None,
+ forced_auth_level=None):
+ pfc_flags_2nd = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST
+ return self._test_generic_auth_first_2nd(auth_type,
+ pfc_flags_2nd,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def _test_generic_auth_first_first(self,
+ auth_type,
+ expected_fault,
+ auth_context_2nd=2,
+ expected_call_id=None,
+ expected_context_id=None,
+ conc_mpx=False,
+ not_executed=False,
+ forced_call_id=None,
+ forced_context_id=None,
+ forced_opnum=None,
+ forced_auth_context_id=None,
+ forced_auth_type=None,
+ forced_auth_level=None):
+ pfc_flags_2nd = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
+ return self._test_generic_auth_first_2nd(auth_type,
+ pfc_flags_2nd,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstSame2(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_SEC_PKG_ERROR
+ auth_context_2nd = 2
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstNext2(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 2
+ expected_call_id = 3
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstSame111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstSame111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstNext111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = 3
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstNext111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = 1
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstSameNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstSameNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = None
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstNextNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstNextNone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstSameNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstSameNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = None
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_first1_firstNextNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = None
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = False
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_multi_auth_MPX_first1_firstNextNone111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ auth_context_2nd = None
+ expected_call_id = 4
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = True
+ forced_call_id = 4
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_first_first(auth_type,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def _test_generic_auth_middle(self,
+ auth_type,
+ expected_fault,
+ expected_context_id=None,
+ not_executed=False,
+ conc_mpx=False,
+ forced_context_id=None,
+ forced_opnum=None,
+ forced_auth_context_id=None,
+ forced_auth_type=None,
+ forced_auth_level=None):
+ auth_context_2nd = 1
+ skip_first = True
+ pfc_flags_2nd = 0
+ expected_call_id = None
+ forced_call_id = None
+ return self._test_generic_auth_first_2nd(auth_type,
+ pfc_flags_2nd,
+ expected_fault,
+ auth_context_2nd=auth_context_2nd,
+ skip_first=skip_first,
+ expected_call_id=expected_call_id,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_call_id=forced_call_id,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_alone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_alone(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_all_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_all_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_UNKNOWN_IF
+ expected_context_id = 0
+ not_executed = True
+ conc_mpx = True
+ forced_context_id = 111
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_auth_all_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = None
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_auth_all_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_context_id = None
+ forced_opnum = 111
+ forced_auth_context_id = 111
+ forced_auth_type = 111
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_auth_context_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = 111
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_auth_context_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = 111
+ forced_auth_type = None
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_auth_type_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = 111
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_auth_type_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = 111
+ forced_auth_level = None
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_middle_auth_level_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_NCA_S_PROTO_ERROR
+ expected_context_id = 0
+ not_executed = False
+ conc_mpx = False
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
+ def test_ntlmssp_auth_MPX_middle_auth_level_111(self):
+ auth_type = dcerpc.DCERPC_AUTH_TYPE_NTLMSSP
+ expected_fault = dcerpc.DCERPC_FAULT_ACCESS_DENIED
+ expected_context_id = None
+ not_executed = False
+ conc_mpx = True
+ forced_context_id = None
+ forced_opnum = None
+ forced_auth_context_id = None
+ forced_auth_type = None
+ forced_auth_level = 111
+ return self._test_generic_auth_middle(auth_type,
+ expected_fault,
+ expected_context_id=expected_context_id,
+ not_executed=not_executed,
+ conc_mpx=conc_mpx,
+ forced_context_id=forced_context_id,
+ forced_opnum=forced_opnum,
+ forced_auth_context_id=forced_auth_context_id,
+ forced_auth_type=forced_auth_type,
+ forced_auth_level=forced_auth_level)
+
def _test_neg_xmit_check_values(self,
req_xmit=None,
req_recv=None,
@@ -1709,7 +2982,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, rep_both)
self.assertEqual(rep.u.max_recv_frag, rep_both)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -1761,7 +3034,7 @@
rep = self.recv_pdu(ndr_print=True, hexdump=True)
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1776,7 +3049,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1792,7 +3065,7 @@
# We get a fault
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -1867,7 +3140,7 @@
auth_length=0)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -1889,7 +3162,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1903,7 +3176,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1917,7 +3190,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -1995,7 +3268,7 @@
# We get a fault back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -2015,7 +3288,7 @@
# We get a fault back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -2037,7 +3310,7 @@
# We get a fault back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -2053,7 +3326,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2099,7 +3372,7 @@
# We get a fault back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -2129,7 +3402,7 @@
# We get a fault back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -2196,7 +3469,7 @@
dcerpc.DCERPC_PFC_FLAG_LAST |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -2244,7 +3517,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2278,7 +3551,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2314,7 +3587,7 @@
pfc_flags=dcerpc.DCERPC_PFC_FLAG_FIRST |
dcerpc.DCERPC_PFC_FLAG_LAST,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -2342,7 +3615,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2377,7 +3650,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2391,7 +3664,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2416,7 +3689,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2451,7 +3724,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2465,7 +3738,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2504,7 +3777,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2518,7 +3791,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2553,7 +3826,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req1.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req1.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -2601,7 +3874,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req2.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -2651,7 +3924,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -2661,7 +3934,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -2692,7 +3965,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -2708,7 +3981,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2728,7 +4001,7 @@
# We don't get an auth_info back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -2748,7 +4021,7 @@
# We get a fault back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -2806,7 +4079,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -2816,7 +4089,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -2847,7 +4120,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -2869,7 +4142,7 @@
# We get a fault back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -2927,7 +4200,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
assoc_group_id = rep.u.assoc_group_id
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
@@ -2938,7 +4211,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -2962,7 +4235,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -3010,7 +4283,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -3020,7 +4293,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3048,7 +4321,7 @@
# We get a fault back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -3099,7 +4372,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -3109,7 +4382,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3138,7 +4411,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3154,7 +4427,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -3174,7 +4447,7 @@
# We don't get an auth_info back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -3206,7 +4479,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -3257,7 +4530,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -3267,7 +4540,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3296,7 +4569,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3312,7 +4585,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -3332,7 +4605,7 @@
# We don't get an auth_info back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -3363,7 +4636,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -3410,7 +4683,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -3420,7 +4693,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3441,7 +4714,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -3494,7 +4767,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -3504,7 +4777,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3525,7 +4798,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -3580,7 +4853,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -3590,7 +4863,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3612,7 +4885,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -3660,7 +4933,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -3670,7 +4943,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3692,7 +4965,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -3747,7 +5020,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -3757,7 +5030,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3779,7 +5052,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -3834,7 +5107,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -3844,7 +5117,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3866,7 +5139,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -3931,7 +5204,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -3941,7 +5214,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -3985,7 +5258,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -4001,7 +5274,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -4021,7 +5294,7 @@
# We don't get an auth_info back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -4145,7 +5418,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -4155,7 +5428,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -4192,7 +5465,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -4257,7 +5530,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -4267,7 +5540,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -4296,7 +5569,7 @@
rep = self.recv_pdu()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -4316,7 +5589,7 @@
# We don't get an auth_info back
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -4376,7 +5649,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_BIND_ACK, req.call_id)
self.assertEqual(rep.u.max_xmit_frag, req.u.max_xmit_frag)
self.assertEqual(rep.u.max_recv_frag, req.u.max_recv_frag)
- self.assertNotEquals(rep.u.assoc_group_id, req.u.assoc_group_id)
+ self.assertNotEqual(rep.u.assoc_group_id, req.u.assoc_group_id)
self.assertEqual(rep.u.secondary_address_size, 4)
self.assertEqual(rep.u.secondary_address, "%d" % self.tcp_port)
self.assertPadding(rep.u._pad1, 2)
@@ -4386,7 +5659,7 @@
self.assertEqual(rep.u.ctx_list[0].reason,
dcerpc.DCERPC_BIND_ACK_REASON_NOT_SPECIFIED)
self.assertNDRSyntaxEquals(rep.u.ctx_list[0].syntax, ndr32)
- self.assertNotEquals(len(rep.u.auth_info), 0)
+ self.assertNotEqual(len(rep.u.auth_info), 0)
a = self.parse_auth(rep.u.auth_info)
from_server = a.credentials
@@ -4407,7 +5680,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -4522,7 +5795,7 @@
self.verify_pdu(rep, dcerpc.DCERPC_PKT_FAULT, req.call_id,
pfc_flags=req.pfc_flags | response_fault_flags,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, ctx1.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -4689,7 +5962,7 @@
(rep, rep_blob) = self.recv_pdu_raw()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=sig_size)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -4757,7 +6030,7 @@
pfc_flags=req.pfc_flags |
dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, ctx1.context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -4806,7 +6079,7 @@
(rep, rep_blob) = self.recv_pdu_raw()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=sig_size)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
@@ -4871,7 +6144,7 @@
(rep, rep_blob) = self.recv_pdu_raw()
self.verify_pdu(rep, dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
auth_length=sig_size)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
diff -Nru samba-4.13.3+dfsg/python/samba/tests/dcerpc/raw_testcase.py samba-4.13.14+dfsg/python/samba/tests/dcerpc/raw_testcase.py
--- samba-4.13.3+dfsg/python/samba/tests/dcerpc/raw_testcase.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/dcerpc/raw_testcase.py 2021-11-08 11:29:14.000000000 +0000
@@ -318,7 +318,7 @@
pfc_flags=req.pfc_flags |
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -358,7 +358,7 @@
if assoc_group_id != 0:
self.assertEqual(rep.u.assoc_group_id, assoc_group_id)
else:
- self.assertNotEquals(rep.u.assoc_group_id, 0)
+ self.assertNotEqual(rep.u.assoc_group_id, 0)
assoc_group_id = rep.u.assoc_group_id
sda_str = self.secondary_address
sda_len = len(sda_str) + 1
@@ -382,7 +382,7 @@
self.assertEqual(rep.auth_length, 0)
self.assertEqual(len(rep.u.auth_info), 0)
return ack
- self.assertNotEquals(rep.auth_length, 0)
+ self.assertNotEqual(rep.auth_length, 0)
self.assertGreater(len(rep.u.auth_info), samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
self.assertEqual(rep.auth_length, len(rep.u.auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
@@ -423,7 +423,7 @@
pfc_flags=req.pfc_flags |
samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_DID_NOT_EXECUTE,
auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, 0)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -448,7 +448,7 @@
if finished:
self.assertEqual(rep.auth_length, 0)
else:
- self.assertNotEquals(rep.auth_length, 0)
+ self.assertNotEqual(rep.auth_length, 0)
self.assertGreaterEqual(len(rep.u.auth_info), samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
self.assertEqual(rep.auth_length, len(rep.u.auth_info) - samba.dcerpc.dcerpc.DCERPC_AUTH_TRAILER_LENGTH)
@@ -523,28 +523,27 @@
if hexdump:
sys.stderr.write("stub_in: %d\n%s" % (len(stub_in), self.hexdump(stub_in)))
- pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
- pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST
- if object is not None:
- pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID
-
- req = self.generate_request_auth(call_id=call_id,
- context_id=ctx.context_id,
- pfc_flags=pfc_flags,
- object=object,
- opnum=io.opnum(),
- stub=stub_in,
- auth_context=auth_context)
- if send_req:
+ pfc_flags = samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_FIRST
+ pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_LAST
+ if object is not None:
+ pfc_flags |= samba.dcerpc.dcerpc.DCERPC_PFC_FLAG_OBJECT_UUID
+
+ req = self.generate_request_auth(call_id=call_id,
+ context_id=ctx.context_id,
+ pfc_flags=pfc_flags,
+ object=object,
+ opnum=io.opnum(),
+ stub=stub_in,
+ auth_context=auth_context)
self.send_pdu(req, ndr_print=ndr_print, hexdump=hexdump)
if recv_rep:
(rep, rep_blob) = self.recv_pdu_raw(timeout=timeout,
ndr_print=ndr_print,
hexdump=hexdump)
if fault_status:
- self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_FAULT, req.call_id,
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_FAULT, call_id,
pfc_flags=fault_pfc_flags, auth_length=0)
- self.assertNotEquals(rep.u.alloc_hint, 0)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
self.assertEqual(rep.u.context_id, fault_context_id)
self.assertEqual(rep.u.cancel_count, 0)
self.assertEqual(rep.u.flags, 0)
@@ -556,12 +555,16 @@
expected_auth_length = 0
if auth_context is not None and \
auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET:
- expected_auth_length = req.auth_length
+ if send_req:
+ expected_auth_length = req.auth_length
+ else:
+ expected_auth_length = rep.auth_length
+
- self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_RESPONSE, req.call_id,
+ self.verify_pdu(rep, samba.dcerpc.dcerpc.DCERPC_PKT_RESPONSE, call_id,
auth_length=expected_auth_length)
- self.assertNotEquals(rep.u.alloc_hint, 0)
- self.assertEqual(rep.u.context_id, req.u.context_id & 0xff)
+ self.assertNotEqual(rep.u.alloc_hint, 0)
+ self.assertEqual(rep.u.context_id, ctx.context_id & 0xff)
self.assertEqual(rep.u.cancel_count, 0)
self.assertGreaterEqual(len(rep.u.stub_and_verifier), rep.u.alloc_hint)
stub_out = self.check_response_auth(rep, rep_blob, auth_context)
@@ -919,12 +922,12 @@
req_data = req_blob[ofs_stub:ofs_trailer]
req_whole = req_blob[0:ofs_sig]
- if auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PRIVACY:
+ if auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PRIVACY:
# TODO: not yet supported here
self.assertTrue(False)
- elif auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET:
+ elif auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_PACKET:
req_sig = auth_context["gensec"].sign_packet(req_data, req_whole)
- elif auth_context["auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_CONNECT:
+ elif auth_context["g_auth_level"] >= dcerpc.DCERPC_AUTH_LEVEL_CONNECT:
self.assertEqual(auth_context["auth_type"],
dcerpc.DCERPC_AUTH_TYPE_NTLMSSP)
req_sig = b"\x01" +b"\x00" *15
diff -Nru samba-4.13.3+dfsg/python/samba/tests/domain_backup_offline.py samba-4.13.14+dfsg/python/samba/tests/domain_backup_offline.py
--- samba-4.13.3+dfsg/python/samba/tests/domain_backup_offline.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/domain_backup_offline.py 2021-08-09 07:17:53.000000000 +0000
@@ -19,8 +19,12 @@
import os
import shutil
import tempfile
-from samba.tests import BlackboxTestCase
+from samba.tests import BlackboxTestCase, BlackboxProcessError
from samba.netcmd import CommandError
+from samba.param import LoadParm
+from samba.join import join_DC
+from samba.credentials import Credentials
+from samba.logger import get_samba_logger
# The backup tests require that a completely clean LoadParm object gets used
# for the restore. Otherwise the same global LP gets re-used, and the LP
@@ -31,6 +35,81 @@
# so that we never inadvertently use .runcmd() by accident.
class DomainBackupOfflineCmp(BlackboxTestCase):
+ def test_domain_backup_offline_nested_tdb(self):
+ self.nested_testcase('tdb')
+
+ def test_domain_backup_offline_nested_mdb(self):
+ self.nested_testcase('mdb')
+
+ def nested_testcase(self, backend):
+ self.prov_dir = self.provision(backend)
+ self.extract_dir = None
+
+ src = os.path.join(self.prov_dir, "private")
+ dst = os.path.join(self.prov_dir, "state", "private")
+
+ # Move private directory inside state directory
+ shutil.move(src, dst)
+
+ smbconf = os.path.join(self.prov_dir, "etc", "smb.conf")
+
+ # Update the conf file
+ lp = LoadParm(filename_for_non_global_lp=smbconf)
+ lp.set("private dir", dst)
+ lp.dump(False, smbconf)
+
+ backup_file = self.backup(self.prov_dir)
+
+ # Ensure each file is only present once in the tar file
+ tf = tarfile.open(backup_file)
+ names = tf.getnames()
+ self.assertEqual(len(names), len(set(names)))
+
+ def test_domain_backup_offline_join_restore_tdb(self):
+ self.join_restore_testcase('tdb')
+
+ def test_domain_backup_offline_join_restore_mdb(self):
+ self.join_restore_testcase('mdb')
+
+ def join_restore_testcase(self, backend):
+ self.prov_dir = self.join(backend)
+ self.extract_dir = None
+
+ try:
+ backup_file = self.backup(self.prov_dir)
+ except BlackboxProcessError as e:
+ self.fail(e)
+
+ self.extract_dir = self.restore(backup_file)
+
+ def test_domain_backup_offline_hard_link_tdb(self):
+ self.hard_link_testcase('tdb')
+
+ def test_domain_backup_offline_hard_link_mdb(self):
+ self.hard_link_testcase('mdb')
+
+ def hard_link_testcase(self, backend):
+ self.prov_dir = self.provision(backend)
+ self.extract_dir = None
+
+ # Create hard links in the private and state directories
+ os.link(os.path.join(self.prov_dir, "private", "krb5.conf"),
+ os.path.join(self.prov_dir, "state", "krb5.conf"))
+
+ backup_file = self.backup(self.prov_dir)
+
+ # Extract the backup
+ self.extract_dir = tempfile.mkdtemp(dir=self.tempdir)
+ tf = tarfile.open(backup_file)
+ tf.extractall(self.extract_dir)
+
+ # Ensure that the hard link in the private directory was backed up,
+ # while the one in the state directory was not.
+ self.assertTrue(os.path.exists(os.path.join(self.extract_dir,
+ "private", "krb5.conf")))
+ self.assertFalse(os.path.exists(os.path.join(self.extract_dir,
+ "statedir", "krb5.conf")))
+
def test_domain_backup_offline_untar_tdb(self):
self.untar_testcase('tdb')
@@ -44,39 +123,33 @@
self.restore_testcase('mdb')
def restore_testcase(self, backend):
- prov_dir, backup_file = self.provision_and_backup(backend)
+ self.prov_dir = self.provision(backend)
+ self.extract_dir = None
+ backup_file = self.backup(self.prov_dir)
- extract_dir = tempfile.mkdtemp(dir=self.tempdir)
- cmd = ("samba-tool domain backup restore --backup-file={f}"
- " --targetdir={d} "
- "--newservername=NEWSERVER").format(f=backup_file, d=extract_dir)
- self.check_output(cmd)
+ self.extract_dir = self.restore(backup_file)
# attrs that are altered by the restore process
ignore_attrs = ["servicePrincipalName", "lastLogonTimestamp",
- "rIDAllocationPool", "rIDAvailablePool",
+ "rIDAllocationPool", "rIDAvailablePool", "rIDUsedPool",
"localPolicyFlags", "operatingSystem", "displayName",
"dnsRecord", "dNSTombstoned",
"msDS-NC-Replica-Locations", "msDS-HasInstantiatedNCs",
"interSiteTopologyGenerator"]
filter_arg = "--filter=" + ",".join(ignore_attrs)
args = ["--two", filter_arg]
- self.ldapcmp(prov_dir, extract_dir, args)
-
- shutil.rmtree(prov_dir)
- shutil.rmtree(extract_dir)
+ self.ldapcmp(self.prov_dir, self.extract_dir, args)
def untar_testcase(self, backend):
- prov_dir, backup_file = self.provision_and_backup(backend)
+ self.prov_dir = self.provision(backend)
+ self.extract_dir = None
+ backup_file = self.backup(self.prov_dir)
- extract_dir = tempfile.mkdtemp(dir=self.tempdir)
+ self.extract_dir = tempfile.mkdtemp(dir=self.tempdir)
tf = tarfile.open(backup_file)
- tf.extractall(extract_dir)
-
- self.ldapcmp(prov_dir, extract_dir)
+ tf.extractall(self.extract_dir)
- shutil.rmtree(prov_dir)
- shutil.rmtree(extract_dir)
+ self.ldapcmp(self.prov_dir, self.extract_dir)
def ldapcmp(self, prov_dir, ex_dir, args=[]):
sam_fn = os.path.join("private", "sam.ldb")
@@ -90,8 +163,8 @@
self.check_output(cmd)
# Test the "samba-tool domain backup" command with ldapcmp
- def provision_and_backup(self, backend):
- prov_dir = tempfile.mkdtemp(dir=self.tempdir)
+ def provision(self, backend):
+ target = tempfile.mkdtemp(dir=self.tempdir)
# Provision domain. Use fake ACLs and store xattrs in tdbs so that
# NTACL backup will work inside the testenv.
@@ -100,13 +173,37 @@
# circumstances, causing the ldapcmp to fail.
prov_cmd = "samba-tool domain provision " +\
"--domain FOO --realm foo.example.com " +\
- "--targetdir {prov_dir} " +\
+ "--targetdir {target} " +\
"--backend-store {backend} " +\
"--host-name OLDSERVER "+\
"--option=\"vfs objects=fake_acls xattr_tdb\""
- prov_cmd = prov_cmd.format(prov_dir=prov_dir, backend=backend)
+ prov_cmd = prov_cmd.format(target=target, backend=backend)
self.check_output(prov_cmd)
+ return target
+
+ def join(self, backend):
+ target = tempfile.mkdtemp(dir=self.tempdir)
+
+ join_cmd = "samba-tool domain join {domain} DC " +\
+ "--server {server} " +\
+ "--realm {realm} " +\
+ "--username {username}%{password} " +\
+ "--targetdir {target} " +\
+ "--backend-store {backend} " +\
+ "--option=\"vfs objects=dfs_samba4 acl_xattr fake_acls xattr_tdb\""
+ join_cmd = join_cmd.format(server=os.environ["DC_SERVER"],
+ domain=os.environ["DOMAIN"],
+ realm=os.environ["REALM"],
+ username=os.environ["USERNAME"],
+ password=os.environ["PASSWORD"],
+ target=target,
+ backend=backend)
+ self.check_output(join_cmd)
+
+ return target
+
+ def backup(self, prov_dir):
# Run the backup and check we got one backup tar file
cmd = ("samba-tool domain backup offline --targetdir={prov_dir} "
"-s {prov_dir}/etc/smb.conf").format(prov_dir=prov_dir)
@@ -120,4 +217,21 @@
" file but got {0}".format(len(tar_files)))
backup_file = os.path.join(prov_dir, tar_files[0])
- return prov_dir, backup_file
+ return backup_file
+
+ def restore(self, backup_file):
+ # Restore from a backup file
+ extract_dir = tempfile.mkdtemp(dir=self.tempdir)
+ cmd = ("samba-tool domain backup restore --backup-file={f}"
+ " --targetdir={d} "
+ "--newservername=NEWSERVER").format(f=backup_file,
+ d=extract_dir)
+ self.check_output(cmd)
+
+ return extract_dir
+
+ def tearDown(self):
+ # Remove temporary directories
+ shutil.rmtree(self.prov_dir)
+ if self.extract_dir:
+ shutil.rmtree(self.extract_dir)
diff -Nru samba-4.13.3+dfsg/python/samba/tests/dsdb_api.py samba-4.13.14+dfsg/python/samba/tests/dsdb_api.py
--- samba-4.13.3+dfsg/python/samba/tests/dsdb_api.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/dsdb_api.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,57 @@
+# Unix SMB/CIFS implementation. Tests for dsdb
+# Copyright (C) Andrew Bartlett 2021
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+"""Tests for samba.dsdb."""
+
+from samba.tests import TestCase, DynamicTestCase
+from samba.dsdb import user_account_control_flag_bit_to_string
+import samba
+
+
+@DynamicTestCase
+class DsdbFlagTests(TestCase):
+
+ @classmethod
+ def setUpDynamicTestCases(cls):
+
+ for x in dir(samba.dsdb):
+ if x.startswith("UF_"):
+ cls.generate_dynamic_test("test",
+ x,
+ x,
+ getattr(samba.dsdb, x))
+
+
+ def _test_with_args(self, uf_string, uf_bit):
+ self.assertEqual(user_account_control_flag_bit_to_string(uf_bit),
+ uf_string)
+
+
+ def test_not_a_flag(self):
+ self.assertRaises(KeyError,
+ user_account_control_flag_bit_to_string,
+ 0xabcdef)
+
+ def test_too_long(self):
+ self.assertRaises(OverflowError,
+ user_account_control_flag_bit_to_string,
+ 0xabcdefffff)
+
+ def test_way_too_long(self):
+ self.assertRaises(OverflowError,
+ user_account_control_flag_bit_to_string,
+ 0xabcdeffffffffffff)
diff -Nru samba-4.13.3+dfsg/python/samba/tests/dsdb.py samba-4.13.14+dfsg/python/samba/tests/dsdb.py
--- samba-4.13.3+dfsg/python/samba/tests/dsdb.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/dsdb.py 2021-08-09 07:17:53.000000000 +0000
@@ -50,13 +50,316 @@
base_dn = self.samdb.domain_dn()
- self.account_dn = "cn=" + user_name + ",cn=Users," + base_dn
+ self.account_dn = "CN=" + user_name + ",CN=Users," + base_dn
self.samdb.newuser(username=user_name,
password=user_pass,
description=user_description)
# Cleanup (teardown)
self.addCleanup(delete_force, self.samdb, self.account_dn)
+ # Get server reference DN
+ res = self.samdb.search(base=ldb.Dn(self.samdb,
+ self.samdb.get_serverName()),
+ scope=ldb.SCOPE_BASE,
+ attrs=["serverReference"])
+ # Get server reference
+ self.server_ref_dn = ldb.Dn(
+ self.samdb, res[0]["serverReference"][0].decode("utf-8"))
+
+ # Get RID Set DN
+ res = self.samdb.search(base=self.server_ref_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=["rIDSetReferences"])
+ rid_set_refs = res[0]
+ self.assertIn("rIDSetReferences", rid_set_refs)
+ rid_set_str = rid_set_refs["rIDSetReferences"][0].decode("utf-8")
+ self.rid_set_dn = ldb.Dn(self.samdb, rid_set_str)
+
+ def get_rid_set(self, rid_set_dn):
+ res = self.samdb.search(base=rid_set_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=["rIDAllocationPool",
+ "rIDPreviousAllocationPool",
+ "rIDUsedPool",
+ "rIDNextRID"])
+ return res[0]
+
+ def test_ridalloc_next_free_rid(self):
+ # Test RID allocation. We assume that RID
+ # pools allocated to us are continguous.
+ self.samdb.transaction_start()
+ try:
+ orig_rid_set = self.get_rid_set(self.rid_set_dn)
+ self.assertIn("rIDAllocationPool", orig_rid_set)
+ self.assertIn("rIDPreviousAllocationPool", orig_rid_set)
+ self.assertIn("rIDUsedPool", orig_rid_set)
+ self.assertIn("rIDNextRID", orig_rid_set)
+
+ # Get rIDNextRID value from RID set.
+ next_rid = int(orig_rid_set["rIDNextRID"][0])
+
+ # Check the result of next_free_rid().
+ next_free_rid = self.samdb.next_free_rid()
+ self.assertEqual(next_rid + 1, next_free_rid)
+
+ # Check calling it twice in succession gives the same result.
+ next_free_rid2 = self.samdb.next_free_rid()
+ self.assertEqual(next_free_rid, next_free_rid2)
+
+ # Ensure that the RID set attributes have not changed.
+ rid_set2 = self.get_rid_set(self.rid_set_dn)
+ self.assertEqual(orig_rid_set, rid_set2)
+ finally:
+ self.samdb.transaction_cancel()
+
+ def test_ridalloc_no_ridnextrid(self):
+ self.samdb.transaction_start()
+ try:
+ # Delete the rIDNextRID attribute of the RID set,
+ # and set up previous and next pools.
+ prev_lo = 1000
+ prev_hi = 1999
+ next_lo = 3000
+ next_hi = 3999
+ msg = ldb.Message()
+ msg.dn = self.rid_set_dn
+ msg["rIDNextRID"] = ldb.MessageElement([],
+ ldb.FLAG_MOD_DELETE,
+ "rIDNextRID")
+ msg["rIDPreviousAllocationPool"] = (
+ ldb.MessageElement(str((prev_hi << 32) | prev_lo),
+ ldb.FLAG_MOD_REPLACE,
+ "rIDPreviousAllocationPool"))
+ msg["rIDAllocationPool"] = (
+ ldb.MessageElement(str((next_hi << 32) | next_lo),
+ ldb.FLAG_MOD_REPLACE,
+ "rIDAllocationPool"))
+ self.samdb.modify(msg)
+
+ # Ensure that next_free_rid() returns the start of the next pool
+ # plus one.
+ next_free_rid3 = self.samdb.next_free_rid()
+ self.assertEqual(next_lo + 1, next_free_rid3)
+
+ # Check the result of allocate_rid() matches.
+ rid = self.samdb.allocate_rid()
+ self.assertEqual(next_free_rid3, rid)
+
+ # Check that the result of next_free_rid() has now changed.
+ next_free_rid4 = self.samdb.next_free_rid()
+ self.assertEqual(rid + 1, next_free_rid4)
+
+ # Check the range of available RIDs.
+ free_lo, free_hi = self.samdb.free_rid_bounds()
+ self.assertEqual(rid + 1, free_lo)
+ self.assertEqual(next_hi, free_hi)
+ finally:
+ self.samdb.transaction_cancel()
+
+ def test_ridalloc_no_free_rids(self):
+ self.samdb.transaction_start()
+ try:
+ # Exhaust our current pool of RIDs.
+ pool_lo = 2000
+ pool_hi = 2999
+ msg = ldb.Message()
+ msg.dn = self.rid_set_dn
+ msg["rIDPreviousAllocationPool"] = (
+ ldb.MessageElement(str((pool_hi << 32) | pool_lo),
+ ldb.FLAG_MOD_REPLACE,
+ "rIDPreviousAllocationPool"))
+ msg["rIDAllocationPool"] = (
+ ldb.MessageElement(str((pool_hi << 32) | pool_lo),
+ ldb.FLAG_MOD_REPLACE,
+ "rIDAllocationPool"))
+ msg["rIDNextRID"] = (
+ ldb.MessageElement(str(pool_hi),
+ ldb.FLAG_MOD_REPLACE,
+ "rIDNextRID"))
+ self.samdb.modify(msg)
+
+ # Ensure that calculating the next free RID fails.
+ with self.assertRaises(ldb.LdbError) as err:
+ self.samdb.next_free_rid()
+
+ self.assertEqual("RID pools out of RIDs", err.exception.args[1])
+
+ # Ensure we can still allocate a new RID.
+ self.samdb.allocate_rid()
+ finally:
+ self.samdb.transaction_cancel()
+
+ def test_ridalloc_new_ridset(self):
+ self.samdb.transaction_start()
+ try:
+ # Test what happens with RID Set values set to zero (similar to
+ # when a RID Set is first created, except we also set
+ # rIDAllocationPool to zero).
+ msg = ldb.Message()
+ msg.dn = self.rid_set_dn
+ msg["rIDPreviousAllocationPool"] = (
+ ldb.MessageElement("0",
+ ldb.FLAG_MOD_REPLACE,
+ "rIDPreviousAllocationPool"))
+ msg["rIDAllocationPool"] = (
+ ldb.MessageElement("0",
+ ldb.FLAG_MOD_REPLACE,
+ "rIDAllocationPool"))
+ msg["rIDNextRID"] = (
+ ldb.MessageElement("0",
+ ldb.FLAG_MOD_REPLACE,
+ "rIDNextRID"))
+ self.samdb.modify(msg)
+
+ # Ensure that calculating the next free RID fails.
+ with self.assertRaises(ldb.LdbError) as err:
+ self.samdb.next_free_rid()
+
+ self.assertEqual("RID pools out of RIDs", err.exception.args[1])
+
+ # Set values for the next pool.
+ pool_lo = 2000
+ pool_hi = 2999
+ msg = ldb.Message()
+ msg.dn = self.rid_set_dn
+ msg["rIDAllocationPool"] = (
+ ldb.MessageElement(str((pool_hi << 32) | pool_lo),
+ ldb.FLAG_MOD_REPLACE,
+ "rIDAllocationPool"))
+ self.samdb.modify(msg)
+
+ # Ensure the next free RID value is equal to the next pool's lower
+ # bound.
+ next_free_rid5 = self.samdb.next_free_rid()
+ self.assertEqual(pool_lo, next_free_rid5)
+
+ # Check the range of available RIDs.
+ free_lo, free_hi = self.samdb.free_rid_bounds()
+ self.assertEqual(pool_lo, free_lo)
+ self.assertEqual(pool_hi, free_hi)
+ finally:
+ self.samdb.transaction_cancel()
+
+ def test_ridalloc_move_to_new_pool(self):
+ self.samdb.transaction_start()
+ try:
+ # Test moving to a new pool from the previous pool.
+ pool_lo = 2000
+ pool_hi = 2999
+ new_pool_lo = 4500
+ new_pool_hi = 4599
+ msg = ldb.Message()
+ msg.dn = self.rid_set_dn
+ msg["rIDPreviousAllocationPool"] = (
+ ldb.MessageElement(str((pool_hi << 32) | pool_lo),
+ ldb.FLAG_MOD_REPLACE,
+ "rIDPreviousAllocationPool"))
+ msg["rIDAllocationPool"] = (
+ ldb.MessageElement(str((new_pool_hi << 32) | new_pool_lo),
+ ldb.FLAG_MOD_REPLACE,
+ "rIDAllocationPool"))
+ msg["rIDNextRID"] = (
+ ldb.MessageElement(str(pool_hi - 1),
+ ldb.FLAG_MOD_REPLACE,
+ "rIDNextRID"))
+ self.samdb.modify(msg)
+
+ # We should have remained in the previous pool.
+ next_free_rid6 = self.samdb.next_free_rid()
+ self.assertEqual(pool_hi, next_free_rid6)
+
+ # Check the range of available RIDs.
+ free_lo, free_hi = self.samdb.free_rid_bounds()
+ self.assertEqual(pool_hi, free_lo)
+ self.assertEqual(pool_hi, free_hi)
+
+ # Allocate a new RID.
+ rid2 = self.samdb.allocate_rid()
+ self.assertEqual(next_free_rid6, rid2)
+
+ # We should now move to the next pool.
+ next_free_rid7 = self.samdb.next_free_rid()
+ self.assertEqual(new_pool_lo, next_free_rid7)
+
+ # Check the new range of available RIDs.
+ free_lo2, free_hi2 = self.samdb.free_rid_bounds()
+ self.assertEqual(new_pool_lo, free_lo2)
+ self.assertEqual(new_pool_hi, free_hi2)
+
+ # Ensure that allocate_rid() matches.
+ rid3 = self.samdb.allocate_rid()
+ self.assertEqual(next_free_rid7, rid3)
+ finally:
+ self.samdb.transaction_cancel()
+
+ def test_ridalloc_no_ridsetreferences(self):
+ self.samdb.transaction_start()
+ try:
+ # Delete the rIDSetReferences attribute.
+ msg = ldb.Message()
+ msg.dn = self.server_ref_dn
+ msg["rIDSetReferences"] = (
+ ldb.MessageElement([],
+ ldb.FLAG_MOD_DELETE,
+ "rIDSetReferences"))
+ self.samdb.modify(msg)
+
+ # Ensure calculating the next free RID fails.
+ with self.assertRaises(ldb.LdbError) as err:
+ self.samdb.next_free_rid()
+
+ enum, estr = err.exception.args
+ self.assertEqual(ldb.ERR_NO_SUCH_ATTRIBUTE, enum)
+ self.assertIn("No RID Set DN - "
+ "Cannot find attribute rIDSetReferences of %s "
+ "to calculate reference dn" % self.server_ref_dn,
+ estr)
+
+ # Ensure allocating a new RID fails.
+ with self.assertRaises(ldb.LdbError) as err:
+ self.samdb.allocate_rid()
+
+ enum, estr = err.exception.args
+ self.assertEqual(ldb.ERR_ENTRY_ALREADY_EXISTS, enum)
+ self.assertIn("No RID Set DN - "
+ "Failed to add RID Set %s - "
+ "Entry %s already exists" %
+ (self.rid_set_dn, self.rid_set_dn),
+ estr)
+ finally:
+ self.samdb.transaction_cancel()
+
+ def test_ridalloc_no_rid_set(self):
+ self.samdb.transaction_start()
+ try:
+ # Set the rIDSetReferences attribute to not point to a RID Set.
+ fake_rid_set_str = self.account_dn
+ msg = ldb.Message()
+ msg.dn = self.server_ref_dn
+ msg["rIDSetReferences"] = (
+ ldb.MessageElement(fake_rid_set_str,
+ ldb.FLAG_MOD_REPLACE,
+ "rIDSetReferences"))
+ self.samdb.modify(msg)
+
+ # Ensure calculating the next free RID fails.
+ with self.assertRaises(ldb.LdbError) as err:
+ self.samdb.next_free_rid()
+
+ enum, estr = err.exception.args
+ self.assertEqual(ldb.ERR_OPERATIONS_ERROR, enum)
+ self.assertIn("Bad RID Set " + fake_rid_set_str, estr)
+
+ # Ensure allocating a new RID fails.
+ with self.assertRaises(ldb.LdbError) as err:
+ self.samdb.allocate_rid()
+
+ enum, estr = err.exception.args
+ self.assertEqual(ldb.ERR_OPERATIONS_ERROR, enum)
+ self.assertIn("Bad RID Set " + fake_rid_set_str, estr)
+ finally:
+ self.samdb.transaction_cancel()
+
def test_get_oid_from_attrid(self):
oid = self.samdb.get_oid_from_attid(591614)
self.assertEqual(oid, "1.2.840.113556.1.4.1790")
diff -Nru samba-4.13.3+dfsg/python/samba/tests/dsdb_schema_attributes.py samba-4.13.14+dfsg/python/samba/tests/dsdb_schema_attributes.py
--- samba-4.13.3+dfsg/python/samba/tests/dsdb_schema_attributes.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/dsdb_schema_attributes.py 2021-09-22 06:59:39.000000000 +0000
@@ -87,7 +87,7 @@
def test_AddIndexedAttribute(self):
# create names for an attribute to add
- (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("schemaAttributes-Attr-")
+ (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("schemaAttributes-IdxAttr-")
ldif = self._make_attr_ldif(attr_name, attr_dn, 1,
"searchFlags: %d" % samba.dsdb.SEARCH_FLAG_ATTINDEX)
@@ -111,7 +111,7 @@
def test_AddUnIndexedAttribute(self):
# create names for an attribute to add
- (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("schemaAttributes-Attr-")
+ (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("schemaAttributes-UnIdxAttr-")
ldif = self._make_attr_ldif(attr_name, attr_dn, 2)
# add the new attribute
@@ -134,7 +134,7 @@
def test_AddTwoIndexedAttributes(self):
# create names for an attribute to add
- (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("schemaAttributes-Attr-")
+ (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("schemaAttributes-2IdxAttr-")
ldif = self._make_attr_ldif(attr_name, attr_dn, 3,
"searchFlags: %d" % samba.dsdb.SEARCH_FLAG_ATTINDEX)
diff -Nru samba-4.13.3+dfsg/python/samba/tests/__init__.py samba-4.13.14+dfsg/python/samba/tests/__init__.py
--- samba-4.13.3+dfsg/python/samba/tests/__init__.py 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/__init__.py 2021-11-08 11:29:14.000000000 +0000
@@ -21,6 +21,7 @@
import os
import tempfile
import warnings
+import collections
import ldb
import samba
from samba import param
@@ -63,6 +64,22 @@
HEXDUMP_FILTER = bytearray([x if ((len(repr(chr(x))) == 3) and (x < 127)) else ord('.') for x in range(256)])
+LDB_ERR_LUT = {v: k for k,v in vars(ldb).items() if k.startswith('ERR_')}
+
+def ldb_err(v):
+ if isinstance(v, ldb.LdbError):
+ v = v.args[0]
+
+ if v in LDB_ERR_LUT:
+ return LDB_ERR_LUT[v]
+
+ try:
+ return f"[{', '.join(LDB_ERR_LUT.get(x, x) for x in v)}]"
+ except TypeError as e:
+ print(e)
+ return v
+
+
def DynamicTestCase(cls):
cls.setUpDynamicTestCases()
return cls
@@ -71,7 +88,7 @@
"""A Samba test case."""
@classmethod
- def generate_dynamic_test(cls, fnname, suffix, *args):
+ def generate_dynamic_test(cls, fnname, suffix, *args, doc=None):
"""
fnname is something like "test_dynamic_sum"
suffix is something like "1plus2"
@@ -84,7 +101,11 @@
"""
def fn(self):
getattr(self, "_%s_with_args" % fnname)(*args)
- setattr(cls, "%s_%s" % (fnname, suffix), fn)
+ fn.__doc__ = doc
+ attr = "%s_%s" % (fnname, suffix)
+ if hasattr(cls, attr):
+ raise RuntimeError(f"Dynamic test {attr} already exists!")
+ setattr(cls, attr, fn)
@classmethod
def setUpDynamicTestCases(cls):
@@ -297,6 +318,42 @@
self.fail(msg)
+ def assertRaisesLdbError(self, errcode, message, f, *args, **kwargs):
+ """Assert a function raises a particular LdbError."""
+ if message is None:
+ message = f"{f.__name__}(*{args}, **{kwargs})"
+ try:
+ f(*args, **kwargs)
+ except ldb.LdbError as e:
+ (num, msg) = e.args
+ if isinstance(errcode, collections.abc.Container):
+ found = num in errcode
+ else:
+ found = num == errcode
+ if not found:
+ lut = {v: k for k, v in vars(ldb).items()
+ if k.startswith('ERR_') and isinstance(v, int)}
+ if isinstance(errcode, collections.abc.Container):
+ errcode_name = ' '.join(lut.get(x) for x in errcode)
+ else:
+ errcode_name = lut.get(errcode)
+ self.fail(f"{message}, expected "
+ f"LdbError {errcode_name}, {errcode} "
+ f"got {lut.get(num)} ({num}) "
+ f"{msg}")
+ else:
+ lut = {v: k for k, v in vars(ldb).items()
+ if k.startswith('ERR_') and isinstance(v, int)}
+ if isinstance(errcode, collections.abc.Container):
+ errcode_name = ' '.join(lut.get(x) for x in errcode)
+ else:
+ errcode_name = lut.get(errcode)
+ self.fail("%s, expected "
+ "LdbError %s, (%s) "
+ "but we got success" % (message,
+ errcode_name,
+ errcode))
+
class LdbTestCase(TestCase):
"""Trivial test case for running tests against a LDB."""
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/alias_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/alias_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/alias_tests.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/alias_tests.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,201 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) 2021 Catalyst.Net Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+import ldb
+
+from samba.tests import delete_force
+import samba.tests.krb5.kcrypto as kcrypto
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+from samba.tests.krb5.rfc4120_constants import (
+ AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ KDC_ERR_CLIENT_NAME_MISMATCH,
+ NT_PRINCIPAL,
+)
+
+sys.path.insert(0, 'bin/python')
+os.environ['PYTHONUNBUFFERED'] = '1'
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class AliasTests(KDCBaseTest):
+ def test_dc_alias_rename(self):
+ self._run_dc_alias(action='rename')
+
+ def test_dc_alias_delete(self):
+ self._run_dc_alias(action='delete')
+
+ def _run_dc_alias(self, action=None):
+ target_creds = self.get_dc_creds()
+ target_name = target_creds.get_username()[:-1]
+
+ self._run_alias(target_name, lambda: target_creds, action=action)
+
+ def test_create_alias_rename(self):
+ self._run_create_alias(action='rename')
+
+ def test_create_alias_delete(self):
+ self._run_create_alias(action='delete')
+
+ def _run_create_alias(self, action=None):
+ target_name = self.get_new_username()
+
+ def create_target():
+ samdb = self.get_samdb()
+
+ realm = samdb.domain_dns_name().lower()
+
+ hostname = f'{target_name}.{realm}'
+ spn = f'ldap/{hostname}'
+
+ details = {
+ 'dNSHostName': hostname
+ }
+
+ creds, fn = self.create_account(
+ samdb,
+ target_name,
+ account_type=self.AccountType.COMPUTER,
+ spn=spn,
+ additional_details=details)
+
+ return creds
+
+ self._run_alias(target_name, create_target, action=action)
+
+ def _run_alias(self, target_name, target_creds_fn, action=None):
+ samdb = self.get_samdb()
+
+ mach_name = self.get_new_username()
+
+ # Create a machine account.
+ mach_creds, mach_dn = self.create_account(
+ samdb, mach_name, account_type=self.AccountType.COMPUTER)
+ self.addCleanup(delete_force, samdb, mach_dn)
+
+ mach_sid = self.get_objectSid(samdb, mach_dn)
+ realm = mach_creds.get_realm()
+
+ # The account salt doesn't change when the account is renamed.
+ old_salt = mach_creds.get_salt()
+ mach_creds.set_forced_salt(old_salt)
+
+ # Rename the account to alias with the target account.
+ msg = ldb.Message(ldb.Dn(samdb, mach_dn))
+ msg['sAMAccountName'] = ldb.MessageElement(target_name,
+ ldb.FLAG_MOD_REPLACE,
+ 'sAMAccountName')
+ samdb.modify(msg)
+ mach_creds.set_username(target_name)
+
+ # Get a TGT for the machine account.
+ tgt = self.get_tgt(mach_creds, kdc_options='0', fresh=True)
+
+ # Check the PAC.
+ pac_data = self.get_pac_data(tgt.ticket_private['authorization-data'])
+
+ upn = f'{target_name}@{realm.lower()}'
+
+ self.assertEqual(target_name, str(pac_data.account_name))
+ self.assertEqual(mach_sid, pac_data.account_sid)
+ self.assertEqual(target_name, pac_data.logon_name)
+ self.assertEqual(upn, pac_data.upn)
+ self.assertEqual(realm, pac_data.domain_name)
+
+ # Rename or delete the machine account.
+ if action == 'rename':
+ mach_name2 = self.get_new_username()
+
+ msg = ldb.Message(ldb.Dn(samdb, mach_dn))
+ msg['sAMAccountName'] = ldb.MessageElement(mach_name2,
+ ldb.FLAG_MOD_REPLACE,
+ 'sAMAccountName')
+ samdb.modify(msg)
+ elif action == 'delete':
+ samdb.delete(mach_dn)
+ else:
+ self.fail(action)
+
+ # Get the credentials for the target account.
+ target_creds = target_creds_fn()
+
+ # Look up the DNS host name of the target account.
+ target_dn = target_creds.get_dn()
+ res = samdb.search(target_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=['dNSHostName'])
+ target_hostname = str(res[0].get('dNSHostName', idx=0))
+
+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=['ldap', target_hostname])
+ target_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[target_name])
+
+ target_decryption_key = self.TicketDecryptionKey_from_creds(
+ target_creds)
+
+ authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256)
+
+ etypes = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+
+ def generate_s4u2self_padata(_kdc_exchange_dict,
+ _callback_dict,
+ req_body):
+ padata = self.PA_S4U2Self_create(name=target_cname,
+ realm=realm,
+ tgt_session_key=tgt.session_key,
+ ctype=None)
+ return [padata], req_body
+
+ expected_error_mode = KDC_ERR_CLIENT_NAME_MISMATCH
+
+ # Make a request using S4U2Self. The request should fail.
+ kdc_exchange_dict = self.tgs_exchange_dict(
+ expected_crealm=realm,
+ expected_cname=target_cname,
+ expected_srealm=realm,
+ expected_sname=sname,
+ ticket_decryption_key=target_decryption_key,
+ generate_padata_fn=generate_s4u2self_padata,
+ expected_error_mode=expected_error_mode,
+ check_error_fn=self.generic_check_kdc_error,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ tgt=tgt,
+ authenticator_subkey=authenticator_subkey,
+ kdc_options='0',
+ expect_pac=True)
+
+ rep = self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=None,
+ realm=realm,
+ sname=sname,
+ etypes=etypes)
+ self.check_error_rep(rep, expected_error_mode)
+
+
+if __name__ == '__main__':
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/as_canonicalization_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/as_canonicalization_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/as_canonicalization_tests.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/as_canonicalization_tests.py 2021-10-29 06:17:36.000000000 +0000
@@ -0,0 +1,435 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+#
+# Copyright (C) Catalyst IT Ltd. 2020
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+from enum import Enum, unique
+import pyasn1
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
+from samba.credentials import DONT_USE_KERBEROS
+from samba.dcerpc.misc import SEC_CHAN_WKSTA
+from samba.tests import DynamicTestCase
+from samba.tests.krb5.rfc4120_constants import (
+ AES256_CTS_HMAC_SHA1_96,
+ AES128_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ KDC_ERR_PREAUTH_REQUIRED,
+ KRB_AS_REP,
+ KU_AS_REP_ENC_PART,
+ KRB_ERROR,
+ KU_PA_ENC_TIMESTAMP,
+ PADATA_ENC_TIMESTAMP,
+ NT_ENTERPRISE_PRINCIPAL,
+ NT_PRINCIPAL,
+ NT_SRV_INST,
+)
+
+global_asn1_print = False
+global_hexdump = False
+
+
+@unique
+class TestOptions(Enum):
+ Canonicalize = 1
+ Enterprise = 2
+ UpperRealm = 4
+ UpperUserName = 8
+ NetbiosRealm = 16
+ UPN = 32
+ RemoveDollar = 64
+ AsReqSelf = 128
+ Last = 256
+
+ def is_set(self, x):
+ return self.value & x
+
+
+@unique
+class CredentialsType(Enum):
+ User = 1
+ Machine = 2
+
+ def is_set(self, x):
+ return self.value & x
+
+
+class TestData:
+
+ def __init__(self, options, creds):
+ self.options = options
+ self.user_creds = creds
+ self.user_name = self._get_username(options, creds)
+ self.realm = self._get_realm(options, creds)
+
+ if TestOptions.Enterprise.is_set(options):
+ client_name_type = NT_ENTERPRISE_PRINCIPAL
+ else:
+ client_name_type = NT_PRINCIPAL
+
+ self.cname = KDCBaseTest.PrincipalName_create(
+ name_type=client_name_type, names=[self.user_name])
+ if TestOptions.AsReqSelf.is_set(options):
+ self.sname = self.cname
+ else:
+ self.sname = KDCBaseTest.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", self.realm])
+ self.canonicalize = TestOptions.Canonicalize.is_set(options)
+
+ def _get_realm(self, options, creds):
+ realm = creds.get_realm()
+ if TestOptions.NetbiosRealm.is_set(options):
+ realm = creds.get_domain()
+ if TestOptions.UpperRealm.is_set(options):
+ realm = realm.upper()
+ else:
+ realm = realm.lower()
+ return realm
+
+ def _get_username(self, options, creds):
+ name = creds.get_username()
+ if TestOptions.RemoveDollar.is_set(options) and name.endswith("$"):
+ name = name[:-1]
+ if TestOptions.Enterprise.is_set(options):
+ realm = creds.get_realm()
+ name = "{0}@{1}".format(name, realm)
+ if TestOptions.UpperUserName.is_set(options):
+ name = name.upper()
+ return name
+
+ def __repr__(self):
+ rep = "Test Data: "
+ rep += "options = '" + "{:08b}".format(self.options) + "'"
+ rep += "user name = '" + self.user_name + "'"
+ rep += ", realm = '" + self.realm + "'"
+ rep += ", cname = '" + str(self.cname) + "'"
+ rep += ", sname = '" + str(self.sname) + "'"
+ return rep
+
+
+MACHINE_NAME = "tstkrb5cnnmch"
+USER_NAME = "tstkrb5cnnusr"
+
+
+@DynamicTestCase
+class KerberosASCanonicalizationTests(KDCBaseTest):
+
+ @classmethod
+ def setUpDynamicTestCases(cls):
+
+ def skip(ct, options):
+ ''' Filter out any mutually exclusive test options '''
+ if ct != CredentialsType.Machine and\
+ TestOptions.RemoveDollar.is_set(options):
+ return True
+ if ct != CredentialsType.Machine and\
+ TestOptions.AsReqSelf.is_set(options):
+ return True
+ return False
+
+ def build_test_name(ct, options):
+ name = "%sCredentials" % ct.name
+ for opt in TestOptions:
+ if opt.is_set(options):
+ name += ("_%s" % opt.name)
+ return name
+
+ for ct in CredentialsType:
+ for x in range(TestOptions.Last.value):
+ if skip(ct, x):
+ continue
+ name = build_test_name(ct, x)
+ cls.generate_dynamic_test("test", name, x, ct)
+
+ def user_account_creds(self):
+ if self.user_creds is None:
+ samdb = self.get_samdb()
+ self.user_creds, _ = self.create_account(samdb, USER_NAME)
+
+ return self.user_creds
+
+ def machine_account_creds(self):
+ if self.machine_creds is None:
+ samdb = self.get_samdb()
+ self.machine_creds, _ = self.create_account(
+ samdb,
+ MACHINE_NAME,
+ account_type=self.AccountType.COMPUTER)
+ self.machine_creds.set_secure_channel_type(SEC_CHAN_WKSTA)
+ self.machine_creds.set_kerberos_state(DONT_USE_KERBEROS)
+
+ return self.machine_creds
+
+ def setUp(self):
+ super().setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ self.user_creds = None
+ self.machine_creds = None
+
+ def _test_with_args(self, x, ct):
+ if ct == CredentialsType.User:
+ creds = self.user_account_creds()
+ elif ct == CredentialsType.Machine:
+ creds = self.machine_account_creds()
+ else:
+ raise Exception("Unexpected credential type")
+ data = TestData(x, creds)
+
+ try:
+ (rep, as_rep) = self.as_req(data)
+ except pyasn1.error.PyAsn1Error as e:
+ import traceback
+ self.fail("ASN1 Error, Options {0:08b}:{1} {2}".format(
+ data.options,
+ traceback.format_exc(),
+ e))
+ # If as_req triggered an expected server error response
+ # No need to test the response data.
+ if rep is not None:
+ # The kvno is optional, heimdal includes it
+ # MIT does not.
+ if 'kvno' in rep['enc-part']:
+ kvno = rep['enc-part']['kvno']
+ self.check_kvno(kvno, data)
+
+ cname = rep['cname']
+ self.check_cname(cname, data)
+
+ crealm = rep['crealm'].decode('ascii')
+ self.check_crealm(crealm, data)
+
+ sname = as_rep['sname']
+ self.check_sname(sname, data)
+
+ srealm = as_rep['srealm'].decode('ascii')
+ self.check_srealm(srealm, data)
+
+ def as_req(self, data):
+ user_creds = data.user_creds
+ realm = data.realm
+
+ cname = data.cname
+ sname = data.sname
+
+ till = self.get_KerberosTime(offset=36000)
+
+ kdc_options = "0"
+ if data.canonicalize:
+ kdc_options = str(krb5_asn1.KDCOptions('canonicalize'))
+
+ padata = None
+
+ # Set the allowable encryption types
+ etypes = (
+ AES256_CTS_HMAC_SHA1_96,
+ AES128_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5)
+
+ req = self.AS_REQ_create(padata=padata,
+ kdc_options=kdc_options,
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ from_time=None,
+ till_time=till,
+ renew_time=None,
+ nonce=0x7fffffff,
+ etypes=etypes,
+ addresses=None,
+ additional_tickets=None)
+ rep = self.send_recv_transaction(req)
+ self.assertIsNotNone(rep)
+
+ #
+ # Check the protocol version, should be 5
+ self.assertEqual(
+ rep['pvno'], 5, "Data {0}".format(str(data)))
+
+ self.assertEqual(
+ rep['msg-type'], KRB_ERROR, "Data {0}".format(str(data)))
+
+ self.assertEqual(
+ rep['error-code'],
+ KDC_ERR_PREAUTH_REQUIRED,
+ "Error code {0}, Data {1}".format(rep['error-code'], str(data)))
+
+ rep_padata = self.der_decode(
+ rep['e-data'], asn1Spec=krb5_asn1.METHOD_DATA())
+
+ for pa in rep_padata:
+ if pa['padata-type'] == 19:
+ etype_info2 = pa['padata-value']
+ break
+
+ etype_info2 = self.der_decode(
+ etype_info2, asn1Spec=krb5_asn1.ETYPE_INFO2())
+
+ key = self.PasswordKey_from_etype_info2(user_creds, etype_info2[0])
+
+ (patime, pausec) = self.get_KerberosTimeWithUsec()
+ pa_ts = self.PA_ENC_TS_ENC_create(patime, pausec)
+ pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
+
+ pa_ts = self.EncryptedData_create(key, KU_PA_ENC_TIMESTAMP, pa_ts)
+ pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.EncryptedData())
+
+ pa_ts = self.PA_DATA_create(PADATA_ENC_TIMESTAMP, pa_ts)
+
+ kdc_options = "0"
+ if data.canonicalize:
+ kdc_options = str(krb5_asn1.KDCOptions('canonicalize'))
+ padata = [pa_ts]
+
+ req = self.AS_REQ_create(padata=padata,
+ kdc_options=kdc_options,
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ from_time=None,
+ till_time=till,
+ renew_time=None,
+ nonce=0x7fffffff,
+ etypes=etypes,
+ addresses=None,
+ additional_tickets=None)
+ rep = self.send_recv_transaction(req)
+ self.assertIsNotNone(rep)
+
+ #
+ # Check the protocol version, should be 5
+ self.assertEqual(
+ rep['pvno'], 5, "Data {0}".format(str(data)))
+
+ msg_type = rep['msg-type']
+ # Should not have got an error.
+ # If we did, fail and print the error code to help debugging
+ self.assertNotEqual(
+ msg_type,
+ KRB_ERROR,
+ "Error code {0}, Data {1}".format(
+ rep.get('error-code', ''),
+ str(data)))
+
+ self.assertEqual(msg_type, KRB_AS_REP, "Data {0}".format(str(data)))
+
+ # Decrypt and decode the EncKdcRepPart
+ enc = key.decrypt(KU_AS_REP_ENC_PART, rep['enc-part']['cipher'])
+ if enc[0] == 0x7A:
+ # MIT Kerberos Tags the EncASRepPart as a EncKDCRepPart
+ # i.e. tag number 26 instead of tag number 25
+ as_rep = self.der_decode(enc, asn1Spec=krb5_asn1.EncTGSRepPart())
+ else:
+ as_rep = self.der_decode(enc, asn1Spec=krb5_asn1.EncASRepPart())
+
+ return (rep, as_rep)
+
+ def check_cname(self, cname, data):
+ if TestOptions.Canonicalize.is_set(data.options):
+ expected_name_type = NT_PRINCIPAL
+ elif TestOptions.Enterprise.is_set(data.options):
+ expected_name_type = NT_ENTERPRISE_PRINCIPAL
+ else:
+ expected_name_type = NT_PRINCIPAL
+
+ name_type = cname['name-type']
+ self.assertEqual(
+ expected_name_type,
+ name_type,
+ "cname name-type, Options {0:08b}".format(data.options))
+
+ ns = cname['name-string']
+ name = ns[0].decode('ascii')
+
+ expected = data.user_name
+ if TestOptions.Canonicalize.is_set(data.options):
+ expected = data.user_creds.get_username()
+ self.assertEqual(
+ expected,
+ name,
+ "cname principal, Options {0:08b}".format(data.options))
+
+ def check_crealm(self, crealm, data):
+ realm = data.user_creds.get_realm()
+ self.assertEqual(
+ realm, crealm, "crealm, Options {0:08b}".format(data.options))
+
+ def check_sname(self, sname, data):
+ nt = sname['name-type']
+ ns = sname['name-string']
+ name = ns[0].decode('ascii')
+
+ if TestOptions.AsReqSelf.is_set(data.options):
+ expected_name_type = NT_PRINCIPAL
+ if not TestOptions.Canonicalize.is_set(data.options)\
+ and TestOptions.Enterprise.is_set(data.options):
+
+ expected_name_type = NT_ENTERPRISE_PRINCIPAL
+
+ self.assertEqual(
+ expected_name_type,
+ nt,
+ "sname name-type, Options {0:08b}".format(data.options))
+ expected = data.user_name
+ if TestOptions.Canonicalize.is_set(data.options):
+ expected = data.user_creds.get_username()
+ self.assertEqual(
+ expected,
+ name,
+ "sname principal, Options {0:08b}".format(data.options))
+ else:
+ self.assertEqual(
+ NT_SRV_INST,
+ nt,
+ "sname name-type, Options {0:08b}".format(data.options))
+ self.assertEqual(
+ 'krbtgt',
+ name,
+ "sname principal, Options {0:08b}".format(data.options))
+
+ realm = ns[1].decode('ascii')
+ expected = data.realm
+ if TestOptions.Canonicalize.is_set(data.options):
+ expected = data.user_creds.get_realm().upper()
+ self.assertEqual(
+ expected,
+ realm,
+ "sname realm, Options {0:08b}".format(data.options))
+
+ def check_srealm(self, srealm, data):
+ realm = data.user_creds.get_realm()
+ self.assertEqual(
+ realm, srealm, "srealm, Options {0:08b}".format(data.options))
+
+ def check_kvno(self, kvno, data):
+ self.assertEqual(
+ 1, kvno, "kvno, Options {0:08b}".format(data.options))
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/as_req_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/as_req_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/as_req_tests.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/as_req_tests.py 2021-10-29 06:17:36.000000000 +0000
@@ -0,0 +1,215 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+from samba.tests import DynamicTestCase
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+import samba.tests.krb5.kcrypto as kcrypto
+import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
+from samba.tests.krb5.rfc4120_constants import (
+ KDC_ERR_ETYPE_NOSUPP,
+ KDC_ERR_PREAUTH_REQUIRED,
+ KU_PA_ENC_TIMESTAMP,
+ NT_PRINCIPAL,
+ NT_SRV_INST,
+ PADATA_ENC_TIMESTAMP
+)
+
+global_asn1_print = False
+global_hexdump = False
+
+@DynamicTestCase
+class AsReqKerberosTests(KDCBaseTest):
+
+ @classmethod
+ def setUpDynamicTestCases(cls):
+ for (name, idx) in cls.etype_test_permutation_name_idx():
+ for pac in [None, True, False]:
+ tname = "%s_pac_%s" % (name, pac)
+ targs = (idx, pac)
+ cls.generate_dynamic_test("test_as_req_no_preauth", tname, *targs)
+
+ def setUp(self):
+ super(AsReqKerberosTests, self).setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ def _test_as_req_nopreauth(self,
+ initial_etypes,
+ pac=None,
+ initial_kdc_options=None):
+ client_creds = self.get_client_creds()
+ client_account = client_creds.get_username()
+ client_as_etypes = self.get_default_enctypes()
+ krbtgt_creds = self.get_krbtgt_creds(require_keys=False)
+ krbtgt_account = krbtgt_creds.get_username()
+ realm = krbtgt_creds.get_realm()
+
+ cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[client_account])
+ sname = self.PrincipalName_create(name_type=NT_SRV_INST,
+ names=[krbtgt_account, realm])
+
+ expected_crealm = realm
+ expected_cname = cname
+ expected_srealm = realm
+ expected_sname = sname
+ expected_salt = client_creds.get_salt()
+
+ if any(etype in client_as_etypes and etype in initial_etypes
+ for etype in (kcrypto.Enctype.AES256,
+ kcrypto.Enctype.AES128,
+ kcrypto.Enctype.RC4)):
+ expected_error_mode = KDC_ERR_PREAUTH_REQUIRED
+ else:
+ expected_error_mode = KDC_ERR_ETYPE_NOSUPP
+
+ kdc_exchange_dict = self.as_exchange_dict(
+ expected_crealm=expected_crealm,
+ expected_cname=expected_cname,
+ expected_srealm=expected_srealm,
+ expected_sname=expected_sname,
+ generate_padata_fn=None,
+ check_error_fn=self.generic_check_kdc_error,
+ check_rep_fn=None,
+ expected_error_mode=expected_error_mode,
+ client_as_etypes=client_as_etypes,
+ expected_salt=expected_salt,
+ kdc_options=str(initial_kdc_options),
+ pac_request=pac)
+
+ self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ etypes=initial_etypes)
+
+ def _test_as_req_no_preauth_with_args(self, etype_idx, pac):
+ name, etypes = self.etype_test_permutation_by_idx(etype_idx)
+ self._test_as_req_nopreauth(
+ pac=pac,
+ initial_etypes=etypes,
+ initial_kdc_options=krb5_asn1.KDCOptions('forwardable'))
+
+ def test_as_req_enc_timestamp(self):
+ client_creds = self.get_client_creds()
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_as_req_enc_timestamp_mac(self):
+ client_creds = self.get_mach_creds()
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def _run_as_req_enc_timestamp(self, client_creds):
+ client_account = client_creds.get_username()
+ client_as_etypes = self.get_default_enctypes()
+ client_kvno = client_creds.get_kvno()
+ krbtgt_creds = self.get_krbtgt_creds(require_strongest_key=True)
+ krbtgt_account = krbtgt_creds.get_username()
+ realm = krbtgt_creds.get_realm()
+
+ cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[client_account])
+ sname = self.PrincipalName_create(name_type=NT_SRV_INST,
+ names=[krbtgt_account, realm])
+
+ expected_crealm = realm
+ expected_cname = cname
+ expected_srealm = realm
+ expected_sname = sname
+ expected_salt = client_creds.get_salt()
+
+ till = self.get_KerberosTime(offset=36000)
+
+ initial_etypes = client_as_etypes
+ initial_kdc_options = krb5_asn1.KDCOptions('forwardable')
+ initial_error_mode = KDC_ERR_PREAUTH_REQUIRED
+
+ rep, kdc_exchange_dict = self._test_as_exchange(cname,
+ realm,
+ sname,
+ till,
+ client_as_etypes,
+ initial_error_mode,
+ expected_crealm,
+ expected_cname,
+ expected_srealm,
+ expected_sname,
+ expected_salt,
+ initial_etypes,
+ None,
+ initial_kdc_options,
+ pac_request=True)
+ etype_info2 = kdc_exchange_dict['preauth_etype_info2']
+ self.assertIsNotNone(etype_info2)
+
+ preauth_key = self.PasswordKey_from_etype_info2(client_creds,
+ etype_info2[0],
+ kvno=client_kvno)
+
+ (patime, pausec) = self.get_KerberosTimeWithUsec()
+ pa_ts = self.PA_ENC_TS_ENC_create(patime, pausec)
+ pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
+
+ enc_pa_ts_usage = KU_PA_ENC_TIMESTAMP
+ pa_ts = self.EncryptedData_create(preauth_key, enc_pa_ts_usage, pa_ts)
+ pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.EncryptedData())
+
+ pa_ts = self.PA_DATA_create(PADATA_ENC_TIMESTAMP, pa_ts)
+
+ preauth_padata = [pa_ts]
+ preauth_etypes = client_as_etypes
+ preauth_kdc_options = krb5_asn1.KDCOptions('forwardable')
+ preauth_error_mode = 0 # AS-REP
+
+ krbtgt_decryption_key = (
+ self.TicketDecryptionKey_from_creds(krbtgt_creds))
+
+ as_rep, kdc_exchange_dict = self._test_as_exchange(
+ cname,
+ realm,
+ sname,
+ till,
+ client_as_etypes,
+ preauth_error_mode,
+ expected_crealm,
+ expected_cname,
+ expected_srealm,
+ expected_sname,
+ expected_salt,
+ preauth_etypes,
+ preauth_padata,
+ preauth_kdc_options,
+ preauth_key=preauth_key,
+ ticket_decryption_key=krbtgt_decryption_key,
+ pac_request=True)
+ self.assertIsNotNone(as_rep)
+
+ return etype_info2
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
+
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/compatability_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/compatability_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/compatability_tests.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/compatability_tests.py 2021-10-29 06:17:36.000000000 +0000
@@ -0,0 +1,267 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) Catalyst.Net Ltd 2020
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
+from samba.tests.krb5.rfc4120_constants import (
+ AES128_CTS_HMAC_SHA1_96,
+ AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ KDC_ERR_PREAUTH_REQUIRED,
+ KRB_AS_REP,
+ KRB_ERROR,
+ KU_AS_REP_ENC_PART,
+ KU_PA_ENC_TIMESTAMP,
+ PADATA_ENC_TIMESTAMP,
+ PADATA_ETYPE_INFO2,
+ NT_PRINCIPAL,
+ NT_SRV_INST,
+)
+
+global_asn1_print = False
+global_hexdump = False
+
+HIEMDAL_ENC_AS_REP_PART_TYPE_TAG = 0x79
+# MIT uses the EncTGSRepPart tag for the EncASRepPart
+MIT_ENC_AS_REP_PART_TYPE_TAG = 0x7A
+
+ENC_PA_REP_FLAG = 0x00010000
+
+
+class SimpleKerberosTests(KDCBaseTest):
+
+ def setUp(self):
+ super(SimpleKerberosTests, self).setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ def test_mit_EncASRepPart_tag(self):
+ creds = self.get_user_creds()
+ (enc, _) = self.as_req(creds)
+ self.assertEqual(MIT_ENC_AS_REP_PART_TYPE_TAG, enc[0])
+
+ def test_heimdal_EncASRepPart_tag(self):
+ creds = self.get_user_creds()
+ (enc, _) = self.as_req(creds)
+ self.assertEqual(HIEMDAL_ENC_AS_REP_PART_TYPE_TAG, enc[0])
+
+ def test_mit_EncryptedData_kvno(self):
+ creds = self.get_user_creds()
+ (_, enc) = self.as_req(creds)
+ if 'kvno' in enc:
+ self.fail("kvno present in EncryptedData")
+
+ def test_heimdal_EncryptedData_kvno(self):
+ creds = self.get_user_creds()
+ (_, enc) = self.as_req(creds)
+ if 'kvno' not in enc:
+ self.fail("kvno absent in EncryptedData")
+
+ def test_mit_EncASRepPart_FAST_support(self):
+ creds = self.get_user_creds()
+ (enc, _) = self.as_req(creds)
+ self.assertEqual(MIT_ENC_AS_REP_PART_TYPE_TAG, enc[0])
+ as_rep = self.der_decode(enc, asn1Spec=krb5_asn1.EncTGSRepPart())
+ flags = int(as_rep['flags'], base=2)
+ # MIT sets enc-pa-rep, flag bit 15
+ # RFC 6806 11. Negotiation of FAST and Detecting Modified Requests
+ self.assertTrue(ENC_PA_REP_FLAG & flags)
+
+ def test_heimdal_EncASRepPart_FAST_support(self):
+ creds = self.get_user_creds()
+ (enc, _) = self.as_req(creds)
+ self.assertEqual(HIEMDAL_ENC_AS_REP_PART_TYPE_TAG, enc[0])
+ as_rep = self.der_decode(enc, asn1Spec=krb5_asn1.EncASRepPart())
+ flags = as_rep['flags']
+ flags = int(as_rep['flags'], base=2)
+ # Heimdal does not set enc-pa-rep, flag bit 15
+ # RFC 6806 11. Negotiation of FAST and Detecting Modified Requests
+ self.assertFalse(ENC_PA_REP_FLAG & flags)
+
+ def test_mit_arcfour_salt(self):
+ creds = self.get_user_creds()
+ etypes = (ARCFOUR_HMAC_MD5,)
+ (rep, *_) = self.as_pre_auth_req(creds, etypes)
+ self.check_preauth_rep(rep)
+ etype_info2 = self.get_etype_info2(rep)
+ if 'salt' not in etype_info2[0]:
+ self.fail(
+ "(MIT) Salt not populated for ARCFOUR_HMAC_MD5 encryption")
+
+ def test_heimdal_arcfour_salt(self):
+ creds = self.get_user_creds()
+ etypes = (ARCFOUR_HMAC_MD5,)
+ (rep, *_) = self.as_pre_auth_req(creds, etypes)
+ self.check_preauth_rep(rep)
+ etype_info2 = self.get_etype_info2(rep)
+ if 'salt' in etype_info2[0]:
+ self.fail(
+ "(Heimdal) Salt populated for ARCFOUR_HMAC_MD5 encryption")
+
+ def test_heimdal_ticket_signature(self):
+ # Ensure that a DC correctly issues tickets signed with its krbtgt key.
+ user_creds = self.get_client_creds()
+ target_creds = self.get_service_creds()
+
+ krbtgt_creds = self.get_krbtgt_creds()
+ key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+
+ # Get a TGT from the DC.
+ tgt = self.get_tgt(user_creds)
+
+ # Ensure the PAC contains the expected checksums.
+ self.verify_ticket(tgt, key)
+
+ # Get a service ticket from the DC.
+ service_ticket = self.get_service_ticket(tgt, target_creds)
+
+ # Ensure the PAC contains the expected checksums.
+ self.verify_ticket(service_ticket, key, expect_ticket_checksum=True)
+
+ def test_mit_ticket_signature(self):
+ # Ensure that a DC does not issue tickets signed with its krbtgt key.
+ user_creds = self.get_client_creds()
+ target_creds = self.get_service_creds()
+
+ krbtgt_creds = self.get_krbtgt_creds()
+ key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+
+ # Get a TGT from the DC.
+ tgt = self.get_tgt(user_creds)
+
+ # Ensure the PAC contains the expected checksums.
+ self.verify_ticket(tgt, key)
+
+ # Get a service ticket from the DC.
+ service_ticket = self.get_service_ticket(tgt, target_creds)
+
+ # Ensure the PAC does not contain the expected checksums.
+ self.verify_ticket(service_ticket, key, expect_ticket_checksum=False)
+
+ def as_pre_auth_req(self, creds, etypes):
+ user = creds.get_username()
+ realm = creds.get_realm()
+
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[user])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST,
+ names=["krbtgt", realm])
+
+ till = self.get_KerberosTime(offset=36000)
+
+ kdc_options = krb5_asn1.KDCOptions('forwardable')
+ padata = None
+
+ req = self.AS_REQ_create(padata=padata,
+ kdc_options=str(kdc_options),
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ from_time=None,
+ till_time=till,
+ renew_time=None,
+ nonce=0x7fffffff,
+ etypes=etypes,
+ addresses=None,
+ additional_tickets=None)
+ rep = self.send_recv_transaction(req)
+
+ return (rep, cname, sname, realm, till)
+
+ def check_preauth_rep(self, rep):
+ self.assertIsNotNone(rep)
+ self.assertEqual(rep['msg-type'], KRB_ERROR)
+ self.assertEqual(rep['error-code'], KDC_ERR_PREAUTH_REQUIRED)
+
+ def get_etype_info2(self, rep):
+
+ rep_padata = self.der_decode(
+ rep['e-data'],
+ asn1Spec=krb5_asn1.METHOD_DATA())
+
+ for pa in rep_padata:
+ if pa['padata-type'] == PADATA_ETYPE_INFO2:
+ etype_info2 = pa['padata-value']
+ break
+
+ etype_info2 = self.der_decode(
+ etype_info2,
+ asn1Spec=krb5_asn1.ETYPE_INFO2())
+ return etype_info2
+
+ def as_req(self, creds):
+ etypes = (
+ AES256_CTS_HMAC_SHA1_96,
+ AES128_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5)
+ (rep, cname, sname, realm, till) = self.as_pre_auth_req(creds, etypes)
+ self.check_preauth_rep(rep)
+
+ etype_info2 = self.get_etype_info2(rep)
+ key = self.PasswordKey_from_etype_info2(creds, etype_info2[0])
+
+ (patime, pausec) = self.get_KerberosTimeWithUsec()
+ pa_ts = self.PA_ENC_TS_ENC_create(patime, pausec)
+ pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
+
+ pa_ts = self.EncryptedData_create(key, KU_PA_ENC_TIMESTAMP, pa_ts)
+ pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.EncryptedData())
+
+ pa_ts = self.PA_DATA_create(PADATA_ENC_TIMESTAMP, pa_ts)
+
+ kdc_options = krb5_asn1.KDCOptions('forwardable')
+ padata = [pa_ts]
+
+ req = self.AS_REQ_create(padata=padata,
+ kdc_options=str(kdc_options),
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ from_time=None,
+ till_time=till,
+ renew_time=None,
+ nonce=0x7fffffff,
+ etypes=etypes,
+ addresses=None,
+ additional_tickets=None)
+ rep = self.send_recv_transaction(req)
+ self.assertIsNotNone(rep)
+
+ msg_type = rep['msg-type']
+ self.assertEqual(msg_type, KRB_AS_REP)
+
+ enc_part = rep['enc-part']
+ enc_as_rep_part = key.decrypt(
+ KU_AS_REP_ENC_PART, rep['enc-part']['cipher'])
+ return (enc_as_rep_part, enc_part)
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/fast_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/fast_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/fast_tests.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/fast_tests.py 2021-10-29 06:17:36.000000000 +0000
@@ -0,0 +1,1521 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) 2020 Catalyst.Net Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import functools
+import os
+import sys
+import collections
+
+import ldb
+
+from samba.dcerpc import security
+from samba.tests.krb5.raw_testcase import Krb5EncryptionKey
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+from samba.tests.krb5.rfc4120_constants import (
+ AD_FX_FAST_ARMOR,
+ AD_FX_FAST_USED,
+ AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ FX_FAST_ARMOR_AP_REQUEST,
+ KDC_ERR_ETYPE_NOSUPP,
+ KDC_ERR_GENERIC,
+ KDC_ERR_S_PRINCIPAL_UNKNOWN,
+ KDC_ERR_NOT_US,
+ KDC_ERR_PREAUTH_FAILED,
+ KDC_ERR_PREAUTH_REQUIRED,
+ KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS,
+ KRB_AS_REP,
+ KRB_TGS_REP,
+ NT_PRINCIPAL,
+ NT_SRV_HST,
+ NT_SRV_INST,
+ PADATA_FX_COOKIE,
+ PADATA_FX_FAST,
+)
+import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
+import samba.tests.krb5.kcrypto as kcrypto
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class FAST_Tests(KDCBaseTest):
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+
+ cls.user_tgt = None
+ cls.user_service_ticket = None
+
+ cls.mach_tgt = None
+ cls.mach_service_ticket = None
+
+ def setUp(self):
+ super().setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ def test_simple(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': False
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': False,
+ 'gen_padata_fn': self.generate_enc_timestamp_padata
+ }
+ ])
+
+ def test_simple_tgs(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': False,
+ 'gen_tgt_fn': self.get_user_tgt
+ }
+ ])
+
+ def test_simple_no_sname(self):
+ expected_sname = self.get_krbtgt_sname()
+
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': (KDC_ERR_GENERIC, KDC_ERR_S_PRINCIPAL_UNKNOWN),
+ 'use_fast': False,
+ 'sname': None,
+ 'expected_sname': expected_sname,
+ 'expect_edata': False
+ }
+ ])
+
+ def test_simple_tgs_no_sname(self):
+ expected_sname = self.get_krbtgt_sname()
+
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': (KDC_ERR_GENERIC, KDC_ERR_S_PRINCIPAL_UNKNOWN),
+ 'use_fast': False,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'sname': None,
+ 'expected_sname': expected_sname,
+ 'expect_edata': False
+ }
+ ])
+
+ def test_fast_no_sname(self):
+ expected_sname = self.get_krbtgt_sname()
+
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_GENERIC,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'sname': None,
+ 'expected_sname': expected_sname
+ }
+ ])
+
+ def test_fast_tgs_no_sname(self):
+ expected_sname = self.get_krbtgt_sname()
+
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': (KDC_ERR_GENERIC, KDC_ERR_S_PRINCIPAL_UNKNOWN),
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'sname': None,
+ 'expected_sname': expected_sname
+ }
+ ])
+
+ def test_simple_tgs_wrong_principal(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': False,
+ 'gen_tgt_fn': self.get_mach_tgt
+ }
+ ])
+
+ def test_simple_tgs_service_ticket(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': KDC_ERR_NOT_US,
+ 'use_fast': False,
+ 'gen_tgt_fn': self.get_user_service_ticket,
+ 'expect_edata': False
+ }
+ ])
+
+ def test_simple_tgs_service_ticket_mach(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': KDC_ERR_NOT_US,
+ 'use_fast': False,
+ 'gen_tgt_fn': self.get_mach_service_ticket,
+ 'expect_edata': False
+ }
+ ])
+
+ def test_fast_no_claims(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'pac_options': '0'
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'pac_options': '0'
+ }
+ ])
+
+ def test_fast_tgs_no_claims(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'pac_options': '0'
+ }
+ ])
+
+ def test_fast_no_claims_or_canon(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'pac_options': '0',
+ 'kdc_options': '0'
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'pac_options': '0',
+ 'kdc_options': '0'
+ }
+ ])
+
+ def test_fast_tgs_no_claims_or_canon(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'pac_options': '0',
+ 'kdc_options': '0'
+ }
+ ])
+
+ def test_fast_no_canon(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'kdc_options': '0'
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'kdc_options': '0'
+ }
+ ])
+
+ def test_fast_tgs_no_canon(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'kdc_options': '0'
+ }
+ ])
+
+ def test_simple_tgs_no_etypes(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
+ 'use_fast': False,
+ 'gen_tgt_fn': self.get_mach_tgt,
+ 'etypes': (),
+ 'expect_edata': False
+ }
+ ])
+
+ def test_fast_tgs_no_etypes(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_mach_tgt,
+ 'fast_armor': None,
+ 'etypes': ()
+ }
+ ])
+
+ def test_simple_no_etypes(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
+ 'use_fast': False,
+ 'etypes': ()
+ }
+ ])
+
+ def test_simple_fast_no_etypes(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_ETYPE_NOSUPP,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'etypes': ()
+ }
+ ])
+
+ def test_empty_fast(self):
+ # Add an empty PA-FX-FAST in the initial AS-REQ. This should get
+ # rejected with a Generic error.
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_GENERIC,
+ 'use_fast': True,
+ 'gen_fast_fn': self.generate_empty_fast,
+ 'fast_armor': None,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'expect_edata': False
+ }
+ ])
+
+ def test_fast_unknown_critical_option(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS,
+ 'use_fast': True,
+ 'fast_options': '001', # unsupported critical option
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ }
+ ])
+
+ def test_unarmored_as_req(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_GENERIC,
+ 'use_fast': True,
+ 'fast_armor': None, # no armor,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'expect_edata': False
+ }
+ ])
+
+ def test_fast_invalid_armor_type(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
+ 'use_fast': True,
+ 'fast_armor': 0, # invalid armor type
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ }
+ ])
+
+ def test_fast_invalid_armor_type2(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
+ 'use_fast': True,
+ 'fast_armor': 2, # invalid armor type
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ }
+ ])
+
+ def test_fast_encrypted_challenge(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ }
+ ])
+
+ def test_fast_encrypted_challenge_wrong_key(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata_wrong_key,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ }
+ ])
+
+ def test_fast_encrypted_challenge_wrong_key_kdc(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_FAILED,
+ 'use_fast': True,
+ 'gen_padata_fn':
+ self.generate_enc_challenge_padata_wrong_key_kdc,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ }
+ ])
+
+ def test_fast_encrypted_challenge_clock_skew(self):
+ # The KDC is supposed to confirm that the timestamp is within its
+ # current clock skew, and return KRB_APP_ERR_SKEW if it is not (RFC6113
+ # 5.4.6). However, Windows accepts a skewed timestamp in the encrypted
+ # challenge.
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': functools.partial(
+ self.generate_enc_challenge_padata,
+ skew=10000),
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ }
+ ])
+
+ def test_fast_invalid_tgt(self):
+ # The armor ticket 'sname' field is required to identify the target
+ # realm TGS (RFC6113 5.4.1.1). However, Windows will still accept a
+ # service ticket identifying a different server principal.
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_user_service_ticket
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_user_service_ticket
+ # ticket not identifying TGS of current
+ # realm
+ }
+ ])
+
+ def test_fast_invalid_tgt_mach(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_service_ticket
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_service_ticket
+ # ticket not identifying TGS of current
+ # realm
+ }
+ ])
+
+ def test_fast_enc_timestamp(self):
+ # Provide ENC-TIMESTAMP as FAST padata when we should be providing
+ # ENCRYPTED-CHALLENGE - ensure that we get PREAUTH_REQUIRED.
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_timestamp_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ }
+ ])
+
+ def test_fast(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ }
+ ])
+
+ def test_fast_tgs(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None
+ }
+ ])
+
+ def test_fast_tgs_armor(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST
+ }
+ ])
+
+ def test_fast_outer_wrong_realm(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'outer_req': {
+ 'realm': 'TEST' # should be ignored
+ }
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'outer_req': {
+ 'realm': 'TEST' # should be ignored
+ }
+ }
+ ])
+
+ def test_fast_tgs_outer_wrong_realm(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'outer_req': {
+ 'realm': 'TEST' # should be ignored
+ }
+ }
+ ])
+
+ def test_fast_outer_wrong_nonce(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'outer_req': {
+ 'nonce': '123' # should be ignored
+ }
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'outer_req': {
+ 'nonce': '123' # should be ignored
+ }
+ }
+ ])
+
+ def test_fast_tgs_outer_wrong_nonce(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'outer_req': {
+ 'nonce': '123' # should be ignored
+ }
+ }
+ ])
+
+ def test_fast_outer_wrong_flags(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'outer_req': {
+ 'kdc-options': '11111111111111111' # should be ignored
+ }
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'outer_req': {
+ 'kdc-options': '11111111111111111' # should be ignored
+ }
+ }
+ ])
+
+ def test_fast_tgs_outer_wrong_flags(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'outer_req': {
+ 'kdc-options': '11111111111111111' # should be ignored
+ }
+ }
+ ])
+
+ def test_fast_outer_no_sname(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'outer_req': {
+ 'sname': None # should be ignored
+ }
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'outer_req': {
+ 'sname': None # should be ignored
+ }
+ }
+ ])
+
+ def test_fast_tgs_outer_no_sname(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'outer_req': {
+ 'sname': None # should be ignored
+ }
+ }
+ ])
+
+ def test_fast_outer_wrong_till(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'outer_req': {
+ 'till': '15000101000000Z' # should be ignored
+ }
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'outer_req': {
+ 'till': '15000101000000Z' # should be ignored
+ }
+ }
+ ])
+
+ def test_fast_tgs_outer_wrong_till(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'outer_req': {
+ 'till': '15000101000000Z' # should be ignored
+ }
+ }
+ ])
+
+ def test_fast_authdata_fast_used(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_authdata_fn': self.generate_fast_used_auth_data,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None
+ }
+ ])
+
+ def test_fast_authdata_fast_not_used(self):
+ # The AD-fx-fast-used authdata type can be included in the
+ # authenticator or the TGT authentication data to indicate that FAST
+ # must be used. The KDC must return KRB_APP_ERR_MODIFIED if it receives
+ # this authdata type in a request not using FAST (RFC6113 5.4.2).
+ self._run_test_sequence([
+ # This request works without FAST.
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': False,
+ 'gen_tgt_fn': self.get_user_tgt
+ },
+ # Add the 'FAST used' auth data and it now fails.
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': KDC_ERR_GENERIC,
+ # should be KRB_APP_ERR_MODIFIED
+ 'use_fast': False,
+ 'gen_authdata_fn': self.generate_fast_used_auth_data,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'expect_edata': False
+ }
+ ])
+
+ def test_fast_ad_fx_fast_armor(self):
+ expected_sname = self.get_krbtgt_sname()
+
+ # If the authenticator or TGT authentication data contains the
+ # AD-fx-fast-armor authdata type, the KDC must reject the request
+ # (RFC6113 5.4.1.1).
+ self._run_test_sequence([
+ # This request works.
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None
+ },
+ # Add the 'FAST armor' auth data and it now fails.
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': KDC_ERR_GENERIC,
+ 'use_fast': True,
+ 'gen_authdata_fn': self.generate_fast_armor_auth_data,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'expected_sname': expected_sname,
+ 'expect_edata': False
+ }
+ ])
+
+ def test_fast_ad_fx_fast_armor2(self):
+ # Show that we can still use the AD-fx-fast-armor authorization data in
+ # FAST armor tickets.
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'gen_authdata_fn': self.generate_fast_armor_auth_data,
+ # include the auth data in the FAST armor.
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ }
+ ])
+
+ def test_fast_ad_fx_fast_armor_ticket(self):
+ expected_sname = self.get_krbtgt_sname()
+
+ # If the authenticator or TGT authentication data contains the
+ # AD-fx-fast-armor authdata type, the KDC must reject the request
+ # (RFC6113 5.4.2).
+ self._run_test_sequence([
+ # This request works.
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None
+ },
+ # Add AD-fx-fast-armor authdata element to user TGT. This request
+ # fails.
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': KDC_ERR_GENERIC,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.gen_tgt_fast_armor_auth_data,
+ 'fast_armor': None,
+ 'expected_sname': expected_sname,
+ 'expect_edata': False
+ }
+ ])
+
+ def test_fast_ad_fx_fast_armor_ticket2(self):
+ self._run_test_sequence([
+ # Show that we can still use the modified ticket as armor.
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.gen_tgt_fast_armor_auth_data
+ }
+ ])
+
+ def test_fast_tgs_service_ticket(self):
+ # Try to use a non-TGT ticket to establish an armor key, which fails
+ # (RFC6113 5.4.2).
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': KDC_ERR_NOT_US,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_service_ticket, # fails
+ 'fast_armor': None
+ }
+ ])
+
+ def test_fast_tgs_service_ticket_mach(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': KDC_ERR_NOT_US, # fails
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_mach_service_ticket,
+ 'fast_armor': None
+ }
+ ])
+
+ def test_simple_tgs_no_subkey(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': False,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'include_subkey': False
+ }
+ ])
+
+ def test_fast_tgs_no_subkey(self):
+ expected_sname = self.get_krbtgt_sname()
+
+ # Show that omitting the subkey in the TGS-REQ authenticator fails
+ # (RFC6113 5.4.2).
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': KDC_ERR_GENERIC,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'include_subkey': False,
+ 'expected_sname': expected_sname,
+ 'expect_edata': False
+ }
+ ])
+
+ def test_fast_hide_client_names(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'fast_options': '01', # hide client names
+ 'expected_anon': True
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'fast_options': '01', # hide client names
+ 'expected_anon': True
+ }
+ ])
+
+ def test_fast_tgs_hide_client_names(self):
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_TGS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_tgt_fn': self.get_user_tgt,
+ 'fast_armor': None,
+ 'fast_options': '01', # hide client names
+ 'expected_anon': True
+ }
+ ])
+
+ def test_fast_encrypted_challenge_replay(self):
+ # The KDC is supposed to check that encrypted challenges are not
+ # replays (RFC6113 5.4.6), but timestamps may be reused; an encrypted
+ # challenge is only considered a replay if the ciphertext is identical
+ # to a previous challenge. Windows does not perform this check.
+
+ self._run_test_sequence([
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': KDC_ERR_PREAUTH_REQUIRED,
+ 'use_fast': True,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt
+ },
+ {
+ 'rep_type': KRB_AS_REP,
+ 'expected_error_mode': 0,
+ 'use_fast': True,
+ 'gen_padata_fn': self.generate_enc_challenge_padata_replay,
+ 'fast_armor': FX_FAST_ARMOR_AP_REQUEST,
+ 'gen_armor_tgt_fn': self.get_mach_tgt,
+ 'repeat': 2
+ }
+ ])
+
+ def generate_enc_timestamp_padata(self,
+ kdc_exchange_dict,
+ callback_dict,
+ req_body):
+ key = kdc_exchange_dict['preauth_key']
+
+ padata = self.get_enc_timestamp_pa_data_from_key(key)
+ return [padata], req_body
+
+ def generate_enc_challenge_padata(self,
+ kdc_exchange_dict,
+ callback_dict,
+ req_body,
+ skew=0):
+ armor_key = kdc_exchange_dict['armor_key']
+ key = kdc_exchange_dict['preauth_key']
+
+ client_challenge_key = (
+ self.generate_client_challenge_key(armor_key, key))
+ padata = self.get_challenge_pa_data(client_challenge_key, skew=skew)
+ return [padata], req_body
+
+ def generate_enc_challenge_padata_wrong_key_kdc(self,
+ kdc_exchange_dict,
+ callback_dict,
+ req_body):
+ armor_key = kdc_exchange_dict['armor_key']
+ key = kdc_exchange_dict['preauth_key']
+
+ kdc_challenge_key = (
+ self.generate_kdc_challenge_key(armor_key, key))
+ padata = self.get_challenge_pa_data(kdc_challenge_key)
+ return [padata], req_body
+
+ def generate_enc_challenge_padata_wrong_key(self,
+ kdc_exchange_dict,
+ callback_dict,
+ req_body):
+ key = kdc_exchange_dict['preauth_key']
+
+ padata = self.get_challenge_pa_data(key)
+ return [padata], req_body
+
+ def generate_enc_challenge_padata_replay(self,
+ kdc_exchange_dict,
+ callback_dict,
+ req_body):
+ padata = callback_dict.get('replay_padata')
+
+ if padata is None:
+ armor_key = kdc_exchange_dict['armor_key']
+ key = kdc_exchange_dict['preauth_key']
+
+ client_challenge_key = (
+ self.generate_client_challenge_key(armor_key, key))
+ padata = self.get_challenge_pa_data(client_challenge_key)
+ callback_dict['replay_padata'] = padata
+
+ return [padata], req_body
+
+ def generate_empty_fast(self,
+ _kdc_exchange_dict,
+ _callback_dict,
+ _req_body,
+ _fast_padata,
+ _fast_armor,
+ _checksum,
+ _fast_options=''):
+ fast_padata = self.PA_DATA_create(PADATA_FX_FAST, b'')
+
+ return fast_padata
+
+ def _run_test_sequence(self, test_sequence):
+ if self.strict_checking:
+ self.check_kdc_fast_support()
+
+ kdc_options_default = str(krb5_asn1.KDCOptions('forwardable,'
+ 'renewable,'
+ 'canonicalize,'
+ 'renewable-ok'))
+
+ client_creds = self.get_client_creds()
+ target_creds = self.get_service_creds()
+ krbtgt_creds = self.get_krbtgt_creds()
+
+ client_username = client_creds.get_username()
+ client_realm = client_creds.get_realm()
+ client_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[client_username])
+
+ krbtgt_username = krbtgt_creds.get_username()
+ krbtgt_realm = krbtgt_creds.get_realm()
+ krbtgt_sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm])
+ krbtgt_decryption_key = self.TicketDecryptionKey_from_creds(
+ krbtgt_creds)
+ krbtgt_etypes = krbtgt_creds.tgs_supported_enctypes
+
+ target_username = target_creds.get_username()[:-1]
+ target_realm = target_creds.get_realm()
+ target_service = 'host'
+ target_sname = self.PrincipalName_create(
+ name_type=NT_SRV_HST, names=[target_service, target_username])
+ target_decryption_key = self.TicketDecryptionKey_from_creds(
+ target_creds)
+ target_etypes = target_creds.tgs_supported_enctypes
+
+ fast_cookie = None
+ preauth_etype_info2 = None
+
+ for kdc_dict in test_sequence:
+ rep_type = kdc_dict.pop('rep_type')
+ self.assertIn(rep_type, (KRB_AS_REP, KRB_TGS_REP))
+
+ expected_error_mode = kdc_dict.pop('expected_error_mode')
+ if expected_error_mode == 0:
+ expected_error_mode = ()
+ elif not isinstance(expected_error_mode, collections.abc.Container):
+ expected_error_mode = (expected_error_mode,)
+ for error in expected_error_mode:
+ self.assertIn(error, range(240))
+
+ use_fast = kdc_dict.pop('use_fast')
+ self.assertIs(type(use_fast), bool)
+
+ if use_fast:
+ self.assertIn('fast_armor', kdc_dict)
+ fast_armor_type = kdc_dict.pop('fast_armor')
+
+ if fast_armor_type is not None:
+ self.assertIn('gen_armor_tgt_fn', kdc_dict)
+ elif KDC_ERR_GENERIC not in expected_error_mode:
+ self.assertNotIn('gen_armor_tgt_fn', kdc_dict)
+
+ gen_armor_tgt_fn = kdc_dict.pop('gen_armor_tgt_fn', None)
+ if gen_armor_tgt_fn is not None:
+ armor_tgt = gen_armor_tgt_fn()
+ else:
+ armor_tgt = None
+
+ fast_options = kdc_dict.pop('fast_options', '')
+ else:
+ fast_armor_type = None
+ armor_tgt = None
+
+ self.assertNotIn('fast_options', kdc_dict)
+ fast_options = None
+
+ if rep_type == KRB_TGS_REP:
+ gen_tgt_fn = kdc_dict.pop('gen_tgt_fn')
+ tgt = gen_tgt_fn()
+ else:
+ self.assertNotIn('gen_tgt_fn', kdc_dict)
+ tgt = None
+
+ if len(expected_error_mode) != 0:
+ check_error_fn = self.generic_check_kdc_error
+ check_rep_fn = None
+ else:
+ check_error_fn = None
+ check_rep_fn = self.generic_check_kdc_rep
+
+ etypes = kdc_dict.pop('etypes', (AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5))
+
+ cname = client_cname if rep_type == KRB_AS_REP else None
+ crealm = client_realm
+
+ if 'sname' in kdc_dict:
+ sname = kdc_dict.pop('sname')
+ else:
+ if rep_type == KRB_AS_REP:
+ sname = krbtgt_sname
+ else: # KRB_TGS_REP
+ sname = target_sname
+
+ if rep_type == KRB_AS_REP:
+ srealm = krbtgt_realm
+ else: # KRB_TGS_REP
+ srealm = target_realm
+
+ if rep_type == KRB_TGS_REP:
+ tgt_cname = tgt.cname
+ else:
+ tgt_cname = client_cname
+
+ expect_edata = kdc_dict.pop('expect_edata', None)
+ if expect_edata is not None:
+ self.assertTrue(expected_error_mode)
+
+ expected_cname = kdc_dict.pop('expected_cname', tgt_cname)
+ expected_anon = kdc_dict.pop('expected_anon',
+ False)
+ expected_crealm = kdc_dict.pop('expected_crealm', client_realm)
+ expected_sname = kdc_dict.pop('expected_sname', sname)
+ expected_srealm = kdc_dict.pop('expected_srealm', srealm)
+
+ expected_salt = client_creds.get_salt()
+
+ authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256)
+ if rep_type == KRB_AS_REP:
+ if use_fast:
+ armor_key = self.generate_armor_key(authenticator_subkey,
+ armor_tgt.session_key)
+ armor_subkey = authenticator_subkey
+ else:
+ armor_key = None
+ armor_subkey = authenticator_subkey
+ else: # KRB_TGS_REP
+ if fast_armor_type is not None:
+ armor_subkey = self.RandomKey(kcrypto.Enctype.AES256)
+ explicit_armor_key = self.generate_armor_key(
+ armor_subkey,
+ armor_tgt.session_key)
+ armor_key = kcrypto.cf2(explicit_armor_key.key,
+ authenticator_subkey.key,
+ b'explicitarmor',
+ b'tgsarmor')
+ armor_key = Krb5EncryptionKey(armor_key, None)
+ else:
+ armor_key = self.generate_armor_key(authenticator_subkey,
+ tgt.session_key)
+ armor_subkey = authenticator_subkey
+
+ if not kdc_dict.pop('include_subkey', True):
+ authenticator_subkey = None
+
+ if use_fast:
+ generate_fast_fn = kdc_dict.pop('gen_fast_fn', None)
+ if generate_fast_fn is None:
+ generate_fast_fn = functools.partial(
+ self.generate_simple_fast,
+ fast_options=fast_options)
+ else:
+ generate_fast_fn = None
+
+ generate_fast_armor_fn = (
+ self.generate_ap_req
+ if fast_armor_type is not None
+ else None)
+
+ def _generate_padata_copy(_kdc_exchange_dict,
+ _callback_dict,
+ req_body,
+ padata):
+ return list(padata), req_body
+
+ pac_options = kdc_dict.pop('pac_options', '1') # claims support
+
+ kdc_options = kdc_dict.pop('kdc_options', kdc_options_default)
+
+ gen_padata_fn = kdc_dict.pop('gen_padata_fn', None)
+
+ if rep_type == KRB_AS_REP and gen_padata_fn is not None:
+ self.assertIsNotNone(preauth_etype_info2)
+
+ preauth_key = self.PasswordKey_from_etype_info2(
+ client_creds,
+ preauth_etype_info2[0],
+ client_creds.get_kvno())
+ else:
+ preauth_key = None
+
+ if use_fast:
+ generate_fast_padata_fn = gen_padata_fn
+ generate_padata_fn = (functools.partial(_generate_padata_copy,
+ padata=[fast_cookie])
+ if fast_cookie is not None else None)
+ else:
+ generate_fast_padata_fn = None
+ generate_padata_fn = gen_padata_fn
+
+ gen_authdata_fn = kdc_dict.pop('gen_authdata_fn', None)
+ if gen_authdata_fn is not None:
+ auth_data = [gen_authdata_fn()]
+ else:
+ auth_data = None
+
+ if not use_fast:
+ self.assertNotIn('inner_req', kdc_dict)
+ self.assertNotIn('outer_req', kdc_dict)
+ inner_req = kdc_dict.pop('inner_req', None)
+ outer_req = kdc_dict.pop('outer_req', None)
+
+ expected_flags = kdc_dict.pop('expected_flags', None)
+ if expected_flags is not None:
+ expected_flags = krb5_asn1.TicketFlags(expected_flags)
+ unexpected_flags = kdc_dict.pop('unexpected_flags', None)
+ if unexpected_flags is not None:
+ unexpected_flags = krb5_asn1.TicketFlags(unexpected_flags)
+
+ if rep_type == KRB_AS_REP:
+ kdc_exchange_dict = self.as_exchange_dict(
+ expected_crealm=expected_crealm,
+ expected_cname=expected_cname,
+ expected_anon=expected_anon,
+ expected_srealm=expected_srealm,
+ expected_sname=expected_sname,
+ expected_supported_etypes=krbtgt_etypes,
+ expected_flags=expected_flags,
+ unexpected_flags=unexpected_flags,
+ ticket_decryption_key=krbtgt_decryption_key,
+ generate_fast_fn=generate_fast_fn,
+ generate_fast_armor_fn=generate_fast_armor_fn,
+ generate_fast_padata_fn=generate_fast_padata_fn,
+ fast_armor_type=fast_armor_type,
+ generate_padata_fn=generate_padata_fn,
+ check_error_fn=check_error_fn,
+ check_rep_fn=check_rep_fn,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ callback_dict={},
+ expected_error_mode=expected_error_mode,
+ client_as_etypes=etypes,
+ expected_salt=expected_salt,
+ authenticator_subkey=authenticator_subkey,
+ preauth_key=preauth_key,
+ auth_data=auth_data,
+ armor_key=armor_key,
+ armor_tgt=armor_tgt,
+ armor_subkey=armor_subkey,
+ kdc_options=kdc_options,
+ inner_req=inner_req,
+ outer_req=outer_req,
+ pac_request=True,
+ pac_options=pac_options,
+ expect_edata=expect_edata)
+ else: # KRB_TGS_REP
+ kdc_exchange_dict = self.tgs_exchange_dict(
+ expected_crealm=expected_crealm,
+ expected_cname=expected_cname,
+ expected_anon=expected_anon,
+ expected_srealm=expected_srealm,
+ expected_sname=expected_sname,
+ expected_supported_etypes=target_etypes,
+ expected_flags=expected_flags,
+ unexpected_flags=unexpected_flags,
+ ticket_decryption_key=target_decryption_key,
+ generate_fast_fn=generate_fast_fn,
+ generate_fast_armor_fn=generate_fast_armor_fn,
+ generate_fast_padata_fn=generate_fast_padata_fn,
+ fast_armor_type=fast_armor_type,
+ generate_padata_fn=generate_padata_fn,
+ check_error_fn=check_error_fn,
+ check_rep_fn=check_rep_fn,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ expected_error_mode=expected_error_mode,
+ callback_dict={},
+ tgt=tgt,
+ armor_key=armor_key,
+ armor_tgt=armor_tgt,
+ armor_subkey=armor_subkey,
+ authenticator_subkey=authenticator_subkey,
+ auth_data=auth_data,
+ body_checksum_type=None,
+ kdc_options=kdc_options,
+ inner_req=inner_req,
+ outer_req=outer_req,
+ pac_request=None,
+ pac_options=pac_options,
+ expect_edata=expect_edata)
+
+ repeat = kdc_dict.pop('repeat', 1)
+ for _ in range(repeat):
+ rep = self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=cname,
+ realm=crealm,
+ sname=sname,
+ etypes=etypes)
+ if len(expected_error_mode) == 0:
+ self.check_reply(rep, rep_type)
+
+ fast_cookie = None
+ preauth_etype_info2 = None
+ else:
+ self.check_error_rep(rep, expected_error_mode)
+
+ if 'fast_cookie' in kdc_exchange_dict:
+ fast_cookie = self.create_fast_cookie(
+ kdc_exchange_dict['fast_cookie'])
+ else:
+ fast_cookie = None
+
+ if KDC_ERR_PREAUTH_REQUIRED in expected_error_mode:
+ preauth_etype_info2 = (
+ kdc_exchange_dict['preauth_etype_info2'])
+ else:
+ preauth_etype_info2 = None
+
+ # Ensure we used all the parameters given to us.
+ self.assertEqual({}, kdc_dict)
+
+ def generate_fast_armor_auth_data(self):
+ auth_data = self.AuthorizationData_create(AD_FX_FAST_ARMOR, b'')
+
+ return auth_data
+
+ def generate_fast_used_auth_data(self):
+ auth_data = self.AuthorizationData_create(AD_FX_FAST_USED, b'')
+
+ return auth_data
+
+ def gen_tgt_fast_armor_auth_data(self):
+ user_tgt = self.get_user_tgt()
+
+ auth_data = self.generate_fast_armor_auth_data()
+
+ def modify_fn(enc_part):
+ enc_part['authorization-data'].append(auth_data)
+
+ return enc_part
+
+ checksum_keys = self.get_krbtgt_checksum_key()
+
+ # Use our modifed TGT to replace the one in the request.
+ return self.modified_ticket(user_tgt,
+ modify_fn=modify_fn,
+ checksum_keys=checksum_keys)
+
+ def create_fast_cookie(self, cookie):
+ self.assertIsNotNone(cookie)
+ if self.strict_checking:
+ self.assertNotEqual(0, len(cookie))
+
+ return self.PA_DATA_create(PADATA_FX_COOKIE, cookie)
+
+ def check_kdc_fast_support(self):
+ # Check that the KDC supports FAST
+
+ samdb = self.get_samdb()
+
+ krbtgt_rid = security.DOMAIN_RID_KRBTGT
+ krbtgt_sid = '%s-%d' % (samdb.get_domain_sid(), krbtgt_rid)
+
+ res = samdb.search(base='' % krbtgt_sid,
+ scope=ldb.SCOPE_BASE,
+ attrs=['msDS-SupportedEncryptionTypes'])
+
+ krbtgt_etypes = int(res[0]['msDS-SupportedEncryptionTypes'][0])
+
+ self.assertTrue(
+ security.KERB_ENCTYPE_FAST_SUPPORTED & krbtgt_etypes)
+ self.assertTrue(
+ security.KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED & krbtgt_etypes)
+ self.assertTrue(
+ security.KERB_ENCTYPE_CLAIMS_SUPPORTED & krbtgt_etypes)
+
+ def get_mach_tgt(self):
+ if self.mach_tgt is None:
+ mach_creds = self.get_mach_creds()
+ type(self).mach_tgt = self.get_tgt(mach_creds)
+
+ return self.mach_tgt
+
+ def get_user_tgt(self):
+ if self.user_tgt is None:
+ user_creds = self.get_client_creds()
+ type(self).user_tgt = self.get_tgt(user_creds)
+
+ return self.user_tgt
+
+ def get_user_service_ticket(self):
+ if self.user_service_ticket is None:
+ user_tgt = self.get_user_tgt()
+ service_creds = self.get_service_creds()
+ type(self).user_service_ticket = (
+ self.get_service_ticket(user_tgt, service_creds))
+
+ return self.user_service_ticket
+
+ def get_mach_service_ticket(self):
+ if self.mach_service_ticket is None:
+ mach_tgt = self.get_mach_tgt()
+ service_creds = self.get_service_creds()
+ type(self).mach_service_ticket = (
+ self.get_service_ticket(mach_tgt, service_creds))
+
+ return self.mach_service_ticket
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/kcrypto.py samba-4.13.14+dfsg/python/samba/tests/krb5/kcrypto.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/kcrypto.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/kcrypto.py 2021-10-29 06:17:36.000000000 +0000
@@ -64,6 +64,7 @@
from samba import generate_random_bytes as get_random_bytes
from samba.compat import get_string, get_bytes
+
class Enctype(object):
DES_CRC = 1
DES_MD4 = 2
@@ -80,8 +81,8 @@
MD4_DES = 3
MD5 = 7
MD5_DES = 8
- SHA1 = 9
SHA1_DES3 = 12
+ SHA1 = 14
SHA1_AES128 = 15
SHA1_AES256 = 16
HMAC_MD5 = -138
@@ -112,26 +113,30 @@
res |= x ^ y
return res == 0
+
def SIMPLE_HASH(string, algo_cls):
hash_ctx = hashes.Hash(algo_cls(), default_backend())
hash_ctx.update(string)
return hash_ctx.finalize()
+
def HMAC_HASH(key, string, algo_cls):
hmac_ctx = hmac.HMAC(key, algo_cls(), default_backend())
hmac_ctx.update(string)
return hmac_ctx.finalize()
+
def _nfold(str, nbytes):
# Convert str to a string of length nbytes using the RFC 3961 nfold
# operation.
# Rotate the bytes in str to the right by nbits bits.
def rotate_right(str, nbits):
- nbytes, remain = (nbits//8) % len(str), nbits % 8
- return bytes([(str[i-nbytes] >> remain) |
- (str[i-nbytes-1] << (8-remain) & 0xff)
- for i in range(len(str))])
+ nbytes, remain = (nbits // 8) % len(str), nbits % 8
+ return bytes([
+ (str[i - nbytes] >> remain)
+ | (str[i - nbytes - 1] << (8 - remain) & 0xff)
+ for i in range(len(str))])
# Add equal-length strings together with end-around carry.
def add_ones_complement(str1, str2):
@@ -139,7 +144,7 @@
v = [a + b for a, b in zip(str1, str2)]
# Propagate carry bits to the left until there aren't any left.
while any(x & ~0xff for x in v):
- v = [(v[i-n+1]>>8) + (v[i]&0xff) for i in range(n)]
+ v = [(v[i - n + 1] >> 8) + (v[i] & 0xff) for i in range(n)]
return bytes([x for x in v])
# Concatenate copies of str to produce the least common multiple
@@ -150,7 +155,7 @@
slen = len(str)
lcm = nbytes * slen // gcd(nbytes, slen)
bigstr = b''.join((rotate_right(str, 13 * i) for i in range(lcm // slen)))
- slices = (bigstr[p:p+nbytes] for p in range(0, lcm, nbytes))
+ slices = (bigstr[p:p + nbytes] for p in range(0, lcm, nbytes))
return reduce(add_ones_complement, slices)
@@ -275,7 +280,7 @@
return b if bin(b & ~1).count('1') % 2 else b | 1
assert len(seed) == 7
firstbytes = [parity(b & ~1) for b in seed]
- lastbyte = parity(sum((seed[i]&1) << i+1 for i in range(7)))
+ lastbyte = parity(sum((seed[i] & 1) << i + 1 for i in range(7)))
keybytes = bytes([b for b in firstbytes + [lastbyte]])
if _is_weak_des_key(keybytes):
keybytes[7] = bytes([keybytes[7] ^ 0xF0])
@@ -369,7 +374,7 @@
if len(ciphertext) == 16:
return aes_decrypt(ciphertext)
# Split the ciphertext into blocks. The last block may be partial.
- cblocks = [ciphertext[p:p+16] for p in range(0, len(ciphertext), 16)]
+ cblocks = [ciphertext[p:p + 16] for p in range(0, len(ciphertext), 16)]
lastlen = len(cblocks[-1])
# CBC-decrypt all but the last two blocks.
prev_cblock = bytes(16)
@@ -383,7 +388,7 @@
# will be the omitted bytes of ciphertext from the final
# block.
b = aes_decrypt(cblocks[-2])
- lastplaintext =_xorbytes(b[:lastlen], cblocks[-1])
+ lastplaintext = _xorbytes(b[:lastlen], cblocks[-1])
omitted = b[lastlen:]
# Decrypt the final cipher block plus the omitted bytes to get
# the second-to-last plaintext block.
@@ -433,7 +438,8 @@
cksum = HMAC_HASH(ki, confounder + plaintext, hashes.MD5)
ke = HMAC_HASH(ki, cksum, hashes.MD5)
- encryptor = Cipher(ciphers.ARC4(ke), None, default_backend()).encryptor()
+ encryptor = Cipher(
+ ciphers.ARC4(ke), None, default_backend()).encryptor()
ctext = encryptor.update(confounder + plaintext)
return cksum + ctext
@@ -446,7 +452,8 @@
ki = HMAC_HASH(key.contents, cls.usage_str(keyusage), hashes.MD5)
ke = HMAC_HASH(ki, cksum, hashes.MD5)
- decryptor = Cipher(ciphers.ARC4(ke), None, default_backend()).decryptor()
+ decryptor = Cipher(
+ ciphers.ARC4(ke), None, default_backend()).decryptor()
basic_plaintext = decryptor.update(basic_ctext)
exp_cksum = HMAC_HASH(ki, basic_plaintext, hashes.MD5)
@@ -471,6 +478,7 @@
# define:
# * checksum
# * verify (if verification is not just checksum-and-compare)
+ # * checksum_len
@classmethod
def verify(cls, key, keyusage, text, cksum):
expected = cls.checksum(key, keyusage, text)
@@ -497,6 +505,10 @@
raise ValueError('Wrong key type for checksum')
super(_SimplifiedChecksum, cls).verify(key, keyusage, text, cksum)
+ @classmethod
+ def checksum_len(cls):
+ return cls.macsize
+
class _SHA1AES128(_SimplifiedChecksum):
macsize = 12
@@ -526,6 +538,10 @@
raise ValueError('Wrong key type for checksum')
super(_HMACMD5, cls).verify(key, keyusage, text, cksum)
+ @classmethod
+ def checksum_len(cls):
+ return hashes.MD5.digest_size
+
class _MD5(_ChecksumProfile):
@classmethod
@@ -533,6 +549,10 @@
# This is unkeyed!
return SIMPLE_HASH(text, hashes.MD5)
+ @classmethod
+ def checksum_len(cls):
+ return hashes.MD5.digest_size
+
class _SHA1(_ChecksumProfile):
@classmethod
@@ -540,6 +560,10 @@
# This is unkeyed!
return SIMPLE_HASH(text, hashes.SHA1)
+ @classmethod
+ def checksum_len(cls):
+ return hashes.SHA1.digest_size
+
class _CRC32(_ChecksumProfile):
@classmethod
@@ -548,6 +572,10 @@
cksum = (~crc32(text, 0xffffffff)) & 0xffffffff
return pack('.
+#
+
+import sys
+import os
+from datetime import datetime, timezone
+import tempfile
+import binascii
+import collections
+import secrets
+from enum import Enum, auto
+
+from collections import namedtuple
+import ldb
+from ldb import SCOPE_BASE
+from samba import generate_random_password
+from samba.auth import system_session
+from samba.credentials import Credentials, SPECIFIED, MUST_USE_KERBEROS
+from samba.dcerpc import drsblobs, drsuapi, misc, krb5pac, krb5ccache, security
+from samba.drs_utils import drs_Replicate, drsuapi_connect
+from samba.dsdb import (
+ DSDB_SYNTAX_BINARY_DN,
+ DS_DOMAIN_FUNCTION_2000,
+ DS_DOMAIN_FUNCTION_2008,
+ DS_GUID_COMPUTERS_CONTAINER,
+ DS_GUID_DOMAIN_CONTROLLERS_CONTAINER,
+ DS_GUID_USERS_CONTAINER,
+ UF_WORKSTATION_TRUST_ACCOUNT,
+ UF_NO_AUTH_DATA_REQUIRED,
+ UF_NORMAL_ACCOUNT,
+ UF_NOT_DELEGATED,
+ UF_PARTIAL_SECRETS_ACCOUNT,
+ UF_SERVER_TRUST_ACCOUNT,
+ UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
+)
+from samba.join import DCJoinContext
+from samba.ndr import ndr_pack, ndr_unpack
+from samba import net
+from samba.samdb import SamDB, dsdb_Dn
+
+from samba.tests import delete_force
+import samba.tests.krb5.kcrypto as kcrypto
+from samba.tests.krb5.raw_testcase import (
+ KerberosCredentials,
+ KerberosTicketCreds,
+ RawKerberosTest
+)
+import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
+from samba.tests.krb5.rfc4120_constants import (
+ AD_IF_RELEVANT,
+ AD_WIN2K_PAC,
+ AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ KDC_ERR_PREAUTH_REQUIRED,
+ KRB_AS_REP,
+ KRB_TGS_REP,
+ KRB_ERROR,
+ KU_AS_REP_ENC_PART,
+ KU_ENC_CHALLENGE_CLIENT,
+ KU_PA_ENC_TIMESTAMP,
+ KU_TICKET,
+ NT_PRINCIPAL,
+ NT_SRV_HST,
+ NT_SRV_INST,
+ PADATA_ENCRYPTED_CHALLENGE,
+ PADATA_ENC_TIMESTAMP,
+ PADATA_ETYPE_INFO2,
+)
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class KDCBaseTest(RawKerberosTest):
+ """ Base class for KDC tests.
+ """
+
+ class AccountType(Enum):
+ USER = auto()
+ COMPUTER = auto()
+ SERVER = auto()
+ RODC = auto()
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls._lp = None
+
+ cls._ldb = None
+ cls._rodc_ldb = None
+
+ cls._functional_level = None
+
+ # An identifier to ensure created accounts have unique names. Windows
+ # caches accounts based on usernames, so account names being different
+ # across test runs avoids previous test runs affecting the results.
+ cls.account_base = f'{secrets.token_hex(4)}_'
+ cls.account_id = 0
+
+ # A set containing DNs of accounts created as part of testing.
+ cls.accounts = set()
+
+ cls.account_cache = {}
+ cls.tkt_cache = {}
+
+ cls._rodc_ctx = None
+
+ cls.ldb_cleanups = []
+
+ @classmethod
+ def tearDownClass(cls):
+ # Clean up any accounts created by create_account. This is
+ # done in tearDownClass() rather than tearDown(), so that
+ # accounts need only be created once for permutation tests.
+ if cls._ldb is not None:
+ for cleanup in reversed(cls.ldb_cleanups):
+ try:
+ cls._ldb.modify(cleanup)
+ except ldb.LdbError:
+ pass
+
+ for dn in cls.accounts:
+ delete_force(cls._ldb, dn)
+
+ if cls._rodc_ctx is not None:
+ cls._rodc_ctx.cleanup_old_join(force=True)
+
+ super().tearDownClass()
+
+ def setUp(self):
+ super().setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ def get_lp(self):
+ if self._lp is None:
+ type(self)._lp = self.get_loadparm()
+
+ return self._lp
+
+ def get_samdb(self):
+ if self._ldb is None:
+ creds = self.get_admin_creds()
+ lp = self.get_lp()
+
+ session = system_session()
+ type(self)._ldb = SamDB(url="ldap://%s" % self.dc_host,
+ session_info=session,
+ credentials=creds,
+ lp=lp)
+
+ return self._ldb
+
+ def get_rodc_samdb(self):
+ if self._rodc_ldb is None:
+ creds = self.get_admin_creds()
+ lp = self.get_lp()
+
+ session = system_session()
+ type(self)._rodc_ldb = SamDB(url="ldap://%s" % self.host,
+ session_info=session,
+ credentials=creds,
+ lp=lp,
+ am_rodc=True)
+
+ return self._rodc_ldb
+
+ def get_server_dn(self, samdb):
+ server = samdb.get_serverName()
+
+ res = samdb.search(base=server,
+ scope=ldb.SCOPE_BASE,
+ attrs=['serverReference'])
+ dn = ldb.Dn(samdb, res[0]['serverReference'][0].decode('utf8'))
+
+ return dn
+
+ def get_mock_rodc_ctx(self):
+ if self._rodc_ctx is None:
+ admin_creds = self.get_admin_creds()
+ lp = self.get_lp()
+
+ rodc_name = 'KRB5RODC'
+ site_name = 'Default-First-Site-Name'
+
+ type(self)._rodc_ctx = DCJoinContext(server=self.dc_host,
+ creds=admin_creds,
+ lp=lp,
+ site=site_name,
+ netbios_name=rodc_name,
+ targetdir=None,
+ domain=None)
+ self.create_rodc(self._rodc_ctx)
+
+ return self._rodc_ctx
+
+ def get_domain_functional_level(self, ldb):
+ if self._functional_level is None:
+ res = ldb.search(base='',
+ scope=SCOPE_BASE,
+ attrs=['domainFunctionality'])
+ try:
+ functional_level = int(res[0]['domainFunctionality'][0])
+ except KeyError:
+ functional_level = DS_DOMAIN_FUNCTION_2000
+
+ type(self)._functional_level = functional_level
+
+ return self._functional_level
+
+ def get_default_enctypes(self):
+ samdb = self.get_samdb()
+ functional_level = self.get_domain_functional_level(samdb)
+
+ # RC4 should always be supported
+ default_enctypes = {kcrypto.Enctype.RC4}
+ if functional_level >= DS_DOMAIN_FUNCTION_2008:
+ # AES is only supported at functional level 2008 or higher
+ default_enctypes.add(kcrypto.Enctype.AES256)
+ default_enctypes.add(kcrypto.Enctype.AES128)
+
+ return default_enctypes
+
+ def create_account(self, samdb, name, account_type=AccountType.USER,
+ spn=None, upn=None, additional_details=None,
+ ou=None, account_control=0, add_dollar=True):
+ '''Create an account for testing.
+ The dn of the created account is added to self.accounts,
+ which is used by tearDownClass to clean up the created accounts.
+ '''
+ if ou is None:
+ if account_type is account_type.COMPUTER:
+ guid = DS_GUID_COMPUTERS_CONTAINER
+ elif account_type is account_type.SERVER:
+ guid = DS_GUID_DOMAIN_CONTROLLERS_CONTAINER
+ else:
+ guid = DS_GUID_USERS_CONTAINER
+
+ ou = samdb.get_wellknown_dn(samdb.get_default_basedn(), guid)
+
+ dn = "CN=%s,%s" % (name, ou)
+
+ # remove the account if it exists, this will happen if a previous test
+ # run failed
+ delete_force(samdb, dn)
+ account_name = name
+ if account_type is self.AccountType.USER:
+ object_class = "user"
+ account_control |= UF_NORMAL_ACCOUNT
+ else:
+ object_class = "computer"
+ if add_dollar:
+ account_name += '$'
+ if account_type is self.AccountType.COMPUTER:
+ account_control |= UF_WORKSTATION_TRUST_ACCOUNT
+ elif account_type is self.AccountType.SERVER:
+ account_control |= UF_SERVER_TRUST_ACCOUNT
+ else:
+ self.fail()
+
+ password = generate_random_password(32, 32)
+ utf16pw = ('"%s"' % password).encode('utf-16-le')
+
+ details = {
+ "dn": dn,
+ "objectclass": object_class,
+ "sAMAccountName": account_name,
+ "userAccountControl": str(account_control),
+ "unicodePwd": utf16pw}
+ if spn is not None:
+ if isinstance(spn, str):
+ spn = spn.format(account=account_name)
+ else:
+ spn = tuple(s.format(account=account_name) for s in spn)
+ details["servicePrincipalName"] = spn
+ if upn is not None:
+ details["userPrincipalName"] = upn
+ if additional_details is not None:
+ details.update(additional_details)
+ samdb.add(details)
+
+ creds = KerberosCredentials()
+ creds.guess(self.get_lp())
+ creds.set_realm(samdb.domain_dns_name().upper())
+ creds.set_domain(samdb.domain_netbios_name().upper())
+ creds.set_password(password)
+ creds.set_username(account_name)
+ if account_type is self.AccountType.USER:
+ creds.set_workstation('')
+ else:
+ creds.set_workstation(name)
+ creds.set_dn(ldb.Dn(samdb, dn))
+ creds.set_upn(upn)
+ creds.set_spn(spn)
+ #
+ # Save the account name so it can be deleted in tearDownClass
+ self.accounts.add(dn)
+
+ self.creds_set_enctypes(creds)
+
+ res = samdb.search(base=dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=['msDS-KeyVersionNumber'])
+ kvno = res[0].get('msDS-KeyVersionNumber', idx=0)
+ if kvno is not None:
+ self.assertEqual(int(kvno), 1)
+ creds.set_kvno(1)
+
+ return (creds, dn)
+
+ def get_security_descriptor(self, dn):
+ samdb = self.get_samdb()
+
+ sid = self.get_objectSid(samdb, dn)
+
+ owner_sid = security.dom_sid(security.SID_BUILTIN_ADMINISTRATORS)
+
+ ace = security.ace()
+ ace.access_mask = security.SEC_ADS_GENERIC_ALL
+
+ ace.trustee = security.dom_sid(sid)
+
+ dacl = security.acl()
+ dacl.revision = security.SECURITY_ACL_REVISION_ADS
+ dacl.aces = [ace]
+ dacl.num_aces = 1
+
+ security_desc = security.descriptor()
+ security_desc.type |= security.SEC_DESC_DACL_PRESENT
+ security_desc.owner_sid = owner_sid
+ security_desc.dacl = dacl
+
+ return ndr_pack(security_desc)
+
+ def create_rodc(self, ctx):
+ ctx.nc_list = [ctx.base_dn, ctx.config_dn, ctx.schema_dn]
+ ctx.full_nc_list = [ctx.base_dn, ctx.config_dn, ctx.schema_dn]
+ ctx.krbtgt_dn = f'CN=krbtgt_{ctx.myname},CN=Users,{ctx.base_dn}'
+
+ ctx.never_reveal_sid = [f'',
+ f'',
+ f'',
+ f'',
+ f'']
+ ctx.reveal_sid = f''
+
+ mysid = ctx.get_mysid()
+ admin_dn = f''
+ ctx.managedby = admin_dn
+
+ ctx.userAccountControl = (UF_WORKSTATION_TRUST_ACCOUNT |
+ UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION |
+ UF_PARTIAL_SECRETS_ACCOUNT)
+
+ ctx.connection_dn = f'CN=RODC Connection (FRS),{ctx.ntds_dn}'
+ ctx.secure_channel_type = misc.SEC_CHAN_RODC
+ ctx.RODC = True
+ ctx.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC |
+ drsuapi.DRSUAPI_DRS_PER_SYNC |
+ drsuapi.DRSUAPI_DRS_GET_ANC |
+ drsuapi.DRSUAPI_DRS_NEVER_SYNCED |
+ drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING)
+ ctx.domain_replica_flags = ctx.replica_flags | drsuapi.DRSUAPI_DRS_CRITICAL_ONLY
+
+ ctx.build_nc_lists()
+
+ ctx.cleanup_old_join()
+
+ try:
+ ctx.join_add_objects()
+ except Exception:
+ # cleanup the failed join (checking we still have a live LDB
+ # connection to the remote DC first)
+ ctx.refresh_ldb_connection()
+ ctx.cleanup_old_join()
+ raise
+
+ def replicate_account_to_rodc(self, dn):
+ samdb = self.get_samdb()
+ rodc_samdb = self.get_rodc_samdb()
+
+ repl_val = f'{samdb.get_dsServiceName()}:{dn}:SECRETS_ONLY'
+
+ msg = ldb.Message()
+ msg.dn = ldb.Dn(rodc_samdb, '')
+ msg['replicateSingleObject'] = ldb.MessageElement(
+ repl_val,
+ ldb.FLAG_MOD_REPLACE,
+ 'replicateSingleObject')
+
+ try:
+ # Try replication using the replicateSingleObject rootDSE
+ # operation.
+ rodc_samdb.modify(msg)
+ except ldb.LdbError as err:
+ enum, estr = err.args
+ self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM)
+ self.assertIn('rootdse_modify: unknown attribute to change!',
+ estr)
+
+ # If that method wasn't supported, we may be in the rodc:local test
+ # environment, where we can try replicating to the local database.
+
+ lp = self.get_lp()
+
+ rodc_creds = Credentials()
+ rodc_creds.guess(lp)
+ rodc_creds.set_machine_account(lp)
+
+ local_samdb = SamDB(url=None, session_info=system_session(),
+ credentials=rodc_creds, lp=lp)
+
+ destination_dsa_guid = misc.GUID(local_samdb.get_ntds_GUID())
+
+ repl = drs_Replicate(f'ncacn_ip_tcp:{self.dc_host}[seal]',
+ lp, rodc_creds,
+ local_samdb, destination_dsa_guid)
+
+ source_dsa_invocation_id = misc.GUID(samdb.invocation_id)
+
+ repl.replicate(dn,
+ source_dsa_invocation_id,
+ destination_dsa_guid,
+ exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET,
+ rodc=True)
+
+ def reveal_account_to_mock_rodc(self, dn):
+ samdb = self.get_samdb()
+ rodc_ctx = self.get_mock_rodc_ctx()
+
+ self.get_secrets(
+ samdb,
+ dn,
+ destination_dsa_guid=rodc_ctx.ntds_guid,
+ source_dsa_invocation_id=misc.GUID(samdb.invocation_id))
+
+ def check_revealed(self, dn, rodc_dn, revealed=True):
+ samdb = self.get_samdb()
+
+ res = samdb.search(base=rodc_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=['msDS-RevealedUsers'])
+
+ revealed_users = res[0].get('msDS-RevealedUsers')
+ if revealed_users is None:
+ self.assertFalse(revealed)
+ return
+
+ revealed_dns = set(str(dsdb_Dn(samdb, str(user),
+ syntax_oid=DSDB_SYNTAX_BINARY_DN).dn)
+ for user in revealed_users)
+
+ if revealed:
+ self.assertIn(str(dn), revealed_dns)
+ else:
+ self.assertNotIn(str(dn), revealed_dns)
+
+ def get_secrets(self, samdb, dn,
+ destination_dsa_guid,
+ source_dsa_invocation_id):
+ admin_creds = self.get_admin_creds()
+
+ dns_hostname = samdb.host_dns_name()
+ (bind, handle, _) = drsuapi_connect(dns_hostname,
+ self.get_lp(),
+ admin_creds)
+
+ req = drsuapi.DsGetNCChangesRequest8()
+
+ req.destination_dsa_guid = destination_dsa_guid
+ req.source_dsa_invocation_id = source_dsa_invocation_id
+
+ naming_context = drsuapi.DsReplicaObjectIdentifier()
+ naming_context.dn = dn
+
+ req.naming_context = naming_context
+
+ hwm = drsuapi.DsReplicaHighWaterMark()
+ hwm.tmp_highest_usn = 0
+ hwm.reserved_usn = 0
+ hwm.highest_usn = 0
+
+ req.highwatermark = hwm
+ req.uptodateness_vector = None
+
+ req.replica_flags = 0
+
+ req.max_object_count = 1
+ req.max_ndr_size = 402116
+ req.extended_op = drsuapi.DRSUAPI_EXOP_REPL_SECRET
+
+ attids = [drsuapi.DRSUAPI_ATTID_supplementalCredentials,
+ drsuapi.DRSUAPI_ATTID_unicodePwd]
+
+ partial_attribute_set = drsuapi.DsPartialAttributeSet()
+ partial_attribute_set.version = 1
+ partial_attribute_set.attids = attids
+ partial_attribute_set.num_attids = len(attids)
+
+ req.partial_attribute_set = partial_attribute_set
+
+ req.partial_attribute_set_ex = None
+ req.mapping_ctr.num_mappings = 0
+ req.mapping_ctr.mappings = None
+
+ _, ctr = bind.DsGetNCChanges(handle, 8, req)
+
+ self.assertEqual(1, ctr.object_count)
+
+ identifier = ctr.first_object.object.identifier
+ attributes = ctr.first_object.object.attribute_ctr.attributes
+
+ self.assertEqual(dn, identifier.dn)
+
+ return bind, identifier, attributes
+
+ def get_keys(self, samdb, dn):
+ admin_creds = self.get_admin_creds()
+
+ bind, identifier, attributes = self.get_secrets(
+ samdb,
+ str(dn),
+ destination_dsa_guid=misc.GUID(samdb.get_ntds_GUID()),
+ source_dsa_invocation_id=misc.GUID())
+
+ rid = identifier.sid.split()[1]
+
+ net_ctx = net.Net(admin_creds)
+
+ keys = {}
+
+ for attr in attributes:
+ if attr.attid == drsuapi.DRSUAPI_ATTID_supplementalCredentials:
+ net_ctx.replicate_decrypt(bind, attr, rid)
+ attr_val = attr.value_ctr.values[0].blob
+
+ spl = ndr_unpack(drsblobs.supplementalCredentialsBlob,
+ attr_val)
+ for pkg in spl.sub.packages:
+ if pkg.name == 'Primary:Kerberos-Newer-Keys':
+ krb5_new_keys_raw = binascii.a2b_hex(pkg.data)
+ krb5_new_keys = ndr_unpack(
+ drsblobs.package_PrimaryKerberosBlob,
+ krb5_new_keys_raw)
+ for key in krb5_new_keys.ctr.keys:
+ keytype = key.keytype
+ if keytype in (kcrypto.Enctype.AES256,
+ kcrypto.Enctype.AES128):
+ keys[keytype] = key.value.hex()
+ elif attr.attid == drsuapi.DRSUAPI_ATTID_unicodePwd:
+ net_ctx.replicate_decrypt(bind, attr, rid)
+ pwd = attr.value_ctr.values[0].blob
+ keys[kcrypto.Enctype.RC4] = pwd.hex()
+
+ default_enctypes = self.get_default_enctypes()
+
+ self.assertCountEqual(default_enctypes, keys)
+
+ return keys
+
+ def creds_set_keys(self, creds, keys):
+ if keys is not None:
+ for enctype, key in keys.items():
+ creds.set_forced_key(enctype, key)
+
+ def creds_set_enctypes(self, creds):
+ samdb = self.get_samdb()
+
+ res = samdb.search(creds.get_dn(),
+ scope=ldb.SCOPE_BASE,
+ attrs=['msDS-SupportedEncryptionTypes'])
+ supported_enctypes = res[0].get('msDS-SupportedEncryptionTypes', idx=0)
+
+ if supported_enctypes is None:
+ supported_enctypes = 0
+
+ creds.set_as_supported_enctypes(supported_enctypes)
+ creds.set_tgs_supported_enctypes(supported_enctypes)
+ creds.set_ap_supported_enctypes(supported_enctypes)
+
+ def creds_set_default_enctypes(self, creds, fast_support=False):
+ default_enctypes = self.get_default_enctypes()
+ supported_enctypes = KerberosCredentials.etypes_to_bits(
+ default_enctypes)
+
+ if fast_support:
+ supported_enctypes |= KerberosCredentials.fast_supported_bits
+
+ creds.set_as_supported_enctypes(supported_enctypes)
+ creds.set_tgs_supported_enctypes(supported_enctypes)
+ creds.set_ap_supported_enctypes(supported_enctypes)
+
+ def add_to_group(self, account_dn, group_dn, group_attr):
+ samdb = self.get_samdb()
+
+ res = samdb.search(base=group_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=[group_attr])
+ orig_msg = res[0]
+ self.assertIn(group_attr, orig_msg)
+
+ members = list(orig_msg[group_attr])
+ members.append(account_dn)
+
+ msg = ldb.Message()
+ msg.dn = group_dn
+ msg[group_attr] = ldb.MessageElement(members,
+ ldb.FLAG_MOD_REPLACE,
+ group_attr)
+
+ cleanup = samdb.msg_diff(msg, orig_msg)
+ self.ldb_cleanups.append(cleanup)
+ samdb.modify(msg)
+
+ return cleanup
+
+ def get_cached_creds(self, *,
+ account_type,
+ opts=None,
+ use_cache=True):
+ if opts is None:
+ opts = {}
+
+ opts_default = {
+ 'name_prefix': None,
+ 'name_suffix': None,
+ 'add_dollar': True,
+ 'upn': None,
+ 'spn': None,
+ 'allowed_replication': False,
+ 'allowed_replication_mock': False,
+ 'denied_replication': False,
+ 'denied_replication_mock': False,
+ 'revealed_to_rodc': False,
+ 'revealed_to_mock_rodc': False,
+ 'no_auth_data_required': False,
+ 'supported_enctypes': None,
+ 'not_delegated': False,
+ 'delegation_to_spn': None,
+ 'delegation_from_dn': None,
+ 'trusted_to_auth_for_delegation': False,
+ 'fast_support': False,
+ 'id': None
+ }
+
+ account_opts = {
+ 'account_type': account_type,
+ **opts_default,
+ **opts
+ }
+
+ cache_key = tuple(sorted(account_opts.items()))
+
+ if use_cache:
+ creds = self.account_cache.get(cache_key)
+ if creds is not None:
+ return creds
+
+ creds = self.create_account_opts(**account_opts)
+ if use_cache:
+ self.account_cache[cache_key] = creds
+
+ return creds
+
+ def create_account_opts(self, *,
+ account_type,
+ name_prefix,
+ name_suffix,
+ add_dollar,
+ upn,
+ spn,
+ allowed_replication,
+ allowed_replication_mock,
+ denied_replication,
+ denied_replication_mock,
+ revealed_to_rodc,
+ revealed_to_mock_rodc,
+ no_auth_data_required,
+ supported_enctypes,
+ not_delegated,
+ delegation_to_spn,
+ delegation_from_dn,
+ trusted_to_auth_for_delegation,
+ fast_support,
+ id):
+ if account_type is self.AccountType.USER:
+ self.assertIsNone(spn)
+ self.assertIsNone(delegation_to_spn)
+ self.assertIsNone(delegation_from_dn)
+ self.assertFalse(trusted_to_auth_for_delegation)
+ else:
+ self.assertFalse(not_delegated)
+
+ samdb = self.get_samdb()
+
+ user_name = self.get_new_username()
+ if name_prefix is not None:
+ user_name = name_prefix + user_name
+ if name_suffix is not None:
+ user_name += name_suffix
+
+ user_account_control = 0
+ if trusted_to_auth_for_delegation:
+ user_account_control |= UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
+ if not_delegated:
+ user_account_control |= UF_NOT_DELEGATED
+ if no_auth_data_required:
+ user_account_control |= UF_NO_AUTH_DATA_REQUIRED
+
+ details = {}
+
+ enctypes = supported_enctypes
+ if fast_support:
+ enctypes = enctypes or 0
+ enctypes |= KerberosCredentials.fast_supported_bits
+
+ if enctypes is not None:
+ details['msDS-SupportedEncryptionTypes'] = str(enctypes)
+
+ if delegation_to_spn:
+ details['msDS-AllowedToDelegateTo'] = delegation_to_spn
+
+ if delegation_from_dn:
+ security_descriptor = self.get_security_descriptor(
+ delegation_from_dn)
+ details['msDS-AllowedToActOnBehalfOfOtherIdentity'] = (
+ security_descriptor)
+
+ if spn is None and account_type is not self.AccountType.USER:
+ spn = 'host/' + user_name
+
+ creds, dn = self.create_account(samdb, user_name,
+ account_type=account_type,
+ upn=upn,
+ spn=spn,
+ additional_details=details,
+ account_control=user_account_control,
+ add_dollar=add_dollar)
+
+ keys = self.get_keys(samdb, dn)
+ self.creds_set_keys(creds, keys)
+
+ # Handle secret replication to the RODC.
+
+ if allowed_replication or revealed_to_rodc:
+ rodc_samdb = self.get_rodc_samdb()
+ rodc_dn = self.get_server_dn(rodc_samdb)
+
+ # Allow replicating this account's secrets if requested, or allow
+ # it only temporarily if we're about to replicate them.
+ allowed_cleanup = self.add_to_group(
+ dn, rodc_dn,
+ 'msDS-RevealOnDemandGroup')
+
+ if revealed_to_rodc:
+ # Replicate this account's secrets to the RODC.
+ self.replicate_account_to_rodc(dn)
+
+ if not allowed_replication:
+ # If we don't want replicating secrets to be allowed for this
+ # account, disable it again.
+ samdb.modify(allowed_cleanup)
+
+ self.check_revealed(dn,
+ rodc_dn,
+ revealed=revealed_to_rodc)
+
+ if denied_replication:
+ rodc_samdb = self.get_rodc_samdb()
+ rodc_dn = self.get_server_dn(rodc_samdb)
+
+ # Deny replicating this account's secrets to the RODC.
+ self.add_to_group(dn, rodc_dn, 'msDS-NeverRevealGroup')
+
+ # Handle secret replication to the mock RODC.
+
+ if allowed_replication_mock or revealed_to_mock_rodc:
+ # Allow replicating this account's secrets if requested, or allow
+ # it only temporarily if we want to add the account to the mock
+ # RODC's msDS-RevealedUsers.
+ rodc_ctx = self.get_mock_rodc_ctx()
+ mock_rodc_dn = ldb.Dn(samdb, rodc_ctx.acct_dn)
+
+ allowed_mock_cleanup = self.add_to_group(
+ dn, mock_rodc_dn,
+ 'msDS-RevealOnDemandGroup')
+
+ if revealed_to_mock_rodc:
+ # Request replicating this account's secrets to the mock RODC,
+ # which updates msDS-RevealedUsers.
+ self.reveal_account_to_mock_rodc(dn)
+
+ if not allowed_replication_mock:
+ # If we don't want replicating secrets to be allowed for this
+ # account, disable it again.
+ samdb.modify(allowed_mock_cleanup)
+
+ self.check_revealed(dn,
+ mock_rodc_dn,
+ revealed=revealed_to_mock_rodc)
+
+ if denied_replication_mock:
+ # Deny replicating this account's secrets to the mock RODC.
+ rodc_ctx = self.get_mock_rodc_ctx()
+ mock_rodc_dn = ldb.Dn(samdb, rodc_ctx.acct_dn)
+
+ self.add_to_group(dn, mock_rodc_dn, 'msDS-NeverRevealGroup')
+
+ return creds
+
+ def get_new_username(self):
+ user_name = self.account_base + str(self.account_id)
+ type(self).account_id += 1
+
+ return user_name
+
+ def get_client_creds(self,
+ allow_missing_password=False,
+ allow_missing_keys=True):
+ def create_client_account():
+ return self.get_cached_creds(account_type=self.AccountType.USER)
+
+ c = self._get_krb5_creds(prefix='CLIENT',
+ allow_missing_password=allow_missing_password,
+ allow_missing_keys=allow_missing_keys,
+ fallback_creds_fn=create_client_account)
+ return c
+
+ def get_mach_creds(self,
+ allow_missing_password=False,
+ allow_missing_keys=True):
+ def create_mach_account():
+ return self.get_cached_creds(account_type=self.AccountType.COMPUTER,
+ opts={'fast_support': True})
+
+ c = self._get_krb5_creds(prefix='MAC',
+ allow_missing_password=allow_missing_password,
+ allow_missing_keys=allow_missing_keys,
+ fallback_creds_fn=create_mach_account)
+ return c
+
+ def get_service_creds(self,
+ allow_missing_password=False,
+ allow_missing_keys=True):
+ def create_service_account():
+ return self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={
+ 'trusted_to_auth_for_delegation': True,
+ 'fast_support': True
+ })
+
+ c = self._get_krb5_creds(prefix='SERVICE',
+ allow_missing_password=allow_missing_password,
+ allow_missing_keys=allow_missing_keys,
+ fallback_creds_fn=create_service_account)
+ return c
+
+ def get_rodc_krbtgt_creds(self,
+ require_keys=True,
+ require_strongest_key=False):
+ if require_strongest_key:
+ self.assertTrue(require_keys)
+
+ def download_rodc_krbtgt_creds():
+ samdb = self.get_samdb()
+ rodc_samdb = self.get_rodc_samdb()
+
+ rodc_dn = self.get_server_dn(rodc_samdb)
+
+ res = samdb.search(rodc_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=['msDS-KrbTgtLink'])
+ krbtgt_dn = res[0]['msDS-KrbTgtLink'][0]
+
+ res = samdb.search(krbtgt_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=['sAMAccountName',
+ 'msDS-KeyVersionNumber',
+ 'msDS-SecondaryKrbTgtNumber'])
+ krbtgt_dn = res[0].dn
+ username = str(res[0]['sAMAccountName'])
+
+ creds = KerberosCredentials()
+ creds.set_domain(self.env_get_var('DOMAIN', 'RODC_KRBTGT'))
+ creds.set_realm(self.env_get_var('REALM', 'RODC_KRBTGT'))
+ creds.set_username(username)
+
+ kvno = int(res[0]['msDS-KeyVersionNumber'][0])
+ krbtgt_number = int(res[0]['msDS-SecondaryKrbTgtNumber'][0])
+
+ rodc_kvno = krbtgt_number << 16 | kvno
+ creds.set_kvno(rodc_kvno)
+ creds.set_dn(krbtgt_dn)
+
+ keys = self.get_keys(samdb, krbtgt_dn)
+ self.creds_set_keys(creds, keys)
+
+ # The RODC krbtgt account should support the default enctypes,
+ # although it might not have the msDS-SupportedEncryptionTypes
+ # attribute.
+ self.creds_set_default_enctypes(creds)
+
+ return creds
+
+ c = self._get_krb5_creds(prefix='RODC_KRBTGT',
+ allow_missing_password=True,
+ allow_missing_keys=not require_keys,
+ require_strongest_key=require_strongest_key,
+ fallback_creds_fn=download_rodc_krbtgt_creds)
+ return c
+
+ def get_mock_rodc_krbtgt_creds(self,
+ require_keys=True,
+ require_strongest_key=False):
+ if require_strongest_key:
+ self.assertTrue(require_keys)
+
+ def create_rodc_krbtgt_account():
+ samdb = self.get_samdb()
+
+ rodc_ctx = self.get_mock_rodc_ctx()
+
+ krbtgt_dn = rodc_ctx.new_krbtgt_dn
+
+ res = samdb.search(base=ldb.Dn(samdb, krbtgt_dn),
+ scope=ldb.SCOPE_BASE,
+ attrs=['msDS-KeyVersionNumber',
+ 'msDS-SecondaryKrbTgtNumber'])
+ dn = res[0].dn
+ username = str(rodc_ctx.krbtgt_name)
+
+ creds = KerberosCredentials()
+ creds.set_domain(self.env_get_var('DOMAIN', 'RODC_KRBTGT'))
+ creds.set_realm(self.env_get_var('REALM', 'RODC_KRBTGT'))
+ creds.set_username(username)
+
+ kvno = int(res[0]['msDS-KeyVersionNumber'][0])
+ krbtgt_number = int(res[0]['msDS-SecondaryKrbTgtNumber'][0])
+
+ rodc_kvno = krbtgt_number << 16 | kvno
+ creds.set_kvno(rodc_kvno)
+ creds.set_dn(dn)
+
+ keys = self.get_keys(samdb, dn)
+ self.creds_set_keys(creds, keys)
+
+ self.creds_set_enctypes(creds)
+
+ return creds
+
+ c = self._get_krb5_creds(prefix='MOCK_RODC_KRBTGT',
+ allow_missing_password=True,
+ allow_missing_keys=not require_keys,
+ require_strongest_key=require_strongest_key,
+ fallback_creds_fn=create_rodc_krbtgt_account)
+ return c
+
+ def get_krbtgt_creds(self,
+ require_keys=True,
+ require_strongest_key=False):
+ if require_strongest_key:
+ self.assertTrue(require_keys)
+
+ def download_krbtgt_creds():
+ samdb = self.get_samdb()
+
+ krbtgt_rid = security.DOMAIN_RID_KRBTGT
+ krbtgt_sid = '%s-%d' % (samdb.get_domain_sid(), krbtgt_rid)
+
+ res = samdb.search(base='' % krbtgt_sid,
+ scope=ldb.SCOPE_BASE,
+ attrs=['sAMAccountName',
+ 'msDS-KeyVersionNumber'])
+ dn = res[0].dn
+ username = str(res[0]['sAMAccountName'])
+
+ creds = KerberosCredentials()
+ creds.set_domain(self.env_get_var('DOMAIN', 'KRBTGT'))
+ creds.set_realm(self.env_get_var('REALM', 'KRBTGT'))
+ creds.set_username(username)
+
+ kvno = int(res[0]['msDS-KeyVersionNumber'][0])
+ creds.set_kvno(kvno)
+ creds.set_dn(dn)
+
+ keys = self.get_keys(samdb, dn)
+ self.creds_set_keys(creds, keys)
+
+ # The krbtgt account should support the default enctypes, although
+ # it might not (on Samba) have the msDS-SupportedEncryptionTypes
+ # attribute.
+ self.creds_set_default_enctypes(creds,
+ fast_support=self.kdc_fast_support)
+
+ return creds
+
+ c = self._get_krb5_creds(prefix='KRBTGT',
+ default_username='krbtgt',
+ allow_missing_password=True,
+ allow_missing_keys=not require_keys,
+ require_strongest_key=require_strongest_key,
+ fallback_creds_fn=download_krbtgt_creds)
+ return c
+
+ def get_dc_creds(self,
+ require_keys=True,
+ require_strongest_key=False):
+ if require_strongest_key:
+ self.assertTrue(require_keys)
+
+ def download_dc_creds():
+ samdb = self.get_samdb()
+
+ dc_rid = 1000
+ dc_sid = '%s-%d' % (samdb.get_domain_sid(), dc_rid)
+
+ res = samdb.search(base='' % dc_sid,
+ scope=ldb.SCOPE_BASE,
+ attrs=['sAMAccountName',
+ 'msDS-KeyVersionNumber'])
+ dn = res[0].dn
+ username = str(res[0]['sAMAccountName'])
+
+ creds = KerberosCredentials()
+ creds.set_domain(self.env_get_var('DOMAIN', 'DC'))
+ creds.set_realm(self.env_get_var('REALM', 'DC'))
+ creds.set_username(username)
+
+ kvno = int(res[0]['msDS-KeyVersionNumber'][0])
+ creds.set_kvno(kvno)
+ creds.set_dn(dn)
+
+ keys = self.get_keys(samdb, dn)
+ self.creds_set_keys(creds, keys)
+
+ self.creds_set_enctypes(creds)
+
+ return creds
+
+ c = self._get_krb5_creds(prefix='DC',
+ allow_missing_password=True,
+ allow_missing_keys=not require_keys,
+ require_strongest_key=require_strongest_key,
+ fallback_creds_fn=download_dc_creds)
+ return c
+
+ def as_req(self, cname, sname, realm, etypes, padata=None, kdc_options=0):
+ '''Send a Kerberos AS_REQ, returns the undecoded response
+ '''
+
+ till = self.get_KerberosTime(offset=36000)
+
+ req = self.AS_REQ_create(padata=padata,
+ kdc_options=str(kdc_options),
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ from_time=None,
+ till_time=till,
+ renew_time=None,
+ nonce=0x7fffffff,
+ etypes=etypes,
+ addresses=None,
+ additional_tickets=None)
+ rep = self.send_recv_transaction(req)
+ return rep
+
+ def get_as_rep_key(self, creds, rep):
+ '''Extract the session key from an AS-REP
+ '''
+ rep_padata = self.der_decode(
+ rep['e-data'],
+ asn1Spec=krb5_asn1.METHOD_DATA())
+
+ for pa in rep_padata:
+ if pa['padata-type'] == PADATA_ETYPE_INFO2:
+ padata_value = pa['padata-value']
+ break
+
+ etype_info2 = self.der_decode(
+ padata_value, asn1Spec=krb5_asn1.ETYPE_INFO2())
+
+ key = self.PasswordKey_from_etype_info2(creds, etype_info2[0],
+ creds.get_kvno())
+ return key
+
+ def get_enc_timestamp_pa_data(self, creds, rep, skew=0):
+ '''generate the pa_data data element for an AS-REQ
+ '''
+
+ key = self.get_as_rep_key(creds, rep)
+
+ return self.get_enc_timestamp_pa_data_from_key(key, skew=skew)
+
+ def get_enc_timestamp_pa_data_from_key(self, key, skew=0):
+ (patime, pausec) = self.get_KerberosTimeWithUsec(offset=skew)
+ padata = self.PA_ENC_TS_ENC_create(patime, pausec)
+ padata = self.der_encode(padata, asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
+
+ padata = self.EncryptedData_create(key, KU_PA_ENC_TIMESTAMP, padata)
+ padata = self.der_encode(padata, asn1Spec=krb5_asn1.EncryptedData())
+
+ padata = self.PA_DATA_create(PADATA_ENC_TIMESTAMP, padata)
+
+ return padata
+
+ def get_challenge_pa_data(self, client_challenge_key, skew=0):
+ patime, pausec = self.get_KerberosTimeWithUsec(offset=skew)
+ padata = self.PA_ENC_TS_ENC_create(patime, pausec)
+ padata = self.der_encode(padata,
+ asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
+
+ padata = self.EncryptedData_create(client_challenge_key,
+ KU_ENC_CHALLENGE_CLIENT,
+ padata)
+ padata = self.der_encode(padata,
+ asn1Spec=krb5_asn1.EncryptedData())
+
+ padata = self.PA_DATA_create(PADATA_ENCRYPTED_CHALLENGE,
+ padata)
+
+ return padata
+
+ def get_as_rep_enc_data(self, key, rep):
+ ''' Decrypt and Decode the encrypted data in an AS-REP
+ '''
+ enc_part = key.decrypt(KU_AS_REP_ENC_PART, rep['enc-part']['cipher'])
+ # MIT KDC encodes both EncASRepPart and EncTGSRepPart with
+ # application tag 26
+ try:
+ enc_part = self.der_decode(
+ enc_part, asn1Spec=krb5_asn1.EncASRepPart())
+ except Exception:
+ enc_part = self.der_decode(
+ enc_part, asn1Spec=krb5_asn1.EncTGSRepPart())
+
+ return enc_part
+
+ def check_pre_authentication(self, rep):
+ """ Check that the kdc response was pre-authentication required
+ """
+ self.check_error_rep(rep, KDC_ERR_PREAUTH_REQUIRED)
+
+ def check_as_reply(self, rep):
+ """ Check that the kdc response is an AS-REP and that the
+ values for:
+ msg-type
+ pvno
+ tkt-pvno
+ kvno
+ match the expected values
+ """
+ self.check_reply(rep, msg_type=KRB_AS_REP)
+
+ def check_tgs_reply(self, rep):
+ """ Check that the kdc response is an TGS-REP and that the
+ values for:
+ msg-type
+ pvno
+ tkt-pvno
+ kvno
+ match the expected values
+ """
+ self.check_reply(rep, msg_type=KRB_TGS_REP)
+
+ def check_reply(self, rep, msg_type):
+
+ # Should have a reply, and it should an TGS-REP message.
+ self.assertIsNotNone(rep)
+ self.assertEqual(rep['msg-type'], msg_type, "rep = {%s}" % rep)
+
+ # Protocol version number should be 5
+ pvno = int(rep['pvno'])
+ self.assertEqual(5, pvno, "rep = {%s}" % rep)
+
+ # The ticket version number should be 5
+ tkt_vno = int(rep['ticket']['tkt-vno'])
+ self.assertEqual(5, tkt_vno, "rep = {%s}" % rep)
+
+ # Check that the kvno is not an RODC kvno
+ # MIT kerberos does not provide the kvno, so we treat it as optional.
+ # This is tested in compatability_test.py
+ if 'kvno' in rep['enc-part']:
+ kvno = int(rep['enc-part']['kvno'])
+ # If the high order bits are set this is an RODC kvno.
+ self.assertEqual(0, kvno & 0xFFFF0000, "rep = {%s}" % rep)
+
+ def check_error_rep(self, rep, expected):
+ """ Check that the reply is an error message, with the expected
+ error-code specified.
+ """
+ self.assertIsNotNone(rep)
+ self.assertEqual(rep['msg-type'], KRB_ERROR, "rep = {%s}" % rep)
+ if isinstance(expected, collections.abc.Container):
+ self.assertIn(rep['error-code'], expected, "rep = {%s}" % rep)
+ else:
+ self.assertEqual(rep['error-code'], expected, "rep = {%s}" % rep)
+
+ def tgs_req(self, cname, sname, realm, ticket, key, etypes,
+ expected_error_mode=0, padata=None, kdc_options=0,
+ to_rodc=False, service_creds=None, expect_pac=True,
+ expect_edata=None, expected_flags=None, unexpected_flags=None):
+ '''Send a TGS-REQ, returns the response and the decrypted and
+ decoded enc-part
+ '''
+
+ subkey = self.RandomKey(key.etype)
+
+ (ctime, cusec) = self.get_KerberosTimeWithUsec()
+
+ tgt = KerberosTicketCreds(ticket,
+ key,
+ crealm=realm,
+ cname=cname)
+
+ if service_creds is not None:
+ decryption_key = self.TicketDecryptionKey_from_creds(
+ service_creds)
+ expected_supported_etypes = service_creds.tgs_supported_enctypes
+ else:
+ decryption_key = None
+ expected_supported_etypes = None
+
+ if not expected_error_mode:
+ check_error_fn = None
+ check_rep_fn = self.generic_check_kdc_rep
+ else:
+ check_error_fn = self.generic_check_kdc_error
+ check_rep_fn = None
+
+ def generate_padata(_kdc_exchange_dict,
+ _callback_dict,
+ req_body):
+
+ return padata, req_body
+
+ kdc_exchange_dict = self.tgs_exchange_dict(
+ expected_crealm=realm,
+ expected_cname=cname,
+ expected_srealm=realm,
+ expected_sname=sname,
+ expected_error_mode=expected_error_mode,
+ expected_flags=expected_flags,
+ unexpected_flags=unexpected_flags,
+ expected_supported_etypes=expected_supported_etypes,
+ check_error_fn=check_error_fn,
+ check_rep_fn=check_rep_fn,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ ticket_decryption_key=decryption_key,
+ generate_padata_fn=generate_padata if padata is not None else None,
+ tgt=tgt,
+ authenticator_subkey=subkey,
+ kdc_options=str(kdc_options),
+ expect_edata=expect_edata,
+ expect_pac=expect_pac,
+ to_rodc=to_rodc)
+
+ rep = self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=None,
+ realm=realm,
+ sname=sname,
+ etypes=etypes)
+
+ if expected_error_mode:
+ enc_part = None
+ else:
+ ticket_creds = kdc_exchange_dict['rep_ticket_creds']
+ enc_part = ticket_creds.encpart_private
+
+ return rep, enc_part
+
+ def get_service_ticket(self, tgt, target_creds, service='host',
+ target_name=None,
+ to_rodc=False, kdc_options=None,
+ expected_flags=None, unexpected_flags=None,
+ pac_request=True, expect_pac=True, fresh=False):
+ user_name = tgt.cname['name-string'][0]
+ if target_name is None:
+ target_name = target_creds.get_username()[:-1]
+ cache_key = (user_name, target_name, service, to_rodc, kdc_options,
+ pac_request, str(expected_flags), str(unexpected_flags),
+ expect_pac)
+
+ if not fresh:
+ ticket = self.tkt_cache.get(cache_key)
+
+ if ticket is not None:
+ return ticket
+
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+
+ if kdc_options is None:
+ kdc_options = '0'
+ kdc_options = str(krb5_asn1.KDCOptions(kdc_options))
+
+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[service, target_name])
+ srealm = target_creds.get_realm()
+
+ authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256)
+
+ decryption_key = self.TicketDecryptionKey_from_creds(target_creds)
+
+ kdc_exchange_dict = self.tgs_exchange_dict(
+ expected_crealm=tgt.crealm,
+ expected_cname=tgt.cname,
+ expected_srealm=srealm,
+ expected_sname=sname,
+ expected_supported_etypes=target_creds.tgs_supported_enctypes,
+ expected_flags=expected_flags,
+ unexpected_flags=unexpected_flags,
+ ticket_decryption_key=decryption_key,
+ check_rep_fn=self.generic_check_kdc_rep,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ tgt=tgt,
+ authenticator_subkey=authenticator_subkey,
+ kdc_options=kdc_options,
+ pac_request=pac_request,
+ expect_pac=expect_pac,
+ to_rodc=to_rodc)
+
+ rep = self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=None,
+ realm=srealm,
+ sname=sname,
+ etypes=etype)
+ self.check_tgs_reply(rep)
+
+ service_ticket_creds = kdc_exchange_dict['rep_ticket_creds']
+
+ if to_rodc:
+ krbtgt_creds = self.get_rodc_krbtgt_creds()
+ else:
+ krbtgt_creds = self.get_krbtgt_creds()
+ krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+ self.verify_ticket(service_ticket_creds, krbtgt_key,
+ expect_pac=expect_pac,
+ expect_ticket_checksum=self.tkt_sig_support)
+
+ self.tkt_cache[cache_key] = service_ticket_creds
+
+ return service_ticket_creds
+
+ def get_tgt(self, creds, to_rodc=False, kdc_options=None,
+ expected_flags=None, unexpected_flags=None,
+ expected_account_name=None, expected_upn_name=None,
+ expected_sid=None,
+ pac_request=True, expect_pac=True,
+ expect_pac_attrs=None, expect_pac_attrs_pac_request=None,
+ expect_requester_sid=None,
+ fresh=False):
+ user_name = creds.get_username()
+ cache_key = (user_name, to_rodc, kdc_options, pac_request,
+ str(expected_flags), str(unexpected_flags),
+ expected_account_name, expected_upn_name, expected_sid,
+ expect_pac, expect_pac_attrs,
+ expect_pac_attrs_pac_request, expect_requester_sid)
+
+ if not fresh:
+ tgt = self.tkt_cache.get(cache_key)
+
+ if tgt is not None:
+ return tgt
+
+ realm = creds.get_realm()
+
+ salt = creds.get_salt()
+
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[user_name])
+ sname = self.PrincipalName_create(name_type=NT_SRV_INST,
+ names=['krbtgt', realm])
+
+ till = self.get_KerberosTime(offset=36000)
+
+ if to_rodc:
+ krbtgt_creds = self.get_rodc_krbtgt_creds()
+ else:
+ krbtgt_creds = self.get_krbtgt_creds()
+ ticket_decryption_key = (
+ self.TicketDecryptionKey_from_creds(krbtgt_creds))
+
+ expected_etypes = krbtgt_creds.tgs_supported_enctypes
+
+ if kdc_options is None:
+ kdc_options = ('forwardable,'
+ 'renewable,'
+ 'canonicalize,'
+ 'renewable-ok')
+ kdc_options = krb5_asn1.KDCOptions(kdc_options)
+
+ pac_options = '1' # supports claims
+
+ rep, kdc_exchange_dict = self._test_as_exchange(
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ till=till,
+ client_as_etypes=etype,
+ expected_error_mode=KDC_ERR_PREAUTH_REQUIRED,
+ expected_crealm=realm,
+ expected_cname=cname,
+ expected_srealm=realm,
+ expected_sname=sname,
+ expected_account_name=expected_account_name,
+ expected_upn_name=expected_upn_name,
+ expected_sid=expected_sid,
+ expected_salt=salt,
+ expected_flags=expected_flags,
+ unexpected_flags=unexpected_flags,
+ expected_supported_etypes=expected_etypes,
+ etypes=etype,
+ padata=None,
+ kdc_options=kdc_options,
+ preauth_key=None,
+ ticket_decryption_key=ticket_decryption_key,
+ pac_request=pac_request,
+ pac_options=pac_options,
+ expect_pac=expect_pac,
+ expect_pac_attrs=expect_pac_attrs,
+ expect_pac_attrs_pac_request=expect_pac_attrs_pac_request,
+ expect_requester_sid=expect_requester_sid,
+ to_rodc=to_rodc)
+ self.check_pre_authentication(rep)
+
+ etype_info2 = kdc_exchange_dict['preauth_etype_info2']
+
+ preauth_key = self.PasswordKey_from_etype_info2(creds,
+ etype_info2[0],
+ creds.get_kvno())
+
+ ts_enc_padata = self.get_enc_timestamp_pa_data(creds, rep)
+
+ padata = [ts_enc_padata]
+
+ expected_realm = realm.upper()
+
+ expected_sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=['krbtgt', realm.upper()])
+
+ rep, kdc_exchange_dict = self._test_as_exchange(
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ till=till,
+ client_as_etypes=etype,
+ expected_error_mode=0,
+ expected_crealm=expected_realm,
+ expected_cname=cname,
+ expected_srealm=expected_realm,
+ expected_sname=expected_sname,
+ expected_account_name=expected_account_name,
+ expected_upn_name=expected_upn_name,
+ expected_sid=expected_sid,
+ expected_salt=salt,
+ expected_flags=expected_flags,
+ unexpected_flags=unexpected_flags,
+ expected_supported_etypes=expected_etypes,
+ etypes=etype,
+ padata=padata,
+ kdc_options=kdc_options,
+ preauth_key=preauth_key,
+ ticket_decryption_key=ticket_decryption_key,
+ pac_request=pac_request,
+ pac_options=pac_options,
+ expect_pac=expect_pac,
+ expect_pac_attrs=expect_pac_attrs,
+ expect_pac_attrs_pac_request=expect_pac_attrs_pac_request,
+ expect_requester_sid=expect_requester_sid,
+ to_rodc=to_rodc)
+ self.check_as_reply(rep)
+
+ ticket_creds = kdc_exchange_dict['rep_ticket_creds']
+
+ self.tkt_cache[cache_key] = ticket_creds
+
+ return ticket_creds
+
+ # Named tuple to contain values of interest when the PAC is decoded.
+ PacData = namedtuple(
+ "PacData",
+ "account_name account_sid logon_name upn domain_name")
+
+ def get_pac_data(self, authorization_data):
+ '''Decode the PAC element contained in the authorization-data element
+ '''
+ account_name = None
+ user_sid = None
+ logon_name = None
+ upn = None
+ domain_name = None
+
+ # The PAC data will be wrapped in an AD_IF_RELEVANT element
+ ad_if_relevant_elements = (
+ x for x in authorization_data if x['ad-type'] == AD_IF_RELEVANT)
+ for dt in ad_if_relevant_elements:
+ buf = self.der_decode(
+ dt['ad-data'], asn1Spec=krb5_asn1.AD_IF_RELEVANT())
+ # The PAC data is further wrapped in a AD_WIN2K_PAC element
+ for ad in (x for x in buf if x['ad-type'] == AD_WIN2K_PAC):
+ pb = ndr_unpack(krb5pac.PAC_DATA, ad['ad-data'])
+ for pac in pb.buffers:
+ if pac.type == krb5pac.PAC_TYPE_LOGON_INFO:
+ account_name = (
+ pac.info.info.info3.base.account_name)
+ user_sid = (
+ str(pac.info.info.info3.base.domain_sid)
+ + "-" + str(pac.info.info.info3.base.rid))
+ elif pac.type == krb5pac.PAC_TYPE_LOGON_NAME:
+ logon_name = pac.info.account_name
+ elif pac.type == krb5pac.PAC_TYPE_UPN_DNS_INFO:
+ upn = pac.info.upn_name
+ domain_name = pac.info.dns_domain_name
+
+ return self.PacData(
+ account_name,
+ user_sid,
+ logon_name,
+ upn,
+ domain_name)
+
+ def decode_service_ticket(self, creds, ticket):
+ '''Decrypt and decode a service ticket
+ '''
+
+ name = creds.get_username()
+ if name.endswith('$'):
+ name = name[:-1]
+ realm = creds.get_realm()
+ salt = "%s.%s@%s" % (name, realm.lower(), realm.upper())
+
+ key = self.PasswordKey_create(
+ ticket['enc-part']['etype'],
+ creds.get_password(),
+ salt,
+ ticket['enc-part']['kvno'])
+
+ enc_part = key.decrypt(KU_TICKET, ticket['enc-part']['cipher'])
+ enc_ticket_part = self.der_decode(
+ enc_part, asn1Spec=krb5_asn1.EncTicketPart())
+ return enc_ticket_part
+
+ def get_objectSid(self, samdb, dn):
+ ''' Get the objectSID for a DN
+ Note: performs an Ldb query.
+ '''
+ res = samdb.search(dn, scope=SCOPE_BASE, attrs=["objectSID"])
+ self.assertTrue(len(res) == 1, "did not get objectSid for %s" % dn)
+ sid = samdb.schema_format_value("objectSID", res[0]["objectSID"][0])
+ return sid.decode('utf8')
+
+ def add_attribute(self, samdb, dn_str, name, value):
+ if isinstance(value, list):
+ values = value
+ else:
+ values = [value]
+ flag = ldb.FLAG_MOD_ADD
+
+ dn = ldb.Dn(samdb, dn_str)
+ msg = ldb.Message(dn)
+ msg[name] = ldb.MessageElement(values, flag, name)
+ samdb.modify(msg)
+
+ def modify_attribute(self, samdb, dn_str, name, value):
+ if isinstance(value, list):
+ values = value
+ else:
+ values = [value]
+ flag = ldb.FLAG_MOD_REPLACE
+
+ dn = ldb.Dn(samdb, dn_str)
+ msg = ldb.Message(dn)
+ msg[name] = ldb.MessageElement(values, flag, name)
+ samdb.modify(msg)
+
+ def create_ccache(self, cname, ticket, enc_part):
+ """ Lay out a version 4 on-disk credentials cache, to be read using the
+ FILE: protocol.
+ """
+
+ field = krb5ccache.DELTATIME_TAG()
+ field.kdc_sec_offset = 0
+ field.kdc_usec_offset = 0
+
+ v4tag = krb5ccache.V4TAG()
+ v4tag.tag = 1
+ v4tag.field = field
+
+ v4tags = krb5ccache.V4TAGS()
+ v4tags.tag = v4tag
+ v4tags.further_tags = b''
+
+ optional_header = krb5ccache.V4HEADER()
+ optional_header.v4tags = v4tags
+
+ cname_string = cname['name-string']
+
+ cprincipal = krb5ccache.PRINCIPAL()
+ cprincipal.name_type = cname['name-type']
+ cprincipal.component_count = len(cname_string)
+ cprincipal.realm = ticket['realm']
+ cprincipal.components = cname_string
+
+ sname = ticket['sname']
+ sname_string = sname['name-string']
+
+ sprincipal = krb5ccache.PRINCIPAL()
+ sprincipal.name_type = sname['name-type']
+ sprincipal.component_count = len(sname_string)
+ sprincipal.realm = ticket['realm']
+ sprincipal.components = sname_string
+
+ key = self.EncryptionKey_import(enc_part['key'])
+
+ key_data = key.export_obj()
+ keyblock = krb5ccache.KEYBLOCK()
+ keyblock.enctype = key_data['keytype']
+ keyblock.data = key_data['keyvalue']
+
+ addresses = krb5ccache.ADDRESSES()
+ addresses.count = 0
+ addresses.data = []
+
+ authdata = krb5ccache.AUTHDATA()
+ authdata.count = 0
+ authdata.data = []
+
+ # Re-encode the ticket, since it was decoded by another layer.
+ ticket_data = self.der_encode(ticket, asn1Spec=krb5_asn1.Ticket())
+
+ authtime = enc_part['authtime']
+ starttime = enc_part.get('starttime', authtime)
+ endtime = enc_part['endtime']
+
+ cred = krb5ccache.CREDENTIAL()
+ cred.client = cprincipal
+ cred.server = sprincipal
+ cred.keyblock = keyblock
+ cred.authtime = self.get_EpochFromKerberosTime(authtime)
+ cred.starttime = self.get_EpochFromKerberosTime(starttime)
+ cred.endtime = self.get_EpochFromKerberosTime(endtime)
+
+ # Account for clock skew of up to five minutes.
+ self.assertLess(cred.authtime - 5 * 60,
+ datetime.now(timezone.utc).timestamp(),
+ "Ticket not yet valid - clocks may be out of sync.")
+ self.assertLess(cred.starttime - 5 * 60,
+ datetime.now(timezone.utc).timestamp(),
+ "Ticket not yet valid - clocks may be out of sync.")
+ self.assertGreater(cred.endtime - 60 * 60,
+ datetime.now(timezone.utc).timestamp(),
+ "Ticket already expired/about to expire - "
+ "clocks may be out of sync.")
+
+ cred.renew_till = cred.endtime
+ cred.is_skey = 0
+ cred.ticket_flags = int(enc_part['flags'], 2)
+ cred.addresses = addresses
+ cred.authdata = authdata
+ cred.ticket = ticket_data
+ cred.second_ticket = b''
+
+ ccache = krb5ccache.CCACHE()
+ ccache.pvno = 5
+ ccache.version = 4
+ ccache.optional_header = optional_header
+ ccache.principal = cprincipal
+ ccache.cred = cred
+
+ # Serialise the credentials cache structure.
+ result = ndr_pack(ccache)
+
+ # Create a temporary file and write the credentials.
+ cachefile = tempfile.NamedTemporaryFile(dir=self.tempdir, delete=False)
+ cachefile.write(result)
+ cachefile.close()
+
+ return cachefile
+
+ def create_ccache_with_user(self, user_credentials, mach_credentials,
+ service="host", target_name=None, pac=True):
+ # Obtain a service ticket authorising the user and place it into a
+ # newly created credentials cache file.
+
+ user_name = user_credentials.get_username()
+ realm = user_credentials.get_realm()
+
+ cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[user_name])
+
+ tgt = self.get_tgt(user_credentials)
+
+ # Request a ticket to the host service on the machine account
+ ticket = self.get_service_ticket(tgt, mach_credentials,
+ service=service,
+ target_name=target_name)
+
+ if not pac:
+ ticket = self.modified_ticket(ticket, exclude_pac=True)
+
+ # Write the ticket into a credentials cache file that can be ingested
+ # by the main credentials code.
+ cachefile = self.create_ccache(cname, ticket.ticket,
+ ticket.encpart_private)
+
+ # Create a credentials object to reference the credentials cache.
+ creds = Credentials()
+ creds.set_kerberos_state(MUST_USE_KERBEROS)
+ creds.set_username(user_name, SPECIFIED)
+ creds.set_realm(realm)
+ creds.set_named_ccache(cachefile.name, SPECIFIED, self.get_lp())
+
+ # Return the credentials along with the cache file.
+ return (creds, cachefile)
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/kdc_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/kdc_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/kdc_tests.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/kdc_tests.py 2021-10-29 06:17:36.000000000 +0000
@@ -0,0 +1,228 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) 2020 Catalyst.Net Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+from samba.tests.krb5.raw_testcase import RawKerberosTest
+import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
+from samba.tests.krb5.rfc4120_constants import (
+ AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ KDC_ERR_PREAUTH_FAILED,
+ KDC_ERR_PREAUTH_REQUIRED,
+ KDC_ERR_SKEW,
+ KRB_AS_REP,
+ KRB_ERROR,
+ KU_PA_ENC_TIMESTAMP,
+ PADATA_ENC_TIMESTAMP,
+ PADATA_ETYPE_INFO2,
+ NT_PRINCIPAL,
+ NT_SRV_INST,
+)
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class KdcTests(RawKerberosTest):
+ """ Port of the tests in source4/torture/krb5/kdc-heimdal.c
+ To python.
+ """
+
+ def setUp(self):
+ super(KdcTests, self).setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ def as_req(self, creds, etypes, padata=None):
+ user = creds.get_username()
+ realm = creds.get_realm()
+
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[user])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST,
+ names=["krbtgt", realm])
+ till = self.get_KerberosTime(offset=36000)
+
+ kdc_options = 0
+
+ req = self.AS_REQ_create(padata=padata,
+ kdc_options=str(kdc_options),
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ from_time=None,
+ till_time=till,
+ renew_time=None,
+ nonce=0x7fffffff,
+ etypes=etypes,
+ addresses=None,
+ additional_tickets=None)
+ rep = self.send_recv_transaction(req)
+ return rep
+
+ def get_enc_timestamp_pa_data(self, creds, rep, skew=0):
+ rep_padata = self.der_decode(
+ rep['e-data'],
+ asn1Spec=krb5_asn1.METHOD_DATA())
+
+ for pa in rep_padata:
+ if pa['padata-type'] == PADATA_ETYPE_INFO2:
+ etype_info2 = pa['padata-value']
+ break
+
+ etype_info2 = self.der_decode(
+ etype_info2, asn1Spec=krb5_asn1.ETYPE_INFO2())
+
+ key = self.PasswordKey_from_etype_info2(creds, etype_info2[0])
+
+ (patime, pausec) = self.get_KerberosTimeWithUsec(offset=skew)
+ pa_ts = self.PA_ENC_TS_ENC_create(patime, pausec)
+ pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
+
+ pa_ts = self.EncryptedData_create(key, KU_PA_ENC_TIMESTAMP, pa_ts)
+ pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.EncryptedData())
+
+ pa_ts = self.PA_DATA_create(PADATA_ENC_TIMESTAMP, pa_ts)
+
+ return pa_ts
+
+ def check_pre_authenication(self, rep):
+ """ Check that the kdc response was pre-authentication required
+ """
+ self.check_error_rep(rep, KDC_ERR_PREAUTH_REQUIRED)
+
+ def check_as_reply(self, rep):
+ """ Check that the kdc response is an AS-REP and that the
+ values for:
+ msg-type
+ pvno
+ tkt-pvno
+ kvno
+ match the expected values
+ """
+
+ # Should have a reply, and it should an AS-REP message.
+ self.assertIsNotNone(rep)
+ self.assertEqual(rep['msg-type'], KRB_AS_REP)
+
+ # Protocol version number should be 5
+ pvno = int(rep['pvno'])
+ self.assertEqual(5, pvno)
+
+ # The ticket version number should be 5
+ tkt_vno = int(rep['ticket']['tkt-vno'])
+ self.assertEqual(5, tkt_vno)
+
+ # Check that the kvno is not an RODC kvno
+ # MIT kerberos does not provide the kvno, so we treat it as optional.
+ # This is tested in compatability_test.py
+ if 'kvno' in rep['enc-part']:
+ kvno = int(rep['enc-part']['kvno'])
+ # If the high order bits are set this is an RODC kvno.
+ self.assertEqual(0, kvno & 0xFFFF0000)
+
+ def check_error_rep(self, rep, expected):
+ """ Check that the reply is an error message, with the expected
+ error-code specified.
+ """
+ self.assertIsNotNone(rep)
+ self.assertEqual(rep['msg-type'], KRB_ERROR)
+ self.assertEqual(rep['error-code'], expected)
+
+ def test_aes256_cts_hmac_sha1_96(self):
+ creds = self.get_user_creds()
+ etype = (AES256_CTS_HMAC_SHA1_96,)
+
+ rep = self.as_req(creds, etype)
+ self.check_pre_authenication(rep)
+
+ padata = self.get_enc_timestamp_pa_data(creds, rep)
+ rep = self.as_req(creds, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ etype = rep['enc-part']['etype']
+ self.assertEquals(AES256_CTS_HMAC_SHA1_96, etype)
+
+ def test_arc4_hmac_md5(self):
+ creds = self.get_user_creds()
+ etype = (ARCFOUR_HMAC_MD5,)
+
+ rep = self.as_req(creds, etype)
+ self.check_pre_authenication(rep)
+
+ padata = self.get_enc_timestamp_pa_data(creds, rep)
+ rep = self.as_req(creds, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ etype = rep['enc-part']['etype']
+ self.assertEquals(ARCFOUR_HMAC_MD5, etype)
+
+ def test_aes_rc4(self):
+ creds = self.get_user_creds()
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+
+ rep = self.as_req(creds, etype)
+ self.check_pre_authenication(rep)
+
+ padata = self.get_enc_timestamp_pa_data(creds, rep)
+ rep = self.as_req(creds, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ etype = rep['enc-part']['etype']
+ self.assertEquals(AES256_CTS_HMAC_SHA1_96, etype)
+
+ def test_clock_skew(self):
+ creds = self.get_user_creds()
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+
+ rep = self.as_req(creds, etype)
+ self.check_pre_authenication(rep)
+
+ padata = self.get_enc_timestamp_pa_data(creds, rep, skew=3600)
+ rep = self.as_req(creds, etype, padata=[padata])
+
+ self.check_error_rep(rep, KDC_ERR_SKEW)
+
+ def test_invalid_password(self):
+ creds = self.insta_creds(template=self.get_user_creds())
+ creds.set_password("Not the correct password")
+
+ etype = (AES256_CTS_HMAC_SHA1_96,)
+
+ rep = self.as_req(creds, etype)
+ self.check_pre_authenication(rep)
+
+ padata = self.get_enc_timestamp_pa_data(creds, rep)
+ rep = self.as_req(creds, etype, padata=[padata])
+
+ self.check_error_rep(rep, KDC_ERR_PREAUTH_FAILED)
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/kdc_tgs_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/kdc_tgs_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/kdc_tgs_tests.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/kdc_tgs_tests.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,2236 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) 2020 Catalyst.Net Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+import ldb
+
+
+from samba import dsdb, ntstatus
+
+from samba.dcerpc import krb5pac, security
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+import samba.tests.krb5.kcrypto as kcrypto
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+from samba.tests.krb5.rfc4120_constants import (
+ AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ KRB_ERROR,
+ KRB_TGS_REP,
+ KDC_ERR_BADMATCH,
+ KDC_ERR_BADOPTION,
+ KDC_ERR_CLIENT_NAME_MISMATCH,
+ KDC_ERR_GENERIC,
+ KDC_ERR_MODIFIED,
+ KDC_ERR_POLICY,
+ KDC_ERR_C_PRINCIPAL_UNKNOWN,
+ KDC_ERR_S_PRINCIPAL_UNKNOWN,
+ KDC_ERR_TGT_REVOKED,
+ KDC_ERR_WRONG_REALM,
+ NT_PRINCIPAL,
+ NT_SRV_INST,
+)
+import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class KdcTgsTests(KDCBaseTest):
+
+ def setUp(self):
+ super().setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ def test_tgs_req_cname_does_not_not_match_authenticator_cname(self):
+ ''' Try and obtain a ticket from the TGS, but supply a cname
+ that differs from that provided to the krbtgt
+ '''
+ # Create the user account
+ samdb = self.get_samdb()
+ user_name = "tsttktusr"
+ (uc, _) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96,)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[user_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a service ticket, but use a cname that does not match
+ # that in the original AS-REQ
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ ticket = rep['ticket']
+
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=["Administrator"])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=["host", samdb.host_dns_name()])
+
+ (rep, enc_part) = self.tgs_req(cname, sname, realm, ticket, key, etype,
+ expected_error_mode=KDC_ERR_BADMATCH,
+ expect_edata=False)
+
+ self.assertIsNone(
+ enc_part,
+ "rep = {%s}, enc_part = {%s}" % (rep, enc_part))
+ self.assertEqual(KRB_ERROR, rep['msg-type'], "rep = {%s}" % rep)
+ self.assertEqual(
+ KDC_ERR_BADMATCH,
+ rep['error-code'],
+ "rep = {%s}" % rep)
+
+ def test_ldap_service_ticket(self):
+ '''Get a ticket to the ldap service
+ '''
+ # Create the user account
+ samdb = self.get_samdb()
+ user_name = "tsttktusr"
+ (uc, _) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96,)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[user_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ ticket = rep['ticket']
+
+ # Request a ticket to the ldap service
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST,
+ names=["ldap", samdb.host_dns_name()])
+
+ (rep, _) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ service_creds=self.get_dc_creds())
+
+ self.check_tgs_reply(rep)
+
+ def test_get_ticket_for_host_service_of_machine_account(self):
+
+ # Create a user and machine account for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "tsttktusr"
+ (uc, dn) = self.create_account(samdb, user_name)
+ (mc, _) = self.create_account(samdb, "tsttktmac",
+ account_type=self.AccountType.COMPUTER)
+ realm = uc.get_realm().lower()
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[user_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[user_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the service ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+
+ pac_data = self.get_pac_data(enc_part['authorization-data'])
+ sid = self.get_objectSid(samdb, dn)
+ upn = "%s@%s" % (uc.get_username(), realm)
+ self.assertEqual(
+ uc.get_username(),
+ str(pac_data.account_name),
+ "rep = {%s},%s" % (rep, pac_data))
+ self.assertEqual(
+ uc.get_username(),
+ pac_data.logon_name,
+ "rep = {%s},%s" % (rep, pac_data))
+ self.assertEqual(
+ uc.get_realm(),
+ pac_data.domain_name,
+ "rep = {%s},%s" % (rep, pac_data))
+ self.assertEqual(
+ upn,
+ pac_data.upn,
+ "rep = {%s},%s" % (rep, pac_data))
+ self.assertEqual(
+ sid,
+ pac_data.account_sid,
+ "rep = {%s},%s" % (rep, pac_data))
+
+ def _make_tgs_request(self, client_creds, service_creds, tgt,
+ pac_request=None, expect_pac=True,
+ expect_error=False,
+ expected_account_name=None,
+ expected_upn_name=None,
+ expected_sid=None):
+ client_account = client_creds.get_username()
+ cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[client_account])
+
+ service_account = service_creds.get_username()
+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[service_account])
+
+ realm = service_creds.get_realm()
+
+ expected_crealm = realm
+ expected_cname = cname
+ expected_srealm = realm
+ expected_sname = sname
+
+ expected_supported_etypes = service_creds.tgs_supported_enctypes
+
+ etypes = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+
+ kdc_options = str(krb5_asn1.KDCOptions('canonicalize'))
+
+ target_decryption_key = self.TicketDecryptionKey_from_creds(
+ service_creds)
+
+ authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256)
+
+ if expect_error:
+ expected_error_mode = KDC_ERR_BADOPTION
+ check_error_fn = self.generic_check_kdc_error
+ check_rep_fn = None
+ else:
+ expected_error_mode = 0
+ check_error_fn = None
+ check_rep_fn = self.generic_check_kdc_rep
+
+ kdc_exchange_dict = self.tgs_exchange_dict(
+ expected_crealm=expected_crealm,
+ expected_cname=expected_cname,
+ expected_srealm=expected_srealm,
+ expected_sname=expected_sname,
+ expected_account_name=expected_account_name,
+ expected_upn_name=expected_upn_name,
+ expected_sid=expected_sid,
+ expected_supported_etypes=expected_supported_etypes,
+ ticket_decryption_key=target_decryption_key,
+ check_error_fn=check_error_fn,
+ check_rep_fn=check_rep_fn,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ expected_error_mode=expected_error_mode,
+ tgt=tgt,
+ authenticator_subkey=authenticator_subkey,
+ kdc_options=kdc_options,
+ pac_request=pac_request,
+ expect_pac=expect_pac)
+
+ rep = self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ etypes=etypes)
+ if expect_error:
+ self.check_error_rep(rep, expected_error_mode)
+
+ return None
+ else:
+ self.check_reply(rep, KRB_TGS_REP)
+
+ return kdc_exchange_dict['rep_ticket_creds']
+
+ def test_request(self):
+ client_creds = self.get_client_creds()
+ service_creds = self.get_service_creds()
+
+ tgt = self.get_tgt(client_creds)
+
+ pac = self.get_ticket_pac(tgt)
+ self.assertIsNotNone(pac)
+
+ ticket = self._make_tgs_request(client_creds, service_creds, tgt)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_request_no_pac(self):
+ client_creds = self.get_client_creds()
+ service_creds = self.get_service_creds()
+
+ tgt = self.get_tgt(client_creds, pac_request=False)
+
+ pac = self.get_ticket_pac(tgt)
+ self.assertIsNotNone(pac)
+
+ ticket = self._make_tgs_request(client_creds, service_creds, tgt,
+ pac_request=False, expect_pac=False)
+
+ pac = self.get_ticket_pac(ticket, expect_pac=False)
+ self.assertIsNone(pac)
+
+ def test_client_no_auth_data_required(self):
+ client_creds = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ opts={'no_auth_data_required': True})
+ service_creds = self.get_service_creds()
+
+ tgt = self.get_tgt(client_creds)
+
+ pac = self.get_ticket_pac(tgt)
+ self.assertIsNotNone(pac)
+
+ ticket = self._make_tgs_request(client_creds, service_creds, tgt)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_no_pac_client_no_auth_data_required(self):
+ client_creds = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ opts={'no_auth_data_required': True})
+ service_creds = self.get_service_creds()
+
+ tgt = self.get_tgt(client_creds)
+
+ pac = self.get_ticket_pac(tgt)
+ self.assertIsNotNone(pac)
+
+ ticket = self._make_tgs_request(client_creds, service_creds, tgt,
+ pac_request=False, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_service_no_auth_data_required(self):
+ client_creds = self.get_client_creds()
+ service_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'no_auth_data_required': True})
+
+ tgt = self.get_tgt(client_creds)
+
+ pac = self.get_ticket_pac(tgt)
+ self.assertIsNotNone(pac)
+
+ ticket = self._make_tgs_request(client_creds, service_creds, tgt,
+ expect_pac=False)
+
+ pac = self.get_ticket_pac(ticket, expect_pac=False)
+ self.assertIsNone(pac)
+
+ def test_no_pac_service_no_auth_data_required(self):
+ client_creds = self.get_client_creds()
+ service_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'no_auth_data_required': True})
+
+ tgt = self.get_tgt(client_creds, pac_request=False)
+
+ pac = self.get_ticket_pac(tgt)
+ self.assertIsNotNone(pac)
+
+ ticket = self._make_tgs_request(client_creds, service_creds, tgt,
+ pac_request=False, expect_pac=False)
+
+ pac = self.get_ticket_pac(ticket, expect_pac=False)
+ self.assertIsNone(pac)
+
+ def test_remove_pac_service_no_auth_data_required(self):
+ client_creds = self.get_client_creds()
+ service_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'no_auth_data_required': True})
+
+ tgt = self.modified_ticket(self.get_tgt(client_creds),
+ exclude_pac=True)
+
+ pac = self.get_ticket_pac(tgt, expect_pac=False)
+ self.assertIsNone(pac)
+
+ self._make_tgs_request(client_creds, service_creds, tgt,
+ expect_pac=False, expect_error=True)
+
+ def test_remove_pac_client_no_auth_data_required(self):
+ client_creds = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ opts={'no_auth_data_required': True})
+ service_creds = self.get_service_creds()
+
+ tgt = self.modified_ticket(self.get_tgt(client_creds),
+ exclude_pac=True)
+
+ pac = self.get_ticket_pac(tgt, expect_pac=False)
+ self.assertIsNone(pac)
+
+ self._make_tgs_request(client_creds, service_creds, tgt,
+ expect_pac=False, expect_error=True)
+
+ def test_remove_pac(self):
+ client_creds = self.get_client_creds()
+ service_creds = self.get_service_creds()
+
+ tgt = self.modified_ticket(self.get_tgt(client_creds),
+ exclude_pac=True)
+
+ pac = self.get_ticket_pac(tgt, expect_pac=False)
+ self.assertIsNone(pac)
+
+ self._make_tgs_request(client_creds, service_creds, tgt,
+ expect_pac=False, expect_error=True)
+
+ def test_upn_dns_info_ex_user(self):
+ client_creds = self.get_client_creds()
+ self._run_upn_dns_info_ex_test(client_creds)
+
+ def test_upn_dns_info_ex_mac(self):
+ mach_creds = self.get_mach_creds()
+ self._run_upn_dns_info_ex_test(mach_creds)
+
+ def test_upn_dns_info_ex_upn_user(self):
+ client_creds = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'upn_dns_info_test_upn0@bar'})
+ self._run_upn_dns_info_ex_test(client_creds)
+
+ def test_upn_dns_info_ex_upn_mac(self):
+ mach_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'upn_dns_info_test_upn1@bar'})
+ self._run_upn_dns_info_ex_test(mach_creds)
+
+ def _run_upn_dns_info_ex_test(self, client_creds):
+ service_creds = self.get_service_creds()
+
+ samdb = self.get_samdb()
+ dn = client_creds.get_dn()
+
+ account_name = client_creds.get_username()
+ upn_name = client_creds.get_upn()
+ if upn_name is None:
+ realm = client_creds.get_realm().lower()
+ upn_name = f'{account_name}@{realm}'
+ sid = self.get_objectSid(samdb, dn)
+
+ tgt = self.get_tgt(client_creds,
+ expected_account_name=account_name,
+ expected_upn_name=upn_name,
+ expected_sid=sid)
+
+ self._make_tgs_request(client_creds, service_creds, tgt,
+ expected_account_name=account_name,
+ expected_upn_name=upn_name,
+ expected_sid=sid)
+
+ # Test making a TGS request.
+ def test_tgs_req(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+ self._run_tgs(tgt, expected_error=0)
+
+ def test_renew_req(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, renewable=True)
+ self._renew_tgt(tgt, expected_error=0)
+
+ def test_validate_req(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, invalid=True)
+ self._validate_tgt(tgt, expected_error=0)
+
+ def test_s4u2self_req(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+ self._s4u2self(tgt, creds, expected_error=0)
+
+ def test_user2user_req(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+ self._user2user(tgt, creds, expected_error=0)
+
+ def test_tgs_req_no_requester_sid(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, remove_requester_sid=True)
+
+ self._run_tgs(tgt, expected_error=0, expect_pac=True,
+ expect_requester_sid=False) # Note: not expected
+
+ def test_tgs_req_no_pac_attrs(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, remove_pac_attrs=True)
+
+ self._run_tgs(tgt, expected_error=0, expect_pac=True,
+ expect_pac_attrs=False)
+
+ def test_tgs_req_from_rodc_no_requester_sid(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True, remove_requester_sid=True)
+
+ samdb = self.get_samdb()
+ sid = self.get_objectSid(samdb, creds.get_dn())
+
+ self._run_tgs(tgt, expected_error=0, expect_pac=True,
+ expect_requester_sid=True, expected_sid=sid)
+
+ def test_tgs_req_from_rodc_no_pac_attrs(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True, remove_pac_attrs=True)
+ self._run_tgs(tgt, expected_error=0, expect_pac=True,
+ expect_pac_attrs=False)
+
+ # Test making a request without a PAC.
+ def test_tgs_no_pac(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, remove_pac=True)
+ self._run_tgs(tgt, expected_error=KDC_ERR_BADOPTION)
+
+ def test_renew_no_pac(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, renewable=True, remove_pac=True)
+ self._renew_tgt(tgt, expected_error=KDC_ERR_BADOPTION)
+
+ def test_validate_no_pac(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, invalid=True, remove_pac=True)
+ self._validate_tgt(tgt, expected_error=KDC_ERR_BADOPTION)
+
+ def test_s4u2self_no_pac(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, remove_pac=True)
+ self._s4u2self(tgt, creds,
+ expected_error=(KDC_ERR_GENERIC, KDC_ERR_BADOPTION),
+ expected_status=ntstatus.NT_STATUS_INVALID_PARAMETER,
+ expect_edata=True)
+
+ def test_user2user_no_pac(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, remove_pac=True)
+ self._user2user(tgt, creds, expected_error=KDC_ERR_BADOPTION)
+
+ # Test making a request with authdata and without a PAC.
+ def test_tgs_authdata_no_pac(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, remove_pac=True, allow_empty_authdata=True)
+ self._run_tgs(tgt, expected_error=KDC_ERR_BADOPTION)
+
+ def test_renew_authdata_no_pac(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, renewable=True, remove_pac=True,
+ allow_empty_authdata=True)
+ self._renew_tgt(tgt, expected_error=KDC_ERR_BADOPTION)
+
+ def test_validate_authdata_no_pac(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, invalid=True, remove_pac=True,
+ allow_empty_authdata=True)
+ self._validate_tgt(tgt, expected_error=KDC_ERR_BADOPTION)
+
+ def test_s4u2self_authdata_no_pac(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, remove_pac=True, allow_empty_authdata=True)
+ self._s4u2self(tgt, creds,
+ expected_error=(KDC_ERR_GENERIC, KDC_ERR_BADOPTION),
+ expected_status=ntstatus.NT_STATUS_INVALID_PARAMETER,
+ expect_edata=True)
+
+ def test_user2user_authdata_no_pac(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds, remove_pac=True, allow_empty_authdata=True)
+ self._user2user(tgt, creds, expected_error=KDC_ERR_BADOPTION)
+
+ # Test changing the SID in the PAC to that of another account.
+ def test_tgs_sid_mismatch_existing(self):
+ creds = self._get_creds()
+ existing_rid = self._get_existing_rid()
+ tgt = self._get_tgt(creds, new_rid=existing_rid)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_renew_sid_mismatch_existing(self):
+ creds = self._get_creds()
+ existing_rid = self._get_existing_rid()
+ tgt = self._get_tgt(creds, renewable=True, new_rid=existing_rid)
+ self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_validate_sid_mismatch_existing(self):
+ creds = self._get_creds()
+ existing_rid = self._get_existing_rid()
+ tgt = self._get_tgt(creds, invalid=True, new_rid=existing_rid)
+ self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_s4u2self_sid_mismatch_existing(self):
+ creds = self._get_creds()
+ existing_rid = self._get_existing_rid()
+ tgt = self._get_tgt(creds, new_rid=existing_rid)
+ self._s4u2self(tgt, creds,
+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_user2user_sid_mismatch_existing(self):
+ creds = self._get_creds()
+ existing_rid = self._get_existing_rid()
+ tgt = self._get_tgt(creds, new_rid=existing_rid)
+ self._user2user(tgt, creds,
+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_requester_sid_mismatch_existing(self):
+ creds = self._get_creds()
+ existing_rid = self._get_existing_rid()
+ tgt = self._get_tgt(creds, new_rid=existing_rid,
+ can_modify_logon_info=False)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_logon_info_sid_mismatch_existing(self):
+ creds = self._get_creds()
+ existing_rid = self._get_existing_rid()
+ tgt = self._get_tgt(creds, new_rid=existing_rid,
+ can_modify_requester_sid=False)
+ self._run_tgs(tgt, expected_error=0)
+
+ def test_logon_info_only_sid_mismatch_existing(self):
+ creds = self._get_creds()
+ existing_rid = self._get_existing_rid()
+ tgt = self._get_tgt(creds, new_rid=existing_rid,
+ remove_requester_sid=True)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ # Test changing the SID in the PAC to a non-existent one.
+ def test_tgs_sid_mismatch_nonexisting(self):
+ creds = self._get_creds()
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, new_rid=nonexistent_rid)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_renew_sid_mismatch_nonexisting(self):
+ creds = self._get_creds()
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, renewable=True,
+ new_rid=nonexistent_rid)
+ self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_validate_sid_mismatch_nonexisting(self):
+ creds = self._get_creds()
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, invalid=True,
+ new_rid=nonexistent_rid)
+ self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_s4u2self_sid_mismatch_nonexisting(self):
+ creds = self._get_creds()
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, new_rid=nonexistent_rid)
+ self._s4u2self(tgt, creds,
+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_user2user_sid_mismatch_nonexisting(self):
+ creds = self._get_creds()
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, new_rid=nonexistent_rid)
+ self._user2user(tgt, creds,
+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_requester_sid_mismatch_nonexisting(self):
+ creds = self._get_creds()
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, new_rid=nonexistent_rid,
+ can_modify_logon_info=False)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_logon_info_sid_mismatch_nonexisting(self):
+ creds = self._get_creds()
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, new_rid=nonexistent_rid,
+ can_modify_requester_sid=False)
+ self._run_tgs(tgt, expected_error=0)
+
+ def test_logon_info_only_sid_mismatch_nonexisting(self):
+ creds = self._get_creds()
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, new_rid=nonexistent_rid,
+ remove_requester_sid=True)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ # Test with an RODC-issued ticket where the client is revealed to the RODC.
+ def test_tgs_rodc_revealed(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._run_tgs(tgt, expected_error=0)
+
+ def test_renew_rodc_revealed(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True)
+ self._renew_tgt(tgt, expected_error=0)
+
+ def test_validate_rodc_revealed(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True)
+ self._validate_tgt(tgt, expected_error=0)
+
+ def test_s4u2self_rodc_revealed(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._s4u2self(tgt, creds, expected_error=0)
+
+ def test_user2user_rodc_revealed(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._user2user(tgt, creds, expected_error=0)
+
+ # Test with an RODC-issued ticket where the SID in the PAC is changed to
+ # that of another account.
+ def test_tgs_rodc_sid_mismatch_existing(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ existing_rid = self._get_existing_rid(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_renew_rodc_sid_mismatch_existing(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ existing_rid = self._get_existing_rid(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True,
+ new_rid=existing_rid)
+ self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_validate_rodc_sid_mismatch_existing(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ existing_rid = self._get_existing_rid(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True,
+ new_rid=existing_rid)
+ self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_s4u2self_rodc_sid_mismatch_existing(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ existing_rid = self._get_existing_rid(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid)
+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_user2user_rodc_sid_mismatch_existing(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ existing_rid = self._get_existing_rid(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid)
+ self._user2user(tgt, creds,
+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_tgs_rodc_requester_sid_mismatch_existing(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ existing_rid = self._get_existing_rid(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid,
+ can_modify_logon_info=False)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_tgs_rodc_logon_info_sid_mismatch_existing(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ existing_rid = self._get_existing_rid(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid,
+ can_modify_requester_sid=False)
+ self._run_tgs(tgt, expected_error=0)
+
+ def test_tgs_rodc_logon_info_only_sid_mismatch_existing(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ existing_rid = self._get_existing_rid(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=existing_rid,
+ remove_requester_sid=True)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ # Test with an RODC-issued ticket where the SID in the PAC is changed to a
+ # non-existent one.
+ def test_tgs_rodc_sid_mismatch_nonexisting(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_renew_rodc_sid_mismatch_nonexisting(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True,
+ new_rid=nonexistent_rid)
+ self._renew_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_validate_rodc_sid_mismatch_nonexisting(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True,
+ new_rid=nonexistent_rid)
+ self._validate_tgt(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_s4u2self_rodc_sid_mismatch_nonexisting(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid)
+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_user2user_rodc_sid_mismatch_nonexisting(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid)
+ self._user2user(tgt, creds,
+ expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_tgs_rodc_requester_sid_mismatch_nonexisting(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid,
+ can_modify_logon_info=False)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ def test_tgs_rodc_logon_info_sid_mismatch_nonexisting(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid,
+ can_modify_requester_sid=False)
+ self._run_tgs(tgt, expected_error=0)
+
+ def test_tgs_rodc_logon_info_only_sid_mismatch_nonexisting(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ nonexistent_rid = self._get_non_existent_rid()
+ tgt = self._get_tgt(creds, from_rodc=True, new_rid=nonexistent_rid,
+ remove_requester_sid=True)
+ self._run_tgs(tgt, expected_error=KDC_ERR_CLIENT_NAME_MISMATCH)
+
+ # Test with an RODC-issued ticket where the client is not revealed to the
+ # RODC.
+ def test_tgs_rodc_not_revealed(self):
+ creds = self._get_creds(replication_allowed=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ # TODO: error code
+ self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_renew_rodc_not_revealed(self):
+ creds = self._get_creds(replication_allowed=True)
+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True)
+ self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_validate_rodc_not_revealed(self):
+ creds = self._get_creds(replication_allowed=True)
+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True)
+ self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_s4u2self_rodc_not_revealed(self):
+ creds = self._get_creds(replication_allowed=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_user2user_rodc_not_revealed(self):
+ creds = self._get_creds(replication_allowed=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
+
+ # Test with an RODC-issued ticket where the RODC account does not have the
+ # PARTIAL_SECRETS bit set.
+ def test_tgs_rodc_no_partial_secrets(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._remove_rodc_partial_secrets()
+ self._run_tgs(tgt, expected_error=KDC_ERR_POLICY)
+
+ def test_renew_rodc_no_partial_secrets(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True)
+ self._remove_rodc_partial_secrets()
+ self._renew_tgt(tgt, expected_error=KDC_ERR_POLICY)
+
+ def test_validate_rodc_no_partial_secrets(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True)
+ self._remove_rodc_partial_secrets()
+ self._validate_tgt(tgt, expected_error=KDC_ERR_POLICY)
+
+ def test_s4u2self_rodc_no_partial_secrets(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._remove_rodc_partial_secrets()
+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_POLICY)
+
+ def test_user2user_rodc_no_partial_secrets(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._remove_rodc_partial_secrets()
+ self._user2user(tgt, creds, expected_error=KDC_ERR_POLICY)
+
+ # Test with an RODC-issued ticket where the RODC account does not have an
+ # msDS-KrbTgtLink.
+ def test_tgs_rodc_no_krbtgt_link(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._remove_rodc_krbtgt_link()
+ self._run_tgs(tgt, expected_error=KDC_ERR_POLICY)
+
+ def test_renew_rodc_no_krbtgt_link(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True)
+ self._remove_rodc_krbtgt_link()
+ self._renew_tgt(tgt, expected_error=KDC_ERR_POLICY)
+
+ def test_validate_rodc_no_krbtgt_link(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True)
+ self._remove_rodc_krbtgt_link()
+ self._validate_tgt(tgt, expected_error=KDC_ERR_POLICY)
+
+ def test_s4u2self_rodc_no_krbtgt_link(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._remove_rodc_krbtgt_link()
+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_POLICY)
+
+ def test_user2user_rodc_no_krbtgt_link(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._remove_rodc_krbtgt_link()
+ self._user2user(tgt, creds, expected_error=KDC_ERR_POLICY)
+
+ # Test with an RODC-issued ticket where the client is not allowed to
+ # replicate to the RODC.
+ def test_tgs_rodc_not_allowed(self):
+ creds = self._get_creds(revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_renew_rodc_not_allowed(self):
+ creds = self._get_creds(revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True)
+ self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_validate_rodc_not_allowed(self):
+ creds = self._get_creds(revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True)
+ self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_s4u2self_rodc_not_allowed(self):
+ creds = self._get_creds(revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_user2user_rodc_not_allowed(self):
+ creds = self._get_creds(revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
+
+ # Test with an RODC-issued ticket where the client is denied from
+ # replicating to the RODC.
+ def test_tgs_rodc_denied(self):
+ creds = self._get_creds(replication_denied=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_renew_rodc_denied(self):
+ creds = self._get_creds(replication_denied=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True)
+ self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_validate_rodc_denied(self):
+ creds = self._get_creds(replication_denied=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True)
+ self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_s4u2self_rodc_denied(self):
+ creds = self._get_creds(replication_denied=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_user2user_rodc_denied(self):
+ creds = self._get_creds(replication_denied=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
+
+ # Test with an RODC-issued ticket where the client is both allowed and
+ # denied replicating to the RODC.
+ def test_tgs_rodc_allowed_denied(self):
+ creds = self._get_creds(replication_allowed=True,
+ replication_denied=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._run_tgs(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_renew_rodc_allowed_denied(self):
+ creds = self._get_creds(replication_allowed=True,
+ replication_denied=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, renewable=True, from_rodc=True)
+ self._renew_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_validate_rodc_allowed_denied(self):
+ creds = self._get_creds(replication_allowed=True,
+ replication_denied=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, invalid=True, from_rodc=True)
+ self._validate_tgt(tgt, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_s4u2self_rodc_allowed_denied(self):
+ creds = self._get_creds(replication_allowed=True,
+ replication_denied=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._s4u2self(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
+
+ def test_user2user_rodc_allowed_denied(self):
+ creds = self._get_creds(replication_allowed=True,
+ replication_denied=True,
+ revealed_to_rodc=True)
+ tgt = self._get_tgt(creds, from_rodc=True)
+ self._user2user(tgt, creds, expected_error=KDC_ERR_TGT_REVOKED)
+
+ # Test user-to-user with incorrect service principal names.
+ def test_user2user_matching_sname_host(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ user_name = creds.get_username()
+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=['host', user_name])
+
+ self._user2user(tgt, creds, sname=sname,
+ expected_error=KDC_ERR_S_PRINCIPAL_UNKNOWN)
+
+ def test_user2user_matching_sname_no_host(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ user_name = creds.get_username()
+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[user_name])
+
+ self._user2user(tgt, creds, sname=sname, expected_error=0)
+
+ def test_user2user_wrong_sname(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ other_creds = self._get_mach_creds()
+ user_name = other_creds.get_username()
+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[user_name])
+
+ self._user2user(tgt, creds, sname=sname,
+ expected_error=(KDC_ERR_BADMATCH,
+ KDC_ERR_BADOPTION))
+
+ def test_user2user_other_sname(self):
+ other_name = self.get_new_username()
+ spn = f'host/{other_name}'
+ creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'spn': spn})
+ tgt = self._get_tgt(creds)
+
+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=['host', other_name])
+
+ self._user2user(tgt, creds, sname=sname, expected_error=0)
+
+ def test_user2user_wrong_sname_krbtgt(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ sname = self.get_krbtgt_sname()
+
+ self._user2user(tgt, creds, sname=sname,
+ expected_error=(KDC_ERR_BADMATCH,
+ KDC_ERR_BADOPTION))
+
+ def test_user2user_wrong_srealm(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ self._user2user(tgt, creds, srealm='OTHER.REALM',
+ expected_error=(KDC_ERR_WRONG_REALM,
+ KDC_ERR_S_PRINCIPAL_UNKNOWN))
+
+ def test_user2user_tgt_correct_realm(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ realm = creds.get_realm().encode('utf-8')
+ tgt = self._modify_tgt(tgt, realm)
+
+ self._user2user(tgt, creds,
+ expected_error=0)
+
+ def test_user2user_tgt_wrong_realm(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ tgt = self._modify_tgt(tgt, b'OTHER.REALM')
+
+ self._user2user(tgt, creds,
+ expected_error=0)
+
+ def test_user2user_tgt_correct_cname(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ user_name = creds.get_username()
+ user_name = user_name.encode('utf-8')
+ cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[user_name])
+
+ tgt = self._modify_tgt(tgt, cname=cname)
+
+ self._user2user(tgt, creds, expected_error=0)
+
+ def test_user2user_tgt_other_cname(self):
+ samdb = self.get_samdb()
+
+ other_name = self.get_new_username()
+ upn = f'{other_name}@{samdb.domain_dns_name()}'
+
+ creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': upn})
+ tgt = self._get_tgt(creds)
+
+ cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[other_name.encode('utf-8')])
+
+ tgt = self._modify_tgt(tgt, cname=cname)
+
+ self._user2user(tgt, creds, expected_error=0)
+
+ def test_user2user_tgt_cname_host(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ user_name = creds.get_username()
+ user_name = user_name.encode('utf-8')
+ cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[b'host', user_name])
+
+ tgt = self._modify_tgt(tgt, cname=cname)
+
+ self._user2user(tgt, creds, expected_error=KDC_ERR_C_PRINCIPAL_UNKNOWN)
+
+ def test_user2user_non_existent_sname(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=['host', 'non_existent_user'])
+
+ self._user2user(tgt, creds, sname=sname,
+ expected_error=KDC_ERR_S_PRINCIPAL_UNKNOWN)
+
+ def test_user2user_no_sname(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ self._user2user(tgt, creds, sname=False,
+ expected_error=(KDC_ERR_GENERIC,
+ KDC_ERR_S_PRINCIPAL_UNKNOWN))
+
+ def test_user2user_service_ticket(self):
+ creds = self._get_creds()
+ tgt = self._get_tgt(creds)
+
+ service_creds = self.get_service_creds()
+ service_ticket = self.get_service_ticket(tgt, service_creds)
+
+ self._user2user(service_ticket, creds,
+ expected_error=(KDC_ERR_MODIFIED, KDC_ERR_POLICY))
+
+ def test_pac_attrs_none(self):
+ creds = self._get_creds()
+ self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=None)
+
+ def test_pac_attrs_false(self):
+ creds = self._get_creds()
+ self.get_tgt(creds, pac_request=False,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=False)
+
+ def test_pac_attrs_true(self):
+ creds = self._get_creds()
+ self.get_tgt(creds, pac_request=True,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=True)
+
+ def test_pac_attrs_renew_none(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=None)
+ tgt = self._modify_tgt(tgt, renewable=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=None)
+
+ def test_pac_attrs_renew_false(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=False,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=False)
+ tgt = self._modify_tgt(tgt, renewable=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=False)
+
+ def test_pac_attrs_renew_true(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=True,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=True)
+ tgt = self._modify_tgt(tgt, renewable=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=True)
+
+ def test_pac_attrs_rodc_renew_none(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=None)
+ tgt = self._modify_tgt(tgt, from_rodc=True, renewable=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=None)
+
+ def test_pac_attrs_rodc_renew_false(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self.get_tgt(creds, pac_request=False,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=False)
+ tgt = self._modify_tgt(tgt, from_rodc=True, renewable=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=False)
+
+ def test_pac_attrs_rodc_renew_true(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self.get_tgt(creds, pac_request=True,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=True)
+ tgt = self._modify_tgt(tgt, from_rodc=True, renewable=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=True)
+
+ def test_pac_attrs_missing_renew_none(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=None)
+ tgt = self._modify_tgt(tgt, renewable=True,
+ remove_pac_attrs=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=False)
+
+ def test_pac_attrs_missing_renew_false(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=False,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=False)
+ tgt = self._modify_tgt(tgt, renewable=True,
+ remove_pac_attrs=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=False)
+
+ def test_pac_attrs_missing_renew_true(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=True,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=True)
+ tgt = self._modify_tgt(tgt, renewable=True,
+ remove_pac_attrs=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=False)
+
+ def test_pac_attrs_missing_rodc_renew_none(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=None)
+ tgt = self._modify_tgt(tgt, from_rodc=True, renewable=True,
+ remove_pac_attrs=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=False)
+
+ def test_pac_attrs_missing_rodc_renew_false(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self.get_tgt(creds, pac_request=False,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=False)
+ tgt = self._modify_tgt(tgt, from_rodc=True, renewable=True,
+ remove_pac_attrs=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=False)
+
+ def test_pac_attrs_missing_rodc_renew_true(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self.get_tgt(creds, pac_request=True,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=True)
+ tgt = self._modify_tgt(tgt, from_rodc=True, renewable=True,
+ remove_pac_attrs=True)
+
+ self._renew_tgt(tgt, expected_error=0,
+ expect_pac=True,
+ expect_pac_attrs=False)
+
+ def test_tgs_pac_attrs_none(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=None)
+
+ self._run_tgs(tgt, expected_error=0, expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=None)
+
+ def test_tgs_pac_attrs_false(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=False,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=False)
+
+ self._run_tgs(tgt, expected_error=0, expect_pac=False)
+
+ def test_tgs_pac_attrs_true(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=True,
+ expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=True)
+
+ self._run_tgs(tgt, expected_error=0, expect_pac=True,
+ expect_pac_attrs=True,
+ expect_pac_attrs_pac_request=True)
+
+ def test_as_requester_sid(self):
+ creds = self._get_creds()
+
+ samdb = self.get_samdb()
+ sid = self.get_objectSid(samdb, creds.get_dn())
+
+ self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expected_sid=sid,
+ expect_requester_sid=True)
+
+ def test_tgs_requester_sid(self):
+ creds = self._get_creds()
+
+ samdb = self.get_samdb()
+ sid = self.get_objectSid(samdb, creds.get_dn())
+
+ tgt = self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expected_sid=sid,
+ expect_requester_sid=True)
+
+ self._run_tgs(tgt, expected_error=0, expect_pac=True,
+ expected_sid=sid,
+ expect_requester_sid=True)
+
+ def test_tgs_requester_sid_renew(self):
+ creds = self._get_creds()
+
+ samdb = self.get_samdb()
+ sid = self.get_objectSid(samdb, creds.get_dn())
+
+ tgt = self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expected_sid=sid,
+ expect_requester_sid=True)
+ tgt = self._modify_tgt(tgt, renewable=True)
+
+ self._renew_tgt(tgt, expected_error=0, expect_pac=True,
+ expected_sid=sid,
+ expect_requester_sid=True)
+
+ def test_tgs_requester_sid_rodc_renew(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+
+ samdb = self.get_samdb()
+ sid = self.get_objectSid(samdb, creds.get_dn())
+
+ tgt = self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expected_sid=sid,
+ expect_requester_sid=True)
+ tgt = self._modify_tgt(tgt, from_rodc=True, renewable=True)
+
+ self._renew_tgt(tgt, expected_error=0, expect_pac=True,
+ expected_sid=sid,
+ expect_requester_sid=True)
+
+ def test_tgs_requester_sid_missing_renew(self):
+ creds = self._get_creds()
+
+ samdb = self.get_samdb()
+ sid = self.get_objectSid(samdb, creds.get_dn())
+
+ tgt = self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expected_sid=sid,
+ expect_requester_sid=True)
+ tgt = self._modify_tgt(tgt, renewable=True,
+ remove_requester_sid=True)
+
+ self._renew_tgt(tgt, expected_error=0, expect_pac=True,
+ expect_requester_sid=False) # Note: not expected
+
+ def test_tgs_requester_sid_missing_rodc_renew(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+
+ samdb = self.get_samdb()
+ sid = self.get_objectSid(samdb, creds.get_dn())
+
+ tgt = self.get_tgt(creds, pac_request=None,
+ expect_pac=True,
+ expected_sid=sid,
+ expect_requester_sid=True)
+ tgt = self._modify_tgt(tgt, from_rodc=True, renewable=True,
+ remove_requester_sid=True)
+
+ self._renew_tgt(tgt, expected_error=0, expect_pac=True,
+ expected_sid=sid,
+ expect_requester_sid=True)
+
+ def test_tgs_pac_request_none(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=None)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_tgs_pac_request_false(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=False)
+
+ pac = self.get_ticket_pac(ticket, expect_pac=False)
+ self.assertIsNone(pac)
+
+ def test_tgs_pac_request_true(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=True)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_renew_pac_request_none(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=None)
+ tgt = self._modify_tgt(tgt, renewable=True)
+
+ tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_renew_pac_request_false(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
+ tgt = self._modify_tgt(tgt, renewable=True)
+
+ tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=False)
+
+ pac = self.get_ticket_pac(ticket, expect_pac=False)
+ self.assertIsNone(pac)
+
+ def test_renew_pac_request_true(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=True)
+ tgt = self._modify_tgt(tgt, renewable=True)
+
+ tgt = self._renew_tgt(tgt, expected_error=0, expect_pac=None)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_validate_pac_request_none(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=None)
+ tgt = self._modify_tgt(tgt, invalid=True)
+
+ tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_validate_pac_request_false(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
+ tgt = self._modify_tgt(tgt, invalid=True)
+
+ tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=False)
+
+ pac = self.get_ticket_pac(ticket, expect_pac=False)
+ self.assertIsNone(pac)
+
+ def test_validate_pac_request_true(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=True)
+ tgt = self._modify_tgt(tgt, invalid=True)
+
+ tgt = self._validate_tgt(tgt, expected_error=0, expect_pac=None)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_s4u2self_pac_request_none(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=None)
+
+ ticket = self._s4u2self(tgt, creds, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_s4u2self_pac_request_false(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
+
+ ticket = self._s4u2self(tgt, creds, expected_error=0, expect_pac=False)
+
+ pac = self.get_ticket_pac(ticket, expect_pac=False)
+ self.assertIsNone(pac)
+
+ def test_s4u2self_pac_request_true(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=True)
+
+ ticket = self._s4u2self(tgt, creds, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_user2user_pac_request_none(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=None)
+
+ ticket = self._user2user(tgt, creds, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_user2user_pac_request_false(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
+
+ ticket = self._user2user(tgt, creds, expected_error=0,
+ expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket, expect_pac=True)
+ self.assertIsNotNone(pac)
+
+ def test_user2user_pac_request_true(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds, pac_request=True)
+
+ ticket = self._user2user(tgt, creds, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_user2user_user_pac_request_none(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds)
+
+ user_creds = self._get_mach_creds()
+ user_tgt = self.get_tgt(user_creds, pac_request=None)
+
+ ticket = self._user2user(tgt, creds, expected_error=0,
+ user_tgt=user_tgt, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_user2user_user_pac_request_false(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds)
+
+ user_creds = self._get_mach_creds()
+ user_tgt = self.get_tgt(user_creds, pac_request=False, expect_pac=None)
+
+ ticket = self._user2user(tgt, creds, expected_error=0,
+ user_tgt=user_tgt, expect_pac=False)
+
+ pac = self.get_ticket_pac(ticket, expect_pac=False)
+ self.assertIsNone(pac)
+
+ def test_user2user_user_pac_request_true(self):
+ creds = self._get_creds()
+ tgt = self.get_tgt(creds)
+
+ user_creds = self._get_mach_creds()
+ user_tgt = self.get_tgt(user_creds, pac_request=True)
+
+ ticket = self._user2user(tgt, creds, expected_error=0,
+ user_tgt=user_tgt, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_tgs_rodc_pac_request_none(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self.get_tgt(creds, pac_request=None)
+ tgt = self._modify_tgt(tgt, from_rodc=True)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_tgs_rodc_pac_request_false(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self.get_tgt(creds, pac_request=False, expect_pac=None)
+ tgt = self._modify_tgt(tgt, from_rodc=True)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=False)
+
+ pac = self.get_ticket_pac(ticket, expect_pac=False)
+ self.assertIsNone(pac)
+
+ def test_tgs_rodc_pac_request_true(self):
+ creds = self._get_creds(replication_allowed=True,
+ revealed_to_rodc=True)
+ tgt = self.get_tgt(creds, pac_request=True)
+ tgt = self._modify_tgt(tgt, from_rodc=True)
+
+ ticket = self._run_tgs(tgt, expected_error=0, expect_pac=True)
+
+ pac = self.get_ticket_pac(ticket)
+ self.assertIsNotNone(pac)
+
+ def test_tgs_rename(self):
+ creds = self.get_cached_creds(account_type=self.AccountType.USER,
+ use_cache=False)
+ tgt = self.get_tgt(creds)
+
+ # Rename the account.
+ new_name = self.get_new_username()
+
+ samdb = self.get_samdb()
+ msg = ldb.Message(creds.get_dn())
+ msg['sAMAccountName'] = ldb.MessageElement(new_name,
+ ldb.FLAG_MOD_REPLACE,
+ 'sAMAccountName')
+ samdb.modify(msg)
+
+ self._run_tgs(tgt, expected_error=KDC_ERR_C_PRINCIPAL_UNKNOWN)
+
+ def _get_tgt(self,
+ client_creds,
+ renewable=False,
+ invalid=False,
+ from_rodc=False,
+ new_rid=None,
+ remove_pac=False,
+ allow_empty_authdata=False,
+ can_modify_logon_info=True,
+ can_modify_requester_sid=True,
+ remove_pac_attrs=False,
+ remove_requester_sid=False):
+ self.assertFalse(renewable and invalid)
+
+ if remove_pac:
+ self.assertIsNone(new_rid)
+
+ tgt = self.get_tgt(client_creds)
+
+ return self._modify_tgt(
+ tgt=tgt,
+ renewable=renewable,
+ invalid=invalid,
+ from_rodc=from_rodc,
+ new_rid=new_rid,
+ remove_pac=remove_pac,
+ allow_empty_authdata=allow_empty_authdata,
+ can_modify_logon_info=can_modify_logon_info,
+ can_modify_requester_sid=can_modify_requester_sid,
+ remove_pac_attrs=remove_pac_attrs,
+ remove_requester_sid=remove_requester_sid)
+
+ def _modify_tgt(self,
+ tgt,
+ renewable=False,
+ invalid=False,
+ from_rodc=False,
+ new_rid=None,
+ remove_pac=False,
+ allow_empty_authdata=False,
+ cname=None,
+ crealm=None,
+ can_modify_logon_info=True,
+ can_modify_requester_sid=True,
+ remove_pac_attrs=False,
+ remove_requester_sid=False):
+ if from_rodc:
+ krbtgt_creds = self.get_mock_rodc_krbtgt_creds()
+ else:
+ krbtgt_creds = self.get_krbtgt_creds()
+
+ if new_rid is not None or remove_requester_sid or remove_pac_attrs:
+ def change_sid_fn(pac):
+ pac_buffers = pac.buffers
+ for pac_buffer in pac_buffers:
+ if pac_buffer.type == krb5pac.PAC_TYPE_LOGON_INFO:
+ if new_rid is not None and can_modify_logon_info:
+ logon_info = pac_buffer.info.info
+
+ logon_info.info3.base.rid = new_rid
+ elif pac_buffer.type == krb5pac.PAC_TYPE_REQUESTER_SID:
+ if remove_requester_sid:
+ pac.num_buffers -= 1
+ pac_buffers.remove(pac_buffer)
+ elif new_rid is not None and can_modify_requester_sid:
+ requester_sid = pac_buffer.info
+
+ samdb = self.get_samdb()
+ domain_sid = samdb.get_domain_sid()
+
+ new_sid = f'{domain_sid}-{new_rid}'
+
+ requester_sid.sid = security.dom_sid(new_sid)
+ elif pac_buffer.type == krb5pac.PAC_TYPE_ATTRIBUTES_INFO:
+ if remove_pac_attrs:
+ pac.num_buffers -= 1
+ pac_buffers.remove(pac_buffer)
+
+ pac.buffers = pac_buffers
+
+ return pac
+ else:
+ change_sid_fn = None
+
+ krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+
+ if remove_pac:
+ checksum_keys = None
+ else:
+ checksum_keys = {
+ krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key
+ }
+
+ if renewable:
+ def flags_modify_fn(enc_part):
+ # Set the renewable flag.
+ renewable_flag = krb5_asn1.TicketFlags('renewable')
+ pos = len(tuple(renewable_flag)) - 1
+
+ flags = enc_part['flags']
+ self.assertLessEqual(pos, len(flags))
+
+ new_flags = flags[:pos] + '1' + flags[pos + 1:]
+ enc_part['flags'] = new_flags
+
+ # Set the renew-till time to be in the future.
+ renew_till = self.get_KerberosTime(offset=100 * 60 * 60)
+ enc_part['renew-till'] = renew_till
+
+ return enc_part
+ elif invalid:
+ def flags_modify_fn(enc_part):
+ # Set the invalid flag.
+ invalid_flag = krb5_asn1.TicketFlags('invalid')
+ pos = len(tuple(invalid_flag)) - 1
+
+ flags = enc_part['flags']
+ self.assertLessEqual(pos, len(flags))
+
+ new_flags = flags[:pos] + '1' + flags[pos + 1:]
+ enc_part['flags'] = new_flags
+
+ # Set the ticket start time to be in the past.
+ past_time = self.get_KerberosTime(offset=-100 * 60 * 60)
+ enc_part['starttime'] = past_time
+
+ return enc_part
+ else:
+ flags_modify_fn = None
+
+ if cname is not None or crealm is not None:
+ def modify_fn(enc_part):
+ if flags_modify_fn is not None:
+ enc_part = flags_modify_fn(enc_part)
+
+ if cname is not None:
+ enc_part['cname'] = cname
+
+ if crealm is not None:
+ enc_part['crealm'] = crealm
+
+ return enc_part
+ else:
+ modify_fn = flags_modify_fn
+
+ if cname is not None:
+ def modify_pac_fn(pac):
+ if change_sid_fn is not None:
+ pac = change_sid_fn(pac)
+
+ for pac_buffer in pac.buffers:
+ if pac_buffer.type == krb5pac.PAC_TYPE_LOGON_NAME:
+ logon_info = pac_buffer.info
+
+ logon_info.account_name = (
+ cname['name-string'][0].decode('utf-8'))
+
+ return pac
+ else:
+ modify_pac_fn = change_sid_fn
+
+ return self.modified_ticket(
+ tgt,
+ new_ticket_key=krbtgt_key,
+ modify_fn=modify_fn,
+ modify_pac_fn=modify_pac_fn,
+ exclude_pac=remove_pac,
+ allow_empty_authdata=allow_empty_authdata,
+ update_pac_checksums=not remove_pac,
+ checksum_keys=checksum_keys)
+
+ def _remove_rodc_partial_secrets(self):
+ samdb = self.get_samdb()
+
+ rodc_ctx = self.get_mock_rodc_ctx()
+ rodc_dn = ldb.Dn(samdb, rodc_ctx.acct_dn)
+
+ def add_rodc_partial_secrets():
+ msg = ldb.Message()
+ msg.dn = rodc_dn
+ msg['userAccountControl'] = ldb.MessageElement(
+ str(rodc_ctx.userAccountControl),
+ ldb.FLAG_MOD_REPLACE,
+ 'userAccountControl')
+ samdb.modify(msg)
+
+ self.addCleanup(add_rodc_partial_secrets)
+
+ uac = rodc_ctx.userAccountControl & ~dsdb.UF_PARTIAL_SECRETS_ACCOUNT
+
+ msg = ldb.Message()
+ msg.dn = rodc_dn
+ msg['userAccountControl'] = ldb.MessageElement(
+ str(uac),
+ ldb.FLAG_MOD_REPLACE,
+ 'userAccountControl')
+ samdb.modify(msg)
+
+ def _remove_rodc_krbtgt_link(self):
+ samdb = self.get_samdb()
+
+ rodc_ctx = self.get_mock_rodc_ctx()
+ rodc_dn = ldb.Dn(samdb, rodc_ctx.acct_dn)
+
+ def add_rodc_krbtgt_link():
+ msg = ldb.Message()
+ msg.dn = rodc_dn
+ msg['msDS-KrbTgtLink'] = ldb.MessageElement(
+ rodc_ctx.new_krbtgt_dn,
+ ldb.FLAG_MOD_ADD,
+ 'msDS-KrbTgtLink')
+ samdb.modify(msg)
+
+ self.addCleanup(add_rodc_krbtgt_link)
+
+ msg = ldb.Message()
+ msg.dn = rodc_dn
+ msg['msDS-KrbTgtLink'] = ldb.MessageElement(
+ [],
+ ldb.FLAG_MOD_DELETE,
+ 'msDS-KrbTgtLink')
+ samdb.modify(msg)
+
+ def _get_creds(self,
+ replication_allowed=False,
+ replication_denied=False,
+ revealed_to_rodc=False):
+ return self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={
+ 'allowed_replication_mock': replication_allowed,
+ 'denied_replication_mock': replication_denied,
+ 'revealed_to_mock_rodc': revealed_to_rodc,
+ 'id': 0
+ })
+
+ def _get_existing_rid(self,
+ replication_allowed=False,
+ replication_denied=False,
+ revealed_to_rodc=False):
+ other_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={
+ 'allowed_replication_mock': replication_allowed,
+ 'denied_replication_mock': replication_denied,
+ 'revealed_to_mock_rodc': revealed_to_rodc,
+ 'id': 1
+ })
+
+ samdb = self.get_samdb()
+
+ other_dn = other_creds.get_dn()
+ other_sid = self.get_objectSid(samdb, other_dn)
+
+ other_rid = int(other_sid.rsplit('-', 1)[1])
+
+ return other_rid
+
+ def _get_mach_creds(self):
+ return self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={
+ 'allowed_replication_mock': True,
+ 'denied_replication_mock': False,
+ 'revealed_to_mock_rodc': True,
+ 'id': 2
+ })
+
+ def _get_non_existent_rid(self):
+ return (1 << 30) - 1
+
+ def _run_tgs(self, tgt, expected_error, expect_pac=True,
+ expect_pac_attrs=None, expect_pac_attrs_pac_request=None,
+ expect_requester_sid=None, expected_sid=None):
+ target_creds = self.get_service_creds()
+ return self._tgs_req(
+ tgt, expected_error, target_creds,
+ expect_pac=expect_pac,
+ expect_pac_attrs=expect_pac_attrs,
+ expect_pac_attrs_pac_request=expect_pac_attrs_pac_request,
+ expect_requester_sid=expect_requester_sid,
+ expected_sid=expected_sid)
+
+ def _renew_tgt(self, tgt, expected_error, expect_pac=True,
+ expect_pac_attrs=None, expect_pac_attrs_pac_request=None,
+ expect_requester_sid=None, expected_sid=None):
+ krbtgt_creds = self.get_krbtgt_creds()
+ kdc_options = str(krb5_asn1.KDCOptions('renew'))
+ return self._tgs_req(
+ tgt, expected_error, krbtgt_creds,
+ kdc_options=kdc_options,
+ expect_pac=expect_pac,
+ expect_pac_attrs=expect_pac_attrs,
+ expect_pac_attrs_pac_request=expect_pac_attrs_pac_request,
+ expect_requester_sid=expect_requester_sid,
+ expected_sid=expected_sid)
+
+ def _validate_tgt(self, tgt, expected_error, expect_pac=True):
+ krbtgt_creds = self.get_krbtgt_creds()
+ kdc_options = str(krb5_asn1.KDCOptions('validate'))
+ return self._tgs_req(tgt, expected_error, krbtgt_creds,
+ kdc_options=kdc_options,
+ expect_pac=expect_pac)
+
+ def _s4u2self(self, tgt, tgt_creds, expected_error, expect_pac=True,
+ expect_edata=False, expected_status=None):
+ user_creds = self._get_mach_creds()
+
+ user_name = user_creds.get_username()
+ user_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[user_name])
+ user_realm = user_creds.get_realm()
+
+ def generate_s4u2self_padata(_kdc_exchange_dict,
+ _callback_dict,
+ req_body):
+ padata = self.PA_S4U2Self_create(
+ name=user_cname,
+ realm=user_realm,
+ tgt_session_key=tgt.session_key,
+ ctype=None)
+
+ return [padata], req_body
+
+ return self._tgs_req(tgt, expected_error, tgt_creds,
+ expected_cname=user_cname,
+ generate_padata_fn=generate_s4u2self_padata,
+ expect_claims=False, expect_edata=expect_edata,
+ expected_status=expected_status,
+ expect_pac=expect_pac)
+
+ def _user2user(self, tgt, tgt_creds, expected_error, sname=None,
+ srealm=None, user_tgt=None, expect_pac=True):
+ if user_tgt is None:
+ user_creds = self._get_mach_creds()
+ user_tgt = self.get_tgt(user_creds)
+
+ kdc_options = str(krb5_asn1.KDCOptions('enc-tkt-in-skey'))
+ return self._tgs_req(user_tgt, expected_error, tgt_creds,
+ kdc_options=kdc_options,
+ additional_ticket=tgt,
+ sname=sname,
+ srealm=srealm,
+ expect_pac=expect_pac)
+
+ def _tgs_req(self, tgt, expected_error, target_creds,
+ kdc_options='0',
+ expected_cname=None,
+ additional_ticket=None,
+ generate_padata_fn=None,
+ sname=None,
+ srealm=None,
+ expect_claims=True,
+ expect_pac=True,
+ expect_pac_attrs=None,
+ expect_pac_attrs_pac_request=None,
+ expect_requester_sid=None,
+ expect_edata=False,
+ expected_sid=None,
+ expected_status=None):
+ if srealm is False:
+ srealm = None
+ elif srealm is None:
+ srealm = target_creds.get_realm()
+
+ if sname is False:
+ sname = None
+ expected_sname = self.get_krbtgt_sname()
+ else:
+ if sname is None:
+ target_name = target_creds.get_username()
+ if target_name == 'krbtgt':
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST,
+ names=[target_name, srealm])
+ else:
+ if target_name[-1] == '$':
+ target_name = target_name[:-1]
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=['host', target_name])
+
+ expected_sname = sname
+
+ if additional_ticket is not None:
+ additional_tickets = [additional_ticket.ticket]
+ decryption_key = additional_ticket.session_key
+ else:
+ additional_tickets = None
+ decryption_key = self.TicketDecryptionKey_from_creds(
+ target_creds)
+
+ subkey = self.RandomKey(tgt.session_key.etype)
+
+ etypes = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+
+ if expected_error:
+ check_error_fn = self.generic_check_kdc_error
+ check_rep_fn = None
+ else:
+ check_error_fn = None
+ check_rep_fn = self.generic_check_kdc_rep
+
+ if expected_cname is None:
+ expected_cname = tgt.cname
+
+ kdc_exchange_dict = self.tgs_exchange_dict(
+ expected_crealm=tgt.crealm,
+ expected_cname=expected_cname,
+ expected_srealm=srealm,
+ expected_sname=expected_sname,
+ ticket_decryption_key=decryption_key,
+ generate_padata_fn=generate_padata_fn,
+ check_error_fn=check_error_fn,
+ check_rep_fn=check_rep_fn,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ expected_error_mode=expected_error,
+ expected_status=expected_status,
+ tgt=tgt,
+ authenticator_subkey=subkey,
+ kdc_options=kdc_options,
+ expect_edata=expect_edata,
+ expect_pac=expect_pac,
+ expect_pac_attrs=expect_pac_attrs,
+ expect_pac_attrs_pac_request=expect_pac_attrs_pac_request,
+ expect_requester_sid=expect_requester_sid,
+ expected_sid=expected_sid,
+ expect_claims=expect_claims)
+
+ rep = self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=None,
+ realm=srealm,
+ sname=sname,
+ etypes=etypes,
+ additional_tickets=additional_tickets)
+ if expected_error:
+ self.check_error_rep(rep, expected_error)
+ return None
+ else:
+ self.check_reply(rep, KRB_TGS_REP)
+ return kdc_exchange_dict['rep_ticket_creds']
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py 2021-10-29 06:17:36.000000000 +0000
@@ -0,0 +1,840 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) 2020 Catalyst.Net Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+from samba.dsdb import UF_NORMAL_ACCOUNT, UF_DONT_REQUIRE_PREAUTH
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+from samba.tests.krb5.rfc4120_constants import (
+ AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ NT_ENTERPRISE_PRINCIPAL,
+ NT_PRINCIPAL,
+ NT_SRV_INST,
+ KDC_ERR_C_PRINCIPAL_UNKNOWN,
+)
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest):
+ ''' Tests for MS-KILE client principal look-up
+ See [MS-KILE]: Kerberos Protocol Extensions
+ secion 3.3.5.6.1 Client Principal Lookup
+ '''
+
+ def setUp(self):
+ super().setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ def check_pac(self, samdb, auth_data, dn, uc, name, upn=None):
+
+ pac_data = self.get_pac_data(auth_data)
+ sid = self.get_objectSid(samdb, dn)
+ if upn is None:
+ upn = "%s@%s" % (name, uc.get_realm().lower())
+ if name.endswith('$'):
+ name = name[:-1]
+
+ self.assertEqual(
+ uc.get_username(),
+ str(pac_data.account_name),
+ "pac_data = {%s}" % str(pac_data))
+ self.assertEqual(
+ name,
+ pac_data.logon_name,
+ "pac_data = {%s}" % str(pac_data))
+ self.assertEqual(
+ uc.get_realm(),
+ pac_data.domain_name,
+ "pac_data = {%s}" % str(pac_data))
+ self.assertEqual(
+ upn,
+ pac_data.upn,
+ "pac_data = {%s}" % str(pac_data))
+ self.assertEqual(
+ sid,
+ pac_data.account_sid,
+ "pac_data = {%s}" % str(pac_data))
+
+ def test_nt_principal_step_1(self):
+ ''' Step 1
+ For an NT_PRINCIPAL cname with no realm or the realm matches the
+ DC's domain
+ search for an account with the
+ sAMAccountName matching the cname.
+ '''
+
+ # Create user and machine accounts for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[user_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[user_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(samdb, enc_part['authorization-data'], dn, uc, user_name)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_PRINCIPAL, cname['name-type'])
+ self.assertEqual(user_name.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_principal_step_2(self):
+ ''' Step 2
+ If not found
+ search for sAMAccountName equal to the cname + "$"
+
+ '''
+
+ # Create a machine account for the test.
+ #
+ samdb = self.get_samdb()
+ mach_name = "mskilemac"
+ (mc, dn) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+ realm = mc.get_realm().lower()
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[mach_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(mc, rep)
+ key = self.get_as_rep_key(mc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mach_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, mc.get_realm(), ticket, key, etype,
+ service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(samdb, enc_part['authorization-data'], dn, mc, mach_name + '$')
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_PRINCIPAL, cname['name-type'])
+ self.assertEqual(mach_name.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_principal_step_3(self):
+ ''' Step 3
+
+ If not found
+ search for a matching UPN name where the UPN is set to
+ cname@realm or cname@DC's domain name
+
+ '''
+ # Create a user account for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ upn_name = "mskileupn"
+ upn = upn_name + "@" + self.get_user_creds().get_realm().lower()
+ (uc, dn) = self.create_account(samdb, user_name, upn=upn)
+ realm = uc.get_realm().lower()
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[upn_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[upn_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the service ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(samdb, enc_part['authorization-data'], dn, uc, upn_name)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_PRINCIPAL, cname['name-type'])
+ self.assertEqual(upn_name.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_principal_step_4_a(self):
+ ''' Step 4, no pre-authentication
+ If not found and no pre-authentication
+ search for a matching altSecurityIdentity
+ '''
+ # Create a user account for the test.
+ # with an altSecurityIdentity, and with UF_DONT_REQUIRE_PREAUTH
+ # set.
+ #
+ # note that in this case IDL_DRSCrackNames is called with
+ # pmsgIn.formatOffered set to
+ # DS_USER_PRINCIPAL_NAME_AND_ALTSECID
+ #
+ # setting UF_DONT_REQUIRE_PREAUTH seems to be the only way
+ # to trigger the no pre-auth step
+
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name,
+ account_control=UF_DONT_REQUIRE_PREAUTH)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, as we've set UF_DONT_REQUIRE_PREAUTH
+ # we should get a valid AS-RESP
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[alt_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_as_reply(rep)
+ salt = "%s%s" % (realm.upper(), user_name)
+ key = self.PasswordKey_create(
+ rep['enc-part']['etype'],
+ uc.get_password(),
+ salt.encode('UTF8'),
+ rep['enc-part']['kvno'])
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[alt_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ service_creds=mc, expect_pac=False)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the service ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ #
+ # We get an empty authorization-data element in the ticket.
+ # i.e. no PAC
+ self.assertEqual([], enc_part['authorization-data'])
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_PRINCIPAL, cname['name-type'])
+ self.assertEqual(alt_name.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_principal_step_4_b(self):
+ ''' Step 4, pre-authentication
+ If not found and pre-authentication
+ search for a matching user principal name
+ '''
+
+ # Create user and machine accounts for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[alt_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ # Note: although we used the alt security id for the pre-auth
+ # we need to use the username for the auth
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[user_name])
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[user_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(samdb,
+ enc_part['authorization-data'], dn, uc, user_name)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_PRINCIPAL, cname['name-type'])
+ self.assertEqual(user_name.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_principal_step_4_c(self):
+ ''' Step 4, pre-authentication
+ If not found and pre-authentication
+ search for a matching user principal name
+
+ This test uses the altsecid, so the AS-REQ should fail.
+ '''
+
+ # Create user and machine accounts for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[alt_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ # Use the alternate security identifier
+ # this should fail
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[alt_sec])
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_error_rep(rep, KDC_ERR_C_PRINCIPAL_UNKNOWN)
+
+ def test_enterprise_principal_step_1_3(self):
+ ''' Steps 1-3
+ For an NT_ENTERPRISE_PRINCIPAL cname
+ search for a user principal name matching the cname
+
+ '''
+
+ # Create a user account for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ upn_name = "mskileupn"
+ upn = upn_name + "@" + self.get_user_creds().get_realm().lower()
+ (uc, dn) = self.create_account(samdb, user_name, upn=upn)
+ realm = uc.get_realm().lower()
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[upn])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[upn])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(
+ samdb, enc_part['authorization-data'], dn, uc, upn, upn=upn)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ crealm = enc_part['crealm']
+ self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
+ self.assertEqual(upn.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), crealm)
+
+ def test_enterprise_principal_step_4(self):
+ ''' Step 4
+
+ If that fails
+ search for an account where the sAMAccountName matches
+ the name before the @
+
+ '''
+
+ # Create a user account for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+ ename = user_name + "@" + realm
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(
+ samdb, enc_part['authorization-data'], dn, uc, ename, upn=ename)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ crealm = enc_part['crealm']
+ self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
+ self.assertEqual(ename.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), crealm)
+
+ def test_enterprise_principal_step_5(self):
+ ''' Step 5
+
+ If that fails
+ search for an account where the sAMAccountName matches
+ the name before the @ with a $ appended.
+
+ '''
+
+ # Create a user account for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ (uc, _) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+
+ mach_name = "mskilemac"
+ (mc, dn) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+ ename = mach_name + "@" + realm
+ uname = mach_name + "$@" + realm
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(mc, rep)
+ key = self.get_as_rep_key(mc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(
+ samdb, enc_part['authorization-data'], dn, mc, ename, upn=uname)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ crealm = enc_part['crealm']
+ self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
+ self.assertEqual(ename.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), crealm)
+
+ def test_enterprise_principal_step_6_a(self):
+ ''' Step 6, no pre-authentication
+ If not found and no pre-authentication
+ search for a matching altSecurityIdentity
+ '''
+ # Create a user account for the test.
+ # with an altSecurityIdentity, and with UF_DONT_REQUIRE_PREAUTH
+ # set.
+ #
+ # note that in this case IDL_DRSCrackNames is called with
+ # pmsgIn.formatOffered set to
+ # DS_USER_PRINCIPAL_NAME_AND_ALTSECID
+ #
+ # setting UF_DONT_REQUIRE_PREAUTH seems to be the only way
+ # to trigger the no pre-auth step
+
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name,
+ account_control=UF_DONT_REQUIRE_PREAUTH)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+ ename = alt_name + "@" + realm
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, as we've set UF_DONT_REQUIRE_PREAUTH
+ # we should get a valid AS-RESP
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_as_reply(rep)
+ salt = "%s%s" % (realm.upper(), user_name)
+ key = self.PasswordKey_create(
+ rep['enc-part']['etype'],
+ uc.get_password(),
+ salt.encode('UTF8'),
+ rep['enc-part']['kvno'])
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ service_creds=mc, expect_pac=False)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the service ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ #
+ # We get an empty authorization-data element in the ticket.
+ # i.e. no PAC
+ self.assertEqual([], enc_part['authorization-data'])
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
+ self.assertEqual(ename.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_enterprise_principal_step_6_b(self):
+ ''' Step 4, pre-authentication
+ If not found and pre-authentication
+ search for a matching user principal name
+ '''
+
+ # Create user and machine accounts for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+ ename = alt_name + "@" + realm
+ uname = user_name + "@" + realm
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ # Note: although we used the alt security id for the pre-auth
+ # we need to use the username for the auth
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[uname])
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL,
+ names=[uname])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(
+ samdb, enc_part['authorization-data'], dn, uc, uname, upn=uname)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
+ self.assertEqual(uname.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_principal_step_6_c(self):
+ ''' Step 4, pre-authentication
+ If not found and pre-authentication
+ search for a matching user principal name
+
+ This test uses the altsecid, so the AS-REQ should fail.
+ '''
+
+ # Create user and machine accounts for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+ ename = alt_name + "@" + realm
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ # Use the alternate security identifier
+ # this should fail
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_error_rep(rep, KDC_ERR_C_PRINCIPAL_UNKNOWN)
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/pyasn1_regen.sh samba-4.13.14+dfsg/python/samba/tests/krb5/pyasn1_regen.sh
--- samba-4.13.3+dfsg/python/samba/tests/krb5/pyasn1_regen.sh 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/pyasn1_regen.sh 2021-09-22 06:59:39.000000000 +0000
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+
+#
+# I used https://github.com/kimgr/asn1ate.git
+# to generate pyasn1 bindings for rfc4120.asn1
+#
+
+PATH_TO_ASN1ATE_CHECKOUT=$1
+PATH_TO_ASN1_INPUT_FILE=$2
+
+set -u
+set -e
+
+usage() {
+ echo "usage: $0 PATH_TO_ASN1ATE_CHECKOUT PATH_TO_ASN1_INPUT_FILE > PATH_TO_PYASN1_OUTPUT_FILE"
+}
+
+test -n "${PATH_TO_ASN1ATE_CHECKOUT}" || {
+ usage
+ exit 1
+}
+test -n "${PATH_TO_ASN1_INPUT_FILE}" || {
+ usage
+ exit 1
+}
+test -d "${PATH_TO_ASN1ATE_CHECKOUT}" || {
+ usage
+ exit 1
+}
+test -f "${PATH_TO_ASN1_INPUT_FILE}" || {
+ usage
+ exit 1
+}
+
+PATH_TO_PYASN1GEN_PY="${PATH_TO_ASN1ATE_CHECKOUT}/asn1ate/pyasn1gen.py"
+
+PYTHONPATH="${PATH_TO_ASN1ATE_CHECKOUT}:${PYTHONPATH-}"
+export PYTHONPATH
+
+python3 "${PATH_TO_PYASN1GEN_PY}" "${PATH_TO_ASN1_INPUT_FILE}"
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/raw_testcase.py samba-4.13.14+dfsg/python/samba/tests/krb5/raw_testcase.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/raw_testcase.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/raw_testcase.py 2021-11-08 11:29:14.000000000 +0000
@@ -22,20 +22,77 @@
import time
import datetime
import random
-
-import samba.tests
-from samba.credentials import Credentials
-from samba.tests import TestCase
-import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
-import samba.tests.krb5.kcrypto as kcrypto
+import binascii
+import itertools
+import collections
from pyasn1.codec.der.decoder import decode as pyasn1_der_decode
from pyasn1.codec.der.encoder import encode as pyasn1_der_encode
from pyasn1.codec.native.decoder import decode as pyasn1_native_decode
from pyasn1.codec.native.encoder import encode as pyasn1_native_encode
-from pyasn1.codec.ber.encoder import BitStringEncoder as BitStringEncoder
-def BitStringEncoder_encodeValue32(self, value, asn1Spec, encodeFun, **options):
+from pyasn1.codec.ber.encoder import BitStringEncoder
+
+from samba.credentials import Credentials
+from samba.dcerpc import krb5pac, security
+from samba.gensec import FEATURE_SEAL
+from samba.ndr import ndr_pack, ndr_unpack
+
+import samba.tests
+from samba.tests import TestCaseInTempDir
+
+import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
+from samba.tests.krb5.rfc4120_constants import (
+ AD_IF_RELEVANT,
+ AD_WIN2K_PAC,
+ FX_FAST_ARMOR_AP_REQUEST,
+ KDC_ERR_GENERIC,
+ KDC_ERR_PREAUTH_FAILED,
+ KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS,
+ KERB_ERR_TYPE_EXTENDED,
+ KRB_AP_REQ,
+ KRB_AS_REP,
+ KRB_AS_REQ,
+ KRB_ERROR,
+ KRB_TGS_REP,
+ KRB_TGS_REQ,
+ KU_AP_REQ_AUTH,
+ KU_AS_REP_ENC_PART,
+ KU_ENC_CHALLENGE_KDC,
+ KU_FAST_ENC,
+ KU_FAST_FINISHED,
+ KU_FAST_REP,
+ KU_FAST_REQ_CHKSUM,
+ KU_NON_KERB_CKSUM_SALT,
+ KU_TGS_REP_ENC_PART_SESSION,
+ KU_TGS_REP_ENC_PART_SUB_KEY,
+ KU_TGS_REQ_AUTH,
+ KU_TGS_REQ_AUTH_CKSUM,
+ KU_TGS_REQ_AUTH_DAT_SESSION,
+ KU_TGS_REQ_AUTH_DAT_SUBKEY,
+ KU_TICKET,
+ NT_SRV_INST,
+ NT_WELLKNOWN,
+ PADATA_ENCRYPTED_CHALLENGE,
+ PADATA_ENC_TIMESTAMP,
+ PADATA_ETYPE_INFO,
+ PADATA_ETYPE_INFO2,
+ PADATA_FOR_USER,
+ PADATA_FX_COOKIE,
+ PADATA_FX_ERROR,
+ PADATA_FX_FAST,
+ PADATA_KDC_REQ,
+ PADATA_PAC_OPTIONS,
+ PADATA_PAC_REQUEST,
+ PADATA_PK_AS_REQ,
+ PADATA_PK_AS_REP_19,
+ PADATA_SUPPORTED_ETYPES
+)
+import samba.tests.krb5.kcrypto as kcrypto
+
+
+def BitStringEncoder_encodeValue32(
+ self, value, asn1Spec, encodeFun, **options):
#
# BitStrings like KDCOptions or TicketFlags should at least
# be 32-Bit on the wire
@@ -59,14 +116,17 @@
padding = 0
ret = b'\x00' + substrate + (b'\x00' * padding)
return ret, False, True
+
+
BitStringEncoder.encodeValue = BitStringEncoder_encodeValue32
+
def BitString_NamedValues_prettyPrint(self, scope=0):
ret = "%s" % self.asBinary()
bits = []
highest_bit = 32
for byte in self.asNumbers():
- for bit in [7,6,5,4,3,2,1,0]:
+ for bit in [7, 6, 5, 4, 3, 2, 1, 0]:
mask = 1 << bit
if byte & mask:
val = 1
@@ -89,12 +149,33 @@
delim = ",\n%s " % indent
ret += "\n%s)" % indent
return ret
-krb5_asn1.TicketFlags.prettyPrintNamedValues = krb5_asn1.TicketFlagsValues.namedValues
-krb5_asn1.TicketFlags.namedValues = krb5_asn1.TicketFlagsValues.namedValues
-krb5_asn1.TicketFlags.prettyPrint = BitString_NamedValues_prettyPrint
-krb5_asn1.KDCOptions.prettyPrintNamedValues = krb5_asn1.KDCOptionsValues.namedValues
-krb5_asn1.KDCOptions.namedValues = krb5_asn1.KDCOptionsValues.namedValues
-krb5_asn1.KDCOptions.prettyPrint = BitString_NamedValues_prettyPrint
+
+
+krb5_asn1.TicketFlags.prettyPrintNamedValues =\
+ krb5_asn1.TicketFlagsValues.namedValues
+krb5_asn1.TicketFlags.namedValues =\
+ krb5_asn1.TicketFlagsValues.namedValues
+krb5_asn1.TicketFlags.prettyPrint =\
+ BitString_NamedValues_prettyPrint
+krb5_asn1.KDCOptions.prettyPrintNamedValues =\
+ krb5_asn1.KDCOptionsValues.namedValues
+krb5_asn1.KDCOptions.namedValues =\
+ krb5_asn1.KDCOptionsValues.namedValues
+krb5_asn1.KDCOptions.prettyPrint =\
+ BitString_NamedValues_prettyPrint
+krb5_asn1.APOptions.prettyPrintNamedValues =\
+ krb5_asn1.APOptionsValues.namedValues
+krb5_asn1.APOptions.namedValues =\
+ krb5_asn1.APOptionsValues.namedValues
+krb5_asn1.APOptions.prettyPrint =\
+ BitString_NamedValues_prettyPrint
+krb5_asn1.PACOptionFlags.prettyPrintNamedValues =\
+ krb5_asn1.PACOptionFlagsValues.namedValues
+krb5_asn1.PACOptionFlags.namedValues =\
+ krb5_asn1.PACOptionFlagsValues.namedValues
+krb5_asn1.PACOptionFlags.prettyPrint =\
+ BitString_NamedValues_prettyPrint
+
def Integer_NamedValues_prettyPrint(self, scope=0):
intval = int(self)
@@ -104,18 +185,35 @@
name = "<__unknown__>"
ret = "%d (0x%x) %s" % (intval, intval, name)
return ret
-krb5_asn1.NameType.prettyPrintNamedValues = krb5_asn1.NameTypeValues.namedValues
-krb5_asn1.NameType.prettyPrint = Integer_NamedValues_prettyPrint
-krb5_asn1.AuthDataType.prettyPrintNamedValues = krb5_asn1.AuthDataTypeValues.namedValues
-krb5_asn1.AuthDataType.prettyPrint = Integer_NamedValues_prettyPrint
-krb5_asn1.PADataType.prettyPrintNamedValues = krb5_asn1.PADataTypeValues.namedValues
-krb5_asn1.PADataType.prettyPrint = Integer_NamedValues_prettyPrint
-krb5_asn1.EncryptionType.prettyPrintNamedValues = krb5_asn1.EncryptionTypeValues.namedValues
-krb5_asn1.EncryptionType.prettyPrint = Integer_NamedValues_prettyPrint
-krb5_asn1.ChecksumType.prettyPrintNamedValues = krb5_asn1.ChecksumTypeValues.namedValues
-krb5_asn1.ChecksumType.prettyPrint = Integer_NamedValues_prettyPrint
-class Krb5EncryptionKey(object):
+
+krb5_asn1.NameType.prettyPrintNamedValues =\
+ krb5_asn1.NameTypeValues.namedValues
+krb5_asn1.NameType.prettyPrint =\
+ Integer_NamedValues_prettyPrint
+krb5_asn1.AuthDataType.prettyPrintNamedValues =\
+ krb5_asn1.AuthDataTypeValues.namedValues
+krb5_asn1.AuthDataType.prettyPrint =\
+ Integer_NamedValues_prettyPrint
+krb5_asn1.PADataType.prettyPrintNamedValues =\
+ krb5_asn1.PADataTypeValues.namedValues
+krb5_asn1.PADataType.prettyPrint =\
+ Integer_NamedValues_prettyPrint
+krb5_asn1.EncryptionType.prettyPrintNamedValues =\
+ krb5_asn1.EncryptionTypeValues.namedValues
+krb5_asn1.EncryptionType.prettyPrint =\
+ Integer_NamedValues_prettyPrint
+krb5_asn1.ChecksumType.prettyPrintNamedValues =\
+ krb5_asn1.ChecksumTypeValues.namedValues
+krb5_asn1.ChecksumType.prettyPrint =\
+ Integer_NamedValues_prettyPrint
+krb5_asn1.KerbErrorDataType.prettyPrintNamedValues =\
+ krb5_asn1.KerbErrorDataTypeValues.namedValues
+krb5_asn1.KerbErrorDataType.prettyPrint =\
+ Integer_NamedValues_prettyPrint
+
+
+class Krb5EncryptionKey:
def __init__(self, key, kvno):
EncTypeChecksum = {
kcrypto.Enctype.AES256: kcrypto.Cksumtype.SHA1_AES256,
@@ -126,7 +224,6 @@
self.etype = key.enctype
self.ctype = EncTypeChecksum[self.etype]
self.kvno = kvno
- return
def encrypt(self, usage, plaintext):
ciphertext = kcrypto.encrypt(self.key, usage, plaintext)
@@ -136,34 +233,393 @@
plaintext = kcrypto.decrypt(self.key, usage, ciphertext)
return plaintext
+ def make_zeroed_checksum(self, ctype=None):
+ if ctype is None:
+ ctype = self.ctype
+
+ checksum_len = kcrypto.checksum_len(ctype)
+ return bytes(checksum_len)
+
def make_checksum(self, usage, plaintext, ctype=None):
if ctype is None:
ctype = self.ctype
cksum = kcrypto.make_checksum(ctype, self.key, usage, plaintext)
return cksum
+ def verify_checksum(self, usage, plaintext, ctype, cksum):
+ if self.ctype != ctype:
+ raise AssertionError(f'key checksum type ({self.ctype}) != '
+ f'checksum type ({ctype})')
+
+ kcrypto.verify_checksum(ctype,
+ self.key,
+ usage,
+ plaintext,
+ cksum)
+
def export_obj(self):
EncryptionKey_obj = {
'keytype': self.etype,
'keyvalue': self.key.contents,
- };
+ }
return EncryptionKey_obj
-class RawKerberosTest(TestCase):
+
+class RodcPacEncryptionKey(Krb5EncryptionKey):
+ def __init__(self, key, kvno, rodc_id=None):
+ super().__init__(key, kvno)
+
+ if rodc_id is None:
+ kvno = self.kvno
+ if kvno is not None:
+ kvno >>= 16
+ kvno &= (1 << 16) - 1
+
+ rodc_id = kvno or None
+
+ if rodc_id is not None:
+ self.rodc_id = rodc_id.to_bytes(2, byteorder='little')
+ else:
+ self.rodc_id = b''
+
+ def make_rodc_zeroed_checksum(self, ctype=None):
+ checksum = super().make_zeroed_checksum(ctype)
+ return checksum + bytes(len(self.rodc_id))
+
+ def make_rodc_checksum(self, usage, plaintext, ctype=None):
+ checksum = super().make_checksum(usage, plaintext, ctype)
+ return checksum + self.rodc_id
+
+ def verify_rodc_checksum(self, usage, plaintext, ctype, cksum):
+ if self.rodc_id:
+ cksum, cksum_rodc_id = cksum[:-2], cksum[-2:]
+
+ if self.rodc_id != cksum_rodc_id:
+ raise AssertionError(f'{self.rodc_id.hex()} != '
+ f'{cksum_rodc_id.hex()}')
+
+ super().verify_checksum(usage,
+ plaintext,
+ ctype,
+ cksum)
+
+
+class ZeroedChecksumKey(RodcPacEncryptionKey):
+ def make_checksum(self, usage, plaintext, ctype=None):
+ return self.make_zeroed_checksum(ctype)
+
+ def make_rodc_checksum(self, usage, plaintext, ctype=None):
+ return self.make_rodc_zeroed_checksum(ctype)
+
+
+class WrongLengthChecksumKey(RodcPacEncryptionKey):
+ def __init__(self, key, kvno, length):
+ super().__init__(key, kvno)
+
+ self._length = length
+
+ @classmethod
+ def _adjust_to_length(cls, checksum, length):
+ diff = length - len(checksum)
+ if diff > 0:
+ checksum += bytes(diff)
+ elif diff < 0:
+ checksum = checksum[:length]
+
+ return checksum
+
+ def make_zeroed_checksum(self, ctype=None):
+ return bytes(self._length)
+
+ def make_checksum(self, usage, plaintext, ctype=None):
+ checksum = super().make_checksum(usage, plaintext, ctype)
+ return self._adjust_to_length(checksum, self._length)
+
+ def make_rodc_zeroed_checksum(self, ctype=None):
+ return bytes(self._length)
+
+ def make_rodc_checksum(self, usage, plaintext, ctype=None):
+ checksum = super().make_rodc_checksum(usage, plaintext, ctype)
+ return self._adjust_to_length(checksum, self._length)
+
+
+class KerberosCredentials(Credentials):
+
+ fast_supported_bits = (security.KERB_ENCTYPE_FAST_SUPPORTED |
+ security.KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED |
+ security.KERB_ENCTYPE_CLAIMS_SUPPORTED)
+
+ def __init__(self):
+ super(KerberosCredentials, self).__init__()
+ all_enc_types = 0
+ all_enc_types |= security.KERB_ENCTYPE_RC4_HMAC_MD5
+ all_enc_types |= security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96
+ all_enc_types |= security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96
+
+ self.as_supported_enctypes = all_enc_types
+ self.tgs_supported_enctypes = all_enc_types
+ self.ap_supported_enctypes = all_enc_types
+
+ self.kvno = None
+ self.forced_keys = {}
+
+ self.forced_salt = None
+
+ self.dn = None
+ self.upn = None
+ self.spn = None
+
+ def set_as_supported_enctypes(self, value):
+ self.as_supported_enctypes = int(value)
+
+ def set_tgs_supported_enctypes(self, value):
+ self.tgs_supported_enctypes = int(value)
+
+ def set_ap_supported_enctypes(self, value):
+ self.ap_supported_enctypes = int(value)
+
+ etype_map = collections.OrderedDict([
+ (kcrypto.Enctype.AES256,
+ security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96),
+ (kcrypto.Enctype.AES128,
+ security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96),
+ (kcrypto.Enctype.RC4,
+ security.KERB_ENCTYPE_RC4_HMAC_MD5),
+ (kcrypto.Enctype.DES_MD5,
+ security.KERB_ENCTYPE_DES_CBC_MD5),
+ (kcrypto.Enctype.DES_CRC,
+ security.KERB_ENCTYPE_DES_CBC_CRC)
+ ])
+
+ @classmethod
+ def etypes_to_bits(cls, etypes):
+ bits = 0
+ for etype in etypes:
+ bit = cls.etype_map[etype]
+ if bits & bit:
+ raise ValueError(f'Got duplicate etype: {etype}')
+ bits |= bit
+
+ return bits
+
+ @classmethod
+ def bits_to_etypes(cls, bits):
+ etypes = ()
+ for etype, bit in cls.etype_map.items():
+ if bit & bits:
+ bits &= ~bit
+ etypes += (etype,)
+
+ bits &= ~cls.fast_supported_bits
+ if bits != 0:
+ raise ValueError(f'Unsupported etype bits: {bits}')
+
+ return etypes
+
+ def get_as_krb5_etypes(self):
+ return self.bits_to_etypes(self.as_supported_enctypes)
+
+ def get_tgs_krb5_etypes(self):
+ return self.bits_to_etypes(self.tgs_supported_enctypes)
+
+ def get_ap_krb5_etypes(self):
+ return self.bits_to_etypes(self.ap_supported_enctypes)
+
+ def set_kvno(self, kvno):
+ # Sign-extend from 32 bits.
+ if kvno & 1 << 31:
+ kvno |= -1 << 31
+ self.kvno = kvno
+
+ def get_kvno(self):
+ return self.kvno
+
+ def set_forced_key(self, etype, hexkey):
+ etype = int(etype)
+ contents = binascii.a2b_hex(hexkey)
+ key = kcrypto.Key(etype, contents)
+ self.forced_keys[etype] = RodcPacEncryptionKey(key, self.kvno)
+
+ def get_forced_key(self, etype):
+ etype = int(etype)
+ return self.forced_keys.get(etype)
+
+ def set_forced_salt(self, salt):
+ self.forced_salt = bytes(salt)
+
+ def get_forced_salt(self):
+ return self.forced_salt
+
+ def get_salt(self):
+ if self.forced_salt is not None:
+ return self.forced_salt
+
+ upn = self.get_upn()
+ if upn is not None:
+ salt_name = upn.rsplit('@', 1)[0].replace('/', '')
+ else:
+ salt_name = self.get_username()
+
+ if self.get_workstation():
+ salt_name = self.get_username().lower()
+ if salt_name[-1] == '$':
+ salt_name = salt_name[:-1]
+ salt_string = '%shost%s.%s' % (
+ self.get_realm().upper(),
+ salt_name,
+ self.get_realm().lower())
+ else:
+ salt_string = self.get_realm().upper() + salt_name
+
+ return salt_string.encode('utf-8')
+
+ def set_dn(self, dn):
+ self.dn = dn
+
+ def get_dn(self):
+ return self.dn
+
+ def set_spn(self, spn):
+ self.spn = spn
+
+ def get_spn(self):
+ return self.spn
+
+ def set_upn(self, upn):
+ self.upn = upn
+
+ def get_upn(self):
+ return self.upn
+
+
+class KerberosTicketCreds:
+ def __init__(self, ticket, session_key,
+ crealm=None, cname=None,
+ srealm=None, sname=None,
+ decryption_key=None,
+ ticket_private=None,
+ encpart_private=None):
+ self.ticket = ticket
+ self.session_key = session_key
+ self.crealm = crealm
+ self.cname = cname
+ self.srealm = srealm
+ self.sname = sname
+ self.decryption_key = decryption_key
+ self.ticket_private = ticket_private
+ self.encpart_private = encpart_private
+
+
+class RawKerberosTest(TestCaseInTempDir):
"""A raw Kerberos Test case."""
+ pac_checksum_types = {krb5pac.PAC_TYPE_SRV_CHECKSUM,
+ krb5pac.PAC_TYPE_KDC_CHECKSUM,
+ krb5pac.PAC_TYPE_TICKET_CHECKSUM}
+
+ etypes_to_test = (
+ {"value": -1111, "name": "dummy", },
+ {"value": kcrypto.Enctype.AES256, "name": "aes128", },
+ {"value": kcrypto.Enctype.AES128, "name": "aes256", },
+ {"value": kcrypto.Enctype.RC4, "name": "rc4", },
+ )
+
+ setup_etype_test_permutations_done = False
+
+ @classmethod
+ def setup_etype_test_permutations(cls):
+ if cls.setup_etype_test_permutations_done:
+ return
+
+ res = []
+
+ num_idxs = len(cls.etypes_to_test)
+ permutations = []
+ for num in range(1, num_idxs + 1):
+ chunk = list(itertools.permutations(range(num_idxs), num))
+ for e in chunk:
+ el = list(e)
+ permutations.append(el)
+
+ for p in permutations:
+ name = None
+ etypes = ()
+ for idx in p:
+ n = cls.etypes_to_test[idx]["name"]
+ if name is None:
+ name = n
+ else:
+ name += "_%s" % n
+ etypes += (cls.etypes_to_test[idx]["value"],)
+
+ r = {"name": name, "etypes": etypes, }
+ res.append(r)
+
+ cls.etype_test_permutations = res
+ cls.setup_etype_test_permutations_done = True
+
+ @classmethod
+ def etype_test_permutation_name_idx(cls):
+ cls.setup_etype_test_permutations()
+ res = []
+ idx = 0
+ for e in cls.etype_test_permutations:
+ r = (e['name'], idx)
+ idx += 1
+ res.append(r)
+ return res
+
+ def etype_test_permutation_by_idx(self, idx):
+ e = self.etype_test_permutations[idx]
+ return (e['name'], e['etypes'])
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+
+ cls.host = samba.tests.env_get_var_value('SERVER')
+ cls.dc_host = samba.tests.env_get_var_value('DC_SERVER')
+
+ # A dictionary containing credentials that have already been
+ # obtained.
+ cls.creds_dict = {}
+
+ kdc_fast_support = samba.tests.env_get_var_value('FAST_SUPPORT',
+ allow_missing=True)
+ if kdc_fast_support is None:
+ kdc_fast_support = '0'
+ cls.kdc_fast_support = bool(int(kdc_fast_support))
+
+ tkt_sig_support = samba.tests.env_get_var_value('TKT_SIG_SUPPORT',
+ allow_missing=True)
+ if tkt_sig_support is None:
+ tkt_sig_support = '0'
+ cls.tkt_sig_support = bool(int(tkt_sig_support))
+
+ expect_pac = samba.tests.env_get_var_value('EXPECT_PAC',
+ allow_missing=True)
+ if expect_pac is None:
+ expect_pac = '1'
+ cls.expect_pac = bool(int(expect_pac))
+
def setUp(self):
- super(RawKerberosTest, self).setUp()
+ super().setUp()
self.do_asn1_print = False
self.do_hexdump = False
- self.host = samba.tests.env_get_var_value('SERVER')
+ strict_checking = samba.tests.env_get_var_value('STRICT_CHECKING',
+ allow_missing=True)
+ if strict_checking is None:
+ strict_checking = '1'
+ self.strict_checking = bool(int(strict_checking))
self.s = None
+ self.unspecified_kvno = object()
+
def tearDown(self):
self._disconnect("tearDown")
- super(TestCase, self).tearDown()
+ super().tearDown()
def _disconnect(self, reason):
if self.s is None:
@@ -173,59 +629,227 @@
if self.do_hexdump:
sys.stderr.write("disconnect[%s]\n" % reason)
- def _connect_tcp(self):
+ def _connect_tcp(self, host):
tcp_port = 88
try:
- self.a = socket.getaddrinfo(self.host, tcp_port, socket.AF_UNSPEC,
+ self.a = socket.getaddrinfo(host, tcp_port, socket.AF_UNSPEC,
socket.SOCK_STREAM, socket.SOL_TCP,
0)
self.s = socket.socket(self.a[0][0], self.a[0][1], self.a[0][2])
self.s.settimeout(10)
self.s.connect(self.a[0][4])
- except socket.error as e:
+ except socket.error:
self.s.close()
raise
- except IOError as e:
+ except IOError:
self.s.close()
raise
- except Exception as e:
- raise
- finally:
- pass
- def connect(self):
+ def connect(self, host):
self.assertNotConnected()
- self._connect_tcp()
+ self._connect_tcp(host)
if self.do_hexdump:
- sys.stderr.write("connected[%s]\n" % self.host)
- return
+ sys.stderr.write("connected[%s]\n" % host)
- def get_user_creds(self):
- c = Credentials()
+ def env_get_var(self, varname, prefix,
+ fallback_default=True,
+ allow_missing=False):
+ val = None
+ if prefix is not None:
+ allow_missing_prefix = allow_missing or fallback_default
+ val = samba.tests.env_get_var_value(
+ '%s_%s' % (prefix, varname),
+ allow_missing=allow_missing_prefix)
+ else:
+ fallback_default = True
+ if val is None and fallback_default:
+ val = samba.tests.env_get_var_value(varname,
+ allow_missing=allow_missing)
+ return val
+
+ def _get_krb5_creds_from_env(self, prefix,
+ default_username=None,
+ allow_missing_password=False,
+ allow_missing_keys=True,
+ require_strongest_key=False):
+ c = KerberosCredentials()
c.guess()
- domain = samba.tests.env_get_var_value('DOMAIN')
- realm = samba.tests.env_get_var_value('REALM')
- username = samba.tests.env_get_var_value('USERNAME')
- password = samba.tests.env_get_var_value('PASSWORD')
- c.set_domain(domain)
- c.set_realm(realm)
- c.set_username(username)
- c.set_password(password)
- return c
- def get_service_creds(self, allow_missing_password=False):
- c = Credentials()
- c.guess()
- domain = samba.tests.env_get_var_value('DOMAIN')
- realm = samba.tests.env_get_var_value('REALM')
- username = samba.tests.env_get_var_value('SERVICE_USERNAME')
- password = samba.tests.env_get_var_value('SERVICE_PASSWORD',
- allow_missing=allow_missing_password)
+ domain = self.env_get_var('DOMAIN', prefix)
+ realm = self.env_get_var('REALM', prefix)
+ allow_missing_username = default_username is not None
+ username = self.env_get_var('USERNAME', prefix,
+ fallback_default=False,
+ allow_missing=allow_missing_username)
+ if username is None:
+ username = default_username
+ password = self.env_get_var('PASSWORD', prefix,
+ fallback_default=False,
+ allow_missing=allow_missing_password)
c.set_domain(domain)
c.set_realm(realm)
c.set_username(username)
if password is not None:
c.set_password(password)
+ as_supported_enctypes = self.env_get_var('AS_SUPPORTED_ENCTYPES',
+ prefix, allow_missing=True)
+ if as_supported_enctypes is not None:
+ c.set_as_supported_enctypes(as_supported_enctypes)
+ tgs_supported_enctypes = self.env_get_var('TGS_SUPPORTED_ENCTYPES',
+ prefix, allow_missing=True)
+ if tgs_supported_enctypes is not None:
+ c.set_tgs_supported_enctypes(tgs_supported_enctypes)
+ ap_supported_enctypes = self.env_get_var('AP_SUPPORTED_ENCTYPES',
+ prefix, allow_missing=True)
+ if ap_supported_enctypes is not None:
+ c.set_ap_supported_enctypes(ap_supported_enctypes)
+
+ if require_strongest_key:
+ kvno_allow_missing = False
+ if password is None:
+ aes256_allow_missing = False
+ else:
+ aes256_allow_missing = True
+ else:
+ kvno_allow_missing = allow_missing_keys
+ aes256_allow_missing = allow_missing_keys
+ kvno = self.env_get_var('KVNO', prefix,
+ fallback_default=False,
+ allow_missing=kvno_allow_missing)
+ if kvno is not None:
+ c.set_kvno(kvno)
+ aes256_key = self.env_get_var('AES256_KEY_HEX', prefix,
+ fallback_default=False,
+ allow_missing=aes256_allow_missing)
+ if aes256_key is not None:
+ c.set_forced_key(kcrypto.Enctype.AES256, aes256_key)
+ aes128_key = self.env_get_var('AES128_KEY_HEX', prefix,
+ fallback_default=False,
+ allow_missing=True)
+ if aes128_key is not None:
+ c.set_forced_key(kcrypto.Enctype.AES128, aes128_key)
+ rc4_key = self.env_get_var('RC4_KEY_HEX', prefix,
+ fallback_default=False, allow_missing=True)
+ if rc4_key is not None:
+ c.set_forced_key(kcrypto.Enctype.RC4, rc4_key)
+
+ if not allow_missing_keys:
+ self.assertTrue(c.forced_keys,
+ 'Please supply %s encryption keys '
+ 'in environment' % prefix)
+
+ return c
+
+ def _get_krb5_creds(self,
+ prefix,
+ default_username=None,
+ allow_missing_password=False,
+ allow_missing_keys=True,
+ require_strongest_key=False,
+ fallback_creds_fn=None):
+ if prefix in self.creds_dict:
+ return self.creds_dict[prefix]
+
+ # We don't have the credentials already
+ creds = None
+ env_err = None
+ try:
+ # Try to obtain them from the environment
+ creds = self._get_krb5_creds_from_env(
+ prefix,
+ default_username=default_username,
+ allow_missing_password=allow_missing_password,
+ allow_missing_keys=allow_missing_keys,
+ require_strongest_key=require_strongest_key)
+ except Exception as err:
+ # An error occurred, so save it for later
+ env_err = err
+ else:
+ self.assertIsNotNone(creds)
+ # Save the obtained credentials
+ self.creds_dict[prefix] = creds
+ return creds
+
+ if fallback_creds_fn is not None:
+ try:
+ # Try to use the fallback method
+ creds = fallback_creds_fn()
+ except Exception as err:
+ print("ERROR FROM ENV: %r" % (env_err))
+ print("FALLBACK-FN: %s" % (fallback_creds_fn))
+ print("FALLBACK-ERROR: %r" % (err))
+ else:
+ self.assertIsNotNone(creds)
+ # Save the obtained credentials
+ self.creds_dict[prefix] = creds
+ return creds
+
+ # Both methods failed, so raise the exception from the
+ # environment method
+ raise env_err
+
+ def get_user_creds(self,
+ allow_missing_password=False,
+ allow_missing_keys=True):
+ c = self._get_krb5_creds(prefix=None,
+ allow_missing_password=allow_missing_password,
+ allow_missing_keys=allow_missing_keys)
+ return c
+
+ def get_service_creds(self,
+ allow_missing_password=False,
+ allow_missing_keys=True):
+ c = self._get_krb5_creds(prefix='SERVICE',
+ allow_missing_password=allow_missing_password,
+ allow_missing_keys=allow_missing_keys)
+ return c
+
+ def get_client_creds(self,
+ allow_missing_password=False,
+ allow_missing_keys=True):
+ c = self._get_krb5_creds(prefix='CLIENT',
+ allow_missing_password=allow_missing_password,
+ allow_missing_keys=allow_missing_keys)
+ return c
+
+ def get_server_creds(self,
+ allow_missing_password=False,
+ allow_missing_keys=True):
+ c = self._get_krb5_creds(prefix='SERVER',
+ allow_missing_password=allow_missing_password,
+ allow_missing_keys=allow_missing_keys)
+ return c
+
+ def get_admin_creds(self,
+ allow_missing_password=False,
+ allow_missing_keys=True):
+ c = self._get_krb5_creds(prefix='ADMIN',
+ allow_missing_password=allow_missing_password,
+ allow_missing_keys=allow_missing_keys)
+ c.set_gensec_features(c.get_gensec_features() | FEATURE_SEAL)
+ return c
+
+ def get_rodc_krbtgt_creds(self,
+ require_keys=True,
+ require_strongest_key=False):
+ if require_strongest_key:
+ self.assertTrue(require_keys)
+ c = self._get_krb5_creds(prefix='RODC_KRBTGT',
+ allow_missing_password=True,
+ allow_missing_keys=not require_keys,
+ require_strongest_key=require_strongest_key)
+ return c
+
+ def get_krbtgt_creds(self,
+ require_keys=True,
+ require_strongest_key=False):
+ if require_strongest_key:
+ self.assertTrue(require_keys)
+ c = self._get_krb5_creds(prefix='KRBTGT',
+ default_username='krbtgt',
+ allow_missing_password=True,
+ allow_missing_keys=not require_keys,
+ require_strongest_key=require_strongest_key)
return c
def get_anon_creds(self):
@@ -246,21 +870,34 @@
if hexdump is None:
hexdump = self.do_hexdump
if hexdump:
- sys.stderr.write("%s: %d\n%s" % (name, len(blob), self.hexdump(blob)))
+ sys.stderr.write(
+ "%s: %d\n%s" % (name, len(blob), self.hexdump(blob)))
- def der_decode(self, blob, asn1Spec=None, native_encode=True, asn1_print=None, hexdump=None):
+ def der_decode(
+ self,
+ blob,
+ asn1Spec=None,
+ native_encode=True,
+ asn1_print=None,
+ hexdump=None):
if asn1Spec is not None:
class_name = type(asn1Spec).__name__.split(':')[0]
else:
class_name = ""
self.hex_dump(class_name, blob, hexdump=hexdump)
- obj,_ = pyasn1_der_decode(blob, asn1Spec=asn1Spec)
+ obj, _ = pyasn1_der_decode(blob, asn1Spec=asn1Spec)
self.asn1_dump(None, obj, asn1_print=asn1_print)
if native_encode:
obj = pyasn1_native_encode(obj)
return obj
- def der_encode(self, obj, asn1Spec=None, native_decode=True, asn1_print=None, hexdump=None):
+ def der_encode(
+ self,
+ obj,
+ asn1Spec=None,
+ native_decode=True,
+ asn1_print=None,
+ hexdump=None):
if native_decode:
obj = pyasn1_native_decode(obj, asn1Spec=asn1Spec)
class_name = type(obj).__name__.split(':')[0]
@@ -273,7 +910,8 @@
def send_pdu(self, req, asn1_print=None, hexdump=None):
try:
- k5_pdu = self.der_encode(req, native_decode=False, asn1_print=asn1_print, hexdump=False)
+ k5_pdu = self.der_encode(
+ req, native_decode=False, asn1_print=asn1_print, hexdump=False)
header = struct.pack('>I', len(k5_pdu))
req_pdu = header
req_pdu += k5_pdu
@@ -290,8 +928,6 @@
except IOError as e:
self._disconnect("send_pdu: %s" % e)
raise
- finally:
- pass
def recv_raw(self, num_recv=0xffff, hexdump=None, timeout=None):
rep_pdu = None
@@ -304,54 +940,54 @@
self._disconnect("recv_raw: EOF")
return None
self.hex_dump("recv_raw", rep_pdu, hexdump=hexdump)
- except socket.timeout as e:
+ except socket.timeout:
self.s.settimeout(10)
sys.stderr.write("recv_raw: TIMEOUT\n")
- pass
except socket.error as e:
self._disconnect("recv_raw: %s" % e)
raise
except IOError as e:
self._disconnect("recv_raw: %s" % e)
raise
- finally:
- pass
return rep_pdu
def recv_pdu_raw(self, asn1_print=None, hexdump=None, timeout=None):
rep_pdu = None
rep = None
- try:
- raw_pdu = self.recv_raw(num_recv=4, hexdump=hexdump, timeout=timeout)
- if raw_pdu is None:
- return (None, None)
- header = struct.unpack(">I", raw_pdu[0:4])
- k5_len = header[0]
- if k5_len == 0:
- return (None, "")
- missing = k5_len
- rep_pdu = b''
- while missing > 0:
- raw_pdu = self.recv_raw(num_recv=missing, hexdump=hexdump, timeout=timeout)
- self.assertGreaterEqual(len(raw_pdu), 1)
- rep_pdu += raw_pdu
- missing = k5_len - len(rep_pdu)
- k5_raw = self.der_decode(rep_pdu, asn1Spec=None, native_encode=False,
- asn1_print=False, hexdump=False)
- pvno=k5_raw['field-0']
- self.assertEqual(pvno, 5)
- msg_type=k5_raw['field-1']
- self.assertIn(msg_type, [11,13,30])
- if msg_type == 11:
- asn1Spec=krb5_asn1.AS_REP()
- elif msg_type == 13:
- asn1Spec=krb5_asn1.TGS_REP()
- elif msg_type == 30:
- asn1Spec=krb5_asn1.KRB_ERROR()
- rep = self.der_decode(rep_pdu, asn1Spec=asn1Spec,
- asn1_print=asn1_print, hexdump=False)
- finally:
- pass
+ raw_pdu = self.recv_raw(
+ num_recv=4, hexdump=hexdump, timeout=timeout)
+ if raw_pdu is None:
+ return (None, None)
+ header = struct.unpack(">I", raw_pdu[0:4])
+ k5_len = header[0]
+ if k5_len == 0:
+ return (None, "")
+ missing = k5_len
+ rep_pdu = b''
+ while missing > 0:
+ raw_pdu = self.recv_raw(
+ num_recv=missing, hexdump=hexdump, timeout=timeout)
+ self.assertGreaterEqual(len(raw_pdu), 1)
+ rep_pdu += raw_pdu
+ missing = k5_len - len(rep_pdu)
+ k5_raw = self.der_decode(
+ rep_pdu,
+ asn1Spec=None,
+ native_encode=False,
+ asn1_print=False,
+ hexdump=False)
+ pvno = k5_raw['field-0']
+ self.assertEqual(pvno, 5)
+ msg_type = k5_raw['field-1']
+ self.assertIn(msg_type, [KRB_AS_REP, KRB_TGS_REP, KRB_ERROR])
+ if msg_type == KRB_AS_REP:
+ asn1Spec = krb5_asn1.AS_REP()
+ elif msg_type == KRB_TGS_REP:
+ asn1Spec = krb5_asn1.TGS_REP()
+ elif msg_type == KRB_ERROR:
+ asn1Spec = krb5_asn1.KRB_ERROR()
+ rep = self.der_decode(rep_pdu, asn1Spec=asn1Spec,
+ asn1_print=asn1_print, hexdump=False)
return (rep, rep_pdu)
def recv_pdu(self, asn1_print=None, hexdump=None, timeout=None):
@@ -362,17 +998,23 @@
def assertIsConnected(self):
self.assertIsNotNone(self.s, msg="Not connected")
- return
def assertNotConnected(self):
self.assertIsNone(self.s, msg="Is connected")
- return
- def send_recv_transaction(self, req, asn1_print=None, hexdump=None, timeout=None):
- self.connect()
+ def send_recv_transaction(
+ self,
+ req,
+ asn1_print=None,
+ hexdump=None,
+ timeout=None,
+ to_rodc=False):
+ host = self.host if to_rodc else self.dc_host
+ self.connect(host)
try:
self.send_pdu(req, asn1_print=asn1_print, hexdump=hexdump)
- rep = self.recv_pdu(asn1_print=asn1_print, hexdump=hexdump, timeout=timeout)
+ rep = self.recv_pdu(
+ asn1_print=asn1_print, hexdump=hexdump, timeout=timeout)
except Exception:
self._disconnect("transaction failed")
raise
@@ -381,20 +1023,104 @@
def assertNoValue(self, value):
self.assertTrue(value.isNoValue)
- return
def assertHasValue(self, value):
self.assertIsNotNone(value)
- return
+
+ def getElementValue(self, obj, elem):
+ return obj.get(elem)
+
+ def assertElementMissing(self, obj, elem):
+ v = self.getElementValue(obj, elem)
+ self.assertIsNone(v)
+
+ def assertElementPresent(self, obj, elem, expect_empty=False):
+ v = self.getElementValue(obj, elem)
+ self.assertIsNotNone(v)
+ if self.strict_checking:
+ if isinstance(v, collections.abc.Container):
+ if expect_empty:
+ self.assertEqual(0, len(v))
+ else:
+ self.assertNotEqual(0, len(v))
+
+ def assertElementEqual(self, obj, elem, value):
+ v = self.getElementValue(obj, elem)
+ self.assertIsNotNone(v)
+ self.assertEqual(v, value)
+
+ def assertElementEqualUTF8(self, obj, elem, value):
+ v = self.getElementValue(obj, elem)
+ self.assertIsNotNone(v)
+ self.assertEqual(v, bytes(value, 'utf8'))
def assertPrincipalEqual(self, princ1, princ2):
self.assertEqual(princ1['name-type'], princ2['name-type'])
- self.assertEqual(len(princ1['name-string']), len(princ2['name-string']),
- msg="princ1=%s != princ2=%s" % (princ1, princ2))
+ self.assertEqual(
+ len(princ1['name-string']),
+ len(princ2['name-string']),
+ msg="princ1=%s != princ2=%s" % (princ1, princ2))
for idx in range(len(princ1['name-string'])):
- self.assertEqual(princ1['name-string'][idx], princ2['name-string'][idx],
- msg="princ1=%s != princ2=%s" % (princ1, princ2))
- return
+ self.assertEqual(
+ princ1['name-string'][idx],
+ princ2['name-string'][idx],
+ msg="princ1=%s != princ2=%s" % (princ1, princ2))
+
+ def assertElementEqualPrincipal(self, obj, elem, value):
+ v = self.getElementValue(obj, elem)
+ self.assertIsNotNone(v)
+ v = pyasn1_native_decode(v, asn1Spec=krb5_asn1.PrincipalName())
+ self.assertPrincipalEqual(v, value)
+
+ def assertElementKVNO(self, obj, elem, value):
+ v = self.getElementValue(obj, elem)
+ if value == "autodetect":
+ value = v
+ if value is not None:
+ self.assertIsNotNone(v)
+ # The value on the wire should never be 0
+ self.assertNotEqual(v, 0)
+ # unspecified_kvno means we don't know the kvno,
+ # but want to enforce its presence
+ if value is not self.unspecified_kvno:
+ value = int(value)
+ self.assertNotEqual(value, 0)
+ self.assertEqual(v, value)
+ else:
+ self.assertIsNone(v)
+
+ def assertElementFlags(self, obj, elem, expected, unexpected):
+ v = self.getElementValue(obj, elem)
+ self.assertIsNotNone(v)
+ if expected is not None:
+ self.assertIsInstance(expected, krb5_asn1.TicketFlags)
+ for i, flag in enumerate(expected):
+ if flag == 1:
+ self.assertEqual('1', v[i],
+ f"'{expected.namedValues[i]}' "
+ f"expected in {v}")
+ if unexpected is not None:
+ self.assertIsInstance(unexpected, krb5_asn1.TicketFlags)
+ for i, flag in enumerate(unexpected):
+ if flag == 1:
+ self.assertEqual('0', v[i],
+ f"'{unexpected.namedValues[i]}' "
+ f"unexpected in {v}")
+
+ def assertSequenceElementsEqual(self, expected, got, *,
+ require_strict=None,
+ require_ordered=True):
+ if self.strict_checking and require_ordered:
+ self.assertEqual(expected, got)
+ else:
+ fail_msg = f'expected: {expected} got: {got}'
+
+ if not self.strict_checking and require_strict is not None:
+ fail_msg += f' (ignoring: {require_strict})'
+ expected = (x for x in expected if x not in require_strict)
+ got = (x for x in got if x not in require_strict)
+
+ self.assertCountEqual(expected, got, fail_msg)
def get_KerberosTimeWithUsec(self, epoch=None, offset=None):
if epoch is None:
@@ -408,29 +1134,91 @@
(s, _) = self.get_KerberosTimeWithUsec(epoch=epoch, offset=offset)
return s
+ def get_EpochFromKerberosTime(self, kerberos_time):
+ if isinstance(kerberos_time, bytes):
+ kerberos_time = kerberos_time.decode()
+
+ epoch = datetime.datetime.strptime(kerberos_time,
+ '%Y%m%d%H%M%SZ')
+ epoch = epoch.replace(tzinfo=datetime.timezone.utc)
+ epoch = int(epoch.timestamp())
+
+ return epoch
+
+ def get_Nonce(self):
+ nonce_min = 0x7f000000
+ nonce_max = 0x7fffffff
+ v = random.randint(nonce_min, nonce_max)
+ return v
+
+ def get_pa_dict(self, pa_data):
+ pa_dict = {}
+
+ if pa_data is not None:
+ for pa in pa_data:
+ pa_type = pa['padata-type']
+ if pa_type in pa_dict:
+ raise RuntimeError(f'Duplicate type {pa_type}')
+ pa_dict[pa_type] = pa['padata-value']
+
+ return pa_dict
+
def SessionKey_create(self, etype, contents, kvno=None):
key = kcrypto.Key(etype, contents)
- return Krb5EncryptionKey(key, kvno)
+ return RodcPacEncryptionKey(key, kvno)
def PasswordKey_create(self, etype=None, pwd=None, salt=None, kvno=None):
+ self.assertIsNotNone(pwd)
+ self.assertIsNotNone(salt)
key = kcrypto.string_to_key(etype, pwd, salt)
- return Krb5EncryptionKey(key, kvno)
+ return RodcPacEncryptionKey(key, kvno)
def PasswordKey_from_etype_info2(self, creds, etype_info2, kvno=None):
e = etype_info2['etype']
- salt = None
- try:
- salt = etype_info2['salt']
- except:
- pass
+
+ salt = etype_info2.get('salt')
if e == kcrypto.Enctype.RC4:
- self.assertIsNone(salt)
nthash = creds.get_nt_hash()
return self.SessionKey_create(etype=e, contents=nthash, kvno=kvno)
password = creds.get_password()
- return self.PasswordKey_create(etype=e, pwd=password, salt=salt, kvno=kvno)
+ return self.PasswordKey_create(
+ etype=e, pwd=password, salt=salt, kvno=kvno)
+
+ def TicketDecryptionKey_from_creds(self, creds, etype=None):
+
+ if etype is None:
+ etypes = creds.get_tgs_krb5_etypes()
+ if etypes:
+ etype = etypes[0]
+ else:
+ etype = kcrypto.Enctype.RC4
+
+ forced_key = creds.get_forced_key(etype)
+ if forced_key is not None:
+ return forced_key
+
+ kvno = creds.get_kvno()
+
+ fail_msg = ("%s has no fixed key for etype[%s] kvno[%s] "
+ "nor a password specified, " % (
+ creds.get_username(), etype, kvno))
+
+ if etype == kcrypto.Enctype.RC4:
+ nthash = creds.get_nt_hash()
+ self.assertIsNotNone(nthash, msg=fail_msg)
+ return self.SessionKey_create(etype=etype,
+ contents=nthash,
+ kvno=kvno)
+
+ password = creds.get_password()
+ self.assertIsNotNone(password, msg=fail_msg)
+ salt = creds.get_salt()
+ return self.PasswordKey_create(etype=etype,
+ pwd=password,
+ salt=salt,
+ kvno=kvno)
def RandomKey(self, etype):
e = kcrypto._get_enctype_profile(etype)
@@ -444,7 +1232,7 @@
def EncryptedData_create(self, key, usage, plaintext):
# EncryptedData ::= SEQUENCE {
# etype [0] Int32 -- EncryptionType --,
- # kvno [1] UInt32 OPTIONAL,
+ # kvno [1] Int32 OPTIONAL,
# cipher [2] OCTET STRING -- ciphertext
# }
ciphertext = key.encrypt(usage, plaintext)
@@ -453,14 +1241,14 @@
'cipher': ciphertext
}
if key.kvno is not None:
- EncryptedData_obj['kvno'] = key.kvno
+ EncryptedData_obj['kvno'] = key.kvno
return EncryptedData_obj
def Checksum_create(self, key, usage, plaintext, ctype=None):
- #Checksum ::= SEQUENCE {
+ # Checksum ::= SEQUENCE {
# cksumtype [0] Int32,
# checksum [1] OCTET STRING
- #}
+ # }
if ctype is None:
ctype = key.ctype
checksum = key.make_checksum(usage, plaintext, ctype=ctype)
@@ -470,7 +1258,8 @@
}
return Checksum_obj
- def PrincipalName_create(self, name_type, names):
+ @classmethod
+ def PrincipalName_create(cls, name_type, names):
# PrincipalName ::= SEQUENCE {
# name-type [0] Int32,
# name-string [1] SEQUENCE OF KerberosString
@@ -481,6 +1270,17 @@
}
return PrincipalName_obj
+ def AuthorizationData_create(self, ad_type, ad_data):
+ # AuthorizationData ::= SEQUENCE {
+ # ad-type [0] Int32,
+ # ad-data [1] OCTET STRING
+ # }
+ AUTH_DATA_obj = {
+ 'ad-type': ad_type,
+ 'ad-data': ad_data
+ }
+ return AUTH_DATA_obj
+
def PA_DATA_create(self, padata_type, padata_value):
# PA-DATA ::= SEQUENCE {
# -- NOTE: first tag is [1], not [0]
@@ -494,16 +1294,100 @@
return PA_DATA_obj
def PA_ENC_TS_ENC_create(self, ts, usec):
- #PA-ENC-TS-ENC ::= SEQUENCE {
+ # PA-ENC-TS-ENC ::= SEQUENCE {
# patimestamp[0] KerberosTime, -- client's time
# pausec[1] krb5int32 OPTIONAL
- #}
+ # }
PA_ENC_TS_ENC_obj = {
'patimestamp': ts,
'pausec': usec,
}
return PA_ENC_TS_ENC_obj
+ def PA_PAC_OPTIONS_create(self, options):
+ # PA-PAC-OPTIONS ::= SEQUENCE {
+ # options [0] PACOptionFlags
+ # }
+ PA_PAC_OPTIONS_obj = {
+ 'options': options
+ }
+ return PA_PAC_OPTIONS_obj
+
+ def KRB_FAST_ARMOR_create(self, armor_type, armor_value):
+ # KrbFastArmor ::= SEQUENCE {
+ # armor-type [0] Int32,
+ # armor-value [1] OCTET STRING,
+ # ...
+ # }
+ KRB_FAST_ARMOR_obj = {
+ 'armor-type': armor_type,
+ 'armor-value': armor_value
+ }
+ return KRB_FAST_ARMOR_obj
+
+ def KRB_FAST_REQ_create(self, fast_options, padata, req_body):
+ # KrbFastReq ::= SEQUENCE {
+ # fast-options [0] FastOptions,
+ # padata [1] SEQUENCE OF PA-DATA,
+ # req-body [2] KDC-REQ-BODY,
+ # ...
+ # }
+ KRB_FAST_REQ_obj = {
+ 'fast-options': fast_options,
+ 'padata': padata,
+ 'req-body': req_body
+ }
+ return KRB_FAST_REQ_obj
+
+ def KRB_FAST_ARMORED_REQ_create(self, armor, req_checksum, enc_fast_req):
+ # KrbFastArmoredReq ::= SEQUENCE {
+ # armor [0] KrbFastArmor OPTIONAL,
+ # req-checksum [1] Checksum,
+ # enc-fast-req [2] EncryptedData -- KrbFastReq --
+ # }
+ KRB_FAST_ARMORED_REQ_obj = {
+ 'req-checksum': req_checksum,
+ 'enc-fast-req': enc_fast_req
+ }
+ if armor is not None:
+ KRB_FAST_ARMORED_REQ_obj['armor'] = armor
+ return KRB_FAST_ARMORED_REQ_obj
+
+ def PA_FX_FAST_REQUEST_create(self, armored_data):
+ # PA-FX-FAST-REQUEST ::= CHOICE {
+ # armored-data [0] KrbFastArmoredReq,
+ # ...
+ # }
+ PA_FX_FAST_REQUEST_obj = {
+ 'armored-data': armored_data
+ }
+ return PA_FX_FAST_REQUEST_obj
+
+ def KERB_PA_PAC_REQUEST_create(self, include_pac, pa_data_create=True):
+ # KERB-PA-PAC-REQUEST ::= SEQUENCE {
+ # include-pac[0] BOOLEAN --If TRUE, and no pac present,
+ # -- include PAC.
+ # --If FALSE, and PAC present,
+ # -- remove PAC.
+ # }
+ KERB_PA_PAC_REQUEST_obj = {
+ 'include-pac': include_pac,
+ }
+ if not pa_data_create:
+ return KERB_PA_PAC_REQUEST_obj
+ pa_pac = self.der_encode(KERB_PA_PAC_REQUEST_obj,
+ asn1Spec=krb5_asn1.KERB_PA_PAC_REQUEST())
+ pa_data = self.PA_DATA_create(PADATA_PAC_REQUEST, pa_pac)
+ return pa_data
+
+ def get_pa_pac_options(self, options):
+ pac_options = self.PA_PAC_OPTIONS_create(options)
+ pac_options = self.der_encode(pac_options,
+ asn1Spec=krb5_asn1.PA_PAC_OPTIONS())
+ pac_options = self.PA_DATA_create(PADATA_PAC_OPTIONS, pac_options)
+
+ return pac_options
+
def KDC_REQ_BODY_create(self,
kdc_options,
cname,
@@ -515,12 +1399,13 @@
nonce,
etypes,
addresses,
+ additional_tickets,
EncAuthorizationData,
EncAuthorizationData_key,
- additional_tickets,
+ EncAuthorizationData_usage,
asn1_print=None,
hexdump=None):
- #KDC-REQ-BODY ::= SEQUENCE {
+ # KDC-REQ-BODY ::= SEQUENCE {
# kdc-options [0] KDCOptions,
# cname [1] PrincipalName OPTIONAL
# -- Used only in AS-REQ --,
@@ -532,20 +1417,24 @@
# till [5] KerberosTime,
# rtime [6] KerberosTime OPTIONAL,
# nonce [7] UInt32,
- # etype [8] SEQUENCE OF Int32 -- EncryptionType
+ # etype [8] SEQUENCE OF Int32
+ # -- EncryptionType
# -- in preference order --,
# addresses [9] HostAddresses OPTIONAL,
# enc-authorization-data [10] EncryptedData OPTIONAL
# -- AuthorizationData --,
# additional-tickets [11] SEQUENCE OF Ticket OPTIONAL
# -- NOTE: not empty
- #}
+ # }
if EncAuthorizationData is not None:
- enc_ad_plain = self.der_encode(EncAuthorizationData,
- asn1Spec=krb5_asn1.AuthorizationData(),
- asn1_print=asn1_print,
- hexdump=hexdump)
- enc_ad = self.EncryptedData_create(EncAuthorizationData_key, enc_ad_plain)
+ enc_ad_plain = self.der_encode(
+ EncAuthorizationData,
+ asn1Spec=krb5_asn1.AuthorizationData(),
+ asn1_print=asn1_print,
+ hexdump=hexdump)
+ enc_ad = self.EncryptedData_create(EncAuthorizationData_key,
+ EncAuthorizationData_usage,
+ enc_ad_plain)
else:
enc_ad = None
KDC_REQ_BODY_obj = {
@@ -574,87 +1463,59 @@
def KDC_REQ_create(self,
msg_type,
padata,
- kdc_options,
- cname,
- realm,
- sname,
- from_time,
- till_time,
- renew_time,
- nonce,
- etypes,
- addresses,
- EncAuthorizationData,
- EncAuthorizationData_key,
- additional_tickets,
+ req_body,
asn1Spec=None,
asn1_print=None,
hexdump=None):
- #KDC-REQ ::= SEQUENCE {
+ # KDC-REQ ::= SEQUENCE {
# -- NOTE: first tag is [1], not [0]
# pvno [1] INTEGER (5) ,
# msg-type [2] INTEGER (10 -- AS -- | 12 -- TGS --),
# padata [3] SEQUENCE OF PA-DATA OPTIONAL
# -- NOTE: not empty --,
# req-body [4] KDC-REQ-BODY
- #}
+ # }
#
- KDC_REQ_BODY_obj = self.KDC_REQ_BODY_create(kdc_options,
- cname,
- realm,
- sname,
- from_time,
- till_time,
- renew_time,
- nonce,
- etypes,
- addresses,
- EncAuthorizationData,
- EncAuthorizationData_key,
- additional_tickets,
- asn1_print=asn1_print,
- hexdump=hexdump)
KDC_REQ_obj = {
'pvno': 5,
'msg-type': msg_type,
- 'req-body': KDC_REQ_BODY_obj,
+ 'req-body': req_body,
}
if padata is not None:
KDC_REQ_obj['padata'] = padata
if asn1Spec is not None:
- KDC_REQ_decoded = pyasn1_native_decode(KDC_REQ_obj, asn1Spec=asn1Spec)
+ KDC_REQ_decoded = pyasn1_native_decode(
+ KDC_REQ_obj, asn1Spec=asn1Spec)
else:
KDC_REQ_decoded = None
return KDC_REQ_obj, KDC_REQ_decoded
def AS_REQ_create(self,
- padata, # optional
- kdc_options, # required
- cname, # optional
- realm, # required
- sname, # optional
- from_time, # optional
- till_time, # required
- renew_time, # optional
- nonce, # required
- etypes, # required
- addresses, # optional
- EncAuthorizationData,
- EncAuthorizationData_key,
+ padata, # optional
+ kdc_options, # required
+ cname, # optional
+ realm, # required
+ sname, # optional
+ from_time, # optional
+ till_time, # required
+ renew_time, # optional
+ nonce, # required
+ etypes, # required
+ addresses, # optional
additional_tickets,
native_decoded_only=True,
asn1_print=None,
hexdump=None):
- #KDC-REQ ::= SEQUENCE {
+ # KDC-REQ ::= SEQUENCE {
# -- NOTE: first tag is [1], not [0]
# pvno [1] INTEGER (5) ,
# msg-type [2] INTEGER (10 -- AS -- | 12 -- TGS --),
# padata [3] SEQUENCE OF PA-DATA OPTIONAL
# -- NOTE: not empty --,
# req-body [4] KDC-REQ-BODY
- #}
+ # }
#
- #KDC-REQ-BODY ::= SEQUENCE {
+ # KDC-REQ-BODY ::= SEQUENCE {
# kdc-options [0] KDCOptions,
# cname [1] PrincipalName OPTIONAL
# -- Used only in AS-REQ --,
@@ -666,32 +1527,39 @@
# till [5] KerberosTime,
# rtime [6] KerberosTime OPTIONAL,
# nonce [7] UInt32,
- # etype [8] SEQUENCE OF Int32 -- EncryptionType
+ # etype [8] SEQUENCE OF Int32
+ # -- EncryptionType
# -- in preference order --,
# addresses [9] HostAddresses OPTIONAL,
# enc-authorization-data [10] EncryptedData OPTIONAL
# -- AuthorizationData --,
# additional-tickets [11] SEQUENCE OF Ticket OPTIONAL
# -- NOTE: not empty
- #}
- obj,decoded = self.KDC_REQ_create(msg_type=10,
- padata=padata,
- kdc_options=kdc_options,
- cname=cname,
- realm=realm,
- sname=sname,
- from_time=from_time,
- till_time=till_time,
- renew_time=renew_time,
- nonce=nonce,
- etypes=etypes,
- addresses=addresses,
- EncAuthorizationData=EncAuthorizationData,
- EncAuthorizationData_key=EncAuthorizationData_key,
- additional_tickets=additional_tickets,
- asn1Spec=krb5_asn1.AS_REQ(),
- asn1_print=asn1_print,
- hexdump=hexdump)
+ # }
+ KDC_REQ_BODY_obj = self.KDC_REQ_BODY_create(
+ kdc_options,
+ cname,
+ realm,
+ sname,
+ from_time,
+ till_time,
+ renew_time,
+ nonce,
+ etypes,
+ addresses,
+ additional_tickets,
+ EncAuthorizationData=None,
+ EncAuthorizationData_key=None,
+ EncAuthorizationData_usage=None,
+ asn1_print=asn1_print,
+ hexdump=hexdump)
+ obj, decoded = self.KDC_REQ_create(
+ msg_type=KRB_AS_REQ,
+ padata=padata,
+ req_body=KDC_REQ_BODY_obj,
+ asn1Spec=krb5_asn1.AS_REQ(),
+ asn1_print=asn1_print,
+ hexdump=hexdump)
if native_decoded_only:
return decoded
return decoded, obj
@@ -703,18 +1571,19 @@
# ap-options [2] APOptions,
# ticket [3] Ticket,
# authenticator [4] EncryptedData -- Authenticator
- #}
+ # }
AP_REQ_obj = {
'pvno': 5,
- 'msg-type': 14,
+ 'msg-type': KRB_AP_REQ,
'ap-options': ap_options,
'ticket': ticket,
'authenticator': authenticator,
}
return AP_REQ_obj
- def Authenticator_create(self, crealm, cname, cksum, cusec, ctime, subkey, seq_number,
- authorization_data):
+ def Authenticator_create(
+ self, crealm, cname, cksum, cusec, ctime, subkey, seq_number,
+ authorization_data):
# -- Unencrypted authenticator
# Authenticator ::= [APPLICATION 2] SEQUENCE {
# authenticator-vno [0] INTEGER (5),
@@ -726,7 +1595,7 @@
# subkey [6] EncryptionKey OPTIONAL,
# seq-number [7] UInt32 OPTIONAL,
# authorization-data [8] AuthorizationData OPTIONAL
- #}
+ # }
Authenticator_obj = {
'authenticator-vno': 5,
'crealm': crealm,
@@ -745,20 +1614,20 @@
return Authenticator_obj
def TGS_REQ_create(self,
- padata, # optional
+ padata, # optional
cusec,
ctime,
ticket,
- kdc_options, # required
- cname, # optional
- realm, # required
- sname, # optional
- from_time, # optional
- till_time, # required
- renew_time, # optional
- nonce, # required
- etypes, # required
- addresses, # optional
+ kdc_options, # required
+ cname, # optional
+ realm, # required
+ sname, # optional
+ from_time, # optional
+ till_time, # required
+ renew_time, # optional
+ nonce, # required
+ etypes, # required
+ addresses, # optional
EncAuthorizationData,
EncAuthorizationData_key,
additional_tickets,
@@ -768,16 +1637,16 @@
native_decoded_only=True,
asn1_print=None,
hexdump=None):
- #KDC-REQ ::= SEQUENCE {
+ # KDC-REQ ::= SEQUENCE {
# -- NOTE: first tag is [1], not [0]
# pvno [1] INTEGER (5) ,
# msg-type [2] INTEGER (10 -- AS -- | 12 -- TGS --),
# padata [3] SEQUENCE OF PA-DATA OPTIONAL
# -- NOTE: not empty --,
# req-body [4] KDC-REQ-BODY
- #}
+ # }
#
- #KDC-REQ-BODY ::= SEQUENCE {
+ # KDC-REQ-BODY ::= SEQUENCE {
# kdc-options [0] KDCOptions,
# cname [1] PrincipalName OPTIONAL
# -- Used only in AS-REQ --,
@@ -789,50 +1658,66 @@
# till [5] KerberosTime,
# rtime [6] KerberosTime OPTIONAL,
# nonce [7] UInt32,
- # etype [8] SEQUENCE OF Int32 -- EncryptionType
+ # etype [8] SEQUENCE OF Int32
+ # -- EncryptionType
# -- in preference order --,
# addresses [9] HostAddresses OPTIONAL,
# enc-authorization-data [10] EncryptedData OPTIONAL
# -- AuthorizationData --,
# additional-tickets [11] SEQUENCE OF Ticket OPTIONAL
# -- NOTE: not empty
- #}
+ # }
- req_body = self.KDC_REQ_BODY_create(kdc_options=kdc_options,
- cname=None,
- realm=realm,
- sname=sname,
- from_time=from_time,
- till_time=till_time,
- renew_time=renew_time,
- nonce=nonce,
- etypes=etypes,
- addresses=addresses,
- EncAuthorizationData=EncAuthorizationData,
- EncAuthorizationData_key=EncAuthorizationData_key,
- additional_tickets=additional_tickets)
- req_body = self.der_encode(req_body, asn1Spec=krb5_asn1.KDC_REQ_BODY(),
- asn1_print=asn1_print, hexdump=hexdump)
+ if authenticator_subkey is not None:
+ EncAuthorizationData_usage = KU_TGS_REQ_AUTH_DAT_SUBKEY
+ else:
+ EncAuthorizationData_usage = KU_TGS_REQ_AUTH_DAT_SESSION
+
+ req_body = self.KDC_REQ_BODY_create(
+ kdc_options=kdc_options,
+ cname=None,
+ realm=realm,
+ sname=sname,
+ from_time=from_time,
+ till_time=till_time,
+ renew_time=renew_time,
+ nonce=nonce,
+ etypes=etypes,
+ addresses=addresses,
+ additional_tickets=additional_tickets,
+ EncAuthorizationData=EncAuthorizationData,
+ EncAuthorizationData_key=EncAuthorizationData_key,
+ EncAuthorizationData_usage=EncAuthorizationData_usage)
+ req_body_blob = self.der_encode(req_body,
+ asn1Spec=krb5_asn1.KDC_REQ_BODY(),
+ asn1_print=asn1_print, hexdump=hexdump)
- req_body_checksum = self.Checksum_create(ticket_session_key, 6, req_body,
+ req_body_checksum = self.Checksum_create(ticket_session_key,
+ KU_TGS_REQ_AUTH_CKSUM,
+ req_body_blob,
ctype=body_checksum_type)
subkey_obj = None
if authenticator_subkey is not None:
subkey_obj = authenticator_subkey.export_obj()
seq_number = random.randint(0, 0xfffffffe)
- authenticator = self.Authenticator_create(crealm=realm,
- cname=cname,
- cksum=req_body_checksum,
- cusec=cusec,
- ctime=ctime,
- subkey=subkey_obj,
- seq_number=seq_number,
- authorization_data=None)
- authenticator = self.der_encode(authenticator, asn1Spec=krb5_asn1.Authenticator(),
- asn1_print=asn1_print, hexdump=hexdump)
+ authenticator = self.Authenticator_create(
+ crealm=realm,
+ cname=cname,
+ cksum=req_body_checksum,
+ cusec=cusec,
+ ctime=ctime,
+ subkey=subkey_obj,
+ seq_number=seq_number,
+ authorization_data=None)
+ authenticator = self.der_encode(
+ authenticator,
+ asn1Spec=krb5_asn1.Authenticator(),
+ asn1_print=asn1_print,
+ hexdump=hexdump)
- authenticator = self.EncryptedData_create(ticket_session_key, 7, authenticator)
+ authenticator = self.EncryptedData_create(
+ ticket_session_key, KU_TGS_REQ_AUTH, authenticator)
ap_options = krb5_asn1.APOptions('0')
ap_req = self.AP_REQ_create(ap_options=str(ap_options),
@@ -840,30 +1725,19 @@
authenticator=authenticator)
ap_req = self.der_encode(ap_req, asn1Spec=krb5_asn1.AP_REQ(),
asn1_print=asn1_print, hexdump=hexdump)
- pa_tgs_req = self.PA_DATA_create(1, ap_req)
+ pa_tgs_req = self.PA_DATA_create(PADATA_KDC_REQ, ap_req)
if padata is not None:
padata.append(pa_tgs_req)
else:
padata = [pa_tgs_req]
- obj,decoded = self.KDC_REQ_create(msg_type=12,
- padata=padata,
- kdc_options=kdc_options,
- cname=None,
- realm=realm,
- sname=sname,
- from_time=from_time,
- till_time=till_time,
- renew_time=renew_time,
- nonce=nonce,
- etypes=etypes,
- addresses=addresses,
- EncAuthorizationData=EncAuthorizationData,
- EncAuthorizationData_key=EncAuthorizationData_key,
- additional_tickets=additional_tickets,
- asn1Spec=krb5_asn1.TGS_REQ(),
- asn1_print=asn1_print,
- hexdump=hexdump)
+ obj, decoded = self.KDC_REQ_create(
+ msg_type=KRB_TGS_REQ,
+ padata=padata,
+ req_body=req_body,
+ asn1Spec=krb5_asn1.TGS_REQ(),
+ asn1_print=asn1_print,
+ hexdump=hexdump)
if native_decoded_only:
return decoded
return decoded, obj
@@ -880,7 +1754,10 @@
cksum_data += n.encode()
cksum_data += realm.encode()
cksum_data += "Kerberos".encode()
- cksum = self.Checksum_create(tgt_session_key, 17, cksum_data, ctype)
+ cksum = self.Checksum_create(tgt_session_key,
+ KU_NON_KERB_CKSUM_SALT,
+ cksum_data,
+ ctype)
PA_S4U2Self_obj = {
'name': name,
@@ -888,5 +1765,2023 @@
'cksum': cksum,
'auth': "Kerberos",
}
- pa_s4u2self = self.der_encode(PA_S4U2Self_obj, asn1Spec=krb5_asn1.PA_S4U2Self())
- return self.PA_DATA_create(129, pa_s4u2self)
+ pa_s4u2self = self.der_encode(
+ PA_S4U2Self_obj, asn1Spec=krb5_asn1.PA_S4U2Self())
+ return self.PA_DATA_create(PADATA_FOR_USER, pa_s4u2self)
+
+ def _generic_kdc_exchange(self,
+ kdc_exchange_dict, # required
+ cname=None, # optional
+ realm=None, # required
+ sname=None, # optional
+ from_time=None, # optional
+ till_time=None, # required
+ renew_time=None, # optional
+ etypes=None, # required
+ addresses=None, # optional
+ additional_tickets=None, # optional
+ EncAuthorizationData=None, # optional
+ EncAuthorizationData_key=None, # optional
+ EncAuthorizationData_usage=None): # optional
+
+ check_error_fn = kdc_exchange_dict['check_error_fn']
+ check_rep_fn = kdc_exchange_dict['check_rep_fn']
+ generate_fast_fn = kdc_exchange_dict['generate_fast_fn']
+ generate_fast_armor_fn = kdc_exchange_dict['generate_fast_armor_fn']
+ generate_fast_padata_fn = kdc_exchange_dict['generate_fast_padata_fn']
+ generate_padata_fn = kdc_exchange_dict['generate_padata_fn']
+ callback_dict = kdc_exchange_dict['callback_dict']
+ req_msg_type = kdc_exchange_dict['req_msg_type']
+ req_asn1Spec = kdc_exchange_dict['req_asn1Spec']
+ rep_msg_type = kdc_exchange_dict['rep_msg_type']
+
+ expected_error_mode = kdc_exchange_dict['expected_error_mode']
+ kdc_options = kdc_exchange_dict['kdc_options']
+
+ pac_request = kdc_exchange_dict['pac_request']
+ pac_options = kdc_exchange_dict['pac_options']
+
+ # Parameters specific to the inner request body
+ inner_req = kdc_exchange_dict['inner_req']
+
+ # Parameters specific to the outer request body
+ outer_req = kdc_exchange_dict['outer_req']
+
+ if till_time is None:
+ till_time = self.get_KerberosTime(offset=36000)
+
+ if 'nonce' in kdc_exchange_dict:
+ nonce = kdc_exchange_dict['nonce']
+ else:
+ nonce = self.get_Nonce()
+ kdc_exchange_dict['nonce'] = nonce
+
+ req_body = self.KDC_REQ_BODY_create(
+ kdc_options=kdc_options,
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ from_time=from_time,
+ till_time=till_time,
+ renew_time=renew_time,
+ nonce=nonce,
+ etypes=etypes,
+ addresses=addresses,
+ additional_tickets=additional_tickets,
+ EncAuthorizationData=EncAuthorizationData,
+ EncAuthorizationData_key=EncAuthorizationData_key,
+ EncAuthorizationData_usage=EncAuthorizationData_usage)
+
+ inner_req_body = dict(req_body)
+ if inner_req is not None:
+ for key, value in inner_req.items():
+ if value is not None:
+ inner_req_body[key] = value
+ else:
+ del inner_req_body[key]
+ if outer_req is not None:
+ for key, value in outer_req.items():
+ if value is not None:
+ req_body[key] = value
+ else:
+ del req_body[key]
+
+ additional_padata = []
+ if pac_request is not None:
+ pa_pac_request = self.KERB_PA_PAC_REQUEST_create(pac_request)
+ additional_padata.append(pa_pac_request)
+ if pac_options is not None:
+ pa_pac_options = self.get_pa_pac_options(pac_options)
+ additional_padata.append(pa_pac_options)
+
+ if req_msg_type == KRB_AS_REQ:
+ tgs_req = None
+ tgs_req_padata = None
+ else:
+ self.assertEqual(KRB_TGS_REQ, req_msg_type)
+
+ tgs_req = self.generate_ap_req(kdc_exchange_dict,
+ callback_dict,
+ req_body,
+ armor=False)
+ tgs_req_padata = self.PA_DATA_create(PADATA_KDC_REQ, tgs_req)
+
+ if generate_fast_padata_fn is not None:
+ self.assertIsNotNone(generate_fast_fn)
+ # This can alter req_body...
+ fast_padata, req_body = generate_fast_padata_fn(kdc_exchange_dict,
+ callback_dict,
+ req_body)
+ else:
+ fast_padata = []
+
+ if generate_fast_armor_fn is not None:
+ self.assertIsNotNone(generate_fast_fn)
+ fast_ap_req = generate_fast_armor_fn(kdc_exchange_dict,
+ callback_dict,
+ req_body,
+ armor=True)
+
+ fast_armor_type = kdc_exchange_dict['fast_armor_type']
+ fast_armor = self.KRB_FAST_ARMOR_create(fast_armor_type,
+ fast_ap_req)
+ else:
+ fast_armor = None
+
+ if generate_padata_fn is not None:
+ # This can alter req_body...
+ outer_padata, req_body = generate_padata_fn(kdc_exchange_dict,
+ callback_dict,
+ req_body)
+ self.assertIsNotNone(outer_padata)
+ self.assertNotIn(PADATA_KDC_REQ,
+ [pa['padata-type'] for pa in outer_padata],
+ 'Don\'t create TGS-REQ manually')
+ else:
+ outer_padata = None
+
+ if generate_fast_fn is not None:
+ armor_key = kdc_exchange_dict['armor_key']
+ self.assertIsNotNone(armor_key)
+
+ if req_msg_type == KRB_AS_REQ:
+ checksum_blob = self.der_encode(
+ req_body,
+ asn1Spec=krb5_asn1.KDC_REQ_BODY())
+ else:
+ self.assertEqual(KRB_TGS_REQ, req_msg_type)
+ checksum_blob = tgs_req
+
+ checksum = self.Checksum_create(armor_key,
+ KU_FAST_REQ_CHKSUM,
+ checksum_blob)
+
+ fast_padata += additional_padata
+ fast = generate_fast_fn(kdc_exchange_dict,
+ callback_dict,
+ inner_req_body,
+ fast_padata,
+ fast_armor,
+ checksum)
+ else:
+ fast = None
+
+ padata = []
+
+ if tgs_req_padata is not None:
+ padata.append(tgs_req_padata)
+
+ if fast is not None:
+ padata.append(fast)
+
+ if outer_padata is not None:
+ padata += outer_padata
+
+ if fast is None:
+ padata += additional_padata
+
+ if not padata:
+ padata = None
+
+ kdc_exchange_dict['req_padata'] = padata
+ kdc_exchange_dict['fast_padata'] = fast_padata
+ kdc_exchange_dict['req_body'] = inner_req_body
+
+ req_obj, req_decoded = self.KDC_REQ_create(msg_type=req_msg_type,
+ padata=padata,
+ req_body=req_body,
+ asn1Spec=req_asn1Spec())
+
+ to_rodc = kdc_exchange_dict['to_rodc']
+
+ rep = self.send_recv_transaction(req_decoded, to_rodc=to_rodc)
+ self.assertIsNotNone(rep)
+
+ msg_type = self.getElementValue(rep, 'msg-type')
+ self.assertIsNotNone(msg_type)
+
+ expected_msg_type = None
+ if check_error_fn is not None:
+ expected_msg_type = KRB_ERROR
+ self.assertIsNone(check_rep_fn)
+ self.assertNotEqual(0, len(expected_error_mode))
+ self.assertNotIn(0, expected_error_mode)
+ if check_rep_fn is not None:
+ expected_msg_type = rep_msg_type
+ self.assertIsNone(check_error_fn)
+ self.assertEqual(0, len(expected_error_mode))
+ self.assertIsNotNone(expected_msg_type)
+ if msg_type == KRB_ERROR:
+ error_code = self.getElementValue(rep, 'error-code')
+ fail_msg = f'Got unexpected error: {error_code}'
+ else:
+ fail_msg = f'Expected to fail with error: {expected_error_mode}'
+ self.assertEqual(msg_type, expected_msg_type, fail_msg)
+
+ if msg_type == KRB_ERROR:
+ return check_error_fn(kdc_exchange_dict,
+ callback_dict,
+ rep)
+
+ return check_rep_fn(kdc_exchange_dict, callback_dict, rep)
+
+ def as_exchange_dict(self,
+ expected_crealm=None,
+ expected_cname=None,
+ expected_anon=False,
+ expected_srealm=None,
+ expected_sname=None,
+ expected_account_name=None,
+ expected_upn_name=None,
+ expected_sid=None,
+ expected_supported_etypes=None,
+ expected_flags=None,
+ unexpected_flags=None,
+ ticket_decryption_key=None,
+ expect_ticket_checksum=None,
+ generate_fast_fn=None,
+ generate_fast_armor_fn=None,
+ generate_fast_padata_fn=None,
+ fast_armor_type=FX_FAST_ARMOR_AP_REQUEST,
+ generate_padata_fn=None,
+ check_error_fn=None,
+ check_rep_fn=None,
+ check_kdc_private_fn=None,
+ callback_dict=None,
+ expected_error_mode=0,
+ expected_status=None,
+ client_as_etypes=None,
+ expected_salt=None,
+ authenticator_subkey=None,
+ preauth_key=None,
+ armor_key=None,
+ armor_tgt=None,
+ armor_subkey=None,
+ auth_data=None,
+ kdc_options='',
+ inner_req=None,
+ outer_req=None,
+ pac_request=None,
+ pac_options=None,
+ expect_edata=None,
+ expect_pac=True,
+ expect_claims=True,
+ expect_upn_dns_info_ex=None,
+ expect_pac_attrs=None,
+ expect_pac_attrs_pac_request=None,
+ expect_requester_sid=None,
+ to_rodc=False):
+ if expected_error_mode == 0:
+ expected_error_mode = ()
+ elif not isinstance(expected_error_mode, collections.abc.Container):
+ expected_error_mode = (expected_error_mode,)
+
+ kdc_exchange_dict = {
+ 'req_msg_type': KRB_AS_REQ,
+ 'req_asn1Spec': krb5_asn1.AS_REQ,
+ 'rep_msg_type': KRB_AS_REP,
+ 'rep_asn1Spec': krb5_asn1.AS_REP,
+ 'rep_encpart_asn1Spec': krb5_asn1.EncASRepPart,
+ 'expected_crealm': expected_crealm,
+ 'expected_cname': expected_cname,
+ 'expected_anon': expected_anon,
+ 'expected_srealm': expected_srealm,
+ 'expected_sname': expected_sname,
+ 'expected_account_name': expected_account_name,
+ 'expected_upn_name': expected_upn_name,
+ 'expected_sid': expected_sid,
+ 'expected_supported_etypes': expected_supported_etypes,
+ 'expected_flags': expected_flags,
+ 'unexpected_flags': unexpected_flags,
+ 'ticket_decryption_key': ticket_decryption_key,
+ 'expect_ticket_checksum': expect_ticket_checksum,
+ 'generate_fast_fn': generate_fast_fn,
+ 'generate_fast_armor_fn': generate_fast_armor_fn,
+ 'generate_fast_padata_fn': generate_fast_padata_fn,
+ 'fast_armor_type': fast_armor_type,
+ 'generate_padata_fn': generate_padata_fn,
+ 'check_error_fn': check_error_fn,
+ 'check_rep_fn': check_rep_fn,
+ 'check_kdc_private_fn': check_kdc_private_fn,
+ 'callback_dict': callback_dict,
+ 'expected_error_mode': expected_error_mode,
+ 'expected_status': expected_status,
+ 'client_as_etypes': client_as_etypes,
+ 'expected_salt': expected_salt,
+ 'authenticator_subkey': authenticator_subkey,
+ 'preauth_key': preauth_key,
+ 'armor_key': armor_key,
+ 'armor_tgt': armor_tgt,
+ 'armor_subkey': armor_subkey,
+ 'auth_data': auth_data,
+ 'kdc_options': kdc_options,
+ 'inner_req': inner_req,
+ 'outer_req': outer_req,
+ 'pac_request': pac_request,
+ 'pac_options': pac_options,
+ 'expect_edata': expect_edata,
+ 'expect_pac': expect_pac,
+ 'expect_claims': expect_claims,
+ 'expect_upn_dns_info_ex': expect_upn_dns_info_ex,
+ 'expect_pac_attrs': expect_pac_attrs,
+ 'expect_pac_attrs_pac_request': expect_pac_attrs_pac_request,
+ 'expect_requester_sid': expect_requester_sid,
+ 'to_rodc': to_rodc
+ }
+ if callback_dict is None:
+ callback_dict = {}
+
+ return kdc_exchange_dict
+
+ def tgs_exchange_dict(self,
+ expected_crealm=None,
+ expected_cname=None,
+ expected_anon=False,
+ expected_srealm=None,
+ expected_sname=None,
+ expected_account_name=None,
+ expected_upn_name=None,
+ expected_sid=None,
+ expected_supported_etypes=None,
+ expected_flags=None,
+ unexpected_flags=None,
+ ticket_decryption_key=None,
+ expect_ticket_checksum=None,
+ generate_fast_fn=None,
+ generate_fast_armor_fn=None,
+ generate_fast_padata_fn=None,
+ fast_armor_type=FX_FAST_ARMOR_AP_REQUEST,
+ generate_padata_fn=None,
+ check_error_fn=None,
+ check_rep_fn=None,
+ check_kdc_private_fn=None,
+ expected_error_mode=0,
+ expected_status=None,
+ callback_dict=None,
+ tgt=None,
+ armor_key=None,
+ armor_tgt=None,
+ armor_subkey=None,
+ authenticator_subkey=None,
+ auth_data=None,
+ body_checksum_type=None,
+ kdc_options='',
+ inner_req=None,
+ outer_req=None,
+ pac_request=None,
+ pac_options=None,
+ expect_edata=None,
+ expect_pac=True,
+ expect_claims=True,
+ expect_upn_dns_info_ex=None,
+ expect_pac_attrs=None,
+ expect_pac_attrs_pac_request=None,
+ expect_requester_sid=None,
+ expected_proxy_target=None,
+ expected_transited_services=None,
+ to_rodc=False):
+ if expected_error_mode == 0:
+ expected_error_mode = ()
+ elif not isinstance(expected_error_mode, collections.abc.Container):
+ expected_error_mode = (expected_error_mode,)
+
+ kdc_exchange_dict = {
+ 'req_msg_type': KRB_TGS_REQ,
+ 'req_asn1Spec': krb5_asn1.TGS_REQ,
+ 'rep_msg_type': KRB_TGS_REP,
+ 'rep_asn1Spec': krb5_asn1.TGS_REP,
+ 'rep_encpart_asn1Spec': krb5_asn1.EncTGSRepPart,
+ 'expected_crealm': expected_crealm,
+ 'expected_cname': expected_cname,
+ 'expected_anon': expected_anon,
+ 'expected_srealm': expected_srealm,
+ 'expected_sname': expected_sname,
+ 'expected_account_name': expected_account_name,
+ 'expected_upn_name': expected_upn_name,
+ 'expected_sid': expected_sid,
+ 'expected_supported_etypes': expected_supported_etypes,
+ 'expected_flags': expected_flags,
+ 'unexpected_flags': unexpected_flags,
+ 'ticket_decryption_key': ticket_decryption_key,
+ 'expect_ticket_checksum': expect_ticket_checksum,
+ 'generate_fast_fn': generate_fast_fn,
+ 'generate_fast_armor_fn': generate_fast_armor_fn,
+ 'generate_fast_padata_fn': generate_fast_padata_fn,
+ 'fast_armor_type': fast_armor_type,
+ 'generate_padata_fn': generate_padata_fn,
+ 'check_error_fn': check_error_fn,
+ 'check_rep_fn': check_rep_fn,
+ 'check_kdc_private_fn': check_kdc_private_fn,
+ 'callback_dict': callback_dict,
+ 'expected_error_mode': expected_error_mode,
+ 'expected_status': expected_status,
+ 'tgt': tgt,
+ 'body_checksum_type': body_checksum_type,
+ 'armor_key': armor_key,
+ 'armor_tgt': armor_tgt,
+ 'armor_subkey': armor_subkey,
+ 'auth_data': auth_data,
+ 'authenticator_subkey': authenticator_subkey,
+ 'kdc_options': kdc_options,
+ 'inner_req': inner_req,
+ 'outer_req': outer_req,
+ 'pac_request': pac_request,
+ 'pac_options': pac_options,
+ 'expect_edata': expect_edata,
+ 'expect_pac': expect_pac,
+ 'expect_claims': expect_claims,
+ 'expect_upn_dns_info_ex': expect_upn_dns_info_ex,
+ 'expect_pac_attrs': expect_pac_attrs,
+ 'expect_pac_attrs_pac_request': expect_pac_attrs_pac_request,
+ 'expect_requester_sid': expect_requester_sid,
+ 'expected_proxy_target': expected_proxy_target,
+ 'expected_transited_services': expected_transited_services,
+ 'to_rodc': to_rodc
+ }
+ if callback_dict is None:
+ callback_dict = {}
+
+ return kdc_exchange_dict
+
+ def generic_check_kdc_rep(self,
+ kdc_exchange_dict,
+ callback_dict,
+ rep):
+
+ expected_crealm = kdc_exchange_dict['expected_crealm']
+ expected_anon = kdc_exchange_dict['expected_anon']
+ expected_srealm = kdc_exchange_dict['expected_srealm']
+ expected_sname = kdc_exchange_dict['expected_sname']
+ ticket_decryption_key = kdc_exchange_dict['ticket_decryption_key']
+ check_kdc_private_fn = kdc_exchange_dict['check_kdc_private_fn']
+ rep_encpart_asn1Spec = kdc_exchange_dict['rep_encpart_asn1Spec']
+ msg_type = kdc_exchange_dict['rep_msg_type']
+ armor_key = kdc_exchange_dict['armor_key']
+
+ self.assertElementEqual(rep, 'msg-type', msg_type) # AS-REP | TGS-REP
+ padata = self.getElementValue(rep, 'padata')
+ if self.strict_checking:
+ self.assertElementEqualUTF8(rep, 'crealm', expected_crealm)
+ if expected_anon:
+ expected_cname = self.PrincipalName_create(
+ name_type=NT_WELLKNOWN,
+ names=['WELLKNOWN', 'ANONYMOUS'])
+ else:
+ expected_cname = kdc_exchange_dict['expected_cname']
+ self.assertElementEqualPrincipal(rep, 'cname', expected_cname)
+ self.assertElementPresent(rep, 'ticket')
+ ticket = self.getElementValue(rep, 'ticket')
+ ticket_encpart = None
+ ticket_cipher = None
+ self.assertIsNotNone(ticket)
+ if ticket is not None: # Never None, but gives indentation
+ self.assertElementEqual(ticket, 'tkt-vno', 5)
+ self.assertElementEqualUTF8(ticket, 'realm', expected_srealm)
+ self.assertElementEqualPrincipal(ticket, 'sname', expected_sname)
+ self.assertElementPresent(ticket, 'enc-part')
+ ticket_encpart = self.getElementValue(ticket, 'enc-part')
+ self.assertIsNotNone(ticket_encpart)
+ if ticket_encpart is not None: # Never None, but gives indentation
+ self.assertElementPresent(ticket_encpart, 'etype')
+
+ kdc_options = kdc_exchange_dict['kdc_options']
+ pos = len(tuple(krb5_asn1.KDCOptions('enc-tkt-in-skey'))) - 1
+ expect_kvno = (pos >= len(kdc_options)
+ or kdc_options[pos] != '1')
+ if expect_kvno:
+ # 'unspecified' means present, with any value != 0
+ self.assertElementKVNO(ticket_encpart, 'kvno',
+ self.unspecified_kvno)
+ else:
+ # For user-to-user, don't expect a kvno.
+ self.assertElementMissing(ticket_encpart, 'kvno')
+
+ self.assertElementPresent(ticket_encpart, 'cipher')
+ ticket_cipher = self.getElementValue(ticket_encpart, 'cipher')
+ self.assertElementPresent(rep, 'enc-part')
+ encpart = self.getElementValue(rep, 'enc-part')
+ encpart_cipher = None
+ self.assertIsNotNone(encpart)
+ if encpart is not None: # Never None, but gives indentation
+ self.assertElementPresent(encpart, 'etype')
+ self.assertElementKVNO(ticket_encpart, 'kvno', 'autodetect')
+ self.assertElementPresent(encpart, 'cipher')
+ encpart_cipher = self.getElementValue(encpart, 'cipher')
+
+ ticket_checksum = None
+
+ # Get the decryption key for the encrypted part
+ encpart_decryption_key, encpart_decryption_usage = (
+ self.get_preauth_key(kdc_exchange_dict))
+
+ if armor_key is not None:
+ pa_dict = self.get_pa_dict(padata)
+
+ if PADATA_FX_FAST in pa_dict:
+ fx_fast_data = pa_dict[PADATA_FX_FAST]
+ fast_response = self.check_fx_fast_data(kdc_exchange_dict,
+ fx_fast_data,
+ armor_key,
+ finished=True)
+
+ if 'strengthen-key' in fast_response:
+ strengthen_key = self.EncryptionKey_import(
+ fast_response['strengthen-key'])
+ encpart_decryption_key = (
+ self.generate_strengthen_reply_key(
+ strengthen_key,
+ encpart_decryption_key))
+
+ fast_finished = fast_response.get('finished')
+ if fast_finished is not None:
+ ticket_checksum = fast_finished['ticket-checksum']
+
+ self.check_rep_padata(kdc_exchange_dict,
+ callback_dict,
+ fast_response['padata'],
+ error_code=0)
+
+ ticket_private = None
+ if ticket_decryption_key is not None:
+ self.assertElementEqual(ticket_encpart, 'etype',
+ ticket_decryption_key.etype)
+ self.assertElementKVNO(ticket_encpart, 'kvno',
+ ticket_decryption_key.kvno)
+ ticket_decpart = ticket_decryption_key.decrypt(KU_TICKET,
+ ticket_cipher)
+ ticket_private = self.der_decode(
+ ticket_decpart,
+ asn1Spec=krb5_asn1.EncTicketPart())
+
+ encpart_private = None
+ self.assertIsNotNone(encpart_decryption_key)
+ if encpart_decryption_key is not None:
+ self.assertElementEqual(encpart, 'etype',
+ encpart_decryption_key.etype)
+ if self.strict_checking:
+ self.assertElementKVNO(encpart, 'kvno',
+ encpart_decryption_key.kvno)
+ rep_decpart = encpart_decryption_key.decrypt(
+ encpart_decryption_usage,
+ encpart_cipher)
+ # MIT KDC encodes both EncASRepPart and EncTGSRepPart with
+ # application tag 26
+ try:
+ encpart_private = self.der_decode(
+ rep_decpart,
+ asn1Spec=rep_encpart_asn1Spec())
+ except Exception:
+ encpart_private = self.der_decode(
+ rep_decpart,
+ asn1Spec=krb5_asn1.EncTGSRepPart())
+
+ self.assertIsNotNone(check_kdc_private_fn)
+ if check_kdc_private_fn is not None:
+ check_kdc_private_fn(kdc_exchange_dict, callback_dict,
+ rep, ticket_private, encpart_private,
+ ticket_checksum)
+
+ return rep
+
+ def check_fx_fast_data(self,
+ kdc_exchange_dict,
+ fx_fast_data,
+ armor_key,
+ finished=False,
+ expect_strengthen_key=True):
+ fx_fast_data = self.der_decode(fx_fast_data,
+ asn1Spec=krb5_asn1.PA_FX_FAST_REPLY())
+
+ enc_fast_rep = fx_fast_data['armored-data']['enc-fast-rep']
+ self.assertEqual(enc_fast_rep['etype'], armor_key.etype)
+
+ fast_rep = armor_key.decrypt(KU_FAST_REP, enc_fast_rep['cipher'])
+
+ fast_response = self.der_decode(fast_rep,
+ asn1Spec=krb5_asn1.KrbFastResponse())
+
+ if expect_strengthen_key and self.strict_checking:
+ self.assertIn('strengthen-key', fast_response)
+
+ if finished:
+ self.assertIn('finished', fast_response)
+
+ # Ensure that the nonce matches the nonce in the body of the request
+ # (RFC6113 5.4.3).
+ nonce = kdc_exchange_dict['nonce']
+ self.assertEqual(nonce, fast_response['nonce'])
+
+ return fast_response
+
+ def generic_check_kdc_private(self,
+ kdc_exchange_dict,
+ callback_dict,
+ rep,
+ ticket_private,
+ encpart_private,
+ ticket_checksum):
+ kdc_options = kdc_exchange_dict['kdc_options']
+ canon_pos = len(tuple(krb5_asn1.KDCOptions('canonicalize'))) - 1
+ canonicalize = (canon_pos < len(kdc_options)
+ and kdc_options[canon_pos] == '1')
+ renewable_pos = len(tuple(krb5_asn1.KDCOptions('renewable'))) - 1
+ renewable = (renewable_pos < len(kdc_options)
+ and kdc_options[renewable_pos] == '1')
+ renew_pos = len(tuple(krb5_asn1.KDCOptions('renew'))) - 1
+ renew = (renew_pos < len(kdc_options)
+ and kdc_options[renew_pos] == '1')
+ expect_renew_till = renewable or renew
+
+ expected_crealm = kdc_exchange_dict['expected_crealm']
+ expected_cname = kdc_exchange_dict['expected_cname']
+ expected_srealm = kdc_exchange_dict['expected_srealm']
+ expected_sname = kdc_exchange_dict['expected_sname']
+ ticket_decryption_key = kdc_exchange_dict['ticket_decryption_key']
+
+ rep_msg_type = kdc_exchange_dict['rep_msg_type']
+
+ expected_flags = kdc_exchange_dict.get('expected_flags')
+ unexpected_flags = kdc_exchange_dict.get('unexpected_flags')
+
+ ticket = self.getElementValue(rep, 'ticket')
+
+ if ticket_checksum is not None:
+ armor_key = kdc_exchange_dict['armor_key']
+ self.verify_ticket_checksum(ticket, ticket_checksum, armor_key)
+
+ to_rodc = kdc_exchange_dict['to_rodc']
+ if to_rodc:
+ krbtgt_creds = self.get_rodc_krbtgt_creds()
+ else:
+ krbtgt_creds = self.get_krbtgt_creds()
+ krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+
+ krbtgt_keys = [krbtgt_key]
+ if not self.strict_checking:
+ krbtgt_key_rc4 = self.TicketDecryptionKey_from_creds(
+ krbtgt_creds,
+ etype=kcrypto.Enctype.RC4)
+ krbtgt_keys.append(krbtgt_key_rc4)
+
+ if self.expect_pac and self.is_tgs(expected_sname):
+ expect_pac = True
+ else:
+ expect_pac = kdc_exchange_dict['expect_pac']
+
+ ticket_session_key = None
+ if ticket_private is not None:
+ self.assertElementFlags(ticket_private, 'flags',
+ expected_flags,
+ unexpected_flags)
+ self.assertElementPresent(ticket_private, 'key')
+ ticket_key = self.getElementValue(ticket_private, 'key')
+ self.assertIsNotNone(ticket_key)
+ if ticket_key is not None: # Never None, but gives indentation
+ self.assertElementPresent(ticket_key, 'keytype')
+ self.assertElementPresent(ticket_key, 'keyvalue')
+ ticket_session_key = self.EncryptionKey_import(ticket_key)
+ self.assertElementEqualUTF8(ticket_private, 'crealm',
+ expected_crealm)
+ if self.strict_checking:
+ self.assertElementEqualPrincipal(ticket_private, 'cname',
+ expected_cname)
+ self.assertElementPresent(ticket_private, 'transited')
+ self.assertElementPresent(ticket_private, 'authtime')
+ if self.strict_checking:
+ self.assertElementPresent(ticket_private, 'starttime')
+ self.assertElementPresent(ticket_private, 'endtime')
+ if expect_renew_till:
+ if self.strict_checking:
+ self.assertElementPresent(ticket_private, 'renew-till')
+ else:
+ self.assertElementMissing(ticket_private, 'renew-till')
+ if self.strict_checking:
+ self.assertElementEqual(ticket_private, 'caddr', [])
+ if expect_pac is not None:
+ self.assertElementPresent(ticket_private, 'authorization-data',
+ expect_empty=not expect_pac)
+
+ encpart_session_key = None
+ if encpart_private is not None:
+ self.assertElementPresent(encpart_private, 'key')
+ encpart_key = self.getElementValue(encpart_private, 'key')
+ self.assertIsNotNone(encpart_key)
+ if encpart_key is not None: # Never None, but gives indentation
+ self.assertElementPresent(encpart_key, 'keytype')
+ self.assertElementPresent(encpart_key, 'keyvalue')
+ encpart_session_key = self.EncryptionKey_import(encpart_key)
+ self.assertElementPresent(encpart_private, 'last-req')
+ self.assertElementEqual(encpart_private, 'nonce',
+ kdc_exchange_dict['nonce'])
+ if rep_msg_type == KRB_AS_REP:
+ if self.strict_checking:
+ self.assertElementPresent(encpart_private,
+ 'key-expiration')
+ else:
+ self.assertElementMissing(encpart_private,
+ 'key-expiration')
+ self.assertElementFlags(encpart_private, 'flags',
+ expected_flags,
+ unexpected_flags)
+ self.assertElementPresent(encpart_private, 'authtime')
+ if self.strict_checking:
+ self.assertElementPresent(encpart_private, 'starttime')
+ self.assertElementPresent(encpart_private, 'endtime')
+ if expect_renew_till:
+ if self.strict_checking:
+ self.assertElementPresent(encpart_private, 'renew-till')
+ else:
+ self.assertElementMissing(encpart_private, 'renew-till')
+ self.assertElementEqualUTF8(encpart_private, 'srealm',
+ expected_srealm)
+ self.assertElementEqualPrincipal(encpart_private, 'sname',
+ expected_sname)
+ if self.strict_checking:
+ self.assertElementEqual(encpart_private, 'caddr', [])
+
+ sent_pac_options = self.get_sent_pac_options(kdc_exchange_dict)
+
+ if self.strict_checking:
+ if canonicalize or '1' in sent_pac_options:
+ self.assertElementPresent(encpart_private,
+ 'encrypted-pa-data')
+ enc_pa_dict = self.get_pa_dict(
+ encpart_private['encrypted-pa-data'])
+ if canonicalize:
+ self.assertIn(PADATA_SUPPORTED_ETYPES, enc_pa_dict)
+
+ expected_supported_etypes = kdc_exchange_dict[
+ 'expected_supported_etypes']
+ expected_supported_etypes |= (
+ security.KERB_ENCTYPE_DES_CBC_CRC |
+ security.KERB_ENCTYPE_DES_CBC_MD5 |
+ security.KERB_ENCTYPE_RC4_HMAC_MD5)
+
+ (supported_etypes,) = struct.unpack(
+ ' expected_aes_type:
+ expected_aes_type = etype
+ if etype in (kcrypto.Enctype.RC4,) and error_code != 0:
+ unexpect_etype_info = False
+ if etype > expected_rc4_type:
+ expected_rc4_type = etype
+
+ if expected_aes_type != 0:
+ expect_etype_info2 += (expected_aes_type,)
+ if expected_rc4_type != 0:
+ expect_etype_info2 += (expected_rc4_type,)
+
+ expected_patypes = ()
+ if sent_fast and error_code != 0:
+ expected_patypes += (PADATA_FX_ERROR,)
+ expected_patypes += (PADATA_FX_COOKIE,)
+
+ if rep_msg_type == KRB_TGS_REP:
+ sent_pac_options = self.get_sent_pac_options(kdc_exchange_dict)
+ if ('1' in sent_pac_options
+ and error_code not in (0, KDC_ERR_GENERIC)):
+ expected_patypes += (PADATA_PAC_OPTIONS,)
+ elif error_code != KDC_ERR_GENERIC:
+ if expect_etype_info:
+ self.assertGreater(len(expect_etype_info2), 0)
+ expected_patypes += (PADATA_ETYPE_INFO,)
+ if len(expect_etype_info2) != 0:
+ expected_patypes += (PADATA_ETYPE_INFO2,)
+
+ if error_code != KDC_ERR_PREAUTH_FAILED:
+ if sent_fast:
+ expected_patypes += (PADATA_ENCRYPTED_CHALLENGE,)
+ else:
+ expected_patypes += (PADATA_ENC_TIMESTAMP,)
+
+ if not sent_enc_challenge:
+ expected_patypes += (PADATA_PK_AS_REQ,)
+ expected_patypes += (PADATA_PK_AS_REP_19,)
+
+ if (self.kdc_fast_support
+ and not sent_fast
+ and not sent_enc_challenge):
+ expected_patypes += (PADATA_FX_FAST,)
+ expected_patypes += (PADATA_FX_COOKIE,)
+
+ got_patypes = tuple(pa['padata-type'] for pa in rep_padata)
+ self.assertSequenceElementsEqual(expected_patypes, got_patypes,
+ require_strict={PADATA_FX_COOKIE,
+ PADATA_FX_FAST,
+ PADATA_PAC_OPTIONS,
+ PADATA_PK_AS_REP_19,
+ PADATA_PK_AS_REQ})
+
+ if not expected_patypes:
+ return None
+
+ pa_dict = self.get_pa_dict(rep_padata)
+
+ enc_timestamp = pa_dict.get(PADATA_ENC_TIMESTAMP)
+ if enc_timestamp is not None:
+ self.assertEqual(len(enc_timestamp), 0)
+
+ pk_as_req = pa_dict.get(PADATA_PK_AS_REQ)
+ if pk_as_req is not None:
+ self.assertEqual(len(pk_as_req), 0)
+
+ pk_as_rep19 = pa_dict.get(PADATA_PK_AS_REP_19)
+ if pk_as_rep19 is not None:
+ self.assertEqual(len(pk_as_rep19), 0)
+
+ fx_fast = pa_dict.get(PADATA_FX_FAST)
+ if fx_fast is not None:
+ self.assertEqual(len(fx_fast), 0)
+
+ fast_cookie = pa_dict.get(PADATA_FX_COOKIE)
+ if fast_cookie is not None:
+ kdc_exchange_dict['fast_cookie'] = fast_cookie
+
+ fast_error = pa_dict.get(PADATA_FX_ERROR)
+ if fast_error is not None:
+ fast_error = self.der_decode(fast_error,
+ asn1Spec=krb5_asn1.KRB_ERROR())
+ self.generic_check_kdc_error(kdc_exchange_dict,
+ callback_dict,
+ fast_error,
+ inner=True)
+
+ pac_options = pa_dict.get(PADATA_PAC_OPTIONS)
+ if pac_options is not None:
+ pac_options = self.der_decode(
+ pac_options,
+ asn1Spec=krb5_asn1.PA_PAC_OPTIONS())
+ self.assertElementEqual(pac_options, 'options', sent_pac_options)
+
+ enc_challenge = pa_dict.get(PADATA_ENCRYPTED_CHALLENGE)
+ if enc_challenge is not None:
+ if not sent_enc_challenge:
+ self.assertEqual(len(enc_challenge), 0)
+ else:
+ armor_key = kdc_exchange_dict['armor_key']
+ self.assertIsNotNone(armor_key)
+
+ preauth_key, _ = self.get_preauth_key(kdc_exchange_dict)
+
+ kdc_challenge_key = self.generate_kdc_challenge_key(
+ armor_key, preauth_key)
+
+ # Ensure that the encrypted challenge FAST factor is supported
+ # (RFC6113 5.4.6).
+ if self.strict_checking:
+ self.assertNotEqual(len(enc_challenge), 0)
+ if len(enc_challenge) != 0:
+ encrypted_challenge = self.der_decode(
+ enc_challenge,
+ asn1Spec=krb5_asn1.EncryptedData())
+ self.assertEqual(encrypted_challenge['etype'],
+ kdc_challenge_key.etype)
+
+ challenge = kdc_challenge_key.decrypt(
+ KU_ENC_CHALLENGE_KDC,
+ encrypted_challenge['cipher'])
+ challenge = self.der_decode(
+ challenge,
+ asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
+
+ # Retrieve the returned timestamp.
+ rep_patime = challenge['patimestamp']
+ self.assertIn('pausec', challenge)
+
+ # Ensure the returned time is within five minutes of the
+ # current time.
+ rep_time = self.get_EpochFromKerberosTime(rep_patime)
+ current_time = time.time()
+
+ self.assertLess(current_time - 300, rep_time)
+ self.assertLess(rep_time, current_time + 300)
+
+ etype_info2 = pa_dict.get(PADATA_ETYPE_INFO2)
+ if etype_info2 is not None:
+ etype_info2 = self.der_decode(etype_info2,
+ asn1Spec=krb5_asn1.ETYPE_INFO2())
+ self.assertGreaterEqual(len(etype_info2), 1)
+ if self.strict_checking:
+ self.assertEqual(len(etype_info2), len(expect_etype_info2))
+ for i in range(0, len(etype_info2)):
+ e = self.getElementValue(etype_info2[i], 'etype')
+ if self.strict_checking:
+ self.assertEqual(e, expect_etype_info2[i])
+ salt = self.getElementValue(etype_info2[i], 'salt')
+ if e == kcrypto.Enctype.RC4:
+ if self.strict_checking:
+ self.assertIsNone(salt)
+ else:
+ self.assertIsNotNone(salt)
+ expected_salt = kdc_exchange_dict['expected_salt']
+ if expected_salt is not None:
+ self.assertEqual(salt, expected_salt)
+ s2kparams = self.getElementValue(etype_info2[i], 's2kparams')
+ if self.strict_checking:
+ self.assertIsNone(s2kparams)
+
+ etype_info = pa_dict.get(PADATA_ETYPE_INFO)
+ if etype_info is not None:
+ etype_info = self.der_decode(etype_info,
+ asn1Spec=krb5_asn1.ETYPE_INFO())
+ self.assertEqual(len(etype_info), 1)
+ e = self.getElementValue(etype_info[0], 'etype')
+ self.assertEqual(e, kcrypto.Enctype.RC4)
+ self.assertEqual(e, expect_etype_info2[0])
+ salt = self.getElementValue(etype_info[0], 'salt')
+ if self.strict_checking:
+ self.assertIsNotNone(salt)
+ self.assertEqual(len(salt), 0)
+
+ return etype_info2
+
+ def generate_simple_fast(self,
+ kdc_exchange_dict,
+ _callback_dict,
+ req_body,
+ fast_padata,
+ fast_armor,
+ checksum,
+ fast_options=''):
+ armor_key = kdc_exchange_dict['armor_key']
+
+ fast_req = self.KRB_FAST_REQ_create(fast_options,
+ fast_padata,
+ req_body)
+ fast_req = self.der_encode(fast_req,
+ asn1Spec=krb5_asn1.KrbFastReq())
+ fast_req = self.EncryptedData_create(armor_key,
+ KU_FAST_ENC,
+ fast_req)
+
+ fast_armored_req = self.KRB_FAST_ARMORED_REQ_create(fast_armor,
+ checksum,
+ fast_req)
+
+ fx_fast_request = self.PA_FX_FAST_REQUEST_create(fast_armored_req)
+ fx_fast_request = self.der_encode(
+ fx_fast_request,
+ asn1Spec=krb5_asn1.PA_FX_FAST_REQUEST())
+
+ fast_padata = self.PA_DATA_create(PADATA_FX_FAST,
+ fx_fast_request)
+
+ return fast_padata
+
+ def generate_ap_req(self,
+ kdc_exchange_dict,
+ _callback_dict,
+ req_body,
+ armor):
+ if armor:
+ tgt = kdc_exchange_dict['armor_tgt']
+ authenticator_subkey = kdc_exchange_dict['armor_subkey']
+
+ req_body_checksum = None
+ else:
+ tgt = kdc_exchange_dict['tgt']
+ authenticator_subkey = kdc_exchange_dict['authenticator_subkey']
+ body_checksum_type = kdc_exchange_dict['body_checksum_type']
+
+ req_body_blob = self.der_encode(req_body,
+ asn1Spec=krb5_asn1.KDC_REQ_BODY())
+
+ req_body_checksum = self.Checksum_create(tgt.session_key,
+ KU_TGS_REQ_AUTH_CKSUM,
+ req_body_blob,
+ ctype=body_checksum_type)
+
+ auth_data = kdc_exchange_dict['auth_data']
+
+ subkey_obj = None
+ if authenticator_subkey is not None:
+ subkey_obj = authenticator_subkey.export_obj()
+ seq_number = random.randint(0, 0xfffffffe)
+ (ctime, cusec) = self.get_KerberosTimeWithUsec()
+ authenticator_obj = self.Authenticator_create(
+ crealm=tgt.crealm,
+ cname=tgt.cname,
+ cksum=req_body_checksum,
+ cusec=cusec,
+ ctime=ctime,
+ subkey=subkey_obj,
+ seq_number=seq_number,
+ authorization_data=auth_data)
+ authenticator_blob = self.der_encode(
+ authenticator_obj,
+ asn1Spec=krb5_asn1.Authenticator())
+
+ usage = KU_AP_REQ_AUTH if armor else KU_TGS_REQ_AUTH
+ authenticator = self.EncryptedData_create(tgt.session_key,
+ usage,
+ authenticator_blob)
+
+ ap_options = krb5_asn1.APOptions('0')
+ ap_req_obj = self.AP_REQ_create(ap_options=str(ap_options),
+ ticket=tgt.ticket,
+ authenticator=authenticator)
+ ap_req = self.der_encode(ap_req_obj, asn1Spec=krb5_asn1.AP_REQ())
+
+ return ap_req
+
+ def generate_simple_tgs_padata(self,
+ kdc_exchange_dict,
+ callback_dict,
+ req_body):
+ ap_req = self.generate_ap_req(kdc_exchange_dict,
+ callback_dict,
+ req_body,
+ armor=False)
+ pa_tgs_req = self.PA_DATA_create(PADATA_KDC_REQ, ap_req)
+ padata = [pa_tgs_req]
+
+ return padata, req_body
+
+ def get_preauth_key(self, kdc_exchange_dict):
+ msg_type = kdc_exchange_dict['rep_msg_type']
+
+ if msg_type == KRB_AS_REP:
+ key = kdc_exchange_dict['preauth_key']
+ usage = KU_AS_REP_ENC_PART
+ else: # KRB_TGS_REP
+ authenticator_subkey = kdc_exchange_dict['authenticator_subkey']
+ if authenticator_subkey is not None:
+ key = authenticator_subkey
+ usage = KU_TGS_REP_ENC_PART_SUB_KEY
+ else:
+ tgt = kdc_exchange_dict['tgt']
+ key = tgt.session_key
+ usage = KU_TGS_REP_ENC_PART_SESSION
+
+ self.assertIsNotNone(key)
+
+ return key, usage
+
+ def generate_armor_key(self, subkey, session_key):
+ armor_key = kcrypto.cf2(subkey.key,
+ session_key.key,
+ b'subkeyarmor',
+ b'ticketarmor')
+ armor_key = Krb5EncryptionKey(armor_key, None)
+
+ return armor_key
+
+ def generate_strengthen_reply_key(self, strengthen_key, reply_key):
+ strengthen_reply_key = kcrypto.cf2(strengthen_key.key,
+ reply_key.key,
+ b'strengthenkey',
+ b'replykey')
+ strengthen_reply_key = Krb5EncryptionKey(strengthen_reply_key,
+ reply_key.kvno)
+
+ return strengthen_reply_key
+
+ def generate_client_challenge_key(self, armor_key, longterm_key):
+ client_challenge_key = kcrypto.cf2(armor_key.key,
+ longterm_key.key,
+ b'clientchallengearmor',
+ b'challengelongterm')
+ client_challenge_key = Krb5EncryptionKey(client_challenge_key, None)
+
+ return client_challenge_key
+
+ def generate_kdc_challenge_key(self, armor_key, longterm_key):
+ kdc_challenge_key = kcrypto.cf2(armor_key.key,
+ longterm_key.key,
+ b'kdcchallengearmor',
+ b'challengelongterm')
+ kdc_challenge_key = Krb5EncryptionKey(kdc_challenge_key, None)
+
+ return kdc_challenge_key
+
+ def verify_ticket_checksum(self, ticket, expected_checksum, armor_key):
+ expected_type = expected_checksum['cksumtype']
+ self.assertEqual(armor_key.ctype, expected_type)
+
+ ticket_blob = self.der_encode(ticket,
+ asn1Spec=krb5_asn1.Ticket())
+ checksum = self.Checksum_create(armor_key,
+ KU_FAST_FINISHED,
+ ticket_blob)
+ self.assertEqual(expected_checksum, checksum)
+
+ def verify_ticket(self, ticket, krbtgt_keys, expect_pac=True,
+ expect_ticket_checksum=True):
+ # Check if the ticket is a TGT.
+ is_tgt = self.is_tgt(ticket)
+
+ # Decrypt the ticket.
+
+ key = ticket.decryption_key
+ enc_part = ticket.ticket['enc-part']
+
+ self.assertElementEqual(enc_part, 'etype', key.etype)
+ self.assertElementKVNO(enc_part, 'kvno', key.kvno)
+
+ enc_part = key.decrypt(KU_TICKET, enc_part['cipher'])
+ enc_part = self.der_decode(
+ enc_part, asn1Spec=krb5_asn1.EncTicketPart())
+
+ # Fetch the authorization data from the ticket.
+ auth_data = enc_part.get('authorization-data')
+ if expect_pac:
+ self.assertIsNotNone(auth_data)
+ elif auth_data is None:
+ return
+
+ # Get a copy of the authdata with an empty PAC, and the existing PAC
+ # (if present).
+ empty_pac = self.get_empty_pac()
+ auth_data, pac_data = self.replace_pac(auth_data,
+ empty_pac,
+ expect_pac=expect_pac)
+ if not expect_pac:
+ return
+
+ # Unpack the PAC as both PAC_DATA and PAC_DATA_RAW types. We use the
+ # raw type to create a new PAC with zeroed signatures for
+ # verification. This is because on Windows, the resource_groups field
+ # is added to PAC_LOGON_INFO after the info3 field has been created,
+ # which results in a different ordering of pointer values than Samba
+ # (see commit 0e201ecdc53). Using the raw type avoids changing
+ # PAC_LOGON_INFO, so verification against Windows can work. We still
+ # need the PAC_DATA type to retrieve the actual checksums, because the
+ # signatures in the raw type may contain padding bytes.
+ pac = ndr_unpack(krb5pac.PAC_DATA,
+ pac_data)
+ raw_pac = ndr_unpack(krb5pac.PAC_DATA_RAW,
+ pac_data)
+
+ checksums = {}
+
+ for pac_buffer, raw_pac_buffer in zip(pac.buffers, raw_pac.buffers):
+ buffer_type = pac_buffer.type
+ if buffer_type in self.pac_checksum_types:
+ self.assertNotIn(buffer_type, checksums,
+ f'Duplicate checksum type {buffer_type}')
+
+ # Fetch the checksum and the checksum type from the PAC buffer.
+ checksum = pac_buffer.info.signature
+ ctype = pac_buffer.info.type
+ if ctype & 1 << 31:
+ ctype |= -1 << 31
+
+ checksums[buffer_type] = checksum, ctype
+
+ if buffer_type != krb5pac.PAC_TYPE_TICKET_CHECKSUM:
+ # Zero the checksum field so that we can later verify the
+ # checksums. The ticket checksum field is not zeroed.
+
+ signature = ndr_unpack(
+ krb5pac.PAC_SIGNATURE_DATA,
+ raw_pac_buffer.info.remaining)
+ signature.signature = bytes(len(checksum))
+ raw_pac_buffer.info.remaining = ndr_pack(
+ signature)
+
+ # Re-encode the PAC.
+ pac_data = ndr_pack(raw_pac)
+
+ # Verify the signatures.
+
+ server_checksum, server_ctype = checksums[
+ krb5pac.PAC_TYPE_SRV_CHECKSUM]
+ key.verify_checksum(KU_NON_KERB_CKSUM_SALT,
+ pac_data,
+ server_ctype,
+ server_checksum)
+
+ kdc_checksum, kdc_ctype = checksums[
+ krb5pac.PAC_TYPE_KDC_CHECKSUM]
+
+ if isinstance(krbtgt_keys, collections.abc.Container):
+ if self.strict_checking:
+ krbtgt_key = krbtgt_keys[0]
+ else:
+ krbtgt_key = next(key for key in krbtgt_keys
+ if key.ctype == kdc_ctype)
+ else:
+ krbtgt_key = krbtgt_keys
+
+ krbtgt_key.verify_rodc_checksum(KU_NON_KERB_CKSUM_SALT,
+ server_checksum,
+ kdc_ctype,
+ kdc_checksum)
+
+ if is_tgt:
+ self.assertNotIn(krb5pac.PAC_TYPE_TICKET_CHECKSUM, checksums)
+ else:
+ ticket_checksum, ticket_ctype = checksums.get(
+ krb5pac.PAC_TYPE_TICKET_CHECKSUM,
+ (None, None))
+ if expect_ticket_checksum:
+ self.assertIsNotNone(ticket_checksum)
+ elif expect_ticket_checksum is False:
+ self.assertIsNone(ticket_checksum)
+ if ticket_checksum is not None:
+ enc_part['authorization-data'] = auth_data
+ enc_part = self.der_encode(enc_part,
+ asn1Spec=krb5_asn1.EncTicketPart())
+
+ krbtgt_key.verify_rodc_checksum(KU_NON_KERB_CKSUM_SALT,
+ enc_part,
+ ticket_ctype,
+ ticket_checksum)
+
+ def modified_ticket(self,
+ ticket, *,
+ new_ticket_key=None,
+ modify_fn=None,
+ modify_pac_fn=None,
+ exclude_pac=False,
+ allow_empty_authdata=False,
+ update_pac_checksums=True,
+ checksum_keys=None,
+ include_checksums=None):
+ if checksum_keys is None:
+ # A dict containing a key for each checksum type to be created in
+ # the PAC.
+ checksum_keys = {}
+
+ if include_checksums is None:
+ # A dict containing a value for each checksum type; True if the
+ # checksum type is to be included in the PAC, False if it is to be
+ # excluded, or None/not present if the checksum is to be included
+ # based on its presence in the original PAC.
+ include_checksums = {}
+
+ # Check that the values passed in by the caller make sense.
+
+ self.assertLessEqual(checksum_keys.keys(), self.pac_checksum_types)
+ self.assertLessEqual(include_checksums.keys(), self.pac_checksum_types)
+
+ if exclude_pac:
+ self.assertIsNone(modify_pac_fn)
+
+ update_pac_checksums = False
+
+ if not update_pac_checksums:
+ self.assertFalse(checksum_keys)
+ self.assertFalse(include_checksums)
+
+ expect_pac = modify_pac_fn is not None
+
+ key = ticket.decryption_key
+
+ if new_ticket_key is None:
+ # Use the same key to re-encrypt the ticket.
+ new_ticket_key = key
+
+ if krb5pac.PAC_TYPE_SRV_CHECKSUM not in checksum_keys:
+ # If the server signature key is not present, fall back to the key
+ # used to encrypt the ticket.
+ checksum_keys[krb5pac.PAC_TYPE_SRV_CHECKSUM] = new_ticket_key
+
+ if krb5pac.PAC_TYPE_TICKET_CHECKSUM not in checksum_keys:
+ # If the ticket signature key is not present, fall back to the key
+ # used for the KDC signature.
+ kdc_checksum_key = checksum_keys.get(krb5pac.PAC_TYPE_KDC_CHECKSUM)
+ if kdc_checksum_key is not None:
+ checksum_keys[krb5pac.PAC_TYPE_TICKET_CHECKSUM] = (
+ kdc_checksum_key)
+
+ # Decrypt the ticket.
+
+ enc_part = ticket.ticket['enc-part']
+
+ self.assertElementEqual(enc_part, 'etype', key.etype)
+ self.assertElementKVNO(enc_part, 'kvno', key.kvno)
+
+ enc_part = key.decrypt(KU_TICKET, enc_part['cipher'])
+ enc_part = self.der_decode(
+ enc_part, asn1Spec=krb5_asn1.EncTicketPart())
+
+ # Modify the ticket here.
+ if modify_fn is not None:
+ enc_part = modify_fn(enc_part)
+
+ auth_data = enc_part.get('authorization-data')
+ if expect_pac:
+ self.assertIsNotNone(auth_data)
+ if auth_data is not None:
+ new_pac = None
+ if not exclude_pac:
+ # Get a copy of the authdata with an empty PAC, and the
+ # existing PAC (if present).
+ empty_pac = self.get_empty_pac()
+ empty_pac_auth_data, pac_data = self.replace_pac(
+ auth_data,
+ empty_pac,
+ expect_pac=expect_pac)
+
+ if pac_data is not None:
+ pac = ndr_unpack(krb5pac.PAC_DATA, pac_data)
+
+ # Modify the PAC here.
+ if modify_pac_fn is not None:
+ pac = modify_pac_fn(pac)
+
+ if update_pac_checksums:
+ # Get the enc-part with an empty PAC, which is needed
+ # to create a ticket signature.
+ enc_part_to_sign = enc_part.copy()
+ enc_part_to_sign['authorization-data'] = (
+ empty_pac_auth_data)
+ enc_part_to_sign = self.der_encode(
+ enc_part_to_sign,
+ asn1Spec=krb5_asn1.EncTicketPart())
+
+ self.update_pac_checksums(pac,
+ checksum_keys,
+ include_checksums,
+ enc_part_to_sign)
+
+ # Re-encode the PAC.
+ pac_data = ndr_pack(pac)
+ new_pac = self.AuthorizationData_create(AD_WIN2K_PAC,
+ pac_data)
+
+ # Replace the PAC in the authorization data and re-add it to the
+ # ticket enc-part.
+ auth_data, _ = self.replace_pac(
+ auth_data, new_pac,
+ expect_pac=expect_pac,
+ allow_empty_authdata=allow_empty_authdata)
+ enc_part['authorization-data'] = auth_data
+
+ # Re-encrypt the ticket enc-part with the new key.
+ enc_part_new = self.der_encode(enc_part,
+ asn1Spec=krb5_asn1.EncTicketPart())
+ enc_part_new = self.EncryptedData_create(new_ticket_key,
+ KU_TICKET,
+ enc_part_new)
+
+ # Create a copy of the ticket with the new enc-part.
+ new_ticket = ticket.ticket.copy()
+ new_ticket['enc-part'] = enc_part_new
+
+ new_ticket_creds = KerberosTicketCreds(
+ new_ticket,
+ session_key=ticket.session_key,
+ crealm=ticket.crealm,
+ cname=ticket.cname,
+ srealm=ticket.srealm,
+ sname=ticket.sname,
+ decryption_key=new_ticket_key,
+ ticket_private=enc_part,
+ encpart_private=ticket.encpart_private)
+
+ return new_ticket_creds
+
+ def update_pac_checksums(self,
+ pac,
+ checksum_keys,
+ include_checksums,
+ enc_part=None):
+ pac_buffers = pac.buffers
+ checksum_buffers = {}
+
+ # Find the relevant PAC checksum buffers.
+ for pac_buffer in pac_buffers:
+ buffer_type = pac_buffer.type
+ if buffer_type in self.pac_checksum_types:
+ self.assertNotIn(buffer_type, checksum_buffers,
+ f'Duplicate checksum type {buffer_type}')
+
+ checksum_buffers[buffer_type] = pac_buffer
+
+ # Create any additional buffers that were requested but not
+ # present. Conversely, remove any buffers that were requested to be
+ # removed.
+ for buffer_type in self.pac_checksum_types:
+ if buffer_type in checksum_buffers:
+ if include_checksums.get(buffer_type) is False:
+ checksum_buffer = checksum_buffers.pop(buffer_type)
+
+ pac.num_buffers -= 1
+ pac_buffers.remove(checksum_buffer)
+
+ elif include_checksums.get(buffer_type) is True:
+ info = krb5pac.PAC_SIGNATURE_DATA()
+
+ checksum_buffer = krb5pac.PAC_BUFFER()
+ checksum_buffer.type = buffer_type
+ checksum_buffer.info = info
+
+ pac_buffers.append(checksum_buffer)
+ pac.num_buffers += 1
+
+ checksum_buffers[buffer_type] = checksum_buffer
+
+ # Fill the relevant checksum buffers.
+ for buffer_type, checksum_buffer in checksum_buffers.items():
+ checksum_key = checksum_keys[buffer_type]
+ ctype = checksum_key.ctype & ((1 << 32) - 1)
+
+ if buffer_type == krb5pac.PAC_TYPE_TICKET_CHECKSUM:
+ self.assertIsNotNone(enc_part)
+
+ signature = checksum_key.make_rodc_checksum(
+ KU_NON_KERB_CKSUM_SALT,
+ enc_part)
+
+ elif buffer_type == krb5pac.PAC_TYPE_SRV_CHECKSUM:
+ signature = checksum_key.make_zeroed_checksum()
+
+ else:
+ signature = checksum_key.make_rodc_zeroed_checksum()
+
+ checksum_buffer.info.signature = signature
+ checksum_buffer.info.type = ctype
+
+ # Add the new checksum buffers to the PAC.
+ pac.buffers = pac_buffers
+
+ # Calculate the server and KDC checksums and insert them into the PAC.
+
+ server_checksum_buffer = checksum_buffers.get(
+ krb5pac.PAC_TYPE_SRV_CHECKSUM)
+ if server_checksum_buffer is not None:
+ server_checksum_key = checksum_keys[krb5pac.PAC_TYPE_SRV_CHECKSUM]
+
+ pac_data = ndr_pack(pac)
+ server_checksum = server_checksum_key.make_checksum(
+ KU_NON_KERB_CKSUM_SALT,
+ pac_data)
+
+ server_checksum_buffer.info.signature = server_checksum
+
+ kdc_checksum_buffer = checksum_buffers.get(
+ krb5pac.PAC_TYPE_KDC_CHECKSUM)
+ if kdc_checksum_buffer is not None:
+ if server_checksum_buffer is None:
+ # There's no server signature to make the checksum over, so
+ # just make the checksum over an empty bytes object.
+ server_checksum = bytes()
+
+ kdc_checksum_key = checksum_keys[krb5pac.PAC_TYPE_KDC_CHECKSUM]
+
+ kdc_checksum = kdc_checksum_key.make_rodc_checksum(
+ KU_NON_KERB_CKSUM_SALT,
+ server_checksum)
+
+ kdc_checksum_buffer.info.signature = kdc_checksum
+
+ def replace_pac(self, auth_data, new_pac, expect_pac=True,
+ allow_empty_authdata=False):
+ if new_pac is not None:
+ self.assertElementEqual(new_pac, 'ad-type', AD_WIN2K_PAC)
+ self.assertElementPresent(new_pac, 'ad-data')
+
+ new_auth_data = []
+
+ ad_relevant = None
+ old_pac = None
+
+ for authdata_elem in auth_data:
+ if authdata_elem['ad-type'] == AD_IF_RELEVANT:
+ ad_relevant = self.der_decode(
+ authdata_elem['ad-data'],
+ asn1Spec=krb5_asn1.AD_IF_RELEVANT())
+
+ relevant_elems = []
+ for relevant_elem in ad_relevant:
+ if relevant_elem['ad-type'] == AD_WIN2K_PAC:
+ self.assertIsNone(old_pac, 'Multiple PACs detected')
+ old_pac = relevant_elem['ad-data']
+
+ if new_pac is not None:
+ relevant_elems.append(new_pac)
+ else:
+ relevant_elems.append(relevant_elem)
+ if expect_pac:
+ self.assertIsNotNone(old_pac, 'Expected PAC')
+
+ if relevant_elems or allow_empty_authdata:
+ ad_relevant = self.der_encode(
+ relevant_elems,
+ asn1Spec=krb5_asn1.AD_IF_RELEVANT())
+
+ authdata_elem = self.AuthorizationData_create(
+ AD_IF_RELEVANT,
+ ad_relevant)
+ else:
+ authdata_elem = None
+
+ if authdata_elem is not None or allow_empty_authdata:
+ new_auth_data.append(authdata_elem)
+
+ if expect_pac:
+ self.assertIsNotNone(ad_relevant, 'Expected AD-RELEVANT')
+
+ return new_auth_data, old_pac
+
+ def get_pac(self, auth_data, expect_pac=True):
+ _, pac = self.replace_pac(auth_data, None, expect_pac)
+ return pac
+
+ def get_ticket_pac(self, ticket, expect_pac=True):
+ auth_data = ticket.ticket_private.get('authorization-data')
+ if expect_pac:
+ self.assertIsNotNone(auth_data)
+ elif auth_data is None:
+ return None
+
+ return self.get_pac(auth_data, expect_pac=expect_pac)
+
+ def get_krbtgt_checksum_key(self):
+ krbtgt_creds = self.get_krbtgt_creds()
+ krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+
+ return {
+ krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key
+ }
+
+ def is_tgs(self, principal):
+ name = principal['name-string'][0]
+ return name in ('krbtgt', b'krbtgt')
+
+ def is_tgt(self, ticket):
+ sname = ticket.ticket['sname']
+ return self.is_tgs(sname)
+
+ def get_empty_pac(self):
+ return self.AuthorizationData_create(AD_WIN2K_PAC, bytes(1))
+
+ def get_outer_pa_dict(self, kdc_exchange_dict):
+ return self.get_pa_dict(kdc_exchange_dict['req_padata'])
+
+ def get_fast_pa_dict(self, kdc_exchange_dict):
+ req_pa_dict = self.get_pa_dict(kdc_exchange_dict['fast_padata'])
+
+ if req_pa_dict:
+ return req_pa_dict
+
+ return self.get_outer_pa_dict(kdc_exchange_dict)
+
+ def sent_fast(self, kdc_exchange_dict):
+ outer_pa_dict = self.get_outer_pa_dict(kdc_exchange_dict)
+
+ return PADATA_FX_FAST in outer_pa_dict
+
+ def sent_enc_challenge(self, kdc_exchange_dict):
+ fast_pa_dict = self.get_fast_pa_dict(kdc_exchange_dict)
+
+ return PADATA_ENCRYPTED_CHALLENGE in fast_pa_dict
+
+ def get_sent_pac_options(self, kdc_exchange_dict):
+ fast_pa_dict = self.get_fast_pa_dict(kdc_exchange_dict)
+
+ if PADATA_PAC_OPTIONS not in fast_pa_dict:
+ return ''
+
+ pac_options = self.der_decode(fast_pa_dict[PADATA_PAC_OPTIONS],
+ asn1Spec=krb5_asn1.PA_PAC_OPTIONS())
+ pac_options = pac_options['options']
+
+ # Mask out unsupported bits.
+ pac_options, remaining = pac_options[:4], pac_options[4:]
+ pac_options += '0' * len(remaining)
+
+ return pac_options
+
+ def get_krbtgt_sname(self):
+ krbtgt_creds = self.get_krbtgt_creds()
+ krbtgt_username = krbtgt_creds.get_username()
+ krbtgt_realm = krbtgt_creds.get_realm()
+ krbtgt_sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=[krbtgt_username, krbtgt_realm])
+
+ return krbtgt_sname
+
+ def _test_as_exchange(self,
+ cname,
+ realm,
+ sname,
+ till,
+ client_as_etypes,
+ expected_error_mode,
+ expected_crealm,
+ expected_cname,
+ expected_srealm,
+ expected_sname,
+ expected_salt,
+ etypes,
+ padata,
+ kdc_options,
+ expected_account_name=None,
+ expected_upn_name=None,
+ expected_sid=None,
+ expected_flags=None,
+ unexpected_flags=None,
+ expected_supported_etypes=None,
+ preauth_key=None,
+ ticket_decryption_key=None,
+ pac_request=None,
+ pac_options=None,
+ expect_pac=True,
+ expect_pac_attrs=None,
+ expect_pac_attrs_pac_request=None,
+ expect_requester_sid=None,
+ to_rodc=False):
+
+ def _generate_padata_copy(_kdc_exchange_dict,
+ _callback_dict,
+ req_body):
+ return padata, req_body
+
+ if not expected_error_mode:
+ check_error_fn = None
+ check_rep_fn = self.generic_check_kdc_rep
+ else:
+ check_error_fn = self.generic_check_kdc_error
+ check_rep_fn = None
+
+ if padata is not None:
+ generate_padata_fn = _generate_padata_copy
+ else:
+ generate_padata_fn = None
+
+ kdc_exchange_dict = self.as_exchange_dict(
+ expected_crealm=expected_crealm,
+ expected_cname=expected_cname,
+ expected_srealm=expected_srealm,
+ expected_sname=expected_sname,
+ expected_account_name=expected_account_name,
+ expected_upn_name=expected_upn_name,
+ expected_sid=expected_sid,
+ expected_supported_etypes=expected_supported_etypes,
+ ticket_decryption_key=ticket_decryption_key,
+ generate_padata_fn=generate_padata_fn,
+ check_error_fn=check_error_fn,
+ check_rep_fn=check_rep_fn,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ expected_error_mode=expected_error_mode,
+ client_as_etypes=client_as_etypes,
+ expected_salt=expected_salt,
+ expected_flags=expected_flags,
+ unexpected_flags=unexpected_flags,
+ preauth_key=preauth_key,
+ kdc_options=str(kdc_options),
+ pac_request=pac_request,
+ pac_options=pac_options,
+ expect_pac=expect_pac,
+ expect_pac_attrs=expect_pac_attrs,
+ expect_pac_attrs_pac_request=expect_pac_attrs_pac_request,
+ expect_requester_sid=expect_requester_sid,
+ to_rodc=to_rodc)
+
+ rep = self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=cname,
+ realm=realm,
+ sname=sname,
+ till_time=till,
+ etypes=etypes)
+
+ return rep, kdc_exchange_dict
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/rfc4120.asn1 samba-4.13.14+dfsg/python/samba/tests/krb5/rfc4120.asn1
--- samba-4.13.3+dfsg/python/samba/tests/krb5/rfc4120.asn1 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/rfc4120.asn1 2021-10-29 06:17:36.000000000 +0000
@@ -1,3 +1,43 @@
+-- Portions of these ASN.1 modules are structures are from RFC6113
+-- authored by S. Hartman (Painless Security) and L. Zhu (Microsoft)
+--
+-- Copyright (c) 2011 IETF Trust and the persons identified as authors of the
+-- code. All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, is permitted pursuant to, and subject to the license terms
+-- contained in, the Simplified BSD License set forth in Section 4.c of the IETF
+-- Trust’s Legal Provisions Relating to IETF Documents
+-- (http://trustee.ietf.org/license-info).
+--
+-- BSD License:
+--
+-- Copyright (c) 2011 IETF Trust and the persons identified as authors of the code. All rights reserved.
+-- Redistribution and use in source and binary forms, with or without modification, are permitted provided
+-- that the following conditions are met:
+-- • Redistributions of source code must retain the above copyright notice, this list of conditions and
+-- the following disclaimer.
+--
+-- • Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+-- and the following disclaimer in the documentation and/or other materials provided with the
+-- distribution.
+--
+-- • Neither the name of Internet Society, IETF or IETF Trust, nor the names of specific contributors,
+-- may be used to endorse or promote products derived from this software without specific prior written
+-- permission.
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
+-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+-- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+-- POSSIBILITY OF SUCH DAMAGE.
+--
+
KerberosV5Spec2 {
iso(1) identified-organization(3) dod(6) internet(1)
security(5) kerberosV5(2) modules(4) krb5spec2(2)
@@ -84,7 +124,7 @@
EncryptedData ::= SEQUENCE {
etype [0] EncryptionType, --Int32 EncryptionType --
- kvno [1] UInt32 OPTIONAL,
+ kvno [1] Int32 OPTIONAL,
cipher [2] OCTET STRING -- ciphertext
}
@@ -196,8 +236,8 @@
-- opt-hardware-auth(11),
-- unused12(12),
-- unused13(13),
--- 15 is reserved for canonicalize
- -- unused15(15),
+-- Canonicalize is used in RFC 6806
+ -- canonicalize(15),
-- 26 was unused in 1510
-- disable-transited-check(26),
--
@@ -239,7 +279,8 @@
renew-till [8] KerberosTime OPTIONAL,
srealm [9] Realm,
sname [10] PrincipalName,
- caddr [11] HostAddresses OPTIONAL
+ caddr [11] HostAddresses OPTIONAL,
+ encrypted-pa-data[12] METHOD-DATA OPTIONAL
}
LastReq ::= SEQUENCE OF SEQUENCE {
@@ -385,14 +426,14 @@
}
ETYPE-INFO-ENTRY ::= SEQUENCE {
- etype [0] Int32,
+ etype [0] EncryptionType, --Int32 EncryptionType --
salt [1] OCTET STRING OPTIONAL
}
ETYPE-INFO ::= SEQUENCE OF ETYPE-INFO-ENTRY
ETYPE-INFO2-ENTRY ::= SEQUENCE {
- etype [0] Int32,
+ etype [0] EncryptionType, --Int32 EncryptionType --
salt [1] KerberosString OPTIONAL,
s2kparams [2] OCTET STRING OPTIONAL
}
@@ -424,9 +465,111 @@
auth [3] KerberosString
}
+--
+--
+-- MS-KILE Start
+
+KERB-ERROR-DATA ::= SEQUENCE {
+ data-type [1] KerbErrorDataType,
+ data-value [2] OCTET STRING OPTIONAL
+}
+
+KerbErrorDataType ::= INTEGER
+
+KERB-PA-PAC-REQUEST ::= SEQUENCE {
+ include-pac[0] BOOLEAN --If TRUE, and no pac present, include PAC.
+ --If FALSE, and PAC present, remove PAC
+}
+
+KERB-LOCAL ::= OCTET STRING -- Implementation-specific data which MUST be
+ -- ignored if Kerberos client is not local.
+
+KERB-AD-RESTRICTION-ENTRY ::= SEQUENCE {
+ restriction-type [0] Int32,
+ restriction [1] OCTET STRING -- LSAP_TOKEN_INFO_INTEGRITY structure
+}
+
+PA-SUPPORTED-ENCTYPES ::= Int32 -- Supported Encryption Types Bit Field --
+
+PACOptionFlags ::= KerberosFlags -- Claims (0)
+ -- Branch Aware (1)
+ -- Forward to Full DC (2)
+ -- Resource Based Constrained Delegation (3)
+PA-PAC-OPTIONS ::= SEQUENCE {
+ options [0] PACOptionFlags
+}
+-- Note: KerberosFlags ::= BIT STRING (SIZE (32..MAX))
+-- minimum number of bits shall be sent, but no fewer than 32
+
+KERB-KEY-LIST-REQ ::= SEQUENCE OF EncryptionType -- Int32 encryption type --
+KERB-KEY-LIST-REP ::= SEQUENCE OF EncryptionKey
+
+FastOptions ::= BIT STRING {
+ reserved(0),
+ hide-client-names(1),
+ kdc-follow-referrals(16)
+}
+
+KrbFastReq ::= SEQUENCE {
+ fast-options [0] FastOptions,
+ padata [1] SEQUENCE OF PA-DATA,
+ req-body [2] KDC-REQ-BODY,
+ ...
+}
+
+KrbFastArmor ::= SEQUENCE {
+ armor-type [0] Int32,
+ armor-value [1] OCTET STRING,
+ ...
+}
+
+KrbFastArmoredReq ::= SEQUENCE {
+ armor [0] KrbFastArmor OPTIONAL,
+ req-checksum [1] Checksum,
+ enc-fast-req [2] EncryptedData -- KrbFastReq --
+}
+
+PA-FX-FAST-REQUEST ::= CHOICE {
+ armored-data [0] KrbFastArmoredReq,
+ ...
+}
+
+KrbFastFinished ::= SEQUENCE {
+ timestamp [0] KerberosTime,
+ usec [1] Int32,
+ crealm [2] Realm,
+ cname [3] PrincipalName,
+ ticket-checksum [4] Checksum,
+ ...
+}
+
+KrbFastResponse ::= SEQUENCE {
+ padata [0] SEQUENCE OF PA-DATA,
+ -- padata typed holes.
+ strengthen-key [1] EncryptionKey OPTIONAL,
+ -- This, if present, strengthens the reply key for AS and
+ -- TGS. MUST be present for TGS.
+ -- MUST be absent in KRB-ERROR.
+ finished [2] KrbFastFinished OPTIONAL,
+ -- Present in AS or TGS reply; absent otherwise.
+ nonce [3] UInt32,
+ -- Nonce from the client request.
+ ...
+}
+KrbFastArmoredRep ::= SEQUENCE {
+ enc-fast-rep [0] EncryptedData, -- KrbFastResponse --
+ ...
+}
+PA-FX-FAST-REPLY ::= CHOICE {
+ armored-data [0] KrbFastArmoredRep,
+ ...
+}
+-- MS-KILE End
+--
+--
--
--
@@ -489,8 +632,9 @@
opt-hardware-auth(11),
unused12(12),
unused13(13),
--- 15 is reserved for canonicalize
- unused15(15),
+ cname-in-addl-tkt(14),
+-- Canonicalize is used by RFC 6806
+ canonicalize(15),
-- 26 was unused in 1510
disable-transited-check(26),
--
@@ -503,6 +647,15 @@
dummy [0] KDCOptionsValues
}
+APOptionsValues ::= BIT STRING { -- KerberosFlags
+ reserved(0),
+ use-session-key(1),
+ mutual-required(2)
+}
+APOptionsSequence ::= SEQUENCE {
+ dummy [0] APOptionsValues
+}
+
MessageTypeValues ::= INTEGER {
krb-as-req(10), -- Request for initial authentication
krb-as-rep(11), -- Response to KRB_AS_REQ request
@@ -582,7 +735,8 @@
kRB5-PADATA-PKINIT-KX(147), -- krb-wg-anon
kRB5-PADATA-PKU2U-NAME(148), -- zhu-pku2u
kRB5-PADATA-REQ-ENC-PA-REP(149), --
- kRB5-PADATA-SUPPORTED-ETYPES(165) -- MS-KILE
+ kRB5-PADATA-SUPPORTED-ETYPES(165), -- MS-KILE
+ kRB5-PADATA-PAC-OPTIONS(167) -- MS-KILE
}
PADataTypeSequence ::= SEQUENCE {
dummy [0] PADataTypeValues
@@ -668,4 +822,22 @@
dummy [0] EncryptionTypeValues
}
+KerbErrorDataTypeValues ::= INTEGER {
+ kERB-AP-ERR-TYPE-SKEW-RECOVERY(2),
+ kERB-ERR-TYPE-EXTENDED(3)
+}
+KerbErrorDataTypeSequence ::= SEQUENCE {
+ dummy [0] KerbErrorDataTypeValues
+}
+
+PACOptionFlagsValues ::= BIT STRING { -- KerberosFlags
+ claims(0),
+ branch-aware(1),
+ forward-to-full-dc(2),
+ resource-based-constrained-delegation(3)
+}
+PACOptionFlagsSequence ::= SEQUENCE {
+ dummy [0] PACOptionFlagsValues
+}
+
END
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/rfc4120_constants.py samba-4.13.14+dfsg/python/samba/tests/krb5/rfc4120_constants.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/rfc4120_constants.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/rfc4120_constants.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,185 @@
+# Unix SMB/CIFS implementation.
+# Copyright (C) 2020 Catalyst.Net Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
+
+# Encryption types
+AES256_CTS_HMAC_SHA1_96 = int(
+ krb5_asn1.EncryptionTypeValues('kRB5-ENCTYPE-AES256-CTS-HMAC-SHA1-96'))
+AES128_CTS_HMAC_SHA1_96 = int(
+ krb5_asn1.EncryptionTypeValues('kRB5-ENCTYPE-AES128-CTS-HMAC-SHA1-96'))
+ARCFOUR_HMAC_MD5 = int(
+ krb5_asn1.EncryptionTypeValues('kRB5-ENCTYPE-ARCFOUR-HMAC-MD5'))
+
+# Message types
+KRB_ERROR = int(krb5_asn1.MessageTypeValues('krb-error'))
+KRB_AP_REQ = int(krb5_asn1.MessageTypeValues('krb-ap-req'))
+KRB_AS_REP = int(krb5_asn1.MessageTypeValues('krb-as-rep'))
+KRB_AS_REQ = int(krb5_asn1.MessageTypeValues('krb-as-req'))
+KRB_TGS_REP = int(krb5_asn1.MessageTypeValues('krb-tgs-rep'))
+KRB_TGS_REQ = int(krb5_asn1.MessageTypeValues('krb-tgs-req'))
+
+# PAData types
+PADATA_ENC_TIMESTAMP = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-ENC-TIMESTAMP'))
+PADATA_ENCRYPTED_CHALLENGE = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-ENCRYPTED-CHALLENGE'))
+PADATA_ETYPE_INFO = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-ETYPE-INFO'))
+PADATA_ETYPE_INFO2 = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-ETYPE-INFO2'))
+PADATA_FOR_USER = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-FOR-USER'))
+PADATA_FX_COOKIE = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-FX-COOKIE'))
+PADATA_FX_ERROR = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-FX-ERROR'))
+PADATA_FX_FAST = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-FX-FAST'))
+PADATA_KDC_REQ = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-KDC-REQ'))
+PADATA_PAC_OPTIONS = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-PAC-OPTIONS'))
+PADATA_PAC_REQUEST = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-PA-PAC-REQUEST'))
+PADATA_PK_AS_REQ = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-PK-AS-REQ'))
+PADATA_PK_AS_REP_19 = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-PK-AS-REP-19'))
+PADATA_PW_SALT = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-PW-SALT'))
+PADATA_SUPPORTED_ETYPES = int(
+ krb5_asn1.PADataTypeValues('kRB5-PADATA-SUPPORTED-ETYPES'))
+
+# Error codes
+KDC_ERR_C_PRINCIPAL_UNKNOWN = 6
+KDC_ERR_S_PRINCIPAL_UNKNOWN = 7
+KDC_ERR_POLICY = 12
+KDC_ERR_BADOPTION = 13
+KDC_ERR_ETYPE_NOSUPP = 14
+KDC_ERR_SUMTYPE_NOSUPP = 15
+KDC_ERR_TGT_REVOKED = 20
+KDC_ERR_PREAUTH_FAILED = 24
+KDC_ERR_PREAUTH_REQUIRED = 25
+KDC_ERR_BAD_INTEGRITY = 31
+KDC_ERR_NOT_US = 35
+KDC_ERR_BADMATCH = 36
+KDC_ERR_SKEW = 37
+KDC_ERR_MODIFIED = 41
+KDC_ERR_INAPP_CKSUM = 50
+KDC_ERR_GENERIC = 60
+KDC_ERR_WRONG_REALM = 68
+KDC_ERR_CLIENT_NAME_MISMATCH = 75
+KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS = 93
+
+# Extended error types
+KERB_AP_ERR_TYPE_SKEW_RECOVERY = int(
+ krb5_asn1.KerbErrorDataTypeValues('kERB-AP-ERR-TYPE-SKEW-RECOVERY'))
+KERB_ERR_TYPE_EXTENDED = int(
+ krb5_asn1.KerbErrorDataTypeValues('kERB-ERR-TYPE-EXTENDED'))
+
+# Name types
+NT_UNKNOWN = int(krb5_asn1.NameTypeValues('kRB5-NT-UNKNOWN'))
+NT_PRINCIPAL = int(krb5_asn1.NameTypeValues('kRB5-NT-PRINCIPAL'))
+NT_SRV_HST = int(krb5_asn1.NameTypeValues('kRB5-NT-SRV-HST'))
+NT_SRV_INST = int(krb5_asn1.NameTypeValues('kRB5-NT-SRV-INST'))
+NT_ENTERPRISE_PRINCIPAL = int(krb5_asn1.NameTypeValues(
+ 'kRB5-NT-ENTERPRISE-PRINCIPAL'))
+NT_WELLKNOWN = int(krb5_asn1.NameTypeValues('kRB5-NT-WELLKNOWN'))
+
+# Authorization data ad-type values
+
+AD_IF_RELEVANT = 1
+AD_INTENDED_FOR_SERVER = 2
+AD_INTENDED_FOR_APPLICATION_CLASS = 3
+AD_KDC_ISSUED = 4
+AD_AND_OR = 5
+AD_MANDATORY_TICKET_EXTENSIONS = 6
+AD_IN_TICKET_EXTENSIONS = 7
+AD_MANDATORY_FOR_KDC = 8
+AD_INITIAL_VERIFIED_CAS = 9
+AD_FX_FAST_ARMOR = 71
+AD_FX_FAST_USED = 72
+AD_WIN2K_PAC = 128
+AD_SIGNTICKET = 512
+
+# Key usage numbers
+# RFC 4120 Section 7.5.1. Key Usage Numbers
+KU_PA_ENC_TIMESTAMP = 1
+''' AS-REQ PA-ENC-TIMESTAMP padata timestamp, encrypted with the
+ client key (section 5.2.7.2) '''
+KU_TICKET = 2
+''' AS-REP Ticket and TGS-REP Ticket (includes tgs session key or
+ application session key), encrypted with the service key
+ (section 5.3) '''
+KU_AS_REP_ENC_PART = 3
+''' AS-REP encrypted part (includes tgs session key or application
+ session key), encrypted with the client key (section 5.4.2) '''
+KU_TGS_REQ_AUTH_DAT_SESSION = 4
+''' TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with the tgs
+ session key (section 5.4.1) '''
+KU_TGS_REQ_AUTH_DAT_SUBKEY = 5
+''' TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with the tgs
+ authenticator subkey (section 5.4.1) '''
+KU_TGS_REQ_AUTH_CKSUM = 6
+''' TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator cksum, keyed
+ with the tgs session key (section 5.5.1) '''
+KU_TGS_REQ_AUTH = 7
+''' TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator (includes tgs
+ authenticator subkey), encrypted with the tgs session key
+ (section 5.5.1) '''
+KU_TGS_REP_ENC_PART_SESSION = 8
+''' TGS-REP encrypted part (includes application session key),
+ encrypted with the tgs session key (section 5.4.2) '''
+KU_TGS_REP_ENC_PART_SUB_KEY = 9
+''' TGS-REP encrypted part (includes application session key),
+ encrypted with the tgs authenticator subkey (section 5.4.2) '''
+KU_AP_REQ_AUTH_CKSUM = 10
+''' AP-REQ Authenticator cksum, keyed with the application session
+ key (section 5.5.1) '''
+KU_AP_REQ_AUTH = 11
+''' AP-REQ Authenticator (includes application authenticator
+ subkey), encrypted with the application session key (section 5.5.1) '''
+KU_AP_REQ_ENC_PART = 12
+''' AP-REP encrypted part (includes application session subkey),
+ encrypted with the application session key (section 5.5.2) '''
+KU_KRB_PRIV = 13
+''' KRB-PRIV encrypted part, encrypted with a key chosen by the
+ application (section 5.7.1) '''
+KU_KRB_CRED = 14
+''' KRB-CRED encrypted part, encrypted with a key chosen by the
+ application (section 5.8.1) '''
+KU_KRB_SAFE_CKSUM = 15
+''' KRB-SAFE cksum, keyed with a key chosen by the application
+ (section 5.6.1) '''
+KU_NON_KERB_SALT = 16
+KU_NON_KERB_CKSUM_SALT = 17
+
+KU_ACCEPTOR_SEAL = 22
+KU_ACCEPTOR_SIGN = 23
+KU_INITIATOR_SEAL = 24
+KU_INITIATOR_SIGN = 25
+
+KU_FAST_REQ_CHKSUM = 50
+KU_FAST_ENC = 51
+KU_FAST_REP = 52
+KU_FAST_FINISHED = 53
+KU_ENC_CHALLENGE_CLIENT = 54
+KU_ENC_CHALLENGE_KDC = 55
+
+# Armor types
+FX_FAST_ARMOR_AP_REQUEST = 1
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/rfc4120_pyasn1.py samba-4.13.14+dfsg/python/samba/tests/krb5/rfc4120_pyasn1.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/rfc4120_pyasn1.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/rfc4120_pyasn1.py 2021-10-29 06:17:36.000000000 +0000
@@ -1,5 +1,5 @@
# Auto-generated by asn1ate v.0.6.1.dev0 from rfc4120.asn1
-# (last modified on 2020-05-06 17:51:00.323318)
+# (last modified on 2021-06-25 12:10:34.484667)
# KerberosV5Spec2
from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful
@@ -120,7 +120,7 @@
EncryptedData.componentType = namedtype.NamedTypes(
namedtype.NamedType('etype', EncryptionType().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
- namedtype.OptionalNamedType('kvno', UInt32().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
+ namedtype.OptionalNamedType('kvno', Int32().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.NamedType('cipher', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
)
@@ -175,6 +175,26 @@
)
+class APOptionsValues(univ.BitString):
+ pass
+
+
+APOptionsValues.namedValues = namedval.NamedValues(
+ ('reserved', 0),
+ ('use-session-key', 1),
+ ('mutual-required', 2)
+)
+
+
+class APOptionsSequence(univ.Sequence):
+ pass
+
+
+APOptionsSequence.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('dummy', APOptionsValues().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
+)
+
+
class PADataType(Int32):
pass
@@ -384,7 +404,7 @@
ETYPE_INFO_ENTRY.componentType = namedtype.NamedTypes(
- namedtype.NamedType('etype', Int32().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
+ namedtype.NamedType('etype', EncryptionType().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
namedtype.OptionalNamedType('salt', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
)
@@ -401,7 +421,7 @@
ETYPE_INFO2_ENTRY.componentType = namedtype.NamedTypes(
- namedtype.NamedType('etype', Int32().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
+ namedtype.NamedType('etype', EncryptionType().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
namedtype.OptionalNamedType('salt', KerberosString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.OptionalNamedType('s2kparams', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
)
@@ -438,6 +458,13 @@
))
+class METHOD_DATA(univ.SequenceOf):
+ pass
+
+
+METHOD_DATA.componentType = PA_DATA()
+
+
class TicketFlags(KerberosFlags):
pass
@@ -458,7 +485,8 @@
namedtype.OptionalNamedType('renew-till', KerberosTime().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 8))),
namedtype.NamedType('srealm', Realm().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 9))),
namedtype.NamedType('sname', PrincipalName().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 10))),
- namedtype.OptionalNamedType('caddr', HostAddresses().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 11)))
+ namedtype.OptionalNamedType('caddr', HostAddresses().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 11))),
+ namedtype.OptionalNamedType('encrypted-pa-data', METHOD_DATA().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 12)))
)
@@ -591,6 +619,17 @@
)
+class FastOptions(univ.BitString):
+ pass
+
+
+FastOptions.namedValues = namedval.NamedValues(
+ ('reserved', 0),
+ ('hide-client-names', 1),
+ ('kdc-follow-referrals', 16)
+)
+
+
class KDCOptionsValues(univ.BitString):
pass
@@ -610,7 +649,8 @@
('opt-hardware-auth', 11),
('unused12', 12),
('unused13', 13),
- ('unused15', 15),
+ ('cname-in-addl-tkt', 14),
+ ('canonicalize', 15),
('disable-transited-check', 26),
('renewable-ok', 27),
('enc-tkt-in-skey', 28),
@@ -628,6 +668,57 @@
)
+class KERB_AD_RESTRICTION_ENTRY(univ.Sequence):
+ pass
+
+
+KERB_AD_RESTRICTION_ENTRY.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('restriction-type', Int32().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
+ namedtype.NamedType('restriction', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
+)
+
+
+class KerbErrorDataType(univ.Integer):
+ pass
+
+
+class KERB_ERROR_DATA(univ.Sequence):
+ pass
+
+
+KERB_ERROR_DATA.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('data-type', KerbErrorDataType().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
+ namedtype.OptionalNamedType('data-value', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2)))
+)
+
+
+class KERB_KEY_LIST_REP(univ.SequenceOf):
+ pass
+
+
+KERB_KEY_LIST_REP.componentType = EncryptionKey()
+
+
+class KERB_KEY_LIST_REQ(univ.SequenceOf):
+ pass
+
+
+KERB_KEY_LIST_REQ.componentType = EncryptionType()
+
+
+class KERB_LOCAL(univ.OctetString):
+ pass
+
+
+class KERB_PA_PAC_REQUEST(univ.Sequence):
+ pass
+
+
+KERB_PA_PAC_REQUEST.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('include-pac', univ.Boolean().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
+)
+
+
class KRB_CRED(univ.Sequence):
pass
@@ -702,11 +793,89 @@
)
-class METHOD_DATA(univ.SequenceOf):
+class KerbErrorDataTypeValues(univ.Integer):
pass
-METHOD_DATA.componentType = PA_DATA()
+KerbErrorDataTypeValues.namedValues = namedval.NamedValues(
+ ('kERB-AP-ERR-TYPE-SKEW-RECOVERY', 2),
+ ('kERB-ERR-TYPE-EXTENDED', 3)
+)
+
+
+class KerbErrorDataTypeSequence(univ.Sequence):
+ pass
+
+
+KerbErrorDataTypeSequence.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('dummy', KerbErrorDataTypeValues().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
+)
+
+
+class KrbFastArmor(univ.Sequence):
+ pass
+
+
+KrbFastArmor.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('armor-type', Int32().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
+ namedtype.NamedType('armor-value', univ.OctetString().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)))
+)
+
+
+class KrbFastArmoredRep(univ.Sequence):
+ pass
+
+
+KrbFastArmoredRep.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('enc-fast-rep', EncryptedData().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
+)
+
+
+class KrbFastArmoredReq(univ.Sequence):
+ pass
+
+
+KrbFastArmoredReq.componentType = namedtype.NamedTypes(
+ namedtype.OptionalNamedType('armor', KrbFastArmor().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
+ namedtype.NamedType('req-checksum', Checksum().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
+ namedtype.NamedType('enc-fast-req', EncryptedData().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
+)
+
+
+class KrbFastFinished(univ.Sequence):
+ pass
+
+
+KrbFastFinished.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('timestamp', KerberosTime().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
+ namedtype.NamedType('usec', Int32().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
+ namedtype.NamedType('crealm', Realm().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
+ namedtype.NamedType('cname', PrincipalName().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 3))),
+ namedtype.NamedType('ticket-checksum', Checksum().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 4)))
+)
+
+
+class KrbFastReq(univ.Sequence):
+ pass
+
+
+KrbFastReq.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('fast-options', FastOptions().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
+ namedtype.NamedType('padata', univ.SequenceOf(componentType=PA_DATA()).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
+ namedtype.NamedType('req-body', KDC_REQ_BODY().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2)))
+)
+
+
+class KrbFastResponse(univ.Sequence):
+ pass
+
+
+KrbFastResponse.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('padata', univ.SequenceOf(componentType=PA_DATA()).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))),
+ namedtype.OptionalNamedType('strengthen-key', EncryptionKey().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))),
+ namedtype.OptionalNamedType('finished', KrbFastFinished().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))),
+ namedtype.NamedType('nonce', UInt32().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3)))
+)
class MessageTypeValues(univ.Integer):
@@ -780,6 +949,37 @@
)
+class PA_FX_FAST_REPLY(univ.Choice):
+ pass
+
+
+PA_FX_FAST_REPLY.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('armored-data', KrbFastArmoredRep().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
+)
+
+
+class PA_FX_FAST_REQUEST(univ.Choice):
+ pass
+
+
+PA_FX_FAST_REQUEST.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('armored-data', KrbFastArmoredReq().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0)))
+)
+
+
+class PACOptionFlags(KerberosFlags):
+ pass
+
+
+class PA_PAC_OPTIONS(univ.Sequence):
+ pass
+
+
+PA_PAC_OPTIONS.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('options', PACOptionFlags().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
+)
+
+
class PA_S4U2Self(univ.Sequence):
pass
@@ -792,6 +992,31 @@
)
+class PA_SUPPORTED_ENCTYPES(Int32):
+ pass
+
+
+class PACOptionFlagsValues(univ.BitString):
+ pass
+
+
+PACOptionFlagsValues.namedValues = namedval.NamedValues(
+ ('claims', 0),
+ ('branch-aware', 1),
+ ('forward-to-full-dc', 2),
+ ('resource-based-constrained-delegation', 3)
+)
+
+
+class PACOptionFlagsSequence(univ.Sequence):
+ pass
+
+
+PACOptionFlagsSequence.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('dummy', PACOptionFlagsValues().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)))
+)
+
+
class PADataTypeValues(univ.Integer):
pass
@@ -851,7 +1076,8 @@
('kRB5-PADATA-PKINIT-KX', 147),
('kRB5-PADATA-PKU2U-NAME', 148),
('kRB5-PADATA-REQ-ENC-PA-REP', 149),
- ('kRB5-PADATA-SUPPORTED-ETYPES', 165)
+ ('kRB5-PADATA-SUPPORTED-ETYPES', 165),
+ ('kRB5-PADATA-PAC-OPTIONS', 167)
)
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/rfc4120_pyasn1_regen.sh samba-4.13.14+dfsg/python/samba/tests/krb5/rfc4120_pyasn1_regen.sh
--- samba-4.13.3+dfsg/python/samba/tests/krb5/rfc4120_pyasn1_regen.sh 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/rfc4120_pyasn1_regen.sh 1970-01-01 00:00:00.000000000 +0000
@@ -1,41 +0,0 @@
-#!/bin/bash
-#
-
-#
-# I used https://github.com/kimgr/asn1ate.git
-# to generate pyasn1 bindings for rfc4120.asn1
-#
-
-PATH_TO_ASN1ATE_CHECKOUT=$1
-PATH_TO_ASN1_INPUT_FILE=$2
-
-set -u
-set -e
-
-usage() {
- echo "usage: $0 PATH_TO_ASN1ATE_CHECKOUT PATH_TO_ASN1_INPUT_FILE > PATH_TO_PYASN1_OUTPUT_FILE"
-}
-
-test -n "${PATH_TO_ASN1ATE_CHECKOUT}" || {
- usage
- exit 1
-}
-test -n "${PATH_TO_ASN1_INPUT_FILE}" || {
- usage
- exit 1
-}
-test -d "${PATH_TO_ASN1ATE_CHECKOUT}" || {
- usage
- exit 1
-}
-test -f "${PATH_TO_ASN1_INPUT_FILE}" || {
- usage
- exit 1
-}
-
-PATH_TO_PYASN1GEN_PY="${PATH_TO_ASN1ATE_CHECKOUT}/asn1ate/pyasn1gen.py"
-
-PYTHONPATH="${PATH_TO_ASN1ATE_CHECKOUT}:${PYTHONPATH-}"
-export PYTHONPATH
-
-python3 "${PATH_TO_PYASN1GEN_PY}" "${PATH_TO_ASN1_INPUT_FILE}"
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/rodc_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/rodc_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/rodc_tests.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/rodc_tests.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class RodcKerberosTests(KDCBaseTest):
+
+ def setUp(self):
+ super().setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ # Ensure that an RODC correctly issues tickets signed with its krbtgt key
+ # and including the RODCIdentifier.
+ def test_rodc_ticket_signature(self):
+ user_creds = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ opts={
+ 'allowed_replication': True,
+ 'revealed_to_rodc': True
+ })
+ target_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={
+ 'allowed_replication': True,
+ 'revealed_to_rodc': True
+ })
+
+ krbtgt_creds = self.get_rodc_krbtgt_creds()
+ rodc_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+
+ # Get a TGT from the RODC.
+ tgt = self.get_tgt(user_creds, to_rodc=True)
+
+ # Ensure the PAC contains the expected checksums.
+ self.verify_ticket(tgt, rodc_key)
+
+ # Get a service ticket from the RODC.
+ service_ticket = self.get_service_ticket(tgt, target_creds,
+ to_rodc=True)
+
+ # Ensure the PAC contains the expected checksums.
+ self.verify_ticket(service_ticket, rodc_key)
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/s4u_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/s4u_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/s4u_tests.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/s4u_tests.py 2021-11-08 11:29:14.000000000 +0000
@@ -18,19 +18,42 @@
import sys
import os
+import functools
sys.path.insert(0, "bin/python")
os.environ["PYTHONUNBUFFERED"] = "1"
+from samba import ntstatus
+from samba.dcerpc import krb5pac, lsa
+
from samba.tests import env_get_var_value
-from samba.tests.krb5.kcrypto import Cksumtype
-from samba.tests.krb5.raw_testcase import RawKerberosTest
+from samba.tests.krb5.kcrypto import Cksumtype, Enctype
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+from samba.tests.krb5.raw_testcase import (
+ RodcPacEncryptionKey,
+ ZeroedChecksumKey
+)
+from samba.tests.krb5.rfc4120_constants import (
+ AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ KDC_ERR_BADOPTION,
+ KDC_ERR_BAD_INTEGRITY,
+ KDC_ERR_GENERIC,
+ KDC_ERR_INAPP_CKSUM,
+ KDC_ERR_MODIFIED,
+ KDC_ERR_SUMTYPE_NOSUPP,
+ KU_PA_ENC_TIMESTAMP,
+ KU_AS_REP_ENC_PART,
+ KU_TGS_REP_ENC_PART_SUB_KEY,
+ NT_PRINCIPAL
+)
import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
global_asn1_print = False
global_hexdump = False
-class S4UKerberosTests(RawKerberosTest):
+
+class S4UKerberosTests(KDCBaseTest):
def setUp(self):
super(S4UKerberosTests, self).setUp()
@@ -50,7 +73,7 @@
kdc_options = krb5_asn1.KDCOptions('forwardable')
padata = None
- etypes=(18,17,23)
+ etypes = (18, 17, 23)
req = self.AS_REQ_create(padata=padata,
kdc_options=str(kdc_options),
@@ -63,22 +86,22 @@
nonce=0x7fffffff,
etypes=etypes,
addresses=None,
- EncAuthorizationData=None,
- EncAuthorizationData_key=None,
additional_tickets=None)
rep = self.send_recv_transaction(req)
self.assertIsNotNone(rep)
self.assertEqual(rep['msg-type'], 30)
self.assertEqual(rep['error-code'], 25)
- rep_padata = self.der_decode(rep['e-data'], asn1Spec=krb5_asn1.METHOD_DATA())
+ rep_padata = self.der_decode(
+ rep['e-data'], asn1Spec=krb5_asn1.METHOD_DATA())
for pa in rep_padata:
if pa['padata-type'] == 19:
etype_info2 = pa['padata-value']
break
- etype_info2 = self.der_decode(etype_info2, asn1Spec=krb5_asn1.ETYPE_INFO2())
+ etype_info2 = self.der_decode(
+ etype_info2, asn1Spec=krb5_asn1.ETYPE_INFO2())
key = self.PasswordKey_from_etype_info2(service_creds, etype_info2[0])
@@ -86,8 +109,7 @@
pa_ts = self.PA_ENC_TS_ENC_create(patime, pausec)
pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
- enc_pa_ts_usage = 1
- pa_ts = self.EncryptedData_create(key, enc_pa_ts_usage, pa_ts)
+ pa_ts = self.EncryptedData_create(key, KU_PA_ENC_TIMESTAMP, pa_ts)
pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.EncryptedData())
pa_ts = self.PA_DATA_create(2, pa_ts)
@@ -106,8 +128,6 @@
nonce=0x7fffffff,
etypes=etypes,
addresses=None,
- EncAuthorizationData=None,
- EncAuthorizationData_key=None,
additional_tickets=None)
rep = self.send_recv_transaction(req)
self.assertIsNotNone(rep)
@@ -115,9 +135,15 @@
msg_type = rep['msg-type']
self.assertEqual(msg_type, 11)
- usage = 3
- enc_part2 = key.decrypt(usage, rep['enc-part']['cipher'])
- enc_part2 = self.der_decode(enc_part2, asn1Spec=krb5_asn1.EncASRepPart())
+ enc_part2 = key.decrypt(KU_AS_REP_ENC_PART, rep['enc-part']['cipher'])
+ # MIT KDC encodes both EncASRepPart and EncTGSRepPart with
+ # application tag 26
+ try:
+ enc_part2 = self.der_decode(
+ enc_part2, asn1Spec=krb5_asn1.EncASRepPart())
+ except Exception:
+ enc_part2 = self.der_decode(
+ enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart())
# S4U2Self Request
sname = cname
@@ -135,7 +161,6 @@
padata = [pa_s4u]
subkey = self.RandomKey(ticket_session_key.etype)
- subkey_usage = 9
(ctime, cusec) = self.get_KerberosTimeWithUsec()
@@ -163,12 +188,15 @@
msg_type = rep['msg-type']
if msg_type == 13:
- enc_part2 = subkey.decrypt(subkey_usage, rep['enc-part']['cipher'])
- enc_part2 = self.der_decode(enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart())
+ enc_part2 = subkey.decrypt(
+ KU_TGS_REP_ENC_PART_SUB_KEY, rep['enc-part']['cipher'])
+ enc_part2 = self.der_decode(
+ enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart())
return msg_type
- # Using the checksum type from the tgt_session_key happens to work everywhere
+ # Using the checksum type from the tgt_session_key happens to work
+ # everywhere
def test_s4u2self(self):
msg_type = self._test_s4u2self()
self.assertEqual(msg_type, 13)
@@ -190,8 +218,1091 @@
msg_type = self._test_s4u2self(pa_s4u2self_ctype=Cksumtype.CRC32)
self.assertEqual(msg_type, 30)
+ def _run_s4u2self_test(self, kdc_dict):
+ client_opts = kdc_dict.pop('client_opts', None)
+ client_creds = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ opts=client_opts)
+
+ service_opts = kdc_dict.pop('service_opts', None)
+ service_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts=service_opts)
+
+ service_tgt = self.get_tgt(service_creds)
+ modify_service_tgt_fn = kdc_dict.pop('modify_service_tgt_fn', None)
+ if modify_service_tgt_fn is not None:
+ service_tgt = modify_service_tgt_fn(service_tgt)
+
+ client_name = client_creds.get_username()
+ client_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[client_name])
+
+ samdb = self.get_samdb()
+ client_dn = client_creds.get_dn()
+ sid = self.get_objectSid(samdb, client_dn)
+
+ service_name = service_creds.get_username()[:-1]
+ service_sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=['host', service_name])
+
+ realm = client_creds.get_realm()
+
+ expected_flags = kdc_dict.pop('expected_flags', None)
+ if expected_flags is not None:
+ expected_flags = krb5_asn1.TicketFlags(expected_flags)
+
+ unexpected_flags = kdc_dict.pop('unexpected_flags', None)
+ if unexpected_flags is not None:
+ unexpected_flags = krb5_asn1.TicketFlags(unexpected_flags)
+
+ expected_error_mode = kdc_dict.pop('expected_error_mode', 0)
+ expected_status = kdc_dict.pop('expected_status', None)
+ if expected_error_mode:
+ check_error_fn = self.generic_check_kdc_error
+ check_rep_fn = None
+ else:
+ check_error_fn = None
+ check_rep_fn = self.generic_check_kdc_rep
+
+ self.assertIsNone(expected_status)
+
+ kdc_options = kdc_dict.pop('kdc_options', '0')
+ kdc_options = krb5_asn1.KDCOptions(kdc_options)
+
+ service_decryption_key = self.TicketDecryptionKey_from_creds(
+ service_creds)
+
+ authenticator_subkey = self.RandomKey(Enctype.AES256)
+
+ etypes = kdc_dict.pop('etypes', (AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5))
+
+ def generate_s4u2self_padata(_kdc_exchange_dict,
+ _callback_dict,
+ req_body):
+ pa_s4u = self.PA_S4U2Self_create(
+ name=client_cname,
+ realm=realm,
+ tgt_session_key=service_tgt.session_key,
+ ctype=None)
+
+ return [pa_s4u], req_body
+
+ kdc_exchange_dict = self.tgs_exchange_dict(
+ expected_crealm=realm,
+ expected_cname=client_cname,
+ expected_srealm=realm,
+ expected_sname=service_sname,
+ expected_account_name=client_name,
+ expected_sid=sid,
+ expected_flags=expected_flags,
+ unexpected_flags=unexpected_flags,
+ ticket_decryption_key=service_decryption_key,
+ expect_ticket_checksum=True,
+ generate_padata_fn=generate_s4u2self_padata,
+ check_error_fn=check_error_fn,
+ check_rep_fn=check_rep_fn,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ expected_error_mode=expected_error_mode,
+ expected_status=expected_status,
+ tgt=service_tgt,
+ authenticator_subkey=authenticator_subkey,
+ kdc_options=str(kdc_options),
+ expect_claims=False)
+
+ self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=None,
+ realm=realm,
+ sname=service_sname,
+ etypes=etypes)
+
+ # Ensure we used all the parameters given to us.
+ self.assertEqual({}, kdc_dict)
+
+ # Test performing an S4U2Self operation with a forwardable ticket. The
+ # resulting ticket should have the 'forwardable' flag set.
+ def test_s4u2self_forwardable(self):
+ self._run_s4u2self_test(
+ {
+ 'client_opts': {
+ 'not_delegated': False
+ },
+ 'kdc_options': 'forwardable',
+ 'modify_service_tgt_fn': functools.partial(
+ self.set_ticket_forwardable, flag=True),
+ 'expected_flags': 'forwardable'
+ })
+
+ # Test performing an S4U2Self operation with a forwardable ticket that does
+ # not contain a PAC. The request should fail.
+ def test_s4u2self_no_pac(self):
+ def forwardable_no_pac(ticket):
+ ticket = self.set_ticket_forwardable(ticket, flag=True)
+ return self.remove_ticket_pac(ticket)
+
+ self._run_s4u2self_test(
+ {
+ 'expected_error_mode': (KDC_ERR_GENERIC,
+ KDC_ERR_BADOPTION),
+ 'expected_status': ntstatus.NT_STATUS_INVALID_PARAMETER,
+ 'client_opts': {
+ 'not_delegated': False
+ },
+ 'kdc_options': 'forwardable',
+ 'modify_service_tgt_fn': forwardable_no_pac,
+ 'expected_flags': 'forwardable'
+ })
+
+ # Test performing an S4U2Self operation without requesting a forwardable
+ # ticket. The resulting ticket should not have the 'forwardable' flag set.
+ def test_s4u2self_without_forwardable(self):
+ self._run_s4u2self_test(
+ {
+ 'client_opts': {
+ 'not_delegated': False
+ },
+ 'modify_service_tgt_fn': functools.partial(
+ self.set_ticket_forwardable, flag=True),
+ 'unexpected_flags': 'forwardable'
+ })
+
+ # Do an S4U2Self with a non-forwardable TGT. The 'forwardable' flag should
+ # not be set on the ticket.
+ def test_s4u2self_not_forwardable(self):
+ self._run_s4u2self_test(
+ {
+ 'client_opts': {
+ 'not_delegated': False
+ },
+ 'kdc_options': 'forwardable',
+ 'modify_service_tgt_fn': functools.partial(
+ self.set_ticket_forwardable, flag=False),
+ 'unexpected_flags': 'forwardable'
+ })
+
+ # Do an S4U2Self with the not_delegated flag set on the client. The
+ # 'forwardable' flag should not be set on the ticket.
+ def test_s4u2self_client_not_delegated(self):
+ self._run_s4u2self_test(
+ {
+ 'client_opts': {
+ 'not_delegated': True
+ },
+ 'kdc_options': 'forwardable',
+ 'modify_service_tgt_fn': functools.partial(
+ self.set_ticket_forwardable, flag=True),
+ 'unexpected_flags': 'forwardable'
+ })
+
+ # Do an S4U2Self with a service not trusted to authenticate for delegation,
+ # but having an empty msDS-AllowedToDelegateTo attribute. The 'forwardable'
+ # flag should be set on the ticket.
+ def test_s4u2self_not_trusted_empty_allowed(self):
+ self._run_s4u2self_test(
+ {
+ 'client_opts': {
+ 'not_delegated': False
+ },
+ 'service_opts': {
+ 'trusted_to_auth_for_delegation': False,
+ 'delegation_to_spn': ()
+ },
+ 'kdc_options': 'forwardable',
+ 'modify_service_tgt_fn': functools.partial(
+ self.set_ticket_forwardable, flag=True),
+ 'expected_flags': 'forwardable'
+ })
+
+ # Do an S4U2Self with a service not trusted to authenticate for delegation
+ # and having a non-empty msDS-AllowedToDelegateTo attribute. The
+ # 'forwardable' flag should not be set on the ticket.
+ def test_s4u2self_not_trusted_nonempty_allowed(self):
+ self._run_s4u2self_test(
+ {
+ 'client_opts': {
+ 'not_delegated': False
+ },
+ 'service_opts': {
+ 'trusted_to_auth_for_delegation': False,
+ 'delegation_to_spn': ('test',)
+ },
+ 'kdc_options': 'forwardable',
+ 'modify_service_tgt_fn': functools.partial(
+ self.set_ticket_forwardable, flag=True),
+ 'unexpected_flags': 'forwardable'
+ })
+
+ # Do an S4U2Self with a service trusted to authenticate for delegation and
+ # having an empty msDS-AllowedToDelegateTo attribute. The 'forwardable'
+ # flag should be set on the ticket.
+ def test_s4u2self_trusted_empty_allowed(self):
+ self._run_s4u2self_test(
+ {
+ 'client_opts': {
+ 'not_delegated': False
+ },
+ 'service_opts': {
+ 'trusted_to_auth_for_delegation': True,
+ 'delegation_to_spn': ()
+ },
+ 'kdc_options': 'forwardable',
+ 'modify_service_tgt_fn': functools.partial(
+ self.set_ticket_forwardable, flag=True),
+ 'expected_flags': 'forwardable'
+ })
+
+ # Do an S4U2Self with a service trusted to authenticate for delegation and
+ # having a non-empty msDS-AllowedToDelegateTo attribute. The 'forwardable'
+ # flag should be set on the ticket.
+ def test_s4u2self_trusted_nonempty_allowed(self):
+ self._run_s4u2self_test(
+ {
+ 'client_opts': {
+ 'not_delegated': False
+ },
+ 'service_opts': {
+ 'trusted_to_auth_for_delegation': True,
+ 'delegation_to_spn': ('test',)
+ },
+ 'kdc_options': 'forwardable',
+ 'modify_service_tgt_fn': functools.partial(
+ self.set_ticket_forwardable, flag=True),
+ 'expected_flags': 'forwardable'
+ })
+
+ def _run_delegation_test(self, kdc_dict):
+ client_opts = kdc_dict.pop('client_opts', None)
+ client_creds = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ opts=client_opts)
+
+ samdb = self.get_samdb()
+ client_dn = client_creds.get_dn()
+ sid = self.get_objectSid(samdb, client_dn)
+
+ service1_opts = kdc_dict.pop('service1_opts', {})
+ service2_opts = kdc_dict.pop('service2_opts', {})
+
+ allow_delegation = kdc_dict.pop('allow_delegation', False)
+ allow_rbcd = kdc_dict.pop('allow_rbcd', False)
+ self.assertFalse(allow_delegation and allow_rbcd)
+
+ if allow_rbcd:
+ service1_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts=service1_opts)
+
+ self.assertNotIn('delegation_from_dn', service2_opts)
+ service2_opts['delegation_from_dn'] = str(service1_creds.get_dn())
+
+ service2_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts=service2_opts)
+ else:
+ service2_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts=service2_opts)
+
+ if allow_delegation:
+ self.assertNotIn('delegation_to_spn', service1_opts)
+ service1_opts['delegation_to_spn'] = service2_creds.get_spn()
+
+ service1_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts=service1_opts)
+
+ client_tkt_options = kdc_dict.pop('client_tkt_options', 'forwardable')
+ expected_flags = krb5_asn1.TicketFlags(client_tkt_options)
+
+ client_tgt = self.get_tgt(client_creds,
+ kdc_options=client_tkt_options,
+ expected_flags=expected_flags)
+ client_service_tkt = self.get_service_ticket(
+ client_tgt,
+ service1_creds,
+ kdc_options=client_tkt_options,
+ expected_flags=expected_flags)
+
+ service1_tgt = self.get_tgt(service1_creds)
+
+ modify_client_tkt_fn = kdc_dict.pop('modify_client_tkt_fn', None)
+ if modify_client_tkt_fn is not None:
+ client_service_tkt = modify_client_tkt_fn(client_service_tkt)
+
+ additional_tickets = [client_service_tkt.ticket]
+
+ modify_service_tgt_fn = kdc_dict.pop('modify_service_tgt_fn', None)
+ if modify_service_tgt_fn is not None:
+ service1_tgt = modify_service_tgt_fn(service1_tgt)
+
+ kdc_options = kdc_dict.pop('kdc_options', None)
+ if kdc_options is None:
+ kdc_options = str(krb5_asn1.KDCOptions('cname-in-addl-tkt'))
+
+ client_username = client_creds.get_username()
+ client_realm = client_creds.get_realm()
+ client_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=[client_username])
+
+ service1_name = service1_creds.get_username()[:-1]
+ service1_realm = service1_creds.get_realm()
+
+ service2_name = service2_creds.get_username()[:-1]
+ service2_realm = service2_creds.get_realm()
+ service2_service = 'host'
+ service2_sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[service2_service,
+ service2_name])
+ service2_decryption_key = self.TicketDecryptionKey_from_creds(
+ service2_creds)
+ service2_etypes = service2_creds.tgs_supported_enctypes
+
+ expected_error_mode = kdc_dict.pop('expected_error_mode')
+ expected_status = kdc_dict.pop('expected_status', None)
+ if expected_error_mode:
+ check_error_fn = self.generic_check_kdc_error
+ check_rep_fn = None
+ else:
+ check_error_fn = None
+ check_rep_fn = self.generic_check_kdc_rep
+
+ self.assertIsNone(expected_status)
+
+ expect_edata = kdc_dict.pop('expect_edata', None)
+ if expect_edata is not None:
+ self.assertTrue(expected_error_mode)
+
+ pac_options = kdc_dict.pop('pac_options', None)
+
+ authenticator_subkey = self.RandomKey(Enctype.AES256)
+
+ etypes = kdc_dict.pop('etypes', (AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5))
+
+ expected_proxy_target = service2_creds.get_spn()
+
+ expected_transited_services = kdc_dict.pop(
+ 'expected_transited_services', [])
+
+ transited_service = f'host/{service1_name}@{service1_realm}'
+ expected_transited_services.append(transited_service)
+
+ expect_pac = kdc_dict.pop('expect_pac', True)
+
+ kdc_exchange_dict = self.tgs_exchange_dict(
+ expected_crealm=client_realm,
+ expected_cname=client_cname,
+ expected_srealm=service2_realm,
+ expected_sname=service2_sname,
+ expected_account_name=client_username,
+ expected_sid=sid,
+ expected_supported_etypes=service2_etypes,
+ ticket_decryption_key=service2_decryption_key,
+ check_error_fn=check_error_fn,
+ check_rep_fn=check_rep_fn,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ expected_error_mode=expected_error_mode,
+ expected_status=expected_status,
+ callback_dict={},
+ tgt=service1_tgt,
+ authenticator_subkey=authenticator_subkey,
+ kdc_options=kdc_options,
+ pac_options=pac_options,
+ expect_edata=expect_edata,
+ expected_proxy_target=expected_proxy_target,
+ expected_transited_services=expected_transited_services,
+ expect_pac=expect_pac)
+
+ self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=None,
+ realm=service2_realm,
+ sname=service2_sname,
+ etypes=etypes,
+ additional_tickets=additional_tickets)
+
+ # Ensure we used all the parameters given to us.
+ self.assertEqual({}, kdc_dict)
+
+ def test_constrained_delegation(self):
+ # Test constrained delegation.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': 0,
+ 'allow_delegation': True
+ })
+
+ def test_constrained_delegation_no_auth_data_required(self):
+ # Test constrained delegation.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': 0,
+ 'allow_delegation': True,
+ 'service2_opts': {
+ 'no_auth_data_required': True
+ },
+ 'expect_pac': False
+ })
+
+ def test_constrained_delegation_existing_delegation_info(self):
+ # Test constrained delegation with an existing S4U_DELEGATION_INFO
+ # structure in the PAC.
+
+ services = ['service1', 'service2', 'service3']
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': 0,
+ 'allow_delegation': True,
+ 'modify_client_tkt_fn': functools.partial(
+ self.add_delegation_info, services=services),
+ 'expected_transited_services': services
+ })
+
+ def test_constrained_delegation_not_allowed(self):
+ # Test constrained delegation when the delegating service does not
+ # allow it.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_BADOPTION,
+ 'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED,
+ 'allow_delegation': False
+ })
+
+ def test_constrained_delegation_no_client_pac(self):
+ # Test constrained delegation when the client service ticket does not
+ # contain a PAC.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': (KDC_ERR_BADOPTION,
+ KDC_ERR_MODIFIED),
+ 'allow_delegation': True,
+ 'modify_client_tkt_fn': self.remove_ticket_pac,
+ 'expect_edata': False
+ })
+
+ def test_constrained_delegation_no_service_pac(self):
+ # Test constrained delegation when the service TGT does not contain a
+ # PAC.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': 0,
+ 'allow_delegation': True,
+ 'modify_service_tgt_fn': self.remove_ticket_pac
+ })
+
+ def test_constrained_delegation_no_client_pac_no_auth_data_required(self):
+ # Test constrained delegation when the client service ticket does not
+ # contain a PAC.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': (KDC_ERR_BADOPTION,
+ KDC_ERR_MODIFIED),
+ 'allow_delegation': True,
+ 'modify_client_tkt_fn': self.remove_ticket_pac,
+ 'expect_edata': False,
+ 'service2_opts': {
+ 'no_auth_data_required': True
+ }
+ })
+
+ def test_constrained_delegation_no_service_pac_no_auth_data_required(self):
+ # Test constrained delegation when the service TGT does not contain a
+ # PAC.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': (KDC_ERR_BADOPTION,
+ KDC_ERR_MODIFIED),
+ 'allow_delegation': True,
+ 'modify_service_tgt_fn': self.remove_ticket_pac,
+ 'service2_opts': {
+ 'no_auth_data_required': True
+ }
+ })
+
+ def test_constrained_delegation_non_forwardable(self):
+ # Test constrained delegation with a non-forwardable ticket.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_BADOPTION,
+ 'expected_status': ntstatus.NT_STATUS_ACCOUNT_RESTRICTION,
+ 'allow_delegation': True,
+ 'modify_client_tkt_fn': functools.partial(
+ self.set_ticket_forwardable, flag=False)
+ })
+
+ def test_constrained_delegation_pac_options_rbcd(self):
+ # Test constrained delegation, but with the RBCD bit set in the PAC
+ # options.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': 0,
+ 'pac_options': '0001', # supports RBCD
+ 'allow_delegation': True
+ })
+
+ def test_rbcd_no_auth_data_required(self):
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': 0,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'service2_opts': {
+ 'no_auth_data_required': True
+ },
+ 'expect_pac': False
+ })
+
+ def test_rbcd_existing_delegation_info(self):
+ # Test constrained delegation with an existing S4U_DELEGATION_INFO
+ # structure in the PAC.
+
+ services = ['service1', 'service2', 'service3']
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': 0,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_client_tkt_fn': functools.partial(
+ self.add_delegation_info, services=services),
+ 'expected_transited_services': services
+ })
+
+ def test_rbcd_not_allowed(self):
+ # Test resource-based constrained delegation when the target service
+ # does not allow it.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_BADOPTION,
+ 'expected_status': ntstatus.NT_STATUS_NOT_FOUND,
+ 'allow_rbcd': False,
+ 'pac_options': '0001' # supports RBCD
+ })
+
+ def test_rbcd_no_client_pac_a(self):
+ # Test constrained delegation when the client service ticket does not
+ # contain a PAC, and an empty msDS-AllowedToDelegateTo attribute.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_MODIFIED,
+ 'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_client_tkt_fn': self.remove_ticket_pac
+ })
+
+ def test_rbcd_no_client_pac_b(self):
+ # Test constrained delegation when the client service ticket does not
+ # contain a PAC, and a non-empty msDS-AllowedToDelegateTo attribute.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_MODIFIED,
+ 'expected_status': ntstatus.NT_STATUS_NO_MATCH,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_client_tkt_fn': self.remove_ticket_pac,
+ 'service1_opts': {
+ 'delegation_to_spn': ('host/test')
+ }
+ })
+
+ def test_rbcd_no_service_pac(self):
+ # Test constrained delegation when the service TGT does not contain a
+ # PAC.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_BADOPTION,
+ 'expected_status':
+ ntstatus.NT_STATUS_NOT_FOUND,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_service_tgt_fn': self.remove_ticket_pac
+ })
+
+ def test_rbcd_no_client_pac_no_auth_data_required_a(self):
+ # Test constrained delegation when the client service ticket does not
+ # contain a PAC, and an empty msDS-AllowedToDelegateTo attribute.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_MODIFIED,
+ 'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_client_tkt_fn': self.remove_ticket_pac,
+ 'service2_opts': {
+ 'no_auth_data_required': True
+ }
+ })
+
+ def test_rbcd_no_client_pac_no_auth_data_required_b(self):
+ # Test constrained delegation when the client service ticket does not
+ # contain a PAC, and a non-empty msDS-AllowedToDelegateTo attribute.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_MODIFIED,
+ 'expected_status': ntstatus.NT_STATUS_NO_MATCH,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_client_tkt_fn': self.remove_ticket_pac,
+ 'service1_opts': {
+ 'delegation_to_spn': ('host/test')
+ },
+ 'service2_opts': {
+ 'no_auth_data_required': True
+ }
+ })
+
+ def test_rbcd_no_service_pac_no_auth_data_required(self):
+ # Test constrained delegation when the service TGT does not contain a
+ # PAC.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_BADOPTION,
+ 'expected_status':
+ ntstatus.NT_STATUS_NOT_FOUND,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_service_tgt_fn': self.remove_ticket_pac,
+ 'service2_opts': {
+ 'no_auth_data_required': True
+ }
+ })
+
+ def test_rbcd_non_forwardable(self):
+ # Test resource-based constrained delegation with a non-forwardable
+ # ticket.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_BADOPTION,
+ 'expected_status': ntstatus.NT_STATUS_ACCOUNT_RESTRICTION,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_client_tkt_fn': functools.partial(
+ self.set_ticket_forwardable, flag=False)
+ })
+
+ def test_rbcd_no_pac_options_a(self):
+ # Test resource-based constrained delegation without the RBCD bit set
+ # in the PAC options, and an empty msDS-AllowedToDelegateTo attribute.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_BADOPTION,
+ 'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED,
+ 'allow_rbcd': True,
+ 'pac_options': '1' # does not support RBCD
+ })
+
+ def test_rbcd_no_pac_options_b(self):
+ # Test resource-based constrained delegation without the RBCD bit set
+ # in the PAC options, and a non-empty msDS-AllowedToDelegateTo
+ # attribute.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_BADOPTION,
+ 'expected_status': ntstatus.NT_STATUS_NO_MATCH,
+ 'allow_rbcd': True,
+ 'pac_options': '1', # does not support RBCD
+ 'service1_opts': {
+ 'delegation_to_spn': ('host/test')
+ }
+ })
+
+ def test_bronze_bit_constrained_delegation_old_checksum(self):
+ # Attempt to modify the ticket without updating the PAC checksums.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': (KDC_ERR_MODIFIED,
+ KDC_ERR_BAD_INTEGRITY),
+ 'allow_delegation': True,
+ 'client_tkt_options': '0', # non-forwardable ticket
+ 'modify_client_tkt_fn': functools.partial(
+ self.set_ticket_forwardable,
+ flag=True, update_pac_checksums=False),
+ 'expect_edata': False
+ })
+
+ def test_bronze_bit_rbcd_old_checksum(self):
+ # Attempt to modify the ticket without updating the PAC checksums.
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_MODIFIED,
+ 'expected_status': ntstatus.NT_STATUS_NOT_SUPPORTED,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'client_tkt_options': '0', # non-forwardable ticket
+ 'modify_client_tkt_fn': functools.partial(
+ self.set_ticket_forwardable,
+ flag=True, update_pac_checksums=False)
+ })
+
+ def test_constrained_delegation_missing_client_checksum(self):
+ # Present a user ticket without the required checksums.
+ for checksum in self.pac_checksum_types:
+ with self.subTest(checksum=checksum):
+ if checksum == krb5pac.PAC_TYPE_TICKET_CHECKSUM:
+ expected_error_mode = (KDC_ERR_BADOPTION,
+ KDC_ERR_MODIFIED)
+ else:
+ expected_error_mode = KDC_ERR_GENERIC
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': expected_error_mode,
+ 'allow_delegation': True,
+ 'modify_client_tkt_fn': functools.partial(
+ self.remove_pac_checksum, checksum=checksum),
+ 'expect_edata': False
+ })
+
+ def test_constrained_delegation_missing_service_checksum(self):
+ # Present the service's ticket without the required checksums.
+ for checksum in filter(lambda x: x != krb5pac.PAC_TYPE_TICKET_CHECKSUM,
+ self.pac_checksum_types):
+ with self.subTest(checksum=checksum):
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_GENERIC,
+ 'expected_status':
+ ntstatus.NT_STATUS_INSUFFICIENT_RESOURCES,
+ 'allow_delegation': True,
+ 'modify_service_tgt_fn': functools.partial(
+ self.remove_pac_checksum, checksum=checksum)
+ })
+
+ def test_rbcd_missing_client_checksum(self):
+ # Present a user ticket without the required checksums.
+ for checksum in self.pac_checksum_types:
+ with self.subTest(checksum=checksum):
+ if checksum == krb5pac.PAC_TYPE_TICKET_CHECKSUM:
+ expected_error_mode = KDC_ERR_MODIFIED
+ else:
+ expected_error_mode = KDC_ERR_GENERIC
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': expected_error_mode,
+ 'expected_status':
+ ntstatus.NT_STATUS_NOT_SUPPORTED,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_client_tkt_fn': functools.partial(
+ self.remove_pac_checksum, checksum=checksum)
+ })
+
+ def test_rbcd_missing_service_checksum(self):
+ # Present the service's ticket without the required checksums.
+ for checksum in filter(lambda x: x != krb5pac.PAC_TYPE_TICKET_CHECKSUM,
+ self.pac_checksum_types):
+ with self.subTest(checksum=checksum):
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_GENERIC,
+ 'expected_status':
+ ntstatus.NT_STATUS_INSUFFICIENT_RESOURCES,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_service_tgt_fn': functools.partial(
+ self.remove_pac_checksum, checksum=checksum)
+ })
+
+ def test_constrained_delegation_zeroed_client_checksum(self):
+ # Present a user ticket with invalid checksums.
+ for checksum in self.pac_checksum_types:
+ with self.subTest(checksum=checksum):
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': (KDC_ERR_MODIFIED,
+ KDC_ERR_BAD_INTEGRITY),
+ 'allow_delegation': True,
+ 'modify_client_tkt_fn': functools.partial(
+ self.zeroed_pac_checksum, checksum=checksum),
+ 'expect_edata': False
+ })
+
+ def test_constrained_delegation_zeroed_service_checksum(self):
+ # Present the service's ticket with invalid checksums.
+ for checksum in self.pac_checksum_types:
+ with self.subTest(checksum=checksum):
+ if checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM:
+ expected_error_mode = (KDC_ERR_MODIFIED,
+ KDC_ERR_BAD_INTEGRITY)
+ expected_status = ntstatus.NT_STATUS_WRONG_PASSWORD
+ else:
+ expected_error_mode = 0
+ expected_status = None
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': expected_error_mode,
+ 'expected_status': expected_status,
+ 'allow_delegation': True,
+ 'modify_service_tgt_fn': functools.partial(
+ self.zeroed_pac_checksum, checksum=checksum)
+ })
+
+ def test_rbcd_zeroed_client_checksum(self):
+ # Present a user ticket with invalid checksums.
+ for checksum in self.pac_checksum_types:
+ with self.subTest(checksum=checksum):
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': KDC_ERR_MODIFIED,
+ 'expected_status':
+ ntstatus.NT_STATUS_NOT_SUPPORTED,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_client_tkt_fn': functools.partial(
+ self.zeroed_pac_checksum, checksum=checksum)
+ })
+
+ def test_rbcd_zeroed_service_checksum(self):
+ # Present the service's ticket with invalid checksums.
+ for checksum in self.pac_checksum_types:
+ with self.subTest(checksum=checksum):
+ if checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM:
+ expected_error_mode = (KDC_ERR_MODIFIED,
+ KDC_ERR_BAD_INTEGRITY)
+ expected_status = ntstatus.NT_STATUS_WRONG_PASSWORD
+ else:
+ expected_error_mode = 0
+ expected_status = None
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': expected_error_mode,
+ 'expected_status': expected_status,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_service_tgt_fn': functools.partial(
+ self.zeroed_pac_checksum, checksum=checksum)
+ })
+
+ unkeyed_ctypes = {Cksumtype.MD5, Cksumtype.SHA1, Cksumtype.CRC32}
+
+ def test_constrained_delegation_unkeyed_client_checksum(self):
+ # Present a user ticket with invalid checksums.
+ for checksum in self.pac_checksum_types:
+ for ctype in self.unkeyed_ctypes:
+ with self.subTest(checksum=checksum, ctype=ctype):
+ if (checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM
+ and ctype == Cksumtype.SHA1):
+ expected_error_mode = (KDC_ERR_SUMTYPE_NOSUPP,
+ KDC_ERR_INAPP_CKSUM)
+ else:
+ expected_error_mode = (KDC_ERR_GENERIC,
+ KDC_ERR_INAPP_CKSUM)
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': expected_error_mode,
+ 'allow_delegation': True,
+ 'modify_client_tkt_fn': functools.partial(
+ self.unkeyed_pac_checksum,
+ checksum=checksum, ctype=ctype),
+ 'expect_edata': False
+ })
+
+ def test_constrained_delegation_unkeyed_service_checksum(self):
+ # Present the service's ticket with invalid checksums.
+ for checksum in self.pac_checksum_types:
+ for ctype in self.unkeyed_ctypes:
+ with self.subTest(checksum=checksum, ctype=ctype):
+ if checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM:
+ if ctype == Cksumtype.SHA1:
+ expected_error_mode = (KDC_ERR_SUMTYPE_NOSUPP,
+ KDC_ERR_INAPP_CKSUM)
+ expected_status = ntstatus.NT_STATUS_LOGON_FAILURE
+ else:
+ expected_error_mode = (KDC_ERR_GENERIC,
+ KDC_ERR_INAPP_CKSUM)
+ expected_status = (
+ ntstatus.NT_STATUS_INSUFFICIENT_RESOURCES)
+ else:
+ expected_error_mode = 0
+ expected_status = None
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': expected_error_mode,
+ 'expected_status': expected_status,
+ 'allow_delegation': True,
+ 'modify_service_tgt_fn': functools.partial(
+ self.unkeyed_pac_checksum,
+ checksum=checksum, ctype=ctype)
+ })
+
+ def test_rbcd_unkeyed_client_checksum(self):
+ # Present a user ticket with invalid checksums.
+ for checksum in self.pac_checksum_types:
+ for ctype in self.unkeyed_ctypes:
+ with self.subTest(checksum=checksum, ctype=ctype):
+ if (checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM
+ and ctype == Cksumtype.SHA1):
+ expected_error_mode = KDC_ERR_SUMTYPE_NOSUPP
+ else:
+ expected_error_mode = KDC_ERR_GENERIC
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': expected_error_mode,
+ 'expected_status':
+ ntstatus.NT_STATUS_NOT_SUPPORTED,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_client_tkt_fn': functools.partial(
+ self.unkeyed_pac_checksum,
+ checksum=checksum, ctype=ctype)
+ })
+
+ def test_rbcd_unkeyed_service_checksum(self):
+ # Present the service's ticket with invalid checksums.
+ for checksum in self.pac_checksum_types:
+ for ctype in self.unkeyed_ctypes:
+ with self.subTest(checksum=checksum, ctype=ctype):
+ if checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM:
+ if ctype == Cksumtype.SHA1:
+ expected_error_mode = (KDC_ERR_SUMTYPE_NOSUPP,
+ KDC_ERR_BAD_INTEGRITY)
+ expected_status = ntstatus.NT_STATUS_LOGON_FAILURE
+ else:
+ expected_error_mode = KDC_ERR_GENERIC
+ expected_status = (
+ ntstatus.NT_STATUS_INSUFFICIENT_RESOURCES)
+ else:
+ expected_error_mode = 0
+ expected_status = None
+
+ self._run_delegation_test(
+ {
+ 'expected_error_mode': expected_error_mode,
+ 'expected_status': expected_status,
+ 'allow_rbcd': True,
+ 'pac_options': '0001', # supports RBCD
+ 'modify_service_tgt_fn': functools.partial(
+ self.unkeyed_pac_checksum,
+ checksum=checksum, ctype=ctype)
+ })
+
+ def remove_pac_checksum(self, ticket, checksum):
+ checksum_keys = self.get_krbtgt_checksum_key()
+
+ return self.modified_ticket(ticket,
+ checksum_keys=checksum_keys,
+ include_checksums={checksum: False})
+
+ def zeroed_pac_checksum(self, ticket, checksum):
+ krbtgt_creds = self.get_krbtgt_creds()
+ krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+
+ server_key = ticket.decryption_key
+
+ checksum_keys = {
+ krb5pac.PAC_TYPE_SRV_CHECKSUM: server_key,
+ krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key,
+ krb5pac.PAC_TYPE_TICKET_CHECKSUM: krbtgt_key,
+ }
+
+ if checksum == krb5pac.PAC_TYPE_SRV_CHECKSUM:
+ zeroed_key = server_key
+ else:
+ zeroed_key = krbtgt_key
+
+ checksum_keys[checksum] = ZeroedChecksumKey(zeroed_key.key,
+ zeroed_key.kvno)
+
+ return self.modified_ticket(ticket,
+ checksum_keys=checksum_keys,
+ include_checksums={checksum: True})
+
+ def unkeyed_pac_checksum(self, ticket, checksum, ctype):
+ krbtgt_creds = self.get_krbtgt_creds()
+ krbtgt_key = self.TicketDecryptionKey_from_creds(krbtgt_creds)
+
+ server_key = ticket.decryption_key
+
+ checksum_keys = {
+ krb5pac.PAC_TYPE_SRV_CHECKSUM: server_key,
+ krb5pac.PAC_TYPE_KDC_CHECKSUM: krbtgt_key,
+ krb5pac.PAC_TYPE_TICKET_CHECKSUM: krbtgt_key,
+ }
+
+ # Make a copy of the existing key and change the ctype.
+ key = checksum_keys[checksum]
+ new_key = RodcPacEncryptionKey(key.key, key.kvno)
+ new_key.ctype = ctype
+ checksum_keys[checksum] = new_key
+
+ return self.modified_ticket(ticket,
+ checksum_keys=checksum_keys,
+ include_checksums={checksum: True})
+
+ def add_delegation_info(self, ticket, services=None):
+ def modify_pac_fn(pac):
+ pac_buffers = pac.buffers
+ self.assertNotIn(krb5pac.PAC_TYPE_CONSTRAINED_DELEGATION,
+ (buffer.type for buffer in pac_buffers))
+
+ transited_services = list(map(lsa.String, services))
+
+ delegation = krb5pac.PAC_CONSTRAINED_DELEGATION()
+ delegation.proxy_target = lsa.String('test_proxy_target')
+ delegation.transited_services = transited_services
+ delegation.num_transited_services = len(transited_services)
+
+ info = krb5pac.PAC_CONSTRAINED_DELEGATION_CTR()
+ info.info = delegation
+
+ pac_buffer = krb5pac.PAC_BUFFER()
+ pac_buffer.type = krb5pac.PAC_TYPE_CONSTRAINED_DELEGATION
+ pac_buffer.info = info
+
+ pac_buffers.append(pac_buffer)
+
+ pac.buffers = pac_buffers
+ pac.num_buffers += 1
+
+ return pac
+
+ checksum_keys = self.get_krbtgt_checksum_key()
+
+ return self.modified_ticket(ticket,
+ checksum_keys=checksum_keys,
+ modify_pac_fn=modify_pac_fn)
+
+ def set_ticket_forwardable(self, ticket, flag, update_pac_checksums=True):
+ flag = '1' if flag else '0'
+
+ def modify_fn(enc_part):
+ # Reset the forwardable flag
+ forwardable_pos = (len(tuple(krb5_asn1.TicketFlags('forwardable')))
+ - 1)
+
+ flags = enc_part['flags']
+ self.assertLessEqual(forwardable_pos, len(flags))
+ enc_part['flags'] = (flags[:forwardable_pos] +
+ flag +
+ flags[forwardable_pos+1:])
+
+ return enc_part
+
+ if update_pac_checksums:
+ checksum_keys = self.get_krbtgt_checksum_key()
+ else:
+ checksum_keys = None
+
+ return self.modified_ticket(ticket,
+ modify_fn=modify_fn,
+ checksum_keys=checksum_keys,
+ update_pac_checksums=update_pac_checksums)
+
+ def remove_ticket_pac(self, ticket):
+ return self.modified_ticket(ticket,
+ exclude_pac=True)
+
+
if __name__ == "__main__":
- global_asn1_print = True
- global_hexdump = True
+ global_asn1_print = False
+ global_hexdump = False
import unittest
unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/salt_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/salt_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/salt_tests.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/salt_tests.py 2021-10-29 06:17:36.000000000 +0000
@@ -0,0 +1,327 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+import ldb
+
+from samba.tests.krb5.as_req_tests import AsReqKerberosTests
+import samba.tests.krb5.kcrypto as kcrypto
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class SaltTests(AsReqKerberosTests):
+
+ def setUp(self):
+ super().setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ def _get_creds(self, *,
+ account_type,
+ opts=None):
+ try:
+ return self.get_cached_creds(
+ account_type=account_type,
+ opts=opts)
+ except ldb.LdbError:
+ self.fail()
+
+ def _run_salt_test(self, client_creds):
+ expected_salt = self.get_salt(client_creds)
+ self.assertIsNotNone(expected_salt)
+
+ etype_info2 = self._run_as_req_enc_timestamp(client_creds)
+
+ self.assertEqual(etype_info2[0]['etype'], kcrypto.Enctype.AES256)
+ self.assertEqual(etype_info2[0]['salt'], expected_salt)
+
+ def test_salt_at_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'name_suffix': 'foo@bar'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_at_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'name_suffix': 'foo@bar'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_at_case_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'name_suffix': 'Foo@bar'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_at_case_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'name_suffix': 'Foo@bar'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_double_at_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'name_suffix': 'foo@@bar'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_double_at_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'name_suffix': 'foo@@bar'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_at_start_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'name_prefix': '@foo'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_at_start_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'name_prefix': '@foo'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_at_end_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'name_suffix': 'foo@'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_at_end_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'name_suffix': 'foo@'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_at_end_no_dollar_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'name_suffix': 'foo@',
+ 'add_dollar': False})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_no_dollar_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'add_dollar': False})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_dollar_mid_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'name_suffix': 'foo$bar',
+ 'add_dollar': False})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_dollar_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'name_suffix': 'foo$bar'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_dollar_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'name_suffix': 'foo$bar'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_dollar_end_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'name_suffix': 'foo$'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_dollar_end_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'name_suffix': 'foo$'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'foo0'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'foo1'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_host_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'host/foo2'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_host_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'host/foo3'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_realm_user(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'foo4@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_realm_mac(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'foo5@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_host_realm_user(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'host/foo6@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_host_realm_mac(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'host/foo7@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_dollar_realm_user(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'foo8$@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_dollar_realm_mac(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'foo9$@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_host_dollar_realm_user(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'host/foo10$@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_host_dollar_realm_mac(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'host/foo11$@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_other_realm_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'foo12@other.realm'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_other_realm_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'foo13@other.realm'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_host_other_realm_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'host/foo14@other.realm'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_host_other_realm_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'host/foo15@other.realm'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_case_user(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'Foo16'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_case_mac(self):
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'Foo17'})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_dollar_mid_realm_user(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'foo$18@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_dollar_mid_realm_mac(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'foo$19@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_host_dollar_mid_realm_user(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'host/foo$20@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_host_dollar_mid_realm_mac(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'host/foo$21@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_at_realm_user(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.USER,
+ opts={'upn': 'foo22@bar@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+ def test_salt_upn_at_realm_mac(self):
+ realm = self.get_samdb().domain_dns_name()
+ client_creds = self._get_creds(
+ account_type=self.AccountType.COMPUTER,
+ opts={'upn': 'foo23@bar@' + realm})
+ self._run_as_req_enc_timestamp(client_creds)
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/simple_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/simple_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/simple_tests.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/simple_tests.py 2021-10-29 06:17:36.000000000 +0000
@@ -23,11 +23,17 @@
os.environ["PYTHONUNBUFFERED"] = "1"
from samba.tests.krb5.raw_testcase import RawKerberosTest
+from samba.tests.krb5.rfc4120_constants import (
+ KU_AS_REP_ENC_PART,
+ KU_PA_ENC_TIMESTAMP,
+ KU_TGS_REP_ENC_PART_SUB_KEY,
+)
import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
global_asn1_print = False
global_hexdump = False
+
class SimpleKerberosTests(RawKerberosTest):
def setUp(self):
@@ -38,17 +44,19 @@
def test_simple(self):
user_creds = self.get_user_creds()
user = user_creds.get_username()
- realm = user_creds.get_realm()
+ krbtgt_creds = self.get_krbtgt_creds(require_keys=False)
+ krbtgt_account = krbtgt_creds.get_username()
+ realm = krbtgt_creds.get_realm()
cname = self.PrincipalName_create(name_type=1, names=[user])
- sname = self.PrincipalName_create(name_type=2, names=["krbtgt", realm])
+ sname = self.PrincipalName_create(name_type=2, names=[krbtgt_account, realm])
till = self.get_KerberosTime(offset=36000)
kdc_options = krb5_asn1.KDCOptions('forwardable')
padata = None
- etypes=(18,17,23)
+ etypes = (18, 17, 23)
req = self.AS_REQ_create(padata=padata,
kdc_options=str(kdc_options),
@@ -61,22 +69,22 @@
nonce=0x7fffffff,
etypes=etypes,
addresses=None,
- EncAuthorizationData=None,
- EncAuthorizationData_key=None,
additional_tickets=None)
rep = self.send_recv_transaction(req)
self.assertIsNotNone(rep)
self.assertEqual(rep['msg-type'], 30)
self.assertEqual(rep['error-code'], 25)
- rep_padata = self.der_decode(rep['e-data'], asn1Spec=krb5_asn1.METHOD_DATA())
+ rep_padata = self.der_decode(
+ rep['e-data'], asn1Spec=krb5_asn1.METHOD_DATA())
for pa in rep_padata:
if pa['padata-type'] == 19:
etype_info2 = pa['padata-value']
break
- etype_info2 = self.der_decode(etype_info2, asn1Spec=krb5_asn1.ETYPE_INFO2())
+ etype_info2 = self.der_decode(
+ etype_info2, asn1Spec=krb5_asn1.ETYPE_INFO2())
key = self.PasswordKey_from_etype_info2(user_creds, etype_info2[0])
@@ -84,8 +92,7 @@
pa_ts = self.PA_ENC_TS_ENC_create(patime, pausec)
pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
- enc_pa_ts_usage = 1
- pa_ts = self.EncryptedData_create(key, enc_pa_ts_usage, pa_ts)
+ pa_ts = self.EncryptedData_create(key, KU_PA_ENC_TIMESTAMP, pa_ts)
pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.EncryptedData())
pa_ts = self.PA_DATA_create(2, pa_ts)
@@ -104,8 +111,6 @@
nonce=0x7fffffff,
etypes=etypes,
addresses=None,
- EncAuthorizationData=None,
- EncAuthorizationData_key=None,
additional_tickets=None)
rep = self.send_recv_transaction(req)
self.assertIsNotNone(rep)
@@ -113,20 +118,23 @@
msg_type = rep['msg-type']
self.assertEqual(msg_type, 11)
- usage = 3
- enc_part2 = key.decrypt(usage, rep['enc-part']['cipher'])
+ enc_part2 = key.decrypt(KU_AS_REP_ENC_PART, rep['enc-part']['cipher'])
- # MIT KDC encodes both EncASRepPart and EncTGSRepPart with application tag 26
+ # MIT KDC encodes both EncASRepPart and EncTGSRepPart with
+ # application tag 26
try:
- enc_part2 = self.der_decode(enc_part2, asn1Spec=krb5_asn1.EncASRepPart())
+ enc_part2 = self.der_decode(
+ enc_part2, asn1Spec=krb5_asn1.EncASRepPart())
except Exception:
- enc_part2 = self.der_decode(enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart())
+ enc_part2 = self.der_decode(
+ enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart())
# TGS Request
service_creds = self.get_service_creds(allow_missing_password=True)
service_name = service_creds.get_username()
- sname = self.PrincipalName_create(name_type=2, names=["host", service_name])
+ sname = self.PrincipalName_create(
+ name_type=2, names=["host", service_name])
kdc_options = krb5_asn1.KDCOptions('forwardable')
till = self.get_KerberosTime(offset=36000)
ticket = rep['ticket']
@@ -134,7 +142,6 @@
padata = []
subkey = self.RandomKey(ticket_session_key.etype)
- subkey_usage = 9
(ctime, cusec) = self.get_KerberosTimeWithUsec()
@@ -163,14 +170,16 @@
msg_type = rep['msg-type']
self.assertEqual(msg_type, 13)
- enc_part2 = subkey.decrypt(subkey_usage, rep['enc-part']['cipher'])
- enc_part2 = self.der_decode(enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart())
+ enc_part2 = subkey.decrypt(
+ KU_TGS_REP_ENC_PART_SUB_KEY, rep['enc-part']['cipher'])
+ enc_part2 = self.der_decode(
+ enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart())
return
if __name__ == "__main__":
- global_asn1_print = True
- global_hexdump = True
+ global_asn1_print = False
+ global_hexdump = False
import unittest
unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/spn_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/spn_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/spn_tests.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/spn_tests.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,212 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) 2020 Catalyst.Net Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import os
+import sys
+
+from samba.tests import DynamicTestCase
+
+import ldb
+
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+from samba.tests.krb5.raw_testcase import KerberosCredentials
+from samba.tests.krb5.rfc4120_constants import (
+ AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ KDC_ERR_S_PRINCIPAL_UNKNOWN,
+ NT_PRINCIPAL,
+)
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+global_asn1_print = False
+global_hexdump = False
+
+
+@DynamicTestCase
+class SpnTests(KDCBaseTest):
+ test_account_types = {
+ 'computer': KDCBaseTest.AccountType.COMPUTER,
+ 'server': KDCBaseTest.AccountType.SERVER,
+ 'rodc': KDCBaseTest.AccountType.RODC
+ }
+ test_spns = {
+ '2_part': 'ldap/{{account}}',
+ '3_part_our_domain': 'ldap/{{account}}/{netbios_domain_name}',
+ '3_part_our_realm': 'ldap/{{account}}/{dns_domain_name}',
+ '3_part_not_our_realm': 'ldap/{{account}}/test',
+ '3_part_instance': 'ldap/{{account}}:test/{dns_domain_name}'
+ }
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+
+ cls._mock_rodc_creds = None
+
+ @classmethod
+ def setUpDynamicTestCases(cls):
+ for account_type_name, account_type in cls.test_account_types.items():
+ for spn_name, spn in cls.test_spns.items():
+ tname = f'{spn_name}_spn_{account_type_name}'
+ targs = (account_type, spn)
+ cls.generate_dynamic_test('test_spn', tname, *targs)
+
+ def _test_spn_with_args(self, account_type, spn):
+ target_creds = self._get_creds(account_type)
+ spn = self._format_spn(spn, target_creds)
+
+ sname = self.PrincipalName_create(name_type=NT_PRINCIPAL,
+ names=spn.split('/'))
+
+ client_creds = self.get_client_creds()
+ tgt = self.get_tgt(client_creds)
+
+ samdb = self.get_samdb()
+ netbios_domain_name = samdb.domain_netbios_name()
+ dns_domain_name = samdb.domain_dns_name()
+
+ subkey = self.RandomKey(tgt.session_key.etype)
+
+ etypes = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5,)
+
+ if account_type is self.AccountType.SERVER:
+ ticket_etype = AES256_CTS_HMAC_SHA1_96
+ else:
+ ticket_etype = None
+ decryption_key = self.TicketDecryptionKey_from_creds(
+ target_creds, etype=ticket_etype)
+
+ if (spn.count('/') > 1
+ and (spn.endswith(netbios_domain_name)
+ or spn.endswith(dns_domain_name))
+ and account_type is not self.AccountType.SERVER
+ and account_type is not self.AccountType.RODC):
+ expected_error_mode = KDC_ERR_S_PRINCIPAL_UNKNOWN
+ check_error_fn = self.generic_check_kdc_error
+ check_rep_fn = None
+ else:
+ expected_error_mode = 0
+ check_error_fn = None
+ check_rep_fn = self.generic_check_kdc_rep
+
+ kdc_exchange_dict = self.tgs_exchange_dict(
+ expected_crealm=tgt.crealm,
+ expected_cname=tgt.cname,
+ expected_srealm=tgt.srealm,
+ expected_sname=sname,
+ ticket_decryption_key=decryption_key,
+ check_rep_fn=check_rep_fn,
+ check_error_fn=check_error_fn,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ expected_error_mode=expected_error_mode,
+ tgt=tgt,
+ authenticator_subkey=subkey,
+ kdc_options='0',
+ expect_edata=False)
+
+ self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=None,
+ realm=tgt.srealm,
+ sname=sname,
+ etypes=etypes)
+
+ def setUp(self):
+ super().setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ def _format_spns(self, spns, creds=None):
+ return map(lambda spn: self._format_spn(spn, creds), spns)
+
+ def _format_spn(self, spn, creds=None):
+ samdb = self.get_samdb()
+
+ spn = spn.format(netbios_domain_name=samdb.domain_netbios_name(),
+ dns_domain_name=samdb.domain_dns_name())
+
+ if creds is not None:
+ account_name = creds.get_username()
+ spn = spn.format(account=account_name)
+
+ return spn
+
+ def _get_creds(self, account_type):
+ spns = self._format_spns(self.test_spns.values())
+
+ if account_type is self.AccountType.RODC:
+ creds = self._mock_rodc_creds
+ if creds is None:
+ creds = self._get_mock_rodc_creds(spns)
+ type(self)._mock_rodc_creds = creds
+ else:
+ creds = self.get_cached_creds(
+ account_type=account_type,
+ opts={
+ 'spn': spns
+ })
+
+ return creds
+
+ def _get_mock_rodc_creds(self, spns):
+ rodc_ctx = self.get_mock_rodc_ctx()
+
+ for spn in spns:
+ spn = spn.format(account=rodc_ctx.myname)
+ if spn not in rodc_ctx.SPNs:
+ rodc_ctx.SPNs.append(spn)
+
+ samdb = self.get_samdb()
+ rodc_dn = ldb.Dn(samdb, rodc_ctx.acct_dn)
+
+ msg = ldb.Message(rodc_dn)
+ msg['servicePrincipalName'] = ldb.MessageElement(
+ rodc_ctx.SPNs,
+ ldb.FLAG_MOD_REPLACE,
+ 'servicePrincipalName')
+ samdb.modify(msg)
+
+ creds = KerberosCredentials()
+ creds.guess(self.get_lp())
+ creds.set_realm(rodc_ctx.realm.upper())
+ creds.set_domain(rodc_ctx.domain_name)
+ creds.set_password(rodc_ctx.acct_pass)
+ creds.set_username(rodc_ctx.myname)
+ creds.set_workstation(rodc_ctx.samname)
+ creds.set_dn(rodc_dn)
+ creds.set_spn(rodc_ctx.SPNs)
+
+ res = samdb.search(base=rodc_dn,
+ scope=ldb.SCOPE_BASE,
+ attrs=['msDS-KeyVersionNumber'])
+ kvno = int(res[0].get('msDS-KeyVersionNumber', idx=0))
+ creds.set_kvno(kvno)
+
+ keys = self.get_keys(samdb, rodc_dn)
+ self.creds_set_keys(creds, keys)
+
+ return creds
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/test_ccache.py samba-4.13.14+dfsg/python/samba/tests/krb5/test_ccache.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/test_ccache.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/test_ccache.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,173 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) 2021 Catalyst.Net Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+import ldb
+
+from ldb import SCOPE_SUBTREE
+from samba import NTSTATUSError, gensec
+from samba.auth import AuthContext
+from samba.dcerpc import security
+from samba.ndr import ndr_unpack
+from samba.ntstatus import NT_STATUS_NO_IMPERSONATION_TOKEN
+
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class CcacheTests(KDCBaseTest):
+ """Test for authentication using Kerberos credentials stored in a
+ credentials cache file.
+ """
+
+ def test_ccache(self):
+ self._run_ccache_test()
+
+ def test_ccache_rename(self):
+ self._run_ccache_test(rename=True)
+
+ def test_ccache_no_pac(self):
+ self._run_ccache_test(include_pac=False,
+ expect_anon=True, allow_error=True)
+
+ def _run_ccache_test(self, rename=False, include_pac=True,
+ expect_anon=False, allow_error=False):
+ # Create a user account and a machine account, along with a Kerberos
+ # credentials cache file where the service ticket authenticating the
+ # user are stored.
+
+ mach_name = "ccachemac"
+ service = "host"
+
+ samdb = self.get_samdb()
+
+ # Create the user account.
+ user_credentials = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ use_cache=False)
+ user_name = user_credentials.get_username()
+
+ # Create the machine account.
+ (mach_credentials, _) = self.create_account(
+ samdb,
+ mach_name,
+ account_type=self.AccountType.COMPUTER,
+ spn="%s/%s" % (service,
+ mach_name))
+
+ # Talk to the KDC to obtain the service ticket, which gets placed into
+ # the cache. The machine account name has to match the name in the
+ # ticket, to ensure that the krbtgt ticket doesn't also need to be
+ # stored.
+ (creds, cachefile) = self.create_ccache_with_user(user_credentials,
+ mach_credentials,
+ pac=include_pac)
+ # Remove the cached credentials file.
+ self.addCleanup(os.remove, cachefile.name)
+
+ # Retrieve the user account's SID.
+ ldb_res = samdb.search(scope=SCOPE_SUBTREE,
+ expression="(sAMAccountName=%s)" % user_name,
+ attrs=["objectSid"])
+ self.assertEqual(1, len(ldb_res))
+ sid = ndr_unpack(security.dom_sid, ldb_res[0]["objectSid"][0])
+
+ if rename:
+ # Rename the account.
+
+ new_name = self.get_new_username()
+
+ msg = ldb.Message(user_credentials.get_dn())
+ msg['sAMAccountName'] = ldb.MessageElement(new_name,
+ ldb.FLAG_MOD_REPLACE,
+ 'sAMAccountName')
+ samdb.modify(msg)
+
+ # Authenticate in-process to the machine account using the user's
+ # cached credentials.
+
+ lp = self.get_lp()
+ lp.set('server role', 'active directory domain controller')
+
+ settings = {}
+ settings["lp_ctx"] = lp
+ settings["target_hostname"] = mach_name
+
+ gensec_client = gensec.Security.start_client(settings)
+ gensec_client.set_credentials(creds)
+ gensec_client.want_feature(gensec.FEATURE_SEAL)
+ gensec_client.start_mech_by_sasl_name("GSSAPI")
+
+ auth_context = AuthContext(lp_ctx=lp, ldb=samdb, methods=[])
+
+ gensec_server = gensec.Security.start_server(settings, auth_context)
+ gensec_server.set_credentials(mach_credentials)
+
+ gensec_server.start_mech_by_sasl_name("GSSAPI")
+
+ client_finished = False
+ server_finished = False
+ server_to_client = b''
+
+ # Operate as both the client and the server to verify the user's
+ # credentials.
+ while not client_finished or not server_finished:
+ if not client_finished:
+ print("running client gensec_update")
+ (client_finished, client_to_server) = gensec_client.update(
+ server_to_client)
+ if not server_finished:
+ print("running server gensec_update")
+ (server_finished, server_to_client) = gensec_server.update(
+ client_to_server)
+
+ # Ensure that the first SID contained within the obtained security
+ # token is the SID of the user we created.
+
+ # Retrieve the SIDs from the security token.
+ try:
+ session = gensec_server.session_info()
+ except NTSTATUSError as e:
+ if not allow_error:
+ self.fail()
+
+ enum, _ = e.args
+ self.assertEqual(NT_STATUS_NO_IMPERSONATION_TOKEN, enum)
+ return
+
+ token = session.security_token
+ token_sids = token.sids
+ self.assertGreater(len(token_sids), 0)
+
+ # Ensure that they match.
+ self.assertEqual(sid, token_sids[0])
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/test_ldap.py samba-4.13.14+dfsg/python/samba/tests/krb5/test_ldap.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/test_ldap.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/test_ldap.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,168 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) 2021 Catalyst.Net Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+import ldb
+
+from ldb import LdbError, ERR_OPERATIONS_ERROR, SCOPE_BASE, SCOPE_SUBTREE
+from samba.dcerpc import security
+from samba.ndr import ndr_unpack
+from samba.samdb import SamDB
+from samba import credentials
+
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class LdapTests(KDCBaseTest):
+ """Test for LDAP authentication using Kerberos credentials stored in a
+ credentials cache file.
+ """
+
+ def test_ldap(self):
+ self._run_ldap_test()
+
+ def test_ldap_rename(self):
+ self._run_ldap_test(rename=True)
+
+ def test_ldap_no_pac(self):
+ self._run_ldap_test(include_pac=False,
+ expect_anon=True, allow_error=True)
+
+ def _run_ldap_test(self, rename=False, include_pac=True,
+ expect_anon=False, allow_error=False):
+ # Create a user account and a machine account, along with a Kerberos
+ # credentials cache file where the service ticket authenticating the
+ # user are stored.
+
+ samdb = self.get_samdb()
+
+ mach_name = samdb.host_dns_name()
+ service = "ldap"
+
+ # Create the user account.
+ user_credentials = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ use_cache=False)
+ user_name = user_credentials.get_username()
+
+ mach_credentials = self.get_dc_creds()
+
+ # Talk to the KDC to obtain the service ticket, which gets placed into
+ # the cache. The machine account name has to match the name in the
+ # ticket, to ensure that the krbtgt ticket doesn't also need to be
+ # stored.
+ (creds, cachefile) = self.create_ccache_with_user(user_credentials,
+ mach_credentials,
+ service,
+ mach_name,
+ pac=include_pac)
+ # Remove the cached credentials file.
+ self.addCleanup(os.remove, cachefile.name)
+
+ # Retrieve the user account's SID.
+ ldb_res = samdb.search(scope=SCOPE_SUBTREE,
+ expression="(sAMAccountName=%s)" % user_name,
+ attrs=["objectSid"])
+ self.assertEqual(1, len(ldb_res))
+ sid = ndr_unpack(security.dom_sid, ldb_res[0]["objectSid"][0])
+
+ if rename:
+ # Rename the account.
+
+ new_name = self.get_new_username()
+
+ msg = ldb.Message(user_credentials.get_dn())
+ msg['sAMAccountName'] = ldb.MessageElement(new_name,
+ ldb.FLAG_MOD_REPLACE,
+ 'sAMAccountName')
+ samdb.modify(msg)
+
+ # Authenticate in-process to the machine account using the user's
+ # cached credentials.
+
+ # Connect to the machine account and retrieve the user SID.
+ try:
+ ldb_as_user = SamDB(url="ldap://%s" % mach_name,
+ credentials=creds,
+ lp=self.get_lp())
+ except LdbError as e:
+ if not allow_error:
+ self.fail()
+
+ enum, estr = e.args
+ self.assertEqual(ERR_OPERATIONS_ERROR, enum)
+ self.assertIn('NT_STATUS_NO_IMPERSONATION_TOKEN', estr)
+ return
+
+ ldb_res = ldb_as_user.search('',
+ scope=SCOPE_BASE,
+ attrs=["tokenGroups"])
+ self.assertEqual(1, len(ldb_res))
+
+ token_groups = ldb_res[0]["tokenGroups"]
+ token_sid = ndr_unpack(security.dom_sid, token_groups[0])
+
+ if expect_anon:
+ # Ensure we got an anonymous token.
+ self.assertEqual(security.SID_NT_ANONYMOUS, str(token_sid))
+ token_sid = ndr_unpack(security.dom_sid, token_groups[1])
+ self.assertEqual(security.SID_NT_NETWORK, str(token_sid))
+ if len(token_groups) >= 3:
+ token_sid = ndr_unpack(security.dom_sid, token_groups[2])
+ self.assertEqual(security.SID_NT_THIS_ORGANISATION,
+ str(token_sid))
+ else:
+ # Ensure that they match.
+ self.assertEqual(sid, token_sid)
+
+ def test_ldap_anonymous(self):
+ samdb = self.get_samdb()
+ mach_name = samdb.host_dns_name()
+
+ anon_creds = credentials.Credentials()
+ anon_creds.set_anonymous()
+
+ # Connect to the machine account and retrieve the user SID.
+ ldb_as_user = SamDB(url="ldap://%s" % mach_name,
+ credentials=anon_creds,
+ lp=self.get_lp())
+ ldb_res = ldb_as_user.search('',
+ scope=SCOPE_BASE,
+ attrs=["tokenGroups"])
+ self.assertEqual(1, len(ldb_res))
+
+ # Ensure we got an anonymous token.
+ token_sid = ndr_unpack(security.dom_sid, ldb_res[0]["tokenGroups"][0])
+ self.assertEqual(security.SID_NT_ANONYMOUS, str(token_sid))
+ self.assertEqual(len(ldb_res[0]["tokenGroups"]), 1)
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/test_min_domain_uid.py samba-4.13.14+dfsg/python/samba/tests/krb5/test_min_domain_uid.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/test_min_domain_uid.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/test_min_domain_uid.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,121 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Samuel Cabrero 2021
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+import pwd
+import ctypes
+
+from samba.tests import env_get_var_value
+from samba.samba3 import libsmb_samba_internal as libsmb
+from samba.samba3 import param as s3param
+from samba import NTSTATUSError, ntstatus
+
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+from samba.credentials import MUST_USE_KERBEROS, DONT_USE_KERBEROS
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+class SmbMinDomainUid(KDCBaseTest):
+ """Test for SMB authorization without NSS winbind. In such setup domain
+ accounts are mapped to local accounts using the 'username map' option.
+ """
+
+ def setUp(self):
+ super(KDCBaseTest, self).setUp()
+
+ # Create a user account, along with a Kerberos credentials cache file
+ # where the service ticket authenticating the user are stored.
+ self.samdb = self.get_samdb()
+
+ self.mach_name = env_get_var_value('SERVER')
+ self.user_name = "root"
+ self.service = "cifs"
+ self.share = "tmp"
+
+ # Create the user account.
+ (self.user_creds, _) = self.create_account(self.samdb, self.user_name)
+
+ # Build the global inject file path
+ server_conf = env_get_var_value('SMB_CONF_PATH')
+ server_conf_dir = os.path.dirname(server_conf)
+ self.global_inject = os.path.join(server_conf_dir, "global_inject.conf")
+
+ def _test_min_uid(self, creds):
+ # Assert unix root uid is less than 'idmap config ADDOMAIN' minimum
+ s3_lp = s3param.get_context()
+ s3_lp.load(self.get_lp().configfile)
+
+ domain_range = s3_lp.get("idmap config * : range").split('-')
+ domain_range_low = int(domain_range[0])
+ unix_root_pw = pwd.getpwnam(self.user_name)
+ self.assertLess(unix_root_pw.pw_uid, domain_range_low)
+ self.assertLess(unix_root_pw.pw_gid, domain_range_low)
+
+ conn = libsmb.Conn(self.mach_name, self.share, lp=s3_lp, creds=creds)
+ # Disconnect
+ conn = None
+
+ # Restrict access to local root account uid
+ with open(self.global_inject, 'w') as f:
+ f.write("min domain uid = %s\n" % (unix_root_pw.pw_uid + 1))
+
+ with self.assertRaises(NTSTATUSError) as cm:
+ conn = libsmb.Conn(self.mach_name,
+ self.share,
+ lp=s3_lp,
+ creds=creds)
+ code = ctypes.c_uint32(cm.exception.args[0]).value
+ self.assertEqual(code, ntstatus.NT_STATUS_INVALID_TOKEN)
+
+ # check that the local root account uid is now allowed
+ with open(self.global_inject, 'w') as f:
+ f.write("min domain uid = %s\n" % unix_root_pw.pw_uid)
+
+ conn = libsmb.Conn(self.mach_name, self.share, lp=s3_lp, creds=creds)
+ # Disconnect
+ conn = None
+
+ with open(self.global_inject, 'w') as f:
+ f.truncate()
+
+ def test_min_domain_uid_krb5(self):
+ krb5_state = self.user_creds.get_kerberos_state()
+ self.user_creds.set_kerberos_state(MUST_USE_KERBEROS)
+ ret = self._test_min_uid(self.user_creds)
+ self.user_creds.set_kerberos_state(krb5_state)
+ return ret
+
+ def test_min_domain_uid_ntlmssp(self):
+ krb5_state = self.user_creds.get_kerberos_state()
+ self.user_creds.set_kerberos_state(DONT_USE_KERBEROS)
+ ret = self._test_min_uid(self.user_creds)
+ self.user_creds.set_kerberos_state(krb5_state)
+ return ret
+
+ def tearDown(self):
+ # Ensure no leftovers in global inject file
+ with open(self.global_inject, 'w') as f:
+ f.truncate()
+
+ super(KDCBaseTest, self).tearDown()
+
+if __name__ == "__main__":
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/test_rpc.py samba-4.13.14+dfsg/python/samba/tests/krb5/test_rpc.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/test_rpc.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/test_rpc.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) 2021 Catalyst.Net Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+import ldb
+
+from samba import NTSTATUSError, credentials
+from samba.dcerpc import lsa
+from samba.ntstatus import NT_STATUS_NO_IMPERSONATION_TOKEN
+
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class RpcTests(KDCBaseTest):
+ """Test for RPC authentication using Kerberos credentials stored in a
+ credentials cache file.
+ """
+
+ def test_rpc(self):
+ self._run_rpc_test()
+
+ def test_rpc_rename(self):
+ self._run_rpc_test(rename=True)
+
+ def test_rpc_no_pac(self):
+ self._run_rpc_test(include_pac=False,
+ expect_anon=True, allow_error=True)
+
+ def _run_rpc_test(self, rename=False, include_pac=True,
+ expect_anon=False, allow_error=False):
+ # Create a user account and a machine account, along with a Kerberos
+ # credentials cache file where the service ticket authenticating the
+ # user are stored.
+
+ samdb = self.get_samdb()
+
+ mach_name = samdb.host_dns_name()
+ service = "cifs"
+
+ # Create the user account.
+ user_credentials = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ use_cache=False)
+ user_name = user_credentials.get_username()
+
+ mach_credentials = self.get_dc_creds()
+
+ # Talk to the KDC to obtain the service ticket, which gets placed into
+ # the cache. The machine account name has to match the name in the
+ # ticket, to ensure that the krbtgt ticket doesn't also need to be
+ # stored.
+ (creds, cachefile) = self.create_ccache_with_user(user_credentials,
+ mach_credentials,
+ service,
+ mach_name,
+ pac=include_pac)
+ # Remove the cached credentials file.
+ self.addCleanup(os.remove, cachefile.name)
+
+ if rename:
+ # Rename the account.
+
+ new_name = self.get_new_username()
+
+ msg = ldb.Message(user_credentials.get_dn())
+ msg['sAMAccountName'] = ldb.MessageElement(new_name,
+ ldb.FLAG_MOD_REPLACE,
+ 'sAMAccountName')
+ samdb.modify(msg)
+
+ # Authenticate in-process to the machine account using the user's
+ # cached credentials.
+
+ binding_str = "ncacn_np:%s[\\pipe\\lsarpc]" % mach_name
+ try:
+ conn = lsa.lsarpc(binding_str, self.get_lp(), creds)
+ except NTSTATUSError as e:
+ if not allow_error:
+ self.fail()
+
+ enum, _ = e.args
+ self.assertEqual(NT_STATUS_NO_IMPERSONATION_TOKEN, enum)
+ return
+
+ (account_name, _) = conn.GetUserName(None, None, None)
+
+ if expect_anon:
+ self.assertNotEqual(user_name, account_name.string)
+ else:
+ self.assertEqual(user_name, account_name.string)
+
+ def test_rpc_anonymous(self):
+ samdb = self.get_samdb()
+ mach_name = samdb.host_dns_name()
+
+ anon_creds = credentials.Credentials()
+ anon_creds.set_anonymous()
+
+ binding_str = "ncacn_np:%s[\\pipe\\lsarpc]" % mach_name
+ conn = lsa.lsarpc(binding_str, self.get_lp(), anon_creds)
+
+ (account_name, _) = conn.GetUserName(None, None, None)
+
+ self.assertEqual('ANONYMOUS LOGON', account_name.string)
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/test_smb.py samba-4.13.14+dfsg/python/samba/tests/krb5/test_smb.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/test_smb.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/test_smb.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,153 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) 2021 Catalyst.Net Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+import sys
+import os
+
+import ldb
+
+from ldb import SCOPE_SUBTREE
+from samba import NTSTATUSError
+from samba.dcerpc import security
+from samba.ndr import ndr_unpack
+from samba.ntstatus import NT_STATUS_NO_IMPERSONATION_TOKEN
+from samba.samba3 import libsmb_samba_internal as libsmb
+from samba.samba3 import param as s3param
+
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class SmbTests(KDCBaseTest):
+ """Test for SMB authentication using Kerberos credentials stored in a
+ credentials cache file.
+ """
+
+ def test_smb(self):
+ self._run_smb_test()
+
+ def test_smb_rename(self):
+ self._run_smb_test(rename=True)
+
+ def test_smb_no_pac(self):
+ self._run_smb_test(include_pac=False,
+ expect_error=True)
+
+ def _run_smb_test(self, rename=False, include_pac=True,
+ expect_error=False):
+ # Create a user account and a machine account, along with a Kerberos
+ # credentials cache file where the service ticket authenticating the
+ # user are stored.
+
+ samdb = self.get_samdb()
+
+ mach_name = samdb.host_dns_name()
+ service = "cifs"
+ share = "tmp"
+
+ # Create the user account.
+ user_credentials = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ use_cache=False)
+ user_name = user_credentials.get_username()
+
+ mach_credentials = self.get_dc_creds()
+
+ mach_credentials = self.get_dc_creds()
+
+ # Talk to the KDC to obtain the service ticket, which gets placed into
+ # the cache. The machine account name has to match the name in the
+ # ticket, to ensure that the krbtgt ticket doesn't also need to be
+ # stored.
+ (creds, cachefile) = self.create_ccache_with_user(user_credentials,
+ mach_credentials,
+ service,
+ mach_name,
+ pac=include_pac)
+ # Remove the cached credentials file.
+ self.addCleanup(os.remove, cachefile.name)
+
+ # Retrieve the user account's SID.
+ ldb_res = samdb.search(scope=SCOPE_SUBTREE,
+ expression="(sAMAccountName=%s)" % user_name,
+ attrs=["objectSid"])
+ self.assertEqual(1, len(ldb_res))
+ sid = ndr_unpack(security.dom_sid, ldb_res[0]["objectSid"][0])
+
+ if rename:
+ # Rename the account.
+
+ new_name = self.get_new_username()
+
+ msg = ldb.Message(user_credentials.get_dn())
+ msg['sAMAccountName'] = ldb.MessageElement(new_name,
+ ldb.FLAG_MOD_REPLACE,
+ 'sAMAccountName')
+ samdb.modify(msg)
+
+ # Set the Kerberos 5 credentials cache environment variable. This is
+ # required because the codepath that gets run (gse_krb5) looks for it
+ # in here and not in the credentials object.
+ krb5_ccname = os.environ.get("KRB5CCNAME", "")
+ self.addCleanup(os.environ.__setitem__, "KRB5CCNAME", krb5_ccname)
+ os.environ["KRB5CCNAME"] = "FILE:" + cachefile.name
+
+ # Authenticate in-process to the machine account using the user's
+ # cached credentials.
+
+ # Connect to a share and retrieve the user SID.
+ s3_lp = s3param.get_context()
+ s3_lp.load(self.get_lp().configfile)
+
+ min_protocol = s3_lp.get("client min protocol")
+ self.addCleanup(s3_lp.set, "client min protocol", min_protocol)
+ s3_lp.set("client min protocol", "NT1")
+
+ max_protocol = s3_lp.get("client max protocol")
+ self.addCleanup(s3_lp.set, "client max protocol", max_protocol)
+ s3_lp.set("client max protocol", "NT1")
+
+ try:
+ conn = libsmb.Conn(mach_name, share, lp=s3_lp, creds=creds)
+ except NTSTATUSError as e:
+ if not expect_error:
+ self.fail()
+
+ enum, _ = e.args
+ self.assertEqual(NT_STATUS_NO_IMPERSONATION_TOKEN, enum)
+ return
+ else:
+ self.assertFalse(expect_error)
+
+ (uid, gid, gids, sids, guest) = conn.posix_whoami()
+
+ # Ensure that they match.
+ self.assertEqual(sid, sids[0])
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/krb5/xrealm_tests.py samba-4.13.14+dfsg/python/samba/tests/krb5/xrealm_tests.py
--- samba-4.13.3+dfsg/python/samba/tests/krb5/xrealm_tests.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/krb5/xrealm_tests.py 2021-10-29 06:17:36.000000000 +0000
@@ -23,12 +23,18 @@
os.environ["PYTHONUNBUFFERED"] = "1"
from samba.tests.krb5.raw_testcase import RawKerberosTest
+from samba.tests.krb5.rfc4120_constants import (
+ KU_PA_ENC_TIMESTAMP,
+ KU_AS_REP_ENC_PART,
+ KU_TGS_REP_ENC_PART_SUB_KEY,
+)
import samba.tests.krb5.rfc4120_pyasn1 as krb5_asn1
import samba.tests
global_asn1_print = False
global_hexdump = False
+
class XrealmKerberosTests(RawKerberosTest):
def setUp(self):
@@ -49,7 +55,7 @@
kdc_options = krb5_asn1.KDCOptions('forwardable')
padata = None
- etypes=(18,17,23)
+ etypes = (18, 17, 23)
req = self.AS_REQ_create(padata=padata,
kdc_options=str(kdc_options),
@@ -62,22 +68,22 @@
nonce=0x7fffffff,
etypes=etypes,
addresses=None,
- EncAuthorizationData=None,
- EncAuthorizationData_key=None,
additional_tickets=None)
rep = self.send_recv_transaction(req)
self.assertIsNotNone(rep)
self.assertEqual(rep['msg-type'], 30)
self.assertEqual(rep['error-code'], 25)
- rep_padata = self.der_decode(rep['e-data'], asn1Spec=krb5_asn1.METHOD_DATA())
+ rep_padata = self.der_decode(
+ rep['e-data'], asn1Spec=krb5_asn1.METHOD_DATA())
for pa in rep_padata:
if pa['padata-type'] == 19:
etype_info2 = pa['padata-value']
break
- etype_info2 = self.der_decode(etype_info2, asn1Spec=krb5_asn1.ETYPE_INFO2())
+ etype_info2 = self.der_decode(
+ etype_info2, asn1Spec=krb5_asn1.ETYPE_INFO2())
key = self.PasswordKey_from_etype_info2(user_creds, etype_info2[0])
@@ -85,8 +91,7 @@
pa_ts = self.PA_ENC_TS_ENC_create(patime, pausec)
pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.PA_ENC_TS_ENC())
- enc_pa_ts_usage = 1
- pa_ts = self.EncryptedData_create(key, enc_pa_ts_usage, pa_ts)
+ pa_ts = self.EncryptedData_create(key, KU_PA_ENC_TIMESTAMP, pa_ts)
pa_ts = self.der_encode(pa_ts, asn1Spec=krb5_asn1.EncryptedData())
pa_ts = self.PA_DATA_create(2, pa_ts)
@@ -105,8 +110,6 @@
nonce=0x7fffffff,
etypes=etypes,
addresses=None,
- EncAuthorizationData=None,
- EncAuthorizationData_key=None,
additional_tickets=None)
rep = self.send_recv_transaction(req)
self.assertIsNotNone(rep)
@@ -114,18 +117,21 @@
msg_type = rep['msg-type']
self.assertEqual(msg_type, 11)
- usage = 3
- enc_part2 = key.decrypt(usage, rep['enc-part']['cipher'])
+ enc_part2 = key.decrypt(KU_AS_REP_ENC_PART, rep['enc-part']['cipher'])
- # MIT KDC encodes both EncASRepPart and EncTGSRepPart with application tag 26
+ # MIT KDC encodes both EncASRepPart and EncTGSRepPart with
+ # application tag 26
try:
- enc_part2 = self.der_decode(enc_part2, asn1Spec=krb5_asn1.EncASRepPart())
+ enc_part2 = self.der_decode(
+ enc_part2, asn1Spec=krb5_asn1.EncASRepPart())
except Exception:
- enc_part2 = self.der_decode(enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart())
+ enc_part2 = self.der_decode(
+ enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart())
# TGS Request (for cross-realm TGT)
trust_realm = samba.tests.env_get_var_value('TRUST_REALM')
- sname = self.PrincipalName_create(name_type=2, names=["krbtgt", trust_realm])
+ sname = self.PrincipalName_create(
+ name_type=2, names=["krbtgt", trust_realm])
kdc_options = krb5_asn1.KDCOptions('forwardable')
till = self.get_KerberosTime(offset=36000)
@@ -134,7 +140,6 @@
padata = []
subkey = self.RandomKey(ticket_session_key.etype)
- subkey_usage = 9
(ctime, cusec) = self.get_KerberosTimeWithUsec()
@@ -163,18 +168,20 @@
msg_type = rep['msg-type']
self.assertEqual(msg_type, 13)
- enc_part2 = subkey.decrypt(subkey_usage, rep['enc-part']['cipher'])
- enc_part2 = self.der_decode(enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart())
+ enc_part2 = subkey.decrypt(
+ KU_TGS_REP_ENC_PART_SUB_KEY, rep['enc-part']['cipher'])
+ enc_part2 = self.der_decode(
+ enc_part2, asn1Spec=krb5_asn1.EncTGSRepPart())
# Check the forwardable flag
- fwd_pos = len(tuple(krb5_asn1.TicketFlags('forwardable'))) -1
+ fwd_pos = len(tuple(krb5_asn1.TicketFlags('forwardable'))) - 1
assert(krb5_asn1.TicketFlags(enc_part2['flags'])[fwd_pos])
return
if __name__ == "__main__":
- global_asn1_print = True
- global_hexdump = True
+ global_asn1_print = False
+ global_hexdump = False
import unittest
unittest.main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/ldap_spn.py samba-4.13.14+dfsg/python/samba/tests/ldap_spn.py
--- samba-4.13.3+dfsg/python/samba/tests/ldap_spn.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/ldap_spn.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,917 @@
+# Unix SMB/CIFS implementation.
+#
+# Copyright 2021 (C) Catalyst IT Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+import sys
+import os
+import pprint
+import re
+from samba.samdb import SamDB
+from samba.auth import system_session
+import ldb
+from samba.sd_utils import SDUtils
+from samba.credentials import DONT_USE_KERBEROS, Credentials
+from samba.gensec import FEATURE_SEAL
+from samba.tests.subunitrun import SubunitOptions, TestProgram
+from samba.tests import TestCase, ldb_err
+from samba.tests import DynamicTestCase
+import samba.getopt as options
+import optparse
+from samba.colour import c_RED, c_GREEN, c_DARK_YELLOW
+from samba.dsdb import (
+ UF_SERVER_TRUST_ACCOUNT,
+ UF_TRUSTED_FOR_DELEGATION,
+)
+
+
+SPN_GUID = 'f3a64788-5306-11d1-a9c5-0000f80367c1'
+
+RELEVANT_ATTRS = {'dNSHostName',
+ 'servicePrincipalName',
+ 'sAMAccountName',
+ 'dn'}
+
+ok = True
+bad = False
+report = 'report'
+
+operr = ldb.ERR_OPERATIONS_ERROR
+denied = ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS
+constraint = ldb.ERR_CONSTRAINT_VIOLATION
+exists = ldb.ERR_ENTRY_ALREADY_EXISTS
+
+add = ldb.FLAG_MOD_ADD
+replace = ldb.FLAG_MOD_REPLACE
+delete = ldb.FLAG_MOD_DELETE
+
+try:
+ breakpoint
+except NameError:
+ # for python <= 3.6
+ def breakpoint():
+ import pdb
+ pdb.set_trace()
+
+
+def init():
+ # This needs to happen before the class definition, and we put it
+ # in a function to keep the namespace clean.
+ global LP, CREDS, SERVER, REALM, COLOUR_TEXT, subunitopts, FILTER
+
+ parser = optparse.OptionParser(
+ "python3 ldap_spn.py [options]")
+ sambaopts = options.SambaOptions(parser)
+ parser.add_option_group(sambaopts)
+
+ # use command line creds if available
+ credopts = options.CredentialsOptions(parser)
+ parser.add_option_group(credopts)
+ subunitopts = SubunitOptions(parser)
+ parser.add_option_group(subunitopts)
+
+ parser.add_option('--colour', action="store_true",
+ help="use colour text",
+ default=sys.stdout.isatty())
+
+ parser.add_option('--filter', help="only run tests matching this regex")
+
+ opts, args = parser.parse_args()
+ if len(args) != 1:
+ parser.print_usage()
+ sys.exit(1)
+
+ LP = sambaopts.get_loadparm()
+ CREDS = credopts.get_credentials(LP)
+ SERVER = args[0]
+ REALM = CREDS.get_realm()
+ COLOUR_TEXT = opts.colour
+ FILTER = opts.filter
+
+
+init()
+
+
+def colour_text(x, state=None):
+ if not COLOUR_TEXT:
+ return x
+ if state == 'error':
+ return c_RED(x)
+ if state == 'pass':
+ return c_GREEN(x)
+
+ return c_DARK_YELLOW(x)
+
+
+def get_samdb(creds=None):
+ if creds is None:
+ creds = CREDS
+ session = system_session()
+ else:
+ session = None
+
+ return SamDB(url=f"ldap://{SERVER}",
+ lp=LP,
+ session_info=session,
+ credentials=creds)
+
+
+def add_unpriv_user(samdb, ou, username,
+ writeable_objects=None,
+ password="samba123@"):
+ creds = Credentials()
+ creds.set_username(username)
+ creds.set_password(password)
+ creds.set_domain(CREDS.get_domain())
+ creds.set_realm(CREDS.get_realm())
+ creds.set_workstation(CREDS.get_workstation())
+ creds.set_gensec_features(CREDS.get_gensec_features() | FEATURE_SEAL)
+ creds.set_kerberos_state(DONT_USE_KERBEROS)
+ dnstr = f"CN={username},{ou}"
+
+ # like, WTF, samdb.newuser(), this is what you make us do.
+ short_ou = ou.split(',', 1)[0]
+
+ samdb.newuser(username, password, userou=short_ou)
+
+ if writeable_objects:
+ sd_utils = SDUtils(samdb)
+ sid = sd_utils.get_object_sid(dnstr)
+ for obj in writeable_objects:
+ mod = f"(OA;CI;WP;{ SPN_GUID };;{ sid })"
+ sd_utils.dacl_add_ace(obj, mod)
+
+ unpriv_samdb = get_samdb(creds=creds)
+ return unpriv_samdb
+
+
+class LdapSpnTestBase(TestCase):
+ _disabled = False
+
+ @classmethod
+ def setUpDynamicTestCases(cls):
+ if getattr(cls, '_disabled', False):
+ return
+ for doc, *rows in cls.cases:
+ if FILTER:
+ if not re.search(FILTER, doc):
+ continue
+ name = re.sub(r'\W+', '_', doc)
+ cls.generate_dynamic_test("test_spn", name, rows, doc)
+
+ def setup_objects(self, rows):
+ objects = set(r[0] for r in rows)
+ for name in objects:
+ if ':' in name:
+ objtype, name = name.split(':', 1)
+ else:
+ objtype = 'dc'
+ getattr(self, f'add_{objtype}')(name)
+
+ def setup_users(self, rows):
+ # When you are adding an SPN that aliases (or would be aliased
+ # by) another SPN on another object, you need to have write
+ # permission on that other object too.
+ #
+ # To test this negatively and positively, we need to have
+ # users with various combinations of write permission, which
+ # means fiddling with SDs on the objects.
+ #
+ # The syntax is:
+ # '' : user with no special permissions
+ # '*' : admin user
+ # 'A' : user can write to A only
+ # 'A,C' : user can write to A and C
+ # 'C,A' : same, but makes another user
+ self.userdbs = {
+ '*': self.samdb
+ }
+
+ permissions = set(r[2] for r in rows)
+ for p in permissions:
+ if p == '*':
+ continue
+ if p == '':
+ user = 'nobody'
+ writeable_objects = None
+ else:
+ user = 'writes_' + p.replace(",", '_')
+ writeable_objects = [self.objects[x][0] for x in p.split(',')]
+
+ self.userdbs[p] = add_unpriv_user(self.samdb, self.ou, user,
+ writeable_objects)
+
+ def _test_spn_with_args(self, rows, doc):
+ cdoc = colour_text(doc)
+ edoc = colour_text(doc, 'error')
+ pdoc = colour_text(doc, 'pass')
+
+ if COLOUR_TEXT:
+ sys.stderr.flush()
+ print('\n', c_DARK_YELLOW('#' * 10), f'starting «{cdoc}»\n')
+ sys.stdout.flush()
+
+ self.samdb = get_samdb()
+ self.base_dn = self.samdb.get_default_basedn()
+ self.short_id = self.id().rsplit('.', 1)[1][:63]
+ self.objects = {}
+ self.ou = f"OU={ self.short_id },{ self.base_dn }"
+ self.addCleanup(self.samdb.delete, self.ou, ["tree_delete:1"])
+ self.samdb.create_ou(self.ou)
+
+ self.setup_objects(rows)
+ self.setup_users(rows)
+
+ for i, row in enumerate(rows):
+ if len(row) == 5:
+ obj, data, rights, expected, op = row
+ else:
+ obj, data, rights, expected = row
+ op = ldb.FLAG_MOD_REPLACE
+
+ # We use this DB with possibly restricted rights for this row
+ samdb = self.userdbs[rights]
+
+ if ':' in obj:
+ objtype, obj = obj.split(':', 1)
+ else:
+ objtype = 'dc'
+
+ dn, dnsname = self.objects[obj]
+ m = {"dn": dn}
+
+ if isinstance(data, dict):
+ m.update(data)
+ else:
+ m['servicePrincipalName'] = data
+
+ # for python's sake (and our sanity) we try to ensure we
+ # have consistent canonical case in our attributes
+ keys = set(m.keys())
+ if not keys.issubset(RELEVANT_ATTRS):
+ raise ValueError(f"unexpected attr {keys - RELEVANT_ATTRS}. "
+ "Casefold typo?")
+
+ for k in ('dNSHostName', 'servicePrincipalName'):
+ if isinstance(m.get(k), str):
+ m[k] = m[k].format(dnsname=f"x.{REALM}")
+
+ msg = ldb.Message.from_dict(samdb, m, op)
+
+ if expected is bad:
+ try:
+ samdb.modify(msg)
+ except ldb.LdbError as e:
+ print(f"row {i+1} of '{pdoc}' failed as expected with "
+ f"{ldb_err(e)}\n")
+ continue
+ self.fail(f"row {i+1}: "
+ f"{rights} {pprint.pformat(m)} on {objtype} {obj} "
+ f"should fail ({edoc})")
+
+ elif expected is ok:
+ try:
+ samdb.modify(msg)
+ except ldb.LdbError as e:
+ self.fail(f"row {i+1} of {edoc} failed with {ldb_err(e)}:\n"
+ f"{rights} {pprint.pformat(m)} on {objtype} {obj}")
+
+ elif expected is report:
+ try:
+ self.samdb.modify(msg)
+ print(f"row {i+1} "
+ f"of '{cdoc}' {colour_text('SUCCEEDED', 'pass')}:\n"
+ f"{pprint.pformat(m)} on {obj}")
+ except ldb.LdbError as e:
+ print(f"row {i+1} "
+ f"of '{cdoc}' {colour_text('FAILED', 'error')} "
+ f"with {ldb_err(e)}:\n{pprint.pformat(m)} on {obj}")
+
+ elif expected is breakpoint:
+ try:
+ breakpoint()
+ samdb.modify(msg)
+ except ldb.LdbError as e:
+ print(f"row {i+1} of '{pdoc}' FAILED with {ldb_err(e)}\n")
+
+ else: # an ldb error number
+ try:
+ samdb.modify(msg)
+ except ldb.LdbError as e:
+ if e.args[0] == expected:
+ continue
+ self.fail(f"row {i+1} of '{edoc}' "
+ f"should have failed with {ldb_err(expected)}:\n"
+ f"not {ldb_err(e)}:\n"
+ f"{rights} {pprint.pformat(m)} on {objtype} {obj}")
+ self.fail(f"row {i+1} of '{edoc}' "
+ f"should have failed with {ldb_err(expected)}:\n"
+ f"{rights} {pprint.pformat(m)} on {objtype} {obj}")
+
+ def add_dc(self, name):
+ dn = f"CN={name},OU=Domain Controllers,{self.base_dn}"
+ dnsname = f"{name}.{REALM}".lower()
+ self.samdb.add({
+ "dn": dn,
+ "objectclass": "computer",
+ "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT |
+ UF_TRUSTED_FOR_DELEGATION),
+ "dnsHostName": dnsname,
+ "carLicense": self.id()
+ })
+ self.addCleanup(self.remove_object, name)
+ self.objects[name] = (dn, dnsname)
+
+ def add_user(self, name):
+ dn = f"CN={name},{self.ou}"
+ self.samdb.add({
+ "dn": dn,
+ "name": name,
+ "samAccountName": name,
+ "objectclass": "user",
+ "carLicense": self.id()
+ })
+ self.addCleanup(self.remove_object, name)
+ self.objects[name] = (dn, None)
+
+ def remove_object(self, name):
+ dn, dnsname = self.objects.pop(name)
+ self.samdb.delete(dn)
+
+
+@DynamicTestCase
+class LdapSpnTest(LdapSpnTestBase):
+ """Make sure we can't add clashing servicePrincipalNames.
+
+ This would be possible using sPNMappings aliases — for example, if
+ the mapping maps host/ to cifs/, we should not be able to add
+ different addresses for each.
+ """
+
+ # default sPNMappings: host=alerter, appmgmt, cisvc, clipsrv,
+ # browser, dhcp, dnscache, replicator, eventlog, eventsystem,
+ # policyagent, oakley, dmserver, dns, mcsvc, fax, msiserver, ias,
+ # messenger, netlogon, netman, netdde, netddedsm, nmagent,
+ # plugplay, protectedstorage, rasman, rpclocator, rpc, rpcss,
+ # remoteaccess, rsvp, samss, scardsvr, scesrv, seclogon, scm,
+ # dcom, cifs, spooler, snmp, schedule, tapisrv, trksvr, trkwks,
+ # ups, time, wins, www, http, w3svc, iisadmin, msdtc
+ #
+ # I think in practice this is rarely if ever changed or added to.
+
+ cases = [
+ ("add one as admin",
+ ('A', 'host/{dnsname}', '*', ok),
+ ),
+ ("add one as rightful user",
+ ('A', 'host/{dnsname}', 'A', ok),
+ ),
+ ("attempt to add one as nobody",
+ ('A', 'host/{dnsname}', '', denied),
+ ),
+
+ ("add and replace as admin",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', 'host/x.{dnsname}', '*', ok),
+ ),
+ ("replace as rightful user",
+ ('A', 'host/{dnsname}', 'A', ok),
+ ('A', 'host/x.{dnsname}', 'A', ok),
+ ),
+ ("attempt to replace one as nobody",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', 'host/x.{dnsname}', '', denied),
+ ),
+
+ ("add second as admin",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', 'host/x.{dnsname}', '*', ok, add),
+ ),
+ ("add second as rightful user",
+ ('A', 'host/{dnsname}', 'A', ok),
+ ('A', 'host/x.{dnsname}', 'A', ok, add),
+ ),
+ ("attempt to add second as nobody",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', 'host/x.{dnsname}', '', denied, add),
+ ),
+
+ ("add the same one twice, simple duplicate error",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', '*', bad, add),
+ ),
+ ("simple duplicate attributes, as non-admin",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', 'A', bad, add),
+ ),
+
+ ("add the same one twice, identical duplicate",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', '*', bad, add),
+ ),
+
+ ("add a conflict, host first, as nobody",
+ ('A', 'host/z.{dnsname}', '*', ok),
+ ('B', 'cifs/z.{dnsname}', '', denied),
+ ),
+
+ ("add a conflict, service first, as nobody",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('B', 'host/{dnsname}', '', denied),
+ ),
+
+
+ ("three way conflict, host first, as admin",
+ ('A', 'host/z.{dnsname}', '*', ok),
+ ('B', 'cifs/z.{dnsname}', '*', ok),
+ ('C', 'www/z.{dnsname}', '*', ok),
+ ),
+ ("three way conflict, host first, with sufficient rights",
+ ('A', 'host/z.{dnsname}', 'A', ok),
+ ('B', 'cifs/z.{dnsname}', 'B,A', ok),
+ ('C', 'www/z.{dnsname}', 'C,A', ok),
+ ),
+ ("three way conflict, host first, adding duplicate",
+ ('A', 'host/z.{dnsname}', 'A', ok),
+ ('B', 'cifs/z.{dnsname}', 'B,A', ok),
+ ('C', 'cifs/z.{dnsname}', 'C,A', bad),
+ ),
+ ("three way conflict, host first, adding duplicate, full rights",
+ ('A', 'host/z.{dnsname}', 'A', ok),
+ ('B', 'cifs/z.{dnsname}', 'B,A', ok),
+ ('C', 'cifs/z.{dnsname}', 'C,B,A', bad),
+ ),
+
+ ("three way conflict, host first, with other write rights",
+ ('A', 'host/z.{dnsname}', '*', ok),
+ ('B', 'cifs/z.{dnsname}', 'A,B', ok),
+ ('C', 'cifs/z.{dnsname}', 'A,B', bad),
+
+ ),
+ ("three way conflict, host first, as nobody",
+ ('A', 'host/z.{dnsname}', '*', ok),
+ ('B', 'cifs/z.{dnsname}', '*', ok),
+ ('C', 'www/z.{dnsname}', '', denied),
+ ),
+
+ ("three way conflict, services first, as admin",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('B', 'www/{dnsname}', '*', ok),
+ ('C', 'host/{dnsname}', '*', constraint),
+ ),
+ ("three way conflict, services first, with service write rights",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('B', 'www/{dnsname}', '*', ok),
+ ('C', 'host/{dnsname}', 'A,B', bad),
+ ),
+
+ ("three way conflict, service first, as nobody",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('B', 'www/{dnsname}', '*', ok),
+ ('C', 'host/{dnsname}', '', denied),
+ ),
+ ("replace host before specific",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ),
+ ("replace host after specific, as nobody",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', '', denied),
+ ),
+
+ ("non-conflict host before specific",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', 'cifs/{dnsname}', '*', ok, add),
+ ),
+ ("non-conflict host after specific",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', '*', ok, add),
+ ),
+ ("non-conflict host before specific, non-admin",
+ ('A', 'host/{dnsname}', 'A', ok),
+ ('A', 'cifs/{dnsname}', 'A', ok, add),
+ ),
+ ("non-conflict host after specific, as nobody",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', '', denied, add),
+ ),
+
+ ("add a conflict, host first on user, as admin",
+ ('user:C', 'host/{dnsname}', '*', ok),
+ ('B', 'cifs/{dnsname}', '*', ok),
+ ),
+ ("add a conflict, host first on user, host rights",
+ ('user:C', 'host/{dnsname}', '*', ok),
+ ('B', 'cifs/{dnsname}', 'C', denied),
+ ),
+ ("add a conflict, host first on user, both rights",
+ ('user:C', 'host/{dnsname}', '*', ok),
+ ('B', 'cifs/{dnsname}', 'B,C', ok),
+ ),
+ ("add a conflict, host first both on user",
+ ('user:C', 'host/{dnsname}', '*', ok),
+ ('user:D', 'www/{dnsname}', '*', ok),
+ ),
+ ("add a conflict, host first both on user, host rights",
+ ('user:C', 'host/{dnsname}', '*', ok),
+ ('user:D', 'www/{dnsname}', 'C', denied),
+ ),
+ ("add a conflict, host first both on user, both rights",
+ ('user:C', 'host/{dnsname}', '*', ok),
+ ('user:D', 'www/{dnsname}', 'C,D', ok),
+ ),
+ ("add a conflict, host first both on user, as nobody",
+ ('user:C', 'host/{dnsname}', '*', ok),
+ ('user:D', 'www/{dnsname}', '', denied),
+ ),
+ ("add a conflict, host first, with both write rights",
+ ('A', 'host/z.{dnsname}', '*', ok),
+ ('B', 'cifs/z.{dnsname}', 'A,B', ok),
+ ),
+
+ ("add a conflict, host first, second on user, as admin",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('user:D', 'cifs/{dnsname}', '*', ok),
+ ),
+ ("add a conflict, host first, second on user, with rights",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('user:D', 'cifs/{dnsname}', 'A,D', ok),
+ ),
+
+ ("nonsense SPNs, part 1, as admin",
+ ('A', 'a-b-c/{dnsname}', '*', ok),
+ ('A', 'rrrrrrrrrrrrr /{dnsname}', '*', ok),
+ ),
+ ("nonsense SPNs, part 1, as user",
+ ('A', 'a-b-c/{dnsname}', 'A', ok),
+ ('A', 'rrrrrrrrrrrrr /{dnsname}', 'A', ok),
+ ),
+ ("nonsense SPNs, part 1, as nobody",
+ ('A', 'a-b-c/{dnsname}', '', denied),
+ ('A', 'rrrrrrrrrrrrr /{dnsname}', '', denied),
+ ),
+
+ ("add a conflict, using port",
+ ('A', 'dns/{dnsname}', '*', ok),
+ ('B', 'dns/{dnsname}:53', '*', ok),
+ ),
+ ("add a conflict, using port, port first",
+ ('user:C', 'dns/{dnsname}:53', '*', ok),
+ ('user:D', 'dns/{dnsname}', '*', ok),
+ ),
+ ("three part spns",
+ ('A', {'dNSHostName': '{dnsname}'}, '*', ok),
+ ('A', 'cifs/{dnsname}/DomainDNSZones.{dnsname}', '*', ok),
+ ('B', 'cifs/{dnsname}/DomainDNSZones.{dnsname}', '*', constraint),
+ ('A', {'dNSHostName': 'y.{dnsname}'}, '*', ok),
+ ('B', 'cifs/{dnsname}/DomainDNSZones.{dnsname}', '*', ok),
+ ('B', 'cifs/y.{dnsname}/DomainDNSZones.{dnsname}', '*', constraint),
+ ),
+ ("three part nonsense spns",
+ ('A', {'dNSHostName': 'bean'}, '*', ok),
+ ('A', 'cifs/bean/DomainDNSZones.bean', '*', ok),
+ ('B', 'cifs/bean/DomainDNSZones.bean', '*', constraint),
+ ('A', {'dNSHostName': 'y.bean'}, '*', ok),
+ ('B', 'cifs/bean/DomainDNSZones.bean', '*', ok),
+ ('B', 'cifs/y.bean/DomainDNSZones.bean', '*', constraint),
+ ('C', 'host/bean/bean', '*', ok),
+ ),
+
+ ("one part spns (no slashes)",
+ ('A', '{dnsname}', '*', constraint),
+ ('B', 'cifs', '*', constraint),
+ ('B', 'cifs/', '*', ok),
+ ('B', ' ', '*', constraint),
+ ('user:C', 'host', '*', constraint),
+ ),
+
+ ("dodgy spns",
+ # These tests pass on Windows. An SPN must have one or two
+ # slashes, with at least one character before the first one,
+ # UNLESS the first slash is followed by a good enough service
+ # name (e.g. "/host/x.y" rather than "sdfsd/x.y").
+ ('A', '\\/{dnsname}', '*', ok),
+ ('B', 'cifs/\\\\{dnsname}', '*', ok),
+ ('B', r'cifs/\\\{dnsname}', '*', ok),
+ ('B', r'cifs/\\\{dnsname}/', '*', ok),
+ ('A', r'cīfs/\\\{dnsname}/', '*', constraint), # 'ī' maps to 'i'
+ # on the next two, full-width solidus (U+FF0F) does not work
+ # as '/'.
+ ('A', 'cifs/sfic', '*', constraint, add),
+ ('A', r'cifs/\\\{dnsname}', '*', constraint, add),
+ ('B', '\n', '*', constraint),
+ ('B', '\n/\n', '*', ok),
+ ('B', '\n/\n/\n', '*', ok),
+ ('B', '\n/\n/\n/\n', '*', constraint),
+ ('B', ' /* and so on */ ', '*', ok, add),
+ ('B', r'¯\_(ツ)_/¯', '*', ok, add), # ¯\_(ツ)_/¯
+ # つ is hiragana for katakana ツ, so the next one fails for
+ # something analogous to casefold reasons.
+ ('A', r'¯\_(つ)_/¯', '*', constraint),
+ ('A', r'¯\_(㋡)_/¯', '*', constraint), # circled ツ
+ ('B', '//', '*', constraint), # all can't be empty,
+ ('B', ' //', '*', ok), # service can be space
+ ('B', '/host/{dnsname}', '*', ok), # or empty if others aren't
+ ('B', '/host/x.y.z', '*', ok),
+ ('B', '/ /x.y.z', '*', ok),
+ ('B', ' / / ', '*', ok),
+ ('user:C', b'host/', '*', ok),
+ ('user:C', ' /host', '*', ok), # service is ' ' (space)
+ ('B', ' /host', '*', constraint), # already on C
+ ('B', ' /HōST', '*', constraint), # ō equiv to O
+ ('B', ' /ħØşt', '*', constraint), # maps to ' /host'
+ ('B', ' /H0ST', '*', ok), # 0 is zero
+ ('B', ' /НoST', '*', ok), # Cyrillic Н (~N)
+ ('B', ' /host', '*', ok), # two space
+ ('B', '\u00a0/host', '*', ok), # non-breaking space
+ ('B', ' 2/HōST/⌷[ ][]¨(', '*', ok),
+ ('B', ' (//)', '*', ok, add),
+ ('B', ' ///', '*', constraint),
+ ('B', r' /\//', '*', constraint), # escape doesn't help
+ ('B', ' /\\//', '*', constraint), # double escape doesn't help
+ ('B', r'\//', '*', ok),
+ ('A', r'\\/\\/', '*', ok),
+ ('B', '|//|', '*', ok, add),
+ ('B', r'\/\/\\', '*', ok, add),
+
+ ('A', ':', '*', constraint),
+ ('A', ':/:', '*', ok),
+ ('A', ':/:80', '*', ok), # port number syntax is not special
+ ('A', ':/:( ツ', '*', ok),
+ ('A', ':/:/:', '*', ok),
+ ('B', b'cifs/\x11\xaa\xbb\xcc\\example.com', '*', ok),
+ ('A', b':/\xcc\xcc\xcc\xcc', '*', ok),
+ ('A', b':/b\x00/b/b/b', '*', ok), # string handlng truncates at \x00
+ ('A', b'a@b/a@b/a@b', '*', ok),
+ ('A', b'a/a@b/a@b', '*', ok),
+ ),
+ ("empty part spns (consecutive slashes)",
+ ('A', 'cifs//{dnsname}', '*', ok),
+ ('B', 'cifs//{dnsname}', '*', bad), # should clash with line 1
+ ('B', 'cifs/zzzy.{dnsname}/', '*', ok),
+ ('B', '/host/zzzy.{dnsname}', '*', ok),
+ ),
+ ("too many spn parts",
+ ('A', 'cifs/{dnsname}/{dnsname}/{dnsname}', '*', bad),
+ ('A', {'dNSHostName': 'y.{dnsname}'}, '*', ok),
+ ('B', 'cifs/{dnsname}/{dnsname}/', '*', bad),
+ ('B', 'cifs/y.{dnsname}/{dnsname}/toop', '*', bad),
+ ('B', 'host/{dnsname}/a/b/c', '*', bad),
+ ),
+ ("add a conflict, host first, as admin",
+ ('A', 'host/z.{dnsname}', '*', ok),
+ ('B', 'cifs/z.{dnsname}', '*', ok),
+ ),
+ ("add a conflict, host first, with host write rights",
+ ('A', 'host/z.{dnsname}', '*', ok),
+ ('B', 'cifs/z.{dnsname}', 'A', denied),
+ ),
+ ("add a conflict, service first, with service write rights",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('B', 'host/{dnsname}', 'A', denied),
+ ),
+ ("adding dNSHostName after cifs with no old dNSHostName",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', {'dNSHostName': 'y.{dnsname}'}, '*', ok),
+ ('B', 'cifs/{dnsname}', '*', constraint),
+ ('B', 'cifs/y.{dnsname}', '*', ok),
+ ('B', 'host/y.{dnsname}', '*', ok),
+ ),
+ ("changing dNSHostName after cifs",
+ ('A', {'dNSHostName': '{dnsname}'}, '*', ok),
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', {'dNSHostName': 'y.{dnsname}'}, '*', ok),
+ ('B', 'cifs/{dnsname}', '*', ok),
+ ('B', 'cifs/y.{dnsname}', '*', bad),
+ ('B', 'host/y.{dnsname}', '*', bad),
+ ),
+ ]
+
+
+@DynamicTestCase
+class LdapSpnSambaOnlyTest(LdapSpnTestBase):
+ # We don't run these ones outside of selftest, where we are
+ # probably testing against Windows and these are known failures.
+ _disabled = 'SAMBA_SELFTEST' not in os.environ
+ cases = [
+ ("add a conflict, host first, with service write rights",
+ ('A', 'host/z.{dnsname}', '*', ok),
+ ('B', 'cifs/z.{dnsname}', 'B', denied),
+ ),
+ ("add a conflict, service first, with host write rights",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('B', 'host/{dnsname}', 'B', constraint),
+ ),
+ ("add a conflict, service first, as admin",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('B', 'host/{dnsname}', '*', constraint),
+ ),
+ ("add a conflict, service first, with both write rights",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('B', 'host/{dnsname}', 'A,B', constraint),
+ ),
+ ("add a conflict, host first both on user, service rights",
+ ('user:C', 'host/{dnsname}', '*', ok),
+ ('user:D', 'www/{dnsname}', 'D', denied),
+ ),
+
+ ("changing dNSHostName after host",
+ ('A', {'dNSHostName': '{dnsname}'}, '*', ok),
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', {'dNSHostName': 'y.{dnsname}'}, '*', ok),
+ ('B', 'cifs/{dnsname}', 'B', ok), # no clash with A
+ ('B', 'cifs/y.{dnsname}', 'B', bad), # should clash with A
+ ('B', 'host/y.{dnsname}', '*', bad),
+ ),
+
+ ("mystery dnsname clash, host first",
+ ('user:C', 'host/heeble.example.net', '*', ok),
+ ('user:D', 'www/heeble.example.net', '*', ok),
+ ),
+ ("mystery dnsname clash, www first",
+ ('user:D', 'www/heeble.example.net', '*', ok),
+ ('user:C', 'host/heeble.example.net', '*', constraint),
+ ),
+ ("replace as admin",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ),
+ ("replace as non-admin with rights",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', 'A', ok),
+ ('A', 'cifs/{dnsname}', 'A', ok),
+ ),
+ ("replace vial delete as non-admin with rights",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', 'A', ok),
+ ('A', 'host/{dnsname}', 'A', ok, delete),
+ ('A', 'cifs/{dnsname}', 'A', ok, add),
+ ),
+ ("replace as non-admin without rights",
+ ('B', 'cifs/b', '*', ok),
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', 'B', denied),
+ ('A', 'cifs/{dnsname}', 'B', denied),
+ ),
+ ("replace as nobody",
+ ('B', 'cifs/b', '*', ok),
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', '', denied),
+ ('A', 'cifs/{dnsname}', '', denied),
+ ),
+ ("accumulate and delete as admin",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', '*', ok, add),
+ ('A', 'www/{dnsname}', '*', ok, add),
+ ('A', 'www/...', '*', ok, add),
+ ('A', 'host/...', '*', ok, add),
+ ('A', 'www/{dnsname}', '*', ok, delete),
+ ('A', 'host/{dnsname}', '*', ok, delete),
+ ('A', 'host/{dnsname}', '*', ok, add),
+ ('A', 'www/{dnsname}', '*', ok, add),
+ ('A', 'host/...', '*', ok, delete),
+ ),
+ ("accumulate and delete with user rights",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', 'host/{dnsname}', 'A', ok, add),
+ ('A', 'www/{dnsname}', 'A', ok, add),
+ ('A', 'www/...', 'A', ok, add),
+ ('A', 'host/...', 'A', ok, add),
+ ('A', 'www/{dnsname}', 'A', ok, delete),
+ ('A', 'host/{dnsname}', 'A', ok, delete),
+ ('A', 'host/{dnsname}', 'A', ok, add),
+ ('A', 'www/{dnsname}', 'A', ok, add),
+ ('A', 'host/...', 'A', ok, delete),
+ ),
+ ("three way conflict, host first, with partial write rights",
+ ('A', 'host/z.{dnsname}', 'A', ok),
+ ('B', 'cifs/z.{dnsname}', 'B', denied),
+ ('C', 'www/z.{dnsname}', 'C', denied),
+ ),
+ ("three way conflict, host first, with partial write rights 2",
+ ('A', 'host/z.{dnsname}', 'A', ok),
+ ('B', 'cifs/z.{dnsname}', 'B', bad),
+ ('C', 'www/z.{dnsname}', 'C,A', ok),
+ ),
+
+ ("three way conflict sandwich, sufficient rights",
+ ('B', 'host/{dnsname}', 'B', ok),
+ ('A', 'cifs/{dnsname}', 'A,B', ok),
+ # the replaces don't fail even though they appear to affect A
+ # and B, because they are effectively no-ops, leaving
+ # everything as it was before.
+ ('A', 'cifs/{dnsname}', 'A', ok),
+ ('B', 'host/{dnsname}', 'B', ok),
+ ('C', 'www/{dnsname}', 'A,B,C', ok),
+ ('C', 'www/{dnsname}', 'B,C', ok),
+ # because B already has host/, C doesn't matter
+ ('B', 'host/{dnsname}', 'A,B', ok),
+ # removing host (via replace) frees others, needs B only
+ ('B', 'ldap/{dnsname}', 'B', ok),
+ ('C', 'www/{dnsname}', 'C', ok),
+ ('A', 'cifs/{dnsname}', 'A', ok),
+
+ # re-adding host is now impossible while A and C have {dnsname} spns
+ ('B', 'host/{dnsname}', '*', bad),
+ ('B', 'host/{dnsname}', 'A,B,C', bad),
+ # so let's remove those... (not needing B rights)
+ ('C', 'www/{dnsname}', 'C', ok, delete),
+ ('A', 'cifs/{dnsname}', 'A', ok, delete),
+ # and now we can add host/ again
+ ('B', 'host/{dnsname}', 'B', ok),
+ ('C', 'www/{dnsname}', 'B,C', ok, add),
+ ('A', 'cifs/{dnsname}', 'A,B', ok),
+ ),
+ ("three way conflict, service first, with all write rights",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('B', 'www/{dnsname}', 'A,B,C', ok),
+ ('C', 'host/{dnsname}', 'A,B,C', bad),
+ ),
+ ("three way conflict, service first, just sufficient rights",
+ ('A', 'cifs/{dnsname}', 'A', ok),
+ ('B', 'www/{dnsname}', 'B', ok),
+ ('C', 'host/{dnsname}', 'A,B,C', bad),
+ ),
+
+ ("three way conflict, service first, with host write rights",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('B', 'www/{dnsname}', '*', ok),
+ ('C', 'host/{dnsname}', 'C', bad),
+ ),
+ ("three way conflict, service first, with both write rights",
+ ('A', 'cifs/{dnsname}', '*', ok),
+ ('A', 'cifs/{dnsname}', '*', ok, delete),
+ ('A', 'www/{dnsname}', 'A,B,C', ok),
+ ('B', 'host/{dnsname}', 'A,B', bad),
+ ('A', 'www/{dnsname}', 'A', ok, delete),
+ ('B', 'host/{dnsname}', 'A,B', ok),
+ ('C', 'cifs/{dnsname}', 'C', bad),
+ ('C', 'cifs/{dnsname}', 'B,C', ok),
+ ),
+ ("three way conflict, services first, with partial rights",
+ ('A', 'cifs/{dnsname}', 'A,C', ok),
+ ('B', 'www/{dnsname}', '*', ok),
+ ('C', 'host/{dnsname}', 'A,C', bad),
+ ),
+ ]
+
+
+@DynamicTestCase
+class LdapSpnAmbitiousTest(LdapSpnTestBase):
+ _disabled = True
+ cases = [
+ ("add a conflict with port, host first both on user",
+ ('user:C', 'host/{dnsname}', '*', ok),
+ ('user:D', 'www/{dnsname}:80', '*', bad),
+ ),
+ # see https://bugzilla.samba.org/show_bug.cgi?id=8929
+ ("add the same one twice, case-insensitive duplicate",
+ ('A', 'host/{dnsname}', '*', ok),
+ ('A', 'Host/{dnsname}', '*', bad, add),
+ ),
+ ("special SPN",
+ # should fail because we don't have all the DSA infrastructure
+ ('A', ("E3514235-4B06-11D1-AB04-00C04FC2DCD2/"
+ "75b84f00-a81b-4a19-8ef2-8e483cccff11/"
+ "{dnsname}"), '*', constraint)
+ ),
+ ("single part SPNs matching sAMAccountName",
+ # setting them both together is allegedly a MacOS behaviour,
+ # but all we get from Windows is a mysterious NO_SUCH_OBJECT.
+ ('user:A', {'sAMAccountName': 'A',
+ 'servicePrincipalName': 'A'}, '*', ldb.ERR_NO_SUCH_OBJECT),
+ ('user:B', {'sAMAccountName': 'B'}, '*', ok),
+ ('user:B', {'servicePrincipalName': 'B'}, '*', constraint),
+ ('user:C', {'servicePrincipalName': 'C'}, '*', constraint),
+ ('user:C', {'sAMAccountName': 'C'}, '*', ok),
+ ),
+ ("three part spns with dnsHostName",
+ ('A', {'dNSHostName': '{dnsname}'}, '*', ok),
+ ('A', 'cifs/{dnsname}/DomainDNSZones.{dnsname}', '*', ok),
+ ('A', {'dNSHostName': 'y.{dnsname}'}, '*', ok),
+ ('B', 'cifs/{dnsname}/DomainDNSZones.{dnsname}', '*', ok),
+ ('B', 'cifs/y.{dnsname}/DomainDNSZones.{dnsname}', '*', constraint),
+ ('C', 'host/{y.dnsname}/{y.dnsname}', '*', constraint),
+ ('A', 'host/y.{dnsname}/{dnsname}', '*', constraint),
+ ),
+ ]
+
+
+def main():
+ TestProgram(module=__name__, opts=subunitopts)
+
+main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/ldap_upn_sam_account.py samba-4.13.14+dfsg/python/samba/tests/ldap_upn_sam_account.py
--- samba-4.13.3+dfsg/python/samba/tests/ldap_upn_sam_account.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/ldap_upn_sam_account.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,510 @@
+# Unix SMB/CIFS implementation.
+#
+# Copyright 2021 (C) Catalyst IT Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+
+import os
+import sys
+from samba.samdb import SamDB
+from samba.auth import system_session
+import ldb
+from samba.tests.subunitrun import SubunitOptions, TestProgram
+from samba.tests import TestCase, ldb_err
+from samba.tests import DynamicTestCase
+import samba.getopt as options
+import optparse
+from samba.colour import c_RED, c_GREEN, c_DARK_YELLOW
+import re
+import pprint
+from samba.dsdb import (
+ UF_SERVER_TRUST_ACCOUNT,
+ UF_TRUSTED_FOR_DELEGATION,
+)
+
+
+# bad sAMAccountName characters from [MS-SAMR]
+# "3.1.1.6 Attribute Constraints for Originating Updates"
+BAD_SAM_CHARS = (''.join(chr(x) for x in range(0, 32)) +
+ '"/\\[]:|<>+=;?,*')
+
+# 0x7f is *said* to be bad, but turns out to be fine.
+ALLEGED_BAD_SAM_CHARS = chr(127)
+
+LATIN1_BAD_CHARS = set([chr(x) for x in range(129, 160)] +
+ list("ªºÿ") +
+ [chr(x) for x in range(0xc0, 0xc6)] +
+ [chr(x) for x in range(0xc7, 0xd7)] +
+ [chr(x) for x in range(0xd8, 0xde)] +
+ [chr(x) for x in range(0xe0, 0xe6)] +
+ [chr(x) for x in range(0xe7, 0xf7)] +
+ [chr(x) for x in range(0xf8, 0xfe)])
+
+
+LATIN_EXTENDED_A_NO_CLASH = {306, 307, 330, 331, 338, 339, 358, 359, 383}
+
+#XXX does '\x00' just truncate the string though?
+#XXX elsewhere we see "[\\\"|,/:<>+=;?*']" with "'"
+
+
+## UPN limits
+# max length 1024 UTF-8 bytes, following "rfc822"
+# for o365 sync https://docs.microsoft.com/en-us/microsoft-365/enterprise/prepare-for-directory-synchronization?view=o365-worldwide
+# max length is 113 [64 before @] "@" [48 after @]
+# invalid chars: '\\%&*+/=?{}|<>();:,[]"'
+# allowed chars: A – Z, a - z, 0 – 9, ' . - _ ! # ^ ~
+# "Letters with diacritical marks, such as umlauts, accents, and tildes, are invalid characters."
+#
+# "@" can't be first
+# "The username cannot end with a period (.), an ampersand (&), a space, or an at sign (@)."
+#
+
+# per RFC 822, «"a b" @ example.org» is
+
+
+ok = True
+bad = False
+report = 'report'
+exists = ldb.ERR_ENTRY_ALREADY_EXISTS
+
+
+if sys.stdout.isatty():
+ c_doc = c_DARK_YELLOW
+else:
+ c_doc = lambda x: x
+
+
+def get_samdb():
+ return SamDB(url=f"ldap://{SERVER}",
+ lp=LP,
+ session_info=system_session(),
+ credentials=CREDS)
+
+
+def format(s):
+ if type(s) is str:
+ s = s.format(realm=REALM.upper(),
+ lrealm=REALM.lower(),
+ other_realm=(REALM + ".another.example.net"))
+ return s
+
+
+class LdapUpnSamTestBase(TestCase):
+ """Make sure we can't add userPrincipalNames or sAMAccountNames that
+ implicitly collide.
+ """
+ _disabled = False
+
+ @classmethod
+ def setUpDynamicTestCases(cls):
+ if getattr(cls, '_disabled', False):
+ return
+ for doc, *rows in cls.cases:
+ name = re.sub(r'\W+', '_', doc)
+ cls.generate_dynamic_test("test_upn_sam", name, rows, doc)
+
+ def setup_objects(self, rows):
+ objects = set(r[0] for r in rows)
+ for name in objects:
+ if ':' in name:
+ objtype, name = name.split(':', 1)
+ else:
+ objtype = 'user'
+ getattr(self, f'add_{objtype}')(name)
+ self.addCleanup(self.remove_object, name)
+
+ def _test_upn_sam_with_args(self, rows, doc):
+ self.setup_objects(rows)
+ cdoc = c_doc(doc)
+
+ for i, row in enumerate(rows):
+ if len(row) == 4:
+ obj, data, expected, op = row
+ else:
+ obj, data, expected = row
+ op = ldb.FLAG_MOD_REPLACE
+
+ dn, dnsname = self.objects[obj]
+ sam, upn = None, None
+ if isinstance(data, dict):
+ sam = data.get('sam')
+ upn = data.get('upn')
+ elif isinstance(data, str):
+ if '@' in data:
+ upn = data
+ else:
+ sam = data
+ else: # bytes
+ if b'@' in data:
+ upn = data
+ else:
+ sam = data
+
+ m = {"dn": dn}
+
+ if upn is not None:
+ m["userPrincipalName"] = format(upn)
+
+ if sam is not None:
+ m["sAMAccountName"] = format(sam)
+
+ msg = ldb.Message.from_dict(self.samdb, m, op)
+
+ if expected is bad:
+ try:
+ self.samdb.modify(msg)
+ except ldb.LdbError as e:
+ print(f"row {i+1} of '{cdoc}' failed as expected with "
+ f"{ldb_err(e)}\n")
+ continue
+ self.fail(f"row {i+1} of '{cdoc}' should have failed:\n"
+ f"{pprint.pformat(m)} on {obj}")
+ elif expected is ok:
+ try:
+ self.samdb.modify(msg)
+ except ldb.LdbError as e:
+ raise AssertionError(
+ f"row {i+1} of '{cdoc}' failed with {ldb_err(e)}:\n"
+ f"{pprint.pformat(m)} on {obj}") from None
+ elif expected is report:
+ try:
+ self.samdb.modify(msg)
+ print(f"row {i+1} of '{cdoc}' SUCCEEDED:\n"
+ f"{pprint.pformat(m)} on {obj}")
+ except ldb.LdbError as e:
+ print(f"row {i+1} of '{cdoc}' FAILED "
+ f"with {ldb_err(e)}:\n"
+ f"{pprint.pformat(m)} on {obj}")
+
+ else:
+ try:
+ self.samdb.modify(msg)
+ except ldb.LdbError as e:
+ if hasattr(expected, '__contains__'):
+ if e.args[0] in expected:
+ continue
+
+ if e.args[0] == expected:
+ continue
+
+ self.fail(f"row {i+1} of '{cdoc}' "
+ f"should have failed with {ldb_err(expected)} "
+ f"but instead failed with {ldb_err(e)}:\n"
+ f"{pprint.pformat(m)} on {obj}")
+ self.fail(f"row {i+1} of '{cdoc}' "
+ f"should have failed with {ldb_err(expected)}:\n"
+ f"{pprint.pformat(m)} on {obj}")
+
+ def add_dc(self, name):
+ dn = f"CN={name},OU=Domain Controllers,{self.base_dn}"
+ dnsname = f"{name}.{REALM}".lower()
+ self.samdb.add({
+ "dn": dn,
+ "objectclass": "computer",
+ "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT |
+ UF_TRUSTED_FOR_DELEGATION),
+ "dnsHostName": dnsname,
+ "carLicense": self.id()
+ })
+ self.objects[name] = (dn, dnsname)
+
+ def add_user(self, name):
+ dn = f"CN={name},{self.ou}"
+ self.samdb.add({
+ "dn": dn,
+ "name": name,
+ "objectclass": "user",
+ "carLicense": self.id()
+ })
+ self.objects[name] = (dn, None)
+
+ def remove_object(self, name):
+ dn, dnsname = self.objects.pop(name)
+ self.samdb.delete(dn)
+
+ def setUp(self):
+ super().setUp()
+ self.samdb = get_samdb()
+ self.base_dn = self.samdb.get_default_basedn()
+ self.short_id = self.id().rsplit('.', 1)[1][:63]
+ self.objects = {}
+ self.ou = f"OU={ self.short_id },{ self.base_dn }"
+ self.addCleanup(self.samdb.delete, self.ou, ["tree_delete:1"])
+ self.samdb.add({"dn": self.ou, "objectclass": "organizationalUnit"})
+
+
+@DynamicTestCase
+class LdapUpnSamTest(LdapUpnSamTestBase):
+ cases = [
+ # The structure is
+ # ( «documentation/message that becomes test name»,
+ # («short object id», «upn or sam or mapping», «expected»),
+ # («short object id», «upn or sam or mapping», «expected»),
+ # ...,
+ # )
+ #
+ # where the first item is a one line string explaining the
+ # test, and subsequent items describe database modifications,
+ # to be applied in series.
+ #
+ # First is a short ID, which maps to an object DN. Second is
+ # either a string or a dictionary.
+ #
+ # * If a string, if it contains '@', it is a UPN, otherwise a
+ # samaccountname.
+ #
+ # * If a dictionary, it is a mapping of some of ['sam', 'upn']
+ # to strings (in this way, you can add two attributes in one
+ # mesage, or attempt a samaccountname with '@').
+ #
+ # expected can be «ok», «bad» (mapped to True and False,
+ # respectively), or a specific LDB error code, if that exact
+ # exception is wanted.
+ ("add good UPN",
+ ('A', 'a@{realm}', ok),
+ ),
+ ("add the same upn to different objects",
+ ('A', 'a@{realm}', ok),
+ ('B', 'a@{realm}', ldb.ERR_CONSTRAINT_VIOLATION),
+ ('B', 'a@{lrealm}', ldb.ERR_CONSTRAINT_VIOLATION), # lowercase realm
+ ),
+ ("replace UPN with itself",
+ ('A', 'a@{realm}', ok),
+ ('A', 'a@{realm}', ok),
+ ('A', 'a@{lrealm}', ok),
+ ),
+ ("replace SAM with itself",
+ ('A', 'a', ok),
+ ('A', 'a', ok),
+ ),
+ ("replace UPN realm",
+ ('A', 'a@{realm}', ok),
+ ('A', 'a@{other_realm}', ok),
+ ),
+ ("matching SAM and UPN",
+ ('A', 'a', ok),
+ ('A', 'a@{realm}', ok),
+ ),
+ ("matching SAM and UPN, other realm",
+ ('A', 'a', ok),
+ ('A', 'a@{other_realm}', ok),
+ ),
+ ("matching SAM and UPN, single message",
+ ('A', {'sam': 'a', 'upn': 'a@{realm}'}, ok),
+ ('A', {'sam': 'a', 'upn': 'a@{other_realm}'}, ok),
+ ),
+ ("different objects, different realms",
+ ('A', 'a@{realm}', ok),
+ ('B', 'a@{other_realm}', ok),
+ ),
+ ("different objects, same UPN, different case",
+ ('A', 'a@{realm}', ok),
+ ('B', 'A@{realm}', ldb.ERR_CONSTRAINT_VIOLATION),
+ ),
+ ("different objects, SAM after UPN",
+ ('A', 'a@{realm}', ok),
+ ('B', 'a', ldb.ERR_CONSTRAINT_VIOLATION),
+ ),
+ ("different objects, SAM before UPN",
+ ('A', 'a', ok),
+ ('B', 'a@{realm}', exists),
+ ),
+ ("different objects, SAM account clash",
+ ('A', 'a', ok),
+ ('B', 'a', exists),
+ ),
+ ("different objects, SAM account clash, different case",
+ ('A', 'a', ok),
+ ('B', 'A', exists),
+ ),
+ ("two way clash",
+ ('A', {'sam': 'x', 'upn': 'y@{realm}'}, ok),
+ # The sam account raises EXISTS while the UPN raises
+ # CONSTRAINT_VIOLATION. We don't really care in which order
+ # they are checked, so either error is ok.
+ ('B', {'sam': 'y', 'upn': 'x@{realm}'},
+ (exists, ldb.ERR_CONSTRAINT_VIOLATION)),
+ ),
+ ("two way clash, other realm",
+ ('A', {'sam': 'x', 'upn': 'y@{other_realm}'}, ok),
+ ('B', {'sam': 'y', 'upn': 'x@{other_realm}'}, ok),
+ ),
+ # UPN versions of bad sam account names
+ ("UPN clash on other realm",
+ ('A', 'a@x.x', ok),
+ ('B', 'a@x.x', ldb.ERR_CONSTRAINT_VIOLATION),
+ ),
+ ("UPN same but for trailing spaces",
+ ('A', 'a@{realm}', ok),
+ ('B', 'a @{realm}', ok),
+ ),
+ # UPN has no at
+ ("UPN has no at",
+ ('A', {'upn': 'noat'}, ok),
+ ('B', {'upn': 'noat'}, ldb.ERR_CONSTRAINT_VIOLATION),
+ ('C', {'upn': 'NOAT'}, ldb.ERR_CONSTRAINT_VIOLATION),
+ ),
+ # UPN has non-ascii at, followed by real at.
+ ("UPN with non-ascii at vs real at",
+ ('A', {'upn': 'smallat﹫{realm}'}, ok),
+ ('B', {'upn': 'smallat@{realm}'}, ok),
+ ('C', {'upn': 'tagat\U000e0040{realm}'}, ok),
+ ('D', {'upn': 'tagat@{realm}'}, ok),
+ ),
+ ("UPN with unicode at vs real at, real at first",
+ ('B', {'upn': 'smallat@{realm}'}, ok),
+ ('A', {'upn': 'smallat﹫{realm}'}, ok),
+ ('D', {'upn': 'tagat@{realm}'}, ok),
+ ('C', {'upn': 'tagat\U000e0040{realm}'}, ok),
+ ),
+ ("UPN username too long",
+ # SPN soft limit 20; hard limit 256, overall UPN 1024
+ ('A', 'a' * 25 + '@b.c', ok),
+ ('A', 'a' * 65 + '@b.c', ok), # Azure AD limit is 64
+ ('A', 'a' * 257 + '@b.c', ok), # 256 is sam account name limit
+ ),
+ ("sam account name 20 long",
+ # SPN soft limit 20
+ ('A', 'a' * 20, ok),
+ ),
+ ("UPN has two at signs",
+ ('A', 'a@{realm}', ok),
+ ('A', 'a@{realm}@{realm}', ok),
+ ('A', 'a@a.b', ok),
+ ('A', 'a@a@a.b', ok),
+ ),
+ ("SAM has at signs clashing upn second, non-realm",
+ ('A', {'sam': 'a@a.b'}, ok),
+ ('B', 'a@a.b@a.b', ok), # UPN won't clash with SAM, because realm
+ ),
+ ("SAM has at signs clashing upn second",
+ ('A', {'sam': 'a@{realm}'}, ok),
+ ('B', 'a@{realm}@{realm}', bad), # UPN would clashes with SAM
+ ),
+ ("SAM has at signs clashing upn first",
+ ('B', 'a@{realm}@{realm}', ok),
+ ('A', {'sam': 'a@{realm}'}, bad),
+ ),
+ ("spaces around at",
+ ('A', 'a name @ {realm}', ok),
+ ('B', 'a name @ {realm}', ldb.ERR_CONSTRAINT_VIOLATION),
+ ('B', 'a name @{realm}', ok), # because realm looks different
+ ('C', 'a name@{realm}', ok),
+ ('D', 'a name', ldb.ERR_CONSTRAINT_VIOLATION),
+ ('D', 'a name ', (exists, ldb.ERR_CONSTRAINT_VIOLATION)), # matches B
+ ),
+ ("SAM starts with at",
+ ('A', {'sam': '@{realm}'}, ok),
+ ('B', {'sam': '@a'}, ok),
+ ('C', {'sam': '@{realm}'}, exists),
+ ('C', {'sam': '@a'}, exists),
+ ('C', {'upn': '@{realm}@{realm}'}, bad),
+ ('C', {'upn': '@a@{realm}'}, bad),
+ ),
+ ("UPN starts with at",
+ ('A', {'upn': '@{realm}'}, ok),
+ ('B', {'upn': '@a@{realm}'}, ok),
+ ('C', {'upn': '@{realm}'}, bad),
+ ('C', {'sam': '@a'}, bad),
+ ),
+ ("SAM ends with at",
+ ('A', {'sam': '{realm}@'}, ok),
+ ('B', {'sam': 'a@'}, ok),
+ ('C', {'sam': '{realm}@'}, exists),
+ ('C', {'sam': 'a@'}, exists),
+ ('C', {'upn': 'a@@{realm}'}, bad),
+ ('C', {'upn': '{realm}@@{realm}'}, bad),
+ ),
+ ("UPN ends with at",
+ ('A', {'upn': '{realm}@'}, ok),
+ ('B', {'upn': '@a@{realm}@'}, ok),
+ ('C', {'upn': '{realm}@'}, bad),
+ ('C', {'sam': '@a@{realm}'}, ok), # not like B, because other realm
+ ),
+ ]
+
+
+@DynamicTestCase
+class LdapUpnSamSambaOnlyTest(LdapUpnSamTestBase):
+ # We don't run these ones outside of selftest, where we are
+ # probably testing against Windows and these are known failures.
+ _disabled = 'SAMBA_SELFTEST' not in os.environ
+ cases = [
+ ("sam account name too long",
+ # SPN soft limit 20
+ ('A', 'a' * 19, ok),
+ ('A', 'a' * 20, ok),
+ ('A', 'a' * 65, ok),
+ ('A', 'a' * 255, ok),
+ ('A', 'a' * 256, ok),
+ ('A', 'a' * 257, ldb.ERR_INVALID_ATTRIBUTE_SYNTAX),
+ ),
+ ("UPN username too long",
+ ('A', 'a' * 254 + '@' + 'b.c' * 257,
+ ldb.ERR_INVALID_ATTRIBUTE_SYNTAX), # 1024 is alleged UPN limit
+ ),
+ ("UPN same but for internal spaces",
+ ('A', 'a b@x.x', ok),
+ ('B', 'a b@x.x', ldb.ERR_CONSTRAINT_VIOLATION),
+ ),
+ ("SAM contains delete",
+ # forbidden according to documentation, but works in practice on Windows
+ ('A', 'a\x7f', ldb.ERR_CONSTRAINT_VIOLATION),
+ ('A', 'a\x7f'.encode(), ldb.ERR_CONSTRAINT_VIOLATION),
+ ('A', 'a\x7fb', ldb.ERR_CONSTRAINT_VIOLATION),
+ ('A', 'a\x7fb'.encode(), ldb.ERR_CONSTRAINT_VIOLATION),
+ ('A', '\x7fb', ldb.ERR_CONSTRAINT_VIOLATION),
+ ('A', '\x7fb'.encode(), ldb.ERR_CONSTRAINT_VIOLATION),
+ ),
+ # The wide at symbol ('@' U+FF20) does not count as '@' for Samba
+ # so it will look like a string with no @s.
+ ("UPN with unicode wide at vs real at",
+ ('A', {'upn': 'wideat@{realm}'}, ok),
+ ('B', {'upn': 'wideat@{realm}'}, ok),
+ ),
+ ("UPN with real at vs wide at",
+ ('B', {'upn': 'wideat@{realm}'}, ok),
+ ('A', {'upn': 'wideat@{realm}'}, ok)
+ ),
+ ]
+
+
+def main():
+ global LP, CREDS, SERVER, REALM
+
+ parser = optparse.OptionParser(
+ "python3 ldap_upn_sam_account_name.py [options]")
+ sambaopts = options.SambaOptions(parser)
+ parser.add_option_group(sambaopts)
+
+ # use command line creds if available
+ credopts = options.CredentialsOptions(parser)
+ parser.add_option_group(credopts)
+ subunitopts = SubunitOptions(parser)
+ parser.add_option_group(subunitopts)
+
+ opts, args = parser.parse_args()
+ if len(args) != 1:
+ parser.print_usage()
+ sys.exit(1)
+
+ LP = sambaopts.get_loadparm()
+ CREDS = credopts.get_credentials(LP)
+ SERVER = args[0]
+ REALM = CREDS.get_realm()
+
+ TestProgram(module=__name__, opts=subunitopts)
+
+main()
diff -Nru samba-4.13.3+dfsg/python/samba/tests/samba_tool/computer.py samba-4.13.14+dfsg/python/samba/tests/samba_tool/computer.py
--- samba-4.13.3+dfsg/python/samba/tests/samba_tool/computer.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/samba_tool/computer.py 2021-11-08 11:29:14.000000000 +0000
@@ -39,23 +39,29 @@
# ips used to test --ip-address option
self.ipv4 = '10.10.10.10'
self.ipv6 = '2001:0db8:0a0b:12f0:0000:0000:0000:0001'
+ computer_basename = self.randomName().lower()
data = [
{
- 'name': 'testcomputer1',
+ 'name': computer_basename + 'cmp1',
'ip_address_list': [self.ipv4]
},
{
- 'name': 'testcomputer2',
+ 'name': computer_basename + 'cmp2',
'ip_address_list': [self.ipv6],
- 'service_principal_name_list': ['SPN0']
+ 'service_principal_name_list': [
+ 'host/' + computer_basename + 'SPN20',
+ ],
},
{
- 'name': 'testcomputer3$',
+ 'name': computer_basename + 'cmp3$',
'ip_address_list': [self.ipv4, self.ipv6],
- 'service_principal_name_list': ['SPN0', 'SPN1']
+ 'service_principal_name_list': [
+ 'host/' + computer_basename + 'SPN30',
+ 'host/' + computer_basename + 'SPN31',
+ ],
},
{
- 'name': 'testcomputer4$',
+ 'name': computer_basename + 'cmp4$',
},
]
self.computers = [self._randomComputer(base=item) for item in data]
diff -Nru samba-4.13.3+dfsg/python/samba/tests/samdb.py samba-4.13.14+dfsg/python/samba/tests/samdb.py
--- samba-4.13.3+dfsg/python/samba/tests/samdb.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/samdb.py 2021-09-22 06:59:39.000000000 +0000
@@ -38,13 +38,13 @@
super(SamDBTestCase, self).setUp()
self.session = system_session()
logger = logging.getLogger("selftest")
- domain = "dsdb"
- realm = "dsdb.samba.example.com"
+ self.domain = "dsdb"
+ self.realm = "dsdb.samba.example.com"
host_name = "test"
server_role = "active directory domain controller"
self.result = provision(logger,
self.session, targetdir=self.tempdir,
- realm=realm, domain=domain,
+ realm=self.realm, domain=self.domain,
hostname=host_name,
use_ntvfs=True,
serverrole=server_role,
@@ -61,3 +61,10 @@
shutil.rmtree(os.path.join(self.tempdir, d))
super(SamDBTestCase, self).tearDown()
+
+
+class SamDBTests(SamDBTestCase):
+
+ def test_get_domain(self):
+ self.assertEqual(self.samdb.domain_dns_name(), self.realm.lower())
+ self.assertEqual(self.samdb.domain_netbios_name(), self.domain.upper())
diff -Nru samba-4.13.3+dfsg/python/samba/tests/segfault.py samba-4.13.14+dfsg/python/samba/tests/segfault.py
--- samba-4.13.3+dfsg/python/samba/tests/segfault.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/segfault.py 2021-10-29 06:17:36.000000000 +0000
@@ -174,3 +174,26 @@
def test_dcerpc_idl_inline_arrays(self):
"""Inline arrays were incorrectly handled."""
dnsserver.DNS_RPC_SERVER_INFO_DOTNET().pExtensions
+
+ @segfault_detector
+ def test_ldb_msg_diff(self):
+ samdb = self.get_samdb()
+
+ msg = ldb.Message()
+ msg.dn = ldb.Dn(samdb, '')
+ diff = samdb.msg_diff(msg, msg)
+
+ del msg
+ diff.dn
+
+ @segfault_detector
+ def test_ldb_msg_del_dn(self):
+ msg = ldb.Message()
+ del msg.dn
+
+ @segfault_detector
+ def test_ldb_control_del_critical(self):
+ samdb = self.get_samdb()
+
+ c = ldb.Control(samdb, 'relax:1')
+ del c.critical
diff -Nru samba-4.13.3+dfsg/python/samba/tests/usage.py samba-4.13.14+dfsg/python/samba/tests/usage.py
--- samba-4.13.3+dfsg/python/samba/tests/usage.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/tests/usage.py 2021-11-08 11:29:14.000000000 +0000
@@ -89,6 +89,24 @@
'python/samba/tests/krb5/simple_tests.py',
'python/samba/tests/krb5/s4u_tests.py',
'python/samba/tests/krb5/xrealm_tests.py',
+ 'python/samba/tests/krb5/as_canonicalization_tests.py',
+ 'python/samba/tests/krb5/compatability_tests.py',
+ 'python/samba/tests/krb5/rfc4120_constants.py',
+ 'python/samba/tests/krb5/kdc_tests.py',
+ 'python/samba/tests/krb5/kdc_base_test.py',
+ 'python/samba/tests/krb5/kdc_tgs_tests.py',
+ 'python/samba/tests/krb5/test_ccache.py',
+ 'python/samba/tests/krb5/test_ldap.py',
+ 'python/samba/tests/krb5/test_rpc.py',
+ 'python/samba/tests/krb5/test_smb.py',
+ 'python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py',
+ 'python/samba/tests/krb5/as_req_tests.py',
+ 'python/samba/tests/krb5/fast_tests.py',
+ 'python/samba/tests/krb5/rodc_tests.py',
+ 'python/samba/tests/krb5/salt_tests.py',
+ 'python/samba/tests/krb5/spn_tests.py',
+ 'python/samba/tests/krb5/alias_tests.py',
+ 'python/samba/tests/krb5/test_min_domain_uid.py',
}
EXCLUDE_HELP = {
diff -Nru samba-4.13.3+dfsg/python/samba/upgrade.py samba-4.13.14+dfsg/python/samba/upgrade.py
--- samba-4.13.3+dfsg/python/samba/upgrade.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/python/samba/upgrade.py 2021-08-06 12:19:57.000000000 +0000
@@ -74,7 +74,7 @@
if 'maximum password age' in policy:
max_pw_age_unix = policy['maximum password age']
- if max_pw_age_unix == -1 or max_pw_age_unix == 0:
+ if max_pw_age_unix == -1 or max_pw_age_unix == 0 or max_pw_age_unix == 0xFFFFFFFF:
max_pw_age_nt = -0x8000000000000000
else:
max_pw_age_nt = int(-max_pw_age_unix * (1e7))
diff -Nru samba-4.13.3+dfsg/script/autobuild.py samba-4.13.14+dfsg/script/autobuild.py
--- samba-4.13.3+dfsg/script/autobuild.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/script/autobuild.py 2021-10-29 06:17:36.000000000 +0000
@@ -4,7 +4,7 @@
# released under GNU GPL v3 or later
from __future__ import print_function
-from subprocess import call, check_call, check_output, Popen, PIPE
+from subprocess import call, check_call, check_output, Popen, PIPE, CalledProcessError
import os
import tarfile
import sys
@@ -154,7 +154,6 @@
def make_test(
cmd='make test',
- FAIL_IMMEDIATELY=1,
TESTS='',
include_envs=None,
exclude_envs=None):
@@ -169,7 +168,13 @@
TESTS = (TESTS + ' ' + ' '.join(test_options)).strip()
_options = []
- if FAIL_IMMEDIATELY:
+
+ # Allow getting a full CI with
+ # git push -o ci.variable='AUTOBUILD_FAIL_IMMEDIATELY=0'
+
+ FAIL_IMMEDIATELY = os.getenv("AUTOBUILD_FAIL_IMMEDIATELY", "1")
+
+ if int(FAIL_IMMEDIATELY):
_options.append('FAIL_IMMEDIATELY=1')
if TESTS:
_options.append("TESTS='{}'".format(TESTS))
@@ -860,6 +865,17 @@
else:
return call(cmd, shell=True, cwd=dir)
+def rmdir_force(dirname, re_raise=True):
+ try:
+ run_cmd("test -d %s && chmod -R +w %s; rm -rf %s" % (
+ dirname, dirname, dirname), output=True, show=True)
+ except CalledProcessError as e:
+ do_print("Failed: '%s'" % (str(e)))
+ run_cmd("tree %s" % dirname, output=True, show=True)
+ if re_raise:
+ raise
+ return False
+ return True
class builder(object):
'''handle build of one directory'''
@@ -882,8 +898,8 @@
self.test_source_dir = "%s/%s" % (testbase, self.tag)
self.cwd = "%s/%s" % (self.test_source_dir, self.dir)
self.prefix = "%s/%s" % (test_prefix, self.tag)
- run_cmd("rm -rf %s" % self.test_source_dir)
- run_cmd("rm -rf %s" % self.prefix)
+ rmdir_force(self.test_source_dir)
+ rmdir_force(self.prefix)
if cp:
run_cmd("cp -R -a -l %s %s" % (test_master, self.test_source_dir), dir=test_master, show=True)
else:
@@ -893,8 +909,8 @@
def start_next(self):
if self.next == len(self.sequence):
if not options.nocleanup:
- run_cmd("rm -rf %s" % self.test_source_dir)
- run_cmd("rm -rf %s" % self.prefix)
+ rmdir_force(self.test_source_dir)
+ rmdir_force(self.prefix)
do_print('%s: Completed OK' % self.name)
self.done = True
return
@@ -1018,7 +1034,7 @@
'df -m %s' % testbase]:
try:
out = run_cmd(cmd, output=True, checkfail=False)
- except subprocess.CalledProcessError as e:
+ except CalledProcessError as e:
out = "" % str(e)
print('### %s' % cmd, file=f)
print(out, file=f)
@@ -1048,14 +1064,23 @@
self.tail_proc = Popen(cmd, close_fds=True)
-def cleanup():
+def cleanup(do_raise=False):
if options.nocleanup:
return
run_cmd("stat %s || true" % test_tmpdir, show=True)
run_cmd("stat %s" % testbase, show=True)
do_print("Cleaning up %r" % cleanup_list)
for d in cleanup_list:
- run_cmd("rm -rf %s" % d)
+ ok = rmdir_force(d, re_raise=False)
+ if ok:
+ continue
+ if os.path.isdir(d):
+ do_print("Killing, waiting and retry")
+ run_cmd("killbysubdir %s > /dev/null 2>&1" % d, checkfail=False)
+ else:
+ do_print("Waiting and retry")
+ time.sleep(1)
+ rmdir_force(d, re_raise=do_raise)
def daemonize(logfile):
@@ -1321,7 +1346,7 @@
(status, failed_task, failed_stage, failed_tag, errstr) = blist.run()
if status != 0 or errstr != "retry":
break
- cleanup()
+ cleanup(do_raise=True)
except Exception:
cleanup()
raise
diff -Nru samba-4.13.3+dfsg/script/bisect-test.py samba-4.13.14+dfsg/script/bisect-test.py
--- samba-4.13.3+dfsg/script/bisect-test.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/script/bisect-test.py 2021-10-29 06:17:36.000000000 +0000
@@ -48,7 +48,7 @@
'''get to the top of the git repo'''
p = os.getcwd()
while p != '/':
- if os.path.isdir(os.path.join(p, ".git")):
+ if os.path.exists(os.path.join(p, ".git")):
return p
p = os.path.abspath(os.path.join(p, '..'))
return None
diff -Nru samba-4.13.3+dfsg/script/release.sh samba-4.13.14+dfsg/script/release.sh
--- samba-4.13.3+dfsg/script/release.sh 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/script/release.sh 2021-08-06 12:19:57.000000000 +0000
@@ -316,7 +316,7 @@
echo "Signing ${tarname} => ${tarname}.asc"
rm -f "${tarname}.asc"
- gpg -u "${GPG_USER}" --detach-sign --armor ${tarname} || {
+ gpg --default-key "${GPG_KEYID}" --detach-sign --armor ${tarname} || {
return 1
}
test -f "${tarname}.asc" || {
@@ -362,7 +362,7 @@
echo "Signing ${patchfile} => ${patchfile}.asc"
rm -f "${patchfile}.asc"
CLEANUP_FILES="${CLEANUP_FILES} ${patchfile}.asc"
- gpg -u "${GPG_USER}" --detach-sign --armor ${patchfile} || {
+ gpg --default-key "${GPG_KEYID}" --detach-sign --armor ${patchfile} || {
return 1
}
test -f "${patchfile}.asc" || {
@@ -1053,7 +1053,7 @@
}
test -z "${GPG_KEYID-}" && {
- GPG_KEYID='6F33915B6568B7EA'
+ GPG_KEYID='AA99442FB680B620'
}
productbase="samba"
@@ -1074,7 +1074,7 @@
}
test -z "${GPG_KEYID-}" && {
- GPG_KEYID='6F33915B6568B7EA'
+ GPG_KEYID='AA99442FB680B620'
}
productbase="samba"
@@ -1096,7 +1096,7 @@
}
test -z "${GPG_KEYID-}" && {
- GPG_KEYID='6F33915B6568B7EA'
+ GPG_KEYID='AA99442FB680B620'
}
productbase="samba"
diff -Nru samba-4.13.3+dfsg/selftest/knownfail samba-4.13.14+dfsg/selftest/knownfail
--- samba-4.13.3+dfsg/selftest/knownfail 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/knownfail 2021-09-22 06:59:39.000000000 +0000
@@ -144,6 +144,7 @@
^samba4.raw.acls.*.create_owner_file
^samba4.smb2.create.*.acldir
^samba4.smb2.create.*.impersonation
+^samba4.smb2.create.quota-fake-file\(ad_dc_ntvfs\) # not supported by the NTVFS
^samba4.smb2.acls.*.generic
^samba4.smb2.acls.*.inheritflags
^samba4.smb2.acls.*.owner
@@ -293,10 +294,6 @@
^samba4.winbind.struct.lookup_name_sid\(ad_member:local\)
^samba4.winbind.struct.getdcname\(nt4_member:local\) # Works in other modes, just not against the classic/NT4 DC
#
-# Differences in our KDC compared to windows
-#
-^samba4.krb5.kdc .*.as-req-pac-request # We should reply to a request for a PAC over UDP with KRB5KRB_ERR_RESPONSE_TOO_BIG unconditionally
-#
# This will fail against the classic DC, because it requires kerberos
#
^samba4.winbind.pac.*\(nt4_member:local\) # No KDC on a classic DC
@@ -335,7 +332,7 @@
#
^samba4.smb.signing.*disabled.*signing=off.*\(ad_dc\)
# fl2000dc doesn't support AES
-^samba4.krb5.kdc.*as-req-aes.*fl2000dc
+^samba4.krb5.kdc.*as-req-aes.fl2000dc
# nt4_member and ad_member don't support ntlmv1 (not even over SMB1)
^samba3.blackbox.smbclient_auth.plain.*option=clientntlmv2auth=no.member.creds.*as.user.*_member
^samba3.blackbox.smbclient_auth.plain.*option=clientntlmv2auth=no.*mNT1.member.creds.*as.user.*_member
diff -Nru samba-4.13.3+dfsg/selftest/knownfail.d/kdc-enterprise samba-4.13.14+dfsg/selftest/knownfail.d/kdc-enterprise
--- samba-4.13.3+dfsg/selftest/knownfail.d/kdc-enterprise 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/knownfail.d/kdc-enterprise 2021-09-22 06:59:39.000000000 +0000
@@ -0,0 +1,63 @@
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName_UPN\(
+
+
+
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN_RemoveDollar_AsReqSelf\(
diff -Nru samba-4.13.3+dfsg/selftest/knownfail.d/kdc-salt samba-4.13.14+dfsg/selftest/knownfail.d/kdc-salt
--- samba-4.13.3+dfsg/selftest/knownfail.d/kdc-salt 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/knownfail.d/kdc-salt 2021-10-29 06:17:36.000000000 +0000
@@ -0,0 +1 @@
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_salt_upn_at_realm_user
diff -Nru samba-4.13.3+dfsg/selftest/knownfail.d/ldap_spn samba-4.13.14+dfsg/selftest/knownfail.d/ldap_spn
--- samba-4.13.3+dfsg/selftest/knownfail.d/ldap_spn 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/knownfail.d/ldap_spn 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1 @@
+samba.tests.ldap_spn.+LdapSpnTest.test_spn_dodgy_spns
diff -Nru samba-4.13.3+dfsg/selftest/knownfail.d/modify-order samba-4.13.14+dfsg/selftest/knownfail.d/modify-order
--- samba-4.13.3+dfsg/selftest/knownfail.d/modify-order 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/knownfail.d/modify-order 2021-11-08 11:29:14.000000000 +0000
@@ -1,8 +1,8 @@
samba4.ldap_modify_order.python.+ModifyOrderTests.test_modify_order_account_locality_device
samba4.ldap_modify_order.python.+ModifyOrderTests.test_modify_order_container_flags_multivalue
-samba4.ldap_modify_order.python.+ModifyOrderTests.test_modify_order_objectclass
samba4.ldap_modify_order.python.+ModifyOrderTests.test_modify_order_objectclass2
samba4.ldap_modify_order.python.+ModifyOrderTests.test_modify_order_singlevalue
samba4.ldap_modify_order.normal_user.+ModifyOrderTests.test_modify_order_account_locality_device
samba4.ldap_modify_order.normal_user.+ModifyOrderTests.test_modify_order_container_flags[^_]
+samba4.ldap_modify_order.normal_user.+ModifyOrderTests.test_modify_order_objectclass[^2]
samba4.ldap_modify_order.normal_user.+ModifyOrderTests.test_modify_order_objectclass2
diff -Nru samba-4.13.3+dfsg/selftest/knownfail.d/priv_attr samba-4.13.14+dfsg/selftest/knownfail.d/priv_attr
--- samba-4.13.3+dfsg/selftest/knownfail.d/priv_attr 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/knownfail.d/priv_attr 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,13 @@
+# These priv_attrs tests would be good to fix, but are not fatal as
+# the testsuite is run twice, once with and once without STRICT_CHECKING=0
+#
+# These knownfails show that we can improve our error matching against Windows.
+#
+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_computer
+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_WP_user
+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_default_computer
+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_CC_default_user
+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_WP_computer
+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_WP_user
+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_default_computer
+samba4.priv_attrs.strict.python\(.*\).__main__.PrivAttrsTests.test_priv_attr_sidHistory_add_admin-add_default_user
diff -Nru samba-4.13.3+dfsg/selftest/knownfail.d/python-segfaults samba-4.13.14+dfsg/selftest/knownfail.d/python-segfaults
--- samba-4.13.3+dfsg/selftest/knownfail.d/python-segfaults 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/knownfail.d/python-segfaults 2021-10-29 06:17:36.000000000 +0000
@@ -1 +1,3 @@
samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_init__3
+samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_dnsp_string_list
+samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_dns_record
diff -Nru samba-4.13.3+dfsg/selftest/knownfail.d/uac_objectclass_restrict samba-4.13.14+dfsg/selftest/knownfail.d/uac_objectclass_restrict
--- samba-4.13.3+dfsg/selftest/knownfail.d/uac_objectclass_restrict 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/knownfail.d/uac_objectclass_restrict 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,17 @@
+# Knownfail entries due to restricting the creation of computer/user
+# accounts (in terms of userAccountControl) that do not match the objectclass
+#
+# All these tests need to be fixed and the entries here removed
+
+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-DC_add_CC_WP_user\(ad_dc_default\)
+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-DC_add_CC_default_user\(ad_dc_default\)
+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_WP_computer\(ad_dc_default\)
+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_add_CC_default_computer\(ad_dc_default\)
+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_mod-del-add_CC_default_computer\(ad_dc_default\)
+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-a2d-user_mod-replace_CC_default_computer\(ad_dc_default\)
+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-user_add_CC_WP_computer\(ad_dc_default\)
+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-user_add_CC_default_computer\(ad_dc_default\)
+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-user_mod-del-add_CC_default_computer\(ad_dc_default\)
+^samba4.priv_attrs.strict.python\(ad_dc_default\).__main__.PrivAttrsTests.test_priv_attr_userAccountControl-t4d-user_mod-replace_CC_default_computer\(ad_dc_default\)
+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_add_computer_sd_cc\(ad_dc_default\)
+^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_computer_cc\(ad_dc_default\)
diff -Nru samba-4.13.3+dfsg/selftest/knownfail_heimdal_kdc samba-4.13.14+dfsg/selftest/knownfail_heimdal_kdc
--- samba-4.13.3+dfsg/selftest/knownfail_heimdal_kdc 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/knownfail_heimdal_kdc 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,261 @@
+#
+# We expect all the MIT specific compatability tests to fail on heimdal
+# kerberos
+^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_mit_
+#
+# Heimdal currently fails the following MS-KILE client principal lookup
+# tests
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_enterprise_principal_step_1_3
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_enterprise_principal_step_4
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_enterprise_principal_step_5
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_enterprise_principal_step_6_a
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_enterprise_principal_step_6_b
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_4_a
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_4_b
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_4_c
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_6_c
+#
+# Heimdal (not MIT) still fails these after 'Make e-data checking less strict'
+#
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_dummy_rc4_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_dummy_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_aes256_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_aes128_pac_True.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_False.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_None.fl2008r2dc
+^samba.tests.krb5.salt_tests.samba.tests.krb5.salt_tests.SaltTests.test_as_req_no_preauth_rc4_dummy_aes256_pac_True.fl2008r2dc
+#
+# FAST tests
+#
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_empty_fast.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_ad_fx_fast_armor.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_ad_fx_fast_armor2.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_ad_fx_fast_armor_ticket.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_ad_fx_fast_armor_ticket2.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_authdata_fast_not_used.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_authdata_fast_used.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_enc_timestamp.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_clock_skew.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_replay.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_wrong_key.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_wrong_key_kdc.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_hide_client_names.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_invalid_armor_type.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_invalid_armor_type2.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_invalid_tgt.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_invalid_tgt_mach.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_no_canon.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_no_claims.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_no_claims_or_canon.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_outer_wrong_flags.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_outer_wrong_nonce.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_outer_wrong_realm.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_outer_wrong_till.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_armor.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_hide_client_names.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_no_claims.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_no_subkey.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_outer_wrong_flags.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_outer_wrong_nonce.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_outer_wrong_realm.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_outer_wrong_till.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_service_ticket.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_service_ticket_mach.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_unknown_critical_option.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_tgs.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_tgs_no_subkey.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_tgs_service_ticket.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_tgs_service_ticket_mach.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_tgs_wrong_principal.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_unarmored_as_req.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_outer_no_sname.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_outer_no_sname.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_no_sname.ad_dc
+#
+# S4U tests
+#
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_bronze_bit_rbcd_old_checksum
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_no_service_pac\(.*\)$
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_existing_delegation_info
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_missing_client_checksum
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_a
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_b
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_unkeyed_client_checksum
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_unkeyed_service_checksum
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_zeroed_client_checksum
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_zeroed_service_checksum
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_forwardable
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_trusted_empty_allowed
+#
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_no_auth_data_required
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_auth_data_required
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_no_auth_data_required_a
+^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_no_auth_data_required_b
+#
+# https://bugzilla.samba.org/show_bug.cgi?id=14886: Tests for accounts not revealed to the RODC
+#
+# The KDC should not accept tickets from an RODC for accounts not in the msDS-RevealedUsers list.
+#
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_not_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_not_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_not_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_not_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_revealed
diff -Nru samba-4.13.3+dfsg/selftest/knownfail_mit_kdc samba-4.13.14+dfsg/selftest/knownfail_mit_kdc
--- samba-4.13.3+dfsg/selftest/knownfail_mit_kdc 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/knownfail_mit_kdc 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,521 @@
+#
+# We expect all the heimdal specific compatability tests to fail on MIT
+# kerberos
+^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_heimdal_
+#
+# Currently MOST but not quite all the Canonicalization tests fail on the
+# MIT KDC
+#
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperRealm_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperRealm_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_Enterprise_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperRealm_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperRealm_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperRealm_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperRealm_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperRealm_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Canonicalize_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_UpperRealm_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_UpperRealm_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_UpperRealm_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_UpperRealm_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_UpperUserName_NetbiosRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_UpperUserName_NetbiosRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_UpperUserName\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_UserCredentials_Enterprise_UpperRealm_UpperUserName_UPN\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_NetbiosRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_NetbiosRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UPN_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_RemoveDollar\(
+samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_UPN_RemoveDollar\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperRealm_UpperUserName_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(ad_dc
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_Enterprise_UpperUserName_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperRealm_UpperUserName_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Canonicalize_UpperUserName_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_Enterprise_UpperRealm_UpperUserName_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_UpperUserName_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperRealm_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_NetbiosRealm_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_NetbiosRealm_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_NetbiosRealm_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_NetbiosRealm_UPN_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_RemoveDollar_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_UPN_AsReqSelf\(
+^samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_tests.KerberosASCanonicalizationTests.test_MachineCredentials_UpperUserName_UPN_RemoveDollar_AsReqSelf\(
+#
+# MIT currently returns an error code of 12 KRB5KDC_ERR_POLICY: KDC policy rejects request, to the
+# following tests
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_ldap_service_ticket\(ad_dc\)
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_get_ticket_for_host_service_of_machine_account\(ad_dc\)
+#
+# KDC TGS PAC tests
+#
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_client_no_auth_data_required\(ad_dc\)
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_no_pac_client_no_auth_data_required\(ad_dc\)
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_no_pac_service_no_auth_data_required\(ad_dc\)
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac\(ad_dc\)
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_client_no_auth_data_required\(ad_dc\)
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_remove_pac_service_no_auth_data_required\(ad_dc\)
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_request_no_pac\(ad_dc\)
+#
+# MIT currently fails the following MS-KILE tests.
+#
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_enterprise_principal_step_1_3
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_enterprise_principal_step_4
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_enterprise_principal_step_5
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_enterprise_principal_step_6_a
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_enterprise_principal_step_6_b
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_1
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_2
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_3
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_4_a
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_4_b
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_4_c
+^samba.tests.krb5.ms_kile_client_principal_lookup_tests.samba.tests.krb5.ms_kile_client_principal_lookup_tests.MS_Kile_Client_Principal_Lookup_Tests.test_nt_principal_step_6_c
+#
+# MIT currently fails some as_req_no_preauth tests.
+#
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth.*aes.*rc4.*fl2003dc
+^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth.*rc4.*aes.*fl2003dc
+# Differences in our KDC compared to windows
+#
+^samba4.krb5.kdc .*.as-req-pac-request # We should reply to a request for a PAC over UDP with KRB5KRB_ERR_RESPONSE_TOO_BIG unconditionally
+#
+# fl2000dc doesn't support AES
+^samba4.krb5.kdc.*as-req-aes.*fl2000dc
+#
+# FAST tests
+#
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_ad_fx_fast_armor.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_ad_fx_fast_armor_ticket.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_authdata_fast_not_used.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_enc_timestamp.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_clock_skew.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_no_fast.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_wrong_key.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_encrypted_challenge_wrong_key_kdc.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_invalid_tgt.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_invalid_tgt_mach.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_armor.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_no_subkey.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_service_ticket.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_service_ticket_mach.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_unknown_critical_option.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_tgs_service_ticket.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_tgs_service_ticket_mach.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_unarmored_as_req.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_outer_no_sname.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_outer_no_sname.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_no_sname.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_no_sname.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_fast_no_etypes.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_no_sname.ad_dc
+^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_simple_tgs_no_sname.ad_dc
+#
+# PAC tests
+#
+^netr-bdc-arcfour.verify-sig-arcfour
+^netr-bdc-arcfour.verify-sig-arcfour
+^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc:local
+^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc_ntvfs:local
+^samba4.blackbox.pkinit_pac.netr-bdc-aes.verify-sig-aes.ad_dc:local
+^samba4.blackbox.pkinit_pac.netr-bdc-aes.verify-sig-aes.ad_dc_ntvfs:local
+^samba4.blackbox.pkinit_pac.netr-mem-aes.s4u2proxy-aes.ad_dc:local
+^samba4.blackbox.pkinit_pac.netr-mem-aes.s4u2proxy-aes.ad_dc_ntvfs:local
+^samba4.blackbox.pkinit_pac.netr-mem-aes.verify-sig-aes.ad_dc:local
+^samba4.blackbox.pkinit_pac.netr-mem-aes.verify-sig-aes.ad_dc_ntvfs:local
+^samba4.blackbox.pkinit_pac.netr-mem-arcfour.s4u2proxy-arcfour.ad_dc:local
+^samba4.blackbox.pkinit_pac.netr-mem-arcfour.s4u2proxy-arcfour.ad_dc_ntvfs:local
+^samba4.blackbox.pkinit_pac.netr-mem-arcfour.verify-sig-arcfour.ad_dc:local
+^samba4.blackbox.pkinit_pac.netr-mem-arcfour.verify-sig-arcfour.ad_dc_ntvfs:local
+^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2000dc
+^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2003dc
+^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2008dc
+^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2008r2dc
+^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2000dc
+^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2003dc
+^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2008dc
+^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2008r2dc
+^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2000dc
+^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2003dc
+^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2008dc
+^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2008r2dc
+^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2000dc
+^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2003dc
+^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2008dc
+^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2008r2dc
+^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2000dc
+^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2003dc
+^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2008dc
+^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2008r2dc
+^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2000dc
+^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2003dc
+^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008dc
+^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008r2dc
+#
+# Alias tests
+#
+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_delete
+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_create_alias_rename
+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_delete
+^samba.tests.krb5.alias_tests.samba.tests.krb5.alias_tests.AliasTests.test_dc_alias_rename
+#
+# KDC TGT tests
+#
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_allowed_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_no_krbtgt_link
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_no_partial_secrets
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_not_allowed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_not_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_req
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_allowed_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_no_krbtgt_link
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_no_partial_secrets
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_not_allowed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_not_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rename
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_allowed_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_no_krbtgt_link
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_no_partial_secrets
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_not_allowed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_not_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_no_sname
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_other_sname
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_req
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_allowed_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_no_krbtgt_link
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_no_partial_secrets
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_not_allowed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_not_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_rodc_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_tgt_cname_host
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_tgt_correct_cname
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_tgt_correct_realm
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_tgt_other_cname
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_tgt_wrong_realm
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname_krbtgt
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_srealm
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_authdata_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_no_pac
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_allowed_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_denied
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_no_krbtgt_link
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_no_partial_secrets
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_allowed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_revealed
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_sid_mismatch_nonexisting
+#
+# PAC attributes tests
+#
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_renew_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_renew_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_renew_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_rodc_renew_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_rodc_renew_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_missing_rodc_renew_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_renew_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_renew_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_renew_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_rodc_renew_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_pac_attrs_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_pac_attrs_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_pac_attrs
+#
+# PAC request tests
+#
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_pac_request_true
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_user_pac_request_false
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_user_pac_request_none
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_user_pac_request_true
+#
+# PAC requester SID tests
+#
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_as_requester_sid
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_logon_info_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_requester_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_requester_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_req_from_rodc_no_requester_sid
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_renew
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_missing_rodc_renew
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_renew
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_requester_sid_rodc_renew
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_only_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_logon_info_sid_mismatch_nonexisting
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_requester_sid_mismatch_existing
+^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_requester_sid_mismatch_nonexisting
diff -Nru samba-4.13.3+dfsg/selftest/selftesthelpers.py samba-4.13.14+dfsg/selftest/selftesthelpers.py
--- samba-4.13.3+dfsg/selftest/selftesthelpers.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/selftesthelpers.py 2021-09-22 06:59:39.000000000 +0000
@@ -1,4 +1,5 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
+#
# This script generates a list of testsuites that should be run as part of
# the Samba 4 test suite.
@@ -25,7 +26,8 @@
def srcdir():
- return os.path.normpath(os.getenv("SRCDIR", os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")))
+ alternate_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
+ return os.path.normpath(os.getenv("SRCDIR", alternate_path))
def source4dir():
@@ -65,7 +67,7 @@
return valgrind + " " + cmdline
-def plantestsuite(name, env, cmdline):
+def plantestsuite(name, env, cmd, environ={}):
"""Plan a test suite.
:param name: Testsuite name
@@ -79,8 +81,18 @@
fullname = "%s(%s)" % (name, env)
print(fullname)
print(env)
- if isinstance(cmdline, list):
- cmdline = " ".join(cmdline)
+
+ cmdline = ""
+ if environ:
+ environ = dict(environ)
+ cmdline_env = ["%s=%s" % item for item in environ.items()]
+ cmdline = " ".join(cmdline_env) + " "
+
+ if isinstance(cmd, list):
+ cmdline += " ".join(cmd)
+ else:
+ cmdline += cmd
+
if "$LISTOPT" in cmdline:
raise AssertionError("test %s supports --list, but not --load-list" % name)
print(cmdline + " 2>&1 " + " | " + add_prefix(name, env))
@@ -91,7 +103,8 @@
listopt = "$LISTOPT "
else:
listopt = ""
- return "%s %s/selftest/filter-subunit %s--fail-on-empty --prefix=\"%s.\" --suffix=\"(%s)\"" % (python, srcdir(), listopt, prefix, env)
+ return ("%s %s/selftest/filter-subunit %s--fail-on-empty --prefix=\"%s.\" --suffix=\"(%s)\"" %
+ (python, srcdir(), listopt, prefix, env))
def plantestsuite_loadlist(name, env, cmdline):
@@ -109,7 +122,9 @@
raise AssertionError("loadlist test %s does not support not --list" % name)
if "$LOADLIST" not in cmdline:
raise AssertionError("loadlist test %s does not support --load-list" % name)
- print(("%s | %s" % (cmdline.replace("$LOADLIST", ""), add_prefix(name, env, support_list))).replace("$LISTOPT", "--list"))
+ print(("%s | %s" %
+ (cmdline.replace("$LOADLIST", ""),
+ add_prefix(name, env, support_list))).replace("$LISTOPT", "--list "))
print(cmdline.replace("$LISTOPT", "") + " 2>&1 " + " | " + add_prefix(name, env, False))
@@ -135,16 +150,18 @@
skiptestsuite(name, "Test::More not available")
-def planpythontestsuite(env, module, name=None, extra_path=None):
+def planpythontestsuite(env, module, name=None, extra_path=[], environ={}, extra_args=[]):
+ environ = dict(environ)
+ py_path = list(extra_path)
+ if py_path is not None:
+ environ["PYTHONPATH"] = ":".join(["$PYTHONPATH"] + py_path)
+ args = ["%s=%s" % item for item in environ.items()]
+ args += [python, "-m", "samba.subunit.run", "$LISTOPT", "$LOADLIST", module]
+ args += extra_args
if name is None:
name = module
- args = [python, "-m", "samba.subunit.run", "$LISTOPT", "$LOADLIST", module]
- if extra_path:
- pypath = ["PYTHONPATH=$PYTHONPATH:%s" % ":".join(extra_path)]
- else:
- pypath = []
- plantestsuite_loadlist(name, env, pypath + args)
+ plantestsuite_loadlist(name, env, args)
def get_env_torture_options():
@@ -162,7 +179,10 @@
configuration = "--configfile=$SMB_CONF_PATH"
smbtorture4 = binpath("smbtorture")
-smbtorture4_testsuite_list = subprocess.Popen([smbtorture4, "--list-suites"], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate("")[0].decode('utf8').splitlines()
+smbtorture4_testsuite_list = subprocess.Popen(
+ [smbtorture4, "--list-suites"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE).communicate("")[0].decode('utf8').splitlines()
smbtorture4_options = [
configuration,
@@ -173,13 +193,17 @@
] + get_env_torture_options()
-def plansmbtorture4testsuite(name, env, options, target, modname=None):
+def plansmbtorture4testsuite(name, env, options, target, modname=None, environ={}):
if modname is None:
modname = "samba4.%s" % name
if isinstance(options, list):
options = " ".join(options)
options = " ".join(smbtorture4_options + ["--target=%s" % target]) + " " + options
- cmdline = "%s $LISTOPT $LOADLIST %s %s" % (valgrindify(smbtorture4), options, name)
+ cmdline = ""
+ if environ:
+ environ = dict(environ)
+ cmdline = ["%s=%s" % item for item in environ.items()]
+ cmdline += " %s $LISTOPT $LOADLIST %s %s" % (valgrindify(smbtorture4), options, name)
plantestsuite_loadlist(modname, env, cmdline)
diff -Nru samba-4.13.3+dfsg/selftest/selftest.pl samba-4.13.14+dfsg/selftest/selftest.pl
--- samba-4.13.3+dfsg/selftest/selftest.pl 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/selftest.pl 2021-11-08 11:29:14.000000000 +0000
@@ -280,7 +280,7 @@
my $torture_maxtime = ($ENV{TORTURE_MAXTIME} or 1200);
$prefix =~ s+//+/+;
-$prefix =~ s+/./+/+;
+$prefix =~ s+/\./+/+;
$prefix =~ s+/$++;
die("using an empty prefix isn't allowed") unless $prefix ne "";
@@ -312,7 +312,6 @@
$ENV{PREFIX_ABS} = $prefix_abs;
$ENV{SRCDIR} = $srcdir;
$ENV{SRCDIR_ABS} = $srcdir_abs;
-$ENV{GNUPGHOME} = "$srcdir_abs/selftest/gnupg";
$ENV{BINDIR} = $bindir_abs;
my $tls_enabled = not $opt_quick;
@@ -610,8 +609,6 @@
client min protocol = CORE
log level = 1
torture:basedir = $clientdir
-#We don't want to pass our self-tests if the PAC code is wrong
- gensec:require_pac = true
#We don't want to run 'speed' tests for very long
torture:timelimit = 1
winbind separator = /
@@ -693,6 +690,9 @@
my $selftest_krbt_ccache_path = "$tmpdir_abs/selftest.krb5_ccache";
$ENV{KRB5CCNAME} = "FILE:${selftest_krbt_ccache_path}.global";
+my $selftest_gnupghome_path = "$tmpdir_abs/selftest.no.gnupg";
+$ENV{GNUPGHOME} = "${selftest_gnupghome_path}.global";
+
my @available = ();
foreach my $fn (@testlists) {
foreach (read_testlist($fn)) {
@@ -829,6 +829,7 @@
$ENV{RESOLV_CONF} = "${selftest_resolv_conf_path}.${envname}/ignore";
$ENV{KRB5CCNAME} = "FILE:${selftest_krbt_ccache_path}.${envname}/ignore";
+ $ENV{GNUPGHOME} = "${selftest_gnupghome_path}.${envname}/ignore";
if (defined(get_running_env($envname))) {
$testenv_vars = get_running_env($envname);
diff -Nru samba-4.13.3+dfsg/selftest/target/Samba3.pm samba-4.13.14+dfsg/selftest/target/Samba3.pm
--- samba-4.13.3+dfsg/selftest/target/Samba3.pm 2020-12-15 07:53:45.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/target/Samba3.pm 2021-11-08 11:29:14.000000000 +0000
@@ -238,6 +238,7 @@
ad_member_idmap_rid => ["ad_dc"],
ad_member_idmap_ad => ["fl2008r2dc"],
ad_member_fips => ["ad_dc_fips"],
+ ad_member_no_nss_wb => ["ad_dc"],
clusteredmember_smb1 => ["nt4_dc"],
);
@@ -648,10 +649,13 @@
{
my ($self,
$prefix,
+ $machine_account,
$dcvars,
$trustvars_f,
$trustvars_e,
- $force_fips_mode) = @_;
+ $extra_member_options,
+ $force_fips_mode,
+ $no_nss_winbind) = @_;
my $prefix_abs = abs_path($prefix);
my @dirs = ();
@@ -683,11 +687,21 @@
$substitution_path = "$share_dir/D_$dcvars->{DOMAIN}/u_$dcvars->{DOMAIN}/alice/g_$dcvars->{DOMAIN}/domain users";
push(@dirs, $substitution_path);
+
+ my $netbios_aliases = "";
+ if ($machine_account eq "LOCALADMEMBER") {
+ $netbios_aliases = "netbios aliases = foo bar";
+ }
+
+ unless (defined($extra_member_options)) {
+ $extra_member_options = "";
+ }
+
my $member_options = "
security = ads
workgroup = $dcvars->{DOMAIN}
realm = $dcvars->{REALM}
- netbios aliases = foo bar
+ $netbios_aliases
template homedir = /home/%D/%G/%U
auth event notification = true
password server = $dcvars->{SERVER}
@@ -706,6 +720,10 @@
rpc_daemon:epmd = fork
rpc_daemon:lsasd = fork
+ # Begin extra member options
+ $extra_member_options
+ # End extra member options
+
[sub_dug]
path = $share_dir/D_%D/U_%U/G_%G
writeable = yes
@@ -723,7 +741,8 @@
my $ret = $self->provision(
prefix => $prefix,
domain => $dcvars->{DOMAIN},
- server => "LOCALADMEMBER",
+ realm => $dcvars->{REALM},
+ server => $machine_account,
password => "loCalMemberPass",
extra_options => $member_options,
resolv_conf => $dcvars->{RESOLV_CONF});
@@ -732,7 +751,6 @@
mkdir($_, 0777) foreach(@dirs);
- close(USERMAP);
$ret->{DOMAIN} = $dcvars->{DOMAIN};
$ret->{REALM} = $dcvars->{REALM};
$ret->{DOMSID} = $dcvars->{DOMSID};
@@ -784,12 +802,17 @@
# access the share for tests.
chmod 0777, "$prefix/share";
- if (not $self->check_or_start(
- env_vars => $ret,
- nmbd => "yes",
- winbindd => "yes",
- smbd => "yes")) {
- return undef;
+ if (defined($no_nss_winbind)) {
+ $ret->{NSS_WRAPPER_MODULE_SO_PATH} = "";
+ $ret->{NSS_WRAPPER_MODULE_FN_PREFIX} = "";
+ }
+
+ if (not $self->check_or_start(
+ env_vars => $ret,
+ nmbd => "yes",
+ winbindd => "yes",
+ smbd => "yes")) {
+ return undef;
}
$ret->{DC_SERVER} = $dcvars->{SERVER};
@@ -838,7 +861,11 @@
print "PROVISIONING AD MEMBER...";
- return $self->provision_ad_member($prefix, $dcvars, $trustvars_f, $trustvars_e);
+ return $self->provision_ad_member($prefix,
+ "LOCALADMEMBER",
+ $dcvars,
+ $trustvars_f,
+ $trustvars_e);
}
sub setup_ad_member_rfc2307
@@ -873,6 +900,7 @@
my $ret = $self->provision(
prefix => $prefix,
domain => $dcvars->{DOMAIN},
+ realm => $dcvars->{REALM},
server => "RFC2307MEMBER",
password => "loCalMemberPass",
extra_options => $member_options,
@@ -880,7 +908,6 @@
$ret or return undef;
- close(USERMAP);
$ret->{DOMAIN} = $dcvars->{DOMAIN};
$ret->{REALM} = $dcvars->{REALM};
$ret->{DOMSID} = $dcvars->{DOMSID};
@@ -970,6 +997,7 @@
my $ret = $self->provision(
prefix => $prefix,
domain => $dcvars->{DOMAIN},
+ realm => $dcvars->{REALM},
server => "IDMAPRIDMEMBER",
password => "loCalMemberPass",
extra_options => $member_options,
@@ -977,7 +1005,6 @@
$ret or return undef;
- close(USERMAP);
$ret->{DOMAIN} = $dcvars->{DOMAIN};
$ret->{REALM} = $dcvars->{REALM};
$ret->{DOMSID} = $dcvars->{DOMSID};
@@ -1067,6 +1094,7 @@
my $ret = $self->provision(
prefix => $prefix,
domain => $dcvars->{DOMAIN},
+ realm => $dcvars->{REALM},
server => "IDMAPADMEMBER",
password => "loCalMemberPass",
extra_options => $member_options,
@@ -1074,7 +1102,6 @@
$ret or return undef;
- close(USERMAP);
$ret->{DOMAIN} = $dcvars->{DOMAIN};
$ret->{REALM} = $dcvars->{REALM};
$ret->{DOMSID} = $dcvars->{DOMSID};
@@ -1159,12 +1186,51 @@
print "PROVISIONING AD FIPS MEMBER...";
return $self->provision_ad_member($prefix,
+ "FIPSADMEMBER",
$dcvars,
$trustvars_f,
$trustvars_e,
+ undef,
1);
}
+sub setup_ad_member_no_nss_wb
+{
+ my ($self,
+ $prefix,
+ $dcvars,
+ $trustvars_f,
+ $trustvars_e) = @_;
+
+ # If we didn't build with ADS, pretend this env was never available
+ if (not $self->have_ads()) {
+ return "UNKNOWN";
+ }
+
+ print "PROVISIONING AD MEMBER WITHOUT NSS WINBIND...";
+
+ my $extra_member_options = "
+ username map = $prefix/lib/username.map
+";
+
+ my $ret = $self->provision_ad_member($prefix,
+ "ADMEMNONSSWB",
+ $dcvars,
+ $trustvars_f,
+ $trustvars_e,
+ $extra_member_options,
+ undef,
+ 1);
+
+ open(USERMAP, ">$prefix/lib/username.map") or die("Unable to open $prefix/lib/username.map");
+ print USERMAP "
+root = $dcvars->{DOMAIN}/root
+";
+ close(USERMAP);
+
+ return $ret;
+}
+
sub setup_simpleserver
{
my ($self, $path) = @_;
@@ -1628,7 +1694,6 @@
workgroup = KTEST
realm = ktest.samba.example.com
security = ads
- username map = $prefix/lib/username.map
server signing = required
server min protocol = SMB3_00
client max protocol = SMB3
@@ -1636,6 +1701,10 @@
# This disables NTLM auth against the local SAM, which
# we use can then test this setting by.
ntlm auth = disabled
+
+ idmap config * : backend = autorid
+ idmap config * : range = 1000000-1999999
+ idmap config * : rangesize = 100000
";
my $ret = $self->provision(
@@ -1661,12 +1730,6 @@
$ret->{KRB5_CONFIG} = $ctx->{krb5_conf};
- open(USERMAP, ">$prefix/lib/username.map") or die("Unable to open $prefix/lib/username.map");
- print USERMAP "
-$ret->{USERNAME} = KTEST\\Administrator
-";
- close(USERMAP);
-
#This is the secrets.tdb created by 'net ads join' from Samba3 to a
#Samba4 DC with the same parameters as are being used here. The
#domain SID is S-1-5-21-1071277805-689288055-3486227160
@@ -1718,6 +1781,7 @@
if (not $self->check_or_start(
env_vars => $ret,
nmbd => "yes",
+ winbindd => "offline",
smbd => "yes")) {
return undef;
}
@@ -1727,12 +1791,22 @@
sub setup_maptoguest
{
my ($self, $path) = @_;
+ my $prefix_abs = abs_path($path);
+ my $libdir="$prefix_abs/lib";
+ my $share_dir="$prefix_abs/share";
+ my $errorinjectconf="$libdir/error_inject.conf";
print "PROVISIONING maptoguest...";
my $options = "
map to guest = bad user
ntlm auth = yes
+
+[force_user_error_inject]
+ path = $share_dir
+ vfs objects = acl_xattr fake_acls xattr_tdb error_inject
+ force user = user1
+ include = $errorinjectconf
";
my $vars = $self->provision(
@@ -1864,7 +1938,7 @@
LOG_FILE => $env_vars->{WINBINDD_TEST_LOG},
PCAP_FILE => "env-$ENV{ENVNAME}-winbindd",
};
- if ($winbindd ne "yes") {
+ if ($winbindd ne "yes" and $winbindd ne "offline") {
$daemon_ctx->{SKIP_DAEMON} = 1;
}
@@ -1930,6 +2004,7 @@
my $prefix = $args{prefix};
my $domain = $args{domain};
+ my $realm = $args{realm};
my $server = $args{server};
my $password = $args{password};
my $extra_options = $args{extra_options};
@@ -1947,6 +2022,12 @@
my %createuser_env = ();
my $server_ip = Samba::get_ipv4_addr($server);
my $server_ipv6 = Samba::get_ipv6_addr($server);
+ my $dns_domain;
+ if (defined($realm)) {
+ $dns_domain = lc($realm);
+ } else {
+ $dns_domain = "samba.example.com";
+ }
my $unix_name = ($ENV{USER} or $ENV{LOGNAME} or `PATH=/usr/ucb:$ENV{PATH} whoami`);
chomp $unix_name;
@@ -2926,8 +3007,8 @@
warn("Unable to open $nss_wrapper_hosts");
return undef;
}
- print HOSTS "${server_ip} ${hostname}.samba.example.com ${hostname}\n";
- print HOSTS "${server_ipv6} ${hostname}.samba.example.com ${hostname}\n";
+ print HOSTS "${server_ip} ${hostname}.${dns_domain} ${hostname}\n";
+ print HOSTS "${server_ipv6} ${hostname}.${dns_domain} ${hostname}\n";
close(HOSTS);
$resolv_conf = "$privatedir/no_resolv.conf" unless defined($resolv_conf);
@@ -3052,13 +3133,17 @@
}
}
- if ($winbindd eq "yes") {
+ if ($winbindd eq "yes" or $winbindd eq "offline") {
print "checking for winbindd\n";
my $count = 0;
$cmd = "SELFTEST_WINBINDD_SOCKET_DIR='$envvars->{SELFTEST_WINBINDD_SOCKET_DIR}' ";
$cmd .= "NSS_WRAPPER_PASSWD='$envvars->{NSS_WRAPPER_PASSWD}' ";
$cmd .= "NSS_WRAPPER_GROUP='$envvars->{NSS_WRAPPER_GROUP}' ";
- $cmd .= Samba::bindir_path($self, "wbinfo") . " --ping-dc";
+ if ($winbindd eq "yes") {
+ $cmd .= Samba::bindir_path($self, "wbinfo") . " --ping-dc";
+ } elsif ($winbindd eq "offline") {
+ $cmd .= Samba::bindir_path($self, "wbinfo") . " --ping";
+ }
do {
$ret = system($cmd);
diff -Nru samba-4.13.3+dfsg/selftest/target/Samba4.pm samba-4.13.14+dfsg/selftest/target/Samba4.pm
--- samba-4.13.3+dfsg/selftest/target/Samba4.pm 2020-09-07 10:52:25.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/target/Samba4.pm 2021-11-08 11:29:14.000000000 +0000
@@ -17,7 +17,6 @@
use target::Samba;
use target::Samba3;
use Archive::Tar;
-use File::Path 'make_path';
sub new($$$$$) {
my ($classname, $SambaCtx, $bindir, $srcdir, $server_maxtime) = @_;
@@ -161,19 +160,7 @@
my $max_wait = 60;
# Add hosts file for name lookups
- my $cmd = "NSS_WRAPPER_HOSTS='$testenv_vars->{NSS_WRAPPER_HOSTS}' ";
- if (defined($testenv_vars->{RESOLV_WRAPPER_CONF})) {
- $cmd .= "RESOLV_WRAPPER_CONF='$testenv_vars->{RESOLV_WRAPPER_CONF}' ";
- } else {
- $cmd .= "RESOLV_WRAPPER_HOSTS='$testenv_vars->{RESOLV_WRAPPER_HOSTS}' ";
- }
- $cmd .= "RESOLV_CONF='$testenv_vars->{RESOLV_CONF}' ";
- if (defined($testenv_vars->{GNUTLS_FORCE_FIPS_MODE})) {
- $cmd .= "GNUTLS_FORCE_FIPS_MODE=$testenv_vars->{GNUTLS_FORCE_FIPS_MODE} ";
- }
- if (defined($testenv_vars->{OPENSSL_FORCE_FIPS_MODE})) {
- $cmd .= "OPENSSL_FORCE_FIPS_MODE=$testenv_vars->{OPENSSL_FORCE_FIPS_MODE} ";
- }
+ my $cmd = $self->get_cmd_env_vars($testenv_vars);
$cmd .= "$ldbsearch ";
$cmd .= "$testenv_vars->{CONFIGURATION} ";
@@ -252,12 +239,19 @@
sub write_ldb_file($$$)
{
- my ($self, $file, $ldif) = @_;
+ my ($self, $file, $ldif_in) = @_;
my $ldbadd = Samba::bindir_path($self, "ldbadd");
- open(LDIF, "|$ldbadd -H $file >/dev/null");
- print LDIF $ldif;
- return(close(LDIF));
+ open(my $ldif, "|$ldbadd -H $file > /dev/null")
+ or die "Failed to run $ldbadd: $!";
+ print $ldif $ldif_in;
+ close($ldif);
+
+ unless ($? == 0) {
+ warn("$ldbadd failed: $?");
+ return undef;
+ }
+ return 1;
}
sub add_wins_config($$)
@@ -281,7 +275,7 @@
my ($self, $hostname, $prefix) = @_;
my $STDIN_READER;
- unless(-d $prefix or make_path($prefix, 0777)) {
+ unless(-d $prefix or mkdir($prefix, 0777)) {
warn("Unable to create $prefix");
return undef;
}
@@ -356,6 +350,10 @@
my $hostname = "rootdnsforwarder";
+ unless(-d $prefix or mkdir($prefix, 0777)) {
+ warn("Unable to create $prefix");
+ return undef;
+ }
my $env = $self->setup_dns_hub_internal("$hostname", "$prefix/$hostname");
$self->{dns_hub_env} = $env;
@@ -375,10 +373,44 @@
return undef;
}
+sub return_env_value
+{
+ my ($env, $overwrite, $key) = @_;
+
+ if (defined($overwrite) and defined($overwrite->{$key})) {
+ return $overwrite->{$key};
+ }
+
+ if (defined($env->{$key})) {
+ return $env->{$key};
+ }
+
+ return undef;
+}
+
# Returns the environmental variables that we pass to samba-tool commands
sub get_cmd_env_vars
{
- my ($self, $localenv) = @_;
+ my ($self, $givenenv, $overwrite) = @_;
+
+ my @keys = (
+ "NSS_WRAPPER_HOSTS",
+ "SOCKET_WRAPPER_DEFAULT_IFACE",
+ "RESOLV_CONF",
+ "RESOLV_WRAPPER_CONF",
+ "RESOLV_WRAPPER_HOSTS",
+ "GNUTLS_FORCE_FIPS_MODE",
+ "OPENSSL_FORCE_FIPS_MODE",
+ "KRB5_CONFIG",
+ "KRB5_CCACHE",
+ "GNUPGHOME",
+ );
+
+ my $localenv = undef;
+ foreach my $key (@keys) {
+ my $v = return_env_value($givenenv, $overwrite, $key);
+ $localenv->{$key} = $v if defined($v);
+ }
my $cmd_env = "NSS_WRAPPER_HOSTS='$localenv->{NSS_WRAPPER_HOSTS}' ";
$cmd_env .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$localenv->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
@@ -393,9 +425,10 @@
if (defined($localenv->{OPENSSL_FORCE_FIPS_MODE})) {
$cmd_env .= "OPENSSL_FORCE_FIPS_MODE=$localenv->{OPENSSL_FORCE_FIPS_MODE} ";
}
- $cmd_env .= " KRB5_CONFIG=\"$localenv->{KRB5_CONFIG}\" ";
+ $cmd_env .= "KRB5_CONFIG=\"$localenv->{KRB5_CONFIG}\" ";
$cmd_env .= "KRB5CCNAME=\"$localenv->{KRB5_CCACHE}\" ";
$cmd_env .= "RESOLV_CONF=\"$localenv->{RESOLV_CONF}\" ";
+ $cmd_env .= "GNUPGHOME=\"$localenv->{GNUPGHOME}\" ";
return $cmd_env;
}
@@ -535,7 +568,7 @@
$ctx->{force_fips_mode} = $force_fips_mode;
$ctx->{krb5_ccname} = "$prefix_abs/krb5cc_%{uid}";
if ($functional_level eq "2000") {
- $ctx->{supported_enctypes} = "arcfour-hmac-md5 des-cbc-md5 des-cbc-crc"
+ $ctx->{supported_enctypes} = "arcfour-hmac-md5 des-cbc-md5 des-cbc-crc";
}
#
@@ -565,6 +598,7 @@
$ctx->{krb5_conf} = "$ctx->{etcdir}/krb5.conf";
$ctx->{krb5_ccache} = "$prefix_abs/krb5_ccache";
$ctx->{mitkdc_conf} = "$ctx->{etcdir}/mitkdc.conf";
+ $ctx->{gnupghome} = "$prefix_abs/gnupg";
$ctx->{privatedir} = "$prefix_abs/private";
$ctx->{binddnsdir} = "$prefix_abs/bind-dns";
$ctx->{ncalrpcdir} = "$prefix_abs/ncalrpc";
@@ -608,8 +642,9 @@
$ctx->{smb_conf_extra_options} = "";
my @provision_options = ();
+ push (@provision_options, "GNUPGHOME=\"$ctx->{gnupghome}\"");
push (@provision_options, "KRB5_CONFIG=\"$ctx->{krb5_conf}\"");
- push (@provision_options, "KRB5_CCACHE=\"$ctx->{krb5_ccache}\"");
+ push (@provision_options, "KRB5CCNAME=\"$ctx->{krb5_ccache}\"");
push (@provision_options, "NSS_WRAPPER_PASSWD=\"$ctx->{nsswrap_passwd}\"");
push (@provision_options, "NSS_WRAPPER_GROUP=\"$ctx->{nsswrap_group}\"");
push (@provision_options, "NSS_WRAPPER_HOSTS=\"$ctx->{nsswrap_hosts}\"");
@@ -700,6 +735,7 @@
return undef;
}
+ Samba::copy_gnupg_home($ctx);
Samba::prepare_keyblobs($ctx);
my $crlfile = "$ctx->{tlsdir}/crl.pem";
$crlfile = "" unless -e ${crlfile};
@@ -741,8 +777,6 @@
notify:inotify = false
ldb:nosync = true
ldap server require strong auth = yes
-#We don't want to pass our self-tests if the PAC code is wrong
- gensec:require_pac = true
log file = $ctx->{logdir}/log.\%m
log level = $ctx->{server_loglevel}
lanman auth = Yes
@@ -843,6 +877,7 @@
# Note that we have SERVER_X and DC_SERVER_X variables (which have the same
# value initially). In a 2 DC setup, $DC_SERVER_X will always be the PDC.
my $ret = {
+ GNUPGHOME => $ctx->{gnupghome},
KRB5_CONFIG => $ctx->{krb5_conf},
KRB5_CCACHE => $ctx->{krb5_ccache},
MITKDC_CONFIG => $ctx->{mitkdc_conf},
@@ -916,17 +951,18 @@
{
my ($self, $ctx, $ret) = @_;
+ my $ldif;
+
my $provision_cmd = join(" ", @{$ctx->{provision_options}});
unless (system($provision_cmd) == 0) {
warn("Unable to provision: \n$provision_cmd\n");
return undef;
}
+ my $cmd_env = $self->get_cmd_env_vars($ret);
+
my $testallowed_account = "testallowed";
- my $samba_tool_cmd = "";
- $samba_tool_cmd .= "RESOLV_CONF=\"$ret->{RESOLV_CONF}\" ";
- $samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
+ my $samba_tool_cmd = ${cmd_env};
$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
. " user create --configfile=$ctx->{smb_conf} $testallowed_account $ctx->{password}";
unless (system($samba_tool_cmd) == 0) {
@@ -935,10 +971,7 @@
}
my $srv_account = "srv_account";
- $samba_tool_cmd = "";
- $samba_tool_cmd .= "RESOLV_CONF=\"$ret->{RESOLV_CONF}\" ";
- $samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
+ $samba_tool_cmd = ${cmd_env};
$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
. " user create --configfile=$ctx->{smb_conf} $srv_account $ctx->{password}";
unless (system($samba_tool_cmd) == 0) {
@@ -946,10 +979,7 @@
return undef;
}
- $samba_tool_cmd = "";
- $samba_tool_cmd .= "RESOLV_CONF=\"$ret->{RESOLV_CONF}\" ";
- $samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
+ $samba_tool_cmd = ${cmd_env};
$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
. " spn add HOST/$srv_account --configfile=$ctx->{smb_conf} $srv_account";
unless (system($samba_tool_cmd) == 0) {
@@ -957,10 +987,7 @@
return undef;
}
- my $ldbmodify = "";
- $ldbmodify .= "RESOLV_CONF=\"$ret->{RESOLV_CONF}\" ";
- $ldbmodify .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $ldbmodify .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
+ my $ldbmodify = ${cmd_env};
$ldbmodify .= Samba::bindir_path($self, "ldbmodify");
$ldbmodify .= " --configfile=$ctx->{smb_conf}";
my $base_dn = "DC=".join(",DC=", split(/\./, $ctx->{realm}));
@@ -971,17 +998,23 @@
my $user_dn = "cn=$testallowed_account,cn=users,$base_dn";
$testallowed_account = "testallowed account";
- open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb");
- print LDIF "dn: $user_dn
+ open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb")
+ or die "Failed to run $ldbmodify: $!";
+ print $ldif "dn: $user_dn
changetype: modify
replace: samAccountName
samAccountName: $testallowed_account
-
";
- close(LDIF);
+ close($ldif);
+ unless ($? == 0) {
+ warn("$ldbmodify failed: $?");
+ return undef;
+ }
- open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb");
- print LDIF "dn: $user_dn
+ open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb")
+ or die "Failed to run $ldbmodify: $!";
+ print $ldif "dn: $user_dn
changetype: modify
replace: userPrincipalName
userPrincipalName: testallowed upn\@$ctx->{realm}
@@ -989,12 +1022,13 @@
servicePrincipalName: host/testallowed
-
";
- close(LDIF);
+ close($ldif);
+ unless ($? == 0) {
+ warn("$ldbmodify failed: $?");
+ return undef;
+ }
- $samba_tool_cmd = "";
- $samba_tool_cmd .= "RESOLV_CONF=\"$ret->{RESOLV_CONF}\" ";
- $samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
+ $samba_tool_cmd = ${cmd_env};
$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
. " user create --configfile=$ctx->{smb_conf} testdenied $ctx->{password}";
unless (system($samba_tool_cmd) == 0) {
@@ -1003,19 +1037,21 @@
}
$user_dn = "cn=testdenied,cn=users,$base_dn";
- open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb");
- print LDIF "dn: $user_dn
+ open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb")
+ or die "Failed to run $ldbmodify: $!";
+ print $ldif "dn: $user_dn
changetype: modify
replace: userPrincipalName
userPrincipalName: testdenied_upn\@$ctx->{realm}.upn
-
";
- close(LDIF);
+ close($ldif);
+ unless ($? == 0) {
+ warn("$ldbmodify failed: $?");
+ return undef;
+ }
- $samba_tool_cmd = "";
- $samba_tool_cmd .= "RESOLV_CONF=\"$ret->{RESOLV_CONF}\" ";
- $samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
+ $samba_tool_cmd = ${cmd_env};
$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
. " user create --configfile=$ctx->{smb_conf} testupnspn $ctx->{password}";
unless (system($samba_tool_cmd) == 0) {
@@ -1024,8 +1060,9 @@
}
$user_dn = "cn=testupnspn,cn=users,$base_dn";
- open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb");
- print LDIF "dn: $user_dn
+ open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb")
+ or die "Failed to run $ldbmodify: $!";
+ print $ldif "dn: $user_dn
changetype: modify
replace: userPrincipalName
userPrincipalName: http/testupnspn.$ctx->{dnsname}\@$ctx->{realm}
@@ -1033,12 +1070,13 @@
servicePrincipalName: http/testupnspn.$ctx->{dnsname}
-
";
- close(LDIF);
+ close($ldif);
+ unless ($? == 0) {
+ warn("$ldbmodify failed: $?");
+ return undef;
+ }
- $samba_tool_cmd = "";
- $samba_tool_cmd .= "RESOLV_CONF=\"$ret->{RESOLV_CONF}\" ";
- $samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
+ $samba_tool_cmd = ${cmd_env};
$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
. " group addmembers --configfile=$ctx->{smb_conf} 'Allowed RODC Password Replication Group' '$testallowed_account'";
unless (system($samba_tool_cmd) == 0) {
@@ -1050,11 +1088,8 @@
my $user_account_array = ["alice", "bob", "jane", "joe"];
foreach my $user_account (@{$user_account_array}) {
- my $samba_tool_cmd = "";
+ my $samba_tool_cmd = ${cmd_env};
- $samba_tool_cmd .= "RESOLV_CONF=\"$ret->{RESOLV_CONF}\" ";
- $samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
. " user create --configfile=$ctx->{smb_conf} $user_account Secret007";
unless (system($samba_tool_cmd) == 0) {
@@ -1066,10 +1101,8 @@
my $group_array = ["Samba Users"];
foreach my $group (@{$group_array}) {
- my $samba_tool_cmd = "";
+ my $samba_tool_cmd = ${cmd_env};
- $samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
. " group add --configfile=$ctx->{smb_conf} \"$group\"";
unless (system($samba_tool_cmd) == 0) {
@@ -1079,12 +1112,10 @@
}
# Add user joe to group "Samba Users"
- $samba_tool_cmd = "";
my $group = "Samba Users";
my $user_account = "joe";
- $samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
+ $samba_tool_cmd = ${cmd_env};
$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
. " group addmembers --configfile=$ctx->{smb_conf} \"$group\" $user_account";
unless (system($samba_tool_cmd) == 0) {
@@ -1092,12 +1123,10 @@
return undef;
}
- $samba_tool_cmd = "";
$group = "Samba Users";
$user_account = "joe";
- $samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
+ $samba_tool_cmd = ${cmd_env};
$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
. " user setprimarygroup --configfile=$ctx->{smb_conf} $user_account \"$group\"";
unless (system($samba_tool_cmd) == 0) {
@@ -1106,23 +1135,21 @@
}
# Change the userPrincipalName for jane
- $ldbmodify = "";
- $ldbmodify .= "RESOLV_CONF=\"$ret->{RESOLV_CONF}\" ";
- $ldbmodify .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $ldbmodify .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
- $ldbmodify .= Samba::bindir_path($self, "ldbmodify");
- $ldbmodify .= " --configfile=$ctx->{smb_conf}";
- $base_dn = "DC=".join(",DC=", split(/\./, $ctx->{realm}));
$user_dn = "cn=jane,cn=users,$base_dn";
- open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb");
- print LDIF "dn: $user_dn
+ open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb")
+ or die "Failed to run $ldbmodify: $!";
+ print $ldif "dn: $user_dn
changetype: modify
replace: userPrincipalName
userPrincipalName: jane.doe\@$ctx->{realm}
-
";
- close(LDIF);
+ close($ldif);
+ unless ($? == 0) {
+ warn("$ldbmodify failed: $?");
+ return undef;
+ }
return $ret;
}
@@ -1409,12 +1436,13 @@
return undef;
}
+ # Prepare a context of the DC, but using the local CCACHE.
+ my $overwrite = undef;
+ $overwrite->{KRB5_CCACHE} = $ret->{KRB5_CCACHE};
+ my $dc_cmd_env = $self->get_cmd_env_vars($dcvars, $overwrite);
+
# Setting up delegation runs in the context of the DC for now
- $cmd = "";
- $cmd .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$dcvars->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
- $cmd .= "KRB5_CONFIG=\"$dcvars->{KRB5_CONFIG}\" ";
- $cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
- $cmd .= "RESOLV_CONF=\"$dcvars->{RESOLV_CONF}\" ";
+ $cmd = $dc_cmd_env;
$cmd .= "$samba_tool delegation for-any-protocol '$ret->{NETBIOSNAME}\$' on";
$cmd .= " $dcvars->{CONFIGURATION}";
print $cmd;
@@ -1425,11 +1453,7 @@
}
# Setting up delegation runs in the context of the DC for now
- $cmd = "";
- $cmd .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$dcvars->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
- $cmd .= "KRB5_CONFIG=\"$dcvars->{KRB5_CONFIG}\" ";
- $cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
- $cmd .= "RESOLV_CONF=\"$dcvars->{RESOLV_CONF}\" ";
+ $cmd = $dc_cmd_env;
$cmd .= "$samba_tool delegation add-service '$ret->{NETBIOSNAME}\$' cifs/$dcvars->{SERVER}";
$cmd .= " $dcvars->{CONFIGURATION}";
@@ -1824,9 +1848,7 @@
# This ensures deterministic behaviour for tests that want to have the 'testallowed account'
# user password verified on the RODC
my $testallowed_account = "testallowed account";
- $cmd = "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
- $cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
- $cmd .= "RESOLV_CONF=\"$ret->{RESOLV_CONF}\" ";
+ $cmd = $self->get_cmd_env_vars($ret);
$cmd .= "$samba_tool rodc preload '$testallowed_account' $ret->{CONFIGURATION}";
$cmd .= " --server=$dcvars->{DC_SERVER}";
@@ -2502,14 +2524,10 @@
# force source and replicated DC to update repsTo/repsFrom
# for vampired partitions
my $samba_tool = Samba::bindir_path($self, "samba-tool");
- my $cmd = "NSS_WRAPPER_HOSTS='$env->{NSS_WRAPPER_HOSTS}' ";
+ my $cmd = $self->get_cmd_env_vars($env);
# as 'vampired' dc may add data in its local replica
# we need to synchronize data between DCs
my $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
- $cmd = "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\"";
- $cmd .= " KRB5_CONFIG=\"$env->{KRB5_CONFIG}\"";
- $cmd .= "KRB5CCNAME=\"$env->{KRB5_CCACHE}\" ";
- $cmd .= "RESOLV_CONF=\"$env->{RESOLV_CONF}\" ";
$cmd .= " $samba_tool drs replicate $env->{DC_SERVER} $env->{SERVER}";
$cmd .= " $dc_vars->{CONFIGURATION}";
$cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
@@ -2545,14 +2563,9 @@
}
my $samba_tool = Samba::bindir_path($self, "samba-tool");
- my $cmd = "";
+ my $cmd = $self->get_cmd_env_vars($env);
my $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
- $cmd .= "NSS_WRAPPER_HOSTS='$env->{NSS_WRAPPER_HOSTS}' ";
- $cmd .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\"";
- $cmd .= " KRB5_CONFIG=\"$env->{KRB5_CONFIG}\"";
- $cmd .= "KRB5CCNAME=\"$env->{KRB5_CCACHE}\" ";
- $cmd .= "RESOLV_CONF=\"$env->{RESOLV_CONF}\" ";
$cmd .= " $samba_tool drs replicate $env->{SERVER} $env->{DC_SERVER}";
$cmd .= " $dc_vars->{CONFIGURATION}";
$cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
@@ -2857,16 +2870,7 @@
"");
my $samba_tool = Samba::bindir_path($self, "samba-tool");
- my $cmd_vars = "NSS_WRAPPER_HOSTS='$env->{NSS_WRAPPER_HOSTS}' ";
- $cmd_vars .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
- if (defined($env->{RESOLV_WRAPPER_CONF})) {
- $cmd_vars .= "RESOLV_WRAPPER_CONF=\"$env->{RESOLV_WRAPPER_CONF}\" ";
- } else {
- $cmd_vars .= "RESOLV_WRAPPER_HOSTS=\"$env->{RESOLV_WRAPPER_HOSTS}\" ";
- }
- $cmd_vars .= "KRB5_CONFIG=\"$env->{KRB5_CONFIG}\" ";
- $cmd_vars .= "KRB5CCNAME=\"$env->{KRB5_CCACHE}\" ";
- $cmd_vars .= "RESOLV_CONF=\"$env->{RESOLV_CONF}\" ";
+ my $cmd_vars = $self->get_cmd_env_vars($env);
my $join_cmd = $cmd_vars;
$join_cmd .= "$samba_tool domain join $env->{CONFIGURATION} $dcvars->{REALM} DC --realm=$dcvars->{REALM}";
@@ -3008,17 +3012,10 @@
my ($self, $env, $dcvars, $backupdir, $backup_cmd) = @_;
# get all the env variables we pass in with the samba-tool command
- my $cmd_env = "NSS_WRAPPER_HOSTS='$env->{NSS_WRAPPER_HOSTS}' ";
- $cmd_env .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
- if (defined($env->{RESOLV_WRAPPER_CONF})) {
- $cmd_env .= "RESOLV_WRAPPER_CONF=\"$env->{RESOLV_WRAPPER_CONF}\" ";
- } else {
- $cmd_env .= "RESOLV_WRAPPER_HOSTS=\"$env->{RESOLV_WRAPPER_HOSTS}\" ";
- }
- $cmd_env .= "RESOLV_CONF=\"$env->{RESOLV_CONF}\" ";
# Note: use the backupfrom-DC's krb5.conf to do the backup
- $cmd_env .= " KRB5_CONFIG=\"$dcvars->{KRB5_CONFIG}\" ";
- $cmd_env .= "KRB5CCNAME=\"$env->{KRB5_CCACHE}\" ";
+ my $overwrite = undef;
+ $overwrite->{KRB5_CONFIG} = $dcvars->{KRB5_CONFIG};
+ my $cmd_env = $self->get_cmd_env_vars($env, $overwrite);
# use samba-tool to create a backup from the 'backupfromdc' DC
my $cmd = "";
diff -Nru samba-4.13.3+dfsg/selftest/target/Samba.pm samba-4.13.14+dfsg/selftest/target/Samba.pm
--- samba-4.13.3+dfsg/selftest/target/Samba.pm 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/target/Samba.pm 2021-11-08 11:29:14.000000000 +0000
@@ -280,6 +280,30 @@
umask $oldumask;
}
+sub copy_gnupg_home($)
+{
+ my ($ctx) = @_;
+
+ my $gnupg_srcdir = "$ENV{SRCDIR_ABS}/selftest/gnupg";
+ my @files = (
+ "gpg.conf",
+ "pubring.gpg",
+ "secring.gpg",
+ "trustdb.gpg",
+ );
+
+ my $oldumask = umask;
+ umask 0077;
+ mkdir($ctx->{gnupghome}, 0777);
+ umask 0177;
+ foreach my $file (@files) {
+ my $srcfile = "${gnupg_srcdir}/${file}";
+ my $dstfile = "$ctx->{gnupghome}/${file}";
+ copy_file_content(${srcfile}, ${dstfile});
+ }
+ umask $oldumask;
+}
+
sub mk_krb5_conf($$)
{
my ($ctx) = @_;
@@ -554,6 +578,8 @@
addcsmb1 => 54,
lclnt4dc2smb1 => 55,
fipsdc => 56,
+ fipsadmember => 57,
+ admemnonsswb => 60,
rootdnsforwarder => 64,
@@ -672,6 +698,7 @@
RESOLV_CONF => $env_vars->{RESOLV_CONF},
KRB5_CONFIG => $env_vars->{KRB5_CONFIG},
KRB5CCNAME => "$env_vars->{KRB5_CCACHE}.$proc_name",
+ GNUPGHOME => $env_vars->{GNUPGHOME},
SELFTEST_WINBINDD_SOCKET_DIR => $env_vars->{SELFTEST_WINBINDD_SOCKET_DIR},
NMBD_SOCKET_DIR => $env_vars->{NMBD_SOCKET_DIR},
NSS_WRAPPER_PASSWD => $env_vars->{NSS_WRAPPER_PASSWD},
@@ -857,6 +884,7 @@
# misc stuff
"KRB5_CONFIG",
"KRB5CCNAME",
+ "GNUPGHOME",
"SELFTEST_WINBINDD_SOCKET_DIR",
"NMBD_SOCKET_DIR",
"LOCAL_PATH",
diff -Nru samba-4.13.3+dfsg/selftest/tests.py samba-4.13.14+dfsg/selftest/tests.py
--- samba-4.13.3+dfsg/selftest/tests.py 2020-08-28 09:32:54.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/tests.py 2021-11-08 11:29:14.000000000 +0000
@@ -87,6 +87,7 @@
planpythontestsuite("none", "samba.tests.s3windb")
planpythontestsuite("none", "samba.tests.s3idmapdb")
planpythontestsuite("none", "samba.tests.samba3sam")
+planpythontestsuite("none", "samba.tests.dsdb_api")
planpythontestsuite(
"none", "wafsamba.tests.test_suite",
extra_path=[os.path.join(samba4srcdir, "..", "buildtools"),
@@ -212,6 +213,7 @@
plantestsuite("wafsamba.duplicate_symbols", "none", [os.path.join(srcdir(), "buildtools/wafsamba/test_duplicate_symbol.sh")])
planpythontestsuite("none", "samba.tests.glue")
planpythontestsuite("none", "samba.tests.tdb_util")
+planpythontestsuite("none", "samba.tests.samdb")
planpythontestsuite("none", "samba.tests.samdb_api")
if with_pam:
@@ -398,6 +400,8 @@
[os.path.join(bindir(), "default/lib/util/test_util_paths")])
plantestsuite("samba.unittests.util", "none",
[os.path.join(bindir(), "default/lib/util/test_util")])
+plantestsuite("samba.unittests.memcache", "none",
+ [os.path.join(bindir(), "default/lib/util/test_memcache")])
plantestsuite("samba.unittests.ntlm_check", "none",
[os.path.join(bindir(), "default/libcli/auth/test_ntlm_check")])
plantestsuite("samba.unittests.gnutls", "none",
diff -Nru samba-4.13.3+dfsg/selftest/wscript samba-4.13.14+dfsg/selftest/wscript
--- samba-4.13.3+dfsg/selftest/wscript 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/selftest/wscript 2021-09-22 06:59:39.000000000 +0000
@@ -260,6 +260,11 @@
if CONFIG_GET(opt, 'USING_SYSTEM_KRB5') and CONFIG_GET(opt, 'MIT_KDC_PATH'):
env.OPTIONS += " --mitkrb5 --exclude=${srcdir}/selftest/skip_mit_kdc"
+ env.FILTER_XFAIL += " --expected-failures=${srcdir}/selftest/"\
+ "knownfail_mit_kdc"
+ else:
+ env.FILTER_XFAIL += " --expected-failures=${srcdir}/selftest/"\
+ "knownfail_heimdal_kdc"
if not CONFIG_GET(opt, 'HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X'):
# older MIT krb5 libraries (< 1.14) don't have
diff -Nru samba-4.13.3+dfsg/source3/auth/auth.c samba-4.13.14+dfsg/source3/auth/auth.c
--- samba-4.13.3+dfsg/source3/auth/auth.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/auth/auth.c 2021-11-08 11:29:14.000000000 +0000
@@ -529,28 +529,29 @@
struct auth_context **auth_context)
{
const char *methods = NULL;
+ const char *role = NULL;
switch (lp_server_role()) {
case ROLE_ACTIVE_DIRECTORY_DC:
- DEBUG(5,("Making default auth method list for server role = "
- "'active directory domain controller'\n"));
+ role = "'active directory domain controller'";
methods = "samba4";
break;
case ROLE_DOMAIN_MEMBER:
- DEBUG(5,("Making default auth method list for server role = 'domain member'\n"));
+ role = "'domain member'";
methods = "anonymous sam winbind sam_ignoredomain";
break;
case ROLE_DOMAIN_BDC:
case ROLE_DOMAIN_PDC:
- DEBUG(5,("Making default auth method list for DC\n"));
+ case ROLE_IPA_DC:
+ role = "'DC'";
methods = "anonymous sam winbind sam_ignoredomain";
break;
case ROLE_STANDALONE:
- DEBUG(5,("Making default auth method list for server role = 'standalone server', encrypt passwords = yes\n"));
if (lp_encrypt_passwords()) {
+ role = "'standalone server', encrypt passwords = yes";
methods = "anonymous sam_ignoredomain";
} else {
- DEBUG(5,("Making default auth method list for server role = 'standalone server', encrypt passwords = no\n"));
+ role = "'standalone server', encrypt passwords = no";
methods = "anonymous unix";
}
break;
@@ -559,6 +560,9 @@
return NT_STATUS_UNSUCCESSFUL;
}
+ DBG_INFO("Making default auth method list for server role = %s\n",
+ role);
+
return make_auth_context_specific(mem_ctx, auth_context, methods);
}
@@ -570,6 +574,7 @@
switch (lp_server_role()) {
case ROLE_DOMAIN_BDC:
case ROLE_DOMAIN_PDC:
+ case ROLE_IPA_DC:
methods = "sam_netlogon3 winbind";
break;
@@ -591,6 +596,7 @@
case ROLE_DOMAIN_MEMBER:
case ROLE_DOMAIN_BDC:
case ROLE_DOMAIN_PDC:
+ case ROLE_IPA_DC:
methods = "sam";
break;
case ROLE_ACTIVE_DIRECTORY_DC:
diff -Nru samba-4.13.3+dfsg/source3/auth/auth_generic.c samba-4.13.14+dfsg/source3/auth/auth_generic.c
--- samba-4.13.3+dfsg/source3/auth/auth_generic.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/auth/auth_generic.c 2021-11-08 11:29:14.000000000 +0000
@@ -46,47 +46,66 @@
uint32_t session_info_flags,
struct auth_session_info **session_info)
{
+ enum server_role server_role = lp_server_role();
TALLOC_CTX *tmp_ctx;
- struct PAC_LOGON_INFO *logon_info = NULL;
- struct netr_SamInfo3 *info3_copy = NULL;
bool is_mapped;
bool is_guest;
char *ntuser;
char *ntdomain;
char *username;
- char *rhost;
+ const char *rhost;
struct passwd *pw;
NTSTATUS status;
- int rc;
tmp_ctx = talloc_new(mem_ctx);
if (!tmp_ctx) {
return NT_STATUS_NO_MEMORY;
}
- if (pac_blob) {
-#ifdef HAVE_KRB5
- struct wbcAuthUserParams params = {};
+ if (tsocket_address_is_inet(remote_address, "ip")) {
+ rhost = tsocket_address_inet_addr_string(
+ remote_address, tmp_ctx);
+ if (rhost == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ } else {
+ rhost = "127.0.0.1";
+ }
+
+ if (server_role != ROLE_STANDALONE) {
+ struct wbcAuthUserParams params = { 0 };
struct wbcAuthUserInfo *info = NULL;
struct wbcAuthErrorInfo *err = NULL;
+ struct auth_serversupplied_info *server_info = NULL;
+ char *original_user_name = NULL;
+ char *p = NULL;
wbcErr wbc_err;
+ if (pac_blob == NULL) {
+ /*
+ * This should already be catched at the main
+ * gensec layer, but better check twice
+ */
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
+
/*
* Let winbind decode the PAC.
* This will also store the user
* data in the netsamlogon cache.
*
- * We need to do this *before* we
- * call get_user_from_kerberos_info()
- * as that does a user lookup that
- * expects info in the netsamlogon cache.
- *
- * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=11259
+ * This used to be a cache prime
+ * optimization, but now we delegate
+ * all logic to winbindd, as we require
+ * winbindd as domain member anyway.
*/
params.level = WBC_AUTH_USER_LEVEL_PAC;
params.password.pac.data = pac_blob->data;
params.password.pac.length = pac_blob->length;
+ /* we are contacting the privileged pipe */
become_root();
wbc_err = wbcAuthenticateUserEx(¶ms, &info, &err);
unbecome_root();
@@ -99,46 +118,103 @@
*/
switch (wbc_err) {
- case WBC_ERR_WINBIND_NOT_AVAILABLE:
case WBC_ERR_SUCCESS:
break;
+ case WBC_ERR_WINBIND_NOT_AVAILABLE:
+ status = NT_STATUS_NO_LOGON_SERVERS;
+ DBG_ERR("winbindd not running - "
+ "but required as domain member: %s\n",
+ nt_errstr(status));
+ goto done;
case WBC_ERR_AUTH_ERROR:
status = NT_STATUS(err->nt_status);
wbcFreeMemory(err);
goto done;
+ case WBC_ERR_NO_MEMORY:
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
default:
status = NT_STATUS_LOGON_FAILURE;
goto done;
}
- status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL,
- NULL, NULL, 0, &logon_info);
-#else
- status = NT_STATUS_ACCESS_DENIED;
-#endif
+ status = make_server_info_wbcAuthUserInfo(tmp_ctx,
+ info->account_name,
+ info->domain_name,
+ info, &server_info);
if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("make_server_info_wbcAuthUserInfo failed: %s\n",
+ nt_errstr(status)));
goto done;
}
- }
- rc = get_remote_hostname(remote_address,
- &rhost,
- tmp_ctx);
- if (rc < 0) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
- if (strequal(rhost, "UNKNOWN")) {
- rhost = tsocket_address_inet_addr_string(remote_address,
- tmp_ctx);
- if (rhost == NULL) {
+ /* We skip doing this step if the caller asked us not to */
+ if (!(server_info->guest)) {
+ const char *unix_username = server_info->unix_name;
+
+ /* We might not be root if we are an RPC call */
+ become_root();
+ status = smb_pam_accountcheck(unix_username, rhost);
+ unbecome_root();
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("check_ntlm_password: PAM Account for user [%s] "
+ "FAILED with error %s\n",
+ unix_username, nt_errstr(status)));
+ goto done;
+ }
+
+ DEBUG(5, ("check_ntlm_password: PAM Account for user [%s] "
+ "succeeded\n", unix_username));
+ }
+
+ DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
+
+ p = strchr_m(princ_name, '@');
+ if (!p) {
+ DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
+ princ_name));
+ status = NT_STATUS_LOGON_FAILURE;
+ goto done;
+ }
+
+ original_user_name = talloc_strndup(tmp_ctx, princ_name, p - princ_name);
+ if (original_user_name == NULL) {
status = NT_STATUS_NO_MEMORY;
goto done;
}
+
+ status = create_local_token(mem_ctx,
+ server_info,
+ NULL,
+ original_user_name,
+ session_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("create_local_token failed: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ goto session_info_ready;
+ }
+
+ /* This is the standalone legacy code path */
+
+ if (pac_blob != NULL) {
+ /*
+ * In standalone mode we don't expect a PAC!
+ * we only support MIT realms
+ */
+ status = NT_STATUS_BAD_TOKEN_TYPE;
+ DBG_WARNING("Unexpected PAC for [%s] in standalone mode - %s\n",
+ princ_name, nt_errstr(status));
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
}
status = get_user_from_kerberos_info(tmp_ctx, rhost,
- princ_name, logon_info,
+ princ_name,
&is_mapped, &is_guest,
&ntuser, &ntdomain,
&username, &pw);
@@ -149,27 +225,19 @@
goto done;
}
- /* Get the info3 from the PAC data if we have it */
- if (logon_info) {
- status = create_info3_from_pac_logon_info(tmp_ctx,
- logon_info,
- &info3_copy);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
- }
-
status = make_session_info_krb5(mem_ctx,
ntuser, ntdomain, username, pw,
- info3_copy, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */,
+ is_guest, is_mapped,
session_info);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to map kerberos pac to server info (%s)\n",
nt_errstr(status)));
- status = NT_STATUS_ACCESS_DENIED;
+ status = nt_status_squash(status);
goto done;
}
+session_info_ready:
+
/* setup the string used by %U */
set_current_user_info((*session_info)->unix_info->sanitized_username,
(*session_info)->unix_info->unix_name,
@@ -179,7 +247,9 @@
lp_load_with_shares(get_dyn_CONFIGFILE());
DEBUG(5, (__location__ "OK: user: %s domain: %s client: %s\n",
- ntuser, ntdomain, rhost));
+ (*session_info)->info->account_name,
+ (*session_info)->info->domain_name,
+ rhost));
status = NT_STATUS_OK;
@@ -416,7 +486,7 @@
{
NTSTATUS nt_status;
void *server_info;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
struct tevent_context *ev = NULL;
struct tevent_req *subreq = NULL;
bool ok;
diff -Nru samba-4.13.3+dfsg/source3/auth/auth_samba4.c samba-4.13.14+dfsg/source3/auth/auth_samba4.c
--- samba-4.13.3+dfsg/source3/auth/auth_samba4.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/auth/auth_samba4.c 2021-11-08 11:29:14.000000000 +0000
@@ -107,18 +107,20 @@
* services the AD DC. It is tested via pdbtest.
*/
-static NTSTATUS check_samba4_security(const struct auth_context *auth_context,
- void *my_private_data,
- TALLOC_CTX *mem_ctx,
- const struct auth_usersupplied_info *user_info,
- struct auth_serversupplied_info **server_info)
+static NTSTATUS check_samba4_security(
+ const struct auth_context *auth_context,
+ void *my_private_data,
+ TALLOC_CTX *mem_ctx,
+ const struct auth_usersupplied_info *user_info,
+ struct auth_serversupplied_info **pserver_info)
{
TALLOC_CTX *frame = talloc_stackframe();
struct netr_SamInfo3 *info3 = NULL;
NTSTATUS nt_status;
struct auth_user_info_dc *user_info_dc;
struct auth4_context *auth4_context;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
+ struct auth_serversupplied_info *server_info = NULL;
nt_status = make_auth4_context_s4(auth_context, mem_ctx, &auth4_context);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -160,17 +162,19 @@
}
if (user_info->flags & USER_INFO_INFO3_AND_NO_AUTHZ) {
- *server_info = make_server_info(mem_ctx);
- if (*server_info == NULL) {
+ server_info = make_server_info(mem_ctx);
+ if (server_info == NULL) {
nt_status = NT_STATUS_NO_MEMORY;
goto done;
}
- (*server_info)->info3 = talloc_steal(*server_info, info3);
-
+ server_info->info3 = talloc_move(server_info, &info3);
} else {
- nt_status = make_server_info_info3(mem_ctx, user_info->client.account_name,
- user_info->mapped.domain_name, server_info,
- info3);
+ nt_status = make_server_info_info3(
+ mem_ctx,
+ user_info->client.account_name,
+ user_info->mapped.domain_name,
+ &server_info,
+ info3);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(10, ("make_server_info_info3 failed: %s\n",
nt_errstr(nt_status)));
@@ -178,6 +182,7 @@
}
}
+ *pserver_info = server_info;
nt_status = NT_STATUS_OK;
done:
diff -Nru samba-4.13.3+dfsg/source3/auth/auth_sam.c samba-4.13.14+dfsg/source3/auth/auth_sam.c
--- samba-4.13.3+dfsg/source3/auth/auth_sam.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/auth/auth_sam.c 2021-11-08 11:29:14.000000000 +0000
@@ -22,6 +22,7 @@
#include "includes.h"
#include "auth.h"
+#include "passdb.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
@@ -142,10 +143,29 @@
break;
case ROLE_DOMAIN_PDC:
case ROLE_DOMAIN_BDC:
- if ( !is_local_name && !is_my_domain ) {
- DEBUG(6,("check_samstrict_security: %s is not one of my local names or domain name (DC)\n",
- effective_domain));
- return NT_STATUS_NOT_IMPLEMENTED;
+ case ROLE_IPA_DC:
+ if (!is_local_name && !is_my_domain) {
+ /* If we are running on a DC that has PASSDB module with domain
+ * information, check if DNS forest name is matching the domain
+ * name. This is the case of IPA domain controller when
+ * trusted AD DCs attempt to authenticate IPA users using
+ * the forest root domain (which is the only domain in IPA).
+ */
+ struct pdb_domain_info *dom_info = NULL;
+
+ dom_info = pdb_get_domain_info(mem_ctx);
+ if ((dom_info != NULL) && (dom_info->dns_forest != NULL)) {
+ is_my_domain = strequal(user_info->mapped.domain_name,
+ dom_info->dns_forest);
+ }
+
+ TALLOC_FREE(dom_info);
+ if (!is_my_domain) {
+ DEBUG(6,("check_samstrict_security: %s is not one "
+ "of my local names or domain name (DC)\n",
+ effective_domain));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
}
break;
@@ -215,6 +235,7 @@
switch (lp_server_role()) {
case ROLE_DOMAIN_PDC:
case ROLE_DOMAIN_BDC:
+ case ROLE_IPA_DC:
break;
default:
DBG_ERR("Invalid server role\n");
@@ -231,6 +252,24 @@
is_my_domain = strequal(user_info->mapped.domain_name, lp_workgroup());
if (!is_my_domain) {
+ /* If we are running on a DC that has PASSDB module with domain
+ * information, check if DNS forest name is matching the domain
+ * name. This is the case of IPA domain controller when
+ * trusted AD DCs attempt to authenticate IPA users using
+ * the forest root domain (which is the only domain in IPA).
+ */
+ struct pdb_domain_info *dom_info = NULL;
+ dom_info = pdb_get_domain_info(mem_ctx);
+
+ if ((dom_info != NULL) && (dom_info->dns_forest != NULL)) {
+ is_my_domain = strequal(user_info->mapped.domain_name,
+ dom_info->dns_forest);
+ }
+
+ TALLOC_FREE(dom_info);
+ }
+
+ if (!is_my_domain) {
DBG_INFO("%s is not our domain name (DC for %s)\n",
effective_domain, lp_workgroup());
return NT_STATUS_NOT_IMPLEMENTED;
diff -Nru samba-4.13.3+dfsg/source3/auth/auth_util.c samba-4.13.14+dfsg/source3/auth/auth_util.c
--- samba-4.13.3+dfsg/source3/auth/auth_util.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/auth/auth_util.c 2021-11-08 11:29:14.000000000 +0000
@@ -485,6 +485,14 @@
return NT_STATUS_LOGON_FAILURE;
}
+ if (!is_allowed_domain(server_info->info3->base.logon_domain.string)) {
+ DBG_NOTICE("Authentication failed for user [%s] "
+ "from firewalled domain [%s]\n",
+ server_info->info3->base.account_name.string,
+ server_info->info3->base.logon_domain.string);
+ return NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
+ }
+
if (server_info->cached_session_info != NULL) {
session_info = copy_session_info(mem_ctx,
server_info->cached_session_info);
@@ -568,13 +576,11 @@
}
/*
- * If winbind is not around, we can not make much use of the SIDs the
- * domain controller provided us with. Likewise if the user name was
- * mapped to some local unix user.
+ * If the user name was mapped to some local unix user,
+ * we can not make much use of the SIDs the
+ * domain controller provided us with.
*/
-
- if (((lp_server_role() == ROLE_DOMAIN_MEMBER) && !winbind_ping()) ||
- (server_info->nss_token)) {
+ if (server_info->nss_token) {
char *found_username = NULL;
status = create_token_from_username(session_info,
server_info->unix_name,
@@ -1890,7 +1896,7 @@
return NT_STATUS_NO_MEMORY;
}
- passwd = smb_getpwnam(mem_ctx, dom_user, &real_username, true );
+ passwd = smb_getpwnam(mem_ctx, dom_user, &real_username, false);
if (!passwd) {
DEBUG(3, ("Failed to find authenticated user %s via "
"getpwnam(), denying access.\n", dom_user));
@@ -1925,7 +1931,7 @@
{
struct passwd *pw = NULL;
char *p = NULL;
- char *username = NULL;
+ const char *username = NULL;
/* we only save a copy of the username it has been mangled
by winbindd use default domain */
@@ -1944,48 +1950,55 @@
/* code for a DOMAIN\user string */
if ( p ) {
- pw = Get_Pwnam_alloc( mem_ctx, domuser );
- if ( pw ) {
- /* make sure we get the case of the username correct */
- /* work around 'winbind use default domain = yes' */
-
- if ( lp_winbind_use_default_domain() &&
- !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) {
- char *domain;
-
- /* split the domain and username into 2 strings */
- *p = '\0';
- domain = username;
-
- *p_save_username = talloc_asprintf(mem_ctx,
- "%s%c%s",
- domain,
- *lp_winbind_separator(),
- pw->pw_name);
- if (!*p_save_username) {
- TALLOC_FREE(pw);
- return NULL;
- }
- } else {
- *p_save_username = talloc_strdup(mem_ctx, pw->pw_name);
- }
+ const char *domain = NULL;
- /* whew -- done! */
- return pw;
- }
+ /* split the domain and username into 2 strings */
+ *p = '\0';
+ domain = username;
+ p++;
+ username = p;
- /* setup for lookup of just the username */
- /* remember that p and username are overlapping memory */
+ if (strequal(domain, get_global_sam_name())) {
+ /*
+ * This typically don't happen
+ * as check_sam_Security()
+ * don't call make_server_info_info3()
+ * and thus check_account().
+ *
+ * But we better keep this.
+ */
+ goto username_only;
+ }
- p++;
- username = talloc_strdup(mem_ctx, p);
- if (!username) {
+ pw = Get_Pwnam_alloc( mem_ctx, domuser );
+ if (pw == NULL) {
return NULL;
}
+ /* make sure we get the case of the username correct */
+ /* work around 'winbind use default domain = yes' */
+
+ if ( lp_winbind_use_default_domain() &&
+ !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) {
+ *p_save_username = talloc_asprintf(mem_ctx,
+ "%s%c%s",
+ domain,
+ *lp_winbind_separator(),
+ pw->pw_name);
+ if (!*p_save_username) {
+ TALLOC_FREE(pw);
+ return NULL;
+ }
+ } else {
+ *p_save_username = talloc_strdup(mem_ctx, pw->pw_name);
+ }
+
+ /* whew -- done! */
+ return pw;
+
}
/* just lookup a plain username */
-
+username_only:
pw = Get_Pwnam_alloc(mem_ctx, username);
/* Create local user if requested but only if winbindd
@@ -2095,6 +2108,22 @@
}
}
goto out;
+ } else if ((lp_security() == SEC_ADS || lp_security() == SEC_DOMAIN) &&
+ !is_myname(domain) && pwd->pw_uid < lp_min_domain_uid()) {
+ /*
+ * !is_myname(domain) because when smbd starts tries to setup
+ * the guest user info, calling this function with nobody
+ * username. Nobody is usually uid 65535 but it can be changed
+ * to a regular user with 'guest account' parameter
+ */
+ nt_status = NT_STATUS_INVALID_TOKEN;
+ DBG_NOTICE("Username '%s%s%s' is invalid on this system, "
+ "it does not meet 'min domain uid' "
+ "restriction (%u < %u): %s\n",
+ nt_domain, lp_winbind_separator(), nt_username,
+ pwd->pw_uid, lp_min_domain_uid(),
+ nt_errstr(nt_status));
+ goto out;
}
result = make_server_info(tmp_ctx);
diff -Nru samba-4.13.3+dfsg/source3/auth/proto.h samba-4.13.14+dfsg/source3/auth/proto.h
--- samba-4.13.3+dfsg/source3/auth/proto.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/auth/proto.h 2021-11-08 11:29:14.000000000 +0000
@@ -423,7 +423,6 @@
NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx,
const char *cli_name,
const char *princ_name,
- struct PAC_LOGON_INFO *logon_info,
bool *is_mapped,
bool *mapped_to_guest,
char **ntuser,
@@ -435,9 +434,7 @@
char *ntdomain,
char *username,
struct passwd *pw,
- const struct netr_SamInfo3 *info3,
bool mapped_to_guest, bool username_was_mapped,
- DATA_BLOB *session_key,
struct auth_session_info **session_info);
/* The following definitions come from auth/auth_samba4.c */
diff -Nru samba-4.13.3+dfsg/source3/auth/user_krb5.c samba-4.13.14+dfsg/source3/auth/user_krb5.c
--- samba-4.13.3+dfsg/source3/auth/user_krb5.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/auth/user_krb5.c 2021-11-08 11:29:14.000000000 +0000
@@ -31,7 +31,6 @@
NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx,
const char *cli_name,
const char *princ_name,
- struct PAC_LOGON_INFO *logon_info,
bool *is_mapped,
bool *mapped_to_guest,
char **ntuser,
@@ -40,8 +39,8 @@
struct passwd **_pw)
{
NTSTATUS status;
- char *domain = NULL;
- char *realm = NULL;
+ const char *domain = NULL;
+ const char *realm = NULL;
char *user = NULL;
char *p;
char *fuser = NULL;
@@ -62,55 +61,16 @@
return NT_STATUS_NO_MEMORY;
}
- realm = talloc_strdup(talloc_tos(), p + 1);
- if (!realm) {
- return NT_STATUS_NO_MEMORY;
- }
+ realm = p + 1;
if (!strequal(realm, lp_realm())) {
DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
if (!lp_allow_trusted_domains()) {
return NT_STATUS_LOGON_FAILURE;
}
- }
-
- if (logon_info && logon_info->info3.base.logon_domain.string) {
- domain = talloc_strdup(mem_ctx,
- logon_info->info3.base.logon_domain.string);
- if (!domain) {
- return NT_STATUS_NO_MEMORY;
- }
- DEBUG(10, ("Domain is [%s] (using PAC)\n", domain));
+ domain = realm;
} else {
-
- /* If we have winbind running, we can (and must) shorten the
- username by using the short netbios name. Otherwise we will
- have inconsistent user names. With Kerberos, we get the
- fully qualified realm, with ntlmssp we get the short
- name. And even w2k3 does use ntlmssp if you for example
- connect to an ip address. */
-
- wbcErr wbc_status;
- struct wbcDomainInfo *info = NULL;
-
- DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
- realm));
-
- wbc_status = wbcDomainInfo(realm, &info);
-
- if (WBC_ERROR_IS_OK(wbc_status)) {
- domain = talloc_strdup(mem_ctx,
- info->short_name);
- wbcFreeMemory(info);
- } else {
- DEBUG(3, ("Could not find short name: %s\n",
- wbcErrorString(wbc_status)));
- domain = talloc_strdup(mem_ctx, realm);
- }
- if (!domain) {
- return NT_STATUS_NO_MEMORY;
- }
- DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
+ domain = lp_workgroup();
}
fuser = talloc_asprintf(mem_ctx,
@@ -155,7 +115,7 @@
if (!fuser) {
return NT_STATUS_NO_MEMORY;
}
- pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true);
+ pw = smb_getpwnam(mem_ctx, fuser, &unixuser, false);
}
/* extra sanity check that the guest account is valid */
@@ -175,7 +135,11 @@
return NT_STATUS_NO_MEMORY;
}
*ntuser = user;
- *ntdomain = domain;
+ *ntdomain = talloc_strdup(mem_ctx, domain);
+ if (*ntdomain == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
*_pw = pw;
return NT_STATUS_OK;
@@ -186,9 +150,7 @@
char *ntdomain,
char *username,
struct passwd *pw,
- const struct netr_SamInfo3 *info3,
bool mapped_to_guest, bool username_was_mapped,
- DATA_BLOB *session_key,
struct auth_session_info **session_info)
{
NTSTATUS status;
@@ -202,20 +164,6 @@
return status;
}
- } else if (info3) {
- /* pass the unmapped username here since map_username()
- will be called again in make_server_info_info3() */
-
- status = make_server_info_info3(mem_ctx,
- ntuser, ntdomain,
- &server_info,
- info3);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("make_server_info_info3 failed: %s!\n",
- nt_errstr(status)));
- return status;
- }
-
} else {
/*
* We didn't get a PAC, we have to make up the user
@@ -267,7 +215,7 @@
server_info->nss_token |= username_was_mapped;
- status = create_local_token(mem_ctx, server_info, session_key, ntuser, session_info);
+ status = create_local_token(mem_ctx, server_info, NULL, ntuser, session_info);
talloc_free(server_info);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("failed to create local token: %s\n",
@@ -282,7 +230,6 @@
NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx,
const char *cli_name,
const char *princ_name,
- struct PAC_LOGON_INFO *logon_info,
bool *is_mapped,
bool *mapped_to_guest,
char **ntuser,
@@ -298,9 +245,7 @@
char *ntdomain,
char *username,
struct passwd *pw,
- const struct netr_SamInfo3 *info3,
bool mapped_to_guest, bool username_was_mapped,
- DATA_BLOB *session_key,
struct auth_session_info **session_info)
{
return NT_STATUS_NOT_IMPLEMENTED;
diff -Nru samba-4.13.3+dfsg/source3/include/idmap.h samba-4.13.14+dfsg/source3/include/idmap.h
--- samba-4.13.3+dfsg/source3/include/idmap.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/include/idmap.h 2021-11-08 11:29:14.000000000 +0000
@@ -42,7 +42,7 @@
* so don't rely on this being filled out everywhere!
*/
struct dom_sid dom_sid;
- struct idmap_methods *methods;
+ const struct idmap_methods *methods;
NTSTATUS (*query_user)(struct idmap_domain *domain,
struct wbint_userinfo *info);
uint32_t low_id;
diff -Nru samba-4.13.3+dfsg/source3/include/nss_info.h samba-4.13.14+dfsg/source3/include/nss_info.h
--- samba-4.13.3+dfsg/source3/include/nss_info.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/include/nss_info.h 2021-11-08 11:29:14.000000000 +0000
@@ -38,7 +38,7 @@
struct nss_function_entry *prev, *next;
const char *name;
- struct nss_info_methods *methods;
+ const struct nss_info_methods *methods;
};
/* List of configured domains. Each domain points
@@ -50,7 +50,7 @@
const char *domain;
NTSTATUS init_status;
- struct nss_function_entry *backend;
+ const struct nss_function_entry *backend;
/* hold state on a per domain basis */
@@ -75,7 +75,7 @@
NTSTATUS smb_register_idmap_nss(int version,
const char *name,
- struct nss_info_methods *methods);
+ const struct nss_info_methods *methods);
NTSTATUS nss_map_to_alias( TALLOC_CTX *mem_ctx, const char *domain,
const char *name, char **alias );
diff -Nru samba-4.13.3+dfsg/source3/include/proto.h samba-4.13.14+dfsg/source3/include/proto.h
--- samba-4.13.3+dfsg/source3/include/proto.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/include/proto.h 2021-08-09 07:20:55.000000000 +0000
@@ -322,6 +322,7 @@
/* The following definitions come from lib/util_names.c */
const char *get_global_sam_name(void);
const char *my_sam_name(void);
+bool is_allowed_domain(const char *domain_name);
/* The following definitions come from lib/util.c */
diff -Nru samba-4.13.3+dfsg/source3/include/smb_macros.h samba-4.13.14+dfsg/source3/include/smb_macros.h
--- samba-4.13.3+dfsg/source3/include/smb_macros.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/include/smb_macros.h 2021-11-08 11:29:14.000000000 +0000
@@ -199,7 +199,7 @@
Check to see if we are a DC for this domain
*****************************************************************************/
-#define IS_DC (lp_server_role()==ROLE_DOMAIN_PDC || lp_server_role()==ROLE_DOMAIN_BDC || lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC)
+#define IS_DC (lp_server_role()==ROLE_DOMAIN_PDC || lp_server_role()==ROLE_DOMAIN_BDC || lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC || lp_server_role() == ROLE_IPA_DC)
#define IS_AD_DC (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC)
/*
diff -Nru samba-4.13.3+dfsg/source3/lib/dbwrap/dbwrap_open.c samba-4.13.14+dfsg/source3/lib/dbwrap/dbwrap_open.c
--- samba-4.13.3+dfsg/source3/lib/dbwrap/dbwrap_open.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/lib/dbwrap/dbwrap_open.c 2021-09-07 07:01:16.000000000 +0000
@@ -149,6 +149,10 @@
* to be initialized.
*/
msg_ctx = global_messaging_context();
+ if (msg_ctx == NULL) {
+ DBG_ERR("Failed to initialize messaging\n");
+ return NULL;
+ }
conn = messaging_ctdb_connection();
if (conn == NULL) {
diff -Nru samba-4.13.3+dfsg/source3/lib/filename_util.c samba-4.13.14+dfsg/source3/lib/filename_util.c
--- samba-4.13.3+dfsg/source3/lib/filename_util.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/lib/filename_util.c 2021-08-09 07:20:55.000000000 +0000
@@ -337,7 +337,7 @@
}
TALLOC_FREE(name->base_name);
- name->base_name = talloc_strdup(mem_ctx, p);
+ name->base_name = talloc_strdup(name, p);
if (name == NULL) {
TALLOC_FREE(frame);
return false;
diff -Nru samba-4.13.3+dfsg/source3/lib/gencache.c samba-4.13.14+dfsg/source3/lib/gencache.c
--- samba-4.13.3+dfsg/source3/lib/gencache.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/lib/gencache.c 2021-08-06 12:19:57.000000000 +0000
@@ -124,7 +124,7 @@
return false;
}
- ok = directory_create_or_exist(cache_dname, 0700);
+ ok = directory_create_or_exists_recursive(cache_dname, 0700);
if (!ok) {
DBG_ERR("Failed to create directory: %s - %s\n",
cache_dname, strerror(errno));
diff -Nru samba-4.13.3+dfsg/source3/lib/g_lock.c samba-4.13.14+dfsg/source3/lib/g_lock.c
--- samba-4.13.3+dfsg/source3/lib/g_lock.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/lib/g_lock.c 2021-08-09 07:17:53.000000000 +0000
@@ -646,8 +646,8 @@
struct g_lock_lock_state *state = tevent_req_data(
req, struct g_lock_lock_state);
struct g_lock_lock_fn_state fn_state;
- struct server_id blocker;
- bool blockerdead;
+ struct server_id blocker = { .pid = 0 };
+ bool blockerdead = false;
NTSTATUS status;
status = dbwrap_watched_watch_recv(subreq, &blockerdead, &blocker);
diff -Nru samba-4.13.3+dfsg/source3/lib/messages.c samba-4.13.14+dfsg/source3/lib/messages.c
--- samba-4.13.3+dfsg/source3/lib/messages.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/lib/messages.c 2021-08-09 07:20:55.000000000 +0000
@@ -157,7 +157,7 @@
{
struct messaging_rec rec;
- int64_t fds64[num_fds];
+ int64_t fds64[MAX(1, num_fds)];
size_t i;
for (i=0; ievent_ctx) {
struct iovec iov;
- int fds[rec->num_fds];
+ int fds[MAX(1, rec->num_fds)];
int ret;
/*
diff -Nru samba-4.13.3+dfsg/source3/lib/netapi/joindomain.c samba-4.13.14+dfsg/source3/lib/netapi/joindomain.c
--- samba-4.13.3+dfsg/source3/lib/netapi/joindomain.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/lib/netapi/joindomain.c 2021-11-08 11:29:14.000000000 +0000
@@ -375,6 +375,7 @@
case ROLE_DOMAIN_MEMBER:
case ROLE_DOMAIN_PDC:
case ROLE_DOMAIN_BDC:
+ case ROLE_IPA_DC:
*r->out.name_type = NetSetupDomainName;
break;
case ROLE_STANDALONE:
diff -Nru samba-4.13.3+dfsg/source3/lib/util_names.c samba-4.13.14+dfsg/source3/lib/util_names.c
--- samba-4.13.3+dfsg/source3/lib/util_names.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/lib/util_names.c 2021-11-08 11:29:14.000000000 +0000
@@ -182,3 +182,36 @@
return lp_workgroup();
}
+
+bool is_allowed_domain(const char *domain_name)
+{
+ const char **ignored_domains = NULL;
+ const char **dom = NULL;
+
+ ignored_domains = lp_parm_string_list(-1,
+ "winbind",
+ "ignore domains",
+ NULL);
+
+ for (dom = ignored_domains; dom != NULL && *dom != NULL; dom++) {
+ if (gen_fnmatch(*dom, domain_name) == 0) {
+ DBG_NOTICE("Ignoring domain '%s'\n", domain_name);
+ return false;
+ }
+ }
+
+ if (lp_allow_trusted_domains()) {
+ return true;
+ }
+
+ if (strequal(lp_workgroup(), domain_name)) {
+ return true;
+ }
+
+ if (is_myname(domain_name)) {
+ return true;
+ }
+
+ DBG_NOTICE("Not trusted domain '%s'\n", domain_name);
+ return false;
+}
diff -Nru samba-4.13.3+dfsg/source3/librpc/rpc/dcerpc_helpers.c samba-4.13.14+dfsg/source3/librpc/rpc/dcerpc_helpers.c
--- samba-4.13.3+dfsg/source3/librpc/rpc/dcerpc_helpers.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/librpc/rpc/dcerpc_helpers.c 2021-11-08 11:29:14.000000000 +0000
@@ -20,6 +20,7 @@
#include "includes.h"
#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_util.h"
#include "librpc/gen_ndr/ndr_dcerpc.h"
#include "librpc/crypto/gse.h"
#include "auth/gensec/gensec.h"
diff -Nru samba-4.13.3+dfsg/source3/libsmb/cliconnect.c samba-4.13.14+dfsg/source3/libsmb/cliconnect.c
--- samba-4.13.3+dfsg/source3/libsmb/cliconnect.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/libsmb/cliconnect.c 2021-11-08 11:29:14.000000000 +0000
@@ -1443,6 +1443,8 @@
uint32_t in_sess_key = 0;
const char *in_native_os = NULL;
const char *in_native_lm = NULL;
+ enum credentials_use_kerberos krb5_state =
+ cli_credentials_get_kerberos_state(creds);
NTSTATUS status;
req = tevent_req_create(mem_ctx, &state,
@@ -1484,6 +1486,13 @@
return req;
}
+ if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ DBG_WARNING("Kerberos authentication requested, but "
+ "the server does not support SPNEGO authentication\n");
+ tevent_req_nterror(req, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
+ return tevent_req_post(req, ev);
+ }
+
if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN1) {
/*
* SessionSetupAndX was introduced by LANMAN 1.0. So we skip
diff -Nru samba-4.13.3+dfsg/source3/libsmb/clidfs.c samba-4.13.14+dfsg/source3/libsmb/clidfs.c
--- samba-4.13.3+dfsg/source3/libsmb/clidfs.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/libsmb/clidfs.c 2021-09-07 07:01:16.000000000 +0000
@@ -50,6 +50,7 @@
uint16_t major, minor;
uint32_t caplow, caphigh;
NTSTATUS status;
+ bool temp_ipc = false;
if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
status = smb2cli_session_encryption_on(c->smb2.session);
@@ -72,12 +73,26 @@
return NT_STATUS_NOT_SUPPORTED;
}
+ if (c->smb1.tcon == NULL) {
+ status = cli_tree_connect_creds(c, "IPC$", "IPC", creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Encryption required and "
+ "can't connect to IPC$ to check "
+ "UNIX CIFS extensions.\n");
+ return NT_STATUS_UNKNOWN_REVISION;
+ }
+ temp_ipc = true;
+ }
+
status = cli_unix_extensions_version(c, &major, &minor, &caplow,
&caphigh);
if (!NT_STATUS_IS_OK(status)) {
d_printf("Encryption required and "
"can't get UNIX CIFS extensions "
"version from server.\n");
+ if (temp_ipc) {
+ cli_tdis(c);
+ }
return NT_STATUS_UNKNOWN_REVISION;
}
@@ -85,6 +100,9 @@
d_printf("Encryption required and "
"share %s doesn't support "
"encryption.\n", sharename);
+ if (temp_ipc) {
+ cli_tdis(c);
+ }
return NT_STATUS_UNSUPPORTED_COMPRESSION;
}
@@ -93,9 +111,15 @@
d_printf("Encryption required and "
"setup failed with error %s.\n",
nt_errstr(status));
+ if (temp_ipc) {
+ cli_tdis(c);
+ }
return status;
}
+ if (temp_ipc) {
+ cli_tdis(c);
+ }
return NT_STATUS_OK;
}
@@ -221,6 +245,16 @@
DEBUG(4,(" session setup ok\n"));
+ if (force_encrypt) {
+ status = cli_cm_force_encryption_creds(c,
+ creds,
+ sharename);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_shutdown(c);
+ return status;
+ }
+ }
+
/* here's the fun part....to support 'msdfs proxy' shares
(on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL
here before trying to connect to the original share.
@@ -246,16 +280,6 @@
return status;
}
- if (force_encrypt) {
- status = cli_cm_force_encryption_creds(c,
- creds,
- sharename);
- if (!NT_STATUS_IS_OK(status)) {
- cli_shutdown(c);
- return status;
- }
- }
-
DEBUG(4,(" tconx ok\n"));
*pcli = c;
return NT_STATUS_OK;
@@ -1230,6 +1254,7 @@
if (force_encrypt) {
status = cli_cm_force_encryption_creds(cli, creds, "IPC$");
if (!NT_STATUS_IS_OK(status)) {
+ cli_tdis(cli);
cli_state_restore_tcon(cli, orig_tcon);
return false;
}
diff -Nru samba-4.13.3+dfsg/source3/libsmb/clientgen.c samba-4.13.14+dfsg/source3/libsmb/clientgen.c
--- samba-4.13.3+dfsg/source3/libsmb/clientgen.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/libsmb/clientgen.c 2021-08-09 07:20:55.000000000 +0000
@@ -352,11 +352,37 @@
struct smbXcli_tcon *cli_state_save_tcon(struct cli_state *cli)
{
+ /*
+ * Note. This used to make a deep copy of either
+ * cli->smb2.tcon or cli->smb1.tcon, but this leaves
+ * the original pointer in place which will then get
+ * TALLOC_FREE()'d when the new connection is made on
+ * this cli_state.
+ *
+ * As there may be pipes open on the old connection with
+ * talloc'ed state allocated using the tcon pointer as a
+ * parent we can't deep copy and then free this as that
+ * closes the open pipes.
+ *
+ * This call is used to temporarily swap out a tcon pointer
+ * to allow a new tcon on the same cli_state.
+ *
+ * Just return the raw pointer and set the old value to NULL.
+ * We know we MUST be calling cli_state_restore_tcon() below
+ * to restore before closing the session.
+ *
+ * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=13992
+ */
+ struct smbXcli_tcon *tcon_ret = NULL;
+
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- return smbXcli_tcon_copy(cli, cli->smb2.tcon);
+ tcon_ret = cli->smb2.tcon;
+ cli->smb2.tcon = NULL; /* *Not* TALLOC_FREE(). */
} else {
- return smbXcli_tcon_copy(cli, cli->smb1.tcon);
+ tcon_ret = cli->smb1.tcon;
+ cli->smb1.tcon = NULL; /* *Not* TALLOC_FREE(). */
}
+ return tcon_ret;
}
void cli_state_restore_tcon(struct cli_state *cli, struct smbXcli_tcon *tcon)
diff -Nru samba-4.13.3+dfsg/source3/libsmb/clifsinfo.c samba-4.13.14+dfsg/source3/libsmb/clifsinfo.c
--- samba-4.13.3+dfsg/source3/libsmb/clifsinfo.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/libsmb/clifsinfo.c 2021-09-22 06:59:39.000000000 +0000
@@ -29,7 +29,6 @@
#include "../libcli/smb/smbXcli_base.h"
#include "auth/credentials/credentials.h"
#include "../librpc/gen_ndr/ndr_security.h"
-#include "libcli/security/dom_sid.h"
/****************************************************************************
Get UNIX extensions version info.
@@ -571,6 +570,8 @@
static void cli_posix_whoami_done(struct tevent_req *subreq);
+static const uint32_t posix_whoami_max_rdata = 62*1024;
+
struct tevent_req *cli_posix_whoami_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli)
@@ -587,7 +588,7 @@
SSVAL(state->setup, 0, TRANSACT2_QFSINFO);
SSVAL(state->param, 0, SMB_QUERY_POSIX_WHOAMI);
- state->max_rdata = 62*1024;
+ state->max_rdata = posix_whoami_max_rdata;
subreq = cli_trans_send(state, /* mem ctx. */
ev, /* event ctx. */
@@ -651,7 +652,7 @@
* parsing network packets in C.
*/
- if (num_rdata < 40 || rdata + num_rdata < rdata) {
+ if (num_rdata < 40 || num_rdata > posix_whoami_max_rdata) {
tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
@@ -662,6 +663,13 @@
state->num_gids = IVAL(rdata, 24);
state->num_sids = IVAL(rdata, 28);
+ /* Ensure the gid array doesn't overflow */
+ if (state->num_gids > (num_rdata - 40) / sizeof(uint64_t)) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
state->gids = talloc_array(state, uint64_t, state->num_gids);
if (tevent_req_nomem(state->gids, req)) {
return;
@@ -674,11 +682,6 @@
p = rdata + 40;
for (i = 0; i < state->num_gids; i++) {
- if (p + 8 > rdata + num_rdata) {
- tevent_req_nterror(req,
- NT_STATUS_INVALID_NETWORK_RESPONSE);
- return;
- }
state->gids[i] = BVAL(p, 0);
p += 8;
}
@@ -686,9 +689,23 @@
num_rdata -= (p - rdata);
for (i = 0; i < state->num_sids; i++) {
- ssize_t sid_size = sid_parse(p, num_rdata, &state->sids[i]);
+ size_t sid_size;
+ DATA_BLOB in = data_blob_const(p, num_rdata);
+ enum ndr_err_code ndr_err;
- if ((sid_size == -1) || (sid_size > num_rdata)) {
+ ndr_err = ndr_pull_struct_blob(&in,
+ state,
+ &state->sids[i],
+ (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ sid_size = ndr_size_dom_sid(&state->sids[i], 0);
+
+ if (sid_size > num_rdata) {
tevent_req_nterror(req,
NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
@@ -697,6 +714,13 @@
p += sid_size;
num_rdata -= sid_size;
}
+
+ if (num_rdata != 0) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
tevent_req_done(req);
}
diff -Nru samba-4.13.3+dfsg/source3/libsmb/pylibsmb.c samba-4.13.14+dfsg/source3/libsmb/pylibsmb.c
--- samba-4.13.3+dfsg/source3/libsmb/pylibsmb.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/libsmb/pylibsmb.c 2021-09-22 06:59:39.000000000 +0000
@@ -43,6 +43,8 @@
SECINFO_DACL | SECINFO_PROTECTED_DACL | SECINFO_UNPROTECTED_DACL | \
SECINFO_SACL | SECINFO_PROTECTED_SACL | SECINFO_UNPROTECTED_SACL)
+static PyTypeObject *dom_sid_Type = NULL;
+
static PyTypeObject *get_pytype(const char *module, const char *type)
{
PyObject *mod;
@@ -1332,6 +1334,123 @@
}
/*
+ * Does a whoami call
+ */
+static PyObject *py_smb_posix_whoami(struct py_cli_state *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct tevent_req *req = NULL;
+ uint64_t uid;
+ uint64_t gid;
+ uint32_t num_gids;
+ uint64_t *gids = NULL;
+ uint32_t num_sids;
+ struct dom_sid *sids = NULL;
+ bool guest;
+ PyObject *py_gids = NULL;
+ PyObject *py_sids = NULL;
+ PyObject *py_guest = NULL;
+ PyObject *py_ret = NULL;
+ Py_ssize_t i;
+
+ req = cli_posix_whoami_send(frame, self->ev, self->cli);
+ if (!py_tevent_req_wait_exc(self, req)) {
+ goto fail;
+ }
+ status = cli_posix_whoami_recv(req,
+ frame,
+ &uid,
+ &gid,
+ &num_gids,
+ &gids,
+ &num_sids,
+ &sids,
+ &guest);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_SetNTSTATUS(status);
+ goto fail;
+ }
+ if (num_gids > PY_SSIZE_T_MAX) {
+ PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many GIDs");
+ goto fail;
+ }
+ if (num_sids > PY_SSIZE_T_MAX) {
+ PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many SIDs");
+ goto fail;
+ }
+
+ py_gids = PyList_New(num_gids);
+ if (!py_gids) {
+ goto fail;
+ }
+ for (i = 0; i < num_gids; ++i) {
+ int ret;
+ PyObject *py_item = PyLong_FromUnsignedLongLong(gids[i]);
+ if (!py_item) {
+ goto fail2;
+ }
+
+ ret = PyList_SetItem(py_gids, i, py_item);
+ if (ret) {
+ goto fail2;
+ }
+ }
+ py_sids = PyList_New(num_sids);
+ if (!py_sids) {
+ goto fail2;
+ }
+ for (i = 0; i < num_sids; ++i) {
+ int ret;
+ struct dom_sid *sid;
+ PyObject *py_item;
+
+ sid = dom_sid_dup(frame, &sids[i]);
+ if (!sid) {
+ PyErr_NoMemory();
+ goto fail3;
+ }
+
+ py_item = pytalloc_steal(dom_sid_Type, sid);
+ if (!py_item) {
+ PyErr_NoMemory();
+ goto fail3;
+ }
+
+ ret = PyList_SetItem(py_sids, i, py_item);
+ if (ret) {
+ goto fail3;
+ }
+ }
+
+ py_guest = guest ? Py_True : Py_False;
+
+ py_ret = Py_BuildValue("KKNNO",
+ uid,
+ gid,
+ py_gids,
+ py_sids,
+ py_guest);
+ if (!py_ret) {
+ goto fail3;
+ }
+
+ TALLOC_FREE(frame);
+ return py_ret;
+
+fail3:
+ Py_CLEAR(py_sids);
+
+fail2:
+ Py_CLEAR(py_gids);
+
+fail:
+ TALLOC_FREE(frame);
+ return NULL;
+}
+
+/*
* Checks existence of a directory
*/
static bool check_dir_path(struct py_cli_state *self, const char *path)
@@ -1587,6 +1706,8 @@
"unlink(path) -> None\n\n \t\tDelete a file." },
{ "mkdir", (PyCFunction)py_smb_mkdir, METH_VARARGS,
"mkdir(path) -> None\n\n \t\tCreate a directory." },
+ { "posix_whoami", (PyCFunction)py_smb_posix_whoami, METH_NOARGS,
+ "posix_whoami() -> (uid, gid, gids, sids, guest)" },
{ "rmdir", (PyCFunction)py_smb_rmdir, METH_VARARGS,
"rmdir(path) -> None\n\n \t\tDelete a directory." },
{ "chkpath", (PyCFunction)py_smb_chkpath, METH_VARARGS,
@@ -1639,16 +1760,31 @@
MODULE_INIT_FUNC(libsmb_samba_internal)
{
PyObject *m = NULL;
+ PyObject *mod = NULL;
talloc_stackframe();
+ if (PyType_Ready(&py_cli_state_type) < 0) {
+ return NULL;
+ }
+
m = PyModule_Create(&moduledef);
if (m == NULL) {
return m;
}
- if (PyType_Ready(&py_cli_state_type) < 0) {
+
+ /* Import dom_sid type from dcerpc.security */
+ mod = PyImport_ImportModule("samba.dcerpc.security");
+ if (mod == NULL) {
return NULL;
}
+
+ dom_sid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "dom_sid");
+ if (dom_sid_Type == NULL) {
+ Py_DECREF(mod);
+ return NULL;
+ }
+
Py_INCREF(&py_cli_state_type);
PyModule_AddObject(m, "Conn", (PyObject *)&py_cli_state_type);
diff -Nru samba-4.13.3+dfsg/source3/locking/share_mode_lock.c samba-4.13.14+dfsg/source3/locking/share_mode_lock.c
--- samba-4.13.3+dfsg/source3/locking/share_mode_lock.c 2020-09-07 10:52:25.000000000 +0000
+++ samba-4.13.14+dfsg/source3/locking/share_mode_lock.c 2021-08-09 07:20:55.000000000 +0000
@@ -2256,7 +2256,7 @@
struct locking_tdb_data *ltdb = NULL;
size_t idx;
bool found = false;
- bool modified;
+ bool modified = false;
struct share_mode_entry e;
uint8_t *e_ptr = NULL;
bool have_share_modes;
diff -Nru samba-4.13.3+dfsg/source3/modules/nfs4_acls.c samba-4.13.14+dfsg/source3/modules/nfs4_acls.c
--- samba-4.13.3+dfsg/source3/modules/nfs4_acls.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/modules/nfs4_acls.c 2021-08-06 12:19:57.000000000 +0000
@@ -997,6 +997,7 @@
}
if (security_descriptor_with_ms_nfs(psd)) {
+ TALLOC_FREE(frame);
return NT_STATUS_OK;
}
diff -Nru samba-4.13.3+dfsg/source3/modules/vfs_error_inject.c samba-4.13.14+dfsg/source3/modules/vfs_error_inject.c
--- samba-4.13.3+dfsg/source3/modules/vfs_error_inject.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/modules/vfs_error_inject.c 2021-08-09 07:20:55.000000000 +0000
@@ -30,6 +30,7 @@
{ "ESTALE", ESTALE },
{ "EBADF", EBADF },
{ "EINTR", EINTR },
+ { "EACCES", EACCES },
};
static int find_unix_error_from_string(const char *err_str)
@@ -122,10 +123,46 @@
return SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, flags, mode);
}
+static int vfs_error_inject_unlinkat(struct vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ int flags)
+{
+ struct smb_filename *parent_fname = NULL;
+ int error = inject_unix_error("unlinkat", handle);
+ int ret;
+ bool ok;
+
+ if (error == 0) {
+ return SMB_VFS_NEXT_UNLINKAT(handle, dirfsp, smb_fname, flags);
+ }
+
+ ok = parent_smb_fname(talloc_tos(), smb_fname, &parent_fname, NULL);
+ if (!ok) {
+ return -1;
+ }
+
+ ret = SMB_VFS_STAT(handle->conn, parent_fname);
+ if (ret != 0) {
+ TALLOC_FREE(parent_fname);
+ return -1;
+ }
+
+ if (parent_fname->st.st_ex_uid == get_current_uid(dirfsp->conn)) {
+ TALLOC_FREE(parent_fname);
+ return SMB_VFS_NEXT_UNLINKAT(handle, dirfsp, smb_fname, flags);
+ }
+
+ TALLOC_FREE(parent_fname);
+ errno = error;
+ return -1;
+}
+
static struct vfs_fn_pointers vfs_error_inject_fns = {
.chdir_fn = vfs_error_inject_chdir,
.pwrite_fn = vfs_error_inject_pwrite,
.openat_fn = vfs_error_inject_openat,
+ .unlinkat_fn = vfs_error_inject_unlinkat,
};
static_decl_vfs;
diff -Nru samba-4.13.3+dfsg/source3/modules/vfs_fruit.c samba-4.13.14+dfsg/source3/modules/vfs_fruit.c
--- samba-4.13.3+dfsg/source3/modules/vfs_fruit.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/modules/vfs_fruit.c 2021-08-09 07:20:55.000000000 +0000
@@ -178,9 +178,6 @@
/* Denote stream type, meta or rsrc */
adouble_type_t type;
- /* Whether the create created the stream */
- bool created;
-
/*
* AFP_AfpInfo stream created, but not written yet, thus still a fake
* pipe fd. This is set to true in fruit_open_meta if there was no
@@ -1679,6 +1676,7 @@
static int fruit_close_meta(vfs_handle_struct *handle,
files_struct *fsp)
{
+ struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
int ret;
struct fruit_config_data *config = NULL;
@@ -1687,11 +1685,16 @@
switch (config->meta) {
case FRUIT_META_STREAM:
- ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
+ if (fio->fake_fd) {
+ ret = vfs_fake_fd_close(fsp->fh->fd);
+ fsp->fh->fd = -1;
+ } else {
+ ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
+ }
break;
case FRUIT_META_NETATALK:
- ret = close(fsp->fh->fd);
+ ret = vfs_fake_fd_close(fsp->fh->fd);
fsp->fh->fd = -1;
break;
@@ -1720,7 +1723,7 @@
break;
case FRUIT_RSRC_XATTR:
- ret = close(fsp->fh->fd);
+ ret = vfs_fake_fd_close(fsp->fh->fd);
fsp->fh->fd = -1;
break;
@@ -2140,9 +2143,14 @@
files_struct *fsp, void *data,
size_t n, off_t offset)
{
+ struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
ssize_t nread;
int ret;
+ if (fio->fake_fd) {
+ return -1;
+ }
+
nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
if (nread == -1 || nread == n) {
return nread;
@@ -2251,7 +2259,7 @@
return -1;
}
- if (nread == -1 && fio->created) {
+ if (nread == -1 && fio->fake_fd) {
AfpInfo *ai = NULL;
char afpinfo_buf[AFP_INFO_SIZE];
@@ -2478,13 +2486,13 @@
}
if (fio->fake_fd) {
- int fd;
+ int fd = fsp->fh->fd;
- ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
+ ret = vfs_fake_fd_close(fd);
+ fsp->fh->fd = -1;
if (ret != 0) {
DBG_ERR("Close [%s] failed: %s\n",
fsp_str_dbg(fsp), strerror(errno));
- fsp->fh->fd = -1;
return -1;
}
@@ -3954,7 +3962,6 @@
NTSTATUS status;
struct fruit_config_data *config = NULL;
files_struct *fsp = NULL;
- struct fio *fio = NULL;
bool internal_open = (oplock_request & INTERNAL_OPEN_ONLY);
int ret;
@@ -4027,11 +4034,6 @@
goto fail;
}
- fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
- if (fio != NULL && pinfo != NULL && *pinfo == FILE_WAS_CREATED) {
- fio->created = true;
- }
-
if (is_named_stream(smb_fname) || fsp->fsp_flags.is_directory) {
return status;
}
diff -Nru samba-4.13.3+dfsg/source3/modules/vfs_streams_xattr.c samba-4.13.14+dfsg/source3/modules/vfs_streams_xattr.c
--- samba-4.13.3+dfsg/source3/modules/vfs_streams_xattr.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/modules/vfs_streams_xattr.c 2021-08-09 07:20:55.000000000 +0000
@@ -504,7 +504,7 @@
fail:
if (fakefd >= 0) {
- close(fakefd);
+ vfs_fake_fd_close(fakefd);
fakefd = -1;
}
@@ -526,7 +526,7 @@
return SMB_VFS_NEXT_CLOSE(handle, fsp);
}
- ret = close(fd);
+ ret = vfs_fake_fd_close(fd);
fsp->fh->fd = -1;
return ret;
diff -Nru samba-4.13.3+dfsg/source3/modules/vfs_virusfilter.c samba-4.13.14+dfsg/source3/modules/vfs_virusfilter.c
--- samba-4.13.3+dfsg/source3/modules/vfs_virusfilter.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/modules/vfs_virusfilter.c 2021-08-09 07:20:55.000000000 +0000
@@ -200,6 +200,14 @@
struct virusfilter_config *config = NULL;
const char *exclude_files = NULL;
const char *temp_quarantine_dir_mode = NULL;
+ const char *infected_file_command = NULL;
+ const char *scan_error_command = NULL;
+ const char *quarantine_dir = NULL;
+ const char *quarantine_prefix = NULL;
+ const char *quarantine_suffix = NULL;
+ const char *rename_prefix = NULL;
+ const char *rename_suffix = NULL;
+ const char *socket_path = NULL;
char *sret = NULL;
char *tmp = NULL;
enum virusfilter_scanner_enum backend;
@@ -257,11 +265,24 @@
snum, "virusfilter", "infected file action",
virusfilter_actions, VIRUSFILTER_ACTION_DO_NOTHING);
- config->infected_file_command = lp_parm_const_string(
+ infected_file_command = lp_parm_const_string(
snum, "virusfilter", "infected file command", NULL);
-
- config->scan_error_command = lp_parm_const_string(
+ if (infected_file_command != NULL) {
+ config->infected_file_command = talloc_strdup(config, infected_file_command);
+ if (config->infected_file_command == NULL) {
+ DBG_ERR("virusfilter-vfs: out of memory!\n");
+ return -1;
+ }
+ }
+ scan_error_command = lp_parm_const_string(
snum, "virusfilter", "scan error command", NULL);
+ if (scan_error_command != NULL) {
+ config->scan_error_command = talloc_strdup(config, scan_error_command);
+ if (config->scan_error_command == NULL) {
+ DBG_ERR("virusfilter-vfs: out of memory!\n");
+ return -1;
+ }
+ }
config->block_access_on_error = lp_parm_bool(
snum, "virusfilter", "block access on error", false);
@@ -269,9 +290,16 @@
tmp = talloc_asprintf(config, "%s/.quarantine",
handle->conn->connectpath);
- config->quarantine_dir = lp_parm_const_string(
+ quarantine_dir = lp_parm_const_string(
snum, "virusfilter", "quarantine directory",
tmp ? tmp : "/tmp/.quarantine");
+ if (quarantine_dir != NULL) {
+ config->quarantine_dir = talloc_strdup(config, quarantine_dir);
+ if (config->quarantine_dir == NULL) {
+ DBG_ERR("virusfilter-vfs: out of memory!\n");
+ return -1;
+ }
+ }
if (tmp != config->quarantine_dir) {
TALLOC_FREE(tmp);
@@ -285,35 +313,53 @@
config->quarantine_dir_mode = mode;
}
- config->quarantine_prefix = lp_parm_const_string(
+ quarantine_prefix = lp_parm_const_string(
snum, "virusfilter", "quarantine prefix",
VIRUSFILTER_DEFAULT_QUARANTINE_PREFIX);
+ if (quarantine_prefix != NULL) {
+ config->quarantine_prefix = talloc_strdup(config, quarantine_prefix);
+ if (config->quarantine_prefix == NULL) {
+ DBG_ERR("virusfilter-vfs: out of memory!\n");
+ return -1;
+ }
+ }
- config->quarantine_suffix = lp_parm_const_string(
+ quarantine_suffix = lp_parm_const_string(
snum, "virusfilter", "quarantine suffix",
VIRUSFILTER_DEFAULT_QUARANTINE_SUFFIX);
+ if (quarantine_suffix != NULL) {
+ config->quarantine_suffix = talloc_strdup(config, quarantine_suffix);
+ if (config->quarantine_suffix == NULL) {
+ DBG_ERR("virusfilter-vfs: out of memory!\n");
+ return -1;
+ }
+ }
/*
* Make sure prefixes and suffixes do not contain directory
* delimiters
*/
- sret = strstr(config->quarantine_prefix, "/");
- if (sret != NULL) {
- DBG_ERR("quarantine prefix must not contain directory "
- "delimiter(s) such as '/' (%s replaced with %s)\n",
- config->quarantine_prefix,
- VIRUSFILTER_DEFAULT_QUARANTINE_PREFIX);
- config->quarantine_prefix =
- VIRUSFILTER_DEFAULT_QUARANTINE_PREFIX;
- }
- sret = strstr(config->quarantine_suffix, "/");
- if (sret != NULL) {
- DBG_ERR("quarantine suffix must not contain directory "
- "delimiter(s) such as '/' (%s replaced with %s)\n",
- config->quarantine_suffix,
- VIRUSFILTER_DEFAULT_QUARANTINE_SUFFIX);
- config->quarantine_suffix =
- VIRUSFILTER_DEFAULT_QUARANTINE_SUFFIX;
+ if (config->quarantine_prefix != NULL) {
+ sret = strstr(config->quarantine_prefix, "/");
+ if (sret != NULL) {
+ DBG_ERR("quarantine prefix must not contain directory "
+ "delimiter(s) such as '/' (%s replaced with %s)\n",
+ config->quarantine_prefix,
+ VIRUSFILTER_DEFAULT_QUARANTINE_PREFIX);
+ config->quarantine_prefix =
+ VIRUSFILTER_DEFAULT_QUARANTINE_PREFIX;
+ }
+ }
+ if (config->quarantine_suffix != NULL) {
+ sret = strstr(config->quarantine_suffix, "/");
+ if (sret != NULL) {
+ DBG_ERR("quarantine suffix must not contain directory "
+ "delimiter(s) such as '/' (%s replaced with %s)\n",
+ config->quarantine_suffix,
+ VIRUSFILTER_DEFAULT_QUARANTINE_SUFFIX);
+ config->quarantine_suffix =
+ VIRUSFILTER_DEFAULT_QUARANTINE_SUFFIX;
+ }
}
config->quarantine_keep_tree = lp_parm_bool(
@@ -322,35 +368,53 @@
config->quarantine_keep_name = lp_parm_bool(
snum, "virusfilter", "quarantine keep name", true);
- config->rename_prefix = lp_parm_const_string(
+ rename_prefix = lp_parm_const_string(
snum, "virusfilter", "rename prefix",
VIRUSFILTER_DEFAULT_RENAME_PREFIX);
+ if (rename_prefix != NULL) {
+ config->rename_prefix = talloc_strdup(config, rename_prefix);
+ if (config->rename_prefix == NULL) {
+ DBG_ERR("virusfilter-vfs: out of memory!\n");
+ return -1;
+ }
+ }
- config->rename_suffix = lp_parm_const_string(
+ rename_suffix = lp_parm_const_string(
snum, "virusfilter", "rename suffix",
VIRUSFILTER_DEFAULT_RENAME_SUFFIX);
+ if (rename_suffix != NULL) {
+ config->rename_suffix = talloc_strdup(config, rename_suffix);
+ if (config->rename_suffix == NULL) {
+ DBG_ERR("virusfilter-vfs: out of memory!\n");
+ return -1;
+ }
+ }
/*
* Make sure prefixes and suffixes do not contain directory
* delimiters
*/
- sret = strstr(config->rename_prefix, "/");
- if (sret != NULL) {
- DBG_ERR("rename prefix must not contain directory "
- "delimiter(s) such as '/' (%s replaced with %s)\n",
- config->rename_prefix,
- VIRUSFILTER_DEFAULT_RENAME_PREFIX);
- config->rename_prefix =
- VIRUSFILTER_DEFAULT_RENAME_PREFIX;
- }
- sret = strstr(config->rename_suffix, "/");
- if (sret != NULL) {
- DBG_ERR("rename suffix must not contain directory "
- "delimiter(s) such as '/' (%s replaced with %s)\n",
- config->rename_suffix,
- VIRUSFILTER_DEFAULT_RENAME_SUFFIX);
- config->rename_suffix =
- VIRUSFILTER_DEFAULT_RENAME_SUFFIX;
+ if (config->rename_prefix != NULL) {
+ sret = strstr(config->rename_prefix, "/");
+ if (sret != NULL) {
+ DBG_ERR("rename prefix must not contain directory "
+ "delimiter(s) such as '/' (%s replaced with %s)\n",
+ config->rename_prefix,
+ VIRUSFILTER_DEFAULT_RENAME_PREFIX);
+ config->rename_prefix =
+ VIRUSFILTER_DEFAULT_RENAME_PREFIX;
+ }
+ }
+ if (config->rename_suffix != NULL) {
+ sret = strstr(config->rename_suffix, "/");
+ if (sret != NULL) {
+ DBG_ERR("rename suffix must not contain directory "
+ "delimiter(s) such as '/' (%s replaced with %s)\n",
+ config->rename_suffix,
+ VIRUSFILTER_DEFAULT_RENAME_SUFFIX);
+ config->rename_suffix =
+ VIRUSFILTER_DEFAULT_RENAME_SUFFIX;
+ }
}
config->infected_open_errno = lp_parm_int(
@@ -365,15 +429,22 @@
config->scan_error_close_errno = lp_parm_int(
snum, "virusfilter", "scan error errno on close", 0);
- config->socket_path = lp_parm_const_string(
+ socket_path = lp_parm_const_string(
snum, "virusfilter", "socket path", NULL);
+ if (socket_path != NULL) {
+ config->socket_path = talloc_strdup(config, socket_path);
+ if (config->socket_path == NULL) {
+ DBG_ERR("virusfilter-vfs: out of memory!\n");
+ return -1;
+ }
+ }
/* canonicalize socket_path */
if (config->socket_path != NULL && config->socket_path[0] != '/') {
DBG_ERR("socket path must be an absolute path. "
"Using backend default\n");
config->socket_path = NULL;
- }
+ }
if (config->socket_path != NULL) {
config->socket_path = canonicalize_absolute_path(
handle, config->socket_path);
diff -Nru samba-4.13.3+dfsg/source3/param/loadparm.c samba-4.13.14+dfsg/source3/param/loadparm.c
--- samba-4.13.3+dfsg/source3/param/loadparm.c 2020-12-15 07:53:45.000000000 +0000
+++ samba-4.13.14+dfsg/source3/param/loadparm.c 2021-11-08 11:29:14.000000000 +0000
@@ -960,6 +960,8 @@
Globals.ldap_max_authenticated_request_size = 16777216;
Globals.ldap_max_search_request_size = 256000;
+ Globals.min_domain_uid = 1000;
+
/* Now put back the settings that were set with lp_set_cmdline() */
apply_lp_set_cmdline();
}
@@ -4403,6 +4405,7 @@
default_server_announce |= SV_TYPE_DOMAIN_MEMBER;
break;
case ROLE_DOMAIN_PDC:
+ case ROLE_IPA_DC:
default_server_announce |= SV_TYPE_DOMAIN_CTRL;
break;
case ROLE_DOMAIN_BDC:
@@ -4428,7 +4431,8 @@
bool lp_domain_master(void)
{
if (Globals._domain_master == Auto)
- return (lp_server_role() == ROLE_DOMAIN_PDC);
+ return (lp_server_role() == ROLE_DOMAIN_PDC ||
+ lp_server_role() == ROLE_IPA_DC);
return (bool)Globals._domain_master;
}
diff -Nru samba-4.13.3+dfsg/source3/passdb/lookup_sid.c samba-4.13.14+dfsg/source3/passdb/lookup_sid.c
--- samba-4.13.3+dfsg/source3/passdb/lookup_sid.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/passdb/lookup_sid.c 2021-11-08 11:29:14.000000000 +0000
@@ -29,6 +29,7 @@
#include "../libcli/security/security.h"
#include "lib/winbind_util.h"
#include "../librpc/gen_ndr/idmap.h"
+#include "lib/util/bitmap.h"
static bool lookup_unix_user_name(const char *name, struct dom_sid *sid)
{
@@ -113,17 +114,36 @@
full_name, domain, name));
DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags));
- if (((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) &&
- strequal(domain, get_global_sam_name()))
- {
+ if ((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) {
+ bool check_global_sam = false;
- /* It's our own domain, lookup the name in passdb */
- if (lookup_global_sam_name(name, flags, &rid, &type)) {
- sid_compose(&sid, get_global_sam_sid(), rid);
- goto ok;
+ check_global_sam = strequal(domain, get_global_sam_name());
+
+ /* If we are running on a DC that has PASSDB module with domain
+ * information, check if DNS forest name is matching the domain
+ * name. This is the case of IPA domain controller when
+ * trusted AD DC looks up users found in a Global Catalog of
+ * the forest root domain. */
+ if (!check_global_sam && (IS_DC)) {
+ struct pdb_domain_info *dom_info = NULL;
+ dom_info = pdb_get_domain_info(tmp_ctx);
+
+ if ((dom_info != NULL) && (dom_info->dns_forest != NULL)) {
+ check_global_sam = strequal(domain, dom_info->dns_forest);
+ }
+
+ TALLOC_FREE(dom_info);
+ }
+
+ if (check_global_sam) {
+ /* It's our own domain, lookup the name in passdb */
+ if (lookup_global_sam_name(name, flags, &rid, &type)) {
+ sid_compose(&sid, get_global_sam_sid(), rid);
+ goto ok;
+ }
+ TALLOC_FREE(tmp_ctx);
+ return false;
}
- TALLOC_FREE(tmp_ctx);
- return false;
}
if ((flags & LOOKUP_NAME_BUILTIN) &&
@@ -1247,7 +1267,9 @@
{
struct wbcDomainSid *wbc_sids = NULL;
struct wbcUnixId *wbc_ids = NULL;
+ struct bitmap *found = NULL;
uint32_t i, num_not_cached;
+ uint32_t wbc_ids_size = 0;
wbcErr err;
bool ret = false;
@@ -1255,6 +1277,20 @@
if (wbc_sids == NULL) {
return false;
}
+ found = bitmap_talloc(wbc_sids, num_sids);
+ if (found == NULL) {
+ goto fail;
+ }
+
+ /*
+ * We go through the requested SID array three times.
+ * First time to look for global_sid_Unix_Users
+ * and global_sid_Unix_Groups SIDS, and to look
+ * for mappings cached in the idmap_cache.
+ *
+ * Use bitmap_set() to mark an ids[] array entry as
+ * being mapped.
+ */
num_not_cached = 0;
@@ -1266,17 +1302,20 @@
&sids[i], &rid)) {
ids[i].type = ID_TYPE_UID;
ids[i].id = rid;
+ bitmap_set(found, i);
continue;
}
if (sid_peek_check_rid(&global_sid_Unix_Groups,
&sids[i], &rid)) {
ids[i].type = ID_TYPE_GID;
ids[i].id = rid;
+ bitmap_set(found, i);
continue;
}
if (idmap_cache_find_sid2unixid(&sids[i], &ids[i], &expired)
&& !expired)
{
+ bitmap_set(found, i);
continue;
}
ids[i].type = ID_TYPE_NOT_SPECIFIED;
@@ -1287,66 +1326,132 @@
if (num_not_cached == 0) {
goto done;
}
- wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, num_not_cached);
+
+ /*
+ * For the ones that we couldn't map in the loop above, query winbindd
+ * via wbcSidsToUnixIds().
+ */
+
+ wbc_ids_size = num_not_cached;
+ wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, wbc_ids_size);
if (wbc_ids == NULL) {
goto fail;
}
- for (i=0; i id is a union anyway */
- ids[i].type = (enum id_type)wbc_ids[num_not_cached].type;
- ids[i].id = wbc_ids[num_not_cached].id.gid;
- break;
- }
- num_not_cached += 1;
+ if (bitmap_query(found, i)) {
+ continue;
}
+
+ SMB_ASSERT(num_not_cached < wbc_ids_size);
+
+ switch (wbc_ids[num_not_cached].type) {
+ case WBC_ID_TYPE_UID:
+ ids[i].type = ID_TYPE_UID;
+ ids[i].id = wbc_ids[num_not_cached].id.uid;
+ bitmap_set(found, i);
+ break;
+ case WBC_ID_TYPE_GID:
+ ids[i].type = ID_TYPE_GID;
+ ids[i].id = wbc_ids[num_not_cached].id.gid;
+ bitmap_set(found, i);
+ break;
+ case WBC_ID_TYPE_BOTH:
+ ids[i].type = ID_TYPE_BOTH;
+ ids[i].id = wbc_ids[num_not_cached].id.uid;
+ bitmap_set(found, i);
+ break;
+ case WBC_ID_TYPE_NOT_SPECIFIED:
+ /*
+ * wbcSidsToUnixIds() wasn't able to map this
+ * so we still need to check legacy_sid_to_XXX()
+ * below. Don't mark the bitmap entry
+ * as being found so the final loop knows
+ * to try and map this entry.
+ */
+ ids[i].type = ID_TYPE_NOT_SPECIFIED;
+ ids[i].id = (uint32_t)-1;
+ break;
+ default:
+ /*
+ * A successful return from wbcSidsToUnixIds()
+ * cannot return anything other than the values
+ * checked for above. Ensure this is so.
+ */
+ smb_panic(__location__);
+ break;
+ }
+ num_not_cached += 1;
}
+ /*
+ * Third and final time through the SID array,
+ * try legacy_sid_to_gid()/legacy_sid_to_uid()
+ * for entries we haven't already been able to
+ * map.
+ *
+ * Use bitmap_set() to mark an ids[] array entry as
+ * being mapped.
+ */
+
for (i=0; isalt_principal == NULL && r->out.domain_is_ad) {
char *p = NULL;
- ret = smb_krb5_salt_principal(info->domain_info.dns_domain.string,
- info->account_name,
- NULL /* userPrincipalName */,
- UF_WORKSTATION_TRUST_ACCOUNT,
- info, &p);
+ ret = smb_krb5_salt_principal_str(info->domain_info.dns_domain.string,
+ info->account_name,
+ NULL /* userPrincipalName */,
+ UF_WORKSTATION_TRUST_ACCOUNT,
+ info, &p);
if (ret != 0) {
status = krb5_to_nt_status(ret);
DBG_ERR("smb_krb5_salt_principal() failed "
diff -Nru samba-4.13.3+dfsg/source3/passdb/py_passdb.c samba-4.13.14+dfsg/source3/passdb/py_passdb.c
--- samba-4.13.3+dfsg/source3/passdb/py_passdb.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/passdb/py_passdb.c 2021-09-22 06:59:39.000000000 +0000
@@ -2075,8 +2075,6 @@
PyObject *py_gmap_list, *py_group_map;
int i;
- Py_INCREF(Py_None);
-
if (!PyArg_ParseTuple(args, "|O!ii:enum_group_mapping", dom_sid_Type, &py_domain_sid,
&lsa_sidtype_value, &unix_only)) {
talloc_free(frame);
@@ -2816,8 +2814,6 @@
PyObject *py_domain_sid = Py_None;
struct dom_sid *domain_sid = NULL;
- Py_INCREF(Py_None);
-
if (!PyArg_ParseTuple(args, "|O!:search_aliases", dom_sid_Type, &py_domain_sid)) {
talloc_free(frame);
return NULL;
diff -Nru samba-4.13.3+dfsg/source3/registry/reg_backend_db.c samba-4.13.14+dfsg/source3/registry/reg_backend_db.c
--- samba-4.13.3+dfsg/source3/registry/reg_backend_db.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/registry/reg_backend_db.c 2021-09-07 07:01:16.000000000 +0000
@@ -733,6 +733,15 @@
return WERR_OK;
}
+ /*
+ * Clustered Samba can only work as root because we need messaging to
+ * talk to ctdb which only works as root.
+ */
+ if (lp_clustering() && geteuid() != 0) {
+ DBG_ERR("Cluster mode requires running as root.\n");
+ return WERR_ACCESS_DENIED;
+ }
+
db_path = state_path(talloc_tos(), "registry.tdb");
if (db_path == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
diff -Nru samba-4.13.3+dfsg/source3/registry/reg_backend_prod_options.c samba-4.13.14+dfsg/source3/registry/reg_backend_prod_options.c
--- samba-4.13.3+dfsg/source3/registry/reg_backend_prod_options.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/registry/reg_backend_prod_options.c 2021-11-08 11:29:14.000000000 +0000
@@ -40,6 +40,7 @@
switch (lp_server_role()) {
case ROLE_DOMAIN_PDC:
case ROLE_DOMAIN_BDC:
+ case ROLE_IPA_DC:
value_ascii = "LanmanNT";
break;
case ROLE_STANDALONE:
diff -Nru samba-4.13.3+dfsg/source3/rpcclient/cmd_netlogon.c samba-4.13.14+dfsg/source3/rpcclient/cmd_netlogon.c
--- samba-4.13.3+dfsg/source3/rpcclient/cmd_netlogon.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/rpcclient/cmd_netlogon.c 2021-11-08 11:29:14.000000000 +0000
@@ -496,7 +496,7 @@
uint32_t logon_param = 0;
const char *workstation = NULL;
struct netr_SamInfo3 *info3 = NULL;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uint32_t flags = 0;
uint16_t validation_level;
union netr_Validation *validation = NULL;
diff -Nru samba-4.13.3+dfsg/source3/rpc_client/cli_pipe.c samba-4.13.14+dfsg/source3/rpc_client/cli_pipe.c
--- samba-4.13.3+dfsg/source3/rpc_client/cli_pipe.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/rpc_client/cli_pipe.c 2021-11-08 11:29:14.000000000 +0000
@@ -30,6 +30,7 @@
#include "librpc/gen_ndr/ndr_dcerpc.h"
#include "librpc/gen_ndr/ndr_netlogon_c.h"
#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_util.h"
#include "rpc_dce.h"
#include "cli_pipe.h"
#include "libsmb/libsmb.h"
diff -Nru samba-4.13.3+dfsg/source3/rpc_client/rpc_transport_np.c samba-4.13.14+dfsg/source3/rpc_client/rpc_transport_np.c
--- samba-4.13.3+dfsg/source3/rpc_client/rpc_transport_np.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/rpc_client/rpc_transport_np.c 2021-11-08 11:29:14.000000000 +0000
@@ -19,6 +19,7 @@
#include "includes.h"
#include "../lib/util/tevent_ntstatus.h"
+#include "librpc/rpc/dcerpc_util.h"
#include "rpc_client/rpc_transport.h"
#include "librpc/ndr/ndr_table.h"
#include "libcli/smb/smbXcli_base.h"
diff -Nru samba-4.13.3+dfsg/source3/rpc_server/dssetup/srv_dssetup_nt.c samba-4.13.14+dfsg/source3/rpc_server/dssetup/srv_dssetup_nt.c
--- samba-4.13.3+dfsg/source3/rpc_server/dssetup/srv_dssetup_nt.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/rpc_server/dssetup/srv_dssetup_nt.c 2021-11-08 11:29:14.000000000 +0000
@@ -63,6 +63,7 @@
basic->domain = get_global_sam_name();
break;
case ROLE_DOMAIN_PDC:
+ case ROLE_IPA_DC:
basic->role = DS_ROLE_PRIMARY_DC;
basic->domain = get_global_sam_name();
break;
diff -Nru samba-4.13.3+dfsg/source3/rpc_server/mdssvc/mdssvc.c samba-4.13.14+dfsg/source3/rpc_server/mdssvc/mdssvc.c
--- samba-4.13.3+dfsg/source3/rpc_server/mdssvc/mdssvc.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/rpc_server/mdssvc/mdssvc.c 2021-08-09 07:20:55.000000000 +0000
@@ -19,6 +19,7 @@
*/
#include "includes.h"
+#include "smbd/proto.h"
#include "librpc/gen_ndr/auth.h"
#include "dbwrap/dbwrap.h"
#include "lib/util/dlinklist.h"
@@ -26,6 +27,7 @@
#include "lib/util/time_basic.h"
#include "lib/dbwrap/dbwrap_rbt.h"
#include "libcli/security/dom_sid.h"
+#include "libcli/security/security.h"
#include "mdssvc.h"
#include "mdssvc_noindex.h"
#ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
@@ -512,11 +514,25 @@
bool mds_add_result(struct sl_query *slq, const char *path)
{
+ struct smb_filename *smb_fname = NULL;
struct stat_ex sb;
+ uint32_t attr;
uint64_t ino64;
int result;
+ NTSTATUS status;
bool ok;
+ smb_fname = synthetic_smb_fname(talloc_tos(),
+ path,
+ NULL,
+ NULL,
+ 0,
+ 0);
+ if (smb_fname == NULL) {
+ DBG_ERR("synthetic_smb_fname() failed\n");
+ return false;
+ }
+
/*
* We're in a tevent callback which means in the case of
* running as external RPC service we're running as root and
@@ -538,33 +554,59 @@
* any function exit below must ensure we switch back
*/
- result = sys_stat(path, &sb, false);
+ result = SMB_VFS_STAT(slq->mds_ctx->conn, smb_fname);
if (result != 0) {
+ DBG_DEBUG("SMB_VFS_STAT [%s] failed: %s\n",
+ smb_fname_str_dbg(smb_fname),
+ strerror(errno));
unbecome_authenticated_pipe_user();
+ TALLOC_FREE(smb_fname);
return true;
}
- result = access(path, R_OK);
- if (result != 0) {
+
+ status = smbd_check_access_rights(slq->mds_ctx->conn,
+ slq->mds_ctx->conn->cwd_fsp,
+ smb_fname,
+ false,
+ FILE_READ_DATA);
+ if (!NT_STATUS_IS_OK(status)) {
unbecome_authenticated_pipe_user();
+ TALLOC_FREE(smb_fname);
return true;
}
+ /* This is needed to fetch the itime from the DOS attribute blob */
+ status = SMB_VFS_GET_DOS_ATTRIBUTES(slq->mds_ctx->conn,
+ smb_fname,
+ &attr);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* Ignore the error, likely no DOS attr xattr */
+ DBG_DEBUG("SMB_VFS_FGET_DOS_ATTRIBUTES [%s]: %s\n",
+ smb_fname_str_dbg(smb_fname),
+ nt_errstr(status));
+ }
+
unbecome_authenticated_pipe_user();
- ino64 = sb.st_ex_ino;
+ sb = smb_fname->st;
+ TALLOC_FREE(smb_fname);
+ ino64 = SMB_VFS_FS_FILE_ID(slq->mds_ctx->conn, &sb);
+
if (slq->cnids) {
+ bool found;
+
/*
* Check whether the found element is in the requested
* set of IDs. Note that we're faking CNIDs by using
* filesystem inode numbers here
*/
- ok = bsearch(&ino64,
- slq->cnids,
- slq->cnids_num,
- sizeof(uint64_t),
- cnid_comp_fn);
- if (!ok) {
- return false;
+ found = bsearch(&ino64,
+ slq->cnids,
+ slq->cnids_num,
+ sizeof(uint64_t),
+ cnid_comp_fn);
+ if (!found) {
+ return true;
}
}
@@ -1230,7 +1272,7 @@
sl_array_t *fm_array;
sl_nil_t nil;
char *path = NULL;
- struct stat_ex sb = {0};
+ struct smb_filename *smb_fname = NULL;
struct stat_ex *sp = NULL;
struct sl_inode_path_map *elem = NULL;
void *p;
@@ -1299,11 +1341,23 @@
elem = talloc_get_type_abort(p, struct sl_inode_path_map);
path = elem->path;
- result = sys_stat(path, &sb, false);
+ smb_fname = synthetic_smb_fname(talloc_tos(),
+ path,
+ NULL,
+ NULL,
+ 0,
+ 0);
+ if (smb_fname == NULL) {
+ DBG_ERR("synthetic_smb_fname() failed\n");
+ goto error;
+ }
+
+ result = SMB_VFS_STAT(mds_ctx->conn, smb_fname);
if (result != 0) {
goto error;
}
- sp = &sb;
+
+ sp = &smb_fname->st;
}
ok = add_filemeta(mds_ctx, reqinfo, fm_array, path, sp);
@@ -1333,9 +1387,12 @@
goto error;
}
+ TALLOC_FREE(smb_fname);
return true;
error:
+
+ TALLOC_FREE(smb_fname);
sl_result = UINT64_MAX;
result = dalloc_add_copy(array, &sl_result, uint64_t);
if (result != 0) {
@@ -1522,15 +1579,21 @@
**/
struct mds_ctx *mds_init_ctx(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
+ struct messaging_context *msg_ctx,
struct auth_session_info *session_info,
int snum,
const char *sharename,
const char *path)
{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
+ struct smb_filename conn_basedir;
struct mds_ctx *mds_ctx;
int backend;
+ int ret;
bool ok;
smb_iconv_t iconv_hnd = (smb_iconv_t)-1;
+ NTSTATUS status;
mds_ctx = talloc_zero(mem_ctx, struct mds_ctx);
if (mds_ctx == NULL) {
@@ -1612,6 +1675,30 @@
goto error;
}
+ status = create_conn_struct_cwd(mds_ctx,
+ ev,
+ msg_ctx,
+ session_info,
+ snum,
+ lp_path(talloc_tos(), lp_sub, snum),
+ &mds_ctx->conn);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("failed to create conn for vfs: %s\n",
+ nt_errstr(status));
+ goto error;
+ }
+
+ conn_basedir = (struct smb_filename) {
+ .base_name = mds_ctx->conn->connectpath,
+ };
+
+ ret = vfs_ChDir(mds_ctx->conn, &conn_basedir);
+ if (ret != 0) {
+ DBG_ERR("vfs_ChDir [%s] failed: %s\n",
+ conn_basedir.base_name, strerror(errno));
+ goto error;
+ }
+
ok = mds_ctx->backend->connect(mds_ctx);
if (!ok) {
DBG_ERR("backend connect failed\n");
@@ -1640,11 +1727,15 @@
struct mdssvc_blob *response_blob)
{
bool ok;
+ int ret;
ssize_t len;
DALLOC_CTX *query = NULL;
DALLOC_CTX *reply = NULL;
char *rpccmd;
const struct slrpc_cmd *slcmd;
+ const struct smb_filename conn_basedir = {
+ .base_name = mds_ctx->conn->connectpath,
+ };
if (CHECK_DEBUGLVL(10)) {
const struct sl_query *slq;
@@ -1695,6 +1786,14 @@
ok = false;
goto cleanup;
}
+
+ ret = vfs_ChDir(mds_ctx->conn, &conn_basedir);
+ if (ret != 0) {
+ DBG_ERR("vfs_ChDir [%s] failed: %s\n",
+ conn_basedir.base_name, strerror(errno));
+ ok = false;
+ goto cleanup;
+ }
ok = slcmd->function(mds_ctx, query, reply);
if (ok) {
diff -Nru samba-4.13.3+dfsg/source3/rpc_server/mdssvc/mdssvc.h samba-4.13.14+dfsg/source3/rpc_server/mdssvc/mdssvc.h
--- samba-4.13.3+dfsg/source3/rpc_server/mdssvc/mdssvc.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/rpc_server/mdssvc/mdssvc.h 2021-08-06 12:19:57.000000000 +0000
@@ -126,6 +126,7 @@
int snum;
const char *sharename;
const char *spath;
+ struct connection_struct *conn;
struct sl_query *query_list; /* list of active queries */
struct db_context *ino_path_map; /* dbwrap rbt for storing inode->path mappings */
};
@@ -150,6 +151,7 @@
extern bool mds_shutdown(void);
struct mds_ctx *mds_init_ctx(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
+ struct messaging_context *msg_ctx,
struct auth_session_info *session_info,
int snum,
const char *sharename,
diff -Nru samba-4.13.3+dfsg/source3/rpc_server/mdssvc/srv_mdssvc_nt.c samba-4.13.14+dfsg/source3/rpc_server/mdssvc/srv_mdssvc_nt.c
--- samba-4.13.3+dfsg/source3/rpc_server/mdssvc/srv_mdssvc_nt.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/rpc_server/mdssvc/srv_mdssvc_nt.c 2021-08-09 07:20:55.000000000 +0000
@@ -95,6 +95,7 @@
mds_ctx = mds_init_ctx(mem_ctx,
messaging_tevent_context(p->msg_ctx),
+ p->msg_ctx,
p->session_info,
snum,
sharename,
diff -Nru samba-4.13.3+dfsg/source3/rpc_server/rpc_handles.c samba-4.13.14+dfsg/source3/rpc_server/rpc_handles.c
--- samba-4.13.3+dfsg/source3/rpc_server/rpc_handles.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/rpc_server/rpc_handles.c 2021-09-07 07:01:16.000000000 +0000
@@ -60,12 +60,6 @@
return ENOMEM;
}
- p->mem_ctx = talloc_named(p, 0, "pipe %s %p", pipe_name, p);
- if (!p->mem_ctx) {
- talloc_free(p);
- return ENOMEM;
- }
-
p->msg_ctx = msg_ctx;
p->transport = transport;
@@ -109,18 +103,36 @@
data_ptr is TALLOC_FREE()'ed
****************************************************************************/
+struct hnd_cnt {
+ bool _dummy;
+};
+
+static int hnd_cnt_destructor(struct hnd_cnt *cnt)
+{
+ num_handles--;
+ return 0;
+}
+
bool create_policy_hnd(struct pipes_struct *p,
struct policy_handle *hnd,
uint8_t handle_type,
void *data_ptr)
{
struct dcesrv_handle *rpc_hnd = NULL;
+ struct hnd_cnt *cnt = NULL;
rpc_hnd = dcesrv_handle_create(p->dce_call, handle_type);
if (rpc_hnd == NULL) {
return false;
}
+ cnt = talloc_zero(rpc_hnd, struct hnd_cnt);
+ if (cnt == NULL) {
+ TALLOC_FREE(rpc_hnd);
+ return false;
+ }
+ talloc_set_destructor(cnt, hnd_cnt_destructor);
+
if (data_ptr != NULL) {
rpc_hnd->data = talloc_move(rpc_hnd, &data_ptr);
}
@@ -210,8 +222,6 @@
TALLOC_FREE(rpc_hnd);
- num_handles--;
-
return true;
}
diff -Nru samba-4.13.3+dfsg/source3/rpc_server/rpc_ncacn_np.c samba-4.13.14+dfsg/source3/rpc_server/rpc_ncacn_np.c
--- samba-4.13.3+dfsg/source3/rpc_server/rpc_ncacn_np.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/rpc_server/rpc_ncacn_np.c 2021-11-08 11:29:14.000000000 +0000
@@ -37,6 +37,7 @@
#include "rpc_server/rpc_config.h"
#include "librpc/ndr/ndr_table.h"
#include "rpc_server/rpc_server.h"
+#include "librpc/rpc/dcerpc_util.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_SRV
@@ -541,7 +542,7 @@
return tevent_req_post(req, ev);
}
- state->call = talloc_zero(hs->conn, struct dcesrv_call_state);
+ state->call = talloc_zero(state, struct dcesrv_call_state);
if (tevent_req_nomem(state->call, req)) {
return tevent_req_post(req, ev);
}
diff -Nru samba-4.13.3+dfsg/source3/rpc_server/spoolss/srv_iremotewinspool.c samba-4.13.14+dfsg/source3/rpc_server/spoolss/srv_iremotewinspool.c
--- samba-4.13.3+dfsg/source3/rpc_server/spoolss/srv_iremotewinspool.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/rpc_server/spoolss/srv_iremotewinspool.c 2021-08-06 12:19:57.000000000 +0000
@@ -100,6 +100,7 @@
/* Update pipes struct opnum */
p->opnum = opnum;
p->dce_call = dce_call;
+ p->mem_ctx = mem_ctx;
/* Update pipes struct session info */
pipe_session_info = p->session_info;
p->session_info = dce_call->auth_state->session_info;
@@ -1238,6 +1239,7 @@
}
p->dce_call = NULL;
+ p->mem_ctx = NULL;
/* Restore session info */
p->session_info = pipe_session_info;
p->auth.auth_type = 0;
diff -Nru samba-4.13.3+dfsg/source3/rpc_server/spoolss/srv_spoolss_nt.c samba-4.13.14+dfsg/source3/rpc_server/spoolss/srv_spoolss_nt.c
--- samba-4.13.3+dfsg/source3/rpc_server/spoolss/srv_spoolss_nt.c 2020-12-15 07:53:45.000000000 +0000
+++ samba-4.13.14+dfsg/source3/rpc_server/spoolss/srv_spoolss_nt.c 2021-08-09 07:20:55.000000000 +0000
@@ -5738,7 +5738,8 @@
}
if (pinfo2->drivername == NULL || pinfo2->drivername[0] == '\0') {
- return WERR_UNKNOWN_PRINTER_DRIVER;
+ result = WERR_UNKNOWN_PRINTER_DRIVER;
+ goto done;
}
DBG_INFO("Construct printer driver [%s] for [%s]\n",
@@ -7030,7 +7031,8 @@
raddr = tsocket_address_inet_addr_string(p->remote_address,
p->mem_ctx);
if (raddr == NULL) {
- return WERR_NOT_ENOUGH_MEMORY;
+ result = WERR_NOT_ENOUGH_MEMORY;
+ goto done;
}
/* add_printer_hook() will call reload_services() */
diff -Nru samba-4.13.3+dfsg/source3/script/tests/test_deadtime.sh samba-4.13.14+dfsg/source3/script/tests/test_deadtime.sh
--- samba-4.13.3+dfsg/source3/script/tests/test_deadtime.sh 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/source3/script/tests/test_deadtime.sh 2021-09-07 07:01:16.000000000 +0000
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+#
+# Test deadtime parameter
+#
+
+if [ $# -lt 1 ]; then
+ echo Usage: test_deadtime.sh IP
+ exit 1
+fi
+
+server=$1
+
+incdir=`dirname $0`/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+failed=0
+
+smbclient="$BINDIR/smbclient"
+smbcontrol="$BINDIR/smbcontrol"
+
+global_inject_conf=$(dirname $SMB_CONF_PATH)/global_inject.conf
+
+echo "deadtime = 1" > $global_inject_conf
+$smbcontrol smbd reload-config
+
+cd $SELFTEST_TMPDIR || exit 1
+
+# Create the smbclient communication pipes.
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+mkfifo smbclient-stdin smbclient-stdout smbclient-stderr
+
+export CLI_FORCE_INTERACTIVE=1
+export SAMBA_DEPRECATED_SUPPRESS=1
+
+# This gets inherited by smbclient and is required to smbclient doesn't get
+# killed by an unhandled SIGPIPE when writing an SMB2 KEEPALIVE packet to the
+# connection fd that was already closed by the server.
+trap "" SIGPIPE
+
+$smbclient //$server/tmp -U${USER}%${PASSWORD} \
+ < smbclient-stdin > smbclient-stdout 2>smbclient-stderr &
+client_pid=$!
+
+sleep 1
+
+exec 100>smbclient-stdin 101 $global_inject_conf
+$smbcontrol smbd reload-config
+
+rm -f smbclient-stdin smbclient-stdout smbclient-stderr
+
+testok $0 $failed
diff -Nru samba-4.13.3+dfsg/source3/script/tests/test_force_user_unlink.sh samba-4.13.14+dfsg/source3/script/tests/test_force_user_unlink.sh
--- samba-4.13.3+dfsg/source3/script/tests/test_force_user_unlink.sh 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/source3/script/tests/test_force_user_unlink.sh 2021-08-06 12:19:57.000000000 +0000
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# Test unlink on share with "force user"
+#
+# Copyright (C) 2021 Ralph Boehme
+
+incdir=$(dirname $0)/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+smbclient="$BINDIR/smbclient"
+error_inject_conf=$(dirname ${SMB_CONF_PATH})/error_inject.conf
+failed=0
+
+test_forced_user_can_delete() {
+ out=$($smbclient -U $DOMAIN/$USERNAME%$PASSWORD //$SERVER_IP/force_user_error_inject -c "rm dir/file")
+ if [ $? -ne 0 ] ; then
+ echo $out
+ return 1
+ fi
+ tmp=$(echo $out | grep NT_STATUS_ )
+ if [ $? -eq 0 ] ; then
+ return 1
+ fi
+ return 0
+}
+
+echo "error_inject:unlinkat = EACCES" > ${error_inject_conf}
+
+$smbclient -U $DOMAIN/$USERNAME%$PASSWORD //$SERVER_IP/force_user_error_inject -c "mkdir dir" || failed=`expr $failed + 1`
+$smbclient -U $DOMAIN/$USERNAME%$PASSWORD //$SERVER_IP/force_user_error_inject -c "put WHATSNEW.txt dir/file" || failed=`expr $failed + 1`
+
+testit "test_forced_user_can_delete" test_forced_user_can_delete || failed=`expr $failed + 1`
+
+rm ${error_inject_conf}
+
+# Clean up after ourselves.
+$smbclient -U $DOMAIN/$USERNAME%$PASSWORD //$SERVER_IP/force_user_error_inject -c "del dir/file; rmdir dir"
+
+testok $0 $failed
diff -Nru samba-4.13.3+dfsg/source3/script/tests/test_net_rpc_share_allowedusers.sh samba-4.13.14+dfsg/source3/script/tests/test_net_rpc_share_allowedusers.sh
--- samba-4.13.3+dfsg/source3/script/tests/test_net_rpc_share_allowedusers.sh 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/script/tests/test_net_rpc_share_allowedusers.sh 2021-08-06 12:19:57.000000000 +0000
@@ -26,5 +26,25 @@
testit_grep "net_rpc_share_allowedusers" '^print\$$' $net usersidlist | $VALGRIND $net rpc share allowedusers -S$SERVER -U$USERNAME%$PASSWORD $ADDARGS - 'print$' || failed=`expr $failed + 1`
# Check user "user1" is allowed to read share "tmp".
testit_grep "net_rpc_share_allowedusers" '^ user1$' $net usersidlist | $VALGRIND $net rpc share allowedusers -S$SERVER -U$USERNAME%$PASSWORD $ADDARGS || failed=`expr $failed + 1`
+#
+# Subtle extra test for bug https://bugzilla.samba.org/show_bug.cgi?id=13992
+#
+# '^ user1$' must appear MORE THAN ONCE, as it can read more than one
+# share. The previous test found user1, but only once as the bug only
+# allows reading the security descriptor for one share, and we were
+# unlucky that the first share security descriptor returned allows
+# user1 to read from it.
+#
+subunit_start_test "net_rpc_share_allowedusers"
+multi_userout=`$net usersidlist | $VALGRIND $net rpc share allowedusers -S$SERVER -U$USERNAME%$PASSWORD $ADDARGS`
+num_matches=`echo "$multi_userout" | grep -c '^ user1$'`
+if [ "$num_matches" -gt "1" ]
+then
+ subunit_pass_test "net_rpc_share_allowedusers"
+else
+ echo "net_rpc_share_allowedusers only found $num_matches shares readable by user1. Should be greater than one.\n"
+ failed=`expr $failed + 1`
+ echo "$multi_userout" | subunit_fail_test "net_rpc_share_allowedusers"
+fi
testok $0 $failed
diff -Nru samba-4.13.3+dfsg/source3/script/tests/test_winbind_ignore_domains.sh samba-4.13.14+dfsg/source3/script/tests/test_winbind_ignore_domains.sh
--- samba-4.13.3+dfsg/source3/script/tests/test_winbind_ignore_domains.sh 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/source3/script/tests/test_winbind_ignore_domains.sh 2021-08-06 12:19:57.000000000 +0000
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+incdir=`dirname $0`/../../../testprogs/blackbox
+. $incdir/subunit.sh
+. $incdir/common_test_fns.inc
+
+failed=0
+
+smbclient="$BINDIR/smbclient"
+smbcontrol="$BINDIR/smbcontrol"
+ldbmodify="$BINDIR/ldbmodify"
+ldbsearch="$BINDIR/ldbsearch"
+wbinfo="$BINDIR/wbinfo"
+global_inject_conf=$(dirname $SMB_CONF_PATH)/global_inject.conf
+SERVER_FQDN=$(echo "$SERVER.$REALM" | awk '{print tolower($0)}')
+
+TRUST_BASE_DN=$($ldbsearch -H ldap://$TRUST_SERVER -b "" -s base defaultNamingContext | awk '/^defaultNamingContext/ {print $2}')
+if [ $? -ne 0 ] ; then
+ echo "Could not find trusted base DN" | subunit_fail_test "test_idmap_ad"
+ exit 1
+fi
+
+#
+# Add POSIX ids to trusted domain
+#
+add_posix_ids() {
+cat < $global_inject_conf
+$smbcontrol winbindd reload-config
+$wbinfo -p
+
+test_smbclient "test_winbind_ignore_domains_ok_ntlm_ip" "ls" "//$SERVER_IP/tmp" -U $TRUST_DOMAIN/$TRUST_USERNAME%$TRUST_PASSWORD || failed=`expr $failed + 1`
+test_smbclient "test_winbind_ignore_domains_ok_ntlm_fqdn" "ls" "//$SERVER_FQDN/tmp" -U $TRUST_DOMAIN/$TRUST_USERNAME%$TRUST_PASSWORD || failed=`expr $failed + 1`
+test_smbclient "test_winbind_ignore_domains_ok_krb5" "ls" "//$SERVER_FQDN/tmp" -U $TRUST_USERNAME@$TRUST_REALM%$TRUST_PASSWORD -k || failed=`expr $failed + 1`
+
+echo "winbind:ignore domains = $TRUST_DOMAIN" > $global_inject_conf
+$smbcontrol winbindd reload-config
+$wbinfo -p
+
+test_smbclient_expect_failure "test_winbind_ignore_domains_fail_ntlm_ip" "ls" "//$SERVER_IP/tmp" -U $TRUST_DOMAIN/$TRUST_USERNAME%$TRUST_PASSWORD || failed=`expr $failed + 1`
+test_smbclient_expect_failure "test_winbind_ignore_domains_fail_ntlm_fqdn" "ls" "//$SERVER_FQDN/tmp" -U $TRUST_DOMAIN/$TRUST_USERNAME%$TRUST_PASSWORD || failed=`expr $failed + 1`
+test_smbclient_expect_failure "test_winbind_ignore_domains_fail_krb5" "ls" "//$SERVER_FQDN/tmp" -U $TRUST_USERNAME@$TRUST_REALM%$TRUST_PASSWORD -k || failed=`expr $failed + 1`
+
+echo "" > $global_inject_conf
+$smbcontrol winbindd reload-config
+$wbinfo -p
+remove_posix_ids
+
+testok $0 $failed
diff -Nru samba-4.13.3+dfsg/source3/selftest/ktest-krb5_ccache-2.txt samba-4.13.14+dfsg/source3/selftest/ktest-krb5_ccache-2.txt
--- samba-4.13.3+dfsg/source3/selftest/ktest-krb5_ccache-2.txt 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/source3/selftest/ktest-krb5_ccache-2.txt 2021-09-22 06:59:39.000000000 +0000
@@ -0,0 +1,1574 @@
+pull returned Success
+ CCACHE: struct CCACHE
+ pvno : 0x05 (5)
+ version : 0x04 (4)
+ optional_header : union OPTIONAL_HEADER(case 0x4)
+ v4header: struct V4HEADER
+ v4tags: struct V4TAGS
+ tag: struct V4TAG
+ tag : 0x0001 (1)
+ field : union FIELD(case 0x1)
+ deltatime_tag: struct DELTATIME_TAG
+ kdc_sec_offset : 0
+ kdc_usec_offset : 0
+ further_tags : DATA_BLOB length=0
+ principal: struct PRINCIPAL
+ name_type : 0x00000001 (1)
+ component_count : 0x00000001 (1)
+ realm : 'KTEST.SAMBA.EXAMPLE.COM'
+ components: ARRAY(1)
+ components : 'administrator'
+ cred: struct CREDENTIAL
+ client: struct PRINCIPAL
+ name_type : 0x00000001 (1)
+ component_count : 0x00000001 (1)
+ realm : 'KTEST.SAMBA.EXAMPLE.COM'
+ components: ARRAY(1)
+ components : 'administrator'
+ server: struct PRINCIPAL
+ name_type : 0x00000000 (0)
+ component_count : 0x00000002 (2)
+ realm : 'KTEST.SAMBA.EXAMPLE.COM'
+ components: ARRAY(2)
+ components : 'krbtgt'
+ components : 'KTEST.SAMBA.EXAMPLE.COM'
+ keyblock: struct KEYBLOCK
+ enctype : 0x0017 (23)
+ data : DATA_BLOB length=16
+[0000] 8B 94 0B 31 51 5B F7 A7 15 E9 EE D7 D7 0C 8C 90 ...1Q[.. ........
+ authtime : 0x4d994f6a (1301892970)
+ starttime : 0x4d994f6a (1301892970)
+ endtime : 0x7d440b68 (2101611368)
+ renew_till : 0x7d440b68 (2101611368)
+ is_skey : 0x00 (0)
+ ticket_flags : 0x40e00000 (1088421888)
+ addresses: struct ADDRESSES
+ count : 0x00000000 (0)
+ data: ARRAY(0)
+ authdata: struct AUTHDATA
+ count : 0x00000000 (0)
+ data: ARRAY(0)
+ ticket : DATA_BLOB length=1032
+[0000] 61 82 04 04 30 82 04 00 A0 03 02 01 05 A1 19 1B a...0... ........
+[0010] 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 .KTEST.S AMBA.EXA
+[0020] 4D 50 4C 45 2E 43 4F 4D A2 2C 30 2A A0 03 02 01 MPLE.COM .,0*....
+[0030] 00 A1 23 30 21 1B 06 6B 72 62 74 67 74 1B 17 4B ..#0!..k rbtgt..K
+[0040] 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 TEST.SAM BA.EXAMP
+[0050] 4C 45 2E 43 4F 4D A3 82 03 AE 30 82 03 AA A0 03 LE.COM.. ..0.....
+[0060] 02 01 17 A1 03 02 01 01 A2 82 03 9C 04 82 03 98 ........ ........
+[0070] 80 66 8F CF AB 24 9D C8 76 E4 28 F5 25 6B 73 B2 .f...$.. v.(.%ks.
+[0080] 4B 94 ED 09 10 29 05 C4 C0 B8 B9 33 FA C4 46 AB K....).. ...3..F.
+[0090] F4 B5 9E 5B 07 54 D6 58 1D B8 CA 04 41 A6 33 A6 ...[.T.X ....A.3.
+[00A0] 67 9D EB 83 70 65 A9 2D 65 A5 19 8C 55 2A 0F FC g...pe.- e...U*..
+[00B0] 1B BB 7A BD 86 C0 32 06 F2 2F 0A A5 93 E7 D1 1E ..z...2. ./......
+[00C0] 16 C4 27 DD 1F A7 61 03 FF 05 81 EF 49 B7 25 A3 ..'...a. ....I.%.
+[00D0] 6E EA E6 E8 15 E3 10 AF A3 F1 21 B3 D9 C0 67 2F n....... ..!...g/
+[00E0] 0C 0C B7 42 D6 9A 34 8E D4 5E 55 C2 FE 62 03 37 ...B..4. .^U..b.7
+[00F0] A5 58 9B 43 E7 26 E3 71 B2 E5 F1 91 B4 23 8F AC .X.C.&.q .....#..
+[0100] 7A 31 3C 4E B4 94 E4 81 36 98 71 3B 98 7B B7 AB z1.......
+[0150] 1A 69 EE 8C 4E A4 D8 55 A5 0B 23 0F D0 89 48 C4 .i..N..U ..#...H.
+[0160] 51 FE 32 FD CC F6 71 E1 95 2D CC 1D 0A 0C 8A A2 Q.2...q. .-......
+[0170] 69 58 3B 65 88 53 EC D0 2E E1 C6 CC 6B BC 09 E5 iX;e.S.. ....k...
+[0180] B9 15 27 8B E4 B2 24 18 61 42 BB 8B 09 1B 8A 7B ..'...$. aB.....{
+[0190] 13 D8 51 E1 0B 79 12 48 DE A9 54 04 00 6D DD E6 ..Q..y.H ..T..m..
+[01A0] 5E 03 91 FF C7 6D 0B 7C 91 44 E1 0F C0 7E 32 34 ^....m.| .D...~24
+[01B0] 82 86 94 F7 CD 53 EC 52 38 18 AA ED FF FC 5C 01 .....S.R 8.....\.
+[01C0] D2 EE 99 45 8E 5B E6 B3 46 B0 F6 3B 22 29 EC 11 ...E.[.. F..;")..
+[01D0] 30 6A F6 A1 1F 9E AE 71 E3 A6 E7 3F F3 7D 2B 75 0j.....q ...?.}+u
+[01E0] 70 4D 63 47 5C 18 2C 8B B1 1A 69 B6 C5 46 01 17 pMcG\.,. ..i..F..
+[01F0] 8E 64 3D 47 88 20 1C AA D7 60 32 28 11 60 EA 28 .d=G. .. .`2(.`.(
+[0200] 66 99 4C B1 2A 28 96 BF 18 2A 3E F4 D6 84 E5 A0 f.L.*(.. .*>.....
+[0210] F4 4E E7 F9 54 95 22 96 2A 87 01 CC 3E A7 FF 42 .N..T.". *...>..B
+[0220] 6A A4 4A 3A B9 24 10 65 99 53 58 2A 4E 72 E7 1F j.J:.$.e .SX*Nr..
+[0230] 82 BC BD 3C 6C 9D 33 3A CE C6 6E 72 A2 81 B3 84 ........
+[0280] AB F0 D0 93 08 42 E5 37 19 24 4E C1 AF FC 92 A9 .....B.7 .$N.....
+[0290] B1 27 B1 9A 2A 62 34 F1 DC C0 6B 83 AE C3 74 E8 .'..*b4. ..k...t.
+[02A0] A3 05 DD 82 DD A3 D7 90 A8 E3 9C EB 64 16 23 06 ........ ....d.#.
+[02B0] 5D FB E4 35 7C 22 29 78 E3 3B 75 92 91 0C 9D A1 ]..5|")x .;u.....
+[02C0] 87 7C 2E 82 AE 49 9D 4A 50 A9 C2 D5 85 B0 16 5D .|...I.J P......]
+[02D0] A2 CD B0 DD 29 3F 6F 66 C9 C1 9F 5C F0 B6 FC D2 ....)?of ...\....
+[02E0] 52 BE 7B F0 1F 26 AF 8A FC C3 A6 24 8C C0 10 06 R.{..&.. ...$....
+[02F0] 73 1E 17 9E 6E 6F 32 44 6A DF 82 5D D0 6B 74 CE s...no2D j..].kt.
+[0300] 58 0B 4C 7B EB A1 13 44 B1 3E D8 F8 BA F4 4E 55 X.L{...D .>....NU
+[0310] 71 3D C1 09 D9 E7 97 9A 14 5C 54 7E 57 81 5F 6B q=...... .\T~W._k
+[0320] 30 BE 9A E1 98 29 47 D4 C0 8F 63 0A F8 27 1F CE 0....)G. ..c..'..
+[0330] ED D9 BB 7B 12 24 D0 34 2A 7C F0 F7 77 F4 F1 1D ...{.$.4 *|..w...
+[0340] 4C 5D 75 2D 6B 0D 80 35 82 CC D8 7A 6B FA A0 55 L]u-k..5 ...zk..U
+[0350] 34 CD 87 15 61 38 78 D4 69 0F AA 72 D6 AC FA 99 4...a8x. i..r....
+[0360] BC 70 39 27 A7 25 2E 1B 6F 36 01 FD E9 B4 9A 79 .p9'.%.. o6.....y
+[0370] 6C 19 DD A6 8C 78 B0 40 92 60 58 F0 28 AD 08 78 l....x.@ .`X.(..x
+[0380] 4A 29 06 2C 82 2B 1A E3 91 0B 5F EE D6 B8 66 47 J).,.+.. .._...fG
+[0390] 31 9B A3 DF 9F 79 D7 BB 0E 2C FA 0E C9 66 84 8D 1....y.. .,...f..
+[03A0] FF BA BB 21 27 9E AD 86 84 55 8D 4C 4C 47 D9 5F ...!'... .U.LLG._
+[03B0] B2 7D 26 CA B7 49 3C 9D 1B 67 71 11 3A 8A EB EA .}&..I<. .gq.:...
+[03C0] 0F 15 EB F0 1E 46 F7 A4 34 04 D7 E3 50 67 47 D3 .....F.. 4...PgG.
+[03D0] 66 21 17 77 51 A7 1F 1D 84 3B 7C B1 5D 4E B8 D4 f!.wQ... .;|.]N..
+[03E0] F9 C5 75 06 AA 19 45 1C E9 06 9E AD 23 26 6B 10 ..u...E. ....#&k.
+[03F0] 53 A0 36 D3 58 9F 5E 8C CB A5 F6 BC C9 30 3C BC S.6.X.^. .....0<.
+[0400] AD FF 7C 92 F0 C6 9A 02 ..|.....
+ second_ticket : DATA_BLOB length=0
+ further_creds : DATA_BLOB length=10683
+[0000] 00 00 00 01 00 00 00 01 00 00 00 17 4B 54 45 53 ........ ....KTES
+[0010] 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E T.SAMBA. EXAMPLE.
+[0020] 43 4F 4D 00 00 00 0D 61 64 6D 69 6E 69 73 74 72 COM....a dministr
+[0030] 61 74 6F 72 00 00 00 01 00 00 00 02 00 00 00 17 ator.... ........
+[0040] 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D KTEST.SA MBA.EXAM
+[0050] 50 4C 45 2E 43 4F 4D 00 00 00 04 63 69 66 73 00 PLE.COM. ...cifs.
+[0060] 00 00 0B 6C 6F 63 61 6C 6B 74 65 73 74 36 00 17 ...local ktest6..
+[0070] 00 00 00 10 00 6E A1 B2 31 6D 48 C7 90 72 3A 0C .....n.. 1mH..r:.
+[0080] 4B 8B 83 8C 4D 99 4F 6A 4D 99 50 85 7D 44 0B 68 K...M.Oj M.P.}D.h
+[0090] 00 00 00 00 00 40 28 00 00 00 00 00 00 00 00 00 .....@(. ........
+[00A0] 00 00 00 03 FA 61 82 03 F6 30 82 03 F2 A0 03 02 .....a.. .0......
+[00B0] 01 05 A1 19 1B 17 4B 54 45 53 54 2E 53 41 4D 42 ......KT EST.SAMB
+[00C0] 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D A2 1E 30 A.EXAMPL E.COM..0
+[00D0] 1C A0 03 02 01 01 A1 15 30 13 1B 04 63 69 66 73 ........ 0...cifs
+[00E0] 1B 0B 6C 6F 63 61 6C 6B 74 65 73 74 36 A3 82 03 ..localk test6...
+[00F0] AE 30 82 03 AA A0 03 02 01 17 A1 03 02 01 02 A2 .0...... ........
+[0100] 82 03 9C 04 82 03 98 C6 BB 64 A8 31 00 FC 5E 51 ........ .d.1..^Q
+[0110] 3C 87 F8 34 47 3B D0 6F 6F FD 9E A6 91 12 74 2D <..4G;.o o.....t-
+[0120] 44 BB AA 91 A0 2D 46 3E 9E FB FB C4 FB F1 15 FD D....-F> ........
+[0130] BB DA EE 06 A9 20 6A 38 DC 46 06 27 D9 A2 9D 2D ..... j8 .F.'...-
+[0140] 1F FD 0D 7D 8A BB 0A 7C E8 47 17 BC 7B 70 E4 51 ...}...| .G..{p.Q
+[0150] 6A BA 51 68 62 28 4A 1E 51 D1 0D CD 02 55 75 44 j.Qhb(J. Q....UuD
+[0160] 8A B9 C2 84 F4 17 34 92 9B 31 85 9E 43 C1 0C 3A ......4. .1..C..:
+[0170] B2 69 7F 20 1A 18 1F 65 4F C0 20 C9 B5 AF E1 61 .i. ...e O. ....a
+[0180] 8C 90 10 63 26 A6 5D 05 3C CD 29 BB 7B 74 D5 8F ...c&.]. <.).{t..
+[0190] 2C 7F 4B E8 84 24 57 37 8A C6 F7 91 FD 22 9A A5 ,.K..$W7 ....."..
+[01A0] 0D E9 4A 78 93 36 FC A8 8C 8A 27 8A C6 28 4B 7B ..Jx.6.. ..'..(K{
+[01B0] DA 11 42 BC 09 10 81 82 14 0F 9C B8 48 26 91 78 ..B..... ....H&.x
+[01C0] A8 DD 97 6C 24 A1 D2 E8 85 19 B3 D3 85 4D 38 C7 ...l$... .....M8.
+[01D0] 7D 49 55 8E 85 46 E1 EE 7B BA 11 62 63 53 C5 16 }IU..F.. {..bcS..
+[01E0] 4A 0C 1C 99 7C 0E FB 45 1D B4 98 58 67 7E 40 65 J...|..E ...Xg~@e
+[01F0] 4B 48 E2 89 9C 8B C2 B8 39 D1 04 C0 A8 56 E8 A1 KH...... 9....V..
+[0200] 04 7A 7A C9 60 18 A0 29 E2 DC 82 4C 8F 18 CE 2F .zz.`..) ...L.../
+[0210] 14 F0 18 5B 6C FF 85 45 88 73 CB A4 55 08 FC BF ...[l..E .s..U...
+[0220] C7 9F 51 0A DB 2C C1 E3 3C DD F6 F0 A3 2D F1 3B ..Q..,.. <....-.;
+[0230] A0 12 1D FC 2A 67 F5 1A 7F E5 7C 6C FB 8A 18 BD ....*g.. ..|l....
+[0240] D1 5D E5 5E 68 30 AA 58 9E 10 13 E0 26 7E 7D C4 .].^h0.X ....&~}.
+[0250] E1 A5 B6 86 0F 1C 0F 13 A4 5E 5E 6A ED 42 79 31 ........ .^^j.By1
+[0260] BB B3 5F 3A 3F DD CB 63 82 FB 06 AE 12 36 C9 1E .._:?..c .....6..
+[0270] 06 7D 41 82 2E D2 FA 26 EC 17 50 5E D0 DE 26 85 .}A....& ..P^..&.
+[0280] 30 71 BC 45 3B DA 2E 08 8D B2 2A 3C E0 79 8F 77 0q.E;... ..*<.y.w
+[0290] 4C 01 69 7A 09 C7 88 E1 D1 DC FF 78 DB 25 7B B1 L.iz.... ...x.%{.
+[02A0] 3C BB 22 27 80 0D 75 96 18 B6 40 95 6D C8 AB 04 <."'..u. ..@.m...
+[02B0] 05 41 A1 C4 25 71 C4 53 3A A6 9C B2 4D E6 15 2C .A..%q.S :...M..,
+[02C0] B2 47 6C DA A8 7D CC A3 89 8B C9 1E 21 F5 E9 B2 .Gl..}.. ....!...
+[02D0] 42 95 68 28 AF C6 37 22 BA 30 8D 53 FA 08 0D CE B.h(..7" .0.S....
+[02E0] CA 81 61 0D 84 A5 2D 75 BD 41 85 4C 88 56 72 C6 ..a...-u .A.L.Vr.
+[02F0] B6 10 F8 34 CD B2 F4 5C 94 FA 80 90 82 A0 BD 68 ...4...\ .......h
+[0300] EC 08 32 C3 B6 51 1E 3F 67 CB 7B EB 70 83 84 D4 ..2..Q.? g.{.p...
+[0310] CB 52 55 36 61 1E 60 90 5B 6F FE 9A 62 05 CF 26 .RU6a.`. [o..b..&
+[0320] 8E 65 E2 60 4B ED 63 B4 C4 E6 44 B4 2F B0 B8 07 .e.`K.c. ..D./...
+[0330] FE BE 0D 50 E4 56 A4 2E 0D 25 76 0B 0F 44 09 20 ...P.V.. .%v..D.
+[0340] 80 E5 C4 94 63 E0 54 46 1D AB 5E 0B 09 93 B1 30 ....c.TF ..^....0
+[0350] 31 7B 04 DC 23 43 3B DB 7D 39 67 FE 9A 1F C1 08 1{..#C;. }9g.....
+[0360] AF 34 24 F6 74 E4 14 DA 34 8F 61 57 6A 7F 1D 4A .4$.t... 4.aWj..J
+[0370] 88 0A 90 78 93 F1 86 54 DB 22 86 D6 69 0F DF 44 ...x...T ."..i..D
+[0380] 7C D3 6B 9D 41 63 50 98 3A 97 B9 7B 4C 53 E3 85 |.k.AcP. :..{LS..
+[0390] 73 9A C9 08 A0 75 12 50 02 87 B0 CF CC 84 84 D9 s....u.P ........
+[03A0] BC FC 94 79 AF 6A A6 08 FF 19 7E E9 22 9B EC 5C ...y.j.. ..~."..\
+[03B0] C1 6B 1D A4 B4 55 32 5E 23 C3 C0 D4 8B 80 E6 67 .k...U2^ #......g
+[03C0] B1 59 EB 9D 5D 9B AD C6 0E 7D E2 FE B1 24 8A B1 .Y..]... .}...$..
+[03D0] 37 1E 60 7F 83 35 48 32 F7 03 E8 12 E6 21 7C 3D 7.`..5H2 .....!|=
+[03E0] 21 7F 6B 14 31 9C 1A A3 4C 2B 1C 5E EC 34 C1 2D !.k.1... L+.^.4.-
+[03F0] DA 19 6C E6 6D 8D 60 D7 55 9E E6 D0 B5 07 06 72 ..l.m.`. U......r
+[0400] C0 E9 4E 91 94 6B 3E 0B F1 0A 75 4D E8 CB 53 6B ..N..k>. ..uM..Sk
+[0410] 34 A4 2F 96 A5 39 1A 18 6E 27 00 6D 41 B7 D8 F5 4./..9.. n'.mA...
+[0420] 9A E5 01 FC 0B A8 97 56 EE 98 04 1D 98 84 5E 82 .......V ......^.
+[0430] C8 E8 EC 17 D5 FA 96 00 3B E1 98 1C D8 FA 66 A0 ........ ;.....f.
+[0440] DC 32 60 F6 03 46 08 3C E5 16 6F F2 8B 4D 72 9F .2`..F.< ..o..Mr.
+[0450] 0F E0 A9 71 6E 7C AE AA FB A3 4D F1 A1 B6 1B 9F ...qn|.. ..M.....
+[0460] 62 71 E1 2C 82 9B AE E3 07 9B 79 90 F1 C2 69 E5 bq.,.... ..y...i.
+[0470] 7E CB 57 E6 C9 1C 4E A8 C7 12 EA 4F 4C 52 17 03 ~.W...N. ...OLR..
+[0480] AB D4 FD 34 60 F4 7C BE 9E 36 30 37 88 95 61 2E ...4`.|. .607..a.
+[0490] CF 70 AF 22 70 DB E8 AA 6E 3D 30 F7 4D 84 D5 00 .p."p... n=0.M...
+[04A0] 00 00 00 00 00 00 01 00 00 00 01 00 00 00 17 4B ........ .......K
+[04B0] 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 TEST.SAM BA.EXAMP
+[04C0] 4C 45 2E 43 4F 4D 00 00 00 0D 61 64 6D 69 6E 69 LE.COM.. ..admini
+[04D0] 73 74 72 61 74 6F 72 00 00 00 01 00 00 00 02 00 strator. ........
+[04E0] 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 ...KTEST .SAMBA.E
+[04F0] 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 04 63 69 XAMPLE.C OM....ci
+[0500] 66 73 00 00 00 0B 6C 6F 63 61 6C 6B 74 65 73 74 fs....lo calktest
+[0510] 36 00 17 00 00 00 10 00 6E A1 B2 31 6D 48 C7 90 6....... n..1mH..
+[0520] 72 3A 0C 4B 8B 83 8C 4D 99 4F 6A 4D 99 50 85 7D r:.K...M .OjM.P.}
+[0530] 44 0B 68 00 00 00 00 00 40 28 00 00 00 00 00 00 D.h..... @(......
+[0540] 00 00 00 00 00 00 03 FA 61 82 03 F6 30 82 03 F2 ........ a...0...
+[0550] A0 03 02 01 05 A1 19 1B 17 4B 54 45 53 54 2E 53 ........ .KTEST.S
+[0560] 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D AMBA.EXA MPLE.COM
+[0570] A2 1E 30 1C A0 03 02 01 01 A1 15 30 13 1B 04 63 ..0..... ...0...c
+[0580] 69 66 73 1B 0B 6C 6F 63 61 6C 6B 74 65 73 74 36 ifs..loc alktest6
+[0590] A3 82 03 AE 30 82 03 AA A0 03 02 01 17 A1 03 02 ....0... ........
+[05A0] 01 02 A2 82 03 9C 04 82 03 98 C6 BB 64 A8 31 00 ........ ....d.1.
+[05B0] FC 5E 51 3C 87 F8 34 47 3B D0 6F 6F FD 9E A6 91 .^Q<..4G ;.oo....
+[05C0] 12 74 2D 44 BB AA 91 A0 2D 46 3E 9E FB FB C4 FB .t-D.... -F>.....
+[05D0] F1 15 FD BB DA EE 06 A9 20 6A 38 DC 46 06 27 D9 ........ j8.F.'.
+[05E0] A2 9D 2D 1F FD 0D 7D 8A BB 0A 7C E8 47 17 BC 7B ..-...}. ..|.G..{
+[05F0] 70 E4 51 6A BA 51 68 62 28 4A 1E 51 D1 0D CD 02 p.Qj.Qhb (J.Q....
+[0600] 55 75 44 8A B9 C2 84 F4 17 34 92 9B 31 85 9E 43 UuD..... .4..1..C
+[0610] C1 0C 3A B2 69 7F 20 1A 18 1F 65 4F C0 20 C9 B5 ..:.i. . ..eO. ..
+[0620] AF E1 61 8C 90 10 63 26 A6 5D 05 3C CD 29 BB 7B ..a...c& .].<.).{
+[0630] 74 D5 8F 2C 7F 4B E8 84 24 57 37 8A C6 F7 91 FD t..,.K.. $W7.....
+[0640] 22 9A A5 0D E9 4A 78 93 36 FC A8 8C 8A 27 8A C6 "....Jx. 6....'..
+[0650] 28 4B 7B DA 11 42 BC 09 10 81 82 14 0F 9C B8 48 (K{..B.. .......H
+[0660] 26 91 78 A8 DD 97 6C 24 A1 D2 E8 85 19 B3 D3 85 &.x...l$ ........
+[0670] 4D 38 C7 7D 49 55 8E 85 46 E1 EE 7B BA 11 62 63 M8.}IU.. F..{..bc
+[0680] 53 C5 16 4A 0C 1C 99 7C 0E FB 45 1D B4 98 58 67 S..J...| ..E...Xg
+[0690] 7E 40 65 4B 48 E2 89 9C 8B C2 B8 39 D1 04 C0 A8 ~@eKH... ...9....
+[06A0] 56 E8 A1 04 7A 7A C9 60 18 A0 29 E2 DC 82 4C 8F V...zz.` ..)...L.
+[06B0] 18 CE 2F 14 F0 18 5B 6C FF 85 45 88 73 CB A4 55 ../...[l ..E.s..U
+[06C0] 08 FC BF C7 9F 51 0A DB 2C C1 E3 3C DD F6 F0 A3 .....Q.. ,..<....
+[06D0] 2D F1 3B A0 12 1D FC 2A 67 F5 1A 7F E5 7C 6C FB -.;....* g....|l.
+[06E0] 8A 18 BD D1 5D E5 5E 68 30 AA 58 9E 10 13 E0 26 ....].^h 0.X....&
+[06F0] 7E 7D C4 E1 A5 B6 86 0F 1C 0F 13 A4 5E 5E 6A ED ~}...... ....^^j.
+[0700] 42 79 31 BB B3 5F 3A 3F DD CB 63 82 FB 06 AE 12 By1.._:? ..c.....
+[0710] 36 C9 1E 06 7D 41 82 2E D2 FA 26 EC 17 50 5E D0 6...}A.. ..&..P^.
+[0720] DE 26 85 30 71 BC 45 3B DA 2E 08 8D B2 2A 3C E0 .&.0q.E; .....*<.
+[0730] 79 8F 77 4C 01 69 7A 09 C7 88 E1 D1 DC FF 78 DB y.wL.iz. ......x.
+[0740] 25 7B B1 3C BB 22 27 80 0D 75 96 18 B6 40 95 6D %{.<."'. .u...@.m
+[0750] C8 AB 04 05 41 A1 C4 25 71 C4 53 3A A6 9C B2 4D ....A..% q.S:...M
+[0760] E6 15 2C B2 47 6C DA A8 7D CC A3 89 8B C9 1E 21 ..,.Gl.. }......!
+[0770] F5 E9 B2 42 95 68 28 AF C6 37 22 BA 30 8D 53 FA ...B.h(. .7".0.S.
+[0780] 08 0D CE CA 81 61 0D 84 A5 2D 75 BD 41 85 4C 88 .....a.. .-u.A.L.
+[0790] 56 72 C6 B6 10 F8 34 CD B2 F4 5C 94 FA 80 90 82 Vr....4. ..\.....
+[07A0] A0 BD 68 EC 08 32 C3 B6 51 1E 3F 67 CB 7B EB 70 ..h..2.. Q.?g.{.p
+[07B0] 83 84 D4 CB 52 55 36 61 1E 60 90 5B 6F FE 9A 62 ....RU6a .`.[o..b
+[07C0] 05 CF 26 8E 65 E2 60 4B ED 63 B4 C4 E6 44 B4 2F ..&.e.`K .c...D./
+[07D0] B0 B8 07 FE BE 0D 50 E4 56 A4 2E 0D 25 76 0B 0F ......P. V...%v..
+[07E0] 44 09 20 80 E5 C4 94 63 E0 54 46 1D AB 5E 0B 09 D. ....c .TF..^..
+[07F0] 93 B1 30 31 7B 04 DC 23 43 3B DB 7D 39 67 FE 9A ..01{..# C;.}9g..
+[0800] 1F C1 08 AF 34 24 F6 74 E4 14 DA 34 8F 61 57 6A ....4$.t ...4.aWj
+[0810] 7F 1D 4A 88 0A 90 78 93 F1 86 54 DB 22 86 D6 69 ..J...x. ..T."..i
+[0820] 0F DF 44 7C D3 6B 9D 41 63 50 98 3A 97 B9 7B 4C ..D|.k.A cP.:..{L
+[0830] 53 E3 85 73 9A C9 08 A0 75 12 50 02 87 B0 CF CC S..s.... u.P.....
+[0840] 84 84 D9 BC FC 94 79 AF 6A A6 08 FF 19 7E E9 22 ......y. j....~."
+[0850] 9B EC 5C C1 6B 1D A4 B4 55 32 5E 23 C3 C0 D4 8B ..\.k... U2^#....
+[0860] 80 E6 67 B1 59 EB 9D 5D 9B AD C6 0E 7D E2 FE B1 ..g.Y..] ....}...
+[0870] 24 8A B1 37 1E 60 7F 83 35 48 32 F7 03 E8 12 E6 $..7.`.. 5H2.....
+[0880] 21 7C 3D 21 7F 6B 14 31 9C 1A A3 4C 2B 1C 5E EC !|=!.k.1 ...L+.^.
+[0890] 34 C1 2D DA 19 6C E6 6D 8D 60 D7 55 9E E6 D0 B5 4.-..l.m .`.U....
+[08A0] 07 06 72 C0 E9 4E 91 94 6B 3E 0B F1 0A 75 4D E8 ..r..N.. k>...uM.
+[08B0] CB 53 6B 34 A4 2F 96 A5 39 1A 18 6E 27 00 6D 41 .Sk4./.. 9..n'.mA
+[08C0] B7 D8 F5 9A E5 01 FC 0B A8 97 56 EE 98 04 1D 98 ........ ..V.....
+[08D0] 84 5E 82 C8 E8 EC 17 D5 FA 96 00 3B E1 98 1C D8 .^...... ...;....
+[08E0] FA 66 A0 DC 32 60 F6 03 46 08 3C E5 16 6F F2 8B .f..2`.. F.<..o..
+[08F0] 4D 72 9F 0F E0 A9 71 6E 7C AE AA FB A3 4D F1 A1 Mr....qn |....M..
+[0900] B6 1B 9F 62 71 E1 2C 82 9B AE E3 07 9B 79 90 F1 ...bq.,. .....y..
+[0910] C2 69 E5 7E CB 57 E6 C9 1C 4E A8 C7 12 EA 4F 4C .i.~.W.. .N....OL
+[0920] 52 17 03 AB D4 FD 34 60 F4 7C BE 9E 36 30 37 88 R.....4` .|..607.
+[0930] 95 61 2E CF 70 AF 22 70 DB E8 AA 6E 3D 30 F7 4D .a..p."p ...n=0.M
+[0940] 84 D5 00 00 00 00 00 00 00 01 00 00 00 01 00 00 ........ ........
+[0950] 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 ..KTEST. SAMBA.EX
+[0960] 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D 61 64 6D AMPLE.CO M....adm
+[0970] 69 6E 69 73 74 72 61 74 6F 72 00 00 00 01 00 00 inistrat or......
+[0980] 00 02 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 ......KT EST.SAMB
+[0990] 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 A.EXAMPL E.COM...
+[09A0] 04 63 69 66 73 00 00 00 0B 6C 6F 63 61 6C 6B 74 .cifs... .localkt
+[09B0] 65 73 74 36 00 17 00 00 00 10 00 6E A1 B2 31 6D est6.... ...n..1m
+[09C0] 48 C7 90 72 3A 0C 4B 8B 83 8C 4D 99 4F 6A 4D 99 H..r:.K. ..M.OjM.
+[09D0] 50 85 7D 44 0B 68 00 00 00 00 00 40 28 00 00 00 P.}D.h.. ...@(...
+[09E0] 00 00 00 00 00 00 00 00 00 03 FA 61 82 03 F6 30 ........ ...a...0
+[09F0] 82 03 F2 A0 03 02 01 05 A1 19 1B 17 4B 54 45 53 ........ ....KTES
+[0A00] 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E T.SAMBA. EXAMPLE.
+[0A10] 43 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 15 30 13 COM..0.. ......0.
+[0A20] 1B 04 63 69 66 73 1B 0B 6C 6F 63 61 6C 6B 74 65 ..cifs.. localkte
+[0A30] 73 74 36 A3 82 03 AE 30 82 03 AA A0 03 02 01 17 st6....0 ........
+[0A40] A1 03 02 01 02 A2 82 03 9C 04 82 03 98 C6 BB 64 ........ .......d
+[0A50] A8 31 00 FC 5E 51 3C 87 F8 34 47 3B D0 6F 6F FD .1..^Q<. .4G;.oo.
+[0A60] 9E A6 91 12 74 2D 44 BB AA 91 A0 2D 46 3E 9E FB ....t-D. ...-F>..
+[0A70] FB C4 FB F1 15 FD BB DA EE 06 A9 20 6A 38 DC 46 ........ ... j8.F
+[0A80] 06 27 D9 A2 9D 2D 1F FD 0D 7D 8A BB 0A 7C E8 47 .'...-.. .}...|.G
+[0A90] 17 BC 7B 70 E4 51 6A BA 51 68 62 28 4A 1E 51 D1 ..{p.Qj. Qhb(J.Q.
+[0AA0] 0D CD 02 55 75 44 8A B9 C2 84 F4 17 34 92 9B 31 ...UuD.. ....4..1
+[0AB0] 85 9E 43 C1 0C 3A B2 69 7F 20 1A 18 1F 65 4F C0 ..C..:.i . ...eO.
+[0AC0] 20 C9 B5 AF E1 61 8C 90 10 63 26 A6 5D 05 3C CD ....a.. .c&.].<.
+[0AD0] 29 BB 7B 74 D5 8F 2C 7F 4B E8 84 24 57 37 8A C6 ).{t..,. K..$W7..
+[0AE0] F7 91 FD 22 9A A5 0D E9 4A 78 93 36 FC A8 8C 8A ...".... Jx.6....
+[0AF0] 27 8A C6 28 4B 7B DA 11 42 BC 09 10 81 82 14 0F '..(K{.. B.......
+[0B00] 9C B8 48 26 91 78 A8 DD 97 6C 24 A1 D2 E8 85 19 ..H&.x.. .l$.....
+[0B10] B3 D3 85 4D 38 C7 7D 49 55 8E 85 46 E1 EE 7B BA ...M8.}I U..F..{.
+[0B20] 11 62 63 53 C5 16 4A 0C 1C 99 7C 0E FB 45 1D B4 .bcS..J. ..|..E..
+[0B30] 98 58 67 7E 40 65 4B 48 E2 89 9C 8B C2 B8 39 D1 .Xg~@eKH ......9.
+[0B40] 04 C0 A8 56 E8 A1 04 7A 7A C9 60 18 A0 29 E2 DC ...V...z z.`..)..
+[0B50] 82 4C 8F 18 CE 2F 14 F0 18 5B 6C FF 85 45 88 73 .L.../.. .[l..E.s
+[0B60] CB A4 55 08 FC BF C7 9F 51 0A DB 2C C1 E3 3C DD ..U..... Q..,..<.
+[0B70] F6 F0 A3 2D F1 3B A0 12 1D FC 2A 67 F5 1A 7F E5 ...-.;.. ..*g....
+[0B80] 7C 6C FB 8A 18 BD D1 5D E5 5E 68 30 AA 58 9E 10 |l.....] .^h0.X..
+[0B90] 13 E0 26 7E 7D C4 E1 A5 B6 86 0F 1C 0F 13 A4 5E ..&~}... .......^
+[0BA0] 5E 6A ED 42 79 31 BB B3 5F 3A 3F DD CB 63 82 FB ^j.By1.. _:?..c..
+[0BB0] 06 AE 12 36 C9 1E 06 7D 41 82 2E D2 FA 26 EC 17 ...6...} A....&..
+[0BC0] 50 5E D0 DE 26 85 30 71 BC 45 3B DA 2E 08 8D B2 P^..&.0q .E;.....
+[0BD0] 2A 3C E0 79 8F 77 4C 01 69 7A 09 C7 88 E1 D1 DC *<.y.wL. iz......
+[0BE0] FF 78 DB 25 7B B1 3C BB 22 27 80 0D 75 96 18 B6 .x.%{.<. "'..u...
+[0BF0] 40 95 6D C8 AB 04 05 41 A1 C4 25 71 C4 53 3A A6 @.m....A ..%q.S:.
+[0C00] 9C B2 4D E6 15 2C B2 47 6C DA A8 7D CC A3 89 8B ..M..,.G l..}....
+[0C10] C9 1E 21 F5 E9 B2 42 95 68 28 AF C6 37 22 BA 30 ..!...B. h(..7".0
+[0C20] 8D 53 FA 08 0D CE CA 81 61 0D 84 A5 2D 75 BD 41 .S...... a...-u.A
+[0C30] 85 4C 88 56 72 C6 B6 10 F8 34 CD B2 F4 5C 94 FA .L.Vr... .4...\..
+[0C40] 80 90 82 A0 BD 68 EC 08 32 C3 B6 51 1E 3F 67 CB .....h.. 2..Q.?g.
+[0C50] 7B EB 70 83 84 D4 CB 52 55 36 61 1E 60 90 5B 6F {.p....R U6a.`.[o
+[0C60] FE 9A 62 05 CF 26 8E 65 E2 60 4B ED 63 B4 C4 E6 ..b..&.e .`K.c...
+[0C70] 44 B4 2F B0 B8 07 FE BE 0D 50 E4 56 A4 2E 0D 25 D./..... .P.V...%
+[0C80] 76 0B 0F 44 09 20 80 E5 C4 94 63 E0 54 46 1D AB v..D. .. ..c.TF..
+[0C90] 5E 0B 09 93 B1 30 31 7B 04 DC 23 43 3B DB 7D 39 ^....01{ ..#C;.}9
+[0CA0] 67 FE 9A 1F C1 08 AF 34 24 F6 74 E4 14 DA 34 8F g......4 $.t...4.
+[0CB0] 61 57 6A 7F 1D 4A 88 0A 90 78 93 F1 86 54 DB 22 aWj..J.. .x...T."
+[0CC0] 86 D6 69 0F DF 44 7C D3 6B 9D 41 63 50 98 3A 97 ..i..D|. k.AcP.:.
+[0CD0] B9 7B 4C 53 E3 85 73 9A C9 08 A0 75 12 50 02 87 .{LS..s. ...u.P..
+[0CE0] B0 CF CC 84 84 D9 BC FC 94 79 AF 6A A6 08 FF 19 ........ .y.j....
+[0CF0] 7E E9 22 9B EC 5C C1 6B 1D A4 B4 55 32 5E 23 C3 ~."..\.k ...U2^#.
+[0D00] C0 D4 8B 80 E6 67 B1 59 EB 9D 5D 9B AD C6 0E 7D .....g.Y ..]....}
+[0D10] E2 FE B1 24 8A B1 37 1E 60 7F 83 35 48 32 F7 03 ...$..7. `..5H2..
+[0D20] E8 12 E6 21 7C 3D 21 7F 6B 14 31 9C 1A A3 4C 2B ...!|=!. k.1...L+
+[0D30] 1C 5E EC 34 C1 2D DA 19 6C E6 6D 8D 60 D7 55 9E .^.4.-.. l.m.`.U.
+[0D40] E6 D0 B5 07 06 72 C0 E9 4E 91 94 6B 3E 0B F1 0A .....r.. N..k>...
+[0D50] 75 4D E8 CB 53 6B 34 A4 2F 96 A5 39 1A 18 6E 27 uM..Sk4. /..9..n'
+[0D60] 00 6D 41 B7 D8 F5 9A E5 01 FC 0B A8 97 56 EE 98 .mA..... .....V..
+[0D70] 04 1D 98 84 5E 82 C8 E8 EC 17 D5 FA 96 00 3B E1 ....^... ......;.
+[0D80] 98 1C D8 FA 66 A0 DC 32 60 F6 03 46 08 3C E5 16 ....f..2 `..F.<..
+[0D90] 6F F2 8B 4D 72 9F 0F E0 A9 71 6E 7C AE AA FB A3 o..Mr... .qn|....
+[0DA0] 4D F1 A1 B6 1B 9F 62 71 E1 2C 82 9B AE E3 07 9B M.....bq .,......
+[0DB0] 79 90 F1 C2 69 E5 7E CB 57 E6 C9 1C 4E A8 C7 12 y...i.~. W...N...
+[0DC0] EA 4F 4C 52 17 03 AB D4 FD 34 60 F4 7C BE 9E 36 .OLR.... .4`.|..6
+[0DD0] 30 37 88 95 61 2E CF 70 AF 22 70 DB E8 AA 6E 3D 07..a..p ."p...n=
+[0DE0] 30 F7 4D 84 D5 00 00 00 00 00 00 00 01 00 00 00 0.M..... ........
+[0DF0] 01 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 .....KTE ST.SAMBA
+[0E00] 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D .EXAMPLE .COM....
+[0E10] 61 64 6D 69 6E 69 73 74 72 61 74 6F 72 00 00 00 administ rator...
+[0E20] 01 00 00 00 02 00 00 00 17 4B 54 45 53 54 2E 53 ........ .KTEST.S
+[0E30] 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D AMBA.EXA MPLE.COM
+[0E40] 00 00 00 04 63 69 66 73 00 00 00 0B 4C 4F 43 41 ....cifs ....LOCA
+[0E50] 4C 4B 54 45 53 54 36 00 17 00 00 00 10 1D C8 5E LKTEST6. .......^
+[0E60] 46 48 82 F9 29 DB C6 A6 F1 72 6D 8D E9 4D 99 4F FH..)... .rm..M.O
+[0E70] 6A 4D 99 85 09 7D 44 0B 68 00 00 00 00 00 40 28 jM...}D. h.....@(
+[0E80] 00 00 00 00 00 00 00 00 00 00 00 00 03 FA 61 82 ........ ......a.
+[0E90] 03 F6 30 82 03 F2 A0 03 02 01 05 A1 19 1B 17 4B ..0..... .......K
+[0EA0] 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 TEST.SAM BA.EXAMP
+[0EB0] 4C 45 2E 43 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 LE.COM.. 0.......
+[0EC0] 15 30 13 1B 04 63 69 66 73 1B 0B 4C 4F 43 41 4C .0...cif s..LOCAL
+[0ED0] 4B 54 45 53 54 36 A3 82 03 AE 30 82 03 AA A0 03 KTEST6.. ..0.....
+[0EE0] 02 01 17 A1 03 02 01 02 A2 82 03 9C 04 82 03 98 ........ ........
+[0EF0] 66 D8 19 46 FA CB 73 2D CF 88 FD 4A EE 07 48 DA f..F..s- ...J..H.
+[0F00] 0E BC 58 30 43 40 A4 9C 00 0F 3B 17 C1 2D F5 9C ..X0C@.. ..;..-..
+[0F10] 3E D9 2F 1D CA 01 9B D7 2E EC D7 70 ED 8B 8B 1B >./..... ...p....
+[0F20] 5E F2 4E EE DD 0F C0 8D 61 E5 D7 0A 56 00 32 B1 ^.N..... a...V.2.
+[0F30] DB 91 37 29 0F 2F 85 EE A8 43 BA A5 B8 D4 19 74 ..7)./.. .C.....t
+[0F40] 33 F0 69 52 E1 58 98 83 D6 16 0B 44 A9 63 9B D4 3.iR.X.. ...D.c..
+[0F50] 4E 6E A7 3E CD 9A 96 4D C4 96 F5 07 6D 29 B6 ED Nn.>...M ....m)..
+[0F60] 2A 62 3D 53 22 33 D1 95 E9 DF 74 4C 2A E2 29 AF *b=S"3.. ..tL*.).
+[0F70] 5B 69 B0 48 2D AD 94 FD A5 1D 54 D8 E2 5E C1 68 [i.H-... ..T..^.h
+[0F80] 6F BA 02 01 79 C3 C9 97 0B 76 66 45 E2 3B 10 17 o...y... .vfE.;..
+[0F90] 95 40 46 E4 85 B9 87 BB CF CF 19 8C 3A C0 EA 38 .@F..... ....:..8
+[0FA0] 3B B9 E9 4B 05 89 E5 27 8C 62 95 BC 0D 65 F0 D2 ;..K...' .b...e..
+[0FB0] C0 5E BC 65 01 D5 0B CB 17 31 0F 06 49 4F A2 4A .^.e.... .1..IO.J
+[0FC0] 70 77 DB BD 92 5B 37 5C EC 06 DF C5 E2 31 C8 40 pw...[7\ .....1.@
+[0FD0] 09 11 68 14 E7 7D CE 54 4F 52 61 31 2C 1C 53 52 ..h..}.T ORa1,.SR
+[0FE0] DB BE D8 95 39 EE 7D C6 CE C8 22 95 92 97 97 3D ....9.}. .."....=
+[0FF0] 5E 66 0F AD DC C2 4E 2E 2B 9F 63 20 30 DF B7 C1 ^f....N. +.c 0...
+[1000] D4 65 AA 6F 2D 10 24 07 20 8D 88 6E 4B 09 04 31 .e.o-.$. ..nK..1
+[1010] B6 A3 EB F7 37 32 0E 0C 73 C6 F6 B8 4D D9 0C 4C ....72.. s...M..L
+[1020] 5B EC 10 6A 51 19 EA 3F FF 46 E7 73 16 A7 1F 33 [..jQ..? .F.s...3
+[1030] 98 7C 9B AD 5A 23 A9 40 7C 0F DF EE 0F AA C7 E8 .|..Z#.@ |.......
+[1040] 63 07 98 3A 4A 0D 18 62 01 21 B2 AE A5 69 B0 C1 c..:J..b .!...i..
+[1050] 15 51 BA 97 D2 C5 42 5B C5 30 38 18 A9 48 AB D7 .Q....B[ .08..H..
+[1060] FC A1 BC 9F 71 E7 EA 18 54 42 DA D6 A4 FC C1 DC ....q... TB......
+[1070] F3 12 30 62 AC 98 E1 7D 2B 34 1E 52 4C 26 67 32 ..0b...} +4.RL&g2
+[1080] D9 44 1A 08 27 0E DA D0 FC 84 66 35 81 D6 EB 98 .D..'... ..f5....
+[1090] 46 6F 1E 47 E0 14 31 BE 47 80 65 AA 0B 20 D6 33 Fo.G..1. G.e.. .3
+[10A0] 36 3B 0D 40 2F 5A 2E 0E 01 BE 00 EB 33 3E 4B 32 6;.@/Z.. ....3>K2
+[10B0] 91 F4 22 96 E5 5F D4 D5 92 94 CC 5B 59 6A 3E D2 ..".._.. ...[Yj>.
+[10C0] FB A0 4F 99 C4 07 8B 6F 2B 14 37 CD 37 44 C0 1F ..O....o +.7.7D..
+[10D0] 80 9C 43 46 F2 5E F4 FE D3 39 70 61 BE 72 5B 3A ..CF.^.. .9pa.r[:
+[10E0] 8F 37 95 78 1E AB D9 E7 E9 DA FC 47 09 81 A0 0D .7.x.... ...G....
+[10F0] 62 E1 F9 34 36 D1 DB E6 98 D8 F4 3E 77 5A 4D E2 b..46... ...>wZM.
+[1100] 5F 20 70 3D 3D 5B 34 D9 FD A8 31 F7 D9 59 F7 A3 _ p==[4. ..1..Y..
+[1110] F0 66 F7 D9 AD 1C CD D5 85 33 A0 87 22 31 D4 F3 .f...... .3.."1..
+[1120] 67 80 68 20 A2 90 72 7A 6F 64 FD 68 82 9E 91 B8 g.h ..rz od.h....
+[1130] E3 F7 6D 6C 38 74 F0 96 A2 F6 25 D7 92 58 14 60 ..ml8t.. ..%..X.`
+[1140] 9F AE 01 4C 0C 09 67 3E 35 67 71 1E 2A 86 21 D3 ...L..g> 5gq.*.!.
+[1150] 60 61 98 16 94 67 0B 52 76 63 93 BD A3 3B A9 F0 `a...g.R vc...;..
+[1160] A2 6A B7 E6 0F 35 64 DA 6A EA 20 A6 3D 94 71 59 .j...5d. j. .=.qY
+[1170] 5E CB B2 D3 F9 4D FE 1B 4B D8 64 C8 3B 7A A8 E6 ^....M.. K.d.;z..
+[1180] D2 D5 76 71 26 D4 5C DA 1A 55 17 F2 16 C9 2F 77 ..vq&.\. .U..../w
+[1190] DB 95 19 48 A5 AC D0 C3 31 9C 0A CC 1B 44 11 6B ...H.... 1....D.k
+[11A0] 7C 88 7A 5D CF 6E 12 DA EF C5 C7 34 1D F4 CC EA |.z].n.. ...4....
+[11B0] 37 24 4B B3 0F C1 A3 F2 29 A0 D8 93 39 C6 16 57 7$K..... )...9..W
+[11C0] D5 BF 57 BF 6C 7E F7 90 E0 EB A3 8B 07 56 9C EC ..W.l~.. .....V..
+[11D0] 15 3E 21 DA A5 7C 00 3C F9 D2 A7 1C 6F 16 25 31 .>!..|.< ....o.%1
+[11E0] C5 28 A7 EA F3 47 31 50 DD E1 ED 0A 93 DB 85 CC .(...G1P ........
+[11F0] 6B 4B 2C 7F E8 F8 2D A9 6D 1D 0A 87 F2 10 8C 82 kK,...-. m.......
+[1200] 2F 9B D4 9B 92 8C 77 40 50 42 1E 42 C4 0A 4F E3 /.....w@ PB.B..O.
+[1210] 6C 6C DC 81 C4 1E BB F0 7D CF 3C 73 22 5B C3 1A ll...... }..x K....%J.
+[1240] 1E 6C 8F 01 D6 59 D7 CF 2E A0 CC 98 F6 75 28 2F .l...Y.. .....u(/
+[1250] F7 2A 70 28 A9 45 1F 75 C2 4E 62 ED D8 C4 A0 8D .*p(.E.u .Nb.....
+[1260] 55 B2 84 1C A4 CE 87 EF 24 EE BC CE 40 09 EB 05 U....... $...@...
+[1270] 0B D1 14 31 50 32 2F B6 A8 97 17 4B A7 95 01 50 ...1P2/. ...K...P
+[1280] 6E 0E 23 49 9C 72 21 91 00 00 00 00 00 00 00 01 n.#I.r!. ........
+[1290] 00 00 00 01 00 00 00 17 4B 54 45 53 54 2E 53 41 ........ KTEST.SA
+[12A0] 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 MBA.EXAM PLE.COM.
+[12B0] 00 00 0D 61 64 6D 69 6E 69 73 74 72 61 74 6F 72 ...admin istrator
+[12C0] 00 00 00 01 00 00 00 02 00 00 00 17 4B 54 45 53 ........ ....KTES
+[12D0] 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E T.SAMBA. EXAMPLE.
+[12E0] 43 4F 4D 00 00 00 04 63 69 66 73 00 00 00 0B 4C COM....c ifs....L
+[12F0] 4F 43 41 4C 4B 54 45 53 54 36 00 17 00 00 00 10 OCALKTES T6......
+[1300] 1D C8 5E 46 48 82 F9 29 DB C6 A6 F1 72 6D 8D E9 ..^FH..) ....rm..
+[1310] 4D 99 4F 6A 4D 99 85 09 7D 44 0B 68 00 00 00 00 M.OjM... }D.h....
+[1320] 00 40 28 00 00 00 00 00 00 00 00 00 00 00 00 03 .@(..... ........
+[1330] FA 61 82 03 F6 30 82 03 F2 A0 03 02 01 05 A1 19 .a...0.. ........
+[1340] 1B 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 ..KTEST. SAMBA.EX
+[1350] 41 4D 50 4C 45 2E 43 4F 4D A2 1E 30 1C A0 03 02 AMPLE.CO M..0....
+[1360] 01 01 A1 15 30 13 1B 04 63 69 66 73 1B 0B 4C 4F ....0... cifs..LO
+[1370] 43 41 4C 4B 54 45 53 54 36 A3 82 03 AE 30 82 03 CALKTEST 6....0..
+[1380] AA A0 03 02 01 17 A1 03 02 01 02 A2 82 03 9C 04 ........ ........
+[1390] 82 03 98 66 D8 19 46 FA CB 73 2D CF 88 FD 4A EE ...f..F. .s-...J.
+[13A0] 07 48 DA 0E BC 58 30 43 40 A4 9C 00 0F 3B 17 C1 .H...X0C @....;..
+[13B0] 2D F5 9C 3E D9 2F 1D CA 01 9B D7 2E EC D7 70 ED -..>./.. ......p.
+[13C0] 8B 8B 1B 5E F2 4E EE DD 0F C0 8D 61 E5 D7 0A 56 ...^.N.. ...a...V
+[13D0] 00 32 B1 DB 91 37 29 0F 2F 85 EE A8 43 BA A5 B8 .2...7). /...C...
+[13E0] D4 19 74 33 F0 69 52 E1 58 98 83 D6 16 0B 44 A9 ..t3.iR. X.....D.
+[13F0] 63 9B D4 4E 6E A7 3E CD 9A 96 4D C4 96 F5 07 6D c..Nn.>. ..M....m
+[1400] 29 B6 ED 2A 62 3D 53 22 33 D1 95 E9 DF 74 4C 2A )..*b=S" 3....tL*
+[1410] E2 29 AF 5B 69 B0 48 2D AD 94 FD A5 1D 54 D8 E2 .).[i.H- .....T..
+[1420] 5E C1 68 6F BA 02 01 79 C3 C9 97 0B 76 66 45 E2 ^.ho...y ....vfE.
+[1430] 3B 10 17 95 40 46 E4 85 B9 87 BB CF CF 19 8C 3A ;...@F.. .......:
+[1440] C0 EA 38 3B B9 E9 4B 05 89 E5 27 8C 62 95 BC 0D ..8;..K. ..'.b...
+[1450] 65 F0 D2 C0 5E BC 65 01 D5 0B CB 17 31 0F 06 49 e...^.e. ....1..I
+[1460] 4F A2 4A 70 77 DB BD 92 5B 37 5C EC 06 DF C5 E2 O.Jpw... [7\.....
+[1470] 31 C8 40 09 11 68 14 E7 7D CE 54 4F 52 61 31 2C 1.@..h.. }.TORa1,
+[1480] 1C 53 52 DB BE D8 95 39 EE 7D C6 CE C8 22 95 92 .SR....9 .}..."..
+[1490] 97 97 3D 5E 66 0F AD DC C2 4E 2E 2B 9F 63 20 30 ..=^f... .N.+.c 0
+[14A0] DF B7 C1 D4 65 AA 6F 2D 10 24 07 20 8D 88 6E 4B ....e.o- .$. ..nK
+[14B0] 09 04 31 B6 A3 EB F7 37 32 0E 0C 73 C6 F6 B8 4D ..1....7 2..s...M
+[14C0] D9 0C 4C 5B EC 10 6A 51 19 EA 3F FF 46 E7 73 16 ..L[..jQ ..?.F.s.
+[14D0] A7 1F 33 98 7C 9B AD 5A 23 A9 40 7C 0F DF EE 0F ..3.|..Z #.@|....
+[14E0] AA C7 E8 63 07 98 3A 4A 0D 18 62 01 21 B2 AE A5 ...c..:J ..b.!...
+[14F0] 69 B0 C1 15 51 BA 97 D2 C5 42 5B C5 30 38 18 A9 i...Q... .B[.08..
+[1500] 48 AB D7 FC A1 BC 9F 71 E7 EA 18 54 42 DA D6 A4 H......q ...TB...
+[1510] FC C1 DC F3 12 30 62 AC 98 E1 7D 2B 34 1E 52 4C .....0b. ..}+4.RL
+[1520] 26 67 32 D9 44 1A 08 27 0E DA D0 FC 84 66 35 81 &g2.D..' .....f5.
+[1530] D6 EB 98 46 6F 1E 47 E0 14 31 BE 47 80 65 AA 0B ...Fo.G. .1.G.e..
+[1540] 20 D6 33 36 3B 0D 40 2F 5A 2E 0E 01 BE 00 EB 33 .36;.@/ Z......3
+[1550] 3E 4B 32 91 F4 22 96 E5 5F D4 D5 92 94 CC 5B 59 >K2..".. _.....[Y
+[1560] 6A 3E D2 FB A0 4F 99 C4 07 8B 6F 2B 14 37 CD 37 j>...O.. ..o+.7.7
+[1570] 44 C0 1F 80 9C 43 46 F2 5E F4 FE D3 39 70 61 BE D....CF. ^...9pa.
+[1580] 72 5B 3A 8F 37 95 78 1E AB D9 E7 E9 DA FC 47 09 r[:.7.x. ......G.
+[1590] 81 A0 0D 62 E1 F9 34 36 D1 DB E6 98 D8 F4 3E 77 ...b..46 ......>w
+[15A0] 5A 4D E2 5F 20 70 3D 3D 5B 34 D9 FD A8 31 F7 D9 ZM._ p== [4...1..
+[15B0] 59 F7 A3 F0 66 F7 D9 AD 1C CD D5 85 33 A0 87 22 Y...f... ....3.."
+[15C0] 31 D4 F3 67 80 68 20 A2 90 72 7A 6F 64 FD 68 82 1..g.h . .rzod.h.
+[15D0] 9E 91 B8 E3 F7 6D 6C 38 74 F0 96 A2 F6 25 D7 92 .....ml8 t....%..
+[15E0] 58 14 60 9F AE 01 4C 0C 09 67 3E 35 67 71 1E 2A X.`...L. .g>5gq.*
+[15F0] 86 21 D3 60 61 98 16 94 67 0B 52 76 63 93 BD A3 .!.`a... g.Rvc...
+[1600] 3B A9 F0 A2 6A B7 E6 0F 35 64 DA 6A EA 20 A6 3D ;...j... 5d.j. .=
+[1610] 94 71 59 5E CB B2 D3 F9 4D FE 1B 4B D8 64 C8 3B .qY^.... M..K.d.;
+[1620] 7A A8 E6 D2 D5 76 71 26 D4 5C DA 1A 55 17 F2 16 z....vq& .\..U...
+[1630] C9 2F 77 DB 95 19 48 A5 AC D0 C3 31 9C 0A CC 1B ./w...H. ...1....
+[1640] 44 11 6B 7C 88 7A 5D CF 6E 12 DA EF C5 C7 34 1D D.k|.z]. n.....4.
+[1650] F4 CC EA 37 24 4B B3 0F C1 A3 F2 29 A0 D8 93 39 ...7$K.. ...)...9
+[1660] C6 16 57 D5 BF 57 BF 6C 7E F7 90 E0 EB A3 8B 07 ..W..W.l ~.......
+[1670] 56 9C EC 15 3E 21 DA A5 7C 00 3C F9 D2 A7 1C 6F V...>!.. |.<....o
+[1680] 16 25 31 C5 28 A7 EA F3 47 31 50 DD E1 ED 0A 93 .%1.(... G1P.....
+[1690] DB 85 CC 6B 4B 2C 7F E8 F8 2D A9 6D 1D 0A 87 F2 ...kK,.. .-.m....
+[16A0] 10 8C 82 2F 9B D4 9B 92 8C 77 40 50 42 1E 42 C4 .../.... .w@PB.B.
+[16B0] 0A 4F E3 6C 6C DC 81 C4 1E BB F0 7D CF 3C 73 22 .O.ll... ...}..xK....
+[16E0] 25 4A 92 1E 6C 8F 01 D6 59 D7 CF 2E A0 CC 98 F6 %J..l... Y.......
+[16F0] 75 28 2F F7 2A 70 28 A9 45 1F 75 C2 4E 62 ED D8 u(/.*p(. E.u.Nb..
+[1700] C4 A0 8D 55 B2 84 1C A4 CE 87 EF 24 EE BC CE 40 ...U.... ...$...@
+[1710] 09 EB 05 0B D1 14 31 50 32 2F B6 A8 97 17 4B A7 ......1P 2/....K.
+[1720] 95 01 50 6E 0E 23 49 9C 72 21 91 00 00 00 00 00 ..Pn.#I. r!......
+[1730] 00 00 01 00 00 00 01 00 00 00 17 4B 54 45 53 54 ........ ...KTEST
+[1740] 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 .SAMBA.E XAMPLE.C
+[1750] 4F 4D 00 00 00 0D 61 64 6D 69 6E 69 73 74 72 61 OM....ad ministra
+[1760] 74 6F 72 00 00 00 01 00 00 00 02 00 00 00 17 4B tor..... .......K
+[1770] 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 TEST.SAM BA.EXAMP
+[1780] 4C 45 2E 43 4F 4D 00 00 00 04 63 69 66 73 00 00 LE.COM.. ..cifs..
+[1790] 00 0B 4C 4F 43 41 4C 4B 54 45 53 54 36 00 17 00 ..LOCALK TEST6...
+[17A0] 00 00 10 1D C8 5E 46 48 82 F9 29 DB C6 A6 F1 72 .....^FH ..)....r
+[17B0] 6D 8D E9 4D 99 4F 6A 4D 99 85 09 7D 44 0B 68 00 m..M.OjM ...}D.h.
+[17C0] 00 00 00 00 40 28 00 00 00 00 00 00 00 00 00 00 ....@(.. ........
+[17D0] 00 00 03 FA 61 82 03 F6 30 82 03 F2 A0 03 02 01 ....a... 0.......
+[17E0] 05 A1 19 1B 17 4B 54 45 53 54 2E 53 41 4D 42 41 .....KTE ST.SAMBA
+[17F0] 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D A2 1E 30 1C .EXAMPLE .COM..0.
+[1800] A0 03 02 01 01 A1 15 30 13 1B 04 63 69 66 73 1B .......0 ...cifs.
+[1810] 0B 4C 4F 43 41 4C 4B 54 45 53 54 36 A3 82 03 AE .LOCALKT EST6....
+[1820] 30 82 03 AA A0 03 02 01 17 A1 03 02 01 02 A2 82 0....... ........
+[1830] 03 9C 04 82 03 98 66 D8 19 46 FA CB 73 2D CF 88 ......f. .F..s-..
+[1840] FD 4A EE 07 48 DA 0E BC 58 30 43 40 A4 9C 00 0F .J..H... X0C@....
+[1850] 3B 17 C1 2D F5 9C 3E D9 2F 1D CA 01 9B D7 2E EC ;..-..>. /.......
+[1860] D7 70 ED 8B 8B 1B 5E F2 4E EE DD 0F C0 8D 61 E5 .p....^. N.....a.
+[1870] D7 0A 56 00 32 B1 DB 91 37 29 0F 2F 85 EE A8 43 ..V.2... 7)./...C
+[1880] BA A5 B8 D4 19 74 33 F0 69 52 E1 58 98 83 D6 16 .....t3. iR.X....
+[1890] 0B 44 A9 63 9B D4 4E 6E A7 3E CD 9A 96 4D C4 96 .D.c..Nn .>...M..
+[18A0] F5 07 6D 29 B6 ED 2A 62 3D 53 22 33 D1 95 E9 DF ..m)..*b =S"3....
+[18B0] 74 4C 2A E2 29 AF 5B 69 B0 48 2D AD 94 FD A5 1D tL*.).[i .H-.....
+[18C0] 54 D8 E2 5E C1 68 6F BA 02 01 79 C3 C9 97 0B 76 T..^.ho. ..y....v
+[18D0] 66 45 E2 3B 10 17 95 40 46 E4 85 B9 87 BB CF CF fE.;...@ F.......
+[18E0] 19 8C 3A C0 EA 38 3B B9 E9 4B 05 89 E5 27 8C 62 ..:..8;. .K...'.b
+[18F0] 95 BC 0D 65 F0 D2 C0 5E BC 65 01 D5 0B CB 17 31 ...e...^ .e.....1
+[1900] 0F 06 49 4F A2 4A 70 77 DB BD 92 5B 37 5C EC 06 ..IO.Jpw ...[7\..
+[1910] DF C5 E2 31 C8 40 09 11 68 14 E7 7D CE 54 4F 52 ...1.@.. h..}.TOR
+[1920] 61 31 2C 1C 53 52 DB BE D8 95 39 EE 7D C6 CE C8 a1,.SR.. ..9.}...
+[1930] 22 95 92 97 97 3D 5E 66 0F AD DC C2 4E 2E 2B 9F "....=^f ....N.+.
+[1940] 63 20 30 DF B7 C1 D4 65 AA 6F 2D 10 24 07 20 8D c 0....e .o-.$. .
+[1950] 88 6E 4B 09 04 31 B6 A3 EB F7 37 32 0E 0C 73 C6 .nK..1.. ..72..s.
+[1960] F6 B8 4D D9 0C 4C 5B EC 10 6A 51 19 EA 3F FF 46 ..M..L[. .jQ..?.F
+[1970] E7 73 16 A7 1F 33 98 7C 9B AD 5A 23 A9 40 7C 0F .s...3.| ..Z#.@|.
+[1980] DF EE 0F AA C7 E8 63 07 98 3A 4A 0D 18 62 01 21 ......c. .:J..b.!
+[1990] B2 AE A5 69 B0 C1 15 51 BA 97 D2 C5 42 5B C5 30 ...i...Q ....B[.0
+[19A0] 38 18 A9 48 AB D7 FC A1 BC 9F 71 E7 EA 18 54 42 8..H.... ..q...TB
+[19B0] DA D6 A4 FC C1 DC F3 12 30 62 AC 98 E1 7D 2B 34 ........ 0b...}+4
+[19C0] 1E 52 4C 26 67 32 D9 44 1A 08 27 0E DA D0 FC 84 .RL&g2.D ..'.....
+[19D0] 66 35 81 D6 EB 98 46 6F 1E 47 E0 14 31 BE 47 80 f5....Fo .G..1.G.
+[19E0] 65 AA 0B 20 D6 33 36 3B 0D 40 2F 5A 2E 0E 01 BE e.. .36; .@/Z....
+[19F0] 00 EB 33 3E 4B 32 91 F4 22 96 E5 5F D4 D5 92 94 ..3>K2.. ".._....
+[1A00] CC 5B 59 6A 3E D2 FB A0 4F 99 C4 07 8B 6F 2B 14 .[Yj>... O....o+.
+[1A10] 37 CD 37 44 C0 1F 80 9C 43 46 F2 5E F4 FE D3 39 7.7D.... CF.^...9
+[1A20] 70 61 BE 72 5B 3A 8F 37 95 78 1E AB D9 E7 E9 DA pa.r[:.7 .x......
+[1A30] FC 47 09 81 A0 0D 62 E1 F9 34 36 D1 DB E6 98 D8 .G....b. .46.....
+[1A40] F4 3E 77 5A 4D E2 5F 20 70 3D 3D 5B 34 D9 FD A8 .>wZM._ p==[4...
+[1A50] 31 F7 D9 59 F7 A3 F0 66 F7 D9 AD 1C CD D5 85 33 1..Y...f .......3
+[1A60] A0 87 22 31 D4 F3 67 80 68 20 A2 90 72 7A 6F 64 .."1..g. h ..rzod
+[1A70] FD 68 82 9E 91 B8 E3 F7 6D 6C 38 74 F0 96 A2 F6 .h...... ml8t....
+[1A80] 25 D7 92 58 14 60 9F AE 01 4C 0C 09 67 3E 35 67 %..X.`.. .L..g>5g
+[1A90] 71 1E 2A 86 21 D3 60 61 98 16 94 67 0B 52 76 63 q.*.!.`a ...g.Rvc
+[1AA0] 93 BD A3 3B A9 F0 A2 6A B7 E6 0F 35 64 DA 6A EA ...;...j ...5d.j.
+[1AB0] 20 A6 3D 94 71 59 5E CB B2 D3 F9 4D FE 1B 4B D8 .=.qY^. ...M..K.
+[1AC0] 64 C8 3B 7A A8 E6 D2 D5 76 71 26 D4 5C DA 1A 55 d.;z.... vq&.\..U
+[1AD0] 17 F2 16 C9 2F 77 DB 95 19 48 A5 AC D0 C3 31 9C ..../w.. .H....1.
+[1AE0] 0A CC 1B 44 11 6B 7C 88 7A 5D CF 6E 12 DA EF C5 ...D.k|. z].n....
+[1AF0] C7 34 1D F4 CC EA 37 24 4B B3 0F C1 A3 F2 29 A0 .4....7$ K.....).
+[1B00] D8 93 39 C6 16 57 D5 BF 57 BF 6C 7E F7 90 E0 EB ..9..W.. W.l~....
+[1B10] A3 8B 07 56 9C EC 15 3E 21 DA A5 7C 00 3C F9 D2 ...V...> !..|.<..
+[1B20] A7 1C 6F 16 25 31 C5 28 A7 EA F3 47 31 50 DD E1 ..o.%1.( ...G1P..
+[1B30] ED 0A 93 DB 85 CC 6B 4B 2C 7F E8 F8 2D A9 6D 1D ......kK ,...-.m.
+[1B40] 0A 87 F2 10 8C 82 2F 9B D4 9B 92 8C 77 40 50 42 ....../. ....w@PB
+[1B50] 1E 42 C4 0A 4F E3 6C 6C DC 81 C4 1E BB F0 7D CF .B..O.ll ......}.
+[1B60] 3C 73 22 5B C3 1A 97 35 EE 3A CD 6D F3 68 A3 C5 .xK.
+[1B80] 18 9F A5 25 4A 92 1E 6C 8F 01 D6 59 D7 CF 2E A0 ...%J..l ...Y....
+[1B90] CC 98 F6 75 28 2F F7 2A 70 28 A9 45 1F 75 C2 4E ...u(/.* p(.E.u.N
+[1BA0] 62 ED D8 C4 A0 8D 55 B2 84 1C A4 CE 87 EF 24 EE b.....U. ......$.
+[1BB0] BC CE 40 09 EB 05 0B D1 14 31 50 32 2F B6 A8 97 ..@..... .1P2/...
+[1BC0] 17 4B A7 95 01 50 6E 0E 23 49 9C 72 21 91 00 00 .K...Pn. #I.r!...
+[1BD0] 00 00 00 00 00 01 00 00 00 01 00 00 00 17 4B 54 ........ ......KT
+[1BE0] 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C EST.SAMB A.EXAMPL
+[1BF0] 45 2E 43 4F 4D 00 00 00 0D 61 64 6D 69 6E 69 73 E.COM... .adminis
+[1C00] 74 72 61 74 6F 72 00 00 00 01 00 00 00 02 00 00 trator.. ........
+[1C10] 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 ..KTEST. SAMBA.EX
+[1C20] 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 04 63 69 66 AMPLE.CO M....cif
+[1C30] 73 00 00 00 0B 4C 4F 43 41 4C 4B 54 45 53 54 36 s....LOC ALKTEST6
+[1C40] 00 17 00 00 00 10 1D C8 5E 46 48 82 F9 29 DB C6 ........ ^FH..)..
+[1C50] A6 F1 72 6D 8D E9 4D 99 4F 6A 4D 99 85 09 7D 44 ..rm..M. OjM...}D
+[1C60] 0B 68 00 00 00 00 00 40 28 00 00 00 00 00 00 00 .h.....@ (.......
+[1C70] 00 00 00 00 00 03 FA 61 82 03 F6 30 82 03 F2 A0 .......a ...0....
+[1C80] 03 02 01 05 A1 19 1B 17 4B 54 45 53 54 2E 53 41 ........ KTEST.SA
+[1C90] 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D A2 MBA.EXAM PLE.COM.
+[1CA0] 1E 30 1C A0 03 02 01 01 A1 15 30 13 1B 04 63 69 .0...... ..0...ci
+[1CB0] 66 73 1B 0B 4C 4F 43 41 4C 4B 54 45 53 54 36 A3 fs..LOCA LKTEST6.
+[1CC0] 82 03 AE 30 82 03 AA A0 03 02 01 17 A1 03 02 01 ...0.... ........
+[1CD0] 02 A2 82 03 9C 04 82 03 98 66 D8 19 46 FA CB 73 ........ .f..F..s
+[1CE0] 2D CF 88 FD 4A EE 07 48 DA 0E BC 58 30 43 40 A4 -...J..H ...X0C@.
+[1CF0] 9C 00 0F 3B 17 C1 2D F5 9C 3E D9 2F 1D CA 01 9B ...;..-. .>./....
+[1D00] D7 2E EC D7 70 ED 8B 8B 1B 5E F2 4E EE DD 0F C0 ....p... .^.N....
+[1D10] 8D 61 E5 D7 0A 56 00 32 B1 DB 91 37 29 0F 2F 85 .a...V.2 ...7)./.
+[1D20] EE A8 43 BA A5 B8 D4 19 74 33 F0 69 52 E1 58 98 ..C..... t3.iR.X.
+[1D30] 83 D6 16 0B 44 A9 63 9B D4 4E 6E A7 3E CD 9A 96 ....D.c. .Nn.>...
+[1D40] 4D C4 96 F5 07 6D 29 B6 ED 2A 62 3D 53 22 33 D1 M....m). .*b=S"3.
+[1D50] 95 E9 DF 74 4C 2A E2 29 AF 5B 69 B0 48 2D AD 94 ...tL*.) .[i.H-..
+[1D60] FD A5 1D 54 D8 E2 5E C1 68 6F BA 02 01 79 C3 C9 ...T..^. ho...y..
+[1D70] 97 0B 76 66 45 E2 3B 10 17 95 40 46 E4 85 B9 87 ..vfE.;. ..@F....
+[1D80] BB CF CF 19 8C 3A C0 EA 38 3B B9 E9 4B 05 89 E5 .....:.. 8;..K...
+[1D90] 27 8C 62 95 BC 0D 65 F0 D2 C0 5E BC 65 01 D5 0B '.b...e. ..^.e...
+[1DA0] CB 17 31 0F 06 49 4F A2 4A 70 77 DB BD 92 5B 37 ..1..IO. Jpw...[7
+[1DB0] 5C EC 06 DF C5 E2 31 C8 40 09 11 68 14 E7 7D CE \.....1. @..h..}.
+[1DC0] 54 4F 52 61 31 2C 1C 53 52 DB BE D8 95 39 EE 7D TORa1,.S R....9.}
+[1DD0] C6 CE C8 22 95 92 97 97 3D 5E 66 0F AD DC C2 4E ...".... =^f....N
+[1DE0] 2E 2B 9F 63 20 30 DF B7 C1 D4 65 AA 6F 2D 10 24 .+.c 0.. ..e.o-.$
+[1DF0] 07 20 8D 88 6E 4B 09 04 31 B6 A3 EB F7 37 32 0E . ..nK.. 1....72.
+[1E00] 0C 73 C6 F6 B8 4D D9 0C 4C 5B EC 10 6A 51 19 EA .s...M.. L[..jQ..
+[1E10] 3F FF 46 E7 73 16 A7 1F 33 98 7C 9B AD 5A 23 A9 ?.F.s... 3.|..Z#.
+[1E20] 40 7C 0F DF EE 0F AA C7 E8 63 07 98 3A 4A 0D 18 @|...... .c..:J..
+[1E30] 62 01 21 B2 AE A5 69 B0 C1 15 51 BA 97 D2 C5 42 b.!...i. ..Q....B
+[1E40] 5B C5 30 38 18 A9 48 AB D7 FC A1 BC 9F 71 E7 EA [.08..H. .....q..
+[1E50] 18 54 42 DA D6 A4 FC C1 DC F3 12 30 62 AC 98 E1 .TB..... ...0b...
+[1E60] 7D 2B 34 1E 52 4C 26 67 32 D9 44 1A 08 27 0E DA }+4.RL&g 2.D..'..
+[1E70] D0 FC 84 66 35 81 D6 EB 98 46 6F 1E 47 E0 14 31 ...f5... .Fo.G..1
+[1E80] BE 47 80 65 AA 0B 20 D6 33 36 3B 0D 40 2F 5A 2E .G.e.. . 36;.@/Z.
+[1E90] 0E 01 BE 00 EB 33 3E 4B 32 91 F4 22 96 E5 5F D4 .....3>K 2..".._.
+[1EA0] D5 92 94 CC 5B 59 6A 3E D2 FB A0 4F 99 C4 07 8B ....[Yj> ...O....
+[1EB0] 6F 2B 14 37 CD 37 44 C0 1F 80 9C 43 46 F2 5E F4 o+.7.7D. ...CF.^.
+[1EC0] FE D3 39 70 61 BE 72 5B 3A 8F 37 95 78 1E AB D9 ..9pa.r[ :.7.x...
+[1ED0] E7 E9 DA FC 47 09 81 A0 0D 62 E1 F9 34 36 D1 DB ....G... .b..46..
+[1EE0] E6 98 D8 F4 3E 77 5A 4D E2 5F 20 70 3D 3D 5B 34 ....>wZM ._ p==[4
+[1EF0] D9 FD A8 31 F7 D9 59 F7 A3 F0 66 F7 D9 AD 1C CD ...1..Y. ..f.....
+[1F00] D5 85 33 A0 87 22 31 D4 F3 67 80 68 20 A2 90 72 ..3.."1. .g.h ..r
+[1F10] 7A 6F 64 FD 68 82 9E 91 B8 E3 F7 6D 6C 38 74 F0 zod.h... ...ml8t.
+[1F20] 96 A2 F6 25 D7 92 58 14 60 9F AE 01 4C 0C 09 67 ...%..X. `...L..g
+[1F30] 3E 35 67 71 1E 2A 86 21 D3 60 61 98 16 94 67 0B >5gq.*.! .`a...g.
+[1F40] 52 76 63 93 BD A3 3B A9 F0 A2 6A B7 E6 0F 35 64 Rvc...;. ..j...5d
+[1F50] DA 6A EA 20 A6 3D 94 71 59 5E CB B2 D3 F9 4D FE .j. .=.q Y^....M.
+[1F60] 1B 4B D8 64 C8 3B 7A A8 E6 D2 D5 76 71 26 D4 5C .K.d.;z. ...vq&.\
+[1F70] DA 1A 55 17 F2 16 C9 2F 77 DB 95 19 48 A5 AC D0 ..U..../ w...H...
+[1F80] C3 31 9C 0A CC 1B 44 11 6B 7C 88 7A 5D CF 6E 12 .1....D. k|.z].n.
+[1F90] DA EF C5 C7 34 1D F4 CC EA 37 24 4B B3 0F C1 A3 ....4... .7$K....
+[1FA0] F2 29 A0 D8 93 39 C6 16 57 D5 BF 57 BF 6C 7E F7 .)...9.. W..W.l~.
+[1FB0] 90 E0 EB A3 8B 07 56 9C EC 15 3E 21 DA A5 7C 00 ......V. ..>!..|.
+[1FC0] 3C F9 D2 A7 1C 6F 16 25 31 C5 28 A7 EA F3 47 31 <....o.% 1.(...G1
+[1FD0] 50 DD E1 ED 0A 93 DB 85 CC 6B 4B 2C 7F E8 F8 2D P....... .kK,...-
+[1FE0] A9 6D 1D 0A 87 F2 10 8C 82 2F 9B D4 9B 92 8C 77 .m...... ./.....w
+[1FF0] 40 50 42 1E 42 C4 0A 4F E3 6C 6C DC 81 C4 1E BB @PB.B..O .ll.....
+[2000] F0 7D CF 3C 73 22 5B C3 1A 97 35 EE 3A CD 6D F3 .}..
+[2020] 78 4B BF 18 9F A5 25 4A 92 1E 6C 8F 01 D6 59 D7 xK....%J ..l...Y.
+[2030] CF 2E A0 CC 98 F6 75 28 2F F7 2A 70 28 A9 45 1F ......u( /.*p(.E.
+[2040] 75 C2 4E 62 ED D8 C4 A0 8D 55 B2 84 1C A4 CE 87 u.Nb.... .U......
+[2050] EF 24 EE BC CE 40 09 EB 05 0B D1 14 31 50 32 2F .$...@.. ....1P2/
+[2060] B6 A8 97 17 4B A7 95 01 50 6E 0E 23 49 9C 72 21 ....K... Pn.#I.r!
+[2070] 91 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 ........ ........
+[2080] 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 .KTEST.S AMBA.EXA
+[2090] 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D 61 64 6D 69 MPLE.COM ....admi
+[20A0] 6E 69 73 74 72 61 74 6F 72 00 00 00 01 00 00 00 nistrato r.......
+[20B0] 02 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 .....KTE ST.SAMBA
+[20C0] 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 04 .EXAMPLE .COM....
+[20D0] 68 6F 73 74 00 00 00 0B 6C 6F 63 61 6C 6B 74 65 host.... localkte
+[20E0] 73 74 36 00 17 00 00 00 10 72 47 04 38 B6 E6 F0 st6..... .rG.8...
+[20F0] 44 9E 9F 27 66 E1 69 9C 9A 4D 99 4F 6A 4D 99 90 D..'f.i. .M.OjM..
+[2100] F5 7D 44 0B 68 00 00 00 00 00 40 28 00 00 00 00 .}D.h... ..@(....
+[2110] 00 00 00 00 00 00 00 00 03 FA 61 82 03 F6 30 82 ........ ..a...0.
+[2120] 03 F2 A0 03 02 01 05 A1 19 1B 17 4B 54 45 53 54 ........ ...KTEST
+[2130] 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 .SAMBA.E XAMPLE.C
+[2140] 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 15 30 13 1B OM..0... .....0..
+[2150] 04 68 6F 73 74 1B 0B 6C 6F 63 61 6C 6B 74 65 73 .host..l ocalktes
+[2160] 74 36 A3 82 03 AE 30 82 03 AA A0 03 02 01 17 A1 t6....0. ........
+[2170] 03 02 01 02 A2 82 03 9C 04 82 03 98 58 95 95 EB ........ ....X...
+[2180] CB 8F 68 D4 77 43 0F 3B 44 B4 15 DA 40 6D FD E9 ..h.wC.; D...@m..
+[2190] 85 D3 2F CD B5 1E 96 CD F6 E9 67 91 36 08 9E B4 ../..... ..g.6...
+[21A0] B3 47 70 7A B3 4E 82 5A 4F 8E 4B F5 8D 04 E4 5C .Gpz.N.Z O.K....\
+[21B0] C4 D8 0C AF 08 25 F9 C1 64 B2 3A 35 26 E9 B2 72 .....%.. d.:5&..r
+[21C0] 66 B5 E9 81 FC BE 12 1B CC 8A A5 82 31 F6 7F C3 f....... ....1...
+[21D0] 5A 19 A3 31 F2 99 14 1E 64 E4 41 E8 C7 C3 F3 DF Z..1.... d.A.....
+[21E0] F5 65 7D B0 9F DC 5D 25 1D 1A A8 EA AA 88 6D F4 .e}...]% ......m.
+[21F0] 7C 25 9F 53 F6 A6 8F B1 24 AF 98 FE 53 7B 35 3C |%.S.... $...S{5<
+[2200] DB EC 7F 09 74 E9 C4 8D 20 B4 47 08 0E 32 B8 C9 ....t... .G..2..
+[2210] 45 27 12 F9 8E F5 D6 C2 DD 1A 96 0E 68 5F 39 65 E'...... ....h_9e
+[2220] 72 C7 BD 8E 04 0E 13 E1 03 27 AC 50 80 76 E6 7A r....... .'.P.v.z
+[2230] 8E F4 C2 72 4F 68 B3 34 00 A9 54 41 DA FD 96 94 ...rOh.4 ..TA....
+[2240] 29 A1 59 15 2F DB 6C 94 85 49 C5 D0 6D 48 B0 C4 ).Y./.l. .I..mH..
+[2250] 65 D0 95 1D DB 3D 25 D0 75 50 D4 CF FA 2F 71 57 e....=%. uP.../qW
+[2260] BD 6C 1C 59 E1 C3 5B C7 24 95 FF B0 20 EF 6A DB .l.Y..[. $... .j.
+[2270] 79 87 67 91 94 E9 16 E2 BB 74 7A 08 E1 6A 36 5F y.g..... .tz..j6_
+[2280] DF 11 AB 35 9B 3E 32 48 83 89 41 4E 06 BF F9 BB ...5.>2H ..AN....
+[2290] EC E4 D7 6D 77 C4 55 22 DF F7 91 4D CB C5 01 A5 ...mw.U" ...M....
+[22A0] BA 2D 1E 92 76 04 E8 02 2F 5E AF 1C B3 B7 A6 FB .-..v... /^......
+[22B0] 3A 9F D9 7C 6D DA B4 8F 31 00 A5 30 F2 76 72 9B :..|m... 1..0.vr.
+[22C0] 62 97 E0 56 E5 E4 C7 6B 8B FC 84 75 57 66 6E D7 b..V...k ...uWfn.
+[22D0] B7 41 6F 61 F4 5B 0F 87 68 F6 54 02 26 1B 1F B7 .Aoa.[.. h.T.&...
+[22E0] 60 D6 E7 FA 4F C7 DB 35 58 EC 13 21 D4 C6 A1 27 `...O..5 X..!...'
+[22F0] BA E7 82 DF 29 FB 9D 5D E8 35 28 C9 9C 4E D7 BE ....)..] .5(..N..
+[2300] 2F 6D F1 E8 0B 5A 74 C9 93 9F AD 42 24 4B B7 3B /m...Zt. ...B$K.;
+[2310] 38 2A 11 CF F0 BD 85 40 48 D8 9D E7 6B 65 70 42 8*.....@ H...kepB
+[2320] 60 DA 9B 65 CB C8 C5 D7 40 3A 12 DC 64 AF 82 54 `..e.... @:..d..T
+[2330] 34 05 38 4F C6 FB 38 E2 73 A9 89 B7 FC 33 15 85 4.8O..8. s....3..
+[2340] 9E CA E9 E0 89 18 18 84 02 65 B4 74 5B D4 A1 6F ........ .e.t[..o
+[2350] 5F 79 20 CB D7 36 C8 6D 5B 1E 5E 0C 82 16 9F CC _y ..6.m [.^.....
+[2360] 5A 1E 57 C1 B6 94 51 87 A1 3D 12 D4 8B FE 0F 93 Z.W...Q. .=......
+[2370] ED 53 A3 F4 88 3C 35 05 89 FE AF 0B 36 62 E3 2F .S...<5. ....6b./
+[2380] 5C 4A 0E 07 67 39 A3 8E C0 45 07 7F 73 32 BC DE \J..g9.. .E..s2..
+[2390] 2D 00 8B 47 79 3D 1C A1 90 AE B6 8F 83 B2 1B 31 -..Gy=.. .......1
+[23A0] EE E4 F2 C5 C1 4A E2 4A 2F 28 F0 AA 19 43 6A 14 .....J.J /(...Cj.
+[23B0] B1 42 61 90 34 2E EE 3D 16 9F 5D 9F 7A A2 01 7A .Ba.4..= ..].z..z
+[23C0] 4B 96 FA 4D C9 85 1A 75 27 B7 6B FD 4D 7D 9C 65 K..M...u '.k.M}.e
+[23D0] 97 DB 05 CC 76 68 EA 05 5D 5D BB BD 51 4B 5B F2 ....vh.. ]]..QK[.
+[23E0] 48 59 BD 1E AD 56 D4 69 A5 75 CD ED EC B1 3E AB HY...V.i .u....>.
+[23F0] FA B7 F8 8D 4F BE 95 63 38 1C 4C 70 26 C4 3A 21 ....O..c 8.Lp&.:!
+[2400] 80 61 05 3A D4 E2 28 2C 85 01 5A DA FC 10 60 F3 .a.:..(, ..Z...`.
+[2410] 74 0C FD DB 2F 5B 25 4B 14 E4 7D 8A DB 85 12 D2 t.../[%K ..}.....
+[2420] D7 69 CD B5 B1 93 CE E5 E6 4D 57 D3 C2 D3 2E A0 .i...... .MW.....
+[2430] 08 37 09 CD 19 99 09 FA 33 68 4A E0 92 46 21 0C .7...... 3hJ..F!.
+[2440] 99 9F DA 05 15 20 8B 3D 7C 7B CA D6 81 AC AA 83 ..... .= |{......
+[2450] 48 C8 24 4C C8 FC A5 14 2C BC 49 1A 1C 49 61 1D H.$L.... ,.I..Ia.
+[2460] 24 86 42 B1 37 6A C8 3A AC 18 CC C0 50 84 12 48 $.B.7j.: ....P..H
+[2470] 8B 29 0A 49 26 A4 E2 B9 E5 96 E7 37 C3 DE 4C 23 .).I&... ...7..L#
+[2480] D2 D4 62 14 8F 1E 72 39 CF 03 BC A3 00 C7 63 51 ..b...r9 ......cQ
+[2490] A9 6B E4 3E B2 65 A1 A2 BB EC 06 41 85 50 22 02 .k.>.e.. ...A.P".
+[24A0] 46 2F 72 2B 32 1A A4 2D 85 94 02 47 69 8D AD 6D F/r+2..- ...Gi..m
+[24B0] 66 AB D4 E4 29 C8 C7 DA F4 18 31 2A DF 50 6A 05 f...)... ..1*.Pj.
+[24C0] D6 47 26 C4 F9 87 0F 35 24 6E 72 D6 23 7D 3A 94 .G&....5 $nr.#}:.
+[24D0] 14 8D E8 57 AA BA D7 CF A9 2D E7 4C 10 7C D8 0D ...W.... .-.L.|..
+[24E0] 51 30 1F E1 FB E5 E2 6C EE AA 65 2F D8 22 05 67 Q0.....l ..e/.".g
+[24F0] 87 4D 4D D2 11 3D B4 1E AA 20 3F 76 E3 94 93 6D .MM..=.. . ?v...m
+[2500] AC 10 05 AF 09 BD 67 86 C5 83 93 D6 1C D3 81 D9 ......g. ........
+[2510] B1 3B E1 76 00 00 00 00 00 00 00 01 00 00 00 01 .;.v.... ........
+[2520] 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E ....KTES T.SAMBA.
+[2530] 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D 61 EXAMPLE. COM....a
+[2540] 64 6D 69 6E 69 73 74 72 61 74 6F 72 00 00 00 01 dministr ator....
+[2550] 00 00 00 02 00 00 00 17 4B 54 45 53 54 2E 53 41 ........ KTEST.SA
+[2560] 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 MBA.EXAM PLE.COM.
+[2570] 00 00 04 68 6F 73 74 00 00 00 0B 4C 4F 43 41 4C ...host. ...LOCAL
+[2580] 4B 54 45 53 54 36 00 17 00 00 00 10 55 6E 3E FC KTEST6.. ....Un>.
+[2590] E2 F4 40 51 19 E6 6E EB 23 4C 48 8E 4D 99 4F 6A ..@Q..n. #LH.M.Oj
+[25A0] 4D 99 90 FC 7D 44 0B 68 00 00 00 00 00 40 28 00 M...}D.h .....@(.
+[25B0] 00 00 00 00 00 00 00 00 00 00 00 03 FA 61 82 03 ........ .....a..
+[25C0] F6 30 82 03 F2 A0 03 02 01 05 A1 19 1B 17 4B 54 .0...... ......KT
+[25D0] 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C EST.SAMB A.EXAMPL
+[25E0] 45 2E 43 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 15 E.COM..0 ........
+[25F0] 30 13 1B 04 68 6F 73 74 1B 0B 4C 4F 43 41 4C 4B 0...host ..LOCALK
+[2600] 54 45 53 54 36 A3 82 03 AE 30 82 03 AA A0 03 02 TEST6... .0......
+[2610] 01 17 A1 03 02 01 02 A2 82 03 9C 04 82 03 98 6E ........ .......n
+[2620] 87 B7 7B 3A 7E EF 4A 1B 29 C9 E3 C4 1F 42 4F 0E ..{:~.J. )....BO.
+[2630] C8 AC AC 4E A2 77 1D DA 93 37 F1 AF DA A3 75 2D ...N.w.. .7....u-
+[2640] 12 8B 40 34 23 0E 8E A9 90 58 46 42 42 39 31 D6 ..@4#... .XFBB91.
+[2650] 03 9E 5D 81 D9 E8 F6 08 2B D9 96 88 8A 2F F1 CC ..]..... +..../..
+[2660] F2 EA 9E 9A 4B 31 B6 04 2D 3D 4C 7F 92 DE 3B 04 ....K1.. -=L...;.
+[2670] 19 EE 28 D0 83 81 C3 46 CD 74 23 4C 14 34 DE 62 ..(....F .t#L.4.b
+[2680] 0A AC E5 12 16 75 E9 A8 4B 32 78 CC 8D AE A2 E5 .....u.. K2x.....
+[2690] 6D E8 09 70 76 52 F5 E5 18 F7 E7 91 15 6A 69 AB m..pvR.. .....ji.
+[26A0] B8 62 DD 80 F5 28 6D DF ED 10 DA AC FB 92 27 CF .b...(m. ......'.
+[26B0] 98 B5 77 9D A5 96 E6 9A CC B9 C3 91 78 22 35 9C ..w..... ....x"5.
+[26C0] A1 13 A3 20 28 D1 16 E5 3E 4A 85 1E 12 0B CA 4D ... (... >J.....M
+[26D0] C6 C8 03 C8 28 2C D8 29 5D 9A 76 4A 92 13 43 56 ....(,.) ].vJ..CV
+[26E0] AF F7 C1 71 25 72 5C 38 75 1C 07 F1 5E 86 05 72 ...q%r\8 u...^..r
+[26F0] 6F 69 95 42 B6 F2 DA A9 91 06 9F B9 54 20 33 A5 oi.B.... ....T 3.
+[2700] 31 60 3B 54 DC 3A 95 34 96 26 07 52 6B 0E 1D 3B 1`;T.:.4 .&.Rk..;
+[2710] D9 F8 48 20 AC CD 05 3B 99 F8 EE DB 83 28 CD C7 ..H ...; .....(..
+[2720] 2F 45 00 7E 2F 0A 65 7A D1 9E 95 4B EE C3 34 93 /E.~/.ez ...K..4.
+[2730] A8 C7 DF 03 8B 14 D0 FC CE 56 90 AC EE 93 C5 D3 ........ .V......
+[2740] F7 12 24 69 0B 20 8D A2 65 87 55 26 2A F9 9A 88 ..$i. .. e.U&*...
+[2750] D7 0D 86 61 D6 92 B6 FE E5 D1 66 F9 1F 9D F4 04 ...a.... ..f.....
+[2760] 48 A6 39 BC 54 20 EA 10 21 E9 6D 30 46 1D C2 1C H.9.T .. !.m0F...
+[2770] A4 E8 B4 63 85 37 27 25 80 52 41 60 C7 A1 32 21 ...c.7'% .RA`..2!
+[2780] 43 90 02 E6 5F 5A E9 4E AF F9 B5 13 BD 42 BD A3 C..._Z.N .....B..
+[2790] A5 4D 10 45 83 4D 92 18 1F C9 CF FB 84 29 89 23 .M.E.M.. .....).#
+[27A0] AC 71 4B 89 1B 52 E5 06 8C 3E 7C 88 CB D3 B3 CF .qK..R.. .>|.....
+[27B0] B9 7A 67 D6 24 F4 AC 00 A6 AD 91 30 9A 95 53 F1 .zg.$... ...0..S.
+[27C0] 48 06 A6 39 DB CF DC 9D C9 55 76 26 5E C1 DB 5D H..9.... .Uv&^..]
+[27D0] B3 5B 3E AE 1A A0 10 BA 82 21 83 44 02 E0 99 33 .[>..... .!.D...3
+[27E0] 40 BA 29 9E 28 E5 73 4C 23 94 A2 4F BF 07 ED 4F @.).(.sL #..O...O
+[27F0] 7C 45 9B 30 C8 41 6B 0A 55 13 6E F5 AD 7A 0C B2 |E.0.Ak. U.n..z..
+[2800] EA FF D0 06 13 4D F3 24 82 7F F6 51 2F 4A 4F 0D .....M.$ ...Q/JO.
+[2810] 37 F8 14 6B E9 E4 82 BB 3A 75 63 63 12 E8 78 6F 7..k.... :ucc..xo
+[2820] 6F FC 6C D3 4B A6 F1 CC 2A F1 7D EB 82 26 2F D0 o.l.K... *.}..&/.
+[2830] A1 8B 3E 9A 71 D7 91 D3 08 E6 FD 62 1B 84 13 2D ..>.q... ...b...-
+[2840] 8E A0 A0 C3 85 78 2F 0D F8 E7 10 FC CB 05 A7 B9 .....x/. ........
+[2850] 9A 33 90 B5 9B 26 E3 23 98 B0 91 4B EB 32 37 D6 .3...&.# ...K.27.
+[2860] F4 ED 61 08 D8 75 CC 03 83 2C 3C CF 21 63 9C F6 ..a..u.. .,<.!c..
+[2870] AF 5B 4F 12 07 74 17 CD 98 BB E7 5E C7 17 2D C4 .[O..t.. ...^..-.
+[2880] 87 A4 74 6D 5E CE DB A3 01 B9 AD 20 73 38 78 22 ..tm^... ... s8x"
+[2890] 3D 45 F5 51 77 C6 47 63 45 61 81 D9 FF 31 90 C4 =E.Qw.Gc Ea...1..
+[28A0] 6F 5A F8 FE 6A 56 5B D4 EE EC 49 C7 A7 51 AE 5C oZ..jV[. ..I..Q.\
+[28B0] 85 53 70 3D 1A 49 83 59 CF 65 58 B3 48 7E 04 9E .Sp=.I.Y .eX.H~..
+[28C0] C7 64 8A 05 73 E3 DC 1A 65 5D 4F 41 01 56 73 90 .d..s... e]OA.Vs.
+[28D0] 61 F3 84 1F FF CF 46 B2 06 46 56 97 93 B9 DB 32 a.....F. .FV....2
+[28E0] 2A 64 8A 48 02 05 84 E9 FA 76 8B 94 96 89 A0 73 *d.H.... .v.....s
+[28F0] 20 75 4D 52 1D 23 13 D1 83 D7 5D 59 23 6A 87 C1 uMR.#.. ..]Y#j..
+[2900] 09 3E 01 3A 28 65 42 8C 35 F1 91 EA 6A 1F 83 0D .>.:(eB. 5...j...
+[2910] 8F 57 69 81 D4 A2 D2 EA 0C BF AF 95 A3 F4 90 15 .Wi..... ........
+[2920] 61 34 F2 6C 8B D0 DA B5 1E 43 AC CE C7 8A 1B 2B a4.l.... .C.....+
+[2930] 29 2B 89 1C C5 53 C8 04 F7 1E 46 72 F3 A8 CE F7 )+...S.. ..Fr....
+[2940] 59 76 55 E7 53 1C A2 9F D8 23 F7 EA 71 B0 74 83 YvU.S... .#..q.t.
+[2950] 71 95 3E DC A6 FA 2D A4 42 13 93 8B 2B FA A2 70 q.>...-. B...+..p
+[2960] 25 21 2D F6 E1 26 56 DF 58 79 25 16 E8 C9 03 EC %!-..&V. Xy%.....
+[2970] 72 5F 35 CF 59 6B E1 AD 85 85 7B AB 78 F2 0D AC r_5.Yk.. ..{.x...
+[2980] AB 89 F2 DA 85 E7 DE 09 77 99 EC 7C F3 97 1F 71 ........ w..|...q
+[2990] 3C DB 09 44 7A 3C 69 E5 03 B0 6D 4D 3B 6B 4C D5 <..Dz.......
+[0150] 1A 69 EE 8C 4E A4 D8 55 A5 0B 23 0F D0 89 48 C4 .i..N..U ..#...H.
+[0160] 51 FE 32 FD CC F6 71 E1 95 2D CC 1D 0A 0C 8A A2 Q.2...q. .-......
+[0170] 69 58 3B 65 88 53 EC D0 2E E1 C6 CC 6B BC 09 E5 iX;e.S.. ....k...
+[0180] B9 15 27 8B E4 B2 24 18 61 42 BB 8B 09 1B 8A 7B ..'...$. aB.....{
+[0190] 13 D8 51 E1 0B 79 12 48 DE A9 54 04 00 6D DD E6 ..Q..y.H ..T..m..
+[01A0] 5E 03 91 FF C7 6D 0B 7C 91 44 E1 0F C0 7E 32 34 ^....m.| .D...~24
+[01B0] 82 86 94 F7 CD 53 EC 52 38 18 AA ED FF FC 5C 01 .....S.R 8.....\.
+[01C0] D2 EE 99 45 8E 5B E6 B3 46 B0 F6 3B 22 29 EC 11 ...E.[.. F..;")..
+[01D0] 30 6A F6 A1 1F 9E AE 71 E3 A6 E7 3F F3 7D 2B 75 0j.....q ...?.}+u
+[01E0] 70 4D 63 47 5C 18 2C 8B B1 1A 69 B6 C5 46 01 17 pMcG\.,. ..i..F..
+[01F0] 8E 64 3D 47 88 20 1C AA D7 60 32 28 11 60 EA 28 .d=G. .. .`2(.`.(
+[0200] 66 99 4C B1 2A 28 96 BF 18 2A 3E F4 D6 84 E5 A0 f.L.*(.. .*>.....
+[0210] F4 4E E7 F9 54 95 22 96 2A 87 01 CC 3E A7 FF 42 .N..T.". *...>..B
+[0220] 6A A4 4A 3A B9 24 10 65 99 53 58 2A 4E 72 E7 1F j.J:.$.e .SX*Nr..
+[0230] 82 BC BD 3C 6C 9D 33 3A CE C6 6E 72 A2 81 B3 84 ........
+[0280] AB F0 D0 93 08 42 E5 37 19 24 4E C1 AF FC 92 A9 .....B.7 .$N.....
+[0290] B1 27 B1 9A 2A 62 34 F1 DC C0 6B 83 AE C3 74 E8 .'..*b4. ..k...t.
+[02A0] A3 05 DD 82 DD A3 D7 90 A8 E3 9C EB 64 16 23 06 ........ ....d.#.
+[02B0] 5D FB E4 35 7C 22 29 78 E3 3B 75 92 91 0C 9D A1 ]..5|")x .;u.....
+[02C0] 87 7C 2E 82 AE 49 9D 4A 50 A9 C2 D5 85 B0 16 5D .|...I.J P......]
+[02D0] A2 CD B0 DD 29 3F 6F 66 C9 C1 9F 5C F0 B6 FC D2 ....)?of ...\....
+[02E0] 52 BE 7B F0 1F 26 AF 8A FC C3 A6 24 8C C0 10 06 R.{..&.. ...$....
+[02F0] 73 1E 17 9E 6E 6F 32 44 6A DF 82 5D D0 6B 74 CE s...no2D j..].kt.
+[0300] 58 0B 4C 7B EB A1 13 44 B1 3E D8 F8 BA F4 4E 55 X.L{...D .>....NU
+[0310] 71 3D C1 09 D9 E7 97 9A 14 5C 54 7E 57 81 5F 6B q=...... .\T~W._k
+[0320] 30 BE 9A E1 98 29 47 D4 C0 8F 63 0A F8 27 1F CE 0....)G. ..c..'..
+[0330] ED D9 BB 7B 12 24 D0 34 2A 7C F0 F7 77 F4 F1 1D ...{.$.4 *|..w...
+[0340] 4C 5D 75 2D 6B 0D 80 35 82 CC D8 7A 6B FA A0 55 L]u-k..5 ...zk..U
+[0350] 34 CD 87 15 61 38 78 D4 69 0F AA 72 D6 AC FA 99 4...a8x. i..r....
+[0360] BC 70 39 27 A7 25 2E 1B 6F 36 01 FD E9 B4 9A 79 .p9'.%.. o6.....y
+[0370] 6C 19 DD A6 8C 78 B0 40 92 60 58 F0 28 AD 08 78 l....x.@ .`X.(..x
+[0380] 4A 29 06 2C 82 2B 1A E3 91 0B 5F EE D6 B8 66 47 J).,.+.. .._...fG
+[0390] 31 9B A3 DF 9F 79 D7 BB 0E 2C FA 0E C9 66 84 8D 1....y.. .,...f..
+[03A0] FF BA BB 21 27 9E AD 86 84 55 8D 4C 4C 47 D9 5F ...!'... .U.LLG._
+[03B0] B2 7D 26 CA B7 49 3C 9D 1B 67 71 11 3A 8A EB EA .}&..I<. .gq.:...
+[03C0] 0F 15 EB F0 1E 46 F7 A4 34 04 D7 E3 50 67 47 D3 .....F.. 4...PgG.
+[03D0] 66 21 17 77 51 A7 1F 1D 84 3B 7C B1 5D 4E B8 D4 f!.wQ... .;|.]N..
+[03E0] F9 C5 75 06 AA 19 45 1C E9 06 9E AD 23 26 6B 10 ..u...E. ....#&k.
+[03F0] 53 A0 36 D3 58 9F 5E 8C CB A5 F6 BC C9 30 3C BC S.6.X.^. .....0<.
+[0400] AD FF 7C 92 F0 C6 9A 02 ..|.....
+ second_ticket : DATA_BLOB length=0
+ further_creds : DATA_BLOB length=10683
+[0000] 00 00 00 01 00 00 00 01 00 00 00 17 4B 54 45 53 ........ ....KTES
+[0010] 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E T.SAMBA. EXAMPLE.
+[0020] 43 4F 4D 00 00 00 0D 61 64 6D 69 6E 69 73 74 72 COM....a dministr
+[0030] 61 74 6F 72 00 00 00 01 00 00 00 02 00 00 00 17 ator.... ........
+[0040] 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D KTEST.SA MBA.EXAM
+[0050] 50 4C 45 2E 43 4F 4D 00 00 00 04 63 69 66 73 00 PLE.COM. ...cifs.
+[0060] 00 00 0B 6C 6F 63 61 6C 6B 74 65 73 74 36 00 17 ...local ktest6..
+[0070] 00 00 00 10 00 6E A1 B2 31 6D 48 C7 90 72 3A 0C .....n.. 1mH..r:.
+[0080] 4B 8B 83 8C 4D 99 4F 6A 4D 99 50 85 7D 44 0B 68 K...M.Oj M.P.}D.h
+[0090] 00 00 00 00 00 40 28 00 00 00 00 00 00 00 00 00 .....@(. ........
+[00A0] 00 00 00 03 FA 61 82 03 F6 30 82 03 F2 A0 03 02 .....a.. .0......
+[00B0] 01 05 A1 19 1B 17 4B 54 45 53 54 2E 53 41 4D 42 ......KT EST.SAMB
+[00C0] 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D A2 1E 30 A.EXAMPL E.COM..0
+[00D0] 1C A0 03 02 01 01 A1 15 30 13 1B 04 63 69 66 73 ........ 0...cifs
+[00E0] 1B 0B 6C 6F 63 61 6C 6B 74 65 73 74 36 A3 82 03 ..localk test6...
+[00F0] AE 30 82 03 AA A0 03 02 01 17 A1 03 02 01 02 A2 .0...... ........
+[0100] 82 03 9C 04 82 03 98 C6 BB 64 A8 31 00 FC 5E 51 ........ .d.1..^Q
+[0110] 3C 87 F8 34 47 3B D0 6F 6F FD 9E A6 91 12 74 2D <..4G;.o o.....t-
+[0120] 44 BB AA 91 A0 2D 46 3E 9E FB FB C4 FB F1 15 FD D....-F> ........
+[0130] BB DA EE 06 A9 20 6A 38 DC 46 06 27 D9 A2 9D 2D ..... j8 .F.'...-
+[0140] 1F FD 0D 7D 8A BB 0A 7C E8 47 17 BC 7B 70 E4 51 ...}...| .G..{p.Q
+[0150] 6A BA 51 68 62 28 4A 1E 51 D1 0D CD 02 55 75 44 j.Qhb(J. Q....UuD
+[0160] 8A B9 C2 84 F4 17 34 92 9B 31 85 9E 43 C1 0C 3A ......4. .1..C..:
+[0170] B2 69 7F 20 1A 18 1F 65 4F C0 20 C9 B5 AF E1 61 .i. ...e O. ....a
+[0180] 8C 90 10 63 26 A6 5D 05 3C CD 29 BB 7B 74 D5 8F ...c&.]. <.).{t..
+[0190] 2C 7F 4B E8 84 24 57 37 8A C6 F7 91 FD 22 9A A5 ,.K..$W7 ....."..
+[01A0] 0D E9 4A 78 93 36 FC A8 8C 8A 27 8A C6 28 4B 7B ..Jx.6.. ..'..(K{
+[01B0] DA 11 42 BC 09 10 81 82 14 0F 9C B8 48 26 91 78 ..B..... ....H&.x
+[01C0] A8 DD 97 6C 24 A1 D2 E8 85 19 B3 D3 85 4D 38 C7 ...l$... .....M8.
+[01D0] 7D 49 55 8E 85 46 E1 EE 7B BA 11 62 63 53 C5 16 }IU..F.. {..bcS..
+[01E0] 4A 0C 1C 99 7C 0E FB 45 1D B4 98 58 67 7E 40 65 J...|..E ...Xg~@e
+[01F0] 4B 48 E2 89 9C 8B C2 B8 39 D1 04 C0 A8 56 E8 A1 KH...... 9....V..
+[0200] 04 7A 7A C9 60 18 A0 29 E2 DC 82 4C 8F 18 CE 2F .zz.`..) ...L.../
+[0210] 14 F0 18 5B 6C FF 85 45 88 73 CB A4 55 08 FC BF ...[l..E .s..U...
+[0220] C7 9F 51 0A DB 2C C1 E3 3C DD F6 F0 A3 2D F1 3B ..Q..,.. <....-.;
+[0230] A0 12 1D FC 2A 67 F5 1A 7F E5 7C 6C FB 8A 18 BD ....*g.. ..|l....
+[0240] D1 5D E5 5E 68 30 AA 58 9E 10 13 E0 26 7E 7D C4 .].^h0.X ....&~}.
+[0250] E1 A5 B6 86 0F 1C 0F 13 A4 5E 5E 6A ED 42 79 31 ........ .^^j.By1
+[0260] BB B3 5F 3A 3F DD CB 63 82 FB 06 AE 12 36 C9 1E .._:?..c .....6..
+[0270] 06 7D 41 82 2E D2 FA 26 EC 17 50 5E D0 DE 26 85 .}A....& ..P^..&.
+[0280] 30 71 BC 45 3B DA 2E 08 8D B2 2A 3C E0 79 8F 77 0q.E;... ..*<.y.w
+[0290] 4C 01 69 7A 09 C7 88 E1 D1 DC FF 78 DB 25 7B B1 L.iz.... ...x.%{.
+[02A0] 3C BB 22 27 80 0D 75 96 18 B6 40 95 6D C8 AB 04 <."'..u. ..@.m...
+[02B0] 05 41 A1 C4 25 71 C4 53 3A A6 9C B2 4D E6 15 2C .A..%q.S :...M..,
+[02C0] B2 47 6C DA A8 7D CC A3 89 8B C9 1E 21 F5 E9 B2 .Gl..}.. ....!...
+[02D0] 42 95 68 28 AF C6 37 22 BA 30 8D 53 FA 08 0D CE B.h(..7" .0.S....
+[02E0] CA 81 61 0D 84 A5 2D 75 BD 41 85 4C 88 56 72 C6 ..a...-u .A.L.Vr.
+[02F0] B6 10 F8 34 CD B2 F4 5C 94 FA 80 90 82 A0 BD 68 ...4...\ .......h
+[0300] EC 08 32 C3 B6 51 1E 3F 67 CB 7B EB 70 83 84 D4 ..2..Q.? g.{.p...
+[0310] CB 52 55 36 61 1E 60 90 5B 6F FE 9A 62 05 CF 26 .RU6a.`. [o..b..&
+[0320] 8E 65 E2 60 4B ED 63 B4 C4 E6 44 B4 2F B0 B8 07 .e.`K.c. ..D./...
+[0330] FE BE 0D 50 E4 56 A4 2E 0D 25 76 0B 0F 44 09 20 ...P.V.. .%v..D.
+[0340] 80 E5 C4 94 63 E0 54 46 1D AB 5E 0B 09 93 B1 30 ....c.TF ..^....0
+[0350] 31 7B 04 DC 23 43 3B DB 7D 39 67 FE 9A 1F C1 08 1{..#C;. }9g.....
+[0360] AF 34 24 F6 74 E4 14 DA 34 8F 61 57 6A 7F 1D 4A .4$.t... 4.aWj..J
+[0370] 88 0A 90 78 93 F1 86 54 DB 22 86 D6 69 0F DF 44 ...x...T ."..i..D
+[0380] 7C D3 6B 9D 41 63 50 98 3A 97 B9 7B 4C 53 E3 85 |.k.AcP. :..{LS..
+[0390] 73 9A C9 08 A0 75 12 50 02 87 B0 CF CC 84 84 D9 s....u.P ........
+[03A0] BC FC 94 79 AF 6A A6 08 FF 19 7E E9 22 9B EC 5C ...y.j.. ..~."..\
+[03B0] C1 6B 1D A4 B4 55 32 5E 23 C3 C0 D4 8B 80 E6 67 .k...U2^ #......g
+[03C0] B1 59 EB 9D 5D 9B AD C6 0E 7D E2 FE B1 24 8A B1 .Y..]... .}...$..
+[03D0] 37 1E 60 7F 83 35 48 32 F7 03 E8 12 E6 21 7C 3D 7.`..5H2 .....!|=
+[03E0] 21 7F 6B 14 31 9C 1A A3 4C 2B 1C 5E EC 34 C1 2D !.k.1... L+.^.4.-
+[03F0] DA 19 6C E6 6D 8D 60 D7 55 9E E6 D0 B5 07 06 72 ..l.m.`. U......r
+[0400] C0 E9 4E 91 94 6B 3E 0B F1 0A 75 4D E8 CB 53 6B ..N..k>. ..uM..Sk
+[0410] 34 A4 2F 96 A5 39 1A 18 6E 27 00 6D 41 B7 D8 F5 4./..9.. n'.mA...
+[0420] 9A E5 01 FC 0B A8 97 56 EE 98 04 1D 98 84 5E 82 .......V ......^.
+[0430] C8 E8 EC 17 D5 FA 96 00 3B E1 98 1C D8 FA 66 A0 ........ ;.....f.
+[0440] DC 32 60 F6 03 46 08 3C E5 16 6F F2 8B 4D 72 9F .2`..F.< ..o..Mr.
+[0450] 0F E0 A9 71 6E 7C AE AA FB A3 4D F1 A1 B6 1B 9F ...qn|.. ..M.....
+[0460] 62 71 E1 2C 82 9B AE E3 07 9B 79 90 F1 C2 69 E5 bq.,.... ..y...i.
+[0470] 7E CB 57 E6 C9 1C 4E A8 C7 12 EA 4F 4C 52 17 03 ~.W...N. ...OLR..
+[0480] AB D4 FD 34 60 F4 7C BE 9E 36 30 37 88 95 61 2E ...4`.|. .607..a.
+[0490] CF 70 AF 22 70 DB E8 AA 6E 3D 30 F7 4D 84 D5 00 .p."p... n=0.M...
+[04A0] 00 00 00 00 00 00 01 00 00 00 01 00 00 00 17 4B ........ .......K
+[04B0] 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 TEST.SAM BA.EXAMP
+[04C0] 4C 45 2E 43 4F 4D 00 00 00 0D 61 64 6D 69 6E 69 LE.COM.. ..admini
+[04D0] 73 74 72 61 74 6F 72 00 00 00 01 00 00 00 02 00 strator. ........
+[04E0] 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 ...KTEST .SAMBA.E
+[04F0] 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 04 63 69 XAMPLE.C OM....ci
+[0500] 66 73 00 00 00 0B 6C 6F 63 61 6C 6B 74 65 73 74 fs....lo calktest
+[0510] 36 00 17 00 00 00 10 00 6E A1 B2 31 6D 48 C7 90 6....... n..1mH..
+[0520] 72 3A 0C 4B 8B 83 8C 4D 99 4F 6A 4D 99 50 85 7D r:.K...M .OjM.P.}
+[0530] 44 0B 68 00 00 00 00 00 40 28 00 00 00 00 00 00 D.h..... @(......
+[0540] 00 00 00 00 00 00 03 FA 61 82 03 F6 30 82 03 F2 ........ a...0...
+[0550] A0 03 02 01 05 A1 19 1B 17 4B 54 45 53 54 2E 53 ........ .KTEST.S
+[0560] 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D AMBA.EXA MPLE.COM
+[0570] A2 1E 30 1C A0 03 02 01 01 A1 15 30 13 1B 04 63 ..0..... ...0...c
+[0580] 69 66 73 1B 0B 6C 6F 63 61 6C 6B 74 65 73 74 36 ifs..loc alktest6
+[0590] A3 82 03 AE 30 82 03 AA A0 03 02 01 17 A1 03 02 ....0... ........
+[05A0] 01 02 A2 82 03 9C 04 82 03 98 C6 BB 64 A8 31 00 ........ ....d.1.
+[05B0] FC 5E 51 3C 87 F8 34 47 3B D0 6F 6F FD 9E A6 91 .^Q<..4G ;.oo....
+[05C0] 12 74 2D 44 BB AA 91 A0 2D 46 3E 9E FB FB C4 FB .t-D.... -F>.....
+[05D0] F1 15 FD BB DA EE 06 A9 20 6A 38 DC 46 06 27 D9 ........ j8.F.'.
+[05E0] A2 9D 2D 1F FD 0D 7D 8A BB 0A 7C E8 47 17 BC 7B ..-...}. ..|.G..{
+[05F0] 70 E4 51 6A BA 51 68 62 28 4A 1E 51 D1 0D CD 02 p.Qj.Qhb (J.Q....
+[0600] 55 75 44 8A B9 C2 84 F4 17 34 92 9B 31 85 9E 43 UuD..... .4..1..C
+[0610] C1 0C 3A B2 69 7F 20 1A 18 1F 65 4F C0 20 C9 B5 ..:.i. . ..eO. ..
+[0620] AF E1 61 8C 90 10 63 26 A6 5D 05 3C CD 29 BB 7B ..a...c& .].<.).{
+[0630] 74 D5 8F 2C 7F 4B E8 84 24 57 37 8A C6 F7 91 FD t..,.K.. $W7.....
+[0640] 22 9A A5 0D E9 4A 78 93 36 FC A8 8C 8A 27 8A C6 "....Jx. 6....'..
+[0650] 28 4B 7B DA 11 42 BC 09 10 81 82 14 0F 9C B8 48 (K{..B.. .......H
+[0660] 26 91 78 A8 DD 97 6C 24 A1 D2 E8 85 19 B3 D3 85 &.x...l$ ........
+[0670] 4D 38 C7 7D 49 55 8E 85 46 E1 EE 7B BA 11 62 63 M8.}IU.. F..{..bc
+[0680] 53 C5 16 4A 0C 1C 99 7C 0E FB 45 1D B4 98 58 67 S..J...| ..E...Xg
+[0690] 7E 40 65 4B 48 E2 89 9C 8B C2 B8 39 D1 04 C0 A8 ~@eKH... ...9....
+[06A0] 56 E8 A1 04 7A 7A C9 60 18 A0 29 E2 DC 82 4C 8F V...zz.` ..)...L.
+[06B0] 18 CE 2F 14 F0 18 5B 6C FF 85 45 88 73 CB A4 55 ../...[l ..E.s..U
+[06C0] 08 FC BF C7 9F 51 0A DB 2C C1 E3 3C DD F6 F0 A3 .....Q.. ,..<....
+[06D0] 2D F1 3B A0 12 1D FC 2A 67 F5 1A 7F E5 7C 6C FB -.;....* g....|l.
+[06E0] 8A 18 BD D1 5D E5 5E 68 30 AA 58 9E 10 13 E0 26 ....].^h 0.X....&
+[06F0] 7E 7D C4 E1 A5 B6 86 0F 1C 0F 13 A4 5E 5E 6A ED ~}...... ....^^j.
+[0700] 42 79 31 BB B3 5F 3A 3F DD CB 63 82 FB 06 AE 12 By1.._:? ..c.....
+[0710] 36 C9 1E 06 7D 41 82 2E D2 FA 26 EC 17 50 5E D0 6...}A.. ..&..P^.
+[0720] DE 26 85 30 71 BC 45 3B DA 2E 08 8D B2 2A 3C E0 .&.0q.E; .....*<.
+[0730] 79 8F 77 4C 01 69 7A 09 C7 88 E1 D1 DC FF 78 DB y.wL.iz. ......x.
+[0740] 25 7B B1 3C BB 22 27 80 0D 75 96 18 B6 40 95 6D %{.<."'. .u...@.m
+[0750] C8 AB 04 05 41 A1 C4 25 71 C4 53 3A A6 9C B2 4D ....A..% q.S:...M
+[0760] E6 15 2C B2 47 6C DA A8 7D CC A3 89 8B C9 1E 21 ..,.Gl.. }......!
+[0770] F5 E9 B2 42 95 68 28 AF C6 37 22 BA 30 8D 53 FA ...B.h(. .7".0.S.
+[0780] 08 0D CE CA 81 61 0D 84 A5 2D 75 BD 41 85 4C 88 .....a.. .-u.A.L.
+[0790] 56 72 C6 B6 10 F8 34 CD B2 F4 5C 94 FA 80 90 82 Vr....4. ..\.....
+[07A0] A0 BD 68 EC 08 32 C3 B6 51 1E 3F 67 CB 7B EB 70 ..h..2.. Q.?g.{.p
+[07B0] 83 84 D4 CB 52 55 36 61 1E 60 90 5B 6F FE 9A 62 ....RU6a .`.[o..b
+[07C0] 05 CF 26 8E 65 E2 60 4B ED 63 B4 C4 E6 44 B4 2F ..&.e.`K .c...D./
+[07D0] B0 B8 07 FE BE 0D 50 E4 56 A4 2E 0D 25 76 0B 0F ......P. V...%v..
+[07E0] 44 09 20 80 E5 C4 94 63 E0 54 46 1D AB 5E 0B 09 D. ....c .TF..^..
+[07F0] 93 B1 30 31 7B 04 DC 23 43 3B DB 7D 39 67 FE 9A ..01{..# C;.}9g..
+[0800] 1F C1 08 AF 34 24 F6 74 E4 14 DA 34 8F 61 57 6A ....4$.t ...4.aWj
+[0810] 7F 1D 4A 88 0A 90 78 93 F1 86 54 DB 22 86 D6 69 ..J...x. ..T."..i
+[0820] 0F DF 44 7C D3 6B 9D 41 63 50 98 3A 97 B9 7B 4C ..D|.k.A cP.:..{L
+[0830] 53 E3 85 73 9A C9 08 A0 75 12 50 02 87 B0 CF CC S..s.... u.P.....
+[0840] 84 84 D9 BC FC 94 79 AF 6A A6 08 FF 19 7E E9 22 ......y. j....~."
+[0850] 9B EC 5C C1 6B 1D A4 B4 55 32 5E 23 C3 C0 D4 8B ..\.k... U2^#....
+[0860] 80 E6 67 B1 59 EB 9D 5D 9B AD C6 0E 7D E2 FE B1 ..g.Y..] ....}...
+[0870] 24 8A B1 37 1E 60 7F 83 35 48 32 F7 03 E8 12 E6 $..7.`.. 5H2.....
+[0880] 21 7C 3D 21 7F 6B 14 31 9C 1A A3 4C 2B 1C 5E EC !|=!.k.1 ...L+.^.
+[0890] 34 C1 2D DA 19 6C E6 6D 8D 60 D7 55 9E E6 D0 B5 4.-..l.m .`.U....
+[08A0] 07 06 72 C0 E9 4E 91 94 6B 3E 0B F1 0A 75 4D E8 ..r..N.. k>...uM.
+[08B0] CB 53 6B 34 A4 2F 96 A5 39 1A 18 6E 27 00 6D 41 .Sk4./.. 9..n'.mA
+[08C0] B7 D8 F5 9A E5 01 FC 0B A8 97 56 EE 98 04 1D 98 ........ ..V.....
+[08D0] 84 5E 82 C8 E8 EC 17 D5 FA 96 00 3B E1 98 1C D8 .^...... ...;....
+[08E0] FA 66 A0 DC 32 60 F6 03 46 08 3C E5 16 6F F2 8B .f..2`.. F.<..o..
+[08F0] 4D 72 9F 0F E0 A9 71 6E 7C AE AA FB A3 4D F1 A1 Mr....qn |....M..
+[0900] B6 1B 9F 62 71 E1 2C 82 9B AE E3 07 9B 79 90 F1 ...bq.,. .....y..
+[0910] C2 69 E5 7E CB 57 E6 C9 1C 4E A8 C7 12 EA 4F 4C .i.~.W.. .N....OL
+[0920] 52 17 03 AB D4 FD 34 60 F4 7C BE 9E 36 30 37 88 R.....4` .|..607.
+[0930] 95 61 2E CF 70 AF 22 70 DB E8 AA 6E 3D 30 F7 4D .a..p."p ...n=0.M
+[0940] 84 D5 00 00 00 00 00 00 00 01 00 00 00 01 00 00 ........ ........
+[0950] 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 ..KTEST. SAMBA.EX
+[0960] 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D 61 64 6D AMPLE.CO M....adm
+[0970] 69 6E 69 73 74 72 61 74 6F 72 00 00 00 01 00 00 inistrat or......
+[0980] 00 02 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 ......KT EST.SAMB
+[0990] 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 A.EXAMPL E.COM...
+[09A0] 04 63 69 66 73 00 00 00 0B 6C 6F 63 61 6C 6B 74 .cifs... .localkt
+[09B0] 65 73 74 36 00 17 00 00 00 10 00 6E A1 B2 31 6D est6.... ...n..1m
+[09C0] 48 C7 90 72 3A 0C 4B 8B 83 8C 4D 99 4F 6A 4D 99 H..r:.K. ..M.OjM.
+[09D0] 50 85 7D 44 0B 68 00 00 00 00 00 40 28 00 00 00 P.}D.h.. ...@(...
+[09E0] 00 00 00 00 00 00 00 00 00 03 FA 61 82 03 F6 30 ........ ...a...0
+[09F0] 82 03 F2 A0 03 02 01 05 A1 19 1B 17 4B 54 45 53 ........ ....KTES
+[0A00] 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E T.SAMBA. EXAMPLE.
+[0A10] 43 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 15 30 13 COM..0.. ......0.
+[0A20] 1B 04 63 69 66 73 1B 0B 6C 6F 63 61 6C 6B 74 65 ..cifs.. localkte
+[0A30] 73 74 36 A3 82 03 AE 30 82 03 AA A0 03 02 01 17 st6....0 ........
+[0A40] A1 03 02 01 02 A2 82 03 9C 04 82 03 98 C6 BB 64 ........ .......d
+[0A50] A8 31 00 FC 5E 51 3C 87 F8 34 47 3B D0 6F 6F FD .1..^Q<. .4G;.oo.
+[0A60] 9E A6 91 12 74 2D 44 BB AA 91 A0 2D 46 3E 9E FB ....t-D. ...-F>..
+[0A70] FB C4 FB F1 15 FD BB DA EE 06 A9 20 6A 38 DC 46 ........ ... j8.F
+[0A80] 06 27 D9 A2 9D 2D 1F FD 0D 7D 8A BB 0A 7C E8 47 .'...-.. .}...|.G
+[0A90] 17 BC 7B 70 E4 51 6A BA 51 68 62 28 4A 1E 51 D1 ..{p.Qj. Qhb(J.Q.
+[0AA0] 0D CD 02 55 75 44 8A B9 C2 84 F4 17 34 92 9B 31 ...UuD.. ....4..1
+[0AB0] 85 9E 43 C1 0C 3A B2 69 7F 20 1A 18 1F 65 4F C0 ..C..:.i . ...eO.
+[0AC0] 20 C9 B5 AF E1 61 8C 90 10 63 26 A6 5D 05 3C CD ....a.. .c&.].<.
+[0AD0] 29 BB 7B 74 D5 8F 2C 7F 4B E8 84 24 57 37 8A C6 ).{t..,. K..$W7..
+[0AE0] F7 91 FD 22 9A A5 0D E9 4A 78 93 36 FC A8 8C 8A ...".... Jx.6....
+[0AF0] 27 8A C6 28 4B 7B DA 11 42 BC 09 10 81 82 14 0F '..(K{.. B.......
+[0B00] 9C B8 48 26 91 78 A8 DD 97 6C 24 A1 D2 E8 85 19 ..H&.x.. .l$.....
+[0B10] B3 D3 85 4D 38 C7 7D 49 55 8E 85 46 E1 EE 7B BA ...M8.}I U..F..{.
+[0B20] 11 62 63 53 C5 16 4A 0C 1C 99 7C 0E FB 45 1D B4 .bcS..J. ..|..E..
+[0B30] 98 58 67 7E 40 65 4B 48 E2 89 9C 8B C2 B8 39 D1 .Xg~@eKH ......9.
+[0B40] 04 C0 A8 56 E8 A1 04 7A 7A C9 60 18 A0 29 E2 DC ...V...z z.`..)..
+[0B50] 82 4C 8F 18 CE 2F 14 F0 18 5B 6C FF 85 45 88 73 .L.../.. .[l..E.s
+[0B60] CB A4 55 08 FC BF C7 9F 51 0A DB 2C C1 E3 3C DD ..U..... Q..,..<.
+[0B70] F6 F0 A3 2D F1 3B A0 12 1D FC 2A 67 F5 1A 7F E5 ...-.;.. ..*g....
+[0B80] 7C 6C FB 8A 18 BD D1 5D E5 5E 68 30 AA 58 9E 10 |l.....] .^h0.X..
+[0B90] 13 E0 26 7E 7D C4 E1 A5 B6 86 0F 1C 0F 13 A4 5E ..&~}... .......^
+[0BA0] 5E 6A ED 42 79 31 BB B3 5F 3A 3F DD CB 63 82 FB ^j.By1.. _:?..c..
+[0BB0] 06 AE 12 36 C9 1E 06 7D 41 82 2E D2 FA 26 EC 17 ...6...} A....&..
+[0BC0] 50 5E D0 DE 26 85 30 71 BC 45 3B DA 2E 08 8D B2 P^..&.0q .E;.....
+[0BD0] 2A 3C E0 79 8F 77 4C 01 69 7A 09 C7 88 E1 D1 DC *<.y.wL. iz......
+[0BE0] FF 78 DB 25 7B B1 3C BB 22 27 80 0D 75 96 18 B6 .x.%{.<. "'..u...
+[0BF0] 40 95 6D C8 AB 04 05 41 A1 C4 25 71 C4 53 3A A6 @.m....A ..%q.S:.
+[0C00] 9C B2 4D E6 15 2C B2 47 6C DA A8 7D CC A3 89 8B ..M..,.G l..}....
+[0C10] C9 1E 21 F5 E9 B2 42 95 68 28 AF C6 37 22 BA 30 ..!...B. h(..7".0
+[0C20] 8D 53 FA 08 0D CE CA 81 61 0D 84 A5 2D 75 BD 41 .S...... a...-u.A
+[0C30] 85 4C 88 56 72 C6 B6 10 F8 34 CD B2 F4 5C 94 FA .L.Vr... .4...\..
+[0C40] 80 90 82 A0 BD 68 EC 08 32 C3 B6 51 1E 3F 67 CB .....h.. 2..Q.?g.
+[0C50] 7B EB 70 83 84 D4 CB 52 55 36 61 1E 60 90 5B 6F {.p....R U6a.`.[o
+[0C60] FE 9A 62 05 CF 26 8E 65 E2 60 4B ED 63 B4 C4 E6 ..b..&.e .`K.c...
+[0C70] 44 B4 2F B0 B8 07 FE BE 0D 50 E4 56 A4 2E 0D 25 D./..... .P.V...%
+[0C80] 76 0B 0F 44 09 20 80 E5 C4 94 63 E0 54 46 1D AB v..D. .. ..c.TF..
+[0C90] 5E 0B 09 93 B1 30 31 7B 04 DC 23 43 3B DB 7D 39 ^....01{ ..#C;.}9
+[0CA0] 67 FE 9A 1F C1 08 AF 34 24 F6 74 E4 14 DA 34 8F g......4 $.t...4.
+[0CB0] 61 57 6A 7F 1D 4A 88 0A 90 78 93 F1 86 54 DB 22 aWj..J.. .x...T."
+[0CC0] 86 D6 69 0F DF 44 7C D3 6B 9D 41 63 50 98 3A 97 ..i..D|. k.AcP.:.
+[0CD0] B9 7B 4C 53 E3 85 73 9A C9 08 A0 75 12 50 02 87 .{LS..s. ...u.P..
+[0CE0] B0 CF CC 84 84 D9 BC FC 94 79 AF 6A A6 08 FF 19 ........ .y.j....
+[0CF0] 7E E9 22 9B EC 5C C1 6B 1D A4 B4 55 32 5E 23 C3 ~."..\.k ...U2^#.
+[0D00] C0 D4 8B 80 E6 67 B1 59 EB 9D 5D 9B AD C6 0E 7D .....g.Y ..]....}
+[0D10] E2 FE B1 24 8A B1 37 1E 60 7F 83 35 48 32 F7 03 ...$..7. `..5H2..
+[0D20] E8 12 E6 21 7C 3D 21 7F 6B 14 31 9C 1A A3 4C 2B ...!|=!. k.1...L+
+[0D30] 1C 5E EC 34 C1 2D DA 19 6C E6 6D 8D 60 D7 55 9E .^.4.-.. l.m.`.U.
+[0D40] E6 D0 B5 07 06 72 C0 E9 4E 91 94 6B 3E 0B F1 0A .....r.. N..k>...
+[0D50] 75 4D E8 CB 53 6B 34 A4 2F 96 A5 39 1A 18 6E 27 uM..Sk4. /..9..n'
+[0D60] 00 6D 41 B7 D8 F5 9A E5 01 FC 0B A8 97 56 EE 98 .mA..... .....V..
+[0D70] 04 1D 98 84 5E 82 C8 E8 EC 17 D5 FA 96 00 3B E1 ....^... ......;.
+[0D80] 98 1C D8 FA 66 A0 DC 32 60 F6 03 46 08 3C E5 16 ....f..2 `..F.<..
+[0D90] 6F F2 8B 4D 72 9F 0F E0 A9 71 6E 7C AE AA FB A3 o..Mr... .qn|....
+[0DA0] 4D F1 A1 B6 1B 9F 62 71 E1 2C 82 9B AE E3 07 9B M.....bq .,......
+[0DB0] 79 90 F1 C2 69 E5 7E CB 57 E6 C9 1C 4E A8 C7 12 y...i.~. W...N...
+[0DC0] EA 4F 4C 52 17 03 AB D4 FD 34 60 F4 7C BE 9E 36 .OLR.... .4`.|..6
+[0DD0] 30 37 88 95 61 2E CF 70 AF 22 70 DB E8 AA 6E 3D 07..a..p ."p...n=
+[0DE0] 30 F7 4D 84 D5 00 00 00 00 00 00 00 01 00 00 00 0.M..... ........
+[0DF0] 01 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 .....KTE ST.SAMBA
+[0E00] 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D .EXAMPLE .COM....
+[0E10] 61 64 6D 69 6E 69 73 74 72 61 74 6F 72 00 00 00 administ rator...
+[0E20] 01 00 00 00 02 00 00 00 17 4B 54 45 53 54 2E 53 ........ .KTEST.S
+[0E30] 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D AMBA.EXA MPLE.COM
+[0E40] 00 00 00 04 63 69 66 73 00 00 00 0B 4C 4F 43 41 ....cifs ....LOCA
+[0E50] 4C 4B 54 45 53 54 36 00 17 00 00 00 10 1D C8 5E LKTEST6. .......^
+[0E60] 46 48 82 F9 29 DB C6 A6 F1 72 6D 8D E9 4D 99 4F FH..)... .rm..M.O
+[0E70] 6A 4D 99 85 09 7D 44 0B 68 00 00 00 00 00 40 28 jM...}D. h.....@(
+[0E80] 00 00 00 00 00 00 00 00 00 00 00 00 03 FA 61 82 ........ ......a.
+[0E90] 03 F6 30 82 03 F2 A0 03 02 01 05 A1 19 1B 17 4B ..0..... .......K
+[0EA0] 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 TEST.SAM BA.EXAMP
+[0EB0] 4C 45 2E 43 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 LE.COM.. 0.......
+[0EC0] 15 30 13 1B 04 63 69 66 73 1B 0B 4C 4F 43 41 4C .0...cif s..LOCAL
+[0ED0] 4B 54 45 53 54 36 A3 82 03 AE 30 82 03 AA A0 03 KTEST6.. ..0.....
+[0EE0] 02 01 17 A1 03 02 01 02 A2 82 03 9C 04 82 03 98 ........ ........
+[0EF0] 66 D8 19 46 FA CB 73 2D CF 88 FD 4A EE 07 48 DA f..F..s- ...J..H.
+[0F00] 0E BC 58 30 43 40 A4 9C 00 0F 3B 17 C1 2D F5 9C ..X0C@.. ..;..-..
+[0F10] 3E D9 2F 1D CA 01 9B D7 2E EC D7 70 ED 8B 8B 1B >./..... ...p....
+[0F20] 5E F2 4E EE DD 0F C0 8D 61 E5 D7 0A 56 00 32 B1 ^.N..... a...V.2.
+[0F30] DB 91 37 29 0F 2F 85 EE A8 43 BA A5 B8 D4 19 74 ..7)./.. .C.....t
+[0F40] 33 F0 69 52 E1 58 98 83 D6 16 0B 44 A9 63 9B D4 3.iR.X.. ...D.c..
+[0F50] 4E 6E A7 3E CD 9A 96 4D C4 96 F5 07 6D 29 B6 ED Nn.>...M ....m)..
+[0F60] 2A 62 3D 53 22 33 D1 95 E9 DF 74 4C 2A E2 29 AF *b=S"3.. ..tL*.).
+[0F70] 5B 69 B0 48 2D AD 94 FD A5 1D 54 D8 E2 5E C1 68 [i.H-... ..T..^.h
+[0F80] 6F BA 02 01 79 C3 C9 97 0B 76 66 45 E2 3B 10 17 o...y... .vfE.;..
+[0F90] 95 40 46 E4 85 B9 87 BB CF CF 19 8C 3A C0 EA 38 .@F..... ....:..8
+[0FA0] 3B B9 E9 4B 05 89 E5 27 8C 62 95 BC 0D 65 F0 D2 ;..K...' .b...e..
+[0FB0] C0 5E BC 65 01 D5 0B CB 17 31 0F 06 49 4F A2 4A .^.e.... .1..IO.J
+[0FC0] 70 77 DB BD 92 5B 37 5C EC 06 DF C5 E2 31 C8 40 pw...[7\ .....1.@
+[0FD0] 09 11 68 14 E7 7D CE 54 4F 52 61 31 2C 1C 53 52 ..h..}.T ORa1,.SR
+[0FE0] DB BE D8 95 39 EE 7D C6 CE C8 22 95 92 97 97 3D ....9.}. .."....=
+[0FF0] 5E 66 0F AD DC C2 4E 2E 2B 9F 63 20 30 DF B7 C1 ^f....N. +.c 0...
+[1000] D4 65 AA 6F 2D 10 24 07 20 8D 88 6E 4B 09 04 31 .e.o-.$. ..nK..1
+[1010] B6 A3 EB F7 37 32 0E 0C 73 C6 F6 B8 4D D9 0C 4C ....72.. s...M..L
+[1020] 5B EC 10 6A 51 19 EA 3F FF 46 E7 73 16 A7 1F 33 [..jQ..? .F.s...3
+[1030] 98 7C 9B AD 5A 23 A9 40 7C 0F DF EE 0F AA C7 E8 .|..Z#.@ |.......
+[1040] 63 07 98 3A 4A 0D 18 62 01 21 B2 AE A5 69 B0 C1 c..:J..b .!...i..
+[1050] 15 51 BA 97 D2 C5 42 5B C5 30 38 18 A9 48 AB D7 .Q....B[ .08..H..
+[1060] FC A1 BC 9F 71 E7 EA 18 54 42 DA D6 A4 FC C1 DC ....q... TB......
+[1070] F3 12 30 62 AC 98 E1 7D 2B 34 1E 52 4C 26 67 32 ..0b...} +4.RL&g2
+[1080] D9 44 1A 08 27 0E DA D0 FC 84 66 35 81 D6 EB 98 .D..'... ..f5....
+[1090] 46 6F 1E 47 E0 14 31 BE 47 80 65 AA 0B 20 D6 33 Fo.G..1. G.e.. .3
+[10A0] 36 3B 0D 40 2F 5A 2E 0E 01 BE 00 EB 33 3E 4B 32 6;.@/Z.. ....3>K2
+[10B0] 91 F4 22 96 E5 5F D4 D5 92 94 CC 5B 59 6A 3E D2 ..".._.. ...[Yj>.
+[10C0] FB A0 4F 99 C4 07 8B 6F 2B 14 37 CD 37 44 C0 1F ..O....o +.7.7D..
+[10D0] 80 9C 43 46 F2 5E F4 FE D3 39 70 61 BE 72 5B 3A ..CF.^.. .9pa.r[:
+[10E0] 8F 37 95 78 1E AB D9 E7 E9 DA FC 47 09 81 A0 0D .7.x.... ...G....
+[10F0] 62 E1 F9 34 36 D1 DB E6 98 D8 F4 3E 77 5A 4D E2 b..46... ...>wZM.
+[1100] 5F 20 70 3D 3D 5B 34 D9 FD A8 31 F7 D9 59 F7 A3 _ p==[4. ..1..Y..
+[1110] F0 66 F7 D9 AD 1C CD D5 85 33 A0 87 22 31 D4 F3 .f...... .3.."1..
+[1120] 67 80 68 20 A2 90 72 7A 6F 64 FD 68 82 9E 91 B8 g.h ..rz od.h....
+[1130] E3 F7 6D 6C 38 74 F0 96 A2 F6 25 D7 92 58 14 60 ..ml8t.. ..%..X.`
+[1140] 9F AE 01 4C 0C 09 67 3E 35 67 71 1E 2A 86 21 D3 ...L..g> 5gq.*.!.
+[1150] 60 61 98 16 94 67 0B 52 76 63 93 BD A3 3B A9 F0 `a...g.R vc...;..
+[1160] A2 6A B7 E6 0F 35 64 DA 6A EA 20 A6 3D 94 71 59 .j...5d. j. .=.qY
+[1170] 5E CB B2 D3 F9 4D FE 1B 4B D8 64 C8 3B 7A A8 E6 ^....M.. K.d.;z..
+[1180] D2 D5 76 71 26 D4 5C DA 1A 55 17 F2 16 C9 2F 77 ..vq&.\. .U..../w
+[1190] DB 95 19 48 A5 AC D0 C3 31 9C 0A CC 1B 44 11 6B ...H.... 1....D.k
+[11A0] 7C 88 7A 5D CF 6E 12 DA EF C5 C7 34 1D F4 CC EA |.z].n.. ...4....
+[11B0] 37 24 4B B3 0F C1 A3 F2 29 A0 D8 93 39 C6 16 57 7$K..... )...9..W
+[11C0] D5 BF 57 BF 6C 7E F7 90 E0 EB A3 8B 07 56 9C EC ..W.l~.. .....V..
+[11D0] 15 3E 21 DA A5 7C 00 3C F9 D2 A7 1C 6F 16 25 31 .>!..|.< ....o.%1
+[11E0] C5 28 A7 EA F3 47 31 50 DD E1 ED 0A 93 DB 85 CC .(...G1P ........
+[11F0] 6B 4B 2C 7F E8 F8 2D A9 6D 1D 0A 87 F2 10 8C 82 kK,...-. m.......
+[1200] 2F 9B D4 9B 92 8C 77 40 50 42 1E 42 C4 0A 4F E3 /.....w@ PB.B..O.
+[1210] 6C 6C DC 81 C4 1E BB F0 7D CF 3C 73 22 5B C3 1A ll...... }..x K....%J.
+[1240] 1E 6C 8F 01 D6 59 D7 CF 2E A0 CC 98 F6 75 28 2F .l...Y.. .....u(/
+[1250] F7 2A 70 28 A9 45 1F 75 C2 4E 62 ED D8 C4 A0 8D .*p(.E.u .Nb.....
+[1260] 55 B2 84 1C A4 CE 87 EF 24 EE BC CE 40 09 EB 05 U....... $...@...
+[1270] 0B D1 14 31 50 32 2F B6 A8 97 17 4B A7 95 01 50 ...1P2/. ...K...P
+[1280] 6E 0E 23 49 9C 72 21 91 00 00 00 00 00 00 00 01 n.#I.r!. ........
+[1290] 00 00 00 01 00 00 00 17 4B 54 45 53 54 2E 53 41 ........ KTEST.SA
+[12A0] 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 MBA.EXAM PLE.COM.
+[12B0] 00 00 0D 61 64 6D 69 6E 69 73 74 72 61 74 6F 72 ...admin istrator
+[12C0] 00 00 00 01 00 00 00 02 00 00 00 17 4B 54 45 53 ........ ....KTES
+[12D0] 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E T.SAMBA. EXAMPLE.
+[12E0] 43 4F 4D 00 00 00 04 63 69 66 73 00 00 00 0B 4C COM....c ifs....L
+[12F0] 4F 43 41 4C 4B 54 45 53 54 36 00 17 00 00 00 10 OCALKTES T6......
+[1300] 1D C8 5E 46 48 82 F9 29 DB C6 A6 F1 72 6D 8D E9 ..^FH..) ....rm..
+[1310] 4D 99 4F 6A 4D 99 85 09 7D 44 0B 68 00 00 00 00 M.OjM... }D.h....
+[1320] 00 40 28 00 00 00 00 00 00 00 00 00 00 00 00 03 .@(..... ........
+[1330] FA 61 82 03 F6 30 82 03 F2 A0 03 02 01 05 A1 19 .a...0.. ........
+[1340] 1B 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 ..KTEST. SAMBA.EX
+[1350] 41 4D 50 4C 45 2E 43 4F 4D A2 1E 30 1C A0 03 02 AMPLE.CO M..0....
+[1360] 01 01 A1 15 30 13 1B 04 63 69 66 73 1B 0B 4C 4F ....0... cifs..LO
+[1370] 43 41 4C 4B 54 45 53 54 36 A3 82 03 AE 30 82 03 CALKTEST 6....0..
+[1380] AA A0 03 02 01 17 A1 03 02 01 02 A2 82 03 9C 04 ........ ........
+[1390] 82 03 98 66 D8 19 46 FA CB 73 2D CF 88 FD 4A EE ...f..F. .s-...J.
+[13A0] 07 48 DA 0E BC 58 30 43 40 A4 9C 00 0F 3B 17 C1 .H...X0C @....;..
+[13B0] 2D F5 9C 3E D9 2F 1D CA 01 9B D7 2E EC D7 70 ED -..>./.. ......p.
+[13C0] 8B 8B 1B 5E F2 4E EE DD 0F C0 8D 61 E5 D7 0A 56 ...^.N.. ...a...V
+[13D0] 00 32 B1 DB 91 37 29 0F 2F 85 EE A8 43 BA A5 B8 .2...7). /...C...
+[13E0] D4 19 74 33 F0 69 52 E1 58 98 83 D6 16 0B 44 A9 ..t3.iR. X.....D.
+[13F0] 63 9B D4 4E 6E A7 3E CD 9A 96 4D C4 96 F5 07 6D c..Nn.>. ..M....m
+[1400] 29 B6 ED 2A 62 3D 53 22 33 D1 95 E9 DF 74 4C 2A )..*b=S" 3....tL*
+[1410] E2 29 AF 5B 69 B0 48 2D AD 94 FD A5 1D 54 D8 E2 .).[i.H- .....T..
+[1420] 5E C1 68 6F BA 02 01 79 C3 C9 97 0B 76 66 45 E2 ^.ho...y ....vfE.
+[1430] 3B 10 17 95 40 46 E4 85 B9 87 BB CF CF 19 8C 3A ;...@F.. .......:
+[1440] C0 EA 38 3B B9 E9 4B 05 89 E5 27 8C 62 95 BC 0D ..8;..K. ..'.b...
+[1450] 65 F0 D2 C0 5E BC 65 01 D5 0B CB 17 31 0F 06 49 e...^.e. ....1..I
+[1460] 4F A2 4A 70 77 DB BD 92 5B 37 5C EC 06 DF C5 E2 O.Jpw... [7\.....
+[1470] 31 C8 40 09 11 68 14 E7 7D CE 54 4F 52 61 31 2C 1.@..h.. }.TORa1,
+[1480] 1C 53 52 DB BE D8 95 39 EE 7D C6 CE C8 22 95 92 .SR....9 .}..."..
+[1490] 97 97 3D 5E 66 0F AD DC C2 4E 2E 2B 9F 63 20 30 ..=^f... .N.+.c 0
+[14A0] DF B7 C1 D4 65 AA 6F 2D 10 24 07 20 8D 88 6E 4B ....e.o- .$. ..nK
+[14B0] 09 04 31 B6 A3 EB F7 37 32 0E 0C 73 C6 F6 B8 4D ..1....7 2..s...M
+[14C0] D9 0C 4C 5B EC 10 6A 51 19 EA 3F FF 46 E7 73 16 ..L[..jQ ..?.F.s.
+[14D0] A7 1F 33 98 7C 9B AD 5A 23 A9 40 7C 0F DF EE 0F ..3.|..Z #.@|....
+[14E0] AA C7 E8 63 07 98 3A 4A 0D 18 62 01 21 B2 AE A5 ...c..:J ..b.!...
+[14F0] 69 B0 C1 15 51 BA 97 D2 C5 42 5B C5 30 38 18 A9 i...Q... .B[.08..
+[1500] 48 AB D7 FC A1 BC 9F 71 E7 EA 18 54 42 DA D6 A4 H......q ...TB...
+[1510] FC C1 DC F3 12 30 62 AC 98 E1 7D 2B 34 1E 52 4C .....0b. ..}+4.RL
+[1520] 26 67 32 D9 44 1A 08 27 0E DA D0 FC 84 66 35 81 &g2.D..' .....f5.
+[1530] D6 EB 98 46 6F 1E 47 E0 14 31 BE 47 80 65 AA 0B ...Fo.G. .1.G.e..
+[1540] 20 D6 33 36 3B 0D 40 2F 5A 2E 0E 01 BE 00 EB 33 .36;.@/ Z......3
+[1550] 3E 4B 32 91 F4 22 96 E5 5F D4 D5 92 94 CC 5B 59 >K2..".. _.....[Y
+[1560] 6A 3E D2 FB A0 4F 99 C4 07 8B 6F 2B 14 37 CD 37 j>...O.. ..o+.7.7
+[1570] 44 C0 1F 80 9C 43 46 F2 5E F4 FE D3 39 70 61 BE D....CF. ^...9pa.
+[1580] 72 5B 3A 8F 37 95 78 1E AB D9 E7 E9 DA FC 47 09 r[:.7.x. ......G.
+[1590] 81 A0 0D 62 E1 F9 34 36 D1 DB E6 98 D8 F4 3E 77 ...b..46 ......>w
+[15A0] 5A 4D E2 5F 20 70 3D 3D 5B 34 D9 FD A8 31 F7 D9 ZM._ p== [4...1..
+[15B0] 59 F7 A3 F0 66 F7 D9 AD 1C CD D5 85 33 A0 87 22 Y...f... ....3.."
+[15C0] 31 D4 F3 67 80 68 20 A2 90 72 7A 6F 64 FD 68 82 1..g.h . .rzod.h.
+[15D0] 9E 91 B8 E3 F7 6D 6C 38 74 F0 96 A2 F6 25 D7 92 .....ml8 t....%..
+[15E0] 58 14 60 9F AE 01 4C 0C 09 67 3E 35 67 71 1E 2A X.`...L. .g>5gq.*
+[15F0] 86 21 D3 60 61 98 16 94 67 0B 52 76 63 93 BD A3 .!.`a... g.Rvc...
+[1600] 3B A9 F0 A2 6A B7 E6 0F 35 64 DA 6A EA 20 A6 3D ;...j... 5d.j. .=
+[1610] 94 71 59 5E CB B2 D3 F9 4D FE 1B 4B D8 64 C8 3B .qY^.... M..K.d.;
+[1620] 7A A8 E6 D2 D5 76 71 26 D4 5C DA 1A 55 17 F2 16 z....vq& .\..U...
+[1630] C9 2F 77 DB 95 19 48 A5 AC D0 C3 31 9C 0A CC 1B ./w...H. ...1....
+[1640] 44 11 6B 7C 88 7A 5D CF 6E 12 DA EF C5 C7 34 1D D.k|.z]. n.....4.
+[1650] F4 CC EA 37 24 4B B3 0F C1 A3 F2 29 A0 D8 93 39 ...7$K.. ...)...9
+[1660] C6 16 57 D5 BF 57 BF 6C 7E F7 90 E0 EB A3 8B 07 ..W..W.l ~.......
+[1670] 56 9C EC 15 3E 21 DA A5 7C 00 3C F9 D2 A7 1C 6F V...>!.. |.<....o
+[1680] 16 25 31 C5 28 A7 EA F3 47 31 50 DD E1 ED 0A 93 .%1.(... G1P.....
+[1690] DB 85 CC 6B 4B 2C 7F E8 F8 2D A9 6D 1D 0A 87 F2 ...kK,.. .-.m....
+[16A0] 10 8C 82 2F 9B D4 9B 92 8C 77 40 50 42 1E 42 C4 .../.... .w@PB.B.
+[16B0] 0A 4F E3 6C 6C DC 81 C4 1E BB F0 7D CF 3C 73 22 .O.ll... ...}..xK....
+[16E0] 25 4A 92 1E 6C 8F 01 D6 59 D7 CF 2E A0 CC 98 F6 %J..l... Y.......
+[16F0] 75 28 2F F7 2A 70 28 A9 45 1F 75 C2 4E 62 ED D8 u(/.*p(. E.u.Nb..
+[1700] C4 A0 8D 55 B2 84 1C A4 CE 87 EF 24 EE BC CE 40 ...U.... ...$...@
+[1710] 09 EB 05 0B D1 14 31 50 32 2F B6 A8 97 17 4B A7 ......1P 2/....K.
+[1720] 95 01 50 6E 0E 23 49 9C 72 21 91 00 00 00 00 00 ..Pn.#I. r!......
+[1730] 00 00 01 00 00 00 01 00 00 00 17 4B 54 45 53 54 ........ ...KTEST
+[1740] 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 .SAMBA.E XAMPLE.C
+[1750] 4F 4D 00 00 00 0D 61 64 6D 69 6E 69 73 74 72 61 OM....ad ministra
+[1760] 74 6F 72 00 00 00 01 00 00 00 02 00 00 00 17 4B tor..... .......K
+[1770] 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 TEST.SAM BA.EXAMP
+[1780] 4C 45 2E 43 4F 4D 00 00 00 04 63 69 66 73 00 00 LE.COM.. ..cifs..
+[1790] 00 0B 4C 4F 43 41 4C 4B 54 45 53 54 36 00 17 00 ..LOCALK TEST6...
+[17A0] 00 00 10 1D C8 5E 46 48 82 F9 29 DB C6 A6 F1 72 .....^FH ..)....r
+[17B0] 6D 8D E9 4D 99 4F 6A 4D 99 85 09 7D 44 0B 68 00 m..M.OjM ...}D.h.
+[17C0] 00 00 00 00 40 28 00 00 00 00 00 00 00 00 00 00 ....@(.. ........
+[17D0] 00 00 03 FA 61 82 03 F6 30 82 03 F2 A0 03 02 01 ....a... 0.......
+[17E0] 05 A1 19 1B 17 4B 54 45 53 54 2E 53 41 4D 42 41 .....KTE ST.SAMBA
+[17F0] 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D A2 1E 30 1C .EXAMPLE .COM..0.
+[1800] A0 03 02 01 01 A1 15 30 13 1B 04 63 69 66 73 1B .......0 ...cifs.
+[1810] 0B 4C 4F 43 41 4C 4B 54 45 53 54 36 A3 82 03 AE .LOCALKT EST6....
+[1820] 30 82 03 AA A0 03 02 01 17 A1 03 02 01 02 A2 82 0....... ........
+[1830] 03 9C 04 82 03 98 66 D8 19 46 FA CB 73 2D CF 88 ......f. .F..s-..
+[1840] FD 4A EE 07 48 DA 0E BC 58 30 43 40 A4 9C 00 0F .J..H... X0C@....
+[1850] 3B 17 C1 2D F5 9C 3E D9 2F 1D CA 01 9B D7 2E EC ;..-..>. /.......
+[1860] D7 70 ED 8B 8B 1B 5E F2 4E EE DD 0F C0 8D 61 E5 .p....^. N.....a.
+[1870] D7 0A 56 00 32 B1 DB 91 37 29 0F 2F 85 EE A8 43 ..V.2... 7)./...C
+[1880] BA A5 B8 D4 19 74 33 F0 69 52 E1 58 98 83 D6 16 .....t3. iR.X....
+[1890] 0B 44 A9 63 9B D4 4E 6E A7 3E CD 9A 96 4D C4 96 .D.c..Nn .>...M..
+[18A0] F5 07 6D 29 B6 ED 2A 62 3D 53 22 33 D1 95 E9 DF ..m)..*b =S"3....
+[18B0] 74 4C 2A E2 29 AF 5B 69 B0 48 2D AD 94 FD A5 1D tL*.).[i .H-.....
+[18C0] 54 D8 E2 5E C1 68 6F BA 02 01 79 C3 C9 97 0B 76 T..^.ho. ..y....v
+[18D0] 66 45 E2 3B 10 17 95 40 46 E4 85 B9 87 BB CF CF fE.;...@ F.......
+[18E0] 19 8C 3A C0 EA 38 3B B9 E9 4B 05 89 E5 27 8C 62 ..:..8;. .K...'.b
+[18F0] 95 BC 0D 65 F0 D2 C0 5E BC 65 01 D5 0B CB 17 31 ...e...^ .e.....1
+[1900] 0F 06 49 4F A2 4A 70 77 DB BD 92 5B 37 5C EC 06 ..IO.Jpw ...[7\..
+[1910] DF C5 E2 31 C8 40 09 11 68 14 E7 7D CE 54 4F 52 ...1.@.. h..}.TOR
+[1920] 61 31 2C 1C 53 52 DB BE D8 95 39 EE 7D C6 CE C8 a1,.SR.. ..9.}...
+[1930] 22 95 92 97 97 3D 5E 66 0F AD DC C2 4E 2E 2B 9F "....=^f ....N.+.
+[1940] 63 20 30 DF B7 C1 D4 65 AA 6F 2D 10 24 07 20 8D c 0....e .o-.$. .
+[1950] 88 6E 4B 09 04 31 B6 A3 EB F7 37 32 0E 0C 73 C6 .nK..1.. ..72..s.
+[1960] F6 B8 4D D9 0C 4C 5B EC 10 6A 51 19 EA 3F FF 46 ..M..L[. .jQ..?.F
+[1970] E7 73 16 A7 1F 33 98 7C 9B AD 5A 23 A9 40 7C 0F .s...3.| ..Z#.@|.
+[1980] DF EE 0F AA C7 E8 63 07 98 3A 4A 0D 18 62 01 21 ......c. .:J..b.!
+[1990] B2 AE A5 69 B0 C1 15 51 BA 97 D2 C5 42 5B C5 30 ...i...Q ....B[.0
+[19A0] 38 18 A9 48 AB D7 FC A1 BC 9F 71 E7 EA 18 54 42 8..H.... ..q...TB
+[19B0] DA D6 A4 FC C1 DC F3 12 30 62 AC 98 E1 7D 2B 34 ........ 0b...}+4
+[19C0] 1E 52 4C 26 67 32 D9 44 1A 08 27 0E DA D0 FC 84 .RL&g2.D ..'.....
+[19D0] 66 35 81 D6 EB 98 46 6F 1E 47 E0 14 31 BE 47 80 f5....Fo .G..1.G.
+[19E0] 65 AA 0B 20 D6 33 36 3B 0D 40 2F 5A 2E 0E 01 BE e.. .36; .@/Z....
+[19F0] 00 EB 33 3E 4B 32 91 F4 22 96 E5 5F D4 D5 92 94 ..3>K2.. ".._....
+[1A00] CC 5B 59 6A 3E D2 FB A0 4F 99 C4 07 8B 6F 2B 14 .[Yj>... O....o+.
+[1A10] 37 CD 37 44 C0 1F 80 9C 43 46 F2 5E F4 FE D3 39 7.7D.... CF.^...9
+[1A20] 70 61 BE 72 5B 3A 8F 37 95 78 1E AB D9 E7 E9 DA pa.r[:.7 .x......
+[1A30] FC 47 09 81 A0 0D 62 E1 F9 34 36 D1 DB E6 98 D8 .G....b. .46.....
+[1A40] F4 3E 77 5A 4D E2 5F 20 70 3D 3D 5B 34 D9 FD A8 .>wZM._ p==[4...
+[1A50] 31 F7 D9 59 F7 A3 F0 66 F7 D9 AD 1C CD D5 85 33 1..Y...f .......3
+[1A60] A0 87 22 31 D4 F3 67 80 68 20 A2 90 72 7A 6F 64 .."1..g. h ..rzod
+[1A70] FD 68 82 9E 91 B8 E3 F7 6D 6C 38 74 F0 96 A2 F6 .h...... ml8t....
+[1A80] 25 D7 92 58 14 60 9F AE 01 4C 0C 09 67 3E 35 67 %..X.`.. .L..g>5g
+[1A90] 71 1E 2A 86 21 D3 60 61 98 16 94 67 0B 52 76 63 q.*.!.`a ...g.Rvc
+[1AA0] 93 BD A3 3B A9 F0 A2 6A B7 E6 0F 35 64 DA 6A EA ...;...j ...5d.j.
+[1AB0] 20 A6 3D 94 71 59 5E CB B2 D3 F9 4D FE 1B 4B D8 .=.qY^. ...M..K.
+[1AC0] 64 C8 3B 7A A8 E6 D2 D5 76 71 26 D4 5C DA 1A 55 d.;z.... vq&.\..U
+[1AD0] 17 F2 16 C9 2F 77 DB 95 19 48 A5 AC D0 C3 31 9C ..../w.. .H....1.
+[1AE0] 0A CC 1B 44 11 6B 7C 88 7A 5D CF 6E 12 DA EF C5 ...D.k|. z].n....
+[1AF0] C7 34 1D F4 CC EA 37 24 4B B3 0F C1 A3 F2 29 A0 .4....7$ K.....).
+[1B00] D8 93 39 C6 16 57 D5 BF 57 BF 6C 7E F7 90 E0 EB ..9..W.. W.l~....
+[1B10] A3 8B 07 56 9C EC 15 3E 21 DA A5 7C 00 3C F9 D2 ...V...> !..|.<..
+[1B20] A7 1C 6F 16 25 31 C5 28 A7 EA F3 47 31 50 DD E1 ..o.%1.( ...G1P..
+[1B30] ED 0A 93 DB 85 CC 6B 4B 2C 7F E8 F8 2D A9 6D 1D ......kK ,...-.m.
+[1B40] 0A 87 F2 10 8C 82 2F 9B D4 9B 92 8C 77 40 50 42 ....../. ....w@PB
+[1B50] 1E 42 C4 0A 4F E3 6C 6C DC 81 C4 1E BB F0 7D CF .B..O.ll ......}.
+[1B60] 3C 73 22 5B C3 1A 97 35 EE 3A CD 6D F3 68 A3 C5 .xK.
+[1B80] 18 9F A5 25 4A 92 1E 6C 8F 01 D6 59 D7 CF 2E A0 ...%J..l ...Y....
+[1B90] CC 98 F6 75 28 2F F7 2A 70 28 A9 45 1F 75 C2 4E ...u(/.* p(.E.u.N
+[1BA0] 62 ED D8 C4 A0 8D 55 B2 84 1C A4 CE 87 EF 24 EE b.....U. ......$.
+[1BB0] BC CE 40 09 EB 05 0B D1 14 31 50 32 2F B6 A8 97 ..@..... .1P2/...
+[1BC0] 17 4B A7 95 01 50 6E 0E 23 49 9C 72 21 91 00 00 .K...Pn. #I.r!...
+[1BD0] 00 00 00 00 00 01 00 00 00 01 00 00 00 17 4B 54 ........ ......KT
+[1BE0] 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C EST.SAMB A.EXAMPL
+[1BF0] 45 2E 43 4F 4D 00 00 00 0D 61 64 6D 69 6E 69 73 E.COM... .adminis
+[1C00] 74 72 61 74 6F 72 00 00 00 01 00 00 00 02 00 00 trator.. ........
+[1C10] 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 ..KTEST. SAMBA.EX
+[1C20] 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 04 63 69 66 AMPLE.CO M....cif
+[1C30] 73 00 00 00 0B 4C 4F 43 41 4C 4B 54 45 53 54 36 s....LOC ALKTEST6
+[1C40] 00 17 00 00 00 10 1D C8 5E 46 48 82 F9 29 DB C6 ........ ^FH..)..
+[1C50] A6 F1 72 6D 8D E9 4D 99 4F 6A 4D 99 85 09 7D 44 ..rm..M. OjM...}D
+[1C60] 0B 68 00 00 00 00 00 40 28 00 00 00 00 00 00 00 .h.....@ (.......
+[1C70] 00 00 00 00 00 03 FA 61 82 03 F6 30 82 03 F2 A0 .......a ...0....
+[1C80] 03 02 01 05 A1 19 1B 17 4B 54 45 53 54 2E 53 41 ........ KTEST.SA
+[1C90] 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D A2 MBA.EXAM PLE.COM.
+[1CA0] 1E 30 1C A0 03 02 01 01 A1 15 30 13 1B 04 63 69 .0...... ..0...ci
+[1CB0] 66 73 1B 0B 4C 4F 43 41 4C 4B 54 45 53 54 36 A3 fs..LOCA LKTEST6.
+[1CC0] 82 03 AE 30 82 03 AA A0 03 02 01 17 A1 03 02 01 ...0.... ........
+[1CD0] 02 A2 82 03 9C 04 82 03 98 66 D8 19 46 FA CB 73 ........ .f..F..s
+[1CE0] 2D CF 88 FD 4A EE 07 48 DA 0E BC 58 30 43 40 A4 -...J..H ...X0C@.
+[1CF0] 9C 00 0F 3B 17 C1 2D F5 9C 3E D9 2F 1D CA 01 9B ...;..-. .>./....
+[1D00] D7 2E EC D7 70 ED 8B 8B 1B 5E F2 4E EE DD 0F C0 ....p... .^.N....
+[1D10] 8D 61 E5 D7 0A 56 00 32 B1 DB 91 37 29 0F 2F 85 .a...V.2 ...7)./.
+[1D20] EE A8 43 BA A5 B8 D4 19 74 33 F0 69 52 E1 58 98 ..C..... t3.iR.X.
+[1D30] 83 D6 16 0B 44 A9 63 9B D4 4E 6E A7 3E CD 9A 96 ....D.c. .Nn.>...
+[1D40] 4D C4 96 F5 07 6D 29 B6 ED 2A 62 3D 53 22 33 D1 M....m). .*b=S"3.
+[1D50] 95 E9 DF 74 4C 2A E2 29 AF 5B 69 B0 48 2D AD 94 ...tL*.) .[i.H-..
+[1D60] FD A5 1D 54 D8 E2 5E C1 68 6F BA 02 01 79 C3 C9 ...T..^. ho...y..
+[1D70] 97 0B 76 66 45 E2 3B 10 17 95 40 46 E4 85 B9 87 ..vfE.;. ..@F....
+[1D80] BB CF CF 19 8C 3A C0 EA 38 3B B9 E9 4B 05 89 E5 .....:.. 8;..K...
+[1D90] 27 8C 62 95 BC 0D 65 F0 D2 C0 5E BC 65 01 D5 0B '.b...e. ..^.e...
+[1DA0] CB 17 31 0F 06 49 4F A2 4A 70 77 DB BD 92 5B 37 ..1..IO. Jpw...[7
+[1DB0] 5C EC 06 DF C5 E2 31 C8 40 09 11 68 14 E7 7D CE \.....1. @..h..}.
+[1DC0] 54 4F 52 61 31 2C 1C 53 52 DB BE D8 95 39 EE 7D TORa1,.S R....9.}
+[1DD0] C6 CE C8 22 95 92 97 97 3D 5E 66 0F AD DC C2 4E ...".... =^f....N
+[1DE0] 2E 2B 9F 63 20 30 DF B7 C1 D4 65 AA 6F 2D 10 24 .+.c 0.. ..e.o-.$
+[1DF0] 07 20 8D 88 6E 4B 09 04 31 B6 A3 EB F7 37 32 0E . ..nK.. 1....72.
+[1E00] 0C 73 C6 F6 B8 4D D9 0C 4C 5B EC 10 6A 51 19 EA .s...M.. L[..jQ..
+[1E10] 3F FF 46 E7 73 16 A7 1F 33 98 7C 9B AD 5A 23 A9 ?.F.s... 3.|..Z#.
+[1E20] 40 7C 0F DF EE 0F AA C7 E8 63 07 98 3A 4A 0D 18 @|...... .c..:J..
+[1E30] 62 01 21 B2 AE A5 69 B0 C1 15 51 BA 97 D2 C5 42 b.!...i. ..Q....B
+[1E40] 5B C5 30 38 18 A9 48 AB D7 FC A1 BC 9F 71 E7 EA [.08..H. .....q..
+[1E50] 18 54 42 DA D6 A4 FC C1 DC F3 12 30 62 AC 98 E1 .TB..... ...0b...
+[1E60] 7D 2B 34 1E 52 4C 26 67 32 D9 44 1A 08 27 0E DA }+4.RL&g 2.D..'..
+[1E70] D0 FC 84 66 35 81 D6 EB 98 46 6F 1E 47 E0 14 31 ...f5... .Fo.G..1
+[1E80] BE 47 80 65 AA 0B 20 D6 33 36 3B 0D 40 2F 5A 2E .G.e.. . 36;.@/Z.
+[1E90] 0E 01 BE 00 EB 33 3E 4B 32 91 F4 22 96 E5 5F D4 .....3>K 2..".._.
+[1EA0] D5 92 94 CC 5B 59 6A 3E D2 FB A0 4F 99 C4 07 8B ....[Yj> ...O....
+[1EB0] 6F 2B 14 37 CD 37 44 C0 1F 80 9C 43 46 F2 5E F4 o+.7.7D. ...CF.^.
+[1EC0] FE D3 39 70 61 BE 72 5B 3A 8F 37 95 78 1E AB D9 ..9pa.r[ :.7.x...
+[1ED0] E7 E9 DA FC 47 09 81 A0 0D 62 E1 F9 34 36 D1 DB ....G... .b..46..
+[1EE0] E6 98 D8 F4 3E 77 5A 4D E2 5F 20 70 3D 3D 5B 34 ....>wZM ._ p==[4
+[1EF0] D9 FD A8 31 F7 D9 59 F7 A3 F0 66 F7 D9 AD 1C CD ...1..Y. ..f.....
+[1F00] D5 85 33 A0 87 22 31 D4 F3 67 80 68 20 A2 90 72 ..3.."1. .g.h ..r
+[1F10] 7A 6F 64 FD 68 82 9E 91 B8 E3 F7 6D 6C 38 74 F0 zod.h... ...ml8t.
+[1F20] 96 A2 F6 25 D7 92 58 14 60 9F AE 01 4C 0C 09 67 ...%..X. `...L..g
+[1F30] 3E 35 67 71 1E 2A 86 21 D3 60 61 98 16 94 67 0B >5gq.*.! .`a...g.
+[1F40] 52 76 63 93 BD A3 3B A9 F0 A2 6A B7 E6 0F 35 64 Rvc...;. ..j...5d
+[1F50] DA 6A EA 20 A6 3D 94 71 59 5E CB B2 D3 F9 4D FE .j. .=.q Y^....M.
+[1F60] 1B 4B D8 64 C8 3B 7A A8 E6 D2 D5 76 71 26 D4 5C .K.d.;z. ...vq&.\
+[1F70] DA 1A 55 17 F2 16 C9 2F 77 DB 95 19 48 A5 AC D0 ..U..../ w...H...
+[1F80] C3 31 9C 0A CC 1B 44 11 6B 7C 88 7A 5D CF 6E 12 .1....D. k|.z].n.
+[1F90] DA EF C5 C7 34 1D F4 CC EA 37 24 4B B3 0F C1 A3 ....4... .7$K....
+[1FA0] F2 29 A0 D8 93 39 C6 16 57 D5 BF 57 BF 6C 7E F7 .)...9.. W..W.l~.
+[1FB0] 90 E0 EB A3 8B 07 56 9C EC 15 3E 21 DA A5 7C 00 ......V. ..>!..|.
+[1FC0] 3C F9 D2 A7 1C 6F 16 25 31 C5 28 A7 EA F3 47 31 <....o.% 1.(...G1
+[1FD0] 50 DD E1 ED 0A 93 DB 85 CC 6B 4B 2C 7F E8 F8 2D P....... .kK,...-
+[1FE0] A9 6D 1D 0A 87 F2 10 8C 82 2F 9B D4 9B 92 8C 77 .m...... ./.....w
+[1FF0] 40 50 42 1E 42 C4 0A 4F E3 6C 6C DC 81 C4 1E BB @PB.B..O .ll.....
+[2000] F0 7D CF 3C 73 22 5B C3 1A 97 35 EE 3A CD 6D F3 .}..
+[2020] 78 4B BF 18 9F A5 25 4A 92 1E 6C 8F 01 D6 59 D7 xK....%J ..l...Y.
+[2030] CF 2E A0 CC 98 F6 75 28 2F F7 2A 70 28 A9 45 1F ......u( /.*p(.E.
+[2040] 75 C2 4E 62 ED D8 C4 A0 8D 55 B2 84 1C A4 CE 87 u.Nb.... .U......
+[2050] EF 24 EE BC CE 40 09 EB 05 0B D1 14 31 50 32 2F .$...@.. ....1P2/
+[2060] B6 A8 97 17 4B A7 95 01 50 6E 0E 23 49 9C 72 21 ....K... Pn.#I.r!
+[2070] 91 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 ........ ........
+[2080] 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 .KTEST.S AMBA.EXA
+[2090] 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D 61 64 6D 69 MPLE.COM ....admi
+[20A0] 6E 69 73 74 72 61 74 6F 72 00 00 00 01 00 00 00 nistrato r.......
+[20B0] 02 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 .....KTE ST.SAMBA
+[20C0] 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 04 .EXAMPLE .COM....
+[20D0] 68 6F 73 74 00 00 00 0B 6C 6F 63 61 6C 6B 74 65 host.... localkte
+[20E0] 73 74 36 00 17 00 00 00 10 72 47 04 38 B6 E6 F0 st6..... .rG.8...
+[20F0] 44 9E 9F 27 66 E1 69 9C 9A 4D 99 4F 6A 4D 99 90 D..'f.i. .M.OjM..
+[2100] F5 7D 44 0B 68 00 00 00 00 00 40 28 00 00 00 00 .}D.h... ..@(....
+[2110] 00 00 00 00 00 00 00 00 03 FA 61 82 03 F6 30 82 ........ ..a...0.
+[2120] 03 F2 A0 03 02 01 05 A1 19 1B 17 4B 54 45 53 54 ........ ...KTEST
+[2130] 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 .SAMBA.E XAMPLE.C
+[2140] 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 15 30 13 1B OM..0... .....0..
+[2150] 04 68 6F 73 74 1B 0B 6C 6F 63 61 6C 6B 74 65 73 .host..l ocalktes
+[2160] 74 36 A3 82 03 AE 30 82 03 AA A0 03 02 01 17 A1 t6....0. ........
+[2170] 03 02 01 02 A2 82 03 9C 04 82 03 98 58 95 95 EB ........ ....X...
+[2180] CB 8F 68 D4 77 43 0F 3B 44 B4 15 DA 40 6D FD E9 ..h.wC.; D...@m..
+[2190] 85 D3 2F CD B5 1E 96 CD F6 E9 67 91 36 08 9E B4 ../..... ..g.6...
+[21A0] B3 47 70 7A B3 4E 82 5A 4F 8E 4B F5 8D 04 E4 5C .Gpz.N.Z O.K....\
+[21B0] C4 D8 0C AF 08 25 F9 C1 64 B2 3A 35 26 E9 B2 72 .....%.. d.:5&..r
+[21C0] 66 B5 E9 81 FC BE 12 1B CC 8A A5 82 31 F6 7F C3 f....... ....1...
+[21D0] 5A 19 A3 31 F2 99 14 1E 64 E4 41 E8 C7 C3 F3 DF Z..1.... d.A.....
+[21E0] F5 65 7D B0 9F DC 5D 25 1D 1A A8 EA AA 88 6D F4 .e}...]% ......m.
+[21F0] 7C 25 9F 53 F6 A6 8F B1 24 AF 98 FE 53 7B 35 3C |%.S.... $...S{5<
+[2200] DB EC 7F 09 74 E9 C4 8D 20 B4 47 08 0E 32 B8 C9 ....t... .G..2..
+[2210] 45 27 12 F9 8E F5 D6 C2 DD 1A 96 0E 68 5F 39 65 E'...... ....h_9e
+[2220] 72 C7 BD 8E 04 0E 13 E1 03 27 AC 50 80 76 E6 7A r....... .'.P.v.z
+[2230] 8E F4 C2 72 4F 68 B3 34 00 A9 54 41 DA FD 96 94 ...rOh.4 ..TA....
+[2240] 29 A1 59 15 2F DB 6C 94 85 49 C5 D0 6D 48 B0 C4 ).Y./.l. .I..mH..
+[2250] 65 D0 95 1D DB 3D 25 D0 75 50 D4 CF FA 2F 71 57 e....=%. uP.../qW
+[2260] BD 6C 1C 59 E1 C3 5B C7 24 95 FF B0 20 EF 6A DB .l.Y..[. $... .j.
+[2270] 79 87 67 91 94 E9 16 E2 BB 74 7A 08 E1 6A 36 5F y.g..... .tz..j6_
+[2280] DF 11 AB 35 9B 3E 32 48 83 89 41 4E 06 BF F9 BB ...5.>2H ..AN....
+[2290] EC E4 D7 6D 77 C4 55 22 DF F7 91 4D CB C5 01 A5 ...mw.U" ...M....
+[22A0] BA 2D 1E 92 76 04 E8 02 2F 5E AF 1C B3 B7 A6 FB .-..v... /^......
+[22B0] 3A 9F D9 7C 6D DA B4 8F 31 00 A5 30 F2 76 72 9B :..|m... 1..0.vr.
+[22C0] 62 97 E0 56 E5 E4 C7 6B 8B FC 84 75 57 66 6E D7 b..V...k ...uWfn.
+[22D0] B7 41 6F 61 F4 5B 0F 87 68 F6 54 02 26 1B 1F B7 .Aoa.[.. h.T.&...
+[22E0] 60 D6 E7 FA 4F C7 DB 35 58 EC 13 21 D4 C6 A1 27 `...O..5 X..!...'
+[22F0] BA E7 82 DF 29 FB 9D 5D E8 35 28 C9 9C 4E D7 BE ....)..] .5(..N..
+[2300] 2F 6D F1 E8 0B 5A 74 C9 93 9F AD 42 24 4B B7 3B /m...Zt. ...B$K.;
+[2310] 38 2A 11 CF F0 BD 85 40 48 D8 9D E7 6B 65 70 42 8*.....@ H...kepB
+[2320] 60 DA 9B 65 CB C8 C5 D7 40 3A 12 DC 64 AF 82 54 `..e.... @:..d..T
+[2330] 34 05 38 4F C6 FB 38 E2 73 A9 89 B7 FC 33 15 85 4.8O..8. s....3..
+[2340] 9E CA E9 E0 89 18 18 84 02 65 B4 74 5B D4 A1 6F ........ .e.t[..o
+[2350] 5F 79 20 CB D7 36 C8 6D 5B 1E 5E 0C 82 16 9F CC _y ..6.m [.^.....
+[2360] 5A 1E 57 C1 B6 94 51 87 A1 3D 12 D4 8B FE 0F 93 Z.W...Q. .=......
+[2370] ED 53 A3 F4 88 3C 35 05 89 FE AF 0B 36 62 E3 2F .S...<5. ....6b./
+[2380] 5C 4A 0E 07 67 39 A3 8E C0 45 07 7F 73 32 BC DE \J..g9.. .E..s2..
+[2390] 2D 00 8B 47 79 3D 1C A1 90 AE B6 8F 83 B2 1B 31 -..Gy=.. .......1
+[23A0] EE E4 F2 C5 C1 4A E2 4A 2F 28 F0 AA 19 43 6A 14 .....J.J /(...Cj.
+[23B0] B1 42 61 90 34 2E EE 3D 16 9F 5D 9F 7A A2 01 7A .Ba.4..= ..].z..z
+[23C0] 4B 96 FA 4D C9 85 1A 75 27 B7 6B FD 4D 7D 9C 65 K..M...u '.k.M}.e
+[23D0] 97 DB 05 CC 76 68 EA 05 5D 5D BB BD 51 4B 5B F2 ....vh.. ]]..QK[.
+[23E0] 48 59 BD 1E AD 56 D4 69 A5 75 CD ED EC B1 3E AB HY...V.i .u....>.
+[23F0] FA B7 F8 8D 4F BE 95 63 38 1C 4C 70 26 C4 3A 21 ....O..c 8.Lp&.:!
+[2400] 80 61 05 3A D4 E2 28 2C 85 01 5A DA FC 10 60 F3 .a.:..(, ..Z...`.
+[2410] 74 0C FD DB 2F 5B 25 4B 14 E4 7D 8A DB 85 12 D2 t.../[%K ..}.....
+[2420] D7 69 CD B5 B1 93 CE E5 E6 4D 57 D3 C2 D3 2E A0 .i...... .MW.....
+[2430] 08 37 09 CD 19 99 09 FA 33 68 4A E0 92 46 21 0C .7...... 3hJ..F!.
+[2440] 99 9F DA 05 15 20 8B 3D 7C 7B CA D6 81 AC AA 83 ..... .= |{......
+[2450] 48 C8 24 4C C8 FC A5 14 2C BC 49 1A 1C 49 61 1D H.$L.... ,.I..Ia.
+[2460] 24 86 42 B1 37 6A C8 3A AC 18 CC C0 50 84 12 48 $.B.7j.: ....P..H
+[2470] 8B 29 0A 49 26 A4 E2 B9 E5 96 E7 37 C3 DE 4C 23 .).I&... ...7..L#
+[2480] D2 D4 62 14 8F 1E 72 39 CF 03 BC A3 00 C7 63 51 ..b...r9 ......cQ
+[2490] A9 6B E4 3E B2 65 A1 A2 BB EC 06 41 85 50 22 02 .k.>.e.. ...A.P".
+[24A0] 46 2F 72 2B 32 1A A4 2D 85 94 02 47 69 8D AD 6D F/r+2..- ...Gi..m
+[24B0] 66 AB D4 E4 29 C8 C7 DA F4 18 31 2A DF 50 6A 05 f...)... ..1*.Pj.
+[24C0] D6 47 26 C4 F9 87 0F 35 24 6E 72 D6 23 7D 3A 94 .G&....5 $nr.#}:.
+[24D0] 14 8D E8 57 AA BA D7 CF A9 2D E7 4C 10 7C D8 0D ...W.... .-.L.|..
+[24E0] 51 30 1F E1 FB E5 E2 6C EE AA 65 2F D8 22 05 67 Q0.....l ..e/.".g
+[24F0] 87 4D 4D D2 11 3D B4 1E AA 20 3F 76 E3 94 93 6D .MM..=.. . ?v...m
+[2500] AC 10 05 AF 09 BD 67 86 C5 83 93 D6 1C D3 81 D9 ......g. ........
+[2510] B1 3B E1 76 00 00 00 00 00 00 00 01 00 00 00 01 .;.v.... ........
+[2520] 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E ....KTES T.SAMBA.
+[2530] 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D 61 EXAMPLE. COM....a
+[2540] 64 6D 69 6E 69 73 74 72 61 74 6F 72 00 00 00 01 dministr ator....
+[2550] 00 00 00 02 00 00 00 17 4B 54 45 53 54 2E 53 41 ........ KTEST.SA
+[2560] 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 MBA.EXAM PLE.COM.
+[2570] 00 00 04 68 6F 73 74 00 00 00 0B 4C 4F 43 41 4C ...host. ...LOCAL
+[2580] 4B 54 45 53 54 36 00 17 00 00 00 10 55 6E 3E FC KTEST6.. ....Un>.
+[2590] E2 F4 40 51 19 E6 6E EB 23 4C 48 8E 4D 99 4F 6A ..@Q..n. #LH.M.Oj
+[25A0] 4D 99 90 FC 7D 44 0B 68 00 00 00 00 00 40 28 00 M...}D.h .....@(.
+[25B0] 00 00 00 00 00 00 00 00 00 00 00 03 FA 61 82 03 ........ .....a..
+[25C0] F6 30 82 03 F2 A0 03 02 01 05 A1 19 1B 17 4B 54 .0...... ......KT
+[25D0] 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C EST.SAMB A.EXAMPL
+[25E0] 45 2E 43 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 15 E.COM..0 ........
+[25F0] 30 13 1B 04 68 6F 73 74 1B 0B 4C 4F 43 41 4C 4B 0...host ..LOCALK
+[2600] 54 45 53 54 36 A3 82 03 AE 30 82 03 AA A0 03 02 TEST6... .0......
+[2610] 01 17 A1 03 02 01 02 A2 82 03 9C 04 82 03 98 6E ........ .......n
+[2620] 87 B7 7B 3A 7E EF 4A 1B 29 C9 E3 C4 1F 42 4F 0E ..{:~.J. )....BO.
+[2630] C8 AC AC 4E A2 77 1D DA 93 37 F1 AF DA A3 75 2D ...N.w.. .7....u-
+[2640] 12 8B 40 34 23 0E 8E A9 90 58 46 42 42 39 31 D6 ..@4#... .XFBB91.
+[2650] 03 9E 5D 81 D9 E8 F6 08 2B D9 96 88 8A 2F F1 CC ..]..... +..../..
+[2660] F2 EA 9E 9A 4B 31 B6 04 2D 3D 4C 7F 92 DE 3B 04 ....K1.. -=L...;.
+[2670] 19 EE 28 D0 83 81 C3 46 CD 74 23 4C 14 34 DE 62 ..(....F .t#L.4.b
+[2680] 0A AC E5 12 16 75 E9 A8 4B 32 78 CC 8D AE A2 E5 .....u.. K2x.....
+[2690] 6D E8 09 70 76 52 F5 E5 18 F7 E7 91 15 6A 69 AB m..pvR.. .....ji.
+[26A0] B8 62 DD 80 F5 28 6D DF ED 10 DA AC FB 92 27 CF .b...(m. ......'.
+[26B0] 98 B5 77 9D A5 96 E6 9A CC B9 C3 91 78 22 35 9C ..w..... ....x"5.
+[26C0] A1 13 A3 20 28 D1 16 E5 3E 4A 85 1E 12 0B CA 4D ... (... >J.....M
+[26D0] C6 C8 03 C8 28 2C D8 29 5D 9A 76 4A 92 13 43 56 ....(,.) ].vJ..CV
+[26E0] AF F7 C1 71 25 72 5C 38 75 1C 07 F1 5E 86 05 72 ...q%r\8 u...^..r
+[26F0] 6F 69 95 42 B6 F2 DA A9 91 06 9F B9 54 20 33 A5 oi.B.... ....T 3.
+[2700] 31 60 3B 54 DC 3A 95 34 96 26 07 52 6B 0E 1D 3B 1`;T.:.4 .&.Rk..;
+[2710] D9 F8 48 20 AC CD 05 3B 99 F8 EE DB 83 28 CD C7 ..H ...; .....(..
+[2720] 2F 45 00 7E 2F 0A 65 7A D1 9E 95 4B EE C3 34 93 /E.~/.ez ...K..4.
+[2730] A8 C7 DF 03 8B 14 D0 FC CE 56 90 AC EE 93 C5 D3 ........ .V......
+[2740] F7 12 24 69 0B 20 8D A2 65 87 55 26 2A F9 9A 88 ..$i. .. e.U&*...
+[2750] D7 0D 86 61 D6 92 B6 FE E5 D1 66 F9 1F 9D F4 04 ...a.... ..f.....
+[2760] 48 A6 39 BC 54 20 EA 10 21 E9 6D 30 46 1D C2 1C H.9.T .. !.m0F...
+[2770] A4 E8 B4 63 85 37 27 25 80 52 41 60 C7 A1 32 21 ...c.7'% .RA`..2!
+[2780] 43 90 02 E6 5F 5A E9 4E AF F9 B5 13 BD 42 BD A3 C..._Z.N .....B..
+[2790] A5 4D 10 45 83 4D 92 18 1F C9 CF FB 84 29 89 23 .M.E.M.. .....).#
+[27A0] AC 71 4B 89 1B 52 E5 06 8C 3E 7C 88 CB D3 B3 CF .qK..R.. .>|.....
+[27B0] B9 7A 67 D6 24 F4 AC 00 A6 AD 91 30 9A 95 53 F1 .zg.$... ...0..S.
+[27C0] 48 06 A6 39 DB CF DC 9D C9 55 76 26 5E C1 DB 5D H..9.... .Uv&^..]
+[27D0] B3 5B 3E AE 1A A0 10 BA 82 21 83 44 02 E0 99 33 .[>..... .!.D...3
+[27E0] 40 BA 29 9E 28 E5 73 4C 23 94 A2 4F BF 07 ED 4F @.).(.sL #..O...O
+[27F0] 7C 45 9B 30 C8 41 6B 0A 55 13 6E F5 AD 7A 0C B2 |E.0.Ak. U.n..z..
+[2800] EA FF D0 06 13 4D F3 24 82 7F F6 51 2F 4A 4F 0D .....M.$ ...Q/JO.
+[2810] 37 F8 14 6B E9 E4 82 BB 3A 75 63 63 12 E8 78 6F 7..k.... :ucc..xo
+[2820] 6F FC 6C D3 4B A6 F1 CC 2A F1 7D EB 82 26 2F D0 o.l.K... *.}..&/.
+[2830] A1 8B 3E 9A 71 D7 91 D3 08 E6 FD 62 1B 84 13 2D ..>.q... ...b...-
+[2840] 8E A0 A0 C3 85 78 2F 0D F8 E7 10 FC CB 05 A7 B9 .....x/. ........
+[2850] 9A 33 90 B5 9B 26 E3 23 98 B0 91 4B EB 32 37 D6 .3...&.# ...K.27.
+[2860] F4 ED 61 08 D8 75 CC 03 83 2C 3C CF 21 63 9C F6 ..a..u.. .,<.!c..
+[2870] AF 5B 4F 12 07 74 17 CD 98 BB E7 5E C7 17 2D C4 .[O..t.. ...^..-.
+[2880] 87 A4 74 6D 5E CE DB A3 01 B9 AD 20 73 38 78 22 ..tm^... ... s8x"
+[2890] 3D 45 F5 51 77 C6 47 63 45 61 81 D9 FF 31 90 C4 =E.Qw.Gc Ea...1..
+[28A0] 6F 5A F8 FE 6A 56 5B D4 EE EC 49 C7 A7 51 AE 5C oZ..jV[. ..I..Q.\
+[28B0] 85 53 70 3D 1A 49 83 59 CF 65 58 B3 48 7E 04 9E .Sp=.I.Y .eX.H~..
+[28C0] C7 64 8A 05 73 E3 DC 1A 65 5D 4F 41 01 56 73 90 .d..s... e]OA.Vs.
+[28D0] 61 F3 84 1F FF CF 46 B2 06 46 56 97 93 B9 DB 32 a.....F. .FV....2
+[28E0] 2A 64 8A 48 02 05 84 E9 FA 76 8B 94 96 89 A0 73 *d.H.... .v.....s
+[28F0] 20 75 4D 52 1D 23 13 D1 83 D7 5D 59 23 6A 87 C1 uMR.#.. ..]Y#j..
+[2900] 09 3E 01 3A 28 65 42 8C 35 F1 91 EA 6A 1F 83 0D .>.:(eB. 5...j...
+[2910] 8F 57 69 81 D4 A2 D2 EA 0C BF AF 95 A3 F4 90 15 .Wi..... ........
+[2920] 61 34 F2 6C 8B D0 DA B5 1E 43 AC CE C7 8A 1B 2B a4.l.... .C.....+
+[2930] 29 2B 89 1C C5 53 C8 04 F7 1E 46 72 F3 A8 CE F7 )+...S.. ..Fr....
+[2940] 59 76 55 E7 53 1C A2 9F D8 23 F7 EA 71 B0 74 83 YvU.S... .#..q.t.
+[2950] 71 95 3E DC A6 FA 2D A4 42 13 93 8B 2B FA A2 70 q.>...-. B...+..p
+[2960] 25 21 2D F6 E1 26 56 DF 58 79 25 16 E8 C9 03 EC %!-..&V. Xy%.....
+[2970] 72 5F 35 CF 59 6B E1 AD 85 85 7B AB 78 F2 0D AC r_5.Yk.. ..{.x...
+[2980] AB 89 F2 DA 85 E7 DE 09 77 99 EC 7C F3 97 1F 71 ........ w..|...q
+[2990] 3C DB 09 44 7A 3C 69 E5 03 B0 6D 4D 3B 6B 4C D5 <..Dz.B].]}
+[00E0] 0B 1F C3 88 2A 93 40 F9 E9 18 7D 3F 73 DA AC 1F ....*.@. ..}?s...
+[00F0] E7 7B C3 B8 14 56 C3 63 86 5B AF C9 C3 21 9F 94 .{...V.c .[...!..
+[0100] B4 67 06 60 7F 56 2D F4 C7 22 CD B4 1C 14 B7 5B .g.`.V-. .".....[
+[0110] 26 67 9D 18 28 B5 5D C2 FC 13 B6 CA 9F AB CD 32 &g..(.]. .......2
+[0120] 71 D5 51 5F A2 11 5A 5D 4A B3 3B 1D D1 6B 4F 7D q.Q_..Z] J.;..kO}
+[0130] E9 54 F0 B4 AC 80 DE 27 80 C5 64 3C 0B 22 79 1C .T.....' ..d<."y.
+[0140] 9E D1 58 A1 3E 20 5A 9F E3 34 49 D8 16 C6 6B 2D ..X.> Z. .4I...k-
+[0150] 36 0E E2 C2 3F 44 DE 63 32 DB EB 78 50 A2 6F 37 6...?D.c 2..xP.o7
+[0160] 05 2B 13 D4 31 07 D4 2A C0 53 B1 30 39 79 C3 D8 .+..1..* .S.09y..
+[0170] C4 4C 30 97 E8 F9 DA ED 10 B0 D0 21 71 8B 56 F3 .L0..... ...!q.V.
+[0180] 0F 3A 2D 26 A2 3D AD 70 27 82 95 59 0A D7 7D 4E .:-&.=.p '..Y..}N
+[0190] 2D 76 96 4D 94 70 2A BB 26 3B 7E FC E1 59 5A 55 -v.M.p*. &;~..YZU
+[01A0] 04 A2 DA 27 AD 46 70 45 43 C0 FB C1 42 7F F0 CB ...'.FpE C...B...
+[01B0] 21 D2 CD 54 35 7C 60 13 EE BB BB 60 6B 91 2B BE !..T5|`. ...`k.+.
+[01C0] 91 8A CF 49 29 F8 60 D1 AB A5 51 B5 5E 4B B2 3A ...I).`. ..Q.^K.:
+[01D0] F4 56 3A 89 2D 88 D0 73 08 A6 FB D8 6E B3 B1 4E .V:.-..s ....n..N
+[01E0] D8 90 27 58 D2 53 40 B2 A0 3C 40 4D E9 21 C6 83 ..'X.S@. .<@M.!..
+[01F0] FC 15 14 F0 8C 08 46 C5 29 14 E3 84 CC 2C 56 C9 ......F. )....,V.
+[0200] 20 53 45 34 D0 BE E0 CC F7 F1 15 D4 D4 B1 3C 43 SE4.... .......BT.Ba
+[03A0] C5 22 B7 AE 51 76 8F 12 83 7F E1 9F 97 D8 31 38 ."..Qv.. ......18
+[03B0] A6 B9 11 B4 E1 BA 19 5B E4 A5 A3 6F 4B B3 03 93 .......[ ...oK...
+[03C0] 4C D6 1E 08 FC 94 D1 C5 7C AA 95 EB 9C 7A C2 57 L....... |....z.W
+[03D0] 60 CA 17 FF 8E 66 80 76 CB 35 46 26 C3 BD CA 83 `....f.v .5F&....
+[03E0] F0 04 08 0D 4C 5D B2 E4 7C 1C 82 28 D7 2C 42 B1 ....L].. |..(.,B.
+[03F0] 36 72 60 5E 26 4A 79 D0 41 94 3C 2C 65 0E 32 18 6r`^&Jy. A.<,e.2.
+[0400] B8 56 26 9D D3 84 78 BB .V&...x.
+ second_ticket : DATA_BLOB length=0
+ further_creds : DATA_BLOB length=4748
+[0000] 00 00 00 01 00 00 00 01 00 00 00 17 4B 54 45 53 ........ ....KTES
+[0010] 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E T.SAMBA. EXAMPLE.
+[0020] 43 4F 4D 00 00 00 0D 61 64 6D 69 6E 69 73 74 72 COM....a dministr
+[0030] 61 74 6F 72 00 00 00 01 00 00 00 02 00 00 00 17 ator.... ........
+[0040] 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D KTEST.SA MBA.EXAM
+[0050] 50 4C 45 2E 43 4F 4D 00 00 00 04 68 6F 73 74 00 PLE.COM. ...host.
+[0060] 00 00 0B 6C 6F 63 61 6C 6B 74 65 73 74 36 00 17 ...local ktest6..
+[0070] 00 00 00 10 EA 0D 3A 24 41 21 F7 7D 7D A3 C5 BB ......:$ A!.}}...
+[0080] A4 88 F6 17 4D 9B 90 45 4D 9B 90 52 7D 46 4C 43 ....M..E M..R}FLC
+[0090] 00 00 00 00 00 40 28 00 00 00 00 00 00 00 00 00 .....@(. ........
+[00A0] 00 00 00 03 FA 61 82 03 F6 30 82 03 F2 A0 03 02 .....a.. .0......
+[00B0] 01 05 A1 19 1B 17 4B 54 45 53 54 2E 53 41 4D 42 ......KT EST.SAMB
+[00C0] 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D A2 1E 30 A.EXAMPL E.COM..0
+[00D0] 1C A0 03 02 01 01 A1 15 30 13 1B 04 68 6F 73 74 ........ 0...host
+[00E0] 1B 0B 6C 6F 63 61 6C 6B 74 65 73 74 36 A3 82 03 ..localk test6...
+[00F0] AE 30 82 03 AA A0 03 02 01 17 A1 03 02 01 03 A2 .0...... ........
+[0100] 82 03 9C 04 82 03 98 44 8B C4 7D BA 9F FE 59 F6 .......D ..}...Y.
+[0110] C1 DF 62 89 02 A4 55 54 AB D6 D6 2E 8B 5E 35 3D ..b...UT .....^5=
+[0120] D9 46 9D 8B 49 93 A6 66 5F 1A 8B 81 AD 09 19 E9 .F..I..f _.......
+[0130] 59 CE 58 18 50 63 4A A6 7D 6F 71 21 51 4A 41 C2 Y.X.PcJ. }oq!QJA.
+[0140] A1 FE B0 D5 0A 3D 38 9F E5 3B 72 A2 7A 59 22 A4 .....=8. .;r.zY".
+[0150] B7 1C A3 8D DB EA 5D A5 E2 D3 1D AE 42 D0 7F 75 ......]. ....B..u
+[0160] B5 E9 ED B5 04 7B 67 1E 28 90 7D 3D 1A 3E F6 62 .....{g. (.}=.>.b
+[0170] D0 A1 56 89 28 76 5C 19 1A FD 66 E5 F2 86 E7 58 ..V.(v\. ..f....X
+[0180] 93 31 90 C5 CD F8 71 96 56 21 15 13 F0 EA C2 CC .1....q. V!......
+[0190] 48 4C B4 50 EF F9 81 44 29 8A 75 C4 31 75 D1 BA HL.P...D ).u.1u..
+[01A0] E2 0B 05 B2 E0 EA 64 3A 11 45 84 3D 69 55 FF E6 ......d: .E.=iU..
+[01B0] 32 7E C9 CA C4 28 E8 40 B6 5E F9 26 0F 09 12 1F 2~...(.@ .^.&....
+[01C0] 1F D4 9C 9A 50 E8 B7 6D F8 4F 55 6E 2A D4 AC 6A ....P..m .OUn*..j
+[01D0] 79 D1 C2 2A 88 99 F8 39 75 36 F1 2D C7 89 0A C6 y..*...9 u6.-....
+[01E0] B4 C7 A1 7B F1 BF 22 87 A4 B2 93 22 54 A1 72 25 ...{..". ..."T.r%
+[01F0] AF 67 FE 20 D5 C8 29 47 28 FF 51 FB F9 4E 2C 17 .g. ..)G (.Q..N,.
+[0200] 10 BE 2E 13 8B 18 BE 3C A3 BE 50 49 A7 65 DD 2E .......< ..PI.e..
+[0210] CC EB D6 0F 47 4E DB 7E 08 D5 F0 37 79 36 8F 24 ....GN.~ ...7y6.$
+[0220] 34 28 86 89 EC A3 84 7F 44 4E 37 03 B5 D8 89 1C 4(...... DN7.....
+[0230] C7 AA AC 42 70 5F 96 73 35 8B 83 D1 16 24 27 C1 ...Bp_.s 5....$'.
+[0240] EC 0E AE 83 59 5A C2 EB C1 91 B6 3D BB 8D 21 49 ....YZ.. ...=..!I
+[0250] 63 41 3C 91 1D E9 01 C2 4F A9 E4 42 C1 FD 54 E3 cA<..... O..B..T.
+[0260] 7B 3B DF 24 3D 98 E9 84 F8 1D 8D CE 4D 85 AC 8A {;.$=... ....M...
+[0270] 12 15 48 C4 DA 1B 3C B8 FC A3 0B AF E2 4D 71 E9 ..H...<. .....Mq.
+[0280] 0A 28 53 DC 4E 6C 23 2C 73 26 50 FE 37 03 BF D1 .(S.Nl#, s&P.7...
+[0290] 5F 8A 39 4F 04 2E 4A CE 3C 90 11 0C DA 84 5C C3 _.9O..J. <.....\.
+[02A0] F8 BE C7 74 ED F4 CF 7E B2 AE 9B 47 D6 2A 1D 93 ...t...~ ...G.*..
+[02B0] 3F A8 8B 51 E9 A3 A0 59 55 DB E3 52 67 E3 DE FF ?..Q...Y U..Rg...
+[02C0] B1 56 74 A0 87 21 99 23 8C 8E D1 92 A6 3D 93 D6 .Vt..!.# .....=..
+[02D0] 4D 5B 84 2B B1 8D DD E4 F7 01 A6 6C 4A DF 3C 6E M[.+.... ...lJ....+...
+[0330] 4B 6D 22 B3 41 DE 85 35 2D 19 09 E5 68 8E 1F 98 Km".A..5 -...h...
+[0340] 1B F2 73 F2 D4 91 08 89 42 0C 05 8B 42 77 6B CC ..s..... B...Bwk.
+[0350] 18 78 43 1A 73 C2 7C E7 C2 23 28 56 F7 A0 19 B3 .xC.s.|. .#(V....
+[0360] 99 A6 25 4F C3 5E 70 EC 78 BB 30 15 36 77 B3 A6 ..%O.^p. x.0.6w..
+[0370] 89 98 B6 A0 85 CC 8F E7 41 40 B5 E0 89 93 25 04 ........ A@....%.
+[0380] B8 1D 0B 06 31 1D C7 30 52 E1 64 29 8C 64 B9 89 ....1..0 R.d).d..
+[0390] 1F 86 5A AD 74 15 1C C8 AF 37 7B 27 E0 C0 DB 73 ..Z.t... .7{'...s
+[03A0] 30 72 65 D3 C0 A5 07 61 E9 0C 07 A1 27 18 8F 50 0re....a ....'..P
+[03B0] DB CE FB 4C DD 75 98 F2 28 D2 76 FF F2 41 9F D5 ...L.u.. (.v..A..
+[03C0] 74 22 8A 03 73 B1 A8 B3 B8 80 93 E5 E2 CD 4B F2 t"..s... ......K.
+[03D0] 6B 99 DF 5B 5B C7 22 69 81 2A 8A CD 2A F9 9D 08 k..[[."i .*..*...
+[03E0] B8 B0 40 77 D3 43 8B AF 40 DD 0C CB 45 E3 88 CB ..@w.C.. @...E...
+[03F0] 06 AA 63 38 EB DD 72 89 03 0E DC 3E 97 3F 16 D4 ..c8..r. ...>.?..
+[0400] 1A 21 40 D8 30 BD B0 B4 04 C2 7A 22 43 15 A2 D8 .!@.0... ..z"C...
+[0410] 2F 08 28 3B 63 26 AA B3 1C B6 FC E4 0B 2A CD 0E /.(;c&.. .....*..
+[0420] A8 7C E8 11 33 03 D3 C5 6C 35 6A 5D 3C 5A 80 1A .|..3... l5j];J
+[0680] 60 25 3D 11 E4 F9 16 02 3E 55 8F CE D2 E9 95 E7 `%=..... >U......
+[0690] B1 C4 8F C4 0B 3E 3C 14 15 28 1A 21 49 15 CE 8E .....><. .(.!I...
+[06A0] 91 5E 98 71 00 1F 29 D3 12 C8 D0 11 4F E7 14 E3 .^.q..). ....O...
+[06B0] 72 1B 61 6D 7B 8A 00 A6 5E 01 01 50 C2 CF 1A A9 r.am{... ^..P....
+[06C0] 34 8C BA 33 9E 62 C5 69 97 6A 24 3D E0 C6 3F C6 4..3.b.i .j$=..?.
+[06D0] F4 36 B1 80 D6 5C 44 19 5B 65 C7 CA 47 DE 4B 65 .6...\D. [e..G.Ke
+[06E0] 41 29 9F F8 EA E8 E0 3B E2 C6 98 9D 58 A4 6C 62 A).....; ....X.lb
+[06F0] EF 25 12 C9 0E 97 CE 9D F0 D8 08 AD 13 73 A6 82 .%...... .....s..
+[0700] C5 54 23 F4 A4 CB 91 35 91 BD 10 B4 04 DD 55 7E .T#....5 ......U~
+[0710] C9 DE AE CB B0 8F C0 D8 28 AE BD 78 64 91 6C AB ........ (..xd.l.
+[0720] CA 36 EA 0E 0E 97 DC 40 ED 26 1D 09 17 28 30 D3 .6.....@ .&...(0.
+[0730] 78 DC F7 D2 9C 78 DA 6F 6F 57 00 B3 FD 8E 75 A1 x....x.o oW....u.
+[0740] 56 98 5C 4B D8 61 A6 0A 89 27 CD 11 BF 7F 79 53 V.\K.a.. .'....yS
+[0750] D9 50 9A 8D EC DD DB BB B8 23 27 0D 20 5B 53 51 .P...... .#'. [SQ
+[0760] 07 C4 26 31 3B D4 DF ED 3C 40 B4 1C 8B 46 E2 A6 ..&1;... <@...F..
+[0770] B7 0F 97 D2 B3 1D 19 FD 13 60 7B 38 E6 37 0C 59 ........ .`{8.7.Y
+[0780] B0 A8 47 5D 32 A5 0C 57 76 EF 2C ED 40 9F BF 4B ..G]2..W v.,.@..K
+[0790] 43 99 3C 68 C4 DE 84 9C A1 36 8C CA CB 2A 08 36 C..%p.4 ...>..-.
+[0930] 72 8E DA 4D 2D 55 EC 49 66 5E 01 96 E4 C1 0C 23 r..M-U.I f^.....#
+[0940] 57 91 00 00 00 00 00 00 00 01 00 00 00 01 00 00 W....... ........
+[0950] 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 ..KTEST. SAMBA.EX
+[0960] 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D 61 64 6D AMPLE.CO M....adm
+[0970] 69 6E 69 73 74 72 61 74 6F 72 00 00 00 01 00 00 inistrat or......
+[0980] 00 02 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 ......KT EST.SAMB
+[0990] 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 A.EXAMPL E.COM...
+[09A0] 04 68 6F 73 74 00 00 00 0B 4C 4F 43 41 4C 4B 54 .host... .LOCALKT
+[09B0] 45 53 54 36 00 17 00 00 00 10 9D AE 06 BE 29 E0 EST6.... ......).
+[09C0] F7 9A 46 97 29 E0 69 8E 5A F0 4D 9B 90 45 4D 9B ..F.).i. Z.M..EM.
+[09D0] 90 61 7D 46 4C 43 00 00 00 00 00 40 28 00 00 00 .a}FLC.. ...@(...
+[09E0] 00 00 00 00 00 00 00 00 00 03 FA 61 82 03 F6 30 ........ ...a...0
+[09F0] 82 03 F2 A0 03 02 01 05 A1 19 1B 17 4B 54 45 53 ........ ....KTES
+[0A00] 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E T.SAMBA. EXAMPLE.
+[0A10] 43 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 15 30 13 COM..0.. ......0.
+[0A20] 1B 04 68 6F 73 74 1B 0B 4C 4F 43 41 4C 4B 54 45 ..host.. LOCALKTE
+[0A30] 53 54 36 A3 82 03 AE 30 82 03 AA A0 03 02 01 17 ST6....0 ........
+[0A40] A1 03 02 01 03 A2 82 03 9C 04 82 03 98 B9 C5 6E ........ .......n
+[0A50] 77 F9 59 6D 19 F0 A6 56 2F 14 B3 9A A3 17 06 A6 w.Ym...V /.......
+[0A60] AD F5 92 38 6A 1E EA 3D 53 BF 5E 95 13 FF 5D BB ...8j..= S.^...].
+[0A70] 43 4F 51 AE FB 12 3B 06 67 36 91 B9 E0 C4 C4 F3 COQ...;. g6......
+[0A80] 45 A0 48 E6 DC 49 E8 EA 6F 55 D2 3F 79 57 54 FF E.H..I.. oU.?yWT.
+[0A90] 10 8D 89 4A A4 E2 B2 80 FD EE 36 C5 D5 4C D0 97 ...J.... ..6..L..
+[0AA0] B3 EC 96 8B E8 5A 05 F0 13 39 8B 1B B3 C4 32 2A .....Z.. .9....2*
+[0AB0] 9B BB EF 06 C4 1C 53 2F 0A F6 A8 C6 BE 09 57 26 ......S/ ......W&
+[0AC0] B9 39 7B 7B 50 13 2D 6C 52 FF C4 B5 83 28 A8 47 .9{{P.-l R....(.G
+[0AD0] 5A CD 1C DD A7 65 FD 8A 84 2A 10 E7 44 E6 83 E7 Z....e.. .*..D...
+[0AE0] E7 AA B8 E5 0A 8B 7E E1 87 7B 3D C4 9F 68 BD 19 ......~. .{=..h..
+[0AF0] 2B 59 5E 5A 45 0D B5 71 CC A6 C7 03 3C B3 17 D3 +Y^ZE..q ....<...
+[0B00] AF 99 F6 A2 52 A0 99 F7 39 56 B4 33 B4 C5 F4 CC ....R... 9V.3....
+[0B10] 74 34 4C 00 76 26 10 D1 3A 87 6E 6A 52 9B 7A BF t4L.v&.. :.njR.z.
+[0B20] 4E 59 36 32 C5 41 29 CF E1 BF 14 E0 54 BF 4A 25 NY62.A). ....T.J%
+[0B30] 1F 0B 6E 9A 8C 0E 5D 47 A9 64 1B A4 9D 99 A9 09 ..n...]G .d......
+[0B40] 39 14 E7 41 22 98 8C 62 CC E2 B5 91 8E C1 31 EB 9..A"..b ......1.
+[0B50] B2 70 A6 3B 86 FC DD 19 0B 3F 5D C9 B5 1A 95 73 .p.;.... .?]....s
+[0B60] EB 97 89 BE 14 87 85 17 BE 40 F6 80 14 23 4D 66 ........ .@...#Mf
+[0B70] E4 B0 E5 51 46 34 DA 1C C8 CB FF C6 84 A3 DF D2 ...QF4.. ........
+[0B80] DC 00 AF 7B 27 C8 78 44 CB 6E 7B CC 5C 94 1E 7A ...{'.xD .n{.\..z
+[0B90] 95 29 19 F4 14 BE 5C 23 C3 B9 A4 2C 5D 4D F3 61 .)....\# ...,]M.a
+[0BA0] 63 1F D4 FE 37 EE 44 14 06 B7 14 50 B6 74 37 75 c...7.D. ...P.t7u
+[0BB0] 2C AB 06 F0 93 F9 93 34 75 63 44 7E 12 48 D1 F1 ,......4 ucD~.H..
+[0BC0] 06 55 14 11 B9 23 43 CE 01 16 3E 6B A3 BD 23 55 .U...#C. ..>k..#U
+[0BD0] DE 48 5D AF E1 2B 89 E8 E7 C2 E2 34 25 A2 09 4A .H]..+.. ...4%..J
+[0BE0] 1F BE 05 AA DE 4B 08 65 27 4C 9B C7 54 96 C2 FB .....K.e 'L..T...
+[0BF0] E2 CE 53 4A 32 93 8D 0B 44 77 8C D3 65 54 F9 0E ..SJ2... Dw..eT..
+[0C00] 7F 74 1E FE 3D 74 83 0F 2F E7 9F BC A2 B0 2B 25 .t..=t.. /.....+%
+[0C10] BB D2 6F A8 49 C1 3E 9E B5 93 67 74 39 A4 FE 84 ..o.I.>. ..gt9...
+[0C20] 4C 45 5F 30 74 E0 CA 5F F6 46 EC 89 B5 2D C8 14 LE_0t.._ .F...-..
+[0C30] 69 76 BC 93 15 F4 60 30 5F AB EB 02 DD 12 4C 62 iv....`0 _.....Lb
+[0C40] F9 73 F7 01 E1 7F 2A 6F 09 05 BF 3A 3A 7E 69 A3 .s....*o ...::~i.
+[0C50] 7B FC 20 2B D6 CE C0 74 4F BB 29 E4 BE CE 04 9D {. +...t O.).....
+[0C60] 24 D4 98 4A ED 94 A8 81 CD 26 A0 63 EA 09 57 42 $..J.... .&.c..WB
+[0C70] 26 B7 B5 4E B5 CB 45 35 A7 84 D8 74 CA C3 9F FF &..N..E5 ...t....
+[0C80] C8 1E 2A 75 34 01 C5 A7 B4 9D 6F A3 E1 BB 2B F8 ..*u4... ..o...+.
+[0C90] F0 21 D6 77 57 74 2E 80 DB 76 53 01 86 33 17 32 .!.wWt.. .vS..3.2
+[0CA0] 2E 16 E1 8D 89 3A B2 67 ED A3 ED 39 82 87 26 A6 .....:.g ...9..&.
+[0CB0] DB CE 59 84 E4 0A A6 CA 7E 07 98 F7 02 91 6E 56 ..Y..... ~.....nV
+[0CC0] 9F 60 03 D3 88 B0 FF EB 20 CA 9E 5B 37 26 67 00 .`...... ..[7&g.
+[0CD0] CC BD 9D 53 15 31 53 14 FD 9C E1 28 08 CB C4 0B ...S.1S. ...(....
+[0CE0] E3 50 D9 DB 0C E2 E4 F9 44 50 E9 28 6E 01 96 AA .P...... DP.(n...
+[0CF0] C1 D2 4E B2 DE 38 A2 F8 94 32 79 AE 49 64 FB 57 ..N..8.. .2y.Id.W
+[0D00] 50 F6 73 E8 98 43 C6 DD 67 3C 91 AC 97 C9 2E 8C P.s..C.. g<......
+[0D10] 06 59 A1 FC 49 EC 2F BF 6F 64 21 63 ED C8 6C CE .Y..I./. od!c..l.
+[0D20] 37 28 7B 80 7F 5F 85 F6 98 93 C0 66 A8 D6 F1 2C 7({.._.. ...f...,
+[0D30] D8 01 68 B1 C8 EA 82 0D 5B 9B 35 4F 3D B3 47 19 ..h..... [.5O=.G.
+[0D40] 54 7A C6 9F AD D7 54 CF B0 DB 3E 18 BA 2A 39 08 Tz....T. ..>..*9.
+[0D50] 0C C4 98 4B 43 DE 53 68 25 B1 83 93 1D E1 6C BF ...KC.Sh %.....l.
+[0D60] F5 B4 A9 83 17 34 64 8C 2F 91 80 97 4A 48 EC 90 .....4d. /...JH..
+[0D70] BB FA 92 2C 01 80 E4 99 91 0E 67 88 D5 75 AB 7C ...,.... ..g..u.|
+[0D80] 98 59 98 45 C9 11 A9 8C 02 98 91 DE AB A0 FF 45 .Y.E.... .......E
+[0D90] 11 66 6F C5 DE 61 6D C6 DB C9 CA A3 A0 2B B1 73 .fo..am. .....+.s
+[0DA0] 05 85 37 BF AB CA 43 7A 6F 38 C8 BE ED CE 12 49 ..7...Cz o8.....I
+[0DB0] 93 C7 7C 1A 33 60 52 7A 67 67 AA 60 57 7E C8 FF ..|.3`Rz gg.`W~..
+[0DC0] DF 91 91 18 45 74 C0 9E 36 19 BC 42 F9 46 CC 84 ....Et.. 6..B.F..
+[0DD0] 09 2E 8C 59 1A E3 65 51 F4 87 6F 4C 3E 29 38 E6 ...Y..eQ ..oL>)8.
+[0DE0] 77 E8 A9 B7 FA 00 00 00 00 00 00 00 01 00 00 00 w....... ........
+[0DF0] 01 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 .....KTE ST.SAMBA
+[0E00] 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D .EXAMPLE .COM....
+[0E10] 61 64 6D 69 6E 69 73 74 72 61 74 6F 72 00 00 00 administ rator...
+[0E20] 01 00 00 00 02 00 00 00 17 4B 54 45 53 54 2E 53 ........ .KTEST.S
+[0E30] 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D AMBA.EXA MPLE.COM
+[0E40] 00 00 00 04 63 69 66 73 00 00 00 0B 4C 4F 43 41 ....cifs ....LOCA
+[0E50] 4C 4B 54 45 53 54 36 00 17 00 00 00 10 01 78 D0 LKTEST6. ......x.
+[0E60] 3B 9B FF F0 88 86 4B 3B FE 41 A9 6B 00 4D 9B 90 ;.....K; .A.k.M..
+[0E70] 45 4D 9B 90 6B 7D 46 4C 43 00 00 00 00 00 40 28 EM..k}FL C.....@(
+[0E80] 00 00 00 00 00 00 00 00 00 00 00 00 03 FA 61 82 ........ ......a.
+[0E90] 03 F6 30 82 03 F2 A0 03 02 01 05 A1 19 1B 17 4B ..0..... .......K
+[0EA0] 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 TEST.SAM BA.EXAMP
+[0EB0] 4C 45 2E 43 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 LE.COM.. 0.......
+[0EC0] 15 30 13 1B 04 63 69 66 73 1B 0B 4C 4F 43 41 4C .0...cif s..LOCAL
+[0ED0] 4B 54 45 53 54 36 A3 82 03 AE 30 82 03 AA A0 03 KTEST6.. ..0.....
+[0EE0] 02 01 17 A1 03 02 01 03 A2 82 03 9C 04 82 03 98 ........ ........
+[0EF0] CA EA 4D 46 2D D1 E9 58 5D 25 8D 9F DF EA C9 01 ..MF-..X ]%......
+[0F00] B6 08 27 CD 14 85 02 DC 20 C6 51 AA F9 6A B1 CE ..'..... .Q..j..
+[0F10] F5 77 84 BF 9A AC 6B A7 B2 F2 1F 60 BF CB C6 FC .w....k. ...`....
+[0F20] C7 14 B7 41 1C A8 C9 70 7B 86 BC 8E 70 2B 65 4B ...A...p {...p+eK
+[0F30] DC F5 B9 23 F8 08 BF 96 C9 A8 77 F4 54 67 25 F8 ...#.... ..w.Tg%.
+[0F40] 0F A8 C5 D6 D1 BB 46 5E A0 7E D2 98 9C CD AF E0 ......F^ .~......
+[0F50] 82 62 ED 39 D2 FB F2 E8 9B 1B EE E5 B4 1B C9 0A .b.9.... ........
+[0F60] 86 27 52 6E 11 8B D7 AD B4 54 F9 C6 69 8D E0 F1 .'Rn.... .T..i...
+[0F70] CD 63 1C 89 7C 8F B6 A0 71 53 A6 DA B1 66 D2 9D .c..|... qS...f..
+[0F80] D3 4C A8 FB C6 9D 81 74 10 8E 84 D2 3D D8 1C BE .L.....t ....=...
+[0F90] BB 3F F7 BF 91 3E 89 66 43 A1 E0 90 1B 1A 97 FF .?...>.f C.......
+[0FA0] EF CC 35 75 14 62 4F 67 3A 29 F4 F9 C5 2E BE C5 ..5u.bOg :)......
+[0FB0] C2 2B A8 35 22 D9 92 31 1D 49 2A A5 19 AA 08 0F .+.5"..1 .I*.....
+[0FC0] A8 22 0B 68 D2 A2 D7 07 7B 37 1E A3 AC 9B 4F 0A .".h.... {7....O.
+[0FD0] A4 FA 7F 37 6F 3E 35 79 4E 00 4B B6 28 A3 6A E4 ...7o>5y N.K.(.j.
+[0FE0] 0C 95 53 BA E8 41 07 DA BE E9 08 B9 51 24 91 49 ..S..A.. ....Q$.I
+[0FF0] 78 5D 44 12 BC 85 63 81 B8 E0 88 D5 95 0C D3 A8 x]D...c. ........
+[1000] 1D 32 4B E4 A0 C8 A7 7D 3C 97 EE D8 59 AC 3A 21 .2K....} <...Y.:!
+[1010] 09 F2 7A CC D0 4A F3 50 10 DC FC 26 BB C2 6A 8E ..z..J.P ...&..j.
+[1020] 8B 14 2B 2D 50 2E B3 1E 9B D2 69 56 22 F2 48 BD ..+-P... ..iV".H.
+[1030] E9 2E 2F 28 DE 77 67 5F 68 AA 29 05 4B 36 58 40 ../(.wg_ h.).K6X@
+[1040] E5 54 11 C5 4D 68 96 49 9D 53 37 87 5F D2 3A 9B .T..Mh.I .S7._.:.
+[1050] E9 8E 79 BE AE 11 B4 6B AB FD DB 8A F5 A0 9B 29 ..y....k .......)
+[1060] D9 F5 ED CA FA 3F FE 35 FC F4 69 7E E4 D0 44 29 .....?.5 ..i~..D)
+[1070] 48 FF 82 61 26 FC D3 E2 10 EE 14 F7 4A E3 CD F2 H..a&... ....J...
+[1080] 8B BC 8B 43 64 2C DE 40 6E BB E1 56 C0 B6 2C D0 ...Cd,.@ n..V..,.
+[1090] E5 1E E9 B3 FB 38 48 66 ED AF D2 25 D1 35 5C C6 .....8Hf ...%.5\.
+[10A0] F0 4D 36 19 0B EC 33 07 34 D0 27 8D 14 DC 01 45 .M6...3. 4.'....E
+[10B0] DE F8 73 A6 A0 F4 C1 91 9D BD 05 E3 70 25 E1 10 ..s..... ....p%..
+[10C0] 44 F6 4B 46 F7 24 84 BF 20 96 AD 6A 96 94 81 58 D.KF.$.. ..j...X
+[10D0] 80 95 06 92 F5 7F 17 39 3B 32 47 B2 C5 CE 7B 73 .......9 ;2G...{s
+[10E0] CF 53 AE FA D1 9A 60 5A 98 EC 8C FA BD C0 CE 8D .S....`Z ........
+[10F0] C5 27 E6 17 1A 4D 47 D8 3F 5D A9 7C FB 2C B3 05 .'...MG. ?].|.,..
+[1100] 0C 69 20 48 99 80 11 DC 48 AB A7 EA 5B 98 C1 15 .i H.... H...[...
+[1110] 27 AE FA 3E 1E 1E E0 E1 F8 32 C0 54 13 D6 30 34 '..>.... .2.T..04
+[1120] 71 98 26 61 6C 1C C4 C7 4E C4 A6 7E FE A8 B8 89 q.&al... N..~....
+[1130] 2A 70 3C 19 58 8D 57 45 55 83 0A C2 B5 F7 89 0E *p<.X.WE U.......
+[1140] 7B 7A 17 0C CF 6E 08 A5 F7 21 4A 62 81 4F 49 CA {z...n.. .!Jb.OI.
+[1150] E2 ED C2 B4 C7 33 5C BC A1 A0 DE 4E 09 37 BE 24 .....3\. ...N.7.$
+[1160] 62 22 94 55 75 AA 53 DE E0 74 5A B0 B8 E9 BF 2B b".Uu.S. .tZ....+
+[1170] 12 65 2F 90 6B 84 ED 11 AD F7 CE 19 A1 96 E4 1E .e/.k... ........
+[1180] 8C EA C8 81 1B 47 4F 5F B1 5D A5 8B E3 0D 5A 80 .....GO_ .]....Z.
+[1190] 89 EC 4B D9 CE ED E8 67 7F 96 FC 1B EF 65 C2 68 ..K....g .....e.h
+[11A0] 40 F7 20 36 83 58 62 F4 CA 02 F4 5C 0D 46 B1 CB @. 6.Xb. ...\.F..
+[11B0] 50 D2 D8 3D B7 9A 96 48 8C CF EB E6 8C F4 B2 B4 P..=...H ........
+[11C0] 47 C9 34 C9 DC 14 F1 33 1B 6F 9E 65 27 D7 9D 46 G.4....3 .o.e'..F
+[11D0] 1E 91 FF 2E FB 8E 97 5D 17 8F 48 54 7C 3C A0 11 .......] ..HT|<..
+[11E0] 9C AA 77 E9 79 DE 26 D1 F0 7C EA 24 73 BE EC 60 ..w.y.&. .|.$s..`
+[11F0] B4 EE BD ED 0D 0A AB 74 60 6E 46 C0 35 5B 65 1A .......t `nF.5[e.
+[1200] A4 4A 5C 22 AC B9 CD B7 56 06 88 09 FC 48 68 55 .J\".... V....HhU
+[1210] B7 5E 39 72 DF 8A 4C CD 79 74 B0 84 0B 78 DA B2 .^9r..L. yt...x..
+[1220] 55 F8 06 0B 5C 27 06 B3 CA 10 65 6B 04 A3 64 11 U...\'.. ..ek..d.
+[1230] 04 09 DC DF 67 00 70 B1 16 DF 24 E9 27 85 11 91 ....g.p. ..$.'...
+[1240] 31 CB 92 95 50 18 91 08 C2 A1 A3 76 C7 1A FC 64 1...P... ...v...d
+[1250] 9E 2C 3A E7 30 F4 16 0D A0 56 C0 BC D2 FE 2D A0 .,:.0... .V....-.
+[1260] 20 A4 E2 82 AD F0 C5 12 71 09 23 E1 66 52 53 D0 ....... q.#.fRS.
+[1270] 89 30 E7 BE B7 C2 89 F2 1C 7A F6 8E D7 28 F0 A4 .0...... .z...(..
+[1280] 33 46 7C A2 79 66 DE 26 00 00 00 00 3F|.yf.& ....
+push returned Success
+pull returned Success
+ CCACHE: struct CCACHE
+ pvno : 0x05 (5)
+ version : 0x04 (4)
+ optional_header : union OPTIONAL_HEADER(case 0x4)
+ v4header: struct V4HEADER
+ v4tags: struct V4TAGS
+ tag: struct V4TAG
+ tag : 0x0001 (1)
+ field : union FIELD(case 0x1)
+ deltatime_tag: struct DELTATIME_TAG
+ kdc_sec_offset : 0
+ kdc_usec_offset : 0
+ further_tags : DATA_BLOB length=0
+ principal: struct PRINCIPAL
+ name_type : 0x00000001 (1)
+ component_count : 0x00000001 (1)
+ realm : 'KTEST.SAMBA.EXAMPLE.COM'
+ components: ARRAY(1)
+ components : 'administrator'
+ cred: struct CREDENTIAL
+ client: struct PRINCIPAL
+ name_type : 0x00000001 (1)
+ component_count : 0x00000001 (1)
+ realm : 'KTEST.SAMBA.EXAMPLE.COM'
+ components: ARRAY(1)
+ components : 'administrator'
+ server: struct PRINCIPAL
+ name_type : 0x00000000 (0)
+ component_count : 0x00000002 (2)
+ realm : 'KTEST.SAMBA.EXAMPLE.COM'
+ components: ARRAY(2)
+ components : 'krbtgt'
+ components : 'KTEST.SAMBA.EXAMPLE.COM'
+ keyblock: struct KEYBLOCK
+ enctype : 0x0017 (23)
+ data : DATA_BLOB length=16
+[0000] E5 E4 15 C8 A8 0F 4D 95 F9 1B E3 B9 98 CA A1 7F ......M. ........
+ authtime : 0x4d9b9045 (1302040645)
+ starttime : 0x4d9b9045 (1302040645)
+ endtime : 0x7d464c43 (2101759043)
+ renew_till : 0x7d464c43 (2101759043)
+ is_skey : 0x00 (0)
+ ticket_flags : 0x40e00000 (1088421888)
+ addresses: struct ADDRESSES
+ count : 0x00000000 (0)
+ data: ARRAY(0)
+ authdata: struct AUTHDATA
+ count : 0x00000000 (0)
+ data: ARRAY(0)
+ ticket : DATA_BLOB length=1032
+[0000] 61 82 04 04 30 82 04 00 A0 03 02 01 05 A1 19 1B a...0... ........
+[0010] 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 .KTEST.S AMBA.EXA
+[0020] 4D 50 4C 45 2E 43 4F 4D A2 2C 30 2A A0 03 02 01 MPLE.COM .,0*....
+[0030] 00 A1 23 30 21 1B 06 6B 72 62 74 67 74 1B 17 4B ..#0!..k rbtgt..K
+[0040] 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 TEST.SAM BA.EXAMP
+[0050] 4C 45 2E 43 4F 4D A3 82 03 AE 30 82 03 AA A0 03 LE.COM.. ..0.....
+[0060] 02 01 17 A1 03 02 01 01 A2 82 03 9C 04 82 03 98 ........ ........
+[0070] 01 40 48 A6 B8 F0 DA 43 54 A5 18 CF B0 15 CB 68 .@H....C T......h
+[0080] 9F A0 69 44 87 A9 FF 06 25 B9 29 48 59 64 26 48 ..iD.... %.)HYd&H
+[0090] 96 7C 46 6A 79 E5 F0 77 DB 46 6C 20 A1 59 D9 F8 .|Fjy..w .Fl .Y..
+[00A0] 6A 8A 2D B5 D9 EF A4 54 DE 19 20 C0 7B 93 D4 3D j.-....T .. .{..=
+[00B0] ED 72 35 AF 9D 87 75 9E 44 01 A4 6C D9 EA 94 A3 .r5...u. D..l....
+[00C0] 18 C6 42 75 E3 0A 0C 76 9A AE 75 BC A3 02 91 BC ..Bu...v ..u.....
+[00D0] 2D BB 3C 23 73 A6 1A A7 8A 3E 85 42 5D 1F 5D 7D -.<#s... .>.B].]}
+[00E0] 0B 1F C3 88 2A 93 40 F9 E9 18 7D 3F 73 DA AC 1F ....*.@. ..}?s...
+[00F0] E7 7B C3 B8 14 56 C3 63 86 5B AF C9 C3 21 9F 94 .{...V.c .[...!..
+[0100] B4 67 06 60 7F 56 2D F4 C7 22 CD B4 1C 14 B7 5B .g.`.V-. .".....[
+[0110] 26 67 9D 18 28 B5 5D C2 FC 13 B6 CA 9F AB CD 32 &g..(.]. .......2
+[0120] 71 D5 51 5F A2 11 5A 5D 4A B3 3B 1D D1 6B 4F 7D q.Q_..Z] J.;..kO}
+[0130] E9 54 F0 B4 AC 80 DE 27 80 C5 64 3C 0B 22 79 1C .T.....' ..d<."y.
+[0140] 9E D1 58 A1 3E 20 5A 9F E3 34 49 D8 16 C6 6B 2D ..X.> Z. .4I...k-
+[0150] 36 0E E2 C2 3F 44 DE 63 32 DB EB 78 50 A2 6F 37 6...?D.c 2..xP.o7
+[0160] 05 2B 13 D4 31 07 D4 2A C0 53 B1 30 39 79 C3 D8 .+..1..* .S.09y..
+[0170] C4 4C 30 97 E8 F9 DA ED 10 B0 D0 21 71 8B 56 F3 .L0..... ...!q.V.
+[0180] 0F 3A 2D 26 A2 3D AD 70 27 82 95 59 0A D7 7D 4E .:-&.=.p '..Y..}N
+[0190] 2D 76 96 4D 94 70 2A BB 26 3B 7E FC E1 59 5A 55 -v.M.p*. &;~..YZU
+[01A0] 04 A2 DA 27 AD 46 70 45 43 C0 FB C1 42 7F F0 CB ...'.FpE C...B...
+[01B0] 21 D2 CD 54 35 7C 60 13 EE BB BB 60 6B 91 2B BE !..T5|`. ...`k.+.
+[01C0] 91 8A CF 49 29 F8 60 D1 AB A5 51 B5 5E 4B B2 3A ...I).`. ..Q.^K.:
+[01D0] F4 56 3A 89 2D 88 D0 73 08 A6 FB D8 6E B3 B1 4E .V:.-..s ....n..N
+[01E0] D8 90 27 58 D2 53 40 B2 A0 3C 40 4D E9 21 C6 83 ..'X.S@. .<@M.!..
+[01F0] FC 15 14 F0 8C 08 46 C5 29 14 E3 84 CC 2C 56 C9 ......F. )....,V.
+[0200] 20 53 45 34 D0 BE E0 CC F7 F1 15 D4 D4 B1 3C 43 SE4.... .......BT.Ba
+[03A0] C5 22 B7 AE 51 76 8F 12 83 7F E1 9F 97 D8 31 38 ."..Qv.. ......18
+[03B0] A6 B9 11 B4 E1 BA 19 5B E4 A5 A3 6F 4B B3 03 93 .......[ ...oK...
+[03C0] 4C D6 1E 08 FC 94 D1 C5 7C AA 95 EB 9C 7A C2 57 L....... |....z.W
+[03D0] 60 CA 17 FF 8E 66 80 76 CB 35 46 26 C3 BD CA 83 `....f.v .5F&....
+[03E0] F0 04 08 0D 4C 5D B2 E4 7C 1C 82 28 D7 2C 42 B1 ....L].. |..(.,B.
+[03F0] 36 72 60 5E 26 4A 79 D0 41 94 3C 2C 65 0E 32 18 6r`^&Jy. A.<,e.2.
+[0400] B8 56 26 9D D3 84 78 BB .V&...x.
+ second_ticket : DATA_BLOB length=0
+ further_creds : DATA_BLOB length=4748
+[0000] 00 00 00 01 00 00 00 01 00 00 00 17 4B 54 45 53 ........ ....KTES
+[0010] 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E T.SAMBA. EXAMPLE.
+[0020] 43 4F 4D 00 00 00 0D 61 64 6D 69 6E 69 73 74 72 COM....a dministr
+[0030] 61 74 6F 72 00 00 00 01 00 00 00 02 00 00 00 17 ator.... ........
+[0040] 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D KTEST.SA MBA.EXAM
+[0050] 50 4C 45 2E 43 4F 4D 00 00 00 04 68 6F 73 74 00 PLE.COM. ...host.
+[0060] 00 00 0B 6C 6F 63 61 6C 6B 74 65 73 74 36 00 17 ...local ktest6..
+[0070] 00 00 00 10 EA 0D 3A 24 41 21 F7 7D 7D A3 C5 BB ......:$ A!.}}...
+[0080] A4 88 F6 17 4D 9B 90 45 4D 9B 90 52 7D 46 4C 43 ....M..E M..R}FLC
+[0090] 00 00 00 00 00 40 28 00 00 00 00 00 00 00 00 00 .....@(. ........
+[00A0] 00 00 00 03 FA 61 82 03 F6 30 82 03 F2 A0 03 02 .....a.. .0......
+[00B0] 01 05 A1 19 1B 17 4B 54 45 53 54 2E 53 41 4D 42 ......KT EST.SAMB
+[00C0] 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D A2 1E 30 A.EXAMPL E.COM..0
+[00D0] 1C A0 03 02 01 01 A1 15 30 13 1B 04 68 6F 73 74 ........ 0...host
+[00E0] 1B 0B 6C 6F 63 61 6C 6B 74 65 73 74 36 A3 82 03 ..localk test6...
+[00F0] AE 30 82 03 AA A0 03 02 01 17 A1 03 02 01 03 A2 .0...... ........
+[0100] 82 03 9C 04 82 03 98 44 8B C4 7D BA 9F FE 59 F6 .......D ..}...Y.
+[0110] C1 DF 62 89 02 A4 55 54 AB D6 D6 2E 8B 5E 35 3D ..b...UT .....^5=
+[0120] D9 46 9D 8B 49 93 A6 66 5F 1A 8B 81 AD 09 19 E9 .F..I..f _.......
+[0130] 59 CE 58 18 50 63 4A A6 7D 6F 71 21 51 4A 41 C2 Y.X.PcJ. }oq!QJA.
+[0140] A1 FE B0 D5 0A 3D 38 9F E5 3B 72 A2 7A 59 22 A4 .....=8. .;r.zY".
+[0150] B7 1C A3 8D DB EA 5D A5 E2 D3 1D AE 42 D0 7F 75 ......]. ....B..u
+[0160] B5 E9 ED B5 04 7B 67 1E 28 90 7D 3D 1A 3E F6 62 .....{g. (.}=.>.b
+[0170] D0 A1 56 89 28 76 5C 19 1A FD 66 E5 F2 86 E7 58 ..V.(v\. ..f....X
+[0180] 93 31 90 C5 CD F8 71 96 56 21 15 13 F0 EA C2 CC .1....q. V!......
+[0190] 48 4C B4 50 EF F9 81 44 29 8A 75 C4 31 75 D1 BA HL.P...D ).u.1u..
+[01A0] E2 0B 05 B2 E0 EA 64 3A 11 45 84 3D 69 55 FF E6 ......d: .E.=iU..
+[01B0] 32 7E C9 CA C4 28 E8 40 B6 5E F9 26 0F 09 12 1F 2~...(.@ .^.&....
+[01C0] 1F D4 9C 9A 50 E8 B7 6D F8 4F 55 6E 2A D4 AC 6A ....P..m .OUn*..j
+[01D0] 79 D1 C2 2A 88 99 F8 39 75 36 F1 2D C7 89 0A C6 y..*...9 u6.-....
+[01E0] B4 C7 A1 7B F1 BF 22 87 A4 B2 93 22 54 A1 72 25 ...{..". ..."T.r%
+[01F0] AF 67 FE 20 D5 C8 29 47 28 FF 51 FB F9 4E 2C 17 .g. ..)G (.Q..N,.
+[0200] 10 BE 2E 13 8B 18 BE 3C A3 BE 50 49 A7 65 DD 2E .......< ..PI.e..
+[0210] CC EB D6 0F 47 4E DB 7E 08 D5 F0 37 79 36 8F 24 ....GN.~ ...7y6.$
+[0220] 34 28 86 89 EC A3 84 7F 44 4E 37 03 B5 D8 89 1C 4(...... DN7.....
+[0230] C7 AA AC 42 70 5F 96 73 35 8B 83 D1 16 24 27 C1 ...Bp_.s 5....$'.
+[0240] EC 0E AE 83 59 5A C2 EB C1 91 B6 3D BB 8D 21 49 ....YZ.. ...=..!I
+[0250] 63 41 3C 91 1D E9 01 C2 4F A9 E4 42 C1 FD 54 E3 cA<..... O..B..T.
+[0260] 7B 3B DF 24 3D 98 E9 84 F8 1D 8D CE 4D 85 AC 8A {;.$=... ....M...
+[0270] 12 15 48 C4 DA 1B 3C B8 FC A3 0B AF E2 4D 71 E9 ..H...<. .....Mq.
+[0280] 0A 28 53 DC 4E 6C 23 2C 73 26 50 FE 37 03 BF D1 .(S.Nl#, s&P.7...
+[0290] 5F 8A 39 4F 04 2E 4A CE 3C 90 11 0C DA 84 5C C3 _.9O..J. <.....\.
+[02A0] F8 BE C7 74 ED F4 CF 7E B2 AE 9B 47 D6 2A 1D 93 ...t...~ ...G.*..
+[02B0] 3F A8 8B 51 E9 A3 A0 59 55 DB E3 52 67 E3 DE FF ?..Q...Y U..Rg...
+[02C0] B1 56 74 A0 87 21 99 23 8C 8E D1 92 A6 3D 93 D6 .Vt..!.# .....=..
+[02D0] 4D 5B 84 2B B1 8D DD E4 F7 01 A6 6C 4A DF 3C 6E M[.+.... ...lJ....+...
+[0330] 4B 6D 22 B3 41 DE 85 35 2D 19 09 E5 68 8E 1F 98 Km".A..5 -...h...
+[0340] 1B F2 73 F2 D4 91 08 89 42 0C 05 8B 42 77 6B CC ..s..... B...Bwk.
+[0350] 18 78 43 1A 73 C2 7C E7 C2 23 28 56 F7 A0 19 B3 .xC.s.|. .#(V....
+[0360] 99 A6 25 4F C3 5E 70 EC 78 BB 30 15 36 77 B3 A6 ..%O.^p. x.0.6w..
+[0370] 89 98 B6 A0 85 CC 8F E7 41 40 B5 E0 89 93 25 04 ........ A@....%.
+[0380] B8 1D 0B 06 31 1D C7 30 52 E1 64 29 8C 64 B9 89 ....1..0 R.d).d..
+[0390] 1F 86 5A AD 74 15 1C C8 AF 37 7B 27 E0 C0 DB 73 ..Z.t... .7{'...s
+[03A0] 30 72 65 D3 C0 A5 07 61 E9 0C 07 A1 27 18 8F 50 0re....a ....'..P
+[03B0] DB CE FB 4C DD 75 98 F2 28 D2 76 FF F2 41 9F D5 ...L.u.. (.v..A..
+[03C0] 74 22 8A 03 73 B1 A8 B3 B8 80 93 E5 E2 CD 4B F2 t"..s... ......K.
+[03D0] 6B 99 DF 5B 5B C7 22 69 81 2A 8A CD 2A F9 9D 08 k..[[."i .*..*...
+[03E0] B8 B0 40 77 D3 43 8B AF 40 DD 0C CB 45 E3 88 CB ..@w.C.. @...E...
+[03F0] 06 AA 63 38 EB DD 72 89 03 0E DC 3E 97 3F 16 D4 ..c8..r. ...>.?..
+[0400] 1A 21 40 D8 30 BD B0 B4 04 C2 7A 22 43 15 A2 D8 .!@.0... ..z"C...
+[0410] 2F 08 28 3B 63 26 AA B3 1C B6 FC E4 0B 2A CD 0E /.(;c&.. .....*..
+[0420] A8 7C E8 11 33 03 D3 C5 6C 35 6A 5D 3C 5A 80 1A .|..3... l5j];J
+[0680] 60 25 3D 11 E4 F9 16 02 3E 55 8F CE D2 E9 95 E7 `%=..... >U......
+[0690] B1 C4 8F C4 0B 3E 3C 14 15 28 1A 21 49 15 CE 8E .....><. .(.!I...
+[06A0] 91 5E 98 71 00 1F 29 D3 12 C8 D0 11 4F E7 14 E3 .^.q..). ....O...
+[06B0] 72 1B 61 6D 7B 8A 00 A6 5E 01 01 50 C2 CF 1A A9 r.am{... ^..P....
+[06C0] 34 8C BA 33 9E 62 C5 69 97 6A 24 3D E0 C6 3F C6 4..3.b.i .j$=..?.
+[06D0] F4 36 B1 80 D6 5C 44 19 5B 65 C7 CA 47 DE 4B 65 .6...\D. [e..G.Ke
+[06E0] 41 29 9F F8 EA E8 E0 3B E2 C6 98 9D 58 A4 6C 62 A).....; ....X.lb
+[06F0] EF 25 12 C9 0E 97 CE 9D F0 D8 08 AD 13 73 A6 82 .%...... .....s..
+[0700] C5 54 23 F4 A4 CB 91 35 91 BD 10 B4 04 DD 55 7E .T#....5 ......U~
+[0710] C9 DE AE CB B0 8F C0 D8 28 AE BD 78 64 91 6C AB ........ (..xd.l.
+[0720] CA 36 EA 0E 0E 97 DC 40 ED 26 1D 09 17 28 30 D3 .6.....@ .&...(0.
+[0730] 78 DC F7 D2 9C 78 DA 6F 6F 57 00 B3 FD 8E 75 A1 x....x.o oW....u.
+[0740] 56 98 5C 4B D8 61 A6 0A 89 27 CD 11 BF 7F 79 53 V.\K.a.. .'....yS
+[0750] D9 50 9A 8D EC DD DB BB B8 23 27 0D 20 5B 53 51 .P...... .#'. [SQ
+[0760] 07 C4 26 31 3B D4 DF ED 3C 40 B4 1C 8B 46 E2 A6 ..&1;... <@...F..
+[0770] B7 0F 97 D2 B3 1D 19 FD 13 60 7B 38 E6 37 0C 59 ........ .`{8.7.Y
+[0780] B0 A8 47 5D 32 A5 0C 57 76 EF 2C ED 40 9F BF 4B ..G]2..W v.,.@..K
+[0790] 43 99 3C 68 C4 DE 84 9C A1 36 8C CA CB 2A 08 36 C..%p.4 ...>..-.
+[0930] 72 8E DA 4D 2D 55 EC 49 66 5E 01 96 E4 C1 0C 23 r..M-U.I f^.....#
+[0940] 57 91 00 00 00 00 00 00 00 01 00 00 00 01 00 00 W....... ........
+[0950] 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 ..KTEST. SAMBA.EX
+[0960] 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D 61 64 6D AMPLE.CO M....adm
+[0970] 69 6E 69 73 74 72 61 74 6F 72 00 00 00 01 00 00 inistrat or......
+[0980] 00 02 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 ......KT EST.SAMB
+[0990] 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 A.EXAMPL E.COM...
+[09A0] 04 68 6F 73 74 00 00 00 0B 4C 4F 43 41 4C 4B 54 .host... .LOCALKT
+[09B0] 45 53 54 36 00 17 00 00 00 10 9D AE 06 BE 29 E0 EST6.... ......).
+[09C0] F7 9A 46 97 29 E0 69 8E 5A F0 4D 9B 90 45 4D 9B ..F.).i. Z.M..EM.
+[09D0] 90 61 7D 46 4C 43 00 00 00 00 00 40 28 00 00 00 .a}FLC.. ...@(...
+[09E0] 00 00 00 00 00 00 00 00 00 03 FA 61 82 03 F6 30 ........ ...a...0
+[09F0] 82 03 F2 A0 03 02 01 05 A1 19 1B 17 4B 54 45 53 ........ ....KTES
+[0A00] 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E T.SAMBA. EXAMPLE.
+[0A10] 43 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 15 30 13 COM..0.. ......0.
+[0A20] 1B 04 68 6F 73 74 1B 0B 4C 4F 43 41 4C 4B 54 45 ..host.. LOCALKTE
+[0A30] 53 54 36 A3 82 03 AE 30 82 03 AA A0 03 02 01 17 ST6....0 ........
+[0A40] A1 03 02 01 03 A2 82 03 9C 04 82 03 98 B9 C5 6E ........ .......n
+[0A50] 77 F9 59 6D 19 F0 A6 56 2F 14 B3 9A A3 17 06 A6 w.Ym...V /.......
+[0A60] AD F5 92 38 6A 1E EA 3D 53 BF 5E 95 13 FF 5D BB ...8j..= S.^...].
+[0A70] 43 4F 51 AE FB 12 3B 06 67 36 91 B9 E0 C4 C4 F3 COQ...;. g6......
+[0A80] 45 A0 48 E6 DC 49 E8 EA 6F 55 D2 3F 79 57 54 FF E.H..I.. oU.?yWT.
+[0A90] 10 8D 89 4A A4 E2 B2 80 FD EE 36 C5 D5 4C D0 97 ...J.... ..6..L..
+[0AA0] B3 EC 96 8B E8 5A 05 F0 13 39 8B 1B B3 C4 32 2A .....Z.. .9....2*
+[0AB0] 9B BB EF 06 C4 1C 53 2F 0A F6 A8 C6 BE 09 57 26 ......S/ ......W&
+[0AC0] B9 39 7B 7B 50 13 2D 6C 52 FF C4 B5 83 28 A8 47 .9{{P.-l R....(.G
+[0AD0] 5A CD 1C DD A7 65 FD 8A 84 2A 10 E7 44 E6 83 E7 Z....e.. .*..D...
+[0AE0] E7 AA B8 E5 0A 8B 7E E1 87 7B 3D C4 9F 68 BD 19 ......~. .{=..h..
+[0AF0] 2B 59 5E 5A 45 0D B5 71 CC A6 C7 03 3C B3 17 D3 +Y^ZE..q ....<...
+[0B00] AF 99 F6 A2 52 A0 99 F7 39 56 B4 33 B4 C5 F4 CC ....R... 9V.3....
+[0B10] 74 34 4C 00 76 26 10 D1 3A 87 6E 6A 52 9B 7A BF t4L.v&.. :.njR.z.
+[0B20] 4E 59 36 32 C5 41 29 CF E1 BF 14 E0 54 BF 4A 25 NY62.A). ....T.J%
+[0B30] 1F 0B 6E 9A 8C 0E 5D 47 A9 64 1B A4 9D 99 A9 09 ..n...]G .d......
+[0B40] 39 14 E7 41 22 98 8C 62 CC E2 B5 91 8E C1 31 EB 9..A"..b ......1.
+[0B50] B2 70 A6 3B 86 FC DD 19 0B 3F 5D C9 B5 1A 95 73 .p.;.... .?]....s
+[0B60] EB 97 89 BE 14 87 85 17 BE 40 F6 80 14 23 4D 66 ........ .@...#Mf
+[0B70] E4 B0 E5 51 46 34 DA 1C C8 CB FF C6 84 A3 DF D2 ...QF4.. ........
+[0B80] DC 00 AF 7B 27 C8 78 44 CB 6E 7B CC 5C 94 1E 7A ...{'.xD .n{.\..z
+[0B90] 95 29 19 F4 14 BE 5C 23 C3 B9 A4 2C 5D 4D F3 61 .)....\# ...,]M.a
+[0BA0] 63 1F D4 FE 37 EE 44 14 06 B7 14 50 B6 74 37 75 c...7.D. ...P.t7u
+[0BB0] 2C AB 06 F0 93 F9 93 34 75 63 44 7E 12 48 D1 F1 ,......4 ucD~.H..
+[0BC0] 06 55 14 11 B9 23 43 CE 01 16 3E 6B A3 BD 23 55 .U...#C. ..>k..#U
+[0BD0] DE 48 5D AF E1 2B 89 E8 E7 C2 E2 34 25 A2 09 4A .H]..+.. ...4%..J
+[0BE0] 1F BE 05 AA DE 4B 08 65 27 4C 9B C7 54 96 C2 FB .....K.e 'L..T...
+[0BF0] E2 CE 53 4A 32 93 8D 0B 44 77 8C D3 65 54 F9 0E ..SJ2... Dw..eT..
+[0C00] 7F 74 1E FE 3D 74 83 0F 2F E7 9F BC A2 B0 2B 25 .t..=t.. /.....+%
+[0C10] BB D2 6F A8 49 C1 3E 9E B5 93 67 74 39 A4 FE 84 ..o.I.>. ..gt9...
+[0C20] 4C 45 5F 30 74 E0 CA 5F F6 46 EC 89 B5 2D C8 14 LE_0t.._ .F...-..
+[0C30] 69 76 BC 93 15 F4 60 30 5F AB EB 02 DD 12 4C 62 iv....`0 _.....Lb
+[0C40] F9 73 F7 01 E1 7F 2A 6F 09 05 BF 3A 3A 7E 69 A3 .s....*o ...::~i.
+[0C50] 7B FC 20 2B D6 CE C0 74 4F BB 29 E4 BE CE 04 9D {. +...t O.).....
+[0C60] 24 D4 98 4A ED 94 A8 81 CD 26 A0 63 EA 09 57 42 $..J.... .&.c..WB
+[0C70] 26 B7 B5 4E B5 CB 45 35 A7 84 D8 74 CA C3 9F FF &..N..E5 ...t....
+[0C80] C8 1E 2A 75 34 01 C5 A7 B4 9D 6F A3 E1 BB 2B F8 ..*u4... ..o...+.
+[0C90] F0 21 D6 77 57 74 2E 80 DB 76 53 01 86 33 17 32 .!.wWt.. .vS..3.2
+[0CA0] 2E 16 E1 8D 89 3A B2 67 ED A3 ED 39 82 87 26 A6 .....:.g ...9..&.
+[0CB0] DB CE 59 84 E4 0A A6 CA 7E 07 98 F7 02 91 6E 56 ..Y..... ~.....nV
+[0CC0] 9F 60 03 D3 88 B0 FF EB 20 CA 9E 5B 37 26 67 00 .`...... ..[7&g.
+[0CD0] CC BD 9D 53 15 31 53 14 FD 9C E1 28 08 CB C4 0B ...S.1S. ...(....
+[0CE0] E3 50 D9 DB 0C E2 E4 F9 44 50 E9 28 6E 01 96 AA .P...... DP.(n...
+[0CF0] C1 D2 4E B2 DE 38 A2 F8 94 32 79 AE 49 64 FB 57 ..N..8.. .2y.Id.W
+[0D00] 50 F6 73 E8 98 43 C6 DD 67 3C 91 AC 97 C9 2E 8C P.s..C.. g<......
+[0D10] 06 59 A1 FC 49 EC 2F BF 6F 64 21 63 ED C8 6C CE .Y..I./. od!c..l.
+[0D20] 37 28 7B 80 7F 5F 85 F6 98 93 C0 66 A8 D6 F1 2C 7({.._.. ...f...,
+[0D30] D8 01 68 B1 C8 EA 82 0D 5B 9B 35 4F 3D B3 47 19 ..h..... [.5O=.G.
+[0D40] 54 7A C6 9F AD D7 54 CF B0 DB 3E 18 BA 2A 39 08 Tz....T. ..>..*9.
+[0D50] 0C C4 98 4B 43 DE 53 68 25 B1 83 93 1D E1 6C BF ...KC.Sh %.....l.
+[0D60] F5 B4 A9 83 17 34 64 8C 2F 91 80 97 4A 48 EC 90 .....4d. /...JH..
+[0D70] BB FA 92 2C 01 80 E4 99 91 0E 67 88 D5 75 AB 7C ...,.... ..g..u.|
+[0D80] 98 59 98 45 C9 11 A9 8C 02 98 91 DE AB A0 FF 45 .Y.E.... .......E
+[0D90] 11 66 6F C5 DE 61 6D C6 DB C9 CA A3 A0 2B B1 73 .fo..am. .....+.s
+[0DA0] 05 85 37 BF AB CA 43 7A 6F 38 C8 BE ED CE 12 49 ..7...Cz o8.....I
+[0DB0] 93 C7 7C 1A 33 60 52 7A 67 67 AA 60 57 7E C8 FF ..|.3`Rz gg.`W~..
+[0DC0] DF 91 91 18 45 74 C0 9E 36 19 BC 42 F9 46 CC 84 ....Et.. 6..B.F..
+[0DD0] 09 2E 8C 59 1A E3 65 51 F4 87 6F 4C 3E 29 38 E6 ...Y..eQ ..oL>)8.
+[0DE0] 77 E8 A9 B7 FA 00 00 00 00 00 00 00 01 00 00 00 w....... ........
+[0DF0] 01 00 00 00 17 4B 54 45 53 54 2E 53 41 4D 42 41 .....KTE ST.SAMBA
+[0E00] 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D 00 00 00 0D .EXAMPLE .COM....
+[0E10] 61 64 6D 69 6E 69 73 74 72 61 74 6F 72 00 00 00 administ rator...
+[0E20] 01 00 00 00 02 00 00 00 17 4B 54 45 53 54 2E 53 ........ .KTEST.S
+[0E30] 41 4D 42 41 2E 45 58 41 4D 50 4C 45 2E 43 4F 4D AMBA.EXA MPLE.COM
+[0E40] 00 00 00 04 63 69 66 73 00 00 00 0B 4C 4F 43 41 ....cifs ....LOCA
+[0E50] 4C 4B 54 45 53 54 36 00 17 00 00 00 10 01 78 D0 LKTEST6. ......x.
+[0E60] 3B 9B FF F0 88 86 4B 3B FE 41 A9 6B 00 4D 9B 90 ;.....K; .A.k.M..
+[0E70] 45 4D 9B 90 6B 7D 46 4C 43 00 00 00 00 00 40 28 EM..k}FL C.....@(
+[0E80] 00 00 00 00 00 00 00 00 00 00 00 00 03 FA 61 82 ........ ......a.
+[0E90] 03 F6 30 82 03 F2 A0 03 02 01 05 A1 19 1B 17 4B ..0..... .......K
+[0EA0] 54 45 53 54 2E 53 41 4D 42 41 2E 45 58 41 4D 50 TEST.SAM BA.EXAMP
+[0EB0] 4C 45 2E 43 4F 4D A2 1E 30 1C A0 03 02 01 01 A1 LE.COM.. 0.......
+[0EC0] 15 30 13 1B 04 63 69 66 73 1B 0B 4C 4F 43 41 4C .0...cif s..LOCAL
+[0ED0] 4B 54 45 53 54 36 A3 82 03 AE 30 82 03 AA A0 03 KTEST6.. ..0.....
+[0EE0] 02 01 17 A1 03 02 01 03 A2 82 03 9C 04 82 03 98 ........ ........
+[0EF0] CA EA 4D 46 2D D1 E9 58 5D 25 8D 9F DF EA C9 01 ..MF-..X ]%......
+[0F00] B6 08 27 CD 14 85 02 DC 20 C6 51 AA F9 6A B1 CE ..'..... .Q..j..
+[0F10] F5 77 84 BF 9A AC 6B A7 B2 F2 1F 60 BF CB C6 FC .w....k. ...`....
+[0F20] C7 14 B7 41 1C A8 C9 70 7B 86 BC 8E 70 2B 65 4B ...A...p {...p+eK
+[0F30] DC F5 B9 23 F8 08 BF 96 C9 A8 77 F4 54 67 25 F8 ...#.... ..w.Tg%.
+[0F40] 0F A8 C5 D6 D1 BB 46 5E A0 7E D2 98 9C CD AF E0 ......F^ .~......
+[0F50] 82 62 ED 39 D2 FB F2 E8 9B 1B EE E5 B4 1B C9 0A .b.9.... ........
+[0F60] 86 27 52 6E 11 8B D7 AD B4 54 F9 C6 69 8D E0 F1 .'Rn.... .T..i...
+[0F70] CD 63 1C 89 7C 8F B6 A0 71 53 A6 DA B1 66 D2 9D .c..|... qS...f..
+[0F80] D3 4C A8 FB C6 9D 81 74 10 8E 84 D2 3D D8 1C BE .L.....t ....=...
+[0F90] BB 3F F7 BF 91 3E 89 66 43 A1 E0 90 1B 1A 97 FF .?...>.f C.......
+[0FA0] EF CC 35 75 14 62 4F 67 3A 29 F4 F9 C5 2E BE C5 ..5u.bOg :)......
+[0FB0] C2 2B A8 35 22 D9 92 31 1D 49 2A A5 19 AA 08 0F .+.5"..1 .I*.....
+[0FC0] A8 22 0B 68 D2 A2 D7 07 7B 37 1E A3 AC 9B 4F 0A .".h.... {7....O.
+[0FD0] A4 FA 7F 37 6F 3E 35 79 4E 00 4B B6 28 A3 6A E4 ...7o>5y N.K.(.j.
+[0FE0] 0C 95 53 BA E8 41 07 DA BE E9 08 B9 51 24 91 49 ..S..A.. ....Q$.I
+[0FF0] 78 5D 44 12 BC 85 63 81 B8 E0 88 D5 95 0C D3 A8 x]D...c. ........
+[1000] 1D 32 4B E4 A0 C8 A7 7D 3C 97 EE D8 59 AC 3A 21 .2K....} <...Y.:!
+[1010] 09 F2 7A CC D0 4A F3 50 10 DC FC 26 BB C2 6A 8E ..z..J.P ...&..j.
+[1020] 8B 14 2B 2D 50 2E B3 1E 9B D2 69 56 22 F2 48 BD ..+-P... ..iV".H.
+[1030] E9 2E 2F 28 DE 77 67 5F 68 AA 29 05 4B 36 58 40 ../(.wg_ h.).K6X@
+[1040] E5 54 11 C5 4D 68 96 49 9D 53 37 87 5F D2 3A 9B .T..Mh.I .S7._.:.
+[1050] E9 8E 79 BE AE 11 B4 6B AB FD DB 8A F5 A0 9B 29 ..y....k .......)
+[1060] D9 F5 ED CA FA 3F FE 35 FC F4 69 7E E4 D0 44 29 .....?.5 ..i~..D)
+[1070] 48 FF 82 61 26 FC D3 E2 10 EE 14 F7 4A E3 CD F2 H..a&... ....J...
+[1080] 8B BC 8B 43 64 2C DE 40 6E BB E1 56 C0 B6 2C D0 ...Cd,.@ n..V..,.
+[1090] E5 1E E9 B3 FB 38 48 66 ED AF D2 25 D1 35 5C C6 .....8Hf ...%.5\.
+[10A0] F0 4D 36 19 0B EC 33 07 34 D0 27 8D 14 DC 01 45 .M6...3. 4.'....E
+[10B0] DE F8 73 A6 A0 F4 C1 91 9D BD 05 E3 70 25 E1 10 ..s..... ....p%..
+[10C0] 44 F6 4B 46 F7 24 84 BF 20 96 AD 6A 96 94 81 58 D.KF.$.. ..j...X
+[10D0] 80 95 06 92 F5 7F 17 39 3B 32 47 B2 C5 CE 7B 73 .......9 ;2G...{s
+[10E0] CF 53 AE FA D1 9A 60 5A 98 EC 8C FA BD C0 CE 8D .S....`Z ........
+[10F0] C5 27 E6 17 1A 4D 47 D8 3F 5D A9 7C FB 2C B3 05 .'...MG. ?].|.,..
+[1100] 0C 69 20 48 99 80 11 DC 48 AB A7 EA 5B 98 C1 15 .i H.... H...[...
+[1110] 27 AE FA 3E 1E 1E E0 E1 F8 32 C0 54 13 D6 30 34 '..>.... .2.T..04
+[1120] 71 98 26 61 6C 1C C4 C7 4E C4 A6 7E FE A8 B8 89 q.&al... N..~....
+[1130] 2A 70 3C 19 58 8D 57 45 55 83 0A C2 B5 F7 89 0E *p<.X.WE U.......
+[1140] 7B 7A 17 0C CF 6E 08 A5 F7 21 4A 62 81 4F 49 CA {z...n.. .!Jb.OI.
+[1150] E2 ED C2 B4 C7 33 5C BC A1 A0 DE 4E 09 37 BE 24 .....3\. ...N.7.$
+[1160] 62 22 94 55 75 AA 53 DE E0 74 5A B0 B8 E9 BF 2B b".Uu.S. .tZ....+
+[1170] 12 65 2F 90 6B 84 ED 11 AD F7 CE 19 A1 96 E4 1E .e/.k... ........
+[1180] 8C EA C8 81 1B 47 4F 5F B1 5D A5 8B E3 0D 5A 80 .....GO_ .]....Z.
+[1190] 89 EC 4B D9 CE ED E8 67 7F 96 FC 1B EF 65 C2 68 ..K....g .....e.h
+[11A0] 40 F7 20 36 83 58 62 F4 CA 02 F4 5C 0D 46 B1 CB @. 6.Xb. ...\.F..
+[11B0] 50 D2 D8 3D B7 9A 96 48 8C CF EB E6 8C F4 B2 B4 P..=...H ........
+[11C0] 47 C9 34 C9 DC 14 F1 33 1B 6F 9E 65 27 D7 9D 46 G.4....3 .o.e'..F
+[11D0] 1E 91 FF 2E FB 8E 97 5D 17 8F 48 54 7C 3C A0 11 .......] ..HT|<..
+[11E0] 9C AA 77 E9 79 DE 26 D1 F0 7C EA 24 73 BE EC 60 ..w.y.&. .|.$s..`
+[11F0] B4 EE BD ED 0D 0A AB 74 60 6E 46 C0 35 5B 65 1A .......t `nF.5[e.
+[1200] A4 4A 5C 22 AC B9 CD B7 56 06 88 09 FC 48 68 55 .J\".... V....HhU
+[1210] B7 5E 39 72 DF 8A 4C CD 79 74 B0 84 0B 78 DA B2 .^9r..L. yt...x..
+[1220] 55 F8 06 0B 5C 27 06 B3 CA 10 65 6B 04 A3 64 11 U...\'.. ..ek..d.
+[1230] 04 09 DC DF 67 00 70 B1 16 DF 24 E9 27 85 11 91 ....g.p. ..$.'...
+[1240] 31 CB 92 95 50 18 91 08 C2 A1 A3 76 C7 1A FC 64 1...P... ...v...d
+[1250] 9E 2C 3A E7 30 F4 16 0D A0 56 C0 BC D2 FE 2D A0 .,:.0... .V....-.
+[1260] 20 A4 E2 82 AD F0 C5 12 71 09 23 E1 66 52 53 D0 ....... q.#.fRS.
+[1270] 89 30 E7 BE B7 C2 89 F2 1C 7A F6 8E D7 28 F0 A4 .0...... .z...(..
+[1280] 33 46 7C A2 79 66 DE 26 00 00 00 00 3F|.yf.& ....
+dump OK
diff -Nru samba-4.13.3+dfsg/source3/selftest/tests.py samba-4.13.14+dfsg/source3/selftest/tests.py
--- samba-4.13.3+dfsg/source3/selftest/tests.py 2020-12-15 07:53:45.000000000 +0000
+++ samba-4.13.14+dfsg/source3/selftest/tests.py 2021-09-07 07:01:16.000000000 +0000
@@ -487,13 +487,13 @@
[os.path.join(samba3srcdir, "script/tests/test_smbclient_tarmode.pl"),
'-n', '$SERVER', '-i', '$SERVER_IP', '-s', 'tarmode2',
'-u', '$USERNAME', '-p', '$PASSWORD', '-l', '$LOCAL_PATH/tarmode2',
- '-d', '$PREFIX', '-b', smbclient3,
+ '-d', 'smbclient_tar.NT1', '-b', smbclient3,
'--subunit', '--', configuration, '-mNT1'])
plantestsuite("samba3.blackbox.smbclient_tar.SMB3", env,
[os.path.join(samba3srcdir, "script/tests/test_smbclient_tarmode.pl"),
'-n', '$SERVER', '-i', '$SERVER_IP', '-s', 'tarmode2',
'-u', '$USERNAME', '-p', '$PASSWORD', '-l', '$LOCAL_PATH/tarmode2',
- '-d', '$PREFIX', '-b', smbclient3,
+ '-d', 'smbclient_tar.SMB3', '-b', smbclient3,
'--subunit', '--', configuration, '-mSMB3'])
for env in ["fileserver:local"]:
@@ -984,6 +984,10 @@
'$SERVER_IP',
"aio_delay_inject"])
+plantestsuite("samba3.blackbox.deadtime", "simpleserver:local",
+ [os.path.join(samba3srcdir, "script/tests/test_deadtime.sh"),
+ '$SERVER_IP'])
+
plantestsuite("samba3.blackbox.smbd_error", "simpleserver:local",
[os.path.join(samba3srcdir, "script/tests/test_smbd_error.sh")])
@@ -991,6 +995,9 @@
[os.path.join(samba3srcdir, "script/tests/test_smbd_no_krb5.sh"),
smbclient3, '$SERVER', "$DC_USERNAME", "$DC_PASSWORD", "$PREFIX"])
+plantestsuite("samba3.blackbox.winbind_ignore_domain", "ad_member_idmap_ad:local",
+ [os.path.join(samba3srcdir, "script/tests/test_winbind_ignore_domains.sh")])
+
plantestsuite("samba3.blackbox.durable_v2_delay", "simpleserver:local",
[os.path.join(samba3srcdir, "script/tests/test_durable_handle_reconnect.sh")])
@@ -1122,6 +1129,11 @@
"",
"-b $PREFIX/clusteredmember_smb1/unclists/tmp.txt -N 5 -o 10"])
+plantestsuite("samba3.blackbox.force-user-unlink",
+ "maptoguest:local",
+ [os.path.join(samba3srcdir,
+ "script/tests/test_force_user_unlink.sh")])
+
def planclusteredmembertestsuite(tname, prefix):
'''Define a clustered test for the clusteredmember environment'''
diff -Nru samba-4.13.3+dfsg/source3/smbd/close.c samba-4.13.14+dfsg/source3/smbd/close.c
--- samba-4.13.3+dfsg/source3/smbd/close.c 2020-12-15 07:53:45.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/close.c 2021-08-09 07:20:55.000000000 +0000
@@ -341,21 +341,13 @@
if (fsp->fsp_flags.initial_delete_on_close &&
!is_delete_on_close_set(lck, fsp->name_hash)) {
- struct auth_session_info *session_info = NULL;
-
/* Initial delete on close was set and no one else
* wrote a real delete on close. */
- status = smbXsrv_session_info_lookup(conn->sconn->client,
- fsp->vuid,
- &session_info);
- if (!NT_STATUS_IS_OK(status)) {
- return NT_STATUS_INTERNAL_ERROR;
- }
fsp->fsp_flags.delete_on_close = true;
set_delete_on_close_lck(fsp, lck,
- session_info->security_token,
- session_info->unix_token);
+ fsp->conn->session_info->security_token,
+ fsp->conn->session_info->unix_token);
}
delete_file = is_delete_on_close_set(lck, fsp->name_hash) &&
@@ -1176,24 +1168,15 @@
}
if (fsp->fsp_flags.initial_delete_on_close) {
- struct auth_session_info *session_info = NULL;
-
/* Initial delete on close was set - for
* directories we don't care if anyone else
* wrote a real delete on close. */
- status = smbXsrv_session_info_lookup(fsp->conn->sconn->client,
- fsp->vuid,
- &session_info);
- if (!NT_STATUS_IS_OK(status)) {
- return NT_STATUS_INTERNAL_ERROR;
- }
-
send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
fsp->fsp_name->base_name);
set_delete_on_close_lck(fsp, lck,
- session_info->security_token,
- session_info->unix_token);
+ fsp->conn->session_info->security_token,
+ fsp->conn->session_info->unix_token);
fsp->fsp_flags.delete_on_close = true;
}
diff -Nru samba-4.13.3+dfsg/source3/smbd/conn.c samba-4.13.14+dfsg/source3/smbd/conn.c
--- samba-4.13.3+dfsg/source3/smbd/conn.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/conn.c 2021-08-09 07:20:55.000000000 +0000
@@ -232,3 +232,22 @@
conn_free_internal(conn);
}
+
+/*
+ * Correctly initialize a share with case options.
+ */
+void conn_setup_case_options(connection_struct *conn)
+{
+ int snum = conn->params->service;
+
+ if (lp_case_sensitive(snum) == Auto) {
+ /* We will be setting this per packet. Set to be case
+ * insensitive for now. */
+ conn->case_sensitive = false;
+ } else {
+ conn->case_sensitive = (bool)lp_case_sensitive(snum);
+ }
+
+ conn->case_preserve = lp_preserve_case(snum);
+ conn->short_case_preserve = lp_short_preserve_case(snum);
+}
diff -Nru samba-4.13.3+dfsg/source3/smbd/conn_idle.c samba-4.13.14+dfsg/source3/smbd/conn_idle.c
--- samba-4.13.3+dfsg/source3/smbd/conn_idle.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/conn_idle.c 2021-08-06 12:19:57.000000000 +0000
@@ -273,5 +273,13 @@
* uid in the meantime. Ensure we're still root.
*/
change_to_root_user();
- reload_services(sconn, conn_snum_used, true);
+ /*
+ * Use 'false' in the last parameter (test) to force
+ * a full reload of services. Prevents
+ * reload_services caching the fact it's
+ * been called multiple times in a row.
+ * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=14604
+ * for details.
+ */
+ reload_services(sconn, conn_snum_used, false);
}
diff -Nru samba-4.13.3+dfsg/source3/smbd/dosmode.c samba-4.13.14+dfsg/source3/smbd/dosmode.c
--- samba-4.13.3+dfsg/source3/smbd/dosmode.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/dosmode.c 2021-09-07 07:01:16.000000000 +0000
@@ -27,6 +27,7 @@
#include "smbd/smbd.h"
#include "lib/param/loadparm.h"
#include "lib/util/tevent_ntstatus.h"
+#include "fake_file.h"
static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
const struct smb_filename *smb_fname,
@@ -754,6 +755,7 @@
{
uint32_t result = 0;
NTSTATUS status = NT_STATUS_OK;
+ enum FAKE_FILE_TYPE fake_file_type;
DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
@@ -761,6 +763,24 @@
return 0;
}
+ fake_file_type = is_fake_file(smb_fname);
+
+ switch (fake_file_type) {
+ case FAKE_FILE_TYPE_NAMED_PIPE_PROXY:
+ case FAKE_FILE_TYPE_NAMED_PIPE:
+ return FILE_ATTRIBUTE_NORMAL;
+
+ case FAKE_FILE_TYPE_QUOTA:
+ /* From Windows 2016 */
+ return FILE_ATTRIBUTE_HIDDEN
+ | FILE_ATTRIBUTE_SYSTEM
+ | FILE_ATTRIBUTE_DIRECTORY
+ | FILE_ATTRIBUTE_ARCHIVE;
+
+ case FAKE_FILE_TYPE_NONE:
+ break;
+ }
+
/* Get the DOS attributes via the VFS if we can */
status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &result);
if (!NT_STATUS_IS_OK(status)) {
diff -Nru samba-4.13.3+dfsg/source3/smbd/filename.c samba-4.13.14+dfsg/source3/smbd/filename.c
--- samba-4.13.3+dfsg/source3/smbd/filename.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/filename.c 2021-09-07 07:01:16.000000000 +0000
@@ -1958,6 +1958,11 @@
return NT_STATUS_NO_MEMORY;
}
smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
+ smb_fname->st.st_ex_btime = (struct timespec){0, SAMBA_UTIME_OMIT};
+ smb_fname->st.st_ex_atime = (struct timespec){0, SAMBA_UTIME_OMIT};
+ smb_fname->st.st_ex_mtime = (struct timespec){0, SAMBA_UTIME_OMIT};
+ smb_fname->st.st_ex_ctime = (struct timespec){0, SAMBA_UTIME_OMIT};
+
*_smb_fname = smb_fname;
return NT_STATUS_OK;
}
diff -Nru samba-4.13.3+dfsg/source3/smbd/globals.h samba-4.13.14+dfsg/source3/smbd/globals.h
--- samba-4.13.3+dfsg/source3/smbd/globals.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/globals.h 2021-09-07 07:01:16.000000000 +0000
@@ -534,6 +534,10 @@
struct smbXsrv_preauth preauth;
struct smbd_smb2_request *requests;
+
+ struct {
+ uint8_t read_body_padding;
+ } smbtorture;
} smb2;
};
diff -Nru samba-4.13.3+dfsg/source3/smbd/msdfs.c samba-4.13.14+dfsg/source3/smbd/msdfs.c
--- samba-4.13.3+dfsg/source3/smbd/msdfs.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/msdfs.c 2021-08-09 07:20:55.000000000 +0000
@@ -243,6 +243,7 @@
*********************************************************/
static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
+ struct tevent_context *ev,
struct messaging_context *msg,
connection_struct **pconn,
int snum,
@@ -261,12 +262,7 @@
return NT_STATUS_NO_MEMORY;
}
- sconn->ev_ctx = samba_tevent_context_init(sconn);
- if (sconn->ev_ctx == NULL) {
- TALLOC_FREE(sconn);
- return NT_STATUS_NO_MEMORY;
- }
-
+ sconn->ev_ctx = ev;
sconn->msg_ctx = msg;
conn = conn_new(sconn);
@@ -318,6 +314,8 @@
vfs_user = get_current_username();
}
+ conn_setup_case_options(conn);
+
set_conn_connectpath(conn, connpath);
/*
@@ -400,6 +398,7 @@
struct conn_struct_tos **_c)
{
struct conn_struct_tos *c = NULL;
+ struct tevent_context *ev = NULL;
NTSTATUS status;
*_c = NULL;
@@ -409,8 +408,15 @@
return NT_STATUS_NO_MEMORY;
}
+ ev = samba_tevent_context_init(c);
+ if (ev == NULL) {
+ TALLOC_FREE(c);
+ return NT_STATUS_NO_MEMORY;
+ }
+
become_root();
status = create_conn_struct_as_root(c,
+ ev,
msg,
&c->conn,
snum,
@@ -490,6 +496,44 @@
return NT_STATUS_OK;
}
+/********************************************************
+ Fake up a connection struct for the VFS layer.
+ This takes an TALLOC_CTX and tevent_context from the
+ caller and the resulting connection_struct is stable
+ across the lifetime of mem_ctx and ev.
+
+ Note: this performs a vfs connect and changes cwd.
+
+ See also the comment for create_conn_struct_tos() above!
+*********************************************************/
+
+NTSTATUS create_conn_struct_cwd(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct messaging_context *msg,
+ const struct auth_session_info *session_info,
+ int snum,
+ const char *path,
+ struct connection_struct **c)
+{
+ NTSTATUS status;
+
+ become_root();
+ status = create_conn_struct_as_root(mem_ctx,
+ ev,
+ msg,
+ c,
+ snum,
+ path,
+ session_info);
+ unbecome_root();
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(c);
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
static void shuffle_strlist(char **list, int count)
{
int i;
diff -Nru samba-4.13.3+dfsg/source3/smbd/open.c samba-4.13.14+dfsg/source3/smbd/open.c
--- samba-4.13.3+dfsg/source3/smbd/open.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/open.c 2021-08-09 07:20:55.000000000 +0000
@@ -477,7 +477,7 @@
unsigned int link_depth)
{
const char *conn_rootdir = NULL;
- struct smb_filename conn_rootdir_fname;
+ struct smb_filename conn_rootdir_fname = { 0 };
int fd = -1;
char *link_target = NULL;
int link_len = -1;
@@ -493,9 +493,16 @@
errno = ENOMEM;
return -1;
}
- conn_rootdir_fname = (struct smb_filename) {
- .base_name = discard_const_p(char, conn_rootdir),
- };
+ /*
+ * With shadow_copy2 conn_rootdir can be talloc_freed
+ * whilst we use it in this function. We must take a copy.
+ */
+ conn_rootdir_fname.base_name = talloc_strdup(talloc_tos(),
+ conn_rootdir);
+ if (conn_rootdir_fname.base_name == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
/*
* Ensure we don't get stuck in a symlink loop.
@@ -602,6 +609,7 @@
TALLOC_FREE(resolved_fname);
TALLOC_FREE(link_target);
+ TALLOC_FREE(conn_rootdir_fname.base_name);
if (oldwd_fname != NULL) {
int ret = vfs_ChDir(conn, oldwd_fname);
if (ret == -1) {
@@ -947,7 +955,6 @@
"directory %s. Error was %s\n",
smb_fname_str_dbg(smb_fname_parent),
strerror(errno)));
- TALLOC_FREE(smb_fname_parent);
return;
}
@@ -957,7 +964,6 @@
"is already owned by uid %d\n",
fsp_str_dbg(fsp),
(int)fsp->fsp_name->st.st_ex_uid ));
- TALLOC_FREE(smb_fname_parent);
return;
}
@@ -2994,6 +3000,9 @@
status = share_mode_watch_recv(subreq, NULL, NULL);
TALLOC_FREE(subreq);
+ open_rec->watch_req = NULL;
+ TALLOC_FREE(open_rec->te);
+
DBG_DEBUG("dbwrap_watched_watch_recv returned %s\n",
nt_errstr(status));
diff -Nru samba-4.13.3+dfsg/source3/smbd/posix_acls.c samba-4.13.14+dfsg/source3/smbd/posix_acls.c
--- samba-4.13.3+dfsg/source3/smbd/posix_acls.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/posix_acls.c 2021-08-09 07:20:55.000000000 +0000
@@ -3475,6 +3475,7 @@
{
SMB_STRUCT_STAT sbuf;
SMB_ACL_T posix_acl = NULL;
+ SMB_ACL_T def_acl = NULL;
struct pai_val *pal;
TALLOC_CTX *frame = talloc_stackframe();
NTSTATUS status;
@@ -3493,10 +3494,19 @@
/* Get the ACL from the fd. */
posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, frame);
+ /* If it's a directory get the default POSIX ACL. */
+ if(fsp->fsp_flags.is_directory) {
+ def_acl = SMB_VFS_SYS_ACL_GET_FILE(fsp->conn,
+ fsp->fsp_name,
+ SMB_ACL_TYPE_DEFAULT,
+ frame);
+ def_acl = free_empty_sys_acl(fsp->conn, def_acl);
+ }
+
pal = fload_inherited_info(fsp);
status = posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name,
- &sbuf, pal, posix_acl, NULL,
+ &sbuf, pal, posix_acl, def_acl,
security_info, mem_ctx, ppdesc);
TALLOC_FREE(frame);
return status;
diff -Nru samba-4.13.3+dfsg/source3/smbd/proto.h samba-4.13.14+dfsg/source3/smbd/proto.h
--- samba-4.13.3+dfsg/source3/smbd/proto.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/proto.h 2021-08-09 07:20:55.000000000 +0000
@@ -156,6 +156,7 @@
bool conn_idle_all(struct smbd_server_connection *sconn, time_t t);
void conn_clear_vuid_caches(struct smbd_server_connection *sconn, uint64_t vuid);
void conn_free(connection_struct *conn);
+void conn_setup_case_options(connection_struct *conn);
void conn_force_tdis(
struct smbd_server_connection *sconn,
bool (*check_fn)(struct connection_struct *conn,
@@ -560,6 +561,14 @@
bool *ppath_contains_wcard);
struct connection_struct;
struct smb_filename;
+
+NTSTATUS create_conn_struct_cwd(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct messaging_context *msg,
+ const struct auth_session_info *session_info,
+ int snum,
+ const char *path,
+ struct connection_struct **c);
struct conn_struct_tos {
struct connection_struct *conn;
struct smb_filename *oldcwd_fname;
@@ -1333,6 +1342,8 @@
unsigned int *num_streams,
struct stream_struct **streams);
void init_smb_file_time(struct smb_file_time *ft);
+int vfs_fake_fd(void);
+int vfs_fake_fd_close(int fd);
/* The following definitions come from smbd/avahi_register.c */
diff -Nru samba-4.13.3+dfsg/source3/smbd/pysmbd.c samba-4.13.14+dfsg/source3/smbd/pysmbd.c
--- samba-4.13.3+dfsg/source3/smbd/pysmbd.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/pysmbd.c 2021-08-09 07:20:55.000000000 +0000
@@ -1144,9 +1144,12 @@
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("init_files_struct failed: %s\n",
nt_errstr(status));
+ } else if (fsp != NULL) {
+ SMB_VFS_CLOSE(fsp);
}
TALLOC_FREE(frame);
+ PyErr_NTSTATUS_NOT_OK_RAISE(status);
Py_RETURN_NONE;
}
diff -Nru samba-4.13.3+dfsg/source3/smbd/reply.c samba-4.13.14+dfsg/source3/smbd/reply.c
--- samba-4.13.3+dfsg/source3/smbd/reply.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/reply.c 2021-08-09 07:20:55.000000000 +0000
@@ -7093,6 +7093,8 @@
DEBUG(3, ("printwrite %s num=%d\n", fsp_fnum_dbg(fsp), numtowrite));
+ reply_outbuf(req, 0, 0);
+
END_PROFILE(SMBsplwr);
return;
}
diff -Nru samba-4.13.3+dfsg/source3/smbd/server.c samba-4.13.14+dfsg/source3/smbd/server.c
--- samba-4.13.3+dfsg/source3/smbd/server.c 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/server.c 2021-11-08 11:29:14.000000000 +0000
@@ -1973,7 +1973,7 @@
exit_daemon("smbd can not open secrets.tdb", EACCES);
}
- if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) {
+ if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC || lp_server_role() == ROLE_IPA_DC) {
struct loadparm_context *lp_ctx = loadparm_init_s3(NULL, loadparm_s3_helpers());
if (!open_schannel_session_store(NULL, lp_ctx)) {
exit_daemon("ERROR: Samba cannot open schannel store for secured NETLOGON operations.", EACCES);
diff -Nru samba-4.13.3+dfsg/source3/smbd/service.c samba-4.13.14+dfsg/source3/smbd/service.c
--- samba-4.13.3+dfsg/source3/smbd/service.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/service.c 2021-08-09 07:20:55.000000000 +0000
@@ -556,16 +556,7 @@
( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
/* Case options for the share. */
- if (lp_case_sensitive(snum) == Auto) {
- /* We will be setting this per packet. Set to be case
- * insensitive for now. */
- conn->case_sensitive = False;
- } else {
- conn->case_sensitive = (bool)lp_case_sensitive(snum);
- }
-
- conn->case_preserve = lp_preserve_case(snum);
- conn->short_case_preserve = lp_short_preserve_case(snum);
+ conn_setup_case_options(conn);
conn->encrypt_level = lp_smb_encrypt(snum);
if (conn->encrypt_level > SMB_SIGNING_OFF) {
diff -Nru samba-4.13.3+dfsg/source3/smbd/smb2_close.c samba-4.13.14+dfsg/source3/smbd/smb2_close.c
--- samba-4.13.3+dfsg/source3/smbd/smb2_close.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/smb2_close.c 2021-08-09 07:20:55.000000000 +0000
@@ -215,10 +215,10 @@
uint16_t flags = 0;
bool posix_open = false;
- ZERO_STRUCTP(out_creation_ts);
- ZERO_STRUCTP(out_last_access_ts);
- ZERO_STRUCTP(out_last_write_ts);
- ZERO_STRUCTP(out_change_ts);
+ *out_creation_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
+ *out_last_access_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
+ *out_last_write_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
+ *out_change_ts = (struct timespec){0, SAMBA_UTIME_OMIT};
*out_flags = 0;
*out_allocation_size = 0;
diff -Nru samba-4.13.3+dfsg/source3/smbd/smb2_create.c samba-4.13.14+dfsg/source3/smbd/smb2_create.c
--- samba-4.13.3+dfsg/source3/smbd/smb2_create.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/smb2_create.c 2021-08-09 07:20:55.000000000 +0000
@@ -1715,6 +1715,7 @@
state->open_was_deferred = false;
/* Ensure we don't have any outstanding immediate event. */
TALLOC_FREE(state->im);
+ TALLOC_FREE(state->open_rec);
}
void remove_deferred_open_message_smb2(
diff -Nru samba-4.13.3+dfsg/source3/smbd/smb2_ioctl.c samba-4.13.14+dfsg/source3/smbd/smb2_ioctl.c
--- samba-4.13.3+dfsg/source3/smbd/smb2_ioctl.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/smb2_ioctl.c 2021-09-07 07:01:16.000000000 +0000
@@ -41,6 +41,7 @@
static NTSTATUS smbd_smb2_ioctl_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
DATA_BLOB *out_output,
+ uint8_t *body_padding,
bool *disconnect);
static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq);
@@ -195,6 +196,8 @@
case FSCTL_VALIDATE_NEGOTIATE_INFO:
case FSCTL_QUERY_NETWORK_INTERFACE_INFO:
case FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT:
+ case FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8:
+ case FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8:
/*
* Some SMB2 specific CtlCodes like FSCTL_DFS_GET_REFERRALS or
* FSCTL_PIPE_WAIT does not take a file handle.
@@ -227,6 +230,21 @@
if (subreq == NULL) {
return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
}
+
+ /*
+ * If the FSCTL has gone async on a file handle, remember
+ * to add it to the list of async requests we need to wait
+ * for on file handle close.
+ */
+ if (in_fsp != NULL && tevent_req_is_in_progress(subreq)) {
+ bool ok;
+
+ ok = aio_add_req_to_fsp(in_fsp, subreq);
+ if (!ok) {
+ return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
+ }
+ }
+
tevent_req_set_callback(subreq, smbd_smb2_request_ioctl_done, req);
return smbd_smb2_request_pending_queue(req, subreq, 1000);
@@ -284,9 +302,12 @@
NTSTATUS status;
NTSTATUS error; /* transport error */
bool disconnect = false;
+ uint16_t body_size;
+ uint8_t body_padding = 0;
status = smbd_smb2_ioctl_recv(subreq, req,
&out_output_buffer,
+ &body_padding,
&disconnect);
DEBUG(10,("smbd_smb2_request_ioctl_done: smbd_smb2_ioctl_recv returned "
@@ -319,10 +340,15 @@
return;
}
- out_input_offset = SMB2_HDR_BODY + 0x30;
- out_output_offset = SMB2_HDR_BODY + 0x30;
+ /*
+ * Only FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8
+ * sets body_padding to a value different from 0.
+ */
+ body_size = 0x30 + body_padding;
+ out_input_offset = SMB2_HDR_BODY + body_size;
+ out_output_offset = SMB2_HDR_BODY + body_size;
- outbody = smbd_smb2_generate_outbody(req, 0x30);
+ outbody = smbd_smb2_generate_outbody(req, body_size);
if (outbody.data == NULL) {
error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
if (!NT_STATUS_IS_OK(error)) {
@@ -350,6 +376,9 @@
out_output_buffer.length); /* output count */
SIVAL(outbody.data, 0x28, 0); /* flags */
SIVAL(outbody.data, 0x2C, 0); /* reserved */
+ if (body_padding != 0) {
+ memset(outbody.data + 0x30, 0, body_padding);
+ }
/*
* Note: Windows Vista and 2008 send back also the
@@ -391,6 +420,35 @@
tevent_req_done(req);
return tevent_req_post(req, ev);
+ case FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8:
+ if (state->in_input.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (state->in_max_output > 0) {
+ uint32_t size = state->in_max_output;
+
+ state->out_output = data_blob_talloc(state, NULL, size);
+ if (tevent_req_nomem(state->out_output.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ memset(state->out_output.data, 8, size);
+ }
+
+ state->body_padding = 8;
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+
+ case FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8:
+ if (state->in_input.length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ state->smb2req->xconn->smb2.smbtorture.read_body_padding = 8;
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
default:
goto not_supported;
}
@@ -476,6 +534,7 @@
static NTSTATUS smbd_smb2_ioctl_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
DATA_BLOB *out_output,
+ uint8_t *body_padding,
bool *disconnect)
{
NTSTATUS status = NT_STATUS_OK;
@@ -484,6 +543,7 @@
enum tevent_req_state req_state;
uint64_t err;
+ *body_padding = state->body_padding;
*disconnect = state->disconnect;
if ((tevent_req_is_error(req, &req_state, &err) == false)
diff -Nru samba-4.13.3+dfsg/source3/smbd/smb2_ioctl_private.h samba-4.13.14+dfsg/source3/smbd/smb2_ioctl_private.h
--- samba-4.13.3+dfsg/source3/smbd/smb2_ioctl_private.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/smb2_ioctl_private.h 2021-08-06 12:19:57.000000000 +0000
@@ -28,6 +28,7 @@
DATA_BLOB in_input;
uint32_t in_max_output;
DATA_BLOB out_output;
+ uint8_t body_padding;
bool disconnect;
};
diff -Nru samba-4.13.3+dfsg/source3/smbd/smb2_read.c samba-4.13.14+dfsg/source3/smbd/smb2_read.c
--- samba-4.13.3+dfsg/source3/smbd/smb2_read.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/smb2_read.c 2021-09-07 07:01:16.000000000 +0000
@@ -116,6 +116,8 @@
{
struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
struct smbd_smb2_request);
+ uint16_t body_size;
+ uint8_t body_padding = req->xconn->smb2.smbtorture.read_body_padding;
DATA_BLOB outbody;
DATA_BLOB outdyn;
uint8_t out_data_offset;
@@ -139,9 +141,14 @@
return;
}
- out_data_offset = SMB2_HDR_BODY + 0x10;
+ /*
+ * Only FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8
+ * sets body_padding to a value different from 0.
+ */
+ body_size = 0x10 + body_padding;
+ out_data_offset = SMB2_HDR_BODY + body_size;
- outbody = smbd_smb2_generate_outbody(req, 0x10);
+ outbody = smbd_smb2_generate_outbody(req, body_size);
if (outbody.data == NULL) {
error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
if (!NT_STATUS_IS_OK(error)) {
@@ -161,6 +168,9 @@
SIVAL(outbody.data, 0x08,
out_data_remaining); /* data remaining */
SIVAL(outbody.data, 0x0C, 0); /* reserved */
+ if (body_padding != 0) {
+ memset(outbody.data + 0x10, 0, body_padding);
+ }
outdyn = out_data_buffer;
diff -Nru samba-4.13.3+dfsg/source3/smbd/smb2_setinfo.c samba-4.13.14+dfsg/source3/smbd/smb2_setinfo.c
--- samba-4.13.3+dfsg/source3/smbd/smb2_setinfo.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/smb2_setinfo.c 2021-08-09 07:20:55.000000000 +0000
@@ -213,6 +213,7 @@
return false;
}
+ state->delay = true;
break_to = (e_lease_type & ~SMB2_LEASE_HANDLE);
send_break_message(
diff -Nru samba-4.13.3+dfsg/source3/smbd/smbXsrv_open.c samba-4.13.14+dfsg/source3/smbd/smbXsrv_open.c
--- samba-4.13.3+dfsg/source3/smbd/smbXsrv_open.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/smbXsrv_open.c 2021-08-09 07:17:53.000000000 +0000
@@ -1468,6 +1468,15 @@
goto done;
}
+ if (global_blob.info.info0 == NULL) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
+ "key '%s' info0 NULL pointer - %s\n",
+ hex_encode_talloc(frame, key.dptr, key.dsize),
+ nt_errstr(status)));
+ goto done;
+ }
+
*global = talloc_move(mem_ctx, &global_blob.info.info0);
status = NT_STATUS_OK;
done:
diff -Nru samba-4.13.3+dfsg/source3/smbd/smbXsrv_session.c samba-4.13.14+dfsg/source3/smbd/smbXsrv_session.c
--- samba-4.13.3+dfsg/source3/smbd/smbXsrv_session.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/smbXsrv_session.c 2021-08-09 07:20:55.000000000 +0000
@@ -2234,6 +2234,13 @@
goto done;
}
+ if (global_blob.info.info0 == NULL) {
+ DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
+ "key '%s' info0 NULL pointer\n",
+ hex_encode_talloc(frame, key.dptr, key.dsize)));
+ goto done;
+ }
+
global_blob.info.info0->db_rec = rec;
ret = state->fn(global_blob.info.info0, state->private_data);
done:
diff -Nru samba-4.13.3+dfsg/source3/smbd/smbXsrv_tcon.c samba-4.13.14+dfsg/source3/smbd/smbXsrv_tcon.c
--- samba-4.13.3+dfsg/source3/smbd/smbXsrv_tcon.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/smbXsrv_tcon.c 2021-08-09 07:17:53.000000000 +0000
@@ -1208,6 +1208,13 @@
goto done;
}
+ if (global_blob.info.info0 == NULL) {
+ DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
+ "key '%s' info0 NULL pointer\n",
+ hex_encode_talloc(frame, key.dptr, key.dsize)));
+ goto done;
+ }
+
global_blob.info.info0->db_rec = rec;
ret = state->fn(global_blob.info.info0, state->private_data);
done:
diff -Nru samba-4.13.3+dfsg/source3/smbd/vfs.c samba-4.13.14+dfsg/source3/smbd/vfs.c
--- samba-4.13.3+dfsg/source3/smbd/vfs.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/smbd/vfs.c 2021-08-09 07:20:55.000000000 +0000
@@ -1583,6 +1583,15 @@
}
/*
+ * This is just a helper to make
+ * users of vfs_fake_fd() more symetric
+ */
+int vfs_fake_fd_close(int fd)
+{
+ return close(fd);
+}
+
+/*
generate a file_id from a stat structure
*/
struct file_id vfs_file_id_from_sbuf(connection_struct *conn, const SMB_STRUCT_STAT *sbuf)
diff -Nru samba-4.13.3+dfsg/source3/torture/pdbtest.c samba-4.13.14+dfsg/source3/torture/pdbtest.c
--- samba-4.13.3+dfsg/source3/torture/pdbtest.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/torture/pdbtest.c 2021-11-08 11:29:14.000000000 +0000
@@ -277,7 +277,7 @@
struct netr_SamInfo6 *info6_wbc = NULL;
NTSTATUS status;
bool ok;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
int rc;
rc = SMBOWFencrypt(pdb_get_nt_passwd(pdb_entry), challenge_8,
diff -Nru samba-4.13.3+dfsg/source3/torture/test_idmap_tdb_common.c samba-4.13.14+dfsg/source3/torture/test_idmap_tdb_common.c
--- samba-4.13.3+dfsg/source3/torture/test_idmap_tdb_common.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/torture/test_idmap_tdb_common.c 2021-11-08 11:29:14.000000000 +0000
@@ -110,12 +110,21 @@
return true;
}
-static struct idmap_tdb_common_context *createcontext(TALLOC_CTX *memctx)
+static NTSTATUS idmap_test_tdb_db_init(struct idmap_domain *dom)
{
struct idmap_tdb_common_context *ret;
- ret = talloc_zero(memctx, struct idmap_tdb_common_context);
+ DBG_DEBUG("called for domain '%s'\n", dom->name);
+
+ ret = talloc_zero(dom, struct idmap_tdb_common_context);
+ if (ret == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
ret->rw_ops = talloc_zero(ret, struct idmap_rw_ops);
+ if (ret->rw_ops == NULL) {
+ TALLOC_FREE(ret);
+ return NT_STATUS_NO_MEMORY;
+ }
ret->max_id = HIGH_ID;
ret->hwmkey_uid = HWM_USER;
@@ -125,25 +134,33 @@
ret->rw_ops->set_mapping = idmap_tdb_common_set_mapping;
if (!open_db(ret)) {
- return NULL;
+ TALLOC_FREE(ret);
+ return NT_STATUS_INTERNAL_ERROR;
};
- return ret;
+ dom->private_data = ret;
+
+ return NT_STATUS_OK;
}
static struct idmap_domain *createdomain(TALLOC_CTX *memctx)
{
struct idmap_domain *dom;
+ struct idmap_methods *m;
dom = talloc_zero(memctx, struct idmap_domain);
dom->name = "*";
dom->low_id = LOW_ID;
dom->high_id = HIGH_ID;
dom->read_only = false;
- dom->methods = talloc_zero(dom, struct idmap_methods);
- dom->methods->sids_to_unixids = idmap_tdb_common_sids_to_unixids;
- dom->methods->unixids_to_sids = idmap_tdb_common_unixids_to_sids;
- dom->methods->allocate_id = idmap_tdb_common_get_new_id;
+ m = talloc_zero(dom, struct idmap_methods);
+ *m = (struct idmap_methods) {
+ .init = idmap_test_tdb_db_init,
+ .sids_to_unixids = idmap_tdb_common_sids_to_unixids,
+ .unixids_to_sids = idmap_tdb_common_unixids_to_sids,
+ .allocate_id = idmap_tdb_common_get_new_id,
+ };
+ dom->methods = m;
return dom;
}
@@ -965,20 +982,20 @@
bool run_idmap_tdb_common_test(int dummy)
{
bool result;
- struct idmap_tdb_common_context *ctx;
struct idmap_domain *dom;
-
- TALLOC_CTX *memctx = talloc_new(NULL);
TALLOC_CTX *stack = talloc_stackframe();
+ TALLOC_CTX *memctx = talloc_new(stack);
+ NTSTATUS status;
- ctx = createcontext(memctx);
- if(!ctx) {
+ dom = createdomain(memctx);
+ if (dom == NULL) {
return false;
}
- dom = createdomain(memctx);
-
- dom->private_data = ctx;
+ status = dom->methods->init(dom);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
/* test a single allocation from pool (no mapping) */
result = test_getnewid1(memctx, dom);
@@ -1022,7 +1039,6 @@
result = test_getnewid2(memctx, dom);
CHECKRESULT(result);
- talloc_free(memctx);
talloc_free(stack);
return true;
diff -Nru samba-4.13.3+dfsg/source3/torture/test_smb2.c samba-4.13.14+dfsg/source3/torture/test_smb2.c
--- samba-4.13.3+dfsg/source3/torture/test_smb2.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/torture/test_smb2.c 2021-08-09 07:20:55.000000000 +0000
@@ -188,11 +188,11 @@
cli->timeout,
cli->smb2.session,
cli->smb2.tcon);
+ cli_state_restore_tcon(cli, saved_tcon);
if (!NT_STATUS_IS_OK(status)) {
printf("smb2cli_tdis returned %s\n", nt_errstr(status));
return false;
}
- cli_state_restore_tcon(cli, saved_tcon);
status = smb2cli_tdis(cli->conn,
cli->timeout,
diff -Nru samba-4.13.3+dfsg/source3/torture/torture.c samba-4.13.14+dfsg/source3/torture/torture.c
--- samba-4.13.3+dfsg/source3/torture/torture.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/torture/torture.c 2021-08-09 07:20:55.000000000 +0000
@@ -1343,6 +1343,7 @@
if (!NT_STATUS_IS_OK(status)) {
printf("%s refused 2nd tree connect (%s)\n", host,
nt_errstr(status));
+ cli_state_restore_tcon(cli, orig_tcon);
cli_shutdown(cli);
return False;
}
@@ -1395,6 +1396,8 @@
status = cli_close(cli, fnum1);
if (!NT_STATUS_IS_OK(status)) {
printf("close failed (%s)\n", nt_errstr(status));
+ cli_state_restore_tcon(cli, orig_tcon);
+ cli_shutdown(cli);
return False;
}
@@ -1403,6 +1406,8 @@
status = cli_tdis(cli);
if (!NT_STATUS_IS_OK(status)) {
printf("secondary tdis failed (%s)\n", nt_errstr(status));
+ cli_state_restore_tcon(cli, orig_tcon);
+ cli_shutdown(cli);
return False;
}
@@ -11714,7 +11719,7 @@
int16_t old_vuid;
int32_t old_cnum;
bool correct = True;
- struct smbXcli_tcon *orig_tcon = NULL;
+ struct smbXcli_tcon *tcon_copy = NULL;
NTSTATUS status;
printf("starting uid regression test\n");
@@ -11755,8 +11760,20 @@
}
old_cnum = cli_state_get_tid(cli);
- orig_tcon = cli_state_save_tcon(cli);
- if (orig_tcon == NULL) {
+ /*
+ * This is an SMB1-only test.
+ * Copy the tcon, not "save/restore".
+ *
+ * In SMB1 the cli_tdis() below frees
+ * cli->smb1.tcon so we need a copy
+ * of the struct to put back for the
+ * second tdis call with invalid vuid.
+ *
+ * This is a test-only hack. Real client code
+ * uses cli_state_save_tcon()/cli_state_restore_tcon().
+ */
+ tcon_copy = smbXcli_tcon_copy(cli, cli->smb1.tcon);
+ if (tcon_copy == NULL) {
correct = false;
goto out;
}
@@ -11772,11 +11789,11 @@
} else {
d_printf("First tdis failed (%s)\n", nt_errstr(status));
correct = false;
- cli_state_restore_tcon(cli, orig_tcon);
+ cli->smb1.tcon = tcon_copy;
goto out;
}
- cli_state_restore_tcon(cli, orig_tcon);
+ cli->smb1.tcon = tcon_copy;
cli_state_set_uid(cli, old_vuid);
cli_state_set_tid(cli, old_cnum);
diff -Nru samba-4.13.3+dfsg/source3/utils/ntlm_auth.c samba-4.13.14+dfsg/source3/utils/ntlm_auth.c
--- samba-4.13.3+dfsg/source3/utils/ntlm_auth.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/utils/ntlm_auth.c 2021-11-08 11:29:14.000000000 +0000
@@ -789,10 +789,8 @@
struct PAC_LOGON_INFO *logon_info = NULL;
char *unixuser;
NTSTATUS status;
- char *domain = NULL;
- char *realm = NULL;
- char *user = NULL;
- char *p;
+ const char *domain = "";
+ const char *user = "";
tmp_ctx = talloc_new(mem_ctx);
if (!tmp_ctx) {
@@ -809,71 +807,44 @@
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
+ } else {
+ status = NT_STATUS_ACCESS_DENIED;
+ DBG_WARNING("Kerberos ticket for[%s] has no PAC: %s\n",
+ princ_name, nt_errstr(status));
+ goto done;
}
- DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
-
- p = strchr_m(princ_name, '@');
- if (!p) {
- DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
- princ_name));
- return NT_STATUS_LOGON_FAILURE;
- }
-
- user = talloc_strndup(mem_ctx, princ_name, p - princ_name);
- if (!user) {
- return NT_STATUS_NO_MEMORY;
+ if (logon_info->info3.base.account_name.string != NULL) {
+ user = logon_info->info3.base.account_name.string;
+ } else {
+ user = "";
}
-
- realm = talloc_strdup(talloc_tos(), p + 1);
- if (!realm) {
- return NT_STATUS_NO_MEMORY;
+ if (logon_info->info3.base.logon_domain.string != NULL) {
+ domain = logon_info->info3.base.logon_domain.string;
+ } else {
+ domain = "";
}
- if (!strequal(realm, lp_realm())) {
- DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
- if (!lp_allow_trusted_domains()) {
- return NT_STATUS_LOGON_FAILURE;
- }
+ if (strlen(user) == 0 || strlen(domain) == 0) {
+ status = NT_STATUS_ACCESS_DENIED;
+ DBG_WARNING("Kerberos ticket for[%s] has invalid "
+ "account_name[%s]/logon_domain[%s]: %s\n",
+ princ_name,
+ logon_info->info3.base.account_name.string,
+ logon_info->info3.base.logon_domain.string,
+ nt_errstr(status));
+ goto done;
}
- if (logon_info && logon_info->info3.base.logon_domain.string) {
- domain = talloc_strdup(mem_ctx,
- logon_info->info3.base.logon_domain.string);
- if (!domain) {
- return NT_STATUS_NO_MEMORY;
- }
- DEBUG(10, ("Domain is [%s] (using PAC)\n", domain));
- } else {
+ DBG_NOTICE("Kerberos ticket principal name is [%s] "
+ "account_name[%s]/logon_domain[%s]\n",
+ princ_name, user, domain);
- /* If we have winbind running, we can (and must) shorten the
- username by using the short netbios name. Otherwise we will
- have inconsistent user names. With Kerberos, we get the
- fully qualified realm, with ntlmssp we get the short
- name. And even w2k3 does use ntlmssp if you for example
- connect to an ip address. */
-
- wbcErr wbc_status;
- struct wbcDomainInfo *info = NULL;
-
- DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
- realm));
-
- wbc_status = wbcDomainInfo(realm, &info);
-
- if (WBC_ERROR_IS_OK(wbc_status)) {
- domain = talloc_strdup(mem_ctx,
- info->short_name);
- wbcFreeMemory(info);
- } else {
- DEBUG(3, ("Could not find short name: %s\n",
- wbcErrorString(wbc_status)));
- domain = talloc_strdup(mem_ctx, realm);
- }
- if (!domain) {
- return NT_STATUS_NO_MEMORY;
+ if (!strequal(domain, lp_workgroup())) {
+ if (!lp_allow_trusted_domains()) {
+ status = NT_STATUS_LOGON_FAILURE;
+ goto done;
}
- DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
}
unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user);
@@ -1926,7 +1897,7 @@
TALLOC_FREE(mem_ctx);
} else {
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
if (!domain) {
domain = smb_xstrdup(get_winbind_domain());
@@ -2442,7 +2413,7 @@
char *hex_lm_key;
char *hex_user_session_key;
char *error_string;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
setbuf(stdout, NULL);
diff -Nru samba-4.13.3+dfsg/source3/utils/ntlm_auth_diagnostics.c samba-4.13.14+dfsg/source3/utils/ntlm_auth_diagnostics.c
--- samba-4.13.3+dfsg/source3/utils/ntlm_auth_diagnostics.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/utils/ntlm_auth_diagnostics.c 2021-11-08 11:29:14.000000000 +0000
@@ -54,7 +54,7 @@
DATA_BLOB lm_response = data_blob(NULL, 24);
DATA_BLOB nt_response = data_blob(NULL, 24);
DATA_BLOB session_key = data_blob(NULL, 16);
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uchar lm_key[8];
uchar user_session_key[16];
uchar lm_hash[16];
@@ -177,7 +177,7 @@
NTSTATUS nt_status;
uint32_t flags = 0;
DATA_BLOB nt_response = data_blob(NULL, 24);
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uchar lm_key[8];
uchar lm_hash[16];
uchar user_session_key[16];
@@ -245,7 +245,7 @@
uint32_t flags = 0;
DATA_BLOB nt_response = data_blob(NULL, 24);
DATA_BLOB session_key = data_blob(NULL, 16);
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uint8_t lm_key[8];
uint8_t lm_hash[16];
uint8_t user_session_key[16];
@@ -322,7 +322,7 @@
DATA_BLOB lmv2_response = data_blob_null;
DATA_BLOB ntlmv2_session_key = data_blob_null;
DATA_BLOB names_blob = NTLMv2_generate_names_blob(NULL, get_winbind_netbios_name(), get_winbind_domain());
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uchar user_session_key[16];
DATA_BLOB chall = get_challenge();
char *error_string;
@@ -452,7 +452,7 @@
char *password;
smb_ucs2_t *nt_response_ucs2;
size_t converted_size;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uchar user_session_key[16];
uchar lm_key[16];
static const uchar zeros[8] = { 0, };
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_ad.c samba-4.13.14+dfsg/source3/winbindd/idmap_ad.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_ad.c 2020-09-07 10:52:25.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_ad.c 2021-11-08 11:29:14.000000000 +0000
@@ -1003,7 +1003,7 @@
return status;
}
-static struct idmap_methods ad_methods = {
+static const struct idmap_methods ad_methods = {
.init = idmap_ad_initialize,
.unixids_to_sids = idmap_ad_unixids_to_sids_retry,
.sids_to_unixids = idmap_ad_sids_to_unixids_retry,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_ad_nss.c samba-4.13.14+dfsg/source3/winbindd/idmap_ad_nss.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_ad_nss.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_ad_nss.c 2021-11-08 11:29:14.000000000 +0000
@@ -370,19 +370,19 @@
/* The SFU and RFC2307 NSS plugins share everything but the init
function which sets the intended schema model to use */
-static struct nss_info_methods nss_rfc2307_methods = {
+static const struct nss_info_methods nss_rfc2307_methods = {
.init = nss_rfc2307_init,
.map_to_alias = nss_ad_map_to_alias,
.map_from_alias = nss_ad_map_from_alias,
};
-static struct nss_info_methods nss_sfu_methods = {
+static const struct nss_info_methods nss_sfu_methods = {
.init = nss_sfu_init,
.map_to_alias = nss_ad_map_to_alias,
.map_from_alias = nss_ad_map_from_alias,
};
-static struct nss_info_methods nss_sfu20_methods = {
+static const struct nss_info_methods nss_sfu20_methods = {
.init = nss_sfu20_init,
.map_to_alias = nss_ad_map_to_alias,
.map_from_alias = nss_ad_map_from_alias,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_autorid.c samba-4.13.14+dfsg/source3/winbindd/idmap_autorid.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_autorid.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_autorid.c 2021-11-08 11:29:14.000000000 +0000
@@ -670,9 +670,9 @@
* range.
*/
- DBG_NOTICE("Allocating range for domain %s refused\n", range.domsid);
- map->status = ID_UNMAPPED;
- return NT_STATUS_NONE_MAPPED;
+ DBG_NOTICE("Allocating range for domain %s required type_hint\n", range.domsid);
+ map->status = ID_REQUIRE_TYPE;
+ return NT_STATUS_SOME_NOT_MAPPED;
allocate:
ret = idmap_autorid_acquire_range(autorid_db, &range);
@@ -919,7 +919,7 @@
return status;
}
-static struct idmap_methods autorid_methods = {
+static const struct idmap_methods autorid_methods = {
.init = idmap_autorid_initialize,
.unixids_to_sids = idmap_autorid_unixids_to_sids,
.sids_to_unixids = idmap_autorid_sids_to_unixids,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap.c samba-4.13.14+dfsg/source3/winbindd/idmap.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap.c 2021-11-08 11:29:14.000000000 +0000
@@ -40,7 +40,7 @@
struct idmap_backend {
const char *name;
- struct idmap_methods *methods;
+ const struct idmap_methods *methods;
struct idmap_backend *prev, *next;
};
static struct idmap_backend *backends = NULL;
@@ -285,7 +285,7 @@
return false;
}
-static struct idmap_methods *get_methods(const char *name)
+static const struct idmap_methods *get_methods(const char *name)
{
struct idmap_backend *b;
@@ -309,7 +309,7 @@
**********************************************************************/
NTSTATUS smb_register_idmap(int version, const char *name,
- struct idmap_methods *methods)
+ const struct idmap_methods *methods)
{
struct idmap_backend *entry;
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_hash/idmap_hash.c samba-4.13.14+dfsg/source3/winbindd/idmap_hash/idmap_hash.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_hash/idmap_hash.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_hash/idmap_hash.c 2021-11-08 11:29:14.000000000 +0000
@@ -261,6 +261,25 @@
ids[i]->status = ID_UNMAPPED;
+ if (ids[i]->xid.type == ID_TYPE_NOT_SPECIFIED) {
+ /*
+ * idmap_hash used to bounce back the requested type,
+ * which was ID_TYPE_UID, ID_TYPE_GID or
+ * ID_TYPE_NOT_SPECIFIED before as the winbindd parent
+ * always used a lookupsids. When the lookupsids
+ * failed because of an unknown domain, the idmap child
+ * weren't requested at all and the caller sees
+ * ID_TYPE_NOT_SPECIFIED.
+ *
+ * Now that the winbindd parent will pass ID_TYPE_BOTH
+ * in order to indicate that the domain exists.
+ * We should ask the parent to fallback to lookupsids
+ * if the domain is not known yet.
+ */
+ ids[i]->status = ID_REQUIRE_TYPE;
+ continue;
+ }
+
sid_copy(&sid, ids[i]->sid);
sid_split_rid(&sid, &rid);
@@ -270,6 +289,22 @@
/* Check that both hashes are non-zero*/
if (h_domain && h_rid) {
+ /*
+ * idmap_hash used to bounce back the requested type,
+ * which was ID_TYPE_UID, ID_TYPE_GID or
+ * ID_TYPE_NOT_SPECIFIED before as the winbindd parent
+ * always used a lookupsids.
+ *
+ * This module should have supported ID_TYPE_BOTH since
+ * samba-4.1.0, similar to idmap_rid and idmap_autorid.
+ *
+ * Now that the winbindd parent will pass ID_TYPE_BOTH
+ * in order to indicate that the domain exists, it's
+ * better to always return ID_TYPE_BOTH instead of a
+ * random mix of ID_TYPE_UID, ID_TYPE_GID or
+ * ID_TYPE_BOTH.
+ */
+ ids[i]->xid.type = ID_TYPE_BOTH;
ids[i]->xid.id = combine_hashes(h_domain, h_rid);
ids[i]->status = ID_MAPPED;
}
@@ -331,13 +366,13 @@
Dispatch Tables for IDMap and NssInfo Methods
********************************************************************/
-static struct idmap_methods hash_idmap_methods = {
+static const struct idmap_methods hash_idmap_methods = {
.init = idmap_hash_initialize,
.unixids_to_sids = unixids_to_sids,
.sids_to_unixids = sids_to_unixids,
};
-static struct nss_info_methods hash_nss_methods = {
+static const struct nss_info_methods hash_nss_methods = {
.init = nss_hash_init,
.map_to_alias = nss_hash_map_to_alias,
.map_from_alias = nss_hash_map_from_alias,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_ldap.c samba-4.13.14+dfsg/source3/winbindd/idmap_ldap.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_ldap.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_ldap.c 2021-11-08 11:29:14.000000000 +0000
@@ -250,6 +250,17 @@
LDAP_ATTR_GIDNUMBER);
break;
+ case ID_TYPE_BOTH:
+ /*
+ * This is not supported here yet and
+ * already handled in idmap_rw_new_mapping()
+ */
+ FALL_THROUGH;
+ case ID_TYPE_NOT_SPECIFIED:
+ /*
+ * This is handled in idmap_rw_new_mapping()
+ */
+ FALL_THROUGH;
default:
DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
return NT_STATUS_INVALID_PARAMETER;
@@ -867,6 +878,7 @@
const char **attr_list;
char *filter = NULL;
bool multi = False;
+ size_t num_required = 0;
int idx = 0;
int bidx = 0;
int count;
@@ -1075,7 +1087,21 @@
ids[i]->status = ID_UNMAPPED;
if (ids[i]->sid != NULL) {
ret = idmap_ldap_new_mapping(dom, ids[i]);
+ DBG_DEBUG("idmap_ldap_new_mapping returned %s\n",
+ nt_errstr(ret));
+ if (NT_STATUS_EQUAL(ret, STATUS_SOME_UNMAPPED)) {
+ if (ids[i]->status == ID_REQUIRE_TYPE) {
+ num_required += 1;
+ continue;
+ }
+ }
if (!NT_STATUS_IS_OK(ret)) {
+ /*
+ * If we can't create
+ * a new mapping it's unlikely
+ * that it will work for the
+ * next entry.
+ */
goto done;
}
}
@@ -1083,6 +1109,9 @@
}
ret = NT_STATUS_OK;
+ if (num_required > 0) {
+ ret = STATUS_SOME_UNMAPPED;
+ }
done:
talloc_free(memctx);
@@ -1093,7 +1122,7 @@
Close the idmap ldap instance
**********************************/
-static struct idmap_methods idmap_ldap_methods = {
+static const struct idmap_methods idmap_ldap_methods = {
.init = idmap_ldap_db_init,
.unixids_to_sids = idmap_ldap_unixids_to_sids,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_nss.c samba-4.13.14+dfsg/source3/winbindd/idmap_nss.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_nss.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_nss.c 2021-11-08 11:29:14.000000000 +0000
@@ -25,6 +25,7 @@
#include "nsswitch/winbind_client.h"
#include "idmap.h"
#include "lib/winbind_util.h"
+#include "libcli/security/dom_sid.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
@@ -55,6 +56,7 @@
struct passwd *pw;
struct group *gr;
const char *name;
+ struct dom_sid sid;
enum lsa_SidType type;
bool ret;
@@ -86,7 +88,7 @@
the following call will not recurse so this is safe */
(void)winbind_on();
/* Lookup name from PDC using lsa_lookup_names() */
- ret = winbind_lookup_name(dom->name, name, ids[i]->sid, &type);
+ ret = winbind_lookup_name(dom->name, name, &sid, &type);
(void)winbind_off();
if (!ret) {
@@ -99,6 +101,7 @@
switch (type) {
case SID_NAME_USER:
if (ids[i]->xid.type == ID_TYPE_UID) {
+ sid_copy(ids[i]->sid, &sid);
ids[i]->status = ID_MAPPED;
}
break;
@@ -107,6 +110,7 @@
case SID_NAME_ALIAS:
case SID_NAME_WKN_GRP:
if (ids[i]->xid.type == ID_TYPE_GID) {
+ sid_copy(ids[i]->sid, &sid);
ids[i]->status = ID_MAPPED;
}
break;
@@ -195,8 +199,7 @@
Close the idmap tdb instance
**********************************/
-static struct idmap_methods nss_methods = {
-
+static const struct idmap_methods nss_methods = {
.init = idmap_nss_int_init,
.unixids_to_sids = idmap_nss_unixids_to_sids,
.sids_to_unixids = idmap_nss_sids_to_unixids,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_passdb.c samba-4.13.14+dfsg/source3/winbindd/idmap_passdb.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_passdb.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_passdb.c 2021-11-08 11:29:14.000000000 +0000
@@ -75,12 +75,7 @@
return NT_STATUS_OK;
}
-/**********************************
- Close the idmap tdb instance
-**********************************/
-
-static struct idmap_methods passdb_methods = {
-
+static const struct idmap_methods passdb_methods = {
.init = idmap_pdb_init,
.unixids_to_sids = idmap_pdb_unixids_to_sids,
.sids_to_unixids = idmap_pdb_sids_to_unixids,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_proto.h samba-4.13.14+dfsg/source3/winbindd/idmap_proto.h
--- samba-4.13.3+dfsg/source3/winbindd/idmap_proto.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_proto.h 2021-11-08 11:29:14.000000000 +0000
@@ -29,7 +29,7 @@
bool idmap_is_offline(void);
NTSTATUS smb_register_idmap(int version, const char *name,
- struct idmap_methods *methods);
+ const struct idmap_methods *methods);
void idmap_close(void);
NTSTATUS idmap_allocate_uid(struct unixid *id);
NTSTATUS idmap_allocate_gid(struct unixid *id);
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_rfc2307.c samba-4.13.14+dfsg/source3/winbindd/idmap_rfc2307.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_rfc2307.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_rfc2307.c 2021-11-08 11:29:14.000000000 +0000
@@ -228,6 +228,7 @@
for (i = 0; i < count; i++) {
char *name;
+ struct dom_sid sid;
enum lsa_SidType lsa_type;
struct id_map *map;
uint32_t id;
@@ -276,7 +277,7 @@
the following call will not recurse so this is safe */
(void)winbind_on();
/* Lookup name from PDC using lsa_lookup_names() */
- b = winbind_lookup_name(dom_name, name, map->sid, &lsa_type);
+ b = winbind_lookup_name(dom_name, name, &sid, &lsa_type);
(void)winbind_off();
if (!b) {
@@ -300,6 +301,7 @@
}
map->status = ID_MAPPED;
+ sid_copy(map->sid, &sid);
}
}
@@ -836,7 +838,7 @@
return status;
}
-static struct idmap_methods rfc2307_methods = {
+static const struct idmap_methods rfc2307_methods = {
.init = idmap_rfc2307_initialize,
.unixids_to_sids = idmap_rfc2307_unixids_to_sids,
.sids_to_unixids = idmap_rfc2307_sids_to_unixids,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_rid.c samba-4.13.14+dfsg/source3/winbindd/idmap_rid.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_rid.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_rid.c 2021-11-08 11:29:14.000000000 +0000
@@ -168,7 +168,7 @@
return NT_STATUS_OK;
}
-static struct idmap_methods rid_methods = {
+static const struct idmap_methods rid_methods = {
.init = idmap_rid_initialize,
.unixids_to_sids = idmap_rid_unixids_to_sids,
.sids_to_unixids = idmap_rid_sids_to_unixids,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_rw.c samba-4.13.14+dfsg/source3/winbindd/idmap_rw.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_rw.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_rw.c 2021-11-08 11:29:14.000000000 +0000
@@ -39,11 +39,39 @@
return NT_STATUS_INVALID_PARAMETER;
}
- if ((map->xid.type != ID_TYPE_UID) && (map->xid.type != ID_TYPE_GID)) {
+ if (map->sid == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
- if (map->sid == NULL) {
+ switch (map->xid.type) {
+ case ID_TYPE_NOT_SPECIFIED:
+ /*
+ * We need to know if we need a user or group mapping.
+ * Ask the winbindd parent to provide a valid type hint.
+ */
+ DBG_INFO("%s ID_TYPE_NOT_SPECIFIED => ID_REQUIRE_TYPE\n",
+ dom_sid_str_buf(map->sid, &buf));
+ map->status = ID_REQUIRE_TYPE;
+ return NT_STATUS_SOME_NOT_MAPPED;
+
+ case ID_TYPE_BOTH:
+ /*
+ * For now we still require
+ * an explicit type as hint
+ * and don't support ID_TYPE_BOTH
+ */
+ DBG_INFO("%s ID_TYPE_BOTH => ID_REQUIRE_TYPE\n",
+ dom_sid_str_buf(map->sid, &buf));
+ map->status = ID_REQUIRE_TYPE;
+ return NT_STATUS_SOME_NOT_MAPPED;
+
+ case ID_TYPE_UID:
+ break;
+
+ case ID_TYPE_GID:
+ break;
+
+ default:
return NT_STATUS_INVALID_PARAMETER;
}
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_script.c samba-4.13.14+dfsg/source3/winbindd/idmap_script.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_script.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_script.c 2021-11-08 11:29:14.000000000 +0000
@@ -665,7 +665,7 @@
return ret;
}
-static struct idmap_methods db_methods = {
+static const struct idmap_methods db_methods = {
.init = idmap_script_db_init,
.unixids_to_sids = idmap_script_unixids_to_sids,
.sids_to_unixids = idmap_script_sids_to_unixids,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_tdb2.c samba-4.13.14+dfsg/source3/winbindd/idmap_tdb2.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_tdb2.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_tdb2.c 2021-11-08 11:29:14.000000000 +0000
@@ -598,7 +598,7 @@
}
-static struct idmap_methods db_methods = {
+static const struct idmap_methods db_methods = {
.init = idmap_tdb2_db_init,
.unixids_to_sids = idmap_tdb_common_unixids_to_sids,
.sids_to_unixids = idmap_tdb_common_sids_to_unixids,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_tdb.c samba-4.13.14+dfsg/source3/winbindd/idmap_tdb.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_tdb.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_tdb.c 2021-11-08 11:29:14.000000000 +0000
@@ -426,7 +426,7 @@
return ret;
}
-static struct idmap_methods db_methods = {
+static const struct idmap_methods db_methods = {
.init = idmap_tdb_db_init,
.unixids_to_sids = idmap_tdb_common_unixids_to_sids,
.sids_to_unixids = idmap_tdb_common_sids_to_unixids,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/idmap_tdb_common.c samba-4.13.14+dfsg/source3/winbindd/idmap_tdb_common.c
--- samba-4.13.3+dfsg/source3/winbindd/idmap_tdb_common.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/idmap_tdb_common.c 2021-11-08 11:29:14.000000000 +0000
@@ -118,6 +118,17 @@
hwmtype = "GID";
break;
+ case ID_TYPE_BOTH:
+ /*
+ * This is not supported here yet and
+ * already handled in idmap_rw_new_mapping()
+ */
+ FALL_THROUGH;
+ case ID_TYPE_NOT_SPECIFIED:
+ /*
+ * This is handled in idmap_rw_new_mapping()
+ */
+ FALL_THROUGH;
default:
DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
return NT_STATUS_INVALID_PARAMETER;
@@ -529,7 +540,7 @@
void *private_data)
{
struct idmap_tdb_common_sids_to_unixids_context *state = private_data;
- size_t i, num_mapped = 0;
+ size_t i, num_mapped = 0, num_required = 0;
NTSTATUS ret = NT_STATUS_OK;
DEBUG(10, ("idmap_tdb_common_sids_to_unixids: "
@@ -579,6 +590,12 @@
state->ids[i]);
DBG_DEBUG("idmap_tdb_common_new_mapping returned %s\n",
nt_errstr(ret));
+ if (NT_STATUS_EQUAL(ret, STATUS_SOME_UNMAPPED)) {
+ if (state->ids[i]->status == ID_REQUIRE_TYPE) {
+ num_required += 1;
+ continue;
+ }
+ }
if (!NT_STATUS_IS_OK(ret)) {
ret = STATUS_SOME_UNMAPPED;
continue;
@@ -598,6 +615,9 @@
} else {
ret = NT_STATUS_OK;
}
+ if (num_required > 0) {
+ ret = STATUS_SOME_UNMAPPED;
+ }
}
return ret;
diff -Nru samba-4.13.3+dfsg/source3/winbindd/nss_info.c samba-4.13.14+dfsg/source3/winbindd/nss_info.c
--- samba-4.13.3+dfsg/source3/winbindd/nss_info.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/nss_info.c 2021-11-08 11:29:14.000000000 +0000
@@ -46,7 +46,8 @@
Allow a module to register itself as a backend.
**********************************************************************/
- NTSTATUS smb_register_idmap_nss(int version, const char *name, struct nss_info_methods *methods)
+ NTSTATUS smb_register_idmap_nss(int version, const char *name,
+ const struct nss_info_methods *methods)
{
struct nss_function_entry *entry;
@@ -319,7 +320,7 @@
const char *name, char **alias )
{
struct nss_domain_entry *p;
- struct nss_info_methods *m;
+ const struct nss_info_methods *m;
if ( (p = find_nss_domain( domain )) == NULL ) {
DEBUG(4,("nss_map_to_alias: Failed to find nss domain pointer for %s\n",
@@ -340,7 +341,7 @@
const char *alias, char **name )
{
struct nss_domain_entry *p;
- struct nss_info_methods *m;
+ const struct nss_info_methods *m;
if ( (p = find_nss_domain( domain )) == NULL ) {
DEBUG(4,("nss_map_from_alias: Failed to find nss domain pointer for %s\n",
diff -Nru samba-4.13.3+dfsg/source3/winbindd/wb_queryuser.c samba-4.13.14+dfsg/source3/winbindd/wb_queryuser.c
--- samba-4.13.3+dfsg/source3/winbindd/wb_queryuser.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/wb_queryuser.c 2021-11-08 11:29:14.000000000 +0000
@@ -25,10 +25,12 @@
struct wb_queryuser_state {
struct tevent_context *ev;
- struct wbint_userinfo *info;
+ struct wbint_userinfo *info;
+ const struct wb_parent_idmap_config *idmap_cfg;
bool tried_dclookup;
};
+static void wb_queryuser_idmap_setup_done(struct tevent_req *subreq);
static void wb_queryuser_got_uid(struct tevent_req *subreq);
static void wb_queryuser_got_domain(struct tevent_req *subreq);
static void wb_queryuser_got_dc(struct tevent_req *subreq);
@@ -60,13 +62,35 @@
sid_copy(&info->user_sid, user_sid);
+ subreq = wb_parent_idmap_setup_send(state, state->ev);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, wb_queryuser_idmap_setup_done, req);
+ return req;
+}
+
+static void wb_queryuser_idmap_setup_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct wb_queryuser_state *state = tevent_req_data(
+ req, struct wb_queryuser_state);
+ NTSTATUS status;
+
+ status = wb_parent_idmap_setup_recv(subreq, &state->idmap_cfg);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
subreq = wb_sids2xids_send(
state, state->ev, &state->info->user_sid, 1);
if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
+ return;
}
tevent_req_set_callback(subreq, wb_queryuser_got_uid, req);
- return req;
+ return;
}
static void wb_queryuser_got_uid(struct tevent_req *subreq)
@@ -77,7 +101,7 @@
req, struct wb_queryuser_state);
struct wbint_userinfo *info = state->info;
struct netr_SamInfo3 *info3;
- struct winbindd_child *child;
+ struct dcerpc_binding_handle *child_binding_handle = NULL;
struct unixid xid;
NTSTATUS status;
@@ -138,10 +162,14 @@
return;
}
- child = idmap_child();
-
+ /*
+ * Note wb_sids2xids_send/recv was called before,
+ * so we're sure that wb_parent_idmap_setup_send/recv
+ * was already called.
+ */
+ child_binding_handle = idmap_child_handle();
subreq = dcerpc_wbint_GetNssInfo_send(
- state, state->ev, child->binding_handle, info);
+ state, state->ev, child_binding_handle, info);
if (tevent_req_nomem(subreq, req)) {
return;
}
@@ -156,7 +184,7 @@
req, struct wb_queryuser_state);
struct wbint_userinfo *info = state->info;
enum lsa_SidType type;
- struct winbindd_child *child;
+ struct dcerpc_binding_handle *child_binding_handle = NULL;
NTSTATUS status;
status = wb_lookupsid_recv(subreq, state, &type,
@@ -186,10 +214,14 @@
return;
}
- child = idmap_child();
-
+ /*
+ * Note wb_sids2xids_send/recv was called before,
+ * so we're sure that wb_parent_idmap_setup_send/recv
+ * was already called.
+ */
+ child_binding_handle = idmap_child_handle();
subreq = dcerpc_wbint_GetNssInfo_send(
- state, state->ev, child->binding_handle, info);
+ state, state->ev, child_binding_handle, info);
if (tevent_req_nomem(subreq, req)) {
return;
}
@@ -270,7 +302,7 @@
req, struct wb_queryuser_state);
struct wbint_userinfo *info = state->info;
struct netr_DsRGetDCNameInfo *dcinfo;
- struct winbindd_child *child;
+ struct dcerpc_binding_handle *child_binding_handle = NULL;
NTSTATUS status;
status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
@@ -286,10 +318,14 @@
return;
}
- child = idmap_child();
-
+ /*
+ * Note wb_sids2xids_send/recv was called before,
+ * so we're sure that wb_parent_idmap_setup_send/recv
+ * was already called.
+ */
+ child_binding_handle = idmap_child_handle();
subreq = dcerpc_wbint_GetNssInfo_send(
- state, state->ev, child->binding_handle, info);
+ state, state->ev, child_binding_handle, info);
if (tevent_req_nomem(subreq, req)) {
return;
}
diff -Nru samba-4.13.3+dfsg/source3/winbindd/wb_sids2xids.c samba-4.13.14+dfsg/source3/winbindd/wb_sids2xids.c
--- samba-4.13.3+dfsg/source3/winbindd/wb_sids2xids.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/wb_sids2xids.c 2021-11-08 11:29:14.000000000 +0000
@@ -29,13 +29,21 @@
struct wb_sids2xids_state {
struct tevent_context *ev;
+ const struct wb_parent_idmap_config *cfg;
+
struct dom_sid *sids;
uint32_t num_sids;
- struct id_map *cached;
+ struct wbint_TransIDArray all_ids;
+
+ /* Used to translated the idx back into all_ids.ids[idx] */
+ uint32_t *tmp_idx;
- struct dom_sid *non_cached;
- uint32_t num_non_cached;
+ uint32_t lookup_count;
+ struct dom_sid *lookup_sids;
+
+ struct wbint_TransIDArray map_ids_in;
+ struct wbint_TransIDArray map_ids_out;
/*
* Domain array to use for the idmap call. The output from
@@ -51,18 +59,17 @@
struct lsa_RefDomainList idmap_doms;
uint32_t dom_index;
- struct wbint_TransIDArray *dom_ids;
struct lsa_RefDomainList idmap_dom;
bool tried_dclookup;
-
- struct wbint_TransIDArray ids;
};
-
+static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq);
static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map);
static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq);
static void wb_sids2xids_done(struct tevent_req *subreq);
static void wb_sids2xids_gotdc(struct tevent_req *subreq);
+static void wb_sids2xids_next_sids2unix(struct tevent_req *req);
+static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type);
struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
@@ -72,6 +79,7 @@
struct tevent_req *req, *subreq;
struct wb_sids2xids_state *state;
uint32_t i;
+ uint32_t num_valid = 0;
req = tevent_req_create(mem_ctx, &state,
struct wb_sids2xids_state);
@@ -92,13 +100,24 @@
sid_copy(&state->sids[i], &sids[i]);
}
- state->cached = talloc_zero_array(state, struct id_map, num_sids);
- if (tevent_req_nomem(state->cached, req)) {
+ state->all_ids.num_ids = num_sids;
+ state->all_ids.ids = talloc_zero_array(state, struct wbint_TransID, num_sids);
+ if (tevent_req_nomem(state->all_ids.ids, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->tmp_idx = talloc_zero_array(state, uint32_t, num_sids);
+ if (tevent_req_nomem(state->tmp_idx, req)) {
return tevent_req_post(req, ev);
}
- state->non_cached = talloc_array(state, struct dom_sid, num_sids);
- if (tevent_req_nomem(state->non_cached, req)) {
+ state->lookup_sids = talloc_zero_array(state, struct dom_sid, num_sids);
+ if (tevent_req_nomem(state->lookup_sids, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->map_ids_in.ids = talloc_zero_array(state, struct wbint_TransID, num_sids);
+ if (tevent_req_nomem(state->map_ids_in.ids, req)) {
return tevent_req_post(req, ev);
}
@@ -108,33 +127,179 @@
* the same index.
*/
for (i=0; inum_sids; i++) {
+ struct wbint_TransID *cur_id = &state->all_ids.ids[i];
+ struct dom_sid domain_sid;
struct dom_sid_buf buf;
+ struct id_map map = { .status = ID_UNMAPPED, };
+ uint32_t rid = 0;
+ bool in_cache;
+
+ sid_copy(&domain_sid, &state->sids[i]);
+ sid_split_rid(&domain_sid, &rid);
+
+ /*
+ * Start with an invalid entry.
+ */
+ *cur_id = (struct wbint_TransID) {
+ .type_hint = ID_TYPE_NOT_SPECIFIED,
+ .domain_index = UINT32_MAX - 1, /* invalid */
+ .rid = rid,
+ .xid = {
+ .id = UINT32_MAX,
+ .type = ID_TYPE_NOT_SPECIFIED,
+ },
+ };
DEBUG(10, ("SID %d: %s\n", (int)i,
dom_sid_str_buf(&state->sids[i], &buf)));
- if (wb_sids2xids_in_cache(&state->sids[i], &state->cached[i])) {
+ in_cache = wb_sids2xids_in_cache(&state->sids[i], &map);
+ if (in_cache) {
+ /*
+ * We used to ignore map.status and just rely
+ * on map.xid.type.
+ *
+ * Lets keep this logic for now...
+ */
+
+ cur_id->xid = map.xid;
+ cur_id->domain_index = UINT32_MAX; /* this marks it as filled entry */
+ num_valid += 1;
continue;
}
- sid_copy(&state->non_cached[state->num_non_cached],
- &state->sids[i]);
- state->num_non_cached += 1;
}
- if (state->num_non_cached == 0) {
+ if (num_valid == num_sids) {
tevent_req_done(req);
return tevent_req_post(req, ev);
}
- subreq = wb_lookupsids_send(state, ev, state->non_cached,
- state->num_non_cached);
+ subreq = wb_parent_idmap_setup_send(state, state->ev);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req);
+ tevent_req_set_callback(subreq, wb_sids2xids_idmap_setup_done, req);
return req;
}
+static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct wb_sids2xids_state *state = tevent_req_data(
+ req, struct wb_sids2xids_state);
+ NTSTATUS status;
+ uint32_t i;
+
+ status = wb_parent_idmap_setup_recv(subreq, &state->cfg);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ SMB_ASSERT(state->cfg->num_doms > 0);
+
+ /*
+ * Now we build a list with all domain
+ * with non cached entries
+ */
+ for (i=0; inum_sids; i++) {
+ struct wbint_TransID *t = &state->all_ids.ids[i];
+ struct dom_sid domain_sid;
+ const char *domain_name = NULL;
+ int domain_index;
+ uint32_t rid = 0;
+ uint32_t di;
+
+ if (t->domain_index == UINT32_MAX) {
+ /* ignore already filled entries */
+ continue;
+ }
+
+ sid_copy(&domain_sid, &state->sids[i]);
+ sid_split_rid(&domain_sid, &rid);
+
+ if (t->type_hint == ID_TYPE_NOT_SPECIFIED) {
+ const char *tmp_name = NULL;
+ enum lsa_SidType sid_type = SID_NAME_USE_NONE;
+ const struct dom_sid *tmp_authority_sid = NULL;
+ const char *tmp_authority_name = NULL;
+
+ /*
+ * Try to get a type hint from for predefined sids
+ */
+ status = dom_sid_lookup_predefined_sid(&state->sids[i],
+ &tmp_name,
+ &sid_type,
+ &tmp_authority_sid,
+ &tmp_authority_name);
+ if (NT_STATUS_IS_OK(status)) {
+ t->type_hint = lsa_SidType_to_id_type(sid_type);
+ }
+ }
+
+ for (di = 0; di < state->cfg->num_doms; di++) {
+ struct wb_parent_idmap_config_dom *dom =
+ &state->cfg->doms[di];
+ bool match;
+
+ match = dom_sid_equal(&domain_sid,
+ &dom->sid);
+ if (!match) {
+ continue;
+ }
+
+ domain_name = dom->name;
+ break;
+ }
+ if (domain_name == NULL) {
+ struct winbindd_domain *wb_domain = NULL;
+
+ /*
+ * Try to fill the name if we already know it
+ */
+ wb_domain = find_domain_from_sid_noinit(&state->sids[i]);
+ if (wb_domain != NULL) {
+ domain_name = wb_domain->name;
+ }
+ }
+ if (domain_name == NULL) {
+ domain_name = "";
+ }
+
+ if (t->type_hint == ID_TYPE_NOT_SPECIFIED) {
+ if (domain_name[0] != '\0') {
+ /*
+ * We know the domain, we indicate this
+ * by passing ID_TYPE_BOTH as a hint
+ *
+ * Maybe that's already enough for the backend
+ */
+ t->type_hint = ID_TYPE_BOTH;
+ }
+ }
+
+ domain_index = init_lsa_ref_domain_list(state,
+ &state->idmap_doms,
+ domain_name,
+ &domain_sid);
+ if (domain_index == -1) {
+ tevent_req_oom(req);
+ return;
+ }
+ t->domain_index = domain_index;
+ }
+
+ /*
+ * We defer lookupsids because it requires domain controller
+ * interaction.
+ *
+ * First we ask the idmap child without explicit type hints.
+ * In most cases mappings already exist in the backend and
+ * a type_hint is not needed.
+ */
+ wb_sids2xids_next_sids2unix(req);
+}
+
static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map)
{
struct unixid id;
@@ -155,11 +320,6 @@
return false;
}
-static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type);
-static struct wbint_TransIDArray *wb_sids2xids_extract_for_domain_index(
- TALLOC_CTX *mem_ctx, const struct wbint_TransIDArray *src,
- uint32_t domain_index);
-
static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
@@ -168,9 +328,8 @@
req, struct wb_sids2xids_state);
struct lsa_RefDomainList *domains = NULL;
struct lsa_TransNameArray *names = NULL;
- struct dcerpc_binding_handle *child_binding_handle = NULL;
NTSTATUS status;
- uint32_t i;
+ uint32_t li;
status = wb_lookupsids_recv(subreq, state, &domains, &names);
TALLOC_FREE(subreq);
@@ -178,83 +337,185 @@
return;
}
- state->ids.num_ids = state->num_non_cached;
- state->ids.ids = talloc_array(state, struct wbint_TransID,
- state->num_non_cached);
- if (tevent_req_nomem(state->ids.ids, req)) {
+ if (domains == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
return;
}
- for (i=0; inum_non_cached; i++) {
- const struct dom_sid *sid = &state->non_cached[i];
- struct dom_sid dom_sid;
- struct lsa_TranslatedName *n = &names->names[i];
- struct wbint_TransID *t = &state->ids.ids[i];
- int domain_index;
- const char *domain_name = NULL;
+ if (names == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
- if (n->sid_index != UINT32_MAX) {
- const struct lsa_DomainInfo *info;
- bool match;
+ for (li = 0; li < state->lookup_count; li++) {
+ struct lsa_TranslatedName *n = &names->names[li];
+ uint32_t ai = state->tmp_idx[li];
+ struct wbint_TransID *t = &state->all_ids.ids[ai];
+ enum id_type type_hint;
- info = &domains->domains[n->sid_index];
- match = dom_sid_in_domain(info->sid, sid);
- if (match) {
- domain_name = info->name.string;
- }
+ type_hint = lsa_SidType_to_id_type(n->sid_type);
+ if (type_hint != ID_TYPE_NOT_SPECIFIED) {
+ /*
+ * We know it's a valid user or group.
+ */
+ t->type_hint = type_hint;
+ continue;
}
- if (domain_name == NULL) {
- struct winbindd_domain *wb_domain = NULL;
+ if (n->sid_index == UINT32_MAX) {
/*
- * This is needed to handle Samba DCs
- * which always return sid_index == UINT32_MAX for
- * unknown sids.
+ * The domain is not known, there's
+ * no point to try mapping again.
+ * mark is done and add a negative cache
+ * entry.
*/
- wb_domain = find_domain_from_sid_noinit(sid);
- if (wb_domain != NULL) {
- domain_name = wb_domain->name;
- }
+ t->domain_index = UINT32_MAX; /* mark as valid */
+ idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid);
+ continue;
}
- if (domain_name == NULL) {
- domain_name = "";
+
+ if (n->sid_index >= domains->count) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
}
- sid_copy(&dom_sid, sid);
- sid_split_rid(&dom_sid, &t->rid);
- t->type = lsa_SidType_to_id_type(n->sid_type);
- domain_index = init_lsa_ref_domain_list(
- state, &state->idmap_doms, domain_name, &dom_sid);
- if (domain_index == -1) {
- tevent_req_oom(req);
+ if (domains->domains[n->sid_index].name.string == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+ if (domains->domains[n->sid_index].sid == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
return;
}
- t->domain_index = domain_index;
- t->xid.id = UINT32_MAX;
- t->xid.type = t->type;
+ if (t->type_hint != ID_TYPE_NOT_SPECIFIED) {
+ /*
+ * We already tried with a type hint there's
+ * no point to try mapping again with ID_TYPE_BOTH.
+ *
+ * Mark is done and add a negative cache entry.
+ */
+ t->domain_index = UINT32_MAX; /* mark as valid */
+ idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid);
+ continue;
+ }
+
+ /*
+ * We only know the domain exists, but the user doesn't
+ */
+ t->type_hint = ID_TYPE_BOTH;
}
TALLOC_FREE(names);
TALLOC_FREE(domains);
- child_binding_handle = idmap_child_handle();
+ /*
+ * Now that we have type_hints for the remaining sids,
+ * we need to restart with the first domain.
+ */
+ state->dom_index = 0;
+ wb_sids2xids_next_sids2unix(req);
+}
+
+static void wb_sids2xids_next_sids2unix(struct tevent_req *req)
+{
+ struct wb_sids2xids_state *state = tevent_req_data(
+ req, struct wb_sids2xids_state);
+ struct tevent_req *subreq = NULL;
+ struct dcerpc_binding_handle *child_binding_handle = NULL;
+ const struct wbint_TransIDArray *src = NULL;
+ struct wbint_TransIDArray *dst = NULL;
+ uint32_t si;
+
+ next_domain:
+ state->tried_dclookup = false;
+
+ if (state->dom_index == state->idmap_doms.count) {
+ if (state->lookup_count != 0) {
+ /*
+ * We already called wb_lookupsids_send()
+ * before, so we're done.
+ */
+ tevent_req_done(req);
+ return;
+ }
+
+ for (si=0; si < state->num_sids; si++) {
+ struct wbint_TransID *t = &state->all_ids.ids[si];
+
+ if (t->domain_index == UINT32_MAX) {
+ /* ignore already filled entries */
+ continue;
+ }
+
+ state->tmp_idx[state->lookup_count] = si;
+ sid_copy(&state->lookup_sids[state->lookup_count],
+ &state->sids[si]);
+ state->lookup_count += 1;
+ }
+
+ if (state->lookup_count == 0) {
+ /*
+ * no wb_lookupsids_send() needed...
+ */
+ tevent_req_done(req);
+ return;
+ }
- state->dom_ids = wb_sids2xids_extract_for_domain_index(
- state, &state->ids, state->dom_index);
- if (tevent_req_nomem(state->dom_ids, req)) {
+ subreq = wb_lookupsids_send(state,
+ state->ev,
+ state->lookup_sids,
+ state->lookup_count);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req);
return;
}
+ src = &state->all_ids;
+ dst = &state->map_ids_in;
+ dst->num_ids = 0;
+
+ for (si=0; si < src->num_ids; si++) {
+ if (src->ids[si].domain_index != state->dom_index) {
+ continue;
+ }
+
+ state->tmp_idx[dst->num_ids] = si;
+ dst->ids[dst->num_ids] = src->ids[si];
+ dst->ids[dst->num_ids].domain_index = 0;
+ dst->num_ids += 1;
+ }
+
+ if (dst->num_ids == 0) {
+ state->dom_index += 1;
+ goto next_domain;
+ }
+
state->idmap_dom = (struct lsa_RefDomainList) {
.count = 1,
.domains = &state->idmap_doms.domains[state->dom_index],
.max_size = 1
};
+ /*
+ * dcerpc_wbint_Sids2UnixIDs_send/recv will
+ * allocate a new array for the response
+ * and overwrite _ids->ids pointer.
+ *
+ * So we better make a temporary copy
+ * of state->map_ids_in (which contains the request array)
+ * into state->map_ids_out.
+ *
+ * That makes it possible to reuse the pre-allocated
+ * state->map_ids_in.ids array.
+ */
+ state->map_ids_out = state->map_ids_in;
+ child_binding_handle = idmap_child_handle();
subreq = dcerpc_wbint_Sids2UnixIDs_send(
state, state->ev, child_binding_handle, &state->idmap_dom,
- state->dom_ids);
+ &state->map_ids_out);
if (tevent_req_nomem(subreq, req)) {
return;
}
@@ -290,10 +551,9 @@
struct wb_sids2xids_state *state = tevent_req_data(
req, struct wb_sids2xids_state);
NTSTATUS status, result;
- struct winbindd_child *child;
-
- struct wbint_TransIDArray *src, *dst;
- uint32_t i, src_idx;
+ const struct wbint_TransIDArray *src = NULL;
+ struct wbint_TransIDArray *dst = NULL;
+ uint32_t si;
status = dcerpc_wbint_Sids2UnixIDs_recv(subreq, state, &result);
TALLOC_FREE(subreq);
@@ -319,9 +579,8 @@
return;
}
- src = state->dom_ids;
- src_idx = 0;
- dst = &state->ids;
+ src = &state->map_ids_out;
+ dst = &state->all_ids;
if (any_nt_status_not_ok(status, result, &status)) {
DBG_DEBUG("status=%s, result=%s\n", nt_errstr(status),
@@ -330,50 +589,62 @@
/*
* All we can do here is to report "not mapped"
*/
- for (i=0; inum_ids; i++) {
- src->ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
+ src = &state->map_ids_in;
+ for (si=0; si < src->num_ids; si++) {
+ src->ids[si].xid.type = ID_TYPE_NOT_SPECIFIED;
}
}
- for (i=0; inum_ids; i++) {
- if (dst->ids[i].domain_index == state->dom_index) {
- dst->ids[i].type = src->ids[src_idx].type;
- dst->ids[i].xid = src->ids[src_idx].xid;
- src_idx += 1;
- }
+ if (src->num_ids != state->map_ids_in.num_ids) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
}
- TALLOC_FREE(state->dom_ids);
+ for (si=0; si < src->num_ids; si++) {
+ uint32_t di = state->tmp_idx[si];
- state->dom_index += 1;
- state->tried_dclookup = false;
+ if (src->ids[si].xid.type == ID_TYPE_WB_REQUIRE_TYPE) {
+ if (state->lookup_count == 0) {
+ /*
+ * The backend asks for more information
+ * (a type_hint), we'll do a lookupsids
+ * later.
+ */
+ continue;
+ }
- if (state->dom_index == state->idmap_doms.count) {
- tevent_req_done(req);
- return;
- }
+ /*
+ * lookupsids was not able to provide a type_hint that
+ * satisfied the backend.
+ *
+ * Make sure we don't expose ID_TYPE_WB_REQUIRE_TYPE
+ * outside of winbindd!
+ */
+ src->ids[si].xid.type = ID_TYPE_NOT_SPECIFIED;
+ }
- child = idmap_child();
+ if (src->ids[si].xid.type != ID_TYPE_NOT_SPECIFIED) {
+ dst->ids[di].xid = src->ids[si].xid;
+ }
+ dst->ids[di].domain_index = UINT32_MAX; /* mark as valid */
+ idmap_cache_set_sid2unixid(&state->sids[di], &dst->ids[di].xid);
+ }
- state->dom_ids = wb_sids2xids_extract_for_domain_index(
- state, &state->ids, state->dom_index);
- if (tevent_req_nomem(state->dom_ids, req)) {
- return;
+ state->map_ids_in.num_ids = 0;
+ if (NT_STATUS_IS_OK(status)) {
+ /*
+ * If we got a valid response, we expect
+ * state->map_ids_out.ids to be a new allocated
+ * array, which we want to free early.
+ */
+ SMB_ASSERT(state->map_ids_out.ids != state->map_ids_in.ids);
+ TALLOC_FREE(state->map_ids_out.ids);
}
+ state->map_ids_out = (struct wbint_TransIDArray) { .num_ids = 0, };
- state->idmap_dom = (struct lsa_RefDomainList) {
- .count = 1,
- .domains = &state->idmap_doms.domains[state->dom_index],
- .max_size = 1
- };
+ state->dom_index += 1;
- subreq = dcerpc_wbint_Sids2UnixIDs_send(
- state, state->ev, child->binding_handle, &state->idmap_dom,
- state->dom_ids);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, wb_sids2xids_done, req);
+ wb_sids2xids_next_sids2unix(req);
}
static void wb_sids2xids_gotdc(struct tevent_req *subreq)
@@ -382,7 +653,7 @@
subreq, struct tevent_req);
struct wb_sids2xids_state *state = tevent_req_data(
req, struct wb_sids2xids_state);
- struct winbindd_child *child = idmap_child();
+ struct dcerpc_binding_handle *child_binding_handle = NULL;
struct netr_DsRGetDCNameInfo *dcinfo;
NTSTATUS status;
@@ -405,9 +676,23 @@
}
}
+ /*
+ * dcerpc_wbint_Sids2UnixIDs_send/recv will
+ * allocate a new array for the response
+ * and overwrite _ids->ids pointer.
+ *
+ * So we better make a temporary copy
+ * of state->map_ids_in (which contains the request array)
+ * into state->map_ids_out.
+ *
+ * That makes it possible to reuse the pre-allocated
+ * state->map_ids_in.ids array.
+ */
+ state->map_ids_out = state->map_ids_in;
+ child_binding_handle = idmap_child_handle();
subreq = dcerpc_wbint_Sids2UnixIDs_send(
- state, state->ev, child->binding_handle, &state->idmap_dom,
- state->dom_ids);
+ state, state->ev, child_binding_handle, &state->idmap_dom,
+ &state->map_ids_out);
if (tevent_req_nomem(subreq, req)) {
return;
}
@@ -420,7 +705,7 @@
struct wb_sids2xids_state *state = tevent_req_data(
req, struct wb_sids2xids_state);
NTSTATUS status;
- uint32_t i, num_non_cached;
+ uint32_t i;
if (tevent_req_is_nterror(req, &status)) {
DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status)));
@@ -433,55 +718,9 @@
return NT_STATUS_INTERNAL_ERROR;
}
- num_non_cached = 0;
-
for (i=0; inum_sids; i++) {
- struct unixid xid;
-
- xid.id = UINT32_MAX;
-
- if (state->cached[i].sid != NULL) {
- xid = state->cached[i].xid;
- } else {
- xid = state->ids.ids[num_non_cached].xid;
-
- idmap_cache_set_sid2unixid(
- &state->non_cached[num_non_cached],
- &xid);
-
- num_non_cached += 1;
- }
-
- xids[i] = xid;
+ xids[i] = state->all_ids.ids[i].xid;
}
return NT_STATUS_OK;
}
-
-static struct wbint_TransIDArray *wb_sids2xids_extract_for_domain_index(
- TALLOC_CTX *mem_ctx, const struct wbint_TransIDArray *src,
- uint32_t domain_index)
-{
- struct wbint_TransIDArray *ret;
- uint32_t i;
-
- ret = talloc_zero(mem_ctx, struct wbint_TransIDArray);
- if (ret == NULL) {
- return NULL;
- }
- ret->ids = talloc_array(ret, struct wbint_TransID, src->num_ids);
- if (ret->ids == NULL) {
- TALLOC_FREE(ret);
- return NULL;
- }
-
- for (i=0; inum_ids; i++) {
- if (src->ids[i].domain_index == domain_index) {
- ret->ids[ret->num_ids] = src->ids[i];
- ret->ids[ret->num_ids].domain_index = 0;
- ret->num_ids += 1;
- }
- }
-
- return ret;
-}
diff -Nru samba-4.13.3+dfsg/source3/winbindd/wb_xids2sids.c samba-4.13.14+dfsg/source3/winbindd/wb_xids2sids.c
--- samba-4.13.3+dfsg/source3/winbindd/wb_xids2sids.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/wb_xids2sids.c 2021-11-08 11:29:14.000000000 +0000
@@ -25,231 +25,13 @@
#include "librpc/gen_ndr/ndr_netlogon.h"
#include "passdb/lookup_sid.h"
-struct wb_xids2sids_dom_map {
- unsigned low_id;
- unsigned high_id;
- const char *name;
- struct dom_sid sid;
-};
-
-/*
- * Map idmap ranges to domain names, taken from smb.conf. This is
- * stored in the parent winbind and used to assemble xid2sid calls
- * into per-idmap-domain chunks.
- */
-static struct wb_xids2sids_dom_map *dom_maps;
-
-static bool wb_xids2sids_add_dom(const char *domname,
- void *private_data)
-{
- struct wb_xids2sids_dom_map *map = NULL;
- size_t num_maps = talloc_array_length(dom_maps);
- size_t i;
- const char *range;
- unsigned low_id, high_id;
- int ret;
-
- range = idmap_config_const_string(domname, "range", NULL);
- if (range == NULL) {
- DBG_DEBUG("No range for domain %s found\n", domname);
- return false;
- }
-
- ret = sscanf(range, "%u - %u", &low_id, &high_id);
- if (ret != 2) {
- DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
- range, domname);
- return false;
- }
-
- if (low_id > high_id) {
- DBG_DEBUG("Invalid range %u - %u for domain %s\n",
- low_id, high_id, domname);
- return false;
- }
-
- for (i=0; iname = talloc_move(dom_maps, &name);
- }
-
- map->low_id = low_id;
- map->high_id = high_id;
-
- return false;
-}
-
-struct wb_xids2sids_init_dom_maps_state {
- struct tevent_context *ev;
- struct tevent_req *req;
- size_t dom_idx;
-};
-
-static void wb_xids2sids_init_dom_maps_lookupname_next(
- struct wb_xids2sids_init_dom_maps_state *state);
-
-static void wb_xids2sids_init_dom_maps_lookupname_done(
- struct tevent_req *subreq);
-
-static struct tevent_req *wb_xids2sids_init_dom_maps_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev)
-{
- struct tevent_req *req = NULL;
- struct wb_xids2sids_init_dom_maps_state *state = NULL;
-
- req = tevent_req_create(mem_ctx, &state,
- struct wb_xids2sids_init_dom_maps_state);
- if (req == NULL) {
- return NULL;
- }
- *state = (struct wb_xids2sids_init_dom_maps_state) {
- .ev = ev,
- .req = req,
- .dom_idx = 0,
- };
-
- if (dom_maps != NULL) {
- tevent_req_done(req);
- return tevent_req_post(req, ev);
- }
- /*
- * Put the passdb idmap domain first. We always need to try
- * there first.
- */
-
- dom_maps = talloc_zero_array(NULL, struct wb_xids2sids_dom_map, 1);
- if (tevent_req_nomem(dom_maps, req)) {
- return tevent_req_post(req, ev);
- }
- dom_maps[0].low_id = 0;
- dom_maps[0].high_id = UINT_MAX;
- dom_maps[0].name = talloc_strdup(dom_maps, get_global_sam_name());
- if (tevent_req_nomem(dom_maps[0].name, req)) {
- TALLOC_FREE(dom_maps);
- return tevent_req_post(req, ev);
- }
-
- lp_scan_idmap_domains(wb_xids2sids_add_dom, NULL);
-
- wb_xids2sids_init_dom_maps_lookupname_next(state);
- if (!tevent_req_is_in_progress(req)) {
- tevent_req_post(req, ev);
- }
- return req;
-}
-
-static void wb_xids2sids_init_dom_maps_lookupname_next(
- struct wb_xids2sids_init_dom_maps_state *state)
-{
- struct tevent_req *subreq = NULL;
-
- if (state->dom_idx == talloc_array_length(dom_maps)) {
- tevent_req_done(state->req);
- return;
- }
-
- if (strequal(dom_maps[state->dom_idx].name, "*")) {
- state->dom_idx++;
- if (state->dom_idx == talloc_array_length(dom_maps)) {
- tevent_req_done(state->req);
- return;
- }
- }
-
- subreq = wb_lookupname_send(state,
- state->ev,
- dom_maps[state->dom_idx].name,
- dom_maps[state->dom_idx].name,
- "",
- LOOKUP_NAME_NO_NSS);
- if (tevent_req_nomem(subreq, state->req)) {
- return;
- }
- tevent_req_set_callback(subreq,
- wb_xids2sids_init_dom_maps_lookupname_done,
- state->req);
-}
-
-static void wb_xids2sids_init_dom_maps_lookupname_done(
- struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct wb_xids2sids_init_dom_maps_state *state = tevent_req_data(
- req, struct wb_xids2sids_init_dom_maps_state);
- enum lsa_SidType type;
- NTSTATUS status;
-
- status = wb_lookupname_recv(subreq,
- &dom_maps[state->dom_idx].sid,
- &type);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_WARNING("Lookup domain name '%s' failed '%s'\n",
- dom_maps[state->dom_idx].name,
- nt_errstr(status));
-
- state->dom_idx++;
- wb_xids2sids_init_dom_maps_lookupname_next(state);
- return;
- }
-
- if (type != SID_NAME_DOMAIN) {
- struct dom_sid_buf buf;
-
- DBG_WARNING("SID %s for idmap domain name '%s' "
- "not a domain SID\n",
- dom_sid_str_buf(&dom_maps[state->dom_idx].sid,
- &buf),
- dom_maps[state->dom_idx].name);
-
- ZERO_STRUCT(dom_maps[state->dom_idx].sid);
- }
-
- state->dom_idx++;
- wb_xids2sids_init_dom_maps_lookupname_next(state);
-
- return;
-}
-
-static NTSTATUS wb_xids2sids_init_dom_maps_recv(struct tevent_req *req)
-{
- return tevent_req_simple_recv_ntstatus(req);
-}
-
struct wb_xids2sids_dom_state {
struct tevent_context *ev;
struct unixid *all_xids;
const bool *cached;
size_t num_all_xids;
struct dom_sid *all_sids;
- struct wb_xids2sids_dom_map *dom_map;
+ const struct wb_parent_idmap_config_dom *dom_map;
bool tried_dclookup;
size_t num_dom_xids;
@@ -262,7 +44,7 @@
static struct tevent_req *wb_xids2sids_dom_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct wb_xids2sids_dom_map *dom_map,
+ const struct wb_parent_idmap_config_dom *dom_map,
struct unixid *xids,
const bool *cached,
size_t num_xids,
@@ -270,7 +52,7 @@
{
struct tevent_req *req, *subreq;
struct wb_xids2sids_dom_state *state;
- struct winbindd_child *child;
+ struct dcerpc_binding_handle *child_binding_handle = NULL;
size_t i;
req = tevent_req_create(mem_ctx, &state,
@@ -317,9 +99,9 @@
return tevent_req_post(req, ev);
}
- child = idmap_child();
+ child_binding_handle = idmap_child_handle();
subreq = dcerpc_wbint_UnixIDs2Sids_send(
- state, ev, child->binding_handle, dom_map->name, dom_map->sid,
+ state, ev, child_binding_handle, dom_map->name, dom_map->sid,
state->num_dom_xids, state->dom_xids, state->dom_sids);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
@@ -334,7 +116,7 @@
subreq, struct tevent_req);
struct wb_xids2sids_dom_state *state = tevent_req_data(
req, struct wb_xids2sids_dom_state);
- struct wb_xids2sids_dom_map *dom_map = state->dom_map;
+ const struct wb_parent_idmap_config_dom *dom_map = state->dom_map;
NTSTATUS status, result;
size_t i;
size_t dom_sid_idx;
@@ -396,7 +178,7 @@
subreq, struct tevent_req);
struct wb_xids2sids_dom_state *state = tevent_req_data(
req, struct wb_xids2sids_dom_state);
- struct winbindd_child *child = idmap_child();
+ struct dcerpc_binding_handle *child_binding_handle = NULL;
struct netr_DsRGetDCNameInfo *dcinfo;
NTSTATUS status;
@@ -413,9 +195,9 @@
return;
}
- child = idmap_child();
+ child_binding_handle = idmap_child_handle();
subreq = dcerpc_wbint_UnixIDs2Sids_send(
- state, state->ev, child->binding_handle, state->dom_map->name,
+ state, state->ev, child_binding_handle, state->dom_map->name,
state->dom_map->sid, state->num_dom_xids,
state->dom_xids, state->dom_sids);
if (tevent_req_nomem(subreq, req)) {
@@ -437,10 +219,11 @@
bool *cached;
size_t dom_idx;
+ const struct wb_parent_idmap_config *cfg;
};
+static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq);
static void wb_xids2sids_done(struct tevent_req *subreq);
-static void wb_xids2sids_init_dom_maps_done(struct tevent_req *subreq);
struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
@@ -495,38 +278,32 @@
}
}
- subreq = wb_xids2sids_init_dom_maps_send(
- state, state->ev);
+ subreq = wb_parent_idmap_setup_send(state, state->ev);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
- tevent_req_set_callback(subreq, wb_xids2sids_init_dom_maps_done, req);
+ tevent_req_set_callback(subreq, wb_xids2sids_idmap_setup_done, req);
return req;
}
-static void wb_xids2sids_init_dom_maps_done(struct tevent_req *subreq)
+static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct wb_xids2sids_state *state = tevent_req_data(
req, struct wb_xids2sids_state);
- size_t num_domains;
NTSTATUS status;
- status = wb_xids2sids_init_dom_maps_recv(subreq);
+ status = wb_parent_idmap_setup_recv(subreq, &state->cfg);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
-
- num_domains = talloc_array_length(dom_maps);
- if (num_domains == 0) {
- tevent_req_done(req);
- return;
- }
+ SMB_ASSERT(state->cfg->num_doms > 0);
subreq = wb_xids2sids_dom_send(
- state, state->ev, &dom_maps[state->dom_idx],
+ state, state->ev,
+ &state->cfg->doms[state->dom_idx],
state->xids, state->cached, state->num_xids, state->sids);
if (tevent_req_nomem(subreq, req)) {
return;
@@ -541,7 +318,6 @@
subreq, struct tevent_req);
struct wb_xids2sids_state *state = tevent_req_data(
req, struct wb_xids2sids_state);
- size_t num_domains = talloc_array_length(dom_maps);
size_t i;
NTSTATUS status;
@@ -553,10 +329,13 @@
state->dom_idx += 1;
- if (state->dom_idx < num_domains) {
+ if (state->dom_idx < state->cfg->num_doms) {
+ const struct wb_parent_idmap_config_dom *dom_map =
+ &state->cfg->doms[state->dom_idx];
+
subreq = wb_xids2sids_dom_send(state,
state->ev,
- &dom_maps[state->dom_idx],
+ dom_map,
state->xids,
state->cached,
state->num_xids,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_allocate_uid.c samba-4.13.14+dfsg/source3/winbindd/winbindd_allocate_uid.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_allocate_uid.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_allocate_uid.c 2021-11-08 11:29:14.000000000 +0000
@@ -22,9 +22,11 @@
#include "librpc/gen_ndr/ndr_winbind_c.h"
struct winbindd_allocate_uid_state {
+ struct tevent_context *ev;
uint64_t uid;
};
+static void winbindd_allocate_uid_initialized(struct tevent_req *subreq);
static void winbindd_allocate_uid_done(struct tevent_req *subreq);
struct tevent_req *winbindd_allocate_uid_send(TALLOC_CTX *mem_ctx,
@@ -34,25 +36,57 @@
{
struct tevent_req *req, *subreq;
struct winbindd_allocate_uid_state *state;
- struct dcerpc_binding_handle *child_binding_handle = NULL;
req = tevent_req_create(mem_ctx, &state,
struct winbindd_allocate_uid_state);
if (req == NULL) {
return NULL;
}
+ state->ev = ev;
DEBUG(3, ("allocate_uid\n"));
- child_binding_handle = idmap_child_handle();
+ subreq = wb_parent_idmap_setup_send(state, ev);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, winbindd_allocate_uid_initialized, req);
+ return req;
+}
+
+static void winbindd_allocate_uid_initialized(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dcerpc_binding_handle *child_binding_handle = NULL;
+ struct winbindd_allocate_uid_state *state = tevent_req_data(
+ req, struct winbindd_allocate_uid_state);
+ const struct wb_parent_idmap_config *cfg = NULL;
+ NTSTATUS status;
+
+ status = wb_parent_idmap_setup_recv(subreq, &cfg);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ if (cfg->num_doms == 0) {
+ /*
+ * idmap_tdb also returns UNSUCCESSFUL if a range is full
+ */
+ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return;
+ }
- subreq = dcerpc_wbint_AllocateUid_send(state, ev, child_binding_handle,
+ child_binding_handle = idmap_child_handle();
+
+ subreq = dcerpc_wbint_AllocateUid_send(state,
+ state->ev,
+ child_binding_handle,
&state->uid);
if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
+ return;
}
tevent_req_set_callback(subreq, winbindd_allocate_uid_done, req);
- return req;
}
static void winbindd_allocate_uid_done(struct tevent_req *subreq)
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd.c samba-4.13.14+dfsg/source3/winbindd/winbindd.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd.c 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd.c 2021-08-09 07:20:55.000000000 +0000
@@ -102,7 +102,7 @@
/* Reload configuration */
-static bool reload_services_file(const char *lfile)
+bool winbindd_reload_services_file(const char *lfile)
{
const struct loadparm_substitution *lp_sub =
loadparm_s3_global_substitution();
@@ -117,6 +117,9 @@
TALLOC_FREE(fname);
}
+ reopen_logs();
+ ret = lp_load_global(get_dyn_CONFIGFILE());
+
/* if this is a child, restore the logfile to the special
name - , idmap, etc. */
if (lfile && *lfile) {
@@ -124,9 +127,6 @@
}
reopen_logs();
- ret = lp_load_global(get_dyn_CONFIGFILE());
-
- reopen_logs();
load_interfaces();
winbindd_setup_max_fds();
@@ -156,7 +156,7 @@
/* Flush client cache */
-static void flush_caches(void)
+void winbindd_flush_caches(void)
{
/* We need to invalidate cached user list entries on a SIGHUP
otherwise cached access denied errors due to restrict anonymous
@@ -363,7 +363,7 @@
DEBUG(1,("Reloading services after SIGHUP\n"));
flush_caches_noinit();
- reload_services_file(file);
+ winbindd_reload_services_file(file);
}
bool winbindd_setup_sig_hup_handler(const char *lfile)
@@ -447,18 +447,6 @@
return true;
}
-/* React on 'smbcontrol winbindd reload-config' in the same way as on SIGHUP*/
-static void msg_reload_services(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- /* Flush various caches */
- flush_caches();
- reload_services_file((const char *) private_data);
-}
-
/* React on 'smbcontrol winbindd shutdown' in the same way as on SIGTERM*/
static void msg_shutdown(struct messaging_context *msg,
void *private_data,
@@ -1420,7 +1408,8 @@
/* React on 'smbcontrol winbindd reload-config' in the same way
as to SIGHUP signal */
messaging_register(msg_ctx, NULL,
- MSG_SMB_CONF_UPDATED, msg_reload_services);
+ MSG_SMB_CONF_UPDATED,
+ winbindd_msg_reload_services_parent);
messaging_register(msg_ctx, NULL,
MSG_SHUTDOWN, msg_shutdown);
@@ -1811,7 +1800,7 @@
exit(1);
}
- if (!reload_services_file(NULL)) {
+ if (!winbindd_reload_services_file(NULL)) {
DEBUG(0, ("error opening config file\n"));
exit(1);
}
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_cm.c samba-4.13.14+dfsg/source3/winbindd/winbindd_cm.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_cm.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_cm.c 2021-11-08 11:29:14.000000000 +0000
@@ -463,11 +463,11 @@
primary domain goes offline */
if ( domain->primary ) {
- struct winbindd_child *idmap = idmap_child();
+ pid_t idmap_pid = idmap_child_pid();
- if ( idmap->pid != 0 ) {
+ if (idmap_pid != 0) {
messaging_send_buf(global_messaging_context(),
- pid_to_procid(idmap->pid),
+ pid_to_procid(idmap_pid),
MSG_WINBIND_OFFLINE,
(const uint8_t *)domain->name,
strlen(domain->name)+1);
@@ -549,11 +549,11 @@
primary domain comes online */
if ( domain->primary ) {
- struct winbindd_child *idmap = idmap_child();
+ pid_t idmap_pid = idmap_child_pid();
- if ( idmap->pid != 0 ) {
+ if (idmap_pid != 0) {
messaging_send_buf(global_messaging_context(),
- pid_to_procid(idmap->pid),
+ pid_to_procid(idmap_pid),
MSG_WINBIND_ONLINE,
(const uint8_t *)domain->name,
strlen(domain->name)+1);
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_dual.c samba-4.13.14+dfsg/source3/winbindd/winbindd_dual.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_dual.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_dual.c 2021-11-08 11:29:14.000000000 +0000
@@ -927,6 +927,39 @@
forall_children(winbind_msg_relay_fn, &state);
}
+static void winbindd_msg_reload_services_child(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ DBG_DEBUG("Got reload-config message\n");
+ winbindd_reload_services_file((const char *)private_data);
+}
+
+/* React on 'smbcontrol winbindd reload-config' in the same way as on SIGHUP*/
+void winbindd_msg_reload_services_parent(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbind_msg_relay_state state = {
+ .msg_ctx = msg,
+ .msg_type = msg_type,
+ .data = data,
+ };
+
+ DBG_DEBUG("Got reload-config message\n");
+
+ /* Flush various caches */
+ winbindd_flush_caches();
+
+ winbindd_reload_services_file((const char *)private_data);
+
+ forall_children(winbind_msg_relay_fn, &state);
+}
+
/* Set our domains as offline and forward the offline message to our children. */
struct winbind_msg_on_offline_state {
@@ -1038,11 +1071,11 @@
primary domain comes back online */
if ( domain->primary ) {
- struct winbindd_child *idmap = idmap_child();
+ pid_t idmap_pid = idmap_child_pid();
- if ( idmap->pid != 0 ) {
+ if (idmap_pid != 0) {
messaging_send_buf(msg_ctx,
- pid_to_procid(idmap->pid),
+ pid_to_procid(idmap_pid),
MSG_WINBIND_ONLINE,
(const uint8_t *)domain->name,
strlen(domain->name)+1);
@@ -1743,7 +1776,7 @@
if (child_domain != NULL) {
setproctitle("domain child [%s]", child_domain->name);
- } else if (child == idmap_child()) {
+ } else if (is_idmap_child(child)) {
setproctitle("idmap child");
}
@@ -1760,6 +1793,10 @@
messaging_register(global_messaging_context(), NULL,
MSG_WINBIND_DISCONNECT_DC,
winbind_msg_disconnect_dc);
+ messaging_register(global_messaging_context(),
+ override_logfile ? NULL : child->logfilename,
+ MSG_SMB_CONF_UPDATED,
+ winbindd_msg_reload_services_child);
primary_domain = find_our_domain();
@@ -1789,7 +1826,7 @@
* We are in idmap child, make sure that we set the
* check_online_event to bring primary domain online.
*/
- if (child == idmap_child()) {
+ if (is_idmap_child(child)) {
set_domain_online_request(primary_domain);
}
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_dual_srv.c samba-4.13.14+dfsg/source3/winbindd/winbindd_dual_srv.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_dual_srv.c 2020-08-14 08:48:07.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_dual_srv.c 2021-11-08 11:29:14.000000000 +0000
@@ -200,7 +200,7 @@
sid_compose(m->sid, d->sid, ids[i].rid);
m->status = ID_UNKNOWN;
- m->xid = (struct unixid) { .type = ids[i].type };
+ m->xid = (struct unixid) { .type = ids[i].type_hint };
}
status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
@@ -227,6 +227,12 @@
for (i=0; istatus == ID_REQUIRE_TYPE) {
+ ids[i].xid.id = UINT32_MAX;
+ ids[i].xid.type = ID_TYPE_WB_REQUIRE_TYPE;
+ continue;
+ }
+
if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
DBG_DEBUG("id %"PRIu32" is out of range "
"%"PRIu32"-%"PRIu32" for domain %s\n",
@@ -276,8 +282,12 @@
}
for (i=0; iin.num_ids; i++) {
- r->out.xids[i] = maps[i]->xid;
- sid_copy(&r->out.sids[i], maps[i]->sid);
+ if (maps[i]->status == ID_MAPPED) {
+ r->out.xids[i] = maps[i]->xid;
+ sid_copy(&r->out.sids[i], maps[i]->sid);
+ } else {
+ r->out.sids[i] = (struct dom_sid) { 0 };
+ }
}
TALLOC_FREE(maps);
@@ -930,6 +940,13 @@
union netr_Validation *validation = NULL;
bool interactive = false;
+ /*
+ * Make sure we start with authoritative=true,
+ * it will only set to false if we don't know the
+ * domain.
+ */
+ r->out.authoritative = true;
+
domain = wb_child_domain();
if (domain == NULL) {
return NT_STATUS_REQUEST_NOT_ACCEPTED;
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_getgroups.c samba-4.13.14+dfsg/source3/winbindd/winbindd_getgroups.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_getgroups.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_getgroups.c 2021-11-08 11:29:14.000000000 +0000
@@ -202,6 +202,13 @@
case ID_TYPE_BOTH:
include_gid = true;
break;
+ case ID_TYPE_WB_REQUIRE_TYPE:
+ /*
+ * these are internal between winbindd
+ * parent and child.
+ */
+ smb_panic(__location__);
+ break;
}
if (!include_gid) {
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd.h samba-4.13.14+dfsg/source3/winbindd/winbindd.h
--- samba-4.13.3+dfsg/source3/winbindd/winbindd.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd.h 2021-11-08 11:29:14.000000000 +0000
@@ -189,6 +189,19 @@
struct winbindd_domain *prev, *next;
};
+struct wb_parent_idmap_config_dom {
+ unsigned low_id;
+ unsigned high_id;
+ const char *name;
+ struct dom_sid sid;
+};
+
+struct wb_parent_idmap_config {
+ struct tevent_queue *queue;
+ uint32_t num_doms;
+ struct wb_parent_idmap_config_dom *doms;
+};
+
struct wb_acct_info {
const char *acct_name; /* account name */
const char *acct_desc; /* account name */
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_idmap.c samba-4.13.14+dfsg/source3/winbindd/winbindd_idmap.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_idmap.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_idmap.c 2021-11-08 11:29:14.000000000 +0000
@@ -23,19 +23,47 @@
#include "includes.h"
#include "winbindd.h"
+#include "../libcli/security/security.h"
+#include "passdb/lookup_sid.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
static struct winbindd_child static_idmap_child;
+/*
+ * Map idmap ranges to domain names, taken from smb.conf. This is
+ * stored in the parent winbind and used to assemble xids2sids/sids2xids calls
+ * into per-idmap-domain chunks.
+ */
+static struct wb_parent_idmap_config static_parent_idmap_config;
+
struct winbindd_child *idmap_child(void)
{
return &static_idmap_child;
}
+bool is_idmap_child(const struct winbindd_child *child)
+{
+ if (child == &static_idmap_child) {
+ return true;
+ }
+
+ return false;
+}
+
+pid_t idmap_child_pid(void)
+{
+ return static_idmap_child.pid;
+}
+
struct dcerpc_binding_handle *idmap_child_handle(void)
{
+ /*
+ * The caller needs to use wb_parent_idmap_setup_send/recv
+ * before talking to the idmap child!
+ */
+ SMB_ASSERT(static_parent_idmap_config.num_doms > 0);
return static_idmap_child.binding_handle;
}
@@ -53,9 +81,353 @@
}
};
+static void init_idmap_child_done(struct tevent_req *subreq);
+
void init_idmap_child(void)
{
- setup_child(NULL, &static_idmap_child,
- idmap_dispatch_table,
- "log.winbindd", "idmap");
+ struct tevent_req *subreq = NULL;
+
+ subreq = wb_parent_idmap_setup_send(global_event_context(),
+ global_event_context());
+ if (subreq == NULL) {
+ /*
+ * This is only an optimization, so we're free to
+ * to ignore errors
+ */
+ DBG_ERR("wb_parent_idmap_setup_send() failed\n");
+ return;
+ }
+ tevent_req_set_callback(subreq, init_idmap_child_done, NULL);
+ DBG_DEBUG("wb_parent_idmap_setup_send() started\n");
+}
+
+static void init_idmap_child_done(struct tevent_req *subreq)
+{
+ const struct wb_parent_idmap_config *cfg = NULL;
+ NTSTATUS status;
+
+ status = wb_parent_idmap_setup_recv(subreq, &cfg);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * This is only an optimization, so we're free to
+ * to ignore errors
+ */
+ DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n",
+ nt_errstr(status));
+ return;
+ }
+
+ DBG_DEBUG("wb_parent_idmap_setup_recv() finished\n");
+}
+
+struct wb_parent_idmap_setup_state {
+ struct tevent_context *ev;
+ struct wb_parent_idmap_config *cfg;
+ size_t dom_idx;
+};
+
+static void wb_parent_idmap_setup_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct wb_parent_idmap_setup_state *state =
+ tevent_req_data(req,
+ struct wb_parent_idmap_setup_state);
+
+ if (req_state == TEVENT_REQ_DONE) {
+ state->cfg = NULL;
+ return;
+ }
+
+ if (state->cfg == NULL) {
+ return;
+ }
+
+ state->cfg->num_doms = 0;
+ TALLOC_FREE(state->cfg->doms);
+ state->cfg = NULL;
+}
+
+static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq);
+static bool wb_parent_idmap_setup_scan_config(const char *domname,
+ void *private_data);
+static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req);
+static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq);
+
+struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev)
+{
+ struct tevent_req *req = NULL;
+ struct wb_parent_idmap_setup_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct wb_parent_idmap_setup_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ *state = (struct wb_parent_idmap_setup_state) {
+ .ev = ev,
+ .cfg = &static_parent_idmap_config,
+ .dom_idx = 0,
+ };
+
+ if (state->cfg->queue == NULL) {
+ state->cfg->queue = tevent_queue_create(NULL,
+ "wb_parent_idmap_config_queue");
+ if (tevent_req_nomem(state->cfg->queue, req)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq,
+ wb_parent_idmap_setup_queue_wait_done,
+ req);
+
+ return req;
+}
+
+static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct wb_parent_idmap_setup_state *state =
+ tevent_req_data(req,
+ struct wb_parent_idmap_setup_state);
+ bool ok;
+
+ /*
+ * Note we don't call TALLOC_FREE(subreq) here in order to block the
+ * queue until tevent_req_received() in wb_parent_idmap_setup_recv()
+ * will destroy it implicitly.
+ */
+ ok = tevent_queue_wait_recv(subreq);
+ if (!ok) {
+ DBG_ERR("tevent_queue_wait_recv() failed\n");
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ if (state->cfg->num_doms != 0) {
+ /*
+ * If we're not the first one we're done.
+ */
+ tevent_req_done(req);
+ return;
+ }
+
+ /*
+ * From this point we start changing state->cfg,
+ * which is &static_parent_idmap_config,
+ * so we better setup a cleanup function
+ * to undo the changes on failure.
+ */
+ tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup);
+
+ /*
+ * Put the passdb idmap domain first. We always need to try
+ * there first.
+ */
+ state->cfg->doms = talloc_zero_array(NULL,
+ struct wb_parent_idmap_config_dom,
+ 1);
+ if (tevent_req_nomem(state->cfg->doms, req)) {
+ return;
+ }
+ state->cfg->doms[0].low_id = 0;
+ state->cfg->doms[0].high_id = UINT_MAX;
+ state->cfg->doms[0].name = talloc_strdup(state->cfg->doms,
+ get_global_sam_name());
+ if (tevent_req_nomem(state->cfg->doms[0].name, req)) {
+ return;
+ }
+ state->cfg->num_doms += 1;
+
+ lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req);
+ if (!tevent_req_is_in_progress(req)) {
+ return;
+ }
+
+ wb_parent_idmap_setup_lookupname_next(req);
+}
+
+static bool wb_parent_idmap_setup_scan_config(const char *domname,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct wb_parent_idmap_setup_state *state =
+ tevent_req_data(req,
+ struct wb_parent_idmap_setup_state);
+ struct wb_parent_idmap_config_dom *map = NULL;
+ size_t i;
+ const char *range;
+ unsigned low_id, high_id;
+ int ret;
+
+ range = idmap_config_const_string(domname, "range", NULL);
+ if (range == NULL) {
+ DBG_DEBUG("No range for domain %s found\n", domname);
+ return false;
+ }
+
+ ret = sscanf(range, "%u - %u", &low_id, &high_id);
+ if (ret != 2) {
+ DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
+ range, domname);
+ return false;
+ }
+
+ if (low_id > high_id) {
+ DBG_DEBUG("Invalid range %u - %u for domain %s\n",
+ low_id, high_id, domname);
+ return false;
+ }
+
+ for (i=0; icfg->num_doms; i++) {
+ if (strequal(domname, state->cfg->doms[i].name)) {
+ map = &state->cfg->doms[i];
+ break;
+ }
+ }
+
+ if (map == NULL) {
+ struct wb_parent_idmap_config_dom *tmp;
+ char *name;
+
+ name = talloc_strdup(state, domname);
+ if (name == NULL) {
+ DBG_ERR("talloc failed\n");
+ return false;
+ }
+
+ tmp = talloc_realloc(
+ NULL, state->cfg->doms, struct wb_parent_idmap_config_dom,
+ state->cfg->num_doms+1);
+ if (tmp == NULL) {
+ DBG_ERR("talloc failed\n");
+ return false;
+ }
+ state->cfg->doms = tmp;
+
+ map = &state->cfg->doms[state->cfg->num_doms];
+ state->cfg->num_doms += 1;
+ ZERO_STRUCTP(map);
+ map->name = talloc_move(state->cfg->doms, &name);
+ }
+
+ map->low_id = low_id;
+ map->high_id = high_id;
+
+ return false;
+}
+
+static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req)
+{
+ struct wb_parent_idmap_setup_state *state =
+ tevent_req_data(req,
+ struct wb_parent_idmap_setup_state);
+ struct wb_parent_idmap_config_dom *dom =
+ &state->cfg->doms[state->dom_idx];
+ struct tevent_req *subreq = NULL;
+
+ next_domain:
+ if (state->dom_idx == state->cfg->num_doms) {
+ /*
+ * We're done, so start the idmap child
+ */
+ setup_child(NULL, &static_idmap_child,
+ idmap_dispatch_table,
+ "log.winbindd", "idmap");
+ tevent_req_done(req);
+ return;
+ }
+
+ if (strequal(dom->name, "*")) {
+ state->dom_idx++;
+ goto next_domain;
+ }
+
+ subreq = wb_lookupname_send(state,
+ state->ev,
+ dom->name,
+ dom->name,
+ "",
+ LOOKUP_NAME_NO_NSS);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ wb_parent_idmap_setup_lookupname_done,
+ req);
+}
+
+static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct wb_parent_idmap_setup_state *state =
+ tevent_req_data(req,
+ struct wb_parent_idmap_setup_state);
+ struct wb_parent_idmap_config_dom *dom =
+ &state->cfg->doms[state->dom_idx];
+ enum lsa_SidType type;
+ NTSTATUS status;
+
+ status = wb_lookupname_recv(subreq, &dom->sid, &type);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Lookup domain name '%s' failed '%s'\n",
+ dom->name,
+ nt_errstr(status));
+
+ state->dom_idx++;
+ wb_parent_idmap_setup_lookupname_next(req);
+ return;
+ }
+
+ if (type != SID_NAME_DOMAIN) {
+ struct dom_sid_buf buf;
+
+ DBG_ERR("SID %s for idmap domain name '%s' "
+ "not a domain SID\n",
+ dom_sid_str_buf(&dom->sid, &buf),
+ dom->name);
+
+ ZERO_STRUCT(dom->sid);
+ }
+
+ state->dom_idx++;
+ wb_parent_idmap_setup_lookupname_next(req);
+
+ return;
+}
+
+NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req,
+ const struct wb_parent_idmap_config **_cfg)
+{
+ const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config;
+ NTSTATUS status;
+
+ *_cfg = NULL;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ /*
+ * Note state->cfg is already set to NULL by
+ * wb_parent_idmap_setup_cleanup()
+ */
+ *_cfg = cfg;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
}
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_irpc.c samba-4.13.14+dfsg/source3/winbindd/winbindd_irpc.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_irpc.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_irpc.c 2021-11-08 11:29:14.000000000 +0000
@@ -141,6 +141,13 @@
const char *target_domain_name = NULL;
const char *account_name = NULL;
+ /*
+ * Make sure we start with authoritative=true,
+ * it will only set to false if we don't know the
+ * domain.
+ */
+ req->out.authoritative = true;
+
switch (req->in.logon_level) {
case NetlogonInteractiveInformation:
case NetlogonServiceInformation:
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_misc.c samba-4.13.14+dfsg/source3/winbindd/winbindd_misc.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_misc.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_misc.c 2021-11-08 11:29:14.000000000 +0000
@@ -75,7 +75,7 @@
case SEC_CHAN_BDC: {
int role = lp_server_role();
- if (role == ROLE_DOMAIN_PDC) {
+ if (role == ROLE_DOMAIN_PDC || role == ROLE_IPA_DC) {
s = talloc_strdup(mem_ctx, "PDC");
if (s == NULL) {
return NULL;
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_pam_auth_crap.c samba-4.13.14+dfsg/source3/winbindd/winbindd_pam_auth_crap.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_pam_auth_crap.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_pam_auth_crap.c 2021-11-08 11:29:14.000000000 +0000
@@ -24,6 +24,7 @@
struct winbindd_pam_auth_crap_state {
struct winbindd_response *response;
+ bool authoritative;
uint32_t flags;
};
@@ -45,7 +46,7 @@
if (req == NULL) {
return NULL;
}
-
+ state->authoritative = true;
state->flags = request->flags;
if (state->flags & WBFLAG_PAM_AUTH_PAC) {
@@ -124,6 +125,11 @@
domain = find_auth_domain(request->flags, auth_domain);
if (domain == NULL) {
+ /*
+ * We don't know the domain so
+ * we're not authoritative
+ */
+ state->authoritative = false;
tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
return tevent_req_post(req, ev);
}
@@ -184,6 +190,7 @@
if (tevent_req_is_nterror(req, &status)) {
set_auth_errors(response, status);
+ response->data.auth.authoritative = state->authoritative;
return status;
}
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_pam.c samba-4.13.14+dfsg/source3/winbindd/winbindd_pam.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_pam.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_pam.c 2021-11-08 11:29:14.000000000 +0000
@@ -1797,7 +1797,7 @@
{
fstring name_namespace, name_domain, name_user;
NTSTATUS result;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uint32_t flags = 0;
uint16_t validation_level = 0;
union netr_Validation *validation = NULL;
@@ -2403,6 +2403,15 @@
goto done;
}
+ if (!is_allowed_domain(info3->base.logon_domain.string)) {
+ DBG_NOTICE("Authentication failed for user [%s] "
+ "from firewalled domain [%s]\n",
+ info3->base.account_name.string,
+ info3->base.logon_domain.string);
+ result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
+ goto done;
+ }
+
result = append_auth_data(state->mem_ctx, state->response,
state->request->flags,
validation_level,
@@ -2442,6 +2451,13 @@
result = NT_STATUS_NO_LOGON_SERVERS;
}
+ /*
+ * Here we don't alter
+ * state->response->data.auth.authoritative based
+ * on the servers response
+ * as we don't want a fallback to the local sam
+ * for interactive PAM logons
+ */
set_auth_errors(state->response, result);
DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
@@ -2656,7 +2672,7 @@
const char *name_domain = NULL;
const char *workstation;
uint64_t logon_id = 0;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uint32_t flags = 0;
uint16_t validation_level;
union netr_Validation *validation = NULL;
@@ -2729,7 +2745,6 @@
&validation_level,
&validation);
if (!NT_STATUS_IS_OK(result)) {
- state->response->data.auth.authoritative = authoritative;
goto done;
}
@@ -2756,6 +2771,15 @@
goto done;
}
+ if (!is_allowed_domain(info3->base.logon_domain.string)) {
+ DBG_NOTICE("Authentication failed for user [%s] "
+ "from firewalled domain [%s]\n",
+ info3->base.account_name.string,
+ info3->base.logon_domain.string);
+ result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
+ goto done;
+ }
+
result = append_auth_data(state->mem_ctx, state->response,
state->request->flags,
validation_level,
@@ -2773,6 +2797,8 @@
}
set_auth_errors(state->response, result);
+ state->response->data.auth.authoritative = authoritative;
+
/*
* Log the winbind pam authentication, the logon_id will tie this to
* any of the logons invoked from this request.
@@ -2824,6 +2850,14 @@
goto done;
}
+ if (!is_allowed_domain(domain)) {
+ DBG_NOTICE("Authentication failed for user [%s] "
+ "from firewalled domain [%s]\n",
+ user, domain);
+ result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
+ goto done;
+ }
+
/* Change password */
oldpass = state->request->data.chauthtok.oldpass;
@@ -3085,6 +3119,15 @@
fstrcpy(domain,lp_workgroup());
}
+ if (!is_allowed_domain(domain)) {
+ DBG_NOTICE("Authentication failed for user [%s] "
+ "from firewalled domain [%s]\n",
+ state->request->data.chng_pswd_auth_crap.user,
+ domain);
+ result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
+ goto done;
+ }
+
if(!*user) {
fstrcpy(user, state->request->data.chng_pswd_auth_crap.user);
}
@@ -3287,6 +3330,14 @@
return result;
}
+ if (!is_allowed_domain(info6->base.logon_domain.string)) {
+ DBG_NOTICE("Authentication failed for user [%s] "
+ "from firewalled domain [%s]\n",
+ info6->base.account_name.string,
+ info6->base.logon_domain.string);
+ return NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
+ }
+
result = map_info6_to_validation(state->mem_ctx,
info6,
&validation_level,
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_proto.h samba-4.13.14+dfsg/source3/winbindd/winbindd_proto.h
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_proto.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_proto.h 2021-11-08 11:29:14.000000000 +0000
@@ -31,6 +31,8 @@
bool winbindd_use_idmap_cache(void);
bool winbindd_use_cache(void);
char *get_winbind_priv_pipe_dir(void);
+void winbindd_flush_caches(void);
+bool winbindd_reload_services_file(const char *lfile);
/* The following definitions come from winbindd/winbindd_ads.c */
@@ -341,6 +343,11 @@
uint32_t msg_type,
struct server_id server_id,
DATA_BLOB *data);
+void winbindd_msg_reload_services_parent(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data);
NTSTATUS winbindd_reinit_after_fork(const struct winbindd_child *myself,
const char *logfilename);
struct winbindd_domain *wb_child_domain(void);
@@ -357,8 +364,15 @@
/* The following definitions come from winbindd/winbindd_idmap.c */
+struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev);
+NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req,
+ const struct wb_parent_idmap_config **_cfg);
+
void init_idmap_child(void);
struct winbindd_child *idmap_child(void);
+bool is_idmap_child(const struct winbindd_child *child);
+pid_t idmap_child_pid(void);
struct dcerpc_binding_handle *idmap_child_handle(void);
struct idmap_domain *idmap_find_domain_with_sid(const char *domname,
const struct dom_sid *sid);
diff -Nru samba-4.13.3+dfsg/source3/winbindd/winbindd_util.c samba-4.13.14+dfsg/source3/winbindd/winbindd_util.c
--- samba-4.13.3+dfsg/source3/winbindd/winbindd_util.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/winbindd/winbindd_util.c 2021-11-08 11:29:14.000000000 +0000
@@ -123,8 +123,6 @@
struct winbindd_domain **_d)
{
struct winbindd_domain *domain = NULL;
- const char **ignored_domains = NULL;
- const char **dom = NULL;
int role = lp_server_role();
struct dom_sid_buf buf;
@@ -133,12 +131,8 @@
return NT_STATUS_INVALID_PARAMETER;
}
- ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
- for (dom=ignored_domains; dom && *dom; dom++) {
- if (gen_fnmatch(*dom, domain_name) == 0) {
- DEBUG(2,("Ignoring domain '%s'\n", domain_name));
- return NT_STATUS_NO_SUCH_DOMAIN;
- }
+ if (!is_allowed_domain(domain_name)) {
+ return NT_STATUS_NO_SUCH_DOMAIN;
}
/*
@@ -1257,15 +1251,37 @@
secure_channel_type = SEC_CHAN_LOCAL;
}
- status = add_trusted_domain(get_global_sam_name(),
- NULL,
- get_global_sam_sid(),
- LSA_TRUST_TYPE_DOWNLEVEL,
- trust_flags,
- 0, /* trust_attribs */
- secure_channel_type,
- NULL,
- &domain);
+ if ((pdb_domain_info != NULL) && (role == ROLE_IPA_DC)) {
+ /* This is IPA DC that presents itself as
+ * an Active Directory domain controller to trusted AD
+ * forests but in fact is a classic domain controller.
+ */
+ trust_flags = NETR_TRUST_FLAG_PRIMARY;
+ trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
+ trust_flags |= NETR_TRUST_FLAG_NATIVE;
+ trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
+ trust_flags |= NETR_TRUST_FLAG_TREEROOT;
+ status = add_trusted_domain(pdb_domain_info->name,
+ pdb_domain_info->dns_domain,
+ &pdb_domain_info->sid,
+ LSA_TRUST_TYPE_UPLEVEL,
+ trust_flags,
+ LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
+ secure_channel_type,
+ NULL,
+ &domain);
+ TALLOC_FREE(pdb_domain_info);
+ } else {
+ status = add_trusted_domain(get_global_sam_name(),
+ NULL,
+ get_global_sam_sid(),
+ LSA_TRUST_TYPE_DOWNLEVEL,
+ trust_flags,
+ 0, /* trust_attribs */
+ secure_channel_type,
+ NULL,
+ &domain);
+ }
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("Failed to add local SAM to "
"domain to winbindd's internal list\n");
@@ -2098,6 +2114,13 @@
void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
{
+ /*
+ * Make sure we start with authoritative=true,
+ * it will only set to false if we don't know the
+ * domain.
+ */
+ resp->data.auth.authoritative = true;
+
resp->data.auth.nt_status = NT_STATUS_V(result);
fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
diff -Nru samba-4.13.3+dfsg/source3/wscript samba-4.13.14+dfsg/source3/wscript
--- samba-4.13.3+dfsg/source3/wscript 2020-12-15 07:53:45.000000000 +0000
+++ samba-4.13.14+dfsg/source3/wscript 2021-08-09 07:20:55.000000000 +0000
@@ -1244,7 +1244,7 @@
int main(void)
{
- uint64_t *hint, get_hint;
+ uint64_t hint, get_hint;
int fd;
fd = open(DATA, O_RDONLY | O_CREAT | O_EXCL);
@@ -1252,8 +1252,8 @@
goto err;
}
- *hint = RWH_WRITE_LIFE_SHORT;
- int ret = fcntl(fd, F_SET_RW_HINT, hint);
+ hint = RWH_WRITE_LIFE_SHORT;
+ int ret = fcntl(fd, F_SET_RW_HINT, &hint);
if (ret == -1) {
goto err;
}
@@ -1267,8 +1267,8 @@
goto err;
}
- *hint = RWH_WRITE_LIFE_EXTREME;
- ret = fcntl(fd, F_SET_FILE_RW_HINT, hint);
+ hint = RWH_WRITE_LIFE_EXTREME;
+ ret = fcntl(fd, F_SET_FILE_RW_HINT, &hint);
if (ret == -1) {
goto err;
}
diff -Nru samba-4.13.3+dfsg/source3/wscript_build samba-4.13.14+dfsg/source3/wscript_build
--- samba-4.13.3+dfsg/source3/wscript_build 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source3/wscript_build 2021-11-08 11:29:14.000000000 +0000
@@ -587,11 +587,6 @@
pc_files=[],
vnum='0')
-bld.SAMBA3_LIBRARY('smbd_conn',
- source='smbd/conn.c',
- deps='samba3-util samba-util FNAME_UTIL',
- private_library=True)
-
bld.SAMBA3_SUBSYSTEM('sysquotas',
source='''
lib/sysquotas.c
@@ -706,6 +701,7 @@
smbd/notify_msg.c
smbd/build_options.c
smbd/smb1_utils.c
+ smbd/conn.c
''' + NOTIFY_SOURCES,
deps='''
talloc
@@ -718,7 +714,6 @@
vfs_posixacl
inotify
samba3core
- smbd_conn
param_service
AVAHI
PRINTBASE
@@ -1037,9 +1032,11 @@
rpc_client/init_spoolss.c
''',
deps='''
- RPC_NDR_SPOOLSS
- smbconf
- secrets3''',
+ RPC_NDR_SPOOLSS
+ smbconf
+ secrets3
+ gensec
+ ''',
private_library=True)
bld.SAMBA3_SUBSYSTEM('LIBCLI_WINREG',
diff -Nru samba-4.13.3+dfsg/source4/auth/auth.h samba-4.13.14+dfsg/source4/auth/auth.h
--- samba-4.13.3+dfsg/source4/auth/auth.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/auth.h 2021-11-08 11:29:14.000000000 +0000
@@ -61,10 +61,6 @@
/* Given the user supplied info, check a password */
- NTSTATUS (*check_password)(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx,
- const struct auth_usersupplied_info *user_info,
- struct auth_user_info_dc **interim_info,
- bool *authoritative);
struct tevent_req *(*check_password_send)(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct auth_method_context *ctx,
@@ -73,14 +69,6 @@
TALLOC_CTX *mem_ctx,
struct auth_user_info_dc **interim_info,
bool *authoritative);
-
- /* Lookup a 'session info interim' return based only on the principal or DN */
- NTSTATUS (*get_user_info_dc_principal)(TALLOC_CTX *mem_ctx,
- struct auth4_context *auth_context,
- const char *principal,
- struct ldb_dn *user_dn,
- struct auth_user_info_dc **interim_info);
- uint32_t flags;
};
struct auth_method_context {
diff -Nru samba-4.13.3+dfsg/source4/auth/gensec/gensec_gssapi.c samba-4.13.14+dfsg/source4/auth/gensec/gensec_gssapi.c
--- samba-4.13.3+dfsg/source4/auth/gensec/gensec_gssapi.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/gensec/gensec_gssapi.c 2021-09-22 06:59:39.000000000 +0000
@@ -1167,6 +1167,10 @@
}
}
+ /*
+ * FIXME: input_message_buffer is marked const, but gss_unwrap() may
+ * modify it (see calls to rrc_rotate() in _gssapi_unwrap_cfx()).
+ */
maj_stat = gss_unwrap(&min_stat,
gensec_gssapi_state->gssapi_context,
&input_token,
diff -Nru samba-4.13.3+dfsg/source4/auth/gensec/gensec_krb5.c samba-4.13.14+dfsg/source4/auth/gensec/gensec_krb5.c
--- samba-4.13.3+dfsg/source4/auth/gensec/gensec_krb5.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/gensec/gensec_krb5.c 2021-08-06 12:19:57.000000000 +0000
@@ -149,8 +149,9 @@
struct samba_sockaddr addr;
bool ok;
+ addr.sa_socklen = sizeof(addr.u);
sockaddr_ret = tsocket_address_bsd_sockaddr(
- tlocal_addr, &addr.u.sa, sizeof(addr.u.sa));
+ tlocal_addr, &addr.u.sa, addr.sa_socklen);
if (sockaddr_ret < 0) {
talloc_free(gensec_krb5_state);
return NT_STATUS_INTERNAL_ERROR;
@@ -170,8 +171,9 @@
struct samba_sockaddr addr;
bool ok;
+ addr.sa_socklen = sizeof(addr.u);
sockaddr_ret = tsocket_address_bsd_sockaddr(
- tremote_addr, &addr.u.sa, sizeof(addr.u.sa));
+ tremote_addr, &addr.u.sa, addr.sa_socklen);
if (sockaddr_ret < 0) {
talloc_free(gensec_krb5_state);
return NT_STATUS_INTERNAL_ERROR;
diff -Nru samba-4.13.3+dfsg/source4/auth/gensec/pygensec.c samba-4.13.14+dfsg/source4/auth/gensec/pygensec.c
--- samba-4.13.3+dfsg/source4/auth/gensec/pygensec.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/gensec/pygensec.c 2021-09-22 06:59:39.000000000 +0000
@@ -310,9 +310,13 @@
return NULL;
}
mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
status = gensec_session_info(security, mem_ctx, &info);
if (NT_STATUS_IS_ERR(status)) {
+ talloc_free(mem_ctx);
PyErr_SetNTSTATUS(status);
return NULL;
}
@@ -337,6 +341,9 @@
return NULL;
}
mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
status = gensec_session_key(security, mem_ctx, &session_key);
if (!NT_STATUS_IS_OK(status)) {
@@ -426,9 +433,9 @@
return NULL;
if (gensec_have_feature(security, feature)) {
- return Py_True;
+ Py_RETURN_TRUE;
}
- return Py_False;
+ Py_RETURN_FALSE;
}
static PyObject *py_gensec_set_max_update_size(PyObject *self, PyObject *args)
@@ -461,18 +468,33 @@
PyObject *py_bytes, *result, *py_in;
struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
PyObject *finished_processing;
+ char *data = NULL;
+ Py_ssize_t len;
+ int err;
if (!PyArg_ParseTuple(args, "O", &py_in))
return NULL;
mem_ctx = talloc_new(NULL);
- if (!PyBytes_Check(py_in)) {
- PyErr_Format(PyExc_TypeError, "bytes expected");
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ err = PyBytes_AsStringAndSize(py_in, &data, &len);
+ if (err) {
+ talloc_free(mem_ctx);
return NULL;
}
- in.data = (uint8_t *)PyBytes_AsString(py_in);
- in.length = PyBytes_Size(py_in);
+ /*
+ * Make a copy of the input buffer, as gensec_update may modify its
+ * input argument.
+ */
+ in = data_blob_talloc(mem_ctx, data, len);
+ if (!in.data) {
+ talloc_free(mem_ctx);
+ return PyErr_NoMemory();
+ }
status = gensec_update(security, mem_ctx, in, &out);
@@ -510,8 +532,12 @@
return NULL;
mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
if (!PyBytes_Check(py_in)) {
+ talloc_free(mem_ctx);
PyErr_Format(PyExc_TypeError, "bytes expected");
return NULL;
}
@@ -540,19 +566,33 @@
DATA_BLOB in, out;
PyObject *ret, *py_in;
struct gensec_security *security = pytalloc_get_type(self, struct gensec_security);
+ char *data = NULL;
+ Py_ssize_t len;
+ int err;
if (!PyArg_ParseTuple(args, "O", &py_in))
return NULL;
mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
- if (!PyBytes_Check(py_in)) {
- PyErr_Format(PyExc_TypeError, "bytes expected");
+ err = PyBytes_AsStringAndSize(py_in, &data, &len);
+ if (err) {
+ talloc_free(mem_ctx);
return NULL;
}
- in.data = (uint8_t *)PyBytes_AsString(py_in);
- in.length = PyBytes_Size(py_in);
+ /*
+ * Make a copy of the input buffer, as gensec_unwrap may modify its
+ * input argument.
+ */
+ in = data_blob_talloc(mem_ctx, data, len);
+ if (!in.data) {
+ talloc_free(mem_ctx);
+ return PyErr_NoMemory();
+ }
status = gensec_unwrap(security, mem_ctx, &in, &out);
@@ -599,6 +639,9 @@
pdu.length = pdu_length;
mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ return PyErr_NoMemory();
+ }
status = gensec_sign_packet(security, mem_ctx,
data.data, data.length,
@@ -654,13 +697,13 @@
METH_VARARGS|METH_KEYWORDS|METH_CLASS,
"S.start_server(auth_ctx, settings) -> gensec" },
{ "set_credentials", (PyCFunction)py_gensec_set_credentials, METH_VARARGS,
- "S.start_client(credentials)" },
+ "S.set_credentials(credentials)" },
{ "set_target_hostname", (PyCFunction)py_gensec_set_target_hostname, METH_VARARGS,
- "S.start_target_hostname(target_hostname) \n This sets the Kerberos target hostname to obtain a ticket for." },
+ "S.set_target_hostname(target_hostname) \n This sets the Kerberos target hostname to obtain a ticket for." },
{ "set_target_service", (PyCFunction)py_gensec_set_target_service, METH_VARARGS,
- "S.start_target_service(target_service) \n This sets the Kerberos target service to obtain a ticket for. The default value is 'host'" },
+ "S.set_target_service(target_service) \n This sets the Kerberos target service to obtain a ticket for. The default value is 'host'" },
{ "set_target_service_description", (PyCFunction)py_gensec_set_target_service_description, METH_VARARGS,
- "S.start_target_service_description(target_service_description) \n This description is set server-side and used in authentication and authorization logs. The default value is that provided to set_target_service() or None."},
+ "S.set_target_service_description(target_service_description) \n This description is set server-side and used in authentication and authorization logs. The default value is that provided to set_target_service() or None."},
{ "session_info", (PyCFunction)py_gensec_session_info, METH_NOARGS,
"S.session_info() -> info" },
{ "session_key", (PyCFunction)py_gensec_session_key, METH_NOARGS,
diff -Nru samba-4.13.3+dfsg/source4/auth/ntlm/auth_anonymous.c samba-4.13.14+dfsg/source4/auth/ntlm/auth_anonymous.c
--- samba-4.13.3+dfsg/source4/auth/ntlm/auth_anonymous.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/ntlm/auth_anonymous.c 2021-11-08 11:29:14.000000000 +0000
@@ -20,9 +20,11 @@
*/
#include "includes.h"
+#include
#include "auth/auth.h"
#include "auth/ntlm/auth_proto.h"
#include "param/param.h"
+#include "lib/util/tevent_ntstatus.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
@@ -84,19 +86,65 @@
* anonymou logons to be dealt with in one place. Non-anonymou logons 'fail'
* and pass onto the next module.
**/
-static NTSTATUS anonymous_check_password(struct auth_method_context *ctx,
- TALLOC_CTX *mem_ctx,
- const struct auth_usersupplied_info *user_info,
- struct auth_user_info_dc **_user_info_dc,
- bool *authoritative)
+
+struct anonymous_check_password_state {
+ struct auth_user_info_dc *user_info_dc;
+};
+
+static struct tevent_req *anonymous_check_password_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct auth_method_context *ctx,
+ const struct auth_usersupplied_info *user_info)
+{
+ struct tevent_req *req = NULL;
+ struct anonymous_check_password_state *state = NULL;
+ NTSTATUS status;
+
+ req = tevent_req_create(
+ mem_ctx,
+ &state,
+ struct anonymous_check_password_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ status = auth_anonymous_user_info_dc(
+ state,
+ lpcfg_netbios_name(ctx->auth_ctx->lp_ctx),
+ &state->user_info_dc);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS anonymous_check_password_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct auth_user_info_dc **interim_info,
+ bool *authoritative)
{
- return auth_anonymous_user_info_dc(mem_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx), _user_info_dc);
+ struct anonymous_check_password_state *state = tevent_req_data(
+ req, struct anonymous_check_password_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+ *interim_info = talloc_move(mem_ctx, &state->user_info_dc);
+ tevent_req_received(req);
+ return NT_STATUS_OK;
}
+
static const struct auth_operations anonymous_auth_ops = {
- .name = "anonymous",
- .want_check = anonymous_want_check,
- .check_password = anonymous_check_password
+ .name = "anonymous",
+ .want_check = anonymous_want_check,
+ .check_password_send = anonymous_check_password_send,
+ .check_password_recv = anonymous_check_password_recv,
};
_PUBLIC_ NTSTATUS auth4_anonymous_init(TALLOC_CTX *ctx)
diff -Nru samba-4.13.3+dfsg/source4/auth/ntlm/auth.c samba-4.13.14+dfsg/source4/auth/ntlm/auth.c
--- samba-4.13.3+dfsg/source4/auth/ntlm/auth.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/ntlm/auth.c 2021-11-08 11:29:14.000000000 +0000
@@ -86,48 +86,6 @@
return NT_STATUS_OK;
}
-/****************************************************************************
-Used in the gensec_gssapi and gensec_krb5 server-side code, where the
-PAC isn't available, and for tokenGroups in the DSDB stack.
-
- Supply either a principal or a DN
-****************************************************************************/
-static NTSTATUS auth_generate_session_info_principal(struct auth4_context *auth_ctx,
- TALLOC_CTX *mem_ctx,
- const char *principal,
- struct ldb_dn *user_dn,
- uint32_t session_info_flags,
- struct auth_session_info **session_info)
-{
- NTSTATUS nt_status;
- struct auth_method_context *method;
- struct auth_user_info_dc *user_info_dc;
-
- for (method = auth_ctx->methods; method; method = method->next) {
- if (!method->ops->get_user_info_dc_principal) {
- continue;
- }
-
- nt_status = method->ops->get_user_info_dc_principal(mem_ctx, auth_ctx, principal, user_dn, &user_info_dc);
- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
- continue;
- }
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-
- nt_status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
- user_info_dc,
- user_info_dc->info->account_name,
- session_info_flags, session_info);
- talloc_free(user_info_dc);
-
- return nt_status;
- }
-
- return NT_STATUS_NOT_IMPLEMENTED;
-}
-
/**
* Check a user's Plaintext, LM or NTLM password.
* (sync version)
@@ -169,6 +127,11 @@
/*TODO: create a new event context here! */
ev = auth_ctx->event_ctx;
+ /*
+ * We are authoritative by default
+ */
+ *pauthoritative = 1;
+
subreq = auth_check_password_send(mem_ctx,
ev,
auth_ctx,
@@ -331,7 +294,6 @@
struct auth_check_password_state *state =
tevent_req_data(req, struct auth_check_password_state);
struct tevent_req *subreq = NULL;
- bool authoritative = true;
NTSTATUS status;
if (state->method == NULL) {
@@ -356,47 +318,12 @@
return;
}
- if (state->method->ops->check_password_send != NULL) {
- subreq = state->method->ops->check_password_send(state,
- state->ev,
- state->method,
- state->user_info);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq,
- auth_check_password_done,
- req);
- return;
- }
-
- if (state->method->ops->check_password == NULL) {
- tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
- return;
- }
-
- status = state->method->ops->check_password(state->method,
- state,
- state->user_info,
- &state->user_info_dc,
- &authoritative);
- if (!authoritative ||
- NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
- DEBUG(11,("auth_check_password_send: "
- "%s passes to the next method\n",
- state->method->ops->name));
- state->method = state->method->next;
- auth_check_password_next(req);
- return;
- }
-
- /* the backend has handled the request */
-
- if (tevent_req_nterror(req, status)) {
+ subreq = state->method->ops->check_password_send(
+ state, state->ev, state->method, state->user_info);
+ if (tevent_req_nomem(subreq, req)) {
return;
}
-
- tevent_req_done(req);
+ tevent_req_set_callback(subreq, auth_check_password_done, req);
}
static void auth_check_password_done(struct tevent_req *subreq)
@@ -657,8 +584,11 @@
TALLOC_CTX *tmp_ctx;
if (!pac_blob) {
- return auth_generate_session_info_principal(auth_ctx, mem_ctx, principal_name,
- NULL, session_info_flags, session_info);
+ /*
+ * This should already be catched at the main
+ * gensec layer, but better check twice
+ */
+ return NT_STATUS_INTERNAL_ERROR;
}
tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
@@ -767,6 +697,7 @@
case ROLE_DOMAIN_BDC:
case ROLE_DOMAIN_PDC:
case ROLE_ACTIVE_DIRECTORY_DC:
+ case ROLE_IPA_DC:
auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL);
break;
}
diff -Nru samba-4.13.3+dfsg/source4/auth/ntlm/auth_developer.c samba-4.13.14+dfsg/source4/auth/ntlm/auth_developer.c
--- samba-4.13.3+dfsg/source4/auth/ntlm/auth_developer.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/ntlm/auth_developer.c 2021-11-08 11:29:14.000000000 +0000
@@ -20,9 +20,11 @@
*/
#include "includes.h"
+#include
#include "auth/auth.h"
#include "auth/ntlm/auth_proto.h"
#include "libcli/security/security.h"
+#include "lib/util/tevent_ntstatus.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
@@ -135,10 +137,67 @@
return nt_status;
}
+struct name_to_ntstatus_check_password_state {
+ struct auth_user_info_dc *user_info_dc;
+ bool authoritative;
+};
+
+static struct tevent_req *name_to_ntstatus_check_password_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct auth_method_context *ctx,
+ const struct auth_usersupplied_info *user_info)
+{
+ struct tevent_req *req = NULL;
+ struct name_to_ntstatus_check_password_state *state = NULL;
+ NTSTATUS status;
+
+ req = tevent_req_create(
+ mem_ctx,
+ &state,
+ struct name_to_ntstatus_check_password_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ status = name_to_ntstatus_check_password(
+ ctx,
+ state,
+ user_info,
+ &state->user_info_dc,
+ &state->authoritative);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS name_to_ntstatus_check_password_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct auth_user_info_dc **interim_info,
+ bool *authoritative)
+{
+ struct name_to_ntstatus_check_password_state *state = tevent_req_data(
+ req, struct name_to_ntstatus_check_password_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+ *interim_info = talloc_move(mem_ctx, &state->user_info_dc);
+ *authoritative = state->authoritative;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
static const struct auth_operations name_to_ntstatus_auth_ops = {
.name = "name_to_ntstatus",
.want_check = name_to_ntstatus_want_check,
- .check_password = name_to_ntstatus_check_password
+ .check_password_send = name_to_ntstatus_check_password_send,
+ .check_password_recv = name_to_ntstatus_check_password_recv,
};
_PUBLIC_ NTSTATUS auth4_developer_init(TALLOC_CTX *ctx)
diff -Nru samba-4.13.3+dfsg/source4/auth/ntlm/auth_sam.c samba-4.13.14+dfsg/source4/auth/ntlm/auth_sam.c
--- samba-4.13.3+dfsg/source4/auth/ntlm/auth_sam.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/ntlm/auth_sam.c 2021-11-08 11:29:14.000000000 +0000
@@ -36,6 +36,7 @@
#include "lib/messaging/irpc.h"
#include "libcli/auth/libcli_auth.h"
#include "libds/common/roles.h"
+#include "lib/util/tevent_ntstatus.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
@@ -732,6 +733,68 @@
return NT_STATUS_OK;
}
+struct authsam_check_password_state {
+ struct auth_user_info_dc *user_info_dc;
+ bool authoritative;
+};
+
+static struct tevent_req *authsam_check_password_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct auth_method_context *ctx,
+ const struct auth_usersupplied_info *user_info)
+{
+ struct tevent_req *req = NULL;
+ struct authsam_check_password_state *state = NULL;
+ NTSTATUS status;
+
+ req = tevent_req_create(
+ mem_ctx, &state, struct authsam_check_password_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ /*
+ * authsam_check_password_internals() sets this to false in
+ * the rodc case, otherwise it leaves it untouched. Default to
+ * "we're authoritative".
+ */
+ state->authoritative = true;
+
+ status = authsam_check_password_internals(
+ ctx,
+ state,
+ user_info,
+ &state->user_info_dc,
+ &state->authoritative);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS authsam_check_password_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct auth_user_info_dc **interim_info,
+ bool *authoritative)
+{
+ struct authsam_check_password_state *state = tevent_req_data(
+ req, struct authsam_check_password_state);
+ NTSTATUS status;
+
+ *authoritative = state->authoritative;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+ *interim_info = talloc_move(mem_ctx, &state->user_info_dc);
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx,
TALLOC_CTX *mem_ctx,
const struct auth_usersupplied_info *user_info)
@@ -874,28 +937,18 @@
return NT_STATUS_OK;
}
-/* Wrapper for the auth subsystem pointer */
-static NTSTATUS authsam_get_user_info_dc_principal_wrapper(TALLOC_CTX *mem_ctx,
- struct auth4_context *auth_context,
- const char *principal,
- struct ldb_dn *user_dn,
- struct auth_user_info_dc **user_info_dc)
-{
- return authsam_get_user_info_dc_principal(mem_ctx, auth_context->lp_ctx, auth_context->sam_ctx,
- principal, user_dn, user_info_dc);
-}
static const struct auth_operations sam_ignoredomain_ops = {
.name = "sam_ignoredomain",
.want_check = authsam_ignoredomain_want_check,
- .check_password = authsam_check_password_internals,
- .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper,
+ .check_password_send = authsam_check_password_send,
+ .check_password_recv = authsam_check_password_recv,
};
static const struct auth_operations sam_ops = {
.name = "sam",
.want_check = authsam_want_check,
- .check_password = authsam_check_password_internals,
- .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper,
+ .check_password_send = authsam_check_password_send,
+ .check_password_recv = authsam_check_password_recv,
};
_PUBLIC_ NTSTATUS auth4_sam_init(TALLOC_CTX *);
diff -Nru samba-4.13.3+dfsg/source4/auth/ntlm/auth_simple.c samba-4.13.14+dfsg/source4/auth/ntlm/auth_simple.c
--- samba-4.13.3+dfsg/source4/auth/ntlm/auth_simple.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/ntlm/auth_simple.c 2021-11-08 11:29:14.000000000 +0000
@@ -150,7 +150,7 @@
const struct tsocket_address *local_address = user_info->local_host;
const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
struct auth_user_info_dc *user_info_dc = NULL;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uint32_t flags = 0;
NTSTATUS nt_status;
diff -Nru samba-4.13.3+dfsg/source4/auth/ntlm/auth_unix.c samba-4.13.14+dfsg/source4/auth/ntlm/auth_unix.c
--- samba-4.13.3+dfsg/source4/auth/ntlm/auth_unix.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/ntlm/auth_unix.c 2021-11-08 11:29:14.000000000 +0000
@@ -27,6 +27,7 @@
#include "lib/tsocket/tsocket.h"
#include "../libcli/auth/pam_errors.h"
#include "param/param.h"
+#include "lib/util/tevent_ntstatus.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
@@ -713,46 +714,78 @@
return NT_STATUS_OK;
}
-static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
- TALLOC_CTX *mem_ctx,
- const struct auth_usersupplied_info *user_info,
- struct auth_user_info_dc **user_info_dc,
- bool *authoritative)
-{
- TALLOC_CTX *check_ctx;
- NTSTATUS nt_status;
- struct passwd *pwd;
+struct authunix_check_password_state {
+ struct auth_user_info_dc *user_info_dc;
+};
- if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
- return NT_STATUS_INVALID_PARAMETER;
+static struct tevent_req *authunix_check_password_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct auth_method_context *ctx,
+ const struct auth_usersupplied_info *user_info)
+{
+ struct tevent_req *req = NULL;
+ struct authunix_check_password_state *state = NULL;
+ struct passwd *pwd = NULL;
+ NTSTATUS status;
+
+ req = tevent_req_create(
+ mem_ctx,
+ &state,
+ struct authunix_check_password_state);
+ if (req == NULL) {
+ return NULL;
}
- check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
- if (check_ctx == NULL) {
- return NT_STATUS_NO_MEMORY;
+ if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
}
- nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd);
- if (!NT_STATUS_IS_OK(nt_status)) {
- talloc_free(check_ctx);
- return nt_status;
+ status = check_unix_password(
+ state, ctx->auth_ctx->lp_ctx, user_info, &pwd);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
}
- nt_status = authunix_make_user_info_dc(mem_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx),
- user_info, pwd, user_info_dc);
- if (!NT_STATUS_IS_OK(nt_status)) {
- talloc_free(check_ctx);
- return nt_status;
+ status = authunix_make_user_info_dc(
+ state,
+ lpcfg_netbios_name(ctx->auth_ctx->lp_ctx),
+ user_info,
+ pwd,
+ &state->user_info_dc);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
}
- talloc_free(check_ctx);
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS authunix_check_password_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct auth_user_info_dc **interim_info,
+ bool *authoritative)
+{
+ struct authunix_check_password_state *state = tevent_req_data(
+ req, struct authunix_check_password_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+ *interim_info = talloc_move(mem_ctx, &state->user_info_dc);
+ tevent_req_received(req);
return NT_STATUS_OK;
}
static const struct auth_operations unix_ops = {
- .name = "unix",
- .want_check = authunix_want_check,
- .check_password = authunix_check_password
+ .name = "unix",
+ .want_check = authunix_want_check,
+ .check_password_send = authunix_check_password_send,
+ .check_password_recv = authunix_check_password_recv,
};
_PUBLIC_ NTSTATUS auth4_unix_init(TALLOC_CTX *ctx)
diff -Nru samba-4.13.3+dfsg/source4/auth/ntlm/wscript_build samba-4.13.14+dfsg/source4/auth/ntlm/wscript_build
--- samba-4.13.3+dfsg/source4/auth/ntlm/wscript_build 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/ntlm/wscript_build 2021-11-08 11:29:14.000000000 +0000
@@ -12,7 +12,7 @@
source='auth_anonymous.c',
subsystem='auth4',
init_function='auth4_anonymous_init',
- deps='talloc'
+ deps='tevent'
)
@@ -28,7 +28,7 @@
source='auth_developer.c',
subsystem='auth4',
init_function='auth4_developer_init',
- deps='talloc'
+ deps='tevent'
)
diff -Nru samba-4.13.3+dfsg/source4/auth/sam.c samba-4.13.14+dfsg/source4/auth/sam.c
--- samba-4.13.3+dfsg/source4/auth/sam.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/auth/sam.c 2021-11-08 11:29:14.000000000 +0000
@@ -57,7 +57,10 @@
\
"pwdLastSet", \
"msDS-UserPasswordExpiryTimeComputed", \
- "accountExpires"
+ "accountExpires", \
+ \
+ /* Needed for RODC rule processing */ \
+ "msDS-KrbTgtLinkBL"
const char *krbtgt_attrs[] = {
KRBTGT_ATTRS, NULL
diff -Nru samba-4.13.3+dfsg/source4/dsdb/common/rodc_helper.c samba-4.13.14+dfsg/source4/dsdb/common/rodc_helper.c
--- samba-4.13.3+dfsg/source4/dsdb/common/rodc_helper.c 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/common/rodc_helper.c 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,284 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ common sid helper functions
+
+ Copyright (C) Catalyst.NET Ltd 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "includes.h"
+#include "rpc_server/dcerpc_server.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "source4/dsdb/samdb/samdb.h"
+#include "libcli/security/security.h"
+
+/*
+ see if any SIDs in list1 are in list2
+ */
+bool sid_list_match(uint32_t num_sids1,
+ const struct dom_sid *list1,
+ uint32_t num_sids2,
+ const struct dom_sid *list2)
+{
+ unsigned int i, j;
+ /* do we ever have enough SIDs here to worry about O(n^2) ? */
+ for (i=0; i < num_sids1; i++) {
+ for (j=0; j < num_sids2; j++) {
+ if (dom_sid_equal(&list1[i], &list2[j])) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/*
+ * Return an array of SIDs from a ldb_message given an attribute name assumes
+ * the SIDs are in NDR form (with primary_sid applied on the start).
+ */
+static WERROR samdb_result_sid_array_ndr(struct ldb_context *sam_ctx,
+ struct ldb_message *msg,
+ TALLOC_CTX *mem_ctx,
+ const char *attr,
+ uint32_t *num_sids,
+ struct dom_sid **sids,
+ const struct dom_sid *primary_sid)
+{
+ struct ldb_message_element *el;
+ unsigned int i;
+
+ el = ldb_msg_find_element(msg, attr);
+ if (!el) {
+ *sids = NULL;
+ return WERR_OK;
+ }
+
+ /* Make array long enough for NULL and additional SID */
+ (*sids) = talloc_array(mem_ctx, struct dom_sid,
+ el->num_values + 1);
+ W_ERROR_HAVE_NO_MEMORY(*sids);
+
+ (*sids)[0] = *primary_sid;
+
+ for (i = 0; inum_values; i++) {
+ enum ndr_err_code ndr_err;
+ struct dom_sid sid = { 0, };
+
+ ndr_err = ndr_pull_struct_blob_all_noalloc(&el->values[i], &sid,
+ (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return WERR_INTERNAL_DB_CORRUPTION;
+ }
+ /* Primary SID is already in position zero. */
+ (*sids)[i+1] = sid;
+ }
+
+ *num_sids = i+1;
+
+ return WERR_OK;
+}
+
+/*
+ return an array of SIDs from a ldb_message given an attribute name
+ assumes the SIDs are in extended DN format
+ */
+WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx,
+ struct ldb_message *msg,
+ TALLOC_CTX *mem_ctx,
+ const char *attr,
+ uint32_t *num_sids,
+ struct dom_sid **sids)
+{
+ struct ldb_message_element *el;
+ unsigned int i;
+
+ el = ldb_msg_find_element(msg, attr);
+ if (!el) {
+ *sids = NULL;
+ return WERR_OK;
+ }
+
+ (*sids) = talloc_array(mem_ctx, struct dom_sid, el->num_values + 1);
+ W_ERROR_HAVE_NO_MEMORY(*sids);
+
+ for (i=0; inum_values; i++) {
+ struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, sam_ctx, &el->values[i]);
+ NTSTATUS status;
+ struct dom_sid sid = { 0, };
+
+ status = dsdb_get_extended_dn_sid(dn, &sid, "SID");
+ if (!NT_STATUS_IS_OK(status)) {
+ return WERR_INTERNAL_DB_CORRUPTION;
+ }
+ (*sids)[i] = sid;
+ }
+ *num_sids = i;
+
+ return WERR_OK;
+}
+
+WERROR samdb_confirm_rodc_allowed_to_repl_to_sid_list(struct ldb_context *sam_ctx,
+ const struct dom_sid *rodc_machine_account_sid,
+ struct ldb_message *rodc_msg,
+ struct ldb_message *obj_msg,
+ uint32_t num_token_sids,
+ struct dom_sid *token_sids)
+{
+ uint32_t num_never_reveal_sids, num_reveal_sids;
+ struct dom_sid *never_reveal_sids, *reveal_sids;
+ TALLOC_CTX *frame = talloc_stackframe();
+ WERROR werr;
+ uint32_t rodc_uac;
+
+ /*
+ * We are not allowed to get anyone elses krbtgt secrets (and
+ * in callers that don't shortcut before this, the RODC should
+ * not deal with any krbtgt)
+ */
+ if (samdb_result_dn(sam_ctx, frame,
+ obj_msg, "msDS-KrbTgtLinkBL", NULL)) {
+ TALLOC_FREE(frame);
+ DBG_INFO("Denied attempt to replicate to/act as a RODC krbtgt trust account %s using RODC: %s\n",
+ ldb_dn_get_linearized(obj_msg->dn),
+ ldb_dn_get_linearized(rodc_msg->dn));
+ return WERR_DS_DRA_SECRETS_DENIED;
+ }
+
+ if (ldb_msg_find_attr_as_uint(obj_msg,
+ "userAccountControl", 0) &
+ UF_INTERDOMAIN_TRUST_ACCOUNT) {
+ DBG_INFO("Denied attempt to replicate to/act as a inter-domain trust account %s using RODC: %s\n",
+ ldb_dn_get_linearized(obj_msg->dn),
+ ldb_dn_get_linearized(rodc_msg->dn));
+ TALLOC_FREE(frame);
+ return WERR_DS_DRA_SECRETS_DENIED;
+ }
+
+ /* Be very sure the RODC is really an RODC */
+ rodc_uac = ldb_msg_find_attr_as_uint(rodc_msg,
+ "userAccountControl",
+ 0);
+ if ((rodc_uac & UF_PARTIAL_SECRETS_ACCOUNT)
+ != UF_PARTIAL_SECRETS_ACCOUNT) {
+ DBG_ERR("Attempt to use an RODC account that is not an RODC: %s\n",
+ ldb_dn_get_linearized(rodc_msg->dn));
+ TALLOC_FREE(frame);
+ return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
+ }
+
+ werr = samdb_result_sid_array_dn(sam_ctx, rodc_msg,
+ frame, "msDS-NeverRevealGroup",
+ &num_never_reveal_sids,
+ &never_reveal_sids);
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_ERR("Failed to parse msDS-NeverRevealGroup on %s: %s\n",
+ ldb_dn_get_linearized(rodc_msg->dn),
+ win_errstr(werr));
+ TALLOC_FREE(frame);
+ return WERR_DS_DRA_SECRETS_DENIED;
+ }
+
+ werr = samdb_result_sid_array_dn(sam_ctx, rodc_msg,
+ frame, "msDS-RevealOnDemandGroup",
+ &num_reveal_sids,
+ &reveal_sids);
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_ERR("Failed to parse msDS-RevealOnDemandGroup on %s: %s\n",
+ ldb_dn_get_linearized(rodc_msg->dn),
+ win_errstr(werr));
+ TALLOC_FREE(frame);
+ return WERR_DS_DRA_SECRETS_DENIED;
+ }
+
+ /* The RODC can replicate and print tickets for itself. */
+ if (dom_sid_equal(&token_sids[0], rodc_machine_account_sid)) {
+ TALLOC_FREE(frame);
+ return WERR_OK;
+ }
+
+ if (never_reveal_sids &&
+ sid_list_match(num_token_sids,
+ token_sids,
+ num_never_reveal_sids,
+ never_reveal_sids)) {
+ TALLOC_FREE(frame);
+ return WERR_DS_DRA_SECRETS_DENIED;
+ }
+
+ if (reveal_sids &&
+ sid_list_match(num_token_sids,
+ token_sids,
+ num_reveal_sids,
+ reveal_sids)) {
+ TALLOC_FREE(frame);
+ return WERR_OK;
+ }
+
+ TALLOC_FREE(frame);
+ return WERR_DS_DRA_SECRETS_DENIED;
+
+}
+
+/*
+ * This is a wrapper for the above that pulls in the tokenGroups
+ * rather than relying on the caller providing those
+ */
+WERROR samdb_confirm_rodc_allowed_to_repl_to(struct ldb_context *sam_ctx,
+ struct dom_sid *rodc_machine_account_sid,
+ struct ldb_message *rodc_msg,
+ struct ldb_message *obj_msg)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ WERROR werr;
+ uint32_t num_token_sids;
+ struct dom_sid *token_sids;
+ const struct dom_sid *object_sid = NULL;
+
+ object_sid = samdb_result_dom_sid(frame,
+ obj_msg,
+ "objectSid");
+ if (object_sid == NULL) {
+ return WERR_DS_DRA_BAD_DN;
+ }
+
+ /*
+ * The SID list needs to include itself as well as the tokenGroups.
+ *
+ * TODO determine if sIDHistory is required for this check
+ */
+ werr = samdb_result_sid_array_ndr(sam_ctx,
+ obj_msg,
+ frame, "tokenGroups",
+ &num_token_sids,
+ &token_sids,
+ object_sid);
+ if (!W_ERROR_IS_OK(werr) || token_sids==NULL) {
+ DBG_ERR("Failed to get tokenGroups on %s to confirm access via RODC %s: %s\n",
+ ldb_dn_get_linearized(obj_msg->dn),
+ ldb_dn_get_linearized(rodc_msg->dn),
+ win_errstr(werr));
+ return WERR_DS_DRA_SECRETS_DENIED;
+ }
+
+ werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(sam_ctx,
+ rodc_machine_account_sid,
+ rodc_msg,
+ obj_msg,
+ num_token_sids,
+ token_sids);
+ TALLOC_FREE(frame);
+ return werr;
+}
diff -Nru samba-4.13.3+dfsg/source4/dsdb/common/util.c samba-4.13.14+dfsg/source4/dsdb/common/util.c
--- samba-4.13.3+dfsg/source4/dsdb/common/util.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/common/util.c 2021-11-08 11:29:14.000000000 +0000
@@ -1179,6 +1179,17 @@
return new_dn;
}
+struct ldb_dn *samdb_extended_rights_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
+{
+ struct ldb_dn *new_dn;
+
+ new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
+ if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Extended-Rights")) {
+ talloc_free(new_dn);
+ return NULL;
+ }
+ return new_dn;
+}
/*
work out the domain sid for the current open ldb
*/
diff -Nru samba-4.13.3+dfsg/source4/dsdb/pydsdb.c samba-4.13.14+dfsg/source4/dsdb/pydsdb.c
--- samba-4.13.3+dfsg/source4/dsdb/pydsdb.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/pydsdb.c 2021-11-08 11:29:14.000000000 +0000
@@ -33,6 +33,7 @@
#include "lib/util/dlinklist.h"
#include "dsdb/kcc/garbage_collect_tombstones.h"
#include "dsdb/kcc/scavenge_dns_records.h"
+#include "libds/common/flag_mapping.h"
/* FIXME: These should be in a header file somewhere */
@@ -1400,6 +1401,30 @@
return pylist;
}
+static PyObject *py_dsdb_user_account_control_flag_bit_to_string(PyObject *self, PyObject *args)
+{
+ const char *str;
+ long long uf;
+ if (!PyArg_ParseTuple(args, "L", &uf)) {
+ return NULL;
+ }
+
+ if (uf > UINT32_MAX) {
+ return PyErr_Format(PyExc_OverflowError, "No UF_ flags are over UINT32_MAX");
+ }
+ if (uf < 0) {
+ return PyErr_Format(PyExc_KeyError, "No UF_ flags are less then zero");
+ }
+
+ str = dsdb_user_account_control_flag_bit_to_string(uf);
+ if (str == NULL) {
+ return PyErr_Format(PyExc_KeyError,
+ "No such UF_ flag 0x%08x",
+ (unsigned int)uf);
+ }
+ return PyUnicode_FromString(str);
+}
+
static PyMethodDef py_dsdb_methods[] = {
{ "_samdb_server_site_name", (PyCFunction)py_samdb_server_site_name,
METH_VARARGS, "Get the server site name as a string"},
@@ -1479,6 +1504,11 @@
"_dsdb_allocate_rid(samdb)"
" -> RID" },
{ "_dsdb_load_udv_v2", (PyCFunction)py_dsdb_load_udv_v2, METH_VARARGS, NULL },
+ { "user_account_control_flag_bit_to_string",
+ (PyCFunction)py_dsdb_user_account_control_flag_bit_to_string,
+ METH_VARARGS,
+ "user_account_control_flag_bit_to_string(bit)"
+ " -> string name" },
{0}
};
diff -Nru samba-4.13.3+dfsg/source4/dsdb/samdb/cracknames.c samba-4.13.14+dfsg/source4/dsdb/samdb/cracknames.c
--- samba-4.13.3+dfsg/source4/dsdb/samdb/cracknames.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/samdb/cracknames.c 2021-11-08 11:29:14.000000000 +0000
@@ -72,13 +72,19 @@
info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
return WERR_OK;
-}
+}
-static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, struct ldb_context *ldb_ctx,
+static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(struct ldb_context *ldb_ctx,
TALLOC_CTX *mem_ctx,
const char *alias_from,
char **alias_to)
{
+ /*
+ * Some of the logic of this function is mirrored in find_spn_alias()
+ * in source4/dsdb.samdb/ldb_modules/samldb.c. If you change this to
+ * not return the first matched alias, you will need to rethink that
+ * function too.
+ */
unsigned int i;
int ret;
struct ldb_result *res;
@@ -99,10 +105,12 @@
service_dn = ldb_dn_new(tmp_ctx, ldb_ctx, "CN=Directory Service,CN=Windows NT,CN=Services");
if ( ! ldb_dn_add_base(service_dn, ldb_get_config_basedn(ldb_ctx))) {
+ talloc_free(tmp_ctx);
return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
}
service_dn_str = ldb_dn_alloc_linearized(tmp_ctx, service_dn);
if ( ! service_dn_str) {
+ talloc_free(tmp_ctx);
return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
}
@@ -111,13 +119,15 @@
if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
DEBUG(1, ("ldb_search: dn: %s not found: %s\n", service_dn_str, ldb_errstring(ldb_ctx)));
+ talloc_free(tmp_ctx);
return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
} else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str));
+ talloc_free(tmp_ctx);
return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
} else if (res->count != 1) {
- talloc_free(res);
DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str));
+ talloc_free(tmp_ctx);
return DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
}
@@ -215,8 +225,7 @@
dns_name = (const char *)component->data;
/* MAP it */
- namestatus = LDB_lookup_spn_alias(smb_krb5_context->krb5_context,
- sam_ctx, mem_ctx,
+ namestatus = LDB_lookup_spn_alias(sam_ctx, mem_ctx,
service, &new_service);
if (namestatus == DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
diff -Nru samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/acl.c samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/acl.c
--- samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/acl.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/acl.c 2021-11-08 11:29:14.000000000 +0000
@@ -653,9 +653,14 @@
return LDB_SUCCESS;
}
+/*
+ * Passing in 'el' is critical, we want to check all the values.
+ *
+ */
static int acl_check_spn(TALLOC_CTX *mem_ctx,
struct ldb_module *module,
struct ldb_request *req,
+ const struct ldb_message_element *el,
struct security_descriptor *sd,
struct dom_sid *sid,
const struct dsdb_attribute *attr,
@@ -667,7 +672,6 @@
struct ldb_context *ldb = ldb_module_get_ctx(module);
struct ldb_result *acl_res;
struct ldb_result *netbios_res;
- struct ldb_message_element *el;
struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx);
uint32_t userAccountControl;
const char *samAccountName;
@@ -698,12 +702,17 @@
return LDB_SUCCESS;
}
- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
+ ret = acl_check_extended_right(tmp_ctx,
+ module,
+ req,
+ objectclass,
+ sd,
+ acl_user_token(module),
GUID_DRS_VALIDATE_SPN,
SEC_ADS_SELF_WRITE,
sid);
- if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
+ if (ret != LDB_SUCCESS) {
dsdb_acl_debug(sd, acl_user_token(module),
req->op.mod.message->dn,
true,
@@ -712,6 +721,23 @@
return ret;
}
+ /*
+ * If we have "validated write spn", allow delete of any
+ * existing value (this keeps constrained delete to the same
+ * rules as unconstrained)
+ */
+ if (req->operation == LDB_MODIFY) {
+ /*
+ * If not add or replace (eg delete),
+ * return success
+ */
+ if ((el->flags
+ & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0) {
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+ }
+ }
+
ret = dsdb_module_search_dn(module, tmp_ctx,
&acl_res, req->op.mod.message->dn,
acl_attrs,
@@ -740,13 +766,6 @@
netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL);
- el = ldb_msg_find_element(req->op.mod.message, "servicePrincipalName");
- if (!el) {
- talloc_free(tmp_ctx);
- return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
- "Error finding element for servicePrincipalName.");
- }
-
/* NTDSDSA objectGuid of object we are checking SPN for */
if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx,
@@ -911,7 +930,7 @@
return ldb_next_request(module, req);
}
-/* ckecks if modifications are allowed on "Member" attribute */
+/* checks if modifications are allowed on "Member" attribute */
static int acl_check_self_membership(TALLOC_CTX *mem_ctx,
struct ldb_module *module,
struct ldb_request *req,
@@ -925,6 +944,16 @@
struct ldb_context *ldb = ldb_module_get_ctx(module);
struct ldb_dn *user_dn;
struct ldb_message_element *member_el;
+ const struct ldb_message *msg = NULL;
+
+ if (req->operation == LDB_MODIFY) {
+ msg = req->op.mod.message;
+ } else if (req->operation == LDB_ADD) {
+ msg = req->op.add.message;
+ } else {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
/* if we have wp, we can do whatever we like */
if (acl_check_access_on_attribute(module,
mem_ctx,
@@ -935,13 +964,13 @@
return LDB_SUCCESS;
}
/* if we are adding/deleting ourselves, check for self membership */
- ret = dsdb_find_dn_by_sid(ldb, mem_ctx,
- &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX],
+ ret = dsdb_find_dn_by_sid(ldb, mem_ctx,
+ &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX],
&user_dn);
if (ret != LDB_SUCCESS) {
return ret;
}
- member_el = ldb_msg_find_element(req->op.mod.message, "member");
+ member_el = ldb_msg_find_element(msg, "member");
if (!member_el) {
return ldb_operr(ldb);
}
@@ -955,13 +984,18 @@
return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
}
}
- ret = acl_check_extended_right(mem_ctx, sd, acl_user_token(module),
+ ret = acl_check_extended_right(mem_ctx,
+ module,
+ req,
+ objectclass,
+ sd,
+ acl_user_token(module),
GUID_DRS_SELF_MEMBERSHIP,
SEC_ADS_SELF_WRITE,
sid);
if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
dsdb_acl_debug(sd, acl_user_token(module),
- req->op.mod.message->dn,
+ msg->dn,
true,
10);
}
@@ -1021,6 +1055,9 @@
* so we don't have to strict verification of the input.
*/
ret = acl_check_extended_right(tmp_ctx,
+ module,
+ req,
+ objectclass,
sd,
acl_user_token(module),
GUID_DRS_USER_CHANGE_PASSWORD,
@@ -1044,7 +1081,12 @@
* the only caller is samdb_set_password_internal(),
* so we don't have to strict verification of the input.
*/
- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
+ ret = acl_check_extended_right(tmp_ctx,
+ module,
+ req,
+ objectclass,
+ sd,
+ acl_user_token(module),
GUID_DRS_FORCE_CHANGE_PASSWORD,
SEC_ADS_CONTROL_ACCESS,
sid);
@@ -1097,7 +1139,12 @@
if (rep_attr_cnt > 0) {
pav->pwd_reset = true;
- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
+ ret = acl_check_extended_right(tmp_ctx,
+ module,
+ req,
+ objectclass,
+ sd,
+ acl_user_token(module),
GUID_DRS_FORCE_CHANGE_PASSWORD,
SEC_ADS_CONTROL_ACCESS,
sid);
@@ -1107,7 +1154,12 @@
if (add_attr_cnt != del_attr_cnt) {
pav->pwd_reset = true;
- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
+ ret = acl_check_extended_right(tmp_ctx,
+ module,
+ req,
+ objectclass,
+ sd,
+ acl_user_token(module),
GUID_DRS_FORCE_CHANGE_PASSWORD,
SEC_ADS_CONTROL_ACCESS,
sid);
@@ -1117,7 +1169,12 @@
if (add_val_cnt == 1 && del_val_cnt == 1) {
pav->pwd_reset = false;
- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
+ ret = acl_check_extended_right(tmp_ctx,
+ module,
+ req,
+ objectclass,
+ sd,
+ acl_user_token(module),
GUID_DRS_USER_CHANGE_PASSWORD,
SEC_ADS_CONTROL_ACCESS,
sid);
@@ -1131,7 +1188,12 @@
if (add_val_cnt == 1 && del_val_cnt == 0) {
pav->pwd_reset = true;
- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module),
+ ret = acl_check_extended_right(tmp_ctx,
+ module,
+ req,
+ objectclass,
+ sd,
+ acl_user_token(module),
GUID_DRS_FORCE_CHANGE_PASSWORD,
SEC_ADS_CONTROL_ACCESS,
sid);
@@ -1462,6 +1524,7 @@
ret = acl_check_spn(tmp_ctx,
module,
req,
+ el,
sd,
sid,
attr,
@@ -1686,6 +1749,9 @@
struct ldb_result *acl_res;
struct security_descriptor *sd = NULL;
struct dom_sid *sid = NULL;
+ const struct dsdb_schema *schema = NULL;
+ const struct dsdb_class *objectclass = NULL;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
static const char *acl_attrs[] = {
"nTSecurityDescriptor",
"objectClass",
@@ -1706,10 +1772,20 @@
ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd);
sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid");
+ schema = dsdb_get_schema(ldb, req);
+ if (!schema) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
if (ret != LDB_SUCCESS || !sd) {
return ldb_operr(ldb_module_get_ctx(module));
}
- return acl_check_extended_right(mem_ctx, sd, acl_user_token(module),
+ return acl_check_extended_right(mem_ctx,
+ module,
+ req,
+ objectclass,
+ sd,
+ acl_user_token(module),
GUID_DRS_REANIMATE_TOMBSTONE,
SEC_ADS_CONTROL_ACCESS, sid);
}
diff -Nru samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/acl_util.c samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/acl_util.c
--- samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/acl_util.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/acl_util.c 2021-11-08 11:29:14.000000000 +0000
@@ -197,6 +197,9 @@
/* checks for validated writes */
int acl_check_extended_right(TALLOC_CTX *mem_ctx,
+ struct ldb_module *module,
+ struct ldb_request *req,
+ const struct dsdb_class *objectclass,
struct security_descriptor *sd,
struct security_token *token,
const char *ext_right,
@@ -208,6 +211,43 @@
uint32_t access_granted;
struct object_tree *root = NULL;
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ static const char *no_attrs[] = { NULL };
+ struct ldb_result *extended_rights_res = NULL;
+ struct ldb_dn *extended_rights_dn = NULL;
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ int ret = 0;
+
+ /*
+ * Find the extended right and check if applies to
+ * the objectclass of the object
+ */
+ extended_rights_dn = samdb_extended_rights_dn(ldb, req);
+ if (!extended_rights_dn) {
+ ldb_set_errstring(ldb,
+ "access_check: CN=Extended-Rights dn could not be generated!");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* Note: we are checking only the structural object class. */
+ ret = dsdb_module_search(module, req, &extended_rights_res,
+ extended_rights_dn, LDB_SCOPE_ONELEVEL,
+ no_attrs,
+ DSDB_FLAG_NEXT_MODULE |
+ DSDB_FLAG_AS_SYSTEM,
+ req,
+ "(&(rightsGuid=%s)(appliesTo=%s))",
+ ext_right,
+ GUID_string(tmp_ctx,
+ &(objectclass->schemaIDGUID)));
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ } else if (extended_rights_res->count == 0 ) {
+ ldb_debug(ldb, LDB_DEBUG_TRACE,
+ "acl_check_extended_right: Could not find appliesTo for %s\n",
+ ext_right);
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
GUID_from_string(ext_right, &right);
diff -Nru samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/dirsync.c samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/dirsync.c
--- samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/dirsync.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/dirsync.c 2021-11-08 11:29:14.000000000 +0000
@@ -1065,7 +1065,9 @@
if (!(dirsync_ctl->flags & LDAP_DIRSYNC_OBJECT_SECURITY)) {
struct dom_sid *sid;
struct security_descriptor *sd = NULL;
- const char *acl_attrs[] = { "nTSecurityDescriptor", "objectSid", NULL };
+ const char *acl_attrs[] = { "nTSecurityDescriptor", "objectSid", "objectClass", NULL };
+ const struct dsdb_schema *schema = NULL;
+ const struct dsdb_class *objectclass = NULL;
/*
* If we don't have the flag and if we have the "replicate directory change" granted
* then we upgrade ourself to system to not be blocked by the acl
@@ -1095,7 +1097,14 @@
if (ret != LDB_SUCCESS) {
return ret;
}
- ret = acl_check_extended_right(dsc, sd, acl_user_token(module), GUID_DRS_GET_CHANGES, SEC_ADS_CONTROL_ACCESS, sid);
+ schema = dsdb_get_schema(ldb, req);
+ if (!schema) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]);
+ ret = acl_check_extended_right(dsc, module, req, objectclass,
+ sd, acl_user_token(module),
+ GUID_DRS_GET_CHANGES, SEC_ADS_CONTROL_ACCESS, sid);
if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
return ret;
diff -Nru samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/objectclass.c samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/objectclass.c
--- samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/objectclass.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/objectclass.c 2021-11-08 11:29:14.000000000 +0000
@@ -811,6 +811,7 @@
struct ldb_message_element *oc_el_entry, *oc_el_change;
struct ldb_val *vals;
struct ldb_message *msg;
+ const struct dsdb_class *current_structural_objectclass;
const struct dsdb_class *objectclass;
unsigned int i, j, k;
bool found;
@@ -830,6 +831,22 @@
return ldb_operr(ldb);
}
+ /*
+ * Get the current new top-most structural object class
+ *
+ * We must not allow this to change
+ */
+
+ current_structural_objectclass
+ = dsdb_get_last_structural_class(ac->schema,
+ oc_el_entry);
+ if (current_structural_objectclass == NULL) {
+ ldb_asprintf_errstring(ldb,
+ "objectclass: cannot find current structural objectclass on %s!",
+ ldb_dn_get_linearized(ac->search_res->message->dn));
+ return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ }
+
/* use a new message structure */
msg = ldb_msg_new(ac);
if (msg == NULL) {
@@ -939,6 +956,25 @@
return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
+ /*
+ * Has (so far, we re-check for each and every
+ * "objectclass" in the message) the structural
+ * objectclass changed?
+ */
+
+ if (objectclass != current_structural_objectclass) {
+ const char *dn
+ = ldb_dn_get_linearized(ac->search_res->message->dn);
+ ldb_asprintf_errstring(ldb,
+ "objectclass: not permitted "
+ "to change the structural "
+ "objectClass on %s [%s] => [%s]!",
+ dn,
+ current_structural_objectclass->lDAPDisplayName,
+ objectclass->lDAPDisplayName);
+ return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ }
+
/* Check for unrelated objectclasses */
ret = check_unrelated_objectclasses(ac->module, ac->schema,
objectclass,
diff -Nru samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/password_hash.c samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/password_hash.c
--- samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/password_hash.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/password_hash.c 2021-11-08 11:29:14.000000000 +0000
@@ -201,6 +201,7 @@
struct ldb_message_element *nthe;
struct ldb_message_element *lmhe;
struct ldb_message_element *sce;
+ int ret;
switch (request->operation) {
case LDB_ADD:
@@ -214,17 +215,26 @@
}
/* nobody must touch password histories and 'supplementalCredentials' */
- nte = dsdb_get_single_valued_attr(msg, "unicodePwd",
- request->operation);
- lme = dsdb_get_single_valued_attr(msg, "dBCSPwd",
- request->operation);
- nthe = dsdb_get_single_valued_attr(msg, "ntPwdHistory",
- request->operation);
- lmhe = dsdb_get_single_valued_attr(msg, "lmPwdHistory",
- request->operation);
- sce = dsdb_get_single_valued_attr(msg, "supplementalCredentials",
- request->operation);
+#define GET_VALUES(el, attr) do { \
+ ret = dsdb_get_expected_new_values(request, \
+ msg, \
+ attr, \
+ &el, \
+ request->operation); \
+ \
+ if (ret != LDB_SUCCESS) { \
+ return ret; \
+ } \
+} while(0)
+
+ GET_VALUES(nte, "unicodePwd");
+ GET_VALUES(lme, "dBCSPwd");
+ GET_VALUES(nthe, "ntPwdHistory");
+ GET_VALUES(lmhe, "lmPwdHistory");
+ GET_VALUES(sce, "supplementalCredentials");
+
+#undef GET_VALUES
#define CHECK_HASH_ELEMENT(e, min, max) do {\
if (e && e->num_values) { \
unsigned int _count; \
@@ -685,8 +695,8 @@
{
struct ldb_context *ldb;
krb5_error_code krb5_ret;
- char *salt_principal = NULL;
- char *salt_data = NULL;
+ krb5_principal salt_principal = NULL;
+ krb5_data salt_data;
krb5_data salt;
krb5_keyblock key;
krb5_data cleartext_data;
@@ -697,11 +707,11 @@
cleartext_data.length = io->n.cleartext_utf8->length;
uac_flags = io->u.userAccountControl & UF_ACCOUNT_TYPE_MASK;
- krb5_ret = smb_krb5_salt_principal(io->ac->status->domain_data.realm,
+ krb5_ret = smb_krb5_salt_principal(io->smb_krb5_context->krb5_context,
+ io->ac->status->domain_data.realm,
io->u.sAMAccountName,
io->u.user_principal_name,
uac_flags,
- io->ac,
&salt_principal);
if (krb5_ret) {
ldb_asprintf_errstring(ldb,
@@ -715,8 +725,10 @@
/*
* create salt from salt_principal
*/
- krb5_ret = smb_krb5_salt_principal2data(io->smb_krb5_context->krb5_context,
- salt_principal, io->ac, &salt_data);
+ krb5_ret = smb_krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
+ salt_principal, &salt_data);
+
+ krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
if (krb5_ret) {
ldb_asprintf_errstring(ldb,
"setup_kerberos_keys: "
@@ -725,12 +737,17 @@
krb5_ret, io->ac));
return LDB_ERR_OPERATIONS_ERROR;
}
- io->g.salt = salt_data;
/* now use the talloced copy of the salt */
- salt.data = discard_const(io->g.salt);
+ salt.data = talloc_strndup(io->ac,
+ (char *)salt_data.data,
+ salt_data.length);
+ io->g.salt = salt.data;
salt.length = strlen(io->g.salt);
+ smb_krb5_free_data_contents(io->smb_krb5_context->krb5_context,
+ &salt_data);
+
/*
* create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
* the salt and the cleartext password
@@ -2210,23 +2227,31 @@
}
if (io->ac->pwd_last_set_bypass) {
- struct ldb_message_element *el1 = NULL;
- struct ldb_message_element *el2 = NULL;
-
+ struct ldb_message_element *el = NULL;
+ size_t i;
+ size_t count = 0;
+ /*
+ * This is a message from pdb_samba_dsdb_replace_by_sam()
+ *
+ * We want to ensure there is only one pwdLastSet element, and
+ * it isn't deleting.
+ */
if (msg == NULL) {
return LDB_ERR_CONSTRAINT_VIOLATION;
}
- el1 = dsdb_get_single_valued_attr(msg, "pwdLastSet",
- io->ac->req->operation);
- if (el1 == NULL) {
- return LDB_ERR_CONSTRAINT_VIOLATION;
+ for (i = 0; i < msg->num_elements; i++) {
+ if (ldb_attr_cmp(msg->elements[i].name,
+ "pwdLastSet") == 0) {
+ count++;
+ el = &msg->elements[i];
+ }
}
- el2 = ldb_msg_find_element(msg, "pwdLastSet");
- if (el2 == NULL) {
+ if (count != 1) {
return LDB_ERR_CONSTRAINT_VIOLATION;
}
- if (el1 != el2) {
+
+ if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
return LDB_ERR_CONSTRAINT_VIOLATION;
}
@@ -2469,6 +2494,59 @@
return LDB_SUCCESS;
}
+ if (io->u.is_krbtgt) {
+ size_t min = 196;
+ size_t max = 255;
+ size_t diff = max - min;
+ size_t len = max;
+ struct ldb_val *krbtgt_utf16 = NULL;
+
+ if (!io->ac->pwd_reset) {
+ return dsdb_module_werror(io->ac->module,
+ LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
+ WERR_DS_ATT_ALREADY_EXISTS,
+ "Password change on krbtgt not permitted!");
+ }
+
+ if (io->n.cleartext_utf16 == NULL) {
+ return dsdb_module_werror(io->ac->module,
+ LDB_ERR_UNWILLING_TO_PERFORM,
+ WERR_DS_INVALID_ATTRIBUTE_SYNTAX,
+ "Password reset on krbtgt requires UTF16!");
+ }
+
+ /*
+ * Instead of taking the callers value,
+ * we just generate a new random value here.
+ *
+ * Include null termination in the array.
+ */
+ if (diff > 0) {
+ size_t tmp;
+
+ generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
+
+ tmp %= diff;
+
+ len = min + tmp;
+ }
+
+ krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val);
+ if (krbtgt_utf16 == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16,
+ (len+1)*2);
+ if (krbtgt_utf16->data == NULL) {
+ return ldb_oom(ldb);
+ }
+ krbtgt_utf16->length = len * 2;
+ generate_secret_buffer(krbtgt_utf16->data,
+ krbtgt_utf16->length);
+ io->n.cleartext_utf16 = krbtgt_utf16;
+ }
+
/* transform the old password (for password changes) */
ret = setup_given_passwords(io, &io->og);
if (ret != LDB_SUCCESS) {
@@ -3646,59 +3724,6 @@
return ldb_operr(ldb);
}
- if (io->u.is_krbtgt) {
- size_t min = 196;
- size_t max = 255;
- size_t diff = max - min;
- size_t len = max;
- struct ldb_val *krbtgt_utf16 = NULL;
-
- if (!ac->pwd_reset) {
- return dsdb_module_werror(ac->module,
- LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
- WERR_DS_ATT_ALREADY_EXISTS,
- "Password change on krbtgt not permitted!");
- }
-
- if (io->n.cleartext_utf16 == NULL) {
- return dsdb_module_werror(ac->module,
- LDB_ERR_UNWILLING_TO_PERFORM,
- WERR_DS_INVALID_ATTRIBUTE_SYNTAX,
- "Password reset on krbtgt requires UTF16!");
- }
-
- /*
- * Instead of taking the callers value,
- * we just generate a new random value here.
- *
- * Include null termination in the array.
- */
- if (diff > 0) {
- size_t tmp;
-
- generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
-
- tmp %= diff;
-
- len = min + tmp;
- }
-
- krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val);
- if (krbtgt_utf16 == NULL) {
- return ldb_oom(ldb);
- }
-
- *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16,
- (len+1)*2);
- if (krbtgt_utf16->data == NULL) {
- return ldb_oom(ldb);
- }
- krbtgt_utf16->length = len * 2;
- generate_secret_buffer(krbtgt_utf16->data,
- krbtgt_utf16->length);
- io->n.cleartext_utf16 = krbtgt_utf16;
- }
-
if (existing_msg != NULL) {
NTSTATUS status;
diff -Nru samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/samldb.c samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/samldb.c
--- samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/samldb.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/samldb.c 2021-11-08 11:29:14.000000000 +0000
@@ -68,6 +68,13 @@
/* used for add operations */
enum samldb_add_type type;
+ /*
+ * should we apply the need_trailing_dollar restriction to
+ * samAccountName
+ */
+
+ bool need_trailing_dollar;
+
/* the resulting message */
struct ldb_message *msg;
@@ -154,49 +161,91 @@
}
}
-static int samldb_unique_attr_check(struct samldb_ctx *ac, const char *attr,
- const char *attr_conflict,
- struct ldb_dn *base_dn)
+static int samldb_get_single_valued_attr(struct ldb_context *ldb,
+ struct samldb_ctx *ac,
+ const char *attr,
+ const char **value)
{
- struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
- const char * const no_attrs[] = { NULL };
- struct ldb_result *res;
- const char *enc_str;
- struct ldb_message_element *el;
+ /*
+ * The steps we end up going through to get and check a single valued
+ * attribute.
+ */
+ struct ldb_message_element *el = NULL;
int ret;
- el = dsdb_get_single_valued_attr(ac->msg, attr,
- ac->req->operation);
+ *value = NULL;
+
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ attr,
+ &el,
+ ac->req->operation);
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
if (el == NULL) {
/* we are not affected */
return LDB_SUCCESS;
}
if (el->num_values > 1) {
- ldb_asprintf_errstring(ldb,
- "samldb: %s has %u values, should be single-valued!",
- attr, el->num_values);
+ ldb_asprintf_errstring(
+ ldb,
+ "samldb: %s has %u values, should be single-valued!",
+ attr, el->num_values);
return LDB_ERR_CONSTRAINT_VIOLATION;
} else if (el->num_values == 0) {
- ldb_asprintf_errstring(ldb,
- "samldb: new value for %s not provided for mandatory, single-valued attribute!",
- attr);
+ ldb_asprintf_errstring(
+ ldb,
+ "samldb: new value for %s "
+ "not provided for mandatory, single-valued attribute!",
+ attr);
return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
+
+
if (el->values[0].length == 0) {
- ldb_asprintf_errstring(ldb,
- "samldb: %s is of zero length, should have a value!",
- attr);
+ ldb_asprintf_errstring(
+ ldb,
+ "samldb: %s is of zero length, should have a value!",
+ attr);
return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
- enc_str = ldb_binary_encode(ac, el->values[0]);
+ *value = (char *)el->values[0].data;
+
+ return LDB_SUCCESS;
+}
+
+static int samldb_unique_attr_check(struct samldb_ctx *ac, const char *attr,
+ const char *attr_conflict,
+ struct ldb_dn *base_dn)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ const char * const no_attrs[] = { NULL };
+ struct ldb_result *res = NULL;
+ const char *str = NULL;
+ const char *enc_str = NULL;
+ int ret;
+
+ ret = samldb_get_single_valued_attr(ldb, ac, attr, &str);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (str == NULL) {
+ /* the attribute wasn't found */
+ return LDB_SUCCESS;
+ }
+
+ enc_str = ldb_binary_encode_string(ac, str);
if (enc_str == NULL) {
return ldb_module_oom(ac->module);
}
- /* Make sure that attr (eg) "sAMAccountName" is only used once */
-
+ /*
+ * No other object should have the attribute with this value.
+ */
if (attr_conflict != NULL) {
ret = dsdb_module_search(ac->module, ac, &res,
base_dn,
@@ -230,14 +279,346 @@
return LDB_SUCCESS;
}
+
+
+static inline int samldb_sam_account_upn_clash_sub_search(
+ struct samldb_ctx *ac,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *base_dn,
+ const char *attr,
+ const char *value,
+ const char *err_msg
+ )
+{
+ /*
+ * A very specific helper function for samldb_sam_account_upn_clash(),
+ * where we end up doing this same thing several times in a row.
+ */
+ const char * const no_attrs[] = { NULL };
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ struct ldb_result *res = NULL;
+ int ret;
+ char *enc_value = ldb_binary_encode_string(ac, value);
+ if (enc_value == NULL) {
+ return ldb_module_oom(ac->module);
+ }
+ ret = dsdb_module_search(ac->module, mem_ctx, &res,
+ base_dn,
+ LDB_SCOPE_SUBTREE, no_attrs,
+ DSDB_FLAG_NEXT_MODULE, ac->req,
+ "(%s=%s)",
+ attr, enc_value);
+ talloc_free(enc_value);
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ } else if (res->count > 1) {
+ return ldb_operr(ldb);
+ } else if (res->count == 1) {
+ if (ldb_dn_compare(res->msgs[0]->dn, ac->msg->dn) != 0){
+ ldb_asprintf_errstring(ldb,
+ "samldb: %s '%s' "
+ "is already in use %s",
+ attr, value, err_msg);
+ /* different errors for different attrs */
+ if (strcasecmp("userPrincipalName", attr) == 0) {
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ return LDB_ERR_ENTRY_ALREADY_EXISTS;
+ }
+ }
+ return LDB_SUCCESS;
+}
+
+static int samaccountname_bad_chars_check(struct samldb_ctx *ac,
+ const char *name)
+{
+ /*
+ * The rules here are based on
+ *
+ * https://social.technet.microsoft.com/wiki/contents/articles/11216.active-directory-requirements-for-creating-objects.aspx
+ *
+ * Windows considers UTF-8 sequences that map to "similar" characters
+ * (e.g. 'a', 'ā') to be the same sAMAccountName, and we don't. Names
+ * that are not valid UTF-8 *are* allowed.
+ *
+ * Additionally, Samba collapses multiple spaces, and Windows doesn't.
+ */
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ size_t i;
+
+ for (i = 0; name[i] != '\0'; i++) {
+ uint8_t c = name[i];
+ char *p = NULL;
+ if (c < 32 || c == 127) {
+ ldb_asprintf_errstring(
+ ldb,
+ "samldb: sAMAccountName contains invalid "
+ "0x%.2x character\n", c);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ p = strchr("\"[]:;|=+*?<>/\\,", c);
+ if (p != NULL) {
+ ldb_asprintf_errstring(
+ ldb,
+ "samldb: sAMAccountName contains invalid "
+ "'%c' character\n", c);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ }
+
+ if (i == 0) {
+ ldb_asprintf_errstring(
+ ldb,
+ "samldb: sAMAccountName is empty\n");
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ if (name[i - 1] == '.') {
+ ldb_asprintf_errstring(
+ ldb,
+ "samldb: sAMAccountName ends with '.'");
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ return LDB_SUCCESS;
+}
+
+static int samldb_sam_account_upn_clash(struct samldb_ctx *ac)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ int ret;
+ struct ldb_dn *base_dn = ldb_get_default_basedn(ldb);
+ TALLOC_CTX *tmp_ctx = NULL;
+ const char *real_sam = NULL;
+ const char *real_upn = NULL;
+ char *implied_sam = NULL;
+ char *implied_upn = NULL;
+ const char *realm = NULL;
+
+ ret = samldb_get_single_valued_attr(ldb, ac,
+ "sAMAccountName",
+ &real_sam);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ ret = samldb_get_single_valued_attr(ldb, ac,
+ "userPrincipalName",
+ &real_upn);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (real_upn == NULL && real_sam == NULL) {
+ /* Not changing these things, so we're done */
+ return LDB_SUCCESS;
+ }
+
+ tmp_ctx = talloc_new(ac);
+ realm = samdb_dn_to_dns_domain(tmp_ctx, base_dn);
+ if (realm == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_operr(ldb);
+ }
+
+ if (real_upn != NULL) {
+ /*
+ * note we take the last @ in the upn because the first (i.e.
+ * sAMAccountName equivalent) part can contain @.
+ *
+ * It is also OK (per Windows) for a UPN to have zero @s.
+ */
+ char *at = NULL;
+ char *upn_realm = NULL;
+ implied_sam = talloc_strdup(tmp_ctx, real_upn);
+ if (implied_sam == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_module_oom(ac->module);
+ }
+
+ at = strrchr(implied_sam, '@');
+ if (at == NULL) {
+ /*
+ * there is no @ in this UPN, so we treat the whole
+ * thing as a sAMAccountName for the purposes of a
+ * clash.
+ */
+ DBG_INFO("samldb: userPrincipalName '%s' contains "
+ "no '@' character\n", implied_sam);
+ } else {
+ /*
+ * Now, this upn only implies a sAMAccountName if the
+ * realm is our realm. So we need to compare the tail
+ * of the upn to the realm.
+ */
+ *at = '\0';
+ upn_realm = at + 1;
+ if (strcasecmp(upn_realm, realm) != 0) {
+ /* implied_sam is not the implied
+ * sAMAccountName after all, because it is
+ * from a different realm. */
+ TALLOC_FREE(implied_sam);
+ }
+ }
+ }
+
+ if (real_sam != NULL) {
+ implied_upn = talloc_asprintf(tmp_ctx, "%s@%s",
+ real_sam, realm);
+ if (implied_upn == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_module_oom(ac->module);
+ }
+ }
+
+ /*
+ * Now we have all of the actual and implied names, in which to search
+ * for conflicts.
+ */
+ if (real_sam != NULL) {
+ ret = samldb_sam_account_upn_clash_sub_search(
+ ac, tmp_ctx, base_dn, "sAMAccountName",
+ real_sam, "");
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ ret = samaccountname_bad_chars_check(ac, real_sam);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+ if (implied_upn != NULL) {
+ ret = samldb_sam_account_upn_clash_sub_search(
+ ac, tmp_ctx, base_dn, "userPrincipalName", implied_upn,
+ "(implied by sAMAccountName)");
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+ if (real_upn != NULL) {
+ ret = samldb_sam_account_upn_clash_sub_search(
+ ac, tmp_ctx, base_dn, "userPrincipalName",
+ real_upn, "");
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+ if (implied_sam != NULL) {
+ ret = samldb_sam_account_upn_clash_sub_search(
+ ac, tmp_ctx, base_dn, "sAMAccountName", implied_sam,
+ "(implied by userPrincipalName)");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+
+/* This is run during an add or modify */
static int samldb_sam_accountname_valid_check(struct samldb_ctx *ac)
{
- int ret = samldb_unique_attr_check(ac, "samAccountName", NULL,
- ldb_get_default_basedn(
- ldb_module_get_ctx(ac->module)));
- if (ret == LDB_ERR_OBJECT_CLASS_VIOLATION) {
+ int ret = 0;
+ bool is_admin;
+ struct security_token *user_token = NULL;
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ struct ldb_message_element *el = NULL;
+
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ "samAccountName",
+ &el,
+ ac->req->operation);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (el == NULL || el->num_values == 0) {
+ ldb_asprintf_errstring(ldb,
+ "%08X: samldb: 'samAccountName' can't be deleted/empty!",
+ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
+ if (ac->req->operation == LDB_ADD) {
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ } else {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ }
+
+ ret = samldb_unique_attr_check(ac, "samAccountName", NULL,
+ ldb_get_default_basedn(
+ ldb_module_get_ctx(ac->module)));
+
+ /*
+ * Error code munging to try and match what must be some quite
+ * strange code-paths in Windows
+ */
+ if (ret == LDB_ERR_CONSTRAINT_VIOLATION
+ && ac->req->operation == LDB_MODIFY) {
+ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ } else if (ret == LDB_ERR_OBJECT_CLASS_VIOLATION) {
ret = LDB_ERR_CONSTRAINT_VIOLATION;
}
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = samldb_sam_account_upn_clash(ac);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ if (!ac->need_trailing_dollar) {
+ return LDB_SUCCESS;
+ }
+
+ /* This does not permit a single $ */
+ if (el->values[0].length < 2) {
+ ldb_asprintf_errstring(ldb,
+ "%08X: samldb: 'samAccountName' "
+ "can't just be one character!",
+ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ user_token = acl_user_token(ac->module);
+ if (user_token == NULL) {
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+
+ is_admin
+ = security_token_has_builtin_administrators(user_token);
+
+ if (is_admin) {
+ /*
+ * Administrators are allowed to select strange names.
+ * This is poor practice but not prevented.
+ */
+ return false;
+ }
+
+ if (el->values[0].data[el->values[0].length - 1] != '$') {
+ ldb_asprintf_errstring(ldb,
+ "%08X: samldb: 'samAccountName' "
+ "must have a trailing $!",
+ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ if (el->values[0].data[el->values[0].length - 2] == '$') {
+ ldb_asprintf_errstring(ldb,
+ "%08X: samldb: 'samAccountName' "
+ "must not have a double trailing $!",
+ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
return ret;
}
@@ -358,8 +739,15 @@
schema = dsdb_get_schema(ldb, ac);
schema_dn = ldb_get_schema_basedn(ldb);
- el = dsdb_get_single_valued_attr(ac->msg, "linkID",
- ac->req->operation);
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ "linkID",
+ &el,
+ ac->req->operation);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
if (el == NULL) {
return LDB_SUCCESS;
}
@@ -519,8 +907,15 @@
schema = dsdb_get_schema(ldb, ac);
schema_dn = ldb_get_schema_basedn(ldb);
- el = dsdb_get_single_valued_attr(ac->msg, "mAPIID",
- ac->req->operation);
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ "mAPIID",
+ &el,
+ ac->req->operation);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
if (el == NULL) {
return LDB_SUCCESS;
}
@@ -554,17 +949,31 @@
}
/* sAMAccountName handling */
-static int samldb_generate_sAMAccountName(struct ldb_context *ldb,
+static int samldb_generate_sAMAccountName(struct samldb_ctx *ac,
struct ldb_message *msg)
{
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
char *name;
- /* Format: $000000-000000000000 */
+ /*
+ * This is currently a Samba-only behaviour, to add a trailing
+ * $ even for the generated accounts.
+ */
+
+ if (ac->need_trailing_dollar) {
+ /* Format: $000000-00000000000$ */
+ name = talloc_asprintf(msg, "$%.6X-%.6X%.5X$",
+ (unsigned int)generate_random(),
+ (unsigned int)generate_random(),
+ (unsigned int)generate_random());
+ } else {
+ /* Format: $000000-000000000000 */
- name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
- (unsigned int)generate_random(),
- (unsigned int)generate_random(),
- (unsigned int)generate_random());
+ name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
+ (unsigned int)generate_random(),
+ (unsigned int)generate_random(),
+ (unsigned int)generate_random());
+ }
if (name == NULL) {
return ldb_oom(ldb);
}
@@ -573,11 +982,10 @@
static int samldb_check_sAMAccountName(struct samldb_ctx *ac)
{
- struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
int ret;
if (ldb_msg_find_element(ac->msg, "sAMAccountName") == NULL) {
- ret = samldb_generate_sAMAccountName(ldb, ac->msg);
+ ret = samldb_generate_sAMAccountName(ac, ac->msg);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -1365,14 +1773,15 @@
struct dom_sid *sid,
uint32_t req_uac,
uint32_t user_account_control,
- uint32_t user_account_control_old);
+ uint32_t user_account_control_old,
+ bool is_computer_objectclass);
/*
* "Objectclass" trigger (MS-SAMR 3.1.1.8.1)
*
- * Has to be invoked on "add" and "modify" operations on "user", "computer" and
+ * Has to be invoked on "add" operations on "user", "computer" and
* "group" objects.
- * ac->msg contains the "add"/"modify" message
+ * ac->msg contains the "add"
* ac->type contains the object type (main objectclass)
*/
static int samldb_objectclass_trigger(struct samldb_ctx *ac)
@@ -1413,19 +1822,35 @@
switch(ac->type) {
case SAMLDB_TYPE_USER: {
+ uint32_t raw_uac;
+ uint32_t user_account_control;
+ bool is_computer_objectclass;
bool uac_generated = false, uac_add_flags = false;
-
+ uint32_t default_user_account_control = UF_NORMAL_ACCOUNT;
/* Step 1.2: Default values */
ret = dsdb_user_obj_set_defaults(ldb, ac->msg, ac->req);
if (ret != LDB_SUCCESS) return ret;
+ is_computer_objectclass
+ = (samdb_find_attribute(ldb,
+ ac->msg,
+ "objectclass",
+ "computer")
+ != NULL);
+
+ if (is_computer_objectclass) {
+ default_user_account_control
+ = UF_WORKSTATION_TRUST_ACCOUNT;
+ }
+
+
/* On add operations we might need to generate a
* "userAccountControl" (if it isn't specified). */
el = ldb_msg_find_element(ac->msg, "userAccountControl");
- if ((el == NULL) && (ac->req->operation == LDB_ADD)) {
+ if (el == NULL) {
ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
"userAccountControl",
- UF_NORMAL_ACCOUNT);
+ default_user_account_control);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -1434,120 +1859,125 @@
}
el = ldb_msg_find_element(ac->msg, "userAccountControl");
- if (el != NULL) {
- uint32_t raw_uac;
- uint32_t user_account_control;
- /* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */
- user_account_control = ldb_msg_find_attr_as_uint(ac->msg,
- "userAccountControl",
- 0);
- raw_uac = user_account_control;
- /*
- * "userAccountControl" = 0 or missing one of
- * the types means "UF_NORMAL_ACCOUNT". See
- * MS-SAMR 3.1.1.8.10 point 8
- */
- if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) {
- user_account_control = UF_NORMAL_ACCOUNT | user_account_control;
- uac_generated = true;
- }
+ SMB_ASSERT(el != NULL);
- /*
- * As per MS-SAMR 3.1.1.8.10 these flags have not to be set
- */
- if ((user_account_control & UF_LOCKOUT) != 0) {
- user_account_control &= ~UF_LOCKOUT;
- uac_generated = true;
- }
- if ((user_account_control & UF_PASSWORD_EXPIRED) != 0) {
- user_account_control &= ~UF_PASSWORD_EXPIRED;
- uac_generated = true;
- }
+ /* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */
+ user_account_control = ldb_msg_find_attr_as_uint(ac->msg,
+ "userAccountControl",
+ 0);
+ raw_uac = user_account_control;
+ /*
+ * "userAccountControl" = 0 or missing one of
+ * the types means "UF_NORMAL_ACCOUNT"
+ * or "UF_WORKSTATION_TRUST_ACCOUNT" (if a computer).
+ * See MS-SAMR 3.1.1.8.10 point 8
+ */
+ if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) {
+ user_account_control
+ = default_user_account_control
+ | user_account_control;
+ uac_generated = true;
+ }
- ret = samldb_check_user_account_control_rules(ac, NULL,
- raw_uac,
- user_account_control,
- 0);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ /*
+ * As per MS-SAMR 3.1.1.8.10 these flags have not to be set
+ */
+ if ((user_account_control & UF_LOCKOUT) != 0) {
+ user_account_control &= ~UF_LOCKOUT;
+ uac_generated = true;
+ }
+ if ((user_account_control & UF_PASSWORD_EXPIRED) != 0) {
+ user_account_control &= ~UF_PASSWORD_EXPIRED;
+ uac_generated = true;
+ }
- /* Workstation and (read-only) DC objects do need objectclass "computer" */
- if ((samdb_find_attribute(ldb, ac->msg,
- "objectclass", "computer") == NULL) &&
- (user_account_control &
- (UF_SERVER_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT))) {
- ldb_set_errstring(ldb,
- "samldb: Requested account type does need objectclass 'computer'!");
- return LDB_ERR_OBJECT_CLASS_VIOLATION;
- }
+ ret = samldb_check_user_account_control_rules(ac, NULL,
+ raw_uac,
+ user_account_control,
+ 0,
+ is_computer_objectclass);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /*
+ * Require, for non-admin modifications, a trailing $
+ * for either objectclass=computer or a trust account
+ * type in userAccountControl
+ */
+ if ((user_account_control
+ & UF_TRUST_ACCOUNT_MASK) != 0) {
+ ac->need_trailing_dollar = true;
+ }
+
+ if (is_computer_objectclass) {
+ ac->need_trailing_dollar = true;
+ }
+
+ /* add "sAMAccountType" attribute */
+ ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
- /* add "sAMAccountType" attribute */
- ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL);
+ /* "isCriticalSystemObject" might be set */
+ if (user_account_control &
+ (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
+ ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
+ "TRUE");
if (ret != LDB_SUCCESS) {
return ret;
}
-
- /* "isCriticalSystemObject" might be set */
- if (user_account_control &
- (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
- ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
- "TRUE");
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- el2 = ldb_msg_find_element(ac->msg,
- "isCriticalSystemObject");
- el2->flags = LDB_FLAG_MOD_REPLACE;
- } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) {
- ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
- "FALSE");
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- el2 = ldb_msg_find_element(ac->msg,
- "isCriticalSystemObject");
- el2->flags = LDB_FLAG_MOD_REPLACE;
+ el2 = ldb_msg_find_element(ac->msg,
+ "isCriticalSystemObject");
+ el2->flags = LDB_FLAG_MOD_REPLACE;
+ } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) {
+ ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
+ "FALSE");
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
+ el2 = ldb_msg_find_element(ac->msg,
+ "isCriticalSystemObject");
+ el2->flags = LDB_FLAG_MOD_REPLACE;
+ }
- /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */
- if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) {
- uint32_t rid;
+ /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */
+ if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) {
+ uint32_t rid;
- ret = dsdb_user_obj_set_primary_group_id(ldb, ac->msg, user_account_control, &rid);
+ ret = dsdb_user_obj_set_primary_group_id(ldb, ac->msg, user_account_control, &rid);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ /*
+ * Older AD deployments don't know about the
+ * RODC group
+ */
+ if (rid == DOMAIN_RID_READONLY_DCS) {
+ ret = samldb_prim_group_tester(ac, rid);
if (ret != LDB_SUCCESS) {
return ret;
}
- /*
- * Older AD deployments don't know about the
- * RODC group
- */
- if (rid == DOMAIN_RID_READONLY_DCS) {
- ret = samldb_prim_group_tester(ac, rid);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
}
+ }
- /* Step 1.5: Add additional flags when needed */
- /* Obviously this is done when the "userAccountControl"
- * has been generated here (tested against Windows
- * Server) */
- if (uac_generated) {
- if (uac_add_flags) {
- user_account_control |= UF_ACCOUNTDISABLE;
- user_account_control |= UF_PASSWD_NOTREQD;
- }
-
- ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
- "userAccountControl",
- user_account_control);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ /* Step 1.5: Add additional flags when needed */
+ /* Obviously this is done when the "userAccountControl"
+ * has been generated here (tested against Windows
+ * Server) */
+ if (uac_generated) {
+ if (uac_add_flags) {
+ user_account_control |= UF_ACCOUNTDISABLE;
+ user_account_control |= UF_PASSWD_NOTREQD;
}
+ ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
+ "userAccountControl",
+ user_account_control);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
}
break;
}
@@ -1691,8 +2121,15 @@
int ret;
const char * const noattrs[] = { NULL };
- el = dsdb_get_single_valued_attr(ac->msg, "primaryGroupID",
- ac->req->operation);
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ "primaryGroupID",
+ &el,
+ ac->req->operation);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
if (el == NULL) {
/* we are not affected */
return LDB_SUCCESS;
@@ -1976,6 +2413,137 @@
return ret;
}
+/*
+ * It would be best if these rules apply, always, but for now they
+ * apply only to non-admins
+ */
+static int samldb_check_user_account_control_objectclass_invariants(
+ struct samldb_ctx *ac,
+ uint32_t user_account_control,
+ uint32_t user_account_control_old,
+ bool is_computer_objectclass)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+
+ uint32_t old_ufa = user_account_control_old & UF_ACCOUNT_TYPE_MASK;
+ uint32_t new_ufa = user_account_control & UF_ACCOUNT_TYPE_MASK;
+
+ uint32_t old_rodc = user_account_control_old & UF_PARTIAL_SECRETS_ACCOUNT;
+ uint32_t new_rodc = user_account_control & UF_PARTIAL_SECRETS_ACCOUNT;
+
+ bool is_admin;
+ struct security_token *user_token
+ = acl_user_token(ac->module);
+ if (user_token == NULL) {
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+
+ is_admin
+ = security_token_has_builtin_administrators(user_token);
+
+
+ /*
+ * We want to allow changes to (eg) disable an account
+ * that was created wrong, only checking the
+ * objectclass if the account type changes.
+ */
+ if (old_ufa == new_ufa && old_rodc == new_rodc) {
+ return LDB_SUCCESS;
+ }
+
+ switch (new_ufa) {
+ case UF_NORMAL_ACCOUNT:
+ if (is_computer_objectclass && !is_admin) {
+ ldb_asprintf_errstring(ldb,
+ "%08X: samldb: UF_NORMAL_ACCOUNT "
+ "requires objectclass 'user' not 'computer'!",
+ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
+ return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ }
+ break;
+
+ case UF_INTERDOMAIN_TRUST_ACCOUNT:
+ if (is_computer_objectclass) {
+ ldb_asprintf_errstring(ldb,
+ "%08X: samldb: UF_INTERDOMAIN_TRUST_ACCOUNT "
+ "requires objectclass 'user' not 'computer'!",
+ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
+ return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ }
+ break;
+
+ case UF_WORKSTATION_TRUST_ACCOUNT:
+ if (!is_computer_objectclass) {
+ /*
+ * Modify of a user account account into a
+ * workstation without objectclass computer
+ * as an admin is still permitted, but not
+ * to make an RODC
+ */
+ if (is_admin
+ && ac->req->operation == LDB_MODIFY
+ && new_rodc == 0) {
+ break;
+ }
+ ldb_asprintf_errstring(ldb,
+ "%08X: samldb: UF_WORKSTATION_TRUST_ACCOUNT "
+ "requires objectclass 'computer'!",
+ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
+ return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ }
+ break;
+
+ case UF_SERVER_TRUST_ACCOUNT:
+ if (!is_computer_objectclass) {
+ ldb_asprintf_errstring(ldb,
+ "%08X: samldb: UF_SERVER_TRUST_ACCOUNT "
+ "requires objectclass 'computer'!",
+ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
+ return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ }
+ break;
+
+ default:
+ ldb_asprintf_errstring(ldb,
+ "%08X: samldb: invalid userAccountControl[0x%08X]",
+ W_ERROR_V(WERR_INVALID_PARAMETER),
+ user_account_control);
+ return LDB_ERR_OTHER;
+ }
+ return LDB_SUCCESS;
+}
+
+static int samldb_get_domain_secdesc_and_oc(struct samldb_ctx *ac,
+ struct security_descriptor **domain_sd,
+ const struct dsdb_class **objectclass)
+{
+ const char * const sd_attrs[] = {"ntSecurityDescriptor", "objectClass", NULL};
+ struct ldb_result *res;
+ struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
+ const struct dsdb_schema *schema = NULL;
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ int ret = dsdb_module_search_dn(ac->module, ac, &res,
+ domain_dn,
+ sd_attrs,
+ DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (res->count != 1) {
+ return ldb_module_operr(ac->module);
+ }
+
+ schema = dsdb_get_schema(ldb, ac->req);
+ if (!schema) {
+ return ldb_module_operr(ac->module);;
+ }
+ *objectclass = dsdb_get_structural_oc_from_msg(schema, res->msgs[0]);
+ return dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(ac->module),
+ ac, res->msgs[0], domain_sd);
+
+}
+
/**
* Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured
*
@@ -1987,12 +2555,9 @@
{
int i, ret = 0;
bool need_acl_check = false;
- struct ldb_result *res;
- const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
struct security_token *user_token;
struct security_descriptor *domain_sd;
- struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
- struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ const struct dsdb_class *objectclass = NULL;
const struct uac_to_guid {
uint32_t uac;
uint32_t priv_to_change_from;
@@ -2078,21 +2643,7 @@
return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
}
- ret = dsdb_module_search_dn(ac->module, ac, &res,
- domain_dn,
- sd_attrs,
- DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
- ac->req);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- if (res->count != 1) {
- return ldb_module_operr(ac->module);
- }
-
- ret = dsdb_get_sd_from_ldb_message(ldb,
- ac, res->msgs[0], &domain_sd);
-
+ ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -2123,7 +2674,11 @@
ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
}
} else if (map[i].guid) {
- ret = acl_check_extended_right(ac, domain_sd,
+ ret = acl_check_extended_right(ac,
+ ac->module,
+ ac->req,
+ objectclass,
+ domain_sd,
user_token,
map[i].guid,
SEC_ADS_CONTROL_ACCESS,
@@ -2154,6 +2709,8 @@
return ldb_module_operr(ac->module);
}
if (map[i].guid) {
+ struct ldb_dn *domain_dn
+ = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
dsdb_acl_debug(domain_sd, acl_user_token(ac->module),
domain_dn,
true,
@@ -2167,7 +2724,8 @@
struct dom_sid *sid,
uint32_t req_uac,
uint32_t user_account_control,
- uint32_t user_account_control_old)
+ uint32_t user_account_control_old,
+ bool is_computer_objectclass)
{
int ret;
struct dsdb_control_password_user_account_control *uac = NULL;
@@ -2176,6 +2734,14 @@
if (ret != LDB_SUCCESS) {
return ret;
}
+ ret = samldb_check_user_account_control_objectclass_invariants(ac,
+ user_account_control,
+ user_account_control_old,
+ is_computer_objectclass);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
ret = samldb_check_user_account_control_acl(ac, sid, user_account_control, user_account_control_old);
if (ret != LDB_SUCCESS) {
return ret;
@@ -2237,12 +2803,19 @@
"objectSid",
NULL
};
- bool is_computer = false;
+ bool is_computer_objectclass = false;
bool old_is_critical = false;
bool new_is_critical = false;
- el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
- ac->req->operation);
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ "userAccountControl",
+ &el,
+ ac->req->operation);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
if (el == NULL || el->num_values == 0) {
ldb_asprintf_errstring(ldb,
"%08X: samldb: 'userAccountControl' can't be deleted!",
@@ -2292,7 +2865,10 @@
"lockoutTime", 0);
old_is_critical = ldb_msg_find_attr_as_bool(res->msgs[0],
"isCriticalSystemObject", 0);
- /* When we do not have objectclass "computer" we cannot switch to a (read-only) DC */
+ /*
+ * When we do not have objectclass "computer" we cannot
+ * switch to a workstation or (RO)DC
+ */
el = ldb_msg_find_element(res->msgs[0], "objectClass");
if (el == NULL) {
return ldb_operr(ldb);
@@ -2300,7 +2876,7 @@
computer_val = data_blob_string_const("computer");
val = ldb_msg_find_val(el, &computer_val);
if (val != NULL) {
- is_computer = true;
+ is_computer_objectclass = true;
}
old_ufa = old_uac & UF_ACCOUNT_TYPE_MASK;
@@ -2325,7 +2901,8 @@
ret = samldb_check_user_account_control_rules(ac, sid,
raw_uac,
new_uac,
- old_uac);
+ old_uac,
+ is_computer_objectclass);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -2347,25 +2924,11 @@
case UF_WORKSTATION_TRUST_ACCOUNT:
new_is_critical = false;
if (new_uac & UF_PARTIAL_SECRETS_ACCOUNT) {
- if (!is_computer) {
- ldb_asprintf_errstring(ldb,
- "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT "
- "requires objectclass 'computer'!",
- W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
- return LDB_ERR_UNWILLING_TO_PERFORM;
- }
new_is_critical = true;
}
break;
case UF_SERVER_TRUST_ACCOUNT:
- if (!is_computer) {
- ldb_asprintf_errstring(ldb,
- "%08X: samldb: UF_SERVER_TRUST_ACCOUNT "
- "requires objectclass 'computer'!",
- W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
- return LDB_ERR_UNWILLING_TO_PERFORM;
- }
new_is_critical = true;
break;
@@ -2399,8 +2962,14 @@
el->flags = LDB_FLAG_MOD_REPLACE;
}
- /* "isCriticalSystemObject" might be set/changed */
- if (old_is_critical != new_is_critical) {
+ /*
+ * "isCriticalSystemObject" might be set/changed
+ *
+ * Even a change from UF_NORMAL_ACCOUNT (implicitly FALSE) to
+ * UF_WORKSTATION_TRUST_ACCOUNT (actually FALSE) triggers
+ * creating the attribute.
+ */
+ if (old_is_critical != new_is_critical || old_atype != new_atype) {
ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject",
new_is_critical ? "TRUE": "FALSE");
if (ret != LDB_SUCCESS) {
@@ -2439,9 +3008,12 @@
return ldb_module_oom(ac->module);
}
- /* Overwrite "userAccountControl" correctly */
- el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl",
- ac->req->operation);
+ ret = ldb_msg_add_empty(ac->msg,
+ "userAccountControl",
+ LDB_FLAG_MOD_REPLACE,
+ &el);
+ el->values = talloc(ac->msg, struct ldb_val);
+ el->num_values = 1;
el->values[0].data = (uint8_t *) tempstr;
el->values[0].length = strlen(tempstr);
} else {
@@ -2456,12 +3028,11 @@
{
struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
int ret = 0;
- struct ldb_result *res = NULL;
- const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
struct security_token *user_token = NULL;
struct security_descriptor *domain_sd = NULL;
struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
const char *operation = "";
+ const struct dsdb_class *objectclass = NULL;
if (dsdb_module_am_system(ac->module)) {
return LDB_SUCCESS;
@@ -2483,24 +3054,15 @@
return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
}
- ret = dsdb_module_search_dn(ac->module, ac, &res,
- domain_dn,
- sd_attrs,
- DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
- ac->req);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- if (res->count != 1) {
- return ldb_module_operr(ac->module);
- }
-
- ret = dsdb_get_sd_from_ldb_message(ldb, ac, res->msgs[0], &domain_sd);
+ ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass);
if (ret != LDB_SUCCESS) {
return ret;
}
-
- ret = acl_check_extended_right(ac, domain_sd,
+ ret = acl_check_extended_right(ac,
+ ac->module,
+ ac->req,
+ objectclass,
+ domain_sd,
user_token,
GUID_DRS_UNEXPIRE_PASSWORD,
SEC_ADS_CONTROL_ACCESS,
@@ -2540,8 +3102,15 @@
NULL
};
- el = dsdb_get_single_valued_attr(ac->msg, "pwdLastSet",
- ac->req->operation);
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ "pwdLastSet",
+ &el,
+ ac->req->operation);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
if (el == NULL || el->num_values == 0) {
ldb_asprintf_errstring(ldb,
"%08X: samldb: 'pwdLastSet' can't be deleted!",
@@ -2595,8 +3164,15 @@
struct ldb_message *tmp_msg;
int ret;
- el = dsdb_get_single_valued_attr(ac->msg, "lockoutTime",
- ac->req->operation);
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ "lockoutTime",
+ &el,
+ ac->req->operation);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
if (el == NULL || el->num_values == 0) {
ldb_asprintf_errstring(ldb,
"%08X: samldb: 'lockoutTime' can't be deleted!",
@@ -2645,8 +3221,15 @@
struct ldb_result *res;
const char * const attrs[] = { "groupType", NULL };
- el = dsdb_get_single_valued_attr(ac->msg, "groupType",
- ac->req->operation);
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ "groupType",
+ &el,
+ ac->req->operation);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
if (el == NULL) {
/* we are not affected */
return LDB_SUCCESS;
@@ -2869,67 +3452,660 @@
return LDB_SUCCESS;
}
-/* This trigger adapts the "servicePrincipalName" attributes if the
- * "dNSHostName" and/or "sAMAccountName" attribute change(s) */
-static int samldb_service_principal_names_change(struct samldb_ctx *ac)
+#define SPN_ALIAS_NONE 0
+#define SPN_ALIAS_LINK 1
+#define SPN_ALIAS_TARGET 2
+
+static int find_spn_aliases(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *service_class,
+ char ***aliases,
+ size_t *n_aliases,
+ int *direction)
{
- struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
- struct ldb_message_element *el = NULL, *el2 = NULL;
- struct ldb_message *msg;
- const char * const attrs[] = { "servicePrincipalName", NULL };
- struct ldb_result *res;
- const char *dns_hostname = NULL, *old_dns_hostname = NULL,
- *sam_accountname = NULL, *old_sam_accountname = NULL;
- unsigned int i, j;
+ /*
+ * If you change the way this works, you should also look at changing
+ * LDB_lookup_spn_alias() in source4/dsdb/samdb/cracknames.c, which
+ * does some of the same work.
+ *
+ * In particular, note that sPNMappings are resolved on a first come,
+ * first served basis. For example, if we have
+ *
+ * host=ldap,cifs
+ * foo=ldap
+ * cifs=host,alerter
+ *
+ * then 'ldap', 'cifs', and 'host' will resolve to 'host', and
+ * 'alerter' will resolve to 'cifs'.
+ *
+ * If this resolution method is made more complicated, then the
+ * cracknames function should also be changed.
+ */
+ size_t i, j;
int ret;
+ bool ok;
+ struct ldb_result *res = NULL;
+ struct ldb_message_element *spnmappings = NULL;
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_dn *service_dn = NULL;
- el = dsdb_get_single_valued_attr(ac->msg, "dNSHostName",
- ac->req->operation);
- el2 = dsdb_get_single_valued_attr(ac->msg, "sAMAccountName",
- ac->req->operation);
- if ((el == NULL) && (el2 == NULL)) {
- /* we are not affected */
- return LDB_SUCCESS;
+ const char *attrs[] = {
+ "sPNMappings",
+ NULL
+ };
+
+ *direction = SPN_ALIAS_NONE;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ldb_oom(ldb);
}
- /* Create a temporary message for fetching the "dNSHostName" */
- if (el != NULL) {
- const char *dns_attrs[] = { "dNSHostName", NULL };
- msg = ldb_msg_new(ac->msg);
- if (msg == NULL) {
- return ldb_module_oom(ac->module);
- }
- ret = ldb_msg_add(msg, el, 0);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- dns_hostname = talloc_strdup(ac,
- ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL));
- if (dns_hostname == NULL) {
- return ldb_module_oom(ac->module);
- }
+ service_dn = ldb_dn_new(
+ tmp_ctx, ldb,
+ "CN=Directory Service,CN=Windows NT,CN=Services");
+ if (service_dn == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
+ }
- talloc_free(msg);
+ ok = ldb_dn_add_base(service_dn, ldb_get_config_basedn(ldb));
+ if (! ok) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn,
- dns_attrs, DSDB_FLAG_NEXT_MODULE, ac->req);
- if (ret == LDB_SUCCESS) {
- old_dns_hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
- }
+ ret = ldb_search(ldb, tmp_ctx, &res, service_dn, LDB_SCOPE_BASE,
+ attrs, "(objectClass=nTDSService)");
+
+ if (ret != LDB_SUCCESS || res->count != 1) {
+ DBG_WARNING("sPNMappings not found.\n");
+ talloc_free(tmp_ctx);
+ return ret;
}
- /* Create a temporary message for fetching the "sAMAccountName" */
- if (el2 != NULL) {
- char *tempstr, *tempstr2 = NULL;
- const char *acct_attrs[] = { "sAMAccountName", NULL };
+ spnmappings = ldb_msg_find_element(res->msgs[0], "sPNMappings");
+ if (spnmappings == NULL || spnmappings->num_values == 0) {
+ DBG_WARNING("no sPNMappings attribute\n");
+ talloc_free(tmp_ctx);
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+ *n_aliases = 0;
- msg = ldb_msg_new(ac->msg);
- if (msg == NULL) {
- return ldb_module_oom(ac->module);
+ for (i = 0; i < spnmappings->num_values; i++) {
+ char *p = NULL;
+ char *mapping = talloc_strndup(
+ tmp_ctx,
+ (char *)spnmappings->values[i].data,
+ spnmappings->values[i].length);
+ if (mapping == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
}
- ret = ldb_msg_add(msg, el2, 0);
- if (ret != LDB_SUCCESS) {
- return ret;
+
+ p = strchr(mapping, '=');
+ if (p == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_ALIAS_PROBLEM;
+ }
+ p[0] = '\0';
+ p++;
+
+ if (strcasecmp(mapping, service_class) == 0) {
+ /*
+ * We need to return the reverse aliases for this one.
+ *
+ * typically, this means the service_class is "host"
+ * and the mapping is "host=alerter,appmgmt,cisvc,..",
+ * so we get "alerter", "appmgmt", etc in the list of
+ * aliases.
+ */
+
+ /* There is one more field than there are commas */
+ size_t n = 1;
+
+ for (j = 0; p[j] != '\0'; j++) {
+ if (p[j] == ',') {
+ n++;
+ p[j] = '\0';
+ }
+ }
+ *aliases = talloc_array(mem_ctx, char*, n);
+ if (*aliases == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
+ }
+ *n_aliases = n;
+ talloc_steal(mem_ctx, mapping);
+ for (j = 0; j < n; j++) {
+ (*aliases)[j] = p;
+ p += strlen(p) + 1;
+ }
+ talloc_free(tmp_ctx);
+ *direction = SPN_ALIAS_LINK;
+ return LDB_SUCCESS;
+ }
+ /*
+ * We need to look along the list to see if service_class is
+ * there; if so, we return a list of one item (probably "host").
+ */
+ do {
+ char *str = p;
+ p = strchr(p, ',');
+ if (p != NULL) {
+ p[0] = '\0';
+ p++;
+ }
+ if (strcasecmp(str, service_class) == 0) {
+ *aliases = talloc_array(mem_ctx, char*, 1);
+ if (*aliases == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
+ }
+ *n_aliases = 1;
+ (*aliases)[0] = mapping;
+ talloc_steal(mem_ctx, mapping);
+ talloc_free(tmp_ctx);
+ *direction = SPN_ALIAS_TARGET;
+ return LDB_SUCCESS;
+ }
+ } while (p != NULL);
+ }
+ DBG_INFO("no sPNMappings alias for '%s'\n", service_class);
+ talloc_free(tmp_ctx);
+ *aliases = NULL;
+ *n_aliases = 0;
+ return LDB_SUCCESS;
+}
+
+
+static int get_spn_dn(struct ldb_context *ldb,
+ TALLOC_CTX *tmp_ctx,
+ const char *candidate,
+ struct ldb_dn **dn)
+{
+ int ret;
+ const char *empty_attrs[] = { NULL };
+ struct ldb_message *msg = NULL;
+ struct ldb_dn *base_dn = ldb_get_default_basedn(ldb);
+
+ const char *enc_candidate = NULL;
+
+ *dn = NULL;
+
+ enc_candidate = ldb_binary_encode_string(tmp_ctx, candidate);
+ if (enc_candidate == NULL) {
+ return ldb_operr(ldb);
+ }
+
+ ret = dsdb_search_one(ldb,
+ tmp_ctx,
+ &msg,
+ base_dn,
+ LDB_SCOPE_SUBTREE,
+ empty_attrs,
+ 0,
+ "(servicePrincipalName=%s)",
+ enc_candidate);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ *dn = msg->dn;
+ return LDB_SUCCESS;
+}
+
+
+static int check_spn_write_rights(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *spn,
+ struct ldb_dn *dn)
+{
+ int ret;
+ struct ldb_message *msg = NULL;
+ struct ldb_message_element *del_el = NULL;
+ struct ldb_message_element *add_el = NULL;
+ struct ldb_val val = {
+ .data = discard_const_p(uint8_t, spn),
+ .length = strlen(spn)
+ };
+
+ msg = ldb_msg_new(mem_ctx);
+ if (msg == NULL) {
+ return ldb_oom(ldb);
+ }
+ msg->dn = dn;
+
+ ret = ldb_msg_add_empty(msg,
+ "servicePrincipalName",
+ LDB_FLAG_MOD_DELETE,
+ &del_el);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ret;
+ }
+
+ del_el->values = talloc_array(msg->elements, struct ldb_val, 1);
+ if (del_el->values == NULL) {
+ talloc_free(msg);
+ return ret;
+ }
+
+ del_el->values[0] = val;
+ del_el->num_values = 1;
+
+ ret = ldb_msg_add_empty(msg,
+ "servicePrincipalName",
+ LDB_FLAG_MOD_ADD,
+ &add_el);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(msg);
+ return ret;
+ }
+
+ add_el->values = talloc_array(msg->elements, struct ldb_val, 1);
+ if (add_el->values == NULL) {
+ talloc_free(msg);
+ return ret;
+ }
+
+ add_el->values[0] = val;
+ add_el->num_values = 1;
+
+ ret = ldb_modify(ldb, msg);
+ if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ DBG_ERR("hmm I think we're OK, but not sure\n");
+ } else if (ret != LDB_SUCCESS) {
+ DBG_ERR("SPN write rights check failed with %d\n", ret);
+ talloc_free(msg);
+ return ret;
+ }
+ talloc_free(msg);
+ return LDB_SUCCESS;
+}
+
+
+static int check_spn_alias_collision(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *spn,
+ struct ldb_dn *target_dn)
+{
+ int ret;
+ char *service_class = NULL;
+ char *spn_tail = NULL;
+ char *p = NULL;
+ char **aliases = NULL;
+ size_t n_aliases = 0;
+ size_t i, len;
+ TALLOC_CTX *tmp_ctx = NULL;
+ const char *target_dnstr = ldb_dn_get_linearized(target_dn);
+ int link_direction;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ /*
+ * "dns/example.com/xxx" gives
+ * service_class = "dns"
+ * spn_tail = "example.com/xxx"
+ */
+ p = strchr(spn, '/');
+ if (p == NULL) {
+ /* bad SPN */
+ talloc_free(tmp_ctx);
+ return ldb_error(ldb,
+ LDB_ERR_OPERATIONS_ERROR,
+ "malformed servicePrincipalName");
+ }
+ len = p - spn;
+
+ service_class = talloc_strndup(tmp_ctx, spn, len);
+ if (service_class == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
+ }
+ spn_tail = p + 1;
+
+ ret = find_spn_aliases(ldb,
+ tmp_ctx,
+ service_class,
+ &aliases,
+ &n_aliases,
+ &link_direction);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ /*
+ * we have the list of aliases, and now we need to combined them with
+ * spn_tail and see if we can find the SPN.
+ */
+ for (i = 0; i < n_aliases; i++) {
+ struct ldb_dn *colliding_dn = NULL;
+ const char *colliding_dnstr = NULL;
+
+ char *candidate = talloc_asprintf(tmp_ctx,
+ "%s/%s",
+ aliases[i],
+ spn_tail);
+ if (candidate == NULL) {
+ talloc_free(tmp_ctx);
+ return ldb_oom(ldb);
+ }
+
+ ret = get_spn_dn(ldb, tmp_ctx, candidate, &colliding_dn);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ DBG_DEBUG("SPN alias '%s' not found (good)\n",
+ candidate);
+ talloc_free(candidate);
+ continue;
+ }
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("SPN '%s' search error %d\n", candidate, ret);
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ target_dnstr = ldb_dn_get_linearized(target_dn);
+ /*
+ * We have found an existing SPN that matches the alias. That
+ * is OK only if it is on the object we are trying to add to,
+ * or if the SPN on the other side is a more generic alias for
+ * this one and we also have rights to modify it.
+ *
+ * That is, we can put "host/X" and "cifs/X" on the same
+ * object, but not on different objects, unless we put the
+ * host/X on first, and could also change that object when we
+ * add cifs/X. It is forbidden to add the objects in the other
+ * order.
+ *
+ * The rationale for this is that adding "cifs/X" effectively
+ * changes "host/X" by diverting traffic. If "host/X" can be
+ * added after "cifs/X", a sneaky person could get "cifs/X" in
+ * first, making "host/X" have less effect than intended.
+ *
+ * Note: we also can't have "host/X" and "Host/X" on the same
+ * object, but that is not relevant here.
+ */
+
+ ret = ldb_dn_compare(colliding_dn, target_dn);
+ if (ret != 0) {
+ colliding_dnstr = ldb_dn_get_linearized(colliding_dn);
+ DBG_ERR("trying to add SPN '%s' on '%s' when '%s' is "
+ "on '%s'\n",
+ spn,
+ target_dnstr,
+ candidate,
+ colliding_dnstr);
+
+ if (link_direction == SPN_ALIAS_LINK) {
+ /* we don't allow host/X if there is a
+ * cifs/X */
+ talloc_free(tmp_ctx);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ ret = check_spn_write_rights(ldb,
+ tmp_ctx,
+ candidate,
+ colliding_dn);
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("SPN '%s' is on '%s' so '%s' can't be "
+ "added to '%s'\n",
+ candidate,
+ colliding_dnstr,
+ spn,
+ target_dnstr);
+ talloc_free(tmp_ctx);
+ ldb_asprintf_errstring(ldb,
+ "samldb: spn[%s] would cause a conflict",
+ spn);
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+ } else {
+ DBG_INFO("SPNs '%s' and '%s' alias both on '%s'\n",
+ candidate, spn, target_dnstr);
+ }
+ talloc_free(candidate);
+ }
+
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+static int check_spn_direct_collision(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ const char *spn,
+ struct ldb_dn *target_dn)
+{
+ int ret;
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_dn *colliding_dn = NULL;
+ const char *target_dnstr = NULL;
+ const char *colliding_dnstr = NULL;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ ret = get_spn_dn(ldb, tmp_ctx, spn, &colliding_dn);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ DBG_DEBUG("SPN '%s' not found (good)\n", spn);
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+ }
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("SPN '%s' search error %d\n", spn, ret);
+ talloc_free(tmp_ctx);
+ if (ret == LDB_ERR_COMPARE_TRUE) {
+ /*
+ * COMPARE_TRUE has special meaning here and we don't
+ * want to return it by mistake.
+ */
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ }
+ return ret;
+ }
+ /*
+ * We have found this exact SPN. This is mostly harmless (depend on
+ * ADD vs REPLACE) when the spn is being put on the object that
+ * already has, so we let it through to succeed or fail as some other
+ * module sees fit.
+ */
+ target_dnstr = ldb_dn_get_linearized(target_dn);
+ ret = ldb_dn_compare(colliding_dn, target_dn);
+ if (ret != 0) {
+ colliding_dnstr = ldb_dn_get_linearized(colliding_dn);
+ DBG_ERR("SPN '%s' is on '%s' so it can't be "
+ "added to '%s'\n",
+ spn,
+ colliding_dnstr,
+ target_dnstr);
+ ldb_asprintf_errstring(ldb,
+ "samldb: spn[%s] would cause a conflict",
+ spn);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ DBG_INFO("SPN '%s' is already on '%s'\n",
+ spn, target_dnstr);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_COMPARE_TRUE;
+}
+
+
+static int count_spn_components(struct ldb_val val)
+{
+ /*
+ * a 3 part servicePrincipalName has two slashes, like
+ * ldap/example.com/DomainDNSZones.example.com.
+ *
+ * In krb5_parse_name_flags() we don't count "\/" as a slash (i.e.
+ * escaped by a backslash), but this is not the behaviour of Windows
+ * on setting a servicePrincipalName -- slashes are counted regardless
+ * of backslashes.
+ *
+ * Accordingly, here we ignore backslashes. This will reject
+ * multi-slash SPNs that krb5_parse_name_flags() would accept, and
+ * allow ones in the form "a\/b" that it won't parse.
+ */
+ size_t i;
+ int slashes = 0;
+ for (i = 0; i < val.length; i++) {
+ char c = val.data[i];
+ if (c == '/') {
+ slashes++;
+ if (slashes == 3) {
+ /* at this point we don't care */
+ return 4;
+ }
+ }
+ }
+ return slashes + 1;
+}
+
+
+/* Check that "servicePrincipalName" changes do not introduce a collision
+ * globally. */
+static int samldb_spn_uniqueness_check(struct samldb_ctx *ac,
+ struct ldb_message_element *spn_el)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ int ret;
+ const char *spn = NULL;
+ size_t i;
+ TALLOC_CTX *tmp_ctx = talloc_new(ac->msg);
+ if (tmp_ctx == NULL) {
+ return ldb_oom(ldb);
+ }
+
+ for (i = 0; i < spn_el->num_values; i++) {
+ int n_components;
+ spn = (char *)spn_el->values[i].data;
+
+ n_components = count_spn_components(spn_el->values[i]);
+ if (n_components > 3 || n_components < 2) {
+ ldb_asprintf_errstring(ldb,
+ "samldb: spn[%s] invalid with %u components",
+ spn, n_components);
+ talloc_free(tmp_ctx);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ ret = check_spn_direct_collision(ldb,
+ tmp_ctx,
+ spn,
+ ac->msg->dn);
+ if (ret == LDB_ERR_COMPARE_TRUE) {
+ DBG_INFO("SPN %s re-added to the same object\n", spn);
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+ }
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("SPN %s failed direct uniqueness check\n", spn);
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ret = check_spn_alias_collision(ldb,
+ tmp_ctx,
+ spn,
+ ac->msg->dn);
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /* we have no sPNMappings, hence no aliases */
+ break;
+ }
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("SPN %s failed alias uniqueness check\n", spn);
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+ DBG_INFO("SPN %s seems to be unique\n", spn);
+ }
+
+ talloc_free(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+
+
+/* This trigger adapts the "servicePrincipalName" attributes if the
+ * "dNSHostName" and/or "sAMAccountName" attribute change(s) */
+static int samldb_service_principal_names_change(struct samldb_ctx *ac)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ struct ldb_message_element *el = NULL, *el2 = NULL;
+ struct ldb_message *msg;
+ const char * const attrs[] = { "servicePrincipalName", NULL };
+ struct ldb_result *res;
+ const char *dns_hostname = NULL, *old_dns_hostname = NULL,
+ *sam_accountname = NULL, *old_sam_accountname = NULL;
+ unsigned int i, j;
+ int ret;
+
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ "dNSHostName",
+ &el,
+ ac->req->operation);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ "sAMAccountName",
+ &el2,
+ ac->req->operation);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if ((el == NULL) && (el2 == NULL)) {
+ /* we are not affected */
+ return LDB_SUCCESS;
+ }
+
+ /* Create a temporary message for fetching the "dNSHostName" */
+ if (el != NULL) {
+ const char *dns_attrs[] = { "dNSHostName", NULL };
+ msg = ldb_msg_new(ac->msg);
+ if (msg == NULL) {
+ return ldb_module_oom(ac->module);
+ }
+ ret = ldb_msg_add(msg, el, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ dns_hostname = talloc_strdup(ac,
+ ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL));
+ if (dns_hostname == NULL) {
+ return ldb_module_oom(ac->module);
+ }
+
+ talloc_free(msg);
+
+ ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn,
+ dns_attrs, DSDB_FLAG_NEXT_MODULE, ac->req);
+ if (ret == LDB_SUCCESS) {
+ old_dns_hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
+ }
+ }
+
+ /* Create a temporary message for fetching the "sAMAccountName" */
+ if (el2 != NULL) {
+ char *tempstr, *tempstr2 = NULL;
+ const char *acct_attrs[] = { "sAMAccountName", NULL };
+
+ msg = ldb_msg_new(ac->msg);
+ if (msg == NULL) {
+ return ldb_module_oom(ac->module);
+ }
+ ret = ldb_msg_add(msg, el2, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
tempstr = talloc_strdup(ac,
ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
@@ -2984,8 +4160,14 @@
return LDB_SUCCESS;
}
- /* Potential "servicePrincipalName" changes in the same request have to
- * be handled before the update (Windows behaviour). */
+ /*
+ * Potential "servicePrincipalName" changes in the same request have
+ * to be handled before the update (Windows behaviour).
+ *
+ * We extract the SPN changes into a new message and run it through
+ * the stack from this module, so that it subjects them to the SPN
+ * checks we have here.
+ */
el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
if (el != NULL) {
msg = ldb_msg_new(ac->msg);
@@ -3007,7 +4189,7 @@
} while (el != NULL);
ret = dsdb_module_modify(ac->module, msg,
- DSDB_FLAG_NEXT_MODULE, ac->req);
+ DSDB_FLAG_OWN_MODULE, ac->req);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -3120,13 +4302,22 @@
struct ldb_dn *res_dn;
struct ldb_result *res;
int ret;
+ ret = dsdb_get_expected_new_values(ac,
+ ac->msg,
+ "fSMORoleOwner",
+ &el,
+ ac->req->operation);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
- el = dsdb_get_single_valued_attr(ac->msg, "fSMORoleOwner",
- ac->req->operation);
if (el == NULL) {
/* we are not affected */
return LDB_SUCCESS;
}
+ if (el->num_values != 1) {
+ goto choose_error_code;
+ }
/* Create a temporary message for fetching the "fSMORoleOwner" */
tmp_msg = ldb_msg_new(ac->msg);
@@ -3143,11 +4334,7 @@
if (res_dn == NULL) {
ldb_set_errstring(ldb,
"samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
- if (ac->req->operation == LDB_ADD) {
- return LDB_ERR_CONSTRAINT_VIOLATION;
- } else {
- return LDB_ERR_UNWILLING_TO_PERFORM;
- }
+ goto choose_error_code;
}
/* Fetched DN has to reference a "nTDSDSA" entry */
@@ -3167,6 +4354,14 @@
talloc_free(res);
return LDB_SUCCESS;
+
+choose_error_code:
+ /* this is just how it is */
+ if (ac->req->operation == LDB_ADD) {
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ } else {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
}
/*
@@ -3486,7 +4681,103 @@
return NULL;
}
+/*
+ * Restrict all access to sensitive attributes.
+ *
+ * We don't want to even inspect the values, so we can use the same
+ * routine for ADD and MODIFY.
+ *
+ */
+
+static int samldb_check_sensitive_attributes(struct samldb_ctx *ac)
+{
+ struct ldb_message_element *el = NULL;
+ struct security_token *user_token = NULL;
+ int ret;
+ if (dsdb_module_am_system(ac->module)) {
+ return LDB_SUCCESS;
+ }
+
+ user_token = acl_user_token(ac->module);
+ if (user_token == NULL) {
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+
+ el = ldb_msg_find_element(ac->msg, "sidHistory");
+ if (el) {
+ /*
+ * sidHistory is restricted to the (not implemented
+ * yet in Samba) DsAddSidHistory call (direct LDB access is
+ * as SYSTEM so will bypass this).
+ *
+ * If you want to modify this, say to merge domains,
+ * directly modify the sam.ldb as root.
+ */
+ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
+ "sidHistory "
+ "(entry %s) cannot be created "
+ "or changed over LDAP!",
+ ldb_dn_get_linearized(ac->msg->dn));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ el = ldb_msg_find_element(ac->msg, "msDS-SecondaryKrbTgtNumber");
+ if (el) {
+ struct security_descriptor *domain_sd;
+ const struct dsdb_class *objectclass = NULL;
+ /*
+ * msDS-SecondaryKrbTgtNumber allows the creator to
+ * become an RODC, this is trusted as an RODC
+ * account
+ */
+ ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ ret = acl_check_extended_right(ac,
+ ac->module,
+ ac->req,
+ objectclass,
+ domain_sd,
+ user_token,
+ GUID_DRS_DS_INSTALL_REPLICA,
+ SEC_ADS_CONTROL_ACCESS,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
+ "msDS-SecondaryKrbTgtNumber "
+ "(entry %s) cannot be created "
+ "or changed without "
+ "DS-Install-Replica extended right!",
+ ldb_dn_get_linearized(ac->msg->dn));
+ return ret;
+ }
+ }
+
+ el = ldb_msg_find_element(ac->msg, "msDS-AllowedToDelegateTo");
+ if (el) {
+ /*
+ * msDS-AllowedToDelegateTo is incredibly powerful,
+ * given that it allows a server to become ANY USER on
+ * the target server only listed by SPN so needs to be
+ * protected just as the userAccountControl
+ * UF_TRUSTED_FOR_DELEGATION is.
+ */
+
+ bool have_priv = security_token_has_privilege(user_token,
+ SEC_PRIV_ENABLE_DELEGATION);
+ if (have_priv == false) {
+ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
+ "msDS-AllowedToDelegateTo "
+ "(entry %s) cannot be created "
+ "or changed without SePrivEnableDelegation!",
+ ldb_dn_get_linearized(ac->msg->dn));
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+ }
+ return LDB_SUCCESS;
+}
/* add */
static int samldb_add(struct ldb_module *module, struct ldb_request *req)
{
@@ -3533,6 +4824,12 @@
return ldb_operr(ldb);
}
+ ret = samldb_check_sensitive_attributes(ac);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ac);
+ return ret;
+ }
+
el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
if (el != NULL) {
ret = samldb_fsmo_role_owner_check(ac);
@@ -3541,6 +4838,18 @@
}
}
+ el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
+ if ((el != NULL)) {
+ /*
+ * We need to check whether the SPN collides with an existing
+ * one (anywhere) including via aliases.
+ */
+ ret = samldb_spn_uniqueness_check(ac, el);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
if (samdb_find_attribute(ldb, ac->msg,
"objectclass", "user") != NULL) {
ac->type = SAMLDB_TYPE_USER;
@@ -3740,6 +5049,12 @@
return ldb_operr(ldb);
}
+ ret = samldb_check_sensitive_attributes(ac);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ac);
+ return ret;
+ }
+
if (is_undelete == NULL) {
el = ldb_msg_find_element(ac->msg, "primaryGroupID");
if (el != NULL) {
@@ -3788,12 +5103,49 @@
el = ldb_msg_find_element(ac->msg, "sAMAccountName");
if (el != NULL) {
+ uint32_t user_account_control;
+ struct ldb_result *res = NULL;
+ const char * const attrs[] = { "userAccountControl",
+ "objectclass",
+ NULL };
+ ret = dsdb_module_search_dn(ac->module,
+ ac,
+ &res,
+ ac->msg->dn,
+ attrs,
+ DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ user_account_control
+ = ldb_msg_find_attr_as_uint(res->msgs[0],
+ "userAccountControl",
+ 0);
+
+ if ((user_account_control
+ & UF_TRUST_ACCOUNT_MASK) != 0) {
+ ac->need_trailing_dollar = true;
+
+ } else if (samdb_find_attribute(ldb,
+ res->msgs[0],
+ "objectclass",
+ "computer")
+ != NULL) {
+ ac->need_trailing_dollar = true;
+ }
+
ret = samldb_sam_accountname_valid_check(ac);
- /*
- * Other errors are checked for elsewhere, we just
- * want to prevent duplicates
- */
- if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ el = ldb_msg_find_element(ac->msg, "userPrincipalName");
+ if (el != NULL) {
+ ret = samldb_sam_account_upn_clash(ac);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ac);
return ret;
}
}
@@ -3846,10 +5198,33 @@
el2 = ldb_msg_find_element(ac->msg, "sAMAccountName");
if ((el != NULL) || (el2 != NULL)) {
modified = true;
+ /*
+ * samldb_service_principal_names_change() might add SPN
+ * changes to the request, so this must come before the SPN
+ * uniqueness check below.
+ *
+ * Note we ALSO have to do the SPN uniqueness check inside
+ * samldb_service_principal_names_change(), because it does a
+ * subrequest to do requested SPN modifications *before* its
+ * automatic ones are added.
+ */
ret = samldb_service_principal_names_change(ac);
if (ret != LDB_SUCCESS) {
return ret;
}
+ }
+
+ el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
+ if ((el != NULL)) {
+ /*
+ * We need to check whether the SPN collides with an existing
+ * one (anywhere) including via aliases.
+ */
+ modified = true;
+ ret = samldb_spn_uniqueness_check(ac, el);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
}
el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
diff -Nru samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/util.c samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/util.c
--- samba-4.13.3+dfsg/source4/dsdb/samdb/ldb_modules/util.c 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/samdb/ldb_modules/util.c 2021-11-08 11:29:14.000000000 +0000
@@ -1442,37 +1442,124 @@
}
/*
- * Gets back a single-valued attribute by the rules of the DSDB triggers when
- * performing a modify operation.
+ * Get all the values that *might* be added by an ldb message, as a composite
+ * ldb element.
*
- * In order that the constraint checking by the "objectclass_attrs" LDB module
- * does work properly, the change request should remain similar or only be
- * enhanced (no other modifications as deletions, variations).
+ * This is useful when we need to check all the possible values against some
+ * criteria.
+ *
+ * In cases where a modify message mixes multiple ADDs, DELETEs, and REPLACES,
+ * the returned element might contain more values than would actually end up
+ * in the database if the message was run to its conclusion.
+ *
+ * If the operation is not LDB_ADD or LDB_MODIFY, an operations error is
+ * returned.
+ *
+ * The returned element might not be new, and should not be modified or freed
+ * before the message is finished.
*/
-struct ldb_message_element *dsdb_get_single_valued_attr(const struct ldb_message *msg,
- const char *attr_name,
- enum ldb_request_type operation)
+
+int dsdb_get_expected_new_values(TALLOC_CTX *mem_ctx,
+ const struct ldb_message *msg,
+ const char *attr_name,
+ struct ldb_message_element **el,
+ enum ldb_request_type operation)
{
- struct ldb_message_element *el = NULL;
unsigned int i;
+ unsigned int el_count = 0;
+ unsigned int val_count = 0;
+ struct ldb_val *v = NULL;
+ struct ldb_message_element *_el = NULL;
+ *el = NULL;
- /* We've to walk over all modification entries and consider the last
- * non-delete one which belongs to "attr_name".
- *
- * If "el" is NULL afterwards then that means there was no interesting
- * change entry. */
+ if (operation != LDB_ADD && operation != LDB_MODIFY) {
+ DBG_ERR("inapplicable operation type: %d\n", operation);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* count the adding or replacing elements */
for (i = 0; i < msg->num_elements; i++) {
if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
+ unsigned int tmp;
+ if ((operation == LDB_MODIFY) &&
+ (LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
+ == LDB_FLAG_MOD_DELETE)) {
+ continue;
+ }
+ el_count++;
+ tmp = val_count + msg->elements[i].num_values;
+ if (unlikely(tmp < val_count)) {
+ DBG_ERR("too many values for one element!");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ val_count = tmp;
+ }
+ }
+ if (el_count == 0) {
+ /* nothing to see here */
+ return LDB_SUCCESS;
+ }
+
+ if (el_count == 1 || val_count == 0) {
+ /*
+ * There is one effective element, which we can return as-is,
+ * OR there are only elements with zero values -- any of which
+ * will do.
+ */
+ for (i = 0; i < msg->num_elements; i++) {
+ if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
+ if ((operation == LDB_MODIFY) &&
+ (LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
+ == LDB_FLAG_MOD_DELETE)) {
+ continue;
+ }
+ *el = &msg->elements[i];
+ return LDB_SUCCESS;
+ }
+ }
+ }
+
+ _el = talloc_zero(mem_ctx, struct ldb_message_element);
+ if (_el == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ _el->name = attr_name;
+
+ if (val_count == 0) {
+ /*
+ * Seems unlikely, but sometimes we might be adding zero
+ * values in multiple separate elements. The talloc zero has
+ * already set the expected values = NULL, num_values = 0.
+ */
+ *el = _el;
+ return LDB_SUCCESS;
+ }
+
+ _el->values = talloc_array(_el, struct ldb_val, val_count);
+ if (_el->values == NULL) {
+ talloc_free(_el);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ _el->num_values = val_count;
+
+ v = _el->values;
+
+ for (i = 0; i < val_count; i++) {
+ if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
if ((operation == LDB_MODIFY) &&
(LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
== LDB_FLAG_MOD_DELETE)) {
continue;
}
- el = &msg->elements[i];
+ memcpy(v,
+ msg->elements[i].values,
+ msg->elements[i].num_values);
+ v += msg->elements[i].num_values;
}
}
- return el;
+ *el = _el;
+ return LDB_SUCCESS;
}
/*
diff -Nru samba-4.13.3+dfsg/source4/dsdb/samdb/samdb.c samba-4.13.14+dfsg/source4/dsdb/samdb/samdb.c
--- samba-4.13.3+dfsg/source4/dsdb/samdb/samdb.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/samdb/samdb.c 2021-08-06 12:19:57.000000000 +0000
@@ -63,6 +63,9 @@
*ldb_ret = NULL;
*errstring = NULL;
+ /* We create sam.ldb in provision, and never anywhere else */
+ flags |= LDB_FLG_DONT_CREATE_DB;
+
if (remote_address == NULL) {
ldb = ldb_wrap_find(url, ev_ctx, lp_ctx,
session_info, NULL, flags);
diff -Nru samba-4.13.3+dfsg/source4/dsdb/schema/schema_set.c samba-4.13.14+dfsg/source4/dsdb/schema/schema_set.c
--- samba-4.13.3+dfsg/source4/dsdb/schema/schema_set.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/schema/schema_set.c 2021-09-22 06:59:39.000000000 +0000
@@ -696,6 +696,8 @@
{
int ret;
void *ptr;
+ void *schema_parent = NULL;
+ bool is_already_parent;
struct dsdb_schema *old_schema;
old_schema = ldb_get_opaque(ldb, "dsdb_schema");
ret = ldb_set_opaque(ldb, "dsdb_schema", schema);
@@ -708,8 +710,9 @@
talloc_unlink(ldb, old_schema);
/* Reference schema on ldb if it wasn't done already */
- ret = talloc_is_parent(ldb, schema);
- if (ret == 0) {
+ schema_parent = talloc_parent(schema);
+ is_already_parent = (schema_parent == ldb);
+ if (!is_already_parent) {
ptr = talloc_reference(ldb, schema);
if (ptr == NULL) {
return ldb_oom(ldb);
@@ -773,10 +776,10 @@
/* Don't write indices and attributes, it's expensive */
ret = dsdb_schema_set_indices_and_attributes(ldb, global_schema, SCHEMA_MEMORY_ONLY);
if (ret == LDB_SUCCESS) {
- /* If ldb doesn't have a reference to the schema, make one,
- * just in case the original copy is replaced */
- ret = talloc_is_parent(ldb, global_schema);
- if (ret == 0) {
+ void *schema_parent = talloc_parent(global_schema);
+ bool is_already_parent =
+ (schema_parent == ldb);
+ if (!is_already_parent) {
ptr = talloc_reference(ldb, global_schema);
if (ptr == NULL) {
return ldb_oom(ldb);
@@ -807,7 +810,6 @@
dsdb_schema_refresh_fn refresh_fn;
struct ldb_module *loaded_from_module;
bool use_global_schema;
- int ret;
TALLOC_CTX *tmp_ctx = talloc_new(reference_ctx);
if (tmp_ctx == NULL) {
return NULL;
@@ -858,13 +860,28 @@
/* This removes the extra reference above */
talloc_free(tmp_ctx);
- /* If ref ctx exists and doesn't already reference schema, then add
- * a reference. Otherwise, just return schema.*/
- ret = talloc_is_parent(reference_ctx, schema_out);
- if ((ret == 1) || (!reference_ctx)) {
+ /*
+ * If ref ctx exists and doesn't already reference schema, then add
+ * a reference. Otherwise, just return schema.
+ *
+ * We must use talloc_parent(), which is not quite free (there
+ * is no direct parent pointer in talloc, only one on the
+ * first child within a linked list), but is much cheaper than
+ * talloc_is_parent() which walks the whole tree up to the top
+ * looking for a potential grand-grand(etc)-parent.
+ */
+ if (reference_ctx == NULL) {
return schema_out;
} else {
- return talloc_reference(reference_ctx, schema_out);
+ void *schema_parent = talloc_parent(schema_out);
+ bool is_already_parent =
+ schema_parent == reference_ctx;
+ if (is_already_parent) {
+ return schema_out;
+ } else {
+ return talloc_reference(reference_ctx,
+ schema_out);
+ }
}
}
diff -Nru samba-4.13.3+dfsg/source4/dsdb/tests/python/acl.py samba-4.13.14+dfsg/source4/dsdb/tests/python/acl.py
--- samba-4.13.3+dfsg/source4/dsdb/tests/python/acl.py 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/tests/python/acl.py 2021-11-08 11:29:14.000000000 +0000
@@ -1647,6 +1647,8 @@
except LdbError as e31:
(num, _) = e31.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ pass # Not self.fail() as we normally want success.
def test_reset_password3(self):
"""Grant WP and see what happens (unicodePwd)"""
@@ -1708,6 +1710,8 @@
except LdbError as e34:
(num, _) = e34.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ pass # Not self.fail() as we normally want success
class AclExtendedTests(AclTests):
@@ -1922,6 +1926,8 @@
self.computername = "testcomp8"
self.test_user = "spn_test_user8"
self.computerdn = "CN=%s,CN=computers,%s" % (self.computername, self.base_dn)
+ self.user_object = "user_with_spn"
+ self.user_object_dn = "CN=%s,CN=Users,%s" % (self.user_object, self.base_dn)
self.dc_dn = "CN=%s,OU=Domain Controllers,%s" % (self.dcname, self.base_dn)
self.site = "Default-First-Site-Name"
self.rodcctx = DCJoinContext(server=host, creds=creds, lp=lp,
@@ -1943,6 +1949,7 @@
self.dcctx.cleanup_old_join()
delete_force(self.ldb_admin, "cn=%s,cn=computers,%s" % (self.computername, self.base_dn))
delete_force(self.ldb_admin, self.get_user_dn(self.test_user))
+ delete_force(self.ldb_admin, self.user_object_dn)
del self.ldb_user1
@@ -2024,6 +2031,8 @@
except LdbError as e39:
(num, _) = e39.args
self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ else:
+ self.fail()
mod = "(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;%s)" % str(self.user_sid1)
self.sd_utils.dacl_add_ace(ctx.acct_dn, mod)
@@ -2062,29 +2071,39 @@
except LdbError as e40:
(num, _) = e40.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
try:
self.replace_spn(self.ldb_user1, ctx.acct_dn, "ldap/%s.%s/DomainDnsZones.%s" %
(ctx.myname, ctx.dnsdomain, ctx.dnsdomain))
except LdbError as e41:
(num, _) = e41.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
try:
self.replace_spn(self.ldb_user1, ctx.acct_dn, "nosuchservice/%s/%s" % ("abcd", "abcd"))
except LdbError as e42:
(num, _) = e42.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
try:
self.replace_spn(self.ldb_user1, ctx.acct_dn, "GC/%s.%s/%s" %
(ctx.myname, ctx.dnsdomain, netbiosdomain))
except LdbError as e43:
(num, _) = e43.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
try:
self.replace_spn(self.ldb_user1, ctx.acct_dn, "E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s" %
(ctx.ntds_guid, ctx.dnsdomain))
except LdbError as e44:
(num, _) = e44.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
def test_computer_spn(self):
# with WP, any value can be set
@@ -2130,6 +2149,8 @@
except LdbError as e45:
(num, _) = e45.args
self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ else:
+ self.fail()
mod = "(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;%s)" % str(self.user_sid1)
self.sd_utils.dacl_add_ace(self.computerdn, mod)
@@ -2148,41 +2169,55 @@
except LdbError as e46:
(num, _) = e46.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
try:
self.replace_spn(self.ldb_user1, self.computerdn, "HOST/%s.%s/%s" %
(self.computername, self.dcctx.dnsdomain, netbiosdomain))
except LdbError as e47:
(num, _) = e47.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
try:
self.replace_spn(self.ldb_user1, self.computerdn, "HOST/%s/%s" %
(self.computername, self.dcctx.dnsdomain))
except LdbError as e48:
(num, _) = e48.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
try:
self.replace_spn(self.ldb_user1, self.computerdn, "HOST/%s.%s/%s" %
(self.computername, self.dcctx.dnsdomain, self.dcctx.dnsdomain))
except LdbError as e49:
(num, _) = e49.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
try:
self.replace_spn(self.ldb_user1, self.computerdn, "GC/%s.%s/%s" %
(self.computername, self.dcctx.dnsdomain, self.dcctx.dnsforest))
except LdbError as e50:
(num, _) = e50.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
try:
self.replace_spn(self.ldb_user1, self.computerdn, "ldap/%s/%s" % (self.computername, netbiosdomain))
except LdbError as e51:
(num, _) = e51.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
try:
self.replace_spn(self.ldb_user1, self.computerdn, "ldap/%s.%s/ForestDnsZones.%s" %
(self.computername, self.dcctx.dnsdomain, self.dcctx.dnsdomain))
except LdbError as e52:
(num, _) = e52.args
self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
def test_spn_rwdc(self):
self.dc_spn_test(self.dcctx)
@@ -2190,6 +2225,68 @@
def test_spn_rodc(self):
self.dc_spn_test(self.rodcctx)
+ def test_user_spn(self):
+ #grant SW to a regular user and try to set the spn on a user object
+ #should get ERR_INSUFFICIENT_ACCESS_RIGHTS, since Validate-SPN only applies to computer
+ self.ldb_admin.newuser(self.user_object, self.user_pass)
+ mod = "(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;%s)" % str(self.user_sid1)
+ self.sd_utils.dacl_add_ace(self.user_object_dn, mod)
+ try:
+ self.replace_spn(self.ldb_user1, self.user_object_dn, "nosuchservice/%s/%s" % ("abcd", "abcd"))
+ except LdbError as e60:
+ (num, _) = e60.args
+ self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ else:
+ self.fail()
+
+ def test_delete_add_spn(self):
+ # Grant Validated-SPN property.
+ mod = f'(OA;;SW;{security.GUID_DRS_VALIDATE_SPN};;{self.user_sid1})'
+ self.sd_utils.dacl_add_ace(self.computerdn, mod)
+
+ spn_base = f'HOST/{self.computername}'
+
+ allowed_spn = f'{spn_base}.{self.dcctx.dnsdomain}'
+ not_allowed_spn = f'{spn_base}/{self.dcctx.get_domain_name()}'
+
+ # Ensure we are able to add an allowed SPN.
+ msg = Message(Dn(self.ldb_user1, self.computerdn))
+ msg['servicePrincipalName'] = MessageElement(allowed_spn,
+ FLAG_MOD_ADD,
+ 'servicePrincipalName')
+ self.ldb_user1.modify(msg)
+
+ # Ensure we are not able to add a disallowed SPN.
+ msg = Message(Dn(self.ldb_user1, self.computerdn))
+ msg['servicePrincipalName'] = MessageElement(not_allowed_spn,
+ FLAG_MOD_ADD,
+ 'servicePrincipalName')
+ try:
+ self.ldb_user1.modify(msg)
+ except LdbError as e:
+ num, _ = e.args
+ self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail(f'able to add disallowed SPN {not_allowed_spn}')
+
+ # Ensure that deleting an existing SPN followed by adding a disallowed
+ # SPN fails.
+ msg = Message(Dn(self.ldb_user1, self.computerdn))
+ msg['0'] = MessageElement([],
+ FLAG_MOD_DELETE,
+ 'servicePrincipalName')
+ msg['1'] = MessageElement(not_allowed_spn,
+ FLAG_MOD_ADD,
+ 'servicePrincipalName')
+ try:
+ self.ldb_user1.modify(msg)
+ except LdbError as e:
+ num, _ = e.args
+ self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail(f'able to add disallowed SPN {not_allowed_spn}')
+
+
# tests SEC_ADS_LIST vs. SEC_ADS_LIST_OBJECT
@DynamicTestCase
class AclVisibiltyTests(AclTests):
diff -Nru samba-4.13.3+dfsg/source4/dsdb/tests/python/ldap.py samba-4.13.14+dfsg/source4/dsdb/tests/python/ldap.py
--- samba-4.13.3+dfsg/source4/dsdb/tests/python/ldap.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/tests/python/ldap.py 2021-11-08 11:29:14.000000000 +0000
@@ -48,6 +48,7 @@
ATYPE_WORKSTATION_TRUST, SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE,
SYSTEM_FLAG_CONFIG_ALLOW_RENAME, SYSTEM_FLAG_CONFIG_ALLOW_MOVE,
SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE)
+from samba.dcerpc.security import DOMAIN_RID_DOMAIN_MEMBERS
from samba.ndr import ndr_pack, ndr_unpack
from samba.dcerpc import security, lsa
@@ -435,33 +436,41 @@
(num, _) = e.args
self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
- # Add a new top-most structural class "inetOrgPerson" and remove it
- # afterwards
+ # Try to add a new top-most structural class "inetOrgPerson"
m = Message()
m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
m["objectClass"] = MessageElement("inetOrgPerson", FLAG_MOD_ADD,
"objectClass")
- ldb.modify(m)
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError as e:
+ (num, _) = e.args
+ self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
+ # Try to remove the structural class "user"
m = Message()
m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
- m["objectClass"] = MessageElement("inetOrgPerson", FLAG_MOD_DELETE,
+ m["objectClass"] = MessageElement("user", FLAG_MOD_DELETE,
"objectClass")
- ldb.modify(m)
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError as e:
+ (num, _) = e.args
+ self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
- # Replace top-most structural class to "inetOrgPerson" and reset it
- # back to "user"
+ # Try to replace top-most structural class to "inetOrgPerson"
m = Message()
m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
m["objectClass"] = MessageElement("inetOrgPerson", FLAG_MOD_REPLACE,
"objectClass")
- ldb.modify(m)
-
- m = Message()
- m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
- m["objectClass"] = MessageElement("user", FLAG_MOD_REPLACE,
- "objectClass")
- ldb.modify(m)
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError as e:
+ (num, _) = e.args
+ self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
# Add a new auxiliary object class "posixAccount" to "ldaptestuser"
m = Message()
@@ -2018,9 +2027,9 @@
self.assertTrue("objectGUID" in res[0])
self.assertTrue("whenCreated" in res[0])
self.assertEqual(str(res[0]["objectCategory"][0]), ("CN=Computer,%s" % ldb.get_schema_basedn()))
- self.assertEqual(int(res[0]["primaryGroupID"][0]), 513)
- self.assertEqual(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT)
- self.assertEqual(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
+ self.assertEqual(int(res[0]["primaryGroupID"][0]), DOMAIN_RID_DOMAIN_MEMBERS)
+ self.assertEqual(int(res[0]["sAMAccountType"][0]), ATYPE_WORKSTATION_TRUST)
+ self.assertEqual(int(res[0]["userAccountControl"][0]), UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
@@ -2499,9 +2508,9 @@
self.assertTrue("objectGUID" in res[0])
self.assertTrue("whenCreated" in res[0])
self.assertEqual(str(res[0]["objectCategory"]), ("CN=Computer,%s" % ldb.get_schema_basedn()))
- self.assertEqual(int(res[0]["primaryGroupID"][0]), 513)
- self.assertEqual(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT)
- self.assertEqual(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
+ self.assertEqual(int(res[0]["primaryGroupID"][0]), DOMAIN_RID_DOMAIN_MEMBERS)
+ self.assertEqual(int(res[0]["sAMAccountType"][0]), ATYPE_WORKSTATION_TRUST)
+ self.assertEqual(int(res[0]["userAccountControl"][0]), UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
self.assertEqual(str(res[0]["memberOf"][0]).upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
self.assertEqual(len(res[0]["memberOf"]), 1)
diff -Nru samba-4.13.3+dfsg/source4/dsdb/tests/python/linked_attributes.py samba-4.13.14+dfsg/source4/dsdb/tests/python/linked_attributes.py
--- samba-4.13.3+dfsg/source4/dsdb/tests/python/linked_attributes.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/tests/python/linked_attributes.py 2021-11-08 11:29:14.000000000 +0000
@@ -166,27 +166,6 @@
attrs=['objectGUID'])
return str(misc.GUID(res[0]['objectGUID'][0]))
- def assertRaisesLdbError(self, errcode, msg, f, *args, **kwargs):
- """Assert a function raises a particular LdbError."""
- try:
- f(*args, **kwargs)
- except ldb.LdbError as e:
- (num, msg) = e.args
- if num != errcode:
- lut = {v: k for k, v in vars(ldb).items()
- if k.startswith('ERR_') and isinstance(v, int)}
- self.fail("%s, expected "
- "LdbError %s, (%d) "
- "got %s (%d)" % (msg,
- lut.get(errcode), errcode,
- lut.get(num), num))
- else:
- lut = {v: k for k, v in vars(ldb).items()
- if k.startswith('ERR_') and isinstance(v, int)}
- self.fail("%s, expected "
- "LdbError %s, (%d) "
- "but we got success" % (msg, lut.get(errcode), errcode))
-
def _test_la_backlinks(self, reveal=False):
tag = 'backlinks'
kwargs = {}
diff -Nru samba-4.13.3+dfsg/source4/dsdb/tests/python/password_settings.py samba-4.13.14+dfsg/source4/dsdb/tests/python/password_settings.py
--- samba-4.13.3+dfsg/source4/dsdb/tests/python/password_settings.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/tests/python/password_settings.py 2021-11-08 11:29:14.000000000 +0000
@@ -594,19 +594,27 @@
dummy_pso.apply_to(user.dn)
self.assertTrue(user.get_resultant_PSO() == dummy_pso.dn)
- # now clear the ADS_UF_NORMAL_ACCOUNT flag for the user, which should
- # mean a resultant PSO is no longer returned (we're essentially turning
- # the user into a DC here, which is a little overkill but tests
- # behaviour as per the Windows specification)
- self.set_attribute(user.dn, "userAccountControl",
- str(dsdb.UF_WORKSTATION_TRUST_ACCOUNT),
- operation=FLAG_MOD_REPLACE)
+ try:
+ # now clear the ADS_UF_NORMAL_ACCOUNT flag for the user, which should
+ # mean a resultant PSO is no longer returned (we're essentially turning
+ # the user into a DC here, which is a little overkill but tests
+ # behaviour as per the Windows specification)
+ self.set_attribute(user.dn, "userAccountControl",
+ str(dsdb.UF_WORKSTATION_TRUST_ACCOUNT),
+ operation=FLAG_MOD_REPLACE)
+ except ldb.LdbError as e:
+ (num, msg) = e.args
+ self.fail("Failed to change user into a workstation: {msg}")
self.assertIsNone(user.get_resultant_PSO())
- # reset it back to a normal user account
- self.set_attribute(user.dn, "userAccountControl",
- str(dsdb.UF_NORMAL_ACCOUNT),
- operation=FLAG_MOD_REPLACE)
+ try:
+ # reset it back to a normal user account
+ self.set_attribute(user.dn, "userAccountControl",
+ str(dsdb.UF_NORMAL_ACCOUNT),
+ operation=FLAG_MOD_REPLACE)
+ except ldb.LdbError as e:
+ (num, msg) = e.args
+ self.fail("Failed to change user back into a user: {msg}")
self.assertTrue(user.get_resultant_PSO() == dummy_pso.dn)
# no PSO should be returned if RID is equal to DOMAIN_USER_RID_KRBTGT
diff -Nru samba-4.13.3+dfsg/source4/dsdb/tests/python/priv_attrs.py samba-4.13.14+dfsg/source4/dsdb/tests/python/priv_attrs.py
--- samba-4.13.3+dfsg/source4/dsdb/tests/python/priv_attrs.py 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/tests/python/priv_attrs.py 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,398 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# This tests the restrictions on userAccountControl that apply even if write access is permitted
+#
+# Copyright Samuel Cabrero 2014
+# Copyright Andrew Bartlett 2014
+#
+# Licenced under the GPLv3
+#
+
+import optparse
+import sys
+import unittest
+import samba
+import samba.getopt as options
+import samba.tests
+import ldb
+import base64
+
+sys.path.insert(0, "bin/python")
+from samba.tests.subunitrun import TestProgram, SubunitOptions
+from samba.tests import DynamicTestCase
+from samba.subunit.run import SubunitTestRunner
+from samba.auth import system_session
+from samba.samdb import SamDB
+from samba.dcerpc import samr, security, lsa
+from samba.credentials import Credentials
+from samba.ndr import ndr_unpack, ndr_pack
+from samba.tests import delete_force
+from samba import gensec, sd_utils
+from samba.credentials import DONT_USE_KERBEROS
+from ldb import SCOPE_SUBTREE, SCOPE_BASE, LdbError
+from ldb import Message, MessageElement, Dn
+from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
+from samba.dsdb import UF_SCRIPT, UF_ACCOUNTDISABLE, UF_00000004, UF_HOMEDIR_REQUIRED, \
+ UF_LOCKOUT, UF_PASSWD_NOTREQD, UF_PASSWD_CANT_CHANGE, UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED,\
+ UF_TEMP_DUPLICATE_ACCOUNT, UF_NORMAL_ACCOUNT, UF_00000400, UF_INTERDOMAIN_TRUST_ACCOUNT, \
+ UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT, UF_00004000, \
+ UF_00008000, UF_DONT_EXPIRE_PASSWD, UF_MNS_LOGON_ACCOUNT, UF_SMARTCARD_REQUIRED, \
+ UF_TRUSTED_FOR_DELEGATION, UF_NOT_DELEGATED, UF_USE_DES_KEY_ONLY, UF_DONT_REQUIRE_PREAUTH, \
+ UF_PASSWORD_EXPIRED, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION, UF_NO_AUTH_DATA_REQUIRED, \
+ UF_PARTIAL_SECRETS_ACCOUNT, UF_USE_AES_KEYS
+
+
+parser = optparse.OptionParser("user_account_control.py [options] ")
+sambaopts = options.SambaOptions(parser)
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+
+# use command line creds if available
+credopts = options.CredentialsOptions(parser)
+parser.add_option_group(credopts)
+opts, args = parser.parse_args()
+
+if len(args) < 1:
+ parser.print_usage()
+ sys.exit(1)
+host = args[0]
+
+if "://" not in host:
+ ldaphost = "ldap://%s" % host
+else:
+ ldaphost = host
+ start = host.rindex("://")
+ host = host.lstrip(start + 3)
+
+lp = sambaopts.get_loadparm()
+creds = credopts.get_credentials(lp)
+creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
+
+
+"""
+Check the combinations of:
+
+rodc kdc
+a2d2
+useraccountcontrol (trusted for delegation)
+sidHistory
+
+x
+
+add
+modify(replace)
+modify(add)
+
+x
+
+sd WP on add
+cc default perms
+admin created, WP to user
+
+x
+
+computer
+user
+"""
+
+attrs = {"sidHistory":
+ {"value": ndr_pack(security.dom_sid(security.SID_BUILTIN_ADMINISTRATORS)),
+ "priv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS},
+
+ "msDS-AllowedToDelegateTo":
+ {"value": f"host/{host}",
+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS},
+
+ "userAccountControl-a2d-user":
+ {"attr": "userAccountControl",
+ "value": str(UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION|UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD),
+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS},
+
+ "userAccountControl-a2d-computer":
+ {"attr": "userAccountControl",
+ "value": str(UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION|UF_WORKSTATION_TRUST_ACCOUNT),
+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ "only-1": "computer"},
+
+ # This flag makes many legitimate authenticated clients
+ # send a forwardable ticket-granting-ticket to the server
+ "userAccountControl-t4d-user":
+ {"attr": "userAccountControl",
+ "value": str(UF_TRUSTED_FOR_DELEGATION|UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD),
+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS},
+
+ "userAccountControl-t4d-computer":
+ {"attr": "userAccountControl",
+ "value": str(UF_TRUSTED_FOR_DELEGATION|UF_WORKSTATION_TRUST_ACCOUNT),
+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ "only-1": "computer"},
+
+ "userAccountControl-DC":
+ {"attr": "userAccountControl",
+ "value": str(UF_SERVER_TRUST_ACCOUNT),
+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ "only-2": "computer"},
+
+ "userAccountControl-RODC":
+ {"attr": "userAccountControl",
+ "value": str(UF_PARTIAL_SECRETS_ACCOUNT|UF_WORKSTATION_TRUST_ACCOUNT),
+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ "only-1": "computer"},
+
+ "msDS-SecondaryKrbTgtNumber":
+ {"value": "65536",
+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS},
+ "primaryGroupID":
+ {"value": str(security.DOMAIN_RID_ADMINS),
+ "priv-error": ldb.ERR_UNWILLING_TO_PERFORM,
+ "unpriv-add-error": ldb.ERR_UNWILLING_TO_PERFORM,
+ "unpriv-error": ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS}
+ }
+
+
+
+@DynamicTestCase
+class PrivAttrsTests(samba.tests.TestCase):
+
+ def get_creds(self, target_username, target_password):
+ creds_tmp = Credentials()
+ creds_tmp.set_username(target_username)
+ creds_tmp.set_password(target_password)
+ creds_tmp.set_domain(creds.get_domain())
+ creds_tmp.set_realm(creds.get_realm())
+ creds_tmp.set_workstation(creds.get_workstation())
+ creds_tmp.set_gensec_features(creds_tmp.get_gensec_features()
+ | gensec.FEATURE_SEAL)
+ creds_tmp.set_kerberos_state(DONT_USE_KERBEROS) # kinit is too expensive to use in a tight loop
+ return creds_tmp
+
+ def assertGotLdbError(self, got, wanted):
+ if not self.strict_checking:
+ self.assertNotEqual(got, ldb.SUCCESS)
+ else:
+ self.assertEqual(got, wanted)
+
+ def setUp(self):
+ super().setUp()
+
+ strict_checking = samba.tests.env_get_var_value('STRICT_CHECKING', allow_missing=True)
+ if strict_checking is None:
+ strict_checking = '1'
+ self.strict_checking = bool(int(strict_checking))
+
+ self.admin_creds = creds
+ self.admin_samdb = SamDB(url=ldaphost, credentials=self.admin_creds, lp=lp)
+ self.domain_sid = security.dom_sid(self.admin_samdb.get_domain_sid())
+ self.base_dn = self.admin_samdb.domain_dn()
+
+ self.unpriv_user = "testuser1"
+ self.unpriv_user_pw = "samba123@"
+ self.unpriv_creds = self.get_creds(self.unpriv_user, self.unpriv_user_pw)
+
+ self.admin_sd_utils = sd_utils.SDUtils(self.admin_samdb)
+
+ self.test_ou_name = "OU=test_priv_attrs"
+ self.test_ou = self.test_ou_name + "," + self.base_dn
+
+ delete_force(self.admin_samdb, self.test_ou, controls=["tree_delete:0"])
+
+ self.admin_samdb.create_ou(self.test_ou)
+
+ expected_user_dn = f"CN={self.unpriv_user},{self.test_ou_name},{self.base_dn}"
+
+ self.admin_samdb.newuser(self.unpriv_user, self.unpriv_user_pw, userou=self.test_ou_name)
+ res = self.admin_samdb.search(expected_user_dn,
+ scope=SCOPE_BASE,
+ attrs=["objectSid"])
+
+ self.assertEqual(1, len(res))
+
+ self.unpriv_user_dn = res[0].dn
+ self.addCleanup(delete_force, self.admin_samdb, self.unpriv_user_dn, controls=["tree_delete:0"])
+
+ self.unpriv_user_sid = self.admin_sd_utils.get_object_sid(self.unpriv_user_dn)
+
+ self.unpriv_samdb = SamDB(url=ldaphost, credentials=self.unpriv_creds, lp=lp)
+
+ @classmethod
+ def setUpDynamicTestCases(cls):
+ for test_name in attrs.keys():
+ for add_or_mod in ["add", "mod-del-add", "mod-replace"]:
+ for permission in ["admin-add", "CC"]:
+ for sd in ["default", "WP"]:
+ for objectclass in ["computer", "user"]:
+ tname = f"{test_name}_{add_or_mod}_{permission}_{sd}_{objectclass}"
+ targs = (test_name,
+ add_or_mod,
+ permission,
+ sd,
+ objectclass)
+ cls.generate_dynamic_test("test_priv_attr",
+ tname,
+ *targs)
+
+ def add_computer_ldap(self, computername, others=None, samdb=None):
+ dn = "CN=%s,%s" % (computername, self.test_ou)
+ domainname = ldb.Dn(samdb, samdb.domain_dn()).canonical_str().replace("/", "")
+ samaccountname = "%s$" % computername
+ dnshostname = "%s.%s" % (computername, domainname)
+ msg_dict = {
+ "dn": dn,
+ "objectclass": "computer"}
+ if others is not None:
+ msg_dict = dict(list(msg_dict.items()) + list(others.items()))
+
+ msg = ldb.Message.from_dict(samdb, msg_dict)
+ msg["sAMAccountName"] = samaccountname
+
+ print("Adding computer account %s" % computername)
+ try:
+ samdb.add(msg)
+ except ldb.LdbError:
+ print(msg)
+ raise
+ return msg.dn
+
+ def add_user_ldap(self, username, others=None, samdb=None):
+ dn = "CN=%s,%s" % (username, self.test_ou)
+ domainname = ldb.Dn(samdb, samdb.domain_dn()).canonical_str().replace("/", "")
+ samaccountname = "%s$" % username
+ msg_dict = {
+ "dn": dn,
+ "objectclass": "user"}
+ if others is not None:
+ msg_dict = dict(list(msg_dict.items()) + list(others.items()))
+
+ msg = ldb.Message.from_dict(samdb, msg_dict)
+ msg["sAMAccountName"] = samaccountname
+
+ print("Adding user account %s" % username)
+ try:
+ samdb.add(msg)
+ except ldb.LdbError:
+ print(msg)
+ raise
+ return msg.dn
+
+ def add_thing_ldap(self, user, others, samdb, objectclass):
+ if objectclass == "user":
+ dn = self.add_user_ldap(user, others, samdb=samdb)
+ elif objectclass == "computer":
+ dn = self.add_computer_ldap(user, others, samdb=samdb)
+ return dn
+
+ def _test_priv_attr_with_args(self, test_name, add_or_mod, permission, sd, objectclass):
+ user="privattrs"
+ if "attr" in attrs[test_name]:
+ attr = attrs[test_name]["attr"]
+ else:
+ attr = test_name
+ if add_or_mod == "add":
+ others = {attr: attrs[test_name]["value"]}
+ else:
+ others = {}
+
+ if permission == "CC":
+ samdb = self.unpriv_samdb
+ # Set CC on container to allow user add
+ mod = "(OA;CI;CC;bf967aba-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.unpriv_user_sid)
+ self.admin_sd_utils.dacl_add_ace(self.test_ou, mod)
+ mod = "(OA;CI;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.unpriv_user_sid)
+ self.admin_sd_utils.dacl_add_ace(self.test_ou, mod)
+
+ else:
+ samdb = self.admin_samdb
+
+ if sd == "WP":
+ # Set SD to WP to the target user as part of add
+ sd = "O:%sG:DUD:(OA;CIID;RPWP;;;%s)(OA;;CR;00299570-246d-11d0-a768-00aa006e0529;;%s)" % (self.unpriv_user_sid, self.unpriv_user_sid, self.unpriv_user_sid)
+ tmp_desc = security.descriptor.from_sddl(sd, self.domain_sid)
+ others["ntSecurityDescriptor"] = ndr_pack(tmp_desc)
+
+ if add_or_mod == "add":
+
+ # only-1 and only-2 are due to windows behaviour
+
+ if "only-1" in attrs[test_name] and \
+ attrs[test_name]["only-1"] != objectclass:
+ try:
+ dn = self.add_thing_ldap(user, others, samdb, objectclass)
+ self.fail(f"{test_name}: Unexpectedly able to set {attr} on new {objectclass} as ADMIN (should fail LDAP_OBJECT_CLASS_VIOLATION)")
+ except LdbError as e5:
+ (enum, estr) = e5.args
+ self.assertGotLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION, enum)
+ elif permission == "CC":
+ try:
+ dn = self.add_thing_ldap(user, others, samdb, objectclass)
+ self.fail(f"{test_name}: Unexpectedly able to set {attr} on new {objectclass}")
+ except LdbError as e5:
+ (enum, estr) = e5.args
+ if "unpriv-add-error" in attrs[test_name]:
+ self.assertGotLdbError(attrs[test_name]["unpriv-add-error"], \
+ enum)
+ else:
+ self.assertGotLdbError(attrs[test_name]["unpriv-error"], \
+ enum)
+ elif "only-2" in attrs[test_name] and \
+ attrs[test_name]["only-2"] != objectclass:
+ try:
+ dn = self.add_thing_ldap(user, others, samdb, objectclass)
+ self.fail(f"{test_name}: Unexpectedly able to set {attr} on new {objectclass} as ADMIN (should fail LDAP_OBJECT_CLASS_VIOLATION)")
+ except LdbError as e5:
+ (enum, estr) = e5.args
+ self.assertGotLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION, enum)
+ elif "priv-error" in attrs[test_name]:
+ try:
+ dn = self.add_thing_ldap(user, others, samdb, objectclass)
+ self.fail(f"{test_name}: Unexpectedly able to set {attr} on new {objectclass} as ADMIN")
+ except LdbError as e5:
+ (enum, estr) = e5.args
+ self.assertGotLdbError(attrs[test_name]["priv-error"], enum)
+ else:
+ try:
+ dn = self.add_thing_ldap(user, others, samdb, objectclass)
+ except LdbError as e5:
+ (enum, estr) = e5.args
+ self.fail(f"Failed to add account {user} as objectclass {objectclass}")
+ else:
+ try:
+ dn = self.add_thing_ldap(user, others, samdb, objectclass)
+ except LdbError as e5:
+ (enum, estr) = e5.args
+ self.fail(f"Failed to add account {user} as objectclass {objectclass}")
+
+ if add_or_mod == "add":
+ return
+
+ m = ldb.Message()
+ m.dn = dn
+
+ # Do modify
+ if add_or_mod == "mod-del-add":
+ m["0"] = ldb.MessageElement([],
+ ldb.FLAG_MOD_DELETE,
+ attr)
+ m["1"] = ldb.MessageElement(attrs[test_name]["value"],
+ ldb.FLAG_MOD_ADD,
+ attr)
+ else:
+ m["0"] = ldb.MessageElement(attrs[test_name]["value"],
+ ldb.FLAG_MOD_REPLACE,
+ attr)
+
+ try:
+ self.unpriv_samdb.modify(m)
+ self.fail(f"{test_name}: Unexpectedly able to set {attr} on {m.dn}")
+ except LdbError as e5:
+ (enum, estr) = e5.args
+ self.assertGotLdbError(attrs[test_name]["unpriv-error"], enum)
+
+
+
+
+runner = SubunitTestRunner()
+rc = 0
+if not runner.run(unittest.makeSuite(PrivAttrsTests)).wasSuccessful():
+ rc = 1
+sys.exit(rc)
diff -Nru samba-4.13.3+dfsg/source4/dsdb/tests/python/rodc_rwdc.py samba-4.13.14+dfsg/source4/dsdb/tests/python/rodc_rwdc.py
--- samba-4.13.3+dfsg/source4/dsdb/tests/python/rodc_rwdc.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/tests/python/rodc_rwdc.py 2021-10-29 06:17:36.000000000 +0000
@@ -251,6 +251,10 @@
res = ldb_system.search(userdn, attrs=['unicodePwd'])
self.assertTrue('unicodePwd' in res[0])
+ # force replication here to flush any pending preloads (this
+ # was a racy test).
+ self.force_replication()
+
newpass = userpass + '!'
# Forcing replication should blank out password (when changed)
@@ -285,14 +289,14 @@
m = ldb.Message()
m.dn = ldb.Dn(self.ldb, self.base_dn)
- self.account_lockout_duration = 10
+ self.account_lockout_duration = 15
account_lockout_duration_ticks = -int(self.account_lockout_duration * (1e7))
m["lockoutDuration"] = ldb.MessageElement(str(account_lockout_duration_ticks),
ldb.FLAG_MOD_REPLACE,
"lockoutDuration")
- self.lockout_observation_window = 10
+ self.lockout_observation_window = 15
lockout_observation_window_ticks = -int(self.lockout_observation_window * (1e7))
m["lockOutObservationWindow"] = ldb.MessageElement(str(lockout_observation_window_ticks),
diff -Nru samba-4.13.3+dfsg/source4/dsdb/tests/python/sam.py samba-4.13.14+dfsg/source4/dsdb/tests/python/sam.py
--- samba-4.13.3+dfsg/source4/dsdb/tests/python/sam.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/tests/python/sam.py 2021-11-08 11:29:14.000000000 +0000
@@ -90,6 +90,7 @@
delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
delete_force(self.ldb, "cn=ldaptest\,specialuser,cn=users," + self.base_dn)
delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
+ delete_force(self.ldb, "cn=ldaptestcomputer2,cn=computers," + self.base_dn)
delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
@@ -291,7 +292,9 @@
ldb.add({
"dn": "cn=ldaptestuser,cn=users," + self.base_dn,
- "objectclass": "computer"})
+ "objectclass": "computer",
+ "userAccountControl": str(UF_NORMAL_ACCOUNT |
+ UF_PASSWD_NOTREQD)})
res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
scope=SCOPE_BASE, attrs=["primaryGroupID"])
@@ -1885,7 +1888,7 @@
delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
- def test_userAccountControl(self):
+ def test_userAccountControl_user_add_0_uac(self):
"""Test the userAccountControl behaviour"""
print("Testing userAccountControl behaviour\n")
@@ -1913,12 +1916,15 @@
self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_PASSWD_NOTREQD == 0)
delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ def test_userAccountControl_user_add_normal(self):
+ """Test the userAccountControl behaviour"""
ldb.add({
"dn": "cn=ldaptestuser,cn=users," + self.base_dn,
"objectclass": "user",
"userAccountControl": str(UF_NORMAL_ACCOUNT)})
delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ def test_userAccountControl_user_add_normal_pwnotreq(self):
ldb.add({
"dn": "cn=ldaptestuser,cn=users," + self.base_dn,
"objectclass": "user",
@@ -1933,6 +1939,7 @@
self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ def test_userAccountControl_user_add_normal_pwnotreq_lockout_expired(self):
ldb.add({
"dn": "cn=ldaptestuser,cn=users," + self.base_dn,
"objectclass": "user",
@@ -1952,6 +1959,7 @@
self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0)
delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ def test_userAccountControl_user_add_temp_dup(self):
try:
ldb.add({
"dn": "cn=ldaptestuser,cn=users," + self.base_dn,
@@ -1963,6 +1971,7 @@
self.assertEqual(num, ERR_OTHER)
delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ def test_userAccountControl_user_add_server(self):
try:
ldb.add({
"dn": "cn=ldaptestuser,cn=users," + self.base_dn,
@@ -1974,6 +1983,7 @@
self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ def test_userAccountControl_user_add_workstation(self):
try:
ldb.add({
"dn": "cn=ldaptestuser,cn=users," + self.base_dn,
@@ -1984,6 +1994,7 @@
self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ def test_userAccountControl_user_add_rodc(self):
try:
ldb.add({
"dn": "cn=ldaptestuser,cn=users," + self.base_dn,
@@ -1994,6 +2005,7 @@
self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ def test_userAccountControl_user_add_trust(self):
try:
ldb.add({
"dn": "cn=ldaptestuser,cn=users," + self.base_dn,
@@ -2007,6 +2019,7 @@
# Modify operation
+ def test_userAccountControl_user_modify(self):
ldb.add({
"dn": "cn=ldaptestuser,cn=users," + self.base_dn,
"objectclass": "user"})
@@ -2125,7 +2138,7 @@
self.fail()
except LdbError as e67:
(num, _) = e67.args
- self.assertEqual(num, ERR_UNWILLING_TO_PERFORM)
+ self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
m = Message()
m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
@@ -2144,7 +2157,7 @@
self.fail()
except LdbError as e68:
(num, _) = e68.args
- self.assertEqual(num, ERR_UNWILLING_TO_PERFORM)
+ self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
scope=SCOPE_BASE, attrs=["sAMAccountType"])
@@ -2177,6 +2190,7 @@
(num, _) = e69.args
self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ def test_userAccountControl_computer_add_0_uac(self):
# With a computer object
# Add operation
@@ -2196,17 +2210,19 @@
attrs=["sAMAccountType", "userAccountControl"])
self.assertTrue(len(res1) == 1)
self.assertEqual(int(res1[0]["sAMAccountType"][0]),
- ATYPE_NORMAL_ACCOUNT)
+ ATYPE_WORKSTATION_TRUST)
self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_PASSWD_NOTREQD == 0)
delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
+ def test_userAccountControl_computer_add_normal(self):
ldb.add({
"dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
"objectclass": "computer",
"userAccountControl": str(UF_NORMAL_ACCOUNT)})
delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
+ def test_userAccountControl_computer_add_normal_pwnotreqd(self):
ldb.add({
"dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
"objectclass": "computer",
@@ -2221,6 +2237,7 @@
self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
+ def test_userAccountControl_computer_add_normal_pwnotreqd_lockout_expired(self):
ldb.add({
"dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
"objectclass": "computer",
@@ -2240,6 +2257,7 @@
self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0)
delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
+ def test_userAccountControl_computer_add_temp_dup(self):
try:
ldb.add({
"dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
@@ -2251,6 +2269,7 @@
self.assertEqual(num, ERR_OTHER)
delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
+ def test_userAccountControl_computer_add_server(self):
ldb.add({
"dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
"objectclass": "computer",
@@ -2263,6 +2282,7 @@
ATYPE_WORKSTATION_TRUST)
delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
+ def test_userAccountControl_computer_add_workstation(self):
try:
ldb.add({
"dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
@@ -2273,6 +2293,7 @@
self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
+ def test_userAccountControl_computer_add_trust(self):
try:
ldb.add({
"dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
@@ -2281,9 +2302,10 @@
self.fail()
except LdbError as e72:
(num, _) = e72.args
- self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
+ def test_userAccountControl_computer_modify(self):
# Modify operation
ldb.add({
@@ -2296,7 +2318,7 @@
attrs=["sAMAccountType", "userAccountControl"])
self.assertTrue(len(res1) == 1)
self.assertEqual(int(res1[0]["sAMAccountType"][0]),
- ATYPE_NORMAL_ACCOUNT)
+ ATYPE_WORKSTATION_TRUST)
self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE != 0)
# As computer you can switch from a normal account to a workstation
@@ -2483,7 +2505,7 @@
self.fail()
except LdbError as e76:
(num, _) = e76.args
- self.assertEqual(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ self.assertEqual(num, ERR_OBJECT_CLASS_VIOLATION)
# "primaryGroupID" does not change if account type remains the same
@@ -2926,6 +2948,39 @@
delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ def test_isCriticalSystemObject_user(self):
+ """Test the isCriticalSystemObject behaviour"""
+ print("Testing isCriticalSystemObject behaviour\n")
+
+ # Add tests (of a user)
+
+ ldb.add({
+ "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
+ "objectclass": "user"})
+
+ res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
+ scope=SCOPE_BASE,
+ attrs=["isCriticalSystemObject"])
+ self.assertTrue(len(res1) == 1)
+ self.assertTrue("isCriticalSystemObject" not in res1[0])
+
+ # Modification tests
+ m = Message()
+
+ m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ m["userAccountControl"] = MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT),
+ FLAG_MOD_REPLACE, "userAccountControl")
+ ldb.modify(m)
+
+ res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
+ scope=SCOPE_BASE,
+ attrs=["isCriticalSystemObject"])
+ self.assertTrue(len(res1) == 1)
+ self.assertTrue("isCriticalSystemObject" in res1[0])
+ self.assertEqual(str(res1[0]["isCriticalSystemObject"][0]), "FALSE")
+
+ delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+
def test_isCriticalSystemObject(self):
"""Test the isCriticalSystemObject behaviour"""
print("Testing isCriticalSystemObject behaviour\n")
@@ -2940,7 +2995,8 @@
scope=SCOPE_BASE,
attrs=["isCriticalSystemObject"])
self.assertTrue(len(res1) == 1)
- self.assertTrue("isCriticalSystemObject" not in res1[0])
+ self.assertTrue("isCriticalSystemObject" in res1[0])
+ self.assertEqual(str(res1[0]["isCriticalSystemObject"][0]), "FALSE")
delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
@@ -3446,6 +3502,26 @@
delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
+ def test_service_principal_name_uniqueness(self):
+ """Test the servicePrincipalName uniqueness behaviour"""
+ print("Testing servicePrincipalName uniqueness behaviour")
+
+ ldb.add({
+ "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
+ "objectclass": "computer",
+ "servicePrincipalName": "HOST/testname.testdom"})
+
+ try:
+ ldb.add({
+ "dn": "cn=ldaptestcomputer2,cn=computers," + self.base_dn,
+ "objectclass": "computer",
+ "servicePrincipalName": "HOST/testname.testdom"})
+ except LdbError as e:
+ num, _ = e.args
+ self.assertEqual(num, ERR_CONSTRAINT_VIOLATION)
+ else:
+ self.fail()
+
def test_sam_description_attribute(self):
"""Test SAM description attribute"""
print("Test SAM description attribute")
diff -Nru samba-4.13.3+dfsg/source4/dsdb/tests/python/subtree_rename.py samba-4.13.14+dfsg/source4/dsdb/tests/python/subtree_rename.py
--- samba-4.13.3+dfsg/source4/dsdb/tests/python/subtree_rename.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/tests/python/subtree_rename.py 2021-11-08 11:29:14.000000000 +0000
@@ -201,31 +201,6 @@
attrs=['objectGUID'])
return str(misc.GUID(res[0]['objectGUID'][0]))
- def assertRaisesLdbError(self, errcode, message, f, *args, **kwargs):
- """Assert a function raises a particular LdbError."""
- try:
- f(*args, **kwargs)
- except ldb.LdbError as e:
- (num, msg) = e.args
- if num != errcode:
- lut = {v: k for k, v in vars(ldb).items()
- if k.startswith('ERR_') and isinstance(v, int)}
- self.fail("%s, expected "
- "LdbError %s, (%d) "
- "got %s (%d) "
- "%s" % (message,
- lut.get(errcode), errcode,
- lut.get(num), num,
- msg))
- else:
- lut = {v: k for k, v in vars(ldb).items()
- if k.startswith('ERR_') and isinstance(v, int)}
- self.fail("%s, expected "
- "LdbError %s, (%d) "
- "but we got success" % (message,
- lut.get(errcode),
- errcode))
-
def test_la_move_ou_tree(self):
tag = 'move_tree'
diff -Nru samba-4.13.3+dfsg/source4/dsdb/tests/python/user_account_control.py samba-4.13.14+dfsg/source4/dsdb/tests/python/user_account_control.py
--- samba-4.13.3+dfsg/source4/dsdb/tests/python/user_account_control.py 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/tests/python/user_account_control.py 2021-11-08 11:29:14.000000000 +0000
@@ -27,7 +27,7 @@
from samba.dcerpc import samr, security, lsa
from samba.credentials import Credentials
from samba.ndr import ndr_unpack, ndr_pack
-from samba.tests import delete_force
+from samba.tests import delete_force, DynamicTestCase
from samba import gensec, sd_utils
from samba.credentials import DONT_USE_KERBEROS
from ldb import SCOPE_SUBTREE, SCOPE_BASE, LdbError
@@ -41,6 +41,7 @@
UF_TRUSTED_FOR_DELEGATION, UF_NOT_DELEGATED, UF_USE_DES_KEY_ONLY, UF_DONT_REQUIRE_PREAUTH, \
UF_PASSWORD_EXPIRED, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION, UF_NO_AUTH_DATA_REQUIRED, \
UF_PARTIAL_SECRETS_ACCOUNT, UF_USE_AES_KEYS
+from samba import dsdb
parser = optparse.OptionParser("user_account_control.py [options] ")
@@ -83,14 +84,126 @@
UF_PARTIAL_SECRETS_ACCOUNT, UF_USE_AES_KEYS,
int("0x10000000", 16), int("0x20000000", 16), int("0x40000000", 16), int("0x80000000", 16)]
-account_types = set([UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT])
+account_types = set([UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT, UF_INTERDOMAIN_TRUST_ACCOUNT])
+@DynamicTestCase
class UserAccountControlTests(samba.tests.TestCase):
+ @classmethod
+ def setUpDynamicTestCases(cls):
+ for priv in [(True, "priv"), (False, "cc")]:
+ for account_type in [UF_NORMAL_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT,
+ UF_SERVER_TRUST_ACCOUNT]:
+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type)
+ for objectclass in ["computer", "user"]:
+ for name in [("oc_uac_lock$", "withdollar"), \
+ ("oc_uac_lock", "plain")]:
+ test_name = f"{account_type_str}_{objectclass}_{priv[1]}_{name[1]}"
+ cls.generate_dynamic_test("test_objectclass_uac_dollar_lock",
+ test_name,
+ account_type,
+ objectclass,
+ name[0],
+ priv[0])
+
+ for priv in [(True, "priv"), (False, "wp")]:
+ for account_type in [UF_NORMAL_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT,
+ UF_SERVER_TRUST_ACCOUNT]:
+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type)
+ for account_type2 in [UF_NORMAL_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT,
+ UF_SERVER_TRUST_ACCOUNT]:
+ for how in ["replace", "deladd"]:
+ account_type2_str = dsdb.user_account_control_flag_bit_to_string(account_type2)
+ test_name = f"{account_type_str}_{account_type2_str}_{how}_{priv[1]}"
+ cls.generate_dynamic_test("test_objectclass_uac_mod_lock",
+ test_name,
+ account_type,
+ account_type2,
+ how,
+ priv[0])
+
+ for objectclass in ["computer", "user"]:
+ account_types = [UF_NORMAL_ACCOUNT]
+ if objectclass == "computer":
+ account_types.append(UF_WORKSTATION_TRUST_ACCOUNT)
+ account_types.append(UF_SERVER_TRUST_ACCOUNT)
+
+ for account_type in account_types:
+ account_type_str = (
+ dsdb.user_account_control_flag_bit_to_string(
+ account_type))
+ for account_type2 in [UF_NORMAL_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT,
+ UF_SERVER_TRUST_ACCOUNT,
+ UF_PARTIAL_SECRETS_ACCOUNT,
+ None]:
+ if account_type2 is None:
+ account_type2_str = None
+ else:
+ account_type2_str = (
+ dsdb.user_account_control_flag_bit_to_string(
+ account_type2))
+
+ for objectclass2 in ["computer", "user", None]:
+ for name2 in [("oc_uac_lock", "remove_dollar"),
+ (None, "keep_dollar")]:
+ test_name = (f"{priv[1]}_{objectclass}_"
+ f"{account_type_str}_to_"
+ f"{objectclass2}_"
+ f"{account_type2_str}_"
+ f"{name2[1]}")
+ cls.generate_dynamic_test("test_mod_lock",
+ test_name,
+ objectclass,
+ objectclass2,
+ account_type,
+ account_type2,
+ name2[0],
+ priv[0])
+
+ for account_type in [UF_NORMAL_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT,
+ UF_SERVER_TRUST_ACCOUNT]:
+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type)
+ for objectclass in ["user", "computer"]:
+ for how in ["replace", "deladd"]:
+ test_name = f"{account_type_str}_{objectclass}_{how}"
+ cls.generate_dynamic_test("test_objectclass_mod_lock",
+ test_name,
+ account_type,
+ objectclass,
+ how)
+
+ for account_type in [UF_NORMAL_ACCOUNT, UF_WORKSTATION_TRUST_ACCOUNT]:
+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type)
+ cls.generate_dynamic_test("test_uac_bits_unrelated_modify",
+ account_type_str, account_type)
+
+ for bit in bits:
+ try:
+ bit_str = dsdb.user_account_control_flag_bit_to_string(bit)
+ except KeyError:
+ bit_str = hex(bit)
+
+ cls.generate_dynamic_test("test_uac_bits_add",
+ bit_str, bit, bit_str)
+
+ cls.generate_dynamic_test("test_uac_bits_set",
+ bit_str, bit, bit_str)
+
+ cls.generate_dynamic_test("test_uac_bits_add",
+ "UF_NORMAL_ACCOUNT_UF_PASSWD_NOTREQD",
+ UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD,
+ "UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD")
+
+
def add_computer_ldap(self, computername, others=None, samdb=None):
if samdb is None:
samdb = self.samdb
- dn = "CN=%s,OU=test_computer_ou1,%s" % (computername, self.base_dn)
+ dn = "CN=%s,%s" % (computername, self.OU)
domainname = ldb.Dn(self.samdb, self.samdb.domain_dn()).canonical_str().replace("/", "")
samaccountname = "%s$" % computername
dnshostname = "%s.%s" % (computername, domainname)
@@ -106,6 +219,23 @@
print("Adding computer account %s" % computername)
samdb.add(msg)
+ def add_user_ldap(self, username, others=None, samdb=None):
+ if samdb is None:
+ samdb = self.samdb
+ dn = "CN=%s,%s" % (username, self.OU)
+ samaccountname = "%s" % username
+ msg_dict = {
+ "dn": dn,
+ "objectclass": "user"}
+ if others is not None:
+ msg_dict = dict(list(msg_dict.items()) + list(others.items()))
+
+ msg = ldb.Message.from_dict(self.samdb, msg_dict)
+ msg["sAMAccountName"] = samaccountname
+
+ print("Adding user account %s" % username)
+ samdb.add(msg)
+
def get_creds(self, target_username, target_password):
creds_tmp = Credentials()
creds_tmp.set_username(target_username)
@@ -131,8 +261,9 @@
self.unpriv_user_pw = "samba123@"
self.unpriv_creds = self.get_creds(self.unpriv_user, self.unpriv_user_pw)
- delete_force(self.admin_samdb, "CN=testcomputer-t,OU=test_computer_ou1,%s" % (self.base_dn))
- delete_force(self.admin_samdb, "OU=test_computer_ou1,%s" % (self.base_dn))
+ self.OU = "OU=test_computer_ou1,%s" % (self.base_dn)
+
+ delete_force(self.admin_samdb, self.OU, controls=["tree_delete:0"])
delete_force(self.admin_samdb, "CN=%s,CN=Users,%s" % (self.unpriv_user, self.base_dn))
self.admin_samdb.newuser(self.unpriv_user, self.unpriv_user_pw)
@@ -143,6 +274,7 @@
self.unpriv_user_sid = ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
self.unpriv_user_dn = res[0].dn
+ self.addCleanup(self.admin_samdb.delete, self.unpriv_user_dn)
self.samdb = SamDB(url=ldaphost, credentials=self.unpriv_creds, lp=lp)
@@ -151,27 +283,28 @@
self.samr_domain = self.samr.OpenDomain(self.samr_handle, security.SEC_FLAG_MAXIMUM_ALLOWED, self.domain_sid)
self.sd_utils = sd_utils.SDUtils(self.admin_samdb)
+ self.admin_samdb.create_ou(self.OU)
+ self.addCleanup(self.admin_samdb.delete, self.OU, ["tree_delete:1"])
- self.admin_samdb.create_ou("OU=test_computer_ou1," + self.base_dn)
self.unpriv_user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn)
mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.unpriv_user_sid)
- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn)
+ old_sd = self.sd_utils.read_sd_on_dn(self.OU)
- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod)
+ self.sd_utils.dacl_add_ace(self.OU, mod)
self.add_computer_ldap("testcomputer-t")
- self.sd_utils.modify_sd_on_dn("OU=test_computer_ou1," + self.base_dn, old_sd)
+ self.sd_utils.modify_sd_on_dn(self.OU, old_sd)
self.computernames = ["testcomputer-0"]
# Get the SD of the template account, then force it to match
# what we expect for SeMachineAccountPrivilege accounts, so we
# can confirm we created the accounts correctly
- self.sd_reference_cc = self.sd_utils.read_sd_on_dn("CN=testcomputer-t,OU=test_computer_ou1,%s" % (self.base_dn))
+ self.sd_reference_cc = self.sd_utils.read_sd_on_dn("CN=testcomputer-t,%s" % (self.OU))
- self.sd_reference_modify = self.sd_utils.read_sd_on_dn("CN=testcomputer-t,OU=test_computer_ou1,%s" % (self.base_dn))
+ self.sd_reference_modify = self.sd_utils.read_sd_on_dn("CN=testcomputer-t,%s" % (self.OU))
for ace in self.sd_reference_modify.dacl.aces:
if ace.type == security.SEC_ACE_TYPE_ACCESS_ALLOWED and ace.trustee == self.unpriv_user_sid:
ace.access_mask = ace.access_mask | security.SEC_ADS_SELF_WRITE | security.SEC_ADS_WRITE_PROP
@@ -179,21 +312,12 @@
# Now reconnect without domain admin rights
self.samdb = SamDB(url=ldaphost, credentials=self.unpriv_creds, lp=lp)
- def tearDown(self):
- super(UserAccountControlTests, self).tearDown()
- for computername in self.computernames:
- delete_force(self.admin_samdb, "CN=%s,OU=test_computer_ou1,%s" % (computername, self.base_dn))
- delete_force(self.admin_samdb, "CN=testcomputer-t,OU=test_computer_ou1,%s" % (self.base_dn))
- delete_force(self.admin_samdb, "OU=test_computer_ou1,%s" % (self.base_dn))
- delete_force(self.admin_samdb, "CN=%s,CN=Users,%s" % (self.unpriv_user, self.base_dn))
-
def test_add_computer_sd_cc(self):
user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn)
mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid)
- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn)
-
- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod)
+ old_sd = self.sd_utils.read_sd_on_dn(self.OU)
+ self.sd_utils.dacl_add_ace(self.OU, mod)
computername = self.computernames[0]
sd = ldb.MessageElement((ndr_pack(self.sd_reference_modify)),
@@ -224,61 +348,54 @@
m.dn = res[0].dn
m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_SERVER_TRUST_ACCOUNT),
ldb.FLAG_MOD_REPLACE, "userAccountControl")
- try:
- self.samdb.modify(m)
- self.fail("Unexpectedly able to set userAccountControl to be a DC on %s" % m.dn)
- except LdbError as e5:
- (enum, estr) = e5.args
- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum)
+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ f"Unexpectedly able to set userAccountControl to be a DC on {m.dn}",
+ self.samdb.modify, m)
m = ldb.Message()
m.dn = res[0].dn
m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT |
samba.dsdb.UF_PARTIAL_SECRETS_ACCOUNT),
ldb.FLAG_MOD_REPLACE, "userAccountControl")
- try:
- self.samdb.modify(m)
- self.fail("Unexpectedly able to set userAccountControl to be an RODC on %s" % m.dn)
- except LdbError as e6:
- (enum, estr) = e6.args
- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum)
+
+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ f"Unexpectedly able to set userAccountControl to be a RODC on {m.dn}",
+ self.samdb.modify, m)
m = ldb.Message()
m.dn = res[0].dn
m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT),
ldb.FLAG_MOD_REPLACE, "userAccountControl")
- try:
- self.samdb.modify(m)
- self.fail("Unexpectedly able to set userAccountControl to be an Workstation on %s" % m.dn)
- except LdbError as e7:
- (enum, estr) = e7.args
- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum)
+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ f"Unexpectedly able to set userAccountControl to be a Workstation on {m.dn}",
+ self.samdb.modify, m)
m = ldb.Message()
m.dn = res[0].dn
- m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT),
+ m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD),
ldb.FLAG_MOD_REPLACE, "userAccountControl")
- self.samdb.modify(m)
+ try:
+ self.samdb.modify(m)
+ except LdbError as e:
+ (enum, estr) = e.args
+ self.fail(f"got {estr} setting userAccountControl to UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD")
m = ldb.Message()
m.dn = res[0].dn
m["primaryGroupID"] = ldb.MessageElement(str(security.DOMAIN_RID_ADMINS),
ldb.FLAG_MOD_REPLACE, "primaryGroupID")
- try:
- self.samdb.modify(m)
- except LdbError as e8:
- (enum, estr) = e8.args
- self.assertEqual(ldb.ERR_UNWILLING_TO_PERFORM, enum)
- return
- self.fail()
+ self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM,
+ f"Unexpectedly able to set primaryGroupID on {m.dn}",
+ self.samdb.modify, m)
+
def test_mod_computer_cc(self):
user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn)
mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid)
- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn)
+ old_sd = self.sd_utils.read_sd_on_dn(self.OU)
- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod)
+ self.sd_utils.dacl_add_ace(self.OU, mod)
computername = self.computernames[0]
self.add_computer_ldap(computername)
@@ -300,40 +417,79 @@
m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT |
samba.dsdb.UF_PARTIAL_SECRETS_ACCOUNT),
ldb.FLAG_MOD_REPLACE, "userAccountControl")
- try:
- self.samdb.modify(m)
- self.fail("Unexpectedly able to set userAccountControl on %s" % m.dn)
- except LdbError as e9:
- (enum, estr) = e9.args
- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum)
+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ f"Unexpectedly able to set userAccountControl as RODC on {m.dn}",
+ self.samdb.modify, m)
m = ldb.Message()
m.dn = res[0].dn
m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_SERVER_TRUST_ACCOUNT),
ldb.FLAG_MOD_REPLACE, "userAccountControl")
- try:
- self.samdb.modify(m)
- self.fail()
- except LdbError as e10:
- (enum, estr) = e10.args
- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum)
+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ f"Unexpectedly able to set userAccountControl as DC on {m.dn}",
+ self.samdb.modify, m)
m = ldb.Message()
m.dn = res[0].dn
- m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT),
+ m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD),
ldb.FLAG_MOD_REPLACE, "userAccountControl")
- self.samdb.modify(m)
+
+ self.assertRaisesLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION,
+ f"Unexpectedly able to set userAccountControl as to UF_NORMAL_ACCOUNT|UF_PASSWD_NOTREQD on {m.dn}",
+ self.samdb.modify, m)
m = ldb.Message()
m.dn = res[0].dn
m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT),
ldb.FLAG_MOD_REPLACE, "userAccountControl")
- try:
- self.samdb.modify(m)
- self.fail("Unexpectedly able to set userAccountControl to be an Workstation on %s" % m.dn)
- except LdbError as e11:
- (enum, estr) = e11.args
- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum)
+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ f"Unexpectedly able to set userAccountControl to be a workstation on {m.dn}",
+ self.samdb.modify, m)
+
+
+ def test_add_computer_cc_normal_bare(self):
+ user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn)
+ mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid)
+
+ old_sd = self.sd_utils.read_sd_on_dn(self.OU)
+ self.sd_utils.dacl_add_ace(self.OU, mod)
+
+ computername = self.computernames[0]
+ sd = ldb.MessageElement((ndr_pack(self.sd_reference_modify)),
+ ldb.FLAG_MOD_ADD,
+ "nTSecurityDescriptor")
+ self.add_computer_ldap(computername,
+ others={"nTSecurityDescriptor": sd})
+
+ res = self.admin_samdb.search("%s" % self.base_dn,
+ expression="(&(objectClass=computer)(samAccountName=%s$))" % computername,
+ scope=SCOPE_SUBTREE,
+ attrs=["ntSecurityDescriptor"])
+
+ desc = res[0]["nTSecurityDescriptor"][0]
+ desc = ndr_unpack(security.descriptor, desc, allow_remaining=True)
+
+ sddl = desc.as_sddl(self.domain_sid)
+ self.assertEqual(self.sd_reference_modify.as_sddl(self.domain_sid), sddl)
+
+ m = ldb.Message()
+ m.dn = res[0].dn
+ m["description"] = ldb.MessageElement(
+ ("A description"), ldb.FLAG_MOD_REPLACE,
+ "description")
+ self.samdb.modify(m)
+
+ m = ldb.Message()
+ m.dn = res[0].dn
+ m["userAccountControl"] = ldb.MessageElement(str(samba.dsdb.UF_NORMAL_ACCOUNT),
+ ldb.FLAG_MOD_REPLACE, "userAccountControl")
+ self.assertRaisesLdbError([ldb.ERR_OBJECT_CLASS_VIOLATION,
+ ldb.ERR_UNWILLING_TO_PERFORM],
+ f"Unexpectedly able to set userAccountControl to be an Normal "
+ "account without |UF_PASSWD_NOTREQD Unexpectedly able to "
+ "set userAccountControl to be a workstation on {m.dn}",
+ self.samdb.modify, m)
+
def test_admin_mod_uac(self):
computername = self.computernames[0]
@@ -344,7 +500,7 @@
scope=SCOPE_SUBTREE,
attrs=["userAccountControl"])
- self.assertEqual(int(res[0]["userAccountControl"][0]), (UF_NORMAL_ACCOUNT |
+ self.assertEqual(int(res[0]["userAccountControl"][0]), (UF_WORKSTATION_TRUST_ACCOUNT |
UF_ACCOUNTDISABLE |
UF_PASSWD_NOTREQD))
@@ -354,12 +510,11 @@
UF_PARTIAL_SECRETS_ACCOUNT |
UF_TRUSTED_FOR_DELEGATION),
ldb.FLAG_MOD_REPLACE, "userAccountControl")
- try:
- self.admin_samdb.modify(m)
- self.fail("Unexpectedly able to set userAccountControl to UF_WORKSTATION_TRUST_ACCOUNT|UF_PARTIAL_SECRETS_ACCOUNT|UF_TRUSTED_FOR_DELEGATION on %s" % m.dn)
- except LdbError as e12:
- (enum, estr) = e12.args
- self.assertEqual(ldb.ERR_OTHER, enum)
+ self.assertRaisesLdbError(ldb.ERR_OTHER,
+ f"Unexpectedly able to set userAccountControl to "
+ "UF_WORKSTATION_TRUST_ACCOUNT|UF_PARTIAL_SECRETS_ACCOUNT|"
+ "UF_TRUSTED_FOR_DELEGATION on {m.dn}",
+ self.admin_samdb.modify, m)
m = ldb.Message()
m.dn = res[0].dn
@@ -379,7 +534,11 @@
m.dn = res[0].dn
m["userAccountControl"] = ldb.MessageElement(str(UF_ACCOUNTDISABLE),
ldb.FLAG_MOD_REPLACE, "userAccountControl")
- self.admin_samdb.modify(m)
+ try:
+ self.admin_samdb.modify(m)
+ except LdbError as e:
+ (enum, estr) = e.args
+ self.fail(f"got {estr} setting userAccountControl to UF_ACCOUNTDISABLE (as admin)")
res = self.admin_samdb.search("%s" % self.base_dn,
expression="(&(objectClass=computer)(samAccountName=%s$))" % computername,
@@ -388,19 +547,23 @@
self.assertEqual(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE)
- def test_uac_bits_set(self):
+ def _test_uac_bits_set_with_args(self, bit, bit_str):
user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn)
- mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid)
+ # Allow the creation of any children and write to any
+ # attributes (this is not a test of ACLs, this is a test of
+ # non-ACL userAccountControl rules
+ mod = f"(OA;CI;WP;;;{user_sid})(OA;;CC;;;{user_sid})"
- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn)
+ old_sd = self.sd_utils.read_sd_on_dn(self.OU)
- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod)
+ self.sd_utils.dacl_add_ace(self.OU, mod)
+ # We want to start with UF_NORMAL_ACCOUNT, so we make a user
computername = self.computernames[0]
- self.add_computer_ldap(computername)
+ self.add_user_ldap(computername)
res = self.admin_samdb.search("%s" % self.base_dn,
- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername,
+ expression="(&(objectClass=user)(cn=%s))" % computername,
scope=SCOPE_SUBTREE,
attrs=[])
@@ -422,42 +585,60 @@
invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT, UF_PARTIAL_SECRETS_ACCOUNT])
- for bit in bits:
- m = ldb.Message()
- m.dn = res[0].dn
- m["userAccountControl"] = ldb.MessageElement(str(bit | UF_PASSWD_NOTREQD),
- ldb.FLAG_MOD_REPLACE, "userAccountControl")
- try:
- self.samdb.modify(m)
- if (bit in priv_bits):
- self.fail("Unexpectedly able to set userAccountControl bit 0x%08X on %s" % (bit, m.dn))
- except LdbError as e:
- (enum, estr) = e.args
- if bit in invalid_bits:
- self.assertEqual(enum, ldb.ERR_OTHER, "was not able to set 0x%08X on %s" % (bit, m.dn))
- # No point going on, try the next bit
- continue
- elif (bit in priv_bits):
- self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum)
- else:
- self.fail("Unable to set userAccountControl bit 0x%08X on %s: %s" % (bit, m.dn, estr))
+ m = ldb.Message()
+ m.dn = res[0].dn
+ m["userAccountControl"] = ldb.MessageElement(str(bit | UF_PASSWD_NOTREQD),
+ ldb.FLAG_MOD_REPLACE, "userAccountControl")
+ try:
+ self.samdb.modify(m)
+ if (bit in priv_bits):
+ self.fail("Unexpectedly able to set userAccountControl bit 0x%08X (%s), on %s"
+ % (bit, bit_str, m.dn))
+ if (bit in account_types and bit != UF_NORMAL_ACCOUNT):
+ self.fail("Unexpectedly able to set userAccountControl bit 0x%08X (%s), on %s"
+ % (bit, bit_str, m.dn))
+ except LdbError as e:
+ (enum, estr) = e.args
+ if bit in invalid_bits:
+ self.assertEqual(enum,
+ ldb.ERR_OTHER,
+ "was not able to set 0x%08X (%s) on %s"
+ % (bit, bit_str, m.dn))
+ elif (bit in account_types):
+ self.assertIn(enum, [ldb.ERR_OBJECT_CLASS_VIOLATION, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS])
+ elif (bit in priv_bits):
+ self.assertEqual(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS, enum)
+ else:
+ self.fail("Unable to set userAccountControl bit 0x%08X (%s) on %s: %s"
+ % (bit, bit_str, m.dn, estr))
- def uac_bits_unrelated_modify_helper(self, account_type):
+ def _test_uac_bits_unrelated_modify_with_args(self, account_type):
user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn)
- mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid)
- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn)
+ # Allow the creation of any children and write to any
+ # attributes (this is not a test of ACLs, this is a test of
+ # non-ACL userAccountControl rules
+ mod = f"(OA;CI;WP;;;{user_sid})(OA;;CC;;;{user_sid})"
+
+ old_sd = self.sd_utils.read_sd_on_dn(self.OU)
- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod)
+ self.sd_utils.dacl_add_ace(self.OU, mod)
computername = self.computernames[0]
- self.add_computer_ldap(computername, others={"userAccountControl": [str(account_type)]})
+ if account_type == UF_WORKSTATION_TRUST_ACCOUNT:
+ self.add_computer_ldap(computername)
+ else:
+ self.add_user_ldap(computername)
- res = self.admin_samdb.search("%s" % self.base_dn,
- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername,
+ res = self.admin_samdb.search(self.OU,
+ expression=f"(&(objectclass=user)(cn={computername}))",
scope=SCOPE_SUBTREE,
attrs=["userAccountControl"])
- self.assertEqual(int(res[0]["userAccountControl"][0]), account_type)
+ self.assertEqual(len(res), 1)
+
+ orig_uac = int(res[0]["userAccountControl"][0])
+ self.assertEqual(orig_uac & account_type,
+ account_type)
m = ldb.Message()
m.dn = res[0].dn
@@ -486,16 +667,22 @@
# Reset this to the initial position, just to be sure
m = ldb.Message()
m.dn = res[0].dn
- m["userAccountControl"] = ldb.MessageElement(str(account_type),
+ m["userAccountControl"] = ldb.MessageElement(str(orig_uac),
ldb.FLAG_MOD_REPLACE, "userAccountControl")
- self.admin_samdb.modify(m)
+ try:
+ self.admin_samdb.modify(m)
+ except LdbError as e:
+ (enum, estr) = e.args
+ self.fail(f"got {estr} resetting userAccountControl to initial value {orig_uac:#08x}")
res = self.admin_samdb.search("%s" % self.base_dn,
- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername,
+ expression="(&(objectClass=user)(cn=%s))" % computername,
scope=SCOPE_SUBTREE,
attrs=["userAccountControl"])
- self.assertEqual(int(res[0]["userAccountControl"][0]), account_type)
+ self.assertEqual(len(res), 1)
+ reset_uac = int(res[0]["userAccountControl"][0])
+ self.assertEqual(orig_uac, reset_uac)
m = ldb.Message()
m.dn = res[0].dn
@@ -503,6 +690,7 @@
ldb.FLAG_MOD_REPLACE, "userAccountControl")
try:
self.admin_samdb.modify(m)
+
if bit in invalid_bits:
self.fail("Should have been unable to set userAccountControl bit 0x%08X on %s" % (bit, m.dn))
@@ -513,14 +701,29 @@
# No point going on, try the next bit
continue
elif bit in super_priv_bits:
- self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ self.assertIn(enum, (ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ ldb.ERR_OBJECT_CLASS_VIOLATION))
# No point going on, try the next bit
continue
+
+ elif (account_type == UF_NORMAL_ACCOUNT) \
+ and (bit in account_types) \
+ and (bit != account_type):
+ self.assertIn(enum, (ldb.ERR_UNWILLING_TO_PERFORM,
+ ldb.ERR_OBJECT_CLASS_VIOLATION))
+ continue
+
+ elif (account_type == UF_WORKSTATION_TRUST_ACCOUNT) \
+ and (bit != UF_NORMAL_ACCOUNT) \
+ and (bit != account_type):
+ self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM)
+ continue
+
else:
self.fail("Unable to set userAccountControl bit 0x%08X on %s: %s" % (bit, m.dn, estr))
res = self.admin_samdb.search("%s" % self.base_dn,
- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername,
+ expression="(&(objectClass=user)(cn=%s))" % computername,
scope=SCOPE_SUBTREE,
attrs=["userAccountControl"])
@@ -550,7 +753,7 @@
self.fail("Unable to set userAccountControl bit 0x%08X on %s: %s" % (bit, m.dn, estr))
res = self.admin_samdb.search("%s" % self.base_dn,
- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername,
+ expression="(&(objectClass=user)(cn=%s))" % computername,
scope=SCOPE_SUBTREE,
attrs=["userAccountControl"])
@@ -585,13 +788,16 @@
except LdbError as e3:
(enum, estr) = e3.args
- if bit in priv_to_remove_bits:
+ if account_type == UF_WORKSTATION_TRUST_ACCOUNT:
+ # Because removing any bit would change the account back to a user, which is locked by objectclass
+ self.assertIn(enum, (ldb.ERR_OBJECT_CLASS_VIOLATION, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS))
+ elif bit in priv_to_remove_bits:
self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS)
else:
self.fail("Unexpectedly unable to remove userAccountControl bit 0x%08X on %s: %s" % (bit, m.dn, estr))
res = self.admin_samdb.search("%s" % self.base_dn,
- expression="(&(objectClass=computer)(samAccountName=%s$))" % computername,
+ expression="(&(objectClass=user)(cn=%s))" % computername,
scope=SCOPE_SUBTREE,
attrs=["userAccountControl"])
@@ -604,54 +810,76 @@
self.assertEqual(int(res[0]["userAccountControl"][0]),
bit | UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD,
"bit 0X%08x should not have been removed" % bit)
- else:
+ elif account_type != UF_WORKSTATION_TRUST_ACCOUNT:
self.assertEqual(int(res[0]["userAccountControl"][0]),
UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD,
"bit 0X%08x should have been removed" % bit)
- def test_uac_bits_unrelated_modify_normal(self):
- self.uac_bits_unrelated_modify_helper(UF_NORMAL_ACCOUNT)
-
- def test_uac_bits_unrelated_modify_workstation(self):
- self.uac_bits_unrelated_modify_helper(UF_WORKSTATION_TRUST_ACCOUNT)
-
- def test_uac_bits_add(self):
+ def _test_uac_bits_add_with_args(self, bit, bit_str):
computername = self.computernames[0]
user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn)
mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid)
- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn)
+ old_sd = self.sd_utils.read_sd_on_dn(self.OU)
- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod)
+ self.sd_utils.dacl_add_ace(self.OU, mod)
+
+ invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT])
+ # UF_NORMAL_ACCOUNT is invalid alone, needs UF_PASSWD_NOTREQD
+ unwilling_bits = set([UF_NORMAL_ACCOUNT])
- invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT, UF_PARTIAL_SECRETS_ACCOUNT])
# These bits are privileged, but authenticated users have that CAR by default, so this is a pain to test
priv_to_auth_users_bits = set([UF_PASSWD_NOTREQD, UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED,
UF_DONT_EXPIRE_PASSWD])
# These bits really are privileged
priv_bits = set([UF_INTERDOMAIN_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT,
- UF_TRUSTED_FOR_DELEGATION, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION])
+ UF_TRUSTED_FOR_DELEGATION, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
+ UF_PARTIAL_SECRETS_ACCOUNT])
- for bit in bits:
- try:
- self.add_computer_ldap(computername, others={"userAccountControl": [str(bit)]})
- delete_force(self.admin_samdb, "CN=%s,OU=test_computer_ou1,%s" % (computername, self.base_dn))
- if bit in priv_bits:
- self.fail("Unexpectdly able to set userAccountControl bit 0x%08X on %s" % (bit, computername))
+ if bit not in account_types and ((bit & UF_NORMAL_ACCOUNT) == 0):
+ bit_add = bit|UF_WORKSTATION_TRUST_ACCOUNT
+ else:
+ bit_add = bit
- except LdbError as e4:
- (enum, estr) = e4.args
- if bit in invalid_bits:
- self.assertEqual(enum, ldb.ERR_OTHER, "Invalid bit 0x%08X was able to be set on %s" % (bit, computername))
- # No point going on, try the next bit
- continue
- elif bit in priv_bits:
- self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS)
- continue
+ try:
+
+ self.add_computer_ldap(computername, others={"userAccountControl": [str(bit_add)]})
+ delete_force(self.admin_samdb, "CN=%s,%s" % (computername, self.OU))
+ if bit in priv_bits:
+ self.fail("Unexpectdly able to set userAccountControl bit 0x%08X (%s) on %s"
+ % (bit, bit_str, computername))
+
+ except LdbError as e4:
+ (enum, estr) = e4.args
+ if bit in invalid_bits:
+ self.assertEqual(enum,
+ ldb.ERR_OTHER,
+ "Invalid bit 0x%08X (%s) was able to be set on %s"
+ % (bit,
+ bit_str,
+ computername))
+ elif bit in priv_bits:
+ if bit == UF_INTERDOMAIN_TRUST_ACCOUNT:
+ self.assertIn(enum, (ldb.ERR_OBJECT_CLASS_VIOLATION,
+ ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS))
else:
- self.fail("Unable to set userAccountControl bit 0x%08X on %s: %s" % (bit, computername, estr))
+ self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ elif bit in unwilling_bits:
+ # This can fail early as user in a computer is not permitted as non-admin
+ self.assertIn(enum, (ldb.ERR_UNWILLING_TO_PERFORM,
+ ldb.ERR_OBJECT_CLASS_VIOLATION))
+ elif bit & UF_NORMAL_ACCOUNT:
+ # This can fail early as user in a computer is not permitted as non-admin
+ self.assertIn(enum, (ldb.ERR_UNWILLING_TO_PERFORM,
+ ldb.ERR_OBJECT_CLASS_VIOLATION))
+ else:
+ self.fail("Unable to set userAccountControl bit 0x%08X (%s) on %s: %s"
+ % (bit,
+ bit_str,
+ computername,
+ estr))
def test_primarygroupID_cc_add(self):
computername = self.computernames[0]
@@ -659,9 +887,9 @@
user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn)
mod = "(OA;;CC;bf967a86-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid)
- old_sd = self.sd_utils.read_sd_on_dn("OU=test_computer_ou1," + self.base_dn)
+ old_sd = self.sd_utils.read_sd_on_dn(self.OU)
- self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod)
+ self.sd_utils.dacl_add_ace(self.OU, mod)
try:
# When creating a new object, you can not ever set the primaryGroupID
self.add_computer_ldap(computername, others={"primaryGroupID": [str(security.DOMAIN_RID_ADMINS)]})
@@ -727,14 +955,10 @@
m["primaryGroupID"] = ldb.MessageElement(
[str(security.DOMAIN_RID_USERS)], ldb.FLAG_MOD_REPLACE,
"primaryGroupID")
- try:
- self.admin_samdb.modify(m)
- # When creating a new object, you can not ever set the primaryGroupID
- self.fail("Unexpectedly able to set primaryGroupID to be other than DCS on %s" % computername)
- except LdbError as e15:
- (enum, estr) = e15.args
- self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM)
+ self.assertRaisesLdbError(ldb.ERR_UNWILLING_TO_PERFORM,
+ f"Unexpectedly able to set primaryGroupID to be other than DCS on {m.dn}",
+ self.admin_samdb.modify, m)
def test_primarygroupID_priv_user_modify(self):
computername = self.computernames[0]
@@ -762,6 +986,321 @@
"primaryGroupID")
self.admin_samdb.modify(m)
+ def _test_objectclass_uac_dollar_lock_with_args(self,
+ account_type,
+ objectclass,
+ name,
+ priv):
+ dn = "CN=%s,%s" % (name, self.OU)
+ msg_dict = {
+ "dn": dn,
+ "objectclass": objectclass,
+ "samAccountName": name,
+ "userAccountControl": str(account_type | UF_PASSWD_NOTREQD)}
+
+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type)
+
+ print(f"Adding account {name} as {account_type_str} with objectclass {objectclass}")
+
+ if priv:
+ samdb = self.admin_samdb
+ else:
+ user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn)
+ mod = "(OA;;CC;;;%s)" % str(user_sid)
+
+ self.sd_utils.dacl_add_ace(self.OU, mod)
+ samdb = self.samdb
+
+ enum = ldb.SUCCESS
+ try:
+ samdb.add(msg_dict)
+ except ldb.LdbError as e:
+ (enum, msg) = e.args
+
+ if (account_type == UF_SERVER_TRUST_ACCOUNT
+ and objectclass != "computer"):
+ self.assertEqual(enum, ldb.ERR_OBJECT_CLASS_VIOLATION)
+ return
+
+ if priv == False and account_type == UF_SERVER_TRUST_ACCOUNT:
+ self.assertEqual(enum, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS)
+ return
+
+ if (objectclass == "user"
+ and account_type != UF_NORMAL_ACCOUNT):
+ self.assertEqual(enum, ldb.ERR_OBJECT_CLASS_VIOLATION)
+ return
+
+ if (not priv and objectclass == "computer"
+ and account_type == UF_NORMAL_ACCOUNT):
+ self.assertEqual(enum, ldb.ERR_OBJECT_CLASS_VIOLATION)
+ return
+
+ if priv and account_type == UF_NORMAL_ACCOUNT:
+ self.assertEqual(enum, 0)
+ return
+
+ if (priv == False and
+ account_type != UF_NORMAL_ACCOUNT and
+ name[-1] != '$'):
+ self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM)
+ return
+
+ self.assertEqual(enum, 0)
+
+ def _test_mod_lock_with_args(self,
+ objectclass,
+ objectclass2,
+ account_type,
+ account_type2,
+ name2,
+ priv):
+ name = "oc_uac_lock$"
+
+ dn = "CN=%s,%s" % (name, self.OU)
+ msg_dict = {
+ "dn": dn,
+ "objectclass": objectclass,
+ "samAccountName": name,
+ "userAccountControl": str(account_type | UF_PASSWD_NOTREQD)}
+
+ account_type_str = dsdb.user_account_control_flag_bit_to_string(
+ account_type)
+
+ print(f"Adding account {name} as {account_type_str} "
+ f"with objectclass {objectclass}")
+
+ # Create the object as admin
+ self.admin_samdb.add(msg_dict)
+
+ if priv:
+ samdb = self.admin_samdb
+ else:
+ samdb = self.samdb
+
+ user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn)
+
+ # We want to test what the underlying rules for non-admins regardless
+ # of security descriptors are, so set this very, dangerously, broadly
+ mod = f"(OA;;WP;;;{user_sid})"
+
+ self.sd_utils.dacl_add_ace(dn, mod)
+
+ msg = "Modifying account"
+ if name2 is not None:
+ msg += f" to {name2}"
+ if account_type2 is not None:
+ account_type2_str = dsdb.user_account_control_flag_bit_to_string(
+ account_type2)
+ msg += f" as {account_type2_str}"
+ else:
+ account_type2_str = None
+ if objectclass2 is not None:
+ msg += f" with objectClass {objectclass2}"
+ print(msg)
+
+ msg = ldb.Message(ldb.Dn(samdb, dn))
+ if objectclass2 is not None:
+ msg["objectClass"] = ldb.MessageElement(objectclass2,
+ ldb.FLAG_MOD_REPLACE,
+ "objectClass")
+ if name2 is not None:
+ msg["sAMAccountName"] = ldb.MessageElement(name2,
+ ldb.FLAG_MOD_REPLACE,
+ "sAMAccountName")
+ if account_type2 is not None:
+ msg["userAccountControl"] = ldb.MessageElement(
+ str(account_type2 | UF_PASSWD_NOTREQD),
+ ldb.FLAG_MOD_REPLACE,
+ "userAccountControl")
+ enum = ldb.SUCCESS
+ try:
+ samdb.modify(msg)
+ except ldb.LdbError as e:
+ enum, _ = e.args
+
+ # Setting userAccountControl to be an RODC is not allowed.
+ if account_type2 == UF_PARTIAL_SECRETS_ACCOUNT:
+ self.assertEqual(enum, ldb.ERR_OTHER)
+ return
+
+ # Unprivileged users cannot change userAccountControl. The exception is
+ # changing a non-normal account to UF_WORKSTATION_TRUST_ACCOUNT, which
+ # is allowed.
+ if (not priv
+ and account_type2 is not None
+ and account_type != account_type2
+ and (account_type == UF_NORMAL_ACCOUNT
+ or account_type2 != UF_WORKSTATION_TRUST_ACCOUNT)):
+ self.assertIn(enum, [ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ ldb.ERR_OBJECT_CLASS_VIOLATION])
+ return
+
+ # A non-computer account cannot have UF_SERVER_TRUST_ACCOUNT.
+ if objectclass == "user" and account_type2 == UF_SERVER_TRUST_ACCOUNT:
+ self.assertIn(enum, [ldb.ERR_UNWILLING_TO_PERFORM,
+ ldb.ERR_OBJECT_CLASS_VIOLATION])
+ return
+
+ # The objectClass is not allowed to change.
+ if objectclass2 is not None and objectclass != objectclass2:
+ self.assertIn(enum, [ldb.ERR_OBJECT_CLASS_VIOLATION,
+ ldb.ERR_UNWILLING_TO_PERFORM])
+ return
+
+ # Unprivileged users cannot remove the trailing dollar from a computer
+ # account.
+ if not priv and objectclass == "computer" and (
+ name2 is not None and name2[-1] != "$"):
+ self.assertEqual(enum, ldb.ERR_UNWILLING_TO_PERFORM)
+ return
+
+ self.assertEqual(enum, 0)
+ return
+
+ def _test_objectclass_uac_mod_lock_with_args(self,
+ account_type,
+ account_type2,
+ how,
+ priv):
+ name = "uac_mod_lock$"
+ dn = "CN=%s,%s" % (name, self.OU)
+ if account_type == UF_NORMAL_ACCOUNT:
+ objectclass = "user"
+ else:
+ objectclass = "computer"
+
+ msg_dict = {
+ "dn": dn,
+ "objectclass": objectclass,
+ "samAccountName": name,
+ "userAccountControl": str(account_type | UF_PASSWD_NOTREQD)}
+
+ account_type_str \
+ = dsdb.user_account_control_flag_bit_to_string(account_type)
+ account_type2_str \
+ = dsdb.user_account_control_flag_bit_to_string(account_type2)
+
+ print(f"Adding account {name} as {account_type_str} with objectclass {objectclass}")
+
+ if priv:
+ samdb = self.admin_samdb
+ else:
+ samdb = self.samdb
+
+ user_sid = self.sd_utils.get_object_sid(self.unpriv_user_dn)
+
+ # Create the object as admin
+ self.admin_samdb.add(msg_dict)
+
+ # We want to test what the underlying rules for non-admins
+ # regardless of security descriptors are, so set this very,
+ # dangerously, broadly
+ mod = "(OA;;WP;;;%s)" % str(user_sid)
+
+ self.sd_utils.dacl_add_ace(dn, mod)
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(samdb, dn)
+ if how == "replace":
+ m["userAccountControl"] = ldb.MessageElement(str(account_type2 | UF_PASSWD_NOTREQD),
+ ldb.FLAG_MOD_REPLACE, "userAccountControl")
+ elif how == "deladd":
+ m["0userAccountControl"] = ldb.MessageElement([],
+ ldb.FLAG_MOD_DELETE, "userAccountControl")
+ m["1userAccountControl"] = ldb.MessageElement(str(account_type2 | UF_PASSWD_NOTREQD),
+ ldb.FLAG_MOD_ADD, "userAccountControl")
+ else:
+ raise ValueError(f"{how} was not a valid argument")
+
+ if (account_type == account_type2):
+ samdb.modify(m)
+ elif (account_type == UF_NORMAL_ACCOUNT) and \
+ (account_type2 == UF_SERVER_TRUST_ACCOUNT) and not priv:
+ self.assertRaisesLdbError([ldb.ERR_OBJECT_CLASS_VIOLATION,
+ ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS],
+ f"Should have been unable to change {account_type_str} to {account_type2_str}",
+ samdb.modify, m)
+ elif (account_type == UF_NORMAL_ACCOUNT) and \
+ (account_type2 == UF_SERVER_TRUST_ACCOUNT) and priv:
+ self.assertRaisesLdbError([ldb.ERR_OBJECT_CLASS_VIOLATION,
+ ldb.ERR_UNWILLING_TO_PERFORM],
+ f"Should have been unable to change {account_type_str} to {account_type2_str}",
+ samdb.modify, m)
+ elif (account_type == UF_WORKSTATION_TRUST_ACCOUNT) and \
+ (account_type2 == UF_SERVER_TRUST_ACCOUNT) and not priv:
+ self.assertRaisesLdbError(ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS,
+ f"Should have been unable to change {account_type_str} to {account_type2_str}",
+ samdb.modify, m)
+ elif priv:
+ samdb.modify(m)
+ elif (account_type in [UF_SERVER_TRUST_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT]) and \
+ (account_type2 in [UF_SERVER_TRUST_ACCOUNT,
+ UF_WORKSTATION_TRUST_ACCOUNT]):
+ samdb.modify(m)
+ elif (account_type == account_type2):
+ samdb.modify(m)
+ else:
+ self.assertRaisesLdbError(ldb.ERR_OBJECT_CLASS_VIOLATION,
+ f"Should have been unable to change {account_type_str} to {account_type2_str}",
+ samdb.modify, m)
+
+ def _test_objectclass_mod_lock_with_args(self,
+ account_type,
+ objectclass,
+ how):
+ name = "uac_mod_lock$"
+ dn = "CN=%s,%s" % (name, self.OU)
+ if objectclass == "computer":
+ new_objectclass = ["top",
+ "person",
+ "organizationalPerson",
+ "user"]
+ elif objectclass == "user":
+ new_objectclass = ["top",
+ "person",
+ "organizationalPerson",
+ "user",
+ "computer"]
+
+ msg_dict = {
+ "dn": dn,
+ "objectclass": objectclass,
+ "samAccountName": name,
+ "userAccountControl": str(account_type | UF_PASSWD_NOTREQD)}
+
+ account_type_str = dsdb.user_account_control_flag_bit_to_string(account_type)
+
+ print(f"Adding account {name} as {account_type_str} with objectclass {objectclass}")
+
+ try:
+ self.admin_samdb.add(msg_dict)
+ if (objectclass == "user" \
+ and account_type != UF_NORMAL_ACCOUNT):
+ self.fail("Able to create {account_type_str} on {objectclass}")
+ except LdbError as e:
+ (enum, estr) = e.args
+ self.assertEqual(enum, ldb.ERR_OBJECT_CLASS_VIOLATION)
+
+ if objectclass == "user" and account_type != UF_NORMAL_ACCOUNT:
+ return
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.admin_samdb, dn)
+ if how == "replace":
+ m["objectclass"] = ldb.MessageElement(new_objectclass,
+ ldb.FLAG_MOD_REPLACE, "objectclass")
+ elif how == "adddel":
+ m["0objectclass"] = ldb.MessageElement([],
+ ldb.FLAG_MOD_DELETE, "objectclass")
+ m["1objectclass"] = ldb.MessageElement(new_objectclass,
+ ldb.FLAG_MOD_ADD, "objectclass")
+
+ self.assertRaisesLdbError([ldb.ERR_OBJECT_CLASS_VIOLATION,
+ ldb.ERR_UNWILLING_TO_PERFORM],
+ "Should have been unable Able to change objectclass of a {objectclass}",
+ self.admin_samdb.modify, m)
runner = SubunitTestRunner()
rc = 0
diff -Nru samba-4.13.3+dfsg/source4/dsdb/wscript_build samba-4.13.14+dfsg/source4/dsdb/wscript_build
--- samba-4.13.3+dfsg/source4/dsdb/wscript_build 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/dsdb/wscript_build 2021-11-08 11:29:14.000000000 +0000
@@ -13,7 +13,7 @@
)
bld.SAMBA_LIBRARY('samdb-common',
- source='common/util.c common/util_trusts.c common/util_groups.c common/util_samr.c common/dsdb_dn.c common/dsdb_access.c common/util_links.c',
+ source='common/util.c common/util_trusts.c common/util_groups.c common/util_samr.c common/dsdb_dn.c common/dsdb_access.c common/util_links.c common/rodc_helper.c',
autoproto='common/proto.h',
private_library=True,
deps='ldb NDR_DRSBLOBS util_ldb LIBCLI_AUTH samba-hostconfig samba_socket cli-ldap-common flag_mapping UTIL_RUNCMD'
diff -Nru samba-4.13.3+dfsg/source4/heimdal/kdc/kerberos5.c samba-4.13.14+dfsg/source4/heimdal/kdc/kerberos5.c
--- samba-4.13.3+dfsg/source4/heimdal/kdc/kerberos5.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/heimdal/kdc/kerberos5.c 2021-11-08 11:29:14.000000000 +0000
@@ -913,27 +913,30 @@
*/
static krb5_boolean
-send_pac_p(krb5_context context, KDC_REQ *req)
+send_pac_p(krb5_context context, KDC_REQ *req, krb5_boolean *pac_request)
{
krb5_error_code ret;
PA_PAC_REQUEST pacreq;
const PA_DATA *pa;
int i = 0;
+ *pac_request = TRUE;
+
pa = _kdc_find_padata(req, &i, KRB5_PADATA_PA_PAC_REQUEST);
if (pa == NULL)
- return TRUE;
+ return FALSE;
ret = decode_PA_PAC_REQUEST(pa->padata_value.data,
pa->padata_value.length,
&pacreq,
NULL);
if (ret)
- return TRUE;
+ return FALSE;
i = pacreq.include_pac;
free_PA_PAC_REQUEST(&pacreq);
- if (i == 0)
- return FALSE;
+ if (i == 0) {
+ *pac_request = FALSE;
+ }
return TRUE;
}
@@ -948,6 +951,33 @@
return 1;
}
+static krb5_error_code
+get_local_tgs(krb5_context context,
+ krb5_kdc_configuration *config,
+ krb5_const_realm realm,
+ hdb_entry_ex **krbtgt)
+{
+ krb5_error_code ret;
+ krb5_principal tgs_name;
+
+ *krbtgt = NULL;
+
+ ret = krb5_make_principal(context,
+ &tgs_name,
+ realm,
+ KRB5_TGS_NAME,
+ realm,
+ NULL);
+ if (ret)
+ return ret;
+
+ ret = _kdc_db_fetch(context, config, tgs_name,
+ HDB_F_GET_KRBTGT, NULL, NULL, krbtgt);
+ krb5_free_principal(context, tgs_name);
+
+ return ret;
+}
+
/*
*
*/
@@ -983,6 +1013,9 @@
pk_client_params *pkp = NULL;
#endif
const EncryptionKey *pk_reply_key = NULL;
+ krb5_boolean is_tgs;
+ hdb_entry_ex *krbtgt = NULL;
+ Key *krbtgt_key = NULL;
memset(&rep, 0, sizeof(rep));
memset(&session_key, 0, sizeof(session_key));
@@ -996,7 +1029,7 @@
flags |= HDB_F_CANON;
if(b->sname == NULL){
- ret = KRB5KRB_ERR_GENERIC;
+ ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
e_text = "No server in request";
} else{
ret = _krb5_principalname2krb5_principal (context,
@@ -1012,7 +1045,7 @@
goto out;
}
if(b->cname == NULL){
- ret = KRB5KRB_ERR_GENERIC;
+ ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
e_text = "No client in request";
} else {
ret = _krb5_principalname2krb5_principal (context,
@@ -1033,6 +1066,8 @@
kdc_log(context, config, 0, "AS-REQ %s from %s for %s",
client_name, from, server_name);
+ is_tgs = krb5_principal_is_krbtgt(context, server_princ);
+
/*
*
*/
@@ -1101,7 +1136,7 @@
goto out;
}
ret = _kdc_db_fetch(context, config, server_princ,
- HDB_F_GET_SERVER|HDB_F_GET_KRBTGT | flags,
+ HDB_F_GET_SERVER | flags | (is_tgs ? HDB_F_GET_KRBTGT : 0),
NULL, NULL, &server);
if(ret == HDB_ERR_NOT_FOUND_HERE) {
kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", server_name);
@@ -1463,6 +1498,22 @@
if(ret)
goto out;
+ /* If server is not krbtgt, fetch local krbtgt key for signing authdata */
+ if (is_tgs) {
+ krbtgt_key = skey;
+ } else {
+ ret = get_local_tgs(context, config, server_princ->realm,
+ &krbtgt);
+ if (ret)
+ goto out;
+
+ ret = _kdc_get_preferred_key(context, config, krbtgt,
+ server_princ->realm,
+ NULL, &krbtgt_key);
+ if (ret)
+ goto out;
+ }
+
if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
|| (f.request_anonymous && !config->allow_anonymous)) {
ret = KRB5KDC_ERR_BADOPTION;
@@ -1709,22 +1760,42 @@
}
/* Add the PAC */
- if (send_pac_p(context, req)) {
+ {
krb5_pac p = NULL;
krb5_data data;
-
- ret = _kdc_pac_generate(context, client, pk_reply_key, &p);
+ uint16_t rodc_id;
+ krb5_principal client_pac;
+ krb5_boolean sent_pac_request;
+ krb5_boolean pac_request;
+
+ sent_pac_request = send_pac_p(context, req, &pac_request);
+
+ ret = _kdc_pac_generate(context, client, pk_reply_key,
+ sent_pac_request ? &pac_request : NULL,
+ &p);
if (ret) {
kdc_log(context, config, 0, "PAC generation failed for -- %s",
client_name);
goto out;
}
if (p != NULL) {
+ rodc_id = server->entry.kvno >> 16;
+
+ /* libkrb5 expects ticket and PAC client names to match */
+ ret = _krb5_principalname2krb5_principal(context, &client_pac,
+ et.cname, et.crealm);
+ if (ret) {
+ krb5_pac_free(context, p);
+ goto out;
+ }
+
ret = _krb5_pac_sign(context, p, et.authtime,
- client->entry.principal,
+ client_pac,
&skey->key, /* Server key */
- &skey->key, /* FIXME: should be krbtgt key */
+ &krbtgt_key->key, /* TGS key */
+ rodc_id,
&data);
+ krb5_free_principal(context, client_pac);
krb5_pac_free(context, p);
if (ret) {
kdc_log(context, config, 0, "PAC signing failed for -- %s",
@@ -1732,9 +1803,7 @@
goto out;
}
- ret = _kdc_tkt_add_if_relevant_ad(context, &et,
- KRB5_AUTHDATA_WIN2K_PAC,
- &data);
+ ret = _kdc_tkt_insert_pac(context, &et, &data);
krb5_data_free(&data);
if (ret)
goto out;
@@ -1744,18 +1813,6 @@
_kdc_log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime,
et.endtime, et.renew_till);
- /* do this as the last thing since this signs the EncTicketPart */
- ret = _kdc_add_KRB5SignedPath(context,
- config,
- server,
- setype,
- client->entry.principal,
- NULL,
- NULL,
- &et);
- if (ret)
- goto out;
-
log_as_req(context, config, reply_key->keytype, setype, b);
ret = _kdc_encode_reply(context, config,
@@ -1804,6 +1861,8 @@
_kdc_free_ent(context, client);
if(server)
_kdc_free_ent(context, server);
+ if (krbtgt)
+ _kdc_free_ent(context, krbtgt);
return ret;
}
@@ -1900,64 +1959,3 @@
return TRUE;
}
-
-/*
- * Add the AuthorizationData `data´ of `type´ to the last element in
- * the sequence of authorization_data in `tkt´ wrapped in an IF_RELEVANT
- */
-
-krb5_error_code
-_kdc_tkt_add_if_relevant_ad(krb5_context context,
- EncTicketPart *tkt,
- int type,
- const krb5_data *data)
-{
- krb5_error_code ret;
- size_t size = 0;
-
- if (tkt->authorization_data == NULL) {
- tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
- if (tkt->authorization_data == NULL) {
- krb5_set_error_message(context, ENOMEM, "out of memory");
- return ENOMEM;
- }
- }
-
- /* add the entry to the last element */
- {
- AuthorizationData ad = { 0, NULL };
- AuthorizationDataElement ade;
-
- ade.ad_type = type;
- ade.ad_data = *data;
-
- ret = add_AuthorizationData(&ad, &ade);
- if (ret) {
- krb5_set_error_message(context, ret, "add AuthorizationData failed");
- return ret;
- }
-
- ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
-
- ASN1_MALLOC_ENCODE(AuthorizationData,
- ade.ad_data.data, ade.ad_data.length,
- &ad, &size, ret);
- free_AuthorizationData(&ad);
- if (ret) {
- krb5_set_error_message(context, ret, "ASN.1 encode of "
- "AuthorizationData failed");
- return ret;
- }
- if (ade.ad_data.length != size)
- krb5_abortx(context, "internal asn.1 encoder error");
-
- ret = add_AuthorizationData(tkt->authorization_data, &ade);
- der_free_octet_string(&ade.ad_data);
- if (ret) {
- krb5_set_error_message(context, ret, "add AuthorizationData failed");
- return ret;
- }
- }
-
- return 0;
-}
diff -Nru samba-4.13.3+dfsg/source4/heimdal/kdc/krb5tgs.c samba-4.13.14+dfsg/source4/heimdal/kdc/krb5tgs.c
--- samba-4.13.3+dfsg/source4/heimdal/kdc/krb5tgs.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/heimdal/kdc/krb5tgs.c 2021-11-08 11:29:14.000000000 +0000
@@ -48,230 +48,6 @@
}
/*
- * The KDC might add a signed path to the ticket authorization data
- * field. This is to avoid server impersonating clients and the
- * request constrained delegation.
- *
- * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
- * entry of type KRB5SignedPath.
- */
-
-static krb5_error_code
-find_KRB5SignedPath(krb5_context context,
- const AuthorizationData *ad,
- krb5_data *data)
-{
- AuthorizationData child;
- krb5_error_code ret;
- int pos;
-
- if (ad == NULL || ad->len == 0)
- return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
-
- pos = ad->len - 1;
-
- if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
- return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
-
- ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
- ad->val[pos].ad_data.length,
- &child,
- NULL);
- if (ret) {
- krb5_set_error_message(context, ret, "Failed to decode "
- "IF_RELEVANT with %d", ret);
- return ret;
- }
-
- if (child.len != 1) {
- free_AuthorizationData(&child);
- return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
- }
-
- if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
- free_AuthorizationData(&child);
- return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
- }
-
- if (data)
- ret = der_copy_octet_string(&child.val[0].ad_data, data);
- free_AuthorizationData(&child);
- return ret;
-}
-
-krb5_error_code
-_kdc_add_KRB5SignedPath(krb5_context context,
- krb5_kdc_configuration *config,
- hdb_entry_ex *krbtgt,
- krb5_enctype enctype,
- krb5_principal client,
- krb5_const_principal server,
- krb5_principals principals,
- EncTicketPart *tkt)
-{
- krb5_error_code ret;
- KRB5SignedPath sp;
- krb5_data data;
- krb5_crypto crypto = NULL;
- size_t size = 0;
-
- if (server && principals) {
- ret = add_Principals(principals, server);
- if (ret)
- return ret;
- }
-
- {
- KRB5SignedPathData spd;
-
- spd.client = client;
- spd.authtime = tkt->authtime;
- spd.delegated = principals;
- spd.method_data = NULL;
-
- ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
- &spd, &size, ret);
- if (ret)
- return ret;
- if (data.length != size)
- krb5_abortx(context, "internal asn.1 encoder error");
- }
-
- {
- Key *key;
- ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
- if (ret == 0)
- ret = krb5_crypto_init(context, &key->key, 0, &crypto);
- if (ret) {
- free(data.data);
- return ret;
- }
- }
-
- /*
- * Fill in KRB5SignedPath
- */
-
- sp.etype = enctype;
- sp.delegated = principals;
- sp.method_data = NULL;
-
- ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
- data.data, data.length, &sp.cksum);
- krb5_crypto_destroy(context, crypto);
- free(data.data);
- if (ret)
- return ret;
-
- ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
- free_Checksum(&sp.cksum);
- if (ret)
- return ret;
- if (data.length != size)
- krb5_abortx(context, "internal asn.1 encoder error");
-
-
- /*
- * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
- * authorization data field.
- */
-
- ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
- KRB5_AUTHDATA_SIGNTICKET, &data);
- krb5_data_free(&data);
-
- return ret;
-}
-
-static krb5_error_code
-check_KRB5SignedPath(krb5_context context,
- krb5_kdc_configuration *config,
- hdb_entry_ex *krbtgt,
- krb5_principal cp,
- EncTicketPart *tkt,
- krb5_principals *delegated,
- int *signedpath)
-{
- krb5_error_code ret;
- krb5_data data;
- krb5_crypto crypto = NULL;
-
- if (delegated)
- *delegated = NULL;
-
- ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
- if (ret == 0) {
- KRB5SignedPathData spd;
- KRB5SignedPath sp;
- size_t size = 0;
-
- ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
- krb5_data_free(&data);
- if (ret)
- return ret;
-
- spd.client = cp;
- spd.authtime = tkt->authtime;
- spd.delegated = sp.delegated;
- spd.method_data = sp.method_data;
-
- ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
- &spd, &size, ret);
- if (ret) {
- free_KRB5SignedPath(&sp);
- return ret;
- }
- if (data.length != size)
- krb5_abortx(context, "internal asn.1 encoder error");
-
- {
- Key *key;
- ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
- if (ret == 0)
- ret = krb5_crypto_init(context, &key->key, 0, &crypto);
- if (ret) {
- free(data.data);
- free_KRB5SignedPath(&sp);
- return ret;
- }
- }
- ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
- data.data, data.length,
- &sp.cksum);
- krb5_crypto_destroy(context, crypto);
- free(data.data);
- if (ret) {
- free_KRB5SignedPath(&sp);
- kdc_log(context, config, 5,
- "KRB5SignedPath not signed correctly, not marking as signed");
- return 0;
- }
-
- if (delegated && sp.delegated) {
-
- *delegated = malloc(sizeof(*sp.delegated));
- if (*delegated == NULL) {
- free_KRB5SignedPath(&sp);
- return ENOMEM;
- }
-
- ret = copy_Principals(*delegated, sp.delegated);
- if (ret) {
- free_KRB5SignedPath(&sp);
- free(*delegated);
- *delegated = NULL;
- return ret;
- }
- }
- free_KRB5SignedPath(&sp);
-
- *signedpath = 1;
- }
-
- return 0;
-}
-
-/*
*
*/
@@ -283,85 +59,67 @@
hdb_entry_ex *client,
hdb_entry_ex *server,
hdb_entry_ex *krbtgt,
+ hdb_entry_ex *ticket_server,
const EncryptionKey *server_check_key,
- const EncryptionKey *server_sign_key,
- const EncryptionKey *krbtgt_sign_key,
+ const EncryptionKey *krbtgt_check_key,
EncTicketPart *tkt,
- krb5_data *rspac,
- int *signedpath)
+ krb5_boolean *kdc_issued,
+ krb5_pac *ppac)
{
- AuthorizationData *ad = tkt->authorization_data;
- unsigned i, j;
+ krb5_pac pac = NULL;
krb5_error_code ret;
+ krb5_boolean signedticket;
- if (ad == NULL || ad->len == 0)
- return 0;
-
- for (i = 0; i < ad->len; i++) {
- AuthorizationData child;
-
- if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
- continue;
+ *kdc_issued = FALSE;
+ *ppac = NULL;
- ret = decode_AuthorizationData(ad->val[i].ad_data.data,
- ad->val[i].ad_data.length,
- &child,
- NULL);
- if (ret) {
- krb5_set_error_message(context, ret, "Failed to decode "
- "IF_RELEVANT with %d", ret);
- return ret;
- }
- for (j = 0; j < child.len; j++) {
-
- if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
- int signed_pac = 0;
- krb5_pac pac;
-
- /* Found PAC */
- ret = krb5_pac_parse(context,
- child.val[j].ad_data.data,
- child.val[j].ad_data.length,
- &pac);
- free_AuthorizationData(&child);
- if (ret)
- return ret;
+ ret = _krb5_kdc_pac_ticket_parse(context, tkt, &signedticket, &pac);
+ if (ret)
+ return ret;
- ret = krb5_pac_verify(context, pac, tkt->authtime,
- client_principal,
- server_check_key, NULL);
- if (ret) {
- krb5_pac_free(context, pac);
- return ret;
- }
+ if (pac == NULL)
+ return KRB5KDC_ERR_BADOPTION;
- ret = _kdc_pac_verify(context, client_principal,
- delegated_proxy_principal,
- client, server, krbtgt, &pac, &signed_pac);
- if (ret) {
- krb5_pac_free(context, pac);
- return ret;
- }
+ /* Verify the server signature. */
+ ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal,
+ server_check_key, NULL);
+ if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
+ }
- /*
- * Only re-sign PAC if we could verify it with the PAC
- * function. The no-verify case happens when we get in
- * a PAC from cross realm from a Windows domain and
- * that there is no PAC verification function.
- */
- if (signed_pac) {
- *signedpath = 1;
- ret = _krb5_pac_sign(context, pac, tkt->authtime,
- client_principal,
- server_sign_key, krbtgt_sign_key, rspac);
- }
+ /* Verify the KDC signatures. */
+ ret = _kdc_pac_verify(context, client_principal, delegated_proxy_principal,
+ client, server, krbtgt, &pac);
+ if (ret == KRB5_PLUGIN_NO_HANDLE) {
+ /*
+ * We can't verify the KDC signatures if the ticket was issued by
+ * another realm's KDC.
+ */
+ if (krb5_realm_compare(context, server->entry.principal,
+ ticket_server->entry.principal)) {
+ ret = krb5_pac_verify(context, pac, 0, NULL, NULL,
+ krbtgt_check_key);
+ if (ret) {
krb5_pac_free(context, pac);
-
return ret;
}
}
- free_AuthorizationData(&child);
+ /* Discard the PAC if the plugin didn't handle it */
+ krb5_pac_free(context, pac);
+ ret = krb5_pac_init(context, &pac);
+ if (ret)
+ return ret;
+ } else if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
}
+
+ *kdc_issued = signedticket ||
+ krb5_principal_is_krbtgt(context,
+ ticket_server->entry.principal);
+ *ppac = pac;
+
return 0;
}
@@ -558,7 +316,7 @@
* Determine if s4u2self is allowed from this client to this server
*
* For example, regardless of the principal being impersonated, if the
- * 'client' and 'server' are the same, then it's safe.
+ * 'client' and 'server' (target) are the same, then it's safe.
*/
static krb5_error_code
@@ -566,18 +324,28 @@
krb5_kdc_configuration *config,
HDB *clientdb,
hdb_entry_ex *client,
- krb5_const_principal server)
+ hdb_entry_ex *target_server,
+ krb5_const_principal target_server_principal)
{
krb5_error_code ret;
- /* if client does a s4u2self to itself, that ok */
- if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
- return 0;
-
+ /*
+ * Always allow the plugin to check, this might be faster, allow a
+ * policy or audit check and can look into the DB records
+ * directly
+ */
if (clientdb->hdb_check_s4u2self) {
- ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
+ ret = clientdb->hdb_check_s4u2self(context,
+ clientdb,
+ client,
+ target_server);
if (ret == 0)
return 0;
+ } else if (krb5_principal_compare(context,
+ client->entry.principal,
+ target_server_principal) == TRUE) {
+ /* if client does a s4u2self to itself, and there is no plugin, that is ok */
+ return 0;
} else {
ret = KRB5KDC_ERR_BADOPTION;
}
@@ -654,8 +422,12 @@
"Decoding transited encoding");
return ret;
}
+
+ /*
+ * If the realm of the presented tgt is neither the client nor the server
+ * realm, it is a transit realm and must be added to transited set.
+ */
if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
- /* not us, so add the previous realm to transited set */
if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
ret = ERANGE;
goto free_realms;
@@ -723,11 +495,12 @@
tgs_make_reply(krb5_context context,
krb5_kdc_configuration *config,
KDC_REQ_BODY *b,
- krb5_const_principal tgt_name,
+ krb5_principal tgt_name,
const EncTicketPart *tgt,
const krb5_keyblock *replykey,
int rk_is_subkey,
const EncryptionKey *serverkey,
+ const EncryptionKey *krbtgtkey,
const krb5_keyblock *sessionkey,
krb5_kvno kvno,
AuthorizationData *auth_data,
@@ -736,10 +509,11 @@
const char *server_name,
hdb_entry_ex *client,
krb5_principal client_principal,
+ const char *tgt_realm,
hdb_entry_ex *krbtgt,
- krb5_enctype krbtgt_etype,
- krb5_principals spp,
- const krb5_data *rspac,
+ krb5_pac mspac,
+ uint16_t rodc_id,
+ krb5_boolean add_ticket_sig,
const METHOD_DATA *enc_pa_data,
const char **e_text,
krb5_data *reply)
@@ -797,7 +571,7 @@
&tgt->transited, &et,
krb5_principal_get_realm(context, client_principal),
krb5_principal_get_realm(context, server->entry.principal),
- krb5_principal_get_realm(context, krbtgt->entry.principal));
+ tgt_realm);
if(ret)
goto out;
@@ -872,17 +646,6 @@
if (!server->entry.flags.proxiable)
et.flags.proxiable = 0;
- if(rspac->length) {
- /*
- * No not need to filter out the any PAC from the
- * auth_data since it's signed by the KDC.
- */
- ret = _kdc_tkt_add_if_relevant_ad(context, &et,
- KRB5_AUTHDATA_WIN2K_PAC, rspac);
- if (ret)
- goto out;
- }
-
if (auth_data) {
unsigned int i = 0;
@@ -903,20 +666,6 @@
goto out;
}
}
-
- /* Filter out type KRB5SignedPath */
- ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
- if (ret == 0) {
- if (et.authorization_data->len == 1) {
- free_AuthorizationData(et.authorization_data);
- free(et.authorization_data);
- et.authorization_data = NULL;
- } else {
- AuthorizationData *ad = et.authorization_data;
- free_AuthorizationDataElement(&ad->val[ad->len - 1]);
- ad->len--;
- }
- }
}
ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
@@ -945,24 +694,6 @@
_kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
et.endtime, et.renew_till);
- /* Don't sign cross realm tickets, they can't be checked anyway */
- {
- char *r = get_krbtgt_realm(&ek.sname);
-
- if (r == NULL || strcmp(r, ek.srealm) == 0) {
- ret = _kdc_add_KRB5SignedPath(context,
- config,
- krbtgt,
- krbtgt_etype,
- client_principal,
- NULL,
- spp,
- &et);
- if (ret)
- goto out;
- }
- }
-
if (enc_pa_data->len) {
rep.padata = calloc(1, sizeof(*rep.padata));
if (rep.padata == NULL) {
@@ -981,6 +712,13 @@
is_weak = 1;
}
+ /* The PAC should be the last change to the ticket. */
+ if (mspac != NULL) {
+ ret = _krb5_kdc_pac_sign_ticket(context, mspac, tgt_name, serverkey,
+ krbtgtkey, rodc_id, add_ticket_sig, &et);
+ if (ret)
+ goto out;
+ }
/* It is somewhat unclear where the etype in the following
encryption should come from. What we have is a session
@@ -1167,6 +905,7 @@
int **cusec,
AuthorizationData **auth_data,
krb5_keyblock **replykey,
+ Key **header_key,
int *rk_is_subkey)
{
static char failed[] = "";
@@ -1304,6 +1043,8 @@
goto out;
}
+ *header_key = tkey;
+
{
krb5_authenticator auth;
@@ -1494,12 +1235,64 @@
}
static krb5_error_code
+db_fetch_client(krb5_context context,
+ krb5_kdc_configuration *config,
+ int flags,
+ krb5_principal cp,
+ const char *cpn,
+ const char *krbtgt_realm,
+ HDB **clientdb,
+ hdb_entry_ex **client_out)
+{
+ krb5_error_code ret;
+ hdb_entry_ex *client = NULL;
+
+ *client_out = NULL;
+
+ ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
+ NULL, clientdb, &client);
+ if (ret == HDB_ERR_NOT_FOUND_HERE) {
+ /*
+ * This is OK, we are just trying to find out if they have
+ * been disabled or deleted in the meantime; missing secrets
+ * are OK.
+ */
+ } else if (ret) {
+ /*
+ * If the client belongs to the same realm as our TGS, it
+ * should exist in the local database.
+ */
+ const char *msg;
+
+ if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
+ if (ret == HDB_ERR_NOENTRY)
+ ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ kdc_log(context, config, 4, "Client no longer in database: %s", cpn);
+ return ret;
+ }
+
+ msg = krb5_get_error_message(context, ret);
+ kdc_log(context, config, 4, "Client not found in database: %s", msg);
+ krb5_free_error_message(context, msg);
+ } else if (client->entry.flags.invalid || !client->entry.flags.client) {
+ kdc_log(context, config, 4, "Client has invalid bit set");
+ _kdc_free_ent(context, client);
+ return KRB5KDC_ERR_POLICY;
+ }
+
+ *client_out = client;
+
+ return 0;
+}
+
+static krb5_error_code
tgs_build_reply(krb5_context context,
krb5_kdc_configuration *config,
KDC_REQ *req,
KDC_REQ_BODY *b,
hdb_entry_ex *krbtgt,
krb5_enctype krbtgt_etype,
+ Key *tkey_check,
const krb5_keyblock *replykey,
int rk_is_subkey,
krb5_ticket *ticket,
@@ -1512,17 +1305,24 @@
krb5_error_code ret;
krb5_principal cp = NULL, sp = NULL, tp = NULL, dp = NULL;
krb5_principal krbtgt_principal = NULL;
+ krb5_principal user2user_princ = NULL;
char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL;
+ char *user2user_name = NULL;
hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
+ hdb_entry_ex *user2user_krbtgt = NULL;
HDB *clientdb, *s4u2self_impersonated_clientdb;
+ HDB *serverdb = NULL;
krb5_realm ref_realm = NULL;
EncTicketPart *tgt = &ticket->ticket;
- krb5_principals spp = NULL;
+ const char *tgt_realm = /* Realm of TGT issuer */
+ krb5_principal_get_realm(context, krbtgt->entry.principal);
const EncryptionKey *ekey;
krb5_keyblock sessionkey;
krb5_kvno kvno;
- krb5_data rspac;
-
+ krb5_pac mspac = NULL;
+ krb5_pac user2user_pac = NULL;
+ uint16_t rodc_id;
+ krb5_boolean add_ticket_sig = FALSE;
hdb_entry_ex *krbtgt_out = NULL;
METHOD_DATA enc_pa_data;
@@ -1532,15 +1332,13 @@
int nloop = 0;
EncTicketPart adtkt;
char opt_str[128];
- int signedpath = 0;
+ krb5_boolean kdc_issued = FALSE;
- Key *tkey_check;
Key *tkey_sign;
int flags = HDB_F_FOR_TGS_REQ;
memset(&sessionkey, 0, sizeof(sessionkey));
memset(&adtkt, 0, sizeof(adtkt));
- krb5_data_zero(&rspac);
memset(&enc_pa_data, 0, sizeof(enc_pa_data));
s = b->sname;
@@ -1549,60 +1347,10 @@
if (b->kdc_options.canonicalize)
flags |= HDB_F_CANON;
- if(b->kdc_options.enc_tkt_in_skey){
- Ticket *t;
- hdb_entry_ex *uu;
- krb5_principal p;
- Key *uukey;
- krb5uint32 second_kvno = 0;
- krb5uint32 *kvno_ptr = NULL;
-
- if(b->additional_tickets == NULL ||
- b->additional_tickets->len == 0){
- ret = KRB5KDC_ERR_BADOPTION; /* ? */
- kdc_log(context, config, 0,
- "No second ticket present in request");
- goto out;
- }
- t = &b->additional_tickets->val[0];
- if(!get_krbtgt_realm(&t->sname)){
- kdc_log(context, config, 0,
- "Additional ticket is not a ticket-granting ticket");
- ret = KRB5KDC_ERR_POLICY;
- goto out;
- }
- _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
- if(t->enc_part.kvno){
- second_kvno = *t->enc_part.kvno;
- kvno_ptr = &second_kvno;
- }
- ret = _kdc_db_fetch(context, config, p,
- HDB_F_GET_KRBTGT, kvno_ptr,
- NULL, &uu);
- krb5_free_principal(context, p);
- if(ret){
- if (ret == HDB_ERR_NOENTRY)
- ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
- goto out;
- }
- ret = hdb_enctype2key(context, &uu->entry,
- t->enc_part.etype, &uukey);
- if(ret){
- _kdc_free_ent(context, uu);
- ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
- goto out;
- }
- ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
- _kdc_free_ent(context, uu);
- if(ret)
- goto out;
-
- ret = verify_flags(context, config, &adtkt, spn);
- if (ret)
- goto out;
-
- s = &adtkt.cname;
- r = adtkt.crealm;
+ if (s == NULL) {
+ ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+ krb5_set_error_message(context, ret, "No server in request");
+ goto out;
}
_krb5_principalname2krb5_principal(context, &sp, *s, r);
@@ -1630,7 +1378,7 @@
server_lookup:
ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
- NULL, NULL, &server);
+ NULL, &serverdb, &server);
if(ret == HDB_ERR_NOT_FOUND_HERE) {
kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
@@ -1721,6 +1469,41 @@
goto out;
}
+ /* Now refetch the primary krbtgt, and get the current kvno (the
+ * sign check may have been on an old kvno, and the server may
+ * have been an incoming trust) */
+ ret = krb5_make_principal(context, &krbtgt_principal,
+ krb5_principal_get_comp_string(context,
+ krbtgt->entry.principal,
+ 1),
+ KRB5_TGS_NAME,
+ krb5_principal_get_comp_string(context,
+ krbtgt->entry.principal,
+ 1), NULL);
+ if(ret) {
+ kdc_log(context, config, 0,
+ "Failed to generate krbtgt principal");
+ goto out;
+ }
+
+ ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
+ krb5_free_principal(context, krbtgt_principal);
+ if (ret) {
+ krb5_error_code ret2;
+ char *ktpn, *ktpn2;
+ ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
+ ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
+ kdc_log(context, config, 0,
+ "Request with wrong krbtgt: %s, %s not found in our database",
+ (ret == 0) ? ktpn : "", (ret2 == 0) ? ktpn2 : "");
+ if(ret == 0)
+ free(ktpn);
+ if(ret2 == 0)
+ free(ktpn2);
+ ret = KRB5KRB_AP_ERR_NOT_US;
+ goto out;
+ }
+
/*
* Select enctype, return key and kvno.
*/
@@ -1729,7 +1512,127 @@
krb5_enctype etype;
if(b->kdc_options.enc_tkt_in_skey) {
+ Ticket *t;
+ krb5_principal p;
+ Key *uukey;
+ krb5uint32 second_kvno = 0;
+ krb5uint32 *kvno_ptr = NULL;
size_t i;
+ hdb_entry_ex *user2user_client = NULL;
+ krb5_boolean user2user_kdc_issued = FALSE;
+
+ if(b->additional_tickets == NULL ||
+ b->additional_tickets->len == 0){
+ ret = KRB5KDC_ERR_BADOPTION; /* ? */
+ kdc_log(context, config, 0,
+ "No second ticket present in request");
+ goto out;
+ }
+ t = &b->additional_tickets->val[0];
+ if(!get_krbtgt_realm(&t->sname)){
+ kdc_log(context, config, 0,
+ "Additional ticket is not a ticket-granting ticket");
+ ret = KRB5KDC_ERR_POLICY;
+ goto out;
+ }
+ ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
+ if (ret) {
+ goto out;
+ }
+ if(t->enc_part.kvno){
+ second_kvno = *t->enc_part.kvno;
+ kvno_ptr = &second_kvno;
+ }
+ ret = _kdc_db_fetch(context, config, p,
+ HDB_F_GET_KRBTGT, kvno_ptr,
+ NULL, &user2user_krbtgt);
+ krb5_free_principal(context, p);
+ if(ret){
+ if (ret == HDB_ERR_NOENTRY)
+ ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+ goto out;
+ }
+ ret = hdb_enctype2key(context, &user2user_krbtgt->entry,
+ t->enc_part.etype, &uukey);
+ if(ret){
+ ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
+ goto out;
+ }
+ ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
+ if(ret)
+ goto out;
+
+ ret = verify_flags(context, config, &adtkt, spn);
+ if (ret)
+ goto out;
+
+ /* Fetch the name from the TGT. */
+ ret = _krb5_principalname2krb5_principal(context, &user2user_princ,
+ adtkt.cname, adtkt.crealm);
+ if (ret) {
+ goto out;
+ }
+
+ ret = krb5_unparse_name(context, user2user_princ, &user2user_name);
+ if (ret) {
+ goto out;
+ }
+
+ /* Look up the name given in the TGT in the database. */
+ ret = db_fetch_client(context, config, flags, user2user_princ, user2user_name,
+ krb5_principal_get_realm(context, krbtgt_out->entry.principal),
+ NULL, &user2user_client);
+ if (ret) {
+ goto out;
+ }
+
+ if (user2user_client != NULL) {
+ /*
+ * If the account is present in the database, check the account
+ * flags.
+ */
+ ret = kdc_check_flags(context, config,
+ user2user_client, user2user_name,
+ NULL, NULL,
+ FALSE);
+ if (ret) {
+ _kdc_free_ent(context, user2user_client);
+ goto out;
+ }
+
+ /*
+ * Also check that the account is the same one specified in the
+ * request.
+ */
+ ret = check_s4u2self(context, config, serverdb, server, user2user_client, user2user_princ);
+ if (ret) {
+ _kdc_free_ent(context, user2user_client);
+ goto out;
+ }
+ }
+
+ /* Verify the PAC of the TGT. */
+ ret = check_PAC(context, config, user2user_princ, NULL,
+ user2user_client, user2user_krbtgt, user2user_krbtgt, user2user_krbtgt,
+ &uukey->key, &tkey_check->key, &adtkt, &user2user_kdc_issued, &user2user_pac);
+ _kdc_free_ent(context, user2user_client);
+ if (ret) {
+ const char *msg = krb5_get_error_message(context, ret);
+ kdc_log(context, config, 0,
+ "Verify PAC failed for %s (%s) from %s with %s",
+ spn, user2user_name, from, msg);
+ krb5_free_error_message(context, msg);
+ goto out;
+ }
+
+ if (user2user_pac == NULL || !user2user_kdc_issued) {
+ ret = KRB5KDC_ERR_BADOPTION;
+ kdc_log(context, config, 0,
+ "Ticket not signed with PAC; user-to-user failed (%s).",
+ mspac ? "Ticket unsigned" : "No PAC");
+ goto out;
+ }
+
ekey = &adtkt.key;
for(i = 0; i < b->etype.len; i++)
if (b->etype.val[i] == adtkt.key.keytype)
@@ -1771,53 +1674,6 @@
* backward.
*/
- /*
- * Validate authoriation data
- */
-
- ret = hdb_enctype2key(context, &krbtgt->entry,
- krbtgt_etype, &tkey_check);
- if(ret) {
- kdc_log(context, config, 0,
- "Failed to find key for krbtgt PAC check");
- goto out;
- }
-
- /* Now refetch the primary krbtgt, and get the current kvno (the
- * sign check may have been on an old kvno, and the server may
- * have been an incoming trust) */
- ret = krb5_make_principal(context, &krbtgt_principal,
- krb5_principal_get_comp_string(context,
- krbtgt->entry.principal,
- 1),
- KRB5_TGS_NAME,
- krb5_principal_get_comp_string(context,
- krbtgt->entry.principal,
- 1), NULL);
- if(ret) {
- kdc_log(context, config, 0,
- "Failed to generate krbtgt principal");
- goto out;
- }
-
- ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
- krb5_free_principal(context, krbtgt_principal);
- if (ret) {
- krb5_error_code ret2;
- char *ktpn, *ktpn2;
- ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
- ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
- kdc_log(context, config, 0,
- "Request with wrong krbtgt: %s, %s not found in our database",
- (ret == 0) ? ktpn : "", (ret2 == 0) ? ktpn2 : "");
- if(ret == 0)
- free(ktpn);
- if(ret2 == 0)
- free(ktpn2);
- ret = KRB5KRB_AP_ERR_NOT_US;
- goto out;
- }
-
/* The first realm is the realm of the service, the second is
* krbtgt//@REALM component of the krbtgt DN the request was
* encrypted to. The redirection via the krbtgt_out entry allows
@@ -1843,62 +1699,18 @@
goto out;
}
- ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
- NULL, &clientdb, &client);
- if(ret == HDB_ERR_NOT_FOUND_HERE) {
- /* This is OK, we are just trying to find out if they have
- * been disabled or deleted in the meantime, missing secrets
- * is OK */
- } else if(ret){
- const char *krbtgt_realm, *msg;
-
- /*
- * If the client belongs to the same realm as our krbtgt, it
- * should exist in the local database.
- *
- */
-
- krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
-
- if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
- if (ret == HDB_ERR_NOENTRY)
- ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
- kdc_log(context, config, 1, "Client no longer in database: %s",
- cpn);
- goto out;
- }
-
- msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 1, "Client not found in database: %s", msg);
- krb5_free_error_message(context, msg);
- }
-
- ret = check_PAC(context, config, cp, NULL,
- client, server, krbtgt,
- &tkey_check->key,
- ekey, &tkey_sign->key,
- tgt, &rspac, &signedpath);
- if (ret) {
- const char *msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 0,
- "Verify PAC failed for %s (%s) from %s with %s",
- spn, cpn, from, msg);
- krb5_free_error_message(context, msg);
+ ret = db_fetch_client(context, config, flags, cp, cpn,
+ krb5_principal_get_realm(context, krbtgt_out->entry.principal),
+ &clientdb, &client);
+ if (ret)
goto out;
- }
- /* also check the krbtgt for signature */
- ret = check_KRB5SignedPath(context,
- config,
- krbtgt,
- cp,
- tgt,
- &spp,
- &signedpath);
+ ret = check_PAC(context, config, cp, NULL, client, server, krbtgt, krbtgt,
+ &tkey_check->key, &tkey_check->key, tgt, &kdc_issued, &mspac);
if (ret) {
const char *msg = krb5_get_error_message(context, ret);
kdc_log(context, config, 0,
- "KRB5SignedPath check failed for %s (%s) from %s with %s",
+ "Verify PAC failed for %s (%s) from %s with %s",
spn, cpn, from, msg);
krb5_free_error_message(context, msg);
goto out;
@@ -2031,34 +1843,22 @@
goto out;
/* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
- if(rspac.data) {
- krb5_pac p = NULL;
- krb5_data_free(&rspac);
- ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, &p);
+ if (mspac) {
+ krb5_pac_free(context, mspac);
+ mspac = NULL;
+ ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, NULL, &mspac);
if (ret) {
kdc_log(context, config, 0, "PAC generation failed for -- %s",
tpn);
goto out;
}
- if (p != NULL) {
- ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
- s4u2self_impersonated_client->entry.principal,
- ekey, &tkey_sign->key,
- &rspac);
- krb5_pac_free(context, p);
- if (ret) {
- kdc_log(context, config, 0, "PAC signing failed for -- %s",
- tpn);
- goto out;
- }
- }
}
/*
* Check that service doing the impersonating is
* requesting a ticket to it-self.
*/
- ret = check_s4u2self(context, config, clientdb, client, sp);
+ ret = check_s4u2self(context, config, clientdb, client, server, sp);
if (ret) {
kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
"to impersonate to service "
@@ -2094,22 +1894,25 @@
&& b->additional_tickets->len != 0
&& b->kdc_options.enc_tkt_in_skey == 0)
{
- int ad_signedpath = 0;
+ hdb_entry_ex *adclient = NULL;
+ krb5_boolean ad_kdc_issued = FALSE;
Key *clientkey;
Ticket *t;
/*
- * Require that the KDC have issued the service's krbtgt (not
- * self-issued ticket with kimpersonate(1).
+ * We require that the service's krbtgt has a PAC.
*/
- if (!signedpath) {
+ if (mspac == NULL) {
ret = KRB5KDC_ERR_BADOPTION;
kdc_log(context, config, 0,
- "Constrained delegation done on service ticket %s/%s",
+ "Constrained delegation without PAC %s/%s",
cpn, spn);
goto out;
}
+ krb5_pac_free(context, mspac);
+ mspac = NULL;
+
t = &b->additional_tickets->val[0];
ret = hdb_enctype2key(context, &client->entry,
@@ -2173,19 +1976,32 @@
goto out;
}
- krb5_data_free(&rspac);
+ /* Try lookup the delegated client in DB */
+ ret = db_fetch_client(context, config, flags, tp, tpn,
+ krb5_principal_get_realm(context, krbtgt_out->entry.principal),
+ NULL, &adclient);
+ if (ret)
+ goto out;
+
+ if (adclient != NULL) {
+ ret = kdc_check_flags(context, config,
+ adclient, tpn,
+ server, spn,
+ FALSE);
+ if (ret) {
+ _kdc_free_ent(context, adclient);
+ goto out;
+ }
+ }
/*
- * generate the PAC for the user.
- *
* TODO: pass in t->sname and t->realm and build
* a S4U_DELEGATION_INFO blob to the PAC.
*/
- ret = check_PAC(context, config, tp, dp,
- client, server, krbtgt,
- &clientkey->key,
- ekey, &tkey_sign->key,
- &adtkt, &rspac, &ad_signedpath);
+ ret = check_PAC(context, config, tp, dp, adclient, server, krbtgt, client,
+ &clientkey->key, &tkey_check->key, &adtkt, &ad_kdc_issued, &mspac);
+ if (adclient)
+ _kdc_free_ent(context, adclient);
if (ret) {
const char *msg = krb5_get_error_message(context, ret);
kdc_log(context, config, 0,
@@ -2196,34 +2012,12 @@
goto out;
}
- /*
- * Check that the KDC issued the user's ticket.
- */
- ret = check_KRB5SignedPath(context,
- config,
- krbtgt,
- cp,
- &adtkt,
- NULL,
- &ad_signedpath);
- if (ret) {
- const char *msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 0,
- "KRB5SignedPath check from service %s failed "
- "for delegation to %s for client %s (%s)"
- "from %s failed with %s",
- spn, tpn, dpn, cpn, from, msg);
- krb5_free_error_message(context, msg);
- goto out;
- }
-
- if (!ad_signedpath) {
+ if (mspac == NULL || !ad_kdc_issued) {
ret = KRB5KDC_ERR_BADOPTION;
kdc_log(context, config, 0,
- "Ticket not signed with PAC nor SignedPath service %s failed "
- "for delegation to %s for client %s (%s)"
- "from %s",
- spn, tpn, dpn, cpn, from);
+ "Ticket not signed with PAC; service %s failed for "
+ "for delegation to %s for client %s (%s) from %s; (%s).",
+ spn, tpn, dpn, cpn, from, mspac ? "Ticket unsigned" : "No PAC");
goto out;
}
@@ -2293,6 +2087,25 @@
}
/*
+ * Only add ticket signature if the requested server is not krbtgt, and
+ * either the header server is krbtgt or, in the case of renewal/validation
+ * if it was signed with PAC ticket signature and we verified it.
+ * Currently Heimdal only allows renewal of krbtgt anyway but that might
+ * change one day (see issue #763) so make sure to check for it.
+ */
+
+ if (kdc_issued &&
+ !krb5_principal_is_krbtgt(context, server->entry.principal))
+ add_ticket_sig = TRUE;
+
+ /*
+ * Active-Directory implementations use the high part of the kvno as the
+ * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
+ */
+
+ rodc_id = krbtgt_out->entry.kvno >> 16;
+
+ /*
*
*/
@@ -2304,6 +2117,7 @@
replykey,
rk_is_subkey,
ekey,
+ &tkey_sign->key,
&sessionkey,
kvno,
*auth_data,
@@ -2312,15 +2126,17 @@
spn,
client,
cp,
+ tgt_realm,
krbtgt_out,
- krbtgt_etype,
- spp,
- &rspac,
+ mspac,
+ rodc_id,
+ add_ticket_sig,
&enc_pa_data,
e_text,
reply);
out:
+ free(user2user_name);
if (tpn != cpn)
free(tpn);
free(spn);
@@ -2328,7 +2144,6 @@
if (dpn)
free(dpn);
- krb5_data_free(&rspac);
krb5_free_keyblock_contents(context, &sessionkey);
if(krbtgt_out)
_kdc_free_ent(context, krbtgt_out);
@@ -2338,7 +2153,11 @@
_kdc_free_ent(context, client);
if(s4u2self_impersonated_client)
_kdc_free_ent(context, s4u2self_impersonated_client);
+ if (user2user_krbtgt)
+ _kdc_free_ent(context, user2user_krbtgt);
+ if (user2user_princ)
+ krb5_free_principal(context, user2user_princ);
if (tp && tp != cp)
krb5_free_principal(context, tp);
if (cp)
@@ -2353,6 +2172,9 @@
free_EncTicketPart(&adtkt);
+ krb5_pac_free(context, mspac);
+ krb5_pac_free(context, user2user_pac);
+
return ret;
}
@@ -2373,6 +2195,7 @@
krb5_error_code ret;
int i = 0;
const PA_DATA *tgs_req;
+ Key *header_key = NULL;
hdb_entry_ex *krbtgt = NULL;
krb5_ticket *ticket = NULL;
@@ -2410,6 +2233,7 @@
&csec, &cusec,
&auth_data,
&replykey,
+ &header_key,
&rk_is_subkey);
if (ret == HDB_ERR_NOT_FOUND_HERE) {
/* kdc_log() is called in tgs_parse_request() */
@@ -2427,6 +2251,7 @@
&req->req_body,
krbtgt,
krbtgt_etype,
+ header_key,
replykey,
rk_is_subkey,
ticket,
diff -Nru samba-4.13.3+dfsg/source4/heimdal/kdc/windc.c samba-4.13.14+dfsg/source4/heimdal/kdc/windc.c
--- samba-4.13.3+dfsg/source4/heimdal/kdc/windc.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/heimdal/kdc/windc.c 2021-11-08 11:29:14.000000000 +0000
@@ -74,15 +74,24 @@
_kdc_pac_generate(krb5_context context,
hdb_entry_ex *client,
const krb5_keyblock *pk_reply_key,
+ const krb5_boolean *pac_request,
krb5_pac *pac)
{
*pac = NULL;
- if (windcft == NULL)
+ if (krb5_config_get_bool_default(context, NULL, FALSE, "realms",
+ client->entry.principal->realm,
+ "disable_pac", NULL))
return 0;
+ if (windcft == NULL) {
+ return krb5_pac_init(context, pac);
+ }
+
if (windcft->pac_pk_generate != NULL && pk_reply_key != NULL)
return (windcft->pac_pk_generate)(windcctx, context,
- client, pk_reply_key, pac);
- return (windcft->pac_generate)(windcctx, context, client, pac);
+ client, pk_reply_key,
+ pac_request, pac);
+ return (windcft->pac_generate)(windcctx, context, client,
+ pac_request, pac);
}
krb5_error_code
@@ -92,20 +101,17 @@
hdb_entry_ex *client,
hdb_entry_ex *server,
hdb_entry_ex *krbtgt,
- krb5_pac *pac,
- int *verified)
+ krb5_pac *pac)
{
krb5_error_code ret;
if (windcft == NULL)
- return 0;
+ return KRB5_PLUGIN_NO_HANDLE;
ret = windcft->pac_verify(windcctx, context,
client_principal,
delegated_proxy_principal,
client, server, krbtgt, pac);
- if (ret == 0)
- *verified = 1;
return ret;
}
diff -Nru samba-4.13.3+dfsg/source4/heimdal/kdc/windc_plugin.h samba-4.13.14+dfsg/source4/heimdal/kdc/windc_plugin.h
--- samba-4.13.3+dfsg/source4/heimdal/kdc/windc_plugin.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/heimdal/kdc/windc_plugin.h 2021-11-08 11:29:14.000000000 +0000
@@ -43,8 +43,9 @@
* krb5_pac_init and fill in the PAC structure for the principal using
* krb5_pac_add_buffer.
*
- * The PAC verify function should verify all components in the PAC
- * using krb5_pac_get_types and krb5_pac_get_buffer for all types.
+ * The PAC verify function should verify the PAC KDC signatures by fetching
+ * the right KDC key and calling krb5_pac_verify() with that KDC key.
+ * Optionally, update the PAC buffers upon success.
*
* Check client access function check if the client is authorized.
*/
@@ -54,12 +55,14 @@
typedef krb5_error_code
(*krb5plugin_windc_pac_generate)(void *, krb5_context,
struct hdb_entry_ex *, /* client */
+ const krb5_boolean *, /* pac_request */
krb5_pac *);
typedef krb5_error_code
(*krb5plugin_windc_pac_pk_generate)(void *, krb5_context,
struct hdb_entry_ex *, /* client */
const krb5_keyblock *, /* pk_replykey */
+ const krb5_boolean *, /* pac_request */
krb5_pac *);
typedef krb5_error_code
diff -Nru samba-4.13.3+dfsg/source4/heimdal/lib/asn1/krb5.asn1 samba-4.13.14+dfsg/source4/heimdal/lib/asn1/krb5.asn1
--- samba-4.13.3+dfsg/source4/heimdal/lib/asn1/krb5.asn1 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/heimdal/lib/asn1/krb5.asn1 2021-10-29 06:17:36.000000000 +0000
@@ -43,9 +43,6 @@
KRB-PRIV,
KRB-SAFE,
KRB-SAFE-BODY,
- KRB5SignedPath,
- KRB5SignedPathData,
- KRB5SignedPathPrincipals,
KerberosString,
KerberosTime,
KrbCredInfo,
@@ -713,24 +710,6 @@
auth[3] GeneralString
}
--- never encoded on the wire, just used to checksum over
-KRB5SignedPathData ::= SEQUENCE {
- client[0] Principal OPTIONAL,
- authtime[1] KerberosTime,
- delegated[2] Principals OPTIONAL,
- method_data[3] METHOD-DATA OPTIONAL
-}
-
-KRB5SignedPath ::= SEQUENCE {
- -- DERcoded KRB5SignedPathData
- -- krbtgt key (etype), KeyUsage = XXX
- etype[0] ENCTYPE,
- cksum[1] Checksum,
- -- srvs delegated though
- delegated[2] Principals OPTIONAL,
- method_data[3] METHOD-DATA OPTIONAL
-}
-
AD-LoginAlias ::= SEQUENCE { -- ad-type number TBD --
login-alias [0] PrincipalName,
checksum [1] Checksum
diff -Nru samba-4.13.3+dfsg/source4/heimdal/lib/hdb/hdb.h samba-4.13.14+dfsg/source4/heimdal/lib/hdb/hdb.h
--- samba-4.13.3+dfsg/source4/heimdal/lib/hdb/hdb.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/heimdal/lib/hdb/hdb.h 2021-11-08 11:29:14.000000000 +0000
@@ -266,7 +266,7 @@
/**
* Check if s4u2self is allowed from this client to this server
*/
- krb5_error_code (*hdb_check_s4u2self)(krb5_context, struct HDB *, hdb_entry_ex *, krb5_const_principal);
+ krb5_error_code (*hdb_check_s4u2self)(krb5_context, struct HDB *, hdb_entry_ex *, hdb_entry_ex *);
}HDB;
#define HDB_INTERFACE_VERSION 7
diff -Nru samba-4.13.3+dfsg/source4/heimdal/lib/krb5/authdata.c samba-4.13.14+dfsg/source4/heimdal/lib/krb5/authdata.c
--- samba-4.13.3+dfsg/source4/heimdal/lib/krb5/authdata.c 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/source4/heimdal/lib/krb5/authdata.c 2021-10-29 06:17:36.000000000 +0000
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1997-2021 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * Copyright (c) 2021 Isaac Boukris
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "krb5_locl.h"
+
+/*
+ * Add the AuthorizationData `data´ of `type´ to the last element in
+ * the sequence of authorization_data in `tkt´ wrapped in an IF_RELEVANT
+ */
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+_kdc_tkt_add_if_relevant_ad(krb5_context context,
+ EncTicketPart *tkt,
+ int type,
+ const krb5_data *data)
+{
+ krb5_error_code ret;
+ size_t size = 0;
+
+ if (tkt->authorization_data == NULL) {
+ tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
+ if (tkt->authorization_data == NULL) {
+ return krb5_enomem(context);
+ }
+ }
+
+ /* add the entry to the last element */
+ {
+ AuthorizationData ad = { 0, NULL };
+ AuthorizationDataElement ade;
+
+ ade.ad_type = type;
+ ade.ad_data = *data;
+
+ ret = add_AuthorizationData(&ad, &ade);
+ if (ret) {
+ krb5_set_error_message(context, ret, "add AuthorizationData failed");
+ return ret;
+ }
+
+ ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
+
+ ASN1_MALLOC_ENCODE(AuthorizationData,
+ ade.ad_data.data, ade.ad_data.length,
+ &ad, &size, ret);
+ free_AuthorizationData(&ad);
+ if (ret) {
+ krb5_set_error_message(context, ret, "ASN.1 encode of "
+ "AuthorizationData failed");
+ return ret;
+ }
+ if (ade.ad_data.length != size)
+ krb5_abortx(context, "internal asn.1 encoder error");
+
+ ret = add_AuthorizationData(tkt->authorization_data, &ade);
+ der_free_octet_string(&ade.ad_data);
+ if (ret) {
+ krb5_set_error_message(context, ret, "add AuthorizationData failed");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Insert a PAC wrapped in AD-IF-RELEVANT container as the first AD element,
+ * as some clients such as Windows may fail to parse it otherwise.
+ */
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+_kdc_tkt_insert_pac(krb5_context context,
+ EncTicketPart *tkt,
+ const krb5_data *data)
+{
+ AuthorizationDataElement ade;
+ unsigned int i;
+ krb5_error_code ret;
+
+ ret = _kdc_tkt_add_if_relevant_ad(context, tkt, KRB5_AUTHDATA_WIN2K_PAC,
+ data);
+ if (ret)
+ return ret;
+
+ heim_assert(tkt->authorization_data->len != 0, "No authorization_data!");
+ ade = tkt->authorization_data->val[tkt->authorization_data->len - 1];
+ for (i = 0; i < tkt->authorization_data->len - 1; i++) {
+ tkt->authorization_data->val[i + 1] = tkt->authorization_data->val[i];
+ }
+ tkt->authorization_data->val[0] = ade;
+
+ return 0;
+}
diff -Nru samba-4.13.3+dfsg/source4/heimdal/lib/krb5/pac.c samba-4.13.14+dfsg/source4/heimdal/lib/krb5/pac.c
--- samba-4.13.3+dfsg/source4/heimdal/lib/krb5/pac.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/heimdal/lib/krb5/pac.c 2021-10-29 06:17:36.000000000 +0000
@@ -53,6 +53,8 @@
struct PAC_INFO_BUFFER *server_checksum;
struct PAC_INFO_BUFFER *privsvr_checksum;
struct PAC_INFO_BUFFER *logon_name;
+ struct PAC_INFO_BUFFER *ticket_checksum;
+ krb5_data ticket_sign_data;
};
#define PAC_ALIGNMENT 8
@@ -60,10 +62,13 @@
#define PACTYPE_SIZE 8
#define PAC_INFO_BUFFER_SIZE 16
+#define PAC_LOGON_INFO 1
#define PAC_SERVER_CHECKSUM 6
#define PAC_PRIVSVR_CHECKSUM 7
#define PAC_LOGON_NAME 10
#define PAC_CONSTRAINED_DELEGATION 11
+#define PAC_UPN_DNS_INFO 12
+#define PAC_TICKET_CHECKSUM 16
#define CHECK(r,f,l) \
do { \
@@ -142,13 +147,13 @@
CHECK(ret, krb5_ret_uint32(sp, &tmp2), out);
if (tmp < 1) {
ret = EINVAL; /* Too few buffers */
- krb5_set_error_message(context, ret, N_("PAC have too few buffer", ""));
+ krb5_set_error_message(context, ret, N_("PAC has too few buffers", ""));
goto out;
}
if (tmp2 != 0) {
ret = EINVAL; /* Wrong version */
krb5_set_error_message(context, ret,
- N_("PAC have wrong version %d", ""),
+ N_("PAC has wrong version %d", ""),
(int)tmp2);
goto out;
}
@@ -191,7 +196,7 @@
if (p->pac->buffers[i].offset_lo > len) {
ret = EINVAL;
krb5_set_error_message(context, ret,
- N_("PAC offset off end", ""));
+ N_("PAC offset overflow", ""));
goto out;
}
if (p->pac->buffers[i].offset_lo < header_end) {
@@ -204,7 +209,7 @@
}
if (p->pac->buffers[i].buffersize > len - p->pac->buffers[i].offset_lo){
ret = EINVAL;
- krb5_set_error_message(context, ret, N_("PAC length off end", ""));
+ krb5_set_error_message(context, ret, N_("PAC length overflow", ""));
goto out;
}
@@ -213,7 +218,7 @@
if (p->server_checksum) {
ret = EINVAL;
krb5_set_error_message(context, ret,
- N_("PAC have two server checksums", ""));
+ N_("PAC has multiple server checksums", ""));
goto out;
}
p->server_checksum = &p->pac->buffers[i];
@@ -221,7 +226,7 @@
if (p->privsvr_checksum) {
ret = EINVAL;
krb5_set_error_message(context, ret,
- N_("PAC have two KDC checksums", ""));
+ N_("PAC has multiple KDC checksums", ""));
goto out;
}
p->privsvr_checksum = &p->pac->buffers[i];
@@ -229,10 +234,18 @@
if (p->logon_name) {
ret = EINVAL;
krb5_set_error_message(context, ret,
- N_("PAC have two logon names", ""));
+ N_("PAC has multiple logon names", ""));
goto out;
}
p->logon_name = &p->pac->buffers[i];
+ } else if (p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) {
+ if (p->ticket_checksum) {
+ ret = EINVAL;
+ krb5_set_error_message(context, ret,
+ N_("PAC has multiple ticket checksums", ""));
+ goto out;
+ }
+ p->ticket_checksum = &p->pac->buffers[i];
}
}
@@ -424,7 +437,10 @@
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_pac_free(krb5_context context, krb5_pac pac)
{
+ if (pac == NULL)
+ return;
krb5_data_free(&pac->data);
+ krb5_data_free(&pac->ticket_sign_data);
free(pac->pac);
free(pac);
}
@@ -444,6 +460,7 @@
uint32_t type;
krb5_error_code ret;
Checksum cksum;
+ size_t cksumsize;
memset(&cksum, 0, sizeof(cksum));
@@ -456,8 +473,17 @@
CHECK(ret, krb5_ret_uint32(sp, &type), out);
cksum.cksumtype = type;
- cksum.checksum.length =
- sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR);
+
+ ret = krb5_checksumsize(context, type, &cksumsize);
+ if (ret)
+ goto out;
+
+ /* Allow for RODCIdentifier trailer, see MS-PAC 2.8 */
+ if (cksumsize > (sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR))) {
+ ret = EINVAL;
+ goto out;
+ }
+ cksum.checksum.length = cksumsize;
cksum.checksum.data = malloc(cksum.checksum.length);
if (cksum.checksum.data == NULL) {
ret = krb5_enomem(context);
@@ -465,13 +491,13 @@
}
ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length);
if (ret != (int)cksum.checksum.length) {
- ret = EINVAL;
+ ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
krb5_set_error_message(context, ret, "PAC checksum missing checksum");
goto out;
}
if (!krb5_checksum_is_keyed(context, cksum.cksumtype)) {
- ret = EINVAL;
+ ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
krb5_set_error_message(context, ret, "Checksum type %d not keyed",
cksum.cksumtype);
goto out;
@@ -804,7 +830,6 @@
return ret;
}
-
/**
* Verify the PAC.
*
@@ -844,18 +869,22 @@
return EINVAL;
}
- ret = verify_logonname(context,
- pac->logon_name,
- &pac->data,
- authtime,
- principal);
- if (ret)
- return ret;
+ if (principal != NULL) {
+ ret = verify_logonname(context, pac->logon_name, &pac->data, authtime,
+ principal);
+ if (ret)
+ return ret;
+ }
+
+ if (pac->server_checksum->buffersize < 4 ||
+ pac->privsvr_checksum->buffersize < 4)
+ return EINVAL;
/*
* in the service case, clean out data option of the privsvr and
* server checksum before checking the checksum.
*/
+ if (server != NULL)
{
krb5_data *copy;
@@ -897,6 +926,20 @@
privsvr);
if (ret)
return ret;
+
+ if (pac->ticket_sign_data.length != 0) {
+ if (pac->ticket_checksum == NULL) {
+ krb5_set_error_message(context, EINVAL,
+ "PAC missing ticket checksum");
+ return EINVAL;
+ }
+
+ ret = verify_checksum(context, pac->ticket_checksum, &pac->data,
+ pac->ticket_sign_data.data,
+ pac->ticket_sign_data.length, privsvr);
+ if (ret)
+ return ret;
+ }
}
return 0;
@@ -965,18 +1008,20 @@
krb5_principal principal,
const krb5_keyblock *server_key,
const krb5_keyblock *priv_key,
+ uint16_t rodc_id,
krb5_data *data)
{
krb5_error_code ret;
krb5_storage *sp = NULL, *spdata = NULL;
uint32_t end;
size_t server_size, priv_size;
- uint32_t server_offset = 0, priv_offset = 0;
+ uint32_t server_offset = 0, priv_offset = 0, ticket_offset = 0;
uint32_t server_cksumtype = 0, priv_cksumtype = 0;
int num = 0;
- size_t i;
+ size_t i, sz;
krb5_data logon, d;
+ krb5_data_zero(&d);
krb5_data_zero(&logon);
for (i = 0; i < p->pac->numbuffers; i++) {
@@ -985,9 +1030,9 @@
p->server_checksum = &p->pac->buffers[i];
}
if (p->server_checksum != &p->pac->buffers[i]) {
- ret = EINVAL;
+ ret = KRB5KDC_ERR_BADOPTION;
krb5_set_error_message(context, ret,
- N_("PAC have two server checksums", ""));
+ N_("PAC has multiple server checksums", ""));
goto out;
}
} else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
@@ -995,9 +1040,9 @@
p->privsvr_checksum = &p->pac->buffers[i];
}
if (p->privsvr_checksum != &p->pac->buffers[i]) {
- ret = EINVAL;
+ ret = KRB5KDC_ERR_BADOPTION;
krb5_set_error_message(context, ret,
- N_("PAC have two KDC checksums", ""));
+ N_("PAC has multiple KDC checksums", ""));
goto out;
}
} else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
@@ -1005,9 +1050,19 @@
p->logon_name = &p->pac->buffers[i];
}
if (p->logon_name != &p->pac->buffers[i]) {
- ret = EINVAL;
+ ret = KRB5KDC_ERR_BADOPTION;
+ krb5_set_error_message(context, ret,
+ N_("PAC has multiple logon names", ""));
+ goto out;
+ }
+ } else if (p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) {
+ if (p->ticket_checksum == NULL) {
+ p->ticket_checksum = &p->pac->buffers[i];
+ }
+ if (p->ticket_checksum != &p->pac->buffers[i]) {
+ ret = KRB5KDC_ERR_BADOPTION;
krb5_set_error_message(context, ret,
- N_("PAC have two logon names", ""));
+ N_("PAC has multiple ticket checksums", ""));
goto out;
}
}
@@ -1019,13 +1074,17 @@
num++;
if (p->privsvr_checksum == NULL)
num++;
+ if (p->ticket_sign_data.length != 0 && p->ticket_checksum == NULL)
+ num++;
if (num) {
void *ptr;
ptr = realloc(p->pac, sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (p->pac->numbuffers + num - 1)));
- if (ptr == NULL)
- return krb5_enomem(context);
+ if (ptr == NULL) {
+ ret = krb5_enomem(context);
+ goto out;
+ }
p->pac = ptr;
@@ -1044,33 +1103,42 @@
memset(p->privsvr_checksum, 0, sizeof(*p->privsvr_checksum));
p->privsvr_checksum->type = PAC_PRIVSVR_CHECKSUM;
}
+ if (p->ticket_sign_data.length != 0 && p->ticket_checksum == NULL) {
+ p->ticket_checksum = &p->pac->buffers[p->pac->numbuffers++];
+ memset(p->ticket_checksum, 0, sizeof(*p->privsvr_checksum));
+ p->ticket_checksum->type = PAC_TICKET_CHECKSUM;
+ }
}
/* Calculate LOGON NAME */
ret = build_logon_name(context, authtime, principal, &logon);
- if (ret)
- goto out;
/* Set lengths for checksum */
- ret = pac_checksum(context, server_key, &server_cksumtype, &server_size);
- if (ret)
- goto out;
- ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size);
- if (ret)
- goto out;
+ if (ret == 0)
+ ret = pac_checksum(context, server_key, &server_cksumtype, &server_size);
- /* Encode PAC */
- sp = krb5_storage_emem();
- if (sp == NULL)
- return krb5_enomem(context);
+ if (ret == 0)
+ ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size);
- krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
+ /* Encode PAC */
+ if (ret == 0) {
+ sp = krb5_storage_emem();
+ if (sp == NULL)
+ ret = krb5_enomem(context);
+ }
- spdata = krb5_storage_emem();
- if (spdata == NULL) {
- krb5_storage_free(sp);
- return krb5_enomem(context);
+ if (ret == 0) {
+ krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
+ spdata = krb5_storage_emem();
+ if (spdata == NULL) {
+ krb5_storage_free(sp);
+ ret = krb5_enomem(context);
+ }
}
+
+ if (ret)
+ goto out;
+
krb5_storage_set_flags(spdata, KRB5_STORAGE_BYTEORDER_LE);
CHECK(ret, krb5_store_uint32(sp, p->pac->numbuffers), out);
@@ -1095,10 +1163,24 @@
priv_offset = end + 4;
CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
CHECK(ret, fill_zeros(context, spdata, priv_size), out);
+ if (rodc_id != 0) {
+ len += sizeof(rodc_id);
+ CHECK(ret, fill_zeros(context, spdata, sizeof(rodc_id)), out);
+ }
+ } else if (p->ticket_sign_data.length != 0 &&
+ p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) {
+ len = priv_size + 4;
+ ticket_offset = end + 4;
+ CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
+ CHECK(ret, fill_zeros(context, spdata, priv_size), out);
+ if (rodc_id != 0) {
+ len += sizeof(rodc_id);
+ CHECK(ret, krb5_store_uint16(spdata, rodc_id), out);
+ }
} else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
len = krb5_storage_write(spdata, logon.data, logon.length);
if (logon.length != len) {
- ret = EINVAL;
+ ret = KRB5KDC_ERR_BADOPTION;
goto out;
}
} else {
@@ -1110,7 +1192,17 @@
ret = krb5_enomem(context);
goto out;
}
- /* XXX if not aligned, fill_zeros */
+
+ if (p->pac->buffers[i].type == PAC_LOGON_INFO
+ || p->pac->buffers[i].type == PAC_UPN_DNS_INFO)
+ {
+ uint32_t rounded = (len + PAC_ALIGNMENT - 1) / PAC_ALIGNMENT
+ * PAC_ALIGNMENT;
+ uint32_t remaining = rounded - len;
+ CHECK(ret, fill_zeros(context, spdata, remaining), out);
+
+ len = rounded;
+ }
}
/* write header */
@@ -1136,41 +1228,56 @@
/* assert (server_offset != 0 && priv_offset != 0); */
/* export PAC */
- ret = krb5_storage_to_data(spdata, &d);
- if (ret) {
- krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
- goto out;
- }
- ret = krb5_storage_write(sp, d.data, d.length);
- if (ret != (int)d.length) {
- krb5_data_free(&d);
- ret = krb5_enomem(context);
- goto out;
+ if (ret == 0)
+ ret = krb5_storage_to_data(spdata, &d);
+ if (ret == 0) {
+ sz = krb5_storage_write(sp, d.data, d.length);
+ if (sz != d.length) {
+ krb5_data_free(&d);
+ ret = krb5_enomem(context);
+ goto out;
+ }
}
krb5_data_free(&d);
- ret = krb5_storage_to_data(sp, &d);
- if (ret) {
- ret = krb5_enomem(context);
- goto out;
- }
+ if (ret == 0)
+ ret = krb5_storage_to_data(sp, &d);
/* sign */
- ret = create_checksum(context, server_key, server_cksumtype,
- d.data, d.length,
- (char *)d.data + server_offset, server_size);
- if (ret) {
- krb5_data_free(&d);
- goto out;
- }
- ret = create_checksum(context, priv_key, priv_cksumtype,
- (char *)d.data + server_offset, server_size,
- (char *)d.data + priv_offset, priv_size);
- if (ret) {
- krb5_data_free(&d);
- goto out;
+ if (ret == 0 && p->ticket_sign_data.length)
+ ret = create_checksum(context, priv_key, priv_cksumtype,
+ p->ticket_sign_data.data,
+ p->ticket_sign_data.length,
+ (char *)d.data + ticket_offset, priv_size);
+ if (ret == 0)
+ ret = create_checksum(context, server_key, server_cksumtype,
+ d.data, d.length,
+ (char *)d.data + server_offset, server_size);
+ if (ret == 0)
+ ret = create_checksum(context, priv_key, priv_cksumtype,
+ (char *)d.data + server_offset, server_size,
+ (char *)d.data + priv_offset, priv_size);
+ if (ret == 0 && rodc_id != 0) {
+ krb5_data rd;
+ krb5_storage *rs = krb5_storage_emem();
+ if (rs == NULL)
+ ret = krb5_enomem(context);
+ krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE);
+ if (ret == 0)
+ ret = krb5_store_uint16(rs, rodc_id);
+ if (ret == 0)
+ ret = krb5_storage_to_data(rs, &rd);
+ krb5_storage_free(rs);
+ if (ret)
+ goto out;
+ heim_assert(rd.length == sizeof(rodc_id), "invalid length");
+ memcpy((char *)d.data + priv_offset + priv_size, rd.data, rd.length);
+ krb5_data_free(&rd);
}
+ if (ret)
+ goto out;
+
/* done */
*data = d;
@@ -1180,6 +1287,7 @@
return 0;
out:
+ krb5_data_free(&d);
krb5_data_free(&logon);
if (sp)
krb5_storage_free(sp);
@@ -1187,3 +1295,227 @@
krb5_storage_free(spdata);
return ret;
}
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+krb5_pac_get_kdc_checksum_info(krb5_context context,
+ krb5_pac pac,
+ krb5_cksumtype *cstype,
+ uint16_t *rodc_id)
+{
+ krb5_error_code ret;
+ krb5_storage *sp = NULL;
+ const struct PAC_INFO_BUFFER *sig;
+ size_t cksumsize, prefix;
+ uint32_t type = 0;
+
+ *cstype = 0;
+ *rodc_id = 0;
+
+ sig = pac->privsvr_checksum;
+ if (sig == NULL) {
+ krb5_set_error_message(context, KRB5KDC_ERR_BADOPTION,
+ "PAC missing kdc checksum");
+ return KRB5KDC_ERR_BADOPTION;
+ }
+
+ sp = krb5_storage_from_mem((char *)pac->data.data + sig->offset_lo,
+ sig->buffersize);
+ if (sp == NULL)
+ return krb5_enomem(context);
+
+ krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
+
+ ret = krb5_ret_uint32(sp, &type);
+ if (ret)
+ goto out;
+
+ ret = krb5_checksumsize(context, type, &cksumsize);
+ if (ret)
+ goto out;
+
+ prefix = krb5_storage_seek(sp, 0, SEEK_CUR);
+
+ if ((sig->buffersize - prefix) >= cksumsize + 2) {
+ krb5_storage_seek(sp, cksumsize, SEEK_CUR);
+ ret = krb5_ret_uint16(sp, rodc_id);
+ if (ret)
+ goto out;
+ }
+
+ *cstype = type;
+
+out:
+ krb5_storage_free(sp);
+
+ return ret;
+}
+
+static unsigned char single_zero = '\0';
+static krb5_data single_zero_pac = { 1, &single_zero };
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+_krb5_kdc_pac_ticket_parse(krb5_context context,
+ EncTicketPart *tkt,
+ krb5_boolean *signedticket,
+ krb5_pac *ppac)
+{
+ AuthorizationData *ad = tkt->authorization_data;
+ krb5_pac pac = NULL;
+ unsigned i, j;
+ size_t len = 0;
+ krb5_error_code ret = 0;
+
+ *signedticket = FALSE;
+ *ppac = NULL;
+
+ if (ad == NULL || ad->len == 0)
+ return 0;
+
+ for (i = 0; i < ad->len; i++) {
+ AuthorizationData child;
+
+ if (ad->val[i].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
+ ret = KRB5KDC_ERR_BADOPTION;
+ goto out;
+ }
+
+ if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
+ continue;
+
+ ret = decode_AuthorizationData(ad->val[i].ad_data.data,
+ ad->val[i].ad_data.length,
+ &child,
+ NULL);
+ if (ret) {
+ krb5_set_error_message(context, ret, "Failed to decode "
+ "AD-IF-RELEVANT with %d", ret);
+ goto out;
+ }
+
+ for (j = 0; j < child.len; j++) {
+ krb5_data adifr_data = ad->val[i].ad_data;
+ krb5_data pac_data = child.val[j].ad_data;
+ krb5_data recoded_adifr;
+
+ if (child.val[j].ad_type != KRB5_AUTHDATA_WIN2K_PAC)
+ continue;
+
+ if (pac != NULL) {
+ free_AuthorizationData(&child);
+ ret = KRB5KDC_ERR_BADOPTION;
+ goto out;
+ }
+
+ ret = krb5_pac_parse(context,
+ pac_data.data,
+ pac_data.length,
+ &pac);
+ if (ret) {
+ free_AuthorizationData(&child);
+ goto out;
+ }
+
+ if (pac->ticket_checksum == NULL)
+ continue;
+
+ /*
+ * Encode the ticket with the PAC replaced with a single zero
+ * byte, to be used as input data to the ticket signature.
+ */
+
+ child.val[j].ad_data = single_zero_pac;
+
+ ASN1_MALLOC_ENCODE(AuthorizationData, recoded_adifr.data,
+ recoded_adifr.length, &child, &len, ret);
+ if (recoded_adifr.length != len)
+ krb5_abortx(context, "Internal error in ASN.1 encoder");
+
+ child.val[j].ad_data = pac_data;
+
+ if (ret) {
+ free_AuthorizationData(&child);
+ goto out;
+ }
+
+ ad->val[i].ad_data = recoded_adifr;
+
+ ASN1_MALLOC_ENCODE(EncTicketPart,
+ pac->ticket_sign_data.data,
+ pac->ticket_sign_data.length, tkt, &len,
+ ret);
+ if (pac->ticket_sign_data.length != len)
+ krb5_abortx(context, "Internal error in ASN.1 encoder");
+
+ ad->val[i].ad_data = adifr_data;
+ krb5_data_free(&recoded_adifr);
+
+ if (ret) {
+ free_AuthorizationData(&child);
+ goto out;
+ }
+
+ *signedticket = TRUE;
+ }
+ free_AuthorizationData(&child);
+ }
+
+out:
+ if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
+ }
+
+ *ppac = pac;
+
+ return 0;
+}
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+_krb5_kdc_pac_sign_ticket(krb5_context context,
+ const krb5_pac pac,
+ krb5_principal client,
+ const krb5_keyblock *server_key,
+ const krb5_keyblock *kdc_key,
+ uint16_t rodc_id,
+ krb5_boolean add_ticket_sig,
+ EncTicketPart *tkt)
+{
+ krb5_error_code ret;
+ krb5_data tkt_data;
+ krb5_data rspac;
+
+ krb5_data_zero(&rspac);
+ krb5_data_zero(&tkt_data);
+
+ krb5_data_free(&pac->ticket_sign_data);
+
+ if (add_ticket_sig) {
+ size_t len = 0;
+
+ ret = _kdc_tkt_insert_pac(context, tkt, &single_zero_pac);
+ if (ret)
+ return ret;
+
+ ASN1_MALLOC_ENCODE(EncTicketPart, tkt_data.data, tkt_data.length,
+ tkt, &len, ret);
+ if(tkt_data.length != len)
+ krb5_abortx(context, "Internal error in ASN.1 encoder");
+ if (ret)
+ return ret;
+
+ ret = remove_AuthorizationData(tkt->authorization_data, 0);
+ if (ret) {
+ krb5_data_free(&tkt_data);
+ return ret;
+ }
+
+ pac->ticket_sign_data = tkt_data;
+ }
+
+ ret = _krb5_pac_sign(context, pac, tkt->authtime, client, server_key,
+ kdc_key, rodc_id, &rspac);
+ if (ret == 0)
+ ret = _kdc_tkt_insert_pac(context, tkt, &rspac);
+ krb5_data_free(&rspac);
+ return ret;
+}
diff -Nru samba-4.13.3+dfsg/source4/heimdal/lib/krb5/store.c samba-4.13.14+dfsg/source4/heimdal/lib/krb5/store.c
--- samba-4.13.3+dfsg/source4/heimdal/lib/krb5/store.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/heimdal/lib/krb5/store.c 2021-08-06 12:19:57.000000000 +0000
@@ -270,6 +270,8 @@
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_storage_free(krb5_storage *sp)
{
+ if (sp == NULL)
+ return 0;
if(sp->free)
(*sp->free)(sp);
free(sp->data);
diff -Nru samba-4.13.3+dfsg/source4/heimdal/lib/krb5/version-script.map samba-4.13.14+dfsg/source4/heimdal/lib/krb5/version-script.map
--- samba-4.13.3+dfsg/source4/heimdal/lib/krb5/version-script.map 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/heimdal/lib/krb5/version-script.map 2021-10-29 06:17:36.000000000 +0000
@@ -470,6 +470,7 @@
krb5_pac_add_buffer;
krb5_pac_free;
krb5_pac_get_buffer;
+ krb5_pac_get_kdc_checksum_info;
krb5_pac_get_types;
krb5_pac_init;
krb5_pac_parse;
@@ -751,6 +752,10 @@
_krb5_get_host_realm_int;
_krb5_get_int;
_krb5_pac_sign;
+ _krb5_kdc_pac_sign_ticket;
+ _krb5_kdc_pac_ticket_parse;
+ _kdc_tkt_insert_pac;
+ _kdc_tkt_add_if_relevant_ad;
_krb5_parse_moduli;
_krb5_pk_kdf;
_krb5_pk_load_id;
diff -Nru samba-4.13.3+dfsg/source4/heimdal_build/wscript_build samba-4.13.14+dfsg/source4/heimdal_build/wscript_build
--- samba-4.13.3+dfsg/source4/heimdal_build/wscript_build 2020-09-15 13:43:18.000000000 +0000
+++ samba-4.13.14+dfsg/source4/heimdal_build/wscript_build 2021-10-29 06:17:36.000000000 +0000
@@ -606,7 +606,7 @@
KRB5_SOURCE = [os.path.join('lib/krb5/', x) for x in to_list(
'''acache.c add_et_list.c
addr_families.c appdefault.c
- asn1_glue.c auth_context.c
+ asn1_glue.c auth_context.c authdata.c
build_ap_req.c build_auth.c cache.c
changepw.c codec.c config_file.c
constants.c convert_creds.c
diff -Nru samba-4.13.3+dfsg/source4/kdc/db-glue.c samba-4.13.14+dfsg/source4/kdc/db-glue.c
--- samba-4.13.3+dfsg/source4/kdc/db-glue.c 2020-08-14 08:48:07.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/db-glue.c 2021-11-08 11:29:14.000000000 +0000
@@ -968,6 +968,29 @@
entry_ex->entry.flags.server = 0;
}
}
+
+ /*
+ * We restrict a 3-part SPN ending in my domain/realm to full
+ * domain controllers.
+ *
+ * This avoids any cases where (eg) a demoted DC still has
+ * these more restricted SPNs.
+ */
+ if (krb5_princ_size(context, principal) > 2) {
+ char *third_part
+ = smb_krb5_principal_get_comp_string(mem_ctx,
+ context,
+ principal,
+ 2);
+ bool is_our_realm =
+ lpcfg_is_my_domain_or_realm(lp_ctx,
+ third_part);
+ bool is_dc = userAccountControl &
+ (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT);
+ if (is_our_realm && !is_dc) {
+ entry_ex->entry.flags.server = 0;
+ }
+ }
/*
* To give the correct type of error to the client, we must
* not just return the entry without .server set, we must
@@ -2508,53 +2531,37 @@
/* Check if a given entry may delegate or do s4u2self to this target principal
*
- * This is currently a very nasty hack - allowing only delegation to itself.
+ * The safest way to determine 'self' is to check the DB record made at
+ * the time the principal was presented to the KDC.
*/
krb5_error_code
samba_kdc_check_s4u2self(krb5_context context,
- struct samba_kdc_db_context *kdc_db_ctx,
- struct samba_kdc_entry *skdc_entry,
- krb5_const_principal target_principal)
+ struct samba_kdc_entry *skdc_entry_client,
+ struct samba_kdc_entry *skdc_entry_server_target)
{
- krb5_error_code ret;
- struct ldb_dn *realm_dn;
- struct ldb_message *msg;
struct dom_sid *orig_sid;
struct dom_sid *target_sid;
- const char *delegation_check_attrs[] = {
- "objectSid", NULL
- };
-
- TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2self");
-
- if (!mem_ctx) {
- ret = ENOMEM;
- krb5_set_error_message(context, ret, "samba_kdc_check_s4u2self: talloc_named() failed!");
- return ret;
- }
-
- ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, target_principal,
- SDB_F_GET_CLIENT|SDB_F_GET_SERVER,
- delegation_check_attrs, &realm_dn, &msg);
-
- if (ret != 0) {
- talloc_free(mem_ctx);
- return ret;
- }
+ TALLOC_CTX *frame = talloc_stackframe();
- orig_sid = samdb_result_dom_sid(mem_ctx, skdc_entry->msg, "objectSid");
- target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
+ orig_sid = samdb_result_dom_sid(frame,
+ skdc_entry_client->msg,
+ "objectSid");
+ target_sid = samdb_result_dom_sid(frame,
+ skdc_entry_server_target->msg,
+ "objectSid");
- /* Allow delegation to the same principal, even if by a different
- * name. The easy and safe way to prove this is by SID
- * comparison */
+ /*
+ * Allow delegation to the same record (representing a
+ * principal), even if by a different name. The easy and safe
+ * way to prove this is by SID comparison
+ */
if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
- talloc_free(mem_ctx);
+ talloc_free(frame);
return KRB5KDC_ERR_BADOPTION;
}
- talloc_free(mem_ctx);
- return ret;
+ talloc_free(frame);
+ return 0;
}
/* Certificates printed by a the Certificate Authority might have a
diff -Nru samba-4.13.3+dfsg/source4/kdc/db-glue.h samba-4.13.14+dfsg/source4/kdc/db-glue.h
--- samba-4.13.3+dfsg/source4/kdc/db-glue.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/db-glue.h 2021-11-08 11:29:14.000000000 +0000
@@ -40,9 +40,8 @@
krb5_error_code
samba_kdc_check_s4u2self(krb5_context context,
- struct samba_kdc_db_context *kdc_db_ctx,
- struct samba_kdc_entry *skdc_entry,
- krb5_const_principal target_principal);
+ struct samba_kdc_entry *skdc_entry_client,
+ struct samba_kdc_entry *skdc_entry_server_target);
krb5_error_code
samba_kdc_check_pkinit_ms_upn_match(krb5_context context,
diff -Nru samba-4.13.3+dfsg/source4/kdc/hdb-samba4.c samba-4.13.14+dfsg/source4/kdc/hdb-samba4.c
--- samba-4.13.3+dfsg/source4/kdc/hdb-samba4.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/hdb-samba4.c 2021-11-08 11:29:14.000000000 +0000
@@ -274,38 +274,19 @@
static krb5_error_code
hdb_samba4_check_s4u2self(krb5_context context, HDB *db,
- hdb_entry_ex *entry,
- krb5_const_principal target_principal)
+ hdb_entry_ex *client_entry,
+ hdb_entry_ex *server_target_entry)
{
- struct samba_kdc_db_context *kdc_db_ctx;
- struct samba_kdc_entry *skdc_entry;
- krb5_error_code ret;
+ struct samba_kdc_entry *skdc_client_entry
+ = talloc_get_type_abort(client_entry->ctx,
+ struct samba_kdc_entry);
+ struct samba_kdc_entry *skdc_server_target_entry
+ = talloc_get_type_abort(server_target_entry->ctx,
+ struct samba_kdc_entry);
- kdc_db_ctx = talloc_get_type_abort(db->hdb_db,
- struct samba_kdc_db_context);
- skdc_entry = talloc_get_type_abort(entry->ctx,
- struct samba_kdc_entry);
-
- ret = samba_kdc_check_s4u2self(context, kdc_db_ctx,
- skdc_entry,
- target_principal);
- switch (ret) {
- case 0:
- break;
- case SDB_ERR_WRONG_REALM:
- ret = HDB_ERR_WRONG_REALM;
- break;
- case SDB_ERR_NOENTRY:
- ret = HDB_ERR_NOENTRY;
- break;
- case SDB_ERR_NOT_FOUND_HERE:
- ret = HDB_ERR_NOT_FOUND_HERE;
- break;
- default:
- break;
- }
-
- return ret;
+ return samba_kdc_check_s4u2self(context,
+ skdc_client_entry,
+ skdc_server_target_entry);
}
static void reset_bad_password_netlogon(TALLOC_CTX *mem_ctx,
diff -Nru samba-4.13.3+dfsg/source4/kdc/kdc-heimdal.c samba-4.13.14+dfsg/source4/kdc/kdc-heimdal.c
--- samba-4.13.3+dfsg/source4/kdc/kdc-heimdal.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/kdc-heimdal.c 2021-11-08 11:29:14.000000000 +0000
@@ -276,6 +276,7 @@
return NT_STATUS_INVALID_DOMAIN_ROLE;
case ROLE_DOMAIN_PDC:
case ROLE_DOMAIN_BDC:
+ case ROLE_IPA_DC:
task_server_terminate(
task, "Cannot start KDC as a 'classic Samba' DC", false);
return NT_STATUS_INVALID_DOMAIN_ROLE;
diff -Nru samba-4.13.3+dfsg/source4/kdc/mit-kdb/kdb_samba.h samba-4.13.14+dfsg/source4/kdc/mit-kdb/kdb_samba.h
--- samba-4.13.3+dfsg/source4/kdc/mit-kdb/kdb_samba.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/mit-kdb/kdb_samba.h 2021-11-08 11:29:14.000000000 +0000
@@ -41,6 +41,13 @@
struct mit_samba_context *ks_get_context(krb5_context kcontext);
+krb5_error_code ks_get_principal(krb5_context context,
+ krb5_const_principal principal,
+ unsigned int kflags,
+ krb5_db_entry **kentry);
+
+void ks_free_principal(krb5_context context, krb5_db_entry *entry);
+
bool ks_data_eq_string(krb5_data d, const char *s);
krb5_data ks_make_data(void *data, unsigned int len);
diff -Nru samba-4.13.3+dfsg/source4/kdc/mit-kdb/kdb_samba_policies.c samba-4.13.14+dfsg/source4/kdc/mit-kdb/kdb_samba_policies.c
--- samba-4.13.3+dfsg/source4/kdc/mit-kdb/kdb_samba_policies.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/mit-kdb/kdb_samba_policies.c 2021-11-08 11:29:14.000000000 +0000
@@ -4,7 +4,7 @@
Samba KDB plugin for MIT Kerberos
Copyright (c) 2010 Simo Sorce .
- Copyright (c) 2014 Andreas Schneider
+ Copyright (c) 2014-2021 Andreas Schneider
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -323,11 +323,18 @@
krb5_authdata ***signed_auth_data)
{
#endif
+ krb5_const_principal ks_client_princ = NULL;
+ krb5_db_entry *client_entry = NULL;
+ krb5_authdata **pac_auth_data = NULL;
krb5_authdata **authdata = NULL;
krb5_boolean is_as_req;
krb5_error_code code;
krb5_pac pac = NULL;
krb5_data pac_data;
+ bool with_pac = false;
+ bool generate_pac = false;
+ char *client_name = NULL;
+
#if KRB5_KDB_API_VERSION >= 10
krbtgt = krbtgt == NULL ? local_krbtgt : krbtgt;
@@ -341,44 +348,168 @@
is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
- if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) {
- code = ks_get_pac(context, client, client_key, &pac);
- if (code != 0) {
- goto done;
+ /*
+ * When using s4u2proxy client_princ actually refers to the proxied user
+ * while client->princ to the proxy service asking for the TGS on behalf
+ * of the proxied user. So always use client_princ in preference.
+ *
+ * Note that when client principal is not NULL, client entry might be
+ * NULL for cross-realm case, so we need to make sure to not
+ * dereference NULL pointer here.
+ */
+ if (client_princ != NULL) {
+ ks_client_princ = client_princ;
+ if (!is_as_req) {
+ krb5_boolean is_equal = false;
+
+ if (client != NULL && client->princ != NULL) {
+ is_equal =
+ krb5_principal_compare(context,
+ client_princ,
+ client->princ);
+ }
+
+ /*
+ * When client principal is the same as supplied client
+ * entry, don't fetch it.
+ */
+ if (!is_equal) {
+ code = ks_get_principal(context,
+ ks_client_princ,
+ 0,
+ &client_entry);
+ if (code != 0) {
+ (void)krb5_unparse_name(context,
+ ks_client_princ,
+ &client_name);
+
+ DBG_DEBUG("We didn't find the client "
+ "principal [%s] in our "
+ "database.\n",
+ client_name);
+ SAFE_FREE(client_name);
+
+ /*
+ * If we didn't find client_princ in our
+ * database it might be from another
+ * realm.
+ */
+ client_entry = NULL;
+ }
+ }
+ }
+ } else {
+ if (client == NULL) {
+ *signed_auth_data = NULL;
+ return 0;
}
+ ks_client_princ = client->princ;
}
- if (!is_as_req) {
- code = ks_verify_pac(context,
- flags,
- client_princ,
- client,
- server,
- krbtgt,
- server_key,
- krbtgt_key,
- authtime,
- tgt_auth_data,
- &pac);
- if (code != 0) {
- goto done;
- }
+ if (client_entry == NULL) {
+ client_entry = client;
}
- if (pac == NULL && client != NULL) {
+ if (is_as_req) {
+ with_pac = mit_samba_princ_needs_pac(client_entry);
+ } else {
+ with_pac = mit_samba_princ_needs_pac(server);
+ }
- code = ks_get_pac(context, client, client_key, &pac);
+ code = krb5_unparse_name(context,
+ client_princ,
+ &client_name);
+ if (code != 0) {
+ goto done;
+ }
+
+ if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC) != 0) {
+ generate_pac = true;
+ }
+
+ DBG_DEBUG("*** Sign data for client principal: %s [%s %s%s]\n",
+ client_name,
+ is_as_req ? "AS-REQ" : "TGS_REQ",
+ with_pac ? is_as_req ? "WITH_PAC" : "FIND_PAC" : "NO_PAC",
+ generate_pac ? " GENERATE_PAC" : "");
+
+ /*
+ * Generate PAC for the AS-REQ or check or generate one for the TGS if
+ * needed.
+ */
+ if (with_pac && generate_pac) {
+ DBG_DEBUG("Generate PAC for AS-REQ [%s]\n", client_name);
+ code = ks_get_pac(context, client_entry, client_key, &pac);
+ if (code != 0) {
+ goto done;
+ }
+ } else if (with_pac && !is_as_req) {
+ /*
+ * Find the PAC in the TGS, if one exists.
+ */
+ code = krb5_find_authdata(context,
+ tgt_auth_data,
+ NULL,
+ KRB5_AUTHDATA_WIN2K_PAC,
+ &pac_auth_data);
if (code != 0) {
+ DBG_ERR("krb5_find_authdata failed: %d\n", code);
goto done;
}
+ DBG_DEBUG("Found PAC data for TGS-REQ [%s]\n", client_name);
+
+ if (pac_auth_data != NULL && pac_auth_data[0] != NULL) {
+ if (pac_auth_data[1] != NULL) {
+ DBG_ERR("Invalid PAC data!\n");
+ code = KRB5KDC_ERR_BADOPTION;
+ goto done;
+ }
+
+ DBG_DEBUG("Verify PAC for TGS [%s]\n",
+ client_name);
+
+ code = ks_verify_pac(context,
+ flags,
+ ks_client_princ,
+ client_entry,
+ server,
+ krbtgt,
+ server_key,
+ krbtgt_key,
+ authtime,
+ tgt_auth_data,
+ &pac);
+ if (code != 0) {
+ goto done;
+ }
+ } else {
+ if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
+ DBG_DEBUG("Generate PAC for constrained"
+ "delegation TGS [%s]\n",
+ client_name);
+
+ code = ks_get_pac(context,
+ client_entry,
+ client_key,
+ &pac);
+ if (code != 0 && code != ENOENT) {
+ goto done;
+ }
+ }
+ }
}
if (pac == NULL) {
- code = KRB5_KDB_DBTYPE_NOSUP;
+ DBG_DEBUG("No PAC data - we're done [%s]\n", client_name);
+ *signed_auth_data = NULL;
+ code = 0;
goto done;
}
- code = krb5_pac_sign(context, pac, authtime, client_princ,
+ DBG_DEBUG("Signing PAC for %s [%s]\n",
+ is_as_req ? "AS-REQ" : "TGS-REQ",
+ client_name);
+ code = krb5_pac_sign(context, pac, authtime, ks_client_princ,
server_key, krbtgt_key, &pac_data);
if (code != 0) {
DBG_ERR("krb5_pac_sign failed: %d\n", code);
@@ -412,8 +543,12 @@
code = 0;
done:
- krb5_pac_free(context, pac);
+ if (client_entry != NULL && client_entry != client) {
+ ks_free_principal(context, client_entry);
+ }
+ SAFE_FREE(client_name);
krb5_free_authdata(context, authdata);
+ krb5_pac_free(context, pac);
return code;
}
diff -Nru samba-4.13.3+dfsg/source4/kdc/mit-kdb/kdb_samba_principals.c samba-4.13.14+dfsg/source4/kdc/mit-kdb/kdb_samba_principals.c
--- samba-4.13.3+dfsg/source4/kdc/mit-kdb/kdb_samba_principals.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/mit-kdb/kdb_samba_principals.c 2021-11-08 11:29:14.000000000 +0000
@@ -33,10 +33,10 @@
#define ADMIN_LIFETIME 60*60*3 /* 3 hours */
#define CHANGEPW_LIFETIME 60*5 /* 5 minutes */
-static krb5_error_code ks_get_principal(krb5_context context,
- krb5_const_principal principal,
- unsigned int kflags,
- krb5_db_entry **kentry)
+krb5_error_code ks_get_principal(krb5_context context,
+ krb5_const_principal principal,
+ unsigned int kflags,
+ krb5_db_entry **kentry)
{
struct mit_samba_context *mit_ctx;
krb5_error_code code;
@@ -59,6 +59,58 @@
return code;
}
+static void ks_free_principal_e_data(krb5_context context, krb5_octet *e_data)
+{
+ struct samba_kdc_entry *skdc_entry;
+
+ skdc_entry = talloc_get_type_abort(e_data,
+ struct samba_kdc_entry);
+ talloc_set_destructor(skdc_entry, NULL);
+ TALLOC_FREE(skdc_entry);
+}
+
+void ks_free_principal(krb5_context context, krb5_db_entry *entry)
+{
+ krb5_tl_data *tl_data_next = NULL;
+ krb5_tl_data *tl_data = NULL;
+ size_t i, j;
+
+ if (entry != NULL) {
+ krb5_free_principal(context, entry->princ);
+
+ for (tl_data = entry->tl_data; tl_data; tl_data = tl_data_next) {
+ tl_data_next = tl_data->tl_data_next;
+ if (tl_data->tl_data_contents != NULL) {
+ free(tl_data->tl_data_contents);
+ }
+ free(tl_data);
+ }
+
+ if (entry->key_data != NULL) {
+ for (i = 0; i < entry->n_key_data; i++) {
+ for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
+ if (entry->key_data[i].key_data_length[j] != 0) {
+ if (entry->key_data[i].key_data_contents[j] != NULL) {
+ memset(entry->key_data[i].key_data_contents[j], 0, entry->key_data[i].key_data_length[j]);
+ free(entry->key_data[i].key_data_contents[j]);
+ }
+ }
+ entry->key_data[i].key_data_contents[j] = NULL;
+ entry->key_data[i].key_data_length[j] = 0;
+ entry->key_data[i].key_data_type[j] = 0;
+ }
+ }
+ free(entry->key_data);
+ }
+
+ if (entry->e_data) {
+ ks_free_principal_e_data(context, entry->e_data);
+ }
+
+ free(entry);
+ }
+}
+
static krb5_boolean ks_is_master_key_principal(krb5_context context,
krb5_const_principal princ)
{
diff -Nru samba-4.13.3+dfsg/source4/kdc/mit_samba.c samba-4.13.14+dfsg/source4/kdc/mit_samba.c
--- samba-4.13.3+dfsg/source4/kdc/mit_samba.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/mit_samba.c 2021-11-08 11:29:14.000000000 +0000
@@ -434,9 +434,15 @@
skdc_entry,
&logon_info_blob,
cred_ndr_ptr,
- &upn_dns_info_blob);
+ &upn_dns_info_blob,
+ NULL, NULL, NULL,
+ NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(tmp_ctx);
+ if (NT_STATUS_EQUAL(nt_status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ return ENOENT;
+ }
return EINVAL;
}
@@ -458,6 +464,8 @@
pcred_blob,
upn_dns_info_blob,
NULL,
+ NULL,
+ NULL,
pac);
talloc_free(tmp_ctx);
@@ -498,37 +506,51 @@
krb5_pac new_pac = NULL;
bool ok;
+ /* Create a memory context early so code can use talloc_stackframe() */
+ tmp_ctx = talloc_named(ctx, 0, "mit_samba_reget_pac context");
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
if (client != NULL) {
client_skdc_entry =
talloc_get_type_abort(client->e_data,
struct samba_kdc_entry);
- /* The user account may be set not to want the PAC */
- ok = samba_princ_needs_pac(client_skdc_entry);
- if (!ok) {
- return EINVAL;
+ /*
+ * Check the objectSID of the client and pac data are the same.
+ * Does a parse and SID check, but no crypto.
+ */
+ code = samba_kdc_validate_pac_blob(context, client_skdc_entry, *pac);
+ if (code != 0) {
+ goto done;
}
}
if (server == NULL) {
- return EINVAL;
+ code = EINVAL;
+ goto done;
}
+
server_skdc_entry =
talloc_get_type_abort(server->e_data,
struct samba_kdc_entry);
+ /* The account may be set not to want the PAC */
+ ok = samba_princ_needs_pac(server_skdc_entry);
+ if (!ok) {
+ code = EINVAL;
+ goto done;
+ }
+
if (krbtgt == NULL) {
- return EINVAL;
+ code = EINVAL;
+ goto done;
}
krbtgt_skdc_entry =
talloc_get_type_abort(krbtgt->e_data,
struct samba_kdc_entry);
- tmp_ctx = talloc_named(ctx, 0, "mit_samba_reget_pac context");
- if (tmp_ctx == NULL) {
- return ENOMEM;
- }
-
code = samba_krbtgt_is_in_db(krbtgt_skdc_entry,
&is_in_db,
&is_untrusted);
@@ -546,7 +568,10 @@
client_skdc_entry,
&pac_blob,
NULL,
- &upn_blob);
+ &upn_blob,
+ NULL, NULL,
+ NULL,
+ NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
code = EINVAL;
goto done;
@@ -575,8 +600,7 @@
nt_status = samba_kdc_update_pac_blob(tmp_ctx,
context,
- krbtgt_skdc_entry,
- server_skdc_entry,
+ krbtgt_skdc_entry->kdc_db_ctx->samdb,
*pac,
pac_blob,
pac_srv_sig,
@@ -1165,3 +1189,11 @@
p->msg,
ldb_get_default_basedn(p->kdc_db_ctx->samdb));
}
+
+bool mit_samba_princ_needs_pac(krb5_db_entry *db_entry)
+{
+ struct samba_kdc_entry *skdc_entry =
+ talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
+
+ return samba_princ_needs_pac(skdc_entry);
+}
diff -Nru samba-4.13.3+dfsg/source4/kdc/mit_samba.h samba-4.13.14+dfsg/source4/kdc/mit_samba.h
--- samba-4.13.3+dfsg/source4/kdc/mit_samba.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/mit_samba.h 2021-11-08 11:29:14.000000000 +0000
@@ -85,4 +85,6 @@
void mit_samba_update_bad_password_count(krb5_db_entry *db_entry);
+bool mit_samba_princ_needs_pac(krb5_db_entry *db_entry);
+
#endif /* _MIT_SAMBA_H */
diff -Nru samba-4.13.3+dfsg/source4/kdc/pac-glue.c samba-4.13.14+dfsg/source4/kdc/pac-glue.c
--- samba-4.13.3+dfsg/source4/kdc/pac-glue.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/pac-glue.c 2021-11-08 11:29:14.000000000 +0000
@@ -35,11 +35,13 @@
#include "libcli/security/security.h"
#include "dsdb/samdb/samdb.h"
#include "auth/kerberos/pac_utils.h"
+#include "source4/dsdb/common/util.h"
static
NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
const struct auth_user_info_dc *info,
- DATA_BLOB *pac_data)
+ DATA_BLOB *pac_data,
+ DATA_BLOB *requester_sid_blob)
{
struct netr_SamInfo3 *info3;
union PAC_INFO pac_info;
@@ -49,6 +51,9 @@
ZERO_STRUCT(pac_info);
*pac_data = data_blob_null;
+ if (requester_sid_blob != NULL) {
+ *requester_sid_blob = data_blob_null;
+ }
nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, info, &info3);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -74,6 +79,25 @@
return nt_status;
}
+ if (requester_sid_blob != NULL && info->num_sids > 0) {
+ union PAC_INFO pac_requester_sid;
+
+ ZERO_STRUCT(pac_requester_sid);
+
+ pac_requester_sid.requester_sid.sid = info->sids[0];
+
+ ndr_err = ndr_push_union_blob(requester_sid_blob, mem_ctx,
+ &pac_requester_sid,
+ PAC_TYPE_REQUESTER_SID,
+ (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ nt_status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(1, ("PAC_REQUESTER_SID (presig) push failed: %s\n",
+ nt_errstr(nt_status)));
+ return nt_status;
+ }
+ }
+
return NT_STATUS_OK;
}
@@ -100,6 +124,14 @@
pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED;
}
+ pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID;
+
+ pac_upn.upn_dns_info.ex.sam_name_and_sid.samaccountname
+ = info->info->account_name;
+
+ pac_upn.upn_dns_info.ex.sam_name_and_sid.objectsid
+ = &info->sids[0];
+
ndr_err = ndr_push_union_blob(upn_data, mem_ctx, &pac_upn,
PAC_TYPE_UPN_DNS_INFO,
(ndr_push_flags_fn_t)ndr_push_PAC_INFO);
@@ -114,6 +146,43 @@
}
static
+NTSTATUS samba_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
+ const krb5_boolean *pac_request,
+ DATA_BLOB *pac_attrs_data)
+{
+ union PAC_INFO pac_attrs;
+ enum ndr_err_code ndr_err;
+ NTSTATUS nt_status;
+
+ ZERO_STRUCT(pac_attrs);
+
+ *pac_attrs_data = data_blob_null;
+
+ /* Set the length of the flags in bits. */
+ pac_attrs.attributes_info.flags_length = 2;
+
+ if (pac_request == NULL) {
+ pac_attrs.attributes_info.flags
+ |= PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY;
+ } else if (*pac_request) {
+ pac_attrs.attributes_info.flags
+ |= PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED;
+ }
+
+ ndr_err = ndr_push_union_blob(pac_attrs_data, mem_ctx, &pac_attrs,
+ PAC_TYPE_ATTRIBUTES_INFO,
+ (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ nt_status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(1, ("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
+ nt_errstr(nt_status)));
+ return nt_status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static
NTSTATUS samba_get_cred_info_ndr_blob(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg,
DATA_BLOB *cred_blob)
@@ -413,12 +482,16 @@
const DATA_BLOB *logon_blob,
const DATA_BLOB *cred_blob,
const DATA_BLOB *upn_blob,
+ const DATA_BLOB *pac_attrs_blob,
+ const DATA_BLOB *requester_sid_blob,
const DATA_BLOB *deleg_blob,
krb5_pac *pac)
{
krb5_data logon_data;
krb5_data cred_data;
krb5_data upn_data;
+ krb5_data pac_attrs_data;
+ krb5_data requester_sid_data;
krb5_data deleg_data;
krb5_error_code ret;
#ifdef SAMBA4_USES_HEIMDAL
@@ -463,6 +536,33 @@
}
}
+ ZERO_STRUCT(pac_attrs_data);
+ if (pac_attrs_blob != NULL) {
+ ret = smb_krb5_copy_data_contents(&pac_attrs_data,
+ pac_attrs_blob->data,
+ pac_attrs_blob->length);
+ if (ret != 0) {
+ smb_krb5_free_data_contents(context, &logon_data);
+ smb_krb5_free_data_contents(context, &cred_data);
+ smb_krb5_free_data_contents(context, &upn_data);
+ return ret;
+ }
+ }
+
+ ZERO_STRUCT(requester_sid_data);
+ if (requester_sid_blob != NULL) {
+ ret = smb_krb5_copy_data_contents(&requester_sid_data,
+ requester_sid_blob->data,
+ requester_sid_blob->length);
+ if (ret != 0) {
+ smb_krb5_free_data_contents(context, &logon_data);
+ smb_krb5_free_data_contents(context, &cred_data);
+ smb_krb5_free_data_contents(context, &upn_data);
+ smb_krb5_free_data_contents(context, &pac_attrs_data);
+ return ret;
+ }
+ }
+
ZERO_STRUCT(deleg_data);
if (deleg_blob != NULL) {
ret = smb_krb5_copy_data_contents(&deleg_data,
@@ -472,6 +572,8 @@
smb_krb5_free_data_contents(context, &logon_data);
smb_krb5_free_data_contents(context, &cred_data);
smb_krb5_free_data_contents(context, &upn_data);
+ smb_krb5_free_data_contents(context, &pac_attrs_data);
+ smb_krb5_free_data_contents(context, &requester_sid_data);
return ret;
}
}
@@ -481,6 +583,8 @@
smb_krb5_free_data_contents(context, &logon_data);
smb_krb5_free_data_contents(context, &cred_data);
smb_krb5_free_data_contents(context, &upn_data);
+ smb_krb5_free_data_contents(context, &pac_attrs_data);
+ smb_krb5_free_data_contents(context, &requester_sid_data);
smb_krb5_free_data_contents(context, &deleg_data);
return ret;
}
@@ -488,8 +592,10 @@
ret = krb5_pac_add_buffer(context, *pac, PAC_TYPE_LOGON_INFO, &logon_data);
smb_krb5_free_data_contents(context, &logon_data);
if (ret != 0) {
- smb_krb5_free_data_contents(context, &upn_data);
smb_krb5_free_data_contents(context, &cred_data);
+ smb_krb5_free_data_contents(context, &upn_data);
+ smb_krb5_free_data_contents(context, &pac_attrs_data);
+ smb_krb5_free_data_contents(context, &requester_sid_data);
smb_krb5_free_data_contents(context, &deleg_data);
return ret;
}
@@ -501,6 +607,8 @@
smb_krb5_free_data_contents(context, &cred_data);
if (ret != 0) {
smb_krb5_free_data_contents(context, &upn_data);
+ smb_krb5_free_data_contents(context, &pac_attrs_data);
+ smb_krb5_free_data_contents(context, &requester_sid_data);
smb_krb5_free_data_contents(context, &deleg_data);
return ret;
}
@@ -519,6 +627,8 @@
&null_data);
if (ret != 0) {
smb_krb5_free_data_contents(context, &upn_data);
+ smb_krb5_free_data_contents(context, &pac_attrs_data);
+ smb_krb5_free_data_contents(context, &requester_sid_data);
smb_krb5_free_data_contents(context, &deleg_data);
return ret;
}
@@ -530,6 +640,31 @@
&upn_data);
smb_krb5_free_data_contents(context, &upn_data);
if (ret != 0) {
+ smb_krb5_free_data_contents(context, &pac_attrs_data);
+ smb_krb5_free_data_contents(context, &requester_sid_data);
+ smb_krb5_free_data_contents(context, &deleg_data);
+ return ret;
+ }
+ }
+
+ if (pac_attrs_blob != NULL) {
+ ret = krb5_pac_add_buffer(context, *pac,
+ PAC_TYPE_ATTRIBUTES_INFO,
+ &pac_attrs_data);
+ smb_krb5_free_data_contents(context, &pac_attrs_data);
+ if (ret != 0) {
+ smb_krb5_free_data_contents(context, &requester_sid_data);
+ smb_krb5_free_data_contents(context, &deleg_data);
+ return ret;
+ }
+ }
+
+ if (requester_sid_blob != NULL) {
+ ret = krb5_pac_add_buffer(context, *pac,
+ PAC_TYPE_REQUESTER_SID,
+ &requester_sid_data);
+ smb_krb5_free_data_contents(context, &requester_sid_data);
+ if (ret != 0) {
smb_krb5_free_data_contents(context, &deleg_data);
return ret;
}
@@ -562,6 +697,48 @@
return true;
}
+int samba_client_requested_pac(krb5_context context,
+ krb5_pac *pac,
+ TALLOC_CTX *mem_ctx,
+ bool *requested_pac)
+{
+ enum ndr_err_code ndr_err;
+ krb5_data k5pac_attrs_in;
+ DATA_BLOB pac_attrs_in;
+ union PAC_INFO pac_attrs;
+ int ret;
+
+ *requested_pac = true;
+
+ ret = krb5_pac_get_buffer(context, *pac, PAC_TYPE_ATTRIBUTES_INFO,
+ &k5pac_attrs_in);
+ if (ret != 0) {
+ return ret == ENOENT ? 0 : ret;
+ }
+
+ pac_attrs_in = data_blob_const(k5pac_attrs_in.data,
+ k5pac_attrs_in.length);
+
+ ndr_err = ndr_pull_union_blob(&pac_attrs_in, mem_ctx, &pac_attrs,
+ PAC_TYPE_ATTRIBUTES_INFO,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
+ smb_krb5_free_data_contents(context, &k5pac_attrs_in);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status)));
+ return EINVAL;
+ }
+
+ if (pac_attrs.attributes_info.flags & (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
+ | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED)) {
+ *requested_pac = true;
+ } else {
+ *requested_pac = false;
+ }
+
+ return 0;
+}
+
/* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
int samba_krbtgt_is_in_db(struct samba_kdc_entry *p,
bool *is_in_db,
@@ -575,12 +752,12 @@
if (!mem_ctx) {
return ENOMEM;
}
-
+
trust_direction = ldb_msg_find_attr_as_int(p->msg, "trustDirection", 0);
if (trust_direction != 0) {
/* Domain trust - we cannot check the sig, but we trust it for a correct PAC
-
+
This is exactly where we should flag for SID
validation when we do inter-foreest trusts
*/
@@ -633,16 +810,27 @@
return 0;
}
+/*
+ * We return not just the blobs, but also the user_info_dc because we
+ * will need, in the RODC case, to confirm that the returned user is
+ * permitted to be replicated to the KDC
+ */
NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
struct samba_kdc_entry *p,
DATA_BLOB **_logon_info_blob,
DATA_BLOB **_cred_ndr_blob,
- DATA_BLOB **_upn_info_blob)
+ DATA_BLOB **_upn_info_blob,
+ DATA_BLOB **_pac_attrs_blob,
+ const krb5_boolean *pac_request,
+ DATA_BLOB **_requester_sid_blob,
+ struct auth_user_info_dc **_user_info_dc)
{
struct auth_user_info_dc *user_info_dc;
DATA_BLOB *logon_blob = NULL;
DATA_BLOB *cred_blob = NULL;
DATA_BLOB *upn_blob = NULL;
+ DATA_BLOB *pac_attrs_blob = NULL;
+ DATA_BLOB *requester_sid_blob = NULL;
NTSTATUS nt_status;
*_logon_info_blob = NULL;
@@ -650,10 +838,11 @@
*_cred_ndr_blob = NULL;
}
*_upn_info_blob = NULL;
-
- /* The user account may be set not to want the PAC */
- if ( ! samba_princ_needs_pac(p)) {
- return NT_STATUS_OK;
+ if (_pac_attrs_blob != NULL) {
+ *_pac_attrs_blob = NULL;
+ }
+ if (_requester_sid_blob != NULL) {
+ *_requester_sid_blob = NULL;
}
logon_blob = talloc_zero(mem_ctx, DATA_BLOB);
@@ -673,6 +862,20 @@
return NT_STATUS_NO_MEMORY;
}
+ if (_pac_attrs_blob != NULL) {
+ pac_attrs_blob = talloc_zero(mem_ctx, DATA_BLOB);
+ if (pac_attrs_blob == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (_requester_sid_blob != NULL) {
+ requester_sid_blob = talloc_zero(mem_ctx, DATA_BLOB);
+ if (requester_sid_blob == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
nt_status = authsam_make_user_info_dc(mem_ctx, p->kdc_db_ctx->samdb,
lpcfg_netbios_name(p->kdc_db_ctx->lp_ctx),
lpcfg_sam_name(p->kdc_db_ctx->lp_ctx),
@@ -690,7 +893,8 @@
nt_status = samba_get_logon_info_pac_blob(logon_blob,
user_info_dc,
- logon_blob);
+ logon_blob,
+ requester_sid_blob);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0, ("Building PAC LOGON INFO failed: %s\n",
nt_errstr(nt_status)));
@@ -717,38 +921,44 @@
return nt_status;
}
- TALLOC_FREE(user_info_dc);
+ if (pac_attrs_blob != NULL) {
+ nt_status = samba_get_pac_attrs_blob(pac_attrs_blob,
+ pac_request,
+ pac_attrs_blob);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("Building PAC ATTRIBUTES failed: %s\n",
+ nt_errstr(nt_status)));
+ return nt_status;
+ }
+ }
+
+ /*
+ * Return to the caller to allow a check on the allowed/denied
+ * RODC replication groups
+ */
+ if (_user_info_dc == NULL) {
+ TALLOC_FREE(user_info_dc);
+ } else {
+ *_user_info_dc = user_info_dc;
+ }
*_logon_info_blob = logon_blob;
if (_cred_ndr_blob != NULL) {
*_cred_ndr_blob = cred_blob;
}
*_upn_info_blob = upn_blob;
- return NT_STATUS_OK;
-}
-
-NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
- struct samba_kdc_entry *p,
- DATA_BLOB **_logon_info_blob)
-{
- NTSTATUS nt_status;
- DATA_BLOB *upn_blob = NULL;
-
- nt_status = samba_kdc_get_pac_blobs(mem_ctx, p,
- _logon_info_blob,
- NULL, /* cred_blob */
- &upn_blob);
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
+ if (_pac_attrs_blob != NULL) {
+ *_pac_attrs_blob = pac_attrs_blob;
+ }
+ if (_requester_sid_blob != NULL) {
+ *_requester_sid_blob = requester_sid_blob;
}
-
- TALLOC_FREE(upn_blob);
return NT_STATUS_OK;
}
NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
krb5_context context,
- struct samba_kdc_entry *krbtgt,
- struct samba_kdc_entry *server,
+ struct ldb_context *samdb,
const krb5_pac pac, DATA_BLOB *pac_blob,
struct PAC_SIGNATURE_DATA *pac_srv_sig,
struct PAC_SIGNATURE_DATA *pac_kdc_sig)
@@ -768,14 +978,14 @@
* as the token might be generated by a trusted domain.
*/
nt_status = authsam_update_user_info_dc(mem_ctx,
- krbtgt->kdc_db_ctx->samdb,
+ samdb,
user_info_dc);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
- nt_status = samba_get_logon_info_pac_blob(mem_ctx,
- user_info_dc, pac_blob);
+ nt_status = samba_get_logon_info_pac_blob(mem_ctx,
+ user_info_dc, pac_blob, NULL);
return nt_status;
}
@@ -924,3 +1134,206 @@
talloc_free(tmp_ctx);
return nt_status;
}
+
+static krb5_error_code samba_get_requester_sid(TALLOC_CTX *mem_ctx,
+ krb5_pac pac,
+ krb5_context context,
+ struct dom_sid *sid)
+{
+ NTSTATUS nt_status;
+ enum ndr_err_code ndr_err;
+ krb5_error_code ret;
+
+ DATA_BLOB pac_requester_sid_in;
+ krb5_data k5pac_requester_sid_in;
+
+ union PAC_INFO info;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_REQUESTER_SID,
+ &k5pac_requester_sid_in);
+ if (ret != 0) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ pac_requester_sid_in = data_blob_const(k5pac_requester_sid_in.data,
+ k5pac_requester_sid_in.length);
+
+ ndr_err = ndr_pull_union_blob(&pac_requester_sid_in, tmp_ctx, &info,
+ PAC_TYPE_REQUESTER_SID,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
+ smb_krb5_free_data_contents(context, &k5pac_requester_sid_in);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ nt_status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status)));
+ talloc_free(tmp_ctx);
+ return EINVAL;
+ }
+
+ *sid = info.requester_sid.sid;
+
+ talloc_free(tmp_ctx);
+ return 0;
+}
+
+/* Does a parse and SID check, but no crypto. */
+krb5_error_code samba_kdc_validate_pac_blob(
+ krb5_context context,
+ struct samba_kdc_entry *client_skdc_entry,
+ const krb5_pac pac)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct auth_user_info_dc *pac_user_info = NULL;
+ struct dom_sid *client_sid = NULL;
+ struct dom_sid pac_sid;
+ krb5_error_code code;
+ bool ok;
+
+ /*
+ * First, try to get the SID from the requester SID buffer in the PAC.
+ */
+ code = samba_get_requester_sid(frame, pac, context, &pac_sid);
+
+ if (code == ENOENT) {
+ /*
+ * If the requester SID buffer isn't present, fall back to the
+ * SID in the LOGON_INFO PAC buffer.
+ */
+ code = kerberos_pac_to_user_info_dc(frame,
+ pac,
+ context,
+ &pac_user_info,
+ NULL,
+ NULL);
+ if (code != 0) {
+ goto out;
+ }
+
+ if (pac_user_info->num_sids == 0) {
+ code = EINVAL;
+ goto out;
+ }
+
+ pac_sid = pac_user_info->sids[0];
+ } else if (code != 0) {
+ goto out;
+ }
+
+ client_sid = samdb_result_dom_sid(frame,
+ client_skdc_entry->msg,
+ "objectSid");
+
+ ok = dom_sid_equal(&pac_sid, client_sid);
+ if (!ok) {
+ struct dom_sid_buf buf1;
+ struct dom_sid_buf buf2;
+
+ DBG_ERR("SID mismatch between PAC and looked up client: "
+ "PAC[%s] != CLI[%s]\n",
+ dom_sid_str_buf(&pac_sid, &buf1),
+ dom_sid_str_buf(client_sid, &buf2));
+#if defined(KRB5KDC_ERR_CLIENT_NAME_MISMATCH) /* MIT */
+ code = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
+#else /* Heimdal (where this is an enum) */
+ code = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
+#endif
+ goto out;
+ }
+
+ code = 0;
+out:
+ TALLOC_FREE(frame);
+ return code;
+}
+
+
+/*
+ * In the RODC case, to confirm that the returned user is permitted to
+ * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
+ */
+WERROR samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids,
+ struct dom_sid *object_sids,
+ struct samba_kdc_entry *rodc,
+ struct samba_kdc_entry *object)
+{
+ int ret;
+ WERROR werr;
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *rodc_attrs[] = { "msDS-KrbTgtLink",
+ "msDS-NeverRevealGroup",
+ "msDS-RevealOnDemandGroup",
+ "userAccountControl",
+ "objectSid",
+ NULL };
+ struct ldb_result *rodc_machine_account = NULL;
+ struct ldb_dn *rodc_machine_account_dn = samdb_result_dn(rodc->kdc_db_ctx->samdb,
+ frame,
+ rodc->msg,
+ "msDS-KrbTgtLinkBL",
+ NULL);
+ const struct dom_sid *rodc_machine_account_sid = NULL;
+
+ if (rodc_machine_account_dn == NULL) {
+ DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
+ ldb_dn_get_linearized(rodc->msg->dn));
+ TALLOC_FREE(frame);
+ return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
+ }
+
+ /*
+ * Follow the link and get the RODC account (the krbtgt
+ * account is the krbtgt_XXX account, but the
+ * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
+ * the RODC$ account)
+ *
+ * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
+ * out of the extended DNs
+ */
+
+ ret = dsdb_search_dn(rodc->kdc_db_ctx->samdb,
+ frame,
+ &rodc_machine_account,
+ rodc_machine_account_dn,
+ rodc_attrs,
+ DSDB_SEARCH_SHOW_EXTENDED_DN);
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
+ ldb_dn_get_linearized(rodc_machine_account_dn),
+ ldb_dn_get_linearized(rodc->msg->dn),
+ ldb_errstring(rodc->kdc_db_ctx->samdb));
+ TALLOC_FREE(frame);
+ return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
+ }
+
+ if (rodc_machine_account->count != 1) {
+ DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
+ ldb_dn_get_linearized(rodc_machine_account_dn),
+ ldb_dn_get_linearized(rodc->msg->dn),
+ rodc_machine_account->count);
+ TALLOC_FREE(frame);
+ return WERR_DS_DRA_BAD_DN;
+ }
+
+ /* if the object SID is equal to the user_sid, allow */
+ rodc_machine_account_sid = samdb_result_dom_sid(frame,
+ rodc_machine_account->msgs[0],
+ "objectSid");
+ if (rodc_machine_account_sid == NULL) {
+ return WERR_DS_DRA_BAD_DN;
+ }
+
+ werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc->kdc_db_ctx->samdb,
+ rodc_machine_account_sid,
+ rodc_machine_account->msgs[0],
+ object->msg,
+ num_object_sids,
+ object_sids);
+
+ TALLOC_FREE(frame);
+ return werr;
+}
diff -Nru samba-4.13.3+dfsg/source4/kdc/pac-glue.h samba-4.13.14+dfsg/source4/kdc/pac-glue.h
--- samba-4.13.3+dfsg/source4/kdc/pac-glue.h 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/pac-glue.h 2021-11-08 11:29:14.000000000 +0000
@@ -31,11 +31,18 @@
const DATA_BLOB *logon_blob,
const DATA_BLOB *cred_blob,
const DATA_BLOB *upn_blob,
+ const DATA_BLOB *pac_attrs_blob,
+ const DATA_BLOB *requester_sid_blob,
const DATA_BLOB *deleg_blob,
krb5_pac *pac);
bool samba_princ_needs_pac(struct samba_kdc_entry *skdc_entry);
+int samba_client_requested_pac(krb5_context context,
+ krb5_pac *pac,
+ TALLOC_CTX *mem_ctx,
+ bool *requested_pac);
+
int samba_krbtgt_is_in_db(struct samba_kdc_entry *skdc_entry,
bool *is_in_db,
bool *is_untrusted);
@@ -44,15 +51,14 @@
struct samba_kdc_entry *skdc_entry,
DATA_BLOB **_logon_info_blob,
DATA_BLOB **_cred_ndr_blob,
- DATA_BLOB **_upn_info_blob);
-NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
- struct samba_kdc_entry *skdc_entry,
- DATA_BLOB **_logon_info_blob);
-
+ DATA_BLOB **_upn_info_blob,
+ DATA_BLOB **_pac_attrs_blob,
+ const krb5_boolean *pac_request,
+ DATA_BLOB **_requester_sid_blob,
+ struct auth_user_info_dc **_user_info_dc);
NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
krb5_context context,
- struct samba_kdc_entry *krbtgt,
- struct samba_kdc_entry *server,
+ struct ldb_context *samdb,
const krb5_pac pac, DATA_BLOB *pac_blob,
struct PAC_SIGNATURE_DATA *pac_srv_sig,
struct PAC_SIGNATURE_DATA *pac_kdc_sig);
@@ -70,3 +76,17 @@
const char *client_name,
const char *workstation,
bool password_change);
+
+krb5_error_code samba_kdc_validate_pac_blob(
+ krb5_context context,
+ struct samba_kdc_entry *client_skdc_entry,
+ const krb5_pac pac);
+
+/*
+ * In the RODC case, to confirm that the returned user is permitted to
+ * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
+ */
+WERROR samba_rodc_confirm_user_is_allowed(uint32_t num_sids,
+ struct dom_sid *sids,
+ struct samba_kdc_entry *rodc,
+ struct samba_kdc_entry *object);
diff -Nru samba-4.13.3+dfsg/source4/kdc/wdc-samba4.c samba-4.13.14+dfsg/source4/kdc/wdc-samba4.c
--- samba-4.13.3+dfsg/source4/kdc/wdc-samba4.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/wdc-samba4.c 2021-11-08 11:29:14.000000000 +0000
@@ -23,7 +23,11 @@
#include "includes.h"
#include "kdc/kdc-glue.h"
+#include "kdc/db-glue.h"
#include "kdc/pac-glue.h"
+#include "sdb.h"
+#include "sdb_hdb.h"
+#include "librpc/gen_ndr/auth.h"
/*
* Given the right private pointer from hdb_samba4,
@@ -34,6 +38,7 @@
static krb5_error_code samba_wdc_get_pac(void *priv, krb5_context context,
struct hdb_entry_ex *client,
const krb5_keyblock *pk_reply_key,
+ const krb5_boolean *pac_request,
krb5_pac *pac)
{
TALLOC_CTX *mem_ctx;
@@ -43,6 +48,8 @@
DATA_BLOB _cred_blob = data_blob_null;
DATA_BLOB *cred_blob = NULL;
DATA_BLOB *upn_blob = NULL;
+ DATA_BLOB *pac_attrs_blob = NULL;
+ DATA_BLOB *requester_sid_blob = NULL;
krb5_error_code ret;
NTSTATUS nt_status;
struct samba_kdc_entry *skdc_entry =
@@ -61,7 +68,11 @@
nt_status = samba_kdc_get_pac_blobs(mem_ctx, skdc_entry,
&logon_blob,
cred_ndr_ptr,
- &upn_blob);
+ &upn_blob,
+ &pac_attrs_blob,
+ pac_request,
+ &requester_sid_blob,
+ NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(mem_ctx);
return EINVAL;
@@ -81,7 +92,8 @@
}
ret = samba_make_krb5_pac(context, logon_blob, cred_blob,
- upn_blob, NULL, pac);
+ upn_blob, pac_attrs_blob,
+ requester_sid_blob, NULL, pac);
talloc_free(mem_ctx);
return ret;
@@ -89,36 +101,36 @@
static krb5_error_code samba_wdc_get_pac_compat(void *priv, krb5_context context,
struct hdb_entry_ex *client,
+ const krb5_boolean *pac_request,
krb5_pac *pac)
{
- return samba_wdc_get_pac(priv, context, client, NULL, pac);
+ return samba_wdc_get_pac(priv, context, client, NULL, pac_request, pac);
}
-/* Resign (and reform, including possibly new groups) a PAC */
-
-static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
- const krb5_principal client_principal,
- const krb5_principal delegated_proxy_principal,
- struct hdb_entry_ex *client,
- struct hdb_entry_ex *server,
- struct hdb_entry_ex *krbtgt,
- krb5_pac *pac)
+static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
+ const krb5_principal delegated_proxy_principal,
+ struct hdb_entry_ex *client,
+ struct hdb_entry_ex *server,
+ struct hdb_entry_ex *krbtgt,
+ krb5_pac *pac,
+ krb5_cksumtype ctype)
{
- struct samba_kdc_entry *p =
+ struct samba_kdc_entry *server_skdc_entry =
talloc_get_type_abort(server->ctx,
struct samba_kdc_entry);
struct samba_kdc_entry *krbtgt_skdc_entry =
talloc_get_type_abort(krbtgt->ctx,
struct samba_kdc_entry);
- TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_kdc_reget_pac context");
+ TALLOC_CTX *mem_ctx = talloc_named(server_skdc_entry,
+ 0,
+ "samba_kdc_reget_pac2 context");
krb5_pac new_pac = NULL;
DATA_BLOB *pac_blob = NULL;
DATA_BLOB *upn_blob = NULL;
+ DATA_BLOB *requester_sid_blob = NULL;
DATA_BLOB *deleg_blob = NULL;
krb5_error_code ret;
NTSTATUS nt_status;
- struct PAC_SIGNATURE_DATA *pac_srv_sig;
- struct PAC_SIGNATURE_DATA *pac_kdc_sig;
bool is_in_db, is_untrusted;
size_t num_types = 0;
uint32_t *types = NULL;
@@ -130,95 +142,163 @@
ssize_t upn_dns_info_idx = -1;
ssize_t srv_checksum_idx = -1;
ssize_t kdc_checksum_idx = -1;
+ ssize_t tkt_checksum_idx = -1;
+ ssize_t attrs_info_idx = -1;
+ ssize_t requester_sid_idx = -1;
if (!mem_ctx) {
return ENOMEM;
}
- /* The user account may be set not to want the PAC */
- if (!samba_princ_needs_pac(p)) {
- talloc_free(mem_ctx);
- return EINVAL;
+ if (client != NULL) {
+ struct samba_kdc_entry *client_skdc_entry = NULL;
+
+ client_skdc_entry = talloc_get_type_abort(client->ctx,
+ struct samba_kdc_entry);
+
+ /*
+ * Check the objectSID of the client and pac data are the same.
+ * Does a parse and SID check, but no crypto.
+ */
+ ret = samba_kdc_validate_pac_blob(context, client_skdc_entry, *pac);
+ if (ret != 0) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
}
- /* If the krbtgt was generated by an RODC, and we are not that
+ /*
+ * If the krbtgt was generated by an RODC, and we are not that
* RODC, then we need to regenerate the PAC - we can't trust
- * it */
+ * it, and confirm that the RODC was permitted to print this ticket
+ *
+ * Becasue of the samba_kdc_validate_pac_blob() step we can be
+ * sure that the record in 'client' matches the SID in the
+ * original PAC.
+ */
ret = samba_krbtgt_is_in_db(krbtgt_skdc_entry, &is_in_db, &is_untrusted);
if (ret != 0) {
talloc_free(mem_ctx);
return ret;
}
- if (is_untrusted) {
- struct samba_kdc_entry *client_skdc_entry = NULL;
+ if (delegated_proxy_principal != NULL) {
+ krb5_enctype etype;
+ Key *key = NULL;
- if (client == NULL) {
- return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ if (!is_in_db) {
+ /*
+ * The RODC-issued PAC was signed by a KDC entry that we
+ * don't have a key for. The server signature is not
+ * trustworthy, since it could have been created by the
+ * server we got the ticket from. We must not proceed as
+ * otherwise the ticket signature is unchecked.
+ */
+ talloc_free(mem_ctx);
+ return HDB_ERR_NOT_FOUND_HERE;
}
- client_skdc_entry = talloc_get_type_abort(client->ctx,
- struct samba_kdc_entry);
-
- nt_status = samba_kdc_get_pac_blobs(mem_ctx, client_skdc_entry,
- &pac_blob, NULL, &upn_blob);
- if (!NT_STATUS_IS_OK(nt_status)) {
- talloc_free(mem_ctx);
- return EINVAL;
+ /* Fetch the correct key depending on the checksum type. */
+ if (ctype == CKSUMTYPE_HMAC_MD5) {
+ etype = ENCTYPE_ARCFOUR_HMAC;
+ } else {
+ ret = krb5_cksumtype_to_enctype(context,
+ ctype,
+ &etype);
+ if (ret != 0) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
}
- } else {
- pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
- if (!pac_blob) {
- talloc_free(mem_ctx);
- return ENOMEM;
+ ret = hdb_enctype2key(context, &krbtgt->entry, etype, &key);
+ if (ret != 0) {
+ return ret;
}
- pac_srv_sig = talloc_zero(mem_ctx, struct PAC_SIGNATURE_DATA);
- if (!pac_srv_sig) {
+ /* Check the KDC and ticket signatures. */
+ ret = krb5_pac_verify(context,
+ *pac,
+ 0,
+ NULL,
+ NULL,
+ &key->key);
+ if (ret != 0) {
+ DEBUG(1, ("PAC KDC signature failed to verify\n"));
talloc_free(mem_ctx);
- return ENOMEM;
+ return ret;
}
- pac_kdc_sig = talloc_zero(mem_ctx, struct PAC_SIGNATURE_DATA);
- if (!pac_kdc_sig) {
+ deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
+ if (!deleg_blob) {
talloc_free(mem_ctx);
return ENOMEM;
}
- nt_status = samba_kdc_update_pac_blob(mem_ctx, context,
- krbtgt_skdc_entry, p,
- *pac, pac_blob,
- pac_srv_sig, pac_kdc_sig);
+ nt_status = samba_kdc_update_delegation_info_blob(mem_ctx,
+ context, *pac,
+ server->entry.principal,
+ delegated_proxy_principal,
+ deleg_blob);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0, ("Building PAC failed: %s\n",
nt_errstr(nt_status)));
talloc_free(mem_ctx);
return EINVAL;
}
-
- if (is_in_db) {
- /* Now check the KDC signature, fetching the correct key based on the enc type */
- ret = kdc_check_pac(context, pac_srv_sig->signature, pac_kdc_sig, krbtgt);
- if (ret != 0) {
- DEBUG(1, ("PAC KDC signature failed to verify\n"));
- talloc_free(mem_ctx);
- return ret;
+ }
+
+ if (is_untrusted) {
+ struct samba_kdc_entry *client_skdc_entry = NULL;
+ struct auth_user_info_dc *user_info_dc = NULL;
+ WERROR werr;
+
+ if (client == NULL) {
+ return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ }
+
+ client_skdc_entry = talloc_get_type_abort(client->ctx,
+ struct samba_kdc_entry);
+
+ nt_status = samba_kdc_get_pac_blobs(mem_ctx, client_skdc_entry,
+ &pac_blob, NULL, &upn_blob,
+ NULL, NULL, &requester_sid_blob,
+ &user_info_dc);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ talloc_free(mem_ctx);
+ return KRB5KDC_ERR_TGT_REVOKED;
+ }
+
+ /*
+ * Now check if the SID list in the user_info_dc
+ * intersects correctly with the RODC allow/deny
+ * lists
+ */
+
+ werr = samba_rodc_confirm_user_is_allowed(user_info_dc->num_sids,
+ user_info_dc->sids,
+ krbtgt_skdc_entry,
+ client_skdc_entry);
+ if (!W_ERROR_IS_OK(werr)) {
+ talloc_free(mem_ctx);
+ if (W_ERROR_EQUAL(werr, WERR_DOMAIN_CONTROLLER_NOT_FOUND)) {
+ return KRB5KDC_ERR_POLICY;
+ } else {
+ return KRB5KDC_ERR_TGT_REVOKED;
}
}
}
- if (delegated_proxy_principal) {
- deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
- if (!deleg_blob) {
+ if (!is_untrusted) {
+ pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
+ if (!pac_blob) {
talloc_free(mem_ctx);
return ENOMEM;
}
- nt_status = samba_kdc_update_delegation_info_blob(mem_ctx,
- context, *pac,
- server->entry.principal,
- delegated_proxy_principal,
- deleg_blob);
+ nt_status = samba_kdc_update_pac_blob(mem_ctx, context,
+ krbtgt_skdc_entry->kdc_db_ctx->samdb,
+ *pac, pac_blob,
+ NULL, NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0, ("Building PAC failed: %s\n",
nt_errstr(nt_status)));
@@ -238,10 +318,10 @@
switch (types[i]) {
case PAC_TYPE_LOGON_INFO:
if (logon_info_idx != -1) {
- DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n",
- (int)types[i],
- (int)logon_info_idx,
- (int)i));
+ DEBUG(1, ("logon info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
+ types[i],
+ logon_info_idx,
+ i));
SAFE_FREE(types);
talloc_free(mem_ctx);
return EINVAL;
@@ -250,10 +330,10 @@
break;
case PAC_TYPE_CONSTRAINED_DELEGATION:
if (delegation_idx != -1) {
- DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n",
- (int)types[i],
- (int)logon_info_idx,
- (int)i));
+ DEBUG(1, ("constrained delegation type[%"PRIu32"] twice [%zd] and [%zu]: \n",
+ types[i],
+ delegation_idx,
+ i));
SAFE_FREE(types);
talloc_free(mem_ctx);
return EINVAL;
@@ -262,10 +342,10 @@
break;
case PAC_TYPE_LOGON_NAME:
if (logon_name_idx != -1) {
- DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n",
- (int)types[i],
- (int)logon_info_idx,
- (int)i));
+ DEBUG(1, ("logon name type[%"PRIu32"] twice [%zd] and [%zu]: \n",
+ types[i],
+ logon_name_idx,
+ i));
SAFE_FREE(types);
talloc_free(mem_ctx);
return EINVAL;
@@ -274,10 +354,10 @@
break;
case PAC_TYPE_UPN_DNS_INFO:
if (upn_dns_info_idx != -1) {
- DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n",
- (int)types[i],
- (int)logon_info_idx,
- (int)i));
+ DEBUG(1, ("upn dns info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
+ types[i],
+ upn_dns_info_idx,
+ i));
SAFE_FREE(types);
talloc_free(mem_ctx);
return EINVAL;
@@ -286,10 +366,10 @@
break;
case PAC_TYPE_SRV_CHECKSUM:
if (srv_checksum_idx != -1) {
- DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n",
- (int)types[i],
- (int)logon_info_idx,
- (int)i));
+ DEBUG(1, ("server checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
+ types[i],
+ srv_checksum_idx,
+ i));
SAFE_FREE(types);
talloc_free(mem_ctx);
return EINVAL;
@@ -298,16 +378,52 @@
break;
case PAC_TYPE_KDC_CHECKSUM:
if (kdc_checksum_idx != -1) {
- DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n",
- (int)types[i],
- (int)logon_info_idx,
- (int)i));
+ DEBUG(1, ("kdc checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
+ types[i],
+ kdc_checksum_idx,
+ i));
SAFE_FREE(types);
talloc_free(mem_ctx);
return EINVAL;
}
kdc_checksum_idx = i;
break;
+ case PAC_TYPE_TICKET_CHECKSUM:
+ if (tkt_checksum_idx != -1) {
+ DEBUG(1, ("ticket checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
+ types[i],
+ tkt_checksum_idx,
+ i));
+ SAFE_FREE(types);
+ talloc_free(mem_ctx);
+ return EINVAL;
+ }
+ tkt_checksum_idx = i;
+ break;
+ case PAC_TYPE_ATTRIBUTES_INFO:
+ if (attrs_info_idx != -1) {
+ DEBUG(1, ("attributes info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
+ types[i],
+ attrs_info_idx,
+ i));
+ SAFE_FREE(types);
+ talloc_free(mem_ctx);
+ return EINVAL;
+ }
+ attrs_info_idx = i;
+ break;
+ case PAC_TYPE_REQUESTER_SID:
+ if (requester_sid_idx != -1) {
+ DEBUG(1, ("requester sid type[%"PRIu32"] twice [%zd] and [%zu]: \n",
+ types[i],
+ requester_sid_idx,
+ i));
+ SAFE_FREE(types);
+ talloc_free(mem_ctx);
+ return EINVAL;
+ }
+ requester_sid_idx = i;
+ break;
default:
continue;
}
@@ -338,12 +454,42 @@
return EINVAL;
}
- /* Build an updated PAC */
+ /*
+ * The server account may be set not to want the PAC.
+ *
+ * While this is wasteful if the above cacluations were done
+ * and now thrown away, this is cleaner as we do any ticket
+ * signature checking etc always.
+ *
+ * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
+ * time (eg not accepting a ticket from the RODC) we do not
+ * need to re-generate anything anyway.
+ */
+ if (!samba_princ_needs_pac(server_skdc_entry)) {
+ ret = 0;
+ new_pac = NULL;
+ goto out;
+ }
+
+ if (!server_skdc_entry->is_krbtgt) {
+ /*
+ * The client may have requested no PAC when obtaining the
+ * TGT.
+ */
+ bool requested_pac;
+ ret = samba_client_requested_pac(context, pac, mem_ctx,
+ &requested_pac);
+ if (ret != 0 || !requested_pac) {
+ new_pac = NULL;
+ goto out;
+ }
+ }
+
+ /* Otherwise build an updated PAC */
ret = krb5_pac_init(context, &new_pac);
if (ret != 0) {
- SAFE_FREE(types);
- talloc_free(mem_ctx);
- return ret;
+ new_pac = NULL;
+ goto out;
}
for (i = 0;;) {
@@ -416,6 +562,11 @@
* we just add a place holder here.
*/
type_blob = data_blob_const(&zero_byte, 1);
+
+ if (requester_sid_idx == -1 && requester_sid_blob != NULL) {
+ /* inject REQUESTER_SID behind */
+ forced_next_type = PAC_TYPE_REQUESTER_SID;
+ }
break;
case PAC_TYPE_KDC_CHECKSUM:
/*
@@ -424,6 +575,18 @@
*/
type_blob = data_blob_const(&zero_byte, 1);
break;
+ case PAC_TYPE_ATTRIBUTES_INFO:
+ /* just copy... */
+ break;
+ case PAC_TYPE_REQUESTER_SID:
+ /*
+ * Replace in the RODC case, otherwise
+ * requester_sid_blob is NULL and we just copy.
+ */
+ if (requester_sid_blob != NULL) {
+ type_blob = *requester_sid_blob;
+ }
+ break;
default:
/* just copy... */
break;
@@ -461,6 +624,8 @@
}
}
+out:
+
SAFE_FREE(types);
/* We now replace the pac */
@@ -471,6 +636,131 @@
return ret;
}
+/* Resign (and reform, including possibly new groups) a PAC */
+
+static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
+ const krb5_principal client_principal,
+ const krb5_principal delegated_proxy_principal,
+ struct hdb_entry_ex *client,
+ struct hdb_entry_ex *server,
+ struct hdb_entry_ex *krbtgt,
+ krb5_pac *pac)
+{
+ struct samba_kdc_entry *krbtgt_skdc_entry =
+ talloc_get_type_abort(krbtgt->ctx,
+ struct samba_kdc_entry);
+ krb5_error_code ret;
+ krb5_cksumtype ctype = CKSUMTYPE_NONE;
+ struct hdb_entry_ex signing_krbtgt_hdb;
+
+ if (delegated_proxy_principal) {
+ uint16_t rodc_id;
+ unsigned int my_krbtgt_number;
+
+ /*
+ * We're using delegated_proxy_principal for the moment to
+ * indicate cases where the ticket was encrypted with the server
+ * key, and not a krbtgt key. This cannot be trusted, so we need
+ * to find a krbtgt key that signs the PAC in order to trust the
+ * ticket.
+ *
+ * The krbtgt passed in to this function refers to the krbtgt
+ * used to decrypt the ticket of the server requesting
+ * S4U2Proxy.
+ *
+ * When we implement service ticket renewal, we need to check
+ * the PAC, and this will need to be updated.
+ */
+ ret = krb5_pac_get_kdc_checksum_info(context,
+ *pac,
+ &ctype,
+ &rodc_id);
+ if (ret != 0) {
+ DEBUG(1, ("Failed to get PAC checksum info\n"));
+ return ret;
+ }
+
+ /*
+ * We need to check the KDC and ticket signatures, fetching the
+ * correct key based on the enctype.
+ */
+
+ my_krbtgt_number = krbtgt_skdc_entry->kdc_db_ctx->my_krbtgt_number;
+
+ if (my_krbtgt_number != 0) {
+ /*
+ * If we are an RODC, and we are not the KDC that signed
+ * the evidence ticket, then we need to proxy the
+ * request.
+ */
+ if (rodc_id != my_krbtgt_number) {
+ return HDB_ERR_NOT_FOUND_HERE;
+ }
+ } else {
+ /*
+ * If we are a DC, the ticket may have been signed by a
+ * different KDC than the one that issued the header
+ * ticket.
+ */
+ if (rodc_id != krbtgt->entry.kvno >> 16) {
+ struct sdb_entry_ex signing_krbtgt_sdb;
+
+ /*
+ * If we didn't sign the ticket, then return an
+ * error.
+ */
+ if (rodc_id != 0) {
+ return KRB5KRB_AP_ERR_MODIFIED;
+ }
+
+ /*
+ * Fetch our key from the database. To support
+ * key rollover, we're going to need to try
+ * multiple keys by trial and error. For now,
+ * krbtgt keys aren't assumed to change.
+ */
+ ret = samba_kdc_fetch(context,
+ krbtgt_skdc_entry->kdc_db_ctx,
+ krbtgt->entry.principal,
+ SDB_F_GET_KRBTGT | SDB_F_CANON,
+ 0,
+ &signing_krbtgt_sdb);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = sdb_entry_ex_to_hdb_entry_ex(context,
+ &signing_krbtgt_sdb,
+ &signing_krbtgt_hdb);
+ sdb_free_entry(&signing_krbtgt_sdb);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /*
+ * Replace the krbtgt entry with our own entry
+ * for further processing.
+ */
+ krbtgt = &signing_krbtgt_hdb;
+ }
+ }
+ }
+
+ ret = samba_wdc_reget_pac2(context,
+ delegated_proxy_principal,
+ client,
+ server,
+ krbtgt,
+ pac,
+ ctype);
+
+ if (krbtgt == &signing_krbtgt_hdb) {
+ hdb_free_entry(context, &signing_krbtgt_hdb);
+ }
+
+ return ret;
+}
+
static char *get_netbios_name(TALLOC_CTX *mem_ctx, HostAddresses *addrs)
{
char *nb_name = NULL;
diff -Nru samba-4.13.3+dfsg/source4/kdc/wscript_build samba-4.13.14+dfsg/source4/kdc/wscript_build
--- samba-4.13.3+dfsg/source4/kdc/wscript_build 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/kdc/wscript_build 2021-10-29 06:17:36.000000000 +0000
@@ -29,6 +29,7 @@
if bld.CONFIG_GET('SAMBA_USES_MITKDC'):
bld.SAMBA_MODULE('service_kdc',
source='kdc-service-mit.c',
+ cflags_end='-Wno-strict-prototypes',
subsystem='service',
init_function='server_service_mitkdc_init',
deps='''
diff -Nru samba-4.13.3+dfsg/source4/libcli/smb_composite/sesssetup.c samba-4.13.14+dfsg/source4/libcli/smb_composite/sesssetup.c
--- samba-4.13.3+dfsg/source4/libcli/smb_composite/sesssetup.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/libcli/smb_composite/sesssetup.c 2021-11-08 11:29:14.000000000 +0000
@@ -620,6 +620,8 @@
struct composite_context *c;
struct sesssetup_state *state;
NTSTATUS status;
+ enum credentials_use_kerberos krb5_state =
+ cli_credentials_get_kerberos_state(io->in.credentials);
c = composite_create(session, session->transport->ev);
if (c == NULL) return NULL;
@@ -635,6 +637,10 @@
/* no session setup at all in earliest protocol varients */
if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) {
+ if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ composite_error(c, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
+ return c;
+ }
ZERO_STRUCT(io->out);
composite_done(c);
return c;
@@ -642,9 +648,17 @@
/* see what session setup interface we will use */
if (session->transport->negotiate.protocol < PROTOCOL_NT1) {
+ if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ composite_error(c, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
+ return c;
+ }
status = session_setup_old(c, session, io, &state->req);
} else if (!session->transport->options.use_spnego ||
!(io->in.capabilities & CAP_EXTENDED_SECURITY)) {
+ if (krb5_state == CRED_MUST_USE_KERBEROS) {
+ composite_error(c, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
+ return c;
+ }
status = session_setup_nt1(c, session, io, &state->req);
} else {
struct tevent_req *subreq = NULL;
diff -Nru samba-4.13.3+dfsg/source4/librpc/ndr/py_security.c samba-4.13.14+dfsg/source4/librpc/ndr/py_security.c
--- samba-4.13.3+dfsg/source4/librpc/ndr/py_security.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/librpc/ndr/py_security.c 2021-10-29 06:17:36.000000000 +0000
@@ -309,9 +309,46 @@
{0}
};
+static PyObject *py_descriptor_richcmp(
+ PyObject *py_self, PyObject *py_other, int op)
+{
+ struct security_descriptor *self = pytalloc_get_ptr(py_self);
+ struct security_descriptor *other = pytalloc_get_ptr(py_other);
+ bool eq;
+
+ if (other == NULL) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+
+ eq = security_descriptor_equal(self, other);
+
+ switch(op) {
+ case Py_EQ:
+ if (eq) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+ break;
+ case Py_NE:
+ if (eq) {
+ Py_RETURN_FALSE;
+ } else {
+ Py_RETURN_TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ Py_RETURN_NOTIMPLEMENTED;
+}
+
static void py_descriptor_patch(PyTypeObject *type)
{
type->tp_new = py_descriptor_new;
+ type->tp_richcompare = py_descriptor_richcmp;
PyType_AddMethods(type, py_descriptor_extra_methods);
}
@@ -410,7 +447,7 @@
{ "has_sid", (PyCFunction)py_token_has_sid, METH_VARARGS,
NULL },
{ "is_anonymous", (PyCFunction)py_token_is_anonymous, METH_NOARGS,
- "S.is_anonymus() -> bool\n"
+ "S.is_anonymous() -> bool\n"
"Check whether this is an anonymous token." },
{ "is_system", (PyCFunction)py_token_is_system, METH_NOARGS,
NULL },
diff -Nru samba-4.13.3+dfsg/source4/librpc/rpc/dcerpc.c samba-4.13.14+dfsg/source4/librpc/rpc/dcerpc.c
--- samba-4.13.3+dfsg/source4/librpc/rpc/dcerpc.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/librpc/rpc/dcerpc.c 2021-11-08 11:29:14.000000000 +0000
@@ -26,6 +26,8 @@
#include "lib/events/events.h"
#include "librpc/rpc/dcerpc.h"
#include "librpc/rpc/dcerpc_proto.h"
+#include "librpc/rpc/dcerpc_util.h"
+#include "librpc/rpc/dcerpc_pkt_auth.h"
#include "librpc/gen_ndr/ndr_misc.h"
#include "librpc/gen_ndr/ndr_dcerpc.h"
#include "auth/gensec/gensec.h"
@@ -724,6 +726,7 @@
status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
c->security_state.generic_state,
+ true, /* check_pkt_auth_fields */
mem_ctx,
ptype,
required_flags,
diff -Nru samba-4.13.3+dfsg/source4/librpc/rpc/dcerpc_roh_channel_out.c samba-4.13.14+dfsg/source4/librpc/rpc/dcerpc_roh_channel_out.c
--- samba-4.13.3+dfsg/source4/librpc/rpc/dcerpc_roh_channel_out.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/librpc/rpc/dcerpc_roh_channel_out.c 2021-11-08 11:29:14.000000000 +0000
@@ -37,6 +37,7 @@
#include "librpc/rpc/dcerpc.h"
#include "librpc/rpc/dcerpc_roh.h"
#include "librpc/rpc/dcerpc_proto.h"
+#include "librpc/rpc/dcerpc_util.h"
#include "libcli/http/http.h"
struct roh_request_state {
diff -Nru samba-4.13.3+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex.b64.txt samba-4.13.14+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex.b64.txt
--- samba-4.13.3+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex.b64.txt 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex.b64.txt 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1 @@
+BgAAAAAAAAABAAAA0AEAAGgAAAAAAAAACgAAABwAAAA4AgAAAAAAAAwAAACoAAAAWAIAAAAAAAAGAAAAFAAAAAADAAAAAAAABwAAABAAAAAYAwAAAAAAABAAAAAQAAAAKAMAAAAAAAABEAgAzMzMzMABAAAAAAAAAAACAAAAAAAAAAAA/////////3//////////f7pMcCzXv9cBugzaVqDA1wG6zMkh2ODXARIAEgAEAAIAAAAAAAgAAgAAAAAADAACAAAAAAAQAAIAAAAAABQAAgAAAAAAGAACAAAAAACOBAAAAQIAAAEAAAAcAAIAIAAAAAAAAAAAAAAAAAAAAAAAAAAOABAAIAACABYAGAAkAAIAKAACAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAALAACAAAAAAAAAAAAAAAAAAkAAAAAAAAACQAAAHQAcwB0AHQAawB0AHUAcwByAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAECAAAHAAAACAAAAAAAAAAHAAAATABPAEMAQQBMAEQAQwAAAAwAAAAAAAAACwAAAFMAQQBNAEIAQQBEAE8ATQBBAEkATgAAAAQAAAABBAAAAAAABRUAAAC2fvX0wDGiOufKt1QBAAAAMAACAAcAAAABAAAAAQEAAAAAABIBAAAAAAAAAIC3ISzXv9cBEgB0AHMAdAB0AGsAdAB1AHMAcgAAAAAANgAYACIAUAADAAAAEgB4ABwAigAAAAAAdABzAHQAdABrAHQAdQBzAHIAQABzAGEAbQBiAGEALgBlAHgAYQBtAHAAbABlAC4AYwBvAG0AAABTAEEATQBCAEEALgBFAFgAQQBNAFAATABFAC4AQwBPAE0AAAAAAAAAdABzAHQAdABrAHQAdQBzAHIAAQUAAAAAAAUVAAAAtn719MAxojrnyrdUjgQAAAAAdv///ys5aox2KdqNY8CVVxkQbs4AAAAAEAAAAFrUeP0b8Pbct0VlVhAAAAB4SC+IGKoLP+0030o=
diff -Nru samba-4.13.3+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.b64.txt samba-4.13.14+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.b64.txt
--- samba-4.13.3+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.b64.txt 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.b64.txt 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1 @@
+BgAAAAAAAAABAAAA0AEAAGgAAAAAAAAACgAAABwAAAA4AgAAAAAAAAwAAACoAAAAWAIAAAAAAAAGAAAAFAAAAAADAAAAAAAABwAAABAAAAAYAwAAAAAAABAAAAAQAAAAKAMAAAAAAAABEAgAzMzMzMABAAAAAAAAAAACAAAAAAAAAAAA/////////3//////////f7pMcCzXv9cBugzaVqDA1wG6zMkh2ODXARIAEgAEAAIAAAAAAAgAAgAAAAAADAACAAAAAAAQAAIAAAAAABQAAgAAAAAAGAACAAAAAACOBAAAAQIAAAEAAAAcAAIAIAAAAAAAAAAAAAAAAAAAAAAAAAAOABAAIAACABYAGAAkAAIAKAACAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAALAACAAAAAAAAAAAAAAAAAAkAAAAAAAAACQAAAHQAcwB0AHQAawB0AHUAcwByAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAECAAAHAAAACAAAAAAAAAAHAAAATABPAEMAQQBMAEQAQwAAAAwAAAAAAAAACwAAAFMAQQBNAEIAQQBEAE8ATQBBAEkATgAAAAQAAAABBAAAAAAABRUAAAC2fvX0wDGiOufKt1QBAAAAMAACAAcAAAABAAAAAQEAAAAAABIBAAAAAAAAAIC3ISzXv9cBEgB0AHMAdAB0AGsAdAB1AHMAcgAAAAAANgAYACIAUAABAAAAEgB4ABwAigAAAAAAdABzAHQAdABrAHQAdQBzAHIAQABzAGEAbQBiAGEALgBlAHgAYQBtAHAAbABlAC4AYwBvAG0AAABTAEEATQBCAEEALgBFAFgAQQBNAFAATABFAC4AQwBPAE0AAAAAAAAAdABzAHQAdABrAHQAdQBzAHIAAQUAAAAAAAUVAAAAtn719MAxojrnyrdUjgQAAAAAdv///ys5aox2KdqNY8CVVxkQbs4AAAAAEAAAAFrUeP0b8Pbct0VlVhAAAAB4SC+IGKoLP+0030o=
diff -Nru samba-4.13.3+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.txt samba-4.13.14+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.txt
--- samba-4.13.3+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.txt 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex_not_supported.txt 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,213 @@
+pull returned Success
+ PAC_DATA: struct PAC_DATA
+ num_buffers : 0x00000006 (6)
+ version : 0x00000000 (0)
+ buffers: ARRAY(6)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_LOGON_INFO (1)
+ _ndr_size : 0x000001d0 (464)
+ info : *
+ info : union PAC_INFO(case 1)
+ logon_info: struct PAC_LOGON_INFO_CTR
+ info : *
+ info: struct PAC_LOGON_INFO
+ info3: struct netr_SamInfo3
+ base: struct netr_SamBaseInfo
+ logon_time : NTTIME(0)
+ logoff_time : Thu Sep 14 02:48:05 AM 30828 UTC
+ kickoff_time : Thu Sep 14 02:48:05 AM 30828 UTC
+ last_password_change : Wed Oct 13 02:08:12 AM 2021 UTC
+ allow_password_change : Thu Oct 14 02:08:12 AM 2021 UTC
+ force_password_change : Wed Nov 24 02:08:12 AM 2021 UTC
+ account_name: struct lsa_String
+ length : 0x0012 (18)
+ size : 0x0012 (18)
+ string : *
+ string : 'tsttktusr'
+ full_name: struct lsa_String
+ length : 0x0000 (0)
+ size : 0x0000 (0)
+ string : *
+ string : ''
+ logon_script: struct lsa_String
+ length : 0x0000 (0)
+ size : 0x0000 (0)
+ string : *
+ string : ''
+ profile_path: struct lsa_String
+ length : 0x0000 (0)
+ size : 0x0000 (0)
+ string : *
+ string : ''
+ home_directory: struct lsa_String
+ length : 0x0000 (0)
+ size : 0x0000 (0)
+ string : *
+ string : ''
+ home_drive: struct lsa_String
+ length : 0x0000 (0)
+ size : 0x0000 (0)
+ string : *
+ string : ''
+ logon_count : 0x0000 (0)
+ bad_password_count : 0x0000 (0)
+ rid : 0x0000048e (1166)
+ primary_gid : 0x00000201 (513)
+ groups: struct samr_RidWithAttributeArray
+ count : 0x00000001 (1)
+ rids : *
+ rids: ARRAY(1)
+ rids: struct samr_RidWithAttribute
+ rid : 0x00000201 (513)
+ attributes : 0x00000007 (7)
+ 1: SE_GROUP_MANDATORY
+ 1: SE_GROUP_ENABLED_BY_DEFAULT
+ 1: SE_GROUP_ENABLED
+ 0: SE_GROUP_OWNER
+ 0: SE_GROUP_USE_FOR_DENY_ONLY
+ 0: SE_GROUP_INTEGRITY
+ 0: SE_GROUP_INTEGRITY_ENABLED
+ 0: SE_GROUP_RESOURCE
+ 0x00: SE_GROUP_LOGON_ID (0)
+ user_flags : 0x00000020 (32)
+ 0: NETLOGON_GUEST
+ 0: NETLOGON_NOENCRYPTION
+ 0: NETLOGON_CACHED_ACCOUNT
+ 0: NETLOGON_USED_LM_PASSWORD
+ 1: NETLOGON_EXTRA_SIDS
+ 0: NETLOGON_SUBAUTH_SESSION_KEY
+ 0: NETLOGON_SERVER_TRUST_ACCOUNT
+ 0: NETLOGON_NTLMV2_ENABLED
+ 0: NETLOGON_RESOURCE_GROUPS
+ 0: NETLOGON_PROFILE_PATH_RETURNED
+ 0: NETLOGON_GRACE_LOGON
+ key: struct netr_UserSessionKey
+ key: ARRAY(16):
+ logon_server: struct lsa_StringLarge
+ length : 0x000e (14)
+ size : 0x0010 (16)
+ string : *
+ string : 'LOCALDC'
+ logon_domain: struct lsa_StringLarge
+ length : 0x0016 (22)
+ size : 0x0018 (24)
+ string : *
+ string : 'SAMBADOMAIN'
+ domain_sid : *
+ domain_sid : S-1-5-21-4109729462-983708096-1421331175
+ LMSessKey: struct netr_LMSessionKey
+ key: ARRAY(8):
+ acct_flags : 0x00000010 (16)
+ 0: ACB_DISABLED
+ 0: ACB_HOMDIRREQ
+ 0: ACB_PWNOTREQ
+ 0: ACB_TEMPDUP
+ 1: ACB_NORMAL
+ 0: ACB_MNS
+ 0: ACB_DOMTRUST
+ 0: ACB_WSTRUST
+ 0: ACB_SVRTRUST
+ 0: ACB_PWNOEXP
+ 0: ACB_AUTOLOCK
+ 0: ACB_ENC_TXT_PWD_ALLOWED
+ 0: ACB_SMARTCARD_REQUIRED
+ 0: ACB_TRUSTED_FOR_DELEGATION
+ 0: ACB_NOT_DELEGATED
+ 0: ACB_USE_DES_KEY_ONLY
+ 0: ACB_DONT_REQUIRE_PREAUTH
+ 0: ACB_PW_EXPIRED
+ 0: ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
+ 0: ACB_NO_AUTH_DATA_REQD
+ 0: ACB_PARTIAL_SECRETS_ACCOUNT
+ 0: ACB_USE_AES_KEYS
+ sub_auth_status : 0x00000000 (0)
+ last_successful_logon : NTTIME(0)
+ last_failed_logon : NTTIME(0)
+ failed_logon_count : 0x00000000 (0)
+ reserved : 0x00000000 (0)
+ sidcount : 0x00000001 (1)
+ sids : *
+ sids: ARRAY(1)
+ sids: struct netr_SidAttr
+ sid : *
+ sid : S-1-18-1
+ attributes : 0x00000007 (7)
+ 1: SE_GROUP_MANDATORY
+ 1: SE_GROUP_ENABLED_BY_DEFAULT
+ 1: SE_GROUP_ENABLED
+ 0: SE_GROUP_OWNER
+ 0: SE_GROUP_USE_FOR_DENY_ONLY
+ 0: SE_GROUP_INTEGRITY
+ 0: SE_GROUP_INTEGRITY_ENABLED
+ 0: SE_GROUP_RESOURCE
+ 0x00: SE_GROUP_LOGON_ID (0)
+ resource_groups: struct PAC_DOMAIN_GROUP_MEMBERSHIP
+ domain_sid : NULL
+ groups: struct samr_RidWithAttributeArray
+ count : 0x00000000 (0)
+ rids : NULL
+ _pad : 0x00000000 (0)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_LOGON_NAME (10)
+ _ndr_size : 0x0000001c (28)
+ info : *
+ info : union PAC_INFO(case 10)
+ logon_name: struct PAC_LOGON_NAME
+ logon_time : Wed Oct 13 02:08:11 AM 2021 UTC
+ size : 0x0012 (18)
+ account_name : 'tsttktusr'
+ _pad : 0x00000000 (0)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_UPN_DNS_INFO (12)
+ _ndr_size : 0x000000a8 (168)
+ info : *
+ info : union PAC_INFO(case 12)
+ upn_dns_info: struct PAC_UPN_DNS_INFO
+ upn_name_size : 0x0036 (54)
+ upn_name : *
+ upn_name : 'tsttktusr@samba.example.com'
+ dns_domain_name_size : 0x0022 (34)
+ dns_domain_name : *
+ dns_domain_name : 'SAMBA.EXAMPLE.COM'
+ flags : 0x00000001 (1)
+ 1: PAC_UPN_DNS_FLAG_CONSTRUCTED
+ 0: PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID
+ ex : union PAC_UPN_DNS_INFO_EX(case 0)
+ _pad : 0x00000000 (0)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_SRV_CHECKSUM (6)
+ _ndr_size : 0x00000014 (20)
+ info : *
+ info : union PAC_INFO(case 6)
+ srv_cksum: struct PAC_SIGNATURE_DATA
+ type : 0xffffff76 (4294967158)
+ signature : DATA_BLOB length=16
+[0000] 2B 39 6A 8C 76 29 DA 8D 63 C0 95 57 19 10 6E CE +9j.v).. c..W..n.
+ _pad : 0x00000000 (0)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_KDC_CHECKSUM (7)
+ _ndr_size : 0x00000010 (16)
+ info : *
+ info : union PAC_INFO(case 7)
+ kdc_cksum: struct PAC_SIGNATURE_DATA
+ type : 0x00000010 (16)
+ signature : DATA_BLOB length=12
+[0000] 5A D4 78 FD 1B F0 F6 DC B7 45 65 56 Z.x..... .EeV
+ _pad : 0x00000000 (0)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_TICKET_CHECKSUM (16)
+ _ndr_size : 0x00000010 (16)
+ info : *
+ info : union PAC_INFO(case 16)
+ ticket_checksum: struct PAC_SIGNATURE_DATA
+ type : 0x00000010 (16)
+ signature : DATA_BLOB length=12
+[0000] 78 48 2F 88 18 AA 0B 3F ED 34 DF 4A xH/....? .4.J
+ _pad : 0x00000000 (0)
+push returned Success
+pull returned Success
+WARNING! orig bytes:824 validated pushed bytes:768
+WARNING! orig pulled bytes:824 validated pulled bytes:768
+WARNING! orig and validated differ at byte 0x2C (44)
+WARNING! orig byte[0x2C] = 0xA8 validated byte[0x2C] = 0x70
+dump OK
diff -Nru samba-4.13.3+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex.txt samba-4.13.14+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex.txt
--- samba-4.13.3+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex.txt 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/source4/librpc/tests/krb5pac_upn_dns_info_ex.txt 2021-11-08 11:29:14.000000000 +0000
@@ -0,0 +1,220 @@
+pull returned Success
+ PAC_DATA: struct PAC_DATA
+ num_buffers : 0x00000006 (6)
+ version : 0x00000000 (0)
+ buffers: ARRAY(6)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_LOGON_INFO (1)
+ _ndr_size : 0x000001d0 (464)
+ info : *
+ info : union PAC_INFO(case 1)
+ logon_info: struct PAC_LOGON_INFO_CTR
+ info : *
+ info: struct PAC_LOGON_INFO
+ info3: struct netr_SamInfo3
+ base: struct netr_SamBaseInfo
+ logon_time : NTTIME(0)
+ logoff_time : Thu Sep 14 02:48:05 AM 30828 UTC
+ kickoff_time : Thu Sep 14 02:48:05 AM 30828 UTC
+ last_password_change : Wed Oct 13 02:08:12 AM 2021 UTC
+ allow_password_change : Thu Oct 14 02:08:12 AM 2021 UTC
+ force_password_change : Wed Nov 24 02:08:12 AM 2021 UTC
+ account_name: struct lsa_String
+ length : 0x0012 (18)
+ size : 0x0012 (18)
+ string : *
+ string : 'tsttktusr'
+ full_name: struct lsa_String
+ length : 0x0000 (0)
+ size : 0x0000 (0)
+ string : *
+ string : ''
+ logon_script: struct lsa_String
+ length : 0x0000 (0)
+ size : 0x0000 (0)
+ string : *
+ string : ''
+ profile_path: struct lsa_String
+ length : 0x0000 (0)
+ size : 0x0000 (0)
+ string : *
+ string : ''
+ home_directory: struct lsa_String
+ length : 0x0000 (0)
+ size : 0x0000 (0)
+ string : *
+ string : ''
+ home_drive: struct lsa_String
+ length : 0x0000 (0)
+ size : 0x0000 (0)
+ string : *
+ string : ''
+ logon_count : 0x0000 (0)
+ bad_password_count : 0x0000 (0)
+ rid : 0x0000048e (1166)
+ primary_gid : 0x00000201 (513)
+ groups: struct samr_RidWithAttributeArray
+ count : 0x00000001 (1)
+ rids : *
+ rids: ARRAY(1)
+ rids: struct samr_RidWithAttribute
+ rid : 0x00000201 (513)
+ attributes : 0x00000007 (7)
+ 1: SE_GROUP_MANDATORY
+ 1: SE_GROUP_ENABLED_BY_DEFAULT
+ 1: SE_GROUP_ENABLED
+ 0: SE_GROUP_OWNER
+ 0: SE_GROUP_USE_FOR_DENY_ONLY
+ 0: SE_GROUP_INTEGRITY
+ 0: SE_GROUP_INTEGRITY_ENABLED
+ 0: SE_GROUP_RESOURCE
+ 0x00: SE_GROUP_LOGON_ID (0)
+ user_flags : 0x00000020 (32)
+ 0: NETLOGON_GUEST
+ 0: NETLOGON_NOENCRYPTION
+ 0: NETLOGON_CACHED_ACCOUNT
+ 0: NETLOGON_USED_LM_PASSWORD
+ 1: NETLOGON_EXTRA_SIDS
+ 0: NETLOGON_SUBAUTH_SESSION_KEY
+ 0: NETLOGON_SERVER_TRUST_ACCOUNT
+ 0: NETLOGON_NTLMV2_ENABLED
+ 0: NETLOGON_RESOURCE_GROUPS
+ 0: NETLOGON_PROFILE_PATH_RETURNED
+ 0: NETLOGON_GRACE_LOGON
+ key: struct netr_UserSessionKey
+ key: ARRAY(16):
+ logon_server: struct lsa_StringLarge
+ length : 0x000e (14)
+ size : 0x0010 (16)
+ string : *
+ string : 'LOCALDC'
+ logon_domain: struct lsa_StringLarge
+ length : 0x0016 (22)
+ size : 0x0018 (24)
+ string : *
+ string : 'SAMBADOMAIN'
+ domain_sid : *
+ domain_sid : S-1-5-21-4109729462-983708096-1421331175
+ LMSessKey: struct netr_LMSessionKey
+ key: ARRAY(8):
+ acct_flags : 0x00000010 (16)
+ 0: ACB_DISABLED
+ 0: ACB_HOMDIRREQ
+ 0: ACB_PWNOTREQ
+ 0: ACB_TEMPDUP
+ 1: ACB_NORMAL
+ 0: ACB_MNS
+ 0: ACB_DOMTRUST
+ 0: ACB_WSTRUST
+ 0: ACB_SVRTRUST
+ 0: ACB_PWNOEXP
+ 0: ACB_AUTOLOCK
+ 0: ACB_ENC_TXT_PWD_ALLOWED
+ 0: ACB_SMARTCARD_REQUIRED
+ 0: ACB_TRUSTED_FOR_DELEGATION
+ 0: ACB_NOT_DELEGATED
+ 0: ACB_USE_DES_KEY_ONLY
+ 0: ACB_DONT_REQUIRE_PREAUTH
+ 0: ACB_PW_EXPIRED
+ 0: ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
+ 0: ACB_NO_AUTH_DATA_REQD
+ 0: ACB_PARTIAL_SECRETS_ACCOUNT
+ 0: ACB_USE_AES_KEYS
+ sub_auth_status : 0x00000000 (0)
+ last_successful_logon : NTTIME(0)
+ last_failed_logon : NTTIME(0)
+ failed_logon_count : 0x00000000 (0)
+ reserved : 0x00000000 (0)
+ sidcount : 0x00000001 (1)
+ sids : *
+ sids: ARRAY(1)
+ sids: struct netr_SidAttr
+ sid : *
+ sid : S-1-18-1
+ attributes : 0x00000007 (7)
+ 1: SE_GROUP_MANDATORY
+ 1: SE_GROUP_ENABLED_BY_DEFAULT
+ 1: SE_GROUP_ENABLED
+ 0: SE_GROUP_OWNER
+ 0: SE_GROUP_USE_FOR_DENY_ONLY
+ 0: SE_GROUP_INTEGRITY
+ 0: SE_GROUP_INTEGRITY_ENABLED
+ 0: SE_GROUP_RESOURCE
+ 0x00: SE_GROUP_LOGON_ID (0)
+ resource_groups: struct PAC_DOMAIN_GROUP_MEMBERSHIP
+ domain_sid : NULL
+ groups: struct samr_RidWithAttributeArray
+ count : 0x00000000 (0)
+ rids : NULL
+ _pad : 0x00000000 (0)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_LOGON_NAME (10)
+ _ndr_size : 0x0000001c (28)
+ info : *
+ info : union PAC_INFO(case 10)
+ logon_name: struct PAC_LOGON_NAME
+ logon_time : Wed Oct 13 02:08:11 AM 2021 UTC
+ size : 0x0012 (18)
+ account_name : 'tsttktusr'
+ _pad : 0x00000000 (0)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_UPN_DNS_INFO (12)
+ _ndr_size : 0x000000a8 (168)
+ info : *
+ info : union PAC_INFO(case 12)
+ upn_dns_info: struct PAC_UPN_DNS_INFO
+ upn_name_size : 0x0036 (54)
+ upn_name : *
+ upn_name : 'tsttktusr@samba.example.com'
+ dns_domain_name_size : 0x0022 (34)
+ dns_domain_name : *
+ dns_domain_name : 'SAMBA.EXAMPLE.COM'
+ flags : 0x00000003 (3)
+ 1: PAC_UPN_DNS_FLAG_CONSTRUCTED
+ 1: PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID
+ ex : union PAC_UPN_DNS_INFO_EX(case 2)
+ sam_name_and_sid: struct PAC_UPN_DNS_INFO_SAM_NAME_AND_SID
+ samaccountname_size : 0x0012 (18)
+ samaccountname : *
+ samaccountname : 'tsttktusr'
+ objectsid_size : 0x001c (28)
+ objectsid : *
+ objectsid : S-1-5-21-4109729462-983708096-1421331175-1166
+ _pad : 0x00000000 (0)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_SRV_CHECKSUM (6)
+ _ndr_size : 0x00000014 (20)
+ info : *
+ info : union PAC_INFO(case 6)
+ srv_cksum: struct PAC_SIGNATURE_DATA
+ type : 0xffffff76 (4294967158)
+ signature : DATA_BLOB length=16
+[0000] 2B 39 6A 8C 76 29 DA 8D 63 C0 95 57 19 10 6E CE +9j.v).. c..W..n.
+ _pad : 0x00000000 (0)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_KDC_CHECKSUM (7)
+ _ndr_size : 0x00000010 (16)
+ info : *
+ info : union PAC_INFO(case 7)
+ kdc_cksum: struct PAC_SIGNATURE_DATA
+ type : 0x00000010 (16)
+ signature : DATA_BLOB length=12
+[0000] 5A D4 78 FD 1B F0 F6 DC B7 45 65 56 Z.x..... .EeV
+ _pad : 0x00000000 (0)
+ buffers: struct PAC_BUFFER
+ type : PAC_TYPE_TICKET_CHECKSUM (16)
+ _ndr_size : 0x00000010 (16)
+ info : *
+ info : union PAC_INFO(case 16)
+ ticket_checksum: struct PAC_SIGNATURE_DATA
+ type : 0x00000010 (16)
+ signature : DATA_BLOB length=12
+[0000] 78 48 2F 88 18 AA 0B 3F ED 34 DF 4A xH/....? .4.J
+ _pad : 0x00000000 (0)
+push returned Success
+pull returned Success
+WARNING! orig bytes:824 validated pushed bytes:832
+WARNING! orig pulled bytes:824 validated pulled bytes:832
+WARNING! orig and validated differ at byte 0x2C (44)
+WARNING! orig byte[0x2C] = 0xA8 validated byte[0x2C] = 0xB0
+dump OK
diff -Nru samba-4.13.3+dfsg/source4/librpc/wscript_build samba-4.13.14+dfsg/source4/librpc/wscript_build
--- samba-4.13.3+dfsg/source4/librpc/wscript_build 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/librpc/wscript_build 2021-11-08 11:29:14.000000000 +0000
@@ -157,7 +157,26 @@
rpc/dcerpc_roh_channel_in.c rpc/dcerpc_roh_channel_out.c rpc/dcerpc_roh.c
rpc/dcerpc_connect.c rpc/dcerpc_secondary.c''',
pc_files='dcerpc.pc',
- deps='samba_socket LIBCLI_RESOLVE LIBCLI_SMB LIBCLI_SMB2 ndr NDR_DCERPC RPC_NDR_EPMAPPER NDR_SCHANNEL RPC_NDR_NETLOGON RPC_NDR_MGMT gensec LIBCLI_AUTH smbclient-raw LP_RESOLVE tevent-util dcerpc-binding param_options http',
+ deps='''
+ samba_socket
+ LIBCLI_RESOLVE
+ LIBCLI_SMB
+ LIBCLI_SMB2
+ ndr
+ NDR_DCERPC
+ RPC_NDR_EPMAPPER
+ NDR_SCHANNEL
+ RPC_NDR_NETLOGON
+ RPC_NDR_MGMT
+ gensec
+ LIBCLI_AUTH
+ smbclient-raw
+ LP_RESOLVE
+ tevent-util
+ dcerpc-binding
+ dcerpc-pkt-auth
+ param_options
+ http''',
autoproto='rpc/dcerpc_proto.h',
public_deps='samba-credentials tevent talloc',
public_headers='''rpc/dcerpc.h''',
@@ -229,6 +248,13 @@
cflags_end=gen_cflags
)
+bld.SAMBA_PYTHON('python_krb5ccache',
+ source='../../librpc/gen_ndr/py_krb5ccache.c',
+ deps='NDR_KRB5CCACHE %s %s' % (pytalloc_util, pyrpc_util),
+ realname='samba/dcerpc/krb5ccache.so',
+ cflags_end=gen_cflags
+ )
+
bld.SAMBA_PYTHON('python_netlogon',
source='../../librpc/gen_ndr/py_netlogon.c',
deps='RPC_NDR_NETLOGON %s %s' % (pytalloc_util, pyrpc_util),
diff -Nru samba-4.13.3+dfsg/source4/ntvfs/posix/python/pyposix_eadb.c samba-4.13.14+dfsg/source4/ntvfs/posix/python/pyposix_eadb.c
--- samba-4.13.3+dfsg/source4/ntvfs/posix/python/pyposix_eadb.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/ntvfs/posix/python/pyposix_eadb.c 2021-09-22 06:59:39.000000000 +0000
@@ -32,7 +32,7 @@
static PyObject *py_is_xattr_supported(PyObject *self,
PyObject *Py_UNUSED(ignored))
{
- return Py_True;
+ Py_RETURN_TRUE;
}
static PyObject *py_wrap_setxattr(PyObject *self, PyObject *args)
diff -Nru samba-4.13.3+dfsg/source4/ntvfs/posix/python/pyxattr_native.c samba-4.13.14+dfsg/source4/ntvfs/posix/python/pyxattr_native.c
--- samba-4.13.3+dfsg/source4/ntvfs/posix/python/pyxattr_native.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/ntvfs/posix/python/pyxattr_native.c 2021-09-22 06:59:39.000000000 +0000
@@ -29,9 +29,9 @@
PyObject *Py_UNUSED(ignored))
{
#if !defined(HAVE_XATTR_SUPPORT)
- return Py_False;
+ Py_RETURN_FALSE;
#else
- return Py_True;
+ Py_RETURN_TRUE;
#endif
}
diff -Nru samba-4.13.3+dfsg/source4/ntvfs/posix/python/pyxattr_tdb.c samba-4.13.14+dfsg/source4/ntvfs/posix/python/pyxattr_tdb.c
--- samba-4.13.3+dfsg/source4/ntvfs/posix/python/pyxattr_tdb.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/ntvfs/posix/python/pyxattr_tdb.c 2021-09-22 06:59:39.000000000 +0000
@@ -36,7 +36,7 @@
static PyObject *py_is_xattr_supported(PyObject *self,
PyObject *Py_UNUSED(ignored))
{
- return Py_True;
+ Py_RETURN_TRUE;
}
static PyObject *py_wrap_setxattr(PyObject *self, PyObject *args)
diff -Nru samba-4.13.3+dfsg/source4/rpc_server/common/server_info.c samba-4.13.14+dfsg/source4/rpc_server/common/server_info.c
--- samba-4.13.3+dfsg/source4/rpc_server/common/server_info.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/rpc_server/common/server_info.c 2021-11-08 11:29:14.000000000 +0000
@@ -28,6 +28,8 @@
#include "param/param.h"
#include "rpc_server/common/common.h"
#include "libds/common/roles.h"
+#include "auth/auth_util.h"
+#include "lib/tsocket/tsocket.h"
/*
Here are common server info functions used by some dcerpc server interfaces
@@ -188,30 +190,117 @@
return true;
}
-/*
- * Open an ldb connection under the system session and save the remote users
- * session details in a ldb_opaque. This will allow the audit logging to
- * log the original session for operations performed in the system session.
- */
-struct ldb_context *dcesrv_samdb_connect_as_system(
+static struct ldb_context *dcesrv_samdb_connect_common(
TALLOC_CTX *mem_ctx,
- struct dcesrv_call_state *dce_call)
+ struct dcesrv_call_state *dce_call,
+ bool as_system)
{
struct ldb_context *samdb = NULL;
+ struct auth_session_info *system_session_info = NULL;
+ const struct auth_session_info *call_session_info =
+ dcesrv_call_session_info(dce_call);
+ struct auth_session_info *user_session_info = NULL;
+ struct auth_session_info *ldb_session_info = NULL;
+ struct auth_session_info *audit_session_info = NULL;
+ struct tsocket_address *remote_address = NULL;
+
+ if (as_system) {
+ system_session_info = system_session(dce_call->conn->dce_ctx->lp_ctx);
+ if (system_session_info == NULL) {
+ return NULL;
+ }
+ }
+
+ user_session_info = copy_session_info(mem_ctx, call_session_info);
+ if (user_session_info == NULL) {
+ return NULL;
+ }
+
+ if (dce_call->conn->remote_address != NULL) {
+ remote_address = tsocket_address_copy(dce_call->conn->remote_address,
+ user_session_info);
+ if (remote_address == NULL) {
+ return NULL;
+ }
+ }
+
+ if (system_session_info != NULL) {
+ ldb_session_info = system_session_info;
+ audit_session_info = user_session_info;
+ } else {
+ ldb_session_info = user_session_info;
+ audit_session_info = NULL;
+ }
+
+ /*
+ * We need to make sure every argument
+ * stays arround for the lifetime of 'samdb',
+ * typically it is allocated on the scope of
+ * an assoc group, so we can't reference dce_call->conn,
+ * as the assoc group may stay when the current connection
+ * gets disconnected.
+ *
+ * The following are global per process:
+ * - dce_call->conn->dce_ctx->lp_ctx
+ * - dce_call->event_ctx
+ * - system_session
+ *
+ * We make a copy of:
+ * - dce_call->conn->remote_address
+ * - dce_call->auth_state->session_info
+ */
samdb = samdb_connect(
mem_ctx,
dce_call->event_ctx,
dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
+ ldb_session_info,
+ remote_address,
0);
- if (samdb) {
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
- ldb_set_opaque(
- samdb,
- DSDB_NETWORK_SESSION_INFO,
- session_info);
+ if (samdb == NULL) {
+ talloc_free(user_session_info);
+ return NULL;
+ }
+ talloc_move(samdb, &user_session_info);
+
+ if (audit_session_info != NULL) {
+ int ret;
+
+ ret = ldb_set_opaque(samdb,
+ DSDB_NETWORK_SESSION_INFO,
+ audit_session_info);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(samdb);
+ return NULL;
+ }
}
+
return samdb;
}
+
+/*
+ * Open an ldb connection under the system session and save the remote users
+ * session details in a ldb_opaque. This will allow the audit logging to
+ * log the original session for operations performed in the system session.
+ *
+ * Access checks are required by the caller!
+ */
+struct ldb_context *dcesrv_samdb_connect_as_system(
+ TALLOC_CTX *mem_ctx,
+ struct dcesrv_call_state *dce_call)
+{
+ return dcesrv_samdb_connect_common(mem_ctx, dce_call,
+ true /* as_system */);
+}
+
+/*
+ * Open an ldb connection under the remote users session details.
+ *
+ * Access checks are done at the ldb level.
+ */
+struct ldb_context *dcesrv_samdb_connect_as_user(
+ TALLOC_CTX *mem_ctx,
+ struct dcesrv_call_state *dce_call)
+{
+ return dcesrv_samdb_connect_common(mem_ctx, dce_call,
+ false /* not as_system */);
+}
diff -Nru samba-4.13.3+dfsg/source4/rpc_server/common/sid_helper.c samba-4.13.14+dfsg/source4/rpc_server/common/sid_helper.c
--- samba-4.13.3+dfsg/source4/rpc_server/common/sid_helper.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/rpc_server/common/sid_helper.c 1970-01-01 00:00:00.000000000 +0000
@@ -1,134 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- common sid helper functions
-
- Copyright (C) Catalyst.NET Ltd 2017
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include "includes.h"
-#include "rpc_server/dcerpc_server.h"
-#include "librpc/gen_ndr/ndr_security.h"
-#include "source4/dsdb/samdb/samdb.h"
-#include "rpc_server/common/sid_helper.h"
-#include "libcli/security/security.h"
-
-/*
- see if any SIDs in list1 are in list2
- */
-bool sid_list_match(const struct dom_sid **list1, const struct dom_sid **list2)
-{
- unsigned int i, j;
- /* do we ever have enough SIDs here to worry about O(n^2) ? */
- for (i=0; list1[i]; i++) {
- for (j=0; list2[j]; j++) {
- if (dom_sid_equal(list1[i], list2[j])) {
- return true;
- }
- }
- }
- return false;
-}
-
-/*
- * Return an array of SIDs from a ldb_message given an attribute name assumes
- * the SIDs are in NDR form (with additional sids applied on the end).
- */
-WERROR samdb_result_sid_array_ndr(struct ldb_context *sam_ctx,
- struct ldb_message *msg,
- TALLOC_CTX *mem_ctx,
- const char *attr,
- const struct dom_sid ***sids,
- const struct dom_sid **additional_sids,
- unsigned int num_additional)
-{
- struct ldb_message_element *el;
- unsigned int i, j;
-
- el = ldb_msg_find_element(msg, attr);
- if (!el) {
- *sids = NULL;
- return WERR_OK;
- }
-
- /* Make array long enough for NULL and additional SID */
- (*sids) = talloc_array(mem_ctx, const struct dom_sid *,
- el->num_values + num_additional + 1);
- W_ERROR_HAVE_NO_MEMORY(*sids);
-
- for (i=0; inum_values; i++) {
- enum ndr_err_code ndr_err;
- struct dom_sid *sid;
-
- sid = talloc(*sids, struct dom_sid);
- W_ERROR_HAVE_NO_MEMORY(sid);
-
- ndr_err = ndr_pull_struct_blob(&el->values[i], sid, sid,
- (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- return WERR_INTERNAL_DB_CORRUPTION;
- }
- (*sids)[i] = sid;
- }
-
- for (j = 0; j < num_additional; j++) {
- (*sids)[i++] = additional_sids[j];
- }
-
- (*sids)[i] = NULL;
-
- return WERR_OK;
-}
-
-/*
- return an array of SIDs from a ldb_message given an attribute name
- assumes the SIDs are in extended DN format
- */
-WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx,
- struct ldb_message *msg,
- TALLOC_CTX *mem_ctx,
- const char *attr,
- const struct dom_sid ***sids)
-{
- struct ldb_message_element *el;
- unsigned int i;
-
- el = ldb_msg_find_element(msg, attr);
- if (!el) {
- *sids = NULL;
- return WERR_OK;
- }
-
- (*sids) = talloc_array(mem_ctx, const struct dom_sid *, el->num_values + 1);
- W_ERROR_HAVE_NO_MEMORY(*sids);
-
- for (i=0; inum_values; i++) {
- struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, sam_ctx, &el->values[i]);
- NTSTATUS status;
- struct dom_sid *sid;
-
- sid = talloc(*sids, struct dom_sid);
- W_ERROR_HAVE_NO_MEMORY(sid);
- status = dsdb_get_extended_dn_sid(dn, sid, "SID");
- if (!NT_STATUS_IS_OK(status)) {
- return WERR_INTERNAL_DB_CORRUPTION;
- }
- (*sids)[i] = sid;
- }
- (*sids)[i] = NULL;
-
- return WERR_OK;
-}
diff -Nru samba-4.13.3+dfsg/source4/rpc_server/dnsserver/dcerpc_dnsserver.c samba-4.13.14+dfsg/source4/rpc_server/dnsserver/dcerpc_dnsserver.c
--- samba-4.13.3+dfsg/source4/rpc_server/dnsserver/dcerpc_dnsserver.c 2020-10-26 14:00:36.000000000 +0000
+++ samba-4.13.14+dfsg/source4/rpc_server/dnsserver/dcerpc_dnsserver.c 2021-11-08 11:29:14.000000000 +0000
@@ -22,6 +22,7 @@
#include "includes.h"
#include "talloc.h"
#include "rpc_server/dcerpc_server.h"
+#include "rpc_server/common/common.h"
#include "dsdb/samdb/samdb.h"
#include "lib/util/dlinklist.h"
#include "librpc/gen_ndr/ndr_dnsserver.h"
@@ -104,8 +105,6 @@
static struct dnsserver_state *dnsserver_connect(struct dcesrv_call_state *dce_call)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct dnsserver_state *dsstate;
struct dnsserver_zone *zones, *z, *znext;
struct dnsserver_partition *partitions, *p;
@@ -125,13 +124,7 @@
dsstate->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
- /* FIXME: create correct auth_session_info for connecting user */
- dsstate->samdb = samdb_connect(dsstate,
- dce_call->event_ctx,
- dsstate->lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ dsstate->samdb = dcesrv_samdb_connect_as_user(dsstate, dce_call);
if (dsstate->samdb == NULL) {
DEBUG(0,("dnsserver: Failed to open samdb"));
goto failed;
diff -Nru samba-4.13.3+dfsg/source4/rpc_server/drsuapi/dcesrv_drsuapi.c samba-4.13.14+dfsg/source4/rpc_server/drsuapi/dcesrv_drsuapi.c
--- samba-4.13.3+dfsg/source4/rpc_server/drsuapi/dcesrv_drsuapi.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/rpc_server/drsuapi/dcesrv_drsuapi.c 2021-11-08 11:29:14.000000000 +0000
@@ -73,9 +73,7 @@
uint32_t supported_extensions;
uint32_t req_length;
int ret;
- struct auth_session_info *auth_info;
WERROR werr;
- bool connected_as_system = false;
r->out.bind_info = NULL;
ZERO_STRUCTP(r->out.bind_handle);
@@ -86,45 +84,30 @@
/* if this is a DC connecting, give them system level access */
werr = drs_security_level_check(dce_call, NULL, SECURITY_DOMAIN_CONTROLLER, NULL);
if (W_ERROR_IS_OK(werr)) {
- DEBUG(3,(__location__ ": doing DsBind with system_session\n"));
- auth_info = system_session(dce_call->conn->dce_ctx->lp_ctx);
- connected_as_system = true;
+ DBG_NOTICE("doing DsBind with system_session\n");
+ b_state->sam_ctx_system = dcesrv_samdb_connect_as_system(b_state, dce_call);
+ if (b_state->sam_ctx_system == NULL) {
+ return WERR_DS_UNAVAILABLE;
+ }
+ b_state->sam_ctx = b_state->sam_ctx_system;
} else {
- auth_info = dcesrv_call_session_info(dce_call);
- }
-
- /*
- * connect to the samdb
- */
- b_state->sam_ctx = samdb_connect(
- b_state,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- auth_info,
- dce_call->conn->remote_address,
- 0);
- if (!b_state->sam_ctx) {
- return WERR_FOOBAR;
- }
+ b_state->sam_ctx = dcesrv_samdb_connect_as_user(b_state, dce_call);
+ if (b_state->sam_ctx == NULL) {
+ return WERR_DS_UNAVAILABLE;
+ }
- if (connected_as_system) {
- b_state->sam_ctx_system = b_state->sam_ctx;
- } else {
- /* an RODC also needs system samdb access for secret
- attribute replication */
+ /*
+ * an RODC also needs system samdb access for secret
+ * attribute replication
+ */
werr = drs_security_level_check(dce_call, NULL, SECURITY_RO_DOMAIN_CONTROLLER,
samdb_domain_sid(b_state->sam_ctx));
if (W_ERROR_IS_OK(werr)) {
- b_state->sam_ctx_system
- = samdb_connect(
- b_state,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
- if (!b_state->sam_ctx_system) {
- return WERR_FOOBAR;
+ DBG_NOTICE("doing DsBind as RODC\n");
+ b_state->sam_ctx_system =
+ dcesrv_samdb_connect_as_system(b_state, dce_call);
+ if (b_state->sam_ctx_system == NULL) {
+ return WERR_DS_UNAVAILABLE;
}
}
}
diff -Nru samba-4.13.3+dfsg/source4/rpc_server/drsuapi/getncchanges.c samba-4.13.14+dfsg/source4/rpc_server/drsuapi/getncchanges.c
--- samba-4.13.3+dfsg/source4/rpc_server/drsuapi/getncchanges.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/rpc_server/drsuapi/getncchanges.c 2021-11-08 11:29:14.000000000 +0000
@@ -31,7 +31,6 @@
#include "libcli/security/security.h"
#include "libcli/security/session.h"
#include "rpc_server/drsuapi/dcesrv_drsuapi.h"
-#include "rpc_server/common/sid_helper.h"
#include "../libcli/drsuapi/drsuapi.h"
#include "lib/util/binsearch.h"
#include "lib/util/tsort.h"
@@ -1168,13 +1167,14 @@
struct ldb_dn *ntds_dn = NULL, *server_dn = NULL;
struct ldb_dn *rodc_dn, *krbtgt_link_dn;
int ret;
- const char *rodc_attrs[] = { "msDS-KrbTgtLink", "msDS-NeverRevealGroup", "msDS-RevealOnDemandGroup", "objectGUID", NULL };
+ const char *rodc_attrs[] = { "msDS-KrbTgtLink",
+ "msDS-NeverRevealGroup",
+ "msDS-RevealOnDemandGroup",
+ "userAccountControl",
+ NULL };
const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL };
struct ldb_result *rodc_res = NULL, *obj_res = NULL;
- const struct dom_sid **never_reveal_sids, **reveal_sids, **token_sids;
- const struct dom_sid *object_sid = NULL;
WERROR werr;
- const struct dom_sid *additional_sids[] = { NULL, NULL };
DEBUG(3,(__location__ ": DRSUAPI_EXOP_REPL_SECRET extended op on %s\n",
drs_ObjectIdentifier_to_string(mem_ctx, ncRoot)));
@@ -1249,7 +1249,11 @@
dom_sid_string(mem_ctx, user_sid));
if (!ldb_dn_validate(rodc_dn)) goto failed;
- /* do the two searches we need */
+ /*
+ * do the two searches we need
+ * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
+ * out of the extended DNs
+ */
ret = dsdb_search_dn(b_state->sam_ctx_system, mem_ctx, &rodc_res, rodc_dn, rodc_attrs,
DSDB_SEARCH_SHOW_EXTENDED_DN);
if (ret != LDB_SUCCESS || rodc_res->count != 1) goto failed;
@@ -1257,14 +1261,6 @@
ret = dsdb_search_dn(b_state->sam_ctx_system, mem_ctx, &obj_res, obj_dn, obj_attrs, 0);
if (ret != LDB_SUCCESS || obj_res->count != 1) goto failed;
- /* if the object SID is equal to the user_sid, allow */
- object_sid = samdb_result_dom_sid(mem_ctx, obj_res->msgs[0], "objectSid");
- if (dom_sid_equal(user_sid, object_sid)) {
- goto allowed;
- }
-
- additional_sids[0] = object_sid;
-
/*
* Must be an RODC account at this point, verify machine DN matches the
* SID account
@@ -1281,49 +1277,12 @@
goto allowed;
}
- /* but it isn't allowed to get anyone elses krbtgt secrets */
- if (samdb_result_dn(b_state->sam_ctx_system, mem_ctx,
- obj_res->msgs[0], "msDS-KrbTgtLinkBL", NULL)) {
- goto denied;
- }
-
- if (ldb_msg_find_attr_as_uint(obj_res->msgs[0],
- "userAccountControl", 0) &
- UF_INTERDOMAIN_TRUST_ACCOUNT) {
- goto denied;
- }
-
- werr = samdb_result_sid_array_dn(b_state->sam_ctx_system, rodc_res->msgs[0],
- mem_ctx, "msDS-NeverRevealGroup", &never_reveal_sids);
- if (!W_ERROR_IS_OK(werr)) {
- goto denied;
- }
-
- werr = samdb_result_sid_array_dn(b_state->sam_ctx_system, rodc_res->msgs[0],
- mem_ctx, "msDS-RevealOnDemandGroup", &reveal_sids);
- if (!W_ERROR_IS_OK(werr)) {
- goto denied;
- }
-
- /*
- * The SID list needs to include itself as well as the tokenGroups.
- *
- * TODO determine if sIDHistory is required for this check
- */
- werr = samdb_result_sid_array_ndr(b_state->sam_ctx_system, obj_res->msgs[0],
- mem_ctx, "tokenGroups", &token_sids,
- additional_sids, 1);
- if (!W_ERROR_IS_OK(werr) || token_sids==NULL) {
- goto denied;
- }
-
- if (never_reveal_sids &&
- sid_list_match(token_sids, never_reveal_sids)) {
- goto denied;
- }
+ werr = samdb_confirm_rodc_allowed_to_repl_to(b_state->sam_ctx_system,
+ user_sid,
+ rodc_res->msgs[0],
+ obj_res->msgs[0]);
- if (reveal_sids &&
- sid_list_match(token_sids, reveal_sids)) {
+ if (W_ERROR_IS_OK(werr)) {
goto allowed;
}
diff -Nru samba-4.13.3+dfsg/source4/rpc_server/lsa/lsa_init.c samba-4.13.14+dfsg/source4/rpc_server/lsa/lsa_init.c
--- samba-4.13.3+dfsg/source4/rpc_server/lsa/lsa_init.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/rpc_server/lsa/lsa_init.c 2021-11-08 11:29:14.000000000 +0000
@@ -71,12 +71,7 @@
}
/* make sure the sam database is accessible */
- state->sam_ldb = samdb_connect(state,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ state->sam_ldb = dcesrv_samdb_connect_as_user(state, dce_call);
if (state->sam_ldb == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
diff -Nru samba-4.13.3+dfsg/source4/rpc_server/lsa/lsa_lookup.c samba-4.13.14+dfsg/source4/rpc_server/lsa/lsa_lookup.c
--- samba-4.13.3+dfsg/source4/rpc_server/lsa/lsa_lookup.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/rpc_server/lsa/lsa_lookup.c 2021-09-22 06:59:39.000000000 +0000
@@ -663,25 +663,24 @@
return status;
}
+/* A random hexidecimal number (honest!) */
+#define LSA_SERVER_IMPLICIT_POLICY_STATE_MAGIC 0xc0c99e00
/*
- lsa_LookupSids3
-
- Identical to LookupSids2, but doesn't take a policy handle
-
+ Ensure we're operating on an schannel connection,
+ and use a lsa_policy_state cache on the connection.
*/
-NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call,
- TALLOC_CTX *mem_ctx,
- struct lsa_LookupSids3 *r)
+static NTSTATUS schannel_call_setup(struct dcesrv_call_state *dce_call,
+ struct lsa_policy_state **_policy_state)
{
+ struct lsa_policy_state *policy_state = NULL;
enum dcerpc_transport_t transport =
dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
- struct dcesrv_lsa_LookupSids_base_state *state = NULL;
- NTSTATUS status;
-
if (transport != NCACN_IP_TCP) {
- DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
+ /* We can't call DCESRV_FAULT() in the sub-function */
+ dce_call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
+ return NT_STATUS_ACCESS_DENIED;
}
/*
@@ -693,8 +692,59 @@
*/
dcesrv_call_auth_info(dce_call, &auth_type, NULL);
if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
- DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
+ /* We can't call DCESRV_FAULT() in the sub-function */
+ dce_call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /*
+ * We don't have a policy handle on this call, so we want to
+ * make a policy state and cache it for the life of the
+ * connection, to avoid re-opening the DB each call.
+ */
+ policy_state
+ = dcesrv_iface_state_find_conn(dce_call,
+ LSA_SERVER_IMPLICIT_POLICY_STATE_MAGIC,
+ struct lsa_policy_state);
+
+ if (policy_state == NULL) {
+ NTSTATUS status
+ = dcesrv_lsa_get_policy_state(dce_call,
+ dce_call /* mem_ctx */,
+ 0, /* we skip access checks */
+ &policy_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * This will talloc_steal() policy_state onto the
+ * connection, which has longer lifetime than the
+ * immidiate caller requires
+ */
+ status = dcesrv_iface_state_store_conn(dce_call,
+ LSA_SERVER_IMPLICIT_POLICY_STATE_MAGIC,
+ policy_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
}
+ *_policy_state = policy_state;
+ return NT_STATUS_OK;
+}
+
+/*
+ lsa_LookupSids3
+
+ Identical to LookupSids2, but doesn't take a policy handle
+
+*/
+NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_LookupSids3 *r)
+{
+ struct dcesrv_lsa_LookupSids_base_state *state = NULL;
+ NTSTATUS status;
*r->out.domains = NULL;
r->out.names->count = 0;
@@ -706,16 +756,27 @@
return NT_STATUS_NO_MEMORY;
}
- state->dce_call = dce_call;
- state->mem_ctx = mem_ctx;
-
- status = dcesrv_lsa_get_policy_state(state->dce_call, mem_ctx,
- 0, /* we skip access checks */
- &state->policy_state);
+ /*
+ * We don't have a policy handle on this call, so we want to
+ * make a policy state and cache it for the life of the
+ * connection, to avoid re-opening the DB each call.
+ *
+ * This also enforces that this is only available over
+ * ncacn_ip_tcp and with SCHANNEL.
+ *
+ * schannel_call_setup may also set the fault state.
+ *
+ * state->policy_state is shared between all calls on this
+ * connection and is moved with talloc_steal() under the
+ * connection, not dce_call or state.
+ */
+ status = schannel_call_setup(dce_call, &state->policy_state);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
+ state->dce_call = dce_call;
+ state->mem_ctx = mem_ctx;
state->r.in.sids = r->in.sids;
state->r.in.level = r->in.level;
state->r.in.lookup_options = r->in.lookup_options;
@@ -1296,25 +1357,9 @@
NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct lsa_LookupNames4 *r)
{
- enum dcerpc_transport_t transport =
- dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
- enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
struct dcesrv_lsa_LookupNames_base_state *state = NULL;
NTSTATUS status;
- if (transport != NCACN_IP_TCP) {
- DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
- }
-
- /*
- * We don't have policy handles on this call. So this must be restricted
- * to crypto connections only.
- */
- dcesrv_call_auth_info(dce_call, &auth_type, NULL);
- if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
- DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
- }
-
*r->out.domains = NULL;
r->out.sids->count = 0;
r->out.sids->sids = NULL;
@@ -1328,9 +1373,21 @@
state->dce_call = dce_call;
state->mem_ctx = mem_ctx;
- status = dcesrv_lsa_get_policy_state(state->dce_call, state,
- 0, /* we skip access checks */
- &state->policy_state);
+ /*
+ * We don't have a policy handle on this call, so we want to
+ * make a policy state and cache it for the life of the
+ * connection, to avoid re-opening the DB each call.
+ *
+ * This also enforces that this is only available over
+ * ncacn_ip_tcp and with SCHANNEL.
+ *
+ * schannel_call_setup may also set the fault state.
+ *
+ * state->policy_state is shared between all calls on this
+ * connection and is moved with talloc_steal() under the
+ * connection, not dce_call or state.
+ */
+ status = schannel_call_setup(dce_call, &state->policy_state);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
diff -Nru samba-4.13.3+dfsg/source4/rpc_server/netlogon/dcerpc_netlogon.c samba-4.13.14+dfsg/source4/rpc_server/netlogon/dcerpc_netlogon.c
--- samba-4.13.3+dfsg/source4/rpc_server/netlogon/dcerpc_netlogon.c 2020-09-22 13:43:27.000000000 +0000
+++ samba-4.13.14+dfsg/source4/rpc_server/netlogon/dcerpc_netlogon.c 2021-11-08 11:29:14.000000000 +0000
@@ -23,6 +23,7 @@
#include "includes.h"
#include "rpc_server/dcerpc_server.h"
+#include "rpc_server/common/common.h"
#include "auth/auth.h"
#include "auth/auth_sam_reply.h"
#include "dsdb/samdb/samdb.h"
@@ -42,7 +43,6 @@
#include "librpc/gen_ndr/ndr_winbind.h"
#include "librpc/gen_ndr/ndr_winbind_c.h"
#include "lib/socket/netif.h"
-#include "rpc_server/common/sid_helper.h"
#include "lib/util/util_str_escape.h"
#define DCESRV_INTERFACE_NETLOGON_BIND(context, iface) \
@@ -284,12 +284,7 @@
return NT_STATUS_INVALID_PARAMETER;
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
@@ -757,12 +752,7 @@
&creds);
NT_STATUS_NOT_OK_RETURN(nt_status);
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
@@ -826,12 +816,7 @@
&creds);
NT_STATUS_NOT_OK_RETURN(nt_status);
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
@@ -1717,8 +1702,6 @@
static WERROR dcesrv_netr_GetDcName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_GetDcName *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
const char * const attrs[] = { NULL };
struct ldb_context *sam_ctx;
struct ldb_message **res;
@@ -1745,12 +1728,7 @@
*/
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
@@ -1952,13 +1930,8 @@
if (!ok) {
struct ldb_context *sam_ctx;
- sam_ctx = samdb_connect(
- state,
- state->dce_call->event_ctx,
- lp_ctx,
- system_session(lp_ctx),
- state->dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(state,
+ state->dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
@@ -2155,8 +2128,6 @@
static WERROR dcesrv_netr_GetAnyDCName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_GetAnyDCName *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct netr_DomainTrustList *trusts;
struct ldb_context *sam_ctx;
struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
@@ -2170,12 +2141,7 @@
r->in.domainname = lpcfg_workgroup(lp_ctx);
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
@@ -2317,17 +2283,9 @@
static WERROR dcesrv_netr_DsRGetSiteName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DsRGetSiteName *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct ldb_context *sam_ctx;
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
@@ -2526,12 +2484,7 @@
}
NT_STATUS_NOT_OK_RETURN(status);
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
@@ -2845,21 +2798,25 @@
struct dom_sid *user_sid,
struct ldb_dn *obj_dn)
{
- const char *rodc_attrs[] = { "msDS-KrbTgtLink", "msDS-NeverRevealGroup", "msDS-RevealOnDemandGroup", "objectGUID", NULL };
+ const char *rodc_attrs[] = { "msDS-NeverRevealGroup",
+ "msDS-RevealOnDemandGroup",
+ "userAccountControl",
+ NULL };
const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL };
struct ldb_dn *rodc_dn;
int ret;
struct ldb_result *rodc_res = NULL, *obj_res = NULL;
- const struct dom_sid *additional_sids[] = { NULL, NULL };
WERROR werr;
- struct dom_sid *object_sid;
- const struct dom_sid **never_reveal_sids, **reveal_sids, **token_sids;
rodc_dn = ldb_dn_new_fmt(mem_ctx, sam_ctx, "",
dom_sid_string(mem_ctx, user_sid));
if (!ldb_dn_validate(rodc_dn)) goto denied;
- /* do the two searches we need */
+ /*
+ * do the two searches we need
+ * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID list
+ * out of the extended DNs
+ */
ret = dsdb_search_dn(sam_ctx, mem_ctx, &rodc_res, rodc_dn, rodc_attrs,
DSDB_SEARCH_SHOW_EXTENDED_DN);
if (ret != LDB_SUCCESS || rodc_res->count != 1) goto denied;
@@ -2867,44 +2824,14 @@
ret = dsdb_search_dn(sam_ctx, mem_ctx, &obj_res, obj_dn, obj_attrs, 0);
if (ret != LDB_SUCCESS || obj_res->count != 1) goto denied;
- object_sid = samdb_result_dom_sid(mem_ctx, obj_res->msgs[0], "objectSid");
-
- additional_sids[0] = object_sid;
-
- werr = samdb_result_sid_array_dn(sam_ctx, rodc_res->msgs[0],
- mem_ctx, "msDS-NeverRevealGroup", &never_reveal_sids);
- if (!W_ERROR_IS_OK(werr)) {
- goto denied;
- }
-
- werr = samdb_result_sid_array_dn(sam_ctx, rodc_res->msgs[0],
- mem_ctx, "msDS-RevealOnDemandGroup", &reveal_sids);
- if (!W_ERROR_IS_OK(werr)) {
- goto denied;
- }
-
- /*
- * The SID list needs to include itself as well as the tokenGroups.
- *
- * TODO determine if sIDHistory is required for this check
- */
- werr = samdb_result_sid_array_ndr(sam_ctx, obj_res->msgs[0],
- mem_ctx, "tokenGroups", &token_sids,
- additional_sids, 1);
- if (!W_ERROR_IS_OK(werr) || token_sids==NULL) {
- goto denied;
- }
-
- if (never_reveal_sids &&
- sid_list_match(token_sids, never_reveal_sids)) {
- goto denied;
- }
+ werr = samdb_confirm_rodc_allowed_to_repl_to(sam_ctx,
+ user_sid,
+ rodc_res->msgs[0],
+ obj_res->msgs[0]);
- if (reveal_sids &&
- sid_list_match(token_sids, reveal_sids)) {
+ if (W_ERROR_IS_OK(werr)) {
goto allowed;
}
-
denied:
return false;
allowed:
@@ -2949,12 +2876,7 @@
return NT_STATUS_INVALID_PARAMETER;
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
@@ -3065,8 +2987,6 @@
static WERROR dcesrv_netr_DsRGetDCName_base_call(struct dcesrv_netr_DsRGetDCName_base_state *state)
{
struct dcesrv_call_state *dce_call = state->dce_call;
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct imessaging_context *imsg_ctx =
dcesrv_imessaging_context(dce_call->conn);
TALLOC_CTX *mem_ctx = state->mem_ctx;
@@ -3089,12 +3009,7 @@
ZERO_STRUCTP(r->out.info);
- sam_ctx = samdb_connect(state,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
@@ -3549,11 +3464,8 @@
static WERROR dcesrv_netr_DsRAddressToSitenamesExW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DsRAddressToSitenamesExW *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct ldb_context *sam_ctx;
struct netr_DsRAddressToSitenamesExWCtr *ctr;
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
sa_family_t sin_family;
struct sockaddr_in *addr;
#ifdef HAVE_IPV6
@@ -3566,12 +3478,7 @@
const char *res;
uint32_t i;
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
@@ -3683,18 +3590,10 @@
static WERROR dcesrv_netr_DsrGetDcSiteCoverageW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_DsrGetDcSiteCoverageW *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct ldb_context *sam_ctx;
struct DcSitesCtr *ctr;
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_DS_UNAVAILABLE;
}
@@ -3820,8 +3719,6 @@
TALLOC_CTX *mem_ctx,
struct netr_DsrEnumerateDomainTrusts *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct netr_DomainTrustList *trusts;
struct ldb_context *sam_ctx;
int ret;
@@ -3863,12 +3760,7 @@
trusts->count = 0;
r->out.trusts = trusts;
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_GEN_FAILURE;
}
@@ -3978,7 +3870,6 @@
TALLOC_CTX *mem_ctx,
struct netr_DsRGetForestTrustInformation *r)
{
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
struct auth_session_info *session_info =
dcesrv_call_session_info(dce_call);
struct imessaging_context *imsg_ctx =
@@ -4002,12 +3893,7 @@
return WERR_INVALID_FLAGS;
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return WERR_GEN_FAILURE;
}
@@ -4134,9 +4020,6 @@
TALLOC_CTX *mem_ctx,
struct netr_GetForestTrustInformation *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
struct netlogon_creds_CredentialState *creds = NULL;
struct ldb_context *sam_ctx = NULL;
struct ldb_dn *domain_dn = NULL;
@@ -4160,12 +4043,7 @@
return NT_STATUS_NOT_IMPLEMENTED;
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INTERNAL_ERROR;
}
@@ -4259,12 +4137,7 @@
return NT_STATUS_INVALID_PARAMETER;
}
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- lp_ctx,
- system_session(lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
diff -Nru samba-4.13.3+dfsg/source4/rpc_server/samr/dcesrv_samr.c samba-4.13.14+dfsg/source4/rpc_server/samr/dcesrv_samr.c
--- samba-4.13.3+dfsg/source4/rpc_server/samr/dcesrv_samr.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/rpc_server/samr/dcesrv_samr.c 2021-11-08 11:29:14.000000000 +0000
@@ -210,8 +210,6 @@
static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct samr_Connect *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct samr_connect_state *c_state;
struct dcesrv_handle *handle;
@@ -223,18 +221,12 @@
}
/* make sure the sam database is accessible */
- c_state->sam_ctx = samdb_connect(c_state,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ c_state->sam_ctx = dcesrv_samdb_connect_as_user(c_state, dce_call);
if (c_state->sam_ctx == NULL) {
talloc_free(c_state);
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
-
handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_CONNECT);
if (!handle) {
talloc_free(c_state);
@@ -573,6 +565,7 @@
break;
case ROLE_DOMAIN_PDC:
case ROLE_DOMAIN_BDC:
+ case ROLE_IPA_DC:
case ROLE_AUTO:
return NT_STATUS_INTERNAL_ERROR;
case ROLE_DOMAIN_MEMBER:
@@ -721,6 +714,7 @@
break;
case ROLE_DOMAIN_PDC:
case ROLE_DOMAIN_BDC:
+ case ROLE_IPA_DC:
case ROLE_AUTO:
return NT_STATUS_INTERNAL_ERROR;
case ROLE_DOMAIN_MEMBER:
@@ -4805,8 +4799,6 @@
static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct samr_GetDomPwInfo *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct ldb_message **msgs;
int ret;
const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
@@ -4814,12 +4806,7 @@
ZERO_STRUCTP(r->out.info);
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
diff -Nru samba-4.13.3+dfsg/source4/rpc_server/samr/samr_password.c samba-4.13.14+dfsg/source4/rpc_server/samr/samr_password.c
--- samba-4.13.3+dfsg/source4/rpc_server/samr/samr_password.c 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/rpc_server/samr/samr_password.c 2021-11-08 11:29:14.000000000 +0000
@@ -22,6 +22,7 @@
#include "includes.h"
#include "rpc_server/dcerpc_server.h"
+#include "rpc_server/common/common.h"
#include "rpc_server/samr/dcesrv_samr.h"
#include "system/time.h"
#include "lib/crypto/md4.h"
@@ -101,8 +102,6 @@
TALLOC_CTX *mem_ctx,
struct samr_OemChangePasswordUser2 *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct imessaging_context *imsg_ctx =
dcesrv_imessaging_context(dce_call->conn);
NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
@@ -146,12 +145,7 @@
/* Connect to a SAMDB with system privileges for fetching the old pw
* hashes. */
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
@@ -249,12 +243,7 @@
}
/* Connect to a SAMDB with user privileges for the password change */
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
@@ -327,8 +316,6 @@
TALLOC_CTX *mem_ctx,
struct samr_ChangePasswordUser3 *r)
{
- struct auth_session_info *session_info =
- dcesrv_call_session_info(dce_call);
struct imessaging_context *imsg_ctx =
dcesrv_imessaging_context(dce_call->conn);
NTSTATUS status = NT_STATUS_WRONG_PASSWORD;
@@ -374,12 +361,7 @@
/* Connect to a SAMDB with system privileges for fetching the old pw
* hashes. */
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- system_session(dce_call->conn->dce_ctx->lp_ctx),
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
@@ -485,12 +467,7 @@
}
/* Connect to a SAMDB with user privileges for the password change */
- sam_ctx = samdb_connect(mem_ctx,
- dce_call->event_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- session_info,
- dce_call->conn->remote_address,
- 0);
+ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
diff -Nru samba-4.13.3+dfsg/source4/rpc_server/wscript_build samba-4.13.14+dfsg/source4/rpc_server/wscript_build
--- samba-4.13.3+dfsg/source4/rpc_server/wscript_build 2020-07-09 09:33:56.000000000 +0000
+++ samba-4.13.14+dfsg/source4/rpc_server/wscript_build 2021-11-08 11:29:14.000000000 +0000
@@ -7,17 +7,10 @@
enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER'),
)
-bld.SAMBA_SUBSYSTEM('DCERPC_SID_HELPER',
- source='common/sid_helper.c',
- autoproto='common/sid_helper.h',
- deps='ldb',
- enabled=bld.AD_DC_BUILD_IS_ENABLED(),
- )
-
bld.SAMBA_SUBSYSTEM('DCERPC_COMMON',
source='common/server_info.c common/forward.c common/loadparm.c',
autoproto='common/proto.h',
- deps='ldb DCERPC_SHARE DCERPC_SID_HELPER',
+ deps='ldb DCERPC_SHARE',
enabled=bld.AD_DC_BUILD_IS_ENABLED()
)
diff -Nru samba-4.13.3+dfsg/source4/selftest/tests.py samba-4.13.14+dfsg/source4/selftest/tests.py
--- samba-4.13.3+dfsg/source4/selftest/tests.py 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/source4/selftest/tests.py 2021-11-08 11:29:14.000000000 +0000
@@ -561,7 +561,8 @@
plantestsuite("samba3.wbinfo_simple.fips.%s" % t, "ad_member_fips:local", [os.path.join(srcdir(), "nsswitch/tests/test_wbinfo_simple.sh"), t])
plantestsuite("samba4.wbinfo_name_lookup.fips", "ad_member_fips", [os.path.join(srcdir(), "nsswitch/tests/test_wbinfo_name_lookup.sh"), '$DOMAIN', '$REALM', '$DC_USERNAME'])
-plantestsuite_loadlist("samba4.rpc.echo against NetBIOS alias", "ad_dc_ntvfs", [valgrindify(smbtorture4), "$LISTOPT", "$LOADLIST", 'ncacn_np:$NETBIOSALIAS', '-U$DOMAIN/$USERNAME%$PASSWORD', 'rpc.echo'])
+plansmbtorture4testsuite('rpc.echo', "ad_dc_ntvfs", ['ncacn_np:$NETBIOSALIAS', '-U$DOMAIN/$USERNAME%$PASSWORD'], "samba4.rpc.echo against NetBIOS alias")
+
# json tests hook into ``chgdcpass'' to make them run in contributor CI on
# gitlab
planpythontestsuite("chgdcpass", "samba.tests.blackbox.netads_json")
@@ -717,6 +718,7 @@
planpythontestsuite("ad_dc_default:local", "samba.tests.dsdb")
planpythontestsuite("none", "samba.tests.dsdb_lock")
planpythontestsuite("ad_dc_default:local", "samba.tests.dcerpc.bare")
+planpythontestsuite("ad_dc_default:local", "samba.tests.dcerpc.lsa")
planpythontestsuite("ad_dc_default:local", "samba.tests.dcerpc.unix")
planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.dcerpc.srvsvc")
planpythontestsuite("ad_dc_default:local", "samba.tests.samba_tool.timecmd")
@@ -785,15 +787,80 @@
planoldpythontestsuite("ad_dc:local", "samba.tests.gpo", extra_args=['-U"$USERNAME%$PASSWORD"'])
planoldpythontestsuite("ad_dc:local", "samba.tests.dckeytab", extra_args=['-U"$USERNAME%$PASSWORD"'])
+have_fast_support = int('SAMBA_USES_MITKDC' in config_hash)
+tkt_sig_support = int('SAMBA4_USES_HEIMDAL' in config_hash)
+expect_pac = int('SAMBA4_USES_HEIMDAL' in config_hash)
planoldpythontestsuite("none", "samba.tests.krb5.kcrypto")
planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.simple_tests",
- environ={'SERVICE_USERNAME':'$SERVER'})
+ environ={'SERVICE_USERNAME':'$SERVER',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac})
planoldpythontestsuite("ad_dc_default:local", "samba.tests.krb5.s4u_tests",
- environ={'SERVICE_USERNAME':'srv_account',
- 'SERVICE_PASSWORD':'$PASSWORD',
- 'FOR_USER':'$USERNAME'})
-
-planoldpythontestsuite("fl2008r2dc:local", "samba.tests.krb5.xrealm_tests")
+ environ={'ADMIN_USERNAME':'$USERNAME',
+ 'ADMIN_PASSWORD':'$PASSWORD',
+ 'FOR_USER':'$USERNAME',
+ 'STRICT_CHECKING':'0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac})
+planoldpythontestsuite("rodc:local", "samba.tests.krb5.rodc_tests",
+ environ={'ADMIN_USERNAME':'$USERNAME',
+ 'ADMIN_PASSWORD':'$PASSWORD',
+ 'STRICT_CHECKING':'0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac})
+
+planoldpythontestsuite("fl2008r2dc:local", "samba.tests.krb5.xrealm_tests",
+ environ={'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac})
+
+planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ccache",
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
+planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.test_ldap",
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
+for env in ['ad_dc_default', 'ad_member']:
+ planoldpythontestsuite(env, "samba.tests.krb5.test_rpc",
+ environ={
+ 'ADMIN_USERNAME': '$DC_USERNAME',
+ 'ADMIN_PASSWORD': '$DC_PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
+planoldpythontestsuite("ad_dc_smb1", "samba.tests.krb5.test_smb",
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
+planoldpythontestsuite("ad_member_no_nss_wb:local",
+ "samba.tests.krb5.test_min_domain_uid",
+ environ={
+ 'ADMIN_USERNAME': '$DC_USERNAME',
+ 'ADMIN_PASSWORD': '$DC_PASSWORD',
+ 'STRICT_CHECKING': '0'
+ })
for env in ["ad_dc", smbv1_disabled_testenv]:
planoldpythontestsuite(env, "samba.tests.smb", extra_args=['-U"$USERNAME%$PASSWORD"'])
@@ -883,7 +950,7 @@
planoldpythontestsuite(env + ":local", "samba.tests.domain_backup",
extra_args=['-U"$USERNAME%$PASSWORD"'])
-planoldpythontestsuite("none",
+planoldpythontestsuite("ad_dc",
"samba.tests.domain_backup_offline")
# Encrypted secrets
# ensure default provision (ad_dc) and join (vampire_dc)
@@ -981,12 +1048,31 @@
extra_args=['-U"$USERNAME%$PASSWORD"'],
environ={'TEST_ENV': 'ad_dc'})
+plantestsuite_loadlist("samba.tests.ldap_spn", "ad_dc",
+ [python,
+ f"{srcdir()}/python/samba/tests/ldap_spn.py",
+ '$SERVER',
+ '-U"$USERNAME%$PASSWORD"',
+ '--workgroup=$DOMAIN',
+ '$LOADLIST', '$LISTOPT'])
+
+plantestsuite_loadlist("samba.tests.ldap_upn_sam_account", "ad_dc_ntvfs",
+ [python,
+ f"{srcdir()}/python/samba/tests/ldap_upn_sam_account.py",
+ '$SERVER',
+ '-U"$USERNAME%$PASSWORD"',
+ '--workgroup=$DOMAIN',
+ '$LOADLIST', '$LISTOPT'])
+
+
plantestsuite_loadlist("samba4.tokengroups.krb5.python(ad_dc_default)", "ad_dc_default:local", [python, os.path.join(DSDB_PYTEST_DIR, "token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '-k', 'yes', '$LOADLIST', '$LISTOPT'])
plantestsuite_loadlist("samba4.tokengroups.ntlm.python(ad_dc_default)", "ad_dc_default:local", [python, os.path.join(DSDB_PYTEST_DIR, "token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '-k', 'no', '$LOADLIST', '$LISTOPT'])
plantestsuite("samba4.sam.python(fl2008r2dc)", "fl2008r2dc", [python, os.path.join(DSDB_PYTEST_DIR, "sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
plantestsuite("samba4.sam.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
plantestsuite("samba4.asq.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "asq.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
plantestsuite("samba4.user_account_control.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "user_account_control.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
+plantestsuite("samba4.priv_attrs.python(ad_dc_default)", "ad_dc_default", ["STRICT_CHECKING=0", python, os.path.join(DSDB_PYTEST_DIR, "priv_attrs.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
+plantestsuite("samba4.priv_attrs.strict.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "priv_attrs.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
for env in ['ad_dc_default:local', 'schema_dc:local']:
planoldpythontestsuite(env, "dsdb_schema_info",
@@ -1188,6 +1274,18 @@
environ={'DC1': "$DC_SERVER", 'DC2': '$SERVER'},
extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
+# This test can pollute the environment a little by creating and
+# deleting DCs which can get into the replication state for a while.
+#
+# The setting of DC1 to $DC_SERVER means that it will join towards and
+# operate on schema_dc. This matters most when running
+# test_samba_tool_replicate_local as this sets up a full temp DC and
+# does new replication to it, which can show up in the replication
+# topology.
+#
+# That is why this test is run on the isolated environment and not on
+# those connected with ad_dc (vampiredc/promoteddc)
+
env = 'schema_pair_dc'
planoldpythontestsuite("%s:local" % env, "samba_tool_drs",
extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')],
@@ -1201,17 +1299,18 @@
"PLEASE_BREAK_MY_WINDOWS": "1"},
extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
+# This test can be sensitive to the DC joins and replications don in
+# "samba_tool_drs" so run this is run against scheam_pair_dc/schema_dc
+# not the set of environments connected with ad_dc.
+
+# This will show the replication state of ad_dc
+planoldpythontestsuite("promoted_dc:local", "samba_tool_drs_showrepl",
+ extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')],
+ name="samba4.drs.samba_tool_drs_showrepl.python(%s)" % env,
+ environ={'DC1': '$DC_SERVER', 'DC2': '$SERVER'},
+ extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
+
for env in ['vampire_dc', 'promoted_dc']:
- planoldpythontestsuite("%s:local" % env, "samba_tool_drs",
- extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')],
- name="samba4.drs.samba_tool_drs.python(%s)" % env,
- environ={'DC1': '$DC_SERVER', 'DC2': '$SERVER'},
- extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
- planoldpythontestsuite("%s:local" % env, "samba_tool_drs_showrepl",
- extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')],
- name="samba4.drs.samba_tool_drs_showrepl.python(%s)" % env,
- environ={'DC1': '$DC_SERVER', 'DC2': '$SERVER'},
- extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
planoldpythontestsuite("%s:local" % env, "replica_sync",
extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')],
name="samba4.drs.replica_sync.python(%s)" % env,
@@ -1322,7 +1421,26 @@
'--option=torture:krb5-hostname=testupnspn.$DNSNAME',
'--option=torture:krb5-service=http'],
"samba4.krb5.kdc with account having identical UPN and SPN")
-
+for env in ["fl2008r2dc", "fl2003dc"]:
+ planoldpythontestsuite(env, "samba.tests.krb5.as_req_tests",
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
+
+planoldpythontestsuite('fl2008r2dc', 'samba.tests.krb5.salt_tests',
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
for env in ["rodc", "promoted_dc", "fl2000dc", "fl2008r2dc"]:
if env == "rodc":
@@ -1338,6 +1456,82 @@
'--option=torture:expect_machine_account=true'] + extra_options,
"samba4.krb5.kdc with machine account")
+planpythontestsuite("ad_dc", "samba.tests.krb5.as_canonicalization_tests",
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
+planpythontestsuite("ad_dc", "samba.tests.krb5.compatability_tests",
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
+planpythontestsuite("ad_dc", "samba.tests.krb5.kdc_tests",
+ environ={'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac})
+planpythontestsuite(
+ "ad_dc",
+ "samba.tests.krb5.kdc_tgs_tests",
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
+planpythontestsuite(
+ "ad_dc",
+ "samba.tests.krb5.fast_tests",
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
+planpythontestsuite(
+ "ad_dc",
+ "samba.tests.krb5.ms_kile_client_principal_lookup_tests",
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
+planpythontestsuite(
+ "ad_dc",
+ "samba.tests.krb5.spn_tests",
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
+planpythontestsuite(
+ "ad_dc",
+ "samba.tests.krb5.alias_tests",
+ environ={
+ 'ADMIN_USERNAME': '$USERNAME',
+ 'ADMIN_PASSWORD': '$PASSWORD',
+ 'STRICT_CHECKING': '0',
+ 'FAST_SUPPORT': have_fast_support,
+ 'TKT_SIG_SUPPORT': tkt_sig_support,
+ 'EXPECT_PAC': expect_pac
+ })
for env in [
'vampire_dc',
diff -Nru samba-4.13.3+dfsg/source4/setup/provision_self_join.ldif samba-4.13.14+dfsg/source4/setup/provision_self_join.ldif
--- samba-4.13.3+dfsg/source4/setup/provision_self_join.ldif 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/setup/provision_self_join.ldif 2021-11-08 11:29:14.000000000 +0000
@@ -15,11 +15,16 @@
operatingSystem: Samba
operatingSystemVersion: ${SAMBA_VERSION_STRING}
sAMAccountName: ${NETBIOSNAME}$
-# The "servicePrincipalName" updates are now handled by the "samba_spnupdate"
-# script
userAccountControl: 532480
clearTextPassword:: ${MACHINEPASS_B64}
objectSid: ${DOMAINSID}-${DCRID}
+# While some "servicePrincipalName" updates might be handled by the
+# "samba_spnupdate" script, we need to get the basics in here before
+# we add any others.
+servicePrincipalName: HOST/${DNSNAME}
+servicePrincipalName: HOST/${NETBIOSNAME}
+servicePrincipalName: HOST/${DNSNAME}/${DNSNAME}
+
dn: CN=RID Set,CN=${NETBIOSNAME},OU=Domain Controllers,${DOMAINDN}
objectClass: rIDSet
diff -Nru samba-4.13.3+dfsg/source4/setup/tests/blackbox_spn.sh samba-4.13.14+dfsg/source4/setup/tests/blackbox_spn.sh
--- samba-4.13.3+dfsg/source4/setup/tests/blackbox_spn.sh 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/setup/tests/blackbox_spn.sh 2021-11-08 11:29:14.000000000 +0000
@@ -22,11 +22,10 @@
testit "delspn" $PYTHON $samba_tool spn delete FOO/bar $CONFIG
testit "readdspn" $PYTHON $samba_tool spn add FOO/bar Administrator $CONFIG
testit_expect_failure "failexistingspn" $PYTHON $samba_tool spn add FOO/bar Guest $CONFIG
-testit "existingspnforce" $PYTHON $samba_tool spn add --force FOO/bar Guest $CONFIG
testit_expect_failure "faildelspnnotgooduser" $PYTHON $samba_tool spn delete FOO/bar krbtgt $CONFIG
-testit_expect_failure "faildelspnmoreoneuser" $PYTHON $samba_tool spn delete FOO/bar $CONFIG
-testit "deluserspn" $PYTHON $samba_tool spn delete FOO/bar Guest $CONFIG
-testit "dellastuserspn" $PYTHON $samba_tool spn delete FOO/bar $CONFIG
+testit "deluserspn" $PYTHON $samba_tool spn delete FOO/bar $CONFIG
+testit "readd_spn_guest" $PYTHON $samba_tool spn add FOO/bar Guest $CONFIG
+testit "deluserspn_guest" $PYTHON $samba_tool spn delete FOO/bar Guest $CONFIG
testit_expect_failure "faildelspn" $PYTHON $samba_tool spn delete FOO/bar $CONFIG
testit_expect_failure "failaddspn" $PYTHON $samba_tool spn add FOO/bar nonexistinguser $CONFIG
diff -Nru samba-4.13.3+dfsg/source4/setup/tests/blackbox_upgradeprovision.sh samba-4.13.14+dfsg/source4/setup/tests/blackbox_upgradeprovision.sh
--- samba-4.13.3+dfsg/source4/setup/tests/blackbox_upgradeprovision.sh 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/setup/tests/blackbox_upgradeprovision.sh 2021-11-08 11:29:14.000000000 +0000
@@ -42,19 +42,19 @@
# really doesn't change anything.
ldapcmp() {
- $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX/upgradeprovision/private/sam.ldb tdb://$PREFIX/upgradeprovision_reference/private/sam.ldb --two --skip-missing-dn
+ $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX/upgradeprovision/private/sam.ldb tdb://$PREFIX/upgradeprovision_reference/private/sam.ldb --two --skip-missing-dn --filter=servicePrincipalName
}
ldapcmp_full() {
- $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX/upgradeprovision_full/private/sam.ldb tdb://$PREFIX/upgradeprovision_reference/private/sam.ldb --two --skip-missing-dn
+ $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX/upgradeprovision_full/private/sam.ldb tdb://$PREFIX/upgradeprovision_reference/private/sam.ldb --two --skip-missing-dn --filter=servicePrincipalName
}
ldapcmp_sd() {
- $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX/upgradeprovision/private/sam.ldb tdb://$PREFIX/upgradeprovision_reference/private/sam.ldb --two --sd --skip-missing-dn
+ $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX/upgradeprovision/private/sam.ldb tdb://$PREFIX/upgradeprovision_reference/private/sam.ldb --two --sd --skip-missing-dn --filter=servicePrincipalName
}
ldapcmp_full_sd() {
- $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX/upgradeprovision_full/private/sam.ldb tdb://$PREFIX/upgradeprovision_reference/private/sam.ldb --two --sd --skip-missing-dn
+ $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX/upgradeprovision_full/private/sam.ldb tdb://$PREFIX/upgradeprovision_reference/private/sam.ldb --two --sd --skip-missing-dn --filter=servicePrincipalName
}
testit "upgradeprovision" upgradeprovision
diff -Nru samba-4.13.3+dfsg/source4/smb_server/smb/sesssetup.c samba-4.13.14+dfsg/source4/smb_server/smb/sesssetup.c
--- samba-4.13.3+dfsg/source4/smb_server/smb/sesssetup.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/smb_server/smb/sesssetup.c 2021-11-08 11:29:14.000000000 +0000
@@ -102,7 +102,7 @@
struct auth_session_info *session_info;
struct smbsrv_session *smb_sess;
NTSTATUS status;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uint32_t flags;
status = auth_check_password_recv(subreq, req, &user_info_dc,
@@ -243,7 +243,7 @@
struct auth_user_info_dc *user_info_dc = NULL;
struct auth_session_info *session_info;
struct smbsrv_session *smb_sess;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uint32_t flags;
NTSTATUS status;
diff -Nru samba-4.13.3+dfsg/source4/torture/drs/python/replica_sync.py samba-4.13.14+dfsg/source4/torture/drs/python/replica_sync.py
--- samba-4.13.3+dfsg/source4/torture/drs/python/replica_sync.py 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/drs/python/replica_sync.py 2021-10-29 06:17:36.000000000 +0000
@@ -140,7 +140,7 @@
# now check properties of the user
name_cur = ou_cur["ou"][0]
self.assertEqual(ou_cur["isDeleted"][0], b"TRUE")
- self.assertTrue(not(b"objectCategory" in ou_cur))
+ self.assertTrue(not("objectCategory" in ou_cur))
self.assertTrue(dodn in str(ou_cur["dn"]),
"OU %s is deleted but it is not located under %s!" % (name_cur, dodn))
diff -Nru samba-4.13.3+dfsg/source4/torture/drs/python/repl_rodc.py samba-4.13.14+dfsg/source4/torture/drs/python/repl_rodc.py
--- samba-4.13.3+dfsg/source4/torture/drs/python/repl_rodc.py 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/drs/python/repl_rodc.py 2021-10-29 06:17:36.000000000 +0000
@@ -37,7 +37,7 @@
from samba.dcerpc import drsuapi, misc, drsblobs, security
from samba.drs_utils import drs_DsBind, drs_Replicate
from samba.ndr import ndr_unpack, ndr_pack
-from samba.common import dsdb_Dn
+from samba.samdb import dsdb_Dn
from samba.credentials import Credentials
import random
diff -Nru samba-4.13.3+dfsg/source4/torture/krb5/kdc-heimdal.c samba-4.13.14+dfsg/source4/torture/krb5/kdc-heimdal.c
--- samba-4.13.3+dfsg/source4/torture/krb5/kdc-heimdal.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/krb5/kdc-heimdal.c 2021-09-22 06:59:39.000000000 +0000
@@ -204,11 +204,12 @@
static bool torture_check_krb5_as_rep_enctype(struct torture_krb5_context *test_context,
const krb5_data *reply,
- krb5_enctype expected_enctype)
+ const krb5_enctype* allowed_enctypes)
{
ENCTYPE reply_enctype = { 0 };
size_t used = 0;
int rc;
+ int expected_enctype = ETYPE_NULL;
rc = decode_AS_REP(reply->data,
reply->length,
@@ -230,8 +231,84 @@
test_context->as_rep.ticket.enc_part.kvno,
"Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
- reply_enctype = test_context->as_rep.enc_part.etype;
+ if (test_context->as_req.padata) {
+ /*
+ * If the AS-REQ contains a PA-ENC-TIMESTAMP, then
+ * that encryption type is used to determine the reply
+ * enctype.
+ */
+ int i = 0;
+ const PA_DATA *pa = krb5_find_padata(test_context->as_req.padata->val,
+ test_context->as_req.padata->len,
+ KRB5_PADATA_ENC_TIMESTAMP,
+ &i);
+ if (pa) {
+ EncryptedData ed;
+ size_t len;
+ krb5_error_code ret = decode_EncryptedData(pa->padata_value.data,
+ pa->padata_value.length,
+ &ed, &len);
+ torture_assert_int_equal(test_context->tctx,
+ ret,
+ 0,
+ "decode_EncryptedData failed");
+ expected_enctype = ed.etype;
+ free_EncryptedData(&ed);
+ }
+ }
+ if (expected_enctype == ETYPE_NULL) {
+ /*
+ * Otherwise, find the strongest enctype contained in
+ * the AS-REQ supported enctypes list.
+ */
+ const krb5_enctype *p = NULL;
+ for (p = krb5_kerberos_enctypes(NULL); *p != (krb5_enctype)ETYPE_NULL; ++p) {
+ int j;
+
+ if ((*p == (krb5_enctype)ETYPE_AES256_CTS_HMAC_SHA1_96 ||
+ *p == (krb5_enctype)ETYPE_AES128_CTS_HMAC_SHA1_96) &&
+ !test_context->as_req.req_body.kdc_options.canonicalize)
+ {
+ /*
+ * AES encryption types are only used here when
+ * we set the canonicalize flag, as the salt
+ * needs to match.
+ */
+ continue;
+ }
+
+ for (j = 0; j < test_context->as_req.req_body.etype.len; ++j) {
+ krb5_enctype etype = test_context->as_req.req_body.etype.val[j];
+ if (*p == etype) {
+ expected_enctype = etype;
+ break;
+ }
+ }
+
+ if (expected_enctype != (krb5_enctype)ETYPE_NULL) {
+ break;
+ }
+ }
+ }
+
+ {
+ /* Ensure the enctype to check against is an expected type. */
+ const krb5_enctype *p = NULL;
+ bool found = false;
+ for (p = allowed_enctypes; *p != (krb5_enctype)ETYPE_NULL; ++p) {
+ if (*p == expected_enctype) {
+ found = true;
+ break;
+ }
+ }
+
+ torture_assert(test_context->tctx,
+ found,
+ "Calculated enctype not in allowed list");
+ }
+
+ reply_enctype = test_context->as_rep.enc_part.etype;
torture_assert_int_equal(test_context->tctx,
reply_enctype, expected_enctype,
"Ticket encrypted with invalid algorithm");
@@ -310,7 +387,7 @@
if (test_context->packet_count == 0) {
ok = torture_check_krb5_error(test_context,
recv_buf,
- KRB5KRB_ERR_RESPONSE_TOO_BIG,
+ KRB5KDC_ERR_PREAUTH_REQUIRED,
false);
torture_assert(test_context->tctx,
ok,
@@ -318,7 +395,7 @@
} else if (test_context->packet_count == 1) {
ok = torture_check_krb5_error(test_context,
recv_buf,
- KRB5KDC_ERR_PREAUTH_REQUIRED,
+ KRB5KRB_ERR_RESPONSE_TOO_BIG,
false);
torture_assert(test_context->tctx,
ok,
@@ -411,9 +488,13 @@
ok,
"torture_check_krb5_error failed");
} else {
+ const krb5_enctype allowed_enctypes[] = {
+ KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ ETYPE_NULL
+ };
ok = torture_check_krb5_as_rep_enctype(test_context,
recv_buf,
- KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96);
+ allowed_enctypes);
torture_assert(test_context->tctx,
ok,
"torture_check_krb5_as_rep_enctype failed");
@@ -443,9 +524,13 @@
ok,
"torture_check_krb5_error failed");
} else {
+ const krb5_enctype allowed_enctypes[] = {
+ KRB5_ENCTYPE_ARCFOUR_HMAC_MD5,
+ ETYPE_NULL
+ };
ok = torture_check_krb5_as_rep_enctype(test_context,
recv_buf,
- KRB5_ENCTYPE_ARCFOUR_HMAC_MD5);
+ allowed_enctypes);
torture_assert(test_context->tctx,
ok,
"torture_check_krb5_as_rep_enctype failed");
@@ -475,9 +560,14 @@
ok,
"torture_check_krb5_error failed");
} else {
+ const krb5_enctype allowed_enctypes[] = {
+ KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ KRB5_ENCTYPE_ARCFOUR_HMAC_MD5,
+ ETYPE_NULL
+ };
ok = torture_check_krb5_as_rep_enctype(test_context,
recv_buf,
- KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96);
+ allowed_enctypes);
torture_assert(test_context->tctx,
ok,
"torture_check_krb5_as_rep_enctype failed");
diff -Nru samba-4.13.3+dfsg/source4/torture/rpc/drsuapi.c samba-4.13.14+dfsg/source4/torture/rpc/drsuapi.c
--- samba-4.13.3+dfsg/source4/torture/rpc/drsuapi.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/rpc/drsuapi.c 2021-11-08 11:29:14.000000000 +0000
@@ -22,18 +22,22 @@
*/
#include "includes.h"
+#include "lib/cmdline/popt_common.h"
#include "librpc/gen_ndr/ndr_drsuapi_c.h"
#include "torture/rpc/torture_rpc.h"
+#include "libcli/security/dom_sid.h"
#include "param/param.h"
#define TEST_MACHINE_NAME "torturetest"
-bool test_DsBind(struct dcerpc_pipe *p,
- struct torture_context *tctx,
- struct DsPrivate *priv)
+static bool test_DsBind(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *bind_handle,
+ struct drsuapi_DsBindInfo28 *srv_info28)
{
NTSTATUS status;
struct drsuapi_DsBind r;
+ struct GUID bind_guid;
struct drsuapi_DsBindInfo28 *bind_info28;
struct drsuapi_DsBindInfoCtr bind_info_ctr;
@@ -70,19 +74,20 @@
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7;
bind_info28->supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT;
- GUID_from_string(DRSUAPI_DS_BIND_GUID, &priv->bind_guid);
+ GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);
- r.in.bind_guid = &priv->bind_guid;
+ r.in.bind_guid = &bind_guid;
r.in.bind_info = &bind_info_ctr;
- r.out.bind_handle = &priv->bind_handle;
+ r.out.bind_handle = bind_handle;
torture_comment(tctx, "Testing DsBind\n");
status = dcerpc_drsuapi_DsBind_r(p->binding_handle, tctx, &r);
torture_drsuapi_assert_call(tctx, p, status, &r, "dcerpc_drsuapi_DsBind");
- /* cache server supported extensions, i.e. bind_info */
- priv->srv_bind_info = r.out.bind_info->info.info28;
+ if (srv_info28 != NULL) {
+ *srv_info28 = r.out.bind_info->info.info28;
+ }
return true;
}
@@ -771,10 +776,11 @@
NTSTATUS status;
int rnd = rand() % 1000;
char *name = talloc_asprintf(tctx, "%s%d", TEST_MACHINE_NAME, rnd);
- struct cli_credentials *machine_credentials;
torture_assert(tctx, priv, "Invalid argument");
+ priv->admin_credentials = popt_get_cmdline_credentials();
+
torture_comment(tctx, "Create DRSUAPI pipe\n");
status = torture_rpc_connection(tctx,
&priv->drs_pipe,
@@ -783,10 +789,13 @@
torture_comment(tctx, "About to join domain with name %s\n", name);
priv->join = torture_join_domain(tctx, name, ACB_SVRTRUST,
- &machine_credentials);
+ &priv->dc_credentials);
torture_assert(tctx, priv->join, "Failed to join as BDC");
- if (!test_DsBind(priv->drs_pipe, tctx, priv)) {
+ if (!test_DsBind(priv->drs_pipe, tctx,
+ &priv->bind_handle,
+ &priv->srv_bind_info))
+ {
/* clean up */
torture_drsuapi_tcase_teardown_common(tctx, priv);
torture_fail(tctx, "Failed execute test_DsBind()");
@@ -837,6 +846,173 @@
return ret;
}
+static bool __test_DsBind_assoc_group(struct torture_context *tctx,
+ const char *testname,
+ struct DsPrivate *priv,
+ struct cli_credentials *creds)
+{
+ NTSTATUS status;
+ const char *err_msg;
+ struct drsuapi_DsCrackNames r;
+ union drsuapi_DsNameRequest req;
+ uint32_t level_out;
+ union drsuapi_DsNameCtr ctr;
+ struct drsuapi_DsNameString names[1];
+ const char *dom_sid = NULL;
+ struct dcerpc_pipe *p1 = NULL;
+ struct dcerpc_pipe *p2 = NULL;
+ TALLOC_CTX *mem_ctx = priv;
+ struct dcerpc_binding *binding = NULL;
+ struct policy_handle ds_bind_handle = { .handle_type = 0, };
+
+ torture_comment(tctx, "%s: starting...\n", testname);
+
+ torture_assert_ntstatus_ok(tctx,
+ torture_rpc_binding(tctx, &binding),
+ "torture_rpc_binding");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx,
+ &p1,
+ binding,
+ &ndr_table_drsuapi,
+ creds,
+ tctx->ev,
+ tctx->lp_ctx),
+ "connect p1");
+
+ torture_assert_ntstatus_ok(tctx,
+ dcerpc_pipe_connect_b(tctx,
+ &p2,
+ p1->binding,
+ &ndr_table_drsuapi,
+ creds,
+ tctx->ev,
+ tctx->lp_ctx),
+ "connect p2");
+
+ torture_assert(tctx, test_DsBind(p1, tctx, &ds_bind_handle, NULL), "DsBind");
+
+ ZERO_STRUCT(r);
+ r.in.bind_handle = &ds_bind_handle;
+ r.in.level = 1;
+ r.in.req = &req;
+ r.in.req->req1.codepage = 1252; /* german */
+ r.in.req->req1.language = 0x00000407; /* german */
+ r.in.req->req1.count = 1;
+ r.in.req->req1.names = names;
+ r.in.req->req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
+
+ r.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
+ r.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
+
+ r.out.level_out = &level_out;
+ r.out.ctr = &ctr;
+
+ dom_sid = dom_sid_string(mem_ctx, torture_join_sid(priv->join));
+
+ names[0].str = dom_sid;
+
+ torture_comment(tctx, "Testing DsCrackNames on p1 with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+ status = dcerpc_drsuapi_DsCrackNames_r(p1->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ torture_comment(tctx, "Testing DsCrackNames on p2 with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+ status = dcerpc_drsuapi_DsCrackNames_r(p2->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ TALLOC_FREE(p1);
+
+ torture_comment(tctx, "Testing DsCrackNames on p2 (with p1 closed) with name '%s'"
+ " offered format: %d desired format:%d\n",
+ names[0].str,
+ r.in.req->req1.format_offered,
+ r.in.req->req1.format_desired);
+ status = dcerpc_drsuapi_DsCrackNames_r(p2->binding_handle, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *errstr = nt_errstr(status);
+ err_msg = talloc_asprintf(mem_ctx, "dcerpc_drsuapi_DsCrackNames failed - %s", errstr);
+ torture_fail(tctx, err_msg);
+ } else if (!W_ERROR_IS_OK(r.out.result)) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed - %s", win_errstr(r.out.result));
+ torture_fail(tctx, err_msg);
+ } else if (r.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+ err_msg = talloc_asprintf(mem_ctx, "DsCrackNames failed on name - %d",
+ r.out.ctr->ctr1->array[0].status);
+ torture_fail(tctx, err_msg);
+ }
+
+ torture_comment(tctx, "%s: ... finished\n", testname);
+ return true;
+}
+
+static bool test_DsBindAssocGroupAdmin(struct torture_context *tctx,
+ struct DsPrivate *priv,
+ struct cli_credentials *creds)
+{
+ return __test_DsBind_assoc_group(tctx, __func__, priv,
+ priv->admin_credentials);
+}
+
+static bool test_DsBindAssocGroupDC(struct torture_context *tctx,
+ struct DsPrivate *priv,
+ struct cli_credentials *creds)
+{
+ return __test_DsBind_assoc_group(tctx, __func__, priv,
+ priv->dc_credentials);
+}
+
+static bool test_DsBindAssocGroupWS(struct torture_context *tctx,
+ struct DsPrivate *priv,
+ struct cli_credentials *creds)
+{
+ struct test_join *wks_join = NULL;
+ struct cli_credentials *wks_credentials = NULL;
+ int rnd = rand() % 1000;
+ char *wks_name = talloc_asprintf(tctx, "WKS%s%d", TEST_MACHINE_NAME, rnd);
+ bool ret;
+
+ torture_comment(tctx, "%s: About to join workstation with name %s\n",
+ __func__, wks_name);
+ wks_join = torture_join_domain(tctx, wks_name, ACB_WSTRUST,
+ &wks_credentials);
+ torture_assert(tctx, wks_join, "Failed to join as WORKSTATION");
+ ret = __test_DsBind_assoc_group(tctx, __func__, priv,
+ wks_credentials);
+ torture_leave_domain(tctx, wks_join);
+ return ret;
+}
+
/**
* DRSUAPI test case implementation
*/
@@ -866,4 +1042,8 @@
torture_tcase_add_simple_test(tcase, "DsReplicaUpdateRefs", (run_func)test_DsReplicaUpdateRefs);
torture_tcase_add_simple_test(tcase, "DsGetNCChanges", (run_func)test_DsGetNCChanges);
+
+ torture_tcase_add_simple_test(tcase, "DsBindAssocGroupAdmin", (run_func)test_DsBindAssocGroupAdmin);
+ torture_tcase_add_simple_test(tcase, "DsBindAssocGroupDC", (run_func)test_DsBindAssocGroupDC);
+ torture_tcase_add_simple_test(tcase, "DsBindAssocGroupWS", (run_func)test_DsBindAssocGroupWS);
}
diff -Nru samba-4.13.3+dfsg/source4/torture/rpc/drsuapi_cracknames.c samba-4.13.14+dfsg/source4/torture/rpc/drsuapi_cracknames.c
--- samba-4.13.3+dfsg/source4/torture/rpc/drsuapi_cracknames.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/rpc/drsuapi_cracknames.c 2021-11-08 11:29:14.000000000 +0000
@@ -801,7 +801,7 @@
.format_offered = DRSUAPI_DS_NAME_FORMAT_GUID,
.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
.comment = "BIND GUID (ie, not in the directory)",
- .str = GUID_string2(mem_ctx, &priv->bind_guid),
+ .str = DRSUAPI_DS_BIND_GUID,
.status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND
},
{
diff -Nru samba-4.13.3+dfsg/source4/torture/rpc/drsuapi.h samba-4.13.14+dfsg/source4/torture/rpc/drsuapi.h
--- samba-4.13.3+dfsg/source4/torture/rpc/drsuapi.h 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/rpc/drsuapi.h 2021-11-08 11:29:14.000000000 +0000
@@ -27,9 +27,9 @@
* Data structure common for most of DRSUAPI tests
*/
struct DsPrivate {
+ struct cli_credentials *admin_credentials;
struct dcerpc_pipe *drs_pipe;
struct policy_handle bind_handle;
- struct GUID bind_guid;
struct drsuapi_DsBindInfo28 srv_bind_info;
const char *domain_obj_dn;
@@ -38,6 +38,7 @@
struct GUID domain_guid;
struct drsuapi_DsGetDCInfo2 dcinfo;
struct test_join *join;
+ struct cli_credentials *dc_credentials;
};
/**
diff -Nru samba-4.13.3+dfsg/source4/torture/rpc/remote_pac.c samba-4.13.14+dfsg/source4/torture/rpc/remote_pac.c
--- samba-4.13.3+dfsg/source4/torture/rpc/remote_pac.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/rpc/remote_pac.c 2021-11-08 11:29:14.000000000 +0000
@@ -266,7 +266,7 @@
(ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed");
- num_pac_buffers = 4;
+ num_pac_buffers = 7;
if (expect_pac_upn_dns_info) {
num_pac_buffers += 1;
}
@@ -317,6 +317,24 @@
pac_buf->info != NULL,
"PAC_TYPE_KDC_CHECKSUM info");
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_TICKET_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_TICKET_CHECKSUM");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_TICKET_CHECKSUM info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_ATTRIBUTES_INFO);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_ATTRIBUTES_INFO");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_ATTRIBUTES_INFO info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_REQUESTER_SID);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_REQUESTER_SID");
+ torture_assert(tctx,
+ pac_buf->info != NULL,
+ "PAC_TYPE_REQUESTER_SID info");
+
ok = netlogon_validate_pac(tctx, p, server_creds, secure_channel_type, test_machine_name,
negotiate_flags, pac_data, session_info);
@@ -1076,7 +1094,7 @@
(ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
torture_assert(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), "ndr_pull_struct_blob of PAC_DATA structure failed");
- num_pac_buffers = 6;
+ num_pac_buffers = 9;
torture_assert_int_equal(tctx, pac_data_struct.version, 0, "version");
torture_assert_int_equal(tctx, pac_data_struct.num_buffers, num_pac_buffers, "num_buffers");
@@ -1101,6 +1119,10 @@
torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_KDC_CHECKSUM");
torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_KDC_CHECKSUM info");
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_TICKET_CHECKSUM);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_TICKET_CHECKSUM");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_TICKET_CHECKSUM info");
+
pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_CONSTRAINED_DELEGATION);
torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_CONSTRAINED_DELEGATION");
torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_CONSTRAINED_DELEGATION info");
@@ -1112,6 +1134,14 @@
talloc_asprintf(tctx, "%s@%s", self_princ, cli_credentials_get_realm(credentials)),
"wrong transited_services[0]");
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_ATTRIBUTES_INFO);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_ATTRIBUTES_INFO");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_ATTRIBUTES_INFO info");
+
+ pac_buf = get_pac_buffer(&pac_data_struct, PAC_TYPE_REQUESTER_SID);
+ torture_assert_not_null(tctx, pac_buf, "PAC_TYPE_REQUESTER_SID");
+ torture_assert_not_null(tctx, pac_buf->info, "PAC_TYPE_REQUESTER_SID info");
+
return netlogon_validate_pac(tctx, p, server_creds, secure_channel_type, test_machine_name,
negotiate_flags, pac_data, session_info);
}
diff -Nru samba-4.13.3+dfsg/source4/torture/rpc/samlogon.c samba-4.13.14+dfsg/source4/torture/rpc/samlogon.c
--- samba-4.13.3+dfsg/source4/torture/rpc/samlogon.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/rpc/samlogon.c 2021-11-08 11:29:14.000000000 +0000
@@ -1407,7 +1407,7 @@
union netr_LogonLevel logon;
union netr_Validation validation;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uint32_t flags = 0;
ZERO_STRUCT(logon);
@@ -1520,7 +1520,7 @@
union netr_LogonLevel logon;
union netr_Validation validation;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
struct dcerpc_binding_handle *b = p->binding_handle;
ZERO_STRUCT(a);
diff -Nru samba-4.13.3+dfsg/source4/torture/rpc/schannel.c samba-4.13.14+dfsg/source4/torture/rpc/schannel.c
--- samba-4.13.3+dfsg/source4/torture/rpc/schannel.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/rpc/schannel.c 2021-11-08 11:29:14.000000000 +0000
@@ -50,7 +50,7 @@
struct netr_NetworkInfo ninfo;
union netr_LogonLevel logon;
union netr_Validation validation;
- uint8_t authoritative = 0;
+ uint8_t authoritative = 1;
uint32_t _flags = 0;
DATA_BLOB names_blob, chal, lm_resp, nt_resp;
int i;
diff -Nru samba-4.13.3+dfsg/source4/torture/smb2/create.c samba-4.13.14+dfsg/source4/torture/smb2/create.c
--- samba-4.13.3+dfsg/source4/torture/smb2/create.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/smb2/create.c 2021-09-07 07:01:16.000000000 +0000
@@ -2708,6 +2708,68 @@
}
/*
+ test opening quota fakefile handle and returned attributes
+*/
+static bool test_smb2_open_quota_fake_file(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *fname = "$Extend\\$Quota:$Q:$INDEX_ALLOCATION";
+ struct smb2_create create;
+ struct smb2_handle h = {{0}};
+ NTSTATUS status;
+ bool ret = true;
+
+ create = (struct smb2_create) {
+ .in.desired_access = SEC_RIGHTS_FILE_READ,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN,
+ .in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS,
+ .in.fname = fname,
+ };
+
+ status = smb2_create(tree, tree, &create);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ h = create.out.file.handle;
+
+ torture_assert_u64_equal_goto(tctx,
+ create.out.file_attr,
+ FILE_ATTRIBUTE_HIDDEN
+ | FILE_ATTRIBUTE_SYSTEM
+ | FILE_ATTRIBUTE_DIRECTORY
+ | FILE_ATTRIBUTE_ARCHIVE,
+ ret,
+ done,
+ "Wrong attributes\n");
+
+ torture_assert_u64_equal_goto(tctx,
+ create.out.create_time, 0,
+ ret,
+ done,
+ "create_time is not 0\n");
+ torture_assert_u64_equal_goto(tctx,
+ create.out.access_time, 0,
+ ret,
+ done,
+ "access_time is not 0\n");
+ torture_assert_u64_equal_goto(tctx,
+ create.out.write_time, 0,
+ ret,
+ done,
+ "write_time is not 0\n");
+ torture_assert_u64_equal_goto(tctx,
+ create.out.change_time, 0,
+ ret,
+ done,
+ "change_time is not 0\n");
+
+done:
+ smb2_util_close(tree, h);
+ return ret;
+}
+
+/*
basic testing of SMB2 read
*/
struct torture_suite *torture_smb2_create_init(TALLOC_CTX *ctx)
@@ -2727,6 +2789,7 @@
torture_suite_add_1smb2_test(suite, "nulldacl", test_create_null_dacl);
torture_suite_add_1smb2_test(suite, "mkdir-dup", test_mkdir_dup);
torture_suite_add_1smb2_test(suite, "dir-alloc-size", test_dir_alloc_size);
+ torture_suite_add_1smb2_test(suite, "quota-fake-file", test_smb2_open_quota_fake_file);
suite->description = talloc_strdup(suite, "SMB2-CREATE tests");
diff -Nru samba-4.13.3+dfsg/source4/torture/smb2/ioctl.c samba-4.13.14+dfsg/source4/torture/smb2/ioctl.c
--- samba-4.13.3+dfsg/source4/torture/smb2/ioctl.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/smb2/ioctl.c 2021-08-06 12:19:57.000000000 +0000
@@ -6795,6 +6795,57 @@
}
/*
+ basic regression test for BUG 14607
+ https://bugzilla.samba.org/show_bug.cgi?id=14607
+*/
+static bool test_ioctl_bug14607(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ uint32_t timeout_msec;
+ NTSTATUS status;
+ DATA_BLOB out_input_buffer = data_blob_null;
+ DATA_BLOB out_output_buffer = data_blob_null;
+
+ timeout_msec = tree->session->transport->options.request_timeout * 1000;
+
+ status = smb2cli_ioctl(tree->session->transport->conn,
+ timeout_msec,
+ tree->session->smbXcli,
+ tree->smbXcli,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ 1, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ tmp_ctx,
+ &out_input_buffer,
+ &out_output_buffer);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_FS_DRIVER_REQUIRED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST))
+ {
+ torture_comment(torture,
+ "FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8: %s\n",
+ nt_errstr(status));
+ torture_skip(torture, "server doesn't support FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8\n");
+ }
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8");
+
+ torture_assert_int_equal(torture, out_output_buffer.length, 1,
+ "output length");
+ torture_assert_int_equal(torture, out_output_buffer.data[0], 8,
+ "output buffer byte should be 8");
+
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
* testing of SMB2 ioctls
*/
struct torture_suite *torture_smb2_ioctl_init(TALLOC_CTX *ctx)
@@ -6939,6 +6990,8 @@
test_ioctl_dup_extents_src_lck);
torture_suite_add_1smb2_test(suite, "dup_extents_dest_lock",
test_ioctl_dup_extents_dest_lck);
+ torture_suite_add_1smb2_test(suite, "bug14607",
+ test_ioctl_bug14607);
suite->description = talloc_strdup(suite, "SMB2-IOCTL tests");
diff -Nru samba-4.13.3+dfsg/source4/torture/smb2/lease.c samba-4.13.14+dfsg/source4/torture/smb2/lease.c
--- samba-4.13.3+dfsg/source4/torture/smb2/lease.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/smb2/lease.c 2021-08-09 07:17:53.000000000 +0000
@@ -3722,6 +3722,148 @@
return ret;
}
+static bool test_lease_rename_wait(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(tctx);
+ struct smb2_create io;
+ struct smb2_lease ls1;
+ struct smb2_lease ls2;
+ struct smb2_lease ls3;
+ struct smb2_handle h1 = {{0}};
+ struct smb2_handle h2 = {{0}};
+ struct smb2_handle h3 = {{0}};
+ union smb_setfileinfo sinfo;
+ NTSTATUS status;
+ const char *fname_src = "lease_rename_src.dat";
+ const char *fname_dst = "lease_rename_dst.dat";
+ bool ret = true;
+ struct smb2_lease_break_ack ack = {};
+ struct smb2_request *rename_req = NULL;
+ uint32_t caps;
+ unsigned int i;
+
+ caps = smb2cli_conn_server_capabilities(tree->session->transport->conn);
+ if (!(caps & SMB2_CAP_LEASING)) {
+ torture_skip(tctx, "leases are not supported");
+ }
+
+ smb2_util_unlink(tree, fname_src);
+ smb2_util_unlink(tree, fname_dst);
+
+ /* Short timeout for fails. */
+ tree->session->transport->options.request_timeout = 15;
+
+ /* Grab a RH lease. */
+ smb2_lease_create(&io,
+ &ls1,
+ false,
+ fname_src,
+ LEASE1,
+ smb2_util_lease_state("RH"));
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RH", true, LEASE1, 0);
+ h1 = io.out.file.handle;
+
+ /* Second open with a RH lease. */
+ smb2_lease_create(&io,
+ &ls2,
+ false,
+ fname_src,
+ LEASE2,
+ smb2_util_lease_state("RH"));
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.desired_access = GENERIC_READ_ACCESS;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+ CHECK_LEASE(&io, "RH", true, LEASE2, 0);
+ h2 = io.out.file.handle;
+
+ /*
+ * Don't ack a lease break.
+ */
+ tree->session->transport->lease.handler = torture_lease_handler;
+ tree->session->transport->lease.private_data = tree;
+ torture_reset_lease_break_info(tctx, &lease_break_info);
+ lease_break_info.lease_skip_ack = true;
+
+ /* Break with a rename. */
+ ZERO_STRUCT(sinfo);
+ sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
+ sinfo.rename_information.in.file.handle = h1;
+ sinfo.rename_information.in.overwrite = true;
+ sinfo.rename_information.in.new_name = fname_dst;
+ rename_req = smb2_setinfo_file_send(tree, &sinfo);
+
+ torture_assert(tctx,
+ rename_req != NULL,
+ "smb2_setinfo_file_send");
+ torture_assert(tctx,
+ rename_req->state == SMB2_REQUEST_RECV,
+ "rename pending");
+
+ /* Try and open the destination with a RH lease. */
+ smb2_lease_create(&io,
+ &ls3,
+ false,
+ fname_dst,
+ LEASE3,
+ smb2_util_lease_state("RH"));
+ /* We want to open, not create. */
+ io.in.create_disposition = NTCREATEX_DISP_OPEN;
+ io.in.desired_access = GENERIC_READ_ACCESS;
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+
+ /*
+ * The smb2_create() I/O should have picked up the break request
+ * caused by the pending rename.
+ */
+
+ /* Copy the break request. */
+ ack.in.lease.lease_key =
+ lease_break_info.lease_break.current_lease.lease_key;
+ ack.in.lease.lease_state =
+ lease_break_info.lease_break.new_lease_state;
+
+ /*
+ * Give the server 3 more chances to have renamed
+ * the file. Better than doing a sleep.
+ */
+ for (i = 0; i < 3; i++) {
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ }
+
+ /* Ack the break. The server is now free to rename. */
+ status = smb2_lease_break_ack(tree, &ack);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* Get the rename reply. */
+ status = smb2_setinfo_recv(rename_req);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ /* The target should now exist. */
+ status = smb2_create(tree, mem_ctx, &io);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ h3 = io.out.file.handle;
+
+ done:
+ smb2_util_close(tree, h1);
+ smb2_util_close(tree, h2);
+ smb2_util_close(tree, h3);
+
+ smb2_util_unlink(tree, fname_src);
+ smb2_util_unlink(tree, fname_dst);
+
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
static bool test_lease_v2_rename(struct torture_context *tctx,
struct smb2_tree *tree)
{
@@ -4192,6 +4334,9 @@
torture_suite_add_1smb2_test(suite, "dynamic_share", test_lease_dynamic_share);
torture_suite_add_1smb2_test(suite, "timeout", test_lease_timeout);
torture_suite_add_1smb2_test(suite, "unlink", test_lease_unlink);
+ torture_suite_add_1smb2_test(suite, "rename_wait",
+ test_lease_rename_wait);
+
suite->description = talloc_strdup(suite, "SMB2-LEASE tests");
diff -Nru samba-4.13.3+dfsg/source4/torture/smb2/read.c samba-4.13.14+dfsg/source4/torture/smb2/read.c
--- samba-4.13.3+dfsg/source4/torture/smb2/read.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/smb2/read.c 2021-09-07 07:01:16.000000000 +0000
@@ -26,6 +26,8 @@
#include "torture/torture.h"
#include "torture/smb2/proto.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "librpc/gen_ndr/ndr_ioctl.h"
#define CHECK_STATUS(_status, _expected) \
@@ -303,6 +305,138 @@
return ret;
}
+/*
+ basic regression test for BUG 14607
+ https://bugzilla.samba.org/show_bug.cgi?id=14607
+*/
+static bool test_read_bug14607(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct smb2_handle h;
+ uint8_t buf[64 * 1024];
+ struct smb2_read rd;
+ uint32_t timeout_msec;
+ DATA_BLOB out_input_buffer = data_blob_null;
+ DATA_BLOB out_output_buffer = data_blob_null;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ uint8_t *data = NULL;
+ uint32_t data_length = 0;
+
+ memset(buf, 0x1f, ARRAY_SIZE(buf));
+
+ /* create a file */
+ smb2_util_unlink(tree, FNAME);
+
+ status = torture_smb2_testfile(tree, FNAME, &h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = ARRAY_SIZE(buf);
+ rd.in.offset = 0;
+ status = smb2_read(tree, tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.out.data.length, ARRAY_SIZE(buf));
+ torture_assert_mem_equal_goto(torture, rd.out.data.data,
+ buf, ARRAY_SIZE(buf),
+ ret, done,
+ "Invalid content smb2_read");
+
+ timeout_msec = tree->session->transport->options.request_timeout * 1000;
+
+ status = smb2cli_read(tree->session->transport->conn,
+ timeout_msec,
+ tree->session->smbXcli,
+ tree->smbXcli,
+ rd.in.length,
+ rd.in.offset,
+ h.data[0],
+ h.data[1],
+ rd.in.min_count,
+ rd.in.remaining,
+ tmp_ctx,
+ &data, &data_length);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(data_length, ARRAY_SIZE(buf));
+ torture_assert_mem_equal_goto(torture, data,
+ buf, ARRAY_SIZE(buf),
+ ret, done,
+ "Invalid content smb2cli_read");
+
+ status = smb2cli_ioctl(tree->session->transport->conn,
+ timeout_msec,
+ tree->session->smbXcli,
+ tree->smbXcli,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ 1, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL,
+ tmp_ctx,
+ &out_input_buffer,
+ &out_output_buffer);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_FS_DRIVER_REQUIRED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST))
+ {
+ torture_comment(torture,
+ "FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8: %s\n",
+ nt_errstr(status));
+ torture_skip(torture, "server doesn't support FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8\n");
+ }
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8");
+
+ torture_assert_int_equal(torture, out_output_buffer.length, 0,
+ "output length");
+
+ ZERO_STRUCT(rd);
+ rd.in.file.handle = h;
+ rd.in.length = ARRAY_SIZE(buf);
+ rd.in.offset = 0;
+ status = smb2_read(tree, tree, &rd);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(rd.out.data.length, ARRAY_SIZE(buf));
+ torture_assert_mem_equal_goto(torture, rd.out.data.data,
+ buf, ARRAY_SIZE(buf),
+ ret, done,
+ "Invalid content after padding smb2_read");
+
+ status = smb2cli_read(tree->session->transport->conn,
+ timeout_msec,
+ tree->session->smbXcli,
+ tree->smbXcli,
+ rd.in.length,
+ rd.in.offset,
+ h.data[0],
+ h.data[1],
+ rd.in.min_count,
+ rd.in.remaining,
+ tmp_ctx,
+ &data, &data_length);
+ CHECK_STATUS(status, NT_STATUS_OK);
+ CHECK_VALUE(data_length, ARRAY_SIZE(buf));
+ torture_assert_mem_equal_goto(torture, data,
+ buf, ARRAY_SIZE(buf),
+ ret, done,
+ "Invalid content after padding smb2cli_read");
+
+ status = smb2_util_close(tree, h);
+ CHECK_STATUS(status, NT_STATUS_OK);
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
/*
basic testing of SMB2 read
*/
@@ -314,6 +448,8 @@
torture_suite_add_1smb2_test(suite, "position", test_read_position);
torture_suite_add_1smb2_test(suite, "dir", test_read_dir);
torture_suite_add_1smb2_test(suite, "access", test_read_access);
+ torture_suite_add_1smb2_test(suite, "bug14607",
+ test_read_bug14607);
suite->description = talloc_strdup(suite, "SMB2-READ tests");
diff -Nru samba-4.13.3+dfsg/source4/torture/smb2/timestamps.c samba-4.13.14+dfsg/source4/torture/smb2/timestamps.c
--- samba-4.13.3+dfsg/source4/torture/smb2/timestamps.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/source4/torture/smb2/timestamps.c 2021-08-06 12:19:57.000000000 +0000
@@ -29,6 +29,70 @@
#define BASEDIR "smb2-timestamps"
#define FNAME "testfile.dat"
+static bool test_close_no_attrib(struct torture_context *tctx,
+ struct smb2_tree *tree)
+{
+ const char *filename = BASEDIR "/" FNAME;
+ struct smb2_create cr;
+ struct smb2_handle handle = {{0}};
+ struct smb2_handle testdirh = {{0}};
+ struct smb2_close c;
+ NTSTATUS status;
+ bool ret = true;
+
+ smb2_deltree(tree, BASEDIR);
+
+ status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "torture_smb2_testdir failed\n");
+ smb2_util_close(tree, testdirh);
+
+ cr = (struct smb2_create) {
+ .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
+ .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+ .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
+ .in.fname = filename,
+ };
+
+ status = smb2_create(tree, tctx, &cr);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "smb2_create failed\n");
+ handle = cr.out.file.handle;
+
+ c = (struct smb2_close) {
+ .in.file.handle = handle,
+ };
+
+ status = smb2_close(tree, &c);
+ torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+ "close failed\n");
+ ZERO_STRUCT(handle);
+
+ torture_assert_u64_equal_goto(tctx, c.out.create_time, NTTIME_OMIT,
+ ret, done, "Unexpected create time\n");
+ torture_assert_u64_equal_goto(tctx, c.out.access_time, NTTIME_OMIT,
+ ret, done, "Unexpected access time\n");
+ torture_assert_u64_equal_goto(tctx, c.out.write_time, NTTIME_OMIT,
+ ret, done, "Unexpected write time\n");
+ torture_assert_u64_equal_goto(tctx, c.out.change_time, NTTIME_OMIT,
+ ret, done, "Unexpected change time\n");
+ torture_assert_u64_equal_goto(tctx, c.out.alloc_size, 0,
+ ret, done, "Unexpected allocation size\n");
+ torture_assert_u64_equal_goto(tctx, c.out.size, 0,
+ ret, done, "Unexpected size\n");
+ torture_assert_u64_equal_goto(tctx, c.out.file_attr, 0,
+ ret, done, "Unexpected attributes\n");
+
+done:
+ if (!smb2_util_handle_empty(handle)) {
+ smb2_util_close(tree, handle);
+ }
+ smb2_deltree(tree, BASEDIR);
+ return ret;
+}
+
static bool test_time_t(struct torture_context *tctx,
struct smb2_tree *tree,
const char *fname,
@@ -907,6 +971,7 @@
{
struct torture_suite *suite = torture_suite_create(ctx, "timestamps");
+ torture_suite_add_1smb2_test(suite, "test_close_not_attrib", test_close_no_attrib);
torture_suite_add_1smb2_test(suite, "time_t_15032385535", test_time_t_15032385535);
torture_suite_add_1smb2_test(suite, "time_t_10000000000", test_time_t_10000000000);
torture_suite_add_1smb2_test(suite, "time_t_4294967295", test_time_t_4294967295);
diff -Nru samba-4.13.3+dfsg/testprogs/blackbox/dbcheck-links.sh samba-4.13.14+dfsg/testprogs/blackbox/dbcheck-links.sh
--- samba-4.13.3+dfsg/testprogs/blackbox/dbcheck-links.sh 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/testprogs/blackbox/dbcheck-links.sh 2021-08-09 07:17:53.000000000 +0000
@@ -42,7 +42,7 @@
if [ "$?" != "$2" ]; then
return 1
fi
- sort $tmpfile > $tmpfile.sorted
+ sort $tmpfile | grep -v "^INFO:" > $tmpfile.sorted
sort $release_dir/expected-dbcheck-link-output${1}.txt > $tmpfile.expected
diff -u $tmpfile.sorted $tmpfile.expected
if [ "$?" != "0" ]; then
diff -Nru samba-4.13.3+dfsg/testprogs/blackbox/dbcheck-oldrelease.sh samba-4.13.14+dfsg/testprogs/blackbox/dbcheck-oldrelease.sh
--- samba-4.13.3+dfsg/testprogs/blackbox/dbcheck-oldrelease.sh 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/testprogs/blackbox/dbcheck-oldrelease.sh 2021-11-08 11:29:14.000000000 +0000
@@ -297,6 +297,17 @@
fi
}
+# This should 'fail', because it returns the number of wrong records, which it must if we did not skip the deleted objects
+dbcheck_deleted_objects() {
+ if [ x$RELEASE = x"alpha13" ]; then
+ basedn=$($ldbsearch -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb -s base -b "" defaultNamingContext| grep -i defaultNamingContext| cut -d\ -f 2)
+
+ $PYTHON $BINDIR/samba-tool dbcheck -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb "cn=deleted objects,$basedn" --scope base $@
+ else
+ return 1
+ fi
+}
+
# This should 'fail', because it returns the number of modified records
dbcheck() {
$PYTHON $BINDIR/samba-tool dbcheck --selftest-check-expired-tombstones --cross-ncs --fix --yes -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb $@
@@ -472,13 +483,13 @@
ldapcmp() {
if [ x$RELEASE = x"release-4-0-0" ]; then
- $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX_ABS/${RELEASE}_reference/private/sam.ldb tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --two --skip-missing-dn --filter=dnsRecord,displayName,msDS-SupportedEncryptionTypes
+ $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX_ABS/${RELEASE}_reference/private/sam.ldb tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --two --skip-missing-dn --filter=dnsRecord,displayName,msDS-SupportedEncryptionTypes,servicePrincipalName
fi
}
ldapcmp_sd() {
if [ x$RELEASE = x"release-4-0-0" ]; then
- $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX_ABS/${RELEASE}_reference/private/sam.ldb tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --two --sd --skip-missing-dn
+ $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX_ABS/${RELEASE}_reference/private/sam.ldb tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --two --sd --skip-missing-dn --filter=servicePrincipalName
fi
}
@@ -488,6 +499,7 @@
testit "reindex" reindex || failed=`expr $failed + 1`
testit "current_version_mod" do_current_version_mod || failed=`expr $failed + 1`
testit "check_expected_before_values" check_expected_before_values || failed=`expr $failed + 1`
+testit_expect_failure "dbcheck_deleted_objects" dbcheck_deleted_objects || failed=`expr $failed + 1`
testit_expect_failure "dbcheck_objectclass" dbcheck_objectclass || failed=`expr $failed + 1`
testit_expect_failure "dbcheck" dbcheck || failed=`expr $failed + 1`
testit "check_expected_after_values" check_expected_after_values || failed=`expr $failed + 1`
diff -Nru samba-4.13.3+dfsg/testprogs/blackbox/dbcheck.sh samba-4.13.14+dfsg/testprogs/blackbox/dbcheck.sh
--- samba-4.13.3+dfsg/testprogs/blackbox/dbcheck.sh 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/testprogs/blackbox/dbcheck.sh 2021-10-29 06:17:36.000000000 +0000
@@ -24,7 +24,7 @@
# This list of attributes can be freely extended
dbcheck_fix_stale_links() {
- $PYTHON $BINDIR/samba-tool dbcheck --quiet --fix --yes remove_plausible_deleted_DN_links --attrs="member msDS-NC-Replica-Locations msDS-NC-RO-Replica-Locations" --cross-ncs $ARGS
+ $PYTHON $BINDIR/samba-tool dbcheck --quiet --fix --yes remove_plausible_deleted_DN_links --attrs="member msDS-NC-Replica-Locations msDS-NC-RO-Replica-Locations msDS-RevealOnDemandGroup msDS-NeverRevealGroup" --cross-ncs $ARGS
}
# This list of attributes can be freely extended
diff -Nru samba-4.13.3+dfsg/testprogs/blackbox/functionalprep.sh samba-4.13.14+dfsg/testprogs/blackbox/functionalprep.sh
--- samba-4.13.3+dfsg/testprogs/blackbox/functionalprep.sh 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/testprogs/blackbox/functionalprep.sh 2021-11-08 11:29:14.000000000 +0000
@@ -72,7 +72,7 @@
ldapcmp_ignore() {
# At some point we will need to ignore, but right now, it should be perfect
IGNORE_ATTRS=$1
- $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX_ABS/$2/private/sam.ldb tdb://$PREFIX_ABS/$3/private/sam.ldb --two --skip-missing-dn --filter msDS-SupportedEncryptionTypes
+ $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX_ABS/$2/private/sam.ldb tdb://$PREFIX_ABS/$3/private/sam.ldb --two --skip-missing-dn --filter msDS-SupportedEncryptionTypes,servicePrincipalName
}
ldapcmp() {
diff -Nru samba-4.13.3+dfsg/testprogs/blackbox/upgradeprovision-oldrelease.sh samba-4.13.14+dfsg/testprogs/blackbox/upgradeprovision-oldrelease.sh
--- samba-4.13.3+dfsg/testprogs/blackbox/upgradeprovision-oldrelease.sh 2020-11-03 12:33:19.000000000 +0000
+++ samba-4.13.14+dfsg/testprogs/blackbox/upgradeprovision-oldrelease.sh 2021-11-08 11:29:14.000000000 +0000
@@ -182,12 +182,12 @@
ldapcmp() {
if [ x$RELEASE != x"alpha13" ]; then
- $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX_ABS/${RELEASE}_upgrade_reference/private/sam.ldb tdb://$PREFIX_ABS/${RELEASE}_upgrade/private/sam.ldb --two --skip-missing-dn --filter=dnsRecord,displayName,msDS-SupportedEncryptionTypes
+ $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX_ABS/${RELEASE}_upgrade_reference/private/sam.ldb tdb://$PREFIX_ABS/${RELEASE}_upgrade/private/sam.ldb --two --skip-missing-dn --filter=dnsRecord,displayName,msDS-SupportedEncryptionTypes,servicePrincipalName
fi
}
ldapcmp_full() {
- $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX_ABS/${RELEASE}_upgrade_reference/private/sam.ldb tdb://$PREFIX_ABS/${RELEASE}_upgrade_full/private/sam.ldb --two --filter=dNSProperty,dnsRecord,cn,displayName,versionNumber,systemFlags,msDS-HasInstantiatedNCs --skip-missing-dn
+ $PYTHON $BINDIR/samba-tool ldapcmp tdb://$PREFIX_ABS/${RELEASE}_upgrade_reference/private/sam.ldb tdb://$PREFIX_ABS/${RELEASE}_upgrade_full/private/sam.ldb --two --filter=dNSProperty,dnsRecord,cn,displayName,versionNumber,systemFlags,msDS-HasInstantiatedNCs,servicePrincipalName --skip-missing-dn
}
ldapcmp_sd() {
diff -Nru samba-4.13.3+dfsg/third_party/socket_wrapper/socket_wrapper.c samba-4.13.14+dfsg/third_party/socket_wrapper/socket_wrapper.c
--- samba-4.13.3+dfsg/third_party/socket_wrapper/socket_wrapper.c 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/third_party/socket_wrapper/socket_wrapper.c 2021-08-06 12:19:57.000000000 +0000
@@ -2,8 +2,8 @@
* BSD 3-Clause License
*
* Copyright (c) 2005-2008, Jelmer Vernooij
- * Copyright (c) 2006-2018, Stefan Metzmacher
- * Copyright (c) 2013-2018, Andreas Schneider
+ * Copyright (c) 2006-2021, Stefan Metzmacher
+ * Copyright (c) 2013-2021, Andreas Schneider
* Copyright (c) 2014-2017, Michael Adam
* Copyright (c) 2016-2018, Anoop C S
* All rights reserved.
@@ -86,6 +86,8 @@
#endif
#include
+#include "socket_wrapper.h"
+
enum swrap_dbglvl_e {
SWRAP_LOG_ERROR = 0,
SWRAP_LOG_WARN,
@@ -178,24 +180,67 @@
# endif
#endif
+#define socket_wrapper_init_mutex(m) \
+ _socket_wrapper_init_mutex(m, #m)
+
/* Add new global locks here please */
-# define SWRAP_LOCK_ALL \
- swrap_mutex_lock(&libc_symbol_binding_mutex); \
+# define SWRAP_REINIT_ALL do { \
+ int ret; \
+ ret = socket_wrapper_init_mutex(&sockets_mutex); \
+ if (ret != 0) exit(-1); \
+ ret = socket_wrapper_init_mutex(&socket_reset_mutex); \
+ if (ret != 0) exit(-1); \
+ ret = socket_wrapper_init_mutex(&first_free_mutex); \
+ if (ret != 0) exit(-1); \
+ ret = socket_wrapper_init_mutex(&sockets_si_global); \
+ if (ret != 0) exit(-1); \
+ ret = socket_wrapper_init_mutex(&autobind_start_mutex); \
+ if (ret != 0) exit(-1); \
+ ret = socket_wrapper_init_mutex(&pcap_dump_mutex); \
+ if (ret != 0) exit(-1); \
+ ret = socket_wrapper_init_mutex(&mtu_update_mutex); \
+ if (ret != 0) exit(-1); \
+} while(0)
+
+# define SWRAP_LOCK_ALL do { \
+ swrap_mutex_lock(&sockets_mutex); \
+ swrap_mutex_lock(&socket_reset_mutex); \
+ swrap_mutex_lock(&first_free_mutex); \
+ swrap_mutex_lock(&sockets_si_global); \
+ swrap_mutex_lock(&autobind_start_mutex); \
+ swrap_mutex_lock(&pcap_dump_mutex); \
+ swrap_mutex_lock(&mtu_update_mutex); \
+} while(0)
-# define SWRAP_UNLOCK_ALL \
- swrap_mutex_unlock(&libc_symbol_binding_mutex); \
+# define SWRAP_UNLOCK_ALL do { \
+ swrap_mutex_unlock(&mtu_update_mutex); \
+ swrap_mutex_unlock(&pcap_dump_mutex); \
+ swrap_mutex_unlock(&autobind_start_mutex); \
+ swrap_mutex_unlock(&sockets_si_global); \
+ swrap_mutex_unlock(&first_free_mutex); \
+ swrap_mutex_unlock(&socket_reset_mutex); \
+ swrap_mutex_unlock(&sockets_mutex); \
+} while(0)
#define SOCKET_INFO_CONTAINER(si) \
(struct socket_info_container *)(si)
#define SWRAP_LOCK_SI(si) do { \
struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); \
- swrap_mutex_lock(&sic->meta.mutex); \
+ if (sic != NULL) { \
+ swrap_mutex_lock(&sockets_si_global); \
+ } else { \
+ abort(); \
+ } \
} while(0)
#define SWRAP_UNLOCK_SI(si) do { \
struct socket_info_container *sic = SOCKET_INFO_CONTAINER(si); \
- swrap_mutex_unlock(&sic->meta.mutex); \
+ if (sic != NULL) { \
+ swrap_mutex_unlock(&sockets_si_global); \
+ } else { \
+ abort(); \
+ } \
} while(0)
#if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID)
@@ -253,10 +298,15 @@
} sa;
};
-int first_free;
+static int first_free;
struct socket_info
{
+ /*
+ * Remember to update swrap_unix_scm_right_magic
+ * on any change.
+ */
+
int family;
int type;
int protocol;
@@ -268,6 +318,7 @@
int pktinfo;
int tcp_nodelay;
int listening;
+ int fd_passed;
/* The unix path so we can unlink it on close() */
struct sockaddr_un un_addr;
@@ -286,7 +337,13 @@
{
unsigned int refcount;
int next_free;
- pthread_mutex_t mutex;
+ /*
+ * As long as we don't use shared memory
+ * for the sockets array, we use
+ * sockets_si_global as a single mutex.
+ *
+ * pthread_mutex_t mutex;
+ */
};
struct socket_info_container
@@ -309,32 +366,42 @@
/* Hash table to map fds to corresponding socket_info index */
static int *socket_fds_idx;
-/* Mutex to synchronize access to global libc.symbols */
-static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
-
/* Mutex for syncronizing port selection during swrap_auto_bind() */
-static pthread_mutex_t autobind_start_mutex;
+static pthread_mutex_t autobind_start_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Mutex to guard the initialization of array of socket_info structures */
-static pthread_mutex_t sockets_mutex;
+static pthread_mutex_t sockets_mutex = PTHREAD_MUTEX_INITIALIZER;
-/* Mutex to guard the socket reset in swrap_close() and swrap_remove_stale() */
-static pthread_mutex_t socket_reset_mutex;
+/* Mutex to guard the socket reset in swrap_remove_wrapper() */
+static pthread_mutex_t socket_reset_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Mutex to synchronize access to first free index in socket_info array */
-static pthread_mutex_t first_free_mutex;
+static pthread_mutex_t first_free_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Mutex to synchronize access to to socket_info structures
+ * We use a single global mutex in order to avoid leaking
+ * ~ 38M copy on write memory per fork.
+ * max_sockets=65535 * sizeof(struct socket_info_container)=592 = 38796720
+ */
+static pthread_mutex_t sockets_si_global = PTHREAD_MUTEX_INITIALIZER;
/* Mutex to synchronize access to packet capture dump file */
-static pthread_mutex_t pcap_dump_mutex;
+static pthread_mutex_t pcap_dump_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Mutex for synchronizing mtu value fetch*/
-static pthread_mutex_t mtu_update_mutex;
+static pthread_mutex_t mtu_update_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Function prototypes */
-bool socket_wrapper_enabled(void);
-
+#if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
+/* xlC and other oldschool compilers support (only) this */
+#pragma init (swrap_constructor)
+#endif
void swrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
+#if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
+#pragma fini (swrap_destructor)
+#endif
void swrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
#ifndef HAVE_GETPROGNAME
@@ -425,6 +492,9 @@
const struct sockaddr *addr,
socklen_t addrlen);
typedef int (*__libc_close)(int fd);
+#ifdef HAVE___CLOSE_NOCANCEL
+typedef int (*__libc___close_nocancel)(int fd);
+#endif
typedef int (*__libc_connect)(int sockfd,
const struct sockaddr *addr,
socklen_t addrlen);
@@ -505,6 +575,9 @@
#endif
SWRAP_SYMBOL_ENTRY(bind);
SWRAP_SYMBOL_ENTRY(close);
+#ifdef HAVE___CLOSE_NOCANCEL
+ SWRAP_SYMBOL_ENTRY(__close_nocancel);
+#endif
SWRAP_SYMBOL_ENTRY(connect);
SWRAP_SYMBOL_ENTRY(dup);
SWRAP_SYMBOL_ENTRY(dup2);
@@ -565,7 +638,6 @@
enum swrap_lib {
SWRAP_LIBC,
- SWRAP_LIBNSL,
SWRAP_LIBSOCKET,
};
@@ -574,8 +646,6 @@
switch (lib) {
case SWRAP_LIBC:
return "libc";
- case SWRAP_LIBNSL:
- return "libnsl";
case SWRAP_LIBSOCKET:
return "libsocket";
}
@@ -613,7 +683,6 @@
#endif
switch (lib) {
- case SWRAP_LIBNSL:
case SWRAP_LIBSOCKET:
#ifdef HAVE_LIBSOCKET
handle = swrap.libc.socket_handle;
@@ -695,25 +764,29 @@
return func;
}
-static void swrap_mutex_lock(pthread_mutex_t *mutex)
+#define swrap_mutex_lock(m) _swrap_mutex_lock(m, #m, __func__, __LINE__)
+static void _swrap_mutex_lock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line)
{
int ret;
ret = pthread_mutex_lock(mutex);
if (ret != 0) {
- SWRAP_LOG(SWRAP_LOG_ERROR, "Couldn't lock pthread mutex - %s",
- strerror(ret));
+ SWRAP_LOG(SWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't lock pthread mutex(%s) - %s",
+ getpid(), getppid(), caller, line, name, strerror(ret));
+ abort();
}
}
-static void swrap_mutex_unlock(pthread_mutex_t *mutex)
+#define swrap_mutex_unlock(m) _swrap_mutex_unlock(m, #m, __func__, __LINE__)
+static void _swrap_mutex_unlock(pthread_mutex_t *mutex, const char *name, const char *caller, unsigned line)
{
int ret;
ret = pthread_mutex_unlock(mutex);
if (ret != 0) {
- SWRAP_LOG(SWRAP_LOG_ERROR, "Couldn't unlock pthread mutex - %s",
- strerror(ret));
+ SWRAP_LOG(SWRAP_LOG_ERROR, "PID(%d):PPID(%d): %s(%u): Couldn't unlock pthread mutex(%s) - %s",
+ getpid(), getppid(), caller, line, name, strerror(ret));
+ abort();
}
}
@@ -723,35 +796,18 @@
* This is an optimization to avoid locking each time we check if the symbol is
* bound.
*/
+#define _swrap_bind_symbol_generic(lib, sym_name) do { \
+ swrap.libc.symbols._libc_##sym_name.obj = \
+ _swrap_bind_symbol(lib, #sym_name); \
+} while(0);
+
#define swrap_bind_symbol_libc(sym_name) \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- swrap_mutex_lock(&libc_symbol_binding_mutex); \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- swrap.libc.symbols._libc_##sym_name.obj = \
- _swrap_bind_symbol(SWRAP_LIBC, #sym_name); \
- } \
- swrap_mutex_unlock(&libc_symbol_binding_mutex); \
- }
+ _swrap_bind_symbol_generic(SWRAP_LIBC, sym_name)
#define swrap_bind_symbol_libsocket(sym_name) \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- swrap_mutex_lock(&libc_symbol_binding_mutex); \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- swrap.libc.symbols._libc_##sym_name.obj = \
- _swrap_bind_symbol(SWRAP_LIBSOCKET, #sym_name); \
- } \
- swrap_mutex_unlock(&libc_symbol_binding_mutex); \
- }
-
-#define swrap_bind_symbol_libnsl(sym_name) \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- swrap_mutex_lock(&libc_symbol_binding_mutex); \
- if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
- swrap.libc.symbols._libc_##sym_name.obj = \
- _swrap_bind_symbol(SWRAP_LIBNSL, #sym_name); \
- } \
- swrap_mutex_unlock(&libc_symbol_binding_mutex); \
- }
+ _swrap_bind_symbol_generic(SWRAP_LIBSOCKET, sym_name)
+
+static void swrap_bind_symbol_all(void);
/****************************************************************************
* IMPORTANT
@@ -770,7 +826,7 @@
socklen_t *addrlen,
int flags)
{
- swrap_bind_symbol_libsocket(accept4);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_accept4.f(sockfd, addr, addrlen, flags);
}
@@ -779,7 +835,7 @@
static int libc_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(accept);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_accept.f(sockfd, addr, addrlen);
}
@@ -789,37 +845,46 @@
const struct sockaddr *addr,
socklen_t addrlen)
{
- swrap_bind_symbol_libsocket(bind);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_bind.f(sockfd, addr, addrlen);
}
static int libc_close(int fd)
{
- swrap_bind_symbol_libc(close);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_close.f(fd);
}
+#ifdef HAVE___CLOSE_NOCANCEL
+static int libc___close_nocancel(int fd)
+{
+ swrap_bind_symbol_all();
+
+ return swrap.libc.symbols._libc___close_nocancel.f(fd);
+}
+#endif /* HAVE___CLOSE_NOCANCEL */
+
static int libc_connect(int sockfd,
const struct sockaddr *addr,
socklen_t addrlen)
{
- swrap_bind_symbol_libsocket(connect);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_connect.f(sockfd, addr, addrlen);
}
static int libc_dup(int fd)
{
- swrap_bind_symbol_libc(dup);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_dup.f(fd);
}
static int libc_dup2(int oldfd, int newfd)
{
- swrap_bind_symbol_libc(dup2);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_dup2.f(oldfd, newfd);
}
@@ -827,7 +892,7 @@
#ifdef HAVE_EVENTFD
static int libc_eventfd(int count, int flags)
{
- swrap_bind_symbol_libc(eventfd);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_eventfd.f(count, flags);
}
@@ -839,7 +904,7 @@
void *arg;
int rc;
- swrap_bind_symbol_libc(fcntl);
+ swrap_bind_symbol_all();
arg = va_arg(ap, void *);
@@ -852,7 +917,7 @@
struct sockaddr *addr,
socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(getpeername);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_getpeername.f(sockfd, addr, addrlen);
}
@@ -861,7 +926,7 @@
struct sockaddr *addr,
socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(getsockname);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_getsockname.f(sockfd, addr, addrlen);
}
@@ -872,7 +937,7 @@
void *optval,
socklen_t *optlen)
{
- swrap_bind_symbol_libsocket(getsockopt);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_getsockopt.f(sockfd,
level,
@@ -887,7 +952,7 @@
void *arg;
int rc;
- swrap_bind_symbol_libc(ioctl);
+ swrap_bind_symbol_all();
arg = va_arg(ap, void *);
@@ -898,14 +963,14 @@
static int libc_listen(int sockfd, int backlog)
{
- swrap_bind_symbol_libsocket(listen);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_listen.f(sockfd, backlog);
}
static FILE *libc_fopen(const char *name, const char *mode)
{
- swrap_bind_symbol_libc(fopen);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_fopen.f(name, mode);
}
@@ -913,7 +978,7 @@
#ifdef HAVE_FOPEN64
static FILE *libc_fopen64(const char *name, const char *mode)
{
- swrap_bind_symbol_libc(fopen64);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_fopen64.f(name, mode);
}
@@ -924,7 +989,7 @@
int mode = 0;
int fd;
- swrap_bind_symbol_libc(open);
+ swrap_bind_symbol_all();
if (flags & O_CREAT) {
mode = va_arg(ap, int);
@@ -952,7 +1017,7 @@
int mode = 0;
int fd;
- swrap_bind_symbol_libc(open64);
+ swrap_bind_symbol_all();
if (flags & O_CREAT) {
mode = va_arg(ap, int);
@@ -968,7 +1033,7 @@
int mode = 0;
int fd;
- swrap_bind_symbol_libc(openat);
+ swrap_bind_symbol_all();
if (flags & O_CREAT) {
mode = va_arg(ap, int);
@@ -997,28 +1062,28 @@
static int libc_pipe(int pipefd[2])
{
- swrap_bind_symbol_libsocket(pipe);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_pipe.f(pipefd);
}
static int libc_read(int fd, void *buf, size_t count)
{
- swrap_bind_symbol_libc(read);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_read.f(fd, buf, count);
}
static ssize_t libc_readv(int fd, const struct iovec *iov, int iovcnt)
{
- swrap_bind_symbol_libsocket(readv);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_readv.f(fd, iov, iovcnt);
}
static int libc_recv(int sockfd, void *buf, size_t len, int flags)
{
- swrap_bind_symbol_libsocket(recv);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_recv.f(sockfd, buf, len, flags);
}
@@ -1030,7 +1095,7 @@
struct sockaddr *src_addr,
socklen_t *addrlen)
{
- swrap_bind_symbol_libsocket(recvfrom);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_recvfrom.f(sockfd,
buf,
@@ -1042,21 +1107,21 @@
static int libc_recvmsg(int sockfd, struct msghdr *msg, int flags)
{
- swrap_bind_symbol_libsocket(recvmsg);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_recvmsg.f(sockfd, msg, flags);
}
static int libc_send(int sockfd, const void *buf, size_t len, int flags)
{
- swrap_bind_symbol_libsocket(send);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_send.f(sockfd, buf, len, flags);
}
static int libc_sendmsg(int sockfd, const struct msghdr *msg, int flags)
{
- swrap_bind_symbol_libsocket(sendmsg);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_sendmsg.f(sockfd, msg, flags);
}
@@ -1068,7 +1133,7 @@
const struct sockaddr *dst_addr,
socklen_t addrlen)
{
- swrap_bind_symbol_libsocket(sendto);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_sendto.f(sockfd,
buf,
@@ -1084,7 +1149,7 @@
const void *optval,
socklen_t optlen)
{
- swrap_bind_symbol_libsocket(setsockopt);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_setsockopt.f(sockfd,
level,
@@ -1096,7 +1161,7 @@
#ifdef HAVE_SIGNALFD
static int libc_signalfd(int fd, const sigset_t *mask, int flags)
{
- swrap_bind_symbol_libsocket(signalfd);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_signalfd.f(fd, mask, flags);
}
@@ -1104,14 +1169,14 @@
static int libc_socket(int domain, int type, int protocol)
{
- swrap_bind_symbol_libsocket(socket);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_socket.f(domain, type, protocol);
}
static int libc_socketpair(int domain, int type, int protocol, int sv[2])
{
- swrap_bind_symbol_libsocket(socketpair);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_socketpair.f(domain, type, protocol, sv);
}
@@ -1119,7 +1184,7 @@
#ifdef HAVE_TIMERFD_CREATE
static int libc_timerfd_create(int clockid, int flags)
{
- swrap_bind_symbol_libc(timerfd_create);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_timerfd_create.f(clockid, flags);
}
@@ -1127,20 +1192,20 @@
static ssize_t libc_write(int fd, const void *buf, size_t count)
{
- swrap_bind_symbol_libc(write);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_write.f(fd, buf, count);
}
static ssize_t libc_writev(int fd, const struct iovec *iov, int iovcnt)
{
- swrap_bind_symbol_libsocket(writev);
+ swrap_bind_symbol_all();
return swrap.libc.symbols._libc_writev.f(fd, iov, iovcnt);
}
/* DO NOT call this function during library initialization! */
-static void swrap_bind_symbol_all(void)
+static void __swrap_bind_symbol_all_once(void)
{
#ifdef HAVE_ACCEPT4
swrap_bind_symbol_libsocket(accept4);
@@ -1149,6 +1214,9 @@
#endif
swrap_bind_symbol_libsocket(bind);
swrap_bind_symbol_libc(close);
+#ifdef HAVE___CLOSE_NOCANCEL
+ swrap_bind_symbol_libc(__close_nocancel);
+#endif
swrap_bind_symbol_libsocket(connect);
swrap_bind_symbol_libc(dup);
swrap_bind_symbol_libc(dup2);
@@ -1192,6 +1260,13 @@
swrap_bind_symbol_libsocket(writev);
}
+static void swrap_bind_symbol_all(void)
+{
+ static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT;
+
+ pthread_once(&all_symbol_binding_once, __swrap_bind_symbol_all_once);
+}
+
/*********************************************************
* SWRAP HELPER FUNCTIONS
*********************************************************/
@@ -1438,7 +1513,7 @@
char *t;
bool ok;
- if (s == NULL) {
+ if (s == NULL || s[0] == '\0') {
SWRAP_LOG(SWRAP_LOG_WARN, "SOCKET_WRAPPER_DIR not set");
return NULL;
}
@@ -1446,7 +1521,8 @@
swrap_dir = realpath(s, NULL);
if (swrap_dir == NULL) {
SWRAP_LOG(SWRAP_LOG_ERROR,
- "Unable to resolve socket_wrapper dir path: %s",
+ "Unable to resolve socket_wrapper dir path: %s - %s",
+ s,
strerror(errno));
abort();
}
@@ -1524,26 +1600,31 @@
return max_mtu;
}
-static int socket_wrapper_init_mutex(pthread_mutex_t *m)
+static int _socket_wrapper_init_mutex(pthread_mutex_t *m, const char *name)
{
pthread_mutexattr_t ma;
- int ret;
+ bool need_destroy = false;
+ int ret = 0;
- ret = pthread_mutexattr_init(&ma);
- if (ret != 0) {
- return ret;
- }
-
- ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK);
- if (ret != 0) {
- goto done;
- }
-
- ret = pthread_mutex_init(m, &ma);
+#define __CHECK(cmd) do { \
+ ret = cmd; \
+ if (ret != 0) { \
+ SWRAP_LOG(SWRAP_LOG_ERROR, \
+ "%s: %s - failed %d", \
+ name, #cmd, ret); \
+ goto done; \
+ } \
+} while(0)
+ *m = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
+ __CHECK(pthread_mutexattr_init(&ma));
+ need_destroy = true;
+ __CHECK(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK));
+ __CHECK(pthread_mutex_init(m, &ma));
done:
- pthread_mutexattr_destroy(&ma);
-
+ if (need_destroy) {
+ pthread_mutexattr_destroy(&ma);
+ }
return ret;
}
@@ -1618,7 +1699,9 @@
{
size_t max_sockets;
size_t i;
- int ret;
+ int ret = 0;
+
+ swrap_bind_symbol_all();
swrap_mutex_lock(&sockets_mutex);
@@ -1627,6 +1710,10 @@
return;
}
+ SWRAP_LOG(SWRAP_LOG_DEBUG,
+ "SOCKET_WRAPPER_PACKAGE[%s] SOCKET_WRAPPER_VERSION[%s]",
+ SOCKET_WRAPPER_PACKAGE, SOCKET_WRAPPER_VERSION);
+
/*
* Intialize the static cache early before
* any thread is able to start.
@@ -1650,44 +1737,18 @@
}
swrap_mutex_lock(&first_free_mutex);
+ swrap_mutex_lock(&sockets_si_global);
first_free = 0;
for (i = 0; i < max_sockets; i++) {
swrap_set_next_free(&sockets[i].info, i+1);
- ret = socket_wrapper_init_mutex(&sockets[i].meta.mutex);
- if (ret != 0) {
- SWRAP_LOG(SWRAP_LOG_ERROR,
- "Failed to initialize pthread mutex");
- goto done;
- }
}
/* mark the end of the free list */
swrap_set_next_free(&sockets[max_sockets-1].info, -1);
- ret = socket_wrapper_init_mutex(&autobind_start_mutex);
- if (ret != 0) {
- SWRAP_LOG(SWRAP_LOG_ERROR,
- "Failed to initialize pthread mutex");
- goto done;
- }
-
- ret = socket_wrapper_init_mutex(&pcap_dump_mutex);
- if (ret != 0) {
- SWRAP_LOG(SWRAP_LOG_ERROR,
- "Failed to initialize pthread mutex");
- goto done;
- }
-
- ret = socket_wrapper_init_mutex(&mtu_update_mutex);
- if (ret != 0) {
- SWRAP_LOG(SWRAP_LOG_ERROR,
- "Failed to initialize pthread mutex");
- goto done;
- }
-
-done:
+ swrap_mutex_unlock(&sockets_si_global);
swrap_mutex_unlock(&first_free_mutex);
swrap_mutex_unlock(&sockets_mutex);
if (ret != 0) {
@@ -1779,7 +1840,7 @@
return socket_fds_idx[fd];
}
-static int swrap_add_socket_info(struct socket_info *si_input)
+static int swrap_add_socket_info(const struct socket_info *si_input)
{
struct socket_info *si = NULL;
int si_index = -1;
@@ -1822,6 +1883,7 @@
"trying to add %d",
socket_fds_max,
fd);
+ errno = EMFILE;
return -1;
}
@@ -1846,31 +1908,40 @@
if (p) p++; else p = un->sun_path;
if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
+ SWRAP_LOG(SWRAP_LOG_ERROR, "sun_path[%s] p[%s]",
+ un->sun_path, p);
errno = EINVAL;
return -1;
}
- SWRAP_LOG(SWRAP_LOG_TRACE, "type %c iface %u port %u",
- type, iface, prt);
-
if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
+ SWRAP_LOG(SWRAP_LOG_ERROR, "type %c iface %u port %u",
+ type, iface, prt);
errno = EINVAL;
return -1;
}
if (prt > 0xFFFF) {
+ SWRAP_LOG(SWRAP_LOG_ERROR, "type %c iface %u port %u",
+ type, iface, prt);
errno = EINVAL;
return -1;
}
+ SWRAP_LOG(SWRAP_LOG_TRACE, "type %c iface %u port %u",
+ type, iface, prt);
+
switch(type) {
case SOCKET_TYPE_CHAR_TCP:
case SOCKET_TYPE_CHAR_UDP: {
struct sockaddr_in *in2 = (struct sockaddr_in *)(void *)in;
if ((*len) < sizeof(*in2)) {
- errno = EINVAL;
- return -1;
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "V4: *len(%zu) < sizeof(*in2)=%zu",
+ (size_t)*len, sizeof(*in2));
+ errno = EINVAL;
+ return -1;
}
memset(in2, 0, sizeof(*in2));
@@ -1887,6 +1958,10 @@
struct sockaddr_in6 *in2 = (struct sockaddr_in6 *)(void *)in;
if ((*len) < sizeof(*in2)) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "V6: *len(%zu) < sizeof(*in2)=%zu",
+ (size_t)*len, sizeof(*in2));
+ SWRAP_LOG(SWRAP_LOG_ERROR, "LINE:%d", __LINE__);
errno = EINVAL;
return -1;
}
@@ -1902,6 +1977,8 @@
}
#endif
default:
+ SWRAP_LOG(SWRAP_LOG_ERROR, "type %c iface %u port %u",
+ type, iface, prt);
errno = EINVAL;
return -1;
}
@@ -1968,6 +2045,13 @@
type = u_type;
iface = (addr & 0x000000FF);
} else {
+ char str[256] = {0,};
+ inet_ntop(inaddr->sa_family,
+ &in->sin_addr,
+ str, sizeof(str));
+ SWRAP_LOG(SWRAP_LOG_WARN,
+ "str[%s] prt[%u]",
+ str, (unsigned)prt);
errno = ENETUNREACH;
return -1;
}
@@ -2003,6 +2087,13 @@
if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
iface = in->sin6_addr.s6_addr[15];
} else {
+ char str[256] = {0,};
+ inet_ntop(inaddr->sa_family,
+ &in->sin6_addr,
+ str, sizeof(str));
+ SWRAP_LOG(SWRAP_LOG_WARN,
+ "str[%s] prt[%u]",
+ str, (unsigned)prt);
errno = ENETUNREACH;
return -1;
}
@@ -2331,46 +2422,7 @@
}
#endif
-static void swrap_remove_stale(int fd)
-{
- struct socket_info *si;
- int si_index;
-
- SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd);
-
- swrap_mutex_lock(&socket_reset_mutex);
-
- si_index = find_socket_info_index(fd);
- if (si_index == -1) {
- swrap_mutex_unlock(&socket_reset_mutex);
- return;
- }
-
- reset_socket_info_index(fd);
-
- si = swrap_get_socket_info(si_index);
-
- swrap_mutex_lock(&first_free_mutex);
- SWRAP_LOCK_SI(si);
-
- swrap_dec_refcount(si);
-
- if (swrap_get_refcount(si) > 0) {
- goto out;
- }
-
- if (si->un_addr.sun_path[0] != '\0') {
- unlink(si->un_addr.sun_path);
- }
-
- swrap_set_next_free(si, first_free);
- first_free = si_index;
-
-out:
- SWRAP_UNLOCK_SI(si);
- swrap_mutex_unlock(&first_free_mutex);
- swrap_mutex_unlock(&socket_reset_mutex);
-}
+static void swrap_remove_stale(int fd);
static int sockaddr_convert_to_un(struct socket_info *si,
const struct sockaddr *in_addr,
@@ -2931,8 +2983,8 @@
file_hdr.frame_max_len = SWRAP_FRAME_LENGTH_MAX;
file_hdr.link_type = 0x0065; /* 101 RAW IP */
- if (write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
- close(fd);
+ if (libc_write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
+ libc_close(fd);
fd = -1;
}
return fd;
@@ -3266,7 +3318,7 @@
fd = swrap_pcap_get_fd(file_name);
if (fd != -1) {
- if (write(fd, packet, packet_len) != (ssize_t)packet_len) {
+ if (libc_write(fd, packet, packet_len) != (ssize_t)packet_len) {
free(packet);
goto done;
}
@@ -3437,6 +3489,9 @@
ret = swrap_create_socket(si, fd);
if (ret == -1) {
+ int saved_errno = errno;
+ libc_close(fd);
+ errno = saved_errno;
return -1;
}
@@ -3585,10 +3640,12 @@
ret = libc_accept(s, &un_addr.sa.s, &un_addr.sa_socklen);
#endif
if (ret == -1) {
- if (errno == ENOTSOCK) {
+ int saved_errno = errno;
+ if (saved_errno == ENOTSOCK) {
/* Remove stale fds */
swrap_remove_stale(s);
}
+ errno = saved_errno;
return ret;
}
@@ -3597,6 +3654,50 @@
/* Check if we have a stale fd and remove it */
swrap_remove_stale(fd);
+ if (un_addr.sa.un.sun_path[0] == '\0') {
+ /*
+ * FreeBSD seems to have a problem where
+ * accept4() on the unix socket doesn't
+ * ECONNABORTED for already disconnected connections.
+ *
+ * Let's try libc_getpeername() to get the peer address
+ * as a fallback, but it'll likely return ENOTCONN,
+ * which we have to map to ECONNABORTED.
+ */
+ un_addr.sa_socklen = sizeof(struct sockaddr_un),
+ ret = libc_getpeername(fd, &un_addr.sa.s, &un_addr.sa_socklen);
+ if (ret == -1) {
+ int saved_errno = errno;
+ libc_close(fd);
+ if (saved_errno == ENOTCONN) {
+ /*
+ * If the connection is already disconnected
+ * we should return ECONNABORTED.
+ */
+ saved_errno = ECONNABORTED;
+ }
+ errno = saved_errno;
+ return ret;
+ }
+ }
+
+ ret = libc_getsockname(fd,
+ &un_my_addr.sa.s,
+ &un_my_addr.sa_socklen);
+ if (ret == -1) {
+ int saved_errno = errno;
+ libc_close(fd);
+ if (saved_errno == ENOTCONN) {
+ /*
+ * If the connection is already disconnected
+ * we should return ECONNABORTED.
+ */
+ saved_errno = ECONNABORTED;
+ }
+ errno = saved_errno;
+ return ret;
+ }
+
SWRAP_LOCK_SI(parent_si);
ret = sockaddr_convert_from_un(parent_si,
@@ -3606,8 +3707,10 @@
&in_addr.sa.s,
&in_addr.sa_socklen);
if (ret == -1) {
+ int saved_errno = errno;
SWRAP_UNLOCK_SI(parent_si);
- close(fd);
+ libc_close(fd);
+ errno = saved_errno;
return ret;
}
@@ -3635,14 +3738,6 @@
*addrlen = in_addr.sa_socklen;
}
- ret = libc_getsockname(fd,
- &un_my_addr.sa.s,
- &un_my_addr.sa_socklen);
- if (ret == -1) {
- close(fd);
- return ret;
- }
-
ret = sockaddr_convert_from_un(child_si,
&un_my_addr.sa.un,
un_my_addr.sa_socklen,
@@ -3650,7 +3745,9 @@
&in_my_addr.sa.s,
&in_my_addr.sa_socklen);
if (ret == -1) {
- close(fd);
+ int saved_errno = errno;
+ libc_close(fd);
+ errno = saved_errno;
return ret;
}
@@ -3665,7 +3762,9 @@
idx = swrap_create_socket(&new_si, fd);
if (idx == -1) {
- close (fd);
+ int saved_errno = errno;
+ libc_close(fd);
+ errno = saved_errno;
return -1;
}
@@ -4959,16 +5058,21 @@
return rc;
}
-static int swrap_sendmsg_copy_cmsg(struct cmsghdr *cmsg,
+static int swrap_sendmsg_copy_cmsg(const struct cmsghdr *cmsg,
uint8_t **cm_data,
size_t *cm_data_space);
-static int swrap_sendmsg_filter_cmsg_socket(struct cmsghdr *cmsg,
- uint8_t **cm_data,
- size_t *cm_data_space);
+static int swrap_sendmsg_filter_cmsg_ipproto_ip(const struct cmsghdr *cmsg,
+ uint8_t **cm_data,
+ size_t *cm_data_space);
+static int swrap_sendmsg_filter_cmsg_sol_socket(const struct cmsghdr *cmsg,
+ uint8_t **cm_data,
+ size_t *cm_data_space);
-static int swrap_sendmsg_filter_cmsghdr(struct msghdr *msg,
+static int swrap_sendmsg_filter_cmsghdr(const struct msghdr *_msg,
uint8_t **cm_data,
- size_t *cm_data_space) {
+ size_t *cm_data_space)
+{
+ struct msghdr *msg = discard_const_p(struct msghdr, _msg);
struct cmsghdr *cmsg;
int rc = -1;
@@ -4982,9 +5086,14 @@
cmsg = CMSG_NXTHDR(msg, cmsg)) {
switch (cmsg->cmsg_level) {
case IPPROTO_IP:
- rc = swrap_sendmsg_filter_cmsg_socket(cmsg,
- cm_data,
- cm_data_space);
+ rc = swrap_sendmsg_filter_cmsg_ipproto_ip(cmsg,
+ cm_data,
+ cm_data_space);
+ break;
+ case SOL_SOCKET:
+ rc = swrap_sendmsg_filter_cmsg_sol_socket(cmsg,
+ cm_data,
+ cm_data_space);
break;
default:
rc = swrap_sendmsg_copy_cmsg(cmsg,
@@ -4992,12 +5101,19 @@
cm_data_space);
break;
}
+ if (rc < 0) {
+ int saved_errno = errno;
+ SAFE_FREE(*cm_data);
+ *cm_data_space = 0;
+ errno = saved_errno;
+ return rc;
+ }
}
return rc;
}
-static int swrap_sendmsg_copy_cmsg(struct cmsghdr *cmsg,
+static int swrap_sendmsg_copy_cmsg(const struct cmsghdr *cmsg,
uint8_t **cm_data,
size_t *cm_data_space)
{
@@ -5020,14 +5136,14 @@
return 0;
}
-static int swrap_sendmsg_filter_cmsg_pktinfo(struct cmsghdr *cmsg,
+static int swrap_sendmsg_filter_cmsg_pktinfo(const struct cmsghdr *cmsg,
uint8_t **cm_data,
size_t *cm_data_space);
-static int swrap_sendmsg_filter_cmsg_socket(struct cmsghdr *cmsg,
- uint8_t **cm_data,
- size_t *cm_data_space)
+static int swrap_sendmsg_filter_cmsg_ipproto_ip(const struct cmsghdr *cmsg,
+ uint8_t **cm_data,
+ size_t *cm_data_space)
{
int rc = -1;
@@ -5053,7 +5169,7 @@
return rc;
}
-static int swrap_sendmsg_filter_cmsg_pktinfo(struct cmsghdr *cmsg,
+static int swrap_sendmsg_filter_cmsg_pktinfo(const struct cmsghdr *cmsg,
uint8_t **cm_data,
size_t *cm_data_space)
{
@@ -5067,22 +5183,926 @@
*/
return 0;
}
-#endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
-static ssize_t swrap_sendmsg_before(int fd,
- struct socket_info *si,
- struct msghdr *msg,
- struct iovec *tmp_iov,
- struct sockaddr_un *tmp_un,
- const struct sockaddr_un **to_un,
- const struct sockaddr **to,
- int *bcast)
+static int swrap_sendmsg_filter_cmsg_sol_socket(const struct cmsghdr *cmsg,
+ uint8_t **cm_data,
+ size_t *cm_data_space)
{
- size_t i, len = 0;
- ssize_t ret = -1;
+ int rc = -1;
- if (to_un) {
- *to_un = NULL;
+ switch (cmsg->cmsg_type) {
+ case SCM_RIGHTS:
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "Ignoring SCM_RIGHTS on inet socket!");
+ rc = 0;
+ break;
+#ifdef SCM_CREDENTIALS
+ case SCM_CREDENTIALS:
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "Ignoring SCM_CREDENTIALS on inet socket!");
+ rc = 0;
+ break;
+#endif /* SCM_CREDENTIALS */
+ default:
+ rc = swrap_sendmsg_copy_cmsg(cmsg,
+ cm_data,
+ cm_data_space);
+ break;
+ }
+
+ return rc;
+}
+
+static const uint64_t swrap_unix_scm_right_magic = 0x8e0e13f27c42fc36;
+
+/*
+ * We only allow up to 6 fds at a time
+ * as that's more than enough for Samba
+ * and it means we can keep the logic simple
+ * and work with fixed size arrays.
+ *
+ * We also keep sizeof(struct swrap_unix_scm_rights)
+ * under PIPE_BUF (4096) in order to allow a non-blocking
+ * write into the pipe.
+ */
+#ifndef PIPE_BUF
+#define PIPE_BUF 4096
+#endif
+#define SWRAP_MAX_PASSED_FDS ((size_t)6)
+#define SWRAP_MAX_PASSED_SOCKET_INFO SWRAP_MAX_PASSED_FDS
+struct swrap_unix_scm_rights_payload {
+ uint8_t num_idxs;
+ int8_t idxs[SWRAP_MAX_PASSED_FDS];
+ struct socket_info infos[SWRAP_MAX_PASSED_SOCKET_INFO];
+};
+struct swrap_unix_scm_rights {
+ uint64_t magic;
+ char package_name[sizeof(SOCKET_WRAPPER_PACKAGE)];
+ char package_version[sizeof(SOCKET_WRAPPER_VERSION)];
+ uint32_t full_size;
+ uint32_t payload_size;
+ struct swrap_unix_scm_rights_payload payload;
+};
+
+static void swrap_dec_fd_passed_array(size_t num, struct socket_info **array)
+{
+ int saved_errno = errno;
+ size_t i;
+
+ for (i = 0; i < num; i++) {
+ struct socket_info *si = array[i];
+ if (si == NULL) {
+ continue;
+ }
+
+ SWRAP_LOCK_SI(si);
+ swrap_dec_refcount(si);
+ if (si->fd_passed > 0) {
+ si->fd_passed -= 1;
+ }
+ SWRAP_UNLOCK_SI(si);
+ array[i] = NULL;
+ }
+
+ errno = saved_errno;
+}
+
+static void swrap_undo_si_idx_array(size_t num, int *array)
+{
+ int saved_errno = errno;
+ size_t i;
+
+ swrap_mutex_lock(&first_free_mutex);
+
+ for (i = 0; i < num; i++) {
+ struct socket_info *si = NULL;
+
+ if (array[i] == -1) {
+ continue;
+ }
+
+ si = swrap_get_socket_info(array[i]);
+ if (si == NULL) {
+ continue;
+ }
+
+ SWRAP_LOCK_SI(si);
+ swrap_dec_refcount(si);
+ SWRAP_UNLOCK_SI(si);
+
+ swrap_set_next_free(si, first_free);
+ first_free = array[i];
+ array[i] = -1;
+ }
+
+ swrap_mutex_unlock(&first_free_mutex);
+ errno = saved_errno;
+}
+
+static void swrap_close_fd_array(size_t num, const int *array)
+{
+ int saved_errno = errno;
+ size_t i;
+
+ for (i = 0; i < num; i++) {
+ if (array[i] == -1) {
+ continue;
+ }
+ libc_close(array[i]);
+ }
+
+ errno = saved_errno;
+}
+
+union __swrap_fds {
+ const uint8_t *p;
+ int *fds;
+};
+
+union __swrap_cmsghdr {
+ const uint8_t *p;
+ struct cmsghdr *cmsg;
+};
+
+static int swrap_sendmsg_unix_scm_rights(const struct cmsghdr *cmsg,
+ uint8_t **cm_data,
+ size_t *cm_data_space,
+ int *scm_rights_pipe_fd)
+{
+ struct swrap_unix_scm_rights info;
+ struct swrap_unix_scm_rights_payload *payload = NULL;
+ int si_idx_array[SWRAP_MAX_PASSED_FDS];
+ struct socket_info *si_array[SWRAP_MAX_PASSED_FDS] = { NULL, };
+ size_t info_idx = 0;
+ size_t size_fds_in;
+ size_t num_fds_in;
+ union __swrap_fds __fds_in = { .p = NULL, };
+ const int *fds_in = NULL;
+ size_t num_fds_out;
+ size_t size_fds_out;
+ union __swrap_fds __fds_out = { .p = NULL, };
+ int *fds_out = NULL;
+ size_t cmsg_len;
+ size_t cmsg_space;
+ size_t new_cm_data_space;
+ union __swrap_cmsghdr __new_cmsg = { .p = NULL, };
+ struct cmsghdr *new_cmsg = NULL;
+ uint8_t *p = NULL;
+ size_t i;
+ int pipefd[2] = { -1, -1 };
+ int rc;
+ ssize_t sret;
+
+ /*
+ * We pass this a buffer to the kernel make sure any padding
+ * is also cleared.
+ */
+ ZERO_STRUCT(info);
+ info.magic = swrap_unix_scm_right_magic;
+ memcpy(info.package_name,
+ SOCKET_WRAPPER_PACKAGE,
+ sizeof(info.package_name));
+ memcpy(info.package_version,
+ SOCKET_WRAPPER_VERSION,
+ sizeof(info.package_version));
+ info.full_size = sizeof(info);
+ info.payload_size = sizeof(info.payload);
+ payload = &info.payload;
+
+ if (*scm_rights_pipe_fd != -1) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "Two SCM_RIGHTS headers are not supported by socket_wrapper");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (cmsg->cmsg_len < CMSG_LEN(0)) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "cmsg->cmsg_len=%zu < CMSG_LEN(0)=%zu",
+ (size_t)cmsg->cmsg_len,
+ CMSG_LEN(0));
+ errno = EINVAL;
+ return -1;
+ }
+ size_fds_in = cmsg->cmsg_len - CMSG_LEN(0);
+ if ((size_fds_in % sizeof(int)) != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "cmsg->cmsg_len=%zu => (size_fds_in=%zu %% sizeof(int)=%zu) != 0",
+ (size_t)cmsg->cmsg_len,
+ size_fds_in,
+ sizeof(int));
+ errno = EINVAL;
+ return -1;
+ }
+ num_fds_in = size_fds_in / sizeof(int);
+ if (num_fds_in > SWRAP_MAX_PASSED_FDS) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "cmsg->cmsg_len=%zu,size_fds_in=%zu => "
+ "num_fds_in=%zu > "
+ "SWRAP_MAX_PASSED_FDS(%zu)",
+ (size_t)cmsg->cmsg_len,
+ size_fds_in,
+ num_fds_in,
+ SWRAP_MAX_PASSED_FDS);
+ errno = EINVAL;
+ return -1;
+ }
+ if (num_fds_in == 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "cmsg->cmsg_len=%zu,size_fds_in=%zu => "
+ "num_fds_in=%zu",
+ (size_t)cmsg->cmsg_len,
+ size_fds_in,
+ num_fds_in);
+ errno = EINVAL;
+ return -1;
+ }
+ __fds_in.p = CMSG_DATA(cmsg);
+ fds_in = __fds_in.fds;
+ num_fds_out = num_fds_in + 1;
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "num_fds_in=%zu num_fds_out=%zu",
+ num_fds_in, num_fds_out);
+
+ size_fds_out = sizeof(int) * num_fds_out;
+ cmsg_len = CMSG_LEN(size_fds_out);
+ cmsg_space = CMSG_SPACE(size_fds_out);
+
+ new_cm_data_space = *cm_data_space + cmsg_space;
+
+ p = realloc((*cm_data), new_cm_data_space);
+ if (p == NULL) {
+ return -1;
+ }
+ (*cm_data) = p;
+ p = (*cm_data) + (*cm_data_space);
+ memset(p, 0, cmsg_space);
+ __new_cmsg.p = p;
+ new_cmsg = __new_cmsg.cmsg;
+ *new_cmsg = *cmsg;
+ __fds_out.p = CMSG_DATA(new_cmsg);
+ fds_out = __fds_out.fds;
+ memcpy(fds_out, fds_in, size_fds_in);
+ new_cmsg->cmsg_len = cmsg->cmsg_len;
+
+ for (i = 0; i < num_fds_in; i++) {
+ size_t j;
+
+ payload->idxs[i] = -1;
+ payload->num_idxs++;
+
+ si_idx_array[i] = find_socket_info_index(fds_in[i]);
+ if (si_idx_array[i] == -1) {
+ continue;
+ }
+
+ si_array[i] = swrap_get_socket_info(si_idx_array[i]);
+ if (si_array[i] == NULL) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "fds_in[%zu]=%d si_idx_array[%zu]=%d missing!",
+ i, fds_in[i], i, si_idx_array[i]);
+ errno = EINVAL;
+ return -1;
+ }
+
+ for (j = 0; j < i; j++) {
+ if (si_array[j] == si_array[i]) {
+ payload->idxs[i] = payload->idxs[j];
+ break;
+ }
+ }
+ if (payload->idxs[i] == -1) {
+ if (info_idx >= SWRAP_MAX_PASSED_SOCKET_INFO) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "fds_in[%zu]=%d,si_idx_array[%zu]=%d: "
+ "info_idx=%zu >= SWRAP_MAX_PASSED_FDS(%zu)!",
+ i, fds_in[i], i, si_idx_array[i],
+ info_idx,
+ SWRAP_MAX_PASSED_SOCKET_INFO);
+ errno = EINVAL;
+ return -1;
+ }
+ payload->idxs[i] = info_idx;
+ info_idx += 1;
+ continue;
+ }
+ }
+
+ for (i = 0; i < num_fds_in; i++) {
+ struct socket_info *si = si_array[i];
+
+ if (si == NULL) {
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "fds_in[%zu]=%d not an inet socket",
+ i, fds_in[i]);
+ continue;
+ }
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "fds_in[%zu]=%d si_idx_array[%zu]=%d "
+ "passing as info.idxs[%zu]=%d!",
+ i, fds_in[i],
+ i, si_idx_array[i],
+ i, payload->idxs[i]);
+
+ SWRAP_LOCK_SI(si);
+ si->fd_passed += 1;
+ payload->infos[payload->idxs[i]] = *si;
+ payload->infos[payload->idxs[i]].fd_passed = 0;
+ SWRAP_UNLOCK_SI(si);
+ }
+
+ rc = pipe(pipefd);
+ if (rc == -1) {
+ int saved_errno = errno;
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "pipe() failed - %d %s",
+ saved_errno,
+ strerror(saved_errno));
+ swrap_dec_fd_passed_array(num_fds_in, si_array);
+ errno = saved_errno;
+ return -1;
+ }
+
+ sret = libc_write(pipefd[1], &info, sizeof(info));
+ if (sret != sizeof(info)) {
+ int saved_errno = errno;
+ if (sret != -1) {
+ saved_errno = EINVAL;
+ }
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "write() failed - sret=%zd - %d %s",
+ sret, saved_errno,
+ strerror(saved_errno));
+ swrap_dec_fd_passed_array(num_fds_in, si_array);
+ libc_close(pipefd[1]);
+ libc_close(pipefd[0]);
+ errno = saved_errno;
+ return -1;
+ }
+ libc_close(pipefd[1]);
+
+ /*
+ * Add the pipe read end to the end of the passed fd array
+ */
+ fds_out[num_fds_in] = pipefd[0];
+ new_cmsg->cmsg_len = cmsg_len;
+
+ /* we're done ... */
+ *scm_rights_pipe_fd = pipefd[0];
+ *cm_data_space = new_cm_data_space;
+
+ return 0;
+}
+
+static int swrap_sendmsg_unix_sol_socket(const struct cmsghdr *cmsg,
+ uint8_t **cm_data,
+ size_t *cm_data_space,
+ int *scm_rights_pipe_fd)
+{
+ int rc = -1;
+
+ switch (cmsg->cmsg_type) {
+ case SCM_RIGHTS:
+ rc = swrap_sendmsg_unix_scm_rights(cmsg,
+ cm_data,
+ cm_data_space,
+ scm_rights_pipe_fd);
+ break;
+ default:
+ rc = swrap_sendmsg_copy_cmsg(cmsg,
+ cm_data,
+ cm_data_space);
+ break;
+ }
+
+ return rc;
+}
+
+static int swrap_recvmsg_unix_scm_rights(const struct cmsghdr *cmsg,
+ uint8_t **cm_data,
+ size_t *cm_data_space)
+{
+ int scm_rights_pipe_fd = -1;
+ struct swrap_unix_scm_rights info;
+ struct swrap_unix_scm_rights_payload *payload = NULL;
+ int si_idx_array[SWRAP_MAX_PASSED_FDS];
+ size_t size_fds_in;
+ size_t num_fds_in;
+ union __swrap_fds __fds_in = { .p = NULL, };
+ const int *fds_in = NULL;
+ size_t num_fds_out;
+ size_t size_fds_out;
+ union __swrap_fds __fds_out = { .p = NULL, };
+ int *fds_out = NULL;
+ size_t cmsg_len;
+ size_t cmsg_space;
+ size_t new_cm_data_space;
+ union __swrap_cmsghdr __new_cmsg = { .p = NULL, };
+ struct cmsghdr *new_cmsg = NULL;
+ uint8_t *p = NULL;
+ ssize_t sret;
+ size_t i;
+ int cmp;
+
+ if (cmsg->cmsg_len < CMSG_LEN(0)) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "cmsg->cmsg_len=%zu < CMSG_LEN(0)=%zu",
+ (size_t)cmsg->cmsg_len,
+ CMSG_LEN(0));
+ errno = EINVAL;
+ return -1;
+ }
+ size_fds_in = cmsg->cmsg_len - CMSG_LEN(0);
+ if ((size_fds_in % sizeof(int)) != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "cmsg->cmsg_len=%zu => (size_fds_in=%zu %% sizeof(int)=%zu) != 0",
+ (size_t)cmsg->cmsg_len,
+ size_fds_in,
+ sizeof(int));
+ errno = EINVAL;
+ return -1;
+ }
+ num_fds_in = size_fds_in / sizeof(int);
+ if (num_fds_in > (SWRAP_MAX_PASSED_FDS + 1)) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "cmsg->cmsg_len=%zu,size_fds_in=%zu => "
+ "num_fds_in=%zu > SWRAP_MAX_PASSED_FDS+1(%zu)",
+ (size_t)cmsg->cmsg_len,
+ size_fds_in,
+ num_fds_in,
+ SWRAP_MAX_PASSED_FDS+1);
+ errno = EINVAL;
+ return -1;
+ }
+ if (num_fds_in <= 1) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "cmsg->cmsg_len=%zu,size_fds_in=%zu => "
+ "num_fds_in=%zu",
+ (size_t)cmsg->cmsg_len,
+ size_fds_in,
+ num_fds_in);
+ errno = EINVAL;
+ return -1;
+ }
+ __fds_in.p = CMSG_DATA(cmsg);
+ fds_in = __fds_in.fds;
+ num_fds_out = num_fds_in - 1;
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "num_fds_in=%zu num_fds_out=%zu",
+ num_fds_in, num_fds_out);
+
+ for (i = 0; i < num_fds_in; i++) {
+ /* Check if we have a stale fd and remove it */
+ swrap_remove_stale(fds_in[i]);
+ }
+
+ scm_rights_pipe_fd = fds_in[num_fds_out];
+ size_fds_out = sizeof(int) * num_fds_out;
+ cmsg_len = CMSG_LEN(size_fds_out);
+ cmsg_space = CMSG_SPACE(size_fds_out);
+
+ new_cm_data_space = *cm_data_space + cmsg_space;
+
+ p = realloc((*cm_data), new_cm_data_space);
+ if (p == NULL) {
+ swrap_close_fd_array(num_fds_in, fds_in);
+ return -1;
+ }
+ (*cm_data) = p;
+ p = (*cm_data) + (*cm_data_space);
+ memset(p, 0, cmsg_space);
+ __new_cmsg.p = p;
+ new_cmsg = __new_cmsg.cmsg;
+ *new_cmsg = *cmsg;
+ __fds_out.p = CMSG_DATA(new_cmsg);
+ fds_out = __fds_out.fds;
+ memcpy(fds_out, fds_in, size_fds_out);
+ new_cmsg->cmsg_len = cmsg_len;
+
+ sret = read(scm_rights_pipe_fd, &info, sizeof(info));
+ if (sret != sizeof(info)) {
+ int saved_errno = errno;
+ if (sret != -1) {
+ saved_errno = EINVAL;
+ }
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "read() failed - sret=%zd - %d %s",
+ sret, saved_errno,
+ strerror(saved_errno));
+ swrap_close_fd_array(num_fds_in, fds_in);
+ errno = saved_errno;
+ return -1;
+ }
+ libc_close(scm_rights_pipe_fd);
+ payload = &info.payload;
+
+ if (info.magic != swrap_unix_scm_right_magic) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "info.magic=0x%llx != swrap_unix_scm_right_magic=0x%llx",
+ (unsigned long long)info.magic,
+ (unsigned long long)swrap_unix_scm_right_magic);
+ swrap_close_fd_array(num_fds_out, fds_out);
+ errno = EINVAL;
+ return -1;
+ }
+
+ cmp = memcmp(info.package_name,
+ SOCKET_WRAPPER_PACKAGE,
+ sizeof(info.package_name));
+ if (cmp != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "info.package_name='%.*s' != '%s'",
+ (int)sizeof(info.package_name),
+ info.package_name,
+ SOCKET_WRAPPER_PACKAGE);
+ swrap_close_fd_array(num_fds_out, fds_out);
+ errno = EINVAL;
+ return -1;
+ }
+
+ cmp = memcmp(info.package_version,
+ SOCKET_WRAPPER_VERSION,
+ sizeof(info.package_version));
+ if (cmp != 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "info.package_version='%.*s' != '%s'",
+ (int)sizeof(info.package_version),
+ info.package_version,
+ SOCKET_WRAPPER_VERSION);
+ swrap_close_fd_array(num_fds_out, fds_out);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (info.full_size != sizeof(info)) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "info.full_size=%zu != sizeof(info)=%zu",
+ (size_t)info.full_size,
+ sizeof(info));
+ swrap_close_fd_array(num_fds_out, fds_out);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (info.payload_size != sizeof(info.payload)) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "info.payload_size=%zu != sizeof(info.payload)=%zu",
+ (size_t)info.payload_size,
+ sizeof(info.payload));
+ swrap_close_fd_array(num_fds_out, fds_out);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (payload->num_idxs != num_fds_out) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "info.num_idxs=%u != num_fds_out=%zu",
+ payload->num_idxs, num_fds_out);
+ swrap_close_fd_array(num_fds_out, fds_out);
+ errno = EINVAL;
+ return -1;
+ }
+
+ for (i = 0; i < num_fds_out; i++) {
+ size_t j;
+
+ si_idx_array[i] = -1;
+
+ if (payload->idxs[i] == -1) {
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "fds_out[%zu]=%d not an inet socket",
+ i, fds_out[i]);
+ continue;
+ }
+
+ if (payload->idxs[i] < 0) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "fds_out[%zu]=%d info.idxs[%zu]=%d < 0!",
+ i, fds_out[i], i, payload->idxs[i]);
+ swrap_close_fd_array(num_fds_out, fds_out);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (payload->idxs[i] >= payload->num_idxs) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "fds_out[%zu]=%d info.idxs[%zu]=%d >= %u!",
+ i, fds_out[i], i, payload->idxs[i],
+ payload->num_idxs);
+ swrap_close_fd_array(num_fds_out, fds_out);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((size_t)fds_out[i] >= socket_fds_max) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "The max socket index limit of %zu has been reached, "
+ "trying to add %d",
+ socket_fds_max,
+ fds_out[i]);
+ swrap_close_fd_array(num_fds_out, fds_out);
+ errno = EMFILE;
+ return -1;
+ }
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "fds_in[%zu]=%d "
+ "received as info.idxs[%zu]=%d!",
+ i, fds_out[i],
+ i, payload->idxs[i]);
+
+ for (j = 0; j < i; j++) {
+ if (payload->idxs[j] == -1) {
+ continue;
+ }
+ if (payload->idxs[j] == payload->idxs[i]) {
+ si_idx_array[i] = si_idx_array[j];
+ }
+ }
+ if (si_idx_array[i] == -1) {
+ const struct socket_info *si = &payload->infos[payload->idxs[i]];
+
+ si_idx_array[i] = swrap_add_socket_info(si);
+ if (si_idx_array[i] == -1) {
+ int saved_errno = errno;
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "The max socket index limit of %zu has been reached, "
+ "trying to add %d",
+ socket_fds_max,
+ fds_out[i]);
+ swrap_undo_si_idx_array(i, si_idx_array);
+ swrap_close_fd_array(num_fds_out, fds_out);
+ errno = saved_errno;
+ return -1;
+ }
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "Imported %s socket for protocol %s, fd=%d",
+ si->family == AF_INET ? "IPv4" : "IPv6",
+ si->type == SOCK_DGRAM ? "UDP" : "TCP",
+ fds_out[i]);
+ }
+ }
+
+ for (i = 0; i < num_fds_out; i++) {
+ if (si_idx_array[i] == -1) {
+ continue;
+ }
+ set_socket_info_index(fds_out[i], si_idx_array[i]);
+ }
+
+ /* we're done ... */
+ *cm_data_space = new_cm_data_space;
+
+ return 0;
+}
+
+static int swrap_recvmsg_unix_sol_socket(const struct cmsghdr *cmsg,
+ uint8_t **cm_data,
+ size_t *cm_data_space)
+{
+ int rc = -1;
+
+ switch (cmsg->cmsg_type) {
+ case SCM_RIGHTS:
+ rc = swrap_recvmsg_unix_scm_rights(cmsg,
+ cm_data,
+ cm_data_space);
+ break;
+ default:
+ rc = swrap_sendmsg_copy_cmsg(cmsg,
+ cm_data,
+ cm_data_space);
+ break;
+ }
+
+ return rc;
+}
+
+#endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+
+static int swrap_sendmsg_before_unix(const struct msghdr *_msg_in,
+ struct msghdr *msg_tmp,
+ int *scm_rights_pipe_fd)
+{
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ struct msghdr *msg_in = discard_const_p(struct msghdr, _msg_in);
+ struct cmsghdr *cmsg = NULL;
+ uint8_t *cm_data = NULL;
+ size_t cm_data_space = 0;
+ int rc = -1;
+
+ *msg_tmp = *msg_in;
+ *scm_rights_pipe_fd = -1;
+
+ /* Nothing to do */
+ if (msg_in->msg_controllen == 0 || msg_in->msg_control == NULL) {
+ return 0;
+ }
+
+ for (cmsg = CMSG_FIRSTHDR(msg_in);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(msg_in, cmsg)) {
+ switch (cmsg->cmsg_level) {
+ case SOL_SOCKET:
+ rc = swrap_sendmsg_unix_sol_socket(cmsg,
+ &cm_data,
+ &cm_data_space,
+ scm_rights_pipe_fd);
+ break;
+
+ default:
+ rc = swrap_sendmsg_copy_cmsg(cmsg,
+ &cm_data,
+ &cm_data_space);
+ break;
+ }
+ if (rc < 0) {
+ int saved_errno = errno;
+ SAFE_FREE(cm_data);
+ errno = saved_errno;
+ return rc;
+ }
+ }
+
+ msg_tmp->msg_controllen = cm_data_space;
+ msg_tmp->msg_control = cm_data;
+
+ return 0;
+#else /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+ *msg_tmp = *_msg_in;
+ return 0;
+#endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+}
+
+static ssize_t swrap_sendmsg_after_unix(struct msghdr *msg_tmp,
+ ssize_t ret,
+ int scm_rights_pipe_fd)
+{
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ int saved_errno = errno;
+ SAFE_FREE(msg_tmp->msg_control);
+ if (scm_rights_pipe_fd != -1) {
+ libc_close(scm_rights_pipe_fd);
+ }
+ errno = saved_errno;
+#endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+ return ret;
+}
+
+static int swrap_recvmsg_before_unix(struct msghdr *msg_in,
+ struct msghdr *msg_tmp,
+ uint8_t **tmp_control)
+{
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ const size_t cm_extra_space = CMSG_SPACE(sizeof(int));
+ uint8_t *cm_data = NULL;
+ size_t cm_data_space = 0;
+
+ *msg_tmp = *msg_in;
+ *tmp_control = NULL;
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "msg_in->msg_controllen=%zu",
+ (size_t)msg_in->msg_controllen);
+
+ /* Nothing to do */
+ if (msg_in->msg_controllen == 0 || msg_in->msg_control == NULL) {
+ return 0;
+ }
+
+ /*
+ * We need to give the kernel a bit more space in order
+ * recv the pipe fd, added by swrap_sendmsg_before_unix()).
+ * swrap_recvmsg_after_unix() will hide it again.
+ */
+ cm_data_space = msg_in->msg_controllen;
+ if (cm_data_space < (INT32_MAX - cm_extra_space)) {
+ cm_data_space += cm_extra_space;
+ }
+ cm_data = calloc(1, cm_data_space);
+ if (cm_data == NULL) {
+ return -1;
+ }
+
+ msg_tmp->msg_controllen = cm_data_space;
+ msg_tmp->msg_control = cm_data;
+ *tmp_control = cm_data;
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "msg_tmp->msg_controllen=%zu",
+ (size_t)msg_tmp->msg_controllen);
+ return 0;
+#else /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+ *msg_tmp = *msg_in;
+ *tmp_control = NULL;
+ return 0;
+#endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+}
+
+static ssize_t swrap_recvmsg_after_unix(struct msghdr *msg_tmp,
+ uint8_t **tmp_control,
+ struct msghdr *msg_out,
+ ssize_t ret)
+{
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ struct cmsghdr *cmsg = NULL;
+ uint8_t *cm_data = NULL;
+ size_t cm_data_space = 0;
+ int rc = -1;
+
+ if (ret < 0) {
+ int saved_errno = errno;
+ SWRAP_LOG(SWRAP_LOG_TRACE, "ret=%zd - %d - %s", ret,
+ saved_errno, strerror(saved_errno));
+ SAFE_FREE(*tmp_control);
+ /* msg_out should not be touched on error */
+ errno = saved_errno;
+ return ret;
+ }
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "msg_tmp->msg_controllen=%zu",
+ (size_t)msg_tmp->msg_controllen);
+
+ /* Nothing to do */
+ if (msg_tmp->msg_controllen == 0 || msg_tmp->msg_control == NULL) {
+ int saved_errno = errno;
+ *msg_out = *msg_tmp;
+ SAFE_FREE(*tmp_control);
+ errno = saved_errno;
+ return ret;
+ }
+
+ for (cmsg = CMSG_FIRSTHDR(msg_tmp);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(msg_tmp, cmsg)) {
+ switch (cmsg->cmsg_level) {
+ case SOL_SOCKET:
+ rc = swrap_recvmsg_unix_sol_socket(cmsg,
+ &cm_data,
+ &cm_data_space);
+ break;
+
+ default:
+ rc = swrap_sendmsg_copy_cmsg(cmsg,
+ &cm_data,
+ &cm_data_space);
+ break;
+ }
+ if (rc < 0) {
+ int saved_errno = errno;
+ SAFE_FREE(cm_data);
+ SAFE_FREE(*tmp_control);
+ errno = saved_errno;
+ return rc;
+ }
+ }
+
+ /*
+ * msg_tmp->msg_control (*tmp_control) was created by
+ * swrap_recvmsg_before_unix() and msg_out->msg_control
+ * is still the buffer of the caller.
+ */
+ msg_tmp->msg_control = msg_out->msg_control;
+ msg_tmp->msg_controllen = msg_out->msg_controllen;
+ *msg_out = *msg_tmp;
+
+ cm_data_space = MIN(cm_data_space, msg_out->msg_controllen);
+ memcpy(msg_out->msg_control, cm_data, cm_data_space);
+ msg_out->msg_controllen = cm_data_space;
+ SAFE_FREE(cm_data);
+ SAFE_FREE(*tmp_control);
+
+ SWRAP_LOG(SWRAP_LOG_TRACE,
+ "msg_out->msg_controllen=%zu",
+ (size_t)msg_out->msg_controllen);
+ return ret;
+#else /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+ int saved_errno = errno;
+ *msg_out = *msg_tmp;
+ SAFE_FREE(*tmp_control);
+ errno = saved_errno;
+ return ret;
+#endif /* ! HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+}
+
+static ssize_t swrap_sendmsg_before(int fd,
+ struct socket_info *si,
+ struct msghdr *msg,
+ struct iovec *tmp_iov,
+ struct sockaddr_un *tmp_un,
+ const struct sockaddr_un **to_un,
+ const struct sockaddr **to,
+ int *bcast)
+{
+ size_t i, len = 0;
+ ssize_t ret = -1;
+
+ if (to_un) {
+ *to_un = NULL;
}
if (to) {
*to = NULL;
@@ -5215,28 +6235,6 @@
goto out;
}
-#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
- if (msg->msg_controllen > 0 && msg->msg_control != NULL) {
- uint8_t *cmbuf = NULL;
- size_t cmlen = 0;
-
- ret = swrap_sendmsg_filter_cmsghdr(msg, &cmbuf, &cmlen);
- if (ret < 0) {
- free(cmbuf);
- goto out;
- }
-
- if (cmlen == 0) {
- msg->msg_controllen = 0;
- msg->msg_control = NULL;
- } else if (cmlen < msg->msg_controllen && cmbuf != NULL) {
- memcpy(msg->msg_control, cmbuf, cmlen);
- msg->msg_controllen = cmlen;
- }
- free(cmbuf);
- }
-#endif
-
ret = 0;
out:
SWRAP_UNLOCK_SI(si);
@@ -6003,7 +7001,13 @@
si = find_socket_info(s);
if (si == NULL) {
- return libc_recvmsg(s, omsg, flags);
+ uint8_t *tmp_control = NULL;
+ rc = swrap_recvmsg_before_unix(omsg, &msg, &tmp_control);
+ if (rc < 0) {
+ return rc;
+ }
+ ret = libc_recvmsg(s, &msg, flags);
+ return swrap_recvmsg_after_unix(&msg, &tmp_control, omsg, ret);
}
tmp.iov_base = NULL;
@@ -6126,7 +7130,15 @@
int bcast = 0;
if (!si) {
- return libc_sendmsg(s, omsg, flags);
+ int scm_rights_pipe_fd = -1;
+
+ rc = swrap_sendmsg_before_unix(omsg, &msg,
+ &scm_rights_pipe_fd);
+ if (rc < 0) {
+ return rc;
+ }
+ ret = libc_sendmsg(s, &msg, flags);
+ return swrap_sendmsg_after_unix(&msg, ret, scm_rights_pipe_fd);
}
ZERO_STRUCT(un_addr);
@@ -6148,20 +7160,32 @@
SWRAP_UNLOCK_SI(si);
#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
- if (msg.msg_controllen > 0 && msg.msg_control != NULL) {
- /* omsg is a const so use a local buffer for modifications */
- uint8_t cmbuf[omsg->msg_controllen];
+ if (omsg != NULL && omsg->msg_controllen > 0 && omsg->msg_control != NULL) {
+ uint8_t *cmbuf = NULL;
+ size_t cmlen = 0;
- memcpy(cmbuf, omsg->msg_control, omsg->msg_controllen);
+ rc = swrap_sendmsg_filter_cmsghdr(omsg, &cmbuf, &cmlen);
+ if (rc < 0) {
+ return rc;
+ }
- msg.msg_control = cmbuf; /* ancillary data, see below */
- msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
+ if (cmlen == 0) {
+ msg.msg_controllen = 0;
+ msg.msg_control = NULL;
+ } else {
+ msg.msg_control = cmbuf;
+ msg.msg_controllen = cmlen;
+ }
}
msg.msg_flags = omsg->msg_flags; /* flags on received message */
#endif
-
rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, &to_un, &to, &bcast);
if (rc < 0) {
+ int saved_errno = errno;
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ SAFE_FREE(msg.msg_control);
+#endif
+ errno = saved_errno;
return -1;
}
@@ -6187,6 +7211,11 @@
/* we capture it as one single packet */
buf = (uint8_t *)malloc(remain);
if (!buf) {
+ int saved_errno = errno;
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ SAFE_FREE(msg.msg_control);
+#endif
+ errno = saved_errno;
return -1;
}
@@ -6203,7 +7232,12 @@
swrap_dir = socket_wrapper_dir();
if (swrap_dir == NULL) {
- free(buf);
+ int saved_errno = errno;
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ SAFE_FREE(msg.msg_control);
+#endif
+ SAFE_FREE(buf);
+ errno = saved_errno;
return -1;
}
@@ -6234,6 +7268,14 @@
swrap_sendmsg_after(s, si, &msg, to, ret);
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+ {
+ int saved_errno = errno;
+ SAFE_FREE(msg.msg_control);
+ errno = saved_errno;
+ }
+#endif
+
return ret;
}
@@ -6354,10 +7396,13 @@
* CLOSE
***************************/
-static int swrap_close(int fd)
+static int swrap_remove_wrapper(const char *__func_name,
+ int (*__close_fd_fn)(int fd),
+ int fd)
{
struct socket_info *si = NULL;
int si_index;
+ int ret_errno = errno;
int ret;
swrap_mutex_lock(&socket_reset_mutex);
@@ -6365,10 +7410,10 @@
si_index = find_socket_info_index(fd);
if (si_index == -1) {
swrap_mutex_unlock(&socket_reset_mutex);
- return libc_close(fd);
+ return __close_fd_fn(fd);
}
- SWRAP_LOG(SWRAP_LOG_TRACE, "Close wrapper for fd=%d", fd);
+ swrap_log(SWRAP_LOG_TRACE, __func_name, "Remove wrapper for fd=%d", fd);
reset_socket_info_index(fd);
si = swrap_get_socket_info(si_index);
@@ -6376,7 +7421,10 @@
swrap_mutex_lock(&first_free_mutex);
SWRAP_LOCK_SI(si);
- ret = libc_close(fd);
+ ret = __close_fd_fn(fd);
+ if (ret == -1) {
+ ret_errno = errno;
+ }
swrap_dec_refcount(si);
@@ -6385,6 +7433,10 @@
goto out;
}
+ if (si->fd_passed) {
+ goto set_next_free;
+ }
+
if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) {
swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0);
}
@@ -6398,6 +7450,7 @@
unlink(si->un_addr.sun_path);
}
+set_next_free:
swrap_set_next_free(si, first_free);
first_free = si_index;
@@ -6406,14 +7459,68 @@
swrap_mutex_unlock(&first_free_mutex);
swrap_mutex_unlock(&socket_reset_mutex);
+ errno = ret_errno;
return ret;
}
+static int swrap_noop_close(int fd)
+{
+ (void)fd; /* unused */
+ return 0;
+}
+
+static void swrap_remove_stale(int fd)
+{
+ swrap_remove_wrapper(__func__, swrap_noop_close, fd);
+}
+
+/*
+ * This allows socket_wrapper aware applications to
+ * indicate that the given fd does not belong to
+ * an inet socket.
+ *
+ * We already overload a lot of unrelated functions
+ * like eventfd(), timerfd_create(), ... in order to
+ * call swrap_remove_stale() on the returned fd, but
+ * we'll never be able to handle all possible syscalls.
+ *
+ * socket_wrapper_indicate_no_inet_fd() gives them a way
+ * to do the same.
+ *
+ * We don't export swrap_remove_stale() in order to
+ * make it easier to analyze SOCKET_WRAPPER_DEBUGLEVEL=3
+ * log files.
+ */
+void socket_wrapper_indicate_no_inet_fd(int fd)
+{
+ swrap_remove_wrapper(__func__, swrap_noop_close, fd);
+}
+
+static int swrap_close(int fd)
+{
+ return swrap_remove_wrapper(__func__, libc_close, fd);
+}
+
int close(int fd)
{
return swrap_close(fd);
}
+#ifdef HAVE___CLOSE_NOCANCEL
+
+static int swrap___close_nocancel(int fd)
+{
+ return swrap_remove_wrapper(__func__, libc___close_nocancel, fd);
+}
+
+int __close_nocancel(int fd);
+int __close_nocancel(int fd)
+{
+ return swrap___close_nocancel(fd);
+}
+
+#endif /* HAVE___CLOSE_NOCANCEL */
+
/****************************
* DUP
***************************/
@@ -6437,6 +7544,17 @@
return -1;
}
+ if ((size_t)dup_fd >= socket_fds_max) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "The max socket index limit of %zu has been reached, "
+ "trying to add %d",
+ socket_fds_max,
+ dup_fd);
+ libc_close(dup_fd);
+ errno = EMFILE;
+ return -1;
+ }
+
SWRAP_LOCK_SI(si);
swrap_inc_refcount(si);
@@ -6482,6 +7600,16 @@
return newfd;
}
+ if ((size_t)newfd >= socket_fds_max) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "The max socket index limit of %zu has been reached, "
+ "trying to add %d",
+ socket_fds_max,
+ newfd);
+ errno = EMFILE;
+ return -1;
+ }
+
if (find_socket_info(newfd)) {
/* dup2() does an implicit close of newfd, which we
* need to emulate */
@@ -6539,14 +7667,26 @@
return -1;
}
+ /* Make sure we don't have an entry for the fd */
+ swrap_remove_stale(dup_fd);
+
+ if ((size_t)dup_fd >= socket_fds_max) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "The max socket index limit of %zu has been reached, "
+ "trying to add %d",
+ socket_fds_max,
+ dup_fd);
+ libc_close(dup_fd);
+ errno = EMFILE;
+ return -1;
+ }
+
SWRAP_LOCK_SI(si);
swrap_inc_refcount(si);
SWRAP_UNLOCK_SI(si);
- /* Make sure we don't have an entry for the fd */
- swrap_remove_stale(dup_fd);
set_socket_info_index(dup_fd, idx);
@@ -6632,7 +7772,7 @@
static void swrap_thread_child(void)
{
- SWRAP_UNLOCK_ALL;
+ SWRAP_REINIT_ALL;
}
/****************************
@@ -6640,7 +7780,20 @@
***************************/
void swrap_constructor(void)
{
- int ret;
+ if (PIPE_BUF < sizeof(struct swrap_unix_scm_rights)) {
+ SWRAP_LOG(SWRAP_LOG_ERROR,
+ "PIPE_BUF=%zu < "
+ "sizeof(struct swrap_unix_scm_rights)=%zu\n"
+ "sizeof(struct swrap_unix_scm_rights_payload)=%zu "
+ "sizeof(struct socket_info)=%zu",
+ (size_t)PIPE_BUF,
+ sizeof(struct swrap_unix_scm_rights),
+ sizeof(struct swrap_unix_scm_rights_payload),
+ sizeof(struct socket_info));
+ exit(-1);
+ }
+
+ SWRAP_REINIT_ALL;
/*
* If we hold a lock and the application forks, then the child
@@ -6650,27 +7803,6 @@
pthread_atfork(&swrap_thread_prepare,
&swrap_thread_parent,
&swrap_thread_child);
-
- ret = socket_wrapper_init_mutex(&sockets_mutex);
- if (ret != 0) {
- SWRAP_LOG(SWRAP_LOG_ERROR,
- "Failed to initialize pthread mutex");
- exit(-1);
- }
-
- ret = socket_wrapper_init_mutex(&socket_reset_mutex);
- if (ret != 0) {
- SWRAP_LOG(SWRAP_LOG_ERROR,
- "Failed to initialize pthread mutex");
- exit(-1);
- }
-
- ret = socket_wrapper_init_mutex(&first_free_mutex);
- if (ret != 0) {
- SWRAP_LOG(SWRAP_LOG_ERROR,
- "Failed to initialize pthread mutex");
- exit(-1);
- }
}
/****************************
diff -Nru samba-4.13.3+dfsg/third_party/socket_wrapper/socket_wrapper.h samba-4.13.14+dfsg/third_party/socket_wrapper/socket_wrapper.h
--- samba-4.13.3+dfsg/third_party/socket_wrapper/socket_wrapper.h 1970-01-01 00:00:00.000000000 +0000
+++ samba-4.13.14+dfsg/third_party/socket_wrapper/socket_wrapper.h 2021-08-06 12:19:57.000000000 +0000
@@ -0,0 +1,89 @@
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2005-2008, Jelmer Vernooij
+ * Copyright (c) 2006-2021, Stefan Metzmacher
+ * Copyright (c) 2013-2021, Andreas Schneider
+ * Copyright (c) 2014-2017, Michael Adam
+ * Copyright (c) 2016-2018, Anoop C S
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __SOCKET_WRAPPER_H__
+#define __SOCKET_WRAPPER_H__ 1
+
+#include
+
+/*
+ Socket wrapper advanced helpers.
+
+ Applications with the need to alter their behaviour when
+ socket wrapper is active, can link use these functions.
+
+ By default it's required for applications to use any of these
+ functions as libsocket_wrapper.so is injected at runtime via
+ LD_PRELOAD.
+
+ Applications using these functions should link against
+ libsocket_wrapper_noop.so by using -lsocket_wrapper_noop,
+ or implement their own noop stubs.
+*/
+
+/*
+ * This returns true when socket wrapper is actively in use.
+ */
+bool socket_wrapper_enabled(void);
+
+/*
+ * This allows socket_wrapper aware applications to
+ * indicate that the given fd does not belong to
+ * an inet socket.
+ *
+ * socket_wrapper may not be able to intercept the __close_nocancel()
+ * syscall made from within libc.so. As result it's possible
+ * that the in memory meta date of socket_wrapper references
+ * stale file descriptors, which are already reused for unrelated
+ * kernel objects, e.g. files, directories, ...
+ *
+ * Socket wrapper already intercepts a lot of unrelated
+ * functions like eventfd(), timerfd_create(), ... in order
+ * to remove stale meta data for the returned fd, but
+ * it will never be able to handle all possible syscalls.
+ *
+ * socket_wrapper_indicate_no_inet_fd() gives applications a way
+ * to do the same, explicitly without waiting for new syscalls to
+ * be added to libsocket_wrapper.so.
+ *
+ * This is a no-op if socket_wrapper is not in use or
+ * if the there is no in memory meta data for the given fd.
+ */
+void socket_wrapper_indicate_no_inet_fd(int fd);
+
+#endif /* __SOCKET_WRAPPER_H__ */
diff -Nru samba-4.13.3+dfsg/third_party/socket_wrapper/wscript samba-4.13.14+dfsg/third_party/socket_wrapper/wscript
--- samba-4.13.3+dfsg/third_party/socket_wrapper/wscript 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/third_party/socket_wrapper/wscript 2021-08-06 12:19:57.000000000 +0000
@@ -2,7 +2,7 @@
import os
-VERSION="1.2.4"
+VERSION="1.3.3"
def configure(conf):
if conf.CHECK_SOCKET_WRAPPER():
@@ -53,6 +53,7 @@
conf.CHECK_FUNCS('bindresvport')
conf.CHECK_FUNCS('pledge')
conf.CHECK_FUNCS('accept4')
+ conf.CHECK_FUNCS('__close_nocancel')
conf.CHECK_FUNCS_IN('bind',
'socket',
@@ -94,6 +95,11 @@
# breaks preloading!
bld.SAMBA_LIBRARY('socket_wrapper',
source='socket_wrapper.c',
+ cflags='-D%s="%s" -D%s="%s"' % (
+ "SOCKET_WRAPPER_PACKAGE",
+ "samba_socket_wrapper",
+ "SOCKET_WRAPPER_VERSION",
+ VERSION),
deps='dl pthread tirpc',
install=False,
realname='libsocket-wrapper.so')
diff -Nru samba-4.13.3+dfsg/VERSION samba-4.13.14+dfsg/VERSION
--- samba-4.13.3+dfsg/VERSION 2020-12-15 07:53:45.000000000 +0000
+++ samba-4.13.14+dfsg/VERSION 2021-11-08 11:29:14.000000000 +0000
@@ -25,7 +25,7 @@
########################################################
SAMBA_VERSION_MAJOR=4
SAMBA_VERSION_MINOR=13
-SAMBA_VERSION_RELEASE=3
+SAMBA_VERSION_RELEASE=14
########################################################
# If a official release has a serious bug #
diff -Nru samba-4.13.3+dfsg/WHATSNEW.txt samba-4.13.14+dfsg/WHATSNEW.txt
--- samba-4.13.3+dfsg/WHATSNEW.txt 2020-12-15 07:53:45.000000000 +0000
+++ samba-4.13.14+dfsg/WHATSNEW.txt 2021-11-08 11:29:14.000000000 +0000
@@ -1,3 +1,805 @@
+ ===============================
+ Release Notes for Samba 4.13.14
+ November 9, 2021
+ ===============================
+
+
+This is a security release in order to address the following defects:
+
+o CVE-2016-2124: SMB1 client connections can be downgraded to plaintext
+ authentication.
+ https://www.samba.org/samba/security/CVE-2016-2124.html
+
+o CVE-2020-25717: A user on the domain can become root on domain members.
+ https://www.samba.org/samba/security/CVE-2020-25717.html
+ (PLEASE READ! There are important behaviour changes described)
+
+o CVE-2020-25718: Samba AD DC did not correctly sandbox Kerberos tickets issued
+ by an RODC.
+ https://www.samba.org/samba/security/CVE-2020-25718.html
+
+o CVE-2020-25719: Samba AD DC did not always rely on the SID and PAC in Kerberos
+ tickets.
+ https://www.samba.org/samba/security/CVE-2020-25719.html
+
+o CVE-2020-25721: Kerberos acceptors need easy access to stable AD identifiers
+ (eg objectSid).
+ https://www.samba.org/samba/security/CVE-2020-25721.html
+
+o CVE-2020-25722: Samba AD DC did not do suffienct access and conformance
+ checking of data stored.
+ https://www.samba.org/samba/security/CVE-2020-25722.html
+
+o CVE-2021-3738: Use after free in Samba AD DC RPC server.
+ https://www.samba.org/samba/security/CVE-2021-3738.html
+
+o CVE-2021-23192: Subsequent DCE/RPC fragment injection vulnerability.
+ https://www.samba.org/samba/security/CVE-2021-23192.html
+
+
+Changes since 4.13.13
+---------------------
+
+o Douglas Bagnall
+ * CVE-2020-25722
+
+o Andrew Bartlett
+ * CVE-2020-25718
+ * CVE-2020-25719
+ * CVE-2020-25721
+ * CVE-2020-25722
+
+o Ralph Boehme
+ * CVE-2020-25717
+
+o Alexander Bokovoy
+ * CVE-2020-25717
+
+o Samuel Cabrero
+ * CVE-2020-25717
+
+o Nadezhda Ivanova
+ * CVE-2020-25722
+
+o Stefan Metzmacher
+ * CVE-2016-2124
+ * CVE-2020-25717
+ * CVE-2020-25719
+ * CVE-2020-25722
+ * CVE-2021-23192
+ * CVE-2021-3738
+ * ldb: version 2.2.3
+
+o Andreas Schneider
+ * CVE-2020-25719
+
+o Joseph Sutton
+ * CVE-2020-17049
+ * CVE-2020-25718
+ * CVE-2020-25719
+ * CVE-2020-25721
+ * CVE-2020-25722
+ * MS CVE-2020-17049
+
+
+#######################################
+Reporting bugs & Development Discussion
+#######################################
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical IRC channel on irc.libera.chat or the
+#samba-technical:matrix.org matrix channel.
+
+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.13.13
+ October 29, 2021
+ ===============================
+
+
+This is the latest stable release of the Samba 4.13 release series.
+
+
+Changes since 4.13.12
+---------------------
+
+o Douglas Bagnall
+ * BUG 14868: rodc_rwdc test flaps.
+ * BUG 14881: Backport bronze bit fixes, tests, and selftest improvements.
+
+o Andrew Bartlett
+ * BUG 14642: Provide a fix for MS CVE-2020-17049 in Samba [SECURITY] 'Bronze
+ bit' S4U2Proxy Constrained Delegation bypass in Samba with
+ embedded Heimdal.
+ * BUG 14836: Python ldb.msg_diff() memory handling failure.
+ * BUG 14845: "in" operator on ldb.Message is case sensitive.
+ * BUG 14848: Release LDB 2.3.1 for Samba 4.14.9.
+ * BUG 14871: Fix Samba support for UF_NO_AUTH_DATA_REQUIRED.
+ * BUG 14874: Allow special chars like "@" in samAccountName when generating
+ the salt.
+ * BUG 14881: Backport bronze bit fixes, tests, and selftest improvements.
+
+o Isaac Boukris
+ * BUG 14642: Provide a fix for MS CVE-2020-17049 in Samba [SECURITY] 'Bronze
+ bit' S4U2Proxy Constrained Delegation bypass in Samba with
+ embedded Heimdal.
+ * BUG 14881: Backport bronze bit fixes, tests, and selftest improvements.
+
+o Viktor Dukhovni
+ * BUG 12998: Fix transit path validation.
+ * BUG 14881: Backport bronze bit fixes, tests, and selftest improvements.
+
+o Luke Howard
+ * BUG 14642: Provide a fix for MS CVE-2020-17049 in Samba [SECURITY] 'Bronze
+ bit' S4U2Proxy Constrained Delegation bypass in Samba with
+ embedded Heimdal.
+ * BUG 14881: Backport bronze bit fixes, tests, and selftest improvements.
+
+o Stefan Metzmacher
+ * BUG 14881: Backport bronze bit fixes, tests, and selftest improvements.
+
+o David Mulder
+ * BUG 14881: Backport bronze bit fixes, tests, and selftest improvements.
+
+o Andreas Schneider
+ * BUG 14870: Prepare to operate with MIT krb5 >= 1.20.
+ * BUG 14881: Backport bronze bit fixes, tests, and selftest improvements.
+
+o Joseph Sutton
+ * BUG 14642: Provide a fix for MS CVE-2020-17049 in Samba [SECURITY] 'Bronze
+ bit' S4U2Proxy Constrained Delegation bypass in Samba with
+ embedded Heimdal.
+ * BUG 14645: rpcclient NetFileEnum and net rpc file both cause lock order
+ violation: brlock.tdb, share_entries.tdb.
+ * BUG 14836: Python ldb.msg_diff() memory handling failure.
+ * BUG 14845: "in" operator on ldb.Message is case sensitive.
+ * BUG 14848: Release LDB 2.3.1 for Samba 4.14.9.
+ * BUG 14868: rodc_rwdc test flaps.
+ * BUG 14871: Fix Samba support for UF_NO_AUTH_DATA_REQUIRED.
+ * BUG 14874: Allow special chars like "@" in samAccountName when generating
+ the salt.
+ * BUG 14881: Backport bronze bit fixes, tests, and selftest improvements.
+
+o Nicolas Williams
+ * BUG 14642: Provide a fix for MS CVE-2020-17049 in Samba [SECURITY] 'Bronze
+ bit' S4U2Proxy Constrained Delegation bypass in Samba with
+ embedded Heimdal.
+ * BUG 14881: Backport bronze bit fixes, tests, and selftest improvements.
+
+
+#######################################
+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 Samba 4.13.12
+ September 22, 2021
+ ===============================
+
+
+This is the latest stable release of the Samba 4.13 release series.
+
+
+Changes since 4.13.11
+---------------------
+
+o Andrew Bartlett
+ * BUG 14806: Address a signifcant performance regression in database access
+ in the AD DC since Samba 4.12.
+ * BUG 14807: Fix performance regression in lsa_LookupSids3/LookupNames4 since
+ Samba 4.9 by using an explicit database handle cache.
+ * BUG 14817: An unuthenticated user can crash the AD DC KDC by omitting the
+ server name in a TGS-REQ.
+ * BUG 14818: Address flapping samba_tool_drs_showrepl test.
+ * BUG 14819: Address flapping dsdb_schema_attributes test.
+
+o Björn Baumbach
+ * BUG 14817: An unuthenticated user can crash the AD DC KDC by omitting the
+ server name in a TGS-REQ
+
+o Luke Howard
+ * BUG 14817: An unuthenticated user can crash the AD DC KDC by omitting the
+ server name in a TGS-REQ.
+
+o Volker Lendecke
+ * BUG 14817: An unuthenticated user can crash the AD DC KDC by omitting the
+ server name in a TGS-REQ.
+
+o Gary Lockyer
+ * BUG 14817: An unuthenticated user can crash the AD DC KDC by omitting the
+ server name in a TGS-REQ.
+
+o Stefan Metzmacher
+ * BUG 14817: An unuthenticated user can crash the AD DC KDC by omitting the
+ server name in a TGS-REQ.
+
+o Andreas Schneider
+ * BUG 14817: An unuthenticated user can crash the AD DC KDC by omitting the
+ server name in a TGS-REQ.
+
+o Martin Schwenke
+ * BUG 14784: Fix CTDB flag/status update race conditions.
+
+o Joseph Sutton
+ * BUG 14817: An unuthenticated user can crash the AD DC KDC by omitting the
+ server name in a TGS-REQ.
+
+
+#######################################
+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 Samba 4.13.11
+ September 07, 2021
+ ===============================
+
+
+This is the latest stable release of the Samba 4.13 release series.
+
+
+Changes since 4.13.10
+---------------------
+
+o Jeremy Allison
+ * BUG 14769: smbd panic on force-close share during offload write.
+
+o Ralph Boehme
+ * BUG 14731: Fix returned attributes on fake quota file handle and avoid
+ hitting the VFS.
+ * BUG 14783: smbd "deadtime" parameter doesn't work anymore.
+ * BUG 14787: net conf list crashes when run as normal user.
+
+o Stefan Metzmacher
+ * BUG 14607: Work around special SMB2 READ response behavior of NetApp Ontap
+ 7.3.7.
+ * BUG 14793: Start the SMB encryption as soon as possible.
+
+o Andreas Schneider
+ * BUG 14792: Winbind should not start if the socket path for the privileged
+ pipe is too long.
+
+
+#######################################
+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 Samba 4.13.10
+ July 14, 2021
+ ===============================
+
+
+This is the latest stable release of the Samba 4.13 release series.
+
+
+Changes since 4.13.9
+--------------------
+
+o Jeremy Allison
+ * BUG 14708: s3: smbd: Ensure POSIX default ACL is mapped into returned
+ Windows ACL for directory handles.
+ * BUG 14721: Take a copy to make sure we don't reference free'd memory.
+ * BUG 14722: s3: lib: Fix talloc heirarcy error in parent_smb_fname().
+ * BUG 14736: s3: smbd: Remove erroneous TALLOC_FREE(smb_fname_parent) in
+ change_file_owner_to_parent() error path.
+
+o Andrew Bartlett
+ * BUG 14575: samba-tool: Give better error information when the
+ 'domain backup restore' fails with a duplicate SID.
+
+o Ralph Boehme
+ * BUG 14714: smbd: Correctly initialize close timestamp fields.
+ * BUG 14740: Spotlight RPC service doesn't work with vfs_glusterfs.
+
+o Volker Lendecke
+ * BUG 14475: ctdb: Fix a crash in run_proc_signal_handler().
+
+o Stefan Metzmacher
+ * BUG 14750: gensec_krb5: Restore ipv6 support for kpasswd.
+ * BUG 14752: smbXsrv_{open,session,tcon}: Protect
+ smbXsrv_{open,session,tcon}_global_traverse_fn against invalid records.
+
+o Joseph Sutton
+ * BUG 14027: samba-tool domain backup offline doesn't work against bind DLZ
+ backend.
+ * BUG 14669: netcmd: Use next_free_rid() function to calculate a SID for
+ restoring a backup.
+
+
+#######################################
+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 Samba 4.13.9
+ May 11, 2021
+ ==============================
+
+
+This is the latest stable release of the Samba 4.13 release series.
+
+
+Changes since 4.13.8
+--------------------
+
+o Jeremy Allison
+ * BUG 14696: s3: smbd: SMB1 SMBsplwr doesn't send a reply packet on success.
+
+o Andrew Bartlett
+ * BUG 14689: Add documentation for dsdb_group_audit and dsdb_group_json_audit
+ to "log level", synchronise "log level" in smb.conf with the code.
+
+o Ralph Boehme
+ * BUG 14672: Fix smbd panic when two clients open same file.
+ * BUG 14675: Fix memory leak in the RPC server.
+ * BUG 14679: s3: smbd: Fix deferred renames.
+
+o Samuel Cabrero
+ * BUG 14675: s3-iremotewinspool: Set the per-request memory context.
+
+o Volker Lendecke
+ * BUG 14675: rpc_server3: Fix a memleak for internal pipes.
+
+o Stefan Metzmacher
+ * BUG 11899: third_party: Update socket_wrapper to version 1.3.2.
+ * BUG 14640: third_party: Update socket_wrapper to version 1.3.3.
+
+
+o Christof Schmitt
+ * BUG 14663: idmap_rfc2307 and idmap_nss return wrong mapping for uid/gid
+ conflict.
+
+o Martin Schwenke
+ * BUG 14571: CVE-2021-20254: Fix buffer overrun in sids_to_unixids().
+
+
+#######################################
+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 Samba 4.13.7
+ March 24, 2021
+ ==============================
+
+
+This is a follow-up release to depend on the correct ldb version. This is only
+needed when building against a system ldb library.
+
+This is a security release in order to address the following defects:
+
+o CVE-2020-27840: Heap corruption via crafted DN strings.
+o CVE-2021-20277: Out of bounds read in AD DC LDAP server.
+
+
+=======
+Details
+=======
+
+o CVE-2020-27840:
+ An anonymous attacker can crash the Samba AD DC LDAP server by sending easily
+ crafted DNs as part of a bind request. More serious heap corruption is likely
+ also possible.
+
+o CVE-2021-20277:
+ User-controlled LDAP filter strings against the AD DC LDAP server may crash
+ the LDAP server.
+
+For more details, please refer to the security advisories.
+
+
+Changes since 4.13.6
+--------------------
+
+o Release with dependency on ldb version 2.2.1.
+
+
+#######################################
+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 Samba 4.13.6
+ March 24, 2021
+ ==============================
+
+
+This is a security release in order to address the following defects:
+
+o CVE-2020-27840: Heap corruption via crafted DN strings.
+o CVE-2021-20277: Out of bounds read in AD DC LDAP server.
+
+
+=======
+Details
+=======
+
+o CVE-2020-27840:
+ An anonymous attacker can crash the Samba AD DC LDAP server by sending easily
+ crafted DNs as part of a bind request. More serious heap corruption is likely
+ also possible.
+
+o CVE-2021-20277:
+ User-controlled LDAP filter strings against the AD DC LDAP server may crash
+ the LDAP server.
+
+For more details, please refer to the security advisories.
+
+
+Changes since 4.13.5
+--------------------
+
+o Andrew Bartlett
+ * BUG 14655: CVE-2021-20277: Fix out of bounds read in ldb_handler_fold.
+
+o Douglas Bagnall
+ * BUG 14595: CVE-2020-27840: Fix unauthenticated remote heap corruption via
+ bad DNs.
+ * BUG 14655: CVE-2021-20277: Fix out of bounds read in ldb_handler_fold.
+
+
+#######################################
+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 Samba 4.13.5
+ March 09, 2021
+ ==============================
+
+
+This is the latest stable release of the Samba 4.13 release series.
+
+
+Changes since 4.13.4
+--------------------
+
+o Trever L. Adams
+ * BUG 14634: s3:modules:vfs_virusfilter: Recent talloc changes cause infinite
+ start-up failure.
+
+o Jeremy Allison
+ * BUG 13992: s3: libsmb: Add missing cli_tdis() in error path if encryption
+ setup failed on temp proxy connection.
+ * BUG 14604: smbd: In conn_force_tdis_done() when forcing a connection closed
+ force a full reload of services.
+
+o Andrew Bartlett
+ * BUG 14593: dbcheck: Check Deleted Objects and reduce noise in reports about
+ expired tombstones.
+
+o Ralph Boehme conn->session_info for the initial
+ delete-on-close token.
+
+o Peter Eriksson
+ * BUG 14648: s3: VFS: nfs4_acls. Add missing TALLOC_FREE(frame) in error
+ path.
+
+o Björn Jacke
+ * BUG 14624: classicupgrade: Treat old never expires value right.
+
+o Volker Lendecke
+ * BUG 14636: g_lock: Fix uninitalized variable reads.
+
+o Stefan Metzmacher
+ * BUG 13898: s3:pysmbd: Fix fd leak in py_smbd_create_file().
+
+o Andreas Schneider
+ * BUG 14625: lib:util: Avoid free'ing our own pointer.
+
+o Paul Wise
+ * BUG 12505: HEIMDAL: krb5_storage_free(NULL) should work.
+
+
+#######################################
+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 Samba 4.13.4
+ January 26, 2021
+ ==============================
+
+
+This is the latest stable release of the Samba 4.13 release series.
+
+
+Changes since 4.13.3
+--------------------
+
+o Jeremy Allison
+ * BUG 14607: Work around special SMB2 IOCTL response behavior of NetApp Ontap
+ 7.3.7.
+ * BUG 14612: Temporary DFS share setup doesn't set case parameters in the
+ same way as a regular share definition does.
+
+o Dimitry Andric
+ * BUG 14605: lib: Avoid declaring zero-length VLAs in various messaging
+ functions.
+
+o Andrew Bartlett
+ * BUG 14579: Do not create an empty DB when accessing a sam.ldb.
+
+o Ralph Boehme
+ * BUG 14596: vfs_fruit may close wrong backend fd.
+ * BUG 14612: Temporary DFS share setup doesn't set case parameters in the
+ same way as a regular share definition does.
+
+o Arne Kreddig
+ * BUG 14606: vfs_virusfilter: Allocate separate memory for config char*.
+
+o Stefan Metzmacher
+ * BUG 14596: vfs_fruit may close wrong backend fd.
+ * BUG 14607: Work around special SMB2 IOCTL response behavior of NetApp Ontap
+ 7.3.7.
+
+o Andreas Schneider
+ * BUG 14601: The cache directory for the user gencache should be created
+ recursively.
+
+o Martin Schwenke
+ * BUG 14594: Be more flexible with repository names in CentOS 8 test
+ environments.
+
+
+#######################################
+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 Samba 4.13.3
December 15, 2020
@@ -66,10 +868,7 @@
======================================================================
-Release notes for older releases follow:
-----------------------------------------
-
- ==============================
+---------------------------------------------------------------------- ==============================
Release Notes for Samba 4.13.2
November 03, 2020
==============================
diff -Nru samba-4.13.3+dfsg/wscript samba-4.13.14+dfsg/wscript
--- samba-4.13.3+dfsg/wscript 2020-07-09 09:33:57.000000000 +0000
+++ samba-4.13.14+dfsg/wscript 2021-10-29 06:17:36.000000000 +0000
@@ -148,11 +148,21 @@
conf.env.DEVELOPER = True
# if we are in a git tree without a pre-commit hook, install a
# simple default.
- pre_commit_hook = os.path.join(Context.g_module.top, '.git/hooks/pre-commit')
- if (os.path.isdir(os.path.dirname(pre_commit_hook)) and
- not os.path.exists(pre_commit_hook)):
- shutil.copy(os.path.join(Context.g_module.top, 'script/git-hooks/pre-commit-hook'),
- pre_commit_hook)
+ # we need git for 'waf dist'
+ githooksdir = None
+ conf.find_program('git', var='GIT')
+ if 'GIT' in conf.env:
+ githooksdir = conf.CHECK_COMMAND('%s rev-parse --git-path hooks' % conf.env.GIT[0],
+ msg='Finding githooks directory',
+ define=None,
+ on_target=False)
+ if githooksdir and os.path.isdir(githooksdir):
+ pre_commit_hook = os.path.join(githooksdir, 'pre-commit')
+ if not os.path.exists(pre_commit_hook):
+ Logs.info("Installing script/git-hooks/pre-commit-hook as %s" %
+ pre_commit_hook)
+ shutil.copy(os.path.join(Context.g_module.top, 'script/git-hooks/pre-commit-hook'),
+ pre_commit_hook)
conf.ADD_EXTRA_INCLUDES('#include/public #source4 #lib #source4/lib #source4/include #include #lib/replace')
@@ -340,7 +350,8 @@
# allows us to find problems on our development hosts faster.
# It also results in faster load time.
- conf.add_as_needed()
+ if conf.CHECK_LDFLAGS('-Wl,--as-needed'):
+ conf.env.append_unique('LINKFLAGS', '-Wl,--as-needed')
if not conf.CHECK_NEED_LC("-lc not needed"):
conf.ADD_LDFLAGS('-lc', testflags=False)