summaryrefslogtreecommitdiffstats
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--source4/dns_server/dns_crypto.c49
-rw-r--r--source4/dns_server/dns_query.c27
-rw-r--r--source4/dns_server/dns_update.c11
-rw-r--r--source4/dns_server/dnsserver_common.c8
-rw-r--r--source4/dsdb/repl/drepl_out_helpers.c26
-rw-r--r--source4/dsdb/samdb/ldb_modules/operational.c2
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c17
-rw-r--r--source4/dsdb/schema/schema_set.c14
-rw-r--r--source4/libcli/dgram/dgramsocket.c40
-rw-r--r--source4/libcli/dgram/libdgram.h3
-rw-r--r--source4/libcli/smb2/session.c16
-rw-r--r--source4/libcli/smb2/smb2.h2
-rw-r--r--source4/nbt_server/dgram/request.c56
-rw-r--r--source4/nbt_server/interfaces.c29
-rw-r--r--source4/nbt_server/nbt_server.c143
-rw-r--r--source4/nbt_server/nbt_server.h2
-rw-r--r--source4/nbt_server/wins/winsdb.c5
-rw-r--r--source4/nbt_server/wins/winsserver.c3
-rw-r--r--source4/nbt_server/wscript_build2
-rw-r--r--source4/ntvfs/posix/pvfs_streams.c3
-rw-r--r--source4/rpc_server/dnsserver/dnsdata.c16
-rw-r--r--source4/rpc_server/samr/dcesrv_samr.c7
-rwxr-xr-xsource4/selftest/tests.py14
-rw-r--r--source4/torture/smb2/ioctl.c64
-rw-r--r--source4/torture/smb2/session.c629
25 files changed, 1132 insertions, 56 deletions
diff --git a/source4/dns_server/dns_crypto.c b/source4/dns_server/dns_crypto.c
index be79a4e..d30e971 100644
--- a/source4/dns_server/dns_crypto.c
+++ b/source4/dns_server/dns_crypto.c
@@ -27,6 +27,7 @@
#include "libcli/util/ntstatus.h"
#include "auth/auth.h"
#include "auth/gensec/gensec.h"
+#include "lib/util/bytearray.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_DNS
@@ -106,7 +107,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
struct dns_server_tkey *tkey = NULL;
struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx,
struct dns_fake_tsig_rec);
-
+ const char *algorithm = NULL;
/* Find the first TSIG record in the additional records */
for (i=0; i < packet->arcount; i++) {
@@ -145,7 +146,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
tkey = dns_find_tkey(dns->tkeys, state->tsig->name);
if (tkey == NULL) {
- DBG_DEBUG("dns_find_tkey() => NOTAUTH / DNS_RCODE_BADKEY\n");
+ DBG_DEBUG("dns_find_tkey() => REFUSED / DNS_RCODE_BADKEY\n");
/*
* We must save the name for use in the TSIG error
* response and have no choice here but to save the
@@ -157,10 +158,20 @@ WERROR dns_verify_tsig(struct dns_server *dns,
return WERR_NOT_ENOUGH_MEMORY;
}
state->tsig_error = DNS_RCODE_BADKEY;
- return DNS_ERR(NOTAUTH);
+ return DNS_ERR(REFUSED);
}
DBG_DEBUG("dns_find_tkey() => found\n");
+ algorithm = state->tsig->rdata.tsig_record.algorithm_name;
+ if (strcmp(algorithm, "gss-tsig") == 0) {
+ /* ok */
+ } else if (strcmp(algorithm, "gss.microsoft.com") == 0) {
+ /* ok */
+ } else {
+ state->tsig_error = DNS_RCODE_BADKEY;
+ return DNS_ERR(REFUSED);
+ }
+
/*
* Remember the keyname that found an existing tkey, used
* later to fetch the key with dns_find_tkey() when signing
@@ -183,7 +194,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
}
check_rec->rr_class = DNS_QCLASS_ANY;
check_rec->ttl = 0;
- check_rec->algorithm_name = talloc_strdup(check_rec, tkey->algorithm);
+ check_rec->algorithm_name = talloc_strdup(check_rec, algorithm);
if (check_rec->algorithm_name == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
@@ -239,7 +250,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
dump_data_dbgc(DBGC_DNS, 8, buffer, buffer_len);
DBG_NOTICE("Verifying tsig failed: %s\n", nt_errstr(status));
state->tsig_error = DNS_RCODE_BADSIG;
- return DNS_ERR(NOTAUTH);
+ return DNS_ERR(REFUSED);
}
if (!NT_STATUS_IS_OK(status)) {
@@ -271,11 +282,19 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx,
struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx,
struct dns_fake_tsig_rec);
size_t mac_size = 0;
+ bool gss_tsig;
if (check_rec == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
+ if (strcmp(tkey->algorithm, "gss-tsig") == 0) {
+ gss_tsig = true;
+ } else {
+ /* gss.microsoft.com */
+ gss_tsig = false;
+ }
+
/* first build and verify check packet */
check_rec->name = talloc_strdup(check_rec, tkey->name);
if (check_rec->name == NULL) {
@@ -315,6 +334,9 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx,
}
buffer_len = mac_size;
+ if (gss_tsig && mac_size > 0) {
+ buffer_len += 2;
+ }
buffer_len += packet_blob.length;
if (buffer_len < packet_blob.length) {
@@ -335,11 +357,21 @@ static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx,
/*
* RFC 2845 "4.2 TSIG on Answers", how to lay out the buffer
* that we're going to sign:
- * 1. MAC of request (if present)
+ * 1. if MAC of request is present
+ * - 16bit big endian length of MAC of request
+ * - MAC of request
* 2. Outgoing packet
* 3. TSIG record
*/
if (mac_size > 0) {
+ if (gss_tsig) {
+ /*
+ * only gss-tsig not with
+ * gss.microsoft.com
+ */
+ PUSH_BE_U16(p, 0, mac_size);
+ p += 2;
+ }
memcpy(p, state->tsig->rdata.tsig_record.mac, mac_size);
p += mac_size;
}
@@ -372,6 +404,7 @@ WERROR dns_sign_tsig(struct dns_server *dns,
.data = NULL,
.length = 0
};
+ const char *algorithm = "gss-tsig";
tsig = talloc_zero(mem_ctx, struct dns_res_rec);
if (tsig == NULL) {
@@ -392,6 +425,8 @@ WERROR dns_sign_tsig(struct dns_server *dns,
if (!W_ERROR_IS_OK(werror)) {
return werror;
}
+
+ algorithm = tkey->algorithm;
}
tsig->name = talloc_strdup(tsig, state->key_name);
@@ -402,7 +437,7 @@ WERROR dns_sign_tsig(struct dns_server *dns,
tsig->rr_type = DNS_QTYPE_TSIG;
tsig->ttl = 0;
tsig->length = UINT16_MAX;
- tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, "gss-tsig");
+ tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, algorithm);
if (tsig->rdata.tsig_record.algorithm_name == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
index 181beda..1f46ee0 100644
--- a/source4/dns_server/dns_query.c
+++ b/source4/dns_server/dns_query.c
@@ -663,8 +663,17 @@ static NTSTATUS create_tkey(struct dns_server *dns,
{
NTSTATUS status;
struct dns_server_tkey_store *store = dns->tkeys;
- struct dns_server_tkey *k = talloc_zero(store, struct dns_server_tkey);
+ struct dns_server_tkey *k = NULL;
+
+ if (strcmp(algorithm, "gss-tsig") == 0) {
+ /* ok */
+ } else if (strcmp(algorithm, "gss.microsoft.com") == 0) {
+ /* ok */
+ } else {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ k = talloc_zero(store, struct dns_server_tkey);
if (k == NULL) {
return NT_STATUS_NO_MEMORY;
}
@@ -790,12 +799,22 @@ static WERROR handle_tkey(struct dns_server *dns,
{
struct dns_res_rec *in_tkey = NULL;
struct dns_res_rec *ret_tkey;
- uint16_t i;
- for (i = 0; i < in->arcount; i++) {
+ /*
+ * TKEY needs to we the last one in
+ * additional or answers
+ */
+ if (in->arcount >= 1) {
+ uint16_t i = in->arcount - 1;
if (in->additional[i].rr_type == DNS_QTYPE_TKEY) {
in_tkey = &in->additional[i];
- break;
+ }
+ } else if (in->nscount >= 1) {
+ /* no lookup */
+ } else if (in->ancount >= 1) {
+ uint16_t i = in->ancount - 1;
+ if (in->answers[i].rr_type == DNS_QTYPE_TKEY) {
+ in_tkey = &in->answers[i];
}
}
diff --git a/source4/dns_server/dns_update.c b/source4/dns_server/dns_update.c
index 4d2ee0b..1285111 100644
--- a/source4/dns_server/dns_update.c
+++ b/source4/dns_server/dns_update.c
@@ -570,6 +570,8 @@ static WERROR handle_one_update(struct dns_server *dns,
W_ERROR_NOT_OK_RETURN(werror);
for (i = first; i < rcount; i++) {
+ struct dnsp_DnssrvRpcRecord orig_rec = recs[i];
+
if (!dns_record_match(&recs[i], &recs[rcount])) {
continue;
}
@@ -583,6 +585,15 @@ static WERROR handle_one_update(struct dns_server *dns,
werror = dns_replace_records(dns, mem_ctx, dn,
needs_add, recs, rcount);
DBG_DEBUG("dns_replace_records(REPLACE): %s\n", win_errstr(werror));
+ if (W_ERROR_EQUAL(werror, WERR_ACCESS_DENIED) &&
+ !needs_add &&
+ orig_rec.dwTtlSeconds == recs[i].dwTtlSeconds)
+ {
+ DBG_NOTICE("dns_replace_records(REPLACE): %s "
+ "=> skip no-op\n",
+ win_errstr(werror));
+ werror = WERR_OK;
+ }
W_ERROR_NOT_OK_RETURN(werror);
return WERR_OK;
diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
index aba7f41..88aed2e 100644
--- a/source4/dns_server/dnsserver_common.c
+++ b/source4/dns_server/dnsserver_common.c
@@ -68,6 +68,8 @@ uint8_t werr_to_dns_err(WERROR werr)
return DNS_RCODE_NOTZONE;
} else if (W_ERROR_EQUAL(DNS_ERR(BADKEY), werr)) {
return DNS_RCODE_BADKEY;
+ } else if (W_ERROR_EQUAL(WERR_ACCESS_DENIED, werr)) {
+ return DNS_RCODE_REFUSED;
}
DEBUG(5, ("No mapping exists for %s\n", win_errstr(werr)));
return DNS_RCODE_SERVFAIL;
@@ -642,7 +644,7 @@ static int rec_cmp(const struct dnsp_DnssrvRpcRecord *r1,
* The records are sorted with higher types first,
* which puts tombstones (type 0) last.
*/
- return r2->wType - r1->wType;
+ return NUMERIC_CMP(r2->wType, r1->wType);
}
/*
* Then we need to sort from the oldest to newest timestamp.
@@ -650,7 +652,7 @@ static int rec_cmp(const struct dnsp_DnssrvRpcRecord *r1,
* Note that dwTimeStamp == 0 (never expiring) records come first,
* then the ones whose expiry is soonest.
*/
- return r1->dwTimeStamp - r2->dwTimeStamp;
+ return NUMERIC_CMP(r1->dwTimeStamp, r2->dwTimeStamp);
}
/*
@@ -1408,7 +1410,7 @@ static int dns_common_sort_zones(struct ldb_message **m1, struct ldb_message **m
/* If the string lengths are not equal just sort by length */
if (l1 != l2) {
/* If m1 is the larger zone name, return it first */
- return l2 - l1;
+ return NUMERIC_CMP(l2, l1);
}
/*TODO: We need to compare DNs here, we want the DomainDNSZones first */
diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c
index d46b19e..7ba5c79 100644
--- a/source4/dsdb/repl/drepl_out_helpers.c
+++ b/source4/dsdb/repl/drepl_out_helpers.c
@@ -1043,7 +1043,7 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
if (W_ERROR_EQUAL(status, WERR_DS_DRA_SCHEMA_MISMATCH)) {
struct dreplsrv_partition *p;
- bool ok;
+ struct tevent_req *subreq = NULL;
if (was_schema) {
nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
@@ -1141,12 +1141,15 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
state->retry_started = true;
- ok = dreplsrv_op_pull_source_detect_schema_cycle(req);
- if (!ok) {
+ subreq = dreplsrv_out_drsuapi_send(state,
+ state->ev,
+ state->op->source_dsa->conn);
+ if (tevent_req_nomem(subreq, req)) {
return;
}
-
- dreplsrv_op_pull_source_get_changes_trigger(req);
+ tevent_req_set_callback(subreq,
+ dreplsrv_op_pull_source_connect_done,
+ req);
return;
} else if (!W_ERROR_IS_OK(status)) {
@@ -1205,10 +1208,21 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
* operation once we are done.
*/
if (state->source_dsa_retry != NULL) {
+ struct tevent_req *subreq = NULL;
+
state->op->source_dsa = state->source_dsa_retry;
state->op->extended_op = state->extended_op_retry;
state->source_dsa_retry = NULL;
- dreplsrv_op_pull_source_get_changes_trigger(req);
+
+ subreq = dreplsrv_out_drsuapi_send(state,
+ state->ev,
+ state->op->source_dsa->conn);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ dreplsrv_op_pull_source_connect_done,
+ req);
return;
}
diff --git a/source4/dsdb/samdb/ldb_modules/operational.c b/source4/dsdb/samdb/ldb_modules/operational.c
index 1317b58..20613a7 100644
--- a/source4/dsdb/samdb/ldb_modules/operational.c
+++ b/source4/dsdb/samdb/ldb_modules/operational.c
@@ -1070,7 +1070,7 @@ static int pso_compare(struct ldb_message **m1, struct ldb_message **m2)
return ndr_guid_compare(&guid1, &guid2);
} else {
- return prec1 - prec2;
+ return NUMERIC_CMP(prec1, prec2);
}
}
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 7aec006..2790679 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -1063,16 +1063,21 @@ static int replmd_ldb_message_element_attid_sort(const struct ldb_message_elemen
a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
/*
- * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
- * in the schema
+ * If the elements do not have valid attribute names in the schema
+ * (which we would prefer to think can't happen), we need to sort them
+ * somehow. The current strategy is to put them at the end, sorted by
+ * attribute name.
*/
- if (!a1 || !a2) {
+ if (a1 == NULL && a2 == NULL) {
return strcasecmp(e1->name, e2->name);
}
- if (a1->attributeID_id == a2->attributeID_id) {
- return 0;
+ if (a1 == NULL) {
+ return 1;
+ }
+ if (a2 == NULL) {
+ return -1;
}
- return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
+ return NUMERIC_CMP(a1->attributeID_id, a2->attributeID_id);
}
static void replmd_ldb_message_sort(struct ldb_message *msg,
diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c
index 398091c..8b90e7f 100644
--- a/source4/dsdb/schema/schema_set.c
+++ b/source4/dsdb/schema/schema_set.c
@@ -478,19 +478,13 @@ static void dsdb_setup_attribute_shortcuts(struct ldb_context *ldb, struct dsdb_
TALLOC_FREE(frame);
}
-static int uint32_cmp(uint32_t c1, uint32_t c2)
-{
- if (c1 == c2) return 0;
- return c1 > c2 ? 1 : -1;
-}
-
static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class **c1, struct dsdb_class **c2)
{
return strcasecmp((*c1)->lDAPDisplayName, (*c2)->lDAPDisplayName);
}
static int dsdb_compare_class_by_governsID_id(struct dsdb_class **c1, struct dsdb_class **c2)
{
- return uint32_cmp((*c1)->governsID_id, (*c2)->governsID_id);
+ return NUMERIC_CMP((*c1)->governsID_id, (*c2)->governsID_id);
}
static int dsdb_compare_class_by_governsID_oid(struct dsdb_class **c1, struct dsdb_class **c2)
{
@@ -507,11 +501,11 @@ static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute **a1,
}
static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
- return uint32_cmp((*a1)->attributeID_id, (*a2)->attributeID_id);
+ return NUMERIC_CMP((*a1)->attributeID_id, (*a2)->attributeID_id);
}
static int dsdb_compare_attribute_by_msDS_IntId(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
- return uint32_cmp((*a1)->msDS_IntId, (*a2)->msDS_IntId);
+ return NUMERIC_CMP((*a1)->msDS_IntId, (*a2)->msDS_IntId);
}
static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
@@ -519,7 +513,7 @@ static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1,
}
static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
- return uint32_cmp((*a1)->linkID, (*a2)->linkID);
+ return NUMERIC_CMP((*a1)->linkID, (*a2)->linkID);
}
static int dsdb_compare_attribute_by_cn(struct dsdb_attribute **a1, struct dsdb_attribute **a2)
{
diff --git a/source4/libcli/dgram/dgramsocket.c b/source4/libcli/dgram/dgramsocket.c
index 154a667..2a98792 100644
--- a/source4/libcli/dgram/dgramsocket.c
+++ b/source4/libcli/dgram/dgramsocket.c
@@ -90,6 +90,10 @@ static void dgm_socket_recv(struct nbt_dgram_socket *dgmsock)
dgmslot->handler(dgmslot, packet, src);
} else {
DEBUG(2,("No mailslot handler for '%s'\n", mailslot_name));
+ /* dispatch if there is a general handler */
+ if (dgmsock->incoming.handler) {
+ dgmsock->incoming.handler(dgmsock, packet, src);
+ }
}
} else {
/* dispatch if there is a general handler */
@@ -205,6 +209,38 @@ NTSTATUS dgram_set_incoming_handler(struct nbt_dgram_socket *dgmsock,
return NT_STATUS_OK;
}
+NTSTATUS nbt_dgram_send_raw(struct nbt_dgram_socket *dgmsock,
+ struct socket_address *dest,
+ const DATA_BLOB pkt_blob)
+{
+ struct nbt_dgram_request *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ req = talloc(dgmsock, struct nbt_dgram_request);
+ if (req == NULL) {
+ goto failed;
+ }
+
+ req->dest = socket_address_copy(req, dest);
+ if (req->dest == NULL) {
+ goto failed;
+ }
+
+ req->encoded = data_blob_dup_talloc(req, pkt_blob);
+ if (req->encoded.length != pkt_blob.length) {
+ goto failed;
+ }
+
+ DLIST_ADD_END(dgmsock->send_queue, req);
+
+ TEVENT_FD_WRITEABLE(dgmsock->fde);
+
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(req);
+ return status;
+}
/*
queue a datagram for send
@@ -220,8 +256,8 @@ NTSTATUS nbt_dgram_send(struct nbt_dgram_socket *dgmsock,
req = talloc(dgmsock, struct nbt_dgram_request);
if (req == NULL) goto failed;
- req->dest = dest;
- if (talloc_reference(req, dest) == NULL) goto failed;
+ req->dest = socket_address_copy(req, dest);
+ if (req->dest == NULL) goto failed;
ndr_err = ndr_push_struct_blob(&req->encoded, req, packet,
(ndr_push_flags_fn_t)ndr_push_nbt_dgram_packet);
diff --git a/source4/libcli/dgram/libdgram.h b/source4/libcli/dgram/libdgram.h
index 0f313a6..7e57a94 100644
--- a/source4/libcli/dgram/libdgram.h
+++ b/source4/libcli/dgram/libdgram.h
@@ -83,6 +83,9 @@ struct dgram_mailslot_handler {
/* prototypes */
+NTSTATUS nbt_dgram_send_raw(struct nbt_dgram_socket *dgmsock,
+ struct socket_address *dest,
+ const DATA_BLOB pkt_blob);
NTSTATUS nbt_dgram_send(struct nbt_dgram_socket *dgmsock,
struct nbt_dgram_packet *packet,
struct socket_address *dest);
diff --git a/source4/libcli/smb2/session.c b/source4/libcli/smb2/session.c
index e94512d..322a7bd 100644
--- a/source4/libcli/smb2/session.c
+++ b/source4/libcli/smb2/session.c
@@ -385,7 +385,9 @@ static void smb2_session_setup_spnego_both_ready(struct tevent_req *req)
return;
}
- if (cli_credentials_is_anonymous(state->credentials)) {
+ if (cli_credentials_is_anonymous(state->credentials) &&
+ !state->session->anonymous_session_key)
+ {
/*
* Windows server does not set the
* SMB2_SESSION_FLAG_IS_GUEST nor
@@ -399,10 +401,14 @@ static void smb2_session_setup_spnego_both_ready(struct tevent_req *req)
return;
}
- status = gensec_session_key(session->gensec, state,
- &session_key);
- if (tevent_req_nterror(req, status)) {
- return;
+ if (state->session->forced_session_key.length != 0) {
+ session_key = state->session->forced_session_key;
+ } else {
+ status = gensec_session_key(session->gensec, state,
+ &session_key);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
}
if (state->session_bind) {
diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h
index 88e651a..1e2f185 100644
--- a/source4/libcli/smb2/smb2.h
+++ b/source4/libcli/smb2/smb2.h
@@ -128,6 +128,8 @@ struct smb2_session {
struct gensec_security *gensec;
struct smbXcli_session *smbXcli;
bool needs_bind;
+ bool anonymous_session_key;
+ DATA_BLOB forced_session_key;
};
diff --git a/source4/nbt_server/dgram/request.c b/source4/nbt_server/dgram/request.c
index ea2b6e8..7614514 100644
--- a/source4/nbt_server/dgram/request.c
+++ b/source4/nbt_server/dgram/request.c
@@ -27,6 +27,11 @@
#include "nbt_server/dgram/proto.h"
#include "librpc/gen_ndr/ndr_nbt.h"
#include "param/param.h"
+#include "lib/util/util_str_escape.h"
+#include "lib/util/util_net.h"
+#include "../source3/include/fstring.h"
+#include "../source3/libsmb/nmblib.h"
+#include "../source3/libsmb/unexpected.h"
/*
a list of mailslots that we have static handlers for
@@ -51,8 +56,55 @@ void dgram_request_handler(struct nbt_dgram_socket *dgmsock,
struct nbt_dgram_packet *packet,
struct socket_address *src)
{
- DEBUG(0,("General datagram request from %s:%d\n", src->addr, src->port));
- NDR_PRINT_DEBUG(nbt_dgram_packet, packet);
+ struct nbtd_interface *iface =
+ talloc_get_type_abort(dgmsock->incoming.private_data,
+ struct nbtd_interface);
+ struct nbtd_server *nbtsrv = iface->nbtsrv;
+ const char *mailslot_name = NULL;
+ struct packet_struct *pstruct = NULL;
+ DATA_BLOB blob = { .length = 0, };
+ enum ndr_err_code ndr_err;
+
+ mailslot_name = dgram_mailslot_name(packet);
+ if (mailslot_name != NULL) {
+ DBG_DEBUG("Unexpected mailslot[%s] datagram request from %s:%d\n",
+ log_escape(packet, mailslot_name),
+ src->addr, src->port);
+ } else {
+ DBG_DEBUG("Unexpected general datagram request from %s:%d\n",
+ src->addr, src->port);
+ }
+
+ if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
+ NDR_PRINT_DEBUG(nbt_dgram_packet, packet);
+ }
+
+ /*
+ * For now we only pass DGRAM_DIRECT_UNIQUE
+ * messages via nb_packet_dispatch() to
+ * nbtsrv->unexpected_server
+ */
+ if (packet->msg_type != DGRAM_DIRECT_UNIQUE) {
+ return;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, packet, packet,
+ (ndr_push_flags_fn_t)ndr_push_nbt_dgram_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("ndr_push_nbt_dgram_packet - %s\n",
+ ndr_errstr(ndr_err));
+ return;
+ }
+
+ pstruct = parse_packet((char *)blob.data,
+ blob.length,
+ DGRAM_PACKET,
+ interpret_addr2(src->addr),
+ src->port);
+ if (pstruct != NULL) {
+ nb_packet_dispatch(nbtsrv->unexpected_server, pstruct);
+ free_packet(pstruct);
+ }
}
diff --git a/source4/nbt_server/interfaces.c b/source4/nbt_server/interfaces.c
index b946a1d..0888c1b 100644
--- a/source4/nbt_server/interfaces.c
+++ b/source4/nbt_server/interfaces.c
@@ -31,6 +31,9 @@
#include "param/param.h"
#include "lib/util/util_net.h"
#include "lib/util/idtree.h"
+#include "../source3/include/fstring.h"
+#include "../source3/libsmb/nmblib.h"
+#include "../source3/libsmb/unexpected.h"
/*
receive an incoming request and dispatch it to the right place
@@ -115,7 +118,33 @@ static void nbtd_unexpected_handler(struct nbt_name_socket *nbtsock,
}
if (!req) {
+ struct packet_struct *pstruct = NULL;
+ DATA_BLOB blob = { .length = 0, };
+ enum ndr_err_code ndr_err;
+
+ /*
+ * Here we have NBT_FLAG_REPLY
+ */
DEBUG(10,("unexpected from src[%s] unable to redirected\n", src->addr));
+
+ ndr_err = ndr_push_struct_blob(&blob, packet, packet,
+ (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("ndr_push_nbt_name_packet - %s\n",
+ ndr_errstr(ndr_err));
+ return;
+ }
+
+ pstruct = parse_packet((char *)blob.data,
+ blob.length,
+ NMB_PACKET,
+ interpret_addr2(src->addr),
+ src->port);
+ if (pstruct != NULL) {
+ nb_packet_dispatch(nbtsrv->unexpected_server, pstruct);
+ free_packet(pstruct);
+ }
+
return;
}
diff --git a/source4/nbt_server/nbt_server.c b/source4/nbt_server/nbt_server.c
index 6d28bbd..c3f9fac 100644
--- a/source4/nbt_server/nbt_server.c
+++ b/source4/nbt_server/nbt_server.c
@@ -29,9 +29,113 @@
#include "auth/auth.h"
#include "dsdb/samdb/samdb.h"
#include "param/param.h"
+#include "dynconfig/dynconfig.h"
+#include "lib/util/pidfile.h"
+#include "lib/util/util_net.h"
+#include "lib/socket/socket.h"
+#include "../source3/include/fstring.h"
+#include "../source3/libsmb/nmblib.h"
+#include "../source3/libsmb/unexpected.h"
+#include "../source3/lib/util_procid.h"
NTSTATUS server_service_nbtd_init(TALLOC_CTX *);
+static void nbtd_server_msg_send_packet(struct imessaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id src,
+ size_t num_fds,
+ int *fds,
+ DATA_BLOB *data)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct nbtd_server *nbtsrv =
+ talloc_get_type_abort(private_data,
+ struct nbtd_server);
+ struct packet_struct *p = (struct packet_struct *)data->data;
+ struct sockaddr_storage ss;
+ struct socket_address *dst = NULL;
+ struct nbtd_interface *iface = NULL;
+ char buf[1024] = { 0, };
+ DATA_BLOB blob = { .length = 0, };
+
+ DBG_DEBUG("Received send_packet from %u\n", (unsigned int)procid_to_pid(&src));
+
+ if (data->length != sizeof(struct packet_struct)) {
+ DBG_WARNING("Discarding invalid packet length from %u\n",
+ (unsigned int)procid_to_pid(&src));
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ if ((p->packet_type != NMB_PACKET) &&
+ (p->packet_type != DGRAM_PACKET)) {
+ DBG_WARNING("Discarding invalid packet type from %u: %d\n",
+ (unsigned int)procid_to_pid(&src), p->packet_type);
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ if (p->packet_type == DGRAM_PACKET) {
+ p->port = 138;
+ }
+
+ in_addr_to_sockaddr_storage(&ss, p->ip);
+ dst = socket_address_from_sockaddr_storage(frame, &ss, p->port);
+ if (dst == NULL) {
+ TALLOC_FREE(frame);
+ return;
+ }
+ if (p->port == 0) {
+ DBG_WARNING("Discarding packet with missing port for addr[%s] "
+ "from %u\n",
+ dst->addr, (unsigned int)procid_to_pid(&src));
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ iface = nbtd_find_request_iface(nbtsrv, dst->addr, true);
+ if (iface == NULL) {
+ DBG_WARNING("Could not find iface for packet to addr[%s] "
+ "from %u\n",
+ dst->addr, (unsigned int)procid_to_pid(&src));
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ p->recv_fd = -1;
+ p->send_fd = -1;
+
+ if (p->packet_type == DGRAM_PACKET) {
+ p->packet.dgram.header.source_ip.s_addr = interpret_addr(iface->ip_address);
+ p->packet.dgram.header.source_port = 138;
+ }
+
+ blob.length = build_packet(buf, sizeof(buf), p);
+ if (blob.length == 0) {
+ TALLOC_FREE(frame);
+ return;
+ }
+ blob.data = (uint8_t *)buf;
+
+ if (p->packet_type == DGRAM_PACKET) {
+ nbt_dgram_send_raw(iface->dgmsock, dst, blob);
+ } else {
+ nbt_name_send_raw(iface->nbtsock, dst, blob);
+ }
+
+ TALLOC_FREE(frame);
+}
+
+static int nbtd_server_destructor(struct nbtd_server *nbtsrv)
+{
+ struct task_server *task = nbtsrv->task;
+
+ pidfile_unlink(lpcfg_pid_directory(task->lp_ctx), "nmbd");
+
+ return 0;
+}
+
/*
startup the nbtd task
*/
@@ -40,6 +144,8 @@ static NTSTATUS nbtd_task_init(struct task_server *task)
struct nbtd_server *nbtsrv;
NTSTATUS status;
struct interface *ifaces;
+ const char *nmbd_socket_dir = NULL;
+ int unexpected_clients;
load_interface_list(task, task->lp_ctx, &ifaces);
@@ -66,6 +172,8 @@ static NTSTATUS nbtd_task_init(struct task_server *task)
nbtsrv->bcast_interface = NULL;
nbtsrv->wins_interface = NULL;
+ talloc_set_destructor(nbtsrv, nbtd_server_destructor);
+
/* start listening on the configured network interfaces */
status = nbtd_startup_interfaces(nbtsrv, task->lp_ctx, ifaces);
if (!NT_STATUS_IS_OK(status)) {
@@ -73,6 +181,30 @@ static NTSTATUS nbtd_task_init(struct task_server *task)
return status;
}
+ nmbd_socket_dir = lpcfg_parm_string(task->lp_ctx,
+ NULL,
+ "nmbd",
+ "socket dir");
+ if (nmbd_socket_dir == NULL) {
+ nmbd_socket_dir = get_dyn_NMBDSOCKETDIR();
+ }
+
+ unexpected_clients = lpcfg_parm_int(task->lp_ctx,
+ NULL,
+ "nmbd",
+ "unexpected_clients",
+ 200);
+
+ status = nb_packet_server_create(nbtsrv,
+ nbtsrv->task->event_ctx,
+ nmbd_socket_dir,
+ unexpected_clients,
+ &nbtsrv->unexpected_server);
+ if (!NT_STATUS_IS_OK(status)) {
+ task_server_terminate(task, "nbtd failed to start unexpected_server", true);
+ return status;
+ }
+
nbtsrv->sam_ctx = samdb_connect(nbtsrv,
task->event_ctx,
task->lp_ctx,
@@ -93,11 +225,22 @@ static NTSTATUS nbtd_task_init(struct task_server *task)
nbtd_register_irpc(nbtsrv);
+ status = imessaging_register(task->msg_ctx,
+ nbtsrv,
+ MSG_SEND_PACKET,
+ nbtd_server_msg_send_packet);
+ if (!NT_STATUS_IS_OK(status)) {
+ task_server_terminate(task, "nbtd failed imessaging_register(MSG_SEND_PACKET)", true);
+ return status;
+ }
+
/* start the process of registering our names on all interfaces */
nbtd_register_names(nbtsrv);
irpc_add_name(task->msg_ctx, "nbt_server");
+ pidfile_create(lpcfg_pid_directory(task->lp_ctx), "nmbd");
+
return NT_STATUS_OK;
}
diff --git a/source4/nbt_server/nbt_server.h b/source4/nbt_server/nbt_server.h
index c80e5bf..cbad3e9 100644
--- a/source4/nbt_server/nbt_server.h
+++ b/source4/nbt_server/nbt_server.h
@@ -78,6 +78,8 @@ struct nbtd_server {
struct nbtd_statistics stats;
struct ldb_context *sam_ctx;
+
+ struct nb_packet_server *unexpected_server;
};
diff --git a/source4/nbt_server/wins/winsdb.c b/source4/nbt_server/wins/winsdb.c
index 2a05e96..7df40c3 100644
--- a/source4/nbt_server/wins/winsdb.c
+++ b/source4/nbt_server/wins/winsdb.c
@@ -32,6 +32,7 @@
#include "lib/socket/netif.h"
#include "param/param.h"
#include "lib/util/smb_strtox.h"
+#include "lib/util/tsort.h"
#undef strcasecmp
@@ -349,7 +350,7 @@ static int winsdb_addr_sort_list (struct winsdb_addr **p1, struct winsdb_addr **
* then the replica addresses with the newest to the oldest address
*/
if (a2->expire_time != a1->expire_time) {
- return a2->expire_time - a1->expire_time;
+ return NUMERIC_CMP(a2->expire_time, a1->expire_time);
}
if (strcmp(a2->wins_owner, h->local_owner) == 0) {
@@ -360,7 +361,7 @@ static int winsdb_addr_sort_list (struct winsdb_addr **p1, struct winsdb_addr **
a1_owned = true;
}
- return a2_owned - a1_owned;
+ return NUMERIC_CMP(a2_owned, a1_owned);
}
struct winsdb_addr **winsdb_addr_list_add(struct winsdb_handle *h, const struct winsdb_record *rec,
diff --git a/source4/nbt_server/wins/winsserver.c b/source4/nbt_server/wins/winsserver.c
index a9f3ecd..6679961 100644
--- a/source4/nbt_server/wins/winsserver.c
+++ b/source4/nbt_server/wins/winsserver.c
@@ -36,6 +36,7 @@
#include "param/param.h"
#include "libcli/resolve/resolve.h"
#include "lib/util/util_net.h"
+#include "lib/util/tsort.h"
/*
work out the ttl we will use given a client requested ttl
@@ -653,7 +654,7 @@ static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
- return match_bits2 - match_bits1;
+ return NUMERIC_CMP(match_bits2, match_bits1);
}
static void nbtd_wins_randomize1Clist(struct loadparm_context *lp_ctx,
diff --git a/source4/nbt_server/wscript_build b/source4/nbt_server/wscript_build
index 9d0c24a..ce436e8 100644
--- a/source4/nbt_server/wscript_build
+++ b/source4/nbt_server/wscript_build
@@ -38,7 +38,7 @@ bld.SAMBA_SUBSYSTEM('NBTD_DGRAM',
bld.SAMBA_SUBSYSTEM('NBT_SERVER',
source='interfaces.c register.c query.c nodestatus.c defense.c packet.c irpc.c',
autoproto='nbt_server_proto.h',
- deps='cli-nbt NBTD_WINS NBTD_DGRAM service',
+ deps='cli-nbt NBTD_WINS NBTD_DGRAM service LIBNMB',
enabled=bld.AD_DC_BUILD_IS_ENABLED()
)
diff --git a/source4/ntvfs/posix/pvfs_streams.c b/source4/ntvfs/posix/pvfs_streams.c
index 9210237..d2d5eed 100644
--- a/source4/ntvfs/posix/pvfs_streams.c
+++ b/source4/ntvfs/posix/pvfs_streams.c
@@ -22,6 +22,7 @@
#include "includes.h"
#include "vfs_posix.h"
#include "librpc/gen_ndr/xattr.h"
+#include "lib/util/tsort.h"
/*
normalise a stream name, removing a :$DATA suffix if there is one
@@ -51,7 +52,7 @@ static int stream_name_cmp(const char *name1, const char *name2)
l1 = c1?(c1 - name1):strlen(name1);
l2 = c2?(c2 - name2):strlen(name2);
if (l1 != l2) {
- return l1 - l2;
+ return NUMERIC_CMP(l1, l2);
}
ret = strncasecmp_m(name1, name2, l1);
if (ret != 0) {
diff --git a/source4/rpc_server/dnsserver/dnsdata.c b/source4/rpc_server/dnsserver/dnsdata.c
index e6d35fc..6ffca19 100644
--- a/source4/rpc_server/dnsserver/dnsdata.c
+++ b/source4/rpc_server/dnsserver/dnsdata.c
@@ -1075,9 +1075,23 @@ int dns_name_compare(struct ldb_message * const *m1, struct ldb_message * const
name1 = ldb_msg_find_attr_as_string(*m1, "name", NULL);
name2 = ldb_msg_find_attr_as_string(*m2, "name", NULL);
- if (name1 == NULL || name2 == NULL) {
+ /*
+ * We sort NULL names to the start of the list, because the only
+ * caller of this function, dnsserver_enumerate_records() will call
+ * dns_build_tree() with the sorted list, which will always return an
+ * error when it hits a NULL, so we might as well make that happen
+ * quickly.
+ */
+ if (name1 == name2) {
+ /* this includes the both NULL case */
return 0;
}
+ if (name1 == NULL) {
+ return -1;
+ }
+ if (name2 == NULL) {
+ return 1;
+ }
/* Compare the last components of names.
* If search_name is not NULL, compare the second last components of names */
diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c
index 841c764..66a7785 100644
--- a/source4/rpc_server/samr/dcesrv_samr.c
+++ b/source4/rpc_server/samr/dcesrv_samr.c
@@ -1166,7 +1166,7 @@ static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call
*/
static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
{
- return e1->idx - e2->idx;
+ return NUMERIC_CMP(e1->idx, e2->idx);
}
static int compare_msgRid(struct ldb_message **m1, struct ldb_message **m2) {
@@ -1197,8 +1197,9 @@ static int compare_msgRid(struct ldb_message **m1, struct ldb_message **m2) {
}
/*
- * Get and compare the rids, if we fail to extract a rid treat it as a
- * missing SID and sort to the end of the list
+ * Get and compare the rids. If we fail to extract a rid (because
+ * there are no subauths) the msg goes to the end of the list, but
+ * before the NULL SIDs.
*/
status = dom_sid_split_rid(NULL, sid1, NULL, &rid1);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index d70d7d5..e47eb57 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -531,7 +531,11 @@ plantestsuite_loadlist("samba.tests.dns_aging", "fl2003dc:local",
plantestsuite_loadlist("samba.tests.dns_forwarder", "fl2003dc:local", [python, os.path.join(srcdir(), "python/samba/tests/dns_forwarder.py"), '$SERVER', '$SERVER_IP', '$DNS_FORWARDER1', '$DNS_FORWARDER2', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
-plantestsuite_loadlist("samba.tests.dns_tkey", "fl2008r2dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_tkey.py"), '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
+plantestsuite_loadlist("samba.tests.dns_tkey", "fl2008r2dc",
+ ['USERNAME_UNPRIV=$DOMAIN_USER','PASSWORD_UNPRIV=$DOMAIN_USER_PASSWORD',
+ python, os.path.join(srcdir(), "python/samba/tests/dns_tkey.py"),
+ '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"',
+ '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
plantestsuite_loadlist("samba.tests.dns_wildcard", "ad_dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_wildcard.py"), '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
plantestsuite_loadlist("samba.tests.dns_invalid", "ad_dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_invalid.py"), '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
@@ -817,6 +821,11 @@ plantestsuite("samba4.blackbox.trust_ntlm", "fl2000dc:local", [os.path.join(bbdi
plantestsuite("samba4.blackbox.trust_ntlm", "ad_member:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$SERVER', '$SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$REALM', '$DOMAIN', 'member', 'auto', 'NT_STATUS_LOGON_FAILURE'])
plantestsuite("samba4.blackbox.trust_ntlm", "nt4_member:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$SERVER', '$SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$DOMAIN', '$DOMAIN', 'member', 'auto', 'NT_STATUS_LOGON_FAILURE'])
+plantestsuite("samba4.blackbox.ldap_token", "fl2008r2dc:local", [os.path.join(bbdir, "test_ldap_token.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$DOMSID'])
+plantestsuite("samba4.blackbox.ldap_token", "fl2003dc:local", [os.path.join(bbdir, "test_ldap_token.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$DOMSID'])
+plantestsuite("samba4.blackbox.ldap_token", "fl2000dc:local", [os.path.join(bbdir, "test_ldap_token.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$DOMSID'])
+plantestsuite("samba4.blackbox.ldap_token", "ad_member:local", [os.path.join(bbdir, "test_ldap_token.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$REALM', '$DOMAIN', '$DOMSID'])
+
plantestsuite("samba4.blackbox.trust_utils(fl2008r2dc:local)", "fl2008r2dc:local", [os.path.join(bbdir, "test_trust_utils.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "forest"])
plantestsuite("samba4.blackbox.trust_utils(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_trust_utils.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external"])
plantestsuite("samba4.blackbox.trust_utils(fl2000dc:local)", "fl2000dc:local", [os.path.join(bbdir, "test_trust_utils.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external"])
@@ -1477,6 +1486,9 @@ planoldpythontestsuite("fileserver",
"samba.tests.blackbox.smbcacls_dfs_propagate_inherit",
"samba.tests.blackbox.smbcacls_dfs_propagate_inherit(DFS-msdfs-root)",
environ={'SHARE': 'smbcacls_share'})
+
+planoldpythontestsuite("fileserver",
+ "samba.tests.blackbox.misc_dfs_widelink")
#
# Want a selection of environments across the process models
#
diff --git a/source4/torture/smb2/ioctl.c b/source4/torture/smb2/ioctl.c
index 3765dc0..beceaa5 100644
--- a/source4/torture/smb2/ioctl.c
+++ b/source4/torture/smb2/ioctl.c
@@ -7389,6 +7389,68 @@ static bool test_ioctl_bug14788_NETWORK_INTERFACE(struct torture_context *tortur
}
/*
+ * basic regression test for BUG 15664
+ * https://bugzilla.samba.org/show_bug.cgi?id=15664
+ */
+static bool test_ioctl_copy_chunk_bug15644(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ union smb_ioctl ioctl;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ struct srv_copychunk chunk;
+ struct srv_copychunk_copy cc_copy;
+ enum ndr_err_code ndr_ret;
+ bool ok;
+
+ ok = test_setup_create_fill(torture,
+ tree,
+ tmp_ctx,
+ FNAME2,
+ &dest_h,
+ 0,
+ SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "dest file create fill");
+
+ ZERO_STRUCT(ioctl);
+ ioctl.smb2.level = RAW_IOCTL_SMB2;
+ ioctl.smb2.in.file.handle = dest_h;
+ ioctl.smb2.in.function = FSCTL_SRV_COPYCHUNK;
+ ioctl.smb2.in.max_output_response = sizeof(struct srv_copychunk_rsp);
+ ioctl.smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
+
+ ZERO_STRUCT(chunk);
+ ZERO_STRUCT(cc_copy);
+ /* overwrite the resume key with a bogus value */
+ memcpy(cc_copy.source_key, "deadbeefdeadbeefdeadbeef", 24);
+ cc_copy.chunk_count = 1;
+ cc_copy.chunks = &chunk;
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = 4096;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ /* Server 2k12 returns NT_STATUS_OBJECT_NAME_NOT_FOUND */
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_equal(torture, status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ "FSCTL_SRV_COPYCHUNK");
+
+ status = smb2_util_close(tree, dest_h);
+ torture_assert_ntstatus_ok(torture, status, "close");
+
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
* testing of SMB2 ioctls
*/
struct torture_suite *torture_smb2_ioctl_init(TALLOC_CTX *ctx)
@@ -7420,6 +7482,8 @@ struct torture_suite *torture_smb2_ioctl_init(TALLOC_CTX *ctx)
test_ioctl_copy_chunk_dest_lck);
torture_suite_add_1smb2_test(suite, "copy_chunk_bad_key",
test_ioctl_copy_chunk_bad_key);
+ torture_suite_add_1smb2_test(suite, "copy_chunk_bug15644",
+ test_ioctl_copy_chunk_bug15644);
torture_suite_add_1smb2_test(suite, "copy_chunk_src_is_dest",
test_ioctl_copy_chunk_src_is_dest);
torture_suite_add_1smb2_test(suite, "copy_chunk_src_is_dest_overlap",
diff --git a/source4/torture/smb2/session.c b/source4/torture/smb2/session.c
index 823304f..2a3d0e6 100644
--- a/source4/torture/smb2/session.c
+++ b/source4/torture/smb2/session.c
@@ -5527,6 +5527,630 @@ static bool test_session_ntlmssp_bug14932(struct torture_context *tctx, struct s
return ret;
}
+static bool test_session_anon_encryption1(struct torture_context *tctx,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = "IPC$";
+ char *unc = NULL;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct cli_credentials *anon_creds = NULL;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_session *anon_session = NULL;
+ struct smb2_tree *anon_tree = NULL;
+ NTSTATUS status;
+ bool ok = true;
+ struct tevent_req *subreq = NULL;
+ uint32_t timeout_msec;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon");
+ ok = cli_credentials_set_smb_encryption(anon_creds,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+ options.only_negprot = true;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ anon_creds,
+ &anon_tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed");
+ anon_session = anon_tree->session;
+ transport = anon_session->transport;
+
+ anon_session->anonymous_session_key = true;
+ smb2cli_session_torture_anonymous_encryption(anon_session->smbXcli, true);
+
+ status = smb2_session_setup_spnego(anon_session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2_session_setup_spnego failed");
+
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ /*
+ * The connection is still in ConstrainedConnection state...
+ *
+ * This will use encryption and causes a connection reset
+ */
+ timeout_msec = transport->options.request_timeout * 1000;
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
+ status = NT_STATUS_CONNECTION_RESET;
+ }
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_CONNECTION_RESET,
+ "smb2cli_tcon_recv");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, !ok, "smbXcli_conn_is_connected still connected");
+
+ return true;
+}
+
+static bool test_session_anon_encryption2(struct torture_context *tctx,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = "IPC$";
+ char *unc = NULL;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct cli_credentials *_creds = samba_cmdline_get_creds();
+ struct cli_credentials *user_creds = NULL;
+ struct cli_credentials *anon_creds = NULL;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_session *user_session = NULL;
+ struct smb2_tree *user_tree = NULL;
+ struct smb2_session *anon_session = NULL;
+ struct smb2_tree *anon_tree = NULL;
+ struct smb2_ioctl ioctl = {
+ .level = RAW_IOCTL_SMB2,
+ .in = {
+ .file = {
+ .handle = {
+ .data = {
+ [0] = UINT64_MAX,
+ [1] = UINT64_MAX,
+ },
+ },
+ },
+ .function = FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+ /* Windows client sets this to 64KiB */
+ .max_output_response = 0x10000,
+ .flags = SMB2_IOCTL_FLAG_IS_FSCTL,
+ },
+ };
+ NTSTATUS status;
+ bool ok = true;
+ struct tevent_req *subreq = NULL;
+ uint32_t timeout_msec;
+ uint32_t caps = smb2cli_conn_server_capabilities(transport0->conn);
+ NTSTATUS expected_mc_status;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ if (caps & SMB2_CAP_MULTI_CHANNEL) {
+ expected_mc_status = NT_STATUS_OK;
+ } else {
+ expected_mc_status = NT_STATUS_FS_DRIVER_REQUIRED;
+ }
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ user_creds = cli_credentials_shallow_copy(tctx, _creds);
+ torture_assert(tctx, user_creds != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(user_creds,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon");
+ ok = cli_credentials_set_smb_encryption(anon_creds,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ user_creds,
+ &user_tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed");
+ user_session = user_tree->session;
+ transport = user_session->transport;
+ ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli);
+ torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(user)");
+ ok = smbXcli_session_is_authenticated(user_session->smbXcli);
+ torture_assert(tctx, ok, "smbXcli_session_is_authenticated(user)");
+
+ anon_session = smb2_session_init(transport,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx);
+ torture_assert(tctx, anon_session != NULL, "smb2_session_init(anon)");
+
+ anon_session->anonymous_session_key = true;
+ smb2cli_session_torture_anonymous_encryption(anon_session->smbXcli, true);
+
+ status = smb2_session_setup_spnego(anon_session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2_session_setup_spnego failed");
+
+ ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli);
+ torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(anon)");
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ anon_tree = smb2_tree_init(anon_session, tctx, false);
+ torture_assert(tctx, anon_tree != NULL, "smb2_tree_init");
+
+ timeout_msec = transport->options.request_timeout * 1000;
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2cli_tcon_recv(anon)");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ ok = smb2cli_tcon_is_encryption_on(anon_tree->smbXcli);
+ torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(anon)");
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ status = smb2_ioctl(user_tree, tctx, &ioctl);
+ torture_assert_ntstatus_equal(tctx, status, expected_mc_status,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO user");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ status = smb2_ioctl(anon_tree, tctx, &ioctl);
+ torture_assert_ntstatus_equal(tctx, status, expected_mc_status,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO anonymous");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ status = smb2_ioctl(user_tree, tctx, &ioctl);
+ torture_assert_ntstatus_equal(tctx, status, expected_mc_status,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO user");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ status = smb2_ioctl(anon_tree, tctx, &ioctl);
+ torture_assert_ntstatus_equal(tctx, status, expected_mc_status,
+ "FSCTL_QUERY_NETWORK_INTERFACE_INFO anonymous");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ return true;
+}
+
+static bool test_session_anon_encryption3(struct torture_context *tctx,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = "IPC$";
+ char *unc = NULL;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct cli_credentials *_creds = samba_cmdline_get_creds();
+ struct cli_credentials *user_creds = NULL;
+ struct cli_credentials *anon_creds = NULL;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_session *user_session = NULL;
+ struct smb2_tree *user_tree = NULL;
+ struct smb2_session *anon_session = NULL;
+ struct smb2_tree *anon_tree = NULL;
+ NTSTATUS status;
+ bool ok = true;
+ struct tevent_req *subreq = NULL;
+ uint32_t timeout_msec;
+ uint8_t wrong_session_key[16] = { 0x1f, 0x2f, 0x3f, };
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ user_creds = cli_credentials_shallow_copy(tctx, _creds);
+ torture_assert(tctx, user_creds != NULL, "cli_credentials_shallow_copy");
+ ok = cli_credentials_set_smb_encryption(user_creds,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon");
+ ok = cli_credentials_set_smb_encryption(anon_creds,
+ SMB_ENCRYPTION_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ user_creds,
+ &user_tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed");
+ user_session = user_tree->session;
+ transport = user_session->transport;
+ ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli);
+ torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(user)");
+ ok = smbXcli_session_is_authenticated(user_session->smbXcli);
+ torture_assert(tctx, ok, "smbXcli_session_is_authenticated(user)");
+
+ anon_session = smb2_session_init(transport,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx);
+ torture_assert(tctx, anon_session != NULL, "smb2_session_init(anon)");
+
+ anon_session->anonymous_session_key = true;
+ anon_session->forced_session_key = data_blob_const(wrong_session_key,
+ ARRAY_SIZE(wrong_session_key));
+ smb2cli_session_torture_anonymous_encryption(anon_session->smbXcli, true);
+
+ status = smb2_session_setup_spnego(anon_session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2_session_setup_spnego failed");
+
+ ok = smb2cli_tcon_is_encryption_on(user_tree->smbXcli);
+ torture_assert(tctx, ok, "smb2cli_tcon_is_encryption_on(anon)");
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ anon_tree = smb2_tree_init(anon_session, tctx, false);
+ torture_assert(tctx, anon_tree != NULL, "smb2_tree_init");
+
+ timeout_msec = transport->options.request_timeout * 1000;
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
+ status = NT_STATUS_CONNECTION_RESET;
+ }
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_CONNECTION_RESET,
+ "smb2cli_tcon_recv");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, !ok, "smbXcli_conn_is_connected still connected");
+
+ return true;
+}
+
+static bool test_session_anon_signing1(struct torture_context *tctx,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = "IPC$";
+ char *unc = NULL;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct cli_credentials *anon_creds = NULL;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_session *anon_session = NULL;
+ struct smb2_tree *anon_tree = NULL;
+ NTSTATUS status;
+ bool ok = true;
+ struct tevent_req *subreq = NULL;
+ uint32_t timeout_msec;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon");
+ ok = cli_credentials_set_smb_signing(anon_creds,
+ SMB_SIGNING_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_signing");
+ ok = cli_credentials_set_smb_ipc_signing(anon_creds,
+ SMB_SIGNING_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_ipc_signing");
+ ok = cli_credentials_set_smb_encryption(anon_creds,
+ SMB_ENCRYPTION_OFF,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+ options.only_negprot = true;
+ options.signing = SMB_SIGNING_REQUIRED;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ anon_creds,
+ &anon_tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed");
+ anon_session = anon_tree->session;
+ transport = anon_session->transport;
+
+ anon_session->anonymous_session_key = true;
+ smb2cli_session_torture_anonymous_signing(anon_session->smbXcli, true);
+
+ status = smb2_session_setup_spnego(anon_session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2_session_setup_spnego failed");
+
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ timeout_msec = transport->options.request_timeout * 1000;
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ return true;
+}
+
+static bool test_session_anon_signing2(struct torture_context *tctx,
+ struct smb2_tree *tree0)
+{
+ const char *host = torture_setting_string(tctx, "host", NULL);
+ const char *share = "IPC$";
+ char *unc = NULL;
+ struct smb2_transport *transport0 = tree0->session->transport;
+ struct cli_credentials *anon_creds = NULL;
+ struct smbcli_options options;
+ struct smb2_transport *transport = NULL;
+ struct smb2_session *anon_session = NULL;
+ struct smb2_session *anon_session_nosign = NULL;
+ struct smb2_tree *anon_tree = NULL;
+ NTSTATUS status;
+ bool ok = true;
+ struct tevent_req *subreq = NULL;
+ uint32_t timeout_msec;
+ uint8_t wrong_session_key[16] = { 0x1f, 0x2f, 0x3f, };
+ uint64_t session_id;
+
+ if (smbXcli_conn_protocol(transport0->conn) < PROTOCOL_SMB3_00) {
+ torture_skip(tctx,
+ "Can't test without SMB3 support");
+ }
+
+ unc = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+ torture_assert(tctx, unc != NULL, "talloc_asprintf");
+
+ anon_creds = cli_credentials_init_anon(tctx);
+ torture_assert(tctx, anon_creds != NULL, "cli_credentials_init_anon");
+ ok = cli_credentials_set_smb_signing(anon_creds,
+ SMB_SIGNING_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_signing");
+ ok = cli_credentials_set_smb_ipc_signing(anon_creds,
+ SMB_SIGNING_REQUIRED,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_ipc_signing");
+ ok = cli_credentials_set_smb_encryption(anon_creds,
+ SMB_ENCRYPTION_OFF,
+ CRED_SPECIFIED);
+ torture_assert(tctx, ok, "cli_credentials_set_smb_encryption");
+
+ options = transport0->options;
+ options.client_guid = GUID_random();
+ options.only_negprot = true;
+ options.signing = SMB_SIGNING_REQUIRED;
+
+ status = smb2_connect(tctx,
+ host,
+ lpcfg_smb_ports(tctx->lp_ctx),
+ share,
+ lpcfg_resolve_context(tctx->lp_ctx),
+ anon_creds,
+ &anon_tree,
+ tctx->ev,
+ &options,
+ lpcfg_socket_options(tctx->lp_ctx),
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx));
+ torture_assert_ntstatus_ok(tctx, status, "smb2_connect failed");
+ anon_session = anon_tree->session;
+ transport = anon_session->transport;
+
+ anon_session->anonymous_session_key = true;
+ anon_session->forced_session_key = data_blob_const(wrong_session_key,
+ ARRAY_SIZE(wrong_session_key));
+ smb2cli_session_torture_anonymous_signing(anon_session->smbXcli, true);
+ smb2cli_session_torture_no_signing_disconnect(anon_session->smbXcli);
+
+ status = smb2_session_setup_spnego(anon_session,
+ anon_creds,
+ 0 /* previous_session_id */);
+ torture_assert_ntstatus_ok(tctx, status,
+ "smb2_session_setup_spnego failed");
+
+ ok = smbXcli_session_is_authenticated(anon_session->smbXcli);
+ torture_assert(tctx, !ok, "smbXcli_session_is_authenticated(anon) wrong");
+
+ /*
+ * create a new structure for the same session id,
+ * but without smb2.should_sign set.
+ */
+ session_id = smb2cli_session_current_id(anon_session->smbXcli);
+ anon_session_nosign = smb2_session_init(transport,
+ lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+ tctx);
+ torture_assert(tctx, anon_session_nosign != NULL, "smb2_session_init(anon_nosign)");
+ smb2cli_session_set_id_and_flags(anon_session_nosign->smbXcli, session_id, 0);
+ smb2cli_session_torture_no_signing_disconnect(anon_session_nosign->smbXcli);
+
+ timeout_msec = transport->options.request_timeout * 1000;
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ torture_assert_ntstatus_equal(tctx, status,
+ NT_STATUS_ACCESS_DENIED,
+ "smb2cli_tcon_recv");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ subreq = smb2cli_tcon_send(tctx,
+ tctx->ev,
+ transport->conn,
+ timeout_msec,
+ anon_session_nosign->smbXcli,
+ anon_tree->smbXcli,
+ 0, /* flags */
+ unc);
+ torture_assert(tctx, subreq != NULL, "smb2cli_tcon_send");
+
+ torture_assert(tctx,
+ tevent_req_poll_ntstatus(subreq, tctx->ev, &status),
+ "tevent_req_poll_ntstatus");
+
+ status = smb2cli_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ torture_assert_ntstatus_ok(tctx, status, "smb2cli_tcon_recv");
+
+ ok = smbXcli_conn_is_connected(transport->conn);
+ torture_assert(tctx, ok, "smbXcli_conn_is_connected");
+
+ return true;
+}
+
struct torture_suite *torture_smb2_session_init(TALLOC_CTX *ctx)
{
struct torture_suite *suite =
@@ -5599,6 +6223,11 @@ struct torture_suite *torture_smb2_session_init(TALLOC_CTX *ctx)
torture_suite_add_1smb2_test(suite, "encryption-aes-256-ccm", test_session_encryption_aes_256_ccm);
torture_suite_add_1smb2_test(suite, "encryption-aes-256-gcm", test_session_encryption_aes_256_gcm);
torture_suite_add_1smb2_test(suite, "ntlmssp_bug14932", test_session_ntlmssp_bug14932);
+ torture_suite_add_1smb2_test(suite, "anon-encryption1", test_session_anon_encryption1);
+ torture_suite_add_1smb2_test(suite, "anon-encryption2", test_session_anon_encryption2);
+ torture_suite_add_1smb2_test(suite, "anon-encryption3", test_session_anon_encryption3);
+ torture_suite_add_1smb2_test(suite, "anon-signing1", test_session_anon_signing1);
+ torture_suite_add_1smb2_test(suite, "anon-signing2", test_session_anon_signing2);
suite->description = talloc_strdup(suite, "SMB2-SESSION tests");