mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 18:21:24 +02:00
ksmbd: fix multichannel binding and enforce channel limit
A signed multichannel SESSION_SETUP binding request can require multiple
authentication rounds. ksmbd excludes SESSION_SETUP from the signed
request check and tries to sign every binding response with the channel
signing key. The channel does not exist for
STATUS_MORE_PROCESSING_REQUIRED, so that response is sent unsigned.
Clients reject it with STATUS_ACCESS_DENIED.
The final channel signing key also needs the key exported by the binding
authentication context. Keep that key in the channel instead of
overwriting the established session key, and use the session signing key
for intermediate and failed binding responses. Retain the binding session
reference until an error response has been signed and sent.
Limit a session to 32 channels while holding the channel lock. Return
STATUS_INSUFFICIENT_RESOURCES for an additional binding, matching the
server limit expected by clients.
This fixes smb2.multichannel.generic.num_channels, which previously
failed the first binding with STATUS_ACCESS_DENIED and returned the same
status instead of STATUS_INSUFFICIENT_RESOURCES for channel 33.
Fixes: f5a544e3ba ("ksmbd: add support for SMB3 multichannel")
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
fbe0bb2b75
commit
4b706360ff
|
|
@ -133,16 +133,17 @@ static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
* @blen: NTLMv2 blob length
|
* @blen: NTLMv2 blob length
|
||||||
* @domain_name: domain name
|
* @domain_name: domain name
|
||||||
* @cryptkey: session crypto key
|
* @cryptkey: session crypto key
|
||||||
|
* @sess_key: derived session key output buffer
|
||||||
*
|
*
|
||||||
* Return: 0 on success, error number on error
|
* Return: 0 on success, error number on error
|
||||||
*/
|
*/
|
||||||
int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
|
struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
|
||||||
char *cryptkey)
|
char *cryptkey, char *sess_key)
|
||||||
{
|
{
|
||||||
char ntlmv2_hash[CIFS_ENCPWD_SIZE];
|
char ntlmv2_hash[CIFS_ENCPWD_SIZE];
|
||||||
char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
|
char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
|
||||||
char sess_key[SMB2_NTLMV2_SESSKEY_SIZE];
|
char base_key[SMB2_NTLMV2_SESSKEY_SIZE];
|
||||||
struct hmac_md5_ctx ctx;
|
struct hmac_md5_ctx ctx;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
|
@ -165,7 +166,7 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
/* Generate the session key */
|
/* Generate the session key */
|
||||||
hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE,
|
hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE,
|
||||||
ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE,
|
ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE,
|
||||||
sess_key);
|
base_key);
|
||||||
|
|
||||||
if (crypto_memneq(ntlmv2->ntlmv2_hash, ntlmv2_rsp,
|
if (crypto_memneq(ntlmv2->ntlmv2_hash, ntlmv2_rsp,
|
||||||
CIFS_HMAC_MD5_HASH_SIZE)) {
|
CIFS_HMAC_MD5_HASH_SIZE)) {
|
||||||
|
|
@ -173,12 +174,12 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(sess->sess_key, sess_key, sizeof(sess_key));
|
memcpy(sess_key, base_key, sizeof(base_key));
|
||||||
rc = 0;
|
rc = 0;
|
||||||
out:
|
out:
|
||||||
memzero_explicit(ntlmv2_hash, sizeof(ntlmv2_hash));
|
memzero_explicit(ntlmv2_hash, sizeof(ntlmv2_hash));
|
||||||
memzero_explicit(ntlmv2_rsp, sizeof(ntlmv2_rsp));
|
memzero_explicit(ntlmv2_rsp, sizeof(ntlmv2_rsp));
|
||||||
memzero_explicit(sess_key, sizeof(sess_key));
|
memzero_explicit(base_key, sizeof(base_key));
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,12 +190,13 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
* @blob_len: length of the @authblob message
|
* @blob_len: length of the @authblob message
|
||||||
* @conn: connection
|
* @conn: connection
|
||||||
* @sess: session of connection
|
* @sess: session of connection
|
||||||
|
* @sess_key: derived session key output buffer
|
||||||
*
|
*
|
||||||
* Return: 0 on success, error number on error
|
* Return: 0 on success, error number on error
|
||||||
*/
|
*/
|
||||||
int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
||||||
int blob_len, struct ksmbd_conn *conn,
|
int blob_len, struct ksmbd_conn *conn,
|
||||||
struct ksmbd_session *sess)
|
struct ksmbd_session *sess, char *sess_key)
|
||||||
{
|
{
|
||||||
char *domain_name;
|
char *domain_name;
|
||||||
unsigned int nt_off, dn_off;
|
unsigned int nt_off, dn_off;
|
||||||
|
|
@ -234,7 +236,7 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
||||||
ret = ksmbd_auth_ntlmv2(conn, sess,
|
ret = ksmbd_auth_ntlmv2(conn, sess,
|
||||||
(struct ntlmv2_resp *)((char *)authblob + nt_off),
|
(struct ntlmv2_resp *)((char *)authblob + nt_off),
|
||||||
nt_len - CIFS_ENCPWD_SIZE,
|
nt_len - CIFS_ENCPWD_SIZE,
|
||||||
domain_name, conn->ntlmssp.cryptkey);
|
domain_name, conn->ntlmssp.cryptkey, sess_key);
|
||||||
kfree(domain_name);
|
kfree(domain_name);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -257,8 +259,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
||||||
if (!ctx_arc4)
|
if (!ctx_arc4)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
arc4_setkey(ctx_arc4, sess->sess_key, SMB2_NTLMV2_SESSKEY_SIZE);
|
arc4_setkey(ctx_arc4, sess_key, SMB2_NTLMV2_SESSKEY_SIZE);
|
||||||
arc4_crypt(ctx_arc4, sess->sess_key,
|
arc4_crypt(ctx_arc4, sess_key,
|
||||||
(char *)authblob + sess_key_off, sess_key_len);
|
(char *)authblob + sess_key_off, sess_key_len);
|
||||||
kfree_sensitive(ctx_arc4);
|
kfree_sensitive(ctx_arc4);
|
||||||
}
|
}
|
||||||
|
|
@ -400,7 +402,8 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
|
||||||
|
|
||||||
#ifdef CONFIG_SMB_SERVER_KERBEROS5
|
#ifdef CONFIG_SMB_SERVER_KERBEROS5
|
||||||
int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
|
int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
|
||||||
int in_len, char *out_blob, int *out_len)
|
int in_len, char *out_blob, int *out_len,
|
||||||
|
char *sess_key)
|
||||||
{
|
{
|
||||||
struct ksmbd_spnego_authen_response *resp;
|
struct ksmbd_spnego_authen_response *resp;
|
||||||
struct ksmbd_login_response_ext *resp_ext = NULL;
|
struct ksmbd_login_response_ext *resp_ext = NULL;
|
||||||
|
|
@ -455,7 +458,7 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
|
||||||
ksmbd_free_user(user);
|
ksmbd_free_user(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(sess->sess_key, resp->payload, resp->session_key_len);
|
memcpy(sess_key, resp->payload, resp->session_key_len);
|
||||||
memcpy(out_blob, resp->payload + resp->session_key_len,
|
memcpy(out_blob, resp->payload + resp->session_key_len,
|
||||||
resp->spnego_blob_len);
|
resp->spnego_blob_len);
|
||||||
*out_len = resp->spnego_blob_len;
|
*out_len = resp->spnego_blob_len;
|
||||||
|
|
@ -466,7 +469,8 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
|
int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
|
||||||
int in_len, char *out_blob, int *out_len)
|
int in_len, char *out_blob, int *out_len,
|
||||||
|
char *sess_key)
|
||||||
{
|
{
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
@ -525,7 +529,7 @@ struct derivation {
|
||||||
bool binding;
|
bool binding;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
static void generate_key(struct ksmbd_conn *conn, const char *sess_key,
|
||||||
struct kvec label, struct kvec context, __u8 *key,
|
struct kvec label, struct kvec context, __u8 *key,
|
||||||
unsigned int key_size)
|
unsigned int key_size)
|
||||||
{
|
{
|
||||||
|
|
@ -536,7 +540,7 @@ static void generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
unsigned char prfhash[SMB2_HMACSHA256_SIZE];
|
unsigned char prfhash[SMB2_HMACSHA256_SIZE];
|
||||||
struct hmac_sha256_ctx ctx;
|
struct hmac_sha256_ctx ctx;
|
||||||
|
|
||||||
hmac_sha256_init_usingrawkey(&ctx, sess->sess_key,
|
hmac_sha256_init_usingrawkey(&ctx, sess_key,
|
||||||
SMB2_NTLMV2_SESSKEY_SIZE);
|
SMB2_NTLMV2_SESSKEY_SIZE);
|
||||||
hmac_sha256_update(&ctx, i, 4);
|
hmac_sha256_update(&ctx, i, 4);
|
||||||
hmac_sha256_update(&ctx, label.iov_base, label.iov_len);
|
hmac_sha256_update(&ctx, label.iov_base, label.iov_len);
|
||||||
|
|
@ -559,18 +563,21 @@ static int generate_smb3signingkey(struct ksmbd_session *sess,
|
||||||
const struct derivation *signing)
|
const struct derivation *signing)
|
||||||
{
|
{
|
||||||
struct channel *chann;
|
struct channel *chann;
|
||||||
char *key;
|
char *key, *sess_key;
|
||||||
|
|
||||||
chann = lookup_chann_list(sess, conn);
|
chann = lookup_chann_list(sess, conn);
|
||||||
if (!chann)
|
if (!chann)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (conn->dialect >= SMB30_PROT_ID && signing->binding)
|
if (conn->dialect >= SMB30_PROT_ID && signing->binding) {
|
||||||
key = chann->smb3signingkey;
|
key = chann->smb3signingkey;
|
||||||
else
|
sess_key = chann->sess_key;
|
||||||
|
} else {
|
||||||
key = sess->smb3signingkey;
|
key = sess->smb3signingkey;
|
||||||
|
sess_key = sess->sess_key;
|
||||||
|
}
|
||||||
|
|
||||||
generate_key(conn, sess, signing->label, signing->context, key,
|
generate_key(conn, sess_key, signing->label, signing->context, key,
|
||||||
SMB3_SIGN_KEY_SIZE);
|
SMB3_SIGN_KEY_SIZE);
|
||||||
|
|
||||||
if (!(conn->dialect >= SMB30_PROT_ID && signing->binding))
|
if (!(conn->dialect >= SMB30_PROT_ID && signing->binding))
|
||||||
|
|
@ -627,11 +634,11 @@ static void generate_smb3encryptionkey(struct ksmbd_conn *conn,
|
||||||
struct ksmbd_session *sess,
|
struct ksmbd_session *sess,
|
||||||
const struct derivation_twin *ptwin)
|
const struct derivation_twin *ptwin)
|
||||||
{
|
{
|
||||||
generate_key(conn, sess, ptwin->encryption.label,
|
generate_key(conn, sess->sess_key, ptwin->encryption.label,
|
||||||
ptwin->encryption.context, sess->smb3encryptionkey,
|
ptwin->encryption.context, sess->smb3encryptionkey,
|
||||||
SMB3_ENC_DEC_KEY_SIZE);
|
SMB3_ENC_DEC_KEY_SIZE);
|
||||||
|
|
||||||
generate_key(conn, sess, ptwin->decryption.label,
|
generate_key(conn, sess->sess_key, ptwin->decryption.label,
|
||||||
ptwin->decryption.context,
|
ptwin->decryption.context,
|
||||||
sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);
|
sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,17 +41,18 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
|
||||||
void ksmbd_copy_gss_neg_header(void *buf);
|
void ksmbd_copy_gss_neg_header(void *buf);
|
||||||
int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||||
struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
|
struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
|
||||||
char *cryptkey);
|
char *cryptkey, char *sess_key);
|
||||||
int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
||||||
int blob_len, struct ksmbd_conn *conn,
|
int blob_len, struct ksmbd_conn *conn,
|
||||||
struct ksmbd_session *sess);
|
struct ksmbd_session *sess, char *sess_key);
|
||||||
int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
|
int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
|
||||||
int blob_len, struct ksmbd_conn *conn);
|
int blob_len, struct ksmbd_conn *conn);
|
||||||
unsigned int
|
unsigned int
|
||||||
ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
|
ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
|
||||||
struct ksmbd_conn *conn);
|
struct ksmbd_conn *conn);
|
||||||
int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
|
int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
|
||||||
int in_len, char *out_blob, int *out_len);
|
int in_len, char *out_blob, int *out_len,
|
||||||
|
char *sess_key);
|
||||||
void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
|
void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
|
||||||
int n_vec, char *sig);
|
int n_vec, char *sig);
|
||||||
void ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
|
void ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ static void free_channel_list(struct ksmbd_session *sess)
|
||||||
down_write(&sess->chann_lock);
|
down_write(&sess->chann_lock);
|
||||||
xa_for_each(&sess->ksmbd_chann_list, index, chann) {
|
xa_for_each(&sess->ksmbd_chann_list, index, chann) {
|
||||||
xa_erase(&sess->ksmbd_chann_list, index);
|
xa_erase(&sess->ksmbd_chann_list, index);
|
||||||
kfree(chann);
|
kfree_sensitive(chann);
|
||||||
}
|
}
|
||||||
|
|
||||||
xa_destroy(&sess->ksmbd_chann_list);
|
xa_destroy(&sess->ksmbd_chann_list);
|
||||||
|
|
@ -449,7 +449,7 @@ static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
|
||||||
if (!chann)
|
if (!chann)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
kfree(chann);
|
kfree_sensitive(chann);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
struct ksmbd_file_table;
|
struct ksmbd_file_table;
|
||||||
|
|
||||||
struct channel {
|
struct channel {
|
||||||
|
char sess_key[SMB2_NTLMV2_SESSKEY_SIZE];
|
||||||
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
|
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
|
||||||
struct ksmbd_conn *conn;
|
struct ksmbd_conn *conn;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,47 @@ struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn
|
||||||
return chann;
|
return chann;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define KSMBD_MAX_CHANNELS 32
|
||||||
|
|
||||||
|
static int register_session_channel(struct ksmbd_session *sess,
|
||||||
|
struct ksmbd_conn *conn,
|
||||||
|
const char *sess_key)
|
||||||
|
{
|
||||||
|
struct channel *chann, *old;
|
||||||
|
unsigned long index;
|
||||||
|
unsigned int count = 0;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
down_write(&sess->chann_lock);
|
||||||
|
if (xa_load(&sess->ksmbd_chann_list, (long)conn))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
xa_for_each(&sess->ksmbd_chann_list, index, chann)
|
||||||
|
count++;
|
||||||
|
if (count >= KSMBD_MAX_CHANNELS) {
|
||||||
|
rc = -ENOSPC;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
chann = kmalloc_obj(struct channel, KSMBD_DEFAULT_GFP);
|
||||||
|
if (!chann) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
chann->conn = conn;
|
||||||
|
memcpy(chann->sess_key, sess_key, sizeof(chann->sess_key));
|
||||||
|
old = xa_store(&sess->ksmbd_chann_list, (long)conn, chann,
|
||||||
|
KSMBD_DEFAULT_GFP);
|
||||||
|
if (xa_is_err(old)) {
|
||||||
|
kfree_sensitive(chann);
|
||||||
|
rc = xa_err(old);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
up_write(&sess->chann_lock);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* smb2_get_ksmbd_tcon() - get tree connection information using a tree id.
|
* smb2_get_ksmbd_tcon() - get tree connection information using a tree id.
|
||||||
* @work: smb work
|
* @work: smb work
|
||||||
|
|
@ -1644,9 +1685,11 @@ static int ntlm_authenticate(struct ksmbd_work *work,
|
||||||
{
|
{
|
||||||
struct ksmbd_conn *conn = work->conn;
|
struct ksmbd_conn *conn = work->conn;
|
||||||
struct ksmbd_session *sess = work->sess;
|
struct ksmbd_session *sess = work->sess;
|
||||||
struct channel *chann = NULL, *old;
|
|
||||||
struct ksmbd_user *user;
|
struct ksmbd_user *user;
|
||||||
|
char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {};
|
||||||
|
char *auth_key = conn->binding ? channel_key : sess->sess_key;
|
||||||
u64 prev_id;
|
u64 prev_id;
|
||||||
|
bool binding = conn->binding;
|
||||||
int sz, rc;
|
int sz, rc;
|
||||||
|
|
||||||
ksmbd_debug(SMB, "authenticate phase\n");
|
ksmbd_debug(SMB, "authenticate phase\n");
|
||||||
|
|
@ -1705,11 +1748,13 @@ static int ntlm_authenticate(struct ksmbd_work *work,
|
||||||
sz = conn->mechTokenLen;
|
sz = conn->mechTokenLen;
|
||||||
else
|
else
|
||||||
sz = le16_to_cpu(req->SecurityBufferLength);
|
sz = le16_to_cpu(req->SecurityBufferLength);
|
||||||
rc = ksmbd_decode_ntlmssp_auth_blob(authblob, sz, conn, sess);
|
rc = ksmbd_decode_ntlmssp_auth_blob(authblob, sz, conn, sess,
|
||||||
|
auth_key);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
set_user_flag(sess->user, KSMBD_USER_FLAG_BAD_PASSWORD);
|
set_user_flag(sess->user, KSMBD_USER_FLAG_BAD_PASSWORD);
|
||||||
ksmbd_debug(SMB, "authentication failed\n");
|
ksmbd_debug(SMB, "authentication failed\n");
|
||||||
return -EPERM;
|
rc = -EPERM;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1744,37 +1789,30 @@ static int ntlm_authenticate(struct ksmbd_work *work,
|
||||||
|
|
||||||
binding_session:
|
binding_session:
|
||||||
if (conn->dialect >= SMB30_PROT_ID) {
|
if (conn->dialect >= SMB30_PROT_ID) {
|
||||||
chann = lookup_chann_list(sess, conn);
|
rc = register_session_channel(sess, conn, auth_key);
|
||||||
if (!chann) {
|
if (rc)
|
||||||
chann = kmalloc_obj(struct channel, KSMBD_DEFAULT_GFP);
|
goto out;
|
||||||
if (!chann)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
chann->conn = conn;
|
|
||||||
down_write(&sess->chann_lock);
|
|
||||||
old = xa_store(&sess->ksmbd_chann_list, (long)conn, chann,
|
|
||||||
KSMBD_DEFAULT_GFP);
|
|
||||||
up_write(&sess->chann_lock);
|
|
||||||
if (xa_is_err(old)) {
|
|
||||||
kfree(chann);
|
|
||||||
return xa_err(old);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->ops->generate_signingkey) {
|
if (conn->ops->generate_signingkey) {
|
||||||
rc = conn->ops->generate_signingkey(sess, conn);
|
rc = conn->ops->generate_signingkey(sess, conn);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
ksmbd_debug(SMB, "SMB3 signing key generation failed\n");
|
ksmbd_debug(SMB, "SMB3 signing key generation failed\n");
|
||||||
return -EINVAL;
|
rc = -EINVAL;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ksmbd_conn_lookup_dialect(conn)) {
|
if (!ksmbd_conn_lookup_dialect(conn)) {
|
||||||
pr_err("fail to verify the dialect\n");
|
pr_err("fail to verify the dialect\n");
|
||||||
return -ENOENT;
|
rc = -ENOENT;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
return 0;
|
rc = 0;
|
||||||
|
out:
|
||||||
|
if (binding)
|
||||||
|
memzero_explicit(channel_key, sizeof(channel_key));
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SMB_SERVER_KERBEROS5
|
#ifdef CONFIG_SMB_SERVER_KERBEROS5
|
||||||
|
|
@ -1785,8 +1823,10 @@ static int krb5_authenticate(struct ksmbd_work *work,
|
||||||
struct ksmbd_conn *conn = work->conn;
|
struct ksmbd_conn *conn = work->conn;
|
||||||
struct ksmbd_session *sess = work->sess;
|
struct ksmbd_session *sess = work->sess;
|
||||||
char *in_blob, *out_blob;
|
char *in_blob, *out_blob;
|
||||||
struct channel *chann = NULL, *old;
|
char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {};
|
||||||
|
char *auth_key = conn->binding ? channel_key : sess->sess_key;
|
||||||
u64 prev_sess_id;
|
u64 prev_sess_id;
|
||||||
|
bool binding = conn->binding;
|
||||||
int in_len, out_len;
|
int in_len, out_len;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
|
@ -1799,10 +1839,11 @@ static int krb5_authenticate(struct ksmbd_work *work,
|
||||||
(le16_to_cpu(rsp->SecurityBufferOffset) + 4);
|
(le16_to_cpu(rsp->SecurityBufferOffset) + 4);
|
||||||
|
|
||||||
retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
|
retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
|
||||||
out_blob, &out_len);
|
out_blob, &out_len, auth_key);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
ksmbd_debug(SMB, "krb5 authentication failed\n");
|
ksmbd_debug(SMB, "krb5 authentication failed\n");
|
||||||
return -EINVAL;
|
retval = -EINVAL;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check previous session */
|
/* Check previous session */
|
||||||
|
|
@ -1839,37 +1880,30 @@ static int krb5_authenticate(struct ksmbd_work *work,
|
||||||
|
|
||||||
binding_session:
|
binding_session:
|
||||||
if (conn->dialect >= SMB30_PROT_ID) {
|
if (conn->dialect >= SMB30_PROT_ID) {
|
||||||
chann = lookup_chann_list(sess, conn);
|
retval = register_session_channel(sess, conn, auth_key);
|
||||||
if (!chann) {
|
if (retval)
|
||||||
chann = kmalloc_obj(struct channel, KSMBD_DEFAULT_GFP);
|
goto out;
|
||||||
if (!chann)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
chann->conn = conn;
|
|
||||||
down_write(&sess->chann_lock);
|
|
||||||
old = xa_store(&sess->ksmbd_chann_list, (long)conn,
|
|
||||||
chann, KSMBD_DEFAULT_GFP);
|
|
||||||
up_write(&sess->chann_lock);
|
|
||||||
if (xa_is_err(old)) {
|
|
||||||
kfree(chann);
|
|
||||||
return xa_err(old);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->ops->generate_signingkey) {
|
if (conn->ops->generate_signingkey) {
|
||||||
retval = conn->ops->generate_signingkey(sess, conn);
|
retval = conn->ops->generate_signingkey(sess, conn);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
ksmbd_debug(SMB, "SMB3 signing key generation failed\n");
|
ksmbd_debug(SMB, "SMB3 signing key generation failed\n");
|
||||||
return -EINVAL;
|
retval = -EINVAL;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ksmbd_conn_lookup_dialect(conn)) {
|
if (!ksmbd_conn_lookup_dialect(conn)) {
|
||||||
pr_err("fail to verify the dialect\n");
|
pr_err("fail to verify the dialect\n");
|
||||||
return -ENOENT;
|
retval = -ENOENT;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
return 0;
|
retval = 0;
|
||||||
|
out:
|
||||||
|
if (binding)
|
||||||
|
memzero_explicit(channel_key, sizeof(channel_key));
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static int krb5_authenticate(struct ksmbd_work *work,
|
static int krb5_authenticate(struct ksmbd_work *work,
|
||||||
|
|
@ -2091,7 +2125,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||||
rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED;
|
rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED;
|
||||||
else if (rc == -EFAULT)
|
else if (rc == -EFAULT)
|
||||||
rsp->hdr.Status = STATUS_NETWORK_SESSION_EXPIRED;
|
rsp->hdr.Status = STATUS_NETWORK_SESSION_EXPIRED;
|
||||||
else if (rc == -ENOMEM)
|
else if (rc == -ENOMEM || rc == -ENOSPC)
|
||||||
rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
|
rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
else if (rc == -EOPNOTSUPP)
|
else if (rc == -EOPNOTSUPP)
|
||||||
rsp->hdr.Status = STATUS_NOT_SUPPORTED;
|
rsp->hdr.Status = STATUS_NOT_SUPPORTED;
|
||||||
|
|
@ -2130,8 +2164,16 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||||
sess->last_active = jiffies;
|
sess->last_active = jiffies;
|
||||||
sess->state = SMB2_SESSION_EXPIRED;
|
sess->state = SMB2_SESSION_EXPIRED;
|
||||||
}
|
}
|
||||||
ksmbd_user_session_put(sess);
|
/*
|
||||||
work->sess = NULL;
|
* Keep the binding session reference until the response is
|
||||||
|
* signed and sent. Error responses for a signed binding
|
||||||
|
* request are signed with the existing session signing key.
|
||||||
|
*/
|
||||||
|
if (!(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) ||
|
||||||
|
work->sess != sess) {
|
||||||
|
ksmbd_user_session_put(sess);
|
||||||
|
work->sess = NULL;
|
||||||
|
}
|
||||||
if (try_delay) {
|
if (try_delay) {
|
||||||
ksmbd_conn_set_need_reconnect(conn);
|
ksmbd_conn_set_need_reconnect(conn);
|
||||||
ssleep(5);
|
ssleep(5);
|
||||||
|
|
@ -9483,7 +9525,6 @@ bool smb2_is_sign_req(struct ksmbd_work *work, unsigned int command)
|
||||||
|
|
||||||
if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) &&
|
if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) &&
|
||||||
command != SMB2_NEGOTIATE_HE &&
|
command != SMB2_NEGOTIATE_HE &&
|
||||||
command != SMB2_SESSION_SETUP_HE &&
|
|
||||||
command != SMB2_OPLOCK_BREAK_HE)
|
command != SMB2_OPLOCK_BREAK_HE)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
@ -9632,13 +9673,14 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
|
||||||
struct channel *chann;
|
struct channel *chann;
|
||||||
char signature[SMB2_CMACAES_SIZE];
|
char signature[SMB2_CMACAES_SIZE];
|
||||||
struct kvec *iov;
|
struct kvec *iov;
|
||||||
|
u16 command = conn->ops->get_cmd_val(work);
|
||||||
int n_vec = 1;
|
int n_vec = 1;
|
||||||
char *signing_key;
|
char *signing_key;
|
||||||
|
|
||||||
hdr = ksmbd_resp_buf_curr(work);
|
hdr = ksmbd_resp_buf_curr(work);
|
||||||
|
|
||||||
if (conn->binding == false &&
|
if (command == SMB2_SESSION_SETUP_HE &&
|
||||||
le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
|
(!conn->binding || hdr->Status != STATUS_SUCCESS)) {
|
||||||
signing_key = work->sess->smb3signingkey;
|
signing_key = work->sess->smb3signingkey;
|
||||||
} else {
|
} else {
|
||||||
chann = lookup_chann_list(work->sess, work->conn);
|
chann = lookup_chann_list(work->sess, work->conn);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user