diff options
-rw-r--r-- | source3/libsmb/cliconnect.c | 3 | ||||
-rw-r--r-- | source3/libsmb/smb_seal.c | 12 | ||||
-rw-r--r-- | source3/smbd/seal.c | 163 |
3 files changed, 149 insertions, 29 deletions
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 0f09747dbf1..3970731b45f 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -763,7 +763,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use } } - /* we have a reference conter on ntlmssp_state, if we are signing + /* we have a reference counter on ntlmssp_state, if we are signing then the state will be kept by the signing engine */ ntlmssp_end(&ntlmssp_state); @@ -973,7 +973,6 @@ NTSTATUS cli_session_setup(struct cli_state *cli, } return NT_STATUS_OK; - } /**************************************************************************** diff --git a/source3/libsmb/smb_seal.c b/source3/libsmb/smb_seal.c index e7b3e8f024c..06662e53fbf 100644 --- a/source3/libsmb/smb_seal.c +++ b/source3/libsmb/smb_seal.c @@ -282,3 +282,15 @@ NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out) { return common_encrypt_buffer(cli->trans_enc_state, cli->outbuf, buf_out); } + +/****************************************************************************** + Start a raw ntlmssp encryption. +******************************************************************************/ + +NTSTATUS cli_ntlm_smb_encryption_on(struct cli_state *cli, + const char *user, + const char *pass, + const char *workgroup) +{ + +} diff --git a/source3/smbd/seal.c b/source3/smbd/seal.c index 0a530526a2a..9910a84f4c4 100644 --- a/source3/smbd/seal.c +++ b/source3/smbd/seal.c @@ -49,7 +49,44 @@ BOOL srv_encryption_on(void) } /****************************************************************************** - Shutdown a server encryption state. + Create an auth_ntlmssp_state and ensure pointer copy is correct. +******************************************************************************/ + +static NTSTATUS make_auth_ntlmssp(struct smb_srv_trans_enc_ctx *ec) +{ + NTSTATUS status = auth_ntlmssp_start(&ec->auth_ntlmssp_state); + if (!NT_STATUS_IS_OK(status)) { + return nt_status_squash(status); + } + + /* + * We must remember to update the pointer copy for the common + * functions after any auth_ntlmssp_start/auth_ntlmssp_end. + */ + ec->es->ntlmssp_state = ec->auth_ntlmssp_state->ntlmssp_state; + return status; +} + +/****************************************************************************** + Destroy an auth_ntlmssp_state and ensure pointer copy is correct. +******************************************************************************/ + +static void destroy_auth_ntlmssp(struct smb_srv_trans_enc_ctx *ec) +{ + /* + * We must remember to update the pointer copy for the common + * functions after any auth_ntlmssp_start/auth_ntlmssp_end. + */ + + if (ec->auth_ntlmssp_state) { + auth_ntlmssp_end(&ec->auth_ntlmssp_state); + /* The auth_ntlmssp_end killed this already. */ + ec->es->ntlmssp_state = NULL; + } +} + +/****************************************************************************** + Shutdown a server encryption context. ******************************************************************************/ static void srv_free_encryption_context(struct smb_srv_trans_enc_ctx **pp_ec) @@ -61,12 +98,8 @@ static void srv_free_encryption_context(struct smb_srv_trans_enc_ctx **pp_ec) } if (ec->es) { - struct smb_trans_enc_state *es = ec->es; - if (es->smb_enc_type == SMB_TRANS_ENC_NTLM && - ec->auth_ntlmssp_state) { - auth_ntlmssp_end(&ec->auth_ntlmssp_state); - /* The auth_ntlmssp_end killed this already. */ - es->ntlmssp_state = NULL; + if (ec->es->smb_enc_type == SMB_TRANS_ENC_NTLM) { + destroy_auth_ntlmssp(ec); } common_free_encryption_state(&ec->es); } @@ -76,6 +109,36 @@ static void srv_free_encryption_context(struct smb_srv_trans_enc_ctx **pp_ec) } /****************************************************************************** + Create a server encryption context. +******************************************************************************/ + +static struct smb_srv_trans_enc_ctx *make_srv_encryption_context(enum smb_trans_enc_type smb_enc_type) +{ + struct smb_srv_trans_enc_ctx *ec; + + ec = SMB_MALLOC_P(struct smb_srv_trans_enc_ctx); + if (!ec) { + return NULL; + } + ZERO_STRUCTP(partial_srv_trans_enc_ctx); + ec->es = SMB_MALLOC_P(struct smb_trans_enc_state); + if (!ec->es) { + SAFE_FREE(ec); + return NULL; + } + ZERO_STRUCTP(ec->es); + ec->es->smb_enc_type = smb_enc_type; + if (smb_enc_type == SMB_TRANS_ENC_NTLM) { + NTSTATUS status = make_auth_ntlmssp(ec); + if (!NT_STATUS_IS_OK(status)) { + srv_free_encryption_context(&ec); + return NULL; + } + } + return ec; +} + +/****************************************************************************** Free an encryption-allocated buffer. ******************************************************************************/ @@ -125,29 +188,33 @@ static NTSTATUS srv_enc_spnego_gss_negotiate(char **ppdata, size_t *p_data_size, #endif /****************************************************************************** - Do the NTLM SPNEGO encryption negotiation. Parameters are in/out. + Do the NTLM SPNEGO (or raw) encryption negotiation. Parameters are in/out. Until success we do everything on the partial enc ctx. ******************************************************************************/ -static NTSTATUS srv_enc_spnego_ntlm_negotiate(unsigned char **ppdata, size_t *p_data_size, DATA_BLOB secblob) +static NTSTATUS srv_enc_ntlm_negotiate(unsigned char **ppdata, size_t *p_data_size, DATA_BLOB secblob, BOOL spnego_wrap) { NTSTATUS status; DATA_BLOB chal = data_blob(NULL, 0); DATA_BLOB response = data_blob(NULL, 0); - struct smb_srv_trans_enc_ctx *ec = partial_srv_trans_enc_ctx; - status = auth_ntlmssp_start(&ec->auth_ntlmssp_state); - if (!NT_STATUS_IS_OK(status)) { - return nt_status_squash(status); + partial_srv_trans_enc_ctx = make_srv_encryption_context(SMB_TRANS_ENC_NTLM); + if (!partial_srv_trans_enc_ctx) { + return NT_STATUS_NO_MEMORY; } - status = auth_ntlmssp_update(ec->auth_ntlmssp_state, secblob, &chal); + status = auth_ntlmssp_update(partial_srv_trans_enc_ctx->auth_ntlmssp_state, secblob, &chal); /* status here should be NT_STATUS_MORE_PROCESSING_REQUIRED * for success ... */ - response = spnego_gen_auth_response(&chal, status, OID_NTLMSSP); - data_blob_free(&chal); + if (spnego_wrap) { + response = spnego_gen_auth_response(&chal, status, OID_NTLMSSP); + data_blob_free(&chal); + } else { + /* Return the raw blob. */ + response = chal; + } SAFE_FREE(*ppdata); *ppdata = response.data; @@ -179,20 +246,13 @@ static NTSTATUS srv_enc_spnego_negotiate(unsigned char **ppdata, size_t *p_data_ srv_free_encryption_context(&partial_srv_trans_enc_ctx); - partial_srv_trans_enc_ctx = SMB_MALLOC_P(struct smb_srv_trans_enc_ctx); - if (!partial_srv_trans_enc_ctx) { - data_blob_free(&secblob); - return NT_STATUS_NO_MEMORY; - } - ZERO_STRUCTP(partial_srv_trans_enc_ctx); - #if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5) if (got_kerberos_mechanism && lp_use_kerberos_keytab()) ) { status = srv_enc_spnego_gss_negotiate(ppdata, p_data_size, secblob); } else #endif { - status = srv_enc_spnego_ntlm_negotiate(ppdata, p_data_size, secblob); + status = srv_enc_ntlm_negotiate(ppdata, p_data_size, secblob, True); } data_blob_free(&secblob); @@ -220,7 +280,7 @@ static NTSTATUS srv_enc_spnego_ntlm_auth(unsigned char **ppdata, size_t *p_data_ /* We must have a partial context here. */ - if (!ec || ec->auth_ntlmssp_state == NULL) { + if (!ec || !ec->es || ec->auth_ntlmssp_state == NULL || ec->es->smb_enc_type != SMB_TRANS_ENC_NTLM) { srv_free_encryption_context(&partial_srv_trans_enc_ctx); return NT_STATUS_INVALID_PARAMETER; } @@ -244,6 +304,44 @@ static NTSTATUS srv_enc_spnego_ntlm_auth(unsigned char **ppdata, size_t *p_data_ } /****************************************************************************** + Raw NTLM encryption negotiation. Parameters are in/out. + This function does both steps. +******************************************************************************/ + +static NTSTATUS srv_enc_raw_ntlm_auth(unsigned char **ppdata, size_t *p_data_size) +{ + NTSTATUS status; + DATA_BLOB blob = data_blob_const(*ppdata, *p_data_size); + DATA_BLOB response = data_blob(NULL,0); + struct smb_srv_trans_enc_ctx *ec; + + if (!partial_srv_trans_enc_ctx) { + /* This is the initial step. */ + status = srv_enc_ntlm_negotiate(ppdata, p_data_size, blob, False); + if (!NT_STATUS_IS_OK(status)) { + srv_free_encryption_context(&partial_srv_trans_enc_ctx); + return nt_status_squash(status); + } + return status; + } + + ec = partial_srv_trans_enc_ctx; + if (!ec || !ec->es || ec->auth_ntlmssp_state == NULL || ec->es->smb_enc_type != SMB_TRANS_ENC_NTLM) { + srv_free_encryption_context(&partial_srv_trans_enc_ctx); + return NT_STATUS_INVALID_PARAMETER; + } + + /* Second step. */ + status = auth_ntlmssp_update(partial_srv_trans_enc_ctx->auth_ntlmssp_state, blob, &response); + + /* Return the raw blob. */ + SAFE_FREE(*ppdata); + *ppdata = response.data; + *p_data_size = response.length; + return status; +} + +/****************************************************************************** Do the SPNEGO encryption negotiation. Parameters are in/out. ******************************************************************************/ @@ -265,11 +363,22 @@ NTSTATUS srv_request_encryption_setup(unsigned char **ppdata, size_t *p_data_siz } if (pdata[0] == ASN1_CONTEXT(1)) { - /* Its a auth packet */ + /* It's an auth packet */ return srv_enc_spnego_ntlm_auth(ppdata, p_data_size); } - return NT_STATUS_INVALID_PARAMETER; + /* Maybe it's a raw unwrapped auth ? */ + if (*p_data_size < 7) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (strncmp((char *)pdata, "NTLMSSP", 7) == 0) { + return srv_enc_raw_ntlm_auth(ppdata, p_data_size); + } + + DEBUG(1,("srv_request_encryption_setup: Unknown packet\n")); + + return NT_STATUS_LOGON_FAILURE; } /****************************************************************************** |