#include "../lib/tsocket/tsocket.h"
#include "../libcli/security/security.h"
#include "../lib/util/tevent_ntstatus.h"
-#include "lib/crypto/sha512.h"
#include "lib/crypto/aes.h"
#include "lib/crypto/aes_ccm_128.h"
#include "lib/crypto/aes_gcm_128.h"
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_SMB2
+
static struct tevent_req *smbd_smb2_session_setup_wrap_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct smbd_smb2_request *smb2req,
}
tevent_req_set_callback(subreq, smbd_smb2_request_sesssetup_done, smb2req);
- return smbd_smb2_request_pending_queue(smb2req, subreq, 500);
+ /*
+ * Avoid sending a STATUS_PENDING message, which
+ * matches a Windows Server and avoids problems with
+ * MacOS clients.
+ *
+ * Even after 90 seconds a Windows Server doesn't return
+ * STATUS_PENDING if using NTLMSSP against a non reachable
+ * trusted domain.
+ */
+ return smbd_smb2_request_pending_queue(smb2req, subreq, 0);
}
static void smbd_smb2_request_sesssetup_done(struct tevent_req *subreq)
struct smbXsrv_preauth *preauth;
struct _derivation *d;
DATA_BLOB p;
- struct hc_sha512state sctx;
+ gnutls_hash_hd_t hash_hnd;
+ int rc;
preauth = talloc_move(smb2req, &auth->preauth);
- samba_SHA512_Init(&sctx);
- samba_SHA512_Update(&sctx, preauth->sha512_value,
- sizeof(preauth->sha512_value));
+ rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_SHA512);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ rc = gnutls_hash(hash_hnd,
+ preauth->sha512_value,
+ sizeof(preauth->sha512_value));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return NT_STATUS_ACCESS_DENIED;
+ }
for (i = 1; i < smb2req->in.vector_count; i++) {
- samba_SHA512_Update(&sctx,
- smb2req->in.vector[i].iov_base,
- smb2req->in.vector[i].iov_len);
+ rc = gnutls_hash(hash_hnd,
+ smb2req->in.vector[i].iov_base,
+ smb2req->in.vector[i].iov_len);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return NT_STATUS_ACCESS_DENIED;
+ }
}
- samba_SHA512_Final(preauth->sha512_value, &sctx);
+ gnutls_hash_deinit(hash_hnd, preauth->sha512_value);
p = data_blob_const(preauth->sha512_value,
sizeof(preauth->sha512_value));
memcpy(session_key, session_info->session_key.data,
MIN(session_info->session_key.length, sizeof(session_key)));
- x->global->signing_key = data_blob_talloc(x->global,
- session_key,
- sizeof(session_key));
- if (x->global->signing_key.data == NULL) {
+ x->global->signing_key = talloc_zero(x->global,
+ struct smb2_signing_key);
+ if (x->global->signing_key == NULL) {
+ ZERO_STRUCT(session_key);
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_set_destructor(x->global->signing_key,
+ smb2_signing_key_destructor);
+
+ x->global->signing_key->blob =
+ x->global->signing_key_blob =
+ data_blob_talloc(x->global,
+ session_key,
+ sizeof(session_key));
+ if (!smb2_signing_key_valid(x->global->signing_key)) {
ZERO_STRUCT(session_key);
return NT_STATUS_NO_MEMORY;
}
if (xconn->protocol >= PROTOCOL_SMB2_24) {
struct _derivation *d = &derivation.signing;
- smb2_key_derivation(session_key, sizeof(session_key),
- d->label.data, d->label.length,
- d->context.data, d->context.length,
- x->global->signing_key.data);
+ status = smb2_key_derivation(session_key, sizeof(session_key),
+ d->label.data, d->label.length,
+ d->context.data, d->context.length,
+ x->global->signing_key->blob.data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
}
if (xconn->protocol >= PROTOCOL_SMB2_24) {
struct _derivation *d = &derivation.decryption;
- x->global->decryption_key = data_blob_talloc(x->global,
+ x->global->decryption_key_blob = data_blob_talloc(x->global,
session_key,
sizeof(session_key));
- if (x->global->decryption_key.data == NULL) {
+ if (x->global->decryption_key_blob.data == NULL) {
ZERO_STRUCT(session_key);
return NT_STATUS_NO_MEMORY;
}
- smb2_key_derivation(session_key, sizeof(session_key),
- d->label.data, d->label.length,
- d->context.data, d->context.length,
- x->global->decryption_key.data);
+ status = smb2_key_derivation(session_key, sizeof(session_key),
+ d->label.data, d->label.length,
+ d->context.data, d->context.length,
+ x->global->decryption_key_blob.data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
}
if (xconn->protocol >= PROTOCOL_SMB2_24) {
struct _derivation *d = &derivation.encryption;
size_t nonce_size;
- x->global->encryption_key = data_blob_talloc(x->global,
+ x->global->encryption_key_blob = data_blob_talloc(x->global,
session_key,
sizeof(session_key));
- if (x->global->encryption_key.data == NULL) {
+ if (x->global->encryption_key_blob.data == NULL) {
ZERO_STRUCT(session_key);
return NT_STATUS_NO_MEMORY;
}
- smb2_key_derivation(session_key, sizeof(session_key),
- d->label.data, d->label.length,
- d->context.data, d->context.length,
- x->global->encryption_key.data);
+ status = smb2_key_derivation(session_key, sizeof(session_key),
+ d->label.data, d->label.length,
+ d->context.data, d->context.length,
+ x->global->encryption_key_blob.data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
/*
* CCM and GCM algorithms must never have their
x->nonce_low = 0;
}
- x->global->application_key = data_blob_dup_talloc(x->global,
- x->global->signing_key);
+ x->global->application_key =
+ data_blob_dup_talloc(x->global, x->global->signing_key->blob);
if (x->global->application_key.data == NULL) {
ZERO_STRUCT(session_key);
return NT_STATUS_NO_MEMORY;
}
+ talloc_keep_secret(x->global->application_key.data);
if (xconn->protocol >= PROTOCOL_SMB2_24) {
struct _derivation *d = &derivation.application;
- smb2_key_derivation(session_key, sizeof(session_key),
- d->label.data, d->label.length,
- d->context.data, d->context.length,
- x->global->application_key.data);
+ status = smb2_key_derivation(session_key, sizeof(session_key),
+ d->label.data, d->label.length,
+ d->context.data, d->context.length,
+ x->global->application_key.data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (xconn->protocol >= PROTOCOL_SMB3_00 && lp_debug_encryption()) {
+ DEBUG(0, ("debug encryption: dumping generated session keys\n"));
+ DEBUGADD(0, ("Session Id "));
+ dump_data(0, (uint8_t*)&session->global->session_wire_id,
+ sizeof(session->global->session_wire_id));
+ DEBUGADD(0, ("Session Key "));
+ dump_data(0, session_key, sizeof(session_key));
+ DEBUGADD(0, ("Signing Key "));
+ dump_data(0, x->global->signing_key->blob.data,
+ x->global->signing_key->blob.length);
+ DEBUGADD(0, ("App Key "));
+ dump_data(0, x->global->application_key.data,
+ x->global->application_key.length);
+
+ /* In server code, ServerIn is the decryption key */
+
+ DEBUGADD(0, ("ServerIn Key "));
+ dump_data(0, x->global->decryption_key_blob.data,
+ x->global->decryption_key_blob.length);
+ DEBUGADD(0, ("ServerOut Key "));
+ dump_data(0, x->global->encryption_key_blob.data,
+ x->global->encryption_key_blob.length);
}
+
ZERO_STRUCT(session_key);
- x->global->channels[0].signing_key = data_blob_dup_talloc(x->global->channels,
- x->global->signing_key);
- if (x->global->channels[0].signing_key.data == NULL) {
+ x->global->channels[0].signing_key =
+ talloc_zero(x->global->channels, struct smb2_signing_key);
+ if (x->global->channels[0].signing_key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_set_destructor(x->global->channels[0].signing_key,
+ smb2_signing_key_destructor);
+
+ x->global->channels[0].signing_key->blob =
+ x->global->channels[0].signing_key_blob =
+ data_blob_dup_talloc(x->global->channels[0].signing_key,
+ x->global->signing_key->blob);
+ if (!smb2_signing_key_valid(x->global->channels[0].signing_key)) {
return NT_STATUS_NO_MEMORY;
}
+ talloc_keep_secret(x->global->channels[0].signing_key->blob.data);
data_blob_clear_free(&session_info->session_key);
session_info->session_key = data_blob_dup_talloc(session_info,
if (session_info->session_key.data == NULL) {
return NT_STATUS_NO_MEMORY;
}
+ talloc_keep_secret(session_info->session_key.data);
session->compat = talloc_zero(session, struct user_struct);
if (session->compat == NULL) {
global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
*out_session_id = session->global->session_wire_id;
+ smb2req->last_session_id = session->global->session_wire_id;
return NT_STATUS_OK;
}
if (session_info->session_key.data == NULL) {
return NT_STATUS_NO_MEMORY;
}
+ talloc_keep_secret(session_info->session_key.data);
session->compat->session_info = session_info;
session->compat->vuid = session->global->session_wire_id;
reload_services(smb2req->sconn, conn_snum_used, true);
+ if (security_session_user_level(session_info, NULL) >= SECURITY_USER) {
+ smb2req->do_signing = true;
+ }
+
session->status = NT_STATUS_OK;
TALLOC_FREE(session->global->auth_session_info);
session->global->auth_session_info = talloc_move(session->global,
conn_clear_vuid_caches(xconn->client->sconn, session->compat->vuid);
- if (security_session_user_level(session_info, NULL) >= SECURITY_USER) {
- smb2req->do_signing = true;
- }
-
*out_session_id = session->global->session_wire_id;
return NT_STATUS_OK;
struct smbXsrv_preauth *preauth;
struct _derivation *d;
DATA_BLOB p;
- struct hc_sha512state sctx;
+ gnutls_hash_hd_t hash_hnd = NULL;
+ int rc;
preauth = talloc_move(smb2req, &auth->preauth);
- samba_SHA512_Init(&sctx);
- samba_SHA512_Update(&sctx, preauth->sha512_value,
- sizeof(preauth->sha512_value));
+ rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_SHA512);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+
+ rc = gnutls_hash(hash_hnd,
+ preauth->sha512_value,
+ sizeof(preauth->sha512_value));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
for (i = 1; i < smb2req->in.vector_count; i++) {
- samba_SHA512_Update(&sctx,
- smb2req->in.vector[i].iov_base,
- smb2req->in.vector[i].iov_len);
+ rc = gnutls_hash(hash_hnd,
+ smb2req->in.vector[i].iov_base,
+ smb2req->in.vector[i].iov_len);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
}
- samba_SHA512_Final(preauth->sha512_value, &sctx);
+ gnutls_hash_deinit(hash_hnd, preauth->sha512_value);
p = data_blob_const(preauth->sha512_value,
sizeof(preauth->sha512_value));
memcpy(session_key, session_info->session_key.data,
MIN(session_info->session_key.length, sizeof(session_key)));
- c->signing_key = data_blob_talloc(x->global,
- session_key,
- sizeof(session_key));
- if (c->signing_key.data == NULL) {
+ c->signing_key = talloc_zero(x->global, struct smb2_signing_key);
+ if (c->signing_key == NULL) {
ZERO_STRUCT(session_key);
return NT_STATUS_NO_MEMORY;
}
+ talloc_set_destructor(c->signing_key,
+ smb2_signing_key_destructor);
+
+ c->signing_key->blob =
+ c->signing_key_blob =
+ data_blob_talloc(c->signing_key,
+ session_key,
+ sizeof(session_key));
+ if (!smb2_signing_key_valid(c->signing_key)) {
+ ZERO_STRUCT(session_key);
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_keep_secret(c->signing_key->blob.data);
if (xconn->protocol >= PROTOCOL_SMB2_24) {
struct _derivation *d = &derivation.signing;
- smb2_key_derivation(session_key, sizeof(session_key),
- d->label.data, d->label.length,
- d->context.data, d->context.length,
- c->signing_key.data);
+ status = smb2_key_derivation(session_key, sizeof(session_key),
+ d->label.data, d->label.length,
+ d->context.data, d->context.length,
+ c->signing_key->blob.data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
}
ZERO_STRUCT(session_key);
smb2req->xconn,
&c);
if (NT_STATUS_IS_OK(status)) {
- if (c->signing_key.length == 0) {
+ if (!smb2_signing_key_valid(c->signing_key)) {
goto auth;
}
tevent_req_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
gensec_want_feature(state->auth->gensec, GENSEC_FEATURE_SESSION_KEY);
gensec_want_feature(state->auth->gensec, GENSEC_FEATURE_UNIX_TOKEN);
+ gensec_want_feature(state->auth->gensec, GENSEC_FEATURE_SMB_TRANSPORT);
status = gensec_start_mech_by_oid(state->auth->gensec,
GENSEC_OID_SPNEGO);
tevent_req_set_callback(subreq, smbd_smb2_request_logoff_done, req);
/*
- * Wait a long time before going async on this to allow
- * requests we're waiting on to finish. Set timeout to 10 secs.
+ * Avoid sending a STATUS_PENDING message, it's very likely
+ * the client won't expect that.
*/
- return smbd_smb2_request_pending_queue(req, subreq, 10000000);
+ return smbd_smb2_request_pending_queue(req, subreq, 0);
}
static void smbd_smb2_request_logoff_done(struct tevent_req *subreq)