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)