From 19d0fde1ace012e366182b511c528f7ab6a0ed37 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 20 Jun 2024 06:07:27 +0200 Subject: Merging upstream version 2:4.20.2+dfsg. Signed-off-by: Daniel Baumann --- source4/dns_server/dns_crypto.c | 49 +- source4/dns_server/dns_query.c | 27 +- source4/dns_server/dns_update.c | 11 + source4/dns_server/dnsserver_common.c | 8 +- source4/dsdb/repl/drepl_out_helpers.c | 26 +- source4/dsdb/samdb/ldb_modules/operational.c | 2 +- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 17 +- source4/dsdb/schema/schema_set.c | 14 +- source4/libcli/dgram/dgramsocket.c | 40 +- source4/libcli/dgram/libdgram.h | 3 + source4/libcli/smb2/session.c | 16 +- source4/libcli/smb2/smb2.h | 2 + source4/nbt_server/dgram/request.c | 56 ++- source4/nbt_server/interfaces.c | 29 ++ source4/nbt_server/nbt_server.c | 143 ++++++ source4/nbt_server/nbt_server.h | 2 + source4/nbt_server/wins/winsdb.c | 5 +- source4/nbt_server/wins/winsserver.c | 3 +- source4/nbt_server/wscript_build | 2 +- source4/ntvfs/posix/pvfs_streams.c | 3 +- source4/rpc_server/dnsserver/dnsdata.c | 16 +- source4/rpc_server/samr/dcesrv_samr.c | 7 +- source4/selftest/tests.py | 14 +- source4/torture/smb2/ioctl.c | 64 +++ source4/torture/smb2/session.c | 629 ++++++++++++++++++++++++ 25 files changed, 1132 insertions(+), 56 deletions(-) (limited to 'source4') 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 @@ -7388,6 +7388,68 @@ static bool test_ioctl_bug14788_NETWORK_INTERFACE(struct torture_context *tortur return true; } +/* + * 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 */ @@ -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"); -- cgit v1.2.3