summaryrefslogtreecommitdiffstats
path: root/libcli
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libcli/http/http.c309
-rw-r--r--libcli/http/http_internal.h4
-rw-r--r--libcli/nbt/libnbt.h3
-rw-r--r--libcli/nbt/nbtsocket.c44
-rw-r--r--libcli/security/dom_sid.c14
-rw-r--r--libcli/smb/smbXcli_base.c104
-rw-r--r--libcli/smb/smbXcli_base.h5
7 files changed, 452 insertions, 31 deletions
diff --git a/libcli/http/http.c b/libcli/http/http.c
index 96c573a..6f22214 100644
--- a/libcli/http/http.c
+++ b/libcli/http/http.c
@@ -28,16 +28,28 @@
#undef strcasecmp
+enum http_body_type {
+ BODY_NONE = 0,
+ BODY_CONTENT_LENGTH,
+ BODY_CHUNKED,
+ BODY_ERROR = -1
+};
+
/**
* Determines if a response should have a body.
- * @return 1 if the response MUST have a body; 0 if the response MUST NOT have
- * a body. Returns -1 on error.
+ * @return 2 if response MUST use chunked encoding,
+ * 1 if the response MUST have a body;
+ * 0 if the response MUST NOT have a body.
+ * Returns -1 on error.
*/
-static int http_response_needs_body(struct http_request *req)
+static enum http_body_type http_response_needs_body(
+ struct http_request *req)
{
struct http_header *h = NULL;
- if (!req) return -1;
+ if (!req) {
+ return BODY_ERROR;
+ }
for (h = req->headers; h != NULL; h = h->next) {
int cmp;
@@ -45,6 +57,18 @@ static int http_response_needs_body(struct http_request *req)
char c;
unsigned long long v;
+ cmp = strcasecmp(h->key, "Transfer-Encoding");
+ if (cmp == 0) {
+ cmp = strcasecmp(h->value, "chunked");
+ if (cmp == 0) {
+ return BODY_CHUNKED;
+ }
+ /* unsupported Transfer-Encoding type */
+ DBG_ERR("Unsupported transfer encoding type %s\n",
+ h->value);
+ return BODY_ERROR;
+ }
+
cmp = strcasecmp(h->key, "Content-Length");
if (cmp != 0) {
continue;
@@ -52,20 +76,25 @@ static int http_response_needs_body(struct http_request *req)
n = sscanf(h->value, "%llu%c", &v, &c);
if (n != 1) {
- return -1;
+ return BODY_ERROR;
}
req->remaining_content_length = v;
if (v != 0) {
- return 1;
+ return BODY_CONTENT_LENGTH;
}
- return 0;
+ return BODY_NONE;
}
- return 0;
+ return BODY_NONE;
}
+struct http_chunk
+{
+ struct http_chunk *prev, *next;
+ DATA_BLOB blob;
+};
struct http_read_response_state {
enum http_parser_state parser_state;
@@ -73,6 +102,7 @@ struct http_read_response_state {
uint64_t max_content_length;
DATA_BLOB buffer;
struct http_request *response;
+ struct http_chunk *chunks;
};
/**
@@ -86,7 +116,7 @@ static enum http_read_status http_parse_headers(struct http_read_response_state
char *key = NULL;
char *value = NULL;
int n = 0;
- int ret;
+ enum http_body_type ret;
/* Sanity checks */
if (!state || !state->response) {
@@ -119,19 +149,24 @@ static enum http_read_status http_parse_headers(struct http_read_response_state
ret = http_response_needs_body(state->response);
switch (ret) {
- case 1:
+ case BODY_CHUNKED:
+ DEBUG(11, ("%s: need to process chunks... %d\n", __func__,
+ state->response->response_code));
+ state->parser_state = HTTP_READING_CHUNK_SIZE;
+ break;
+ case BODY_CONTENT_LENGTH:
if (state->response->remaining_content_length <= state->max_content_length) {
DEBUG(11, ("%s: Start of read body\n", __func__));
state->parser_state = HTTP_READING_BODY;
break;
}
FALL_THROUGH;
- case 0:
+ case BODY_NONE:
DEBUG(11, ("%s: Skipping body for code %d\n", __func__,
state->response->response_code));
state->parser_state = HTTP_READING_DONE;
break;
- case -1:
+ case BODY_ERROR:
DEBUG(0, ("%s_: Error in http_response_needs_body\n", __func__));
TALLOC_FREE(line);
return HTTP_DATA_CORRUPTED;
@@ -162,6 +197,141 @@ error:
return status;
}
+static bool http_response_process_chunks(struct http_read_response_state *state)
+{
+ struct http_chunk *chunk = NULL;
+ struct http_request *resp = state->response;
+
+ for (chunk = state->chunks; chunk; chunk = chunk->next) {
+ DBG_DEBUG("processing chunk of size %zi\n",
+ chunk->blob.length);
+ if (resp->body.data == NULL) {
+ resp->body = chunk->blob;
+ chunk->blob = data_blob_null;
+ talloc_steal(resp, resp->body.data);
+ continue;
+ }
+
+ resp->body.data =
+ talloc_realloc(resp,
+ resp->body.data,
+ uint8_t,
+ resp->body.length + chunk->blob.length);
+ if (!resp->body.data) {
+ return false;
+ }
+ memcpy(resp->body.data + resp->body.length,
+ chunk->blob.data,
+ chunk->blob.length);
+
+ resp->body.length += chunk->blob.length;
+
+ TALLOC_FREE(chunk->blob.data);
+ chunk->blob = data_blob_null;
+ }
+ return true;
+}
+
+static enum http_read_status http_read_chunk_term(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_ALL_DATA_READ;
+ char *ptr = NULL;
+ char *line = NULL;
+
+ /* Sanity checks */
+ if (!state || !state->response) {
+ DBG_ERR("%s: Invalid Parameter\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DBG_ERR("%s: Memory error\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+ ptr = strstr(line, "\r\n");
+ if (ptr == NULL) {
+ TALLOC_FREE(line);
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ if (strncmp(line, "\r\n", 2) == 0) {
+ /* chunk terminator */
+ if (state->parser_state == HTTP_READING_FINAL_CHUNK_TERM) {
+ if (http_response_process_chunks(state) == false) {
+ status = HTTP_DATA_CORRUPTED;
+ goto out;
+ }
+ state->parser_state = HTTP_READING_DONE;
+ } else {
+ state->parser_state = HTTP_READING_CHUNK_SIZE;
+ }
+ status = HTTP_ALL_DATA_READ;
+ goto out;
+ }
+
+ status = HTTP_DATA_CORRUPTED;
+out:
+ TALLOC_FREE(line);
+ return status;
+}
+
+static enum http_read_status http_read_chunk_size(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_ALL_DATA_READ;
+ char *ptr = NULL;
+ char *line = NULL;
+ char *value = NULL;
+ int n = 0;
+ unsigned long long v;
+
+ /* Sanity checks */
+ if (!state || !state->response) {
+ DBG_ERR("%s: Invalid Parameter\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DBG_ERR("%s: Memory error\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+ ptr = strstr(line, "\r\n");
+ if (ptr == NULL) {
+ TALLOC_FREE(line);
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ n = sscanf(line, "%m[^\r\n]\r\n", &value);
+ if (n != 1) {
+ DBG_ERR("%s: Error parsing chunk size '%s'\n", __func__, line);
+ status = HTTP_DATA_CORRUPTED;
+ goto out;
+ }
+
+ DBG_DEBUG("Got chunk size string %s\n", value);
+ n = sscanf(value, "%llx", &v);
+ if (n != 1) {
+ DBG_ERR("%s: Error parsing chunk size '%s'\n", __func__, line);
+ status = HTTP_DATA_CORRUPTED;
+ goto out;
+ }
+ DBG_DEBUG("Got chunk size %llu 0x%llx\n", v, v);
+ if (v == 0) {
+ state->parser_state = HTTP_READING_FINAL_CHUNK_TERM;
+ } else {
+ state->parser_state = HTTP_READING_CHUNK;
+ }
+ state->response->remaining_content_length = v;
+ status = HTTP_ALL_DATA_READ;
+out:
+ if (value) {
+ free(value);
+ }
+ TALLOC_FREE(line);
+ return status;
+}
+
/**
* Parses the first line of a HTTP response
*/
@@ -301,6 +471,55 @@ static enum http_read_status http_read_body(struct http_read_response_state *sta
return HTTP_ALL_DATA_READ;
}
+static enum http_read_status http_read_chunk(struct http_read_response_state *state)
+{
+ struct http_request *resp = state->response;
+ struct http_chunk *chunk = NULL;
+ size_t total = 0;
+ size_t prev = 0;
+
+ if (state->buffer.length < resp->remaining_content_length) {
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ for (chunk = state->chunks; chunk; chunk = chunk->next) {
+ total += chunk->blob.length;
+ }
+
+ prev = total;
+ total = total + state->buffer.length;
+ if (total < prev) {
+ DBG_ERR("adding chunklen %zu to buf len %zu "
+ "will overflow\n",
+ state->buffer.length,
+ prev);
+ return HTTP_DATA_CORRUPTED;
+ }
+ if (total > state->max_content_length) {
+ DBG_DEBUG("size %zu exceeds "
+ "max content len %"PRIu64" skipping body\n",
+ total,
+ state->max_content_length);
+ state->parser_state = HTTP_READING_DONE;
+ goto out;
+ }
+
+ /* chunk read */
+ chunk = talloc_zero(state, struct http_chunk);
+ if (chunk == NULL) {
+ DBG_ERR("%s: Memory error\n", __func__);
+ return HTTP_DATA_CORRUPTED;
+ }
+ chunk->blob = state->buffer;
+ talloc_steal(chunk, chunk->blob.data);
+ DLIST_ADD_END(state->chunks, chunk);
+ state->parser_state = HTTP_READING_CHUNK_TERM;
+out:
+ state->buffer = data_blob_null;
+ resp->remaining_content_length = 0;
+ return HTTP_ALL_DATA_READ;
+}
+
static enum http_read_status http_read_trailer(struct http_read_response_state *state)
{
enum http_read_status status = HTTP_DATA_CORRUPTED;
@@ -323,6 +542,16 @@ static enum http_read_status http_parse_buffer(struct http_read_response_state *
case HTTP_READING_BODY:
return http_read_body(state);
break;
+ case HTTP_READING_FINAL_CHUNK_TERM:
+ case HTTP_READING_CHUNK_TERM:
+ return http_read_chunk_term(state);
+ break;
+ case HTTP_READING_CHUNK_SIZE:
+ return http_read_chunk_size(state);
+ break;
+ case HTTP_READING_CHUNK:
+ return http_read_chunk(state);
+ break;
case HTTP_READING_TRAILER:
return http_read_trailer(state);
break;
@@ -527,20 +756,60 @@ static int http_read_response_next_vector(struct tstream_context *stream,
*_count = 1;
}
break;
- case HTTP_MORE_DATA_EXPECTED:
- /* TODO Optimize, allocating byte by byte */
- state->buffer.data = talloc_realloc(state, state->buffer.data,
- uint8_t, state->buffer.length + 1);
+ case HTTP_MORE_DATA_EXPECTED: {
+ size_t toread = 1;
+ size_t total;
+ if (state->parser_state == HTTP_READING_BODY ||
+ state->parser_state == HTTP_READING_CHUNK) {
+ struct http_request *resp = state->response;
+ toread = resp->remaining_content_length -
+ state->buffer.length;
+ }
+
+ total = toread + state->buffer.length;
+
+ if (total < state->buffer.length) {
+ DBG_ERR("adding %zu to buf len %zu "
+ "will overflow\n",
+ toread,
+ state->buffer.length);
+ return -1;
+ }
+
+ /*
+ * test if content-length message exceeds the
+ * specified max_content_length
+ * Note: This check won't be hit at the moment
+ * due to an existing check in parse_headers
+ * which will skip the body. Check is here
+ * for completeness and to cater for future
+ * code changes.
+ */
+ if (state->parser_state == HTTP_READING_BODY) {
+ if (total > state->max_content_length) {
+ DBG_ERR("content size %zu exceeds "
+ "max content len %"PRIu64"\n",
+ total,
+ state->max_content_length);
+ return -1;
+ }
+ }
+
+ state->buffer.data =
+ talloc_realloc(state, state->buffer.data,
+ uint8_t,
+ state->buffer.length + toread);
if (!state->buffer.data) {
return -1;
}
- state->buffer.length++;
+ state->buffer.length += toread;
vector[0].iov_base = (void *)(state->buffer.data +
- state->buffer.length - 1);
- vector[0].iov_len = 1;
+ state->buffer.length - toread);
+ vector[0].iov_len = toread;
*_vector = vector;
*_count = 1;
break;
+ }
case HTTP_DATA_CORRUPTED:
case HTTP_REQUEST_CANCELED:
case HTTP_DATA_TOO_LONG:
@@ -603,7 +872,7 @@ static void http_read_response_done(struct tevent_req *subreq)
{
NTSTATUS status;
struct tevent_req *req;
- int ret;
+ enum http_body_type ret;
int sys_errno;
if (!subreq) {
diff --git a/libcli/http/http_internal.h b/libcli/http/http_internal.h
index ec17f7e..786ace6 100644
--- a/libcli/http/http_internal.h
+++ b/libcli/http/http_internal.h
@@ -28,6 +28,10 @@ enum http_parser_state {
HTTP_READING_BODY,
HTTP_READING_TRAILER,
HTTP_READING_DONE,
+ HTTP_READING_CHUNK_SIZE,
+ HTTP_READING_CHUNK,
+ HTTP_READING_CHUNK_TERM,
+ HTTP_READING_FINAL_CHUNK_TERM,
};
enum http_read_status {
diff --git a/libcli/nbt/libnbt.h b/libcli/nbt/libnbt.h
index 204484b..6a30c9f 100644
--- a/libcli/nbt/libnbt.h
+++ b/libcli/nbt/libnbt.h
@@ -331,6 +331,9 @@ NTSTATUS nbt_set_unexpected_handler(struct nbt_name_socket *nbtsock,
void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
struct socket_address *),
void *private_data);
+NTSTATUS nbt_name_send_raw(struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ const DATA_BLOB pkt_blob);
NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
struct socket_address *dest,
struct nbt_name_packet *request);
diff --git a/libcli/nbt/nbtsocket.c b/libcli/nbt/nbtsocket.c
index 47e73cf..b2945ad 100644
--- a/libcli/nbt/nbtsocket.c
+++ b/libcli/nbt/nbtsocket.c
@@ -448,6 +448,50 @@ failed:
return NULL;
}
+/*
+ send off a nbt name packet
+*/
+_PUBLIC_ NTSTATUS nbt_name_send_raw(struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ const DATA_BLOB pkt_blob)
+{
+ struct nbt_name_request *req;
+
+ req = talloc_zero(nbtsock, struct nbt_name_request);
+ NT_STATUS_HAVE_NO_MEMORY(req);
+
+ req->nbtsock = nbtsock;
+ req->dest = socket_address_copy(req, dest);
+ if (req->dest == NULL) {
+ goto failed;
+ }
+ req->state = NBT_REQUEST_SEND;
+ /*
+ * We don't expect a response so
+ * just pretent it is a request,
+ * but we really don't care about the
+ * content.
+ */
+ req->is_reply = true;
+
+ req->encoded = data_blob_dup_talloc(req, pkt_blob);
+ if (req->encoded.length != pkt_blob.length) {
+ goto failed;
+ }
+
+ talloc_set_destructor(req, nbt_name_request_destructor);
+
+ DLIST_ADD_END(nbtsock->send_queue, req);
+
+ TEVENT_FD_WRITEABLE(nbtsock->fde);
+
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(req);
+ return NT_STATUS_NO_MEMORY;
+}
+
/*
send off a nbt name reply
diff --git a/libcli/security/dom_sid.c b/libcli/security/dom_sid.c
index eaece2a..21012b7 100644
--- a/libcli/security/dom_sid.c
+++ b/libcli/security/dom_sid.c
@@ -28,6 +28,7 @@
#include "librpc/gen_ndr/security.h"
#include "dom_sid.h"
#include "lib/util/smb_strtox.h"
+#include "lib/util/tsort.h"
/*****************************************************************
Compare the auth portion of two sids.
@@ -46,11 +47,12 @@ int dom_sid_compare_auth(const struct dom_sid *sid1,
return 1;
if (sid1->sid_rev_num != sid2->sid_rev_num)
- return sid1->sid_rev_num - sid2->sid_rev_num;
+ return NUMERIC_CMP(sid1->sid_rev_num, sid2->sid_rev_num);
for (i = 0; i < 6; i++)
- if (sid1->id_auth[i] != sid2->id_auth[i])
- return sid1->id_auth[i] - sid2->id_auth[i];
+ if (sid1->id_auth[i] != sid2->id_auth[i]) {
+ return NUMERIC_CMP(sid1->id_auth[i], sid2->id_auth[i]);
+ }
return 0;
}
@@ -71,9 +73,9 @@ int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2)
return 1;
/* Compare most likely different rids, first: i.e start at end */
- if (sid1->num_auths != sid2->num_auths)
- return sid1->num_auths - sid2->num_auths;
-
+ if (sid1->num_auths != sid2->num_auths) {
+ return NUMERIC_CMP(sid1->num_auths, sid2->num_auths);
+ }
for (i = sid1->num_auths-1; i >= 0; --i) {
if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
return -1;
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index a52a615..87acddf 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -166,6 +166,13 @@ struct smb2cli_session {
uint16_t channel_sequence;
bool replay_active;
bool require_signed_response;
+
+ /*
+ * The following are just for torture tests
+ */
+ bool anonymous_signing;
+ bool anonymous_encryption;
+ bool no_signing_disconnect;
};
struct smbXcli_session {
@@ -3999,6 +4006,9 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED) ||
NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) ||
+ (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ session != NULL &&
+ session->smb2->no_signing_disconnect) ||
NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
/*
* if the server returns
@@ -4042,8 +4052,29 @@ static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
/*
* If the signing check fails, we disconnect
* the connection.
+ *
+ * Unless
+ * smb2cli_session_torture_no_signing_disconnect
+ * was called in torture tests
*/
- return signing_status;
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ return signing_status;
+ }
+
+ if (!NT_STATUS_EQUAL(status, signing_status)) {
+ return signing_status;
+ }
+
+ if (session == NULL) {
+ return signing_status;
+ }
+
+ if (!session->smb2->no_signing_disconnect) {
+ return signing_status;
+ }
+
+ state->smb2.signing_skipped = true;
}
}
@@ -6332,6 +6363,23 @@ void smb2cli_session_require_signed_response(struct smbXcli_session *session,
session->smb2->require_signed_response = require_signed_response;
}
+void smb2cli_session_torture_anonymous_signing(struct smbXcli_session *session,
+ bool anonymous_signing)
+{
+ session->smb2->anonymous_signing = anonymous_signing;
+}
+
+void smb2cli_session_torture_anonymous_encryption(struct smbXcli_session *session,
+ bool anonymous_encryption)
+{
+ session->smb2->anonymous_encryption = anonymous_encryption;
+}
+
+void smb2cli_session_torture_no_signing_disconnect(struct smbXcli_session *session)
+{
+ session->smb2->no_signing_disconnect = true;
+}
+
NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session,
const struct iovec *iov)
{
@@ -6432,6 +6480,10 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
conn->protocol,
preauth_hash);
+ if (session->smb2->anonymous_encryption) {
+ goto skip_signing_key;
+ }
+
status = smb2_signing_key_sign_create(session->smb2,
conn->smb2.server.sign_algo,
&_session_key,
@@ -6441,6 +6493,15 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
return status;
}
+ if (session->smb2->anonymous_signing) {
+ /*
+ * skip encryption and application keys
+ */
+ goto skip_application_key;
+ }
+
+skip_signing_key:
+
status = smb2_signing_key_cipher_create(session->smb2,
conn->smb2.server.cipher,
&_session_key,
@@ -6459,6 +6520,10 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
return status;
}
+ if (session->smb2->anonymous_encryption) {
+ goto skip_application_key;
+ }
+
status = smb2_signing_key_sign_create(session->smb2,
conn->smb2.server.sign_algo,
&_session_key,
@@ -6468,6 +6533,8 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
return status;
}
+skip_application_key:
+
status = smb2_signing_key_copy(session,
session->smb2->signing_key,
&session->smb2_channel.signing_key);
@@ -6477,6 +6544,18 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
check_signature = conn->mandatory_signing;
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ check_signature = true;
+ }
+
+ if (session->smb2->anonymous_signing) {
+ check_signature = false;
+ }
+
+ if (session->smb2->anonymous_encryption) {
+ check_signature = false;
+ }
+
hdr_flags = IVAL(recv_iov[0].iov_base, SMB2_HDR_FLAGS);
if (hdr_flags & SMB2_HDR_FLAG_SIGNED) {
/*
@@ -6492,10 +6571,6 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
check_signature = true;
}
- if (conn->protocol >= PROTOCOL_SMB3_11) {
- check_signature = true;
- }
-
if (check_signature) {
status = smb2_signing_check_pdu(session->smb2_channel.signing_key,
recv_iov, 3);
@@ -6527,6 +6602,15 @@ NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
session->smb2->should_encrypt = false;
}
+ if (session->smb2->anonymous_signing) {
+ session->smb2->should_sign = true;
+ }
+
+ if (session->smb2->anonymous_encryption) {
+ session->smb2->should_encrypt = true;
+ session->smb2->should_sign = false;
+ }
+
/*
* CCM and GCM algorithms must never have their
* nonce wrap, or the security of the whole
@@ -6698,6 +6782,16 @@ NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session,
NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session)
{
+ if (session->smb2->anonymous_signing) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (session->smb2->anonymous_encryption) {
+ SMB_ASSERT(session->smb2->should_encrypt);
+ SMB_ASSERT(!session->smb2->should_sign);
+ return NT_STATUS_OK;
+ }
+
if (!session->smb2->should_sign) {
/*
* We need required signing on the session
diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
index 25ccd84..69fa131 100644
--- a/libcli/smb/smbXcli_base.h
+++ b/libcli/smb/smbXcli_base.h
@@ -535,6 +535,11 @@ void smb2cli_session_start_replay(struct smbXcli_session *session);
void smb2cli_session_stop_replay(struct smbXcli_session *session);
void smb2cli_session_require_signed_response(struct smbXcli_session *session,
bool require_signed_response);
+void smb2cli_session_torture_anonymous_signing(struct smbXcli_session *session,
+ bool anonymous_signing);
+void smb2cli_session_torture_anonymous_encryption(struct smbXcli_session *session,
+ bool anonymous_encryption);
+void smb2cli_session_torture_no_signing_disconnect(struct smbXcli_session *session);
NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session,
const struct iovec *iov);
NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,